| Differences between
and this patch
- a/Source/ThirdParty/ANGLE/ChangeLog +1049 lines
Lines 1-3 a/Source/ThirdParty/ANGLE/ChangeLog_sec1
1
2020-12-10  Kyle Piddington  <kpiddington@apple.com>
2
3
        Added a new backend for translating GLSL content to MSL. Added fixes, updates, and workarounds in the open source
4
        metal backend for ANGLE.
5
       
6
	https://bugs.webkit.org/show_bug.cgi?id=219759
7
8
        Reviewed by NOBODY (OOPS!)
9
10
	This changelog includes a WebGL1 compliant transpiler for GLSL content. With this change,
11
        we can leverage the already present open source work in the ANGLE project to enable webgl to run on top of Metal. 
12
        In addition, this patch contains a number of fixes to the metal backend. 
13
        
14
        Test: Tests were validated with the dEQP test suite with ANGLE, in addition to running standard layout tests.
15
16
        * ANGLE.xcodeproj/project.pbxproj:
17
        * Configurations/ANGLE-dynamic.xcconfig:
18
        * include/GLSLANG/ShaderLang.h:
19
        * include/platform/FeaturesMtl.h:
20
        * src/common/PoolAlloc.cpp:
21
        (angle::Allocation::checkAllocList const):
22
        * src/common/PoolAlloc.h:
23
        (angle::Allocation::checkAlloc const):
24
        * src/common/apple_platform_utils.h:
25
        * src/common/debug.h:
26
        * src/common/system_utils_ios.mm: Added.
27
        (angle::GetExecutablePath):
28
        (angle::GetExecutableDirectory):
29
        (angle::GetSharedLibraryExtension):
30
        (angle::GetCurrentTime):
31
        * src/common/utilities.cpp:
32
        (gl::VariableAttributeCount):
33
        * src/common/utilities.h:
34
        * src/compiler/translator/CodeGen.cpp:
35
        (sh::ConstructCompiler):
36
        * src/compiler/translator/Common.h:
37
        * src/compiler/translator/Compiler.cpp:
38
        (sh::TCompiler::checkAndSimplifyAST):
39
        * src/compiler/translator/Compiler.h:
40
        (sh::TShHandleBase::getAsTranslatorMetalDirect):
41
        * src/compiler/translator/ConstantUnion.cpp:
42
        (sh::TConstantUnion::TConstantUnion):
43
        * src/compiler/translator/ConstantUnion.h:
44
        * src/compiler/translator/IntermNode.cpp:
45
        (sh::TIntermBlock::TIntermBlock):
46
        (sh::TIntermDeclaration::TIntermDeclaration):
47
        (sh::TIntermAggregateBase::replaceChildNodeInternal):
48
        (sh::TIntermAggregateBase::replaceChildNodeWithMultiple):
49
        (sh::TIntermAggregateBase::insertChildNodes):
50
        (sh::TIntermAggregate::shallowCopy const):
51
        * src/compiler/translator/IntermNode.h:
52
        * src/compiler/translator/Symbol.cpp:
53
        (sh::TFunction::buildMangledName const):
54
        * src/compiler/translator/Symbol.h:
55
        (sh::TFunction::isDefined const):
56
        * src/compiler/translator/SymbolTable_ESSL_autogen.cpp:
57
        * src/compiler/translator/TranslatorMetal.cpp:
58
        (sh::TranslatorMetal::GetCoverageMaskEnabledConstName):
59
        (sh::TranslatorMetal::GetRasterizationDiscardEnabledConstName):
60
        (sh::TranslatorMetal::translate):
61
        (sh::TranslatorMetal::createAdditionalGraphicsDriverUniformFields):
62
        (sh::TranslatorMetal::insertRasterizationDiscardLogic):
63
        (sh::TranslatorMetal::replaceAllMainDiscardUses):
64
        (sh::TranslatorMetal::createDiscardWrapperFunc):
65
        * src/compiler/translator/TranslatorMetal.h:
66
        (sh::TranslatorMetal::enableEmulatedInstanceID):
67
        * src/compiler/translator/TranslatorMetalDirect.cpp: Added.
68
        (sh::TranslatorMetalDirect::TranslatorMetalDirect):
69
        (sh::TranslatorMetalDirect::GetCoverageMaskEnabledConstName):
70
        (sh::TranslatorMetalDirect::GetRasterizationDiscardEnabledConstName):
71
        (sh::TranslatorMetalDirect::insertRasterizationDiscardLogic):
72
        (sh::TranslatorMetalDirect::transformDepthBeforeCorrection):
73
        (sh::TranslatorMetalDirect::createAdditionalGraphicsDriverUniformFields):
74
        (sh::TranslatorMetalDirect::getDriverUniformNegFlipYRef const):
75
        (sh::GetMslKeywords):
76
        (sh::TranslatorMetalDirect::translateImpl):
77
        (sh::TranslatorMetalDirect::translate):
78
        (sh::TranslatorMetalDirect::shouldFlattenPragmaStdglInvariantAll):
79
        * src/compiler/translator/TranslatorMetalDirect.h: Added.
80
        (sh::TranslatorMetalReflection::TranslatorMetalReflection):
81
        (sh::TranslatorMetalReflection::~TranslatorMetalReflection):
82
        (sh::TranslatorMetalReflection::addOriginalName):
83
        (sh::TranslatorMetalReflection::addSamplerBinding):
84
        (sh::TranslatorMetalReflection::addTextureBinding):
85
        (sh::TranslatorMetalReflection::addUniformBufferBinding):
86
        (sh::TranslatorMetalReflection::getOriginalName):
87
        (sh::TranslatorMetalReflection::getSamplerBindings const):
88
        (sh::TranslatorMetalReflection::getTextureBindings const):
89
        (sh::TranslatorMetalReflection::getUniformBufferBindings const):
90
        (sh::TranslatorMetalReflection::getSamplerBinding const):
91
        (sh::TranslatorMetalReflection::getTextureBinding const):
92
        (sh::TranslatorMetalReflection::getUniformBufferBinding const):
93
        (sh::TranslatorMetalReflection::reset):
94
        (sh::TranslatorMetalDirect::enableEmulatedInstanceID):
95
        (sh::TranslatorMetalDirect::getTranslatorMetalReflection):
96
        * src/compiler/translator/TranslatorMetalDirect/AddExplicitTypeCasts.cpp: Added.
97
        (sh::Rewriter::Rewriter):
98
        (sh::AddExplicitTypeCasts):
99
        * src/compiler/translator/TranslatorMetalDirect/AddExplicitTypeCasts.h: Added.
100
        * src/compiler/translator/TranslatorMetalDirect/AstHelpers.cpp: Added.
101
        (sh::ViewDeclaration):
102
        (sh::CreateStructTypeVariable):
103
        (sh::CreateInstanceVariable):
104
        (AcquireFunctionExtras):
105
        (sh::CloneSequenceAndPrepend):
106
        (sh::AddParametersFrom):
107
        (sh::CloneFunction):
108
        (sh::CloneFunctionAndPrependParam):
109
        (sh::CloneFunctionAndAppendParams):
110
        (sh::CloneFunctionAndChangeReturnType):
111
        (sh::GetArg):
112
        (sh::SetArg):
113
        (sh::GetFieldIndex):
114
        (sh::AccessField):
115
        (sh::AccessFieldByIndex):
116
        (sh::AccessIndex):
117
        (sh::SubVector):
118
        (sh::IsScalarBasicType):
119
        (sh::IsVectorBasicType):
120
        (sh::HasScalarBasicType):
121
        (InitType):
122
        (sh::CloneType):
123
        (sh::InnermostType):
124
        (sh::DropColumns):
125
        (sh::DropOuterDimension):
126
        (SetTypeDimsImpl):
127
        (sh::SetVectorDim):
128
        (sh::SetMatrixRowDim):
129
        (sh::HasMatrixField):
130
        (sh::HasArrayField):
131
        (sh::CoerceSimple):
132
        (sh::AsType):
133
        * src/compiler/translator/TranslatorMetalDirect/AstHelpers.h: Added.
134
        * src/compiler/translator/TranslatorMetalDirect/ConstantNames.h: Added.
135
        * src/compiler/translator/TranslatorMetalDirect/Debug.h: Added.
136
        * src/compiler/translator/TranslatorMetalDirect/DebugSink.h: Added.
137
        (sh::StringObserver::StringObserver):
138
        (sh::StringObserver::observe):
139
        (sh::StringObserver::getNeedle const):
140
        (sh::StringObserver::reset):
141
        (sh::DebugSink::EscapedSink::EscapedSink):
142
        (sh::DebugSink::EscapedSink::~EscapedSink):
143
        (sh::DebugSink::EscapedSink::get):
144
        (sh::DebugSink::EscapedSink::operator TInfoSinkBase &):
145
        (sh::DebugSink::DebugSink):
146
        (sh::DebugSink::watch):
147
        (sh::DebugSink::erase):
148
        (sh::DebugSink::size):
149
        (sh::DebugSink::str const):
150
        (sh::DebugSink::c_str const):
151
        (sh::DebugSink::escape):
152
        (sh::DebugSink::operator<<):
153
        (sh::DebugSink::onWrite):
154
        * src/compiler/translator/TranslatorMetalDirect/DiscoverDependentFunctions.cpp: Added.
155
        (sh::Discoverer::Discoverer):
156
        * src/compiler/translator/TranslatorMetalDirect/DiscoverDependentFunctions.h: Added.
157
        * src/compiler/translator/TranslatorMetalDirect/DiscoverEnclosingFunctionTraverser.cpp: Added.
158
        (DiscoverEnclosingFunctionTraverser::DiscoverEnclosingFunctionTraverser):
159
        (DiscoverEnclosingFunctionTraverser::discoverEnclosingFunction):
160
        * src/compiler/translator/TranslatorMetalDirect/DiscoverEnclosingFunctionTraverser.h: Added.
161
        * src/compiler/translator/TranslatorMetalDirect/EmitMetal.cpp: Added.
162
        (GenMetalTraverser::~GenMetalTraverser):
163
        (GenMetalTraverser::GenMetalTraverser):
164
        (GenMetalTraverser::emitIndentation):
165
        (GetOperatorString):
166
        (GetOperatorPrecedence):
167
        (GetAssociativity):
168
        (IsSymbolicOperator):
169
        (AsSpecificBinaryNode):
170
        (Parenthesize):
171
        (GenMetalTraverser::groupedTraverse):
172
        (GenMetalTraverser::emitPostQualifier):
173
        (EmitName):
174
        (GenMetalTraverser::emitNameOf):
175
        (GenMetalTraverser::emitBareTypeName):
176
        (GenMetalTraverser::emitType):
177
        (GenMetalTraverser::emitFieldDeclaration):
178
        (BuildExternalAttributeIndexMap):
179
        (GenMetalTraverser::emitAttributeDeclaration):
180
        (GenMetalTraverser::emitStructDeclaration):
181
        (GenMetalTraverser::emitOrdinaryVariableDeclaration):
182
        (GenMetalTraverser::emitVariableDeclaration):
183
        (GenMetalTraverser::visitSymbol):
184
        (GenMetalTraverser::emitSingleConstant):
185
        (GenMetalTraverser::emitConstantUnionArray):
186
        (GenMetalTraverser::emitConstantUnion):
187
        (GenMetalTraverser::visitConstantUnion):
188
        (GenMetalTraverser::visitSwizzle):
189
        (GenMetalTraverser::getDirectField):
190
        (GenMetalTraverser::visitBinary):
191
        (IsPostfix):
192
        (GenMetalTraverser::visitUnary):
193
        (GenMetalTraverser::visitTernary):
194
        (GenMetalTraverser::visitIfElse):
195
        (GenMetalTraverser::visitSwitch):
196
        (GenMetalTraverser::visitCase):
197
        (GenMetalTraverser::emitFunctionSignature):
198
        (GenMetalTraverser::emitFunctionReturn):
199
        (GenMetalTraverser::emitFunctionParameter):
200
        (GenMetalTraverser::visitFunctionPrototype):
201
        (GenMetalTraverser::visitFunctionDefinition):
202
        (GenMetalTraverser::BuildFuncToName):
203
        (GenMetalTraverser::visitAggregate):
204
        (GenMetalTraverser::emitOpenBrace):
205
        (GenMetalTraverser::emitCloseBrace):
206
        (RequiresSemicolonTerminator):
207
        (NewlinePad):
208
        (GenMetalTraverser::visitBlock):
209
        (GenMetalTraverser::visitGlobalQualifierDeclaration):
210
        (GenMetalTraverser::visitDeclaration):
211
        (GenMetalTraverser::visitLoop):
212
        (GenMetalTraverser::visitForLoop):
213
        (GenMetalTraverser::visitWhileLoop):
214
        (GenMetalTraverser::visitDoWhileLoop):
215
        (GenMetalTraverser::visitBranch):
216
        (sh::EmitMetal):
217
        * src/compiler/translator/TranslatorMetalDirect/EmitMetal.h: Added.
218
        * src/compiler/translator/TranslatorMetalDirect/EnvironmentVariable.h: Added.
219
        (sh::readBoolEnvVar):
220
        (sh::readStringEnvVar):
221
        * src/compiler/translator/TranslatorMetalDirect/HoistConstants.cpp: Added.
222
        (sh::Rewriter::Rewriter):
223
        (sh::Rewriter::rewrite):
224
        (sh::HoistConstants):
225
        * src/compiler/translator/TranslatorMetalDirect/HoistConstants.h: Added.
226
        * src/compiler/translator/TranslatorMetalDirect/IdGen.cpp: Added.
227
        (IdGen::IdGen):
228
        (IdGen::createNewName):
229
        * src/compiler/translator/TranslatorMetalDirect/IdGen.h: Added.
230
        * src/compiler/translator/TranslatorMetalDirect/Layout.cpp: Added.
231
        (RoundUpToMultipleOf):
232
        (Layout::requireAlignment):
233
        (Layout::operator== const):
234
        (Layout::operator+=):
235
        (Layout::operator*=):
236
        (Layout::operator+ const):
237
        (Layout::operator* const):
238
        (ScalarLayoutOf):
239
        (sh::Overlay):
240
        (sh::CanBePacked):
241
        (sh::SetBlockStorage):
242
        (CommonGlslStructLayoutOf):
243
        (CommonGlslLayoutOf):
244
        (sh::GlslLayoutOf):
245
        (sh::GlslStructLayoutOf):
246
        * src/compiler/translator/TranslatorMetalDirect/Layout.h: Added.
247
        (sh::Layout::Identity):
248
        (sh::Layout::Invalid):
249
        (sh::Layout::Both):
250
        (sh::MetalLayoutOf):
251
        * src/compiler/translator/TranslatorMetalDirect/MapFunctionsToDefinitions.cpp: Added.
252
        (Mapper::Mapper):
253
        (sh::MapFunctionsToDefinitions):
254
        * src/compiler/translator/TranslatorMetalDirect/MapFunctionsToDefinitions.h: Added.
255
        * src/compiler/translator/TranslatorMetalDirect/MapSymbols.cpp: Added.
256
        (sh::Rewriter::Rewriter):
257
        (sh::MapSymbols):
258
        * src/compiler/translator/TranslatorMetalDirect/MapSymbols.h: Added.
259
        * src/compiler/translator/TranslatorMetalDirect/ModifyStruct.cpp: Added.
260
        (ModifiedStructMachineries::size const):
261
        (ModifiedStructMachineries::at const):
262
        (ModifiedStructMachineries::find const):
263
        (ModifiedStructMachineries::insert):
264
        (sh::TryCreateModifiedStruct):
265
        * src/compiler/translator/TranslatorMetalDirect/ModifyStruct.h: Added.
266
        (sh::ModifyStructConfig::Predicate::False):
267
        (sh::ModifyStructConfig::Predicate::True):
268
        (sh::ModifyStructConfig::SaturateVector::DontSaturate):
269
        (sh::ModifyStructConfig::SaturateVector::FullySaturate):
270
        (sh::ModifyStructConfig::ModifyStructConfig):
271
        (sh::ModifiedStructMachinery::getConverter):
272
        * src/compiler/translator/TranslatorMetalDirect/Name.cpp: Added.
273
        (GetName):
274
        (Name::Name):
275
        (Name::operator== const):
276
        (Name::operator!= const):
277
        (Name::operator< const):
278
        (Name::empty const):
279
        (Name::beginsWith const):
280
        (Name::emit const):
281
        (sh::ExpressionContainsName):
282
        * src/compiler/translator/TranslatorMetalDirect/Name.h: Added.
283
        (sh::Name::Name):
284
        (sh::Name::rawName const):
285
        (sh::Name::symbolType const):
286
        * src/compiler/translator/TranslatorMetalDirect/Pipeline.cpp: Added.
287
        (Pipeline::uses const):
288
        (Pipeline::getStructTypeName const):
289
        (Pipeline::getStructInstanceName const):
290
        (AllowPacking):
291
        (AllowPadding):
292
        (CompareBy):
293
        (SaturateVectorOf):
294
        (Pipeline::externalStructModifyConfig const):
295
        (Pipeline::alwaysRequiresLocalVariableDeclarationInMain const):
296
        (Pipeline::isPipelineOut const):
297
        (Pipeline::externalAddressSpace const):
298
        (PipelineStructs::matches const):
299
        * src/compiler/translator/TranslatorMetalDirect/Pipeline.h: Added.
300
        (sh::PipelineScoped::matches const):
301
        (sh::PipelineScoped::isTotallyFull const):
302
        (sh::PipelineScoped::isTotallyEmpty const):
303
        (sh::PipelineScoped::isUniform const):
304
        * src/compiler/translator/TranslatorMetalDirect/ProgramPrelude.cpp: Added.
305
        (sh::ProgramPrelude::ProgramPrelude):
306
        (sh::ProgramPrelude::emitGuard):
307
        (ANGLE_is_vector::PROGRAM_PRELUDE_DECLARE):
308
        * src/compiler/translator/TranslatorMetalDirect/ProgramPrelude.h: Added.
309
        * src/compiler/translator/TranslatorMetalDirect/ReduceInterfaceBlocks.cpp: Added.
310
        (sh::Reducer::Reducer):
311
        (sh::ReduceInterfaceBlocks):
312
        * src/compiler/translator/TranslatorMetalDirect/ReduceInterfaceBlocks.h: Added.
313
        * src/compiler/translator/TranslatorMetalDirect/Reference.h: Added.
314
        (sh::Ref::Ref):
315
        (sh::Ref::operator== const):
316
        (sh::Ref::operator!= const):
317
        (sh::Ref::operator<= const):
318
        (sh::Ref::operator>= const):
319
        (sh::Ref::operator< const):
320
        (sh::Ref::operator> const):
321
        (sh::Ref::get):
322
        (sh::Ref::get const):
323
        (sh::Ref::operator T &):
324
        (sh::Ref::operator T const & const):
325
        (sh::Ref::operator T *):
326
        (sh::Ref::operator T const * const):
327
        * src/compiler/translator/TranslatorMetalDirect/RewriteCaseDeclarations.cpp: Added.
328
        (sh::Rewriter::Rewriter):
329
        (sh::RewriteCaseDeclarations):
330
        * src/compiler/translator/TranslatorMetalDirect/RewriteCaseDeclarations.h: Added.
331
        * src/compiler/translator/TranslatorMetalDirect/RewriteGlobalQualifierDecls.cpp: Added.
332
        (sh::FindDeclaredGlobals::FindDeclaredGlobals):
333
        (sh::Rewriter::Rewriter):
334
        (sh::RewriteGlobalQualifierDecls):
335
        * src/compiler/translator/TranslatorMetalDirect/RewriteGlobalQualifierDecls.h: Added.
336
        (sh::Invariants::insert):
337
        (sh::Invariants::contains const):
338
        * src/compiler/translator/TranslatorMetalDirect/RewriteKeywords.cpp: Added.
339
        (sh::Rewriter::maybeCreateNewName):
340
        (sh::Rewriter::createRenamed):
341
        (sh::Rewriter::tryGetRenamedImpl):
342
        (sh::Rewriter::tryGetRenamed):
343
        (sh::Rewriter::getRenamedOrOriginal):
344
        (sh::Rewriter::needsRenamingImpl const):
345
        (sh::Rewriter::needsRenaming const):
346
        (sh::Rewriter::Rewriter):
347
        (sh::Rewriter::visitSymbol):
348
        (sh::Rewriter::visitFunctionPrototype):
349
        (sh::RewriteKeywords):
350
        * src/compiler/translator/TranslatorMetalDirect/RewriteKeywords.h: Added.
351
        * src/compiler/translator/TranslatorMetalDirect/RewriteOutArgs.cpp: Added.
352
        (sh::SmallMultiSet::find const):
353
        (sh::SmallMultiSet::multiplicity const):
354
        (sh::SmallMultiSet::insert):
355
        (sh::SmallMultiSet::clear):
356
        (sh::SmallMultiSet::empty const):
357
        (sh::SmallMultiSet::uniqueSize const):
358
        (sh::SmallMultiSet::findMutable):
359
        (sh::GetVariable):
360
        (sh::Rewriter::Rewriter):
361
        (sh::RewriteOutArgs):
362
        * src/compiler/translator/TranslatorMetalDirect/RewriteOutArgs.h: Added.
363
        * src/compiler/translator/TranslatorMetalDirect/RewritePipelines.cpp: Added.
364
        (sh::PipelineStructInfo::isEmpty const):
365
        (sh::GeneratePipelineStruct::Exec):
366
        (sh::GeneratePipelineStruct::GeneratePipelineStruct):
367
        (sh::GeneratePipelineStruct::exec):
368
        (sh::GeneratePipelineStruct::createInternalPipelineStruct):
369
        (sh::CreatePipelineMainLocalVar):
370
        (sh::PipelineFunctionEnv::PipelineFunctionEnv):
371
        (sh::PipelineFunctionEnv::isOriginalPipelineFunction const):
372
        (sh::PipelineFunctionEnv::isUpdatedPipelineFunction const):
373
        (sh::PipelineFunctionEnv::getUpdatedFunction):
374
        (sh::PipelineFunctionEnv::createUpdatedFunctionPrototype):
375
        (sh::UpdatePipelineFunctions::ThreadPipeline):
376
        (sh::UpdatePipelineFunctions::UpdatePipelineFunctions):
377
        (sh::UpdatePipelineFunctions::getInternalPipelineVariable):
378
        (sh::UpdatePipelineFunctions::getExternalPipelineVariable):
379
        (sh::UpdatePipelineFunctions::visitNonMain):
380
        (sh::UpdatePipelineFunctions::visitMain):
381
        (sh::UpdatePipelineSymbols):
382
        (sh::RewritePipeline):
383
        (sh::RewritePipelines):
384
        * src/compiler/translator/TranslatorMetalDirect/RewritePipelines.h: Added.
385
        * src/compiler/translator/TranslatorMetalDirect/RewriteUnaddressableReferences.cpp: Added.
386
        (sh::IsOutParam):
387
        (sh::IsVectorAccess):
388
        (sh::IsAssignEqualsSign):
389
        (sh::IsCompoundAssign):
390
        (sh::ReturnsReference):
391
        (sh::DecomposeCompoundAssignment):
392
        (sh::Rewriter1::Rewriter1):
393
        (sh::Rewriter2::requiresAddressing const):
394
        (sh::Rewriter2::Rewriter2):
395
        (sh::RewriteUnaddressableReferences):
396
        * src/compiler/translator/TranslatorMetalDirect/RewriteUnaddressableReferences.h: Added.
397
        * src/compiler/translator/TranslatorMetalDirect/SeparateCompoundExpressions.cpp: Added.
398
        (sh::IsIndex):
399
        (sh::ViewBinaryChain):
400
        (sh::PrePass::PrePass):
401
        (sh::PrePass::reassociateRight):
402
        (sh::Separator::Separator):
403
        (sh::Separator::pushStmt):
404
        (sh::Separator::isTerminalExpr):
405
        (sh::Separator::pullMappedExpr):
406
        (sh::Separator::isStandaloneExpr):
407
        (sh::Separator::pushBinding):
408
        (sh::Separator::pushStacks):
409
        (sh::Separator::popStacks):
410
        (sh::Separator::pushStmtsIntoBlock):
411
        (sh::Separator::buildBlockWithTailAssign):
412
        (sh::SeparateCompoundExpressions):
413
        * src/compiler/translator/TranslatorMetalDirect/SeparateCompoundExpressions.h: Added.
414
        * src/compiler/translator/TranslatorMetalDirect/SeparateCompoundStructDeclarations.cpp: Added.
415
        (sh::Separator::Separator):
416
        (sh::SeparateCompoundStructDeclarations):
417
        * src/compiler/translator/TranslatorMetalDirect/SeparateCompoundStructDeclarations.h: Added.
418
        * src/compiler/translator/TranslatorMetalDirect/SkippingTraverser.h: Added.
419
        (sh::SkippingTraverser::SkippingTraverser):
420
        (sh::SkippingTraverser::visitSwizzle):
421
        (sh::SkippingTraverser::visitUnary):
422
        (sh::SkippingTraverser::visitBinary):
423
        (sh::SkippingTraverser::visitTernary):
424
        (sh::SkippingTraverser::visitIfElse):
425
        (sh::SkippingTraverser::visitSwitch):
426
        (sh::SkippingTraverser::visitCase):
427
        (sh::SkippingTraverser::visitFunctionDefinition):
428
        (sh::SkippingTraverser::visitAggregate):
429
        (sh::SkippingTraverser::visitBlock):
430
        (sh::SkippingTraverser::visitDeclaration):
431
        (sh::SkippingTraverser::visitLoop):
432
        (sh::SkippingTraverser::visitBranch):
433
        (sh::SkippingTraverser::visitGlobalQualifierDeclaration):
434
        * src/compiler/translator/TranslatorMetalDirect/SymbolEnv.cpp: Added.
435
        (StructFinder::StructFinder):
436
        (StructFinder::FindStructs):
437
        (TemplateArg::TemplateArg):
438
        (TemplateArg::operator== const):
439
        (TemplateArg::operator< const):
440
        (SymbolEnv::TemplateName::operator== const):
441
        (SymbolEnv::TemplateName::operator< const):
442
        (SymbolEnv::TemplateName::empty const):
443
        (SymbolEnv::TemplateName::clear):
444
        (SymbolEnv::TemplateName::fullName const):
445
        (SymbolEnv::TemplateName::assign):
446
        (SymbolEnv::SymbolEnv):
447
        (SymbolEnv::remap const):
448
        (SymbolEnv::getFunctionOverloadImpl):
449
        (SymbolEnv::getFunctionOverload):
450
        (SymbolEnv::callFunctionOverload):
451
        (SymbolEnv::newStructure):
452
        (SymbolEnv::getTextureEnv):
453
        (SymbolEnv::getSamplerStruct):
454
        (SymbolEnv::markSpace):
455
        (SymbolEnv::isSpace const):
456
        (SymbolEnv::markAsPointer):
457
        (SymbolEnv::markAsReference):
458
        (SymbolEnv::isPointer const):
459
        (SymbolEnv::isReference const):
460
        (SymbolEnv::markAsPacked):
461
        (SymbolEnv::isPacked const):
462
        (GetTextureBasicType):
463
        (sh::GetTextureTypeName):
464
        * src/compiler/translator/TranslatorMetalDirect/SymbolEnv.h: Added.
465
        (sh::VarField::VarField):
466
        (sh::VarField::variable const):
467
        (sh::VarField::field const):
468
        (sh::VarField::operator== const):
469
        (std::hash<sh::VarField>::operator() const):
470
        (sh::TemplateArg::kind const):
471
        (sh::TemplateArg::value const):
472
        (sh::SymbolEnv::symbolTable):
473
        * src/compiler/translator/TranslatorMetalDirect/ToposortStructs.cpp: Added.
474
        (sh::BuildGraphImpl):
475
        (sh::Toposort):
476
        (sh::CreateStructEqualityFunction):
477
        (sh::GetAsDeclaredStructure):
478
        (sh::FindStructEqualityUse::FindStructEqualityUse):
479
        (sh::FindStructEqualityUse::useStruct):
480
        (sh::ToposortStructs):
481
        * src/compiler/translator/TranslatorMetalDirect/ToposortStructs.h: Added.
482
        * src/compiler/translator/TranslatorMetalDirect/WrapMain.cpp: Added.
483
        (sh::Wrapper::Wrapper):
484
        (sh::Wrapper::visitMain):
485
        (sh::WrapMain):
486
        * src/compiler/translator/TranslatorMetalDirect/WrapMain.h: Added.
487
        * src/compiler/translator/TranslatorMetalUtils.cpp: Added.
488
        (sh::getBasicMetalString):
489
        (sh::getBuiltInMetalTypeNameString):
490
        (sh::GetMetalTypeName):
491
        * src/compiler/translator/TranslatorMetalUtils.h: Added.
492
        * src/compiler/translator/TranslatorVulkan.cpp:
493
        * src/compiler/translator/Types.h:
494
        (sh::TType::isRank0 const):
495
        * src/compiler/translator/ValidateAST.cpp:
496
        * src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp:
497
        * src/compiler/translator/tree_ops/PruneEmptyCases.cpp:
498
        * src/compiler/translator/tree_ops/RemoveSwitchFallThrough.cpp:
499
        * src/compiler/translator/tree_ops/SimplifyLoopConditions.cpp:
500
        (sh::SimplifyLoopConditions):
501
        * src/compiler/translator/tree_ops/SimplifyLoopConditions.h:
502
        * src/compiler/translator/tree_util/AsNode.h: Added.
503
        (sh::priv::AsNode<TIntermNode>::exec):
504
        (sh::priv::AsNode<TIntermTyped>::exec):
505
        (sh::priv::AsNode<TIntermSymbol>::exec):
506
        (sh::priv::AsNode<TIntermConstantUnion>::exec):
507
        (sh::priv::AsNode<TIntermFunctionPrototype>::exec):
508
        (sh::priv::AsNode<TIntermPreprocessorDirective>::exec):
509
        (sh::priv::AsNode<TIntermSwizzle>::exec):
510
        (sh::priv::AsNode<TIntermBinary>::exec):
511
        (sh::priv::AsNode<TIntermUnary>::exec):
512
        (sh::priv::AsNode<TIntermTernary>::exec):
513
        (sh::priv::AsNode<TIntermIfElse>::exec):
514
        (sh::priv::AsNode<TIntermSwitch>::exec):
515
        (sh::priv::AsNode<TIntermCase>::exec):
516
        (sh::priv::AsNode<TIntermFunctionDefinition>::exec):
517
        (sh::priv::AsNode<TIntermAggregate>::exec):
518
        (sh::priv::AsNode<TIntermBlock>::exec):
519
        (sh::priv::AsNode<TIntermGlobalQualifierDeclaration>::exec):
520
        (sh::priv::AsNode<TIntermDeclaration>::exec):
521
        (sh::priv::AsNode<TIntermLoop>::exec):
522
        (sh::priv::AsNode<TIntermBranch>::exec):
523
        (sh::asNode):
524
        * src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp:
525
        (sh::IntermNodePatternMatcher::matchInternal const):
526
        (sh::IntermNodePatternMatcher::match const):
527
        * src/compiler/translator/tree_util/IntermNodePatternMatcher.h:
528
        * src/compiler/translator/tree_util/IntermNode_util.cpp:
529
        * src/compiler/translator/tree_util/IntermNode_util.h:
530
        * src/compiler/translator/tree_util/IntermRebuild.cpp: Added.
531
        (sh::AllBits):
532
        (sh::AnyBits):
533
        (sh::TIntermRebuild::BaseResult::BaseResult):
534
        (sh::TIntermRebuild::BaseResult::moveAssignImpl):
535
        (sh::TIntermRebuild::BaseResult::Multi):
536
        (sh::TIntermRebuild::BaseResult::isFail const):
537
        (sh::TIntermRebuild::BaseResult::isDrop const):
538
        (sh::TIntermRebuild::BaseResult::single const):
539
        (sh:: const):
540
        (sh::PreResult::PreResult):
541
        (sh::PreResult::operator=):
542
        (sh::PostResult::PostResult):
543
        (sh::PostResult::operator=):
544
        (sh::TIntermRebuild::TIntermRebuild):
545
        (sh::TIntermRebuild::~TIntermRebuild):
546
        (sh::TIntermRebuild::getParentFunction const):
547
        (sh::TIntermRebuild::getParentNode const):
548
        (sh::TIntermRebuild::rebuildRoot):
549
        (sh::TIntermRebuild::rebuildInPlace):
550
        (sh::TIntermRebuild::rebuildInPlaceImpl):
551
        (sh::TIntermRebuild::rebuild):
552
        (sh::TIntermRebuild::traverseAnyAs):
553
        (sh::TIntermRebuild::traverseAggregateBaseChildren):
554
        (sh::TIntermRebuild::NodeStackGuard::NodeStackGuard):
555
        (sh::TIntermRebuild::NodeStackGuard::~NodeStackGuard):
556
        (sh::TIntermRebuild::traverseAny):
557
        (sh::TIntermRebuild::traversePre):
558
        (sh::TIntermRebuild::traverseChildren):
559
        (sh::TIntermRebuild::traversePost):
560
        (sh::TIntermRebuild::traverseAggregateChildren):
561
        (sh::TIntermRebuild::traverseBlockChildren):
562
        (sh::TIntermRebuild::traverseDeclarationChildren):
563
        (sh::TIntermRebuild::traverseSwizzleChildren):
564
        (sh::TIntermRebuild::traverseBinaryChildren):
565
        (sh::TIntermRebuild::traverseUnaryChildren):
566
        (sh::TIntermRebuild::traverseTernaryChildren):
567
        (sh::TIntermRebuild::traverseIfElseChildren):
568
        (sh::TIntermRebuild::traverseSwitchChildren):
569
        (sh::TIntermRebuild::traverseCaseChildren):
570
        (sh::TIntermRebuild::traverseFunctionDefinitionChildren):
571
        (sh::TIntermRebuild::traverseGlobalQualifierDeclarationChildren):
572
        (sh::TIntermRebuild::traverseLoopChildren):
573
        (sh::TIntermRebuild::traverseBranchChildren):
574
        (sh::TIntermRebuild::visitSymbolPre):
575
        (sh::TIntermRebuild::visitConstantUnionPre):
576
        (sh::TIntermRebuild::visitFunctionPrototypePre):
577
        (sh::TIntermRebuild::visitPreprocessorDirectivePre):
578
        (sh::TIntermRebuild::visitUnaryPre):
579
        (sh::TIntermRebuild::visitBinaryPre):
580
        (sh::TIntermRebuild::visitTernaryPre):
581
        (sh::TIntermRebuild::visitSwizzlePre):
582
        (sh::TIntermRebuild::visitIfElsePre):
583
        (sh::TIntermRebuild::visitSwitchPre):
584
        (sh::TIntermRebuild::visitCasePre):
585
        (sh::TIntermRebuild::visitLoopPre):
586
        (sh::TIntermRebuild::visitBranchPre):
587
        (sh::TIntermRebuild::visitDeclarationPre):
588
        (sh::TIntermRebuild::visitBlockPre):
589
        (sh::TIntermRebuild::visitAggregatePre):
590
        (sh::TIntermRebuild::visitFunctionDefinitionPre):
591
        (sh::TIntermRebuild::visitGlobalQualifierDeclarationPre):
592
        (sh::TIntermRebuild::visitSymbolPost):
593
        (sh::TIntermRebuild::visitConstantUnionPost):
594
        (sh::TIntermRebuild::visitFunctionPrototypePost):
595
        (sh::TIntermRebuild::visitPreprocessorDirectivePost):
596
        (sh::TIntermRebuild::visitUnaryPost):
597
        (sh::TIntermRebuild::visitBinaryPost):
598
        (sh::TIntermRebuild::visitTernaryPost):
599
        (sh::TIntermRebuild::visitSwizzlePost):
600
        (sh::TIntermRebuild::visitIfElsePost):
601
        (sh::TIntermRebuild::visitSwitchPost):
602
        (sh::TIntermRebuild::visitCasePost):
603
        (sh::TIntermRebuild::visitLoopPost):
604
        (sh::TIntermRebuild::visitBranchPost):
605
        (sh::TIntermRebuild::visitDeclarationPost):
606
        (sh::TIntermRebuild::visitBlockPost):
607
        (sh::TIntermRebuild::visitAggregatePost):
608
        (sh::TIntermRebuild::visitFunctionDefinitionPost):
609
        (sh::TIntermRebuild::visitGlobalQualifierDeclarationPost):
610
        * src/compiler/translator/tree_util/IntermRebuild.h: Added.
611
        (sh::TIntermRebuild::BaseResult::Multi):
612
        (sh::TIntermRebuild::PreResult::Multi):
613
        (sh::TIntermRebuild::PostResult::Multi):
614
        * src/compiler/translator/tree_util/NodeType.h: Added.
615
        (sh::GetNodeType::GetNodeType):
616
        (sh::GetNodeType::operator()):
617
        * src/compiler/translator/util.cpp:
618
        (sh::IsOutputMetalDirect):
619
        * src/compiler/translator/util.h:
620
        * src/gpu_info_util/SystemInfo_apple.mm:
621
        (angle::GetSystemInfo):
622
        * src/gpu_info_util/SystemInfo_ios.cpp:
623
        (angle::GetSystemInfo_ios):
624
        * src/gpu_info_util/SystemInfo_macos.mm:
625
        (angle::GetSystemInfo_mac):
626
        * src/libANGLE/Caps.cpp:
627
        (gl::GetFormatSupportBase):
628
        (gl::DetermineASTCLDRTextureSupport):
629
        (gl::DetermineDepthTextureANGLESupport):
630
        (gl::DetermineDepthTextureOESSupport):
631
        * src/libANGLE/Display.cpp:
632
        (egl::Display::makeCurrent):
633
        * src/libANGLE/Display.h:
634
        * src/libANGLE/Program.h:
635
        * src/libANGLE/ProgramExecutable.h:
636
        * src/libANGLE/renderer/driver_utils.cpp:
637
        (rx::GetiOSVersion):
638
        * src/libANGLE/renderer/driver_utils.h:
639
        (rx::IsMac):
640
        * src/libANGLE/renderer/driver_utils_ios.mm: Copied from Source/ThirdParty/ANGLE/src/libANGLE/renderer/driver_utils_mac.mm.
641
        (rx::GetiOSVersion):
642
        * src/libANGLE/renderer/driver_utils_mac.mm:
643
        * src/libANGLE/renderer/gl/SoftLinking_apple.h: Added.
644
        * src/libANGLE/renderer/gl/cgl/CGLFunctions.cpp: Added.
645
        * src/libANGLE/renderer/gl/cgl/CGLFunctions.h: Added.
646
        * src/libANGLE/renderer/gl/cgl/DisplayCGL.mm:
647
        (rx::DisplayCGL::initialize):
648
        (rx::DisplayCGL::isValidNativeWindow const):
649
        * src/libANGLE/renderer/gl/eagl/DisplayEAGL.mm:
650
        (rx::DisplayEAGL::initialize):
651
        (rx::DisplayEAGL::terminate):
652
        (rx::DisplayEAGL::isValidNativeWindow const):
653
        (rx::DisplayEAGL::generateExtensions const):
654
        * src/libANGLE/renderer/gl/eagl/EAGLFunctions.h: Added.
655
        * src/libANGLE/renderer/gl/eagl/EAGLFunctions.mm: Added.
656
        * src/libANGLE/renderer/gl/eagl/IOSurfaceSurfaceEAGL.mm:
657
        (rx::IOSurfaceSurfaceEAGL::IOSurfaceSurfaceEAGL):
658
        (rx::IOSurfaceSurfaceEAGL::bindTexImage):
659
        (rx::IOSurfaceSurfaceEAGL::releaseTexImage):
660
        * src/libANGLE/renderer/glslang_wrapper_utils.cpp:
661
        * src/libANGLE/renderer/glslang_wrapper_utils.h:
662
        * src/libANGLE/renderer/load_functions_data.json:
663
        * src/libANGLE/renderer/load_functions_table_autogen.cpp:
664
        (angle::GetLoadFunctionsMap):
665
        * src/libANGLE/renderer/metal/BUILD.gn:
666
        * src/libANGLE/renderer/metal/BufferMtl.h:
667
        (rx::BufferMtl::getClientShadowCopyData):
668
        * src/libANGLE/renderer/metal/BufferMtl.mm:
669
        (rx::BufferMtl::setData):
670
        (rx::BufferMtl::mapRange):
671
        (rx::BufferMtl::setDataImpl):
672
        * src/libANGLE/renderer/metal/CompilerMtl.mm:
673
        (rx::CompilerMtl::getTranslatorOutputType const):
674
        * src/libANGLE/renderer/metal/ContextMtl.h:
675
        (rx::ContextMtl::getProgram const):
676
        * src/libANGLE/renderer/metal/ContextMtl.mm:
677
        (rx::ContextMtl::ContextMtl):
678
        (rx::ContextMtl::initialize):
679
        (rx::ContextMtl::ensureIncompleteTexturesCreated):
680
        (rx::ContextMtl::drawTriFanArraysWithBaseVertex):
681
        (rx::ContextMtl::drawTriFanArraysLegacy):
682
        (rx::ContextMtl::drawLineLoopArrays):
683
        (rx::ContextMtl::drawArraysImpl):
684
        (rx::ContextMtl::drawTriFanElements):
685
        (rx::ContextMtl::drawLineLoopElements):
686
        (rx::ContextMtl::drawElementsSimpleTypesPrimitiveRestart):
687
        (rx::ContextMtl::drawElementsImpl):
688
        (rx::ContextMtl::drawElementsBaseVertex):
689
        (rx::ContextMtl::drawElementsInstancedBaseVertex):
690
        (rx::ContextMtl::drawElementsInstancedBaseVertexBaseInstance):
691
        (rx::ContextMtl::drawRangeElementsBaseVertex):
692
        (rx::ContextMtl::execDrawInstanced):
693
        (rx::ContextMtl::execDrawIndexedInstanced):
694
        (rx::ContextMtl::insertEventMarker):
695
        (rx::ContextMtl::pushGroupMarker):
696
        (rx::ContextMtl::invalidateCurrentTransformFeedbackBuffers):
697
        (rx::ContextMtl::onTransformFeedbackStateChanged):
698
        (rx::ContextMtl::onBeginTransformFeedback):
699
        (rx::ContextMtl::populateTransformFeedbackBufferSet):
700
        (rx::ContextMtl::onEndTransformFeedback):
701
        (rx::ContextMtl::onPauseTransformFeedback):
702
        (rx::ContextMtl::getNativeFormatCaps const):
703
        (rx::ContextMtl::endRenderEncoding):
704
        (rx::ContextMtl::flushCommandBufer):
705
        (rx::ContextMtl::getRenderPassCommandEncoder):
706
        (rx::ContextMtl::getTextureRenderCommandEncoder):
707
        (rx::ContextMtl::ensureCommandBufferReady):
708
        (rx::ContextMtl::onBackbufferResized):
709
        (rx::ContextMtl::onOcclusionQueryBegan):
710
        (rx::ContextMtl::onOcclusionQueryEnded):
711
        (rx::ContextMtl::onOcclusionQueryDestroyed):
712
        (rx::ContextMtl::setupDraw):
713
        (rx::ContextMtl::handleDirtyActiveTextures):
714
        (rx::ContextMtl::handleDirtyDefaultAttribs):
715
        (rx::ContextMtl::handleDirtyDriverUniforms):
716
        (rx::ContextMtl::handleDirtyGraphicsTransformFeedbackBuffersEmulation):
717
        (rx::ContextMtl::handleDirtyDepthStencilState):
718
        (rx::ContextMtl::checkIfPipelineChanged):
719
        * src/libANGLE/renderer/metal/DisplayMtl.h:
720
        * src/libANGLE/renderer/metal/DisplayMtl.mm:
721
        (rx::GetDepthSize):
722
        (rx::GetStencilSize):
723
        (rx::DisplayMtl::DisplayMtl):
724
        (rx::DisplayMtl::initializeImpl):
725
        (rx::DisplayMtl::terminate):
726
        (rx::DisplayMtl::validateClientBuffer const):
727
        (rx::DisplayMtl::createPbufferSurface):
728
        (rx::DisplayMtl::createPbufferFromClientBuffer):
729
        (rx::DisplayMtl::getMaxSupportedESVersion const):
730
        (rx::DisplayMtl::createShareGroup):
731
        (rx::DisplayMtl::generateConfigs):
732
        (rx::DisplayMtl::ensureCapsInitialized const):
733
        (rx::DisplayMtl::initializeExtensions const):
734
        (rx::DisplayMtl::initializeTextureCaps const):
735
        (rx::DisplayMtl::initializeLimitations):
736
        (rx::DisplayMtl::initializeFeatures):
737
        (rx::DisplayMtl::initializeShaderLibrary):
738
        * src/libANGLE/renderer/metal/FrameBufferMtl.h:
739
        (rx::FramebufferMtl::getAttachedBackbuffer const):
740
        * src/libANGLE/renderer/metal/FrameBufferMtl.mm:
741
        (rx::FramebufferMtl::FramebufferMtl):
742
        (rx::FramebufferMtl::reset):
743
        (rx::FramebufferMtl::clearBufferfv):
744
        (rx::FramebufferMtl::clearBufferuiv):
745
        (rx::FramebufferMtl::clearBufferiv):
746
        (rx::FramebufferMtl::clearBufferfi):
747
        (rx::FramebufferMtl::getImplementationColorReadFormat const):
748
        (rx::FramebufferMtl::syncState):
749
        (rx::FramebufferMtl::onFrameEnd):
750
        (rx::FramebufferMtl::getReadableViewForRenderTarget):
751
        (rx::FramebufferMtl::prepareRenderPass):
752
        (rx::FramebufferMtl::overrideClearColor):
753
        (rx::FramebufferMtl::clearWithLoadOpRenderPassNotStarted):
754
        (rx::FramebufferMtl::clearWithLoadOpRenderPassStarted):
755
        (rx::FramebufferMtl::getCorrectFlippedReadArea const):
756
        (rx::FramebufferMtl::readPixelsImpl const):
757
        (rx::FramebufferMtl::readPixelsToPBO const):
758
        (rx::FramebufferMtl::readPixelsToBuffer const):
759
        * src/libANGLE/renderer/metal/IOSurfaceSurfaceMtl.h: Added.
760
        * src/libANGLE/renderer/metal/IOSurfaceSurfaceMtl.mm: Added.
761
        (rx::IOSurfaceSurfaceMtl::IOSurfaceSurfaceMtl):
762
        (rx::IOSurfaceSurfaceMtl::~IOSurfaceSurfaceMtl):
763
        (rx::IOSurfaceSurfaceMtl::destroy):
764
        (rx::IOSurfaceSurfaceMtl::initialize):
765
        (rx::IOSurfaceSurfaceMtl::createDefaultFramebuffer):
766
        (rx::IOSurfaceSurfaceMtl::makeCurrent):
767
        (rx::IOSurfaceSurfaceMtl::unMakeCurrent):
768
        (rx::IOSurfaceSurfaceMtl::swap):
769
        (rx::IOSurfaceSurfaceMtl::postSubBuffer):
770
        (rx::IOSurfaceSurfaceMtl::querySurfacePointerANGLE):
771
        (rx::IOSurfaceSurfaceMtl::bindTexImage):
772
        (rx::IOSurfaceSurfaceMtl::releaseTexImage):
773
        (rx::IOSurfaceSurfaceMtl::getSyncValues):
774
        (rx::IOSurfaceSurfaceMtl::getMscRate):
775
        (rx::IOSurfaceSurfaceMtl::setSwapInterval):
776
        (rx::IOSurfaceSurfaceMtl::setFixedWidth):
777
        (rx::IOSurfaceSurfaceMtl::setFixedHeight):
778
        (rx::IOSurfaceSurfaceMtl::getWidth const):
779
        (rx::IOSurfaceSurfaceMtl::getHeight const):
780
        (rx::IOSurfaceSurfaceMtl::isPostSubBufferSupported const):
781
        (rx::IOSurfaceSurfaceMtl::getSwapBehavior const):
782
        (rx::IOSurfaceSurfaceMtl::getAttachmentRenderTarget):
783
        (rx::IOSurfaceSurfaceMtl::ensureCurrentDrawableObtained):
784
        (rx::IOSurfaceSurfaceMtl::createBackingTexture):
785
        (rx::IOSurfaceSurfaceMtl::ensureTextureCreated):
786
        (rx::IOSurfaceSurfaceMtl::getTexture):
787
        (rx::IOSurfaceSurfaceMtl::createTexture):
788
        * src/libANGLE/renderer/metal/ProgramMtl.h:
789
        (rx::ProgramMtl::getXfbMslSource const):
790
        * src/libANGLE/renderer/metal/ProgramMtl.mm:
791
        (rx::ProgramMtl::ProgramMtl):
792
        (rx::ProgramMtl::~ProgramMtl):
793
        (rx::ProgramMtl::reset):
794
        (rx::ProgramMtl::saveTranslatedShaders):
795
        (rx::ProgramMtl::loadTranslatedShaders):
796
        (rx::ProgramMtl::load):
797
        (rx::ProgramMtl::save):
798
        (rx::ProgramMtl::link):
799
        (rx::ProgramMtl::linkImplSpirv):
800
        (rx::ProgramMtl::linkImplDirect):
801
        (rx::ProgramMtl::linkImpl):
802
        (rx::ProgramMtl::linkTranslatedShaders):
803
        (rx::ProgramMtl::initDefaultUniformBlocks):
804
        (rx::ProgramMtl::resizeDefaultUniformBlocksMemory):
805
        (rx::ProgramMtl::getSpecializedShader):
806
        (rx::ProgramMtl::saveDefaultUniformBlocksInfo):
807
        (rx::ProgramMtl::loadDefaultUniformBlocksInfo):
808
        (rx::ProgramMtl::saveShaderInternalInfo):
809
        (rx::ProgramMtl::loadShaderInternalInfo):
810
        (rx::ProgramMtl::setupDraw):
811
        (rx::ProgramMtl::updateTextures):
812
        (rx::ProgramMtl::updateUniformBuffers):
813
        (rx::ProgramMtl::bindUniformBuffersToDiscreteSlots):
814
        (rx::ProgramMtl::encodeUniformBuffersInfoArgumentBuffer):
815
        * src/libANGLE/renderer/metal/QueryMtl.h:
816
        * src/libANGLE/renderer/metal/QueryMtl.mm:
817
        (rx::QueryMtl::QueryMtl):
818
        (rx::QueryMtl::onDestroy):
819
        (rx::QueryMtl::begin):
820
        (rx::QueryMtl::end):
821
        (rx::QueryMtl::waitAndGetResult):
822
        (rx::QueryMtl::isResultAvailable):
823
        (rx::QueryMtl::onTransformFeedbackEnd):
824
        * src/libANGLE/renderer/metal/RenderBufferMtl.h:
825
        * src/libANGLE/renderer/metal/RenderBufferMtl.mm:
826
        (rx::RenderbufferMtl::releaseTexture):
827
        (rx::RenderbufferMtl::setStorageImpl):
828
        (rx::RenderbufferMtl::getAttachmentRenderTarget):
829
        * src/libANGLE/renderer/metal/RenderTargetMtl.h:
830
        * src/libANGLE/renderer/metal/RenderTargetMtl.mm:
831
        (rx::RenderTargetMtl::RenderTargetMtl):
832
        (rx::RenderTargetMtl::setWithImplicitMSTexture):
833
        (rx::RenderTargetMtl::setTexture):
834
        (rx::RenderTargetMtl::setImplicitMSTexture):
835
        (rx::RenderTargetMtl::reset):
836
        (rx::RenderTargetMtl::getRenderSamples const):
837
        (rx::RenderTargetMtl::toRenderPassAttachmentDesc const):
838
        * src/libANGLE/renderer/metal/ShaderMtl.h:
839
        (rx::ShaderMtl::getTranslatorMetalReflection):
840
        * src/libANGLE/renderer/metal/ShaderMtl.mm:
841
        (rx::TranslateTask::TranslateTask):
842
        (rx::TranslateTask::getResult):
843
        (rx::TranslateTask::getHandle):
844
        (rx::ShaderMtl::compileImplMtl):
845
        (rx::ShaderMtl::compile):
846
        * src/libANGLE/renderer/metal/SurfaceMtl.h:
847
        (rx::SurfaceMtlProtocol::SurfaceMtlProtocol):
848
        * src/libANGLE/renderer/metal/SurfaceMtl.mm:
849
        (rx::SurfaceMtl::SurfaceMtl):
850
        (rx::WindowSurfaceMtl::ensureCurrentDrawableObtained):
851
        * src/libANGLE/renderer/metal/SyncMtl.h:
852
        * src/libANGLE/renderer/metal/SyncMtl.mm:
853
        (rx::mtl::Sync::clientWait):
854
        (rx::FenceNVMtl::onDestroy):
855
        (rx::EGLSyncMtl::dupNativeFenceFD const):
856
        * src/libANGLE/renderer/metal/TextureMtl.h:
857
        * src/libANGLE/renderer/metal/TextureMtl.mm:
858
        (rx::TextureMtl::ensureTextureCreated):
859
        (rx::TextureMtl::bindTexImage):
860
        (rx::TextureMtl::releaseTexImage):
861
        (rx::TextureMtl::getAttachmentRenderTarget):
862
        * src/libANGLE/renderer/metal/TransformFeedbackMtl.h:
863
        (rx::TransformFeedbackMtl:: const):
864
        * src/libANGLE/renderer/metal/TransformFeedbackMtl.mm:
865
        (rx::TransformFeedbackMtl::TransformFeedbackMtl):
866
        (rx::TransformFeedbackMtl::begin):
867
        (rx::TransformFeedbackMtl::end):
868
        (rx::TransformFeedbackMtl::pause):
869
        (rx::TransformFeedbackMtl::resume):
870
        (rx::TransformFeedbackMtl::bindIndexedBuffer):
871
        (rx::TransformFeedbackMtl::getBufferOffsets const):
872
        * src/libANGLE/renderer/metal/VertexArrayMtl.h:
873
        * src/libANGLE/renderer/metal/VertexArrayMtl.mm:
874
        (rx::VertexArrayMtl::reset):
875
        (rx::VertexArrayMtl::setupDraw):
876
        (rx::VertexArrayMtl::emulateInstanceDrawStep):
877
        (rx::VertexArrayMtl::updateClientAttribs):
878
        (rx::VertexArrayMtl::syncDirtyAttrib):
879
        (rx::VertexArrayMtl::getIndexBuffer):
880
        (rx::VertexArrayMtl::convertIndexBuffer):
881
        (rx::VertexArrayMtl::streamIndexBufferFromClient):
882
        (rx::VertexArrayMtl::convertVertexBuffer):
883
        * src/libANGLE/renderer/metal/doc/APPLE_clip_distance.md:
884
        * src/libANGLE/renderer/metal/gen_mtl_format_table.py:
885
        * src/libANGLE/renderer/metal/mtl_buffer_pool.h:
886
        * src/libANGLE/renderer/metal/mtl_buffer_pool.mm:
887
        (rx::mtl::BufferPool::commit):
888
        * src/libANGLE/renderer/metal/mtl_command_buffer.h:
889
        (rx::mtl::IntermediateCommandStream::push):
890
        (rx::mtl::IntermediateCommandStream::peek):
891
        (rx::mtl::IntermediateCommandStream::fetch):
892
        * src/libANGLE/renderer/metal/mtl_command_buffer.mm:
893
        (rx::mtl::CommandBuffer::valid const):
894
        (rx::mtl::CommandBuffer::setWriteDependency):
895
        (rx::mtl::CommandBuffer::setReadDependency):
896
        (rx::mtl::CommandBuffer::insertDebugSign):
897
        (rx::mtl::CommandBuffer::pushDebugGroup):
898
        (rx::mtl::CommandBuffer::popDebugGroup):
899
        (rx::mtl::CommandBuffer::queueEventSignal):
900
        (rx::mtl::CommandBuffer::serverWaitEvent):
901
        (rx::mtl::CommandBuffer::setActiveCommandEncoder):
902
        (rx::mtl::CommandBuffer::validImpl const):
903
        (rx::mtl::CommandBuffer::commitImpl):
904
        (rx::mtl::CommandEncoder::insertDebugSign):
905
        (rx::mtl::CommandEncoder::insertDebugSignImpl):
906
        (rx::mtl::RenderCommandEncoderStates::reset):
907
        (rx::mtl::RenderCommandEncoder::finalizeLoadStoreAction):
908
        (rx::mtl::RenderCommandEncoder::endEncoding):
909
        (rx::mtl::RenderCommandEncoder::endEncodingImpl):
910
        (rx::mtl::RenderCommandEncoder::initWriteDependency):
911
        (rx::mtl::RenderCommandEncoder::simulateDiscardFramebuffer):
912
        (rx::mtl::RenderCommandEncoder::encodeMetalEncoder):
913
        (rx::mtl::RenderCommandEncoder::restart):
914
        (rx::mtl::RenderCommandEncoder::setScissorRect):
915
        (rx::mtl::RenderCommandEncoder::commonSetBuffer):
916
        (rx::mtl::RenderCommandEncoder::draw):
917
        (rx::mtl::RenderCommandEncoder::drawInstanced):
918
        (rx::mtl::RenderCommandEncoder::drawIndexed):
919
        (rx::mtl::RenderCommandEncoder::drawIndexedInstanced):
920
        (rx::mtl::RenderCommandEncoder::drawIndexedInstancedBaseVertex):
921
        (rx::mtl::RenderCommandEncoder::insertDebugSignImpl):
922
        (rx::mtl::BlitCommandEncoder::restart):
923
        (rx::mtl::BlitCommandEncoder::copyTexture):
924
        (rx::mtl::BlitCommandEncoder::synchronizeResource):
925
        (rx::mtl::ComputeCommandEncoder::restart):
926
        * src/libANGLE/renderer/metal/mtl_common.h:
927
        (rx::mtl::GetImpl):
928
        (rx::mtl::ClearColorValue::ClearColorValue):
929
        (rx::mtl::ClearColorValue::getType const):
930
        (rx::mtl::ClearColorValue::getValueBytes const):
931
        * src/libANGLE/renderer/metal/mtl_constants.h: Added.
932
        * src/libANGLE/renderer/metal/mtl_format_map.json:
933
        * src/libANGLE/renderer/metal/mtl_format_table_autogen.mm:
934
        (rx::mtl::Format::init):
935
        * src/libANGLE/renderer/metal/mtl_format_utils.h:
936
        * src/libANGLE/renderer/metal/mtl_format_utils.mm:
937
        (rx::mtl::Format::needConversion const):
938
        (rx::mtl::FormatTable::initialize):
939
        (rx::mtl::FormatTable::setFormatCaps):
940
        (rx::mtl::FormatTable::adjustFormatCapsForDevice):
941
        (rx::mtl::FormatTable::initNativeFormatCaps):
942
        * src/libANGLE/renderer/metal/mtl_glslang_mtl_utils.h: Added.
943
        * src/libANGLE/renderer/metal/mtl_glslang_mtl_utils.mm: Added.
944
        (rx::mtl::TranslatedShaderInfo::reset):
945
        (rx::mtl::MappedSamplerNameNeedsUserDefinedPrefix):
946
        (rx::mtl::MSLGetMappedSamplerName):
947
        (rx::mtl::MSLGetShaderSource):
948
        (rx::mtl::GetAssignedSamplerBindings):
949
        (rx::mtl::getReflectionFromShader):
950
        (rx::mtl::getReflectionFromCompiler):
951
        (rx::mtl::GlslangGetMSL):
952
        (rx::mtl::MslGetShaderShadowCompareMode):
953
        * src/libANGLE/renderer/metal/mtl_glslang_utils.h:
954
        * src/libANGLE/renderer/metal/mtl_glslang_utils.mm:
955
        (rx::mtl::GlslangGetShaderSource):
956
        (rx::mtl::SpirvCodeToMsl):
957
        * src/libANGLE/renderer/metal/mtl_occlusion_query_pool.h:
958
        * src/libANGLE/renderer/metal/mtl_occlusion_query_pool.mm:
959
        (rx::mtl::OcclusionQueryPool::allocateQueryOffset):
960
        (rx::mtl::OcclusionQueryPool::resolveVisibilityResults):
961
        * src/libANGLE/renderer/metal/mtl_render_utils.h:
962
        * src/libANGLE/renderer/metal/mtl_render_utils.mm:
963
        (rx::mtl::StencilBlitViaBufferParams::StencilBlitViaBufferParams):
964
        (rx::mtl::RenderUtils::generateTriFanBufferFromElementsArray):
965
        (rx::mtl::RenderUtils::generatePrimitiveRestartPointsBuffer):
966
        (rx::mtl::RenderUtils::generatePrimitiveRestartLinesBuffer):
967
        (rx::mtl::RenderUtils::generatePrimitiveRestartTrianglesBuffer):
968
        (rx::mtl::RenderUtils::createTransformFeedbackPSO):
969
        (rx::mtl::ClearUtils::clearWithDraw):
970
        (rx::mtl::ColorBlitUtils::blitColorWithDraw):
971
        (rx::mtl::DepthStencilBlitUtils::blitDepthStencilWithDraw):
972
        (rx::mtl::IndexGeneratorUtils::generateTriFanBufferFromElementsArray):
973
        (rx::mtl::IndexGeneratorUtils::generateTriFanBufferFromElementsArrayCPU):
974
        (rx::mtl::IndexGeneratorUtils::generatePrimitiveRestartBuffer):
975
        (rx::mtl::IndexGeneratorUtils::generatePrimitiveRestartTrianglesBuffer):
976
        (rx::mtl::IndexGeneratorUtils::generatePrimitiveRestartLinesBuffer):
977
        (rx::mtl::IndexGeneratorUtils::generatePrimitiveRestartPointsBuffer):
978
        (rx::mtl::MipmapUtils::onDestroy):
979
        (rx::mtl::MipmapUtils::ensure2DMipGeneratorPipelineInitialized):
980
        (rx::mtl::MipmapUtils::ensure2DArrayMipGeneratorPipelineInitialized):
981
        (rx::mtl::MipmapUtils::ensureCubeMipGeneratorPipelineInitialized):
982
        (rx::mtl::MipmapUtils::generateMipmapCS):
983
        (rx::mtl::CopyPixelsUtils::getPixelsCopyPipeline):
984
        (rx::mtl::VertexFormatConversionUtils::getComponentsExpandRenderPipeline):
985
        (rx::mtl::VertexFormatConversionUtils::getFloatConverstionComputePipeline):
986
        (rx::mtl::TransformFeedbackUtils::createMslXfbLibrary):
987
        (rx::mtl::TransformFeedbackUtils::getTransformFeedbackRenderPipeline):
988
        * src/libANGLE/renderer/metal/mtl_resources.h:
989
        * src/libANGLE/renderer/metal/mtl_resources.mm:
990
        (rx::mtl::Texture::MakeMemoryLess2DTexture):
991
        (rx::mtl::Texture::MakeIOSurfaceTexture):
992
        (rx::mtl::Texture::MakeTexture):
993
        (rx::mtl::Texture::Texture):
994
        (rx::mtl::Texture::syncContent):
995
        (rx::mtl::Texture::syncContentIfNeeded):
996
        (rx::mtl::Texture::isShaderReadable const):
997
        (rx::mtl::Texture::createViewWithCompatibleFormat):
998
        (rx::mtl::Texture::getReadableCopy):
999
        (rx::mtl::Texture::releaseReadableCopy):
1000
        (rx::mtl::Buffer::syncContent):
1001
        (rx::mtl::Buffer::mapWithOpt):
1002
        * src/libANGLE/renderer/metal/mtl_state_cache.h:
1003
        (rx::mtl::RenderPassAttachmentTextureTargetDesc::getTextureRef const):
1004
        (rx::mtl::RenderPassAttachmentTextureTargetDesc::getImplicitMSTextureRef const):
1005
        (rx::mtl::RenderPassAttachmentTextureTargetDesc::hasImplicitMSTexture const):
1006
        (rx::mtl::RenderPassAttachmentTextureTargetDesc::getRenderSamples const):
1007
        (rx::mtl::RenderPassAttachmentDesc::texture const):
1008
        (rx::mtl::RenderPassAttachmentDesc::implicitMSTexture const):
1009
        (rx::mtl::RenderPassAttachmentDesc::hasImplicitMSTexture const):
1010
        (rx::mtl::RenderPassAttachmentDesc::renderSamples const):
1011
        (rx::mtl::RenderPassAttachmentDesc::level const):
1012
        (rx::mtl::RenderPassAttachmentDesc::sliceOrDepth const):
1013
        (rx::mtl::RenderPassAttachmentDesc::blendable const):
1014
        * src/libANGLE/renderer/metal/mtl_state_cache.mm:
1015
        (rx::mtl::RenderPassAttachmentDesc::reset):
1016
        (rx::mtl::RenderPassAttachmentDesc::equalIgnoreLoadStoreOptions const):
1017
        (rx::mtl::RenderPassDesc::convertToMetalDesc const):
1018
        (rx::mtl::RenderPassDesc::populateRenderPipelineOutputDesc const):
1019
        (rx::mtl::RenderPipelineCache::RenderPipelineCache):
1020
        (rx::mtl::RenderPipelineCache::setVertexShader):
1021
        (rx::mtl::RenderPipelineCache::setFragmentShader):
1022
        (rx::mtl::RenderPipelineCache::insertRenderPipelineState):
1023
        (rx::mtl::RenderPipelineCache::createRenderPipelineState):
1024
        (rx::mtl::StateCache::StateCache):
1025
        (rx::mtl::StateCache::getSamplerState):
1026
        * src/libANGLE/renderer/metal/mtl_utils.h:
1027
        * src/libANGLE/renderer/metal/mtl_utils.mm:
1028
        (rx::mtl::InitializeTextureContents):
1029
        (rx::mtl::InitializeTextureContentsGPU):
1030
        (rx::mtl::InitializeDepthStencilTextureContentsGPU):
1031
        (rx::mtl::GetHighestSupportedMSLVersion):
1032
        (rx::mtl::CreateShaderLibrary):
1033
        (rx::mtl::GetEmulatedColorWriteMask):
1034
        (rx::mtl::IsFormatEmulated):
1035
        (rx::mtl::GetMaxRenderTargetSizeForDeviceInBytes):
1036
        (rx::mtl::GetMaxNumberOfRenderTargetsForDevice):
1037
        (rx::mtl::DeviceHasMaximumRenderTargetSize):
1038
        (rx::mtl::getNextLocationForFormat):
1039
        (rx::mtl::ComputeTotalSizeUsedForMTLRenderPassDescriptor):
1040
        (rx::mtl::ComputeTotalSizeUsedForMTLRenderPipelineDescriptor):
1041
        * src/libANGLE/renderer/metal/shaders/blit.metal:
1042
        * src/libANGLE/renderer/metal/shaders/common.h:
1043
        * src/libANGLE/renderer/metal/shaders/copy_buffer.metal:
1044
        * src/libANGLE/renderer/metal/shaders/format_autogen.h:
1045
        * src/libANGLE/renderer/metal/shaders/gen_indices.metal:
1046
        * src/libANGLE/renderer/metal/shaders/gen_mipmap.metal:
1047
        * src/libANGLE/renderer/metal/shaders/visibility.metal:
1048
        * src/libGLESv2/entry_points_egl.cpp:
1049
1
2020-12-04  Adam Roben  <aroben@apple.com>
1050
2020-12-04  Adam Roben  <aroben@apple.com>
2
1051
3
        More FALLBACK_PLATFORM adoption
1052
        More FALLBACK_PLATFORM adoption
- a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj +601 lines
Lines 1180-1185 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec1
1180
		A3D3291523CFCB7700375657 /* RewriteRowMajorMatrices.h in Headers */ = {isa = PBXBuildFile; fileRef = A3D3290F23CFCB7600375657 /* RewriteRowMajorMatrices.h */; };
1180
		A3D3291523CFCB7700375657 /* RewriteRowMajorMatrices.h in Headers */ = {isa = PBXBuildFile; fileRef = A3D3290F23CFCB7600375657 /* RewriteRowMajorMatrices.h */; };
1181
		A3D3291823CFCB7700375657 /* RemoveInactiveInterfaceVariables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A3D3291223CFCB7600375657 /* RemoveInactiveInterfaceVariables.cpp */; };
1181
		A3D3291823CFCB7700375657 /* RemoveInactiveInterfaceVariables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A3D3291223CFCB7600375657 /* RemoveInactiveInterfaceVariables.cpp */; };
1182
		A3D3291923CFCB7700375657 /* RemoveInactiveInterfaceVariables.h in Headers */ = {isa = PBXBuildFile; fileRef = A3D3291323CFCB7600375657 /* RemoveInactiveInterfaceVariables.h */; };
1182
		A3D3291923CFCB7700375657 /* RemoveInactiveInterfaceVariables.h in Headers */ = {isa = PBXBuildFile; fileRef = A3D3291323CFCB7600375657 /* RemoveInactiveInterfaceVariables.h */; };
1183
		FF81FED025818D6800894E24 /* mtl_glslang_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FE8025818D6800894E24 /* mtl_glslang_utils.h */; };
1184
		FF81FED125818D6800894E24 /* ProgramMtl.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FE8125818D6800894E24 /* ProgramMtl.h */; };
1185
		FF81FED225818D6800894E24 /* DisplayMtl_api.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FE8225818D6800894E24 /* DisplayMtl_api.h */; };
1186
		FF81FED325818D6800894E24 /* SyncMtl.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FE8325818D6800894E24 /* SyncMtl.mm */; };
1187
		FF81FED425818D6900894E24 /* QueryMtl.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FE8425818D6800894E24 /* QueryMtl.h */; };
1188
		FF81FED525818D6900894E24 /* mtl_format_utils.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FE8525818D6800894E24 /* mtl_format_utils.mm */; };
1189
		FF81FED625818D6900894E24 /* RenderBufferMtl.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FE8625818D6800894E24 /* RenderBufferMtl.mm */; };
1190
		FF81FED725818D6900894E24 /* mtl_common.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FE8825818D6800894E24 /* mtl_common.h */; };
1191
		FF81FED825818D6900894E24 /* mtl_constants.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FE8925818D6800894E24 /* mtl_constants.h */; };
1192
		FF81FED925818D6900894E24 /* SamplerMtl.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FE8A25818D6800894E24 /* SamplerMtl.h */; };
1193
		FF81FEDA25818D6900894E24 /* DisplayMtl.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FE8B25818D6800894E24 /* DisplayMtl.h */; };
1194
		FF81FEDB25818D6900894E24 /* SyncMtl.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FE8C25818D6800894E24 /* SyncMtl.h */; };
1195
		FF81FEDC25818D6900894E24 /* QueryMtl.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FE8D25818D6800894E24 /* QueryMtl.mm */; };
1196
		FF81FEDD25818D6900894E24 /* mtl_format_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FE8E25818D6800894E24 /* mtl_format_utils.h */; };
1197
		FF81FEDE25818D6900894E24 /* RenderBufferMtl.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FE8F25818D6800894E24 /* RenderBufferMtl.h */; };
1198
		FF81FEDF25818D6900894E24 /* TransformFeedbackMtl.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FE9025818D6800894E24 /* TransformFeedbackMtl.h */; };
1199
		FF81FEE025818D6900894E24 /* BufferMtl.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FE9125818D6800894E24 /* BufferMtl.mm */; };
1200
		FF81FEE125818D6900894E24 /* mtl_format_table_autogen.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FE9225818D6800894E24 /* mtl_format_table_autogen.mm */; };
1201
		FF81FEE225818D6900894E24 /* RenderTargetMtl.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FE9325818D6800894E24 /* RenderTargetMtl.h */; };
1202
		FF81FEE325818D6900894E24 /* SurfaceMtl.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FE9425818D6800894E24 /* SurfaceMtl.mm */; };
1203
		FF81FEE425818D6900894E24 /* mtl_glslang_mtl_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FE9525818D6800894E24 /* mtl_glslang_mtl_utils.h */; };
1204
		FF81FEE525818D6900894E24 /* mtl_command_buffer.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FE9625818D6800894E24 /* mtl_command_buffer.mm */; };
1205
		FF81FEE625818D6900894E24 /* VertexArrayMtl.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FE9725818D6800894E24 /* VertexArrayMtl.h */; };
1206
		FF81FEE725818D6900894E24 /* SurfaceMtl.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FE9825818D6800894E24 /* SurfaceMtl.h */; };
1207
		FF81FEE825818D6900894E24 /* RenderTargetMtl.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FE9925818D6800894E24 /* RenderTargetMtl.mm */; };
1208
		FF81FEE925818D6900894E24 /* VertexArrayMtl.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FE9A25818D6800894E24 /* VertexArrayMtl.mm */; };
1209
		FF81FEEA25818D6900894E24 /* mtl_command_buffer.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FE9B25818D6800894E24 /* mtl_command_buffer.h */; };
1210
		FF81FEEB25818D6900894E24 /* BufferMtl.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FE9C25818D6800894E24 /* BufferMtl.h */; };
1211
		FF81FEEC25818D6900894E24 /* mtl_utils.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FE9D25818D6800894E24 /* mtl_utils.mm */; };
1212
		FF81FEED25818D6900894E24 /* IOSurfaceSurfaceMtl.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FE9E25818D6800894E24 /* IOSurfaceSurfaceMtl.mm */; };
1213
		FF81FEEE25818D6900894E24 /* mtl_resources.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FE9F25818D6800894E24 /* mtl_resources.mm */; };
1214
		FF81FEEF25818D6900894E24 /* mtl_resources.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FEA025818D6800894E24 /* mtl_resources.h */; };
1215
		FF81FEF025818D6900894E24 /* mtl_state_cache.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FEA125818D6800894E24 /* mtl_state_cache.mm */; };
1216
		FF81FEF225818D6900894E24 /* mtl_render_utils.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FEA325818D6800894E24 /* mtl_render_utils.mm */; };
1217
		FF81FEF325818D6900894E24 /* TransformFeedbackMtl.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FEA425818D6800894E24 /* TransformFeedbackMtl.mm */; };
1218
		FF81FEF425818D6900894E24 /* IOSurfaceSurfaceMtl.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FEA525818D6800894E24 /* IOSurfaceSurfaceMtl.h */; };
1219
		FF81FEF525818D6900894E24 /* TextureMtl.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FEA625818D6800894E24 /* TextureMtl.mm */; };
1220
		FF81FEF625818D6900894E24 /* TextureMtl.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FEA725818D6800894E24 /* TextureMtl.h */; };
1221
		FF81FEF725818D6900894E24 /* SamplerMtl.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FEA825818D6800894E24 /* SamplerMtl.mm */; };
1222
		FF81FEFA25818D6900894E24 /* constants.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FEAC25818D6800894E24 /* constants.h */; };
1223
		FF81FEFB25818D6900894E24 /* common.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FEAD25818D6800894E24 /* common.h */; };
1224
		FF81FEFE25818D6900894E24 /* format_autogen.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FEB025818D6800894E24 /* format_autogen.h */; };
1225
		FF81FF0225818D6900894E24 /* mtl_occlusion_query_pool.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FEBB25818D6800894E24 /* mtl_occlusion_query_pool.mm */; };
1226
		FF81FF0325818D6900894E24 /* FrameBufferMtl.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FEBC25818D6800894E24 /* FrameBufferMtl.h */; };
1227
		FF81FF0425818D6900894E24 /* CompilerMtl.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FEBD25818D6800894E24 /* CompilerMtl.h */; };
1228
		FF81FF0525818D6900894E24 /* mtl_glslang_mtl_utils.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FEBE25818D6800894E24 /* mtl_glslang_mtl_utils.mm */; };
1229
		FF81FF0625818D6900894E24 /* ContextMtl.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FEBF25818D6800894E24 /* ContextMtl.mm */; };
1230
		FF81FF0725818D6900894E24 /* CompilerMtl.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FEC025818D6800894E24 /* CompilerMtl.mm */; };
1231
		FF81FF0825818D6900894E24 /* mtl_buffer_pool.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FEC125818D6800894E24 /* mtl_buffer_pool.h */; };
1232
		FF81FF0925818D6900894E24 /* mtl_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FEC225818D6800894E24 /* mtl_utils.h */; };
1233
		FF81FF0A25818D6900894E24 /* ContextMtl.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FEC425818D6800894E24 /* ContextMtl.h */; };
1234
		FF81FF0B25818D6900894E24 /* mtl_buffer_pool.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FEC525818D6800894E24 /* mtl_buffer_pool.mm */; };
1235
		FF81FF0C25818D6A00894E24 /* mtl_common.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FEC625818D6800894E24 /* mtl_common.mm */; };
1236
		FF81FF0D25818D6A00894E24 /* mtl_render_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FEC725818D6800894E24 /* mtl_render_utils.h */; };
1237
		FF81FF0E25818D6A00894E24 /* mtl_state_cache.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FEC825818D6800894E24 /* mtl_state_cache.h */; };
1238
		FF81FF0F25818D6A00894E24 /* FrameBufferMtl.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FEC925818D6800894E24 /* FrameBufferMtl.mm */; };
1239
		FF81FF1025818D6A00894E24 /* mtl_occlusion_query_pool.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FECA25818D6800894E24 /* mtl_occlusion_query_pool.h */; };
1240
		FF81FF1125818D6A00894E24 /* ShaderMtl.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FECB25818D6800894E24 /* ShaderMtl.h */; };
1241
		FF81FF1225818D6A00894E24 /* ShaderMtl.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FECC25818D6800894E24 /* ShaderMtl.mm */; };
1242
		FF81FF1325818D6A00894E24 /* ProgramMtl.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FECD25818D6800894E24 /* ProgramMtl.mm */; };
1243
		FF81FF1425818D6A00894E24 /* DisplayMtl.mm in Sources */ = {isa = PBXBuildFile; fileRef = FF81FECE25818D6800894E24 /* DisplayMtl.mm */; };
1244
		FF81FF1B258190CA00894E24 /* TranslatorMetalDirect.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF15258190CA00894E24 /* TranslatorMetalDirect.h */; };
1245
		FF81FF1C258190CA00894E24 /* TranslatorMetalDirect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF16258190CA00894E24 /* TranslatorMetalDirect.cpp */; };
1246
		FF81FF1D258190CA00894E24 /* StaticType.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF17258190CA00894E24 /* StaticType.h */; };
1247
		FF81FF1E258190CA00894E24 /* TranslatorMetalUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF19258190CA00894E24 /* TranslatorMetalUtils.cpp */; };
1248
		FF81FF1F258190CA00894E24 /* TranslatorMetalUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF1A258190CA00894E24 /* TranslatorMetalUtils.h */; };
1249
		FF81FF5B2581919700894E24 /* Name.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF212581919700894E24 /* Name.cpp */; };
1250
		FF81FF5C2581919700894E24 /* DiscoverDependentFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF222581919700894E24 /* DiscoverDependentFunctions.h */; };
1251
		FF81FF5D2581919700894E24 /* Debug.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF232581919700894E24 /* Debug.h */; };
1252
		FF81FF5E2581919700894E24 /* Name.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF242581919700894E24 /* Name.h */; };
1253
		FF81FF5F2581919700894E24 /* SeparateCompoundStructDeclarations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF252581919700894E24 /* SeparateCompoundStructDeclarations.cpp */; };
1254
		FF81FF602581919700894E24 /* ModifyStruct.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF262581919700894E24 /* ModifyStruct.cpp */; };
1255
		FF81FF612581919700894E24 /* ReduceInterfaceBlocks.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF272581919700894E24 /* ReduceInterfaceBlocks.h */; };
1256
		FF81FF622581919700894E24 /* EnvironmentVariable.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF282581919700894E24 /* EnvironmentVariable.h */; };
1257
		FF81FF632581919700894E24 /* DiscoverDependentFunctions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF292581919700894E24 /* DiscoverDependentFunctions.cpp */; };
1258
		FF81FF642581919700894E24 /* DiscoverEnclosingFunctionTraverser.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF2A2581919700894E24 /* DiscoverEnclosingFunctionTraverser.h */; };
1259
		FF81FF652581919700894E24 /* DebugSink.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF2B2581919700894E24 /* DebugSink.h */; };
1260
		FF81FF662581919700894E24 /* SeparateCompoundStructDeclarations.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF2C2581919700894E24 /* SeparateCompoundStructDeclarations.h */; };
1261
		FF81FF672581919700894E24 /* EmitMetal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF2D2581919700894E24 /* EmitMetal.cpp */; };
1262
		FF81FF682581919800894E24 /* RewriteOutArgs.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF2E2581919700894E24 /* RewriteOutArgs.h */; };
1263
		FF81FF692581919800894E24 /* MapSymbols.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF2F2581919700894E24 /* MapSymbols.cpp */; };
1264
		FF81FF6A2581919800894E24 /* SymbolEnv.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF302581919700894E24 /* SymbolEnv.cpp */; };
1265
		FF81FF6B2581919800894E24 /* RewriteKeywords.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF312581919700894E24 /* RewriteKeywords.h */; };
1266
		FF81FF6C2581919800894E24 /* Layout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF322581919700894E24 /* Layout.cpp */; };
1267
		FF81FF6D2581919800894E24 /* ToposortStructs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF332581919700894E24 /* ToposortStructs.cpp */; };
1268
		FF81FF6E2581919800894E24 /* MapFunctionsToDefinitions.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF342581919700894E24 /* MapFunctionsToDefinitions.h */; };
1269
		FF81FF6F2581919800894E24 /* SkippingTraverser.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF352581919700894E24 /* SkippingTraverser.h */; };
1270
		FF81FF702581919800894E24 /* RewriteOutArgs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF362581919700894E24 /* RewriteOutArgs.cpp */; };
1271
		FF81FF712581919800894E24 /* Pipeline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF372581919700894E24 /* Pipeline.cpp */; };
1272
		FF81FF722581919800894E24 /* IdGen.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF382581919700894E24 /* IdGen.h */; };
1273
		FF81FF732581919800894E24 /* SeparateCompoundExpressions.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF392581919700894E24 /* SeparateCompoundExpressions.h */; };
1274
		FF81FF742581919800894E24 /* AddExplicitTypeCasts.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF3A2581919700894E24 /* AddExplicitTypeCasts.cpp */; };
1275
		FF81FF752581919800894E24 /* MapSymbols.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF3B2581919700894E24 /* MapSymbols.h */; };
1276
		FF81FF762581919800894E24 /* RewritePipelines.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF3C2581919700894E24 /* RewritePipelines.cpp */; };
1277
		FF81FF772581919800894E24 /* ReduceInterfaceBlocks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF3D2581919700894E24 /* ReduceInterfaceBlocks.cpp */; };
1278
		FF81FF782581919800894E24 /* AstHelpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF3E2581919700894E24 /* AstHelpers.cpp */; };
1279
		FF81FF792581919800894E24 /* RewriteUnaddressableReferences.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF3F2581919700894E24 /* RewriteUnaddressableReferences.h */; };
1280
		FF81FF7A2581919800894E24 /* Layout.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF402581919700894E24 /* Layout.h */; };
1281
		FF81FF7B2581919800894E24 /* DiscoverEnclosingFunctionTraverser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF412581919700894E24 /* DiscoverEnclosingFunctionTraverser.cpp */; };
1282
		FF81FF7C2581919800894E24 /* ProgramPrelude.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF422581919700894E24 /* ProgramPrelude.h */; };
1283
		FF81FF7D2581919800894E24 /* RewriteGlobalQualifierDecls.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF432581919700894E24 /* RewriteGlobalQualifierDecls.h */; };
1284
		FF81FF7E2581919800894E24 /* SymbolEnv.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF442581919700894E24 /* SymbolEnv.h */; };
1285
		FF81FF7F2581919800894E24 /* RewriteGlobalQualifierDecls.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF452581919700894E24 /* RewriteGlobalQualifierDecls.cpp */; };
1286
		FF81FF802581919800894E24 /* RewriteUnaddressableReferences.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF462581919700894E24 /* RewriteUnaddressableReferences.cpp */; };
1287
		FF81FF812581919800894E24 /* AstHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF472581919700894E24 /* AstHelpers.h */; };
1288
		FF81FF822581919800894E24 /* HoistConstants.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF482581919700894E24 /* HoistConstants.cpp */; };
1289
		FF81FF832581919800894E24 /* Pipeline.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF492581919700894E24 /* Pipeline.h */; };
1290
		FF81FF842581919800894E24 /* RewritePipelines.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF4A2581919700894E24 /* RewritePipelines.h */; };
1291
		FF81FF852581919800894E24 /* Reference.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF4B2581919700894E24 /* Reference.h */; };
1292
		FF81FF862581919800894E24 /* HoistConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF4C2581919700894E24 /* HoistConstants.h */; };
1293
		FF81FF872581919800894E24 /* WrapMain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF4D2581919700894E24 /* WrapMain.cpp */; };
1294
		FF81FF882581919800894E24 /* ConstantNames.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF4E2581919700894E24 /* ConstantNames.h */; };
1295
		FF81FF892581919800894E24 /* RewriteKeywords.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF4F2581919700894E24 /* RewriteKeywords.cpp */; };
1296
		FF81FF8A2581919800894E24 /* ProgramPrelude.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF502581919700894E24 /* ProgramPrelude.cpp */; };
1297
		FF81FF8B2581919800894E24 /* IdGen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF512581919700894E24 /* IdGen.cpp */; };
1298
		FF81FF8C2581919800894E24 /* EmitMetal.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF522581919700894E24 /* EmitMetal.h */; };
1299
		FF81FF8D2581919800894E24 /* WrapMain.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF532581919700894E24 /* WrapMain.h */; };
1300
		FF81FF8E2581919800894E24 /* AddExplicitTypeCasts.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF542581919700894E24 /* AddExplicitTypeCasts.h */; };
1301
		FF81FF8F2581919800894E24 /* SeparateCompoundExpressions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF552581919700894E24 /* SeparateCompoundExpressions.cpp */; };
1302
		FF81FF902581919800894E24 /* ModifyStruct.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF562581919700894E24 /* ModifyStruct.h */; };
1303
		FF81FF912581919800894E24 /* ToposortStructs.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF572581919700894E24 /* ToposortStructs.h */; };
1304
		FF81FF922581919800894E24 /* RewriteCaseDeclarations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF582581919700894E24 /* RewriteCaseDeclarations.cpp */; };
1305
		FF81FF932581919800894E24 /* RewriteCaseDeclarations.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF592581919700894E24 /* RewriteCaseDeclarations.h */; };
1306
		FF81FF942581919800894E24 /* MapFunctionsToDefinitions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF5A2581919700894E24 /* MapFunctionsToDefinitions.cpp */; };
1307
		FF81FF962581A39700894E24 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF81FF952581A39700894E24 /* Metal.framework */; };
1308
		FF81FF9B2581A3C200894E24 /* NodeType.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF972581A3C100894E24 /* NodeType.h */; };
1309
		FF81FF9C2581A3C200894E24 /* AsNode.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF982581A3C100894E24 /* AsNode.h */; };
1310
		FF81FF9D2581A3C200894E24 /* IntermRebuild.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF81FF992581A3C100894E24 /* IntermRebuild.cpp */; };
1311
		FF81FF9E2581A3C200894E24 /* IntermRebuild.h in Headers */ = {isa = PBXBuildFile; fileRef = FF81FF9A2581A3C200894E24 /* IntermRebuild.h */; };
1312
		FF81FF9F2581AD0400894E24 /* blit.metal in Sources */ = {isa = PBXBuildFile; fileRef = FF81FEAA25818D6800894E24 /* blit.metal */; };
1313
		FF81FFA02581AD0400894E24 /* visibility.metal in Sources */ = {isa = PBXBuildFile; fileRef = FF81FEAB25818D6800894E24 /* visibility.metal */; };
1314
		FF81FFA12581AD0400894E24 /* copy_buffer.metal in Sources */ = {isa = PBXBuildFile; fileRef = FF81FEAF25818D6800894E24 /* copy_buffer.metal */; };
1315
		FF81FFA22581AD0400894E24 /* clear.metal in Sources */ = {isa = PBXBuildFile; fileRef = FF81FEB125818D6800894E24 /* clear.metal */; };
1316
		FF81FFA32581AD0400894E24 /* gen_mipmap.metal in Sources */ = {isa = PBXBuildFile; fileRef = FF81FEB225818D6800894E24 /* gen_mipmap.metal */; };
1317
		FF81FFA42581AD0400894E24 /* gen_indices.metal in Sources */ = {isa = PBXBuildFile; fileRef = FF81FEB325818D6800894E24 /* gen_indices.metal */; };
1183
/* End PBXBuildFile section */
1318
/* End PBXBuildFile section */
1184
1319
1185
/* Begin PBXBuildRule section */
1320
/* Begin PBXBuildRule section */
Lines 2030-2035 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec2
2030
		A3D3291323CFCB7600375657 /* RemoveInactiveInterfaceVariables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemoveInactiveInterfaceVariables.h; sourceTree = "<group>"; };
2165
		A3D3291323CFCB7600375657 /* RemoveInactiveInterfaceVariables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemoveInactiveInterfaceVariables.h; sourceTree = "<group>"; };
2031
		FB39D0D11200F0E300088E69 /* libANGLE.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libANGLE.a; sourceTree = BUILT_PRODUCTS_DIR; };
2166
		FB39D0D11200F0E300088E69 /* libANGLE.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libANGLE.a; sourceTree = BUILT_PRODUCTS_DIR; };
2032
		FB39D2BF1200F3E600088E69 /* ShaderLang.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = ShaderLang.h; sourceTree = "<group>"; };
2167
		FB39D2BF1200F3E600088E69 /* ShaderLang.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = ShaderLang.h; sourceTree = "<group>"; };
2168
		FF81FE8025818D6800894E24 /* mtl_glslang_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mtl_glslang_utils.h; sourceTree = "<group>"; };
2169
		FF81FE8125818D6800894E24 /* ProgramMtl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProgramMtl.h; sourceTree = "<group>"; };
2170
		FF81FE8225818D6800894E24 /* DisplayMtl_api.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DisplayMtl_api.h; sourceTree = "<group>"; };
2171
		FF81FE8325818D6800894E24 /* SyncMtl.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SyncMtl.mm; sourceTree = "<group>"; };
2172
		FF81FE8425818D6800894E24 /* QueryMtl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QueryMtl.h; sourceTree = "<group>"; };
2173
		FF81FE8525818D6800894E24 /* mtl_format_utils.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = mtl_format_utils.mm; sourceTree = "<group>"; };
2174
		FF81FE8625818D6800894E24 /* RenderBufferMtl.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RenderBufferMtl.mm; sourceTree = "<group>"; };
2175
		FF81FE8825818D6800894E24 /* mtl_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mtl_common.h; sourceTree = "<group>"; };
2176
		FF81FE8925818D6800894E24 /* mtl_constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mtl_constants.h; sourceTree = "<group>"; };
2177
		FF81FE8A25818D6800894E24 /* SamplerMtl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SamplerMtl.h; sourceTree = "<group>"; };
2178
		FF81FE8B25818D6800894E24 /* DisplayMtl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DisplayMtl.h; sourceTree = "<group>"; };
2179
		FF81FE8C25818D6800894E24 /* SyncMtl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SyncMtl.h; sourceTree = "<group>"; };
2180
		FF81FE8D25818D6800894E24 /* QueryMtl.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = QueryMtl.mm; sourceTree = "<group>"; };
2181
		FF81FE8E25818D6800894E24 /* mtl_format_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mtl_format_utils.h; sourceTree = "<group>"; };
2182
		FF81FE8F25818D6800894E24 /* RenderBufferMtl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderBufferMtl.h; sourceTree = "<group>"; };
2183
		FF81FE9025818D6800894E24 /* TransformFeedbackMtl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TransformFeedbackMtl.h; sourceTree = "<group>"; };
2184
		FF81FE9125818D6800894E24 /* BufferMtl.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = BufferMtl.mm; sourceTree = "<group>"; };
2185
		FF81FE9225818D6800894E24 /* mtl_format_table_autogen.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = mtl_format_table_autogen.mm; sourceTree = "<group>"; };
2186
		FF81FE9325818D6800894E24 /* RenderTargetMtl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderTargetMtl.h; sourceTree = "<group>"; };
2187
		FF81FE9425818D6800894E24 /* SurfaceMtl.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SurfaceMtl.mm; sourceTree = "<group>"; };
2188
		FF81FE9525818D6800894E24 /* mtl_glslang_mtl_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mtl_glslang_mtl_utils.h; sourceTree = "<group>"; };
2189
		FF81FE9625818D6800894E24 /* mtl_command_buffer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = mtl_command_buffer.mm; sourceTree = "<group>"; };
2190
		FF81FE9725818D6800894E24 /* VertexArrayMtl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VertexArrayMtl.h; sourceTree = "<group>"; };
2191
		FF81FE9825818D6800894E24 /* SurfaceMtl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SurfaceMtl.h; sourceTree = "<group>"; };
2192
		FF81FE9925818D6800894E24 /* RenderTargetMtl.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RenderTargetMtl.mm; sourceTree = "<group>"; };
2193
		FF81FE9A25818D6800894E24 /* VertexArrayMtl.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = VertexArrayMtl.mm; sourceTree = "<group>"; };
2194
		FF81FE9B25818D6800894E24 /* mtl_command_buffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mtl_command_buffer.h; sourceTree = "<group>"; };
2195
		FF81FE9C25818D6800894E24 /* BufferMtl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BufferMtl.h; sourceTree = "<group>"; };
2196
		FF81FE9D25818D6800894E24 /* mtl_utils.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = mtl_utils.mm; sourceTree = "<group>"; };
2197
		FF81FE9E25818D6800894E24 /* IOSurfaceSurfaceMtl.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = IOSurfaceSurfaceMtl.mm; sourceTree = "<group>"; };
2198
		FF81FE9F25818D6800894E24 /* mtl_resources.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = mtl_resources.mm; sourceTree = "<group>"; };
2199
		FF81FEA025818D6800894E24 /* mtl_resources.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mtl_resources.h; sourceTree = "<group>"; };
2200
		FF81FEA125818D6800894E24 /* mtl_state_cache.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = mtl_state_cache.mm; sourceTree = "<group>"; };
2201
		FF81FEA325818D6800894E24 /* mtl_render_utils.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = mtl_render_utils.mm; sourceTree = "<group>"; };
2202
		FF81FEA425818D6800894E24 /* TransformFeedbackMtl.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TransformFeedbackMtl.mm; sourceTree = "<group>"; };
2203
		FF81FEA525818D6800894E24 /* IOSurfaceSurfaceMtl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IOSurfaceSurfaceMtl.h; sourceTree = "<group>"; };
2204
		FF81FEA625818D6800894E24 /* TextureMtl.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TextureMtl.mm; sourceTree = "<group>"; };
2205
		FF81FEA725818D6800894E24 /* TextureMtl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextureMtl.h; sourceTree = "<group>"; };
2206
		FF81FEA825818D6800894E24 /* SamplerMtl.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SamplerMtl.mm; sourceTree = "<group>"; };
2207
		FF81FEAA25818D6800894E24 /* blit.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = blit.metal; sourceTree = "<group>"; };
2208
		FF81FEAB25818D6800894E24 /* visibility.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = visibility.metal; sourceTree = "<group>"; };
2209
		FF81FEAC25818D6800894E24 /* constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = constants.h; sourceTree = "<group>"; };
2210
		FF81FEAD25818D6800894E24 /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = "<group>"; };
2211
		FF81FEAE25818D6800894E24 /* mtl_default_shaders_src_autogen.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = mtl_default_shaders_src_autogen.inc; sourceTree = "<group>"; };
2212
		FF81FEAF25818D6800894E24 /* copy_buffer.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = copy_buffer.metal; sourceTree = "<group>"; };
2213
		FF81FEB025818D6800894E24 /* format_autogen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = format_autogen.h; sourceTree = "<group>"; };
2214
		FF81FEB125818D6800894E24 /* clear.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = clear.metal; sourceTree = "<group>"; };
2215
		FF81FEB225818D6800894E24 /* gen_mipmap.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = gen_mipmap.metal; sourceTree = "<group>"; };
2216
		FF81FEB325818D6800894E24 /* gen_indices.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = gen_indices.metal; sourceTree = "<group>"; };
2217
		FF81FEBB25818D6800894E24 /* mtl_occlusion_query_pool.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = mtl_occlusion_query_pool.mm; sourceTree = "<group>"; };
2218
		FF81FEBC25818D6800894E24 /* FrameBufferMtl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FrameBufferMtl.h; sourceTree = "<group>"; };
2219
		FF81FEBD25818D6800894E24 /* CompilerMtl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CompilerMtl.h; sourceTree = "<group>"; };
2220
		FF81FEBE25818D6800894E24 /* mtl_glslang_mtl_utils.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = mtl_glslang_mtl_utils.mm; sourceTree = "<group>"; };
2221
		FF81FEBF25818D6800894E24 /* ContextMtl.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ContextMtl.mm; sourceTree = "<group>"; };
2222
		FF81FEC025818D6800894E24 /* CompilerMtl.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CompilerMtl.mm; sourceTree = "<group>"; };
2223
		FF81FEC125818D6800894E24 /* mtl_buffer_pool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mtl_buffer_pool.h; sourceTree = "<group>"; };
2224
		FF81FEC225818D6800894E24 /* mtl_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mtl_utils.h; sourceTree = "<group>"; };
2225
		FF81FEC425818D6800894E24 /* ContextMtl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContextMtl.h; sourceTree = "<group>"; };
2226
		FF81FEC525818D6800894E24 /* mtl_buffer_pool.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = mtl_buffer_pool.mm; sourceTree = "<group>"; };
2227
		FF81FEC625818D6800894E24 /* mtl_common.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = mtl_common.mm; sourceTree = "<group>"; };
2228
		FF81FEC725818D6800894E24 /* mtl_render_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mtl_render_utils.h; sourceTree = "<group>"; };
2229
		FF81FEC825818D6800894E24 /* mtl_state_cache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mtl_state_cache.h; sourceTree = "<group>"; };
2230
		FF81FEC925818D6800894E24 /* FrameBufferMtl.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FrameBufferMtl.mm; sourceTree = "<group>"; };
2231
		FF81FECA25818D6800894E24 /* mtl_occlusion_query_pool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mtl_occlusion_query_pool.h; sourceTree = "<group>"; };
2232
		FF81FECB25818D6800894E24 /* ShaderMtl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShaderMtl.h; sourceTree = "<group>"; };
2233
		FF81FECC25818D6800894E24 /* ShaderMtl.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ShaderMtl.mm; sourceTree = "<group>"; };
2234
		FF81FECD25818D6800894E24 /* ProgramMtl.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ProgramMtl.mm; sourceTree = "<group>"; };
2235
		FF81FECE25818D6800894E24 /* DisplayMtl.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DisplayMtl.mm; sourceTree = "<group>"; };
2236
		FF81FF15258190CA00894E24 /* TranslatorMetalDirect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TranslatorMetalDirect.h; sourceTree = "<group>"; };
2237
		FF81FF16258190CA00894E24 /* TranslatorMetalDirect.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TranslatorMetalDirect.cpp; sourceTree = "<group>"; };
2238
		FF81FF17258190CA00894E24 /* StaticType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaticType.h; sourceTree = "<group>"; };
2239
		FF81FF18258190CA00894E24 /* TranslatorMetalDirect */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = TranslatorMetalDirect; sourceTree = "<group>"; };
2240
		FF81FF19258190CA00894E24 /* TranslatorMetalUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TranslatorMetalUtils.cpp; sourceTree = "<group>"; };
2241
		FF81FF1A258190CA00894E24 /* TranslatorMetalUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TranslatorMetalUtils.h; sourceTree = "<group>"; };
2242
		FF81FF212581919700894E24 /* Name.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Name.cpp; sourceTree = "<group>"; };
2243
		FF81FF222581919700894E24 /* DiscoverDependentFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DiscoverDependentFunctions.h; sourceTree = "<group>"; };
2244
		FF81FF232581919700894E24 /* Debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Debug.h; sourceTree = "<group>"; };
2245
		FF81FF242581919700894E24 /* Name.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Name.h; sourceTree = "<group>"; };
2246
		FF81FF252581919700894E24 /* SeparateCompoundStructDeclarations.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SeparateCompoundStructDeclarations.cpp; sourceTree = "<group>"; };
2247
		FF81FF262581919700894E24 /* ModifyStruct.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ModifyStruct.cpp; sourceTree = "<group>"; };
2248
		FF81FF272581919700894E24 /* ReduceInterfaceBlocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReduceInterfaceBlocks.h; sourceTree = "<group>"; };
2249
		FF81FF282581919700894E24 /* EnvironmentVariable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EnvironmentVariable.h; sourceTree = "<group>"; };
2250
		FF81FF292581919700894E24 /* DiscoverDependentFunctions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DiscoverDependentFunctions.cpp; sourceTree = "<group>"; };
2251
		FF81FF2A2581919700894E24 /* DiscoverEnclosingFunctionTraverser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DiscoverEnclosingFunctionTraverser.h; sourceTree = "<group>"; };
2252
		FF81FF2B2581919700894E24 /* DebugSink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugSink.h; sourceTree = "<group>"; };
2253
		FF81FF2C2581919700894E24 /* SeparateCompoundStructDeclarations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SeparateCompoundStructDeclarations.h; sourceTree = "<group>"; };
2254
		FF81FF2D2581919700894E24 /* EmitMetal.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EmitMetal.cpp; sourceTree = "<group>"; };
2255
		FF81FF2E2581919700894E24 /* RewriteOutArgs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RewriteOutArgs.h; sourceTree = "<group>"; };
2256
		FF81FF2F2581919700894E24 /* MapSymbols.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MapSymbols.cpp; sourceTree = "<group>"; };
2257
		FF81FF302581919700894E24 /* SymbolEnv.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SymbolEnv.cpp; sourceTree = "<group>"; };
2258
		FF81FF312581919700894E24 /* RewriteKeywords.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RewriteKeywords.h; sourceTree = "<group>"; };
2259
		FF81FF322581919700894E24 /* Layout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Layout.cpp; sourceTree = "<group>"; };
2260
		FF81FF332581919700894E24 /* ToposortStructs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ToposortStructs.cpp; sourceTree = "<group>"; };
2261
		FF81FF342581919700894E24 /* MapFunctionsToDefinitions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MapFunctionsToDefinitions.h; sourceTree = "<group>"; };
2262
		FF81FF352581919700894E24 /* SkippingTraverser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SkippingTraverser.h; sourceTree = "<group>"; };
2263
		FF81FF362581919700894E24 /* RewriteOutArgs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RewriteOutArgs.cpp; sourceTree = "<group>"; };
2264
		FF81FF372581919700894E24 /* Pipeline.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Pipeline.cpp; sourceTree = "<group>"; };
2265
		FF81FF382581919700894E24 /* IdGen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IdGen.h; sourceTree = "<group>"; };
2266
		FF81FF392581919700894E24 /* SeparateCompoundExpressions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SeparateCompoundExpressions.h; sourceTree = "<group>"; };
2267
		FF81FF3A2581919700894E24 /* AddExplicitTypeCasts.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AddExplicitTypeCasts.cpp; sourceTree = "<group>"; };
2268
		FF81FF3B2581919700894E24 /* MapSymbols.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MapSymbols.h; sourceTree = "<group>"; };
2269
		FF81FF3C2581919700894E24 /* RewritePipelines.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RewritePipelines.cpp; sourceTree = "<group>"; };
2270
		FF81FF3D2581919700894E24 /* ReduceInterfaceBlocks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ReduceInterfaceBlocks.cpp; sourceTree = "<group>"; };
2271
		FF81FF3E2581919700894E24 /* AstHelpers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AstHelpers.cpp; sourceTree = "<group>"; };
2272
		FF81FF3F2581919700894E24 /* RewriteUnaddressableReferences.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RewriteUnaddressableReferences.h; sourceTree = "<group>"; };
2273
		FF81FF402581919700894E24 /* Layout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Layout.h; sourceTree = "<group>"; };
2274
		FF81FF412581919700894E24 /* DiscoverEnclosingFunctionTraverser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DiscoverEnclosingFunctionTraverser.cpp; sourceTree = "<group>"; };
2275
		FF81FF422581919700894E24 /* ProgramPrelude.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProgramPrelude.h; sourceTree = "<group>"; };
2276
		FF81FF432581919700894E24 /* RewriteGlobalQualifierDecls.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RewriteGlobalQualifierDecls.h; sourceTree = "<group>"; };
2277
		FF81FF442581919700894E24 /* SymbolEnv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SymbolEnv.h; sourceTree = "<group>"; };
2278
		FF81FF452581919700894E24 /* RewriteGlobalQualifierDecls.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RewriteGlobalQualifierDecls.cpp; sourceTree = "<group>"; };
2279
		FF81FF462581919700894E24 /* RewriteUnaddressableReferences.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RewriteUnaddressableReferences.cpp; sourceTree = "<group>"; };
2280
		FF81FF472581919700894E24 /* AstHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AstHelpers.h; sourceTree = "<group>"; };
2281
		FF81FF482581919700894E24 /* HoistConstants.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HoistConstants.cpp; sourceTree = "<group>"; };
2282
		FF81FF492581919700894E24 /* Pipeline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Pipeline.h; sourceTree = "<group>"; };
2283
		FF81FF4A2581919700894E24 /* RewritePipelines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RewritePipelines.h; sourceTree = "<group>"; };
2284
		FF81FF4B2581919700894E24 /* Reference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reference.h; sourceTree = "<group>"; };
2285
		FF81FF4C2581919700894E24 /* HoistConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HoistConstants.h; sourceTree = "<group>"; };
2286
		FF81FF4D2581919700894E24 /* WrapMain.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WrapMain.cpp; sourceTree = "<group>"; };
2287
		FF81FF4E2581919700894E24 /* ConstantNames.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConstantNames.h; sourceTree = "<group>"; };
2288
		FF81FF4F2581919700894E24 /* RewriteKeywords.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RewriteKeywords.cpp; sourceTree = "<group>"; };
2289
		FF81FF502581919700894E24 /* ProgramPrelude.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProgramPrelude.cpp; sourceTree = "<group>"; };
2290
		FF81FF512581919700894E24 /* IdGen.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IdGen.cpp; sourceTree = "<group>"; };
2291
		FF81FF522581919700894E24 /* EmitMetal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EmitMetal.h; sourceTree = "<group>"; };
2292
		FF81FF532581919700894E24 /* WrapMain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WrapMain.h; sourceTree = "<group>"; };
2293
		FF81FF542581919700894E24 /* AddExplicitTypeCasts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AddExplicitTypeCasts.h; sourceTree = "<group>"; };
2294
		FF81FF552581919700894E24 /* SeparateCompoundExpressions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SeparateCompoundExpressions.cpp; sourceTree = "<group>"; };
2295
		FF81FF562581919700894E24 /* ModifyStruct.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModifyStruct.h; sourceTree = "<group>"; };
2296
		FF81FF572581919700894E24 /* ToposortStructs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ToposortStructs.h; sourceTree = "<group>"; };
2297
		FF81FF582581919700894E24 /* RewriteCaseDeclarations.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RewriteCaseDeclarations.cpp; sourceTree = "<group>"; };
2298
		FF81FF592581919700894E24 /* RewriteCaseDeclarations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RewriteCaseDeclarations.h; sourceTree = "<group>"; };
2299
		FF81FF5A2581919700894E24 /* MapFunctionsToDefinitions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MapFunctionsToDefinitions.cpp; sourceTree = "<group>"; };
2300
		FF81FF952581A39700894E24 /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; };
2301
		FF81FF972581A3C100894E24 /* NodeType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NodeType.h; sourceTree = "<group>"; };
2302
		FF81FF982581A3C100894E24 /* AsNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AsNode.h; sourceTree = "<group>"; };
2303
		FF81FF992581A3C100894E24 /* IntermRebuild.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntermRebuild.cpp; sourceTree = "<group>"; };
2304
		FF81FF9A2581A3C200894E24 /* IntermRebuild.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntermRebuild.h; sourceTree = "<group>"; };
2033
/* End PBXFileReference section */
2305
/* End PBXFileReference section */
2034
2306
2035
/* Begin PBXFrameworksBuildPhase section */
2307
/* Begin PBXFrameworksBuildPhase section */
Lines 2045-2050 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec3
2045
			buildActionMask = 2147483647;
2317
			buildActionMask = 2147483647;
2046
			files = (
2318
			files = (
2047
				5CB304941DE4157200D2C405 /* CoreGraphics.framework in Frameworks */,
2319
				5CB304941DE4157200D2C405 /* CoreGraphics.framework in Frameworks */,
2320
				FF81FF962581A39700894E24 /* Metal.framework in Frameworks */,
2048
				5CB304931DE4156B00D2C405 /* QuartzCore.framework in Frameworks */,
2321
				5CB304931DE4156B00D2C405 /* QuartzCore.framework in Frameworks */,
2049
			);
2322
			);
2050
			runOnlyForDeploymentPostprocessing = 0;
2323
			runOnlyForDeploymentPostprocessing = 0;
Lines 2055-2060 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec4
2055
		31012D9F18B97B9B0039062F /* translator */ = {
2328
		31012D9F18B97B9B0039062F /* translator */ = {
2056
			isa = PBXGroup;
2329
			isa = PBXGroup;
2057
			children = (
2330
			children = (
2331
				FF81FF202581919700894E24 /* TranslatorMetalDirect */,
2332
				FF81FF18258190CA00894E24 /* TranslatorMetalDirect */,
2058
				5CBD596922826A00002B22AA /* treeops */,
2333
				5CBD596922826A00002B22AA /* treeops */,
2059
				5C55D6EA22826C9800B5BA2C /* treeutil */,
2334
				5C55D6EA22826C9800B5BA2C /* treeutil */,
2060
				5C1DBBFB1B04375F00235552 /* ASTMetadataHLSL.cpp */,
2335
				5C1DBBFB1B04375F00235552 /* ASTMetadataHLSL.cpp */,
Lines 2144-2149 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec5
2144
				31A331D11EA5EDDA00FD2203 /* Severity.h */,
2419
				31A331D11EA5EDDA00FD2203 /* Severity.h */,
2145
				31012DF218B97B9B0039062F /* ShaderLang.cpp */,
2420
				31012DF218B97B9B0039062F /* ShaderLang.cpp */,
2146
				5C1DBC1A1B04375F00235552 /* ShaderVars.cpp */,
2421
				5C1DBC1A1B04375F00235552 /* ShaderVars.cpp */,
2422
				FF81FF17258190CA00894E24 /* StaticType.h */,
2147
				315EBD471FCE442800AC7A89 /* StructureHLSL.cpp */,
2423
				315EBD471FCE442800AC7A89 /* StructureHLSL.cpp */,
2148
				315EBD731FCE443400AC7A89 /* StructureHLSL.h */,
2424
				315EBD731FCE443400AC7A89 /* StructureHLSL.h */,
2149
				5C55D6D922826C7800B5BA2C /* Symbol.cpp */,
2425
				5C55D6D922826C7800B5BA2C /* Symbol.cpp */,
Lines 2160-2165 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec6
2160
				31012DFC18B97B9B0039062F /* TranslatorESSL.h */,
2436
				31012DFC18B97B9B0039062F /* TranslatorESSL.h */,
2161
				31012DFD18B97B9B0039062F /* TranslatorGLSL.cpp */,
2437
				31012DFD18B97B9B0039062F /* TranslatorGLSL.cpp */,
2162
				31012DFE18B97B9B0039062F /* TranslatorGLSL.h */,
2438
				31012DFE18B97B9B0039062F /* TranslatorGLSL.h */,
2439
				FF81FF16258190CA00894E24 /* TranslatorMetalDirect.cpp */,
2440
				FF81FF15258190CA00894E24 /* TranslatorMetalDirect.h */,
2441
				FF81FF19258190CA00894E24 /* TranslatorMetalUtils.cpp */,
2442
				FF81FF1A258190CA00894E24 /* TranslatorMetalUtils.h */,
2163
				315EBD401FCE442600AC7A89 /* TranslatorVulkan.cpp */,
2443
				315EBD401FCE442600AC7A89 /* TranslatorVulkan.cpp */,
2164
				315EBD661FCE443100AC7A89 /* TranslatorVulkan.h */,
2444
				315EBD661FCE443100AC7A89 /* TranslatorVulkan.h */,
2165
				5C1DBC1D1B04375F00235552 /* Types.cpp */,
2445
				5C1DBC1D1B04375F00235552 /* Types.cpp */,
Lines 2522-2527 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec7
2522
		5C55D6EA22826C9800B5BA2C /* treeutil */ = {
2802
		5C55D6EA22826C9800B5BA2C /* treeutil */ = {
2523
			isa = PBXGroup;
2803
			isa = PBXGroup;
2524
			children = (
2804
			children = (
2805
				FF81FF982581A3C100894E24 /* AsNode.h */,
2525
				A30306FE2305F636002DA972 /* FindFunction.cpp */,
2806
				A30306FE2305F636002DA972 /* FindFunction.cpp */,
2526
				A30306FF2305F636002DA972 /* FindFunction.h */,
2807
				A30306FF2305F636002DA972 /* FindFunction.h */,
2527
				5C55D6ED22826CB200B5BA2C /* FindMain.cpp */,
2808
				5C55D6ED22826CB200B5BA2C /* FindMain.cpp */,
Lines 2532-2540 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec8
2532
				5C55D6EE22826CB200B5BA2C /* IntermNode_util.h */,
2813
				5C55D6EE22826CB200B5BA2C /* IntermNode_util.h */,
2533
				5C55D6F422826CB200B5BA2C /* IntermNodePatternMatcher.cpp */,
2814
				5C55D6F422826CB200B5BA2C /* IntermNodePatternMatcher.cpp */,
2534
				5C55D6F822826CB300B5BA2C /* IntermNodePatternMatcher.h */,
2815
				5C55D6F822826CB300B5BA2C /* IntermNodePatternMatcher.h */,
2816
				FF81FF992581A3C100894E24 /* IntermRebuild.cpp */,
2817
				FF81FF9A2581A3C200894E24 /* IntermRebuild.h */,
2535
				5C55D6F222826CB200B5BA2C /* IntermTraverse.cpp */,
2818
				5C55D6F222826CB200B5BA2C /* IntermTraverse.cpp */,
2536
				5C55D6F122826CB200B5BA2C /* IntermTraverse.h */,
2819
				5C55D6F122826CB200B5BA2C /* IntermTraverse.h */,
2537
				5C55D6F722826CB300B5BA2C /* NodeSearch.h */,
2820
				5C55D6F722826CB300B5BA2C /* NodeSearch.h */,
2821
				FF81FF972581A3C100894E24 /* NodeType.h */,
2538
				A3C3FE12255DDD9200B73018 /* ReplaceArrayOfMatrixVarying.cpp */,
2822
				A3C3FE12255DDD9200B73018 /* ReplaceArrayOfMatrixVarying.cpp */,
2539
				A3C3FE11255DDD9200B73018 /* ReplaceArrayOfMatrixVarying.h */,
2823
				A3C3FE11255DDD9200B73018 /* ReplaceArrayOfMatrixVarying.h */,
2540
				6EB01C1F247727A900E50B35 /* ReplaceClipDistanceVariable.cpp */,
2824
				6EB01C1F247727A900E50B35 /* ReplaceClipDistanceVariable.cpp */,
Lines 2590-2595 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec9
2590
			isa = PBXGroup;
2874
			isa = PBXGroup;
2591
			children = (
2875
			children = (
2592
				5CB300DF1DE39F0300D2C405 /* gl */,
2876
				5CB300DF1DE39F0300D2C405 /* gl */,
2877
				FF81FE7F25818D6800894E24 /* metal */,
2593
				6E33E8E724D0D196002309AC /* BufferImpl.cpp */,
2878
				6E33E8E724D0D196002309AC /* BufferImpl.cpp */,
2594
				5CB304AA1DE4164800D2C405 /* BufferImpl.h */,
2879
				5CB304AA1DE4164800D2C405 /* BufferImpl.h */,
2595
				5CB304AB1DE4164800D2C405 /* CompilerImpl.h */,
2880
				5CB304AB1DE4164800D2C405 /* CompilerImpl.h */,
Lines 2745-2750 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec10
2745
			isa = PBXGroup;
3030
			isa = PBXGroup;
2746
			children = (
3031
			children = (
2747
				5CB3048B1DE4143500D2C405 /* CoreGraphics.framework */,
3032
				5CB3048B1DE4143500D2C405 /* CoreGraphics.framework */,
3033
				FF81FF952581A39700894E24 /* Metal.framework */,
2748
				5CB3048D1DE4144400D2C405 /* OpenGL.framework */,
3034
				5CB3048D1DE4144400D2C405 /* OpenGL.framework */,
2749
				5CB3048F1DE4145500D2C405 /* QuartzCore.framework */,
3035
				5CB3048F1DE4145500D2C405 /* QuartzCore.framework */,
2750
			);
3036
			);
Lines 3187-3192 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec11
3187
			path = include/GLSLANG;
3473
			path = include/GLSLANG;
3188
			sourceTree = "<group>";
3474
			sourceTree = "<group>";
3189
		};
3475
		};
3476
		FF81FE7F25818D6800894E24 /* metal */ = {
3477
			isa = PBXGroup;
3478
			children = (
3479
				FF81FEA925818D6800894E24 /* shaders */,
3480
				FF81FE9C25818D6800894E24 /* BufferMtl.h */,
3481
				FF81FE9125818D6800894E24 /* BufferMtl.mm */,
3482
				FF81FEBD25818D6800894E24 /* CompilerMtl.h */,
3483
				FF81FEC025818D6800894E24 /* CompilerMtl.mm */,
3484
				FF81FEC425818D6800894E24 /* ContextMtl.h */,
3485
				FF81FEBF25818D6800894E24 /* ContextMtl.mm */,
3486
				FF81FE8B25818D6800894E24 /* DisplayMtl.h */,
3487
				FF81FECE25818D6800894E24 /* DisplayMtl.mm */,
3488
				FF81FE8225818D6800894E24 /* DisplayMtl_api.h */,
3489
				FF81FEBC25818D6800894E24 /* FrameBufferMtl.h */,
3490
				FF81FEC925818D6800894E24 /* FrameBufferMtl.mm */,
3491
				FF81FEA525818D6800894E24 /* IOSurfaceSurfaceMtl.h */,
3492
				FF81FE9E25818D6800894E24 /* IOSurfaceSurfaceMtl.mm */,
3493
				FF81FEC125818D6800894E24 /* mtl_buffer_pool.h */,
3494
				FF81FEC525818D6800894E24 /* mtl_buffer_pool.mm */,
3495
				FF81FE9B25818D6800894E24 /* mtl_command_buffer.h */,
3496
				FF81FE9625818D6800894E24 /* mtl_command_buffer.mm */,
3497
				FF81FE8825818D6800894E24 /* mtl_common.h */,
3498
				FF81FEC625818D6800894E24 /* mtl_common.mm */,
3499
				FF81FE8925818D6800894E24 /* mtl_constants.h */,
3500
				FF81FE9225818D6800894E24 /* mtl_format_table_autogen.mm */,
3501
				FF81FE8E25818D6800894E24 /* mtl_format_utils.h */,
3502
				FF81FE8525818D6800894E24 /* mtl_format_utils.mm */,
3503
				FF81FE9525818D6800894E24 /* mtl_glslang_mtl_utils.h */,
3504
				FF81FEBE25818D6800894E24 /* mtl_glslang_mtl_utils.mm */,
3505
				FF81FE8025818D6800894E24 /* mtl_glslang_utils.h */,
3506
				FF81FECA25818D6800894E24 /* mtl_occlusion_query_pool.h */,
3507
				FF81FEBB25818D6800894E24 /* mtl_occlusion_query_pool.mm */,
3508
				FF81FEC725818D6800894E24 /* mtl_render_utils.h */,
3509
				FF81FEA325818D6800894E24 /* mtl_render_utils.mm */,
3510
				FF81FEA025818D6800894E24 /* mtl_resources.h */,
3511
				FF81FE9F25818D6800894E24 /* mtl_resources.mm */,
3512
				FF81FEC825818D6800894E24 /* mtl_state_cache.h */,
3513
				FF81FEA125818D6800894E24 /* mtl_state_cache.mm */,
3514
				FF81FEC225818D6800894E24 /* mtl_utils.h */,
3515
				FF81FE9D25818D6800894E24 /* mtl_utils.mm */,
3516
				FF81FE8125818D6800894E24 /* ProgramMtl.h */,
3517
				FF81FECD25818D6800894E24 /* ProgramMtl.mm */,
3518
				FF81FE8425818D6800894E24 /* QueryMtl.h */,
3519
				FF81FE8D25818D6800894E24 /* QueryMtl.mm */,
3520
				FF81FE8F25818D6800894E24 /* RenderBufferMtl.h */,
3521
				FF81FE8625818D6800894E24 /* RenderBufferMtl.mm */,
3522
				FF81FE9325818D6800894E24 /* RenderTargetMtl.h */,
3523
				FF81FE9925818D6800894E24 /* RenderTargetMtl.mm */,
3524
				FF81FE8A25818D6800894E24 /* SamplerMtl.h */,
3525
				FF81FEA825818D6800894E24 /* SamplerMtl.mm */,
3526
				FF81FECB25818D6800894E24 /* ShaderMtl.h */,
3527
				FF81FECC25818D6800894E24 /* ShaderMtl.mm */,
3528
				FF81FE9825818D6800894E24 /* SurfaceMtl.h */,
3529
				FF81FE9425818D6800894E24 /* SurfaceMtl.mm */,
3530
				FF81FE8C25818D6800894E24 /* SyncMtl.h */,
3531
				FF81FE8325818D6800894E24 /* SyncMtl.mm */,
3532
				FF81FEA725818D6800894E24 /* TextureMtl.h */,
3533
				FF81FEA625818D6800894E24 /* TextureMtl.mm */,
3534
				FF81FE9025818D6800894E24 /* TransformFeedbackMtl.h */,
3535
				FF81FEA425818D6800894E24 /* TransformFeedbackMtl.mm */,
3536
				FF81FE9725818D6800894E24 /* VertexArrayMtl.h */,
3537
				FF81FE9A25818D6800894E24 /* VertexArrayMtl.mm */,
3538
			);
3539
			path = metal;
3540
			sourceTree = "<group>";
3541
		};
3542
		FF81FEA925818D6800894E24 /* shaders */ = {
3543
			isa = PBXGroup;
3544
			children = (
3545
				FF81FEAA25818D6800894E24 /* blit.metal */,
3546
				FF81FEB125818D6800894E24 /* clear.metal */,
3547
				FF81FEAD25818D6800894E24 /* common.h */,
3548
				FF81FEAC25818D6800894E24 /* constants.h */,
3549
				FF81FEAF25818D6800894E24 /* copy_buffer.metal */,
3550
				FF81FEB025818D6800894E24 /* format_autogen.h */,
3551
				FF81FEB325818D6800894E24 /* gen_indices.metal */,
3552
				FF81FEB225818D6800894E24 /* gen_mipmap.metal */,
3553
				FF81FEAE25818D6800894E24 /* mtl_default_shaders_src_autogen.inc */,
3554
				FF81FEAB25818D6800894E24 /* visibility.metal */,
3555
			);
3556
			path = shaders;
3557
			sourceTree = "<group>";
3558
		};
3559
		FF81FF202581919700894E24 /* TranslatorMetalDirect */ = {
3560
			isa = PBXGroup;
3561
			children = (
3562
				FF81FF3A2581919700894E24 /* AddExplicitTypeCasts.cpp */,
3563
				FF81FF542581919700894E24 /* AddExplicitTypeCasts.h */,
3564
				FF81FF3E2581919700894E24 /* AstHelpers.cpp */,
3565
				FF81FF472581919700894E24 /* AstHelpers.h */,
3566
				FF81FF4E2581919700894E24 /* ConstantNames.h */,
3567
				FF81FF232581919700894E24 /* Debug.h */,
3568
				FF81FF2B2581919700894E24 /* DebugSink.h */,
3569
				FF81FF292581919700894E24 /* DiscoverDependentFunctions.cpp */,
3570
				FF81FF222581919700894E24 /* DiscoverDependentFunctions.h */,
3571
				FF81FF412581919700894E24 /* DiscoverEnclosingFunctionTraverser.cpp */,
3572
				FF81FF2A2581919700894E24 /* DiscoverEnclosingFunctionTraverser.h */,
3573
				FF81FF2D2581919700894E24 /* EmitMetal.cpp */,
3574
				FF81FF522581919700894E24 /* EmitMetal.h */,
3575
				FF81FF282581919700894E24 /* EnvironmentVariable.h */,
3576
				FF81FF482581919700894E24 /* HoistConstants.cpp */,
3577
				FF81FF4C2581919700894E24 /* HoistConstants.h */,
3578
				FF81FF512581919700894E24 /* IdGen.cpp */,
3579
				FF81FF382581919700894E24 /* IdGen.h */,
3580
				FF81FF322581919700894E24 /* Layout.cpp */,
3581
				FF81FF402581919700894E24 /* Layout.h */,
3582
				FF81FF5A2581919700894E24 /* MapFunctionsToDefinitions.cpp */,
3583
				FF81FF342581919700894E24 /* MapFunctionsToDefinitions.h */,
3584
				FF81FF2F2581919700894E24 /* MapSymbols.cpp */,
3585
				FF81FF3B2581919700894E24 /* MapSymbols.h */,
3586
				FF81FF262581919700894E24 /* ModifyStruct.cpp */,
3587
				FF81FF562581919700894E24 /* ModifyStruct.h */,
3588
				FF81FF212581919700894E24 /* Name.cpp */,
3589
				FF81FF242581919700894E24 /* Name.h */,
3590
				FF81FF372581919700894E24 /* Pipeline.cpp */,
3591
				FF81FF492581919700894E24 /* Pipeline.h */,
3592
				FF81FF502581919700894E24 /* ProgramPrelude.cpp */,
3593
				FF81FF422581919700894E24 /* ProgramPrelude.h */,
3594
				FF81FF3D2581919700894E24 /* ReduceInterfaceBlocks.cpp */,
3595
				FF81FF272581919700894E24 /* ReduceInterfaceBlocks.h */,
3596
				FF81FF4B2581919700894E24 /* Reference.h */,
3597
				FF81FF582581919700894E24 /* RewriteCaseDeclarations.cpp */,
3598
				FF81FF592581919700894E24 /* RewriteCaseDeclarations.h */,
3599
				FF81FF452581919700894E24 /* RewriteGlobalQualifierDecls.cpp */,
3600
				FF81FF432581919700894E24 /* RewriteGlobalQualifierDecls.h */,
3601
				FF81FF4F2581919700894E24 /* RewriteKeywords.cpp */,
3602
				FF81FF312581919700894E24 /* RewriteKeywords.h */,
3603
				FF81FF362581919700894E24 /* RewriteOutArgs.cpp */,
3604
				FF81FF2E2581919700894E24 /* RewriteOutArgs.h */,
3605
				FF81FF3C2581919700894E24 /* RewritePipelines.cpp */,
3606
				FF81FF4A2581919700894E24 /* RewritePipelines.h */,
3607
				FF81FF462581919700894E24 /* RewriteUnaddressableReferences.cpp */,
3608
				FF81FF3F2581919700894E24 /* RewriteUnaddressableReferences.h */,
3609
				FF81FF552581919700894E24 /* SeparateCompoundExpressions.cpp */,
3610
				FF81FF392581919700894E24 /* SeparateCompoundExpressions.h */,
3611
				FF81FF252581919700894E24 /* SeparateCompoundStructDeclarations.cpp */,
3612
				FF81FF2C2581919700894E24 /* SeparateCompoundStructDeclarations.h */,
3613
				FF81FF352581919700894E24 /* SkippingTraverser.h */,
3614
				FF81FF302581919700894E24 /* SymbolEnv.cpp */,
3615
				FF81FF442581919700894E24 /* SymbolEnv.h */,
3616
				FF81FF332581919700894E24 /* ToposortStructs.cpp */,
3617
				FF81FF572581919700894E24 /* ToposortStructs.h */,
3618
				FF81FF4D2581919700894E24 /* WrapMain.cpp */,
3619
				FF81FF532581919700894E24 /* WrapMain.h */,
3620
			);
3621
			path = TranslatorMetalDirect;
3622
			sourceTree = "<group>";
3623
		};
3190
/* End PBXGroup section */
3624
/* End PBXGroup section */
3191
3625
3192
/* Begin PBXHeadersBuildPhase section */
3626
/* Begin PBXHeadersBuildPhase section */
Lines 3611-3616 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec12
3611
			files = (
4045
			files = (
3612
				A3C49C15255DF865005E8DF7 /* AddAndTrueToLoopCondition.h in Headers */,
4046
				A3C49C15255DF865005E8DF7 /* AddAndTrueToLoopCondition.h in Headers */,
3613
				5C55D69722826B9F00B5BA2C /* AddDefaultReturnStatements.h in Headers */,
4047
				5C55D69722826B9F00B5BA2C /* AddDefaultReturnStatements.h in Headers */,
4048
				FF81FF8E2581919800894E24 /* AddExplicitTypeCasts.h in Headers */,
3614
				5C55D7242282747700B5BA2C /* aligned_memory.h in Headers */,
4049
				5C55D7242282747700B5BA2C /* aligned_memory.h in Headers */,
3615
				A30307A1230625C6002DA972 /* android_util.h in Headers */,
4050
				A30307A1230625C6002DA972 /* android_util.h in Headers */,
3616
				A303079923060253002DA972 /* angle_gl.h in Headers */,
4051
				A303079923060253002DA972 /* angle_gl.h in Headers */,
Lines 3618-3623 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec13
3618
				5CC7D46B19102620000B8C1F /* angleutils.h in Headers */,
4053
				5CC7D46B19102620000B8C1F /* angleutils.h in Headers */,
3619
				A08C3CDD16D6CB61003F0B83 /* ArrayBoundsClamper.h in Headers */,
4054
				A08C3CDD16D6CB61003F0B83 /* ArrayBoundsClamper.h in Headers */,
3620
				5C55D68A22826B9F00B5BA2C /* ArrayReturnValueToOutParameter.h in Headers */,
4055
				5C55D68A22826B9F00B5BA2C /* ArrayReturnValueToOutParameter.h in Headers */,
4056
				FF81FF9C2581A3C200894E24 /* AsNode.h in Headers */,
4057
				FF81FF812581919800894E24 /* AstHelpers.h in Headers */,
3621
				5C1DBC231B04375F00235552 /* ASTMetadataHLSL.h in Headers */,
4058
				5C1DBC231B04375F00235552 /* ASTMetadataHLSL.h in Headers */,
3622
				5C1DBDD61B0438D300235552 /* AttributeMap.h in Headers */,
4059
				5C1DBDD61B0438D300235552 /* AttributeMap.h in Headers */,
3623
				31012E1218B97B9B0039062F /* BaseTypes.h in Headers */,
4060
				31012E1218B97B9B0039062F /* BaseTypes.h in Headers */,
Lines 3631-3636 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec14
3631
				5C1DBDD91B0438D300235552 /* Buffer.h in Headers */,
4068
				5C1DBDD91B0438D300235552 /* Buffer.h in Headers */,
3632
				5CB301191DE39F1A00D2C405 /* BufferGL.h in Headers */,
4069
				5CB301191DE39F1A00D2C405 /* BufferGL.h in Headers */,
3633
				5CB304DB1DE4164800D2C405 /* BufferImpl.h in Headers */,
4070
				5CB304DB1DE4164800D2C405 /* BufferImpl.h in Headers */,
4071
				FF81FEEB25818D6900894E24 /* BufferMtl.h in Headers */,
3634
				31012E1418B97B9B0039062F /* BuiltInFunctionEmulator.h in Headers */,
4072
				31012E1418B97B9B0039062F /* BuiltInFunctionEmulator.h in Headers */,
3635
				5C1DBC291B04375F00235552 /* BuiltInFunctionEmulatorGLSL.h in Headers */,
4073
				5C1DBC291B04375F00235552 /* BuiltInFunctionEmulatorGLSL.h in Headers */,
3636
				315EBD7D1FCE443600AC7A89 /* BuiltInFunctionEmulatorHLSL.h in Headers */,
4074
				315EBD7D1FCE443600AC7A89 /* BuiltInFunctionEmulatorHLSL.h in Headers */,
Lines 3643-3655 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec15
3643
				315EBD9A1FCE443600AC7A89 /* CollectVariables.h in Headers */,
4081
				315EBD9A1FCE443600AC7A89 /* CollectVariables.h in Headers */,
3644
				5CCD818E1DBFEA10006066B8 /* Color.h in Headers */,
4082
				5CCD818E1DBFEA10006066B8 /* Color.h in Headers */,
3645
				31012E1618B97B9B0039062F /* Common.h in Headers */,
4083
				31012E1618B97B9B0039062F /* Common.h in Headers */,
4084
				FF81FEFB25818D6900894E24 /* common.h in Headers */,
3646
				5C1DBDDD1B0438D300235552 /* Compiler.h in Headers */,
4085
				5C1DBDDD1B0438D300235552 /* Compiler.h in Headers */,
3647
				5C1DBC2C1B04375F00235552 /* Compiler.h in Headers */,
4086
				5C1DBC2C1B04375F00235552 /* Compiler.h in Headers */,
3648
				5CB3011B1DE39F1A00D2C405 /* CompilerGL.h in Headers */,
4087
				5CB3011B1DE39F1A00D2C405 /* CompilerGL.h in Headers */,
3649
				5CB304DC1DE4164800D2C405 /* CompilerImpl.h in Headers */,
4088
				5CB304DC1DE4164800D2C405 /* CompilerImpl.h in Headers */,
4089
				FF81FF0425818D6900894E24 /* CompilerMtl.h in Headers */,
3650
				A3C49BF3255DF697005E8DF7 /* compression_utils_portable.h in Headers */,
4090
				A3C49BF3255DF697005E8DF7 /* compression_utils_portable.h in Headers */,
3651
				5C1DBDE01B0438D300235552 /* Config.h in Headers */,
4091
				5C1DBDE01B0438D300235552 /* Config.h in Headers */,
4092
				FF81FF882581919800894E24 /* ConstantNames.h in Headers */,
3652
				5C1DBDE11B0438D300235552 /* Constants.h in Headers */,
4093
				5C1DBDE11B0438D300235552 /* Constants.h in Headers */,
4094
				FF81FEFA25818D6900894E24 /* constants.h in Headers */,
3653
				31012E1A18B97B9B0039062F /* ConstantUnion.h in Headers */,
4095
				31012E1A18B97B9B0039062F /* ConstantUnion.h in Headers */,
3654
				5C1DBDE31B0438D300235552 /* Context.h in Headers */,
4096
				5C1DBDE31B0438D300235552 /* Context.h in Headers */,
3655
				A30307272305F7C4002DA972 /* Context.inl.h in Headers */,
4097
				A30307272305F7C4002DA972 /* Context.inl.h in Headers */,
Lines 3657-3665 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec16
3657
				313BCE5F2361133A00FC39E5 /* ContextEAGL.h in Headers */,
4099
				313BCE5F2361133A00FC39E5 /* ContextEAGL.h in Headers */,
3658
				5CB3011D1DE39F1A00D2C405 /* ContextGL.h in Headers */,
4100
				5CB3011D1DE39F1A00D2C405 /* ContextGL.h in Headers */,
3659
				5CB304DE1DE4164800D2C405 /* ContextImpl.h in Headers */,
4101
				5CB304DE1DE4164800D2C405 /* ContextImpl.h in Headers */,
4102
				FF81FF0A25818D6900894E24 /* ContextMtl.h in Headers */,
3660
				5CCD598E2284FC400018F2D8 /* copyimage.h in Headers */,
4103
				5CCD598E2284FC400018F2D8 /* copyimage.h in Headers */,
3661
				5CCD81731DBFE999006066B8 /* Debug.h in Headers */,
4104
				5CCD81731DBFE999006066B8 /* Debug.h in Headers */,
3662
				5CC7D46F19102621000B8C1F /* debug.h in Headers */,
4105
				5CC7D46F19102621000B8C1F /* debug.h in Headers */,
4106
				FF81FF5D2581919700894E24 /* Debug.h in Headers */,
4107
				FF81FF652581919700894E24 /* DebugSink.h in Headers */,
3663
				5C55D734228274DE00B5BA2C /* Declarator.h in Headers */,
4108
				5C55D734228274DE00B5BA2C /* Declarator.h in Headers */,
3664
				5C55D65E22826B9F00B5BA2C /* DeclareAndInitBuiltinsForInstancedMultiview.h in Headers */,
4109
				5C55D65E22826B9F00B5BA2C /* DeclareAndInitBuiltinsForInstancedMultiview.h in Headers */,
3665
				5C55D68922826B9F00B5BA2C /* DeferGlobalInitializers.h in Headers */,
4110
				5C55D68922826B9F00B5BA2C /* DeferGlobalInitializers.h in Headers */,
Lines 3672-3677 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec17
3672
				31012E2918B97B9B0039062F /* DirectiveHandler.h in Headers */,
4117
				31012E2918B97B9B0039062F /* DirectiveHandler.h in Headers */,
3673
				A264F8AF16974DED006FAA5A /* DirectiveHandlerBase.h in Headers */,
4118
				A264F8AF16974DED006FAA5A /* DirectiveHandlerBase.h in Headers */,
3674
				A264F8B116974DED006FAA5A /* DirectiveParser.h in Headers */,
4119
				A264F8B116974DED006FAA5A /* DirectiveParser.h in Headers */,
4120
				FF81FF5C2581919700894E24 /* DiscoverDependentFunctions.h in Headers */,
4121
				FF81FF642581919700894E24 /* DiscoverEnclosingFunctionTraverser.h in Headers */,
3675
				315EBDBC1FCE44BF00AC7A89 /* DispatchTableGL_autogen.h in Headers */,
4122
				315EBDBC1FCE44BF00AC7A89 /* DispatchTableGL_autogen.h in Headers */,
3676
				5C1DBDE91B0438D300235552 /* Display.h in Headers */,
4123
				5C1DBDE91B0438D300235552 /* Display.h in Headers */,
3677
				A3C49C1E255DF88E005E8DF7 /* DisplayApple_api.h in Headers */,
4124
				A3C49C1E255DF88E005E8DF7 /* DisplayApple_api.h in Headers */,
Lines 3679-3684 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec18
3679
				313BCE542361133A00FC39E5 /* DisplayEAGL.h in Headers */,
4126
				313BCE542361133A00FC39E5 /* DisplayEAGL.h in Headers */,
3680
				5CB3011F1DE39F1A00D2C405 /* DisplayGL.h in Headers */,
4127
				5CB3011F1DE39F1A00D2C405 /* DisplayGL.h in Headers */,
3681
				5CB304E21DE4164800D2C405 /* DisplayImpl.h in Headers */,
4128
				5CB304E21DE4164800D2C405 /* DisplayImpl.h in Headers */,
4129
				FF81FEDA25818D6900894E24 /* DisplayMtl.h in Headers */,
4130
				FF81FED225818D6800894E24 /* DisplayMtl_api.h in Headers */,
3682
				315EBDC91FCE44E400AC7A89 /* driver_utils.h in Headers */,
4131
				315EBDC91FCE44E400AC7A89 /* driver_utils.h in Headers */,
3683
				6EB01C1D2477279A00E50B35 /* EarlyFragmentTestsOptimization.h in Headers */,
4132
				6EB01C1D2477279A00E50B35 /* EarlyFragmentTestsOptimization.h in Headers */,
3684
				31DB79582491C84500982878 /* egl.h in Headers */,
4133
				31DB79582491C84500982878 /* egl.h in Headers */,
Lines 3689-3694 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec19
3689
				A3C49BF9255DF6E5005E8DF7 /* EGLReusableSync.h in Headers */,
4138
				A3C49BF9255DF6E5005E8DF7 /* EGLReusableSync.h in Headers */,
3690
				5CCD59672284F7960018F2D8 /* EGLSync.h in Headers */,
4139
				5CCD59672284F7960018F2D8 /* EGLSync.h in Headers */,
3691
				A3C49BFA255DF6E5005E8DF7 /* EGLSyncImpl.h in Headers */,
4140
				A3C49BFA255DF6E5005E8DF7 /* EGLSyncImpl.h in Headers */,
4141
				FF81FF8C2581919800894E24 /* EmitMetal.h in Headers */,
3692
				5C55D66A22826B9F00B5BA2C /* EmulateGLFragColorBroadcast.h in Headers */,
4142
				5C55D66A22826B9F00B5BA2C /* EmulateGLFragColorBroadcast.h in Headers */,
3693
				A30306F72305F5EE002DA972 /* EmulateMultiDrawShaderBuiltins.h in Headers */,
4143
				A30306F72305F5EE002DA972 /* EmulateMultiDrawShaderBuiltins.h in Headers */,
3694
				5C55D6A322826B9F00B5BA2C /* EmulatePrecision.h in Headers */,
4144
				5C55D6A322826B9F00B5BA2C /* EmulatePrecision.h in Headers */,
Lines 3701-3706 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec20
3701
				A30B582B238DF8260079FDDC /* entry_points_gles_3_2_autogen.h in Headers */,
4151
				A30B582B238DF8260079FDDC /* entry_points_gles_3_2_autogen.h in Headers */,
3702
				31DB796C2491C8F500982878 /* entry_points_gles_ext_autogen.h in Headers */,
4152
				31DB796C2491C8F500982878 /* entry_points_gles_ext_autogen.h in Headers */,
3703
				A30307252305F7C4002DA972 /* entry_points_utils.h in Headers */,
4153
				A30307252305F7C4002DA972 /* entry_points_utils.h in Headers */,
4154
				FF81FF622581919700894E24 /* EnvironmentVariable.h in Headers */,
3704
				5C1DBDEB1B0438D300235552 /* Error.h in Headers */,
4155
				5C1DBDEB1B0438D300235552 /* Error.h in Headers */,
3705
				315EBDE91FCE452D00AC7A89 /* ErrorStrings.h in Headers */,
4156
				315EBDE91FCE452D00AC7A89 /* ErrorStrings.h in Headers */,
3706
				5CC7D47119102621000B8C1F /* event_tracer.h in Headers */,
4157
				5CC7D47119102621000B8C1F /* event_tracer.h in Headers */,
Lines 3722-3727 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec21
3722
				5C9FFF4F19102A000025B8FA /* FlagStd140Structs.h in Headers */,
4173
				5C9FFF4F19102A000025B8FA /* FlagStd140Structs.h in Headers */,
3723
				5C55D6A422826B9F00B5BA2C /* FoldExpressions.h in Headers */,
4174
				5C55D6A422826B9F00B5BA2C /* FoldExpressions.h in Headers */,
3724
				5CB304E81DE4164800D2C405 /* Format.h in Headers */,
4175
				5CB304E81DE4164800D2C405 /* Format.h in Headers */,
4176
				FF81FEFE25818D6900894E24 /* format_autogen.h in Headers */,
3725
				5C1DBDF21B0438D300235552 /* formatutils.h in Headers */,
4177
				5C1DBDF21B0438D300235552 /* formatutils.h in Headers */,
3726
				5CB301261DE39F1A00D2C405 /* formatutilsgl.h in Headers */,
4178
				5CB301261DE39F1A00D2C405 /* formatutilsgl.h in Headers */,
3727
				6E33E8EE24D0D209002309AC /* frame_capture_utils.h in Headers */,
4179
				6E33E8EE24D0D209002309AC /* frame_capture_utils.h in Headers */,
Lines 3731-3736 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec22
3731
				5CB301281DE39F1A00D2C405 /* FramebufferGL.h in Headers */,
4183
				5CB301281DE39F1A00D2C405 /* FramebufferGL.h in Headers */,
3732
				5CB304EB1DE4164800D2C405 /* FramebufferImpl.h in Headers */,
4184
				5CB304EB1DE4164800D2C405 /* FramebufferImpl.h in Headers */,
3733
				5CB304EA1DE4164800D2C405 /* FramebufferImpl_mock.h in Headers */,
4185
				5CB304EA1DE4164800D2C405 /* FramebufferImpl_mock.h in Headers */,
4186
				FF81FF0325818D6900894E24 /* FrameBufferMtl.h in Headers */,
3734
				5C55D6E922826C7900B5BA2C /* FunctionLookup.h in Headers */,
4187
				5C55D6E922826C7900B5BA2C /* FunctionLookup.h in Headers */,
3735
				A3C49C00255DF711005E8DF7 /* FunctionsCGL.h in Headers */,
4188
				A3C49C00255DF711005E8DF7 /* FunctionsCGL.h in Headers */,
3736
				A3C49C05255DF735005E8DF7 /* FunctionsEAGL.h in Headers */,
4189
				A3C49C05255DF735005E8DF7 /* FunctionsEAGL.h in Headers */,
Lines 3760-3765 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec23
3760
				5C55D72C2282747700B5BA2C /* hash_utils.h in Headers */,
4213
				5C55D72C2282747700B5BA2C /* hash_utils.h in Headers */,
3761
				31012E3318B97B9B0039062F /* HashNames.h in Headers */,
4214
				31012E3318B97B9B0039062F /* HashNames.h in Headers */,
3762
				5C1DBDFA1B0438D300235552 /* histogram_macros.h in Headers */,
4215
				5C1DBDFA1B0438D300235552 /* histogram_macros.h in Headers */,
4216
				FF81FF862581919800894E24 /* HoistConstants.h in Headers */,
4217
				FF81FF722581919800894E24 /* IdGen.h in Headers */,
3763
				5CCD81771DBFE999006066B8 /* Image.h in Headers */,
4218
				5CCD81771DBFE999006066B8 /* Image.h in Headers */,
3764
				5CCD59932284FC400018F2D8 /* imageformats.h in Headers */,
4219
				5CCD59932284FC400018F2D8 /* imageformats.h in Headers */,
3765
				315EBD961FCE443600AC7A89 /* ImageFunctionHLSL.h in Headers */,
4220
				315EBD961FCE443600AC7A89 /* ImageFunctionHLSL.h in Headers */,
Lines 3780-3790 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec24
3780
				5C1DBC311B04375F00235552 /* IntermNode.h in Headers */,
4235
				5C1DBC311B04375F00235552 /* IntermNode.h in Headers */,
3781
				5C55D6FE22826CB300B5BA2C /* IntermNode_util.h in Headers */,
4236
				5C55D6FE22826CB300B5BA2C /* IntermNode_util.h in Headers */,
3782
				5C55D70822826CB300B5BA2C /* IntermNodePatternMatcher.h in Headers */,
4237
				5C55D70822826CB300B5BA2C /* IntermNodePatternMatcher.h in Headers */,
4238
				FF81FF9E2581A3C200894E24 /* IntermRebuild.h in Headers */,
3783
				5C55D70122826CB300B5BA2C /* IntermTraverse.h in Headers */,
4239
				5C55D70122826CB300B5BA2C /* IntermTraverse.h in Headers */,
3784
				5CCD59772284FA830018F2D8 /* IOSurfaceSurfaceCGL.h in Headers */,
4240
				5CCD59772284FA830018F2D8 /* IOSurfaceSurfaceCGL.h in Headers */,
3785
				313BCE552361133A00FC39E5 /* IOSurfaceSurfaceEAGL.h in Headers */,
4241
				313BCE552361133A00FC39E5 /* IOSurfaceSurfaceEAGL.h in Headers */,
4242
				FF81FEF425818D6900894E24 /* IOSurfaceSurfaceMtl.h in Headers */,
3786
				315EBD8E1FCE443600AC7A89 /* IsASTDepthBelowLimit.h in Headers */,
4243
				315EBD8E1FCE443600AC7A89 /* IsASTDepthBelowLimit.h in Headers */,
3787
				31DB79662491C88200982878 /* khrplatform.h in Headers */,
4244
				31DB79662491C88200982878 /* khrplatform.h in Headers */,
4245
				FF81FF7A2581919800894E24 /* Layout.h in Headers */,
3788
				5C1DBC321B04375F00235552 /* length_limits.h in Headers */,
4246
				5C1DBC321B04375F00235552 /* length_limits.h in Headers */,
3789
				A264F8B716974DED006FAA5A /* Lexer.h in Headers */,
4247
				A264F8B716974DED006FAA5A /* Lexer.h in Headers */,
3790
				5CB304F01DE4164800D2C405 /* load_functions_table.h in Headers */,
4248
				5CB304F01DE4164800D2C405 /* load_functions_table.h in Headers */,
Lines 3792-3797 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec25
3792
				315EBDF11FCE452D00AC7A89 /* LoggingAnnotator.h in Headers */,
4250
				315EBDF11FCE452D00AC7A89 /* LoggingAnnotator.h in Headers */,
3793
				A264F8B916974DED006FAA5A /* Macro.h in Headers */,
4251
				A264F8B916974DED006FAA5A /* Macro.h in Headers */,
3794
				A264F8BB16974DED006FAA5A /* MacroExpander.h in Headers */,
4252
				A264F8BB16974DED006FAA5A /* MacroExpander.h in Headers */,
4253
				FF81FF6E2581919800894E24 /* MapFunctionsToDefinitions.h in Headers */,
4254
				FF81FF752581919800894E24 /* MapSymbols.h in Headers */,
3795
				5CC7D47319102621000B8C1F /* mathutil.h in Headers */,
4255
				5CC7D47319102621000B8C1F /* mathutil.h in Headers */,
3796
				5CCD81901DBFEA10006066B8 /* matrix_utils.h in Headers */,
4256
				5CCD81901DBFEA10006066B8 /* matrix_utils.h in Headers */,
3797
				5C1DBBF21B0436EC00235552 /* MemoryBuffer.h in Headers */,
4257
				5C1DBBF21B0436EC00235552 /* MemoryBuffer.h in Headers */,
Lines 3799-3807 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec26
3799
				A303078C2305F8F0002DA972 /* MemoryObjectGL.h in Headers */,
4259
				A303078C2305F8F0002DA972 /* MemoryObjectGL.h in Headers */,
3800
				5CCD59822284FB900018F2D8 /* MemoryObjectImpl.h in Headers */,
4260
				5CCD59822284FB900018F2D8 /* MemoryObjectImpl.h in Headers */,
3801
				315EBDED1FCE452D00AC7A89 /* MemoryProgramCache.h in Headers */,
4261
				315EBDED1FCE452D00AC7A89 /* MemoryProgramCache.h in Headers */,
4262
				FF81FF902581919800894E24 /* ModifyStruct.h in Headers */,
4263
				FF81FF0825818D6900894E24 /* mtl_buffer_pool.h in Headers */,
4264
				FF81FEEA25818D6900894E24 /* mtl_command_buffer.h in Headers */,
4265
				FF81FED725818D6900894E24 /* mtl_common.h in Headers */,
4266
				FF81FED825818D6900894E24 /* mtl_constants.h in Headers */,
4267
				FF81FEDD25818D6900894E24 /* mtl_format_utils.h in Headers */,
4268
				FF81FEE425818D6900894E24 /* mtl_glslang_mtl_utils.h in Headers */,
4269
				FF81FED025818D6800894E24 /* mtl_glslang_utils.h in Headers */,
4270
				FF81FF1025818D6A00894E24 /* mtl_occlusion_query_pool.h in Headers */,
4271
				FF81FF0D25818D6A00894E24 /* mtl_render_utils.h in Headers */,
4272
				FF81FEEF25818D6900894E24 /* mtl_resources.h in Headers */,
4273
				FF81FF0E25818D6A00894E24 /* mtl_state_cache.h in Headers */,
4274
				FF81FF0925818D6900894E24 /* mtl_utils.h in Headers */,
4275
				FF81FF5E2581919700894E24 /* Name.h in Headers */,
3802
				5C55D66922826B9F00B5BA2C /* NameEmbeddedUniformStructs.h in Headers */,
4276
				5C55D66922826B9F00B5BA2C /* NameEmbeddedUniformStructs.h in Headers */,
3803
				A303070B2305F6B5002DA972 /* no_destructor.h in Headers */,
4277
				A303070B2305F6B5002DA972 /* no_destructor.h in Headers */,
3804
				5C55D70722826CB300B5BA2C /* NodeSearch.h in Headers */,
4278
				5C55D70722826CB300B5BA2C /* NodeSearch.h in Headers */,
4279
				FF81FF9B2581A3C200894E24 /* NodeType.h in Headers */,
3805
				315EBDC21FCE44BF00AC7A89 /* null_functions.h in Headers */,
4280
				315EBDC21FCE44BF00AC7A89 /* null_functions.h in Headers */,
3806
				A264F8BC16974DED006FAA5A /* numeric_lex.h in Headers */,
4281
				A264F8BC16974DED006FAA5A /* numeric_lex.h in Headers */,
3807
				5CCD59662284F7960018F2D8 /* Observer.h in Headers */,
4282
				5CCD59662284F7960018F2D8 /* Observer.h in Headers */,
Lines 3821-3826 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec27
3821
				31012E5518B97B9B0039062F /* ParseContext.h in Headers */,
4296
				31012E5518B97B9B0039062F /* ParseContext.h in Headers */,
3822
				5CB301511DE39F4700D2C405 /* PbufferSurfaceCGL.h in Headers */,
4297
				5CB301511DE39F4700D2C405 /* PbufferSurfaceCGL.h in Headers */,
3823
				313BCE5D2361133A00FC39E5 /* PbufferSurfaceEAGL.h in Headers */,
4298
				313BCE5D2361133A00FC39E5 /* PbufferSurfaceEAGL.h in Headers */,
4299
				FF81FF832581919800894E24 /* Pipeline.h in Headers */,
3824
				5C1DBBF51B0436EC00235552 /* platform.h in Headers */,
4300
				5C1DBBF51B0436EC00235552 /* platform.h in Headers */,
3825
				315EBE291FCF808C00AC7A89 /* PMurHash.h in Headers */,
4301
				315EBE291FCF808C00AC7A89 /* PMurHash.h in Headers */,
3826
				5C55D7272282747700B5BA2C /* PoolAlloc.h in Headers */,
4302
				5C55D7272282747700B5BA2C /* PoolAlloc.h in Headers */,
Lines 3834-3842 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec28
3834
				5CB304F31DE4164800D2C405 /* ProgramImpl.h in Headers */,
4310
				5CB304F31DE4164800D2C405 /* ProgramImpl.h in Headers */,
3835
				5CB304F21DE4164800D2C405 /* ProgramImpl_mock.h in Headers */,
4311
				5CB304F21DE4164800D2C405 /* ProgramImpl_mock.h in Headers */,
3836
				315EBDE61FCE452D00AC7A89 /* ProgramLinkedResources.h in Headers */,
4312
				315EBDE61FCE452D00AC7A89 /* ProgramLinkedResources.h in Headers */,
4313
				FF81FED125818D6800894E24 /* ProgramMtl.h in Headers */,
3837
				315EBDEE1FCE452D00AC7A89 /* ProgramPipeline.h in Headers */,
4314
				315EBDEE1FCE452D00AC7A89 /* ProgramPipeline.h in Headers */,
3838
				315EBDBB1FCE44BF00AC7A89 /* ProgramPipelineGL.h in Headers */,
4315
				315EBDBB1FCE44BF00AC7A89 /* ProgramPipelineGL.h in Headers */,
3839
				315EBDC81FCE44E400AC7A89 /* ProgramPipelineImpl.h in Headers */,
4316
				315EBDC81FCE44E400AC7A89 /* ProgramPipelineImpl.h in Headers */,
4317
				FF81FF7C2581919800894E24 /* ProgramPrelude.h in Headers */,
3840
				5C55D67722826B9F00B5BA2C /* PruneEmptyCases.h in Headers */,
4318
				5C55D67722826B9F00B5BA2C /* PruneEmptyCases.h in Headers */,
3841
				5C55D6A522826B9F00B5BA2C /* PruneNoOps.h in Headers */,
4319
				5C55D6A522826B9F00B5BA2C /* PruneNoOps.h in Headers */,
3842
				5CCD81B61DBFEA5C006066B8 /* QualifierTypes.h in Headers */,
4320
				5CCD81B61DBFEA5C006066B8 /* QualifierTypes.h in Headers */,
Lines 3844-3853 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec29
3844
				5C1DBE041B0438D300235552 /* queryconversions.h in Headers */,
4322
				5C1DBE041B0438D300235552 /* queryconversions.h in Headers */,
3845
				5CB301321DE39F1A00D2C405 /* QueryGL.h in Headers */,
4323
				5CB301321DE39F1A00D2C405 /* QueryGL.h in Headers */,
3846
				5CB304F41DE4164800D2C405 /* QueryImpl.h in Headers */,
4324
				5CB304F41DE4164800D2C405 /* QueryImpl.h in Headers */,
4325
				FF81FED425818D6900894E24 /* QueryMtl.h in Headers */,
3847
				5CCD817D1DBFE999006066B8 /* queryutils.h in Headers */,
4326
				5CCD817D1DBFE999006066B8 /* queryutils.h in Headers */,
3848
				5C55D67C22826B9F00B5BA2C /* RecordConstantPrecision.h in Headers */,
4327
				5C55D67C22826B9F00B5BA2C /* RecordConstantPrecision.h in Headers */,
3849
				A3C49C13255DF865005E8DF7 /* RecordUniformBlocksTranslatedToStructuredBuffers.h in Headers */,
4328
				A3C49C13255DF865005E8DF7 /* RecordUniformBlocksTranslatedToStructuredBuffers.h in Headers */,
4329
				FF81FF612581919700894E24 /* ReduceInterfaceBlocks.h in Headers */,
3850
				5C1DBE061B0438D300235552 /* RefCountObject.h in Headers */,
4330
				5C1DBE061B0438D300235552 /* RefCountObject.h in Headers */,
4331
				FF81FF852581919800894E24 /* Reference.h in Headers */,
3851
				5C55D65C22826B9F00B5BA2C /* RegenerateStructNames.h in Headers */,
4332
				5C55D65C22826B9F00B5BA2C /* RegenerateStructNames.h in Headers */,
3852
				5C55D69A22826B9F00B5BA2C /* RemoveArrayLengthMethod.h in Headers */,
4333
				5C55D69A22826B9F00B5BA2C /* RemoveArrayLengthMethod.h in Headers */,
3853
				6ED7BDF12432CCC400E01503 /* RemoveAtomicCounterBuiltins.h in Headers */,
4334
				6ED7BDF12432CCC400E01503 /* RemoveAtomicCounterBuiltins.h in Headers */,
Lines 3861-3871 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec30
3861
				5CB301341DE39F1A00D2C405 /* RenderbufferGL.h in Headers */,
4342
				5CB301341DE39F1A00D2C405 /* RenderbufferGL.h in Headers */,
3862
				5CB304F61DE4164800D2C405 /* RenderbufferImpl.h in Headers */,
4343
				5CB304F61DE4164800D2C405 /* RenderbufferImpl.h in Headers */,
3863
				5CB304F51DE4164800D2C405 /* RenderbufferImpl_mock.h in Headers */,
4344
				5CB304F51DE4164800D2C405 /* RenderbufferImpl_mock.h in Headers */,
4345
				FF81FEDE25818D6900894E24 /* RenderBufferMtl.h in Headers */,
3864
				5CB304F81DE4164800D2C405 /* renderer_utils.h in Headers */,
4346
				5CB304F81DE4164800D2C405 /* renderer_utils.h in Headers */,
3865
				5CCD597C2284FA830018F2D8 /* RendererCGL.h in Headers */,
4347
				5CCD597C2284FA830018F2D8 /* RendererCGL.h in Headers */,
3866
				313BCE572361133A00FC39E5 /* RendererEAGL.h in Headers */,
4348
				313BCE572361133A00FC39E5 /* RendererEAGL.h in Headers */,
3867
				5CB301381DE39F1A00D2C405 /* RendererGL.h in Headers */,
4349
				5CB301381DE39F1A00D2C405 /* RendererGL.h in Headers */,
3868
				5CB301361DE39F1A00D2C405 /* renderergl_utils.h in Headers */,
4350
				5CB301361DE39F1A00D2C405 /* renderergl_utils.h in Headers */,
4351
				FF81FEE225818D6900894E24 /* RenderTargetMtl.h in Headers */,
3869
				A3C49C1A255DF86F005E8DF7 /* ReplaceArrayOfMatrixVarying.h in Headers */,
4352
				A3C49C1A255DF86F005E8DF7 /* ReplaceArrayOfMatrixVarying.h in Headers */,
3870
				6EB01C22247727A900E50B35 /* ReplaceClipDistanceVariable.h in Headers */,
4353
				6EB01C22247727A900E50B35 /* ReplaceClipDistanceVariable.h in Headers */,
3871
				A30307072305F636002DA972 /* ReplaceShadowingVariables.h in Headers */,
4354
				A30307072305F636002DA972 /* ReplaceShadowingVariables.h in Headers */,
Lines 3876-3891 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec31
3876
				315EBDF91FCE452D00AC7A89 /* ResourceMap.h in Headers */,
4359
				315EBDF91FCE452D00AC7A89 /* ResourceMap.h in Headers */,
3877
				A30306F62305F5EE002DA972 /* RewriteAtomicCounters.h in Headers */,
4360
				A30306F62305F5EE002DA972 /* RewriteAtomicCounters.h in Headers */,
3878
				5C55D65722826B9F00B5BA2C /* RewriteAtomicFunctionExpressions.h in Headers */,
4361
				5C55D65722826B9F00B5BA2C /* RewriteAtomicFunctionExpressions.h in Headers */,
4362
				FF81FF932581919800894E24 /* RewriteCaseDeclarations.h in Headers */,
3879
				A30306F92305F5EE002DA972 /* RewriteCubeMapSamplersAs2DArray.h in Headers */,
4363
				A30306F92305F5EE002DA972 /* RewriteCubeMapSamplersAs2DArray.h in Headers */,
3880
				A30306F82305F5EE002DA972 /* RewriteDfdy.h in Headers */,
4364
				A30306F82305F5EE002DA972 /* RewriteDfdy.h in Headers */,
3881
				5C55D64E22826B9F00B5BA2C /* RewriteDoWhile.h in Headers */,
4365
				5C55D64E22826B9F00B5BA2C /* RewriteDoWhile.h in Headers */,
3882
				5C55D69122826B9F00B5BA2C /* RewriteElseBlocks.h in Headers */,
4366
				5C55D69122826B9F00B5BA2C /* RewriteElseBlocks.h in Headers */,
3883
				5C55D69E22826B9F00B5BA2C /* RewriteExpressionsWithShaderStorageBlock.h in Headers */,
4367
				5C55D69E22826B9F00B5BA2C /* RewriteExpressionsWithShaderStorageBlock.h in Headers */,
4368
				FF81FF7D2581919800894E24 /* RewriteGlobalQualifierDecls.h in Headers */,
3884
				A3C49C14255DF865005E8DF7 /* RewriteInterpolateAtOffset.h in Headers */,
4369
				A3C49C14255DF865005E8DF7 /* RewriteInterpolateAtOffset.h in Headers */,
4370
				FF81FF6B2581919800894E24 /* RewriteKeywords.h in Headers */,
4371
				FF81FF682581919800894E24 /* RewriteOutArgs.h in Headers */,
4372
				FF81FF842581919800894E24 /* RewritePipelines.h in Headers */,
3885
				5C55D66822826B9F00B5BA2C /* RewriteRepeatedAssignToSwizzled.h in Headers */,
4373
				5C55D66822826B9F00B5BA2C /* RewriteRepeatedAssignToSwizzled.h in Headers */,
3886
				A3D3291523CFCB7700375657 /* RewriteRowMajorMatrices.h in Headers */,
4374
				A3D3291523CFCB7700375657 /* RewriteRowMajorMatrices.h in Headers */,
3887
				5C55D64F22826B9F00B5BA2C /* RewriteStructSamplers.h in Headers */,
4375
				5C55D64F22826B9F00B5BA2C /* RewriteStructSamplers.h in Headers */,
3888
				5C55D68722826B9F00B5BA2C /* RewriteTexelFetchOffset.h in Headers */,
4376
				5C55D68722826B9F00B5BA2C /* RewriteTexelFetchOffset.h in Headers */,
4377
				FF81FF792581919800894E24 /* RewriteUnaddressableReferences.h in Headers */,
3889
				5C55D68422826B9F00B5BA2C /* RewriteUnaryMinusOperatorFloat.h in Headers */,
4378
				5C55D68422826B9F00B5BA2C /* RewriteUnaryMinusOperatorFloat.h in Headers */,
3890
				5C55D68522826B9F00B5BA2C /* RewriteUnaryMinusOperatorInt.h in Headers */,
4379
				5C55D68522826B9F00B5BA2C /* RewriteUnaryMinusOperatorInt.h in Headers */,
3891
				5C55D70A22826CB300B5BA2C /* RunAtTheEndOfShader.h in Headers */,
4380
				5C55D70A22826CB300B5BA2C /* RunAtTheEndOfShader.h in Headers */,
Lines 3896-3907 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec32
3896
				5C1DBF281B0438D300235552 /* Sampler.h in Headers */,
4385
				5C1DBF281B0438D300235552 /* Sampler.h in Headers */,
3897
				5CB3013A1DE39F1A00D2C405 /* SamplerGL.h in Headers */,
4386
				5CB3013A1DE39F1A00D2C405 /* SamplerGL.h in Headers */,
3898
				5CB304F91DE4164800D2C405 /* SamplerImpl.h in Headers */,
4387
				5CB304F91DE4164800D2C405 /* SamplerImpl.h in Headers */,
4388
				FF81FED925818D6900894E24 /* SamplerMtl.h in Headers */,
3899
				5C55D68E22826B9F00B5BA2C /* ScalarizeVecAndMatConstructorArgs.h in Headers */,
4389
				5C55D68E22826B9F00B5BA2C /* ScalarizeVecAndMatConstructorArgs.h in Headers */,
3900
				A30307292305F7C4002DA972 /* Semaphore.h in Headers */,
4390
				A30307292305F7C4002DA972 /* Semaphore.h in Headers */,
3901
				A303078D2305F8F0002DA972 /* SemaphoreGL.h in Headers */,
4391
				A303078D2305F8F0002DA972 /* SemaphoreGL.h in Headers */,
3902
				A303072B2305F800002DA972 /* SemaphoreImpl.h in Headers */,
4392
				A303072B2305F800002DA972 /* SemaphoreImpl.h in Headers */,
3903
				5C55D67D22826B9F00B5BA2C /* SeparateArrayConstructorStatements.h in Headers */,
4393
				5C55D67D22826B9F00B5BA2C /* SeparateArrayConstructorStatements.h in Headers */,
3904
				5C55D69622826B9F00B5BA2C /* SeparateArrayInitialization.h in Headers */,
4394
				5C55D69622826B9F00B5BA2C /* SeparateArrayInitialization.h in Headers */,
4395
				FF81FF732581919800894E24 /* SeparateCompoundExpressions.h in Headers */,
4396
				FF81FF662581919700894E24 /* SeparateCompoundStructDeclarations.h in Headers */,
3905
				5C55D67022826B9F00B5BA2C /* SeparateDeclarations.h in Headers */,
4397
				5C55D67022826B9F00B5BA2C /* SeparateDeclarations.h in Headers */,
3906
				5C55D64C22826B9F00B5BA2C /* SeparateExpressionsReturningArrays.h in Headers */,
4398
				5C55D64C22826B9F00B5BA2C /* SeparateExpressionsReturningArrays.h in Headers */,
3907
				A3D3290323CFC5A300375657 /* serial_utils.h in Headers */,
4399
				A3D3290323CFC5A300375657 /* serial_utils.h in Headers */,
Lines 3910-3923 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec33
3910
				5CB3013C1DE39F1A00D2C405 /* ShaderGL.h in Headers */,
4402
				5CB3013C1DE39F1A00D2C405 /* ShaderGL.h in Headers */,
3911
				5CB304FA1DE4164800D2C405 /* ShaderImpl.h in Headers */,
4403
				5CB304FA1DE4164800D2C405 /* ShaderImpl.h in Headers */,
3912
				31DB79642491C87600982878 /* ShaderLang.h in Headers */,
4404
				31DB79642491C87600982878 /* ShaderLang.h in Headers */,
4405
				FF81FF1125818D6A00894E24 /* ShaderMtl.h in Headers */,
3913
				31DB79652491C87600982878 /* ShaderVars.h in Headers */,
4406
				31DB79652491C87600982878 /* ShaderVars.h in Headers */,
3914
				5C55D66122826B9F00B5BA2C /* SimplifyLoopConditions.h in Headers */,
4407
				5C55D66122826B9F00B5BA2C /* SimplifyLoopConditions.h in Headers */,
3915
				315EBDF01FCE452D00AC7A89 /* SizedMRUCache.h in Headers */,
4408
				315EBDF01FCE452D00AC7A89 /* SizedMRUCache.h in Headers */,
4409
				FF81FF6F2581919800894E24 /* SkippingTraverser.h in Headers */,
3916
				A3C49C03255DF719005E8DF7 /* SoftLinking.h in Headers */,
4410
				A3C49C03255DF719005E8DF7 /* SoftLinking.h in Headers */,
3917
				A264F8C016974DED006FAA5A /* SourceLocation.h in Headers */,
4411
				A264F8C016974DED006FAA5A /* SourceLocation.h in Headers */,
3918
				5C55D69B22826B9F00B5BA2C /* SplitSequenceOperator.h in Headers */,
4412
				5C55D69B22826B9F00B5BA2C /* SplitSequenceOperator.h in Headers */,
3919
				5C1DBF2C1B0438D300235552 /* State.h in Headers */,
4413
				5C1DBF2C1B0438D300235552 /* State.h in Headers */,
3920
				5CB3013E1DE39F1A00D2C405 /* StateManagerGL.h in Headers */,
4414
				5CB3013E1DE39F1A00D2C405 /* StateManagerGL.h in Headers */,
4415
				FF81FF1D258190CA00894E24 /* StaticType.h in Headers */,
3921
				5CCD81811DBFE999006066B8 /* Stream.h in Headers */,
4416
				5CCD81811DBFE999006066B8 /* Stream.h in Headers */,
3922
				5CB304FB1DE4164800D2C405 /* StreamProducerImpl.h in Headers */,
4417
				5CB304FB1DE4164800D2C405 /* StreamProducerImpl.h in Headers */,
3923
				5CCD81921DBFEA10006066B8 /* string_utils.h in Headers */,
4418
				5CCD81921DBFEA10006066B8 /* string_utils.h in Headers */,
Lines 3925-3936 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec34
3925
				5C1DBF2F1B0438D300235552 /* Surface.h in Headers */,
4420
				5C1DBF2F1B0438D300235552 /* Surface.h in Headers */,
3926
				5CB301401DE39F1A00D2C405 /* SurfaceGL.h in Headers */,
4421
				5CB301401DE39F1A00D2C405 /* SurfaceGL.h in Headers */,
3927
				5CB304FD1DE4164800D2C405 /* SurfaceImpl.h in Headers */,
4422
				5CB304FD1DE4164800D2C405 /* SurfaceImpl.h in Headers */,
4423
				FF81FEE725818D6900894E24 /* SurfaceMtl.h in Headers */,
3928
				5C55D6E622826C7900B5BA2C /* Symbol.h in Headers */,
4424
				5C55D6E622826C7900B5BA2C /* Symbol.h in Headers */,
4425
				FF81FF7E2581919800894E24 /* SymbolEnv.h in Headers */,
3929
				31012E6518B97B9B0039062F /* SymbolTable.h in Headers */,
4426
				31012E6518B97B9B0039062F /* SymbolTable.h in Headers */,
3930
				5C55D70D2282741400B5BA2C /* SymbolTable_autogen.h in Headers */,
4427
				5C55D70D2282741400B5BA2C /* SymbolTable_autogen.h in Headers */,
3931
				315EBD851FCE443600AC7A89 /* SymbolUniqueId.h in Headers */,
4428
				315EBD851FCE443600AC7A89 /* SymbolUniqueId.h in Headers */,
3932
				315EBDB91FCE44BF00AC7A89 /* SyncGL.h in Headers */,
4429
				315EBDB91FCE44BF00AC7A89 /* SyncGL.h in Headers */,
3933
				315EBDCB1FCE44E400AC7A89 /* SyncImpl.h in Headers */,
4430
				315EBDCB1FCE44E400AC7A89 /* SyncImpl.h in Headers */,
4431
				FF81FEDB25818D6900894E24 /* SyncMtl.h in Headers */,
3934
				31A331C71EA5ED5F00FD2203 /* system_utils.h in Headers */,
4432
				31A331C71EA5ED5F00FD2203 /* system_utils.h in Headers */,
3935
				5CCD599C2284FC750018F2D8 /* SystemInfo.h in Headers */,
4433
				5CCD599C2284FC750018F2D8 /* SystemInfo.h in Headers */,
3936
				31B15722236B803300CAA4FD /* SystemInfo_internal.h in Headers */,
4434
				31B15722236B803300CAA4FD /* SystemInfo_internal.h in Headers */,
Lines 3939-3956 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec35
3939
				5CB301421DE39F1A00D2C405 /* TextureGL.h in Headers */,
4437
				5CB301421DE39F1A00D2C405 /* TextureGL.h in Headers */,
3940
				5CB305001DE4164800D2C405 /* TextureImpl.h in Headers */,
4438
				5CB305001DE4164800D2C405 /* TextureImpl.h in Headers */,
3941
				5CB304FE1DE4164800D2C405 /* TextureImpl_mock.h in Headers */,
4439
				5CB304FE1DE4164800D2C405 /* TextureImpl_mock.h in Headers */,
4440
				FF81FEF625818D6900894E24 /* TextureMtl.h in Headers */,
3942
				315EBDF41FCE452D00AC7A89 /* Thread.h in Headers */,
4441
				315EBDF41FCE452D00AC7A89 /* Thread.h in Headers */,
3943
				5C1DBBF71B0436EC00235552 /* tls.h in Headers */,
4442
				5C1DBBF71B0436EC00235552 /* tls.h in Headers */,
3944
				A264F8C216974DED006FAA5A /* Token.h in Headers */,
4443
				A264F8C216974DED006FAA5A /* Token.h in Headers */,
3945
				A264F8C416974DED006FAA5A /* Tokenizer.h in Headers */,
4444
				A264F8C416974DED006FAA5A /* Tokenizer.h in Headers */,
4445
				FF81FF912581919800894E24 /* ToposortStructs.h in Headers */,
3946
				A30307202305F7C4002DA972 /* trace.h in Headers */,
4446
				A30307202305F7C4002DA972 /* trace.h in Headers */,
3947
				31A331E21EA5EFB800FD2203 /* trace_event.h in Headers */,
4447
				31A331E21EA5EFB800FD2203 /* trace_event.h in Headers */,
3948
				5C1DBF341B0438D300235552 /* TransformFeedback.h in Headers */,
4448
				5C1DBF341B0438D300235552 /* TransformFeedback.h in Headers */,
3949
				5CB301441DE39F1A00D2C405 /* TransformFeedbackGL.h in Headers */,
4449
				5CB301441DE39F1A00D2C405 /* TransformFeedbackGL.h in Headers */,
3950
				5CB305021DE4164800D2C405 /* TransformFeedbackImpl.h in Headers */,
4450
				5CB305021DE4164800D2C405 /* TransformFeedbackImpl.h in Headers */,
3951
				5CB305011DE4164800D2C405 /* TransformFeedbackImpl_mock.h in Headers */,
4451
				5CB305011DE4164800D2C405 /* TransformFeedbackImpl_mock.h in Headers */,
4452
				FF81FEDF25818D6900894E24 /* TransformFeedbackMtl.h in Headers */,
3952
				31012E6B18B97B9B0039062F /* TranslatorESSL.h in Headers */,
4453
				31012E6B18B97B9B0039062F /* TranslatorESSL.h in Headers */,
3953
				31012E6D18B97B9B0039062F /* TranslatorGLSL.h in Headers */,
4454
				31012E6D18B97B9B0039062F /* TranslatorGLSL.h in Headers */,
4455
				FF81FF1B258190CA00894E24 /* TranslatorMetalDirect.h in Headers */,
4456
				FF81FF1F258190CA00894E24 /* TranslatorMetalUtils.h in Headers */,
3954
				315EBD9D1FCE443600AC7A89 /* TranslatorVulkan.h in Headers */,
4457
				315EBD9D1FCE443600AC7A89 /* TranslatorVulkan.h in Headers */,
3955
				31012E7018B97B9B0039062F /* Types.h in Headers */,
4458
				31012E7018B97B9B0039062F /* Types.h in Headers */,
3956
				5C55D68622826B9F00B5BA2C /* UnfoldShortCircuitAST.h in Headers */,
4459
				5C55D68622826B9F00B5BA2C /* UnfoldShortCircuitAST.h in Headers */,
Lines 4010-4020 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec36
4010
				5C1DBF401B0438D300235552 /* VertexArray.h in Headers */,
4513
				5C1DBF401B0438D300235552 /* VertexArray.h in Headers */,
4011
				5CB301461DE39F1A00D2C405 /* VertexArrayGL.h in Headers */,
4514
				5CB301461DE39F1A00D2C405 /* VertexArrayGL.h in Headers */,
4012
				5CB305031DE4164800D2C405 /* VertexArrayImpl.h in Headers */,
4515
				5CB305031DE4164800D2C405 /* VertexArrayImpl.h in Headers */,
4516
				FF81FEE625818D6900894E24 /* VertexArrayMtl.h in Headers */,
4013
				5C1DBF421B0438D300235552 /* VertexAttribute.h in Headers */,
4517
				5C1DBF421B0438D300235552 /* VertexAttribute.h in Headers */,
4014
				5C55D70022826CB300B5BA2C /* Visit.h in Headers */,
4518
				5C55D70022826CB300B5BA2C /* Visit.h in Headers */,
4015
				A31B6183230B747F001610D7 /* WindowSurfaceCGL.h in Headers */,
4519
				A31B6183230B747F001610D7 /* WindowSurfaceCGL.h in Headers */,
4016
				313BCE5E2361133A00FC39E5 /* WindowSurfaceEAGL.h in Headers */,
4520
				313BCE5E2361133A00FC39E5 /* WindowSurfaceEAGL.h in Headers */,
4017
				315EBDFA1FCE452D00AC7A89 /* WorkerThread.h in Headers */,
4521
				315EBDFA1FCE452D00AC7A89 /* WorkerThread.h in Headers */,
4522
				FF81FF8D2581919800894E24 /* WrapMain.h in Headers */,
4018
				5C55D67522826B9F00B5BA2C /* WrapSwitchStatementsInBlocks.h in Headers */,
4523
				5C55D67522826B9F00B5BA2C /* WrapSwitchStatementsInBlocks.h in Headers */,
4019
				5CCD59512284ECD10018F2D8 /* xxhash.h in Headers */,
4524
				5CCD59512284ECD10018F2D8 /* xxhash.h in Headers */,
4020
			);
4525
			);
Lines 4137-4150 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec37
4137
			files = (
4642
			files = (
4138
				A3C49C0E255DF85F005E8DF7 /* AddAndTrueToLoopCondition.cpp in Sources */,
4643
				A3C49C0E255DF85F005E8DF7 /* AddAndTrueToLoopCondition.cpp in Sources */,
4139
				5C55D6A922826BC800B5BA2C /* AddDefaultReturnStatements.cpp in Sources */,
4644
				5C55D6A922826BC800B5BA2C /* AddDefaultReturnStatements.cpp in Sources */,
4645
				FF81FF742581919800894E24 /* AddExplicitTypeCasts.cpp in Sources */,
4140
				5C55D7212282747700B5BA2C /* aligned_memory.cpp in Sources */,
4646
				5C55D7212282747700B5BA2C /* aligned_memory.cpp in Sources */,
4141
				A30307A0230625C6002DA972 /* android_util.cpp in Sources */,
4647
				A30307A0230625C6002DA972 /* android_util.cpp in Sources */,
4142
				5C1DBDD31B0438D300235552 /* angletypes.cpp in Sources */,
4648
				5C1DBDD31B0438D300235552 /* angletypes.cpp in Sources */,
4143
				5C1DBBF01B0436EC00235552 /* angleutils.cpp in Sources */,
4649
				5C1DBBF01B0436EC00235552 /* angleutils.cpp in Sources */,
4144
				A08C3CDC16D6CB61003F0B83 /* ArrayBoundsClamper.cpp in Sources */,
4650
				A08C3CDC16D6CB61003F0B83 /* ArrayBoundsClamper.cpp in Sources */,
4145
				5C55D6AA22826BC800B5BA2C /* ArrayReturnValueToOutParameter.cpp in Sources */,
4651
				5C55D6AA22826BC800B5BA2C /* ArrayReturnValueToOutParameter.cpp in Sources */,
4652
				FF81FF782581919800894E24 /* AstHelpers.cpp in Sources */,
4146
				5C1DBC221B04375F00235552 /* ASTMetadataHLSL.cpp in Sources */,
4653
				5C1DBC221B04375F00235552 /* ASTMetadataHLSL.cpp in Sources */,
4147
				5C1DBDD51B0438D300235552 /* AttributeMap.cpp in Sources */,
4654
				5C1DBDD51B0438D300235552 /* AttributeMap.cpp in Sources */,
4655
				FF81FF9F2581AD0400894E24 /* blit.metal in Sources */,
4148
				5CB301161DE39F1A00D2C405 /* BlitGL.cpp in Sources */,
4656
				5CB301161DE39F1A00D2C405 /* BlitGL.cpp in Sources */,
4149
				5CCD59612284F7960018F2D8 /* BlobCache.cpp in Sources */,
4657
				5CCD59612284F7960018F2D8 /* BlobCache.cpp in Sources */,
4150
				5C1DBC241B04375F00235552 /* blocklayout.cpp in Sources */,
4658
				5C1DBC241B04375F00235552 /* blocklayout.cpp in Sources */,
Lines 4153-4158 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec38
4153
				5C1DBDD81B0438D300235552 /* Buffer.cpp in Sources */,
4661
				5C1DBDD81B0438D300235552 /* Buffer.cpp in Sources */,
4154
				5CB301181DE39F1A00D2C405 /* BufferGL.cpp in Sources */,
4662
				5CB301181DE39F1A00D2C405 /* BufferGL.cpp in Sources */,
4155
				6E33E8E824D0D1EB002309AC /* BufferImpl.cpp in Sources */,
4663
				6E33E8E824D0D1EB002309AC /* BufferImpl.cpp in Sources */,
4664
				FF81FEE025818D6900894E24 /* BufferMtl.mm in Sources */,
4156
				31012E1318B97B9B0039062F /* BuiltInFunctionEmulator.cpp in Sources */,
4665
				31012E1318B97B9B0039062F /* BuiltInFunctionEmulator.cpp in Sources */,
4157
				5C1DBC281B04375F00235552 /* BuiltInFunctionEmulatorGLSL.cpp in Sources */,
4666
				5C1DBC281B04375F00235552 /* BuiltInFunctionEmulatorGLSL.cpp in Sources */,
4158
				315EBD841FCE443600AC7A89 /* BuiltInFunctionEmulatorHLSL.cpp in Sources */,
4667
				315EBD841FCE443600AC7A89 /* BuiltInFunctionEmulatorHLSL.cpp in Sources */,
Lines 4161-4172 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec39
4161
				5C1DBDDA1B0438D300235552 /* Caps.cpp in Sources */,
4670
				5C1DBDDA1B0438D300235552 /* Caps.cpp in Sources */,
4162
				5C55D6AC22826BC800B5BA2C /* ClampFragDepth.cpp in Sources */,
4671
				5C55D6AC22826BC800B5BA2C /* ClampFragDepth.cpp in Sources */,
4163
				5C55D6AD22826BC800B5BA2C /* ClampPointSize.cpp in Sources */,
4672
				5C55D6AD22826BC800B5BA2C /* ClampPointSize.cpp in Sources */,
4673
				FF81FFA22581AD0400894E24 /* clear.metal in Sources */,
4164
				315EBDBD1FCE44BF00AC7A89 /* ClearMultiviewGL.cpp in Sources */,
4674
				315EBDBD1FCE44BF00AC7A89 /* ClearMultiviewGL.cpp in Sources */,
4165
				31012E1518B97B9B0039062F /* CodeGen.cpp in Sources */,
4675
				31012E1518B97B9B0039062F /* CodeGen.cpp in Sources */,
4166
				315EBD8C1FCE443600AC7A89 /* CollectVariables.cpp in Sources */,
4676
				315EBD8C1FCE443600AC7A89 /* CollectVariables.cpp in Sources */,
4167
				31012E1718B97B9B0039062F /* Compiler.cpp in Sources */,
4677
				31012E1718B97B9B0039062F /* Compiler.cpp in Sources */,
4168
				5C1DBDDC1B0438D300235552 /* Compiler.cpp in Sources */,
4678
				5C1DBDDC1B0438D300235552 /* Compiler.cpp in Sources */,
4169
				5CB3011A1DE39F1A00D2C405 /* CompilerGL.cpp in Sources */,
4679
				5CB3011A1DE39F1A00D2C405 /* CompilerGL.cpp in Sources */,
4680
				FF81FF0725818D6900894E24 /* CompilerMtl.mm in Sources */,
4170
				A3C49BF2255DF697005E8DF7 /* compression_utils_portable.cc in Sources */,
4681
				A3C49BF2255DF697005E8DF7 /* compression_utils_portable.cc in Sources */,
4171
				5C1DBDDF1B0438D300235552 /* Config.cpp in Sources */,
4682
				5C1DBDDF1B0438D300235552 /* Config.cpp in Sources */,
4172
				5CCD81B01DBFEA5C006066B8 /* ConstantUnion.cpp in Sources */,
4683
				5CCD81B01DBFEA5C006066B8 /* ConstantUnion.cpp in Sources */,
Lines 4177-4182 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec40
4177
				313BCE582361133A00FC39E5 /* ContextEAGL.cpp in Sources */,
4688
				313BCE582361133A00FC39E5 /* ContextEAGL.cpp in Sources */,
4178
				5CB3011C1DE39F1A00D2C405 /* ContextGL.cpp in Sources */,
4689
				5CB3011C1DE39F1A00D2C405 /* ContextGL.cpp in Sources */,
4179
				5CB304DD1DE4164800D2C405 /* ContextImpl.cpp in Sources */,
4690
				5CB304DD1DE4164800D2C405 /* ContextImpl.cpp in Sources */,
4691
				FF81FF0625818D6900894E24 /* ContextMtl.mm in Sources */,
4692
				FF81FFA12581AD0400894E24 /* copy_buffer.metal in Sources */,
4180
				5CCD598F2284FC400018F2D8 /* copyimage.cpp in Sources */,
4693
				5CCD598F2284FC400018F2D8 /* copyimage.cpp in Sources */,
4181
				5CCD81721DBFE999006066B8 /* Debug.cpp in Sources */,
4694
				5CCD81721DBFE999006066B8 /* Debug.cpp in Sources */,
4182
				5CC7D46E19102621000B8C1F /* debug.cpp in Sources */,
4695
				5CC7D46E19102621000B8C1F /* debug.cpp in Sources */,
Lines 4192-4197 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec41
4192
				31012E2818B97B9B0039062F /* DirectiveHandler.cpp in Sources */,
4705
				31012E2818B97B9B0039062F /* DirectiveHandler.cpp in Sources */,
4193
				A264F8AE16974DED006FAA5A /* DirectiveHandlerBase.cpp in Sources */,
4706
				A264F8AE16974DED006FAA5A /* DirectiveHandlerBase.cpp in Sources */,
4194
				A264F8B016974DED006FAA5A /* DirectiveParser.cpp in Sources */,
4707
				A264F8B016974DED006FAA5A /* DirectiveParser.cpp in Sources */,
4708
				FF81FF632581919700894E24 /* DiscoverDependentFunctions.cpp in Sources */,
4709
				FF81FF7B2581919800894E24 /* DiscoverEnclosingFunctionTraverser.cpp in Sources */,
4195
				315EBDBE1FCE44BF00AC7A89 /* DispatchTableGL_autogen.cpp in Sources */,
4710
				315EBDBE1FCE44BF00AC7A89 /* DispatchTableGL_autogen.cpp in Sources */,
4196
				5C1DBDE81B0438D300235552 /* Display.cpp in Sources */,
4711
				5C1DBDE81B0438D300235552 /* Display.cpp in Sources */,
4197
				A3C49C1C255DF889005E8DF7 /* DisplayApple_api.cpp in Sources */,
4712
				A3C49C1C255DF889005E8DF7 /* DisplayApple_api.cpp in Sources */,
Lines 4199-4210 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec42
4199
				313BCE612361133A00FC39E5 /* DisplayEAGL.mm in Sources */,
4714
				313BCE612361133A00FC39E5 /* DisplayEAGL.mm in Sources */,
4200
				5CB3011E1DE39F1A00D2C405 /* DisplayGL.cpp in Sources */,
4715
				5CB3011E1DE39F1A00D2C405 /* DisplayGL.cpp in Sources */,
4201
				5CB304E11DE4164800D2C405 /* DisplayImpl.cpp in Sources */,
4716
				5CB304E11DE4164800D2C405 /* DisplayImpl.cpp in Sources */,
4717
				FF81FF1425818D6A00894E24 /* DisplayMtl.mm in Sources */,
4202
				315EBDCC1FCE44E400AC7A89 /* driver_utils.cpp in Sources */,
4718
				315EBDCC1FCE44E400AC7A89 /* driver_utils.cpp in Sources */,
4203
				A303079D23062565002DA972 /* driver_utils_mac.mm in Sources */,
4719
				A303079D23062565002DA972 /* driver_utils_mac.mm in Sources */,
4204
				6EB01C1E2477279A00E50B35 /* EarlyFragmentTestsOptimization.cpp in Sources */,
4720
				6EB01C1E2477279A00E50B35 /* EarlyFragmentTestsOptimization.cpp in Sources */,
4205
				A3C49BF7255DF6DF005E8DF7 /* EGLReusableSync.cpp in Sources */,
4721
				A3C49BF7255DF6DF005E8DF7 /* EGLReusableSync.cpp in Sources */,
4206
				5CCD596A2284F7960018F2D8 /* EGLSync.cpp in Sources */,
4722
				5CCD596A2284F7960018F2D8 /* EGLSync.cpp in Sources */,
4207
				A3C49BF8255DF6E1005E8DF7 /* EGLSyncImpl.cpp in Sources */,
4723
				A3C49BF8255DF6E1005E8DF7 /* EGLSyncImpl.cpp in Sources */,
4724
				FF81FF672581919700894E24 /* EmitMetal.cpp in Sources */,
4208
				315EBD971FCE443600AC7A89 /* emulated_builtin_functions_hlsl_autogen.cpp in Sources */,
4725
				315EBD971FCE443600AC7A89 /* emulated_builtin_functions_hlsl_autogen.cpp in Sources */,
4209
				5C55D6B122826BC800B5BA2C /* EmulateGLFragColorBroadcast.cpp in Sources */,
4726
				5C55D6B122826BC800B5BA2C /* EmulateGLFragColorBroadcast.cpp in Sources */,
4210
				A30306FC2305F5EE002DA972 /* EmulateMultiDrawShaderBuiltins.cpp in Sources */,
4727
				A30306FC2305F5EE002DA972 /* EmulateMultiDrawShaderBuiltins.cpp in Sources */,
Lines 4242-4252 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec43
4242
				5C1DBDF31B0438D300235552 /* Framebuffer.cpp in Sources */,
4759
				5C1DBDF31B0438D300235552 /* Framebuffer.cpp in Sources */,
4243
				5C1DBDF51B0438D300235552 /* FramebufferAttachment.cpp in Sources */,
4760
				5C1DBDF51B0438D300235552 /* FramebufferAttachment.cpp in Sources */,
4244
				5CB301271DE39F1A00D2C405 /* FramebufferGL.cpp in Sources */,
4761
				5CB301271DE39F1A00D2C405 /* FramebufferGL.cpp in Sources */,
4762
				FF81FF0F25818D6A00894E24 /* FrameBufferMtl.mm in Sources */,
4245
				6EA0D69323515A5C00B8651F /* FrameCapture_mock.cpp in Sources */,
4763
				6EA0D69323515A5C00B8651F /* FrameCapture_mock.cpp in Sources */,
4246
				5C55D6E422826C7900B5BA2C /* FunctionLookup.cpp in Sources */,
4764
				5C55D6E422826C7900B5BA2C /* FunctionLookup.cpp in Sources */,
4247
				A3C49C02255DF714005E8DF7 /* FunctionsCGL.cpp in Sources */,
4765
				A3C49C02255DF714005E8DF7 /* FunctionsCGL.cpp in Sources */,
4248
				A3C49C07255DF739005E8DF7 /* FunctionsEAGL.mm in Sources */,
4766
				A3C49C07255DF739005E8DF7 /* FunctionsEAGL.mm in Sources */,
4249
				5CB3012B1DE39F1A00D2C405 /* FunctionsGL.cpp in Sources */,
4767
				5CB3012B1DE39F1A00D2C405 /* FunctionsGL.cpp in Sources */,
4768
				FF81FFA42581AD0400894E24 /* gen_indices.metal in Sources */,
4769
				FF81FFA32581AD0400894E24 /* gen_mipmap.metal in Sources */,
4250
				5CCD596B2284F7960018F2D8 /* GLES1Renderer.cpp in Sources */,
4770
				5CCD596B2284F7960018F2D8 /* GLES1Renderer.cpp in Sources */,
4251
				5CCD59632284F7960018F2D8 /* GLES1State.cpp in Sources */,
4771
				5CCD59632284F7960018F2D8 /* GLES1State.cpp in Sources */,
4252
				5C1BAAB11DFB6F33002906BB /* global_state.cpp in Sources */,
4772
				5C1BAAB11DFB6F33002906BB /* global_state.cpp in Sources */,
Lines 4254-4259 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec44
4254
				A3D3290B23CFCB4D00375657 /* glslang_tab_autogen.cpp in Sources */,
4774
				A3D3290B23CFCB4D00375657 /* glslang_tab_autogen.cpp in Sources */,
4255
				5C1DBDF81B0438D300235552 /* HandleAllocator.cpp in Sources */,
4775
				5C1DBDF81B0438D300235552 /* HandleAllocator.cpp in Sources */,
4256
				315EBD861FCE443600AC7A89 /* HashNames.cpp in Sources */,
4776
				315EBD861FCE443600AC7A89 /* HashNames.cpp in Sources */,
4777
				FF81FF822581919800894E24 /* HoistConstants.cpp in Sources */,
4778
				FF81FF8B2581919800894E24 /* IdGen.cpp in Sources */,
4257
				5CCD81761DBFE999006066B8 /* Image.cpp in Sources */,
4779
				5CCD81761DBFE999006066B8 /* Image.cpp in Sources */,
4258
				5CCD59912284FC400018F2D8 /* imageformats.cpp in Sources */,
4780
				5CCD59912284FC400018F2D8 /* imageformats.cpp in Sources */,
4259
				315EBD831FCE443600AC7A89 /* ImageFunctionHLSL.cpp in Sources */,
4781
				315EBD831FCE443600AC7A89 /* ImageFunctionHLSL.cpp in Sources */,
Lines 4270-4279 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec45
4270
				5C1DBC301B04375F00235552 /* IntermNode.cpp in Sources */,
4792
				5C1DBC301B04375F00235552 /* IntermNode.cpp in Sources */,
4271
				5C55D70922826CB300B5BA2C /* IntermNode_util.cpp in Sources */,
4793
				5C55D70922826CB300B5BA2C /* IntermNode_util.cpp in Sources */,
4272
				5C55D70422826CB300B5BA2C /* IntermNodePatternMatcher.cpp in Sources */,
4794
				5C55D70422826CB300B5BA2C /* IntermNodePatternMatcher.cpp in Sources */,
4795
				FF81FF9D2581A3C200894E24 /* IntermRebuild.cpp in Sources */,
4273
				5C55D70222826CB300B5BA2C /* IntermTraverse.cpp in Sources */,
4796
				5C55D70222826CB300B5BA2C /* IntermTraverse.cpp in Sources */,
4274
				5CCD59792284FA830018F2D8 /* IOSurfaceSurfaceCGL.cpp in Sources */,
4797
				5CCD59792284FA830018F2D8 /* IOSurfaceSurfaceCGL.cpp in Sources */,
4275
				313BCE5C2361133A00FC39E5 /* IOSurfaceSurfaceEAGL.mm in Sources */,
4798
				313BCE5C2361133A00FC39E5 /* IOSurfaceSurfaceEAGL.mm in Sources */,
4799
				FF81FEED25818D6900894E24 /* IOSurfaceSurfaceMtl.mm in Sources */,
4276
				315EBD9C1FCE443600AC7A89 /* IsASTDepthBelowLimit.cpp in Sources */,
4800
				315EBD9C1FCE443600AC7A89 /* IsASTDepthBelowLimit.cpp in Sources */,
4801
				FF81FF6C2581919800894E24 /* Layout.cpp in Sources */,
4277
				A264F8B616974DED006FAA5A /* Lexer.cpp in Sources */,
4802
				A264F8B616974DED006FAA5A /* Lexer.cpp in Sources */,
4278
				5CB304EF1DE4164800D2C405 /* load_functions_table_autogen.cpp in Sources */,
4803
				5CB304EF1DE4164800D2C405 /* load_functions_table_autogen.cpp in Sources */,
4279
				5CCD59952284FC400018F2D8 /* loadimage.cpp in Sources */,
4804
				5CCD59952284FC400018F2D8 /* loadimage.cpp in Sources */,
Lines 4281-4292 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec46
4281
				315EBDE81FCE452D00AC7A89 /* LoggingAnnotator.cpp in Sources */,
4806
				315EBDE81FCE452D00AC7A89 /* LoggingAnnotator.cpp in Sources */,
4282
				A264F8B816974DED006FAA5A /* Macro.cpp in Sources */,
4807
				A264F8B816974DED006FAA5A /* Macro.cpp in Sources */,
4283
				A264F8BA16974DED006FAA5A /* MacroExpander.cpp in Sources */,
4808
				A264F8BA16974DED006FAA5A /* MacroExpander.cpp in Sources */,
4809
				FF81FF942581919800894E24 /* MapFunctionsToDefinitions.cpp in Sources */,
4810
				FF81FF692581919800894E24 /* MapSymbols.cpp in Sources */,
4284
				5CC7D47219102621000B8C1F /* mathutil.cpp in Sources */,
4811
				5CC7D47219102621000B8C1F /* mathutil.cpp in Sources */,
4285
				5C55D7252282747700B5BA2C /* matrix_utils.cpp in Sources */,
4812
				5C55D7252282747700B5BA2C /* matrix_utils.cpp in Sources */,
4286
				5C1DBBF11B0436EC00235552 /* MemoryBuffer.cpp in Sources */,
4813
				5C1DBBF11B0436EC00235552 /* MemoryBuffer.cpp in Sources */,
4287
				5CCD59642284F7960018F2D8 /* MemoryObject.cpp in Sources */,
4814
				5CCD59642284F7960018F2D8 /* MemoryObject.cpp in Sources */,
4288
				A303078B2305F8F0002DA972 /* MemoryObjectGL.cpp in Sources */,
4815
				A303078B2305F8F0002DA972 /* MemoryObjectGL.cpp in Sources */,
4289
				315EBDF31FCE452D00AC7A89 /* MemoryProgramCache.cpp in Sources */,
4816
				315EBDF31FCE452D00AC7A89 /* MemoryProgramCache.cpp in Sources */,
4817
				FF81FF602581919700894E24 /* ModifyStruct.cpp in Sources */,
4818
				FF81FF0B25818D6900894E24 /* mtl_buffer_pool.mm in Sources */,
4819
				FF81FEE525818D6900894E24 /* mtl_command_buffer.mm in Sources */,
4820
				FF81FF0C25818D6A00894E24 /* mtl_common.mm in Sources */,
4821
				FF81FEE125818D6900894E24 /* mtl_format_table_autogen.mm in Sources */,
4822
				FF81FED525818D6900894E24 /* mtl_format_utils.mm in Sources */,
4823
				FF81FF0525818D6900894E24 /* mtl_glslang_mtl_utils.mm in Sources */,
4824
				FF81FF0225818D6900894E24 /* mtl_occlusion_query_pool.mm in Sources */,
4825
				FF81FEF225818D6900894E24 /* mtl_render_utils.mm in Sources */,
4826
				FF81FEEE25818D6900894E24 /* mtl_resources.mm in Sources */,
4827
				FF81FEF025818D6900894E24 /* mtl_state_cache.mm in Sources */,
4828
				FF81FEEC25818D6900894E24 /* mtl_utils.mm in Sources */,
4829
				FF81FF5B2581919700894E24 /* Name.cpp in Sources */,
4290
				5C55D6B622826BC800B5BA2C /* NameEmbeddedUniformStructs.cpp in Sources */,
4830
				5C55D6B622826BC800B5BA2C /* NameEmbeddedUniformStructs.cpp in Sources */,
4291
				315EBDBF1FCE44BF00AC7A89 /* null_functions.cpp in Sources */,
4831
				315EBDBF1FCE44BF00AC7A89 /* null_functions.cpp in Sources */,
4292
				5CCD59692284F7960018F2D8 /* Observer.cpp in Sources */,
4832
				5CCD59692284F7960018F2D8 /* Observer.cpp in Sources */,
Lines 4306-4311 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec47
4306
				31012E5418B97B9B0039062F /* ParseContext.cpp in Sources */,
4846
				31012E5418B97B9B0039062F /* ParseContext.cpp in Sources */,
4307
				5CCD596F2284F9550018F2D8 /* PbufferSurfaceCGL.cpp in Sources */,
4847
				5CCD596F2284F9550018F2D8 /* PbufferSurfaceCGL.cpp in Sources */,
4308
				313BCE562361133A00FC39E5 /* PbufferSurfaceEAGL.cpp in Sources */,
4848
				313BCE562361133A00FC39E5 /* PbufferSurfaceEAGL.cpp in Sources */,
4849
				FF81FF712581919800894E24 /* Pipeline.cpp in Sources */,
4309
				5C1DBDFE1B0438D300235552 /* Platform.cpp in Sources */,
4850
				5C1DBDFE1B0438D300235552 /* Platform.cpp in Sources */,
4310
				315EBE281FCF808C00AC7A89 /* PMurHash.cpp in Sources */,
4851
				315EBE281FCF808C00AC7A89 /* PMurHash.cpp in Sources */,
4311
				31012E5618B97B9B0039062F /* PoolAlloc.cpp in Sources */,
4852
				31012E5618B97B9B0039062F /* PoolAlloc.cpp in Sources */,
Lines 4318-4326 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec48
4318
				6ED7BDF62432CD6200E01503 /* ProgramExecutable.cpp in Sources */,
4859
				6ED7BDF62432CD6200E01503 /* ProgramExecutable.cpp in Sources */,
4319
				5CB3012F1DE39F1A00D2C405 /* ProgramGL.cpp in Sources */,
4860
				5CB3012F1DE39F1A00D2C405 /* ProgramGL.cpp in Sources */,
4320
				315EBDEC1FCE452D00AC7A89 /* ProgramLinkedResources.cpp in Sources */,
4861
				315EBDEC1FCE452D00AC7A89 /* ProgramLinkedResources.cpp in Sources */,
4862
				FF81FF1325818D6A00894E24 /* ProgramMtl.mm in Sources */,
4321
				315EBDE51FCE452D00AC7A89 /* ProgramPipeline.cpp in Sources */,
4863
				315EBDE51FCE452D00AC7A89 /* ProgramPipeline.cpp in Sources */,
4322
				315EBDBA1FCE44BF00AC7A89 /* ProgramPipelineGL.cpp in Sources */,
4864
				315EBDBA1FCE44BF00AC7A89 /* ProgramPipelineGL.cpp in Sources */,
4323
				6EB01C24247727C200E50B35 /* ProgramPipelineImpl.cpp in Sources */,
4865
				6EB01C24247727C200E50B35 /* ProgramPipelineImpl.cpp in Sources */,
4866
				FF81FF8A2581919800894E24 /* ProgramPrelude.cpp in Sources */,
4324
				5C55D6B722826BC800B5BA2C /* PruneEmptyCases.cpp in Sources */,
4867
				5C55D6B722826BC800B5BA2C /* PruneEmptyCases.cpp in Sources */,
4325
				5C55D6B822826BC800B5BA2C /* PruneNoOps.cpp in Sources */,
4868
				5C55D6B822826BC800B5BA2C /* PruneNoOps.cpp in Sources */,
4326
				5CCD81B51DBFEA5C006066B8 /* QualifierTypes.cpp in Sources */,
4869
				5CCD81B51DBFEA5C006066B8 /* QualifierTypes.cpp in Sources */,
Lines 4328-4336 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec49
4328
				5C1DBE031B0438D300235552 /* queryconversions.cpp in Sources */,
4871
				5C1DBE031B0438D300235552 /* queryconversions.cpp in Sources */,
4329
				5CB301311DE39F1A00D2C405 /* QueryGL.cpp in Sources */,
4872
				5CB301311DE39F1A00D2C405 /* QueryGL.cpp in Sources */,
4330
				5CCD59802284FB900018F2D8 /* QueryImpl.cpp in Sources */,
4873
				5CCD59802284FB900018F2D8 /* QueryImpl.cpp in Sources */,
4874
				FF81FEDC25818D6900894E24 /* QueryMtl.mm in Sources */,
4331
				5CCD817C1DBFE999006066B8 /* queryutils.cpp in Sources */,
4875
				5CCD817C1DBFE999006066B8 /* queryutils.cpp in Sources */,
4332
				5C55D6B922826BC800B5BA2C /* RecordConstantPrecision.cpp in Sources */,
4876
				5C55D6B922826BC800B5BA2C /* RecordConstantPrecision.cpp in Sources */,
4333
				A3C49C0C255DF85F005E8DF7 /* RecordUniformBlocksTranslatedToStructuredBuffers.cpp in Sources */,
4877
				A3C49C0C255DF85F005E8DF7 /* RecordUniformBlocksTranslatedToStructuredBuffers.cpp in Sources */,
4878
				FF81FF772581919800894E24 /* ReduceInterfaceBlocks.cpp in Sources */,
4334
				5C55D6BA22826BC800B5BA2C /* RegenerateStructNames.cpp in Sources */,
4879
				5C55D6BA22826BC800B5BA2C /* RegenerateStructNames.cpp in Sources */,
4335
				5C55D6BB22826BC800B5BA2C /* RemoveArrayLengthMethod.cpp in Sources */,
4880
				5C55D6BB22826BC800B5BA2C /* RemoveArrayLengthMethod.cpp in Sources */,
4336
				6ED7BDF02432CCC400E01503 /* RemoveAtomicCounterBuiltins.cpp in Sources */,
4881
				6ED7BDF02432CCC400E01503 /* RemoveAtomicCounterBuiltins.cpp in Sources */,
Lines 4342-4352 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec50
4342
				5C55D6C022826BC800B5BA2C /* RemoveUnreferencedVariables.cpp in Sources */,
4887
				5C55D6C022826BC800B5BA2C /* RemoveUnreferencedVariables.cpp in Sources */,
4343
				5C1DBE071B0438D300235552 /* Renderbuffer.cpp in Sources */,
4888
				5C1DBE071B0438D300235552 /* Renderbuffer.cpp in Sources */,
4344
				5CB301331DE39F1A00D2C405 /* RenderbufferGL.cpp in Sources */,
4889
				5CB301331DE39F1A00D2C405 /* RenderbufferGL.cpp in Sources */,
4890
				FF81FED625818D6900894E24 /* RenderBufferMtl.mm in Sources */,
4345
				5CB304F71DE4164800D2C405 /* renderer_utils.cpp in Sources */,
4891
				5CB304F71DE4164800D2C405 /* renderer_utils.cpp in Sources */,
4346
				5CCD597A2284FA830018F2D8 /* RendererCGL.cpp in Sources */,
4892
				5CCD597A2284FA830018F2D8 /* RendererCGL.cpp in Sources */,
4347
				313BCE592361133A00FC39E5 /* RendererEAGL.cpp in Sources */,
4893
				313BCE592361133A00FC39E5 /* RendererEAGL.cpp in Sources */,
4348
				5CB301371DE39F1A00D2C405 /* RendererGL.cpp in Sources */,
4894
				5CB301371DE39F1A00D2C405 /* RendererGL.cpp in Sources */,
4349
				5CB301351DE39F1A00D2C405 /* renderergl_utils.cpp in Sources */,
4895
				5CB301351DE39F1A00D2C405 /* renderergl_utils.cpp in Sources */,
4896
				FF81FEE825818D6900894E24 /* RenderTargetMtl.mm in Sources */,
4350
				A3C49C19255DF86C005E8DF7 /* ReplaceArrayOfMatrixVarying.cpp in Sources */,
4897
				A3C49C19255DF86C005E8DF7 /* ReplaceArrayOfMatrixVarying.cpp in Sources */,
4351
				6EB01C21247727A900E50B35 /* ReplaceClipDistanceVariable.cpp in Sources */,
4898
				6EB01C21247727A900E50B35 /* ReplaceClipDistanceVariable.cpp in Sources */,
4352
				A30307052305F636002DA972 /* ReplaceShadowingVariables.cpp in Sources */,
4899
				A30307052305F636002DA972 /* ReplaceShadowingVariables.cpp in Sources */,
Lines 4354-4380 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec51
4354
				5C1DBF251B0438D300235552 /* ResourceManager.cpp in Sources */,
4901
				5C1DBF251B0438D300235552 /* ResourceManager.cpp in Sources */,
4355
				A30306FB2305F5EE002DA972 /* RewriteAtomicCounters.cpp in Sources */,
4902
				A30306FB2305F5EE002DA972 /* RewriteAtomicCounters.cpp in Sources */,
4356
				5C55D6C122826BC800B5BA2C /* RewriteAtomicFunctionExpressions.cpp in Sources */,
4903
				5C55D6C122826BC800B5BA2C /* RewriteAtomicFunctionExpressions.cpp in Sources */,
4904
				FF81FF922581919800894E24 /* RewriteCaseDeclarations.cpp in Sources */,
4357
				A30306FD2305F5EE002DA972 /* RewriteCubeMapSamplersAs2DArray.cpp in Sources */,
4905
				A30306FD2305F5EE002DA972 /* RewriteCubeMapSamplersAs2DArray.cpp in Sources */,
4358
				A30306FA2305F5EE002DA972 /* RewriteDfdy.cpp in Sources */,
4906
				A30306FA2305F5EE002DA972 /* RewriteDfdy.cpp in Sources */,
4359
				5C55D6C222826BC800B5BA2C /* RewriteDoWhile.cpp in Sources */,
4907
				5C55D6C222826BC800B5BA2C /* RewriteDoWhile.cpp in Sources */,
4360
				5C55D6C322826BC800B5BA2C /* RewriteElseBlocks.cpp in Sources */,
4908
				5C55D6C322826BC800B5BA2C /* RewriteElseBlocks.cpp in Sources */,
4361
				5C55D6C422826BC800B5BA2C /* RewriteExpressionsWithShaderStorageBlock.cpp in Sources */,
4909
				5C55D6C422826BC800B5BA2C /* RewriteExpressionsWithShaderStorageBlock.cpp in Sources */,
4910
				FF81FF7F2581919800894E24 /* RewriteGlobalQualifierDecls.cpp in Sources */,
4362
				A3C49C0D255DF85F005E8DF7 /* RewriteInterpolateAtOffset.cpp in Sources */,
4911
				A3C49C0D255DF85F005E8DF7 /* RewriteInterpolateAtOffset.cpp in Sources */,
4912
				FF81FF892581919800894E24 /* RewriteKeywords.cpp in Sources */,
4913
				FF81FF702581919800894E24 /* RewriteOutArgs.cpp in Sources */,
4914
				FF81FF762581919800894E24 /* RewritePipelines.cpp in Sources */,
4363
				5C55D6C522826BC800B5BA2C /* RewriteRepeatedAssignToSwizzled.cpp in Sources */,
4915
				5C55D6C522826BC800B5BA2C /* RewriteRepeatedAssignToSwizzled.cpp in Sources */,
4364
				A3D3291423CFCB7700375657 /* RewriteRowMajorMatrices.cpp in Sources */,
4916
				A3D3291423CFCB7700375657 /* RewriteRowMajorMatrices.cpp in Sources */,
4365
				5C55D6C622826BC800B5BA2C /* RewriteStructSamplers.cpp in Sources */,
4917
				5C55D6C622826BC800B5BA2C /* RewriteStructSamplers.cpp in Sources */,
4366
				31CD00CC249196A500486F27 /* RewriteStructSamplersOld.cpp in Sources */,
4918
				31CD00CC249196A500486F27 /* RewriteStructSamplersOld.cpp in Sources */,
4367
				5C55D6C722826BC800B5BA2C /* RewriteTexelFetchOffset.cpp in Sources */,
4919
				5C55D6C722826BC800B5BA2C /* RewriteTexelFetchOffset.cpp in Sources */,
4920
				FF81FF802581919800894E24 /* RewriteUnaddressableReferences.cpp in Sources */,
4368
				5C55D6C822826BC800B5BA2C /* RewriteUnaryMinusOperatorFloat.cpp in Sources */,
4921
				5C55D6C822826BC800B5BA2C /* RewriteUnaryMinusOperatorFloat.cpp in Sources */,
4369
				5C55D6C922826BC800B5BA2C /* RewriteUnaryMinusOperatorInt.cpp in Sources */,
4922
				5C55D6C922826BC800B5BA2C /* RewriteUnaryMinusOperatorInt.cpp in Sources */,
4370
				5C55D6FC22826CB300B5BA2C /* RunAtTheEndOfShader.cpp in Sources */,
4923
				5C55D6FC22826CB300B5BA2C /* RunAtTheEndOfShader.cpp in Sources */,
4371
				5C1DBF271B0438D300235552 /* Sampler.cpp in Sources */,
4924
				5C1DBF271B0438D300235552 /* Sampler.cpp in Sources */,
4372
				5CB301391DE39F1A00D2C405 /* SamplerGL.cpp in Sources */,
4925
				5CB301391DE39F1A00D2C405 /* SamplerGL.cpp in Sources */,
4926
				FF81FEF725818D6900894E24 /* SamplerMtl.mm in Sources */,
4373
				5C55D6CA22826BC800B5BA2C /* ScalarizeVecAndMatConstructorArgs.cpp in Sources */,
4927
				5C55D6CA22826BC800B5BA2C /* ScalarizeVecAndMatConstructorArgs.cpp in Sources */,
4374
				A30307282305F7C4002DA972 /* Semaphore.cpp in Sources */,
4928
				A30307282305F7C4002DA972 /* Semaphore.cpp in Sources */,
4375
				A303078A2305F8F0002DA972 /* SemaphoreGL.cpp in Sources */,
4929
				A303078A2305F8F0002DA972 /* SemaphoreGL.cpp in Sources */,
4376
				5C55D6CB22826BC800B5BA2C /* SeparateArrayConstructorStatements.cpp in Sources */,
4930
				5C55D6CB22826BC800B5BA2C /* SeparateArrayConstructorStatements.cpp in Sources */,
4377
				5C55D6CC22826BC800B5BA2C /* SeparateArrayInitialization.cpp in Sources */,
4931
				5C55D6CC22826BC800B5BA2C /* SeparateArrayInitialization.cpp in Sources */,
4932
				FF81FF8F2581919800894E24 /* SeparateCompoundExpressions.cpp in Sources */,
4933
				FF81FF5F2581919700894E24 /* SeparateCompoundStructDeclarations.cpp in Sources */,
4378
				5C55D6CD22826BC800B5BA2C /* SeparateDeclarations.cpp in Sources */,
4934
				5C55D6CD22826BC800B5BA2C /* SeparateDeclarations.cpp in Sources */,
4379
				5C55D6CE22826BC800B5BA2C /* SeparateExpressionsReturningArrays.cpp in Sources */,
4935
				5C55D6CE22826BC800B5BA2C /* SeparateExpressionsReturningArrays.cpp in Sources */,
4380
				5CCD59842284FBE70018F2D8 /* sha1.cc in Sources */,
4936
				5CCD59842284FBE70018F2D8 /* sha1.cc in Sources */,
Lines 4382-4387 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec52
4382
				5CB3013B1DE39F1A00D2C405 /* ShaderGL.cpp in Sources */,
4938
				5CB3013B1DE39F1A00D2C405 /* ShaderGL.cpp in Sources */,
4383
				5CCD59812284FB900018F2D8 /* ShaderImpl.cpp in Sources */,
4939
				5CCD59812284FB900018F2D8 /* ShaderImpl.cpp in Sources */,
4384
				31012E6218B97B9B0039062F /* ShaderLang.cpp in Sources */,
4940
				31012E6218B97B9B0039062F /* ShaderLang.cpp in Sources */,
4941
				FF81FF1225818D6A00894E24 /* ShaderMtl.mm in Sources */,
4385
				5C1DBC411B04375F00235552 /* ShaderVars.cpp in Sources */,
4942
				5C1DBC411B04375F00235552 /* ShaderVars.cpp in Sources */,
4386
				5C55D6CF22826BC800B5BA2C /* SimplifyLoopConditions.cpp in Sources */,
4943
				5C55D6CF22826BC800B5BA2C /* SimplifyLoopConditions.cpp in Sources */,
4387
				5C55D6D022826BC800B5BA2C /* SplitSequenceOperator.cpp in Sources */,
4944
				5C55D6D022826BC800B5BA2C /* SplitSequenceOperator.cpp in Sources */,
Lines 4393-4403 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec53
4393
				5C1DBF2E1B0438D300235552 /* Surface.cpp in Sources */,
4950
				5C1DBF2E1B0438D300235552 /* Surface.cpp in Sources */,
4394
				5CB3013F1DE39F1A00D2C405 /* SurfaceGL.cpp in Sources */,
4951
				5CB3013F1DE39F1A00D2C405 /* SurfaceGL.cpp in Sources */,
4395
				5CB304FC1DE4164800D2C405 /* SurfaceImpl.cpp in Sources */,
4952
				5CB304FC1DE4164800D2C405 /* SurfaceImpl.cpp in Sources */,
4953
				FF81FEE325818D6900894E24 /* SurfaceMtl.mm in Sources */,
4396
				5C55D6E322826C7900B5BA2C /* Symbol.cpp in Sources */,
4954
				5C55D6E322826C7900B5BA2C /* Symbol.cpp in Sources */,
4955
				FF81FF6A2581919800894E24 /* SymbolEnv.cpp in Sources */,
4397
				31012E6418B97B9B0039062F /* SymbolTable.cpp in Sources */,
4956
				31012E6418B97B9B0039062F /* SymbolTable.cpp in Sources */,
4398
				5C55D70E2282741400B5BA2C /* SymbolTable_autogen.cpp in Sources */,
4957
				5C55D70E2282741400B5BA2C /* SymbolTable_autogen.cpp in Sources */,
4399
				315EBDAE1FCE443600AC7A89 /* SymbolUniqueId.cpp in Sources */,
4958
				315EBDAE1FCE443600AC7A89 /* SymbolUniqueId.cpp in Sources */,
4400
				315EBDC01FCE44BF00AC7A89 /* SyncGL.cpp in Sources */,
4959
				315EBDC01FCE44BF00AC7A89 /* SyncGL.cpp in Sources */,
4960
				FF81FED325818D6800894E24 /* SyncMtl.mm in Sources */,
4401
				A3C49C21255DF973005E8DF7 /* system_utils.cpp in Sources */,
4961
				A3C49C21255DF973005E8DF7 /* system_utils.cpp in Sources */,
4402
				31A331C61EA5ED5F00FD2203 /* system_utils_mac.cpp in Sources */,
4962
				31A331C61EA5ED5F00FD2203 /* system_utils_mac.cpp in Sources */,
4403
				5C55D7302282747700B5BA2C /* system_utils_posix.cpp in Sources */,
4963
				5C55D7302282747700B5BA2C /* system_utils_posix.cpp in Sources */,
Lines 4409-4421 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec54
4409
				315EBD991FCE443600AC7A89 /* TextureFunctionHLSL.cpp in Sources */,
4969
				315EBD991FCE443600AC7A89 /* TextureFunctionHLSL.cpp in Sources */,
4410
				5CB301411DE39F1A00D2C405 /* TextureGL.cpp in Sources */,
4970
				5CB301411DE39F1A00D2C405 /* TextureGL.cpp in Sources */,
4411
				5CB304FF1DE4164800D2C405 /* TextureImpl.cpp in Sources */,
4971
				5CB304FF1DE4164800D2C405 /* TextureImpl.cpp in Sources */,
4972
				FF81FEF525818D6900894E24 /* TextureMtl.mm in Sources */,
4412
				315EBDF21FCE452D00AC7A89 /* Thread.cpp in Sources */,
4973
				315EBDF21FCE452D00AC7A89 /* Thread.cpp in Sources */,
4413
				5C1DBBF61B0436EC00235552 /* tls.cpp in Sources */,
4974
				5C1DBBF61B0436EC00235552 /* tls.cpp in Sources */,
4414
				A264F8C116974DED006FAA5A /* Token.cpp in Sources */,
4975
				A264F8C116974DED006FAA5A /* Token.cpp in Sources */,
4976
				FF81FF6D2581919800894E24 /* ToposortStructs.cpp in Sources */,
4415
				5C1DBF331B0438D300235552 /* TransformFeedback.cpp in Sources */,
4977
				5C1DBF331B0438D300235552 /* TransformFeedback.cpp in Sources */,
4416
				5CB301431DE39F1A00D2C405 /* TransformFeedbackGL.cpp in Sources */,
4978
				5CB301431DE39F1A00D2C405 /* TransformFeedbackGL.cpp in Sources */,
4979
				FF81FEF325818D6900894E24 /* TransformFeedbackMtl.mm in Sources */,
4417
				31012E6A18B97B9B0039062F /* TranslatorESSL.cpp in Sources */,
4980
				31012E6A18B97B9B0039062F /* TranslatorESSL.cpp in Sources */,
4418
				31012E6C18B97B9B0039062F /* TranslatorGLSL.cpp in Sources */,
4981
				31012E6C18B97B9B0039062F /* TranslatorGLSL.cpp in Sources */,
4982
				FF81FF1C258190CA00894E24 /* TranslatorMetalDirect.cpp in Sources */,
4983
				FF81FF1E258190CA00894E24 /* TranslatorMetalUtils.cpp in Sources */,
4419
				315EBD781FCE443600AC7A89 /* TranslatorVulkan.cpp in Sources */,
4984
				315EBD781FCE443600AC7A89 /* TranslatorVulkan.cpp in Sources */,
4420
				5C1DBC441B04375F00235552 /* Types.cpp in Sources */,
4985
				5C1DBC441B04375F00235552 /* Types.cpp in Sources */,
4421
				5C55D6D122826BC800B5BA2C /* UnfoldShortCircuitAST.cpp in Sources */,
4986
				5C55D6D122826BC800B5BA2C /* UnfoldShortCircuitAST.cpp in Sources */,
Lines 4466-4475 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec55
4466
				31012E7F18B97B9B0039062F /* VersionGLSL.cpp in Sources */,
5031
				31012E7F18B97B9B0039062F /* VersionGLSL.cpp in Sources */,
4467
				5C1DBF3F1B0438D300235552 /* VertexArray.cpp in Sources */,
5032
				5C1DBF3F1B0438D300235552 /* VertexArray.cpp in Sources */,
4468
				5CB301451DE39F1A00D2C405 /* VertexArrayGL.cpp in Sources */,
5033
				5CB301451DE39F1A00D2C405 /* VertexArrayGL.cpp in Sources */,
5034
				FF81FEE925818D6900894E24 /* VertexArrayMtl.mm in Sources */,
4469
				5C1DBF411B0438D300235552 /* VertexAttribute.cpp in Sources */,
5035
				5C1DBF411B0438D300235552 /* VertexAttribute.cpp in Sources */,
5036
				FF81FFA02581AD0400894E24 /* visibility.metal in Sources */,
4470
				A31B6184230B747F001610D7 /* WindowSurfaceCGL.mm in Sources */,
5037
				A31B6184230B747F001610D7 /* WindowSurfaceCGL.mm in Sources */,
4471
				31B15723236B82BB00CAA4FD /* WindowSurfaceEAGL.mm in Sources */,
5038
				31B15723236B82BB00CAA4FD /* WindowSurfaceEAGL.mm in Sources */,
4472
				315EBDE71FCE452D00AC7A89 /* WorkerThread.cpp in Sources */,
5039
				315EBDE71FCE452D00AC7A89 /* WorkerThread.cpp in Sources */,
5040
				FF81FF872581919800894E24 /* WrapMain.cpp in Sources */,
4473
				5C55D6D522826BC800B5BA2C /* WrapSwitchStatementsInBlocks.cpp in Sources */,
5041
				5C55D6D522826BC800B5BA2C /* WrapSwitchStatementsInBlocks.cpp in Sources */,
4474
				5CCD59502284ECD10018F2D8 /* xxhash.c in Sources */,
5042
				5CCD59502284ECD10018F2D8 /* xxhash.c in Sources */,
4475
			);
5043
			);
Lines 4552-4557 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec56
4552
			isa = XCBuildConfiguration;
5120
			isa = XCBuildConfiguration;
4553
			baseConfigurationReference = 31CDFDEF24917F8900486F27 /* ANGLE-static.xcconfig */;
5121
			baseConfigurationReference = 31CDFDEF24917F8900486F27 /* ANGLE-static.xcconfig */;
4554
			buildSettings = {
5122
			buildSettings = {
5123
				GCC_PREPROCESSOR_DEFINITIONS = (
5124
					"$(DEBUG_DEFINES)",
5125
					LIBGLESV2_IMPLEMENTATION,
5126
					LIBANGLE_IMPLEMENTATION,
5127
					ANGLE_ENABLE_OPENGL,
5128
					ANGLE_ENABLE_GLSL,
5129
					ANGLE_ENABLE_ESSL,
5130
					GL_SILENCE_DEPRECATION,
5131
					GLES_SILENCE_DEPRECATION,
5132
					ANGLE_ENABLE_METAL,
5133
				);
4555
			};
5134
			};
4556
			name = Production;
5135
			name = Production;
4557
		};
5136
		};
Lines 4574-4579 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec57
4574
			isa = XCBuildConfiguration;
5153
			isa = XCBuildConfiguration;
4575
			baseConfigurationReference = 31CDFDEF24917F8900486F27 /* ANGLE-static.xcconfig */;
5154
			baseConfigurationReference = 31CDFDEF24917F8900486F27 /* ANGLE-static.xcconfig */;
4576
			buildSettings = {
5155
			buildSettings = {
5156
				GCC_PREPROCESSOR_DEFINITIONS = (
5157
					"$(DEBUG_DEFINES)",
5158
					LIBGLESV2_IMPLEMENTATION,
5159
					LIBANGLE_IMPLEMENTATION,
5160
					ANGLE_ENABLE_OPENGL,
5161
					ANGLE_ENABLE_GLSL,
5162
					ANGLE_ENABLE_ESSL,
5163
					GL_SILENCE_DEPRECATION,
5164
					GLES_SILENCE_DEPRECATION,
5165
					ANGLE_ENABLE_METAL,
5166
				);
4577
			};
5167
			};
4578
			name = Debug;
5168
			name = Debug;
4579
		};
5169
		};
Lines 4581-4586 a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj_sec58
4581
			isa = XCBuildConfiguration;
5171
			isa = XCBuildConfiguration;
4582
			baseConfigurationReference = 31CDFDEF24917F8900486F27 /* ANGLE-static.xcconfig */;
5172
			baseConfigurationReference = 31CDFDEF24917F8900486F27 /* ANGLE-static.xcconfig */;
4583
			buildSettings = {
5173
			buildSettings = {
5174
				GCC_PREPROCESSOR_DEFINITIONS = (
5175
					"$(DEBUG_DEFINES)",
5176
					LIBGLESV2_IMPLEMENTATION,
5177
					LIBANGLE_IMPLEMENTATION,
5178
					ANGLE_ENABLE_OPENGL,
5179
					ANGLE_ENABLE_GLSL,
5180
					ANGLE_ENABLE_ESSL,
5181
					GL_SILENCE_DEPRECATION,
5182
					GLES_SILENCE_DEPRECATION,
5183
					ANGLE_ENABLE_METAL,
5184
				);
4584
			};
5185
			};
4585
			name = Release;
5186
			name = Release;
4586
		};
5187
		};
- a/Source/ThirdParty/ANGLE/Configurations/ANGLE-dynamic.xcconfig -1 / +1 lines
Lines 4-10 a/Source/ThirdParty/ANGLE/Configurations/ANGLE-dynamic.xcconfig_sec1
4
PRODUCT_NAME = ANGLE-shared;
4
PRODUCT_NAME = ANGLE-shared;
5
EXECUTABLE_PREFIX = lib;
5
EXECUTABLE_PREFIX = lib;
6
6
7
ANGLE_OTHER_LDFLAGS = -allowable_client WebCore -allowable_client WebCoreTestSupport -framework QuartzCore -framework CoreGraphics -framework Foundation -framework IOSurface $(ANGLE_OTHER_LDFLAGS_$(WK_PLATFORM_NAME)) $(ANGLE_STATIC_LIB_OTHER_LDFLAGS);
7
ANGLE_OTHER_LDFLAGS = -allowable_client WebCore -allowable_client WebCoreTestSupport -framework QuartzCore -framework CoreGraphics -framework Foundation -framework IOSurface -framework Metal $(ANGLE_OTHER_LDFLAGS_$(WK_PLATFORM_NAME)) $(ANGLE_STATIC_LIB_OTHER_LDFLAGS);
8
ANGLE_OTHER_LDFLAGS_iphoneos = -lz;
8
ANGLE_OTHER_LDFLAGS_iphoneos = -lz;
9
ANGLE_OTHER_LDFLAGS_iphonesimulator = $(ANGLE_OTHER_LDFLAGS_iphoneos);
9
ANGLE_OTHER_LDFLAGS_iphonesimulator = $(ANGLE_OTHER_LDFLAGS_iphoneos);
10
ANGLE_OTHER_LDFLAGS_watchos = $(ANGLE_OTHER_LDFLAGS_iphoneos);
10
ANGLE_OTHER_LDFLAGS_watchos = $(ANGLE_OTHER_LDFLAGS_iphoneos);
- a/Source/ThirdParty/ANGLE/changes.diff -257 / +35062 lines
Lines 10-15 index 6d9040a..c8c9b6c 100644 a/Source/ThirdParty/ANGLE/changes.diff_sec1
10
 /tools/clang
10
 /tools/clang
11
 /tools/flex-bison/linux/bison
11
 /tools/flex-bison/linux/bison
12
 /tools/flex-bison/linux/flex
12
 /tools/flex-bison/linux/flex
13
diff --git a/include/GLSLANG/ShaderLang.h b/include/GLSLANG/ShaderLang.h
14
index e10d112..6f6a72b 100644
15
--- a/include/GLSLANG/ShaderLang.h
16
+++ b/include/GLSLANG/ShaderLang.h
17
@@ -73,6 +73,9 @@ enum ShShaderOutput
18
     // Output specialized GLSL to be fed to glslang for Vulkan SPIR to be cross compiled to Metal
19
     // later.
20
     SH_GLSL_METAL_OUTPUT = 0x8B4C,
21
+
22
+    // Output for MSL
23
+    SH_MSL_METAL_OUTPUT = 0x8B4D,
24
 };
25
 
26
 // Compile options.
27
diff --git a/include/platform/FeaturesMtl.h b/include/platform/FeaturesMtl.h
28
index fe5e8ab..9a0bee0 100644
29
--- a/include/platform/FeaturesMtl.h
30
+++ b/include/platform/FeaturesMtl.h
31
@@ -27,7 +27,7 @@ struct FeaturesMtl : FeatureSetBase
32
         "The renderer supports depth texture's filtering other than nearest", &members};
33
 
34
     // Support explicit memory barrier
35
-    Feature hasExplicitMemBarrier = {"has_explicit_mem_barrier_mtl", FeatureCategory::MetalFeatures,
36
+    Feature hasExplicitMemBarrier = {"has_explicit_mem_barrier", FeatureCategory::MetalFeatures,
37
                                      "The renderer supports explicit memory barrier", &members};
38
 
39
     // Some renderer can break render pass cheaply, i.e. desktop class GPUs.
40
@@ -40,7 +40,7 @@ struct FeaturesMtl : FeatureSetBase
41
         "The renderer supports non uniform compute shader dispatch's group size", &members};
42
 
43
     // fragment stencil output support
44
-    Feature hasStencilOutput = {"has_shader_stencil_output", FeatureCategory::MetalFeatures,
45
+    Feature hasStencilOutput = {"has_stencil_output", FeatureCategory::MetalFeatures,
46
                                 "The renderer supports stencil output from fragment shader",
47
                                 &members};
48
 
49
@@ -59,6 +59,10 @@ struct FeaturesMtl : FeatureSetBase
50
     Feature hasEvents = {"has_mtl_events", FeatureCategory::MetalFeatures,
51
                          "The renderer supports MTL(Shared)Event", &members};
52
 
53
+    Feature allowInlineConstVertexData = {
54
+        "allow_inline_const_vertex_data", FeatureCategory::MetalFeatures,
55
+        "The renderer supports using inline constant data for small client vertex data", &members};
56
+
57
     // On macos, separate depth & stencil buffers are not supproted. However, on iOS devices,
58
     // they are supproted:
59
     Feature allowSeparatedDepthStencilBuffers = {
60
@@ -67,6 +71,21 @@ struct FeaturesMtl : FeatureSetBase
61
         "whereas others such as macOS don't",
62
         &members};
63
 
64
+    Feature allowRuntimeSamplerCompareMode = {
65
+        "allow_runtime_sampler_compare_mode", FeatureCategory::MetalFeatures,
66
+        "The renderer supports changing sampler's compare mode outside shaders", &members};
67
+
68
+    Feature allowSamplerCompareGradient = {
69
+        "allow_sampler_compare_gradient", FeatureCategory::MetalFeatures,
70
+        "The renderer supports sample_compare with gradients", &members};
71
+
72
+    Feature allowSamplerCompareLod = {"allow_sampler_compare_lod", FeatureCategory::MetalFeatures,
73
+                                      "The renderer supports sample_compare with lod", &members};
74
+
75
+    Feature allowBufferReadWrite = {"allow_buffer_read_write", FeatureCategory::MetalFeatures,
76
+                                    "The renderer supports buffer read & write in the same shader",
77
+                                    &members};
78
+
79
     Feature allowMultisampleStoreAndResolve = {
80
         "allow_msaa_store_and_resolve", FeatureCategory::MetalFeatures,
81
         "The renderer supports MSAA store and resolve in the same pass", &members};
82
@@ -75,14 +94,27 @@ struct FeaturesMtl : FeatureSetBase
83
         "gen_multiple_mips_per_pass", FeatureCategory::MetalFeatures,
84
         "The renderer supports generating multiple mipmaps per pass", &members};
85
 
86
+    Feature forceD24S8AsUnsupported = {"force_d24s8_as_unsupported", FeatureCategory::MetalFeatures,
87
+                                       "Force Depth24Stencil8 format as unsupported.", &members};
88
+
89
+    Feature breakRenderPassIsCheap = {"break_render_pass_is_cheap", FeatureCategory::MetalFeatures,
90
+                                      "Breaking render pass is a cheap operation", &members};
91
+
92
     Feature forceBufferGPUStorage = {
93
-        "force_buffer_gpu_storage_mtl", FeatureCategory::MetalFeatures,
94
-        "On systems that support both buffer's memory allocation on GPU and shared memory (such as "
95
-        "macOS), force using GPU memory allocation for buffers.",
96
+        "force_buffer_gpu_storage", FeatureCategory::MetalFeatures,
97
+        "On systems that support both buffer' memory allocation on GPU and shared memory (such as "
98
+        "macOS), force using GPU memory allocation for buffers everytime or not.",
99
         &members};
100
 
101
-    Feature forceD24S8AsUnsupported = {"force_d24s8_as_unsupported", FeatureCategory::MetalFeatures,
102
-                                       "Force Depth24Stencil8 format as unsupported.", &members};
103
+    Feature forceNonCSBaseMipmapGeneration = {
104
+        "force_non_cs_mipmap_gen", FeatureCategory::MetalFeatures,
105
+        "Turn this feature on to disallow Compute Shader based mipmap generation. Compute Shader "
106
+        "based mipmap generation might cause GPU hang on some older iOS devices.",
107
+        &members};
108
+
109
+    Feature emulateTransformFeedback = {
110
+        "emulate_transform_feedback", FeatureCategory::MetalFeatures,
111
+        "Turn this on to allow transform feedback in Metal using a 2-pass VS for GLES3.", &members};
112
 };
113
 
114
 }  // namespace angle
115
diff --git a/src/common/PoolAlloc.cpp b/src/common/PoolAlloc.cpp
116
index 27dd930..3bdcc30 100644
117
--- a/src/common/PoolAlloc.cpp
118
+++ b/src/common/PoolAlloc.cpp
119
@@ -335,7 +335,7 @@ void PoolAllocator::unlock()
120
 void Allocation::checkAllocList() const
121
 {
122
     for (const Allocation *alloc = this; alloc != 0; alloc = alloc->mPrevAlloc)
123
-        alloc->check();
124
+        alloc->checkAlloc();
125
 }
126
 
127
 }  // namespace angle
128
diff --git a/src/common/PoolAlloc.h b/src/common/PoolAlloc.h
129
index 692992c..cd266a0 100644
130
--- a/src/common/PoolAlloc.h
131
+++ b/src/common/PoolAlloc.h
132
@@ -65,7 +65,7 @@ class Allocation
133
 #endif
134
     }
135
 
136
-    void check() const
137
+    void checkAlloc() const
138
     {
139
         checkGuardBlock(preGuard(), kGuardBlockBeginVal, "before");
140
         checkGuardBlock(postGuard(), kGuardBlockEndVal, "after");
141
diff --git a/src/common/apple_platform_utils.h b/src/common/apple_platform_utils.h
142
index 55ebb7a..83ab532 100644
143
--- a/src/common/apple_platform_utils.h
144
+++ b/src/common/apple_platform_utils.h
145
@@ -15,24 +15,32 @@
146
 
147
 // TARGET_OS_MACCATALYST only available in MacSDK 10.15
148
 
149
+#if TARGET_OS_MACCATALYST
150
 // ANGLE_APPLE_AVAILABLE_XCI: check if either of the 3 platforms (OSX/Catalyst/iOS) min verions is
151
 // available:
152
-#if TARGET_OS_MACCATALYST
153
 #    define ANGLE_APPLE_AVAILABLE_XCI(macVer, macCatalystVer, iOSVer) \
154
         @available(macOS macVer, macCatalyst macCatalystVer, iOS iOSVer, *)
155
 // ANGLE_APPLE_AVAILABLE_XC: check if either of the 2 platforms (OSX/Catalyst) min verions is
156
 // available:
157
 #    define ANGLE_APPLE_AVAILABLE_XC(macVer, macCatalystVer) \
158
         @available(macOS macVer, macCatalyst macCatalystVer, *)
159
+// ANGLE_APPLE_AVAILABLE_CI: check if either of the 2 platforms (Catalyst/iOS) min verions is
160
+// available:
161
+#    define ANGLE_APPLE_AVAILABLE_CI(macCatalystVer, iOSVer) \
162
+        @available(macCatalyst macCatalystVer, iOS iOSVer, *)
163
 #else
164
 #    define ANGLE_APPLE_AVAILABLE_XCI(macVer, macCatalystVer, iOSVer) \
165
         ANGLE_APPLE_AVAILABLE_XI(macVer, iOSVer)
166
-// ANGLE_APPLE_AVAILABLE_XC: check if either of the 2 platforms (OSX/Catalyst) min verions is
167
-// available:
168
+
169
 #    define ANGLE_APPLE_AVAILABLE_XC(macVer, macCatalystVer) @available(macOS macVer, *)
170
+#    define ANGLE_APPLE_AVAILABLE_CI(macCatalystVer, iOSVer) @available(iOS iOSVer, tvOS iOSVer, *)
171
 #endif
172
 
173
 // ANGLE_APPLE_AVAILABLE_XI: check if either of the 2 platforms (OSX/iOS) min verions is available:
174
-#define ANGLE_APPLE_AVAILABLE_XI(macVer, iOSVer) @available(macOS macVer, iOS iOSVer, *)
175
+#define ANGLE_APPLE_AVAILABLE_XI(macVer, iOSVer) \
176
+    @available(macOS macVer, iOS iOSVer, tvOS iOSVer, *)
177
+
178
+// ANGLE_APPLE_AVAILABLE_I: check if a particular iOS version is available
179
+#define ANGLE_APPLE_AVAILABLE_I(iOSVer) @available(iOS iOSVer, tvOS iOSVer, *)
180
 
181
 #endif
182
diff --git a/src/common/debug.h b/src/common/debug.h
183
index e0037a4..28170a5 100644
184
--- a/src/common/debug.h
185
+++ b/src/common/debug.h
186
@@ -314,9 +314,15 @@ std::ostream &FmtHex(std::ostream &os, T value)
187
 // A macro asserting a condition and outputting failures to the debug log
188
 #if defined(ANGLE_ENABLE_ASSERTS)
189
 #    define ASSERT(expression)                                                  \
190
-        (expression ? static_cast<void>(0)                                                    \
191
-                    : (FATAL() << "\t! Assert failed in " << __FUNCTION__ << " (" << __FILE__ \
192
-                               << ":" << __LINE__ << "): " << #expression))
193
+        do                                                                      \
194
+        {                                                                       \
195
+            if (!(expression))                                                  \
196
+            {                                                                   \
197
+                __builtin_debugtrap();                                          \
198
+            }                                                                   \
199
+            int x = 0; /* This forces sane breakpoint location at call site. */ \
200
+            (void)x;                                                            \
201
+        } while (false)
202
 #else
203
 #    define ASSERT(condition) ANGLE_EAT_STREAM_PARAMETERS << !(condition)
204
 #endif  // defined(ANGLE_ENABLE_ASSERTS)
13
diff --git a/src/common/gl/cgl/FunctionsCGL.cpp b/src/common/gl/cgl/FunctionsCGL.cpp
205
diff --git a/src/common/gl/cgl/FunctionsCGL.cpp b/src/common/gl/cgl/FunctionsCGL.cpp
14
index b57f42b..3e5a37a 100644
206
index b57f42b..3e5a37a 100644
15
--- a/src/common/gl/cgl/FunctionsCGL.cpp
207
--- a/src/common/gl/cgl/FunctionsCGL.cpp
Lines 34-55 index 9112659..39df6fe 100644 a/Source/ThirdParty/ANGLE/changes.diff_sec2
34
 SOFT_LINK_FUNCTION_HEADER(OpenGL, CGLSetCurrentContext, CGLError, (CGLContextObj ctx), (ctx))
226
 SOFT_LINK_FUNCTION_HEADER(OpenGL, CGLSetCurrentContext, CGLError, (CGLContextObj ctx), (ctx))
35
 SOFT_LINK_FUNCTION_HEADER(OpenGL,
227
 SOFT_LINK_FUNCTION_HEADER(OpenGL,
36
                           CGLSetVirtualScreen,
228
                           CGLSetVirtualScreen,
229
diff --git a/src/common/system_utils_ios.mm b/src/common/system_utils_ios.mm
230
new file mode 100644
231
index 0000000..a36bea4
232
--- /dev/null
233
+++ b/src/common/system_utils_ios.mm
234
@@ -0,0 +1,53 @@
235
+//
236
+// Copyright 2015 The ANGLE Project Authors. All rights reserved.
237
+// Use of this source code is governed by a BSD-style license that can be
238
+// found in the LICENSE file.
239
+//
240
+
241
+// system_utils_ios.mm: Implementation of iOS-specific functions for OSX
242
+
243
+#include "system_utils.h"
244
+
245
+#include <unistd.h>
246
+
247
+#include <CoreServices/CoreServices.h>
248
+#include <mach-o/dyld.h>
249
+#include <mach/mach.h>
250
+#include <mach/mach_time.h>
251
+#include <array>
252
+#include <cstdlib>
253
+#include <vector>
254
+
255
+#import <Foundation/Foundation.h>
256
+
257
+namespace angle
258
+{
259
+std::string GetExecutablePath()
260
+{
261
+
262
+    NSString *executableString = [[NSBundle mainBundle] executablePath];
263
+    std::string result([executableString UTF8String]);
264
+    return result;
265
+}
266
+
267
+std::string GetExecutableDirectory()
268
+{
269
+    std::string executablePath = GetExecutablePath();
270
+    size_t lastPathSepLoc      = executablePath.find_last_of("/");
271
+    return (lastPathSepLoc != std::string::npos) ? executablePath.substr(0, lastPathSepLoc) : "";
272
+}
273
+
274
+const char *GetSharedLibraryExtension()
275
+{
276
+    return "dylib";
277
+}
278
+
279
+double GetCurrentTime()
280
+{
281
+    mach_timebase_info_data_t timebaseInfo;
282
+    mach_timebase_info(&timebaseInfo);
283
+
284
+    double secondCoeff = timebaseInfo.numer * 1e-9 / timebaseInfo.denom;
285
+    return secondCoeff * mach_absolute_time();
286
+}
287
+}  // namespace angle
37
diff --git a/src/common/utilities.cpp b/src/common/utilities.cpp
288
diff --git a/src/common/utilities.cpp b/src/common/utilities.cpp
38
index c953ff9..63b3a59 100644
289
index c953ff9..d09e270 100644
39
--- a/src/common/utilities.cpp
290
--- a/src/common/utilities.cpp
40
+++ b/src/common/utilities.cpp
291
+++ b/src/common/utilities.cpp
41
@@ -6,6 +6,11 @@
292
@@ -471,6 +471,50 @@ int VariableColumnCount(GLenum type)
42
 
43
 // utilities.cpp: Conversion functions and other utility routines.
44
 
293
 
45
+// Older clang versions have a false positive on this warning here.
294
     return 0;
46
+#if defined(__clang__)
295
 }
47
+#pragma clang diagnostic ignored "-Wglobal-constructors"
296
+/**
48
+#endif
297
+Determine the number of attribute slots used by a variable type
298
+*/
299
+int VariableAttributeCount(GLenum type)
300
+{
301
+    switch (type)
302
+    {
303
+        case GL_NONE:
304
+            return 0;
305
+        case GL_BOOL:
306
+        case GL_FLOAT:
307
+        case GL_INT:
308
+        case GL_UNSIGNED_INT:
309
+        case GL_BOOL_VEC2:
310
+        case GL_FLOAT_VEC2:
311
+        case GL_INT_VEC2:
312
+        case GL_UNSIGNED_INT_VEC2:
313
+        case GL_BOOL_VEC3:
314
+        case GL_FLOAT_VEC3:
315
+        case GL_INT_VEC3:
316
+        case GL_UNSIGNED_INT_VEC3:
317
+        case GL_BOOL_VEC4:
318
+        case GL_FLOAT_VEC4:
319
+        case GL_INT_VEC4:
320
+        case GL_UNSIGNED_INT_VEC4:
321
+            return 1;
322
+        case GL_FLOAT_MAT2:
323
+        case GL_FLOAT_MAT2x3:
324
+        case GL_FLOAT_MAT2x4:
325
+            return 2;
326
+        case GL_FLOAT_MAT3:
327
+        case GL_FLOAT_MAT3x2:
328
+        case GL_FLOAT_MAT3x4:
329
+            return 3;
330
+        case GL_FLOAT_MAT4:
331
+        case GL_FLOAT_MAT4x2:
332
+        case GL_FLOAT_MAT4x3:
333
+            return 4;
334
+        default:
335
+            UNREACHABLE();
336
+    }
49
+
337
+
50
 #include "common/utilities.h"
338
+    return 0;
51
 #include "GLES3/gl3.h"
339
+}
52
 #include "common/mathutil.h"
340
 
341
 bool IsSamplerType(GLenum type)
342
 {
343
diff --git a/src/common/utilities.h b/src/common/utilities.h
344
index 0c7d811..ba693a2 100644
345
--- a/src/common/utilities.h
346
+++ b/src/common/utilities.h
347
@@ -37,6 +37,7 @@ size_t VariableInternalSize(GLenum type);
348
 size_t VariableExternalSize(GLenum type);
349
 int VariableRowCount(GLenum type);
350
 int VariableColumnCount(GLenum type);
351
+int VariableAttributeCount(GLenum type);
352
 bool IsSamplerType(GLenum type);
353
 bool IsSamplerCubeType(GLenum type);
354
 bool IsImageType(GLenum type);
53
diff --git a/src/compiler/preprocessor/preprocessor_tab_autogen.cpp b/src/compiler/preprocessor/preprocessor_tab_autogen.cpp
355
diff --git a/src/compiler/preprocessor/preprocessor_tab_autogen.cpp b/src/compiler/preprocessor/preprocessor_tab_autogen.cpp
54
index 4711774..cf25e48 100644
356
index 4711774..cf25e48 100644
55
--- a/src/compiler/preprocessor/preprocessor_tab_autogen.cpp
357
--- a/src/compiler/preprocessor/preprocessor_tab_autogen.cpp
Lines 62-299 index 4711774..cf25e48 100644 a/Source/ThirdParty/ANGLE/changes.diff_sec3
62
 /* Bison implementation for Yacc-like parsers in C
364
 /* Bison implementation for Yacc-like parsers in C
63
 
365
 
64
    Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2019 Free Software Foundation,
366
    Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2019 Free Software Foundation,
65
diff --git a/src/compiler/translator/glslang_tab_autogen.cpp b/src/compiler/translator/glslang_tab_autogen.cpp
367
diff --git a/src/compiler/translator/CodeGen.cpp b/src/compiler/translator/CodeGen.cpp
66
index 130b98a..33b83db 100644
368
index a444499..cac9f49 100644
67
--- a/src/compiler/translator/glslang_tab_autogen.cpp
369
--- a/src/compiler/translator/CodeGen.cpp
68
+++ b/src/compiler/translator/glslang_tab_autogen.cpp
370
+++ b/src/compiler/translator/CodeGen.cpp
69
@@ -1,5 +1,7 @@
371
@@ -21,8 +21,11 @@
70
 /* A Bison parser, made by GNU Bison 3.3.2.  */
372
 #endif  // ANGLE_ENABLE_VULKAN
71
 
373
 
72
+/* Apple Note: For the avoidance of doubt, Apple elects to distribute this file under the terms of the BSD license. */
374
 #ifdef ANGLE_ENABLE_METAL
375
-#    include "compiler/translator/TranslatorMetal.h"
376
+#    include "compiler/translator/TranslatorMetalDirect.h"
377
 #endif  // ANGLE_ENABLE_METAL
378
+#ifdef ANGLE_ENABLE_METAL_SPIRV
379
+#    include "compiler/translator/TranslatorMetal.h"
380
+#endif  // ANGLE_ENABLE_METAL_SPIRV
381
 
382
 #include "compiler/translator/util.h"
383
 
384
@@ -64,11 +67,17 @@ TCompiler *ConstructCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput
385
     }
386
 #endif  // ANGLE_ENABLE_VULKAN
387
 
388
-#ifdef ANGLE_ENABLE_METAL
389
+#ifdef ANGLE_ENABLE_METAL_SPIRV
390
     if (IsOutputMetal(output))
391
     {
392
         return new TranslatorMetal(type, spec);
393
     }
394
+#endif
395
+#ifdef ANGLE_ENABLE_METAL
396
+    if (IsOutputMetalDirect(output))
397
+    {
398
+        return new TranslatorMetalDirect(type, spec, output);
399
+    }
400
 #endif  // ANGLE_ENABLE_METAL
401
 
402
     // Unsupported compiler or unknown format. Return nullptr per the sh::ConstructCompiler API.
403
diff --git a/src/compiler/translator/Common.h b/src/compiler/translator/Common.h
404
index 835c90a..1c09cda 100644
405
--- a/src/compiler/translator/Common.h
406
+++ b/src/compiler/translator/Common.h
407
@@ -31,6 +31,8 @@ struct TSourceLoc
408
     int last_line;
409
 };
410
 
411
+constexpr TSourceLoc kNoSourceLoc{-1, -1, -1, -1};
73
+
412
+
74
 /* Bison implementation for Yacc-like parsers in C
413
 //
414
 // Put POOL_ALLOCATOR_NEW_DELETE in base classes to make them use this scheme.
415
 //
416
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
417
index 34d8e12..9316e2e 100644
418
--- a/src/compiler/translator/Compiler.cpp
419
+++ b/src/compiler/translator/Compiler.cpp
420
@@ -722,7 +722,7 @@ bool TCompiler::checkAndSimplifyAST(TIntermBlock *root,
421
         }
422
     }
75
 
423
 
76
    Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2019 Free Software Foundation,
424
-    int simplifyScalarized = (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS)
77
diff --git a/src/compiler/translator/glslang_tab_autogen.h b/src/compiler/translator/glslang_tab_autogen.h
425
+    unsigned int simplifyScalarized = (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS)
78
index 5306032..0250300 100644
426
                                           ? IntermNodePatternMatcher::kScalarizedVecOrMatConstructor
79
--- a/src/compiler/translator/glslang_tab_autogen.h
427
                                           : 0;
80
+++ b/src/compiler/translator/glslang_tab_autogen.h
81
@@ -1,5 +1,7 @@
82
 /* A Bison parser, made by GNU Bison 3.3.2.  */
83
 
428
 
84
+/* Apple Note: For the avoidance of doubt, Apple elects to distribute this file under the terms of the BSD license. */
429
diff --git a/src/compiler/translator/Compiler.h b/src/compiler/translator/Compiler.h
430
index d0b24ba..043ddd5 100644
431
--- a/src/compiler/translator/Compiler.h
432
+++ b/src/compiler/translator/Compiler.h
433
@@ -35,6 +35,9 @@ class TParseContext;
434
 #ifdef ANGLE_ENABLE_HLSL
435
 class TranslatorHLSL;
436
 #endif  // ANGLE_ENABLE_HLSL
437
+#ifdef ANGLE_ENABLE_METAL
438
+class TranslatorMetalDirect;
439
+#endif  // ANGLE_ENABLE_METAL
440
 
441
 //
442
 // Helper function to check if the shader type is GLSL.
443
@@ -63,6 +66,9 @@ class TShHandleBase
444
 #ifdef ANGLE_ENABLE_HLSL
445
     virtual TranslatorHLSL *getAsTranslatorHLSL() { return 0; }
446
 #endif  // ANGLE_ENABLE_HLSL
447
+#ifdef ANGLE_ENABLE_METAL
448
+    virtual TranslatorMetalDirect *getAsTranslatorMetalDirect() { return nullptr; }
449
+#endif  // ANGLE_ENABLE_METAL
450
 
451
   protected:
452
     // Memory allocator. Allocates and tracks memory required by the compiler.
453
diff --git a/src/compiler/translator/ConstantUnion.cpp b/src/compiler/translator/ConstantUnion.cpp
454
index 0335171..104affb 100644
455
--- a/src/compiler/translator/ConstantUnion.cpp
456
+++ b/src/compiler/translator/ConstantUnion.cpp
457
@@ -67,11 +67,15 @@ bool IsValidShiftOffset(const TConstantUnion &rhs)
458
 
459
 }  // anonymous namespace
460
 
461
-TConstantUnion::TConstantUnion()
462
-{
463
-    iConst = 0;
464
-    type   = EbtVoid;
465
-}
466
+TConstantUnion::TConstantUnion() : iConst(0), type(EbtVoid) {}
85
+
467
+
86
 /* Bison interface for Yacc-like parsers in C
468
+TConstantUnion::TConstantUnion(int i) : iConst(i), type(EbtInt) {}
469
+
470
+TConstantUnion::TConstantUnion(unsigned int u) : uConst(u), type(EbtUInt) {}
471
+
472
+TConstantUnion::TConstantUnion(float f) : fConst(f), type(EbtFloat) {}
473
+
474
+TConstantUnion::TConstantUnion(bool b) : bConst(b), type(EbtBool) {}
87
 
475
 
88
    Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2019 Free Software Foundation,
476
 int TConstantUnion::getIConst() const
89
diff --git a/src/gpu_info_util/SystemInfo.cpp b/src/gpu_info_util/SystemInfo.cpp
477
 {
90
index f748949..54c3db5 100644
478
diff --git a/src/compiler/translator/ConstantUnion.h b/src/compiler/translator/ConstantUnion.h
91
--- a/src/gpu_info_util/SystemInfo.cpp
479
index a623d65..df53857 100644
92
+++ b/src/gpu_info_util/SystemInfo.cpp
480
--- a/src/compiler/translator/ConstantUnion.h
93
@@ -47,6 +47,8 @@ std::string VendorName(VendorID vendor)
481
+++ b/src/compiler/translator/ConstantUnion.h
94
             return "Vivante";
482
@@ -20,6 +20,10 @@ class TConstantUnion
95
         case kVendorID_VMWare:
483
   public:
96
             return "VMWare";
484
     POOL_ALLOCATOR_NEW_DELETE
97
+        case kVendorID_Apple:
485
     TConstantUnion();
98
+            return "Apple";
486
+    TConstantUnion(int i);
99
         default:
487
+    TConstantUnion(unsigned int u);
100
             return "Unknown (" + std::to_string(vendor) + ")";
488
+    TConstantUnion(float f);
489
+    TConstantUnion(bool b);
490
 
491
     bool cast(TBasicType newType, const TConstantUnion &constant);
492
 
493
diff --git a/src/compiler/translator/IntermNode.cpp b/src/compiler/translator/IntermNode.cpp
494
index bbdf866..5136d20 100644
495
--- a/src/compiler/translator/IntermNode.cpp
496
+++ b/src/compiler/translator/IntermNode.cpp
497
@@ -41,7 +41,7 @@ TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
498
 TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
499
 {
500
     TConstantUnion *constUnion = new TConstantUnion[size];
501
-    for (unsigned int i = 0; i < size; ++i)
502
+    for (size_t i = 0; i < size; ++i)
503
         constUnion[i] = constant;
504
 
505
     return constUnion;
506
@@ -415,6 +415,14 @@ TIntermBlock::TIntermBlock(const TIntermBlock &node)
101
     }
507
     }
102
@@ -160,6 +162,11 @@ bool IsVivante(VendorID vendorId)
103
     return vendorId == kVendorID_Vivante;
104
 }
508
 }
105
 
509
 
106
+bool IsApple(VendorID vendorId)
510
+TIntermBlock::TIntermBlock(std::initializer_list<TIntermNode *> stmts)
107
+{
511
+{
108
+    return vendorId == kVendorID_Apple;
512
+    for (TIntermNode *stmt : stmts)
513
+    {
514
+        appendStatement(stmt);
515
+    }
109
+}
516
+}
110
+
517
+
111
 bool ParseAMDBrahmaDriverVersion(const std::string &content, std::string *version)
518
 size_t TIntermBlock::getChildCount() const
112
 {
519
 {
113
     const size_t begin = content.find_first_of("0123456789");
520
     return mStatements.size();
114
diff --git a/src/gpu_info_util/SystemInfo.h b/src/gpu_info_util/SystemInfo.h
521
@@ -446,6 +454,37 @@ bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNo
115
index ad17698..509a1e9 100644
522
     return false;
116
--- a/src/gpu_info_util/SystemInfo.h
523
 }
117
+++ b/src/gpu_info_util/SystemInfo.h
118
@@ -67,9 +67,8 @@ struct SystemInfo
119
     bool isAMDSwitchable = false;
120
     // Only true on dual-GPU Mac laptops.
121
     bool isMacSwitchable = false;
122
-    // Only true on Apple Silicon Macs when running iOS binaries.
123
-    // See https://developer.apple.com/documentation/foundation/nsprocessinfo/3608556-iosapponmac
124
-    bool isiOSAppOnMac = false;
125
+    // Only true on Apple Silicon Macs when running in macCatalyst.
126
+    bool needsEAGLOnMac   = false;
127
 
128
     // Only available on Android
129
     std::string machineManufacturer;
130
@@ -99,6 +98,7 @@ constexpr VendorID kVendorID_Intel    = 0x8086;
131
 constexpr VendorID kVendorID_NVIDIA   = 0x10DE;
132
 constexpr VendorID kVendorID_Qualcomm = 0x5143;
133
 constexpr VendorID kVendorID_VMWare   = 0x15ad;
134
+constexpr VendorID kVendorID_Apple    = 0x106B;
135
 
136
 // Known non-PCI (i.e. Khronos-registered) vendor IDs
137
 constexpr VendorID kVendorID_Vivante     = 0x10001;
138
@@ -124,6 +124,7 @@ bool IsSwiftshader(VendorID vendorId);
139
 bool IsVeriSilicon(VendorID vendorId);
140
 bool IsVMWare(VendorID vendorId);
141
 bool IsVivante(VendorID vendorId);
142
+bool IsApple(VendorID vendorId);
143
 
524
 
144
 // Use a heuristic to attempt to find the GPU used for 3D graphics. Sets activeGPUIndex,
525
+TIntermDeclaration::TIntermDeclaration(const TVariable *var, TIntermTyped *initExpr)
145
 // isOptimus, and isAMDSwitchable.
526
+{
146
diff --git a/src/gpu_info_util/SystemInfo_apple.mm b/src/gpu_info_util/SystemInfo_apple.mm
527
+    if (initExpr)
147
index c7756f6..a49dc52 100644
528
+    {
148
--- a/src/gpu_info_util/SystemInfo_apple.mm
529
+        appendDeclarator(
149
+++ b/src/gpu_info_util/SystemInfo_apple.mm
530
+            new TIntermBinary(TOperator::EOpInitialize, new TIntermSymbol(var), initExpr));
150
@@ -19,25 +19,7 @@ namespace angle
531
+    }
532
+    else
533
+    {
534
+        appendDeclarator(new TIntermSymbol(var));
535
+    }
536
+}
537
+
538
+TIntermDeclaration::TIntermDeclaration(std::initializer_list<const TVariable *> declarators)
539
+    : TIntermDeclaration()
540
+{
541
+    for (auto *d : declarators)
542
+    {
543
+        appendDeclarator(new TIntermSymbol(d));
544
+    }
545
+}
546
+
547
+TIntermDeclaration::TIntermDeclaration(std::initializer_list<TIntermTyped *> declarators)
548
+    : TIntermDeclaration()
549
+{
550
+    for (auto *d : declarators)
551
+    {
552
+        appendDeclarator(d);
553
+    }
554
+}
555
+
556
 size_t TIntermDeclaration::getChildCount() const
557
 {
558
     return mDeclarators.size();
559
@@ -463,9 +502,10 @@ bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *re
151
 
560
 
152
 bool GetSystemInfo(SystemInfo *info)
561
 bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
153
 {
562
 {
154
-#    if defined(ANGLE_PLATFORM_MACCATALYST) && defined(ANGLE_CPU_ARM64)
563
-    for (size_t ii = 0; ii < getSequence()->size(); ++ii)
155
-    static bool isiOSAppOnMac = false;
564
+    auto &seq = *getSequence();
156
-    static dispatch_once_t once;
565
+    for (auto *&node : seq)
157
-    dispatch_once(&once, ^{
566
     {
158
-      isiOSAppOnMac = [[NSProcessInfo processInfo] isiOSAppOnMac];
567
-        REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
159
-    });
568
+        REPLACE_IF_IS(node, TIntermNode, original, replacement);
160
-
569
     }
161
-    if (isiOSAppOnMac)
570
     return false;
162
-    {
571
 }
163
-        GetSystemInfo_ios(info);
572
@@ -473,12 +513,13 @@ bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TInte
164
-        if (info)
573
 bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
165
-        {
574
                                                         const TIntermSequence &replacements)
166
-            info->isiOSAppOnMac = true;
167
-        }
168
-        return info;
169
-    }
170
-
171
-    return GetSystemInfo_mac(info);
172
-#    elif defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
173
+#if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
174
     return GetSystemInfo_mac(info);
175
 #    else
176
     return GetSystemInfo_ios(info);
177
diff --git a/src/gpu_info_util/SystemInfo_ios.cpp b/src/gpu_info_util/SystemInfo_ios.cpp
178
index 323af2c..e52ecb3 100644
179
--- a/src/gpu_info_util/SystemInfo_ios.cpp
180
+++ b/src/gpu_info_util/SystemInfo_ios.cpp
181
@@ -18,8 +18,9 @@ namespace angle
182
 bool GetSystemInfo_ios(SystemInfo *info)
183
 {
575
 {
576
-    for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
577
+    auto &seq = *getSequence();
578
+    for (auto it = seq.begin(); it < seq.end(); ++it)
184
     {
579
     {
185
-        // TODO(anglebug.com/4275): Get the actual system version.
580
         if (*it == original)
186
+        // TODO(anglebug.com/4275): Get the actual system version and GPU info.
581
         {
187
         info->machineModelVersion = "0.0";
582
-            it = getSequence()->erase(it);
188
+        info->gpus.emplace_back().vendorId = kVendorID_Apple;
583
-            getSequence()->insert(it, replacements.begin(), replacements.end());
584
+            it = seq.erase(it);
585
+            seq.insert(it, replacements.begin(), replacements.end());
586
             return true;
587
         }
189
     }
588
     }
190
 
589
@@ -488,12 +529,13 @@ bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
191
     return true;
590
 bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
192
diff --git a/src/gpu_info_util/SystemInfo_macos.mm b/src/gpu_info_util/SystemInfo_macos.mm
591
                                             const TIntermSequence &insertions)
193
index b1cd055..c5e039e 100644
592
 {
194
--- a/src/gpu_info_util/SystemInfo_macos.mm
593
-    if (position > getSequence()->size())
195
+++ b/src/gpu_info_util/SystemInfo_macos.mm
594
+    auto &seq = *getSequence();
196
@@ -322,6 +322,10 @@ bool GetSystemInfo_mac(SystemInfo *info)
595
+    if (position > seq.size())
197
         info->isMacSwitchable = true;
596
     {
597
         return false;
198
     }
598
     }
199
     
599
-    auto it = getSequence()->begin() + position;
200
+#if defined(ANGLE_PLATFORM_MACCATALYST) && defined(ANGLE_CPU_ARM64)
600
-    getSequence()->insert(it, insertions.begin(), insertions.end());
201
+    info->needsEAGLOnMac = true;
601
+    auto it = seq.begin() + position;
202
+#endif
602
+    seq.insert(it, insertions.begin(), insertions.end());
203
+
204
     return true;
603
     return true;
205
 }
604
 }
206
 
605
 
207
diff --git a/src/libANGLE/Caps.cpp b/src/libANGLE/Caps.cpp
606
@@ -1040,8 +1082,8 @@ TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
208
index f906783..1dddd4d 100644
209
--- a/src/libANGLE/Caps.cpp
210
+++ b/src/libANGLE/Caps.cpp
211
@@ -630,7 +630,12 @@ static bool DetermineDepthTextureANGLESupport(const TextureCapsMap &textureCaps)
212
 {
213
     constexpr GLenum requiredFormats[] = {
214
         GL_DEPTH_COMPONENT16,
215
+#if !defined(ANGLE_PLATFORM_IOS) && (!defined(ANGLE_PLATFORM_MACCATALYST) || !defined(ANGLE_CPU_ARM64))
216
+        // TODO(dino): Temporarily Removing the need for GL_DEPTH_COMPONENT32_OES
217
+        // because it is not supported on iOS.
218
+        // TODO(dino): I think this needs to be a runtime check when running an iOS app on Mac.
219
         GL_DEPTH_COMPONENT32_OES,
220
+#endif
221
         GL_DEPTH24_STENCIL8_OES,
222
     };
223
 
607
 
224
@@ -642,7 +647,12 @@ static bool DetermineDepthTextureOESSupport(const TextureCapsMap &textureCaps)
608
 TIntermAggregate *TIntermAggregate::shallowCopy() const
225
 {
609
 {
226
     constexpr GLenum requiredFormats[] = {
610
-    TIntermSequence *copySeq = new TIntermSequence();
227
         GL_DEPTH_COMPONENT16,
611
-    copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
228
+#if !defined(ANGLE_PLATFORM_IOS) && (!defined(ANGLE_PLATFORM_MACCATALYST) || !defined(ANGLE_CPU_ARM64))
612
+    auto &seq                  = *getSequence();
229
+        // TODO(dino): Temporarily Removing the need for GL_DEPTH_COMPONENT32_OES
613
+    TIntermSequence *copySeq   = new TIntermSequence(seq.begin(), seq.end());
230
+        // because it is not supported on iOS.
614
     TIntermAggregate *copyNode = new TIntermAggregate(mFunction, mType, mOp, copySeq);
231
+        // TODO(dino): I think this needs to be a runtime check when running an iOS app on Mac.
615
     copyNode->setLine(mLine);
232
         GL_DEPTH_COMPONENT32_OES,
616
     return copyNode;
233
+#endif
617
diff --git a/src/compiler/translator/IntermNode.h b/src/compiler/translator/IntermNode.h
234
     };
618
index 3643847..3b6f872 100644
619
--- a/src/compiler/translator/IntermNode.h
620
+++ b/src/compiler/translator/IntermNode.h
621
@@ -674,6 +674,7 @@ class TIntermBlock : public TIntermNode, public TIntermAggregateBase
622
 {
623
   public:
624
     TIntermBlock() : TIntermNode() {}
625
+    TIntermBlock(std::initializer_list<TIntermNode *> stmts);
626
     ~TIntermBlock() override {}
235
 
627
 
236
     return GetFormatSupport(textureCaps, requiredFormats, true, true, true, true, false);
628
     TIntermBlock *getAsBlock() override { return this; }
237
diff --git a/src/libANGLE/State.cpp b/src/libANGLE/State.cpp
629
@@ -776,6 +777,9 @@ class TIntermDeclaration : public TIntermNode, public TIntermAggregateBase
238
index 7b08d8d..a804486 100644
630
 {
239
--- a/src/libANGLE/State.cpp
631
   public:
240
+++ b/src/libANGLE/State.cpp
632
     TIntermDeclaration() : TIntermNode() {}
241
@@ -6,6 +6,9 @@
633
+    TIntermDeclaration(const TVariable *var, TIntermTyped *initExpr);
634
+    TIntermDeclaration(std::initializer_list<const TVariable *> declarators);
635
+    TIntermDeclaration(std::initializer_list<TIntermTyped *> declarators);
636
     ~TIntermDeclaration() override {}
242
 
637
 
243
 // State.cpp: Implements the State class, encapsulating raw GL state.
638
     TIntermDeclaration *getAsDeclarationNode() override { return this; }
639
diff --git a/src/compiler/translator/Symbol.cpp b/src/compiler/translator/Symbol.cpp
640
index d0389af..fe2e19b 100644
641
--- a/src/compiler/translator/Symbol.cpp
642
+++ b/src/compiler/translator/Symbol.cpp
643
@@ -196,7 +196,8 @@ void TFunction::shareParameters(const TFunction &parametersSource)
244
 
644
 
245
+// Older clang versions have a false positive on this warning here.
645
 ImmutableString TFunction::buildMangledName() const
246
+#pragma clang diagnostic ignored "-Wglobal-constructors"
646
 {
247
+
647
-    std::string newName(name().data(), name().length());
248
 #include "libANGLE/State.h"
648
+    ImmutableString name = this->name();
649
+    std::string newName(name.data(), name.length());
650
     newName += kFunctionMangledNameSeparator;
249
 
651
 
250
 #include <string.h>
652
     for (size_t i = 0u; i < mParamCount; ++i)
251
diff --git a/src/libANGLE/formatutils.cpp b/src/libANGLE/formatutils.cpp
653
diff --git a/src/compiler/translator/Symbol.h b/src/compiler/translator/Symbol.h
252
index 3f9f37d..5e628f2 100644
654
index b9cf908..0abb1d4 100644
253
--- a/src/libANGLE/formatutils.cpp
655
--- a/src/compiler/translator/Symbol.h
254
+++ b/src/libANGLE/formatutils.cpp
656
+++ b/src/compiler/translator/Symbol.h
255
@@ -1034,7 +1034,7 @@ static InternalFormatInfoMap BuildInternalFormatInfoMap()
657
@@ -222,7 +222,7 @@ class TFunction : public TSymbol
256
     angle::SystemInfo info;
658
     TOperator getBuiltInOp() const { return mOp; }
257
     if (angle::GetSystemInfo(&info))
258
     {
259
-        if (info.isiOSAppOnMac)
260
+        if (info.needsEAGLOnMac)
261
         {
262
             // Using OpenGLES.framework.
263
             AddRGBAFormat(&map, GL_BGRA_EXT,       false,  8,  8,  8,  8, 0, GL_BGRA_EXT,       GL_UNSIGNED_BYTE,               GL_UNSIGNED_NORMALIZED, false, RequireES<2, 0>,                                  AlwaysSupported, RequireES<2, 0>,                                NeverSupported, NeverSupported);
264
diff --git a/src/libANGLE/renderer/gl/apple/DisplayApple_api.cpp b/src/libANGLE/renderer/gl/apple/DisplayApple_api.cpp
265
index de216fb..e63a8b6 100644
266
--- a/src/libANGLE/renderer/gl/apple/DisplayApple_api.cpp
267
+++ b/src/libANGLE/renderer/gl/apple/DisplayApple_api.cpp
268
@@ -37,7 +37,7 @@ DisplayImpl *CreateDisplayCGLOrEAGL(const egl::DisplayState &state)
269
         break;
270
     }
271
 
659
 
272
-    if (info.isiOSAppOnMac)
660
     void setDefined() { defined = true; }
273
+    if (info.needsEAGLOnMac)
661
-    bool isDefined() { return defined; }
274
     {
662
+    bool isDefined() const { return defined; }
275
         return new rx::DisplayEAGL(state);
663
     void setHasPrototypeDeclaration() { mHasPrototypeDeclaration = true; }
276
     }
664
     bool hasPrototypeDeclaration() const { return mHasPrototypeDeclaration; }
277
diff --git a/src/libANGLE/renderer/gl/cgl/ContextCGL.cpp b/src/libANGLE/renderer/gl/cgl/ContextCGL.cpp
278
index bdf5597..be99b85 100644
279
--- a/src/libANGLE/renderer/gl/cgl/ContextCGL.cpp
280
+++ b/src/libANGLE/renderer/gl/cgl/ContextCGL.cpp
281
@@ -13,6 +13,8 @@
282
 #include "libANGLE/Display.h"
283
 #include "libANGLE/renderer/gl/cgl/DisplayCGL.h"
284
 
665
 
285
+#if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
666
diff --git a/src/compiler/translator/TranslatorMetal.cpp b/src/compiler/translator/TranslatorMetal.cpp
286
+
667
index a1fcf8c..ea566b1 100644
287
 namespace rx
668
--- a/src/compiler/translator/TranslatorMetal.cpp
669
+++ b/src/compiler/translator/TranslatorMetal.cpp
670
@@ -41,8 +41,14 @@ const char kRasterizerDiscardEnabledConstName[] = "ANGLERasterizerDisabled";
671
 namespace
288
 {
672
 {
289
 
673
 
290
@@ -63,3 +65,5 @@ void ContextCGL::onDestroy(const gl::Context *context)
674
+constexpr ImmutableString kRasterizationDiscardEnabledConstName =
675
+    ImmutableString("ANGLERasterizationDisabled");
676
+constexpr ImmutableString kCoverageMaskEnabledConstName =
677
+    ImmutableString("ANGLECoverageMaskEnabled");
678
 constexpr ImmutableString kCoverageMaskField       = ImmutableString("coverageMask");
679
+constexpr ImmutableString kEmuInstanceIDField      = ImmutableString("emulatedInstanceID");
680
 constexpr ImmutableString kSampleMaskWriteFuncName = ImmutableString("ANGLEWriteSampleMask");
681
+constexpr ImmutableString kDiscardWrapperFuncName  = ImmutableString("ANGLEDiscardWrapper");
682
 
683
 TIntermBinary *CreateDriverUniformRef(const TVariable *driverUniforms, const char *fieldName)
684
 {
685
@@ -86,6 +92,21 @@ ANGLE_NO_DISCARD bool AppendVertexShaderPositionYCorrectionToMain(TCompiler *com
686
     return RunAtTheEndOfShader(compiler, root, assignment, symbolTable);
291
 }
687
 }
292
 
688
 
293
 }  // namespace rx
689
+ANGLE_NO_DISCARD bool EmulateInstanceID(TCompiler *compiler,
690
+                                        TIntermBlock *root,
691
+                                        TSymbolTable *symbolTable,
692
+                                        const TVariable *driverUniforms)
693
+{
694
+    // emuInstanceID
695
+    TIntermBinary *emuInstanceID =
696
+        CreateDriverUniformRef(driverUniforms, kEmuInstanceIDField.data());
294
+
697
+
295
+#endif  // defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
698
+    // Create a symbol reference to "gl_InstanceIndex"
296
\ No newline at end of file
699
+    const TVariable *instanceID = BuiltInVariable::gl_InstanceIndex();
700
+
701
+    return ReplaceVariableWithTyped(compiler, root, instanceID, emuInstanceID);
702
+}
703
+
704
 // Initialize unused varying outputs.
705
 ANGLE_NO_DISCARD bool InitializeUnusedOutputs(TIntermBlock *root,
706
                                               TSymbolTable *symbolTable,
707
@@ -123,6 +144,18 @@ ANGLE_NO_DISCARD bool InitializeUnusedOutputs(TIntermBlock *root,
708
 
709
 }  // anonymous namespace
710
 
711
+/** static */
712
+const char *TranslatorMetal::GetCoverageMaskEnabledConstName()
713
+{
714
+    return kCoverageMaskEnabledConstName.data();
715
+}
716
+
717
+/** static */
718
+const char *TranslatorMetal::GetRasterizationDiscardEnabledConstName()
719
+{
720
+    return kRasterizationDiscardEnabledConstName.data();
721
+}
722
+
723
 TranslatorMetal::TranslatorMetal(sh::GLenum type, ShShaderSpec spec) : TranslatorVulkan(type, spec)
724
 {}
725
 
726
@@ -153,20 +186,58 @@ bool TranslatorMetal::translate(TIntermBlock *root,
727
     {
728
         auto negFlipY = getDriverUniformNegFlipYRef(driverUniforms);
729
 
730
+        if (mEmulatedInstanceID)
731
+        {
732
+            // Emulate gl_InstanceID
733
+            if (!EmulateInstanceID(this, root, &getSymbolTable(), driverUniforms))
734
+            {
735
+                return false;
736
+            }
737
+        }
738
+
739
         // Append gl_Position.y correction to main
740
         if (!AppendVertexShaderPositionYCorrectionToMain(this, root, &getSymbolTable(), negFlipY))
741
         {
742
             return false;
743
         }
744
 
745
-        // Insert rasterizer discard logic
746
-        if (!insertRasterizerDiscardLogic(root))
747
+        // Insert rasterization discard logic
748
+        if (!insertRasterizationDiscardLogic(root))
749
+        {
750
+            return false;
751
+        }
752
+    }
753
+
754
+    // Initialize unused varying outputs to avoid spirv-cross dead-code removing them in later
755
+    // stage. Only do this if SH_INIT_OUTPUT_VARIABLES is not specified.
756
+    if ((getShaderType() == GL_VERTEX_SHADER || getShaderType() == GL_GEOMETRY_SHADER_EXT) &&
757
+        !(compileOptions & SH_INIT_OUTPUT_VARIABLES))
758
+    {
759
+        InitVariableList list;
760
+        for (const sh::ShaderVariable &var : mOutputVaryings)
761
+        {
762
+            if (!var.active)
763
+            {
764
+                list.push_back(var);
765
+            }
766
+        }
767
+
768
+        if (!InitializeUnusedOutputs(root, &getSymbolTable(), list))
769
         {
770
             return false;
771
         }
772
     }
773
     else if (getShaderType() == GL_FRAGMENT_SHADER)
774
     {
775
+        // For non void MSL fragment functions replace discard
776
+        // with ANGLEDiscardWrapper()
777
+        if (mOutputVariables.size() > 0)
778
+        {
779
+            if (!replaceAllMainDiscardUses(root))
780
+            {
781
+                return false;
782
+            }
783
+        }
784
         if (!insertSampleMaskWritingLogic(root, driverUniforms))
785
         {
786
             return false;
787
@@ -235,6 +306,13 @@ void TranslatorMetal::createAdditionalGraphicsDriverUniformFields(std::vector<TF
788
     TField *coverageMaskField =
789
         new TField(new TType(EbtUInt), kCoverageMaskField, TSourceLoc(), SymbolType::AngleInternal);
790
     fieldsOut->push_back(coverageMaskField);
791
+
792
+    if (mEmulatedInstanceID)
793
+    {
794
+        TField *emuInstanceIDField = new TField(new TType(EbtInt), kEmuInstanceIDField,
795
+                                                TSourceLoc(), SymbolType::AngleInternal);
796
+        fieldsOut->push_back(emuInstanceIDField);
797
+    }
798
 }
799
 
800
 // Add sample_mask writing to main, guarded by the specialization constant
801
@@ -293,24 +371,24 @@ ANGLE_NO_DISCARD bool TranslatorMetal::insertSampleMaskWritingLogic(TIntermBlock
802
     return RunAtTheEndOfShader(this, root, ifCall, symbolTable);
803
 }
804
 
805
-ANGLE_NO_DISCARD bool TranslatorMetal::insertRasterizerDiscardLogic(TIntermBlock *root)
806
+ANGLE_NO_DISCARD bool TranslatorMetal::insertRasterizationDiscardLogic(TIntermBlock *root)
807
 {
808
     TInfoSinkBase &sink       = getInfoSink().obj;
809
     TSymbolTable *symbolTable = &getSymbolTable();
810
 
811
     // Insert rasterizationDisabled specialization constant.
812
-    sink << "layout (constant_id=0) const bool " << mtl::kRasterizerDiscardEnabledConstName;
813
+    sink << "layout (constant_id=0) const bool " << kRasterizationDiscardEnabledConstName;
814
     sink << " = false;\n";
815
 
816
-    // Create kRasterizerDiscardEnabledConstName variable reference.
817
+    // Create kRasterizationDiscardEnabledConstName and kRasterizationDiscardFuncName variable
818
+    // references.
819
     TType *boolType = new TType(EbtBool);
820
     boolType->setQualifier(EvqConst);
821
-    TVariable *discardEnabledVar =
822
-        new TVariable(symbolTable, ImmutableString(mtl::kRasterizerDiscardEnabledConstName),
823
+    TVariable *discardEnabledVar = new TVariable(symbolTable, kRasterizationDiscardEnabledConstName,
824
                                                  boolType, SymbolType::AngleInternal);
825
 
826
     // Insert this code to the end of main()
827
-    // if (ANGLERasterizerDisabled)
828
+    // if (ANGLERasterizationDisabled)
829
     // {
830
     //      gl_Position = vec4(-3.0, -3.0, -3.0, 1.0);
831
     // }
832
@@ -341,4 +419,79 @@ ANGLE_NO_DISCARD bool TranslatorMetal::insertRasterizerDiscardLogic(TIntermBlock
833
     return RunAtTheEndOfShader(this, root, ifCall, symbolTable);
834
 }
835
 
836
+// If the MSL fragment shader is non-void, we need to ensure
837
+// that there is a return at the end. The MSL compiler
838
+// will error out if there's no return at the end, even if all
839
+// paths lead to discard_fragment(). So wrap discard in a wrapper function.
840
+// Fixes dEQP-GLES3.functional.shaders.discard.basic_always
841
+ANGLE_NO_DISCARD bool TranslatorMetal::replaceAllMainDiscardUses(TIntermBlock *root)
842
+{
843
+    // before
844
+    // void main (void)
845
+    // {
846
+    //     o_color = v_color;
847
+    //     discard;
848
+    // }
849
+
850
+    // after
851
+    // void ANGLEDiscardWrapper()
852
+    // {
853
+    //    discard;
854
+    // }
855
+    // void main (void)
856
+    // {
857
+    //     o_color = v_color;
858
+    //     ANGLEDiscardWrapper();
859
+    // }
860
+
861
+    TIntermFunctionDefinition *main   = FindMain(root);
862
+    TIntermBlock *mainBody            = main->getBody();
863
+    TIntermSequence *functionSequence = mainBody->getSequence();
864
+    TIntermAggregate *discardFunc     = nullptr;
865
+    // Iterate over all branches in main function, and replace all uses
866
+    // of discard with ANGLEDiscardWrapper().
867
+    for (size_t index = 0; index < functionSequence->size(); ++index)
868
+    {
869
+        TIntermNode *functionNode = (*functionSequence)[index];
870
+        TIntermBranch *branchNode = functionNode->getAsBranchNode();
871
+        if (branchNode != nullptr)
872
+        {
873
+            if (branchNode->getFlowOp() == EOpKill)
874
+            {
875
+                if (discardFunc == nullptr)
876
+                {
877
+                    discardFunc = createDiscardWrapperFunc(root);
878
+                }
879
+                bool replaced = mainBody->replaceChildNode(branchNode, discardFunc);
880
+                if (!replaced)
881
+                {
882
+                    return false;
883
+                }
884
+            }
885
+        }
886
+    }
887
+    return validateAST(root);
888
+}
889
+
890
+// Create discard_wrapper function to ensure that SPIRV-Cross will always have a return at the end
891
+// of fragment shaders
892
+ANGLE_NO_DISCARD TIntermAggregate *TranslatorMetal::createDiscardWrapperFunc(TIntermBlock *root)
893
+{
894
+    TInfoSinkBase &sink       = getInfoSink().obj;
895
+    TSymbolTable *symbolTable = &getSymbolTable();
896
+
897
+    sink << "void " << kDiscardWrapperFuncName << "()\n";
898
+    sink << "{\n";
899
+    sink << "   discard;\n";
900
+    sink << "}\n";
901
+
902
+    TFunction *discardWrapperFunc =
903
+        new TFunction(symbolTable, kDiscardWrapperFuncName, SymbolType::AngleInternal,
904
+                      StaticType::GetBasic<EbtVoid>(), true);
905
+
906
+    TIntermAggregate *callDiscardWrapperFunc =
907
+        TIntermAggregate::CreateFunctionCall(*discardWrapperFunc, new TIntermSequence());
908
+    return callDiscardWrapperFunc;
909
+}
910
+
911
 }  // namespace sh
912
diff --git a/src/compiler/translator/TranslatorMetal.h b/src/compiler/translator/TranslatorMetal.h
913
index 0f4f1cc..bcc3187 100644
914
--- a/src/compiler/translator/TranslatorMetal.h
915
+++ b/src/compiler/translator/TranslatorMetal.h
916
@@ -25,6 +25,11 @@ class TranslatorMetal : public TranslatorVulkan
917
   public:
918
     TranslatorMetal(sh::GLenum type, ShShaderSpec spec);
919
 
920
+    static const char *GetCoverageMaskEnabledConstName();
921
+    static const char *GetRasterizationDiscardEnabledConstName();
922
+
923
+    void enableEmulatedInstanceID(bool e) { mEmulatedInstanceID = e; }
924
+
925
   protected:
926
     ANGLE_NO_DISCARD bool translate(TIntermBlock *root,
927
                                     ShCompileOptions compileOptions,
928
@@ -37,7 +42,13 @@ class TranslatorMetal : public TranslatorVulkan
929
 
930
     ANGLE_NO_DISCARD bool insertSampleMaskWritingLogic(TIntermBlock *root,
931
                                                        const TVariable *driverUniforms);
932
-    ANGLE_NO_DISCARD bool insertRasterizerDiscardLogic(TIntermBlock *root);
933
+    ANGLE_NO_DISCARD bool insertRasterizationDiscardLogic(TIntermBlock *root);
934
+
935
+    ANGLE_NO_DISCARD bool replaceAllMainDiscardUses(TIntermBlock *root);
936
+
937
+    ANGLE_NO_DISCARD TIntermAggregate *createDiscardWrapperFunc(TIntermBlock *root);
938
+
939
+    bool mEmulatedInstanceID = false;
940
 };
941
 
942
 }  // namespace sh
943
diff --git a/src/compiler/translator/TranslatorMetalDirect.cpp b/src/compiler/translator/TranslatorMetalDirect.cpp
944
new file mode 100644
945
index 0000000..4e10228
946
--- /dev/null
947
+++ b/src/compiler/translator/TranslatorMetalDirect.cpp
948
@@ -0,0 +1,1439 @@
949
+//
950
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
951
+// Use of this source code is governed by a BSD-style license that can be
952
+// found in the LICENSE file.
953
+//
954
+
955
+#include "compiler/translator/TranslatorMetalDirect.h"
956
+
957
+#include "angle_gl.h"
958
+#include "common/utilities.h"
959
+#include "compiler/translator/BuiltinsWorkaroundGLSL.h"
960
+#include "compiler/translator/ImmutableStringBuilder.h"
961
+#include "compiler/translator/OutputVulkanGLSL.h"
962
+#include "compiler/translator/StaticType.h"
963
+#include "compiler/translator/TranslatorMetalDirect/AddExplicitTypeCasts.h"
964
+#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
965
+#include "compiler/translator/TranslatorMetalDirect/ConstantNames.h"
966
+#include "compiler/translator/TranslatorMetalDirect/EmitMetal.h"
967
+#include "compiler/translator/TranslatorMetalDirect/HoistConstants.h"
968
+#include "compiler/translator/TranslatorMetalDirect/Name.h"
969
+#include "compiler/translator/TranslatorMetalDirect/ReduceInterfaceBlocks.h"
970
+#include "compiler/translator/TranslatorMetalDirect/RewriteCaseDeclarations.h"
971
+#include "compiler/translator/TranslatorMetalDirect/RewriteGlobalQualifierDecls.h"
972
+#include "compiler/translator/TranslatorMetalDirect/RewriteKeywords.h"
973
+#include "compiler/translator/TranslatorMetalDirect/RewriteOutArgs.h"
974
+#include "compiler/translator/TranslatorMetalDirect/RewritePipelines.h"
975
+#include "compiler/translator/TranslatorMetalDirect/RewriteUnaddressableReferences.h"
976
+#include "compiler/translator/TranslatorMetalDirect/SeparateCompoundExpressions.h"
977
+#include "compiler/translator/TranslatorMetalDirect/SeparateCompoundStructDeclarations.h"
978
+#include "compiler/translator/TranslatorMetalDirect/SymbolEnv.h"
979
+#include "compiler/translator/TranslatorMetalDirect/ToposortStructs.h"
980
+#include "compiler/translator/TranslatorMetalDirect/WrapMain.h"
981
+#include "compiler/translator/TranslatorMetalUtils.h"
982
+#include "compiler/translator/tree_ops/InitializeVariables.h"
983
+#include "compiler/translator/tree_ops/NameEmbeddedUniformStructs.h"
984
+#include "compiler/translator/tree_ops/RemoveAtomicCounterBuiltins.h"
985
+#include "compiler/translator/tree_ops/RemoveInactiveInterfaceVariables.h"
986
+#include "compiler/translator/tree_ops/RewriteAtomicCounters.h"
987
+#include "compiler/translator/tree_ops/RewriteCubeMapSamplersAs2DArray.h"
988
+#include "compiler/translator/tree_ops/RewriteDfdy.h"
989
+#include "compiler/translator/tree_ops/RewriteStructSamplers.h"
990
+#include "compiler/translator/tree_util/BuiltIn.h"
991
+#include "compiler/translator/tree_util/FindFunction.h"
992
+#include "compiler/translator/tree_util/FindMain.h"
993
+#include "compiler/translator/tree_util/FindSymbolNode.h"
994
+#include "compiler/translator/tree_util/IntermNode_util.h"
995
+#include "compiler/translator/tree_util/ReplaceClipDistanceVariable.h"
996
+#include "compiler/translator/tree_util/ReplaceVariable.h"
997
+#include "compiler/translator/tree_util/RunAtTheEndOfShader.h"
998
+#include "compiler/translator/util.h"
999
+
1000
+namespace sh
1001
+{
1002
+
1003
+namespace
1004
+{
1005
+
1006
+constexpr Name kCoverageMaskField("coverageMask", SymbolType::UserDefined);
1007
+constexpr Name kEmuInstanceIDField("emulatedInstanceID", SymbolType::UserDefined);
1008
+#if 0
1009
+constexpr Name kSampleMaskWriteFuncName("WriteSampleMask");
1010
+constexpr Name kDiscardWrapperFuncName("DiscardWrapper");
1011
+#endif
1012
+constexpr Name kEmulatedDepthRangeParams("DepthRangeParams");
1013
+constexpr Name kUniformsBlockName("AngleUniforms");
1014
+constexpr Name kUniformsVarName("angleUniforms");
1015
+constexpr Name kFlippedPointCoordName("flippedPointCoord", SymbolType::UserDefined);
1016
+constexpr Name kFlippedFragCoordName("flippedFragCoord", SymbolType::UserDefined);
1017
+
1018
+constexpr const char kViewport[]             = "viewport";
1019
+constexpr const char kHalfRenderArea[]       = "halfRenderArea";
1020
+constexpr const char kFlipXY[]               = "flipXY";
1021
+constexpr const char kNegFlipXY[]            = "negFlipXY";
1022
+constexpr const char kClipDistancesEnabled[] = "clipDistancesEnabled";
1023
+constexpr const char kXfbActiveUnpaused[]    = "xfbActiveUnpaused";
1024
+constexpr const char kXfbVerticesPerDraw[]   = "xfbVerticesPerDraw";
1025
+constexpr const char kXfbBufferOffsets[]     = "xfbBufferOffsets";
1026
+constexpr const char kAcbBufferOffsets[]     = "acbBufferOffsets";
1027
+constexpr const char kDepthRange[]           = "depthRange";
1028
+constexpr const char kPreRotation[]          = "preRotation";
1029
+constexpr const char kFragRotation[]         = "fragRotation";
1030
+
1031
+constexpr const TVariable kgl_VertexIndexMetal(
1032
+    BuiltInId::gl_VertexIndex,
1033
+    ImmutableString("gl_VertexIndex"),
1034
+    SymbolType::BuiltIn,
1035
+    TExtension::UNDEFINED,
1036
+    StaticType::Get<EbtUInt, EbpHigh, EvqVertexID, 1, 1>());
1037
+
1038
+constexpr size_t kNumGraphicsDriverUniforms                                                = 12;
1039
+constexpr std::array<const char *, kNumGraphicsDriverUniforms> kGraphicsDriverUniformNames = {
1040
+    {kViewport, kHalfRenderArea, kFlipXY, kNegFlipXY, kClipDistancesEnabled, kXfbActiveUnpaused,
1041
+     kXfbVerticesPerDraw, kXfbBufferOffsets, kAcbBufferOffsets, kDepthRange, kPreRotation,
1042
+     kFragRotation}};
1043
+
1044
+constexpr size_t kNumComputeDriverUniforms                                               = 1;
1045
+constexpr std::array<const char *, kNumComputeDriverUniforms> kComputeDriverUniformNames = {
1046
+    {kAcbBufferOffsets}};
1047
+
1048
+class DeclareStructTypesTraverser : public TIntermTraverser
1049
+{
1050
+  public:
1051
+    explicit DeclareStructTypesTraverser(TOutputMSL *outputMSL)
1052
+        : TIntermTraverser(true, false, false), mOutputMSL(outputMSL)
1053
+    {}
1054
+
1055
+    bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
1056
+    {
1057
+        ASSERT(visit == PreVisit);
1058
+        if (!mInGlobalScope)
1059
+        {
1060
+            return false;
1061
+        }
1062
+
1063
+        const TIntermSequence &sequence = *(node->getSequence());
1064
+        TIntermTyped *declarator        = sequence.front()->getAsTyped();
1065
+        const TType &type               = declarator->getType();
1066
+
1067
+        if (type.isStructSpecifier())
1068
+        {
1069
+            const TStructure *structure = type.getStruct();
1070
+
1071
+            // Embedded structs should be parsed away by now.
1072
+            ASSERT(structure->symbolType() != SymbolType::Empty);
1073
+            // outputMSL->writeStructType(structure);
1074
+
1075
+            TIntermSymbol *symbolNode = declarator->getAsSymbolNode();
1076
+            if (symbolNode && symbolNode->variable().symbolType() == SymbolType::Empty)
1077
+            {
1078
+                // Remove the struct specifier declaration from the tree so it isn't parsed again.
1079
+                TIntermSequence emptyReplacement;
1080
+                mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), node,
1081
+                                                emptyReplacement);
1082
+            }
1083
+        }
1084
+        // TODO: REMOVE, used to remove 'unsued' warning
1085
+        mOutputMSL = nullptr;
1086
+
1087
+        return false;
1088
+    }
1089
+
1090
+  private:
1091
+    TOutputMSL *mOutputMSL;
1092
+};
1093
+
1094
+class DeclareDefaultUniformsTraverser : public TIntermTraverser
1095
+{
1096
+  public:
1097
+    DeclareDefaultUniformsTraverser(TInfoSinkBase *sink,
1098
+                                    ShHashFunction64 hashFunction,
1099
+                                    NameMap *nameMap)
1100
+        : TIntermTraverser(true, true, true),
1101
+          mSink(sink),
1102
+          mHashFunction(hashFunction),
1103
+          mNameMap(nameMap),
1104
+          mInDefaultUniform(false)
1105
+    {}
1106
+
1107
+    bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
1108
+    {
1109
+        const TIntermSequence &sequence = *(node->getSequence());
1110
+
1111
+        // TODO(jmadill): Compound declarations.
1112
+        ASSERT(sequence.size() == 1);
1113
+
1114
+        TIntermTyped *variable = sequence.front()->getAsTyped();
1115
+        const TType &type      = variable->getType();
1116
+        bool isUniform         = type.getQualifier() == EvqUniform && !type.isInterfaceBlock() &&
1117
+                         !IsOpaqueType(type.getBasicType());
1118
+
1119
+        if (visit == PreVisit)
1120
+        {
1121
+            if (isUniform)
1122
+            {
1123
+                (*mSink) << "    " << GetTypeName(type, mHashFunction, mNameMap) << " ";
1124
+                mInDefaultUniform = true;
1125
+            }
1126
+        }
1127
+        else if (visit == InVisit)
1128
+        {
1129
+            mInDefaultUniform = isUniform;
1130
+        }
1131
+        else if (visit == PostVisit)
1132
+        {
1133
+            if (isUniform)
1134
+            {
1135
+                (*mSink) << ";\n";
1136
+
1137
+                // Remove the uniform declaration from the tree so it isn't parsed again.
1138
+                TIntermSequence emptyReplacement;
1139
+                mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), node,
1140
+                                                emptyReplacement);
1141
+            }
1142
+
1143
+            mInDefaultUniform = false;
1144
+        }
1145
+        return true;
1146
+    }
1147
+
1148
+    void visitSymbol(TIntermSymbol *symbol) override
1149
+    {
1150
+        if (mInDefaultUniform)
1151
+        {
1152
+            const ImmutableString &name = symbol->variable().name();
1153
+            ASSERT(!name.beginsWith("gl_"));
1154
+            (*mSink) << HashName(&symbol->variable(), mHashFunction, mNameMap)
1155
+                     << ArrayString(symbol->getType());
1156
+        }
1157
+    }
1158
+
1159
+  private:
1160
+    TInfoSinkBase *mSink;
1161
+    ShHashFunction64 mHashFunction;
1162
+    NameMap *mNameMap;
1163
+    bool mInDefaultUniform;
1164
+};
1165
+
1166
+TIntermBinary *CreateDriverUniformRef(const TVariable &driverUniforms, const char *fieldName)
1167
+{
1168
+    size_t fieldIndex = FindFieldIndex(driverUniforms.getType().getStruct()->fields(), fieldName);
1169
+
1170
+    TIntermSymbol *angleUniformsRef = new TIntermSymbol(&driverUniforms);
1171
+    TConstantUnion *uniformIndex    = new TConstantUnion;
1172
+    uniformIndex->setIConst(static_cast<int>(fieldIndex));
1173
+    TIntermConstantUnion *indexRef =
1174
+        new TIntermConstantUnion(uniformIndex, *StaticType::GetBasic<EbtInt>());
1175
+    return new TIntermBinary(EOpIndexDirectStruct, angleUniformsRef, indexRef);
1176
+}
1177
+
1178
+#if 0
1179
+// Unlike Vulkan having auto viewport flipping extension, in Metal we have to flip gl_Position.y
1180
+// manually.
1181
+// This operation performs flipping the gl_Position.y using this expression:
1182
+// gl_Position.y = gl_Position.y * negViewportScaleY
1183
+ANGLE_NO_DISCARD bool AppendVertexShaderPositionYCorrectionToMain(TCompiler &compiler,
1184
+                                                                  TIntermBlock &root,
1185
+                                                                  TIntermSwizzle &negFlipY)
1186
+{
1187
+    TSymbolTable &symbolTable = compiler.getSymbolTable();
1188
+
1189
+    // Create a symbol reference to "gl_Position"
1190
+    const TVariable *position  = BuiltInVariable::gl_Position();
1191
+    TIntermSymbol *positionRef = new TIntermSymbol(position);
1192
+
1193
+    // Create a swizzle to "gl_Position.y"
1194
+    TVector<int> swizzleOffsetY;
1195
+    swizzleOffsetY.push_back(1);
1196
+    TIntermSwizzle *positionY = new TIntermSwizzle(positionRef, swizzleOffsetY);
1197
+
1198
+    // Create the expression "gl_Position.y * negFlipY"
1199
+    TIntermBinary *inverseY = new TIntermBinary(EOpMul, positionY->deepCopy(), &negFlipY);
1200
+
1201
+    // Create the assignment "gl_Position.y = gl_Position.y * negViewportScaleY
1202
+    TIntermTyped *positionYLHS = positionY->deepCopy();
1203
+    TIntermBinary *assignment  = new TIntermBinary(TOperator::EOpAssign, positionYLHS, inverseY);
1204
+
1205
+    // Append the assignment as a statement at the end of the shader.
1206
+    return RunAtTheEndOfShader(&compiler, &root, assignment, &symbolTable);
1207
+}
1208
+#endif
1209
+
1210
+#if 0
1211
+// Initialize unused varying outputs.
1212
+ANGLE_NO_DISCARD bool InitializeUnusedOutputs(TIntermBlock &root,
1213
+                                              TSymbolTable &symbolTable,
1214
+                                              const InitVariableList &unusedVars)
1215
+{
1216
+    if (unusedVars.empty())
1217
+    {
1218
+        return true;
1219
+    }
1220
+
1221
+    TIntermSequence *insertSequence = new TIntermSequence;
1222
+
1223
+    for (const sh::ShaderVariable &var : unusedVars)
1224
+    {
1225
+        ASSERT(!var.active);
1226
+        const TIntermSymbol *symbol = FindSymbolNode(&root, var.name);
1227
+        ASSERT(symbol);
1228
+
1229
+        TIntermSequence *initCode = CreateInitCode(symbol, false, false, &symbolTable);
1230
+
1231
+        insertSequence->insert(insertSequence->end(), initCode->begin(), initCode->end());
1232
+    }
1233
+
1234
+    if (insertSequence)
1235
+    {
1236
+        TIntermFunctionDefinition *main = FindMain(&root);
1237
+        TIntermSequence *mainSequence   = main->getBody()->getSequence();
1238
+
1239
+        // Insert init code at the start of main()
1240
+        mainSequence->insert(mainSequence->begin(), insertSequence->begin(), insertSequence->end());
1241
+    }
1242
+
1243
+    return true;
1244
+}
1245
+#endif
1246
+
1247
+const TVariable *AddComputeDriverUniformsToShader(TIntermBlock &root, TSymbolTable &symbolTable)
1248
+{
1249
+    // This field list mirrors the structure of ComputeDriverUniforms in ContextVk.cpp.
1250
+    TFieldList *driverFieldList = new TFieldList;
1251
+
1252
+    const std::array<TType *, kNumComputeDriverUniforms> kDriverUniformTypes = {{
1253
+        new TType(EbtUInt, 4),
1254
+    }};
1255
+
1256
+    for (size_t uniformIndex = 0; uniformIndex < kNumComputeDriverUniforms; ++uniformIndex)
1257
+    {
1258
+        TField *driverUniformField =
1259
+            new TField(kDriverUniformTypes[uniformIndex],
1260
+                       ImmutableString(kComputeDriverUniformNames[uniformIndex]), kNoSourceLoc,
1261
+                       SymbolType::AngleInternal);
1262
+        driverFieldList->push_back(driverUniformField);
1263
+    }
1264
+
1265
+    return DeclareStructure(&root, &symbolTable, driverFieldList, EvqUniform,
1266
+                            TMemoryQualifier::Create(), 0, kUniformsBlockName.rawName(),
1267
+                            &kUniformsVarName.rawName())
1268
+        .second;
1269
+}
1270
+
1271
+// The Add*DriverUniformsToShader operation adds an internal uniform block to a shader. The driver
1272
+// block is used to implement Vulkan-specific features and workarounds. Returns the driver uniforms
1273
+// variable.
1274
+//
1275
+// There are Graphics and Compute variations as they require different uniforms.
1276
+const TVariable *AddGraphicsDriverUniformsToShader(TIntermBlock &root,
1277
+                                                   TSymbolTable &symbolTable,
1278
+                                                   const std::vector<TField *> &additionalFields)
1279
+{
1280
+    // Init the depth range type.
1281
+    TFieldList *depthRangeParamsFields = new TFieldList();
1282
+    depthRangeParamsFields->push_back(new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1, 1),
1283
+                                                 ImmutableString("near"), kNoSourceLoc,
1284
+                                                 SymbolType::AngleInternal));
1285
+    depthRangeParamsFields->push_back(new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1, 1),
1286
+                                                 ImmutableString("far"), kNoSourceLoc,
1287
+                                                 SymbolType::AngleInternal));
1288
+    depthRangeParamsFields->push_back(new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1, 1),
1289
+                                                 ImmutableString("diff"), kNoSourceLoc,
1290
+                                                 SymbolType::AngleInternal));
1291
+    // This additional field might be used by subclass such as TranslatorMetal.
1292
+    depthRangeParamsFields->push_back(new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1, 1),
1293
+                                                 ImmutableString("reserved"), kNoSourceLoc,
1294
+                                                 SymbolType::AngleInternal));
1295
+
1296
+    const TStructure *emulatedDepthRangeParams =
1297
+        DeclareStructure(&root, &symbolTable, depthRangeParamsFields, EvqGlobal,
1298
+                         TMemoryQualifier::Create(), 0, kEmulatedDepthRangeParams.rawName(),
1299
+                         nullptr)
1300
+            .first->getType()
1301
+            .getStruct();
1302
+
1303
+    // This field list mirrors the structure of GraphicsDriverUniforms in ContextVk.cpp.
1304
+    TFieldList *driverFieldList = new TFieldList;
1305
+
1306
+    const std::array<TType *, kNumGraphicsDriverUniforms> kDriverUniformTypes = {{
1307
+        new TType(EbtFloat, 4),
1308
+        new TType(EbtFloat, 2),
1309
+        new TType(EbtFloat, 2),
1310
+        new TType(EbtFloat, 2),
1311
+        new TType(EbtUInt),  // uint clipDistancesEnabled;  // 32 bits for 32 clip distances max
1312
+        new TType(EbtUInt),
1313
+        new TType(EbtUInt),
1314
+        // NOTE: There's a vec3 gap here that can be used in the future
1315
+        new TType(EbtInt, 4),
1316
+        new TType(EbtUInt, 4),
1317
+        new TType(emulatedDepthRangeParams, false),
1318
+        new TType(EbtFloat, 2, 4),
1319
+        new TType(EbtFloat, 2, 4),
1320
+    }};
1321
+
1322
+    for (size_t uniformIndex = 0; uniformIndex < kNumGraphicsDriverUniforms; ++uniformIndex)
1323
+    {
1324
+        TField *driverUniformField =
1325
+            new TField(kDriverUniformTypes[uniformIndex],
1326
+                       ImmutableString(kGraphicsDriverUniformNames[uniformIndex]), kNoSourceLoc,
1327
+                       SymbolType::AngleInternal);
1328
+        driverFieldList->push_back(driverUniformField);
1329
+    }
1330
+
1331
+    // Back-end specific fields
1332
+    driverFieldList->insert(driverFieldList->end(), additionalFields.begin(),
1333
+                            additionalFields.end());
1334
+
1335
+    // Define a driver uniform block "ANGLEUniformBlock" with instance name "ANGLEUniforms".
1336
+    return DeclareStructure(&root, &symbolTable, driverFieldList, EvqUniform,
1337
+                            TMemoryQualifier::Create(), 0, kUniformsBlockName.rawName(),
1338
+                            &kUniformsVarName.rawName())
1339
+        .second;
1340
+}
1341
+
1342
+// Declares a new variable to replace gl_DepthRange, its values are fed from a driver uniform.
1343
+ANGLE_NO_DISCARD bool ReplaceGLDepthRangeWithDriverUniform(TCompiler &compiler,
1344
+                                                           TIntermBlock &root,
1345
+                                                           const TVariable &driverUniforms)
1346
+{
1347
+    TSymbolTable &symbolTable = compiler.getSymbolTable();
1348
+
1349
+    // Create a symbol reference to "gl_DepthRange"
1350
+    const TVariable *depthRangeVar = static_cast<const TVariable *>(
1351
+        symbolTable.findBuiltIn(ImmutableString("gl_DepthRange"), 0));
1352
+
1353
+    // ANGLEUniforms.depthRange
1354
+    TIntermBinary *angleEmulatedDepthRangeRef = CreateDriverUniformRef(driverUniforms, kDepthRange);
1355
+
1356
+    // Use this variable instead of gl_DepthRange everywhere.
1357
+    return ReplaceVariableWithTyped(&compiler, &root, depthRangeVar, angleEmulatedDepthRangeRef);
1358
+}
1359
+
1360
+TIntermSequence *GetMainSequence(TIntermBlock &root)
1361
+{
1362
+    TIntermFunctionDefinition *main = FindMain(&root);
1363
+    return main->getBody()->getSequence();
1364
+}
1365
+
1366
+ANGLE_NO_DISCARD bool AppendVertexShaderTransformFeedbackOutputToMain(TCompiler &compiler,
1367
+                                                                      TIntermBlock &root)
1368
+{
1369
+    TSymbolTable &symbolTable = compiler.getSymbolTable();
1370
+    TVariable *xfbPlaceholder = new TVariable(&symbolTable, ImmutableString("@@ XFB-OUT @@"),
1371
+                                              new TType(), SymbolType::AngleInternal);
1372
+
1373
+    // Append the assignment as a statement at the end of the shader.
1374
+    return RunAtTheEndOfShader(&compiler, &root, new TIntermSymbol(xfbPlaceholder), &symbolTable);
1375
+}
1376
+
1377
+// This operation performs the viewport depth translation needed by Vulkan. In GL the viewport
1378
+// transformation is slightly different - see the GL 2.0 spec section "2.12.1 Controlling the
1379
+// Viewport". In Vulkan the corresponding spec section is currently "23.4. Coordinate
1380
+// Transformations".
1381
+// The equations reduce to an expression:
1382
+//
1383
+//     z_vk = 0.5 * (w_gl + z_gl)
1384
+//
1385
+// where z_vk is the depth output of a Vulkan vertex shader and z_gl is the same for GL.
1386
+ANGLE_NO_DISCARD bool AppendVertexShaderDepthCorrectionToMain(TCompiler &compiler,
1387
+                                                              TIntermBlock &root)
1388
+{
1389
+    TSymbolTable &symbolTable = compiler.getSymbolTable();
1390
+
1391
+    const TVariable *position  = BuiltInVariable::gl_Position();
1392
+    TIntermSymbol *positionRef = new TIntermSymbol(position);
1393
+
1394
+    TVector<int> swizzleOffsetZ = {2};
1395
+    TIntermSwizzle *positionZ   = new TIntermSwizzle(positionRef, swizzleOffsetZ);
1396
+
1397
+    TIntermConstantUnion *oneHalf = CreateFloatNode(0.5f);
1398
+
1399
+    TVector<int> swizzleOffsetW = {3};
1400
+    TIntermSwizzle *positionW   = new TIntermSwizzle(positionRef->deepCopy(), swizzleOffsetW);
1401
+
1402
+    // Create the expression "(gl_Position.z + gl_Position.w) * 0.5".
1403
+    TIntermBinary *zPlusW = new TIntermBinary(EOpAdd, positionZ->deepCopy(), positionW->deepCopy());
1404
+    TIntermBinary *halfZPlusW = new TIntermBinary(EOpMul, zPlusW, oneHalf->deepCopy());
1405
+
1406
+    // Create the assignment "gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5"
1407
+    TIntermTyped *positionZLHS = positionZ->deepCopy();
1408
+    TIntermBinary *assignment  = new TIntermBinary(TOperator::EOpAssign, positionZLHS, halfZPlusW);
1409
+
1410
+    // Append the assignment as a statement at the end of the shader.
1411
+    return RunAtTheEndOfShader(&compiler, &root, assignment, &symbolTable);
1412
+}
1413
+
1414
+// This operation performs Android pre-rotation and y-flip.  For Android (and potentially other
1415
+// platforms), the device may rotate, such that the orientation of the application is rotated
1416
+// relative to the native orientation of the device.  This is corrected in part by multiplying
1417
+// gl_Position by a mat2.
1418
+// The equations reduce to an expression:
1419
+//
1420
+//     gl_Position.xy = gl_Position.xy * preRotation
1421
+ANGLE_NO_DISCARD bool AppendPreRotation(TCompiler &compiler,
1422
+                                        TIntermBlock &root,
1423
+                                        const TVariable &driverUniforms)
1424
+{
1425
+    TSymbolTable &symbolTable     = compiler.getSymbolTable();
1426
+    TIntermBinary *preRotationRef = CreateDriverUniformRef(driverUniforms, kPreRotation);
1427
+    TIntermSymbol *glPos          = new TIntermSymbol(BuiltInVariable::gl_Position());
1428
+    TVector<int> swizzleOffsetXY  = {0, 1};
1429
+    TIntermSwizzle *glPosXY       = new TIntermSwizzle(glPos, swizzleOffsetXY);
1430
+
1431
+    // Create the expression "(gl_Position.xy * preRotation)"
1432
+    TIntermBinary *zRotated =
1433
+        new TIntermBinary(EOpMatrixTimesVector, preRotationRef->deepCopy(), glPosXY->deepCopy());
1434
+
1435
+    // Create the assignment "gl_Position.xy = (gl_Position.xy * preRotation)"
1436
+    TIntermBinary *assignment =
1437
+        new TIntermBinary(TOperator::EOpAssign, glPosXY->deepCopy(), zRotated);
1438
+
1439
+    // Append the assignment as a statement at the end of the shader.
1440
+    return RunAtTheEndOfShader(&compiler, &root, assignment, &symbolTable);
1441
+}
1442
+
1443
+ANGLE_NO_DISCARD bool RotateAndFlipBuiltinVariable(TCompiler &compiler,
1444
+                                                   TIntermBlock &root,
1445
+                                                   TIntermSequence &insertSequence,
1446
+                                                   TIntermTyped &flipXY,
1447
+                                                   const TVariable &builtin,
1448
+                                                   const Name &flippedVariableName,
1449
+                                                   TIntermTyped &pivot,
1450
+                                                   TIntermTyped *fragRotation)
1451
+{
1452
+    TSymbolTable &symbolTable = compiler.getSymbolTable();
1453
+
1454
+    // Create a symbol reference to 'builtin'.
1455
+    TIntermSymbol *builtinRef = new TIntermSymbol(&builtin);
1456
+
1457
+    // Create a swizzle to "builtin.xy"
1458
+    TVector<int> swizzleOffsetXY = {0, 1};
1459
+    TIntermSwizzle *builtinXY    = new TIntermSwizzle(builtinRef, swizzleOffsetXY);
1460
+
1461
+    // Create a symbol reference to our new variable that will hold the modified builtin.
1462
+    const TType *type = StaticType::GetForVec<EbtFloat>(
1463
+        EvqGlobal, static_cast<unsigned char>(builtin.getType().getNominalSize()));
1464
+    TVariable *replacementVar = new TVariable(&symbolTable, flippedVariableName.rawName(), type,
1465
+                                              flippedVariableName.symbolType());
1466
+    DeclareGlobalVariable(&root, replacementVar);
1467
+    TIntermSymbol *flippedBuiltinRef = new TIntermSymbol(replacementVar);
1468
+
1469
+    // Use this new variable instead of 'builtin' everywhere.
1470
+    if (!ReplaceVariable(&compiler, &root, &builtin, replacementVar))
1471
+    {
1472
+        return false;
1473
+    }
1474
+
1475
+    // Create the expression "(builtin.xy * fragRotation)"
1476
+    TIntermTyped *rotatedXY;
1477
+    if (fragRotation)
1478
+    {
1479
+        rotatedXY = new TIntermBinary(EOpMatrixTimesVector, fragRotation->deepCopy(),
1480
+                                      builtinXY->deepCopy());
1481
+    }
1482
+    else
1483
+    {
1484
+        // No rotation applied, use original variable.
1485
+        rotatedXY = builtinXY->deepCopy();
1486
+    }
1487
+
1488
+    // Create the expression "(builtin.xy - pivot) * flipXY + pivot
1489
+    TIntermBinary *removePivot = new TIntermBinary(EOpSub, rotatedXY, &pivot);
1490
+    TIntermBinary *inverseXY   = new TIntermBinary(EOpMul, removePivot, &flipXY);
1491
+    TIntermBinary *plusPivot   = new TIntermBinary(EOpAdd, inverseXY, pivot.deepCopy());
1492
+
1493
+    // Create the corrected variable and copy the value of the original builtin.
1494
+    TIntermSequence *sequence = new TIntermSequence();
1495
+    sequence->push_back(builtinRef->deepCopy());
1496
+    TIntermAggregate *aggregate = TIntermAggregate::CreateConstructor(builtin.getType(), sequence);
1497
+    TIntermBinary *assignment   = new TIntermBinary(EOpInitialize, flippedBuiltinRef, aggregate);
1498
+
1499
+    // Create an assignment to the replaced variable's .xy.
1500
+    TIntermSwizzle *correctedXY =
1501
+        new TIntermSwizzle(flippedBuiltinRef->deepCopy(), swizzleOffsetXY);
1502
+    TIntermBinary *assignToY = new TIntermBinary(EOpAssign, correctedXY, plusPivot);
1503
+
1504
+    // Add this assigment at the beginning of the main function
1505
+    {
1506
+        TIntermBinary *nodes[] = {assignment, assignToY};
1507
+        insertSequence.insert(insertSequence.begin(), std::begin(nodes), std::end(nodes));
1508
+    }
1509
+
1510
+    return compiler.validateAST(&root);
1511
+}
1512
+
1513
+ANGLE_NO_DISCARD bool InsertFragCoordCorrection(TCompiler &compiler,
1514
+                                                ShCompileOptions compileOptions,
1515
+                                                TIntermBlock &root,
1516
+                                                TIntermSequence &insertSequence,
1517
+                                                const TVariable &driverUniforms)
1518
+{
1519
+    TIntermBinary &flipXY       = *CreateDriverUniformRef(driverUniforms, kFlipXY);
1520
+    TIntermBinary &pivot        = *CreateDriverUniformRef(driverUniforms, kHalfRenderArea);
1521
+    TIntermBinary *fragRotation = (compileOptions & SH_ADD_PRE_ROTATION)
1522
+                                      ? CreateDriverUniformRef(driverUniforms, kFragRotation)
1523
+                                      : nullptr;
1524
+    return RotateAndFlipBuiltinVariable(compiler, root, insertSequence, flipXY,
1525
+                                        *BuiltInVariable::gl_FragCoord(), kFlippedFragCoordName,
1526
+                                        pivot, fragRotation);
1527
+}
1528
+
1529
+TIntermBinary *GetDriverUniformDepthRangeReservedFieldRef(const TVariable &driverUniforms)
1530
+{
1531
+    TIntermBinary *depthRange = CreateDriverUniformRef(driverUniforms, kDepthRange);
1532
+
1533
+    return new TIntermBinary(EOpIndexDirectStruct, depthRange, CreateIndexNode(3));
1534
+}
1535
+
1536
+void DeclareRightBeforeMain(TIntermBlock &root, const TVariable &var)
1537
+{
1538
+    root.insertChildNodes(FindMainIndex(&root), {new TIntermDeclaration{&var}});
1539
+}
1540
+
1541
+void AddFragColorDeclaration(TIntermBlock &root, TSymbolTable &symbolTable)
1542
+{
1543
+    root.insertChildNodes(FindMainIndex(&root),
1544
+                          TIntermSequence{new TIntermDeclaration{BuiltInVariable::gl_FragColor()}});
1545
+}
1546
+
1547
+void AddFragDepthDeclaration(TIntermBlock &root, TSymbolTable &symbolTable)
1548
+{
1549
+    root.insertChildNodes(FindMainIndex(&root),
1550
+                          TIntermSequence{new TIntermDeclaration{BuiltInVariable::gl_FragDepth()}});
1551
+}
1552
+
1553
+ANGLE_NO_DISCARD bool AddFragDataDeclaration(TCompiler &compiler, TIntermBlock &root)
1554
+{
1555
+    TSymbolTable &symbolTable = compiler.getSymbolTable();
1556
+    const int maxDrawBuffers  = compiler.getResources().MaxDrawBuffers;
1557
+    TType *gl_FragDataType    = new TType(EbtFloat, EbpMedium, EvqFragData, 4, 1);
1558
+    std::vector<const TVariable *> glFragDataSlots;
1559
+    TIntermSequence declareGLFragdataSequence;
1560
+
1561
+    // Create gl_FragData_0,1,2,3
1562
+    for (int i = 0; i < maxDrawBuffers; i++)
1563
+    {
1564
+        ImmutableStringBuilder builder(strlen("gl_FragData_") + 2);
1565
+        builder << "gl_FragData_";
1566
+        builder.appendDecimal(i);
1567
+        const TVariable *glFragData =
1568
+            new TVariable(&symbolTable, builder, gl_FragDataType, SymbolType::AngleInternal,
1569
+                          TExtension::UNDEFINED);
1570
+        glFragDataSlots.push_back(glFragData);
1571
+        declareGLFragdataSequence.push_back(new TIntermDeclaration{glFragData});
1572
+    }
1573
+    root.insertChildNodes(FindMainIndex(&root), declareGLFragdataSequence);
1574
+
1575
+    // Create an internal gl_FragData array type, compatible with indexing syntax.
1576
+    TType *gl_FragDataTypeArray = new TType(EbtFloat, EbpMedium, EvqGlobal, 4, 1);
1577
+    gl_FragDataTypeArray->makeArray(maxDrawBuffers);
1578
+    const TVariable *glFragDataGlobal = new TVariable(&symbolTable, ImmutableString("gl_FragData"),
1579
+                                                      gl_FragDataTypeArray, SymbolType::BuiltIn);
1580
+
1581
+    DeclareGlobalVariable(&root, glFragDataGlobal);
1582
+    const TIntermSymbol *originalGLFragData = FindSymbolNode(&root, ImmutableString("gl_FragData"));
1583
+    ASSERT(originalGLFragData);
1584
+
1585
+    // Replace gl_FragData() with our globally defined fragdata
1586
+    if (!ReplaceVariable(&compiler, &root, &(originalGLFragData->variable()), glFragDataGlobal))
1587
+    {
1588
+        return false;
1589
+    }
1590
+
1591
+    // Assign each array attribute to an output
1592
+    TIntermBlock *insertSequence = new TIntermBlock();
1593
+    for (int i = 0; i < maxDrawBuffers; i++)
1594
+    {
1595
+        TIntermTyped *glFragDataSlot         = new TIntermSymbol(glFragDataSlots[i]);
1596
+        TIntermTyped *glFragDataGlobalSymbol = new TIntermSymbol(glFragDataGlobal);
1597
+        auto &access                         = AccessIndex(*glFragDataGlobalSymbol, i);
1598
+        TIntermBinary *assignment =
1599
+            new TIntermBinary(TOperator::EOpAssign, glFragDataSlot, &access);
1600
+        insertSequence->appendStatement(assignment);
1601
+    }
1602
+    return RunAtTheEndOfShader(&compiler, &root, insertSequence, &symbolTable);
1603
+}
1604
+
1605
+ANGLE_NO_DISCARD bool EmulateInstanceID(TCompiler &compiler,
1606
+                                        TIntermBlock &root,
1607
+                                        const TVariable &driverUniforms)
1608
+{
1609
+    TIntermBinary *emuInstanceID =
1610
+        CreateDriverUniformRef(driverUniforms, kEmuInstanceIDField.rawName().data());
1611
+    const TVariable *instanceID = BuiltInVariable::gl_InstanceIndex();
1612
+    return ReplaceVariableWithTyped(&compiler, &root, instanceID, emuInstanceID);
1613
+}
1614
+
1615
+// Unlike Vulkan having auto viewport flipping extension, in Metal we have to flip gl_Position.y
1616
+// manually.
1617
+// This operation performs flipping the gl_Position.y using this expression:
1618
+// gl_Position.y = gl_Position.y * negViewportScaleY
1619
+ANGLE_NO_DISCARD bool AppendVertexShaderPositionYCorrectionToMain(TCompiler &compiler,
1620
+                                                                  TIntermBlock &root,
1621
+                                                                  TIntermSwizzle &negFlipY)
1622
+{
1623
+    TSymbolTable &symbolTable = compiler.getSymbolTable();
1624
+
1625
+    const TVariable *position  = BuiltInVariable::gl_Position();
1626
+    TIntermSymbol *positionRef = new TIntermSymbol(position);
1627
+
1628
+    TVector<int> swizzleOffsetY;
1629
+    swizzleOffsetY.push_back(1);
1630
+    TIntermSwizzle *positionY = new TIntermSwizzle(positionRef, swizzleOffsetY);
1631
+
1632
+    // Create the expression "gl_Position.y * negFlipY"
1633
+    TIntermBinary *inverseY = new TIntermBinary(EOpMul, positionY->deepCopy(), &negFlipY);
1634
+
1635
+    // Create the assignment "gl_Position.y = gl_Position.y * negViewportScaleY
1636
+    TIntermTyped *positionYLHS = positionY->deepCopy();
1637
+    TIntermBinary *assignment  = new TIntermBinary(TOperator::EOpAssign, positionYLHS, inverseY);
1638
+
1639
+    // Append the assignment as a statement at the end of the shader.
1640
+    return RunAtTheEndOfShader(&compiler, &root, assignment, &symbolTable);
1641
+}
1642
+
1643
+}  // namespace
1644
+
1645
+TranslatorMetalDirect::TranslatorMetalDirect(sh::GLenum type,
1646
+                                             ShShaderSpec spec,
1647
+                                             ShShaderOutput output)
1648
+    : TCompiler(type, spec, output)
1649
+{}
1650
+
1651
+// static
1652
+const char *TranslatorMetalDirect::GetCoverageMaskEnabledConstName()
1653
+{
1654
+    return constant_names::kCoverageMaskEnabled.rawName().data();
1655
+}
1656
+
1657
+// static
1658
+const char *TranslatorMetalDirect::GetRasterizationDiscardEnabledConstName()
1659
+{
1660
+    return constant_names::kRasterizationDiscardEnabled.rawName().data();
1661
+}
1662
+
1663
+ANGLE_NO_DISCARD bool TranslatorMetalDirect::insertRasterizationDiscardLogic(TIntermBlock &root)
1664
+{
1665
+    TSymbolTable *symbolTable = &getSymbolTable();
1666
+
1667
+    TType *boolType = new TType(EbtBool);
1668
+    boolType->setQualifier(EvqConst);
1669
+    TVariable *discardEnabledVar =
1670
+        new TVariable(symbolTable, constant_names::kRasterizationDiscardEnabled.rawName(), boolType,
1671
+                      constant_names::kRasterizationDiscardEnabled.symbolType());
1672
+
1673
+    const TVariable *position  = BuiltInVariable::gl_Position();
1674
+    TIntermSymbol *positionRef = new TIntermSymbol(position);
1675
+
1676
+    // Create vec4(-3, -3, -3, 1):
1677
+    auto vec4Type             = new TType(EbtFloat, 4);
1678
+    TIntermSequence *vec4Args = new TIntermSequence();
1679
+    vec4Args->push_back(CreateFloatNode(-3.0f));
1680
+    vec4Args->push_back(CreateFloatNode(-3.0f));
1681
+    vec4Args->push_back(CreateFloatNode(-3.0f));
1682
+    vec4Args->push_back(CreateFloatNode(1.0f));
1683
+    TIntermAggregate *constVarConstructor =
1684
+        TIntermAggregate::CreateConstructor(*vec4Type, vec4Args);
1685
+
1686
+    // Create the assignment "gl_Position = vec4(-3, -3, -3, 1)"
1687
+    TIntermBinary *assignment =
1688
+        new TIntermBinary(TOperator::EOpAssign, positionRef->deepCopy(), constVarConstructor);
1689
+
1690
+    TIntermBlock *discardBlock = new TIntermBlock;
1691
+    discardBlock->appendStatement(assignment);
1692
+
1693
+    TIntermSymbol *discardEnabled = new TIntermSymbol(discardEnabledVar);
1694
+    TIntermIfElse *ifCall         = new TIntermIfElse(discardEnabled, discardBlock, nullptr);
1695
+
1696
+    return RunAtTheEndOfShader(this, &root, ifCall, symbolTable);
1697
+}
1698
+
1699
+// Metal needs to inverse the depth if depthRange is is reverse order, i.e. depth near > depth far
1700
+// This is achieved by multiply the depth value with scale value stored in
1701
+// driver uniform's depthRange.reserved
1702
+bool TranslatorMetalDirect::transformDepthBeforeCorrection(TIntermBlock &root,
1703
+                                                           const TVariable &driverUniforms)
1704
+{
1705
+    const TVariable *position  = BuiltInVariable::gl_Position();
1706
+    TIntermSymbol *positionRef = new TIntermSymbol(position);
1707
+
1708
+    TVector<int> swizzleOffsetZ = {2};
1709
+    TIntermSwizzle *positionZ   = new TIntermSwizzle(positionRef, swizzleOffsetZ);
1710
+
1711
+    TIntermBinary *viewportZScale = GetDriverUniformDepthRangeReservedFieldRef(driverUniforms);
1712
+
1713
+    // Create the expression "gl_Position.z * depthRange.reserved".
1714
+    TIntermBinary *zScale = new TIntermBinary(EOpMul, positionZ->deepCopy(), viewportZScale);
1715
+
1716
+    // Create the assignment "gl_Position.z = gl_Position.z * depthRange.reserved"
1717
+    TIntermTyped *positionZLHS = positionZ->deepCopy();
1718
+    TIntermBinary *assignment  = new TIntermBinary(TOperator::EOpAssign, positionZLHS, zScale);
1719
+
1720
+    return RunAtTheEndOfShader(this, &root, assignment, &getSymbolTable());
1721
+}
1722
+
1723
+void TranslatorMetalDirect::createAdditionalGraphicsDriverUniformFields(
1724
+    std::vector<TField *> &fieldsOut)
1725
+{
1726
+    // Add coverage mask to driver uniform. Metal doesn't have built-in GL_SAMPLE_COVERAGE_VALUE
1727
+    // equivalent functionality, needs to emulate it using fragment shader's [[sample_mask]] output
1728
+    // value.
1729
+    TField *coverageMaskField = new TField(new TType(EbtUInt), kCoverageMaskField.rawName(),
1730
+                                           kNoSourceLoc, kCoverageMaskField.symbolType());
1731
+    fieldsOut.push_back(coverageMaskField);
1732
+
1733
+    if (mEmulatedInstanceID)
1734
+    {
1735
+        TField *emuInstanceIDField = new TField(new TType(EbtInt), kEmuInstanceIDField.rawName(),
1736
+                                                kNoSourceLoc, kEmuInstanceIDField.symbolType());
1737
+        fieldsOut.push_back(emuInstanceIDField);
1738
+    }
1739
+}
1740
+
1741
+TIntermSwizzle *TranslatorMetalDirect::getDriverUniformNegFlipYRef(
1742
+    const TVariable &driverUniforms) const
1743
+{
1744
+    // Create a swizzle to "negFlipXY.y"
1745
+    TIntermBinary *negFlipXY    = CreateDriverUniformRef(driverUniforms, kNegFlipXY);
1746
+    TVector<int> swizzleOffsetY = {1};
1747
+    TIntermSwizzle *negFlipY    = new TIntermSwizzle(negFlipXY, swizzleOffsetY);
1748
+    return negFlipY;
1749
+}
1750
+
1751
+static std::set<ImmutableString> GetMslKeywords()
1752
+{
1753
+    std::set<ImmutableString> keywords;
1754
+
1755
+    keywords.emplace("alignas");
1756
+    keywords.emplace("alignof");
1757
+    keywords.emplace("as_type");
1758
+    keywords.emplace("auto");
1759
+    keywords.emplace("catch");
1760
+    keywords.emplace("char");
1761
+    keywords.emplace("class");
1762
+    keywords.emplace("const_cast");
1763
+    keywords.emplace("constant");
1764
+    keywords.emplace("constexpr");
1765
+    keywords.emplace("decltype");
1766
+    keywords.emplace("delete");
1767
+    keywords.emplace("device");
1768
+    keywords.emplace("dynamic_cast");
1769
+    keywords.emplace("enum");
1770
+    keywords.emplace("explicit");
1771
+    keywords.emplace("export");
1772
+    keywords.emplace("extern");
1773
+    keywords.emplace("fragment");
1774
+    keywords.emplace("friend");
1775
+    keywords.emplace("goto");
1776
+    keywords.emplace("half");
1777
+    keywords.emplace("inline");
1778
+    keywords.emplace("int16_t");
1779
+    keywords.emplace("int32_t");
1780
+    keywords.emplace("int64_t");
1781
+    keywords.emplace("int8_t");
1782
+    keywords.emplace("kernel");
1783
+    keywords.emplace("long");
1784
+    keywords.emplace("main0");
1785
+    keywords.emplace("metal");
1786
+    keywords.emplace("mutable");
1787
+    keywords.emplace("namespace");
1788
+    keywords.emplace("new");
1789
+    keywords.emplace("noexcept");
1790
+    keywords.emplace("nullptr_t");
1791
+    keywords.emplace("nullptr");
1792
+    keywords.emplace("operator");
1793
+    keywords.emplace("override");
1794
+    keywords.emplace("private");
1795
+    keywords.emplace("protected");
1796
+    keywords.emplace("ptrdiff_t");
1797
+    keywords.emplace("public");
1798
+    keywords.emplace("ray_data");
1799
+    keywords.emplace("register");
1800
+    keywords.emplace("short");
1801
+    keywords.emplace("signed");
1802
+    keywords.emplace("size_t");
1803
+    keywords.emplace("sizeof");
1804
+    keywords.emplace("stage_in");
1805
+    keywords.emplace("static_assert");
1806
+    keywords.emplace("static_cast");
1807
+    keywords.emplace("static");
1808
+    keywords.emplace("template");
1809
+    keywords.emplace("this");
1810
+    keywords.emplace("thread_local");
1811
+    keywords.emplace("thread");
1812
+    keywords.emplace("threadgroup_imageblock");
1813
+    keywords.emplace("threadgroup");
1814
+    keywords.emplace("throw");
1815
+    keywords.emplace("try");
1816
+    keywords.emplace("typedef");
1817
+    keywords.emplace("typeid");
1818
+    keywords.emplace("typename");
1819
+    keywords.emplace("uchar");
1820
+    keywords.emplace("uint16_t");
1821
+    keywords.emplace("uint32_t");
1822
+    keywords.emplace("uint64_t");
1823
+    keywords.emplace("uint8_t");
1824
+    keywords.emplace("union");
1825
+    keywords.emplace("unsigned");
1826
+    keywords.emplace("ushort");
1827
+    keywords.emplace("using");
1828
+    keywords.emplace("vertex");
1829
+    keywords.emplace("virtual");
1830
+    keywords.emplace("volatile");
1831
+    keywords.emplace("wchar_t");
1832
+
1833
+    return keywords;
1834
+}
1835
+
1836
+bool TranslatorMetalDirect::translateImpl(TIntermBlock &root, ShCompileOptions compileOptions)
1837
+{
1838
+    TSymbolTable &symbolTable = getSymbolTable();
1839
+    IdGen idGen;
1840
+    ProgramPreludeConfig ppc;
1841
+
1842
+    if (!WrapMain(*this, idGen, root))
1843
+    {
1844
+        return false;
1845
+    }
1846
+
1847
+    TInfoSinkBase &sink = getInfoSink().obj;
1848
+#if 0
1849
+    if (getShaderType() == GL_VERTEX_SHADER)
1850
+    {
1851
+        if (!ShaderBuiltinsWorkaround(this, &root, &symbolTable, compileOptions))
1852
+        {
1853
+            return false;
1854
+        }
1855
+    }
1856
+#endif
1857
+
1858
+    // Strip any inactive variables from the program.
1859
+    if (!RemoveInactiveInterfaceVariables(this, &root, getAttributes(), getInputVaryings(),
1860
+                                          getOutputVariables(), getUniforms(),
1861
+                                          getInterfaceBlocks()))
1862
+    {
1863
+        return false;
1864
+    }
1865
+
1866
+    // Write out default uniforms into a uniform block assigned to a specific set/binding.
1867
+    int defaultUniformCount           = 0;
1868
+    int aggregateTypesUsedForUniforms = 0;
1869
+    int atomicCounterCount            = 0;
1870
+    for (const auto &uniform : getUniforms())
1871
+    {
1872
+        if (!uniform.isBuiltIn() && uniform.active && !gl::IsOpaqueType(uniform.type))
1873
+        {
1874
+            ++defaultUniformCount;
1875
+        }
1876
+
1877
+        if (uniform.isStruct() || uniform.isArrayOfArrays())
1878
+        {
1879
+            ++aggregateTypesUsedForUniforms;
1880
+        }
1881
+
1882
+        if (uniform.active && gl::IsAtomicCounterType(uniform.type))
1883
+        {
1884
+            ++atomicCounterCount;
1885
+        }
1886
+    }
1887
+
1888
+    if (aggregateTypesUsedForUniforms > 0)
1889
+    {
1890
+        if (!NameEmbeddedStructUniforms(this, &root, &symbolTable))
1891
+        {
1892
+            return false;
1893
+        }
1894
+
1895
+        bool rewriteStructSamplersResult;
1896
+        int removedUniformsCount;
1897
+
1898
+        if (compileOptions & SH_USE_OLD_REWRITE_STRUCT_SAMPLERS)
1899
+        {
1900
+            rewriteStructSamplersResult =
1901
+                RewriteStructSamplersOld(this, &root, &symbolTable, &removedUniformsCount);
1902
+        }
1903
+        else
1904
+        {
1905
+            rewriteStructSamplersResult =
1906
+                RewriteStructSamplers(this, &root, &symbolTable, &removedUniformsCount);
1907
+        }
1908
+
1909
+        if (!rewriteStructSamplersResult)
1910
+        {
1911
+            return false;
1912
+        }
1913
+        defaultUniformCount -= removedUniformsCount;
1914
+
1915
+#if 0
1916
+        // We must declare the struct types before using them.
1917
+        DeclareStructTypesTraverser structTypesTraverser(outputMSL);
1918
+        root->traverse(&structTypesTraverser);
1919
+        if (!structTypesTraverser.updateTree(this, root))
1920
+        {
1921
+            return false;
1922
+        }
1923
+#endif
1924
+    }
1925
+
1926
+    if (compileOptions & SH_EMULATE_SEAMFUL_CUBE_MAP_SAMPLING)
1927
+    {
1928
+        if (!RewriteCubeMapSamplersAs2DArray(this, &root, &symbolTable,
1929
+                                             getShaderType() == GL_FRAGMENT_SHADER))
1930
+        {
1931
+            return false;
1932
+        }
1933
+    }
1934
+
1935
+#if 0
1936
+    // Write default uniform block
1937
+    if (defaultUniformCount > 0)
1938
+    {
1939
+        gl::ShaderType shaderType = gl::FromGLenum<gl::ShaderType>(getShaderType());
1940
+        sink << "\nstruct " << kDefaultUniformNames[shaderType] << "\n{\n";
1941
+        DeclareDefaultUniformsTraverser defaultTraverser(&sink, getHashFunction(), &getNameMap());
1942
+        root->traverse(&defaultTraverser);
1943
+        if (!defaultTraverser.updateTree(this, root))
1944
+        {
1945
+            return false;
1946
+        }
1947
+
1948
+        sink << "};\n";
1949
+    }
1950
+#endif
1951
+
1952
+    const TVariable &driverUniforms = *[&]() {
1953
+        if (getShaderType() == GL_COMPUTE_SHADER)
1954
+        {
1955
+            return AddComputeDriverUniformsToShader(root, symbolTable);
1956
+        }
1957
+        else
1958
+        {
1959
+            std::vector<TField *> additionalFields;
1960
+            createAdditionalGraphicsDriverUniformFields(additionalFields);
1961
+            return AddGraphicsDriverUniformsToShader(root, symbolTable, additionalFields);
1962
+        }
1963
+    }();
1964
+
1965
+    if (atomicCounterCount > 0)
1966
+    {
1967
+        // ANGLEUniforms.acbBufferOffsets
1968
+        const TIntermBinary *acbBufferOffsets =
1969
+            CreateDriverUniformRef(driverUniforms, kAcbBufferOffsets);
1970
+
1971
+        if (!RewriteAtomicCounters(this, &root, &symbolTable, acbBufferOffsets))
1972
+        {
1973
+            return false;
1974
+        }
1975
+    }
1976
+    else if (getShaderVersion() >= 310)
1977
+    {
1978
+        // Vulkan doesn't support Atomic Storage as a Storage Class, but we've seen
1979
+        // cases where builtins are using it even with no active atomic counters.
1980
+        // This pass simply removes those builtins in that scenario.
1981
+        if (!RemoveAtomicCounterBuiltins(this, &root))
1982
+        {
1983
+            return false;
1984
+        }
1985
+    }
1986
+
1987
+    if (getShaderType() != GL_COMPUTE_SHADER)
1988
+    {
1989
+        if (!ReplaceGLDepthRangeWithDriverUniform(*this, root, driverUniforms))
1990
+        {
1991
+            return false;
1992
+        }
1993
+
1994
+#if 0
1995
+        // Add specialization constant declarations.  The default value of the specialization
1996
+        // constant is irrelevant, as it will be set when creating the pipeline.
1997
+        if (compileOptions & SH_ADD_BRESENHAM_LINE_RASTER_EMULATION)
1998
+        {
1999
+            sink << "layout(constant_id="
2000
+                 << static_cast<uint32_t>(vk::SpecializationConstantId::LineRasterEmulation)
2001
+                 << ") const bool " << kLineRasterEmulationSpecConstVarName << " = false;\n\n";
2002
+        }
2003
+#endif
2004
+    }
2005
+
2006
+    {
2007
+        bool usesInstanceId = false;
2008
+        for (const ShaderVariable &var : mAttributes)
2009
+        {
2010
+            if (var.isBuiltIn())
2011
+            {
2012
+                if (var.name == "gl_InstanceID")
2013
+                {
2014
+                    usesInstanceId = true;
2015
+                }
2016
+            }
2017
+        }
2018
+
2019
+        if (usesInstanceId)
2020
+        {
2021
+            root.insertChildNodes(
2022
+                FindMainIndex(&root),
2023
+                TIntermSequence{new TIntermDeclaration{BuiltInVariable::gl_InstanceID()}});
2024
+        }
2025
+    }
2026
+
2027
+    // Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData
2028
+    // if it's core profile shaders and they are used.
2029
+    if (getShaderType() == GL_FRAGMENT_SHADER)
2030
+    {
2031
+        bool usesPointCoord  = false;
2032
+        bool usesFragCoord   = false;
2033
+        bool usesFrontFacing = false;
2034
+        for (const ShaderVariable &inputVarying : mInputVaryings)
2035
+        {
2036
+            if (inputVarying.isBuiltIn())
2037
+            {
2038
+                if (inputVarying.name == "gl_PointCoord")
2039
+                {
2040
+                    usesPointCoord = true;
2041
+                }
2042
+                else if (inputVarying.name == "gl_FragCoord")
2043
+                {
2044
+                    usesFragCoord = true;
2045
+                }
2046
+                else if (inputVarying.name == "gl_FrontFacing")
2047
+                {
2048
+                    usesFrontFacing = true;
2049
+                }
2050
+            }
2051
+        }
2052
+
2053
+        bool usesFragColor = false;
2054
+        bool usesFragData  = false;
2055
+        bool usesFragDepth = false;
2056
+        for (const ShaderVariable &outputVarying : mOutputVariables)
2057
+        {
2058
+            if (outputVarying.isBuiltIn())
2059
+            {
2060
+                if (outputVarying.name == "gl_FragColor")
2061
+                {
2062
+                    usesFragColor = true;
2063
+                }
2064
+                else if (outputVarying.name == "gl_FragData")
2065
+                {
2066
+                    usesFragData = true;
2067
+                }
2068
+                else if (outputVarying.name == "gl_FragDepth")
2069
+                {
2070
+                    usesFragDepth = true;
2071
+                }
2072
+            }
2073
+        }
2074
+
2075
+        if (usesFragColor && usesFragData)
2076
+        {
2077
+            return false;
2078
+        }
2079
+
2080
+        if (usesFragColor)
2081
+        {
2082
+            AddFragColorDeclaration(root, symbolTable);
2083
+        }
2084
+
2085
+        if (usesFragData)
2086
+        {
2087
+            if (!AddFragDataDeclaration(*this, root))
2088
+            {
2089
+                return false;
2090
+            }
2091
+        }
2092
+
2093
+        if (usesFragDepth)
2094
+        {
2095
+            AddFragDepthDeclaration(root, symbolTable);
2096
+        }
2097
+
2098
+#if 0
2099
+        if (compileOptions & SH_ADD_BRESENHAM_LINE_RASTER_EMULATION)
2100
+        {
2101
+            if (!AddBresenhamEmulationFS(this, compileOptions, sink, root, &symbolTable,
2102
+                                         driverUniforms, usesFragCoord))
2103
+            {
2104
+                return false;
2105
+            }
2106
+        }
2107
+#endif
2108
+
2109
+        bool usePreRotation = compileOptions & SH_ADD_PRE_ROTATION;
2110
+
2111
+        if (usesPointCoord)
2112
+        {
2113
+            TIntermBinary &flipXY       = *CreateDriverUniformRef(driverUniforms, kNegFlipXY);
2114
+            TIntermConstantUnion &pivot = *CreateFloatNode(0.5f);
2115
+            TIntermBinary *fragRotation =
2116
+                usePreRotation ? CreateDriverUniformRef(driverUniforms, kFragRotation) : nullptr;
2117
+            if (!RotateAndFlipBuiltinVariable(*this, root, *GetMainSequence(root), flipXY,
2118
+                                              *BuiltInVariable::gl_PointCoord(),
2119
+                                              kFlippedPointCoordName, pivot, fragRotation))
2120
+            {
2121
+                return false;
2122
+            }
2123
+            DeclareRightBeforeMain(root, *BuiltInVariable::gl_PointCoord());
2124
+        }
2125
+
2126
+        if (usesFragCoord)
2127
+        {
2128
+            if (!InsertFragCoordCorrection(*this, compileOptions, root, *GetMainSequence(root),
2129
+                                           driverUniforms))
2130
+            {
2131
+                return false;
2132
+            }
2133
+            DeclareRightBeforeMain(root, *BuiltInVariable::gl_FragCoord());
2134
+        }
2135
+
2136
+        {
2137
+            TIntermBinary *flipXY = CreateDriverUniformRef(driverUniforms, kFlipXY);
2138
+            TIntermBinary *fragRotation =
2139
+                usePreRotation ? CreateDriverUniformRef(driverUniforms, kFragRotation) : nullptr;
2140
+            if (!RewriteDfdy(this, &root, symbolTable, getShaderVersion(), flipXY, fragRotation))
2141
+            {
2142
+                return false;
2143
+            }
2144
+        }
2145
+
2146
+        if (usesFrontFacing)
2147
+        {
2148
+            DeclareRightBeforeMain(root, *BuiltInVariable::gl_FrontFacing());
2149
+        }
2150
+
2151
+        EmitEarlyFragmentTestsGLSL(*this, sink);
2152
+    }
2153
+    else if (getShaderType() == GL_VERTEX_SHADER)
2154
+    {
2155
+        DeclareRightBeforeMain(root, *BuiltInVariable::gl_Position());
2156
+
2157
+        if (FindSymbolNode(&root, BuiltInVariable::gl_PointSize()->name()))
2158
+        {
2159
+            DeclareRightBeforeMain(root, *BuiltInVariable::gl_PointSize());
2160
+        }
2161
+
2162
+        if (FindSymbolNode(&root, BuiltInVariable::gl_VertexIndex()->name()))
2163
+        {
2164
+            if (!ReplaceVariable(this, &root, BuiltInVariable::gl_VertexIndex(),
2165
+                                 &kgl_VertexIndexMetal))
2166
+            {
2167
+                return false;
2168
+            }
2169
+            DeclareRightBeforeMain(root, kgl_VertexIndexMetal);
2170
+        }
2171
+
2172
+#if 0
2173
+        if (compileOptions & SH_ADD_BRESENHAM_LINE_RASTER_EMULATION)
2174
+        {
2175
+            if (!AddBresenhamEmulationVS(this, root, &symbolTable, driverUniforms))
2176
+            {
2177
+                return false;
2178
+            }
2179
+        }
2180
+
2181
+        // Add a macro to declare transform feedback buffers.
2182
+        sink << "@@ XFB-DECL @@\n\n";
2183
+#endif
2184
+
2185
+        // Append a macro for transform feedback substitution prior to modifying depth.
2186
+        if (!AppendVertexShaderTransformFeedbackOutputToMain(*this, root))
2187
+        {
2188
+            return false;
2189
+        }
2190
+
2191
+        // Search for the gl_ClipDistance usage, if its used, we need to do some replacements.
2192
+        bool useClipDistance = false;
2193
+        for (const ShaderVariable &outputVarying : mOutputVaryings)
2194
+        {
2195
+            if (outputVarying.name == "gl_ClipDistance")
2196
+            {
2197
+                useClipDistance = true;
2198
+                break;
2199
+            }
2200
+        }
2201
+
2202
+        if (useClipDistance && !ReplaceClipDistanceAssignments(
2203
+                                   this, &root, &symbolTable,
2204
+                                   CreateDriverUniformRef(driverUniforms, kClipDistancesEnabled)))
2205
+        {
2206
+            return false;
2207
+        }
2208
+
2209
+        if (!transformDepthBeforeCorrection(root, driverUniforms))
2210
+        {
2211
+            return false;
2212
+        }
2213
+
2214
+        if (!AppendVertexShaderDepthCorrectionToMain(*this, root))
2215
+        {
2216
+            return false;
2217
+        }
2218
+
2219
+        if ((compileOptions & SH_ADD_PRE_ROTATION) != 0 &&
2220
+            !AppendPreRotation(*this, root, driverUniforms))
2221
+        {
2222
+            return false;
2223
+        }
2224
+    }
2225
+    else if (getShaderType() == GL_GEOMETRY_SHADER)
2226
+    {
2227
+        WriteGeometryShaderLayoutQualifiers(
2228
+            sink, getGeometryShaderInputPrimitiveType(), getGeometryShaderInvocations(),
2229
+            getGeometryShaderOutputPrimitiveType(), getGeometryShaderMaxVertices());
2230
+    }
2231
+    else
2232
+    {
2233
+        ASSERT(getShaderType() == GL_COMPUTE_SHADER);
2234
+        EmitWorkGroupSizeGLSL(*this, sink);
2235
+    }
2236
+
2237
+    if (getShaderType() == GL_VERTEX_SHADER)
2238
+    {
2239
+        auto &negFlipY = *getDriverUniformNegFlipYRef(driverUniforms);
2240
+
2241
+        if (mEmulatedInstanceID)
2242
+        {
2243
+            if (!EmulateInstanceID(*this, root, driverUniforms))
2244
+            {
2245
+                return false;
2246
+            }
2247
+        }
2248
+
2249
+        if (!AppendVertexShaderPositionYCorrectionToMain(*this, root, negFlipY))
2250
+        {
2251
+            return false;
2252
+        }
2253
+
2254
+        if (!insertRasterizationDiscardLogic(root))
2255
+        {
2256
+            return false;
2257
+        }
2258
+    }
2259
+
2260
+    if (!validateAST(&root))
2261
+    {
2262
+        return false;
2263
+    }
2264
+
2265
+    if (!RewriteKeywords(*this, root, idGen, GetMslKeywords()))
2266
+    {
2267
+        return false;
2268
+    }
2269
+
2270
+    if (!ReduceInterfaceBlocks(*this, root))
2271
+    {
2272
+        return false;
2273
+    }
2274
+
2275
+    if (!SeparateCompoundStructDeclarations(*this, root))
2276
+    {
2277
+        return false;
2278
+    }
2279
+
2280
+    // This is the largest size required to pass all the tests in
2281
+    // (dEQP-GLES3.functional.shaders.large_constant_arrays)
2282
+    // This value could in principle be smaller.
2283
+    const size_t hoistThresholdSize = 256;
2284
+    if (!HoistConstants(*this, root, idGen, hoistThresholdSize))
2285
+    {
2286
+        return false;
2287
+    }
2288
+
2289
+    Invariants invariants;
2290
+    if (!RewriteGlobalQualifierDecls(*this, root, invariants))
2291
+    {
2292
+        return false;
2293
+    }
2294
+
2295
+    SymbolEnv symbolEnv(*this, root);
2296
+
2297
+    if (!AddExplicitTypeCasts(*this, root, symbolEnv))
2298
+    {
2299
+        return false;
2300
+    }
2301
+
2302
+    PipelineStructs pipelineStructs;
2303
+    if (!RewritePipelines(*this, root, idGen, driverUniforms, symbolEnv, invariants,
2304
+                          pipelineStructs))
2305
+    {
2306
+        return false;
2307
+    }
2308
+
2309
+    if (!SeparateCompoundExpressions(*this, symbolEnv, idGen, root))
2310
+    {
2311
+        return false;
2312
+    }
2313
+
2314
+    if (!RewriteCaseDeclarations(*this, root))
2315
+    {
2316
+        return false;
2317
+    }
2318
+
2319
+    if (!RewriteUnaddressableReferences(*this, root, symbolEnv))
2320
+    {
2321
+        return false;
2322
+    }
2323
+
2324
+    if (!RewriteOutArgs(*this, root, symbolEnv))
2325
+    {
2326
+        return false;
2327
+    }
2328
+
2329
+    if (!ToposortStructs(*this, symbolEnv, root, ppc))
2330
+    {
2331
+        return false;
2332
+    }
2333
+
2334
+    if (!EmitMetal(*this, root, idGen, pipelineStructs, invariants, symbolEnv, ppc))
2335
+    {
2336
+        return false;
2337
+    }
2338
+
2339
+    ASSERT(validateAST(&root));
2340
+
2341
+    return true;
2342
+}
2343
+
2344
+bool TranslatorMetalDirect::translate(TIntermBlock *root,
2345
+                                      ShCompileOptions compileOptions,
2346
+                                      PerformanceDiagnostics *perfDiagnostics)
2347
+{
2348
+    if (!root)
2349
+    {
2350
+        return false;
2351
+    }
2352
+
2353
+    TInfoSinkBase &sink = getInfoSink().obj;
2354
+
2355
+    bool precisionEmulation = false;
2356
+    if (!emulatePrecisionIfNeeded(root, sink, &precisionEmulation, SH_GLSL_VULKAN_OUTPUT))
2357
+    {
2358
+        return false;
2359
+    }
2360
+
2361
+#if 0
2362
+    bool enablePrecision = ((compileOptions & SH_IGNORE_PRECISION_QUALIFIERS) == 0);
2363
+
2364
+    TOutputMSL outputMSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(),
2365
+                         &getSymbolTable(), getShaderType(), getShaderVersion(), getOutputType(),
2366
+                         precisionEmulation, enablePrecision, compileOptions);
2367
+#endif
2368
+
2369
+    if (!translateImpl(*root, compileOptions))
2370
+    {
2371
+        return false;
2372
+    }
2373
+
2374
+#if 0
2375
+    // Write translated shader.
2376
+    root->traverse(outputMSL);
2377
+#endif
2378
+
2379
+    return true;
2380
+}
2381
+bool TranslatorMetalDirect::shouldFlattenPragmaStdglInvariantAll()
2382
+{
2383
+    // Not neccesary for MSL transformation.
2384
+    return false;
2385
+}
2386
+
2387
+}  // namespace sh
2388
diff --git a/src/compiler/translator/TranslatorMetalDirect.h b/src/compiler/translator/TranslatorMetalDirect.h
2389
new file mode 100644
2390
index 0000000..efcb306
2391
--- /dev/null
2392
+++ b/src/compiler/translator/TranslatorMetalDirect.h
2393
@@ -0,0 +1,132 @@
2394
+//
2395
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
2396
+// Use of this source code is governed by a BSD-style license that can be
2397
+// found in the LICENSE file.
2398
+//
2399
+
2400
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_H_
2401
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_H_
2402
+
2403
+#include "compiler/translator/Compiler.h"
2404
+
2405
+namespace sh
2406
+{
2407
+class TOutputMSL;
2408
+
2409
+typedef std::unordered_map<size_t, std::string> originalNamesMap;
2410
+typedef std::unordered_map<std::string, size_t> samplerBindingMap;
2411
+typedef std::unordered_map<std::string, size_t> textureBindingMap;
2412
+typedef std::unordered_map<std::string, size_t> uniformBufferBindingMap;
2413
+
2414
+class TranslatorMetalReflection
2415
+{
2416
+  public:
2417
+    TranslatorMetalReflection() {}
2418
+    ~TranslatorMetalReflection() {}
2419
+
2420
+    void addOriginalName(const size_t id, const std::string &name)
2421
+    {
2422
+        originalNames.insert({id, name});
2423
+    }
2424
+    void addSamplerBinding(const std::string &name, size_t samplerBinding)
2425
+    {
2426
+        samplerBindings.insert({name, samplerBinding});
2427
+    }
2428
+    void addTextureBinding(const std::string &name, size_t textureBinding)
2429
+    {
2430
+        textureBindings.insert({name, textureBinding});
2431
+    }
2432
+    void addUniformBufferBinding(const std::string &name, size_t uniformBufferBinding)
2433
+    {
2434
+        uniformBufferBindings.insert({name, uniformBufferBinding});
2435
+    }
2436
+    std::string getOriginalName(const size_t id) { return originalNames.at(id); }
2437
+    samplerBindingMap getSamplerBindings() const { return samplerBindings; }
2438
+    textureBindingMap getTextureBindings() const { return textureBindings; }
2439
+    uniformBufferBindingMap getUniformBufferBindings() const { return uniformBufferBindings; }
2440
+    size_t getSamplerBinding(const std::string &name) const
2441
+    {
2442
+        auto it = samplerBindings.find(name);
2443
+        if (it != samplerBindings.end())
2444
+        {
2445
+            return it->second;
2446
+        }
2447
+        ASSERT(0);
2448
+        return std::numeric_limits<size_t>::max();
2449
+    }
2450
+    size_t getTextureBinding(const std::string &name) const
2451
+    {
2452
+        auto it = textureBindings.find(name);
2453
+        if (it != textureBindings.end())
2454
+        {
2455
+            return it->second;
2456
+        }
2457
+        ASSERT(0);
2458
+        return std::numeric_limits<size_t>::max();
2459
+    }
2460
+    size_t getUniformBufferBinding(const std::string &name) const
2461
+    {
2462
+        auto it = uniformBufferBindings.find(name);
2463
+        if (it != uniformBufferBindings.end())
2464
+        {
2465
+            return it->second;
2466
+        }
2467
+        ASSERT(0);
2468
+        return std::numeric_limits<size_t>::max();
2469
+    }
2470
+    void reset()
2471
+    {
2472
+        originalNames.clear();
2473
+        samplerBindings.clear();
2474
+        textureBindings.clear();
2475
+        uniformBufferBindings.clear();
2476
+    }
2477
+
2478
+  private:
2479
+    originalNamesMap originalNames;
2480
+    samplerBindingMap samplerBindings;
2481
+    textureBindingMap textureBindings;
2482
+    uniformBufferBindingMap uniformBufferBindings;
2483
+};
2484
+
2485
+class TranslatorMetalDirect : public TCompiler
2486
+{
2487
+  public:
2488
+    TranslatorMetalDirect(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output);
2489
+
2490
+#ifdef ANGLE_ENABLE_METAL
2491
+    TranslatorMetalDirect *getAsTranslatorMetalDirect() override { return this; }
2492
+#endif
2493
+
2494
+    static const char *GetCoverageMaskEnabledConstName();
2495
+    static const char *GetRasterizationDiscardEnabledConstName();
2496
+
2497
+    void enableEmulatedInstanceID(bool e) { mEmulatedInstanceID = e; }
2498
+    TranslatorMetalReflection *getTranslatorMetalReflection() { return &translatorMetalReflection; }
2499
+
2500
+  protected:
2501
+    bool translate(TIntermBlock *root,
2502
+                   ShCompileOptions compileOptions,
2503
+                   PerformanceDiagnostics *perfDiagnostics) override;
2504
+
2505
+    ANGLE_NO_DISCARD bool translateImpl(TIntermBlock &root, ShCompileOptions compileOptions);
2506
+
2507
+    ANGLE_NO_DISCARD bool shouldFlattenPragmaStdglInvariantAll() override;
2508
+
2509
+    ANGLE_NO_DISCARD bool transformDepthBeforeCorrection(TIntermBlock &root,
2510
+                                                         const TVariable &driverUniforms);
2511
+    ANGLE_NO_DISCARD bool insertRasterizationDiscardLogic(TIntermBlock &root);
2512
+
2513
+    void createAdditionalGraphicsDriverUniformFields(std::vector<TField *> &fieldsOut);
2514
+
2515
+    ANGLE_NO_DISCARD TIntermSwizzle *getDriverUniformNegFlipYRef(
2516
+        const TVariable &driverUniforms) const;
2517
+
2518
+    bool mEmulatedInstanceID = false;
2519
+
2520
+    TranslatorMetalReflection translatorMetalReflection = {};
2521
+};
2522
+
2523
+}  // namespace sh
2524
+
2525
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_H_
2526
diff --git a/src/compiler/translator/TranslatorMetalDirect/AddExplicitTypeCasts.cpp b/src/compiler/translator/TranslatorMetalDirect/AddExplicitTypeCasts.cpp
2527
new file mode 100644
2528
index 0000000..5341180
2529
--- /dev/null
2530
+++ b/src/compiler/translator/TranslatorMetalDirect/AddExplicitTypeCasts.cpp
2531
@@ -0,0 +1,95 @@
2532
+//
2533
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
2534
+// Use of this source code is governed by a BSD-style license that can be
2535
+// found in the LICENSE file.
2536
+//
2537
+
2538
+#include "compiler/translator/TranslatorMetalDirect/AddExplicitTypeCasts.h"
2539
+#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
2540
+#include "compiler/translator/tree_util/IntermRebuild.h"
2541
+
2542
+using namespace sh;
2543
+
2544
+namespace
2545
+{
2546
+
2547
+class Rewriter : public TIntermRebuild
2548
+{
2549
+    SymbolEnv &mSymbolEnv;
2550
+
2551
+  public:
2552
+    Rewriter(TCompiler &compiler, SymbolEnv &symbolEnv)
2553
+        : TIntermRebuild(compiler, false, true), mSymbolEnv(symbolEnv)
2554
+    {}
2555
+
2556
+    PostResult visitAggregatePost(TIntermAggregate &callNode) override
2557
+    {
2558
+        const size_t argCount = callNode.getChildCount();
2559
+        const TType &retType  = callNode.getType();
2560
+
2561
+        if (callNode.isConstructor())
2562
+        {
2563
+            if (IsScalarBasicType(retType))
2564
+            {
2565
+                if (argCount == 1)
2566
+                {
2567
+                    TIntermTyped &arg   = GetArg(callNode, 0);
2568
+                    const TType argType = arg.getType();
2569
+                    if (argType.isVector())
2570
+                    {
2571
+                        return CoerceSimple(retType, SubVector(arg, 0, 1));
2572
+                    }
2573
+                }
2574
+            }
2575
+            else if (retType.isVector())
2576
+            {
2577
+                if (argCount == 1)
2578
+                {
2579
+                    TIntermTyped &arg   = GetArg(callNode, 0);
2580
+                    const TType argType = arg.getType();
2581
+                    if (argType.isVector())
2582
+                    {
2583
+                        return CoerceSimple(retType, SubVector(arg, 0, retType.getNominalSize()));
2584
+                    }
2585
+                }
2586
+                for (size_t i = 0; i < argCount; ++i)
2587
+                {
2588
+                    TIntermTyped &arg = GetArg(callNode, i);
2589
+                    SetArg(callNode, i, CoerceSimple(retType.getBasicType(), arg));
2590
+                }
2591
+            }
2592
+            else if (retType.isMatrix())
2593
+            {
2594
+                if (argCount == 1)
2595
+                {
2596
+                    TIntermTyped &arg   = GetArg(callNode, 0);
2597
+                    const TType argType = arg.getType();
2598
+                    if (argType.isMatrix())
2599
+                    {
2600
+                        if (retType.getCols() != argType.getCols() ||
2601
+                            retType.getRows() != argType.getRows())
2602
+                        {
2603
+                            TemplateArg templateArgs[] = {retType.getCols(), retType.getRows()};
2604
+                            return mSymbolEnv.callFunctionOverload(
2605
+                                Name("cast"), retType, *new TIntermSequence{&arg}, 2, templateArgs);
2606
+                        }
2607
+                    }
2608
+                }
2609
+            }
2610
+        }
2611
+
2612
+        return callNode;
2613
+    }
2614
+};
2615
+
2616
+}  // anonymous namespace
2617
+
2618
+bool sh::AddExplicitTypeCasts(TCompiler &compiler, TIntermBlock &root, SymbolEnv &symbolEnv)
2619
+{
2620
+    Rewriter rewriter(compiler, symbolEnv);
2621
+    if (!rewriter.rebuildRoot(root))
2622
+    {
2623
+        return false;
2624
+    }
2625
+    return true;
2626
+}
2627
diff --git a/src/compiler/translator/TranslatorMetalDirect/AddExplicitTypeCasts.h b/src/compiler/translator/TranslatorMetalDirect/AddExplicitTypeCasts.h
2628
new file mode 100644
2629
index 0000000..5034288
2630
--- /dev/null
2631
+++ b/src/compiler/translator/TranslatorMetalDirect/AddExplicitTypeCasts.h
2632
@@ -0,0 +1,24 @@
2633
+//
2634
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
2635
+// Use of this source code is governed by a BSD-style license that can be
2636
+// found in the LICENSE file.
2637
+//
2638
+
2639
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_ADDEXPLICITTYPECASTS_H_
2640
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_ADDEXPLICITTYPECASTS_H_
2641
+
2642
+#include "compiler/translator/Compiler.h"
2643
+#include "compiler/translator/TranslatorMetalDirect/ProgramPrelude.h"
2644
+#include "compiler/translator/TranslatorMetalDirect/SymbolEnv.h"
2645
+
2646
+namespace sh
2647
+{
2648
+
2649
+// Adds explicit type casts into the AST where casting is done implicitly.
2650
+ANGLE_NO_DISCARD bool AddExplicitTypeCasts(TCompiler &compiler,
2651
+                                           TIntermBlock &root,
2652
+                                           SymbolEnv &symbolEnv);
2653
+
2654
+}  // namespace sh
2655
+
2656
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_ADDEXPLICITTYPECASTS_H_
2657
diff --git a/src/compiler/translator/TranslatorMetalDirect/AstHelpers.cpp b/src/compiler/translator/TranslatorMetalDirect/AstHelpers.cpp
2658
new file mode 100644
2659
index 0000000..4ba4ec7
2660
--- /dev/null
2661
+++ b/src/compiler/translator/TranslatorMetalDirect/AstHelpers.cpp
2662
@@ -0,0 +1,474 @@
2663
+//
2664
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
2665
+// Use of this source code is governed by a BSD-style license that can be
2666
+// found in the LICENSE file.
2667
+//
2668
+
2669
+#include <cstring>
2670
+#include <numeric>
2671
+#include <unordered_map>
2672
+#include <unordered_set>
2673
+
2674
+#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
2675
+
2676
+using namespace sh;
2677
+
2678
+////////////////////////////////////////////////////////////////////////////////
2679
+
2680
+Declaration sh::ViewDeclaration(TIntermDeclaration &declNode)
2681
+{
2682
+    ASSERT(declNode.getChildCount() == 1);
2683
+    TIntermNode *childNode = declNode.getChildNode(0);
2684
+    ASSERT(childNode);
2685
+    TIntermSymbol *symbolNode;
2686
+    if ((symbolNode = childNode->getAsSymbolNode()))
2687
+    {
2688
+        return {*symbolNode, nullptr};
2689
+    }
2690
+    else
2691
+    {
2692
+        TIntermBinary *initNode = childNode->getAsBinaryNode();
2693
+        ASSERT(initNode);
2694
+        ASSERT(initNode->getOp() == TOperator::EOpInitialize);
2695
+        symbolNode = initNode->getLeft()->getAsSymbolNode();
2696
+        ASSERT(symbolNode);
2697
+        return {*symbolNode, initNode->getRight()};
2698
+    }
2699
+}
2700
+
2701
+const TVariable &sh::CreateStructTypeVariable(TSymbolTable &symbolTable,
2702
+                                              const TStructure &structure)
2703
+{
2704
+    auto *type = new TType(&structure, true);
2705
+    auto *var  = new TVariable(&symbolTable, ImmutableString(""), type, SymbolType::Empty);
2706
+    return *var;
2707
+}
2708
+
2709
+const TVariable &sh::CreateInstanceVariable(TSymbolTable &symbolTable,
2710
+                                            const TStructure &structure,
2711
+                                            const Name &name,
2712
+                                            TQualifier qualifier,
2713
+                                            const TSpan<const unsigned int> *arraySizes)
2714
+{
2715
+    auto *type = new TType(&structure, false);
2716
+    type->setQualifier(qualifier);
2717
+    if (arraySizes)
2718
+    {
2719
+        type->makeArrays(*arraySizes);
2720
+    }
2721
+    auto *var = new TVariable(&symbolTable, name.rawName(), type, name.symbolType());
2722
+    return *var;
2723
+}
2724
+
2725
+static void AcquireFunctionExtras(TFunction &dest, const TFunction &src)
2726
+{
2727
+    if (src.isDefined())
2728
+    {
2729
+        dest.setDefined();
2730
+    }
2731
+
2732
+    if (src.hasPrototypeDeclaration())
2733
+    {
2734
+        dest.setHasPrototypeDeclaration();
2735
+    }
2736
+}
2737
+
2738
+TIntermSequence &sh::CloneSequenceAndPrepend(const TIntermSequence &seq, TIntermNode &node)
2739
+{
2740
+    auto *newSeq = new TIntermSequence();
2741
+    newSeq->push_back(&node);
2742
+
2743
+    for (TIntermNode *oldNode : seq)
2744
+    {
2745
+        newSeq->push_back(oldNode);
2746
+    }
2747
+
2748
+    return *newSeq;
2749
+}
2750
+
2751
+void sh::AddParametersFrom(TFunction &dest, const TFunction &src)
2752
+{
2753
+    const size_t paramCount = src.getParamCount();
2754
+    for (size_t i = 0; i < paramCount; ++i)
2755
+    {
2756
+        const TVariable *var = src.getParam(i);
2757
+        dest.addParameter(var);
2758
+    }
2759
+}
2760
+
2761
+const TFunction &sh::CloneFunction(TSymbolTable &symbolTable,
2762
+                                   IdGen &idGen,
2763
+                                   const TFunction &oldFunc)
2764
+{
2765
+    ASSERT(oldFunc.symbolType() == SymbolType::UserDefined);
2766
+
2767
+    Name newName = idGen.createNewName(Name(oldFunc));
2768
+
2769
+    auto &newFunc = *new TFunction(&symbolTable, newName.rawName(), newName.symbolType(),
2770
+                                   &oldFunc.getReturnType(), oldFunc.isKnownToNotHaveSideEffects());
2771
+
2772
+    AcquireFunctionExtras(newFunc, oldFunc);
2773
+    AddParametersFrom(newFunc, oldFunc);
2774
+
2775
+    return newFunc;
2776
+}
2777
+
2778
+const TFunction &sh::CloneFunctionAndPrependParam(TSymbolTable &symbolTable,
2779
+                                                  IdGen *idGen,
2780
+                                                  const TFunction &oldFunc,
2781
+                                                  const TVariable &newParam)
2782
+{
2783
+    ASSERT(oldFunc.symbolType() == SymbolType::UserDefined ||
2784
+           oldFunc.symbolType() == SymbolType::AngleInternal);
2785
+
2786
+    Name newName = idGen ? idGen->createNewName(Name(oldFunc)) : Name(oldFunc);
2787
+
2788
+    auto &newFunc = *new TFunction(&symbolTable, newName.rawName(), newName.symbolType(),
2789
+                                   &oldFunc.getReturnType(), oldFunc.isKnownToNotHaveSideEffects());
2790
+
2791
+    AcquireFunctionExtras(newFunc, oldFunc);
2792
+    newFunc.addParameter(&newParam);
2793
+    AddParametersFrom(newFunc, oldFunc);
2794
+
2795
+    return newFunc;
2796
+}
2797
+
2798
+const TFunction &sh::CloneFunctionAndAppendParams(TSymbolTable &symbolTable,
2799
+                                                  IdGen *idGen,
2800
+                                                  const TFunction &oldFunc,
2801
+                                                  const std::vector<const TVariable *> &newParams)
2802
+{
2803
+    ASSERT(oldFunc.symbolType() == SymbolType::UserDefined ||
2804
+           oldFunc.symbolType() == SymbolType::AngleInternal);
2805
+
2806
+    Name newName = idGen ? idGen->createNewName(Name(oldFunc)) : Name(oldFunc);
2807
+
2808
+    auto &newFunc = *new TFunction(&symbolTable, newName.rawName(), newName.symbolType(),
2809
+                                   &oldFunc.getReturnType(), oldFunc.isKnownToNotHaveSideEffects());
2810
+
2811
+    AcquireFunctionExtras(newFunc, oldFunc);
2812
+    AddParametersFrom(newFunc, oldFunc);
2813
+    for (auto *param : newParams)
2814
+    {
2815
+        newFunc.addParameter(param);
2816
+    }
2817
+
2818
+    return newFunc;
2819
+}
2820
+
2821
+const TFunction &sh::CloneFunctionAndChangeReturnType(TSymbolTable &symbolTable,
2822
+                                                      IdGen *idGen,
2823
+                                                      const TFunction &oldFunc,
2824
+                                                      const TStructure &newReturn)
2825
+{
2826
+    ASSERT(oldFunc.symbolType() == SymbolType::UserDefined);
2827
+
2828
+    Name newName = idGen ? idGen->createNewName(Name(oldFunc)) : Name(oldFunc);
2829
+
2830
+    auto *newReturnType = new TType(&newReturn, true);
2831
+    auto &newFunc       = *new TFunction(&symbolTable, newName.rawName(), newName.symbolType(),
2832
+                                   newReturnType, oldFunc.isKnownToNotHaveSideEffects());
2833
+
2834
+    AcquireFunctionExtras(newFunc, oldFunc);
2835
+    AddParametersFrom(newFunc, oldFunc);
2836
+
2837
+    return newFunc;
2838
+}
2839
+
2840
+TIntermTyped &sh::GetArg(const TIntermAggregate &call, size_t index)
2841
+{
2842
+    ASSERT(index < call.getChildCount());
2843
+    auto *arg = call.getChildNode(index);
2844
+    ASSERT(arg);
2845
+    auto *targ = arg->getAsTyped();
2846
+    ASSERT(targ);
2847
+    return *targ;
2848
+}
2849
+
2850
+void sh::SetArg(TIntermAggregate &call, size_t index, TIntermTyped &arg)
2851
+{
2852
+    ASSERT(index < call.getChildCount());
2853
+    (*call.getSequence())[index] = &arg;
2854
+}
2855
+
2856
+int sh::GetFieldIndex(const TStructure &structure, const ImmutableString &fieldName)
2857
+{
2858
+    const TFieldList &fieldList = structure.fields();
2859
+
2860
+    int i = 0;
2861
+    for (TField *field : fieldList)
2862
+    {
2863
+        if (field->name() == fieldName)
2864
+        {
2865
+            return i;
2866
+        }
2867
+        ++i;
2868
+    }
2869
+
2870
+    return -1;
2871
+}
2872
+
2873
+TIntermBinary &sh::AccessField(const TVariable &structInstanceVar, const ImmutableString &fieldName)
2874
+{
2875
+    return AccessField(*new TIntermSymbol(&structInstanceVar), fieldName);
2876
+}
2877
+
2878
+TIntermBinary &sh::AccessField(TIntermTyped &object, const ImmutableString &fieldName)
2879
+{
2880
+    const TStructure *structure = object.getType().getStruct();
2881
+    ASSERT(structure);
2882
+
2883
+    const int index = GetFieldIndex(*structure, fieldName);
2884
+    ASSERT(index >= 0);
2885
+    return AccessFieldByIndex(object, index);
2886
+}
2887
+
2888
+TIntermBinary &sh::AccessFieldByIndex(TIntermTyped &object, int index)
2889
+{
2890
+#if defined(ANGLE_ENABLE_ASSERTS)
2891
+    const TType &type = object.getType();
2892
+    ASSERT(!type.isArray());
2893
+    const TStructure *structure = type.getStruct();
2894
+    ASSERT(structure);
2895
+    ASSERT(0 <= index);
2896
+    ASSERT(static_cast<size_t>(index) < structure->fields().size());
2897
+#endif
2898
+
2899
+    return *new TIntermBinary(
2900
+        TOperator::EOpIndexDirectStruct, &object,
2901
+        new TIntermConstantUnion(new TConstantUnion(index), *new TType(TBasicType::EbtInt)));
2902
+}
2903
+
2904
+TIntermBinary &sh::AccessIndex(TIntermTyped &indexableNode, int index)
2905
+{
2906
+#if defined(ANGLE_ENABLE_ASSERTS)
2907
+    const TType &type = indexableNode.getType();
2908
+    ASSERT(type.isArray() || type.isVector() || type.isMatrix());
2909
+#endif
2910
+
2911
+    auto *accessNode = new TIntermBinary(
2912
+        TOperator::EOpIndexDirect, &indexableNode,
2913
+        new TIntermConstantUnion(new TConstantUnion(index), *new TType(TBasicType::EbtInt)));
2914
+    return *accessNode;
2915
+}
2916
+
2917
+TIntermTyped &sh::AccessIndex(TIntermTyped &node, const int *index)
2918
+{
2919
+    if (index)
2920
+    {
2921
+        return AccessIndex(node, *index);
2922
+    }
2923
+    return node;
2924
+}
2925
+
2926
+TIntermTyped &sh::SubVector(TIntermTyped &vectorNode, int begin, int end)
2927
+{
2928
+    ASSERT(vectorNode.getType().isVector());
2929
+    ASSERT(0 <= begin);
2930
+    ASSERT(end <= 4);
2931
+    ASSERT(begin <= end);
2932
+    if (begin == 0 && end == vectorNode.getType().getNominalSize())
2933
+    {
2934
+        return vectorNode;
2935
+    }
2936
+    TVector<int> offsets(static_cast<size_t>(end - begin));
2937
+    std::iota(offsets.begin(), offsets.end(), begin);
2938
+    auto *swizzle = new TIntermSwizzle(&vectorNode, offsets);
2939
+    return *swizzle;
2940
+}
2941
+
2942
+bool sh::IsScalarBasicType(const TType &type)
2943
+{
2944
+    if (!type.isScalar())
2945
+    {
2946
+        return false;
2947
+    }
2948
+    return HasScalarBasicType(type);
2949
+}
2950
+
2951
+bool sh::IsVectorBasicType(const TType &type)
2952
+{
2953
+    if (!type.isVector())
2954
+    {
2955
+        return false;
2956
+    }
2957
+    return HasScalarBasicType(type);
2958
+}
2959
+
2960
+bool sh::HasScalarBasicType(TBasicType type)
2961
+{
2962
+    switch (type)
2963
+    {
2964
+        case TBasicType::EbtFloat:
2965
+        case TBasicType::EbtDouble:
2966
+        case TBasicType::EbtInt:
2967
+        case TBasicType::EbtUInt:
2968
+        case TBasicType::EbtBool:
2969
+            return true;
2970
+
2971
+        default:
2972
+            return false;
2973
+    }
2974
+}
2975
+
2976
+bool sh::HasScalarBasicType(const TType &type)
2977
+{
2978
+    return HasScalarBasicType(type.getBasicType());
2979
+}
2980
+
2981
+static void InitType(TType &type)
2982
+{
2983
+    if (type.isArray())
2984
+    {
2985
+        auto sizes = type.getArraySizes();
2986
+        type.toArrayBaseType();
2987
+        type.makeArrays(sizes);
2988
+    }
2989
+}
2990
+
2991
+TType &sh::CloneType(const TType &type)
2992
+{
2993
+    auto &clone = *new TType(type);
2994
+    InitType(clone);
2995
+    return clone;
2996
+}
2997
+
2998
+TType &sh::InnermostType(const TType &type)
2999
+{
3000
+    auto &inner = *new TType(type);
3001
+    inner.toArrayBaseType();
3002
+    InitType(inner);
3003
+    return inner;
3004
+}
3005
+
3006
+TType &sh::DropColumns(const TType &matrixType)
3007
+{
3008
+    ASSERT(matrixType.isMatrix());
3009
+    ASSERT(HasScalarBasicType(matrixType));
3010
+    const char *mangledName = nullptr;
3011
+
3012
+    auto &vectorType =
3013
+        *new TType(matrixType.getBasicType(), matrixType.getPrecision(), matrixType.getQualifier(),
3014
+                   matrixType.getRows(), 1, matrixType.getArraySizes(), mangledName);
3015
+    InitType(vectorType);
3016
+    return vectorType;
3017
+}
3018
+
3019
+TType &sh::DropOuterDimension(const TType &arrayType)
3020
+{
3021
+    ASSERT(arrayType.isArray());
3022
+    const char *mangledName = nullptr;
3023
+    const auto &arraySizes  = arrayType.getArraySizes();
3024
+
3025
+    auto &innerType =
3026
+        *new TType(arrayType.getBasicType(), arrayType.getPrecision(), arrayType.getQualifier(),
3027
+                   arrayType.getNominalSize(), arrayType.getSecondarySize(),
3028
+                   arraySizes.subspan(0, arraySizes.size() - 1), mangledName);
3029
+    InitType(innerType);
3030
+    return innerType;
3031
+}
3032
+
3033
+static TType &SetTypeDimsImpl(const TType &type, int primary, int secondary)
3034
+{
3035
+    ASSERT(1 < primary && primary <= 4);
3036
+    ASSERT(1 <= secondary && secondary <= 4);
3037
+    ASSERT(HasScalarBasicType(type));
3038
+    const char *mangledName = nullptr;
3039
+
3040
+    auto &newType = *new TType(type.getBasicType(), type.getPrecision(), type.getQualifier(),
3041
+                               primary, secondary, type.getArraySizes(), mangledName);
3042
+    InitType(newType);
3043
+    return newType;
3044
+}
3045
+
3046
+TType &sh::SetVectorDim(const TType &type, int newDim)
3047
+{
3048
+    ASSERT(type.isRank0() || type.isVector());
3049
+    return SetTypeDimsImpl(type, newDim, 1);
3050
+}
3051
+
3052
+TType &sh::SetMatrixRowDim(const TType &matrixType, int newDim)
3053
+{
3054
+    ASSERT(matrixType.isMatrix());
3055
+    ASSERT(1 < newDim && newDim <= 4);
3056
+    return SetTypeDimsImpl(matrixType, matrixType.getCols(), newDim);
3057
+}
3058
+
3059
+bool sh::HasMatrixField(const TStructure &structure)
3060
+{
3061
+    for (const TField *field : structure.fields())
3062
+    {
3063
+        const TType &type = *field->type();
3064
+        if (type.isMatrix())
3065
+        {
3066
+            return true;
3067
+        }
3068
+    }
3069
+    return false;
3070
+}
3071
+
3072
+bool sh::HasArrayField(const TStructure &structure)
3073
+{
3074
+    for (const TField *field : structure.fields())
3075
+    {
3076
+        const TType &type = *field->type();
3077
+        if (type.isArray())
3078
+        {
3079
+            return true;
3080
+        }
3081
+    }
3082
+    return false;
3083
+}
3084
+
3085
+TIntermTyped &sh::CoerceSimple(TBasicType toType, TIntermTyped &fromNode)
3086
+{
3087
+    const TType &fromType = fromNode.getType();
3088
+
3089
+    ASSERT(HasScalarBasicType(toType));
3090
+    ASSERT(HasScalarBasicType(fromType));
3091
+    ASSERT(!fromType.isArray());
3092
+
3093
+    if (toType != fromType.getBasicType())
3094
+    {
3095
+        return *TIntermAggregate::CreateConstructor(
3096
+            *new TType(toType, fromType.getNominalSize(), fromType.getSecondarySize()),
3097
+            new TIntermSequence{&fromNode});
3098
+    }
3099
+    return fromNode;
3100
+}
3101
+
3102
+TIntermTyped &sh::CoerceSimple(const TType &toType, TIntermTyped &fromNode)
3103
+{
3104
+    const TType &fromType = fromNode.getType();
3105
+
3106
+    ASSERT(HasScalarBasicType(toType));
3107
+    ASSERT(HasScalarBasicType(fromType));
3108
+    ASSERT(toType.getNominalSize() == fromType.getNominalSize());
3109
+    ASSERT(toType.getSecondarySize() == fromType.getSecondarySize());
3110
+    ASSERT(!toType.isArray());
3111
+    ASSERT(!fromType.isArray());
3112
+
3113
+    if (toType.getBasicType() != fromType.getBasicType())
3114
+    {
3115
+        return *TIntermAggregate::CreateConstructor(toType, new TIntermSequence{&fromNode});
3116
+    }
3117
+    return fromNode;
3118
+}
3119
+
3120
+TIntermTyped &sh::AsType(SymbolEnv &symbolEnv, const TType &toType, TIntermTyped &fromNode)
3121
+{
3122
+    const TType &fromType = fromNode.getType();
3123
+
3124
+    ASSERT(HasScalarBasicType(toType));
3125
+    ASSERT(HasScalarBasicType(fromType));
3126
+    ASSERT(!toType.isArray());
3127
+    ASSERT(!fromType.isArray());
3128
+
3129
+    if (toType == fromType)
3130
+    {
3131
+        return fromNode;
3132
+    }
3133
+    TemplateArg targ(toType);
3134
+    return symbolEnv.callFunctionOverload(Name("as_type", SymbolType::BuiltIn), toType,
3135
+                                          *new TIntermSequence{&fromNode}, 1, &targ);
3136
+}
3137
diff --git a/src/compiler/translator/TranslatorMetalDirect/AstHelpers.h b/src/compiler/translator/TranslatorMetalDirect/AstHelpers.h
3138
new file mode 100644
3139
index 0000000..d9e89fe
3140
--- /dev/null
3141
+++ b/src/compiler/translator/TranslatorMetalDirect/AstHelpers.h
3142
@@ -0,0 +1,157 @@
3143
+//
3144
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
3145
+// Use of this source code is governed by a BSD-style license that can be
3146
+// found in the LICENSE file.
3147
+//
3148
+
3149
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_ASTHELPERS_H_
3150
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_ASTHELPERS_H_
3151
+
3152
+#include <cstring>
3153
+#include <unordered_map>
3154
+#include <unordered_set>
3155
+
3156
+#include "compiler/translator/TranslatorMetalDirect/IdGen.h"
3157
+#include "compiler/translator/TranslatorMetalDirect/Name.h"
3158
+#include "compiler/translator/TranslatorMetalDirect/SymbolEnv.h"
3159
+
3160
+namespace sh
3161
+{
3162
+
3163
+// A convenience view of a TIntermDeclaration node's children.
3164
+struct Declaration
3165
+{
3166
+    TIntermSymbol &symbol;
3167
+    TIntermTyped *initExpr;  // Non-null iff declaration is initialized.
3168
+};
3169
+
3170
+// Returns a `Declaration` view of the given node.
3171
+Declaration ViewDeclaration(TIntermDeclaration &declNode);
3172
+
3173
+// Creates a variable for a struct type.
3174
+const TVariable &CreateStructTypeVariable(TSymbolTable &symbolTable, const TStructure &structure);
3175
+
3176
+// Creates a variable for a struct instance.
3177
+const TVariable &CreateInstanceVariable(TSymbolTable &symbolTable,
3178
+                                        const TStructure &structure,
3179
+                                        const Name &name,
3180
+                                        TQualifier qualifier = TQualifier::EvqTemporary,
3181
+                                        const TSpan<const unsigned int> *arraySizes = nullptr);
3182
+
3183
+// The input sequence should be discarded from AST after this is called.
3184
+TIntermSequence &CloneSequenceAndPrepend(const TIntermSequence &seq, TIntermNode &node);
3185
+
3186
+// Appends parameters from `src` function to `dest` function.
3187
+void AddParametersFrom(TFunction &dest, const TFunction &src);
3188
+
3189
+// Clones a function.
3190
+const TFunction &CloneFunction(TSymbolTable &symbolTable, IdGen &idGen, const TFunction &oldFunc);
3191
+
3192
+// Clones a function and prepends the provided extr parameter.
3193
+// If `idGen` is null, the original function must be discarded from the AST.
3194
+const TFunction &CloneFunctionAndPrependParam(TSymbolTable &symbolTable,
3195
+                                              IdGen *idGen,
3196
+                                              const TFunction &oldFunc,
3197
+                                              const TVariable &newParam);
3198
+
3199
+// Clones a function and appends the provided extra parameters.
3200
+// If `idGen` is null, the original function must be discarded from the AST.
3201
+const TFunction &CloneFunctionAndAppendParams(TSymbolTable &symbolTable,
3202
+                                              IdGen *idGen,
3203
+                                              const TFunction &oldFunc,
3204
+                                              const std::vector<const TVariable *> &newParam);
3205
+
3206
+// Clones a function and changes its return type.
3207
+// If `idGen` is null, the original function must be discarded from the AST.
3208
+const TFunction &CloneFunctionAndChangeReturnType(TSymbolTable &symbolTable,
3209
+                                                  IdGen *idGen,
3210
+                                                  const TFunction &oldFunc,
3211
+                                                  const TStructure &newReturn);
3212
+
3213
+// Gets the argument of a function call at the given index.
3214
+TIntermTyped &GetArg(const TIntermAggregate &call, size_t index);
3215
+
3216
+// Sets the argument of a function call at the given index.
3217
+void SetArg(TIntermAggregate &call, size_t index, TIntermTyped &arg);
3218
+
3219
+// Returns the field index within the given struct for the given field name.
3220
+// Returns -1 if the struct has no field with the given name.
3221
+int GetFieldIndex(const TStructure &structure, const ImmutableString &fieldName);
3222
+
3223
+// Accesses a field for the given variable with the given field name.
3224
+// The variable must be a struct instance.
3225
+TIntermBinary &AccessField(const TVariable &structInstanceVar, const ImmutableString &fieldName);
3226
+
3227
+// Accesses a field for the given node with the given field name.
3228
+// The node must be a struct instance.
3229
+TIntermBinary &AccessField(TIntermTyped &object, const ImmutableString &fieldName);
3230
+
3231
+// Accesses a field for the given node by its field index.
3232
+// The node must be a struct instance.
3233
+TIntermBinary &AccessFieldByIndex(TIntermTyped &object, int index);
3234
+
3235
+// Accesses an element by index for the given node.
3236
+// The node must be an array, vector, or matrix.
3237
+TIntermBinary &AccessIndex(TIntermTyped &indexableNode, int index);
3238
+
3239
+// Accesses an element by index for the given node if `index` is non-null.
3240
+// Returns the original node if `index` is null.
3241
+// The node must be an array, vector, or matrix if `index` is non-null.
3242
+TIntermTyped &AccessIndex(TIntermTyped &node, const int *index);
3243
+
3244
+// Returns a subvector based on the input slice range.
3245
+// This returns the original node if the slice is an identity for the node.
3246
+TIntermTyped &SubVector(TIntermTyped &vectorNode, int begin, int end);
3247
+
3248
+// Matches scalar bool, int, uint, float, double.
3249
+bool IsScalarBasicType(const TType &type);
3250
+
3251
+// Matches vector bool, int, uint, float, double.
3252
+bool IsVectorBasicType(const TType &type);
3253
+
3254
+// Matches bool, int, uint, float, double.
3255
+// Type does not need to be a scalar.
3256
+bool HasScalarBasicType(const TType &type);
3257
+
3258
+// Matches bool, int, uint, float, double.
3259
+bool HasScalarBasicType(TBasicType type);
3260
+
3261
+// Clones a type.
3262
+TType &CloneType(const TType &type);
3263
+
3264
+// Clones a type and drops all array dimensions.
3265
+TType &InnermostType(const TType &type);
3266
+
3267
+// Creates a vector type by dropping the columns off of a matrix type.
3268
+TType &DropColumns(const TType &matrixType);
3269
+
3270
+// Creates a type by dropping the outer dimension off of an array type.
3271
+TType &DropOuterDimension(const TType &arrayType);
3272
+
3273
+// Creates a scalar or vector type by changing the dimensions of a vector type.
3274
+TType &SetVectorDim(const TType &type, int newDim);
3275
+
3276
+// Creates a matrix type by changing the row dimensions of a matrix type.
3277
+TType &SetMatrixRowDim(const TType &matrixType, int newDim);
3278
+
3279
+// Returns true iff the structure directly contains a field with matrix type.
3280
+bool HasMatrixField(const TStructure &structure);
3281
+
3282
+// Returns true iff the structure directly contains a field with array type.
3283
+bool HasArrayField(const TStructure &structure);
3284
+
3285
+// Coerces `fromNode` to `toType` by a constructor call of `toType` if their types differ.
3286
+// Vector and matrix dimensions are retained.
3287
+// Array types are not allowed.
3288
+TIntermTyped &CoerceSimple(TBasicType toType, TIntermTyped &fromNode);
3289
+
3290
+// Coerces `fromNode` to `toType` by a constructor call of `toType` if their types differ.
3291
+// Vector and matrix dimensions must coincide between to and from.
3292
+// Array types are not allowed.
3293
+TIntermTyped &CoerceSimple(const TType &toType, TIntermTyped &fromNode);
3294
+
3295
+TIntermTyped &AsType(SymbolEnv &symbolEnv, const TType &toType, TIntermTyped &fromNode);
3296
+
3297
+}  // namespace sh
3298
+
3299
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_ASTHELPERS_H_
3300
diff --git a/src/compiler/translator/TranslatorMetalDirect/ConstantNames.h b/src/compiler/translator/TranslatorMetalDirect/ConstantNames.h
3301
new file mode 100644
3302
index 0000000..fddd865
3303
--- /dev/null
3304
+++ b/src/compiler/translator/TranslatorMetalDirect/ConstantNames.h
3305
@@ -0,0 +1,26 @@
3306
+//
3307
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
3308
+// Use of this source code is governed by a BSD-style license that can be
3309
+// found in the LICENSE file.
3310
+//
3311
+
3312
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_CONSTANT_NAMES_H_
3313
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_CONSTANT_NAMES_H_
3314
+
3315
+#include "compiler/translator/TranslatorMetalDirect/Name.h"
3316
+
3317
+namespace sh
3318
+{
3319
+
3320
+namespace constant_names
3321
+{
3322
+
3323
+constexpr Name kCoverageMaskEnabled("ANGLE_CoverageMaskEnabled", SymbolType::AngleInternal);
3324
+constexpr Name kRasterizationDiscardEnabled("ANGLE_RasterizationDiscard",
3325
+                                            SymbolType::AngleInternal);
3326
+
3327
+}  // namespace constant_names
3328
+
3329
+}  // namespace sh
3330
+
3331
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_CONSTANT_NAMES_H_
3332
diff --git a/src/compiler/translator/TranslatorMetalDirect/Debug.h b/src/compiler/translator/TranslatorMetalDirect/Debug.h
3333
new file mode 100644
3334
index 0000000..585e9a6
3335
--- /dev/null
3336
+++ b/src/compiler/translator/TranslatorMetalDirect/Debug.h
3337
@@ -0,0 +1,16 @@
3338
+//
3339
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
3340
+// Use of this source code is governed by a BSD-style license that can be
3341
+// found in the LICENSE file.
3342
+//
3343
+
3344
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_DEBUG_H_
3345
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_DEBUG_H_
3346
+
3347
+#include "common/debug.h"
3348
+
3349
+#define TODO() ASSERT(false)
3350
+
3351
+#define LOGIC_ERROR() ASSERT(false)
3352
+
3353
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_DEBUG_H_
3354
diff --git a/src/compiler/translator/TranslatorMetalDirect/DebugSink.h b/src/compiler/translator/TranslatorMetalDirect/DebugSink.h
3355
new file mode 100644
3356
index 0000000..872add7
3357
--- /dev/null
3358
+++ b/src/compiler/translator/TranslatorMetalDirect/DebugSink.h
3359
@@ -0,0 +1,159 @@
3360
+//
3361
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
3362
+// Use of this source code is governed by a BSD-style license that can be
3363
+// found in the LICENSE file.
3364
+//
3365
+
3366
+#include <iostream>
3367
+
3368
+#include "compiler/translator/InfoSink.h"
3369
+
3370
+namespace sh
3371
+{
3372
+
3373
+class StringObserver
3374
+{
3375
+  public:
3376
+    StringObserver(const std::string &needle) : needle(needle) { ASSERT(!needle.empty()); }
3377
+
3378
+    bool observe(char c)
3379
+    {
3380
+        if (needle[currPos] == c)
3381
+        {
3382
+            ++currPos;
3383
+            if (currPos == needle.size())
3384
+            {
3385
+                reset();
3386
+                return true;
3387
+            }
3388
+        }
3389
+        else
3390
+        {
3391
+            reset();
3392
+        }
3393
+        return false;
3394
+    }
3395
+
3396
+    const std::string &getNeedle() const { return needle; }
3397
+
3398
+    void reset() { currPos = 0; }
3399
+
3400
+  private:
3401
+    std::string needle;
3402
+    size_t currPos = 0;
3403
+};
3404
+
3405
+class DebugSink : angle::NonCopyable
3406
+{
3407
+  public:
3408
+    friend class EscapedSink;
3409
+    class EscapedSink : angle::NonCopyable
3410
+    {
3411
+        friend class DebugSink;
3412
+
3413
+      private:
3414
+        EscapedSink(DebugSink &owner) : mOwner(owner), mBegin(owner.size()) {}
3415
+
3416
+      public:
3417
+        EscapedSink(EscapedSink &&other) : mOwner(other.mOwner), mBegin(other.mBegin) {}
3418
+
3419
+        ~EscapedSink()
3420
+        {
3421
+            const char *p = mOwner.c_str();
3422
+            const int end = mOwner.size();
3423
+            mOwner.onWrite(p + mBegin, p + end);
3424
+        }
3425
+
3426
+        TInfoSinkBase &get() { return mOwner.mParent; }
3427
+
3428
+        operator TInfoSinkBase &() { return get(); }
3429
+
3430
+      private:
3431
+        DebugSink &mOwner;
3432
+        const int mBegin;
3433
+    };
3434
+
3435
+  public:
3436
+    DebugSink(TInfoSinkBase &parent, bool alsoLogToStdout)
3437
+        : mParent(parent), mAlsoLogToStdout(alsoLogToStdout)
3438
+    {}
3439
+
3440
+    void watch(std::string const &needle)
3441
+    {
3442
+        if (!needle.empty())
3443
+        {
3444
+            mObservers.emplace_back(needle);
3445
+        }
3446
+    }
3447
+
3448
+    void erase()
3449
+    {
3450
+        mParent.erase();
3451
+        for (StringObserver &observer : mObservers)
3452
+        {
3453
+            observer.reset();
3454
+        }
3455
+    }
3456
+
3457
+    int size() { return mParent.size(); }
3458
+
3459
+    const TPersistString &str() const { return mParent.str(); }
3460
+
3461
+    const char *c_str() const { return mParent.c_str(); }
3462
+
3463
+    EscapedSink escape() { return EscapedSink(*this); }
3464
+
3465
+    template <typename T>
3466
+    DebugSink &operator<<(const T &value)
3467
+    {
3468
+        const size_t begin = mParent.size();
3469
+        mParent << value;
3470
+        const size_t end = mParent.size();
3471
+
3472
+        const char *p = mParent.c_str();
3473
+        onWrite(p + begin, p + end);
3474
+
3475
+        return *this;
3476
+    }
3477
+
3478
+  private:
3479
+    void onWrite(const char *begin, char const *end)
3480
+    {
3481
+        const char *p = begin;
3482
+        while (p != end)
3483
+        {
3484
+            if (mAlsoLogToStdout)
3485
+            {
3486
+                std::cout << *p;
3487
+            }
3488
+
3489
+            for (StringObserver &observer : mObservers)
3490
+            {
3491
+                if (observer.observe(*p))
3492
+                {
3493
+                    if (mAlsoLogToStdout)
3494
+                    {
3495
+                        std::cout.flush();
3496
+                    }
3497
+                    const std::string &needle = observer.getNeedle();
3498
+                    (void)needle;
3499
+                    ASSERT(true);  // place your breakpoint here
3500
+                }
3501
+            }
3502
+
3503
+            ++p;
3504
+        }
3505
+
3506
+        if (mAlsoLogToStdout)
3507
+        {
3508
+            std::cout.flush();
3509
+        }
3510
+    }
3511
+
3512
+  private:
3513
+    TInfoSinkBase &mParent;
3514
+    std::vector<StringObserver> mObservers;
3515
+    bool mAlsoLogToStdout;
3516
+};
3517
+
3518
+}  // namespace sh
3519
diff --git a/src/compiler/translator/TranslatorMetalDirect/DiscoverDependentFunctions.cpp b/src/compiler/translator/TranslatorMetalDirect/DiscoverDependentFunctions.cpp
3520
new file mode 100644
3521
index 0000000..42df430
3522
--- /dev/null
3523
+++ b/src/compiler/translator/TranslatorMetalDirect/DiscoverDependentFunctions.cpp
3524
@@ -0,0 +1,131 @@
3525
+//
3526
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
3527
+// Use of this source code is governed by a BSD-style license that can be
3528
+// found in the LICENSE file.
3529
+//
3530
+
3531
+#include <cstring>
3532
+#include <unordered_map>
3533
+#include <unordered_set>
3534
+
3535
+#include "compiler/translator/TranslatorMetalDirect/DiscoverDependentFunctions.h"
3536
+#include "compiler/translator/TranslatorMetalDirect/DiscoverEnclosingFunctionTraverser.h"
3537
+#include "compiler/translator/TranslatorMetalDirect/MapFunctionsToDefinitions.h"
3538
+
3539
+using namespace sh;
3540
+
3541
+////////////////////////////////////////////////////////////////////////////////
3542
+
3543
+namespace
3544
+{
3545
+
3546
+class Discoverer : public DiscoverEnclosingFunctionTraverser
3547
+{
3548
+  private:
3549
+    const std::function<bool(const TVariable &)> &mVars;
3550
+    const FunctionToDefinition &mFuncToDef;
3551
+    std::unordered_set<const TFunction *> mNonDepFunctions;
3552
+
3553
+  public:
3554
+    std::unordered_set<const TFunction *> mDepFunctions;
3555
+
3556
+  public:
3557
+    Discoverer(const std::function<bool(const TVariable &)> &vars,
3558
+               const FunctionToDefinition &funcToDef)
3559
+        : DiscoverEnclosingFunctionTraverser(true, false, true), mVars(vars), mFuncToDef(funcToDef)
3560
+    {}
3561
+
3562
+    void visitSymbol(TIntermSymbol *symbolNode) override
3563
+    {
3564
+        const TVariable &var = symbolNode->variable();
3565
+        if (!mVars(var))
3566
+        {
3567
+            return;
3568
+        }
3569
+        const TFunction *owner = discoverEnclosingFunction(symbolNode);
3570
+        ASSERT(owner);
3571
+        mDepFunctions.insert(owner);
3572
+    }
3573
+
3574
+    bool visitAggregate(Visit visit, TIntermAggregate *aggregateNode) override
3575
+    {
3576
+        if (visit != Visit::PreVisit)
3577
+        {
3578
+            return true;
3579
+        }
3580
+
3581
+        if (!aggregateNode->isConstructor())
3582
+        {
3583
+            const TFunction *func = aggregateNode->getFunction();
3584
+
3585
+            if (mNonDepFunctions.find(func) != mNonDepFunctions.end())
3586
+            {
3587
+                return true;
3588
+            }
3589
+
3590
+            if (mDepFunctions.find(func) == mDepFunctions.end())
3591
+            {
3592
+                auto it = mFuncToDef.find(func);
3593
+                if (it == mFuncToDef.end())
3594
+                {
3595
+                    return true;
3596
+                }
3597
+
3598
+                // Recursion is banned in GLSL, so I believe AngleIR has this property too.
3599
+                // This implementation assumes (direct and mutual) recursion is prohibited.
3600
+                TIntermFunctionDefinition &funcDefNode = *it->second;
3601
+                funcDefNode.traverse(this);
3602
+                if (mNonDepFunctions.find(func) != mNonDepFunctions.end())
3603
+                {
3604
+                    return true;
3605
+                }
3606
+                ASSERT(mDepFunctions.find(func) != mDepFunctions.end());
3607
+            }
3608
+
3609
+            const TFunction *owner = discoverEnclosingFunction(aggregateNode);
3610
+            ASSERT(owner);
3611
+            mDepFunctions.insert(owner);
3612
+        }
3613
+
3614
+        return true;
3615
+    }
3616
+
3617
+    bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *funcDefNode) override
3618
+    {
3619
+        const TFunction *func = funcDefNode->getFunction();
3620
+
3621
+        if (visit != Visit::PostVisit)
3622
+        {
3623
+            if (mDepFunctions.find(func) != mDepFunctions.end())
3624
+            {
3625
+                return false;
3626
+            }
3627
+
3628
+            if (mNonDepFunctions.find(func) != mNonDepFunctions.end())
3629
+            {
3630
+                return false;
3631
+            }
3632
+
3633
+            return true;
3634
+        }
3635
+
3636
+        if (mDepFunctions.find(func) == mDepFunctions.end())
3637
+        {
3638
+            mNonDepFunctions.insert(func);
3639
+        }
3640
+
3641
+        return true;
3642
+    }
3643
+};
3644
+
3645
+}  // namespace
3646
+
3647
+std::unordered_set<const TFunction *> sh::DiscoverDependentFunctions(
3648
+    TIntermBlock &root,
3649
+    const std::function<bool(const TVariable &)> &vars)
3650
+{
3651
+    const FunctionToDefinition funcToDef = MapFunctionsToDefinitions(root);
3652
+    Discoverer discoverer(vars, funcToDef);
3653
+    root.traverse(&discoverer);
3654
+    return std::move(discoverer.mDepFunctions);
3655
+}
3656
diff --git a/src/compiler/translator/TranslatorMetalDirect/DiscoverDependentFunctions.h b/src/compiler/translator/TranslatorMetalDirect/DiscoverDependentFunctions.h
3657
new file mode 100644
3658
index 0000000..5d1bf27
3659
--- /dev/null
3660
+++ b/src/compiler/translator/TranslatorMetalDirect/DiscoverDependentFunctions.h
3661
@@ -0,0 +1,25 @@
3662
+//
3663
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
3664
+// Use of this source code is governed by a BSD-style license that can be
3665
+// found in the LICENSE file.
3666
+//
3667
+
3668
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_DISCOVERDEPENDENTFUNCTIONS_H_
3669
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_DISCOVERDEPENDENTFUNCTIONS_H_
3670
+
3671
+#include <unordered_set>
3672
+
3673
+#include "common/angleutils.h"
3674
+#include "compiler/translator/Compiler.h"
3675
+
3676
+namespace sh
3677
+{
3678
+
3679
+// Finds and returns all functions that contain the provided variables.
3680
+ANGLE_NO_DISCARD std::unordered_set<const TFunction *> DiscoverDependentFunctions(
3681
+    TIntermBlock &root,
3682
+    const std::function<bool(const TVariable &)> &vars);
3683
+
3684
+}  // namespace sh
3685
+
3686
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_DISCOVERDEPENDENTFUNCTIONS_H_
3687
diff --git a/src/compiler/translator/TranslatorMetalDirect/DiscoverEnclosingFunctionTraverser.cpp b/src/compiler/translator/TranslatorMetalDirect/DiscoverEnclosingFunctionTraverser.cpp
3688
new file mode 100644
3689
index 0000000..22d390e
3690
--- /dev/null
3691
+++ b/src/compiler/translator/TranslatorMetalDirect/DiscoverEnclosingFunctionTraverser.cpp
3692
@@ -0,0 +1,33 @@
3693
+//
3694
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
3695
+// Use of this source code is governed by a BSD-style license that can be
3696
+// found in the LICENSE file.
3697
+//
3698
+
3699
+#include "compiler/translator/TranslatorMetalDirect/DiscoverEnclosingFunctionTraverser.h"
3700
+
3701
+using namespace sh;
3702
+
3703
+DiscoverEnclosingFunctionTraverser::DiscoverEnclosingFunctionTraverser(bool preVisit_,
3704
+                                                                       bool inVisit_,
3705
+                                                                       bool postVisit_,
3706
+                                                                       TSymbolTable *symbolTable)
3707
+    : TIntermTraverser(preVisit_, inVisit_, postVisit_, symbolTable)
3708
+{}
3709
+
3710
+const TFunction *DiscoverEnclosingFunctionTraverser::discoverEnclosingFunction(TIntermNode *node)
3711
+{
3712
+    ASSERT(!node->getAsFunctionDefinition());
3713
+
3714
+    unsigned height = 0;
3715
+    while (TIntermNode *ancestor = getAncestorNode(height))
3716
+    {
3717
+        if (TIntermFunctionDefinition *funcDefNode = ancestor->getAsFunctionDefinition())
3718
+        {
3719
+            return funcDefNode->getFunction();
3720
+        }
3721
+        ++height;
3722
+    }
3723
+
3724
+    return nullptr;
3725
+}
3726
diff --git a/src/compiler/translator/TranslatorMetalDirect/DiscoverEnclosingFunctionTraverser.h b/src/compiler/translator/TranslatorMetalDirect/DiscoverEnclosingFunctionTraverser.h
3727
new file mode 100644
3728
index 0000000..f9cb2aa
3729
--- /dev/null
3730
+++ b/src/compiler/translator/TranslatorMetalDirect/DiscoverEnclosingFunctionTraverser.h
3731
@@ -0,0 +1,31 @@
3732
+//
3733
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
3734
+// Use of this source code is governed by a BSD-style license that can be
3735
+// found in the LICENSE file.
3736
+//
3737
+
3738
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_DISCOVERENCLOSINGFUNCTIONTRAVERSER_H_
3739
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_DISCOVERENCLOSINGFUNCTIONTRAVERSER_H_
3740
+
3741
+#include "compiler/translator/tree_util/IntermTraverse.h"
3742
+
3743
+namespace sh
3744
+{
3745
+
3746
+// A TIntermTraverser that supports discovery of the function a node belongs to.
3747
+class DiscoverEnclosingFunctionTraverser : public TIntermTraverser
3748
+{
3749
+  public:
3750
+    DiscoverEnclosingFunctionTraverser(bool preVisit,
3751
+                                       bool inVisit,
3752
+                                       bool postVisit,
3753
+                                       TSymbolTable *symbolTable = nullptr);
3754
+
3755
+    // Returns the function a node belongs inside.
3756
+    // Returns null if the node does not belong inside a function.
3757
+    const TFunction *discoverEnclosingFunction(TIntermNode *node);
3758
+};
3759
+
3760
+}  // namespace sh
3761
+
3762
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_DISCOVERENCLOSINGFUNCTIONTRAVERSER_H_
3763
diff --git a/src/compiler/translator/TranslatorMetalDirect/EmitMetal.cpp b/src/compiler/translator/TranslatorMetalDirect/EmitMetal.cpp
3764
new file mode 100644
3765
index 0000000..1bbdd3f
3766
--- /dev/null
3767
+++ b/src/compiler/translator/TranslatorMetalDirect/EmitMetal.cpp
3768
@@ -0,0 +1,2455 @@
3769
+//
3770
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
3771
+// Use of this source code is governed by a BSD-style license that can be
3772
+// found in the LICENSE file.
3773
+//
3774
+
3775
+#include <cctype>
3776
+#include <map>
3777
+
3778
+#include "compiler/translator/ImmutableStringBuilder.h"
3779
+#include "compiler/translator/SymbolTable.h"
3780
+#include "compiler/translator/TranslatorMetalDirect.h"
3781
+#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
3782
+#include "compiler/translator/TranslatorMetalDirect/Debug.h"
3783
+#include "compiler/translator/TranslatorMetalDirect/DebugSink.h"
3784
+#include "compiler/translator/TranslatorMetalDirect/EmitMetal.h"
3785
+#include "compiler/translator/TranslatorMetalDirect/EnvironmentVariable.h"
3786
+#include "compiler/translator/TranslatorMetalDirect/Layout.h"
3787
+#include "compiler/translator/TranslatorMetalDirect/Name.h"
3788
+#include "compiler/translator/TranslatorMetalDirect/ProgramPrelude.h"
3789
+#include "compiler/translator/TranslatorMetalDirect/RewritePipelines.h"
3790
+#include "compiler/translator/tree_util/IntermTraverse.h"
3791
+#include "libANGLE/renderer/metal/mtl_constants.h"
3792
+
3793
+using namespace sh;
3794
+
3795
+////////////////////////////////////////////////////////////////////////////////
3796
+
3797
+#if defined(ANGLE_ENABLE_ASSERTS)
3798
+using Sink = DebugSink;
3799
+#else
3800
+using Sink = TInfoSinkBase;
3801
+#endif
3802
+
3803
+////////////////////////////////////////////////////////////////////////////////
3804
+
3805
+namespace
3806
+{
3807
+
3808
+struct VarDecl
3809
+{
3810
+    explicit VarDecl(const TVariable &var) : mVariable(&var), mIsField(false) {}
3811
+    explicit VarDecl(const TField &field) : mField(&field), mIsField(true) {}
3812
+
3813
+    ANGLE_INLINE const TVariable &variable() const
3814
+    {
3815
+        ASSERT(isVariable());
3816
+        return *mVariable;
3817
+    }
3818
+
3819
+    ANGLE_INLINE const TField &field() const
3820
+    {
3821
+        ASSERT(isField());
3822
+        return *mField;
3823
+    }
3824
+
3825
+    ANGLE_INLINE bool isVariable() const { return !mIsField; }
3826
+
3827
+    ANGLE_INLINE bool isField() const { return mIsField; }
3828
+
3829
+    const TType &type() const { return isField() ? *field().type() : variable().getType(); }
3830
+
3831
+    SymbolType symbolType() const
3832
+    {
3833
+        return isField() ? field().symbolType() : variable().symbolType();
3834
+    }
3835
+
3836
+  private:
3837
+    union
3838
+    {
3839
+        const TVariable *mVariable;
3840
+        const TField *mField;
3841
+    };
3842
+    bool mIsField;
3843
+};
3844
+
3845
+class GenMetalTraverser : public TIntermTraverser
3846
+{
3847
+  public:
3848
+    ~GenMetalTraverser() override;
3849
+
3850
+    GenMetalTraverser(const TCompiler &compiler,
3851
+                      Sink &out,
3852
+                      IdGen &idGen,
3853
+                      const PipelineStructs &pipelineStructs,
3854
+                      const Invariants &invariants,
3855
+                      SymbolEnv &symbolEnv);
3856
+
3857
+    void visitSymbol(TIntermSymbol *) override;
3858
+    void visitConstantUnion(TIntermConstantUnion *) override;
3859
+    bool visitSwizzle(Visit, TIntermSwizzle *) override;
3860
+    bool visitBinary(Visit, TIntermBinary *) override;
3861
+    bool visitUnary(Visit, TIntermUnary *) override;
3862
+    bool visitTernary(Visit, TIntermTernary *) override;
3863
+    bool visitIfElse(Visit, TIntermIfElse *) override;
3864
+    bool visitSwitch(Visit, TIntermSwitch *) override;
3865
+    bool visitCase(Visit, TIntermCase *) override;
3866
+    void visitFunctionPrototype(TIntermFunctionPrototype *) override;
3867
+    bool visitFunctionDefinition(Visit, TIntermFunctionDefinition *) override;
3868
+    bool visitAggregate(Visit, TIntermAggregate *) override;
3869
+    bool visitBlock(Visit, TIntermBlock *) override;
3870
+    bool visitGlobalQualifierDeclaration(Visit, TIntermGlobalQualifierDeclaration *) override;
3871
+    bool visitDeclaration(Visit, TIntermDeclaration *) override;
3872
+    bool visitLoop(Visit, TIntermLoop *) override;
3873
+    bool visitForLoop(TIntermLoop *);
3874
+    bool visitWhileLoop(TIntermLoop *);
3875
+    bool visitDoWhileLoop(TIntermLoop *);
3876
+    bool visitBranch(Visit, TIntermBranch *) override;
3877
+
3878
+  private:
3879
+    using FuncToName = std::map<ImmutableString, Name>;
3880
+    static FuncToName BuildFuncToName();
3881
+
3882
+    struct EmitVariableDeclarationConfig
3883
+    {
3884
+        bool isParameter                = false;
3885
+        bool isMainParameter            = false;
3886
+        bool emitPostQualifier          = false;
3887
+        bool isPacked                   = false;
3888
+        bool disableStructSpecifier     = false;
3889
+        const AddressSpace *isPointer   = nullptr;
3890
+        const AddressSpace *isReference = nullptr;
3891
+    };
3892
+
3893
+    struct EmitTypeConfig
3894
+    {
3895
+        const EmitVariableDeclarationConfig *evdConfig = nullptr;
3896
+    };
3897
+
3898
+    void emitIndentation();
3899
+    void emitFunctionSignature(const TFunction &func);
3900
+    void emitFunctionReturn(const TFunction &func);
3901
+    void emitFunctionParameter(const TFunction &func, const TVariable &param);
3902
+
3903
+    void emitNameOf(const TField &object);
3904
+    void emitNameOf(const TSymbol &object);
3905
+    void emitNameOf(const VarDecl &object);
3906
+
3907
+    void emitBareTypeName(const TType &type, const EmitTypeConfig &etConfig);
3908
+    void emitType(const TType &type, const EmitTypeConfig &etConfig);
3909
+    void emitPostQualifier(const EmitVariableDeclarationConfig &evdConfig,
3910
+                           const VarDecl &decl,
3911
+                           const TQualifier qualifier);
3912
+
3913
+    struct FieldAnnotationIndices
3914
+    {
3915
+        size_t attribute = 0;
3916
+        size_t color     = 0;
3917
+    };
3918
+
3919
+    void emitFieldDeclaration(const TField &field,
3920
+                              const TStructure &parent,
3921
+                              FieldAnnotationIndices &annotationIndices);
3922
+    void emitAttributeDeclaration(const TField &field, FieldAnnotationIndices &annotationIndices);
3923
+    void emitStructDeclaration(const TType &type);
3924
+    void emitOrdinaryVariableDeclaration(const VarDecl &decl,
3925
+                                         const EmitVariableDeclarationConfig &evdConfig);
3926
+    void emitVariableDeclaration(const VarDecl &decl,
3927
+                                 const EmitVariableDeclarationConfig &evdConfig);
3928
+
3929
+    void emitOpenBrace();
3930
+    void emitCloseBrace();
3931
+
3932
+    void groupedTraverse(TIntermNode &node);
3933
+
3934
+    const TField &getDirectField(const TFieldListCollection &fieldsNode,
3935
+                                 const TConstantUnion &index);
3936
+    const TField &getDirectField(const TIntermTyped &fieldsNode, TIntermTyped &indexNode);
3937
+
3938
+    const TConstantUnion *emitConstantUnionArray(const TConstantUnion *const constUnion,
3939
+                                                 const size_t size);
3940
+
3941
+    const TConstantUnion *emitConstantUnion(const TType &type, const TConstantUnion *constUnion);
3942
+
3943
+    void emitSingleConstant(const TConstantUnion *const constUnion);
3944
+
3945
+  private:
3946
+    Sink &mOut;
3947
+    const TCompiler &mCompiler;
3948
+    const PipelineStructs &mPipelineStructs;
3949
+    const Invariants &mInvariants;
3950
+    SymbolEnv &mSymbolEnv;
3951
+    IdGen &mIdGen;
3952
+    int mIndentLevel        = -1;
3953
+    int mLastIndentationPos = -1;
3954
+    bool mParentIsSwitch    = false;
3955
+    std::unordered_map<const TSymbol *, Name> mRenamedSymbols;
3956
+    const FuncToName mFuncToName   = BuildFuncToName();
3957
+    size_t mMainTextureIndex       = 0;
3958
+    size_t mMainSamplerIndex       = 0;
3959
+    size_t mMainUniformBufferIndex = rx::mtl::kDefaultUniformsBindingIndex;
3960
+};
3961
+
3962
+}  // anonymous namespace
3963
+
3964
+GenMetalTraverser::~GenMetalTraverser()
3965
+{
3966
+    ASSERT(mIndentLevel == -1);
3967
+    ASSERT(!mParentIsSwitch);
3968
+}
3969
+
3970
+GenMetalTraverser::GenMetalTraverser(const TCompiler &compiler,
3971
+                                     Sink &out,
3972
+                                     IdGen &idGen,
3973
+                                     const PipelineStructs &pipelineStructs,
3974
+                                     const Invariants &invariants,
3975
+                                     SymbolEnv &symbolEnv)
3976
+    : TIntermTraverser(true, false, false),
3977
+      mOut(out),
3978
+      mCompiler(compiler),
3979
+      mPipelineStructs(pipelineStructs),
3980
+      mInvariants(invariants),
3981
+      mSymbolEnv(symbolEnv),
3982
+      mIdGen(idGen)
3983
+{}
3984
+
3985
+void GenMetalTraverser::emitIndentation()
3986
+{
3987
+    ASSERT(mIndentLevel >= 0);
3988
+
3989
+    if (mLastIndentationPos == mOut.size())
3990
+    {
3991
+        return;  // Line is already indented.
3992
+    }
3993
+
3994
+    for (int i = 0; i < mIndentLevel; ++i)
3995
+    {
3996
+        mOut << "  ";
3997
+    }
3998
+
3999
+    mLastIndentationPos = mOut.size();
4000
+}
4001
+
4002
+static const char *GetOperatorString(TOperator op,
4003
+                                     const TType &resultType,
4004
+                                     const TType *argType0,
4005
+                                     const TType *argType1 = nullptr)
4006
+{
4007
+    switch (op)
4008
+    {
4009
+        case TOperator::EOpComma:
4010
+            return ",";
4011
+        case TOperator::EOpAssign:
4012
+            return "=";
4013
+        case TOperator::EOpInitialize:
4014
+            return "=";
4015
+        case TOperator::EOpAddAssign:
4016
+            return "+=";
4017
+        case TOperator::EOpSubAssign:
4018
+            return "-=";
4019
+        case TOperator::EOpMulAssign:
4020
+            return "*=";
4021
+        case TOperator::EOpDivAssign:
4022
+            return "/=";
4023
+        case TOperator::EOpIModAssign:
4024
+            return "%=";
4025
+        case TOperator::EOpBitShiftLeftAssign:
4026
+            return "<<=";  // TODO: Check logical vs arithmetic shifting.
4027
+        case TOperator::EOpBitShiftRightAssign:
4028
+            return ">>=";  // TODO: Check logical vs arithmetic shifting.
4029
+        case TOperator::EOpBitwiseAndAssign:
4030
+            return "&=";
4031
+        case TOperator::EOpBitwiseXorAssign:
4032
+            return "^=";
4033
+        case TOperator::EOpBitwiseOrAssign:
4034
+            return "|=";
4035
+        case TOperator::EOpAdd:
4036
+            return "+";
4037
+        case TOperator::EOpSub:
4038
+            return "-";
4039
+        case TOperator::EOpMul:
4040
+            return "*";
4041
+        case TOperator::EOpDiv:
4042
+            return "/";
4043
+        case TOperator::EOpIMod:
4044
+            return "%";
4045
+        case TOperator::EOpBitShiftLeft:
4046
+            return "<<";  // TODO: Check logical vs arithmetic shifting.
4047
+        case TOperator::EOpBitShiftRight:
4048
+            return ">>";  // TODO: Check logical vs arithmetic shifting.
4049
+        case TOperator::EOpBitwiseAnd:
4050
+            return "&";
4051
+        case TOperator::EOpBitwiseXor:
4052
+            return "^";
4053
+        case TOperator::EOpBitwiseOr:
4054
+            return "|";
4055
+        case TOperator::EOpLessThan:
4056
+            return "<";
4057
+        case TOperator::EOpGreaterThan:
4058
+            return ">";
4059
+        case TOperator::EOpLessThanEqual:
4060
+            return "<=";
4061
+        case TOperator::EOpGreaterThanEqual:
4062
+            return ">=";
4063
+        case TOperator::EOpLessThanComponentWise:
4064
+            return "<";
4065
+        case TOperator::EOpLessThanEqualComponentWise:
4066
+            return "<=";
4067
+        case TOperator::EOpGreaterThanEqualComponentWise:
4068
+            return ">=";
4069
+        case TOperator::EOpGreaterThanComponentWise:
4070
+            return ">";
4071
+        case TOperator::EOpLogicalOr:
4072
+            return "||";
4073
+        case TOperator::EOpLogicalXor:
4074
+            return "!=/*xor*/";  // XXX: This might need to be handled differently for some obtuse
4075
+                                 // use case.
4076
+        case TOperator::EOpLogicalAnd:
4077
+            return "&&";
4078
+        case TOperator::EOpNegative:
4079
+            return "-";
4080
+        case TOperator::EOpPositive:
4081
+            if (argType0->isMatrix())
4082
+            {
4083
+                return "";
4084
+            }
4085
+            return "+";
4086
+        case TOperator::EOpLogicalNot:
4087
+            return "!";
4088
+        case TOperator::EOpLogicalNotComponentWise:
4089
+            return "!";
4090
+        case TOperator::EOpBitwiseNot:
4091
+            return "~";
4092
+        case TOperator::EOpPostIncrement:
4093
+            return "++";
4094
+        case TOperator::EOpPostDecrement:
4095
+            return "--";
4096
+        case TOperator::EOpPreIncrement:
4097
+            return "++";
4098
+        case TOperator::EOpPreDecrement:
4099
+            return "--";
4100
+        case TOperator::EOpVectorTimesScalarAssign:
4101
+            return "*=";
4102
+        case TOperator::EOpVectorTimesMatrixAssign:
4103
+            return "*=";
4104
+        case TOperator::EOpMatrixTimesScalarAssign:
4105
+            return "*=";
4106
+        case TOperator::EOpMatrixTimesMatrixAssign:
4107
+            return "*=";
4108
+        case TOperator::EOpVectorTimesScalar:
4109
+            return "*";
4110
+        case TOperator::EOpVectorTimesMatrix:
4111
+            return "*";
4112
+        case TOperator::EOpMatrixTimesVector:
4113
+            return "*";
4114
+        case TOperator::EOpMatrixTimesScalar:
4115
+            return "*";
4116
+        case TOperator::EOpMatrixTimesMatrix:
4117
+            return "*";
4118
+        case TOperator::EOpEqualComponentWise:
4119
+            return "==";
4120
+        case TOperator::EOpNotEqualComponentWise:
4121
+            return "!=";
4122
+
4123
+        case TOperator::EOpEqual:
4124
+            if ((argType0->isVector() && argType1->isVector()) ||
4125
+                (argType0->getStruct() && argType1->getStruct()) ||
4126
+                (argType0->isArray() && argType1->isArray()))
4127
+
4128
+            {
4129
+                return "ANGLE_equal";
4130
+            }
4131
+
4132
+            return "==";
4133
+
4134
+        case TOperator::EOpNotEqual:
4135
+            if ((argType0->isVector() && argType1->isVector()) ||
4136
+                (argType0->isArray() && argType1->isArray()))
4137
+            {
4138
+                return "ANGLE_notEqual";
4139
+            }
4140
+            else if (argType0->getStruct() && argType1->getStruct())
4141
+            {
4142
+                return "ANGLE_notEqualStruct";
4143
+            }
4144
+            return "!=";
4145
+
4146
+        case TOperator::EOpKill:
4147
+            TODO();
4148
+            return "kill";
4149
+        case TOperator::EOpReturn:
4150
+            return "return";
4151
+        case TOperator::EOpBreak:
4152
+            return "break";
4153
+        case TOperator::EOpContinue:
4154
+            return "continue";
4155
+
4156
+        case TOperator::EOpRadians:
4157
+            return "ANGLE_radians";
4158
+        case TOperator::EOpDegrees:
4159
+            return "ANGLE_degrees";
4160
+        case TOperator::EOpAtan:
4161
+            return "ANGLE_atan";
4162
+        case TOperator::EOpMod:
4163
+            return "ANGLE_mod";  // differs from metal::mod
4164
+        case TOperator::EOpRefract:
4165
+            return "ANGLE_refract";
4166
+        case TOperator::EOpDistance:
4167
+            return "ANGLE_distance";
4168
+        case TOperator::EOpLength:
4169
+            return "ANGLE_length";
4170
+        case TOperator::EOpDot:
4171
+            return "ANGLE_dot";
4172
+        case TOperator::EOpNormalize:
4173
+            return "ANGLE_normalize";
4174
+        case TOperator::EOpFaceforward:
4175
+            return "ANGLE_faceforward";
4176
+        case TOperator::EOpReflect:
4177
+            return "ANGLE_reflect";
4178
+        case TOperator::EOpMulMatrixComponentWise:
4179
+            return "ANGLE_componentWiseMultiply";
4180
+        case TOperator::EOpOuterProduct:
4181
+            return "ANGLE_outerProduct";
4182
+        case TOperator::EOpSign:
4183
+            return "ANGLE_sign";
4184
+
4185
+        case TOperator::EOpAbs:
4186
+            return "metal::abs";
4187
+        case TOperator::EOpAll:
4188
+            return "metal::all";
4189
+        case TOperator::EOpAny:
4190
+            return "metal::any";
4191
+        case TOperator::EOpSin:
4192
+            return "metal::sin";
4193
+        case TOperator::EOpCos:
4194
+            return "metal::cos";
4195
+        case TOperator::EOpTan:
4196
+            return "metal::tan";
4197
+        case TOperator::EOpAsin:
4198
+            return "metal::asin";
4199
+        case TOperator::EOpAcos:
4200
+            return "metal::acos";
4201
+        case TOperator::EOpSinh:
4202
+            return "metal::sinh";
4203
+        case TOperator::EOpCosh:
4204
+            return "metal::cosh";
4205
+        case TOperator::EOpTanh:
4206
+            return "metal::tanh";
4207
+        case TOperator::EOpAsinh:
4208
+            return "metal::asinh";
4209
+        case TOperator::EOpAcosh:
4210
+            return "metal::acosh";
4211
+        case TOperator::EOpAtanh:
4212
+            return "metal::atanh";
4213
+        case TOperator::EOpFma:
4214
+            return "metal::fma";
4215
+        case TOperator::EOpPow:
4216
+            return "metal::pow";
4217
+        case TOperator::EOpExp:
4218
+            return "metal::exp";
4219
+        case TOperator::EOpExp2:
4220
+            return "metal::exp2";
4221
+        case TOperator::EOpLog:
4222
+            return "metal::log";
4223
+        case TOperator::EOpLog2:
4224
+            return "metal::log2";
4225
+        case TOperator::EOpSqrt:
4226
+            return "metal::sqrt";
4227
+        case TOperator::EOpFloor:
4228
+            return "metal::floor";
4229
+        case TOperator::EOpTrunc:
4230
+            return "metal::trunc";
4231
+        case TOperator::EOpCeil:
4232
+            return "metal::ceil";
4233
+        case TOperator::EOpFract:
4234
+            return "metal::fract";
4235
+        case TOperator::EOpMin:
4236
+            return "metal::min";
4237
+        case TOperator::EOpMax:
4238
+            return "metal::max";
4239
+        case TOperator::EOpRound:
4240
+            return "metal::round";
4241
+        case TOperator::EOpRoundEven:
4242
+            return "metal::rint";
4243
+        case TOperator::EOpClamp:
4244
+            return "metal::clamp";  // TODO fast vs precise namespace
4245
+        case TOperator::EOpMix:
4246
+            return "metal::mix";
4247
+        case TOperator::EOpStep:
4248
+            return "metal::step";
4249
+        case TOperator::EOpSmoothstep:
4250
+            return "metal::smoothstep";
4251
+        case TOperator::EOpModf:
4252
+            return "metal::modf";
4253
+        case TOperator::EOpIsnan:
4254
+            return "metal::isnan";
4255
+        case TOperator::EOpIsinf:
4256
+            return "metal::isinf";
4257
+        case TOperator::EOpLdexp:
4258
+            return "metal::ldexp";
4259
+        case TOperator::EOpFrexp:
4260
+            return "metal::frexp";
4261
+        case TOperator::EOpInversesqrt:
4262
+            return "metal::rsqrt";
4263
+        case TOperator::EOpCross:
4264
+            return "metal::cross";
4265
+        case TOperator::EOpDFdx:
4266
+            return "metal::dfdx";
4267
+        case TOperator::EOpDFdy:
4268
+            return "metal::dfdy";
4269
+        case TOperator::EOpFwidth:
4270
+            return "metal::fwidth";
4271
+        case TOperator::EOpTranspose:
4272
+            return "metal::transpose";
4273
+        case TOperator::EOpDeterminant:
4274
+            return "metal::determinant";
4275
+
4276
+        case TOperator::EOpInverse:
4277
+            return "ANGLE_inverse";
4278
+
4279
+        case TOperator::EOpFloatBitsToInt:
4280
+        case TOperator::EOpFloatBitsToUint:
4281
+        case TOperator::EOpIntBitsToFloat:
4282
+        case TOperator::EOpUintBitsToFloat:
4283
+        {
4284
+#define RETURN_AS_TYPE(post)                     \
4285
+    do                                           \
4286
+        switch (resultType.getBasicType())       \
4287
+        {                                        \
4288
+            case TBasicType::EbtInt:             \
4289
+                return "as_type<int" post ">";   \
4290
+            case TBasicType::EbtUInt:            \
4291
+                return "as_type<uint" post ">";  \
4292
+            case TBasicType::EbtFloat:           \
4293
+                return "as_type<float" post ">"; \
4294
+            default:                             \
4295
+                TODO();                          \
4296
+                return "TOperator_TODO";         \
4297
+        }                                        \
4298
+    while (false)
4299
+
4300
+            if (resultType.isScalar())
4301
+            {
4302
+                RETURN_AS_TYPE("");
4303
+            }
4304
+            else if (resultType.isVector())
4305
+            {
4306
+                switch (resultType.getNominalSize())
4307
+                {
4308
+                    case 2:
4309
+                        RETURN_AS_TYPE("2");
4310
+                    case 3:
4311
+                        RETURN_AS_TYPE("3");
4312
+                    case 4:
4313
+                        RETURN_AS_TYPE("4");
4314
+                    default:
4315
+                        LOGIC_ERROR();
4316
+                        return nullptr;
4317
+                }
4318
+            }
4319
+            else
4320
+            {
4321
+                TODO();
4322
+                return "TOperator_TODO";
4323
+            }
4324
+
4325
+#undef RETURN_AS_TYPE
4326
+        }
4327
+
4328
+        case TOperator::EOpPackUnorm2x16:
4329
+            return "metal::pack_float_to_unorm2x16";
4330
+        case TOperator::EOpPackSnorm2x16:
4331
+            return "metal::pack_float_to_snorm2x16";
4332
+
4333
+        case TOperator::EOpPackUnorm4x8:
4334
+            return "metal::pack_float_to_unorm4x8";
4335
+        case TOperator::EOpPackSnorm4x8:
4336
+            return "metal::pack_float_to_snorm4x8";
4337
+
4338
+        case TOperator::EOpUnpackUnorm2x16:
4339
+            return "metal::unpack_unorm2x16_to_float";
4340
+        case TOperator::EOpUnpackSnorm2x16:
4341
+            return "metal::unpack_snorm2x16_to_float";
4342
+
4343
+        case TOperator::EOpUnpackUnorm4x8:
4344
+            return "metal::unpack_unorm4x8_to_float";
4345
+        case TOperator::EOpUnpackSnorm4x8:
4346
+            return "metal::unpack_snorm4x8_to_float";
4347
+
4348
+        case TOperator::EOpPackHalf2x16:
4349
+            return "ANGLE_pack_half_2x16";
4350
+        case TOperator::EOpUnpackHalf2x16:
4351
+            return "ANGLE_unpack_half_2x16";
4352
+
4353
+        case TOperator::EOpBitfieldExtract:
4354
+        case TOperator::EOpBitfieldInsert:
4355
+        case TOperator::EOpBitfieldReverse:
4356
+        case TOperator::EOpBitCount:
4357
+        case TOperator::EOpFindLSB:
4358
+        case TOperator::EOpFindMSB:
4359
+        case TOperator::EOpUaddCarry:
4360
+        case TOperator::EOpUsubBorrow:
4361
+        case TOperator::EOpUmulExtended:
4362
+        case TOperator::EOpImulExtended:
4363
+        case TOperator::EOpBarrier:
4364
+        case TOperator::EOpMemoryBarrier:
4365
+        case TOperator::EOpMemoryBarrierAtomicCounter:
4366
+        case TOperator::EOpMemoryBarrierBuffer:
4367
+        case TOperator::EOpMemoryBarrierImage:
4368
+        case TOperator::EOpMemoryBarrierShared:
4369
+        case TOperator::EOpGroupMemoryBarrier:
4370
+        case TOperator::EOpAtomicAdd:
4371
+        case TOperator::EOpAtomicMin:
4372
+        case TOperator::EOpAtomicMax:
4373
+        case TOperator::EOpAtomicAnd:
4374
+        case TOperator::EOpAtomicOr:
4375
+        case TOperator::EOpAtomicXor:
4376
+        case TOperator::EOpAtomicExchange:
4377
+        case TOperator::EOpAtomicCompSwap:
4378
+        case TOperator::EOpEmitVertex:
4379
+        case TOperator::EOpEndPrimitive:
4380
+        case TOperator::EOpFTransform:
4381
+        case TOperator::EOpPackDouble2x32:
4382
+        case TOperator::EOpUnpackDouble2x32:
4383
+        case TOperator::EOpArrayLength:
4384
+            TODO();
4385
+            return "TOperator_TODO";
4386
+
4387
+        case TOperator::EOpNull:
4388
+        case TOperator::EOpConstruct:
4389
+        case TOperator::EOpCallFunctionInAST:
4390
+        case TOperator::EOpCallInternalRawFunction:
4391
+        case TOperator::EOpCallBuiltInFunction:
4392
+        case TOperator::EOpIndexDirect:
4393
+        case TOperator::EOpIndexIndirect:
4394
+        case TOperator::EOpIndexDirectStruct:
4395
+        case TOperator::EOpIndexDirectInterfaceBlock:
4396
+            LOGIC_ERROR();
4397
+            return nullptr;
4398
+    }
4399
+}
4400
+
4401
+#if 0
4402
+static int GetOperatorPrecedence(TOperator op)
4403
+{
4404
+    switch (op)
4405
+    {
4406
+        case TOperator::EOpComma: {
4407
+            return 17;
4408
+        } break;
4409
+
4410
+        case TOperator::EOpAssign:
4411
+        case TOperator::EOpInitialize:
4412
+        case TOperator::EOpAddAssign:
4413
+        case TOperator::EOpSubAssign:
4414
+        case TOperator::EOpMulAssign:
4415
+        case TOperator::EOpDivAssign:
4416
+        case TOperator::EOpIModAssign:
4417
+        case TOperator::EOpBitShiftLeftAssign:
4418
+        case TOperator::EOpBitShiftRightAssign:
4419
+        case TOperator::EOpBitwiseAndAssign:
4420
+        case TOperator::EOpBitwiseXorAssign:
4421
+        case TOperator::EOpBitwiseOrAssign: {
4422
+            return 16;
4423
+        } break;
4424
+
4425
+        case TOperator::EOpLogicalOr: {
4426
+            return 15;
4427
+        } break;
4428
+
4429
+        case TOperator::EOpLogicalAnd: {
4430
+            return 14;
4431
+        } break;
4432
+
4433
+        case TOperator::EOpBitwiseOr: {
4434
+            return 13;
4435
+        } break;
4436
+
4437
+        case TOperator::EOpBitwiseXor: {
4438
+            return 12;
4439
+        } break;
4440
+
4441
+        case TOperator::EOpBitwiseAnd: {
4442
+            return 11;
4443
+        } break;
4444
+
4445
+        case TOperator::EOpLogicalXor:
4446
+        case TOperator::EOpEqual:
4447
+        case TOperator::EOpNotEqual: {
4448
+            return 10;
4449
+        } break;
4450
+
4451
+        case TOperator::EOpLessThan:
4452
+        case TOperator::EOpGreaterThan:
4453
+        case TOperator::EOpLessThanEqual:
4454
+        case TOperator::EOpGreaterThanEqual: {
4455
+            return 9;
4456
+        } break;
4457
+
4458
+        case TOperator::EOpBitShiftLeft:
4459
+        case TOperator::EOpBitShiftRight: {
4460
+            return 7;
4461
+        } break;
4462
+
4463
+        case TOperator::EOpAdd:
4464
+        case TOperator::EOpSub: {
4465
+            return 6;
4466
+        } break;
4467
+
4468
+        case TOperator::EOpMul:
4469
+        case TOperator::EOpDiv:
4470
+        case TOperator::EOpIMod: {
4471
+            return 5;
4472
+        } break;
4473
+
4474
+        case TOperator::EOpNegative:
4475
+        case TOperator::EOpPositive:
4476
+        case TOperator::EOpLogicalNot:
4477
+        case TOperator::EOpBitwiseNot:
4478
+        case TOperator::EOpPreIncrement:
4479
+        case TOperator::EOpPreDecrement: {
4480
+            return 3;
4481
+        } break;
4482
+
4483
+        case TOperator::EOpPostIncrement:
4484
+        case TOperator::EOpPostDecrement: {
4485
+            return 2;
4486
+        } break;
4487
+
4488
+        default: {
4489
+            TODO();
4490
+            return -1;
4491
+        }
4492
+    }
4493
+}
4494
+
4495
+namespace
4496
+{
4497
+
4498
+enum class Associativity
4499
+{
4500
+    None,
4501
+    Left,
4502
+    Right,
4503
+};
4504
+
4505
+} // anonymous namespace
4506
+
4507
+static Associativity GetAssociativity(TOperator op)
4508
+{
4509
+    switch (op)
4510
+    {
4511
+        case TOperator::EOpAdd:
4512
+        case TOperator::EOpSub:
4513
+        case TOperator::EOpMul:
4514
+        case TOperator::EOpDiv:
4515
+        case TOperator::EOpIMod:
4516
+        case TOperator::EOpBitShiftLeft:
4517
+        case TOperator::EOpBitShiftRight:
4518
+        case TOperator::EOpBitwiseAnd:
4519
+        case TOperator::EOpBitwiseXor:
4520
+        case TOperator::EOpBitwiseOr:
4521
+        case TOperator::EOpEqual:
4522
+        case TOperator::EOpNotEqual:
4523
+        case TOperator::EOpLessThan:
4524
+        case TOperator::EOpGreaterThan:
4525
+        case TOperator::EOpLessThanEqual:
4526
+        case TOperator::EOpGreaterThanEqual:
4527
+        case TOperator::EOpLogicalOr:
4528
+        case TOperator::EOpLogicalXor:
4529
+        case TOperator::EOpLogicalAnd:
4530
+        case TOperator::EOpComma: {
4531
+            return Associativity::Left;
4532
+        } break;
4533
+
4534
+        case TOperator::EOpAssign:
4535
+        case TOperator::EOpInitialize:
4536
+        case TOperator::EOpAddAssign:
4537
+        case TOperator::EOpSubAssign:
4538
+        case TOperator::EOpMulAssign:
4539
+        case TOperator::EOpDivAssign:
4540
+        case TOperator::EOpIModAssign:
4541
+        case TOperator::EOpBitShiftLeftAssign:
4542
+        case TOperator::EOpBitShiftRightAssign:
4543
+        case TOperator::EOpBitwiseAndAssign:
4544
+        case TOperator::EOpBitwiseXorAssign:
4545
+        case TOperator::EOpBitwiseOrAssign: {
4546
+            return Associativity::Right;
4547
+        } break;
4548
+
4549
+        case TOperator::EOpNegative:
4550
+        case TOperator::EOpPositive:
4551
+        case TOperator::EOpLogicalNot:
4552
+        case TOperator::EOpBitwiseNot:
4553
+        case TOperator::EOpPostIncrement:
4554
+        case TOperator::EOpPostDecrement:
4555
+        case TOperator::EOpPreIncrement:
4556
+        case TOperator::EOpPreDecrement: {
4557
+            return Associativity::None;
4558
+        } break;
4559
+
4560
+        default: {
4561
+            TODO();
4562
+            return Associativity::None;
4563
+        }
4564
+    }
4565
+}
4566
+#endif
4567
+
4568
+static bool IsSymbolicOperator(TOperator op,
4569
+                               const TType &resultType,
4570
+                               const TType *argType0,
4571
+                               const TType *argType1 = nullptr)
4572
+{
4573
+    if (op == TOperator::EOpCallBuiltInFunction)
4574
+    {
4575
+        return false;
4576
+    }
4577
+    return !std::isalnum(GetOperatorString(op, resultType, argType0, argType1)[0]);
4578
+}
4579
+
4580
+static TIntermBinary *AsSpecificBinaryNode(TIntermNode &node, TOperator op)
4581
+{
4582
+    TIntermBinary *binaryNode = node.getAsBinaryNode();
4583
+    if (binaryNode)
4584
+    {
4585
+        return binaryNode->getOp() == op ? binaryNode : nullptr;
4586
+    }
4587
+    return nullptr;
4588
+}
4589
+
4590
+static bool Parenthesize(TIntermNode &node)
4591
+{
4592
+    if (node.getAsSymbolNode())
4593
+    {
4594
+        return false;
4595
+    }
4596
+    if (node.getAsConstantUnion())
4597
+    {
4598
+        return false;
4599
+    }
4600
+    if (node.getAsAggregate())
4601
+    {
4602
+        return false;
4603
+    }
4604
+    if (node.getAsSwizzleNode())
4605
+    {
4606
+        return false;
4607
+    }
4608
+
4609
+    if (TIntermUnary *unaryNode = node.getAsUnaryNode())
4610
+    {
4611
+        // TODO: Use a precedence and associativity rules instead of this ad-hoc impl.
4612
+        const TType &resultType = unaryNode->getType();
4613
+        const TType &argType    = unaryNode->getOperand()->getType();
4614
+        return IsSymbolicOperator(unaryNode->getOp(), resultType, &argType);
4615
+    }
4616
+
4617
+    if (TIntermBinary *binaryNode = node.getAsBinaryNode())
4618
+    {
4619
+        // TODO: Use a precedence and associativity rules instead of this ad-hoc impl.
4620
+        const TOperator op = binaryNode->getOp();
4621
+        switch (op)
4622
+        {
4623
+            case TOperator::EOpIndexDirectStruct:
4624
+            case TOperator::EOpIndexDirectInterfaceBlock:
4625
+            case TOperator::EOpIndexDirect:
4626
+            case TOperator::EOpIndexIndirect:
4627
+                return Parenthesize(*binaryNode->getLeft());
4628
+
4629
+            case TOperator::EOpAssign:
4630
+            case TOperator::EOpInitialize:
4631
+                return AsSpecificBinaryNode(*binaryNode->getRight(), TOperator::EOpComma);
4632
+
4633
+            default:
4634
+            {
4635
+                const TType &resultType = binaryNode->getType();
4636
+                const TType &leftType   = binaryNode->getLeft()->getType();
4637
+                const TType &rightType  = binaryNode->getRight()->getType();
4638
+                return IsSymbolicOperator(binaryNode->getOp(), resultType, &leftType, &rightType);
4639
+            }
4640
+        }
4641
+    }
4642
+
4643
+    return true;
4644
+}
4645
+
4646
+void GenMetalTraverser::groupedTraverse(TIntermNode &node)
4647
+{
4648
+    const bool emitParens = Parenthesize(node);
4649
+
4650
+    if (emitParens)
4651
+    {
4652
+        mOut << "(";
4653
+    }
4654
+
4655
+    node.traverse(this);
4656
+
4657
+    if (emitParens)
4658
+    {
4659
+        mOut << ")";
4660
+    }
4661
+}
4662
+
4663
+void GenMetalTraverser::emitPostQualifier(const EmitVariableDeclarationConfig &evdConfig,
4664
+                                          const VarDecl &decl,
4665
+                                          const TQualifier qualifier)
4666
+{
4667
+    switch (qualifier)
4668
+    {
4669
+        case TQualifier::EvqPosition:
4670
+        case TQualifier::EvqFragCoord:
4671
+            mOut << " [[position]]";
4672
+            break;
4673
+
4674
+        case TQualifier::EvqPointSize:
4675
+            mOut << " [[point_size]]";
4676
+            break;
4677
+
4678
+        case TQualifier::EvqVertexID:
4679
+            if (evdConfig.isMainParameter)
4680
+            {
4681
+                mOut << " [[vertex_id]]";
4682
+            }
4683
+            break;
4684
+
4685
+        case TQualifier::EvqPointCoord:
4686
+            if (evdConfig.isMainParameter)
4687
+            {
4688
+                mOut << " [[point_coord]]";
4689
+            }
4690
+            break;
4691
+
4692
+        case TQualifier::EvqFrontFacing:
4693
+            if (evdConfig.isMainParameter)
4694
+            {
4695
+                mOut << " [[front_facing]]";
4696
+            }
4697
+            break;
4698
+
4699
+        default:
4700
+            break;
4701
+    }
4702
+
4703
+    const bool isInvariant =
4704
+        decl.isField() ? mInvariants.contains(decl.field()) : mInvariants.contains(decl.variable());
4705
+
4706
+    if (isInvariant)
4707
+    {
4708
+        mOut << " [[invariant]]";
4709
+    }
4710
+}
4711
+
4712
+static void EmitName(Sink &out, const Name &name)
4713
+{
4714
+#if defined(ANGLE_ENABLE_ASSERTS)
4715
+    DebugSink::EscapedSink escapedOut(out.escape());
4716
+#else
4717
+    TInfoSinkBase &escapedOut = out;
4718
+#endif
4719
+    name.emit(escapedOut);
4720
+}
4721
+
4722
+void GenMetalTraverser::emitNameOf(const TField &object)
4723
+{
4724
+    EmitName(mOut, Name(object));
4725
+}
4726
+
4727
+void GenMetalTraverser::emitNameOf(const TSymbol &object)
4728
+{
4729
+    auto it = mRenamedSymbols.find(&object);
4730
+    if (it == mRenamedSymbols.end())
4731
+    {
4732
+        EmitName(mOut, Name(object));
4733
+    }
4734
+    else
4735
+    {
4736
+        EmitName(mOut, it->second);
4737
+    }
4738
+}
4739
+
4740
+void GenMetalTraverser::emitNameOf(const VarDecl &object)
4741
+{
4742
+    if (object.isField())
4743
+    {
4744
+        emitNameOf(object.field());
4745
+    }
4746
+    else
4747
+    {
4748
+        emitNameOf(object.variable());
4749
+    }
4750
+}
4751
+
4752
+void GenMetalTraverser::emitBareTypeName(const TType &type, const EmitTypeConfig &etConfig)
4753
+{
4754
+    const TBasicType basicType = type.getBasicType();
4755
+
4756
+    switch (basicType)
4757
+    {
4758
+        case TBasicType::EbtVoid:
4759
+        case TBasicType::EbtBool:
4760
+        case TBasicType::EbtFloat:
4761
+        case TBasicType::EbtInt:
4762
+        case TBasicType::EbtUInt:
4763
+        {
4764
+            mOut << type.getBasicString();
4765
+        }
4766
+        break;
4767
+
4768
+        case TBasicType::EbtStruct:
4769
+        {
4770
+            const TStructure &structure = *type.getStruct();
4771
+            emitNameOf(structure);
4772
+        }
4773
+        break;
4774
+
4775
+        case TBasicType::EbtInterfaceBlock:
4776
+        {
4777
+            const TInterfaceBlock &interfaceBlock = *type.getInterfaceBlock();
4778
+            emitNameOf(interfaceBlock);
4779
+        }
4780
+        break;
4781
+
4782
+        default:
4783
+        {
4784
+            if (IsSampler(basicType))
4785
+            {
4786
+                if (etConfig.evdConfig && etConfig.evdConfig->isMainParameter)
4787
+                {
4788
+                    EmitName(mOut, GetTextureTypeName(basicType));
4789
+                }
4790
+                else
4791
+                {
4792
+                    const TStructure &env = mSymbolEnv.getTextureEnv(basicType);
4793
+                    emitNameOf(env);
4794
+                }
4795
+            }
4796
+            else
4797
+            {
4798
+                TODO();
4799
+            }
4800
+        }
4801
+    }
4802
+}
4803
+
4804
+void GenMetalTraverser::emitType(const TType &type, const EmitTypeConfig &etConfig)
4805
+{
4806
+    if (etConfig.evdConfig)
4807
+    {
4808
+        const auto &evdConfig = *etConfig.evdConfig;
4809
+        if (evdConfig.isPointer)
4810
+        {
4811
+            mOut << toString(*evdConfig.isPointer);
4812
+            mOut << " ";
4813
+        }
4814
+        else if (evdConfig.isReference)
4815
+        {
4816
+            mOut << toString(*evdConfig.isReference);
4817
+            mOut << " ";
4818
+        }
4819
+    }
4820
+
4821
+    if (type.isArray())
4822
+    {
4823
+        mOut << "ANGLE_tensor<";
4824
+    }
4825
+
4826
+    if (type.isVector() || type.isMatrix())
4827
+    {
4828
+        mOut << "metal::";
4829
+    }
4830
+
4831
+    if (etConfig.evdConfig && etConfig.evdConfig->isPacked)
4832
+    {
4833
+        mOut << "packed_";
4834
+    }
4835
+
4836
+    emitBareTypeName(type, etConfig);
4837
+
4838
+    if (type.isVector())
4839
+    {
4840
+        mOut << type.getNominalSize();
4841
+    }
4842
+    else if (type.isMatrix())
4843
+    {
4844
+        mOut << type.getCols() << "x" << type.getRows();
4845
+    }
4846
+
4847
+    if (type.isArray())
4848
+    {
4849
+        for (auto size : type.getArraySizes())
4850
+        {
4851
+            mOut << ", " << size;
4852
+        }
4853
+        mOut << ">";
4854
+    }
4855
+
4856
+    if (etConfig.evdConfig)
4857
+    {
4858
+        const auto &evdConfig = *etConfig.evdConfig;
4859
+        if (evdConfig.isPointer)
4860
+        {
4861
+            mOut << " *";
4862
+        }
4863
+        else if (evdConfig.isReference)
4864
+        {
4865
+            mOut << " &";
4866
+        }
4867
+    }
4868
+}
4869
+
4870
+void GenMetalTraverser::emitFieldDeclaration(const TField &field,
4871
+                                             const TStructure &parent,
4872
+                                             FieldAnnotationIndices &annotationIndices)
4873
+{
4874
+    const TType &type      = *field.type();
4875
+    const TBasicType basic = type.getBasicType();
4876
+
4877
+    EmitVariableDeclarationConfig evdConfig;
4878
+    evdConfig.emitPostQualifier      = true;
4879
+    evdConfig.disableStructSpecifier = true;
4880
+    evdConfig.isPacked               = mSymbolEnv.isPacked(field);
4881
+    evdConfig.isPointer              = mSymbolEnv.isPointer(field);
4882
+    evdConfig.isReference            = mSymbolEnv.isReference(field);
4883
+    emitVariableDeclaration(VarDecl(field), evdConfig);
4884
+
4885
+    const TQualifier qual = type.getQualifier();
4886
+    switch (qual)
4887
+    {
4888
+        case TQualifier::EvqFlatIn:
4889
+            if (mPipelineStructs.fragmentIn.external == &parent)
4890
+            {
4891
+                mOut << " [[flat]]";
4892
+            }
4893
+            break;
4894
+
4895
+        case TQualifier::EvqFragmentOut:
4896
+        case TQualifier::EvqFragData:
4897
+            if (mPipelineStructs.fragmentOut.external == &parent)
4898
+            {
4899
+                if ((type.isVector() &&
4900
+                     (basic == TBasicType::EbtInt || basic == TBasicType::EbtUInt ||
4901
+                      basic == TBasicType::EbtFloat)) ||
4902
+                    type.getQualifier() == EvqFragData)
4903
+                {
4904
+                    // TODO:
4905
+                    // This is not correct in general and needs a reimplementation.
4906
+                    // In GLSL 3.0, We can't always assume this is going to be a safe index.
4907
+                    // See 4.3.8.2
4908
+                    // https://www.khronos.org/registry/OpenGL/specs/es/3.0/GLSL_ES_Specification_3.00.pdf
4909
+                    size_t index = annotationIndices.color++;
4910
+                    mOut << " [[color(" << index << ")]]";
4911
+                }
4912
+            }
4913
+            break;
4914
+
4915
+        case TQualifier::EvqFragDepth:
4916
+            mOut << " [[depth(any)]]";
4917
+            break;
4918
+
4919
+        default:
4920
+            break;
4921
+    }
4922
+}
4923
+
4924
+static std::map<Name, size_t> BuildExternalAttributeIndexMap(
4925
+    const TCompiler &compiler,
4926
+    const PipelineScoped<TStructure> &structure)
4927
+{
4928
+    ASSERT(structure.isTotallyFull());
4929
+
4930
+    const auto &shaderVars     = compiler.getAttributes();
4931
+    const size_t shaderVarSize = shaderVars.size();
4932
+    size_t shaderVarIndex      = 0;
4933
+
4934
+    const auto &externalFields = structure.external->fields();
4935
+    const size_t externalSize  = externalFields.size();
4936
+    size_t externalIndex       = 0;
4937
+
4938
+    const auto &internalFields = structure.internal->fields();
4939
+    const size_t internalSize  = internalFields.size();
4940
+    size_t internalIndex       = 0;
4941
+
4942
+    // Internal fields are never split. External fields are sometimes split.
4943
+    ASSERT(externalSize >= internalSize);
4944
+
4945
+    // Structures do not contain any inactive fields.
4946
+    ASSERT(shaderVarSize >= internalSize);
4947
+
4948
+    std::map<Name, size_t> externalNameToAttributeIndex;
4949
+    size_t attributeIndex = 0;
4950
+
4951
+    while (internalIndex < internalSize)
4952
+    {
4953
+        const TField &internalField = *internalFields[internalIndex];
4954
+        const Name internalName     = Name(internalField);
4955
+        const TType &internalType   = *internalField.type();
4956
+        while (internalName.rawName() != shaderVars[shaderVarIndex].name)
4957
+        {
4958
+            // This case represents an inactive field.
4959
+
4960
+            ++shaderVarIndex;
4961
+            ASSERT(shaderVarIndex < shaderVarSize);
4962
+
4963
+            ++attributeIndex;  // TODO: Might need to increment more if shader var type is a matrix.
4964
+        }
4965
+
4966
+        const size_t cols = internalType.isMatrix() ? internalType.getCols() : 1;
4967
+
4968
+        for (size_t c = 0; c < cols; ++c)
4969
+        {
4970
+            const TField &externalField = *externalFields[externalIndex];
4971
+            const Name externalName     = Name(externalField);
4972
+            ASSERT(!externalField.type()->isMatrix());
4973
+
4974
+            externalNameToAttributeIndex[externalName] = attributeIndex;
4975
+
4976
+            ++externalIndex;
4977
+            ++attributeIndex;
4978
+        }
4979
+
4980
+        ++shaderVarIndex;
4981
+        ++internalIndex;
4982
+    }
4983
+
4984
+    ASSERT(shaderVarIndex <= shaderVarSize);
4985
+    ASSERT(externalIndex <= externalSize);  // less than if padding was introduced
4986
+    ASSERT(internalIndex == internalSize);
4987
+
4988
+    return externalNameToAttributeIndex;
4989
+}
4990
+
4991
+void GenMetalTraverser::emitAttributeDeclaration(const TField &field,
4992
+                                                 FieldAnnotationIndices &annotationIndices)
4993
+{
4994
+    EmitVariableDeclarationConfig evdConfig;
4995
+    evdConfig.disableStructSpecifier = true;
4996
+    emitVariableDeclaration(VarDecl(field), evdConfig);
4997
+    mOut << " [[attribute(" << annotationIndices.attribute++ << ")]]";
4998
+}
4999
+
5000
+void GenMetalTraverser::emitStructDeclaration(const TType &type)
5001
+{
5002
+    ASSERT(type.getBasicType() == TBasicType::EbtStruct);
5003
+    ASSERT(type.isStructSpecifier());
5004
+
5005
+    mOut << "struct ";
5006
+    emitBareTypeName(type, {});
5007
+
5008
+    mOut << "\n";
5009
+    emitOpenBrace();
5010
+
5011
+    const TStructure &structure = *type.getStruct();
5012
+    std::map<Name, size_t> fieldToAttributeIndex;
5013
+    const bool hasAttributeIndices           = mPipelineStructs.vertexIn.external == &structure;
5014
+    const bool reclaimUnusedAttributeIndices = mCompiler.getShaderVersion() < 300;
5015
+
5016
+    if (hasAttributeIndices)
5017
+    {
5018
+        fieldToAttributeIndex =
5019
+            BuildExternalAttributeIndexMap(mCompiler, mPipelineStructs.vertexIn);
5020
+    }
5021
+
5022
+    FieldAnnotationIndices annotationIndices;
5023
+
5024
+    for (const TField *field : structure.fields())
5025
+    {
5026
+        emitIndentation();
5027
+        if (hasAttributeIndices)
5028
+        {
5029
+            const auto it = fieldToAttributeIndex.find(Name(*field));
5030
+            if (it == fieldToAttributeIndex.end())
5031
+            {
5032
+                ASSERT(field->symbolType() == SymbolType::AngleInternal);
5033
+                ASSERT(field->name().beginsWith("_"));
5034
+                ASSERT(angle::EndsWith(field->name().data(), "_pad"));
5035
+                emitFieldDeclaration(*field, structure, annotationIndices);
5036
+            }
5037
+            else
5038
+            {
5039
+                ASSERT(field->symbolType() != SymbolType::AngleInternal ||
5040
+                       !field->name().beginsWith("_") ||
5041
+                       !angle::EndsWith(field->name().data(), "_pad"));
5042
+                if (!reclaimUnusedAttributeIndices)
5043
+                {
5044
+                    annotationIndices.attribute = it->second;
5045
+                }
5046
+                emitAttributeDeclaration(*field, annotationIndices);
5047
+            }
5048
+        }
5049
+        else
5050
+        {
5051
+            emitFieldDeclaration(*field, structure, annotationIndices);
5052
+        }
5053
+        mOut << ";\n";
5054
+    }
5055
+
5056
+    if (!mPipelineStructs.matches(structure, true, true))
5057
+    {
5058
+        MetalLayoutOfConfig layoutConfig;
5059
+        layoutConfig.treatSamplersAsTextureEnv = true;
5060
+        Layout layout                          = MetalLayoutOf(type, layoutConfig);
5061
+        size_t pad                             = layout.sizeOf % 16;
5062
+        if (pad != 0)
5063
+        {
5064
+            emitIndentation();
5065
+            mOut << "char ";
5066
+            EmitName(mOut, mIdGen.createNewName("pad"));
5067
+            mOut << "[" << pad << "];\n";
5068
+        }
5069
+    }
5070
+
5071
+    emitCloseBrace();
5072
+}
5073
+
5074
+void GenMetalTraverser::emitOrdinaryVariableDeclaration(
5075
+    const VarDecl &decl,
5076
+    const EmitVariableDeclarationConfig &evdConfig)
5077
+{
5078
+    EmitTypeConfig etConfig;
5079
+    etConfig.evdConfig = &evdConfig;
5080
+
5081
+    const TType &type = decl.type();
5082
+    emitType(type, etConfig);
5083
+
5084
+    if (decl.symbolType() != SymbolType::Empty)
5085
+    {
5086
+        mOut << " ";
5087
+        emitNameOf(decl);
5088
+    }
5089
+}
5090
+
5091
+void GenMetalTraverser::emitVariableDeclaration(const VarDecl &decl,
5092
+                                                const EmitVariableDeclarationConfig &evdConfig)
5093
+{
5094
+    const SymbolType symbolType = decl.symbolType();
5095
+    const TType &type           = decl.type();
5096
+    const TBasicType basicType  = type.getBasicType();
5097
+
5098
+    switch (basicType)
5099
+    {
5100
+        case TBasicType::EbtStruct:
5101
+        {
5102
+            if (type.isStructSpecifier() && !evdConfig.disableStructSpecifier)
5103
+            {
5104
+                ASSERT(!evdConfig.isParameter);
5105
+                emitStructDeclaration(type);
5106
+                if (symbolType != SymbolType::Empty)
5107
+                {
5108
+                    mOut << " ";
5109
+                    emitNameOf(decl);
5110
+                }
5111
+            }
5112
+            else
5113
+            {
5114
+                emitOrdinaryVariableDeclaration(decl, evdConfig);
5115
+            }
5116
+        }
5117
+        break;
5118
+
5119
+        default:
5120
+        {
5121
+            ASSERT(symbolType != SymbolType::Empty || evdConfig.isParameter);
5122
+            emitOrdinaryVariableDeclaration(decl, evdConfig);
5123
+        }
5124
+    }
5125
+
5126
+    if (evdConfig.emitPostQualifier)
5127
+    {
5128
+        emitPostQualifier(evdConfig, decl, type.getQualifier());
5129
+    }
5130
+}
5131
+
5132
+void GenMetalTraverser::visitSymbol(TIntermSymbol *symbolNode)
5133
+{
5134
+    const TVariable &var = symbolNode->variable();
5135
+    const TType &type    = var.getType();
5136
+
5137
+    ASSERT(var.symbolType() != SymbolType::Empty);
5138
+
5139
+    if (type.getBasicType() == TBasicType::EbtVoid)
5140
+    {
5141
+        mOut << "/*";
5142
+        emitNameOf(var);
5143
+        mOut << "*/";
5144
+    }
5145
+    else
5146
+    {
5147
+        emitNameOf(var);
5148
+    }
5149
+}
5150
+
5151
+void GenMetalTraverser::emitSingleConstant(const TConstantUnion *const constUnion)
5152
+{
5153
+    switch (constUnion->getType())
5154
+    {
5155
+        case TBasicType::EbtBool:
5156
+        {
5157
+            mOut << (constUnion->getBConst() ? "true" : "false");
5158
+        }
5159
+        break;
5160
+
5161
+        case TBasicType::EbtFloat:
5162
+        {
5163
+            mOut << constUnion->getFConst() << "f";
5164
+        }
5165
+        break;
5166
+
5167
+        case TBasicType::EbtInt:
5168
+        {
5169
+            mOut << constUnion->getIConst();
5170
+        }
5171
+        break;
5172
+
5173
+        case TBasicType::EbtUInt:
5174
+        {
5175
+            mOut << constUnion->getUConst() << "u";
5176
+        }
5177
+        break;
5178
+
5179
+        default:
5180
+        {
5181
+            TODO();
5182
+        }
5183
+    }
5184
+}
5185
+
5186
+const TConstantUnion *GenMetalTraverser::emitConstantUnionArray(
5187
+    const TConstantUnion *const constUnion,
5188
+    const size_t size)
5189
+{
5190
+    const TConstantUnion *constUnionIterated = constUnion;
5191
+    for (size_t i = 0; i < size; i++, constUnionIterated++)
5192
+    {
5193
+        emitSingleConstant(constUnionIterated);
5194
+
5195
+        if (i != size - 1)
5196
+        {
5197
+            mOut << ", ";
5198
+        }
5199
+    }
5200
+    return constUnionIterated;
5201
+}
5202
+
5203
+const TConstantUnion *GenMetalTraverser::emitConstantUnion(const TType &type,
5204
+                                                           const TConstantUnion *constUnionBegin)
5205
+{
5206
+    const TConstantUnion *constUnionCurr = constUnionBegin;
5207
+    const TStructure *structure          = type.getStruct();
5208
+    if (structure)
5209
+    {
5210
+        EmitTypeConfig config = EmitTypeConfig{nullptr};
5211
+        emitType(type, config);
5212
+        mOut << "{";
5213
+        const TFieldList &fields = structure->fields();
5214
+        for (size_t i = 0; i < fields.size(); ++i)
5215
+        {
5216
+            const TType *fieldType = fields[i]->type();
5217
+            constUnionCurr         = emitConstantUnion(*fieldType, constUnionCurr);
5218
+            if (i != fields.size() - 1)
5219
+            {
5220
+                mOut << ", ";
5221
+            }
5222
+        }
5223
+        mOut << "}";
5224
+    }
5225
+    else
5226
+    {
5227
+        size_t size    = type.getObjectSize();
5228
+        bool writeType = size > 1;
5229
+        if (writeType)
5230
+        {
5231
+            EmitTypeConfig config = EmitTypeConfig{nullptr};
5232
+            emitType(type, config);
5233
+            mOut << "(";
5234
+        }
5235
+        constUnionCurr = emitConstantUnionArray(constUnionCurr, size);
5236
+        if (writeType)
5237
+        {
5238
+            mOut << ")";
5239
+        }
5240
+    }
5241
+    return constUnionCurr;
5242
+}
5243
+
5244
+void GenMetalTraverser::visitConstantUnion(TIntermConstantUnion *constValueNode)
5245
+{
5246
+    emitConstantUnion(constValueNode->getType(), constValueNode->getConstantValue());
5247
+}
5248
+
5249
+bool GenMetalTraverser::visitSwizzle(Visit, TIntermSwizzle *swizzleNode)
5250
+{
5251
+    groupedTraverse(*swizzleNode->getOperand());
5252
+    mOut << ".";
5253
+
5254
+    {
5255
+#if defined(ANGLE_ENABLE_ASSERTS)
5256
+        DebugSink::EscapedSink escapedOut(mOut.escape());
5257
+        TInfoSinkBase &out = escapedOut.get();
5258
+#else
5259
+        TInfoSinkBase &out        = mOut;
5260
+#endif
5261
+        swizzleNode->writeOffsetsAsXYZW(&out);
5262
+    }
5263
+
5264
+    return false;
5265
+}
5266
+
5267
+const TField &GenMetalTraverser::getDirectField(const TFieldListCollection &fieldListCollection,
5268
+                                                const TConstantUnion &index)
5269
+{
5270
+    ASSERT(index.getType() == TBasicType::EbtInt);
5271
+
5272
+    const TFieldList &fieldList = fieldListCollection.fields();
5273
+    const int indexVal          = index.getIConst();
5274
+    const TField &field         = *fieldList[indexVal];
5275
+
5276
+    return field;
5277
+}
5278
+
5279
+const TField &GenMetalTraverser::getDirectField(const TIntermTyped &fieldsNode,
5280
+                                                TIntermTyped &indexNode)
5281
+{
5282
+    const TType &fieldsType = fieldsNode.getType();
5283
+
5284
+    const TFieldListCollection *fieldListCollection = fieldsType.getStruct();
5285
+    if (fieldListCollection == nullptr)
5286
+    {
5287
+        fieldListCollection = fieldsType.getInterfaceBlock();
5288
+    }
5289
+    ASSERT(fieldListCollection);
5290
+
5291
+    const TIntermConstantUnion *indexNode_ = indexNode.getAsConstantUnion();
5292
+    ASSERT(indexNode_);
5293
+    const TConstantUnion &index = *indexNode_->getConstantValue();
5294
+
5295
+    return getDirectField(*fieldListCollection, index);
5296
+}
5297
+
5298
+bool GenMetalTraverser::visitBinary(Visit, TIntermBinary *binaryNode)
5299
+{
5300
+    const TOperator op      = binaryNode->getOp();
5301
+    TIntermTyped &leftNode  = *binaryNode->getLeft();
5302
+    TIntermTyped &rightNode = *binaryNode->getRight();
5303
+
5304
+    switch (op)
5305
+    {
5306
+        case TOperator::EOpIndexDirectStruct:
5307
+        case TOperator::EOpIndexDirectInterfaceBlock:
5308
+        {
5309
+            groupedTraverse(leftNode);
5310
+            mOut << ".";
5311
+            emitNameOf(getDirectField(leftNode, rightNode));
5312
+        }
5313
+        break;
5314
+
5315
+        case TOperator::EOpIndexDirect:
5316
+        case TOperator::EOpIndexIndirect:
5317
+        {
5318
+            groupedTraverse(leftNode);
5319
+            mOut << "[";
5320
+            rightNode.traverse(this);
5321
+            mOut << "]";
5322
+        }
5323
+        break;
5324
+
5325
+        default:
5326
+        {
5327
+            const TType &resultType = binaryNode->getType();
5328
+            const TType &leftType   = leftNode.getType();
5329
+            const TType &rightType  = rightNode.getType();
5330
+
5331
+            if (IsSymbolicOperator(op, resultType, &leftType, &rightType))
5332
+            {
5333
+                groupedTraverse(leftNode);
5334
+                if (op != TOperator::EOpComma)
5335
+                {
5336
+                    mOut << " ";
5337
+                }
5338
+                mOut << GetOperatorString(op, resultType, &leftType, &rightType) << " ";
5339
+                groupedTraverse(rightNode);
5340
+            }
5341
+            else
5342
+            {
5343
+                mOut << GetOperatorString(op, resultType, &leftType, &rightType) << "(";
5344
+                leftNode.traverse(this);
5345
+                mOut << ", ";
5346
+                rightNode.traverse(this);
5347
+                mOut << ")";
5348
+            }
5349
+        }
5350
+    }
5351
+
5352
+    return false;
5353
+}
5354
+
5355
+static bool IsPostfix(TOperator op)
5356
+{
5357
+    switch (op)
5358
+    {
5359
+        case TOperator::EOpPostIncrement:
5360
+        case TOperator::EOpPostDecrement:
5361
+            return true;
5362
+
5363
+        default:
5364
+            return false;
5365
+    }
5366
+}
5367
+
5368
+bool GenMetalTraverser::visitUnary(Visit, TIntermUnary *unaryNode)
5369
+{
5370
+    const TOperator op      = unaryNode->getOp();
5371
+    const TType &resultType = unaryNode->getType();
5372
+
5373
+    TIntermTyped &arg    = *unaryNode->getOperand();
5374
+    const TType &argType = arg.getType();
5375
+
5376
+    const char *name = GetOperatorString(op, resultType, &argType);
5377
+
5378
+    if (IsSymbolicOperator(op, resultType, &argType))
5379
+    {
5380
+        const bool postfix = IsPostfix(op);
5381
+        if (!postfix)
5382
+        {
5383
+            mOut << name;
5384
+        }
5385
+        groupedTraverse(arg);
5386
+        if (postfix)
5387
+        {
5388
+            mOut << name;
5389
+        }
5390
+    }
5391
+    else
5392
+    {
5393
+        mOut << name << "(";
5394
+        arg.traverse(this);
5395
+        mOut << ")";
5396
+    }
5397
+
5398
+    return false;
5399
+}
5400
+
5401
+bool GenMetalTraverser::visitTernary(Visit, TIntermTernary *conditionalNode)
5402
+{
5403
+    groupedTraverse(*conditionalNode->getCondition());
5404
+    mOut << " ? ";
5405
+    groupedTraverse(*conditionalNode->getTrueExpression());
5406
+    mOut << " : ";
5407
+    groupedTraverse(*conditionalNode->getFalseExpression());
5408
+
5409
+    return false;
5410
+}
5411
+
5412
+bool GenMetalTraverser::visitIfElse(Visit, TIntermIfElse *ifThenElseNode)
5413
+{
5414
+    TIntermTyped &condNode = *ifThenElseNode->getCondition();
5415
+    TIntermBlock *thenNode = ifThenElseNode->getTrueBlock();
5416
+    TIntermBlock *elseNode = ifThenElseNode->getFalseBlock();
5417
+
5418
+    emitIndentation();
5419
+    mOut << "if (";
5420
+    condNode.traverse(this);
5421
+    mOut << ")";
5422
+
5423
+    if (thenNode)
5424
+    {
5425
+        mOut << "\n";
5426
+        thenNode->traverse(this);
5427
+    }
5428
+    else
5429
+    {
5430
+        mOut << " {}";
5431
+    }
5432
+
5433
+    if (elseNode)
5434
+    {
5435
+        mOut << "\n";
5436
+        emitIndentation();
5437
+        mOut << "else\n";
5438
+        elseNode->traverse(this);
5439
+    }
5440
+    else
5441
+    {
5442
+        // Always emit "else" even when empty block to avoid nested if-stmt issues.
5443
+        mOut << " else {}";
5444
+    }
5445
+
5446
+    return false;
5447
+}
5448
+
5449
+bool GenMetalTraverser::visitSwitch(Visit, TIntermSwitch *switchNode)
5450
+{
5451
+    emitIndentation();
5452
+    mOut << "switch (";
5453
+    switchNode->getInit()->traverse(this);
5454
+    mOut << ")\n";
5455
+
5456
+    ASSERT(!mParentIsSwitch);
5457
+    mParentIsSwitch = true;
5458
+    switchNode->getStatementList()->traverse(this);
5459
+    mParentIsSwitch = false;
5460
+
5461
+    return false;
5462
+}
5463
+
5464
+bool GenMetalTraverser::visitCase(Visit, TIntermCase *caseNode)
5465
+{
5466
+    emitIndentation();
5467
+
5468
+    if (caseNode->hasCondition())
5469
+    {
5470
+        TIntermTyped *condExpr = caseNode->getCondition();
5471
+        mOut << "case ";
5472
+        condExpr->traverse(this);
5473
+        mOut << ":";
5474
+    }
5475
+    else
5476
+    {
5477
+        mOut << "default:\n";
5478
+    }
5479
+
5480
+    return false;
5481
+}
5482
+
5483
+void GenMetalTraverser::emitFunctionSignature(const TFunction &func)
5484
+{
5485
+    const bool isMain = func.isMain();
5486
+
5487
+    emitFunctionReturn(func);
5488
+
5489
+    mOut << " ";
5490
+    emitNameOf(func);
5491
+    if (isMain)
5492
+    {
5493
+        mOut << "0";
5494
+    }
5495
+    mOut << "(";
5496
+
5497
+    bool emitComma          = false;
5498
+    const size_t paramCount = func.getParamCount();
5499
+    for (size_t i = 0; i < paramCount; ++i)
5500
+    {
5501
+        if (emitComma)
5502
+        {
5503
+            mOut << ", ";
5504
+        }
5505
+        emitComma = true;
5506
+
5507
+        const TVariable &param = *func.getParam(i);
5508
+        emitFunctionParameter(func, param);
5509
+    }
5510
+
5511
+    mOut << ")";
5512
+}
5513
+
5514
+void GenMetalTraverser::emitFunctionReturn(const TFunction &func)
5515
+{
5516
+    const bool isMain = func.isMain();
5517
+
5518
+    const TType &returnType = func.getReturnType();
5519
+    if (isMain)
5520
+    {
5521
+        const TStructure *structure = returnType.getStruct();
5522
+        ASSERT(structure != nullptr);
5523
+        if (mPipelineStructs.fragmentOut.matches(*structure))
5524
+        {
5525
+            mOut << "fragment ";
5526
+        }
5527
+        else if (mPipelineStructs.vertexOut.matches(*structure))
5528
+        {
5529
+            mOut << "vertex ";
5530
+        }
5531
+        else
5532
+        {
5533
+            TODO();
5534
+        }
5535
+    }
5536
+    emitType(returnType, EmitTypeConfig());
5537
+}
5538
+
5539
+void GenMetalTraverser::emitFunctionParameter(const TFunction &func, const TVariable &param)
5540
+{
5541
+    const bool isMain = func.isMain();
5542
+
5543
+    const TType &type           = param.getType();
5544
+    const TStructure *structure = type.getStruct();
5545
+
5546
+    EmitVariableDeclarationConfig evdConfig;
5547
+    evdConfig.isParameter       = true;
5548
+    evdConfig.isMainParameter   = isMain;
5549
+    evdConfig.emitPostQualifier = isMain;
5550
+    evdConfig.isPointer         = mSymbolEnv.isPointer(param);
5551
+    evdConfig.isReference       = mSymbolEnv.isReference(param);
5552
+    emitVariableDeclaration(VarDecl(param), evdConfig);
5553
+
5554
+    if (isMain)
5555
+    {
5556
+        TranslatorMetalReflection *reflection =
5557
+            ((sh::TranslatorMetalDirect *)&mCompiler)->getTranslatorMetalReflection();
5558
+        if (structure)
5559
+        {
5560
+            if (mPipelineStructs.fragmentIn.matches(*structure) ||
5561
+                mPipelineStructs.vertexIn.matches(*structure))
5562
+            {
5563
+                mOut << " [[stage_in]]";
5564
+            }
5565
+            else if (mPipelineStructs.angleUniforms.matches(*structure))
5566
+            {
5567
+                mOut << " [[buffer(" << rx::mtl::kDriverUniformsBindingIndex << ")]]";
5568
+            }
5569
+            else if (mPipelineStructs.userUniforms.matches(*structure))
5570
+            {
5571
+                mOut << " [[buffer(" << mMainUniformBufferIndex << ")]]";
5572
+                reflection->addUniformBufferBinding(param.name().data(), mMainUniformBufferIndex);
5573
+                mMainUniformBufferIndex += type.getArraySizeProduct();
5574
+            }
5575
+            else if (structure->name() == "metal::sampler")
5576
+            {
5577
+                mOut << " [[sampler(" << (mMainSamplerIndex) << ")]]";
5578
+                const std::string originalName =
5579
+                    reflection->getOriginalName(param.uniqueId().get());
5580
+                reflection->addSamplerBinding(originalName, mMainSamplerIndex);
5581
+                mMainSamplerIndex += type.getArraySizeProduct();
5582
+            }
5583
+        }
5584
+        else if (IsSampler(type.getBasicType()))
5585
+        {
5586
+            mOut << " [[texture(" << (mMainTextureIndex) << ")]]";
5587
+            const std::string originalName = reflection->getOriginalName(param.uniqueId().get());
5588
+            reflection->addTextureBinding(originalName, mMainSamplerIndex);
5589
+            mMainTextureIndex += type.getArraySizeProduct();
5590
+        }
5591
+        else if (Name(param) == Pipeline{Pipeline::Type::InstanceId, nullptr}.getStructInstanceName(
5592
+                                    Pipeline::Variant::Modified))
5593
+        {
5594
+            mOut << " [[instance_id]]";
5595
+        }
5596
+    }
5597
+}
5598
+
5599
+void GenMetalTraverser::visitFunctionPrototype(TIntermFunctionPrototype *funcProtoNode)
5600
+{
5601
+    const TFunction &func = *funcProtoNode->getFunction();
5602
+
5603
+    emitIndentation();
5604
+    emitFunctionSignature(func);
5605
+}
5606
+
5607
+bool GenMetalTraverser::visitFunctionDefinition(Visit, TIntermFunctionDefinition *funcDefNode)
5608
+{
5609
+    const TFunction &func = *funcDefNode->getFunction();
5610
+    TIntermBlock &body    = *funcDefNode->getBody();
5611
+
5612
+    emitIndentation();
5613
+    emitFunctionSignature(func);
5614
+    mOut << "\n";
5615
+    body.traverse(this);
5616
+
5617
+    return false;
5618
+}
5619
+
5620
+GenMetalTraverser::FuncToName GenMetalTraverser::BuildFuncToName()
5621
+{
5622
+    FuncToName map;
5623
+
5624
+    auto putAngle = [&](const char *nameStr) {
5625
+        const ImmutableString name(nameStr);
5626
+        ASSERT(map.find(name) == map.end());
5627
+        map[name] = Name(nameStr, SymbolType::AngleInternal);
5628
+    };
5629
+
5630
+    putAngle("texelFetch");
5631
+    putAngle("texelFetchOffset");
5632
+    putAngle("texture");
5633
+    putAngle("texture1D");
5634
+    putAngle("texture1DLod");
5635
+    putAngle("texture1DProjLod");
5636
+    putAngle("texture2D");
5637
+    putAngle("texture2DLod");
5638
+    putAngle("texture2DProj");
5639
+    putAngle("texture2DProjLod");
5640
+    putAngle("texture3D");
5641
+    putAngle("texture3DLod");
5642
+    putAngle("texture3DProjLod");
5643
+    putAngle("textureCube");
5644
+    putAngle("textureCubeLod");
5645
+    putAngle("textureCubeProjLod");
5646
+    putAngle("textureGrad");
5647
+    putAngle("textureGradOffset");
5648
+    putAngle("textureLod");
5649
+    putAngle("textureLodOffset");
5650
+    putAngle("textureOffset");
5651
+    putAngle("textureProj");
5652
+    putAngle("textureProjGrad");
5653
+    putAngle("textureProjGradOffset");
5654
+    putAngle("textureProjLod");
5655
+    putAngle("textureProjLodOffset");
5656
+    putAngle("textureProjOffset");
5657
+    putAngle("textureSize");
5658
+
5659
+    return map;
5660
+}
5661
+
5662
+bool GenMetalTraverser::visitAggregate(Visit, TIntermAggregate *aggregateNode)
5663
+{
5664
+    const TIntermSequence &args = *aggregateNode->getSequence();
5665
+
5666
+    auto emitArgList = [&](const char *open, const char *close) {
5667
+        mOut << open;
5668
+
5669
+        bool emitComma = false;
5670
+        for (TIntermNode *arg : args)
5671
+        {
5672
+            if (emitComma)
5673
+            {
5674
+                mOut << ", ";
5675
+            }
5676
+            emitComma = true;
5677
+            arg->traverse(this);
5678
+        }
5679
+
5680
+        mOut << close;
5681
+    };
5682
+
5683
+    const TType &retType = aggregateNode->getType();
5684
+
5685
+    if (aggregateNode->isConstructor())
5686
+    {
5687
+        const bool isStandalone = getParentNode()->getAsBlock();
5688
+        if (isStandalone)
5689
+        {
5690
+            // Prevent constructor from being interpreted as a declaration by wrapping in parens.
5691
+            // This can happen if given something like:
5692
+            //      int(symbol); // <- This will be treated like `int symbol;`... don't want that.
5693
+            // So instead emit:
5694
+            //      (int(symbol));
5695
+            mOut << "(";
5696
+        }
5697
+
5698
+        const EmitTypeConfig etConfig;
5699
+
5700
+        if (retType.isArray())
5701
+        {
5702
+            emitType(retType, etConfig);
5703
+            emitArgList("{", "}");
5704
+        }
5705
+        else if (retType.getStruct())
5706
+        {
5707
+            emitType(retType, etConfig);
5708
+            emitArgList("{", "}");
5709
+        }
5710
+        else
5711
+        {
5712
+            emitType(retType, etConfig);
5713
+            emitArgList("(", ")");
5714
+        }
5715
+
5716
+        if (isStandalone)
5717
+        {
5718
+            mOut << ")";
5719
+        }
5720
+
5721
+        return false;
5722
+    }
5723
+    else
5724
+    {
5725
+        const TOperator op = aggregateNode->getOp();
5726
+        switch (op)
5727
+        {
5728
+            case TOperator::EOpCallFunctionInAST:
5729
+            case TOperator::EOpCallInternalRawFunction:
5730
+            {
5731
+                const TFunction &func = *aggregateNode->getFunction();
5732
+                emitNameOf(func);
5733
+                emitArgList("(", ")");
5734
+                return false;
5735
+            }
5736
+
5737
+            case TOperator::EOpCallBuiltInFunction:
5738
+            {
5739
+                const TFunction &func = *aggregateNode->getFunction();
5740
+                auto it               = mFuncToName.find(func.name());
5741
+                ASSERT(it != mFuncToName.end());
5742
+                EmitName(mOut, it->second);
5743
+                emitArgList("(", ")");
5744
+                return false;
5745
+            }
5746
+
5747
+            default:
5748
+            {
5749
+                auto getArgType = [&](size_t index) -> const TType * {
5750
+                    if (index < args.size())
5751
+                    {
5752
+                        TIntermTyped *arg = args[index]->getAsTyped();
5753
+                        ASSERT(arg);
5754
+                        return &arg->getType();
5755
+                    }
5756
+                    return nullptr;
5757
+                };
5758
+
5759
+                ASSERT(!args.empty());
5760
+                const TType *argType0 = getArgType(0);
5761
+                const TType *argType1 = getArgType(1);
5762
+                ASSERT(argType0);
5763
+
5764
+                const char *opName = GetOperatorString(op, retType, argType0, argType1);
5765
+
5766
+                if (IsSymbolicOperator(op, retType, argType0, argType1))
5767
+                {
5768
+                    switch (args.size())
5769
+                    {
5770
+                        case 1:
5771
+                        {
5772
+                            TIntermNode &operandNode = *aggregateNode->getChildNode(0);
5773
+                            if (IsPostfix(op))
5774
+                            {
5775
+                                mOut << opName;
5776
+                                groupedTraverse(operandNode);
5777
+                                return false;
5778
+                            }
5779
+                            else
5780
+                            {
5781
+                                groupedTraverse(operandNode);
5782
+                                mOut << opName;
5783
+                                return false;
5784
+                            }
5785
+                        }
5786
+                        break;
5787
+
5788
+                        case 2:
5789
+                        {
5790
+                            TIntermNode &leftNode  = *aggregateNode->getChildNode(0);
5791
+                            TIntermNode &rightNode = *aggregateNode->getChildNode(1);
5792
+                            groupedTraverse(leftNode);
5793
+                            mOut << " " << opName << " ";
5794
+                            groupedTraverse(rightNode);
5795
+                            return false;
5796
+                        }
5797
+                        break;
5798
+
5799
+                        default:
5800
+                            LOGIC_ERROR();
5801
+                            return false;
5802
+                    }
5803
+                }
5804
+                else
5805
+                {
5806
+                    mOut << opName;
5807
+                    emitArgList("(", ")");
5808
+                    return false;
5809
+                }
5810
+            }
5811
+        }
5812
+    }
5813
+}
5814
+
5815
+void GenMetalTraverser::emitOpenBrace()
5816
+{
5817
+    ASSERT(mIndentLevel >= 0);
5818
+
5819
+    emitIndentation();
5820
+    mOut << "{\n";
5821
+    ++mIndentLevel;
5822
+}
5823
+
5824
+void GenMetalTraverser::emitCloseBrace()
5825
+{
5826
+    ASSERT(mIndentLevel >= 1);
5827
+
5828
+    --mIndentLevel;
5829
+    emitIndentation();
5830
+    mOut << "}";
5831
+}
5832
+
5833
+static bool RequiresSemicolonTerminator(TIntermNode &node)
5834
+{
5835
+    if (node.getAsBlock())
5836
+    {
5837
+        return false;
5838
+    }
5839
+    if (node.getAsLoopNode())
5840
+    {
5841
+        return false;
5842
+    }
5843
+    if (node.getAsSwitchNode())
5844
+    {
5845
+        return false;
5846
+    }
5847
+    if (node.getAsIfElseNode())
5848
+    {
5849
+        return false;
5850
+    }
5851
+    if (node.getAsFunctionDefinition())
5852
+    {
5853
+        return false;
5854
+    }
5855
+    if (node.getAsCaseNode())
5856
+    {
5857
+        return false;
5858
+    }
5859
+    return true;
5860
+}
5861
+
5862
+static bool NewlinePad(TIntermNode &node)
5863
+{
5864
+    if (node.getAsFunctionDefinition())
5865
+    {
5866
+        return true;
5867
+    }
5868
+    if (TIntermDeclaration *declNode = node.getAsDeclarationNode())
5869
+    {
5870
+        ASSERT(declNode->getChildCount() == 1);
5871
+        TIntermNode &childNode = *declNode->getChildNode(0);
5872
+        if (TIntermSymbol *symbolNode = childNode.getAsSymbolNode())
5873
+        {
5874
+            const TVariable &var = symbolNode->variable();
5875
+            return var.getType().isStructSpecifier();
5876
+        }
5877
+        return false;
5878
+    }
5879
+    return false;
5880
+}
5881
+
5882
+bool GenMetalTraverser::visitBlock(Visit, TIntermBlock *blockNode)
5883
+{
5884
+    ASSERT(mIndentLevel >= -1);
5885
+    const bool isGlobalScope  = mIndentLevel == -1;
5886
+    const bool parentIsSwitch = mParentIsSwitch;
5887
+    mParentIsSwitch           = false;
5888
+
5889
+    if (isGlobalScope)
5890
+    {
5891
+        ++mIndentLevel;
5892
+    }
5893
+    else
5894
+    {
5895
+        emitOpenBrace();
5896
+        if (parentIsSwitch)
5897
+        {
5898
+            ++mIndentLevel;
5899
+        }
5900
+    }
5901
+
5902
+    TIntermNode *prevStmtNode = nullptr;
5903
+
5904
+    const size_t stmtCount = blockNode->getChildCount();
5905
+    for (size_t i = 0; i < stmtCount; ++i)
5906
+    {
5907
+        TIntermNode &stmtNode = *blockNode->getChildNode(i);
5908
+
5909
+        if (isGlobalScope && prevStmtNode && (NewlinePad(*prevStmtNode) || NewlinePad(stmtNode)))
5910
+        {
5911
+            mOut << "\n";
5912
+        }
5913
+        const bool isCase = stmtNode.getAsCaseNode();
5914
+        mIndentLevel -= isCase;
5915
+        emitIndentation();
5916
+        mIndentLevel += isCase;
5917
+        stmtNode.traverse(this);
5918
+        if (RequiresSemicolonTerminator(stmtNode))
5919
+        {
5920
+            mOut << ";";
5921
+        }
5922
+        mOut << "\n";
5923
+
5924
+        prevStmtNode = &stmtNode;
5925
+    }
5926
+
5927
+    if (isGlobalScope)
5928
+    {
5929
+        ASSERT(mIndentLevel == 0);
5930
+        --mIndentLevel;
5931
+    }
5932
+    else
5933
+    {
5934
+        if (parentIsSwitch)
5935
+        {
5936
+            ASSERT(mIndentLevel >= 1);
5937
+            --mIndentLevel;
5938
+        }
5939
+        emitCloseBrace();
5940
+        mParentIsSwitch = parentIsSwitch;
5941
+    }
5942
+
5943
+    return false;
5944
+}
5945
+
5946
+bool GenMetalTraverser::visitGlobalQualifierDeclaration(Visit, TIntermGlobalQualifierDeclaration *)
5947
+{
5948
+    LOGIC_ERROR();  // RewriteGlobalQualifierDecls should have been called before this.
5949
+    return false;
5950
+}
5951
+
5952
+bool GenMetalTraverser::visitDeclaration(Visit, TIntermDeclaration *declNode)
5953
+{
5954
+    ASSERT(declNode->getChildCount() == 1);
5955
+    TIntermNode &node = *declNode->getChildNode(0);
5956
+
5957
+    EmitVariableDeclarationConfig evdConfig;
5958
+
5959
+    if (TIntermSymbol *symbolNode = node.getAsSymbolNode())
5960
+    {
5961
+        const TVariable &var = symbolNode->variable();
5962
+        emitVariableDeclaration(VarDecl(var), evdConfig);
5963
+    }
5964
+    else if (TIntermBinary *initNode = node.getAsBinaryNode())
5965
+    {
5966
+        ASSERT(initNode->getOp() == TOperator::EOpInitialize);
5967
+        TIntermSymbol *symbolNode = initNode->getLeft()->getAsSymbolNode();
5968
+        TIntermTyped *valueNode   = initNode->getRight()->getAsTyped();
5969
+        ASSERT(symbolNode && valueNode);
5970
+
5971
+        if (getRootNode() == getParentBlock())
5972
+        {
5973
+            // DeferGlobalInitializers should have turned non-const global initializers into
5974
+            // deferred initializers. Note that variables marked as EvqGlobal can be treated as
5975
+            // EvqConst in some ANGLE code but not actually have their qualifier actually changed to
5976
+            // EvqConst. Thus just assume all EvqGlobal are actually EvqConst for all code run after
5977
+            // DeferGlobalInitializers.
5978
+            mOut << "constant ";
5979
+        }
5980
+
5981
+        const TVariable &var = symbolNode->variable();
5982
+        const Name varName(var);
5983
+
5984
+        if (ExpressionContainsName(varName, *valueNode))
5985
+        {
5986
+            mRenamedSymbols[&var] = mIdGen.createNewName(varName);
5987
+        }
5988
+
5989
+        emitVariableDeclaration(VarDecl(var), evdConfig);
5990
+        mOut << " = ";
5991
+        groupedTraverse(*valueNode);
5992
+    }
5993
+    else
5994
+    {
5995
+        LOGIC_ERROR();
5996
+    }
5997
+
5998
+    return false;
5999
+}
6000
+
6001
+bool GenMetalTraverser::visitLoop(Visit, TIntermLoop *loopNode)
6002
+{
6003
+    const TLoopType loopType = loopNode->getType();
6004
+
6005
+    switch (loopType)
6006
+    {
6007
+        case TLoopType::ELoopFor:
6008
+            return visitForLoop(loopNode);
6009
+        case TLoopType::ELoopWhile:
6010
+            return visitWhileLoop(loopNode);
6011
+        case TLoopType::ELoopDoWhile:
6012
+            return visitDoWhileLoop(loopNode);
6013
+    }
6014
+}
6015
+
6016
+bool GenMetalTraverser::visitForLoop(TIntermLoop *loopNode)
6017
+{
6018
+    ASSERT(loopNode->getType() == TLoopType::ELoopFor);
6019
+
6020
+    TIntermNode *initNode  = loopNode->getInit();
6021
+    TIntermTyped *condNode = loopNode->getCondition();
6022
+    TIntermTyped *exprNode = loopNode->getExpression();
6023
+    TIntermBlock *bodyNode = loopNode->getBody();
6024
+    ASSERT(bodyNode);
6025
+
6026
+    mOut << "for (";
6027
+
6028
+    if (initNode)
6029
+    {
6030
+        initNode->traverse(this);
6031
+    }
6032
+    else
6033
+    {
6034
+        mOut << " ";
6035
+    }
6036
+
6037
+    mOut << "; ";
6038
+
6039
+    if (condNode)
6040
+    {
6041
+        condNode->traverse(this);
6042
+    }
6043
+
6044
+    mOut << "; ";
6045
+
6046
+    if (exprNode)
6047
+    {
6048
+        exprNode->traverse(this);
6049
+    }
6050
+
6051
+    mOut << ")\n";
6052
+
6053
+    bodyNode->traverse(this);
6054
+
6055
+    return false;
6056
+}
6057
+
6058
+bool GenMetalTraverser::visitWhileLoop(TIntermLoop *loopNode)
6059
+{
6060
+    ASSERT(loopNode->getType() == TLoopType::ELoopWhile);
6061
+
6062
+    TIntermNode *initNode  = loopNode->getInit();
6063
+    TIntermTyped *condNode = loopNode->getCondition();
6064
+    TIntermTyped *exprNode = loopNode->getExpression();
6065
+    TIntermBlock *bodyNode = loopNode->getBody();
6066
+    ASSERT(condNode && bodyNode);
6067
+    ASSERT(!initNode && !exprNode);
6068
+
6069
+    emitIndentation();
6070
+    mOut << "while (";
6071
+    condNode->traverse(this);
6072
+    mOut << ")\n";
6073
+    bodyNode->traverse(this);
6074
+
6075
+    return false;
6076
+}
6077
+
6078
+bool GenMetalTraverser::visitDoWhileLoop(TIntermLoop *loopNode)
6079
+{
6080
+    ASSERT(loopNode->getType() == TLoopType::ELoopDoWhile);
6081
+
6082
+    TIntermNode *initNode  = loopNode->getInit();
6083
+    TIntermTyped *condNode = loopNode->getCondition();
6084
+    TIntermTyped *exprNode = loopNode->getExpression();
6085
+    TIntermBlock *bodyNode = loopNode->getBody();
6086
+    ASSERT(condNode && bodyNode);
6087
+    ASSERT(!initNode && !exprNode);
6088
+
6089
+    emitIndentation();
6090
+    mOut << "do\n";
6091
+    bodyNode->traverse(this);
6092
+    mOut << "\n";
6093
+    emitIndentation();
6094
+    mOut << "while (";
6095
+    condNode->traverse(this);
6096
+    mOut << ");";
6097
+
6098
+    return false;
6099
+}
6100
+
6101
+bool GenMetalTraverser::visitBranch(Visit, TIntermBranch *branchNode)
6102
+{
6103
+    const TOperator flowOp = branchNode->getFlowOp();
6104
+    TIntermTyped *exprNode = branchNode->getExpression();
6105
+
6106
+    emitIndentation();
6107
+
6108
+    switch (flowOp)
6109
+    {
6110
+        case TOperator::EOpKill:
6111
+        {
6112
+            ASSERT(exprNode == nullptr);
6113
+            mOut << "metal::discard_fragment()";
6114
+        }
6115
+        break;
6116
+
6117
+        case TOperator::EOpReturn:
6118
+        {
6119
+            mOut << "return";
6120
+            if (exprNode)
6121
+            {
6122
+                mOut << " ";
6123
+                exprNode->traverse(this);
6124
+            }
6125
+        }
6126
+        break;
6127
+
6128
+        case TOperator::EOpBreak:
6129
+        {
6130
+            ASSERT(exprNode == nullptr);
6131
+            mOut << "break";
6132
+        }
6133
+        break;
6134
+
6135
+        case TOperator::EOpContinue:
6136
+        {
6137
+            ASSERT(exprNode == nullptr);
6138
+            mOut << "continue";
6139
+        }
6140
+        break;
6141
+
6142
+        default:
6143
+        {
6144
+            LOGIC_ERROR();
6145
+        }
6146
+    }
6147
+
6148
+    return false;
6149
+}
6150
+
6151
+static size_t emitMetalCallCount = 0;
6152
+
6153
+bool sh::EmitMetal(TCompiler &compiler,
6154
+                   TIntermBlock &root,
6155
+                   IdGen &idGen,
6156
+                   const PipelineStructs &pipelineStructs,
6157
+                   const Invariants &invariants,
6158
+                   SymbolEnv &symbolEnv,
6159
+                   const ProgramPreludeConfig &ppc)
6160
+{
6161
+    TInfoSinkBase &out = compiler.getInfoSink().obj;
6162
+
6163
+    {
6164
+        ++emitMetalCallCount;
6165
+        auto filenameProto = readStringEnvVar("GMD_FIXED_EMIT");
6166
+        if (!filenameProto.empty())
6167
+        {
6168
+            if (filenameProto != "/dev/null")
6169
+            {
6170
+                auto tryOpen = [&](char const *ext) {
6171
+                    auto filename = filenameProto;
6172
+                    filename += std::to_string(emitMetalCallCount);
6173
+                    filename += ".";
6174
+                    filename += ext;
6175
+                    return fopen(filename.c_str(), "rb");
6176
+                };
6177
+                FILE *file = tryOpen("metal");
6178
+                if (!file)
6179
+                {
6180
+                    file = tryOpen("cpp");
6181
+                }
6182
+                ASSERT(file);
6183
+
6184
+                fseek(file, 0, SEEK_END);
6185
+                size_t fileSize = ftell(file);
6186
+                fseek(file, 0, SEEK_SET);
6187
+
6188
+                std::vector<char> buff;
6189
+                buff.resize(fileSize + 1);
6190
+                fread(buff.data(), fileSize, 1, file);
6191
+                buff.back() = '\0';
6192
+
6193
+                fclose(file);
6194
+
6195
+                out << buff.data();
6196
+            }
6197
+
6198
+            return true;
6199
+        }
6200
+    }
6201
+
6202
+    out << "\n\n";
6203
+
6204
+    if (!EmitProgramPrelude(root, out, ppc))
6205
+    {
6206
+        return false;
6207
+    }
6208
+
6209
+    {
6210
+#if defined(ANGLE_ENABLE_ASSERTS)
6211
+        DebugSink outWrapper(out, readBoolEnvVar("GMD_STDOUT"));
6212
+        outWrapper.watch(readStringEnvVar("GMD_WATCH_STRING"));
6213
+#else
6214
+        TInfoSinkBase &outWrapper = out;
6215
+#endif
6216
+        GenMetalTraverser gen(compiler, outWrapper, idGen, pipelineStructs, invariants, symbolEnv);
6217
+        root.traverse(&gen);
6218
+    }
6219
+
6220
+    out << "\n";
6221
+
6222
+    return true;
6223
+}
6224
diff --git a/src/compiler/translator/TranslatorMetalDirect/EmitMetal.h b/src/compiler/translator/TranslatorMetalDirect/EmitMetal.h
6225
new file mode 100644
6226
index 0000000..d48af9a
6227
--- /dev/null
6228
+++ b/src/compiler/translator/TranslatorMetalDirect/EmitMetal.h
6229
@@ -0,0 +1,32 @@
6230
+//
6231
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
6232
+// Use of this source code is governed by a BSD-style license that can be
6233
+// found in the LICENSE file.
6234
+//
6235
+
6236
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_EMITMETAL_H_
6237
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_EMITMETAL_H_
6238
+
6239
+#include "common/angleutils.h"
6240
+#include "compiler/translator/Compiler.h"
6241
+#include "compiler/translator/TranslatorMetalDirect/IdGen.h"
6242
+#include "compiler/translator/TranslatorMetalDirect/ProgramPrelude.h"
6243
+#include "compiler/translator/TranslatorMetalDirect/RewriteGlobalQualifierDecls.h"
6244
+#include "compiler/translator/TranslatorMetalDirect/RewritePipelines.h"
6245
+#include "compiler/translator/TranslatorMetalDirect/SymbolEnv.h"
6246
+
6247
+namespace sh
6248
+{
6249
+
6250
+// Walks the AST and emits Metal code.
6251
+ANGLE_NO_DISCARD bool EmitMetal(TCompiler &compiler,
6252
+                                TIntermBlock &root,
6253
+                                IdGen &idGen,
6254
+                                const PipelineStructs &pipelineStructs,
6255
+                                const Invariants &invariants,
6256
+                                SymbolEnv &symbolEnv,
6257
+                                const ProgramPreludeConfig &ppc);
6258
+
6259
+}  // namespace sh
6260
+
6261
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_EMITMETAL_H_
6262
diff --git a/src/compiler/translator/TranslatorMetalDirect/EnvironmentVariable.h b/src/compiler/translator/TranslatorMetalDirect/EnvironmentVariable.h
6263
new file mode 100644
6264
index 0000000..d823fc7
6265
--- /dev/null
6266
+++ b/src/compiler/translator/TranslatorMetalDirect/EnvironmentVariable.h
6267
@@ -0,0 +1,45 @@
6268
+//
6269
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
6270
+// Use of this source code is governed by a BSD-style license that can be
6271
+// found in the LICENSE file.
6272
+//
6273
+
6274
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_ENVIRONMENTVARIABLE_H_
6275
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_ENVIRONMENTVARIABLE_H_
6276
+
6277
+#include <cstdlib>
6278
+#include <string>
6279
+
6280
+#include "common/debug.h"
6281
+
6282
+namespace sh
6283
+{
6284
+
6285
+inline bool readBoolEnvVar(const char *var)
6286
+{
6287
+    const char *str = std::getenv(var);
6288
+    if (str == nullptr)
6289
+    {
6290
+        return false;
6291
+    }
6292
+    if (strcmp(str, "0") == 0)
6293
+    {
6294
+        return false;
6295
+    }
6296
+    ASSERT(strcmp(str, "1") == 0);
6297
+    return true;
6298
+}
6299
+
6300
+inline std::string readStringEnvVar(const char *var)
6301
+{
6302
+    const char *str = std::getenv(var);
6303
+    if (str == nullptr)
6304
+    {
6305
+        return "";
6306
+    }
6307
+    return str;
6308
+}
6309
+
6310
+}  // namespace sh
6311
+
6312
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_ENVIRONMENTVARIABLE_H_
6313
diff --git a/src/compiler/translator/TranslatorMetalDirect/HoistConstants.cpp b/src/compiler/translator/TranslatorMetalDirect/HoistConstants.cpp
6314
new file mode 100644
6315
index 0000000..ce9c03e
6316
--- /dev/null
6317
+++ b/src/compiler/translator/TranslatorMetalDirect/HoistConstants.cpp
6318
@@ -0,0 +1,96 @@
6319
+//
6320
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
6321
+// Use of this source code is governed by a BSD-style license that can be
6322
+// found in the LICENSE file.
6323
+//
6324
+
6325
+#include "compiler/translator/TranslatorMetalDirect/HoistConstants.h"
6326
+#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
6327
+#include "compiler/translator/TranslatorMetalDirect/Layout.h"
6328
+#include "compiler/translator/tree_util/FindFunction.h"
6329
+#include "compiler/translator/tree_util/IntermRebuild.h"
6330
+#include "compiler/translator/tree_util/ReplaceVariable.h"
6331
+
6332
+using namespace sh;
6333
+
6334
+////////////////////////////////////////////////////////////////////////////////
6335
+
6336
+namespace
6337
+{
6338
+
6339
+class Rewriter : private TIntermRebuild
6340
+{
6341
+  private:
6342
+    const size_t mMinRequiredSize;
6343
+    TIntermSequence mHoistedDeclNodes;
6344
+
6345
+  public:
6346
+    Rewriter(TCompiler &compiler, size_t minRequiredSize)
6347
+        : TIntermRebuild(compiler, true, false), mMinRequiredSize(minRequiredSize)
6348
+    {}
6349
+
6350
+    PreResult visitDeclarationPre(TIntermDeclaration &declNode) override
6351
+    {
6352
+        if (getParentFunction())
6353
+        {
6354
+            Declaration decl  = ViewDeclaration(declNode);
6355
+            const TType &type = decl.symbol.getType();
6356
+            if (type.getQualifier() == TQualifier::EvqConst)
6357
+            {
6358
+                if (decl.initExpr && decl.initExpr->hasConstantValue())
6359
+                {
6360
+                    const size_t size = MetalLayoutOf(type).sizeOf;
6361
+                    if (size >= mMinRequiredSize)
6362
+                    {
6363
+                        mHoistedDeclNodes.push_back(&declNode);
6364
+                        return nullptr;
6365
+                    }
6366
+                }
6367
+            }
6368
+        }
6369
+        return {declNode, VisitBits::Neither};
6370
+    }
6371
+
6372
+    bool rewrite(TIntermBlock &root, IdGen &idGen)
6373
+    {
6374
+        if (!rebuildRoot(root))
6375
+        {
6376
+            return false;
6377
+        }
6378
+
6379
+        if (mHoistedDeclNodes.empty())
6380
+        {
6381
+            return true;
6382
+        }
6383
+
6384
+        root.insertChildNodes(FindFirstFunctionDefinitionIndex(&root), mHoistedDeclNodes);
6385
+
6386
+        for (TIntermNode *opaqueDeclNode : mHoistedDeclNodes)
6387
+        {
6388
+            TIntermDeclaration *declNode = opaqueDeclNode->getAsDeclarationNode();
6389
+            ASSERT(declNode);
6390
+            const TVariable &oldVar = ViewDeclaration(*declNode).symbol.variable();
6391
+            const Name newName      = idGen.createNewName(oldVar.name());
6392
+            auto *newVar = new TVariable(&mSymbolTable, newName.rawName(), &oldVar.getType(),
6393
+                                         newName.symbolType());
6394
+            if (!ReplaceVariable(&mCompiler, &root, &oldVar, newVar))
6395
+            {
6396
+                return false;
6397
+            }
6398
+        }
6399
+
6400
+        return true;
6401
+    }
6402
+};
6403
+
6404
+}  // anonymous namespace
6405
+
6406
+////////////////////////////////////////////////////////////////////////////////
6407
+
6408
+bool sh::HoistConstants(TCompiler &compiler,
6409
+                        TIntermBlock &root,
6410
+                        IdGen &idGen,
6411
+                        size_t minRequiredSize)
6412
+{
6413
+    return Rewriter(compiler, minRequiredSize).rewrite(root, idGen);
6414
+}
6415
diff --git a/src/compiler/translator/TranslatorMetalDirect/HoistConstants.h b/src/compiler/translator/TranslatorMetalDirect/HoistConstants.h
6416
new file mode 100644
6417
index 0000000..0306a5e
6418
--- /dev/null
6419
+++ b/src/compiler/translator/TranslatorMetalDirect/HoistConstants.h
6420
@@ -0,0 +1,26 @@
6421
+//
6422
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
6423
+// Use of this source code is governed by a BSD-style license that can be
6424
+// found in the LICENSE file.
6425
+//
6426
+
6427
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_HOISTCONSTANTS_H_
6428
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_HOISTCONSTANTS_H_
6429
+
6430
+#include "common/angleutils.h"
6431
+#include "compiler/translator/Compiler.h"
6432
+#include "compiler/translator/TranslatorMetalDirect/IdGen.h"
6433
+
6434
+namespace sh
6435
+{
6436
+
6437
+// Hoists function-local constants to the global scope if their Metal sizeof meets
6438
+// `minRequiredSize`.
6439
+ANGLE_NO_DISCARD bool HoistConstants(TCompiler &compiler,
6440
+                                     TIntermBlock &root,
6441
+                                     IdGen &idGen,
6442
+                                     size_t minRequiredSize);
6443
+
6444
+}  // namespace sh
6445
+
6446
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_HOISTCONSTANTS_H_
6447
diff --git a/src/compiler/translator/TranslatorMetalDirect/IdGen.cpp b/src/compiler/translator/TranslatorMetalDirect/IdGen.cpp
6448
new file mode 100644
6449
index 0000000..84aed6b
6450
--- /dev/null
6451
+++ b/src/compiler/translator/TranslatorMetalDirect/IdGen.cpp
6452
@@ -0,0 +1,97 @@
6453
+//
6454
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
6455
+// Use of this source code is governed by a BSD-style license that can be
6456
+// found in the LICENSE file.
6457
+//
6458
+
6459
+#include <cctype>
6460
+#include <cstring>
6461
+#include <limits>
6462
+#include <unordered_map>
6463
+#include <unordered_set>
6464
+
6465
+#include "compiler/translator/TranslatorMetalDirect/RewriteKeywords.h"
6466
+
6467
+using namespace sh;
6468
+
6469
+////////////////////////////////////////////////////////////////////////////////
6470
+
6471
+IdGen::IdGen() {}
6472
+
6473
+template <typename String, typename StringToImmutable>
6474
+Name IdGen::createNewName(size_t count,
6475
+                          const String *baseNames,
6476
+                          const StringToImmutable &toImmutable)
6477
+{
6478
+    const unsigned id = mNext++;
6479
+    char idBuffer[std::numeric_limits<unsigned>::digits10 + 1];
6480
+    sprintf(idBuffer, "%u", id);
6481
+
6482
+    mNewNameBuffer.clear();
6483
+    mNewNameBuffer += '_';
6484
+    mNewNameBuffer += idBuffer;
6485
+
6486
+    // Note:
6487
+    // Double underscores are only allowed in C++ (and thus Metal) vendor identifiers, so here we
6488
+    // take care not to introduce any.
6489
+
6490
+    for (size_t i = 0; i < count; ++i)
6491
+    {
6492
+        const ImmutableString baseName = toImmutable(baseNames[i]);
6493
+        if (!baseName.empty())
6494
+        {
6495
+            const char *base = baseName.data();
6496
+            if (baseName.beginsWith(kAngleInternalPrefix))
6497
+            {
6498
+                base += sizeof(kAngleInternalPrefix) - 1;
6499
+            }
6500
+            if (*base == '_')
6501
+            {
6502
+                ++base;
6503
+            }
6504
+            ASSERT(*base != '_');
6505
+
6506
+            if (mNewNameBuffer.back() != '_')
6507
+            {
6508
+                mNewNameBuffer += '_';
6509
+            }
6510
+
6511
+            mNewNameBuffer += base;
6512
+        }
6513
+    }
6514
+
6515
+    return Name(ImmutableString(mNewNameBuffer), SymbolType::AngleInternal);
6516
+}
6517
+
6518
+Name IdGen::createNewName(const ImmutableString &baseName)
6519
+{
6520
+    return createNewName({baseName});
6521
+}
6522
+
6523
+Name IdGen::createNewName(const Name &baseName)
6524
+{
6525
+    return createNewName(baseName.rawName());
6526
+}
6527
+
6528
+Name IdGen::createNewName(const char *baseName)
6529
+{
6530
+    return createNewName(ImmutableString(baseName));
6531
+}
6532
+
6533
+Name IdGen::createNewName(std::initializer_list<ImmutableString> baseNames)
6534
+{
6535
+    return createNewName(baseNames.size(), baseNames.begin(),
6536
+                         [](const ImmutableString &s) { return s; });
6537
+}
6538
+
6539
+Name IdGen::createNewName(std::initializer_list<Name> baseNames)
6540
+{
6541
+    return createNewName(baseNames.size(), baseNames.begin(),
6542
+                         [](const Name &s) { return s.rawName(); });
6543
+}
6544
+
6545
+Name IdGen::createNewName(std::initializer_list<const char *> baseNames)
6546
+{
6547
+    return createNewName(baseNames.size(), baseNames.begin(),
6548
+                         [](const char *s) { return ImmutableString(s); });
6549
+}
6550
diff --git a/src/compiler/translator/TranslatorMetalDirect/IdGen.h b/src/compiler/translator/TranslatorMetalDirect/IdGen.h
6551
new file mode 100644
6552
index 0000000..582089f
6553
--- /dev/null
6554
+++ b/src/compiler/translator/TranslatorMetalDirect/IdGen.h
6555
@@ -0,0 +1,41 @@
6556
+//
6557
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
6558
+// Use of this source code is governed by a BSD-style license that can be
6559
+// found in the LICENSE file.
6560
+//
6561
+
6562
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_IDGEN_H_
6563
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_IDGEN_H_
6564
+
6565
+#include "common/angleutils.h"
6566
+#include "compiler/translator/TranslatorMetalDirect/Name.h"
6567
+
6568
+namespace sh
6569
+{
6570
+
6571
+// For creating new fresh names.
6572
+// All names created are marked as SymbolType::AngleInternal.
6573
+class IdGen : angle::NonCopyable
6574
+{
6575
+  public:
6576
+    IdGen();
6577
+
6578
+    Name createNewName(const ImmutableString &baseName);
6579
+    Name createNewName(const Name &baseName);
6580
+    Name createNewName(const char *baseName);
6581
+    Name createNewName(std::initializer_list<ImmutableString> baseNames);
6582
+    Name createNewName(std::initializer_list<Name> baseNames);
6583
+    Name createNewName(std::initializer_list<const char *> baseNames);
6584
+
6585
+  private:
6586
+    template <typename String, typename StringToImmutable>
6587
+    Name createNewName(size_t count, const String *baseNames, const StringToImmutable &toImmutable);
6588
+
6589
+  private:
6590
+    unsigned mNext = 0;          // `unsigned` because of "%u" use in sprintf
6591
+    std::string mNewNameBuffer;  // reusable buffer to avoid tons of reallocations
6592
+};
6593
+
6594
+}  // namespace sh
6595
+
6596
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_IDGEN_H_
6597
diff --git a/src/compiler/translator/TranslatorMetalDirect/Layout.cpp b/src/compiler/translator/TranslatorMetalDirect/Layout.cpp
6598
new file mode 100644
6599
index 0000000..5346f6f
6600
--- /dev/null
6601
+++ b/src/compiler/translator/TranslatorMetalDirect/Layout.cpp
6602
@@ -0,0 +1,401 @@
6603
+//
6604
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
6605
+// Use of this source code is governed by a BSD-style license that can be
6606
+// found in the LICENSE file.
6607
+//
6608
+
6609
+#include <algorithm>
6610
+#include <cctype>
6611
+#include <cstring>
6612
+#include <limits>
6613
+#include <unordered_map>
6614
+#include <unordered_set>
6615
+
6616
+#include "compiler/translator/Symbol.h"
6617
+#include "compiler/translator/TranslatorMetalDirect/Debug.h"
6618
+#include "compiler/translator/TranslatorMetalDirect/Layout.h"
6619
+
6620
+using namespace sh;
6621
+
6622
+////////////////////////////////////////////////////////////////////////////////
6623
+
6624
+enum class Language
6625
+{
6626
+    Metal,
6627
+    GLSL,
6628
+};
6629
+
6630
+static size_t RoundUpToMultipleOf(size_t x, size_t multiple)
6631
+{
6632
+    const size_t rem = x % multiple;
6633
+    return rem == 0 ? x : x + (multiple - rem);
6634
+}
6635
+
6636
+void Layout::requireAlignment(size_t align, bool pad)
6637
+{
6638
+    alignOf = std::max(alignOf, align);
6639
+    if (pad)
6640
+    {
6641
+        sizeOf = RoundUpToMultipleOf(sizeOf, align);
6642
+    }
6643
+}
6644
+
6645
+bool Layout::operator==(const Layout &other) const
6646
+{
6647
+    return sizeOf == other.sizeOf && alignOf == other.alignOf;
6648
+}
6649
+
6650
+void Layout::operator+=(const Layout &other)
6651
+{
6652
+    requireAlignment(other.alignOf, true);
6653
+    sizeOf += other.sizeOf;
6654
+}
6655
+
6656
+void Layout::operator*=(size_t scale)
6657
+{
6658
+    sizeOf *= scale;
6659
+}
6660
+
6661
+Layout Layout::operator+(const Layout &other) const
6662
+{
6663
+    auto self = *this;
6664
+    self += other;
6665
+    return self;
6666
+}
6667
+
6668
+Layout Layout::operator*(size_t scale) const
6669
+{
6670
+    auto self = *this;
6671
+    self *= scale;
6672
+    return self;
6673
+}
6674
+
6675
+static Layout ScalarLayoutOf(const TType &type, Language language)
6676
+{
6677
+    const TBasicType basicType = type.getBasicType();
6678
+    switch (basicType)
6679
+    {
6680
+        case TBasicType::EbtBool:
6681
+            return {1, 1};
6682
+        case TBasicType::EbtInt:
6683
+        case TBasicType::EbtUInt:
6684
+        case TBasicType::EbtFloat:
6685
+            return {4, 4};
6686
+        default:
6687
+            if (IsSampler(basicType))
6688
+            {
6689
+                switch (language)
6690
+                {
6691
+                    case Language::Metal:
6692
+                        return {8, 8};
6693
+                    case Language::GLSL:
6694
+                        return {4, 4};
6695
+                }
6696
+            }
6697
+            TODO();
6698
+            return Layout::Invalid();
6699
+    }
6700
+}
6701
+
6702
+static const size_t innerScalesPacked[]   = {0, 1, 2, 3, 4};
6703
+static const size_t innerScalesUnpacked[] = {0, 1, 2, 4, 4};
6704
+
6705
+Layout sh::MetalLayoutOf(const TType &type, MetalLayoutOfConfig config)
6706
+{
6707
+    ASSERT(type.getNominalSize() <= 4);
6708
+    ASSERT(type.getSecondarySize() <= 4);
6709
+
6710
+    const TLayoutBlockStorage storage = type.getLayoutQualifier().blockStorage;
6711
+
6712
+    const bool isPacked = !config.disablePacking && (storage == TLayoutBlockStorage::EbsPacked ||
6713
+                                                     storage == TLayoutBlockStorage::EbsShared);
6714
+
6715
+    if (type.isArray() && !config.maskArray)
6716
+    {
6717
+        config.maskArray    = true;
6718
+        const Layout layout = MetalLayoutOf(type, config);
6719
+        config.maskArray    = false;
6720
+        const size_t vol    = type.getArraySizeProduct();
6721
+        return layout * vol;
6722
+    }
6723
+
6724
+    if (const TStructure *structure = type.getStruct())
6725
+    {
6726
+        ASSERT(type.getNominalSize() == 1);
6727
+        ASSERT(type.getSecondarySize() == 1);
6728
+        auto config2             = config;
6729
+        config2.maskArray        = false;
6730
+        auto layout              = Layout::Identity();
6731
+        const TFieldList &fields = structure->fields();
6732
+        for (const TField *field : fields)
6733
+        {
6734
+            layout += MetalLayoutOf(*field->type(), config2);
6735
+        }
6736
+        if (config.assumeStructsAreTailPadded)
6737
+        {
6738
+            size_t pad = layout.sizeOf % 16;
6739
+            layout.sizeOf += pad;
6740
+        }
6741
+        layout.sizeOf = RoundUpToMultipleOf(layout.sizeOf, layout.alignOf);
6742
+        return layout;
6743
+    }
6744
+
6745
+    if (config.treatSamplersAsTextureEnv && IsSampler(type.getBasicType()))
6746
+    {
6747
+        return {16, 8};  // pointer{8,8} and metal::sampler{8,8}
6748
+    }
6749
+
6750
+    const Layout scalarLayout = ScalarLayoutOf(type, Language::Metal);
6751
+
6752
+    if (type.isRank0())
6753
+    {
6754
+        return scalarLayout;
6755
+    }
6756
+    else if (type.isVector())
6757
+    {
6758
+        if (isPacked)
6759
+        {
6760
+            const size_t innerScale = innerScalesPacked[type.getNominalSize()];
6761
+            auto layout = Layout{scalarLayout.sizeOf * innerScale, scalarLayout.alignOf};
6762
+            return layout;
6763
+        }
6764
+        else
6765
+        {
6766
+            const size_t innerScale = innerScalesUnpacked[type.getNominalSize()];
6767
+            auto layout             = Layout::Both(scalarLayout.sizeOf * innerScale);
6768
+            return layout;
6769
+        }
6770
+    }
6771
+    else
6772
+    {
6773
+        ASSERT(type.isMatrix());
6774
+        ASSERT(type.getBasicType() == TBasicType::EbtFloat);
6775
+        // typeCxR <=> typeR[C]
6776
+        const size_t innerScale = innerScalesUnpacked[type.getRows()];
6777
+        const size_t outerScale = static_cast<size_t>(type.getCols());
6778
+        const size_t n          = scalarLayout.sizeOf * innerScale;
6779
+        return {n * outerScale, n};
6780
+    }
6781
+}
6782
+
6783
+TLayoutBlockStorage sh::Overlay(TLayoutBlockStorage oldStorage, const TType &type)
6784
+{
6785
+    const TLayoutBlockStorage newStorage = type.getLayoutQualifier().blockStorage;
6786
+    switch (newStorage)
6787
+    {
6788
+        case TLayoutBlockStorage::EbsUnspecified:
6789
+            return oldStorage == TLayoutBlockStorage::EbsUnspecified ? kDefaultLayoutBlockStorage
6790
+                                                                     : oldStorage;
6791
+        default:
6792
+            return newStorage;
6793
+    }
6794
+}
6795
+
6796
+TLayoutMatrixPacking sh::Overlay(TLayoutMatrixPacking oldPacking, const TType &type)
6797
+{
6798
+    const TLayoutMatrixPacking newPacking = type.getLayoutQualifier().matrixPacking;
6799
+    switch (newPacking)
6800
+    {
6801
+        case TLayoutMatrixPacking::EmpUnspecified:
6802
+            return oldPacking == TLayoutMatrixPacking::EmpUnspecified ? kDefaultLayoutMatrixPacking
6803
+                                                                      : oldPacking;
6804
+        default:
6805
+            return newPacking;
6806
+    }
6807
+}
6808
+
6809
+bool sh::CanBePacked(TLayoutBlockStorage storage)
6810
+{
6811
+    switch (storage)
6812
+    {
6813
+        case TLayoutBlockStorage::EbsPacked:
6814
+        case TLayoutBlockStorage::EbsShared:
6815
+            return true;
6816
+        case TLayoutBlockStorage::EbsStd140:
6817
+        case TLayoutBlockStorage::EbsStd430:
6818
+            return false;
6819
+        case TLayoutBlockStorage::EbsUnspecified:
6820
+            LOGIC_ERROR();
6821
+            return false;
6822
+    }
6823
+}
6824
+
6825
+bool sh::CanBePacked(TLayoutQualifier layoutQualifier)
6826
+{
6827
+    return CanBePacked(layoutQualifier.blockStorage);
6828
+}
6829
+
6830
+bool sh::CanBePacked(const TType &type)
6831
+{
6832
+    if (!type.isVector())
6833
+    {
6834
+        return false;
6835
+    }
6836
+    return CanBePacked(type.getLayoutQualifier());
6837
+}
6838
+
6839
+void sh::SetBlockStorage(TType &type, TLayoutBlockStorage storage)
6840
+{
6841
+    auto qual         = type.getLayoutQualifier();
6842
+    qual.blockStorage = storage;
6843
+    type.setLayoutQualifier(qual);
6844
+}
6845
+
6846
+static Layout CommonGlslStructLayoutOf(TField const *const *begin,
6847
+                                       TField const *const *end,
6848
+                                       const TLayoutBlockStorage storage,
6849
+                                       const TLayoutMatrixPacking matrixPacking,
6850
+                                       const bool maskArray,
6851
+                                       const size_t baseAlignment)
6852
+{
6853
+    const bool isPacked =
6854
+        storage == TLayoutBlockStorage::EbsPacked || storage == TLayoutBlockStorage::EbsShared;
6855
+
6856
+    auto layout = Layout::Identity();
6857
+    for (auto iter = begin; iter != end; ++iter)
6858
+    {
6859
+        layout += GlslLayoutOf(*(*iter)->type(), storage, matrixPacking, false);
6860
+    }
6861
+    if (!isPacked)  // XXX: Correct?
6862
+    {
6863
+        layout.sizeOf = RoundUpToMultipleOf(layout.sizeOf, layout.alignOf);
6864
+    }
6865
+    layout.requireAlignment(baseAlignment, true);
6866
+    return layout;
6867
+}
6868
+
6869
+static Layout CommonGlslLayoutOf(const TType &type,
6870
+                                 const TLayoutBlockStorage storage,
6871
+                                 const TLayoutMatrixPacking matrixPacking,
6872
+                                 const bool maskArray,
6873
+                                 const size_t baseAlignment)
6874
+{
6875
+    ASSERT(storage != TLayoutBlockStorage::EbsUnspecified);
6876
+
6877
+    const bool isPacked =
6878
+        storage == TLayoutBlockStorage::EbsPacked || storage == TLayoutBlockStorage::EbsShared;
6879
+
6880
+    if (type.isArray() && !type.isMatrix() && !maskArray)
6881
+    {
6882
+        auto layout = GlslLayoutOf(type, storage, matrixPacking, true);
6883
+        layout *= type.getArraySizeProduct();
6884
+        layout.requireAlignment(baseAlignment, true);
6885
+        return layout;
6886
+    }
6887
+
6888
+    if (const TStructure *structure = type.getStruct())
6889
+    {
6890
+        ASSERT(type.getNominalSize() == 1);
6891
+        ASSERT(type.getSecondarySize() == 1);
6892
+        const TFieldList &fields = structure->fields();
6893
+        return CommonGlslStructLayoutOf(fields.data(), fields.data() + fields.size(), storage,
6894
+                                        matrixPacking, maskArray, baseAlignment);
6895
+    }
6896
+
6897
+    const auto scalarLayout = ScalarLayoutOf(type, Language::GLSL);
6898
+
6899
+    if (type.isRank0())
6900
+    {
6901
+        return scalarLayout;
6902
+    }
6903
+    else if (type.isVector())
6904
+    {
6905
+        if (isPacked)
6906
+        {
6907
+            const size_t sizeScale  = innerScalesPacked[type.getNominalSize()];
6908
+            const size_t alignScale = innerScalesUnpacked[type.getNominalSize()];
6909
+            auto layout =
6910
+                Layout{scalarLayout.sizeOf * sizeScale, scalarLayout.alignOf * alignScale};
6911
+            return layout;
6912
+        }
6913
+        else
6914
+        {
6915
+            const size_t innerScale = innerScalesUnpacked[type.getNominalSize()];
6916
+            auto layout             = Layout::Both(scalarLayout.sizeOf * innerScale);
6917
+            return layout;
6918
+        }
6919
+    }
6920
+    else
6921
+    {
6922
+        ASSERT(type.isMatrix());
6923
+
6924
+        size_t innerDim;
6925
+        size_t outerDim;
6926
+
6927
+        switch (matrixPacking)
6928
+        {
6929
+            case TLayoutMatrixPacking::EmpColumnMajor:
6930
+                innerDim = static_cast<size_t>(type.getRows());
6931
+                outerDim = static_cast<size_t>(type.getCols());
6932
+                break;
6933
+            case TLayoutMatrixPacking::EmpRowMajor:
6934
+                innerDim = static_cast<size_t>(type.getCols());
6935
+                outerDim = static_cast<size_t>(type.getRows());
6936
+                break;
6937
+            case TLayoutMatrixPacking::EmpUnspecified:
6938
+                LOGIC_ERROR();
6939
+                innerDim = 0;
6940
+                outerDim = 0;
6941
+        }
6942
+
6943
+        outerDim *= type.getArraySizeProduct();
6944
+
6945
+        const size_t innerScale = innerScalesUnpacked[innerDim];
6946
+        const size_t n          = innerScale * scalarLayout.sizeOf;
6947
+        Layout layout           = {outerDim * n, n};
6948
+        layout.requireAlignment(baseAlignment, true);
6949
+        return layout;
6950
+    }
6951
+}
6952
+
6953
+Layout sh::GlslLayoutOf(const TType &type,
6954
+                        TLayoutBlockStorage storage,
6955
+                        TLayoutMatrixPacking matrixPacking,
6956
+                        bool maskArray)
6957
+{
6958
+    ASSERT(type.getNominalSize() <= 4);
6959
+    ASSERT(type.getSecondarySize() <= 4);
6960
+
6961
+    storage       = Overlay(storage, type);
6962
+    matrixPacking = Overlay(matrixPacking, type);
6963
+
6964
+    switch (storage)
6965
+    {
6966
+        case TLayoutBlockStorage::EbsPacked:
6967
+            return CommonGlslLayoutOf(type, storage, matrixPacking, maskArray, 1);
6968
+        case TLayoutBlockStorage::EbsShared:
6969
+            return CommonGlslLayoutOf(type, storage, matrixPacking, maskArray, 16);
6970
+        case TLayoutBlockStorage::EbsStd140:
6971
+            return CommonGlslLayoutOf(type, storage, matrixPacking, maskArray, 16);
6972
+        case TLayoutBlockStorage::EbsStd430:
6973
+            return CommonGlslLayoutOf(type, storage, matrixPacking, maskArray, 1);
6974
+        case TLayoutBlockStorage::EbsUnspecified:
6975
+            LOGIC_ERROR();
6976
+            return Layout::Invalid();
6977
+    }
6978
+}
6979
+
6980
+ANGLE_NO_DISCARD Layout sh::GlslStructLayoutOf(TField const *const *begin,
6981
+                                               TField const *const *end,
6982
+                                               TLayoutBlockStorage storage,
6983
+                                               TLayoutMatrixPacking matrixPacking,
6984
+                                               bool maskArray)
6985
+{
6986
+    ASSERT(storage != TLayoutBlockStorage::EbsUnspecified);
6987
+    ASSERT(matrixPacking != TLayoutMatrixPacking::EmpUnspecified);
6988
+
6989
+    switch (storage)
6990
+    {
6991
+        case TLayoutBlockStorage::EbsPacked:
6992
+            return CommonGlslStructLayoutOf(begin, end, storage, matrixPacking, maskArray, 1);
6993
+        case TLayoutBlockStorage::EbsShared:
6994
+            return CommonGlslStructLayoutOf(begin, end, storage, matrixPacking, maskArray, 16);
6995
+        case TLayoutBlockStorage::EbsStd140:
6996
+            return CommonGlslStructLayoutOf(begin, end, storage, matrixPacking, maskArray, 16);
6997
+        case TLayoutBlockStorage::EbsStd430:
6998
+            return CommonGlslStructLayoutOf(begin, end, storage, matrixPacking, maskArray, 1);
6999
+        case TLayoutBlockStorage::EbsUnspecified:
7000
+            LOGIC_ERROR();
7001
+            return Layout::Invalid();
7002
+    }
7003
+}
7004
diff --git a/src/compiler/translator/TranslatorMetalDirect/Layout.h b/src/compiler/translator/TranslatorMetalDirect/Layout.h
7005
new file mode 100644
7006
index 0000000..1413edf
7007
--- /dev/null
7008
+++ b/src/compiler/translator/TranslatorMetalDirect/Layout.h
7009
@@ -0,0 +1,88 @@
7010
+//
7011
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
7012
+// Use of this source code is governed by a BSD-style license that can be
7013
+// found in the LICENSE file.
7014
+//
7015
+
7016
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_LAYOUT_H_
7017
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_LAYOUT_H_
7018
+
7019
+#include "common/angleutils.h"
7020
+#include "compiler/translator/Types.h"
7021
+
7022
+namespace sh
7023
+{
7024
+
7025
+constexpr const auto kDefaultLayoutBlockStorage  = TLayoutBlockStorage::EbsShared;
7026
+constexpr const auto kDefaultLayoutMatrixPacking = TLayoutMatrixPacking::EmpColumnMajor;
7027
+
7028
+// Returns `oldStorage` if `type` has unspecified block storage.
7029
+// Otherwise returns block storage of `type`.
7030
+TLayoutBlockStorage Overlay(TLayoutBlockStorage oldStorage, const TType &type);
7031
+
7032
+// Returns `oldPacking` if `type` has unspecified matrix packing.
7033
+// Otherwise returns matrix packing of `type`.
7034
+TLayoutMatrixPacking Overlay(TLayoutMatrixPacking oldPacking, const TType &type);
7035
+
7036
+// Returns whether or not it is permissable for the block storage to use a packed representation.
7037
+bool CanBePacked(TLayoutBlockStorage storage);
7038
+
7039
+// Returns whether or not it is permissable for the layout qualifier to use a packed representation.
7040
+bool CanBePacked(TLayoutQualifier layoutQualifier);
7041
+
7042
+// Returns whether or not it is permissable for the type to use a packed representation.
7043
+bool CanBePacked(const TType &type);
7044
+
7045
+// Sets the block storage for a type.
7046
+void SetBlockStorage(TType &type, TLayoutBlockStorage storage);
7047
+
7048
+// Contains `sizeof` and `alignof` information.
7049
+struct Layout
7050
+{
7051
+    size_t sizeOf;
7052
+    size_t alignOf;
7053
+
7054
+    static Layout Identity() { return {0, 1}; }
7055
+    static Layout Invalid() { return {0, 0}; }
7056
+    static Layout Both(size_t n) { return {n, n}; }
7057
+
7058
+    void requireAlignment(size_t align, bool pad);
7059
+
7060
+    bool operator==(const Layout &other) const;
7061
+
7062
+    void operator+=(const Layout &other);
7063
+    void operator*=(size_t scale);
7064
+
7065
+    Layout operator+(const Layout &other) const;
7066
+    Layout operator*(size_t scale) const;
7067
+};
7068
+
7069
+struct MetalLayoutOfConfig
7070
+{
7071
+    bool disablePacking             = false;
7072
+    bool maskArray                  = false;
7073
+    bool treatSamplersAsTextureEnv  = false;
7074
+    bool assumeStructsAreTailPadded = false;  // Pad to multiple of 16
7075
+};
7076
+
7077
+// Returns the layout of a type if it were to be represented in a Metal program.
7078
+// This deliberately ignores the TLayoutBlockStorage and TLayoutMatrixPacking of any type.
7079
+ANGLE_NO_DISCARD Layout MetalLayoutOf(const TType &type, MetalLayoutOfConfig config = {});
7080
+
7081
+// Returns the layout of a type if it were to be represented in a GLSL program.
7082
+ANGLE_NO_DISCARD Layout
7083
+GlslLayoutOf(const TType &type,
7084
+             TLayoutBlockStorage storage        = TLayoutBlockStorage::EbsUnspecified,
7085
+             TLayoutMatrixPacking matrixPacking = TLayoutMatrixPacking::EmpUnspecified,
7086
+             bool maskArray                     = false);
7087
+
7088
+// Returns the layout of a structure if it were to be represented in a GLSL program.
7089
+ANGLE_NO_DISCARD Layout GlslStructLayoutOf(TField const *const *begin,
7090
+                                           TField const *const *end,
7091
+                                           TLayoutBlockStorage storage,
7092
+                                           TLayoutMatrixPacking matrixPacking,
7093
+                                           bool maskArray = false);
7094
+
7095
+}  // namespace sh
7096
+
7097
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_LAYOUT_H_
7098
diff --git a/src/compiler/translator/TranslatorMetalDirect/MapFunctionsToDefinitions.cpp b/src/compiler/translator/TranslatorMetalDirect/MapFunctionsToDefinitions.cpp
7099
new file mode 100644
7100
index 0000000..3e30dae
7101
--- /dev/null
7102
+++ b/src/compiler/translator/TranslatorMetalDirect/MapFunctionsToDefinitions.cpp
7103
@@ -0,0 +1,34 @@
7104
+//
7105
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
7106
+// Use of this source code is governed by a BSD-style license that can be
7107
+// found in the LICENSE file.
7108
+//
7109
+
7110
+#include "compiler/translator/TranslatorMetalDirect/MapFunctionsToDefinitions.h"
7111
+#include "compiler/translator/Symbol.h"
7112
+
7113
+using namespace sh;
7114
+
7115
+class Mapper : public TIntermTraverser
7116
+{
7117
+  public:
7118
+    FunctionToDefinition mFuncToDef;
7119
+
7120
+  public:
7121
+    Mapper() : TIntermTraverser(true, false, false) {}
7122
+
7123
+    bool visitFunctionDefinition(Visit, TIntermFunctionDefinition *funcDefNode) override
7124
+    {
7125
+        const TFunction *func = funcDefNode->getFunction();
7126
+        ASSERT(func->getBuiltInOp() == TOperator::EOpNull);
7127
+        mFuncToDef[func] = funcDefNode;
7128
+        return false;
7129
+    }
7130
+};
7131
+
7132
+FunctionToDefinition sh::MapFunctionsToDefinitions(TIntermBlock &root)
7133
+{
7134
+    Mapper mapper;
7135
+    root.traverse(&mapper);
7136
+    return std::move(mapper.mFuncToDef);
7137
+}
7138
diff --git a/src/compiler/translator/TranslatorMetalDirect/MapFunctionsToDefinitions.h b/src/compiler/translator/TranslatorMetalDirect/MapFunctionsToDefinitions.h
7139
new file mode 100644
7140
index 0000000..4e56dde
7141
--- /dev/null
7142
+++ b/src/compiler/translator/TranslatorMetalDirect/MapFunctionsToDefinitions.h
7143
@@ -0,0 +1,25 @@
7144
+//
7145
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
7146
+// Use of this source code is governed by a BSD-style license that can be
7147
+// found in the LICENSE file.
7148
+//
7149
+
7150
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_MAPFUNCTIONSTODEFINITIONS_H_
7151
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_MAPFUNCTIONSTODEFINITIONS_H_
7152
+
7153
+#include <unordered_map>
7154
+
7155
+#include "compiler/translator/tree_util/IntermTraverse.h"
7156
+
7157
+namespace sh
7158
+{
7159
+
7160
+// A map from functions to their corresponding definitions.
7161
+using FunctionToDefinition = std::unordered_map<const TFunction *, TIntermFunctionDefinition *>;
7162
+
7163
+// Maps functions to their corresponding definitions.
7164
+ANGLE_NO_DISCARD FunctionToDefinition MapFunctionsToDefinitions(TIntermBlock &root);
7165
+
7166
+}  // namespace sh
7167
+
7168
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_MAPFUNCTIONSTODEFINITIONS_H_
7169
diff --git a/src/compiler/translator/TranslatorMetalDirect/MapSymbols.cpp b/src/compiler/translator/TranslatorMetalDirect/MapSymbols.cpp
7170
new file mode 100644
7171
index 0000000..035c930
7172
--- /dev/null
7173
+++ b/src/compiler/translator/TranslatorMetalDirect/MapSymbols.cpp
7174
@@ -0,0 +1,46 @@
7175
+//
7176
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
7177
+// Use of this source code is governed by a BSD-style license that can be
7178
+// found in the LICENSE file.
7179
+//
7180
+
7181
+#include "compiler/translator/TranslatorMetalDirect/MapSymbols.h"
7182
+#include "compiler/translator/tree_util/IntermRebuild.h"
7183
+
7184
+using namespace sh;
7185
+
7186
+////////////////////////////////////////////////////////////////////////////////
7187
+
7188
+namespace
7189
+{
7190
+
7191
+class Rewriter : public TIntermRebuild
7192
+{
7193
+  private:
7194
+    std::function<TIntermNode &(const TFunction *, TIntermSymbol &)> mMap;
7195
+
7196
+  public:
7197
+    Rewriter(TCompiler &compiler,
7198
+             std::function<TIntermNode &(const TFunction *, TIntermSymbol &)> map)
7199
+        : TIntermRebuild(compiler, false, true), mMap(map)
7200
+    {}
7201
+
7202
+    PostResult visitSymbolPost(TIntermSymbol &symbolNode) override
7203
+    {
7204
+        return mMap(getParentFunction(), symbolNode);
7205
+    }
7206
+};
7207
+
7208
+}  // namespace
7209
+
7210
+bool sh::MapSymbols(TCompiler &compiler,
7211
+                    TIntermBlock &root,
7212
+                    std::function<TIntermNode &(const TFunction *, TIntermSymbol &)> map)
7213
+{
7214
+    Rewriter rewriter(compiler, std::move(map));
7215
+    if (!rewriter.rebuildRoot(root))
7216
+    {
7217
+        return false;
7218
+    }
7219
+    return true;
7220
+}
7221
diff --git a/src/compiler/translator/TranslatorMetalDirect/MapSymbols.h b/src/compiler/translator/TranslatorMetalDirect/MapSymbols.h
7222
new file mode 100644
7223
index 0000000..656890a
7224
--- /dev/null
7225
+++ b/src/compiler/translator/TranslatorMetalDirect/MapSymbols.h
7226
@@ -0,0 +1,27 @@
7227
+//
7228
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
7229
+// Use of this source code is governed by a BSD-style license that can be
7230
+// found in the LICENSE file.
7231
+//
7232
+
7233
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_MAPVARIABLESTOMEMBERACCESS_H_
7234
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_MAPVARIABLESTOMEMBERACCESS_H_
7235
+
7236
+#include <functional>
7237
+
7238
+#include "common/angleutils.h"
7239
+#include "compiler/translator/Compiler.h"
7240
+
7241
+namespace sh
7242
+{
7243
+
7244
+// Maps TIntermSymbol nodes to TIntermNode nodes.
7245
+// The parent function of a symbol is provided to the mapping when applicable.
7246
+ANGLE_NO_DISCARD bool MapSymbols(
7247
+    TCompiler &compiler,
7248
+    TIntermBlock &root,
7249
+    std::function<TIntermNode &(const TFunction *, TIntermSymbol &)> map);
7250
+
7251
+}  // namespace sh
7252
+
7253
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_MAPVARIABLESTOMEMBERACCESS_H_
7254
diff --git a/src/compiler/translator/TranslatorMetalDirect/ModifyStruct.cpp b/src/compiler/translator/TranslatorMetalDirect/ModifyStruct.cpp
7255
new file mode 100644
7256
index 0000000..9778d34
7257
--- /dev/null
7258
+++ b/src/compiler/translator/TranslatorMetalDirect/ModifyStruct.cpp
7259
@@ -0,0 +1,1001 @@
7260
+//
7261
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
7262
+// Use of this source code is governed by a BSD-style license that can be
7263
+// found in the LICENSE file.
7264
+//
7265
+
7266
+#include <algorithm>
7267
+#include <cstring>
7268
+#include <numeric>
7269
+#include <unordered_map>
7270
+#include <unordered_set>
7271
+
7272
+#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
7273
+#include "compiler/translator/TranslatorMetalDirect/ModifyStruct.h"
7274
+
7275
+using namespace sh;
7276
+
7277
+////////////////////////////////////////////////////////////////////////////////
7278
+
7279
+size_t ModifiedStructMachineries::size() const
7280
+{
7281
+    return ordering.size();
7282
+}
7283
+
7284
+const ModifiedStructMachinery &ModifiedStructMachineries::at(size_t index) const
7285
+{
7286
+    ASSERT(index < size());
7287
+    const TStructure *s              = ordering[index];
7288
+    const ModifiedStructMachinery *m = find(*s);
7289
+    ASSERT(m);
7290
+    return *m;
7291
+}
7292
+
7293
+const ModifiedStructMachinery *ModifiedStructMachineries::find(const TStructure &s) const
7294
+{
7295
+    auto iter = originalToMachinery.find(&s);
7296
+    if (iter == originalToMachinery.end())
7297
+    {
7298
+        return nullptr;
7299
+    }
7300
+    return &iter->second;
7301
+}
7302
+
7303
+void ModifiedStructMachineries::insert(const TStructure &s,
7304
+                                       const ModifiedStructMachinery &machinery)
7305
+{
7306
+    ASSERT(!find(s));
7307
+    originalToMachinery[&s] = machinery;
7308
+    ordering.push_back(&s);
7309
+}
7310
+
7311
+////////////////////////////////////////////////////////////////////////////////
7312
+
7313
+namespace
7314
+{
7315
+
7316
+TIntermTyped &Flatten(SymbolEnv &symbolEnv, TIntermTyped &node)
7317
+{
7318
+    auto &type = node.getType();
7319
+    ASSERT(type.isArray());
7320
+
7321
+    auto &retType = InnermostType(type);
7322
+    retType.makeArray(1);
7323
+
7324
+    return symbolEnv.callFunctionOverload(Name("flatten"), retType, *new TIntermSequence{&node});
7325
+}
7326
+
7327
+struct FlattenArray
7328
+{};
7329
+
7330
+struct PathItem
7331
+{
7332
+    enum class Type
7333
+    {
7334
+        Field,         // Struct field indexing.
7335
+        Index,         // Array, vector, or matrix indexing.
7336
+        FlattenArray,  // Array of any rank -> pointer of innermost type.
7337
+    };
7338
+
7339
+    PathItem(const TField &field) : field(&field), type(Type::Field) {}
7340
+    PathItem(int index) : index(index), type(Type::Index) {}
7341
+    PathItem(unsigned index) : PathItem(static_cast<int>(index)) {}
7342
+    PathItem(FlattenArray flatten) : type(Type::FlattenArray) {}
7343
+
7344
+    union
7345
+    {
7346
+        const TField *field;
7347
+        int index;
7348
+    };
7349
+    Type type;
7350
+};
7351
+
7352
+TIntermTyped &BuildPathAccess(SymbolEnv &symbolEnv,
7353
+                              const TVariable &var,
7354
+                              const std::vector<PathItem> &path)
7355
+{
7356
+    TIntermTyped *curr = new TIntermSymbol(&var);
7357
+    for (const PathItem &item : path)
7358
+    {
7359
+        switch (item.type)
7360
+        {
7361
+            case PathItem::Type::Field:
7362
+                curr = &AccessField(*curr, item.field->name());
7363
+                break;
7364
+            case PathItem::Type::Index:
7365
+                curr = &AccessIndex(*curr, item.index);
7366
+                break;
7367
+            case PathItem::Type::FlattenArray:
7368
+            {
7369
+                curr = &Flatten(symbolEnv, *curr);
7370
+            }
7371
+            break;
7372
+        }
7373
+    }
7374
+    return *curr;
7375
+}
7376
+
7377
+////////////////////////////////////////////////////////////////////////////////
7378
+
7379
+using OriginalParam = const TVariable &;
7380
+using ModifiedParam = const TVariable &;
7381
+
7382
+using OriginalAccess = TIntermTyped;
7383
+using ModifiedAccess = TIntermTyped;
7384
+
7385
+struct Access
7386
+{
7387
+    OriginalAccess &original;
7388
+    ModifiedAccess &modified;
7389
+
7390
+    struct Env
7391
+    {
7392
+        const ConvertType type;
7393
+    };
7394
+};
7395
+
7396
+using ConversionFunc = std::function<Access(Access::Env &, OriginalAccess &, ModifiedAccess &)>;
7397
+
7398
+class ConvertStructState : angle::NonCopyable
7399
+{
7400
+  private:
7401
+    struct ConversionInfo
7402
+    {
7403
+        ConversionFunc stdFunc;
7404
+        const TFunction *astFunc;
7405
+        std::vector<PathItem> pathItems;
7406
+        ImmutableString pathName;
7407
+    };
7408
+
7409
+  public:
7410
+    ConvertStructState(SymbolEnv &symbolEnv,
7411
+                       IdGen &idGen,
7412
+                       const ModifyStructConfig &config,
7413
+                       ModifiedStructMachineries &outMachineries)
7414
+        : config(config),
7415
+          symbolEnv(symbolEnv),
7416
+          modifiedFields(*new TFieldList()),
7417
+          symbolTable(symbolEnv.symbolTable()),
7418
+          idGen(idGen),
7419
+          outMachineries(outMachineries)
7420
+    {}
7421
+
7422
+    ~ConvertStructState()
7423
+    {
7424
+        ASSERT(namePath.empty());
7425
+        ASSERT(namePathSizes.empty());
7426
+    }
7427
+
7428
+    void publish(const TStructure &originalStruct, const Name &modifiedStructName)
7429
+    {
7430
+        const bool isOriginalToModified = config.convertType == ConvertType::OriginalToModified;
7431
+
7432
+        auto &modifiedStruct = *new TStructure(&symbolTable, modifiedStructName.rawName(),
7433
+                                               &modifiedFields, modifiedStructName.symbolType());
7434
+
7435
+        auto &func = *new TFunction(
7436
+            &symbolTable,
7437
+            idGen.createNewName(isOriginalToModified ? "originalToModified" : "modifiedToOriginal")
7438
+                .rawName(),
7439
+            SymbolType::AngleInternal, new TType(TBasicType::EbtVoid), false);
7440
+
7441
+        OriginalParam originalParam =
7442
+            CreateInstanceVariable(symbolTable, originalStruct, Name("original"));
7443
+        ModifiedParam modifiedParam =
7444
+            CreateInstanceVariable(symbolTable, modifiedStruct, Name("modified"));
7445
+        symbolEnv.markAsReference(originalParam, AddressSpace::Thread);
7446
+        symbolEnv.markAsReference(modifiedParam, config.externalAddressSpace);
7447
+        if (isOriginalToModified)
7448
+        {
7449
+            func.addParameter(&originalParam);
7450
+            func.addParameter(&modifiedParam);
7451
+        }
7452
+        else
7453
+        {
7454
+            func.addParameter(&modifiedParam);
7455
+            func.addParameter(&originalParam);
7456
+        }
7457
+
7458
+        TIntermBlock &body = *new TIntermBlock();
7459
+
7460
+        Access::Env env{config.convertType};
7461
+
7462
+        for (ConversionInfo &info : conversionInfos)
7463
+        {
7464
+            auto convert = [&](OriginalAccess &original, ModifiedAccess &modified) {
7465
+                if (info.astFunc)
7466
+                {
7467
+                    ASSERT(!info.stdFunc);
7468
+                    TIntermTyped &src  = isOriginalToModified ? modified : original;
7469
+                    TIntermTyped &dest = isOriginalToModified ? original : modified;
7470
+                    body.appendStatement(TIntermAggregate::CreateFunctionCall(
7471
+                        *info.astFunc, new TIntermSequence{&dest, &src}));
7472
+                }
7473
+                else
7474
+                {
7475
+                    ASSERT(info.stdFunc);
7476
+                    Access access      = info.stdFunc(env, original, modified);
7477
+                    TIntermTyped &src  = isOriginalToModified ? access.original : access.modified;
7478
+                    TIntermTyped &dest = isOriginalToModified ? access.modified : access.original;
7479
+                    body.appendStatement(new TIntermBinary(TOperator::EOpAssign, &dest, &src));
7480
+                }
7481
+            };
7482
+
7483
+            OriginalAccess *original = &BuildPathAccess(symbolEnv, originalParam, info.pathItems);
7484
+            ModifiedAccess *modified = &AccessField(modifiedParam, info.pathName);
7485
+
7486
+            const TType ot = original->getType();
7487
+            const TType mt = modified->getType();
7488
+            ASSERT(ot.isArray() == mt.isArray());
7489
+
7490
+            if (ot.isArray() && ot != mt)
7491
+            {
7492
+                ASSERT(ot.getArraySizes() == mt.getArraySizes());
7493
+                if (ot.isArrayOfArrays())
7494
+                {
7495
+                    original = &Flatten(symbolEnv, *original);
7496
+                    modified = &Flatten(symbolEnv, *modified);
7497
+                }
7498
+                const int volume = static_cast<int>(ot.getArraySizeProduct());
7499
+                for (int i = 0; i < volume; ++i)
7500
+                {
7501
+                    if (i != 0)
7502
+                    {
7503
+                        original = original->deepCopy();
7504
+                        modified = modified->deepCopy();
7505
+                    }
7506
+                    OriginalAccess &o = AccessIndex(*original, i);
7507
+                    OriginalAccess &m = AccessIndex(*modified, i);
7508
+                    convert(o, m);
7509
+                }
7510
+            }
7511
+            else
7512
+            {
7513
+                convert(*original, *modified);
7514
+            }
7515
+        }
7516
+
7517
+        auto *funcProto = new TIntermFunctionPrototype(&func);
7518
+        auto *funcDef   = new TIntermFunctionDefinition(funcProto, &body);
7519
+
7520
+        ModifiedStructMachinery machinery;
7521
+        machinery.modifiedStruct                   = &modifiedStruct;
7522
+        machinery.getConverter(config.convertType) = funcDef;
7523
+
7524
+        outMachineries.insert(originalStruct, machinery);
7525
+    }
7526
+
7527
+    void pushPath(PathItem const &item)
7528
+    {
7529
+        pathItems.push_back(item);
7530
+
7531
+        switch (item.type)
7532
+        {
7533
+            case PathItem::Type::Field:
7534
+                pushNamePath(item.field->name().data());
7535
+                break;
7536
+
7537
+            case PathItem::Type::Index:
7538
+                pushNamePath(item.index);
7539
+                break;
7540
+
7541
+            case PathItem::Type::FlattenArray:
7542
+                namePathSizes.push_back(namePath.size());
7543
+                break;
7544
+        }
7545
+    }
7546
+
7547
+    void popPath()
7548
+    {
7549
+        ASSERT(!namePath.empty());
7550
+        ASSERT(!namePathSizes.empty());
7551
+        namePath.resize(namePathSizes.back());
7552
+        namePathSizes.pop_back();
7553
+
7554
+        ASSERT(!pathItems.empty());
7555
+        pathItems.pop_back();
7556
+    }
7557
+
7558
+    void finalize()
7559
+    {
7560
+        ASSERT(!finalized);
7561
+        finalized = true;
7562
+        introducePacking();
7563
+        ASSERT(metalLayoutTotal == Layout::Identity());
7564
+        introducePadding();
7565
+    }
7566
+
7567
+    void addModifiedField(const TField &field,
7568
+                          TType &newType,
7569
+                          TLayoutBlockStorage storage,
7570
+                          TLayoutMatrixPacking packing)
7571
+    {
7572
+        TLayoutQualifier layoutQualifier = newType.getLayoutQualifier();
7573
+        layoutQualifier.blockStorage     = storage;
7574
+        layoutQualifier.matrixPacking    = packing;
7575
+        newType.setLayoutQualifier(layoutQualifier);
7576
+
7577
+        const ImmutableString pathName(namePath);
7578
+        modifiedFields.push_back(new TField(&newType, pathName, field.line(), field.symbolType()));
7579
+    }
7580
+
7581
+    void addConversion(const ConversionFunc &func)
7582
+    {
7583
+        ASSERT(!modifiedFields.empty());
7584
+        conversionInfos.push_back({func, nullptr, pathItems, modifiedFields.back()->name()});
7585
+    }
7586
+
7587
+    void addConversion(const TFunction &func)
7588
+    {
7589
+        ASSERT(!modifiedFields.empty());
7590
+        conversionInfos.push_back({{}, &func, pathItems, modifiedFields.back()->name()});
7591
+    }
7592
+
7593
+    bool hasPacking() const { return containsPacked; }
7594
+
7595
+    bool hasPadding() const { return padFieldCount > 0; }
7596
+
7597
+    bool recurse(const TStructure &structure, ModifiedStructMachinery &outMachinery)
7598
+    {
7599
+        const ModifiedStructMachinery *m = outMachineries.find(structure);
7600
+        if (m == nullptr)
7601
+        {
7602
+            const Name name = idGen.createNewName(structure.name().data());
7603
+            if (!TryCreateModifiedStruct(symbolEnv, idGen, config, structure, name, outMachineries))
7604
+            {
7605
+                return false;
7606
+            }
7607
+            m = outMachineries.find(structure);
7608
+            ASSERT(m);
7609
+        }
7610
+        outMachinery = *m;
7611
+        return true;
7612
+    }
7613
+
7614
+  private:
7615
+    void addPadding(size_t padAmount, bool updateLayout)
7616
+    {
7617
+        if (padAmount == 0)
7618
+        {
7619
+            return;
7620
+        }
7621
+
7622
+        const size_t begin = modifiedFields.size();
7623
+
7624
+        // Iteratively adding in scalar or vector padding because some struct types will not
7625
+        // allow matrix or array members.
7626
+        while (padAmount > 0)
7627
+        {
7628
+            TType *padType;
7629
+            if (padAmount >= 16)
7630
+            {
7631
+                padAmount -= 16;
7632
+                padType = new TType(TBasicType::EbtFloat, 4);
7633
+            }
7634
+            else if (padAmount >= 8)
7635
+            {
7636
+                padAmount -= 8;
7637
+                padType = new TType(TBasicType::EbtFloat, 2);
7638
+            }
7639
+            else if (padAmount >= 4)
7640
+            {
7641
+                padAmount -= 4;
7642
+                padType = new TType(TBasicType::EbtFloat);
7643
+            }
7644
+            else if (padAmount >= 2)
7645
+            {
7646
+                padAmount -= 2;
7647
+                padType = new TType(TBasicType::EbtBool, 2);
7648
+            }
7649
+            else
7650
+            {
7651
+                ASSERT(padAmount == 1);
7652
+                padAmount -= 1;
7653
+                padType = new TType(TBasicType::EbtBool);
7654
+            }
7655
+
7656
+            if (updateLayout)
7657
+            {
7658
+                metalLayoutTotal += MetalLayoutOf(*padType);
7659
+            }
7660
+
7661
+            const Name name = idGen.createNewName("pad");
7662
+            modifiedFields.push_back(
7663
+                new TField(padType, name.rawName(), kNoSourceLoc, name.symbolType()));
7664
+            ++padFieldCount;
7665
+        }
7666
+
7667
+        std::reverse(modifiedFields.begin() + begin, modifiedFields.end());
7668
+    }
7669
+
7670
+    void introducePacking()
7671
+    {
7672
+        if (!config.allowPacking)
7673
+        {
7674
+            return;
7675
+        }
7676
+
7677
+        auto setUnpackedStorage = [](TType &type) {
7678
+            TLayoutBlockStorage storage = type.getLayoutQualifier().blockStorage;
7679
+            switch (storage)
7680
+            {
7681
+                case TLayoutBlockStorage::EbsShared:
7682
+                    storage = TLayoutBlockStorage::EbsStd140;
7683
+                    break;
7684
+                case TLayoutBlockStorage::EbsPacked:
7685
+                    storage = TLayoutBlockStorage::EbsStd430;
7686
+                    break;
7687
+                case TLayoutBlockStorage::EbsStd140:
7688
+                case TLayoutBlockStorage::EbsStd430:
7689
+                case TLayoutBlockStorage::EbsUnspecified:
7690
+                    break;
7691
+            }
7692
+            SetBlockStorage(type, storage);
7693
+        };
7694
+
7695
+        Layout glslLayoutTotal = Layout::Identity();
7696
+        const size_t size      = modifiedFields.size();
7697
+
7698
+        for (size_t i = 0; i < size; ++i)
7699
+        {
7700
+            TField &curr           = *modifiedFields[i];
7701
+            TType &currType        = *curr.type();
7702
+            const bool canBePacked = CanBePacked(currType);
7703
+
7704
+            auto dontPack = [&]() {
7705
+                if (canBePacked)
7706
+                {
7707
+                    setUnpackedStorage(currType);
7708
+                }
7709
+                glslLayoutTotal += GlslLayoutOf(currType);
7710
+            };
7711
+
7712
+            if (!CanBePacked(currType))
7713
+            {
7714
+                dontPack();
7715
+                continue;
7716
+            }
7717
+
7718
+            const Layout packedGlslLayout           = GlslLayoutOf(currType);
7719
+            const TLayoutBlockStorage packedStorage = currType.getLayoutQualifier().blockStorage;
7720
+            setUnpackedStorage(currType);
7721
+            const Layout unpackedGlslLayout = GlslLayoutOf(currType);
7722
+            SetBlockStorage(currType, packedStorage);
7723
+
7724
+            ASSERT(packedGlslLayout.sizeOf <= unpackedGlslLayout.sizeOf);
7725
+            if (packedGlslLayout.sizeOf == unpackedGlslLayout.sizeOf)
7726
+            {
7727
+                dontPack();
7728
+                continue;
7729
+            }
7730
+
7731
+            const size_t j = i + 1;
7732
+            if (j == size)
7733
+            {
7734
+                dontPack();
7735
+                break;
7736
+            }
7737
+
7738
+            const size_t pad            = unpackedGlslLayout.sizeOf - packedGlslLayout.sizeOf;
7739
+            const TField &next          = *modifiedFields[j];
7740
+            const Layout nextGlslLayout = GlslLayoutOf(*next.type());
7741
+
7742
+            if (pad < nextGlslLayout.sizeOf)
7743
+            {
7744
+                dontPack();
7745
+                continue;
7746
+            }
7747
+
7748
+            symbolEnv.markAsPacked(curr);
7749
+            glslLayoutTotal += packedGlslLayout;
7750
+            containsPacked = true;
7751
+        }
7752
+    }
7753
+
7754
+    void introducePadding()
7755
+    {
7756
+        if (!config.allowPadding)
7757
+        {
7758
+            return;
7759
+        }
7760
+
7761
+        MetalLayoutOfConfig layoutConfig;
7762
+        layoutConfig.disablePacking             = !config.allowPacking;
7763
+        layoutConfig.assumeStructsAreTailPadded = true;
7764
+
7765
+        TFieldList fields = std::move(modifiedFields);
7766
+        ASSERT(!fields.empty());  // GLSL requires at least one member.
7767
+
7768
+        const TField *const first = fields.front();
7769
+
7770
+        for (TField *field : fields)
7771
+        {
7772
+            const TType &type = *field->type();
7773
+
7774
+            const Layout glslLayout  = GlslLayoutOf(type);
7775
+            const Layout metalLayout = MetalLayoutOf(type, layoutConfig);
7776
+
7777
+            size_t prePadAmount = 0;
7778
+            if (glslLayout.alignOf > metalLayout.alignOf && field != first)
7779
+            {
7780
+                const size_t prePaddedSize = metalLayoutTotal.sizeOf;
7781
+                metalLayoutTotal.requireAlignment(glslLayout.alignOf, true);
7782
+                const size_t paddedSize = metalLayoutTotal.sizeOf;
7783
+                prePadAmount            = paddedSize - prePaddedSize;
7784
+                metalLayoutTotal += metalLayout;
7785
+                addPadding(prePadAmount, false);  // Note: requireAlignment() already updated layout
7786
+            }
7787
+            else
7788
+            {
7789
+                metalLayoutTotal += metalLayout;
7790
+            }
7791
+
7792
+            modifiedFields.push_back(field);
7793
+
7794
+            if (glslLayout.sizeOf > metalLayout.sizeOf && field != fields.back())
7795
+            {
7796
+                const bool updateLayout = true;  // XXX: Correct?
7797
+                const size_t padAmount  = glslLayout.sizeOf - metalLayout.sizeOf;
7798
+                addPadding(padAmount, updateLayout);
7799
+            }
7800
+        }
7801
+    }
7802
+
7803
+    void pushNamePath(const char *extra)
7804
+    {
7805
+        ASSERT(extra && *extra != '\0');
7806
+        namePathSizes.push_back(namePath.size());
7807
+        const char *p = extra;
7808
+        if (namePath.empty())
7809
+        {
7810
+            namePath = p;
7811
+            return;
7812
+        }
7813
+        while (*p == '_')
7814
+        {
7815
+            ++p;
7816
+        }
7817
+        if (*p == '\0')
7818
+        {
7819
+            p = "x";
7820
+        }
7821
+        if (namePath.back() != '_')
7822
+        {
7823
+            namePath += '_';
7824
+        }
7825
+        namePath += p;
7826
+    }
7827
+
7828
+    void pushNamePath(unsigned extra)
7829
+    {
7830
+        char buffer[std::numeric_limits<unsigned>::digits10 + 1];
7831
+        sprintf(buffer, "%u", extra);
7832
+        pushNamePath(buffer);
7833
+    }
7834
+
7835
+  public:
7836
+    const ModifyStructConfig &config;
7837
+    SymbolEnv &symbolEnv;
7838
+
7839
+  private:
7840
+    TFieldList &modifiedFields;
7841
+    Layout metalLayoutTotal = Layout::Identity();
7842
+    size_t padFieldCount    = 0;
7843
+    bool containsPacked     = false;
7844
+    bool finalized          = false;
7845
+
7846
+    std::vector<PathItem> pathItems;
7847
+
7848
+    std::vector<size_t> namePathSizes;
7849
+    std::string namePath;
7850
+
7851
+    std::vector<ConversionInfo> conversionInfos;
7852
+    TSymbolTable &symbolTable;
7853
+    IdGen &idGen;
7854
+    ModifiedStructMachineries &outMachineries;
7855
+};
7856
+
7857
+////////////////////////////////////////////////////////////////////////////////
7858
+
7859
+using ModifyFunc = bool (*)(ConvertStructState &state,
7860
+                            const TField &field,
7861
+                            const TLayoutBlockStorage storage,
7862
+                            const TLayoutMatrixPacking packing);
7863
+
7864
+bool ModifyRecursive(ConvertStructState &state,
7865
+                     const TField &field,
7866
+                     const TLayoutBlockStorage storage,
7867
+                     const TLayoutMatrixPacking packing);
7868
+
7869
+bool IdentityModify(ConvertStructState &state,
7870
+                    const TField &field,
7871
+                    const TLayoutBlockStorage storage,
7872
+                    const TLayoutMatrixPacking packing)
7873
+{
7874
+    const TType &type = *field.type();
7875
+    state.addModifiedField(field, CloneType(type), storage, packing);
7876
+    state.addConversion([=](Access::Env &, OriginalAccess &o, ModifiedAccess &m) {
7877
+        return Access{o, m};
7878
+    });
7879
+    return false;
7880
+}
7881
+
7882
+bool InlineStruct(ConvertStructState &state,
7883
+                  const TField &field,
7884
+                  const TLayoutBlockStorage storage,
7885
+                  const TLayoutMatrixPacking packing)
7886
+{
7887
+    const TType &type              = *field.type();
7888
+    const TStructure *substructure = state.symbolEnv.remap(type.getStruct());
7889
+    if (!substructure)
7890
+    {
7891
+        return false;
7892
+    }
7893
+    if (type.isArray())
7894
+    {
7895
+        return false;
7896
+    }
7897
+    if (!state.config.inlineStruct(field))
7898
+    {
7899
+        return false;
7900
+    }
7901
+
7902
+    const TFieldList &subfields = substructure->fields();
7903
+    for (const TField *subfield : subfields)
7904
+    {
7905
+        const TType &subtype                  = *subfield->type();
7906
+        const TLayoutBlockStorage substorage  = Overlay(storage, subtype);
7907
+        const TLayoutMatrixPacking subpacking = Overlay(packing, subtype);
7908
+        ModifyRecursive(state, *subfield, substorage, subpacking);
7909
+    }
7910
+
7911
+    return true;
7912
+}
7913
+
7914
+bool RecurseStruct(ConvertStructState &state,
7915
+                   const TField &field,
7916
+                   const TLayoutBlockStorage storage,
7917
+                   const TLayoutMatrixPacking packing)
7918
+{
7919
+    const TType &type              = *field.type();
7920
+    const TStructure *substructure = state.symbolEnv.remap(type.getStruct());
7921
+    if (!substructure)
7922
+    {
7923
+        return false;
7924
+    }
7925
+    if (!state.config.recurseStruct(field))
7926
+    {
7927
+        return false;
7928
+    }
7929
+
7930
+    ModifiedStructMachinery machinery;
7931
+    if (!state.recurse(*substructure, machinery))
7932
+    {
7933
+        return false;
7934
+    }
7935
+
7936
+    TType &newType = *new TType(machinery.modifiedStruct, false);
7937
+    if (type.isArray())
7938
+    {
7939
+        newType.makeArrays(type.getArraySizes());
7940
+    }
7941
+
7942
+    TIntermFunctionDefinition *converter = machinery.getConverter(state.config.convertType);
7943
+    ASSERT(converter);
7944
+
7945
+    state.addModifiedField(field, newType, storage, packing);
7946
+    state.addConversion(*converter->getFunction());
7947
+
7948
+    return true;
7949
+}
7950
+
7951
+bool SplitMatrixColumns(ConvertStructState &state,
7952
+                        const TField &field,
7953
+                        const TLayoutBlockStorage storage,
7954
+                        const TLayoutMatrixPacking packing)
7955
+{
7956
+    const TType &type = *field.type();
7957
+    if (!type.isMatrix())
7958
+    {
7959
+        return false;
7960
+    }
7961
+    if (!state.config.splitMatrixColumns(field))
7962
+    {
7963
+        return false;
7964
+    }
7965
+
7966
+    const int cols = type.getCols();
7967
+    TType &rowType = DropColumns(type);
7968
+
7969
+    for (int c = 0; c < cols; ++c)
7970
+    {
7971
+        state.pushPath(c);
7972
+
7973
+        state.addModifiedField(field, rowType, storage, packing);
7974
+        state.addConversion([=](Access::Env &, OriginalAccess &o, ModifiedAccess &m) {
7975
+            return Access{o, m};
7976
+        });
7977
+
7978
+        state.popPath();
7979
+    }
7980
+
7981
+    return true;
7982
+}
7983
+
7984
+bool SaturateMatrixRows(ConvertStructState &state,
7985
+                        const TField &field,
7986
+                        const TLayoutBlockStorage storage,
7987
+                        const TLayoutMatrixPacking packing)
7988
+{
7989
+    const TType &type = *field.type();
7990
+    if (!type.isMatrix())
7991
+    {
7992
+        return false;
7993
+    }
7994
+    const int rows       = type.getRows();
7995
+    const int saturation = state.config.saturateMatrixRows(field);
7996
+    if (saturation <= rows)
7997
+    {
7998
+        return false;
7999
+    }
8000
+
8001
+    const int cols = type.getCols();
8002
+    TType &satType = SetMatrixRowDim(type, saturation);
8003
+    state.addModifiedField(field, satType, storage, packing);
8004
+
8005
+    for (int c = 0; c < cols; ++c)
8006
+    {
8007
+        for (int r = 0; r < rows; ++r)
8008
+        {
8009
+            state.addConversion([=](Access::Env &, OriginalAccess &o, ModifiedAccess &m) {
8010
+                auto &o_ = AccessIndex(AccessIndex(o, c), r);
8011
+                auto &m_ = AccessIndex(AccessIndex(m, c), r);
8012
+                return Access{o_, m_};
8013
+            });
8014
+        }
8015
+    }
8016
+
8017
+    return true;
8018
+}
8019
+
8020
+bool TestBoolToUint(ConvertStructState &state, const TField &field)
8021
+{
8022
+    if (field.type()->getBasicType() != TBasicType::EbtBool)
8023
+    {
8024
+        return false;
8025
+    }
8026
+    if (!state.config.promoteBoolToUint(field))
8027
+    {
8028
+        return false;
8029
+    }
8030
+    return true;
8031
+}
8032
+
8033
+Access ConvertBoolToUint(ConvertType convertType, OriginalAccess &o, ModifiedAccess &m)
8034
+{
8035
+    auto coerce = [](TIntermTyped &to, TIntermTyped &from) -> TIntermTyped & {
8036
+        return *TIntermAggregate::CreateConstructor(to.getType(), new TIntermSequence{&from});
8037
+    };
8038
+    switch (convertType)
8039
+    {
8040
+        case ConvertType::OriginalToModified:
8041
+            return Access{coerce(m, o), m};
8042
+        case ConvertType::ModifiedToOriginal:
8043
+            return Access{o, coerce(o, m)};
8044
+    }
8045
+}
8046
+
8047
+bool SaturateScalarOrVectorCommon(ConvertStructState &state,
8048
+                                  const TField &field,
8049
+                                  const TLayoutBlockStorage storage,
8050
+                                  const TLayoutMatrixPacking packing,
8051
+                                  const bool array)
8052
+{
8053
+    const TType &type = *field.type();
8054
+    if (type.isArray() != array)
8055
+    {
8056
+        return false;
8057
+    }
8058
+    if (!((type.isRank0() && HasScalarBasicType(type)) || type.isVector()))
8059
+    {
8060
+        return false;
8061
+    }
8062
+    const auto saturator =
8063
+        array ? state.config.saturateScalarOrVectorArrays : state.config.saturateScalarOrVector;
8064
+    const int dim        = type.getNominalSize();
8065
+    const int saturation = saturator(field);
8066
+    if (saturation <= dim)
8067
+    {
8068
+        return false;
8069
+    }
8070
+
8071
+    TType &satType        = SetVectorDim(type, saturation);
8072
+    const bool boolToUint = TestBoolToUint(state, field);
8073
+    if (boolToUint)
8074
+    {
8075
+        satType.setBasicType(TBasicType::EbtUInt);
8076
+    }
8077
+    state.addModifiedField(field, satType, storage, packing);
8078
+
8079
+    for (int d = 0; d < dim; ++d)
8080
+    {
8081
+        state.addConversion([=](Access::Env &env, OriginalAccess &o, ModifiedAccess &m) {
8082
+            auto &o_ = dim > 1 ? AccessIndex(o, d) : o;
8083
+            auto &m_ = AccessIndex(m, d);
8084
+            if (boolToUint)
8085
+            {
8086
+                return ConvertBoolToUint(env.type, o_, m_);
8087
+            }
8088
+            else
8089
+            {
8090
+                return Access{o_, m_};
8091
+            }
8092
+        });
8093
+    }
8094
+
8095
+    return true;
8096
+}
8097
+
8098
+bool SaturateScalarOrVectorArrays(ConvertStructState &state,
8099
+                                  const TField &field,
8100
+                                  const TLayoutBlockStorage storage,
8101
+                                  const TLayoutMatrixPacking packing)
8102
+{
8103
+    return SaturateScalarOrVectorCommon(state, field, storage, packing, true);
8104
+}
8105
+
8106
+bool SaturateScalarOrVector(ConvertStructState &state,
8107
+                            const TField &field,
8108
+                            const TLayoutBlockStorage storage,
8109
+                            const TLayoutMatrixPacking packing)
8110
+{
8111
+    return SaturateScalarOrVectorCommon(state, field, storage, packing, false);
8112
+}
8113
+
8114
+bool PromoteBoolToUint(ConvertStructState &state,
8115
+                       const TField &field,
8116
+                       const TLayoutBlockStorage storage,
8117
+                       const TLayoutMatrixPacking packing)
8118
+{
8119
+    if (!TestBoolToUint(state, field))
8120
+    {
8121
+        return false;
8122
+    }
8123
+
8124
+    auto &promotedType = CloneType(*field.type());
8125
+    promotedType.setBasicType(TBasicType::EbtUInt);
8126
+    state.addModifiedField(field, promotedType, storage, packing);
8127
+
8128
+    state.addConversion([=](Access::Env &env, OriginalAccess &o, ModifiedAccess &m) {
8129
+        return ConvertBoolToUint(env.type, o, m);
8130
+    });
8131
+
8132
+    return true;
8133
+}
8134
+
8135
+bool ModifyCommon(ConvertStructState &state,
8136
+                  const TField &field,
8137
+                  const TLayoutBlockStorage storage,
8138
+                  const TLayoutMatrixPacking packing)
8139
+{
8140
+    ModifyFunc funcs[] = {
8141
+        InlineStruct,                  //
8142
+        RecurseStruct,                 //
8143
+        SplitMatrixColumns,            //
8144
+        SaturateMatrixRows,            //
8145
+        SaturateScalarOrVectorArrays,  //
8146
+        SaturateScalarOrVector,        //
8147
+        PromoteBoolToUint,             //
8148
+    };
8149
+
8150
+    for (ModifyFunc func : funcs)
8151
+    {
8152
+        if (func(state, field, storage, packing))
8153
+        {
8154
+            return true;
8155
+        }
8156
+    }
8157
+
8158
+    return IdentityModify(state, field, storage, packing);
8159
+}
8160
+
8161
+bool InlineArray(ConvertStructState &state,
8162
+                 const TField &field,
8163
+                 const TLayoutBlockStorage storage,
8164
+                 const TLayoutMatrixPacking packing)
8165
+{
8166
+    const TType &type = *field.type();
8167
+    if (!type.isArray())
8168
+    {
8169
+        return false;
8170
+    }
8171
+    if (!state.config.inlineArray(field))
8172
+    {
8173
+        return false;
8174
+    }
8175
+
8176
+    const unsigned volume = type.getArraySizeProduct();
8177
+    const bool isMultiDim = type.isArrayOfArrays();
8178
+
8179
+    auto &innermostType = InnermostType(type);
8180
+    const TField innermostField(&innermostType, field.name(), field.line(), field.symbolType());
8181
+
8182
+    if (isMultiDim)
8183
+    {
8184
+        state.pushPath(FlattenArray());
8185
+    }
8186
+
8187
+    for (unsigned i = 0; i < volume; ++i)
8188
+    {
8189
+        state.pushPath(i);
8190
+        ModifyCommon(state, innermostField, storage, packing);
8191
+        state.popPath();
8192
+    }
8193
+
8194
+    if (isMultiDim)
8195
+    {
8196
+        state.popPath();
8197
+    }
8198
+
8199
+    return true;
8200
+}
8201
+
8202
+bool ModifyRecursive(ConvertStructState &state,
8203
+                     const TField &field,
8204
+                     const TLayoutBlockStorage storage,
8205
+                     const TLayoutMatrixPacking packing)
8206
+{
8207
+    state.pushPath(field);
8208
+
8209
+    bool modified;
8210
+    if (InlineArray(state, field, storage, packing))
8211
+    {
8212
+        modified = true;
8213
+    }
8214
+    else
8215
+    {
8216
+        modified = ModifyCommon(state, field, storage, packing);
8217
+    }
8218
+
8219
+    state.popPath();
8220
+
8221
+    return modified;
8222
+}
8223
+
8224
+}  // anonymous namespace
8225
+
8226
+////////////////////////////////////////////////////////////////////////////////
8227
+
8228
+bool sh::TryCreateModifiedStruct(SymbolEnv &symbolEnv,
8229
+                                 IdGen &idGen,
8230
+                                 const ModifyStructConfig &config,
8231
+                                 const TStructure &originalStruct,
8232
+                                 const Name &modifiedStructName,
8233
+                                 ModifiedStructMachineries &outMachineries)
8234
+{
8235
+    ConvertStructState state(symbolEnv, idGen, config, outMachineries);
8236
+    size_t identicalFieldCount = 0;
8237
+
8238
+    const TFieldList &originalFields = originalStruct.fields();
8239
+    for (TField *originalField : originalFields)
8240
+    {
8241
+        const TType &originalType          = *originalField->type();
8242
+        const TLayoutBlockStorage storage  = Overlay(config.initialBlockStorage, originalType);
8243
+        const TLayoutMatrixPacking packing = Overlay(config.initialMatrixPacking, originalType);
8244
+        if (!ModifyRecursive(state, *originalField, storage, packing))
8245
+        {
8246
+            ++identicalFieldCount;
8247
+        }
8248
+    }
8249
+
8250
+    state.finalize();
8251
+
8252
+    if (identicalFieldCount == originalFields.size() && !state.hasPacking() && !state.hasPadding())
8253
+    {
8254
+        return false;
8255
+    }
8256
+
8257
+    state.publish(originalStruct, modifiedStructName);
8258
+
8259
+    return true;
8260
+}
8261
diff --git a/src/compiler/translator/TranslatorMetalDirect/ModifyStruct.h b/src/compiler/translator/TranslatorMetalDirect/ModifyStruct.h
8262
new file mode 100644
8263
index 0000000..4b8cfc5
8264
--- /dev/null
8265
+++ b/src/compiler/translator/TranslatorMetalDirect/ModifyStruct.h
8266
@@ -0,0 +1,135 @@
8267
+//
8268
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
8269
+// Use of this source code is governed by a BSD-style license that can be
8270
+// found in the LICENSE file.
8271
+//
8272
+
8273
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_MODIFYSTRUCT_H_
8274
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_MODIFYSTRUCT_H_
8275
+
8276
+#include <cstring>
8277
+#include <unordered_map>
8278
+#include <unordered_set>
8279
+
8280
+#include "compiler/translator/TranslatorMetalDirect/IdGen.h"
8281
+#include "compiler/translator/TranslatorMetalDirect/Layout.h"
8282
+#include "compiler/translator/TranslatorMetalDirect/Name.h"
8283
+#include "compiler/translator/TranslatorMetalDirect/ProgramPrelude.h"
8284
+#include "compiler/translator/TranslatorMetalDirect/SymbolEnv.h"
8285
+
8286
+namespace sh
8287
+{
8288
+
8289
+enum class ConvertType
8290
+{
8291
+    OriginalToModified,
8292
+    ModifiedToOriginal,
8293
+};
8294
+
8295
+// Configures how struct modification is performed.
8296
+class ModifyStructConfig
8297
+{
8298
+  public:
8299
+    struct Predicate
8300
+    {
8301
+        using Func = bool (*)(const TField &);
8302
+        static bool False(const TField &) { return false; }
8303
+        static bool True(const TField &) { return true; }
8304
+    };
8305
+
8306
+    struct SaturateVector
8307
+    {
8308
+        // Valid return values are [0, 1, 2, 3, 4].
8309
+        // If original dim >= return value, the field remains untouched.
8310
+        using Func = int (*)(const TField &);
8311
+        static int DontSaturate(const TField &) { return 0; }
8312
+        static int FullySaturate(const TField &) { return 4; }
8313
+    };
8314
+
8315
+  public:
8316
+    ModifyStructConfig(ConvertType convertType, bool allowPacking, bool allowPadding)
8317
+        : convertType(convertType), allowPacking(allowPacking), allowPadding(allowPadding)
8318
+    {}
8319
+
8320
+    // Matrix field is split into multiple fields of row vectors.
8321
+    Predicate::Func splitMatrixColumns = Predicate::False;
8322
+
8323
+    // Array fields are split into multiple fields of element type.
8324
+    Predicate::Func inlineArray = Predicate::False;
8325
+
8326
+    // Struct fields have their subfields inlined directly.
8327
+    Predicate::Func inlineStruct = Predicate::False;
8328
+
8329
+    // Struct fields are modified.
8330
+    Predicate::Func recurseStruct = Predicate::False;
8331
+
8332
+    // Vector and scalar bool fields are promoted to uint fields.
8333
+    Predicate::Func promoteBoolToUint = Predicate::False;
8334
+
8335
+    // Creates a new structure where scalar or vector fields are saturated vectors.
8336
+    // e.g. `float -> float4`.
8337
+    // e.g. `float2 -> float4`.
8338
+    SaturateVector::Func saturateScalarOrVector = SaturateVector::DontSaturate;
8339
+
8340
+    // Creates a new structure where scalar or vector array fields are saturated.
8341
+    // e.g. `float[10] -> float4[10]`
8342
+    // e.g. `float2[10] -> float4[10]`
8343
+    SaturateVector::Func saturateScalarOrVectorArrays = SaturateVector::DontSaturate;
8344
+
8345
+    // Creates a new structure where matrix fields are row-saturated.
8346
+    // e.g. `float2x2 -> float2x4`.
8347
+    SaturateVector::Func saturateMatrixRows = SaturateVector::DontSaturate;
8348
+
8349
+    TLayoutBlockStorage initialBlockStorage   = kDefaultLayoutBlockStorage;
8350
+    TLayoutMatrixPacking initialMatrixPacking = kDefaultLayoutMatrixPacking;
8351
+    ConvertType convertType;
8352
+    bool allowPacking;
8353
+    bool allowPadding;
8354
+    AddressSpace externalAddressSpace;
8355
+};
8356
+
8357
+struct ModifiedStructMachinery
8358
+{
8359
+    const TStructure *modifiedStruct                  = nullptr;
8360
+    TIntermFunctionDefinition *funcOriginalToModified = nullptr;
8361
+    TIntermFunctionDefinition *funcModifiedToOriginal = nullptr;
8362
+
8363
+    TIntermFunctionDefinition *&getConverter(ConvertType convertType)
8364
+    {
8365
+        if (convertType == ConvertType::OriginalToModified)
8366
+        {
8367
+            return funcOriginalToModified;
8368
+        }
8369
+        else
8370
+        {
8371
+            return funcModifiedToOriginal;
8372
+        }
8373
+    }
8374
+};
8375
+
8376
+// Indexed by topological order.
8377
+class ModifiedStructMachineries
8378
+{
8379
+  public:
8380
+    size_t size() const;
8381
+    const ModifiedStructMachinery &at(size_t index) const;
8382
+    const ModifiedStructMachinery *find(const TStructure &s) const;
8383
+    void insert(const TStructure &s, const ModifiedStructMachinery &machinery);
8384
+
8385
+  private:
8386
+    std::unordered_map<const TStructure *, ModifiedStructMachinery> originalToMachinery;
8387
+    std::vector<const TStructure *> ordering;
8388
+};
8389
+
8390
+// Returns true and `outMachinery` populated if modifications were performed.
8391
+// Returns false otherwise.
8392
+bool TryCreateModifiedStruct(SymbolEnv &symbolEnv,
8393
+                             IdGen &idGen,
8394
+                             const ModifyStructConfig &config,
8395
+                             const TStructure &originalStruct,
8396
+                             const Name &modifiedStructName,
8397
+                             ModifiedStructMachineries &outMachineries);
8398
+
8399
+}  // namespace sh
8400
+
8401
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_MODIFYSTRUCT_H_
8402
diff --git a/src/compiler/translator/TranslatorMetalDirect/Name.cpp b/src/compiler/translator/TranslatorMetalDirect/Name.cpp
8403
new file mode 100644
8404
index 0000000..07c5d18
8405
--- /dev/null
8406
+++ b/src/compiler/translator/TranslatorMetalDirect/Name.cpp
8407
@@ -0,0 +1,220 @@
8408
+//
8409
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
8410
+// Use of this source code is governed by a BSD-style license that can be
8411
+// found in the LICENSE file.
8412
+//
8413
+
8414
+#include "compiler/translator/TranslatorMetalDirect/Name.h"
8415
+#include "common/debug.h"
8416
+#include "compiler/translator/TranslatorMetalDirect/Debug.h"
8417
+#include "compiler/translator/tree_util/IntermTraverse.h"
8418
+
8419
+using namespace sh;
8420
+
8421
+////////////////////////////////////////////////////////////////////////////////
8422
+
8423
+template <typename T>
8424
+static ImmutableString GetName(T const &object)
8425
+{
8426
+    if (object.symbolType() == SymbolType::Empty)
8427
+    {
8428
+        return kEmptyImmutableString;
8429
+    }
8430
+    return object.name();
8431
+}
8432
+
8433
+Name::Name(const TField &field) : Name(GetName(field), field.symbolType()) {}
8434
+
8435
+Name::Name(const TSymbol &symbol) : Name(GetName(symbol), symbol.symbolType()) {}
8436
+
8437
+bool Name::operator==(const Name &other) const
8438
+{
8439
+    return mRawName == other.mRawName && mSymbolType == other.mSymbolType;
8440
+}
8441
+
8442
+bool Name::operator!=(const Name &other) const
8443
+{
8444
+    return !(*this == other);
8445
+}
8446
+
8447
+bool Name::operator<(const Name &other) const
8448
+{
8449
+    if (mRawName < other.mRawName)
8450
+    {
8451
+        return true;
8452
+    }
8453
+    if (other.mRawName < mRawName)
8454
+    {
8455
+        return false;
8456
+    }
8457
+    return mSymbolType < other.mSymbolType;
8458
+}
8459
+
8460
+bool Name::empty() const
8461
+{
8462
+    return mSymbolType == SymbolType::Empty;
8463
+}
8464
+
8465
+bool Name::beginsWith(const Name &prefix) const
8466
+{
8467
+    if (mSymbolType != prefix.mSymbolType)
8468
+    {
8469
+        return false;
8470
+    }
8471
+    return mRawName.beginsWith(prefix.mRawName);
8472
+}
8473
+
8474
+void Name::emit(TInfoSinkBase &out) const
8475
+{
8476
+    switch (mSymbolType)
8477
+    {
8478
+        case SymbolType::BuiltIn:
8479
+        case SymbolType::UserDefined:
8480
+            ASSERT(!mRawName.empty());
8481
+            out << mRawName;
8482
+            break;
8483
+
8484
+        case SymbolType::AngleInternal:
8485
+            ASSERT(!mRawName.empty());
8486
+            if (mRawName.beginsWith(kAngleInternalPrefix))
8487
+            {
8488
+                out << mRawName;
8489
+            }
8490
+            else if (mRawName[0] != '_')
8491
+            {
8492
+                out << kAngleInternalPrefix << '_' << mRawName;
8493
+            }
8494
+            else
8495
+            {
8496
+                out << kAngleInternalPrefix << mRawName;
8497
+            }
8498
+            break;
8499
+
8500
+        case SymbolType::Empty:
8501
+            LOGIC_ERROR();
8502
+            break;
8503
+    }
8504
+}
8505
+
8506
+////////////////////////////////////////////////////////////////////////////////
8507
+
8508
+namespace
8509
+{
8510
+
8511
+// NOTE: This matches more things than FindSymbolNode.
8512
+class ExpressionContainsNameVisitor : public TIntermTraverser
8513
+{
8514
+    Name mName;
8515
+    bool mFoundName = false;
8516
+
8517
+  public:
8518
+    ExpressionContainsNameVisitor(const Name &name)
8519
+        : TIntermTraverser(true, false, false), mName(name)
8520
+    {}
8521
+
8522
+    bool foundName() const { return mFoundName; }
8523
+
8524
+    void visitSymbol(TIntermSymbol *node) override
8525
+    {
8526
+        if (Name(node->variable()) == mName)
8527
+        {
8528
+            mFoundName = true;
8529
+        }
8530
+    }
8531
+
8532
+    bool visitSwizzle(Visit, TIntermSwizzle *) override { return !mFoundName; }
8533
+
8534
+    bool visitBinary(Visit visit, TIntermBinary *node) override { return !mFoundName; }
8535
+
8536
+    bool visitUnary(Visit visit, TIntermUnary *node) override  { return !mFoundName; }
8537
+
8538
+    bool visitTernary(Visit visit, TIntermTernary *node) override { return !mFoundName; }
8539
+
8540
+    bool visitAggregate(Visit visit, TIntermAggregate *node) override
8541
+    {
8542
+        if (node->isConstructor())
8543
+        {
8544
+            const TType &type           = node->getType();
8545
+            const TStructure *structure = type.getStruct();
8546
+            if (structure && Name(*structure) == mName)
8547
+            {
8548
+                mFoundName = true;
8549
+            }
8550
+        }
8551
+        else
8552
+        {
8553
+            const TFunction *func = node->getFunction();
8554
+            if (func && Name(*func) == mName)
8555
+            {
8556
+                mFoundName = true;
8557
+            }
8558
+        }
8559
+        return !mFoundName;
8560
+    }
8561
+
8562
+    bool visitIfElse(Visit visit, TIntermIfElse *node) override
8563
+    {
8564
+        LOGIC_ERROR();
8565
+        return false;
8566
+    }
8567
+
8568
+    bool visitSwitch(Visit, TIntermSwitch *) override
8569
+    {
8570
+        LOGIC_ERROR();
8571
+        return false;
8572
+    }
8573
+    bool visitCase(Visit, TIntermCase *) override
8574
+    {
8575
+        LOGIC_ERROR();
8576
+        return false;
8577
+    }
8578
+
8579
+    void visitFunctionPrototype(TIntermFunctionPrototype *) override { LOGIC_ERROR(); }
8580
+
8581
+    bool visitFunctionDefinition(Visit, TIntermFunctionDefinition *) override
8582
+    {
8583
+        LOGIC_ERROR();
8584
+        return false;
8585
+    }
8586
+
8587
+    bool visitBlock(Visit, TIntermBlock *) override
8588
+    {
8589
+        LOGIC_ERROR();
8590
+        return false;
8591
+    }
8592
+
8593
+    bool visitGlobalQualifierDeclaration(Visit, TIntermGlobalQualifierDeclaration *) override
8594
+    {
8595
+        LOGIC_ERROR();
8596
+        return false;
8597
+    }
8598
+
8599
+    bool visitDeclaration(Visit, TIntermDeclaration *) override
8600
+    {
8601
+        LOGIC_ERROR();
8602
+        return false;
8603
+    }
8604
+
8605
+    bool visitLoop(Visit, TIntermLoop *) override
8606
+    {
8607
+        LOGIC_ERROR();
8608
+        return false;
8609
+    }
8610
+
8611
+    bool visitBranch(Visit, TIntermBranch *) override
8612
+    {
8613
+        LOGIC_ERROR();
8614
+        return false;
8615
+    }
8616
+
8617
+    void visitPreprocessorDirective(TIntermPreprocessorDirective *) override { LOGIC_ERROR(); }
8618
+};
8619
+
8620
+}  // anonymous namespace
8621
+
8622
+bool sh::ExpressionContainsName(const Name &name, TIntermTyped &node)
8623
+{
8624
+    ExpressionContainsNameVisitor visitor(name);
8625
+    node.traverse(&visitor);
8626
+    return visitor.foundName();
8627
+}
8628
diff --git a/src/compiler/translator/TranslatorMetalDirect/Name.h b/src/compiler/translator/TranslatorMetalDirect/Name.h
8629
new file mode 100644
8630
index 0000000..d6eaea8
8631
--- /dev/null
8632
+++ b/src/compiler/translator/TranslatorMetalDirect/Name.h
8633
@@ -0,0 +1,68 @@
8634
+//
8635
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
8636
+// Use of this source code is governed by a BSD-style license that can be
8637
+// found in the LICENSE file.
8638
+//
8639
+
8640
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_NAME_H_
8641
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_NAME_H_
8642
+
8643
+#include "compiler/translator/ImmutableString.h"
8644
+#include "compiler/translator/InfoSink.h"
8645
+#include "compiler/translator/IntermNode.h"
8646
+#include "compiler/translator/Symbol.h"
8647
+#include "compiler/translator/Types.h"
8648
+
8649
+namespace sh
8650
+{
8651
+
8652
+constexpr char kAngleInternalPrefix[] = "ANGLE";
8653
+
8654
+// Represents the name of a symbol.
8655
+class Name
8656
+{
8657
+  public:
8658
+    constexpr Name(const Name &) = default;
8659
+
8660
+    constexpr Name() : Name(kEmptyImmutableString, SymbolType::Empty) {}
8661
+
8662
+    explicit constexpr Name(ImmutableString rawName, SymbolType symbolType)
8663
+        : mRawName(rawName), mSymbolType(symbolType)
8664
+    {
8665
+        ASSERT(rawName.empty() == (symbolType == SymbolType::Empty));
8666
+    }
8667
+
8668
+    explicit constexpr Name(const char *rawName, SymbolType symbolType = SymbolType::AngleInternal)
8669
+        : Name(ImmutableString(rawName), symbolType)
8670
+    {}
8671
+
8672
+    explicit Name(const std::string &rawName, SymbolType symbolType)
8673
+        : Name(ImmutableString(rawName), symbolType)
8674
+    {}
8675
+
8676
+    explicit Name(const TField &field);
8677
+    explicit Name(const TSymbol &symbol);
8678
+
8679
+    Name &operator=(const Name &) = default;
8680
+    bool operator==(const Name &other) const;
8681
+    bool operator!=(const Name &other) const;
8682
+    bool operator<(const Name &other) const;
8683
+
8684
+    constexpr const ImmutableString &rawName() const { return mRawName; }
8685
+    constexpr SymbolType symbolType() const { return mSymbolType; }
8686
+
8687
+    bool empty() const;
8688
+    bool beginsWith(const Name &prefix) const;
8689
+
8690
+    void emit(TInfoSinkBase &out) const;
8691
+
8692
+  private:
8693
+    ImmutableString mRawName;
8694
+    SymbolType mSymbolType;
8695
+};
8696
+
8697
+ANGLE_NO_DISCARD bool ExpressionContainsName(const Name &name, TIntermTyped &node);
8698
+
8699
+}  // namespace sh
8700
+
8701
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_NAME_H_
8702
diff --git a/src/compiler/translator/TranslatorMetalDirect/Pipeline.cpp b/src/compiler/translator/TranslatorMetalDirect/Pipeline.cpp
8703
new file mode 100644
8704
index 0000000..54c378a
8705
--- /dev/null
8706
+++ b/src/compiler/translator/TranslatorMetalDirect/Pipeline.cpp
8707
@@ -0,0 +1,476 @@
8708
+//
8709
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
8710
+// Use of this source code is governed by a BSD-style license that can be
8711
+// found in the LICENSE file.
8712
+//
8713
+
8714
+#include "compiler/translator/TranslatorMetalDirect/Pipeline.h"
8715
+#include "compiler/translator/TranslatorMetalDirect/Debug.h"
8716
+#include "compiler/translator/tree_util/BuiltIn.h"
8717
+
8718
+using namespace sh;
8719
+
8720
+////////////////////////////////////////////////////////////////////////////////
8721
+
8722
+#define VARIANT_NAME(variant, base) (variant == Variant::Modified ? base "Mod" : base)
8723
+
8724
+bool Pipeline::uses(const TVariable &var) const
8725
+{
8726
+    if (var.symbolType() == SymbolType::Empty)
8727
+    {
8728
+        return false;
8729
+    }
8730
+
8731
+    if (globalInstanceVar)
8732
+    {
8733
+        return &var == globalInstanceVar;
8734
+    }
8735
+
8736
+    const TType &nodeType      = var.getType();
8737
+    const TQualifier qualifier = nodeType.getQualifier();
8738
+
8739
+    switch (type)
8740
+    {
8741
+        case Type::VertexIn:
8742
+            switch (qualifier)
8743
+            {
8744
+                case TQualifier::EvqAttribute:
8745
+                case TQualifier::EvqVertexIn:
8746
+                    return true;
8747
+                default:
8748
+                    return false;
8749
+            }
8750
+
8751
+        case Type::VertexOut:
8752
+            switch (qualifier)
8753
+            {
8754
+                case TQualifier::EvqVertexOut:
8755
+                case TQualifier::EvqPosition:
8756
+                case TQualifier::EvqFlatOut:
8757
+                case TQualifier::EvqPointSize:
8758
+                case TQualifier::EvqSmoothOut:
8759
+                case TQualifier::EvqCentroidOut:
8760
+                case TQualifier::EvqNoPerspectiveOut:
8761
+                case TQualifier::EvqVaryingOut:
8762
+                    return true;
8763
+                default:
8764
+                    return false;
8765
+            }
8766
+
8767
+        case Type::FragmentIn:
8768
+            switch (qualifier)
8769
+            {
8770
+                case TQualifier::EvqFragmentIn:
8771
+                case TQualifier::EvqFlatIn:
8772
+                case TQualifier::EvqSmoothIn:
8773
+                case TQualifier::EvqCentroidIn:
8774
+                case TQualifier::EvqNoPerspectiveIn:
8775
+                case TQualifier::EvqVaryingIn:
8776
+                    return true;
8777
+                default:
8778
+                    return false;
8779
+            }
8780
+
8781
+        case Type::FragmentOut:
8782
+            switch (qualifier)
8783
+            {
8784
+                case TQualifier::EvqFragmentOut:
8785
+                case TQualifier::EvqFragColor:
8786
+                case TQualifier::EvqFragData:
8787
+                case TQualifier::EvqFragDepth:
8788
+                    return true;
8789
+                default:
8790
+                    return false;
8791
+            }
8792
+
8793
+        case Type::UserUniforms:
8794
+            switch (qualifier)
8795
+            {
8796
+                case TQualifier::EvqUniform:
8797
+                    return true;
8798
+                default:
8799
+                    return false;
8800
+            }
8801
+
8802
+        case Type::NonConstantGlobals:
8803
+            switch (qualifier)
8804
+            {
8805
+                case TQualifier::EvqGlobal:
8806
+                    return true;
8807
+                default:
8808
+                    return false;
8809
+            }
8810
+
8811
+        case Type::InvocationVertexGlobals:
8812
+            switch (qualifier)
8813
+            {
8814
+                case TQualifier::EvqVertexID:
8815
+                    return true;
8816
+                default:
8817
+                    return false;
8818
+            }
8819
+
8820
+        case Type::InvocationFragmentGlobals:
8821
+            switch (qualifier)
8822
+            {
8823
+                case TQualifier::EvqFragCoord:
8824
+                case TQualifier::EvqPointCoord:
8825
+                case TQualifier::EvqFrontFacing:
8826
+                    return true;
8827
+                default:
8828
+                    return false;
8829
+            }
8830
+
8831
+        case Type::AngleUniforms:
8832
+            LOGIC_ERROR();  // globalInstanceVar should be non-null and thus never reach here.
8833
+            return false;
8834
+
8835
+        case Type::Texture:
8836
+            return IsSampler(nodeType.getBasicType());
8837
+
8838
+        case Type::InstanceId:
8839
+            return Name(var) == Name(*BuiltInVariable::gl_InstanceID());
8840
+    }
8841
+}
8842
+
8843
+Name Pipeline::getStructTypeName(Variant variant) const
8844
+{
8845
+    const char *name;
8846
+    switch (type)
8847
+    {
8848
+        case Type::VertexIn:
8849
+            name = VARIANT_NAME(variant, "VertexIn");
8850
+            break;
8851
+        case Type::VertexOut:
8852
+            name = VARIANT_NAME(variant, "VertexOut");
8853
+            break;
8854
+        case Type::FragmentIn:
8855
+            name = VARIANT_NAME(variant, "FragmentIn");
8856
+            break;
8857
+        case Type::FragmentOut:
8858
+            name = VARIANT_NAME(variant, "FragmentOut");
8859
+            break;
8860
+        case Type::UserUniforms:
8861
+            name = VARIANT_NAME(variant, "UserUniforms");
8862
+            break;
8863
+        case Type::AngleUniforms:
8864
+            name = VARIANT_NAME(variant, "AngleUniforms");
8865
+            break;
8866
+        case Type::NonConstantGlobals:
8867
+            name = VARIANT_NAME(variant, "NonConstGlobals");
8868
+            break;
8869
+        case Type::InvocationVertexGlobals:
8870
+            name = VARIANT_NAME(variant, "InvocationVertexGlobals");
8871
+            break;
8872
+        case Type::InvocationFragmentGlobals:
8873
+            name = VARIANT_NAME(variant, "InvocationFragmentGlobals");
8874
+            break;
8875
+        case Type::Texture:
8876
+            name = VARIANT_NAME(variant, "TextureEnvs");
8877
+            break;
8878
+        case Type::InstanceId:
8879
+            name = VARIANT_NAME(variant, "InstanceId");
8880
+            break;
8881
+    }
8882
+    return Name(name);
8883
+}
8884
+
8885
+Name Pipeline::getStructInstanceName(Variant variant) const
8886
+{
8887
+    const char *name;
8888
+    switch (type)
8889
+    {
8890
+        case Type::VertexIn:
8891
+            name = VARIANT_NAME(variant, "vertexIn");
8892
+            break;
8893
+        case Type::VertexOut:
8894
+            name = VARIANT_NAME(variant, "vertexOut");
8895
+            break;
8896
+        case Type::FragmentIn:
8897
+            name = VARIANT_NAME(variant, "fragmentIn");
8898
+            break;
8899
+        case Type::FragmentOut:
8900
+            name = VARIANT_NAME(variant, "fragmentOut");
8901
+            break;
8902
+        case Type::UserUniforms:
8903
+            name = VARIANT_NAME(variant, "userUniforms");
8904
+            break;
8905
+        case Type::AngleUniforms:
8906
+            name = VARIANT_NAME(variant, "angleUniforms");
8907
+            break;
8908
+        case Type::NonConstantGlobals:
8909
+            name = VARIANT_NAME(variant, "nonConstGlobals");
8910
+            break;
8911
+        case Type::InvocationVertexGlobals:
8912
+            name = VARIANT_NAME(variant, "invocationVertexGlobals");
8913
+            break;
8914
+        case Type::InvocationFragmentGlobals:
8915
+            name = VARIANT_NAME(variant, "invocationFragmentGlobals");
8916
+            break;
8917
+        case Type::Texture:
8918
+            name = VARIANT_NAME(variant, "textureEnvs");
8919
+            break;
8920
+        case Type::InstanceId:
8921
+            name = VARIANT_NAME(variant, "instanceId");
8922
+            break;
8923
+    }
8924
+    return Name(name);
8925
+}
8926
+
8927
+static bool AllowPacking(Pipeline::Type type)
8928
+{
8929
+    using Type = Pipeline::Type;
8930
+
8931
+    switch (type)
8932
+    {
8933
+        case Type::UserUniforms:
8934
+            return true;
8935
+
8936
+        case Type::VertexIn:
8937
+        case Type::VertexOut:
8938
+        case Type::FragmentIn:
8939
+        case Type::FragmentOut:
8940
+        case Type::AngleUniforms:
8941
+        case Type::NonConstantGlobals:
8942
+        case Type::InvocationVertexGlobals:
8943
+        case Type::InvocationFragmentGlobals:
8944
+        case Type::Texture:
8945
+        case Type::InstanceId:
8946
+            return false;
8947
+    }
8948
+}
8949
+
8950
+static bool AllowPadding(Pipeline::Type type)
8951
+{
8952
+    using Type = Pipeline::Type;
8953
+
8954
+    switch (type)
8955
+    {
8956
+        case Type::UserUniforms:
8957
+        case Type::VertexIn:
8958
+        case Type::VertexOut:
8959
+        case Type::FragmentIn:
8960
+        case Type::FragmentOut:
8961
+        case Type::AngleUniforms:
8962
+        case Type::NonConstantGlobals:
8963
+        case Type::InvocationVertexGlobals:
8964
+        case Type::InvocationFragmentGlobals:
8965
+            return true;
8966
+
8967
+        case Type::Texture:
8968
+        case Type::InstanceId:
8969
+            return false;
8970
+    }
8971
+}
8972
+enum Compare
8973
+{
8974
+    LT,
8975
+    LTE,
8976
+    EQ,
8977
+    GTE,
8978
+    GT,
8979
+};
8980
+
8981
+template <typename T>
8982
+static bool CompareBy(Compare op, const T &x, const T &y)
8983
+{
8984
+    switch (op)
8985
+    {
8986
+        case LT:
8987
+            return x < y;
8988
+        case LTE:
8989
+            return x <= y;
8990
+        case EQ:
8991
+            return x == y;
8992
+        case GTE:
8993
+            return x >= y;
8994
+        case GT:
8995
+            return x > y;
8996
+    }
8997
+}
8998
+
8999
+template <TBasicType BT, Compare Cmp, int MatchDim, int NewDim>
9000
+static int SaturateVectorOf(const TField &field)
9001
+{
9002
+    static_assert(NewDim >= MatchDim, "");
9003
+
9004
+    const TType &type = *field.type();
9005
+    ASSERT(type.isScalar() || type.isVector());
9006
+
9007
+    const bool cond = type.getBasicType() == BT && !type.isArray() &&
9008
+                      CompareBy(Cmp, type.getNominalSize(), MatchDim);
9009
+
9010
+    if (cond)
9011
+    {
9012
+        return NewDim;
9013
+    }
9014
+    return 0;
9015
+}
9016
+
9017
+ModifyStructConfig Pipeline::externalStructModifyConfig() const
9018
+{
9019
+    using Pred   = ModifyStructConfig::Predicate;
9020
+    using SatVec = ModifyStructConfig::SaturateVector;
9021
+
9022
+    ModifyStructConfig config(
9023
+        isPipelineOut() ? ConvertType::OriginalToModified : ConvertType::ModifiedToOriginal,
9024
+        AllowPacking(type), AllowPadding(type));
9025
+
9026
+    config.externalAddressSpace = externalAddressSpace();
9027
+
9028
+    switch (type)
9029
+    {
9030
+        case Type::VertexIn:
9031
+            config.inlineArray        = Pred::True;
9032
+            config.splitMatrixColumns = Pred::True;
9033
+            config.inlineStruct       = Pred::True;
9034
+            break;
9035
+
9036
+        case Type::VertexOut:
9037
+            config.inlineArray        = Pred::True;
9038
+            config.splitMatrixColumns = Pred::True;
9039
+            config.inlineStruct       = Pred::True;
9040
+            break;
9041
+
9042
+        case Type::FragmentIn:
9043
+            config.inlineArray        = Pred::True;
9044
+            config.splitMatrixColumns = Pred::True;
9045
+            config.inlineStruct       = Pred::True;
9046
+            break;
9047
+
9048
+        case Type::FragmentOut:
9049
+            config.inlineArray            = Pred::True;
9050
+            config.splitMatrixColumns     = Pred::True;
9051
+            config.inlineStruct           = Pred::True;
9052
+            config.saturateScalarOrVector = [](const TField &field) {
9053
+                if (int s = SaturateVectorOf<TBasicType::EbtInt, LT, 4, 4>(field))
9054
+                {
9055
+                    return s;
9056
+                }
9057
+                if (int s = SaturateVectorOf<TBasicType::EbtUInt, LT, 4, 4>(field))
9058
+                {
9059
+                    return s;
9060
+                }
9061
+                if (int s = SaturateVectorOf<TBasicType::EbtFloat, LT, 4, 4>(field))
9062
+                {
9063
+                    return s;
9064
+                }
9065
+                return 0;
9066
+            };
9067
+            break;
9068
+
9069
+        case Type::UserUniforms:
9070
+            config.promoteBoolToUint            = Pred::True;
9071
+            config.saturateMatrixRows           = SatVec::FullySaturate;
9072
+            config.saturateScalarOrVectorArrays = SatVec::FullySaturate;
9073
+            config.recurseStruct                = Pred::True;
9074
+            break;
9075
+
9076
+        case Type::AngleUniforms:
9077
+            config.initialBlockStorage = TLayoutBlockStorage::EbsStd430;  // XXX: Correct?
9078
+            break;
9079
+
9080
+        case Type::NonConstantGlobals:
9081
+            break;
9082
+
9083
+        case Type::InvocationVertexGlobals:
9084
+        case Type::InvocationFragmentGlobals:
9085
+        case Type::Texture:
9086
+        case Type::InstanceId:
9087
+            break;
9088
+    }
9089
+
9090
+    return config;
9091
+}
9092
+
9093
+bool Pipeline::alwaysRequiresLocalVariableDeclarationInMain() const
9094
+{
9095
+    switch (type)
9096
+    {
9097
+        case Type::VertexIn:
9098
+        case Type::FragmentIn:
9099
+        case Type::UserUniforms:
9100
+        case Type::AngleUniforms:
9101
+            return false;
9102
+
9103
+        case Type::VertexOut:
9104
+        case Type::FragmentOut:
9105
+        case Type::NonConstantGlobals:
9106
+        case Type::InvocationVertexGlobals:
9107
+        case Type::InvocationFragmentGlobals:
9108
+        case Type::Texture:
9109
+        case Type::InstanceId:
9110
+            return true;
9111
+    }
9112
+}
9113
+
9114
+bool Pipeline::isPipelineOut() const
9115
+{
9116
+    switch (type)
9117
+    {
9118
+        case Type::VertexIn:
9119
+        case Type::FragmentIn:
9120
+        case Type::UserUniforms:
9121
+        case Type::AngleUniforms:
9122
+        case Type::NonConstantGlobals:
9123
+        case Type::InvocationVertexGlobals:
9124
+        case Type::InvocationFragmentGlobals:
9125
+        case Type::Texture:
9126
+        case Type::InstanceId:
9127
+            return false;
9128
+
9129
+        case Type::VertexOut:
9130
+        case Type::FragmentOut:
9131
+            return true;
9132
+    }
9133
+}
9134
+
9135
+AddressSpace Pipeline::externalAddressSpace() const
9136
+{
9137
+    switch (type)
9138
+    {
9139
+        case Type::VertexIn:
9140
+        case Type::FragmentIn:
9141
+        case Type::NonConstantGlobals:
9142
+        case Type::InvocationVertexGlobals:
9143
+        case Type::InvocationFragmentGlobals:
9144
+        case Type::Texture:
9145
+        case Type::InstanceId:
9146
+        case Type::FragmentOut:
9147
+        case Type::VertexOut:
9148
+            return AddressSpace::Thread;
9149
+
9150
+        case Type::UserUniforms:
9151
+        case Type::AngleUniforms:
9152
+            return AddressSpace::Constant;
9153
+    }
9154
+}
9155
+
9156
+bool PipelineStructs::matches(const TStructure &s, bool internal, bool external) const
9157
+{
9158
+    PipelineScoped<TStructure> ps[] = {
9159
+        fragmentIn,
9160
+        fragmentOut,
9161
+        vertexIn,
9162
+        vertexOut,
9163
+        userUniforms,
9164
+        angleUniforms,
9165
+        nonConstantGlobals,
9166
+        invocationVertexGlobals,
9167
+        invocationFragmentGlobals,
9168
+        texture,
9169
+        instanceId,
9170
+    };
9171
+    for (const auto &p : ps)
9172
+    {
9173
+        if (internal && p.internal == &s)
9174
+        {
9175
+            return true;
9176
+        }
9177
+        if (external && p.external == &s)
9178
+        {
9179
+            return true;
9180
+        }
9181
+    }
9182
+    return false;
9183
+}
9184
diff --git a/src/compiler/translator/TranslatorMetalDirect/Pipeline.h b/src/compiler/translator/TranslatorMetalDirect/Pipeline.h
9185
new file mode 100644
9186
index 0000000..9bf476a
9187
--- /dev/null
9188
+++ b/src/compiler/translator/TranslatorMetalDirect/Pipeline.h
9189
@@ -0,0 +1,123 @@
9190
+//
9191
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
9192
+// Use of this source code is governed by a BSD-style license that can be
9193
+// found in the LICENSE file.
9194
+//
9195
+
9196
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_PIPELINE_H_
9197
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_PIPELINE_H_
9198
+
9199
+#include "compiler/translator/Symbol.h"
9200
+#include "compiler/translator/TranslatorMetalDirect/ModifyStruct.h"
9201
+#include "compiler/translator/TranslatorMetalDirect/Name.h"
9202
+#include "compiler/translator/TranslatorMetalDirect/SymbolEnv.h"
9203
+
9204
+namespace sh
9205
+{
9206
+
9207
+// Data that is scoped as `external` and `internal` for a given pipeline.
9208
+template <typename T>
9209
+struct PipelineScoped
9210
+{
9211
+    // Data that is configured to talk externally to the program.
9212
+    // May coincide with `internal`, but may also diverge from `internal`.
9213
+    const T *external = nullptr;
9214
+
9215
+    // Data that is configured to talk internally within the program.
9216
+    // May coincide with `external`, but may also diverge from `external`.
9217
+    const T *internal = nullptr;
9218
+
9219
+    // Returns true iff the input coincides with either `external` or `internal` data.
9220
+    bool matches(const T &object) const { return external == &object || internal == &object; }
9221
+
9222
+    // Both `external` and `internal` representations are non-null.
9223
+    bool isTotallyFull() const { return external && internal; }
9224
+
9225
+    // Both `external` and `internal` representations are null.
9226
+    bool isTotallyEmpty() const { return !external && !internal; }
9227
+
9228
+    // Both `external` and `internal` representations are the same.
9229
+    bool isUniform() const { return external == internal; }
9230
+};
9231
+
9232
+// Represents a high-level program pipeline.
9233
+class Pipeline
9234
+{
9235
+  public:
9236
+    enum class Type
9237
+    {
9238
+        VertexIn,
9239
+        VertexOut,
9240
+        FragmentIn,
9241
+        FragmentOut,
9242
+        UserUniforms,
9243
+        AngleUniforms,
9244
+        NonConstantGlobals,
9245
+        InvocationVertexGlobals,
9246
+        InvocationFragmentGlobals,
9247
+        Texture,
9248
+        InstanceId,
9249
+    };
9250
+
9251
+    enum class Variant
9252
+    {
9253
+        // For all internal pipeline uses.
9254
+        // For external pipeline uses if pipeline does not require splitting or saturation.
9255
+        Original,
9256
+
9257
+        // Only for external pipeline uses if the pipeline was split or saturated.
9258
+        Modified,
9259
+    };
9260
+
9261
+  public:
9262
+    // The type of the pipeline.
9263
+    Type type;
9264
+
9265
+    // Non-null if a global instance of the pipeline struct already exists.
9266
+    // If non-null struct splitting should not be needed.
9267
+    const TVariable *globalInstanceVar;
9268
+
9269
+  public:
9270
+    // Returns true iff the variable belongs to the pipeline.
9271
+    bool uses(const TVariable &var) const;
9272
+
9273
+    // Returns the name for the struct type that stores variables of this pipeline.
9274
+    Name getStructTypeName(Variant variant) const;
9275
+
9276
+    // Returns the name for the struct instance that stores variables of this pipeline.
9277
+    Name getStructInstanceName(Variant variant) const;
9278
+
9279
+    ModifyStructConfig externalStructModifyConfig() const;
9280
+
9281
+    // Returns true if the pipeline always requires a non-parameter local instance declaration of
9282
+    // the pipeline structures.
9283
+    bool alwaysRequiresLocalVariableDeclarationInMain() const;
9284
+
9285
+    // Returns true iff the pipeline is an output pipeline. The external pipeline structure should
9286
+    // be returned from `main`.
9287
+    bool isPipelineOut() const;
9288
+
9289
+    AddressSpace externalAddressSpace() const;
9290
+};
9291
+
9292
+// A collection of various pipeline structures.
9293
+struct PipelineStructs : angle::NonCopyable
9294
+{
9295
+    PipelineScoped<TStructure> fragmentIn;
9296
+    PipelineScoped<TStructure> fragmentOut;
9297
+    PipelineScoped<TStructure> vertexIn;
9298
+    PipelineScoped<TStructure> vertexOut;
9299
+    PipelineScoped<TStructure> userUniforms;
9300
+    PipelineScoped<TStructure> angleUniforms;
9301
+    PipelineScoped<TStructure> nonConstantGlobals;
9302
+    PipelineScoped<TStructure> invocationVertexGlobals;
9303
+    PipelineScoped<TStructure> invocationFragmentGlobals;
9304
+    PipelineScoped<TStructure> texture;
9305
+    PipelineScoped<TStructure> instanceId;
9306
+
9307
+    bool matches(const TStructure &s, bool internal, bool external) const;
9308
+};
9309
+
9310
+}  // namespace sh
9311
+
9312
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_PIPELINE_H_
9313
diff --git a/src/compiler/translator/TranslatorMetalDirect/ProgramPrelude.cpp b/src/compiler/translator/TranslatorMetalDirect/ProgramPrelude.cpp
9314
new file mode 100644
9315
index 0000000..8bf5a02
9316
--- /dev/null
9317
+++ b/src/compiler/translator/TranslatorMetalDirect/ProgramPrelude.cpp
9318
@@ -0,0 +1,3757 @@
9319
+//
9320
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
9321
+// Use of this source code is governed by a BSD-style license that can be
9322
+// found in the LICENSE file.
9323
+//
9324
+
9325
+#include <cctype>
9326
+
9327
+#include "compiler/translator/InfoSink.h"
9328
+#include "compiler/translator/Symbol.h"
9329
+#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
9330
+#include "compiler/translator/TranslatorMetalDirect/ConstantNames.h"
9331
+#include "compiler/translator/TranslatorMetalDirect/Debug.h"
9332
+#include "compiler/translator/TranslatorMetalDirect/Name.h"
9333
+#include "compiler/translator/TranslatorMetalDirect/ProgramPrelude.h"
9334
+#include "compiler/translator/tree_util/IntermTraverse.h"
9335
+
9336
+using namespace sh;
9337
+
9338
+////////////////////////////////////////////////////////////////////////////////
9339
+
9340
+namespace
9341
+{
9342
+
9343
+class ProgramPrelude : public TIntermTraverser
9344
+{
9345
+    using LineTag       = unsigned;
9346
+    using FuncEmitter   = void (*)(ProgramPrelude &, const TFunction &);
9347
+    using FuncToEmitter = std::map<Name, FuncEmitter>;
9348
+
9349
+  public:
9350
+    ProgramPrelude(TInfoSinkBase &out, const ProgramPreludeConfig &ppc)
9351
+        : TIntermTraverser(true, false, false), mOut(out)
9352
+    {
9353
+        ALWAYS_INLINE();
9354
+
9355
+        if (ppc.hasStructEq)
9356
+        {
9357
+            equalVector();
9358
+            equalMatrix();
9359
+        }
9360
+
9361
+#if 1
9362
+        mOut << "#define ANGLE_tensor metal::array\n";
9363
+#else
9364
+        tensor();
9365
+#endif
9366
+    }
9367
+
9368
+  private:
9369
+    bool emitGuard(LineTag lineTag)
9370
+    {
9371
+        if (mEmitted.find(lineTag) != mEmitted.end())
9372
+        {
9373
+            return false;
9374
+        }
9375
+        mEmitted.insert(lineTag);
9376
+        return true;
9377
+    }
9378
+
9379
+    static FuncToEmitter BuildFuncToEmitter();
9380
+
9381
+    void visitOperator(TOperator op,
9382
+                       const TFunction *func,
9383
+                       const TType *argType0,
9384
+                       const TType *argType1 = nullptr);
9385
+    void visitVariable(const Name &name, const TType &type);
9386
+    void visitVariable(const TVariable &var);
9387
+    void visitStructure(const TStructure &s);
9388
+
9389
+    bool visitBinary(Visit, TIntermBinary *node) override;
9390
+    bool visitUnary(Visit, TIntermUnary *node) override;
9391
+    bool visitAggregate(Visit, TIntermAggregate *node) override;
9392
+    bool visitDeclaration(Visit, TIntermDeclaration *node) override;
9393
+    void visitSymbol(TIntermSymbol *node) override;
9394
+
9395
+  private:
9396
+    void ALWAYS_INLINE();
9397
+
9398
+    void include_metal_atomic();
9399
+    void include_metal_common();
9400
+    void include_metal_geometric();
9401
+    void include_metal_graphics();
9402
+    void include_metal_math();
9403
+    void include_metal_matrix();
9404
+    void include_metal_pack();
9405
+    void include_metal_relational();
9406
+
9407
+    void enable_if();
9408
+    void scalar_of();
9409
+    void is_scalar();
9410
+    void is_vector();
9411
+    void is_matrix();
9412
+    void addressof();
9413
+    void distance();
9414
+    void length();
9415
+    void dot();
9416
+    void normalize();
9417
+    void faceforward();
9418
+    void reflect();
9419
+    void refract();
9420
+    void degrees();
9421
+    void radians();
9422
+    void mod();
9423
+    void postIncrementMatrix();
9424
+    void preIncrementMatrix();
9425
+    void postDecrementMatrix();
9426
+    void preDecrementMatrix();
9427
+    void negateMatrix();
9428
+    void matmulAssign();
9429
+    void atan();
9430
+    void addMatrixScalarAssign();
9431
+    void subMatrixScalarAssign();
9432
+    void addMatrixScalar();
9433
+    void subMatrixScalar();
9434
+    void divMatrixScalar();
9435
+    void divMatrixScalarFast();
9436
+    void divMatrixScalarAssign();
9437
+    void divMatrixScalarAssignFast();
9438
+    void tensor();
9439
+    void componentWiseDivide();
9440
+    void componentWiseDivideAssign();
9441
+    void componentWiseMultiply();
9442
+    void outerProduct();
9443
+    void inverse2();
9444
+    void inverse3();
9445
+    void inverse4();
9446
+    void equalVector();
9447
+    void equalMatrix();
9448
+    void notEqualVector();
9449
+    void notEqualStruct();
9450
+    void equalArray();
9451
+    void notEqualArray();
9452
+    void sign();
9453
+    void pack_half_2x16();
9454
+    void unpack_half_2x16();
9455
+    void vectorElemRef();
9456
+    void swizzleRef();
9457
+    void out();
9458
+    void inout();
9459
+    void flattenArray();
9460
+    void castVector();
9461
+    void castMatrix();
9462
+    void functionConstants();
9463
+    void gradient();
9464
+    void textureEnv();
9465
+    void texelFetch();
9466
+    void texelFetchOffset();
9467
+    void texture();
9468
+    void texture_generic_float2();
9469
+    void texture_generic_float2_float();
9470
+    void texture_generic_float3();
9471
+    void texture_generic_float3_float();
9472
+    void texture_depth2d_float3();
9473
+    void texture_depth2d_float3_float();
9474
+    void texture_depth2darray_float4();
9475
+    void texture_depth2darray_float4_float();
9476
+    void texture_depthcube_float4();
9477
+    void texture_depthcube_float4_float();
9478
+    void texture_texture2darray_float3();
9479
+    void texture_texture2darray_float3_float();
9480
+    void texture_texture2darray_float4();
9481
+    void texture_texture2darray_float4_float();
9482
+    void texture1DLod();
9483
+    void texture1DProj();
9484
+    void texture1DProjLod();
9485
+    void texture2D();
9486
+    void texture2DLod();
9487
+    void texture2DProj();
9488
+    void texture2DProjLod();
9489
+    void texture3DLod();
9490
+    void texture3DProj();
9491
+    void texture3DProjLod();
9492
+    void textureCube();
9493
+    void textureCubeLod();
9494
+    void textureCubeProj();
9495
+    void textureCubeProjLod();
9496
+    void textureGrad();
9497
+    void textureGrad_generic_floatN_floatN_floatN();
9498
+    void textureGrad_generic_float3_float2_float2();
9499
+    void textureGrad_generic_float4_float2_float2();
9500
+    void textureGrad_depth2d_float3_float2_float2();
9501
+    void textureGrad_depth2darray_float4_float2_float2();
9502
+    void textureGrad_depthcube_float4_float3_float3();
9503
+    void textureGrad_texturecube_float3_float3_float3();
9504
+    void textureGradOffset();
9505
+    void textureGradOffset_generic_floatN_floatN_floatN_intN();
9506
+    void textureGradOffset_generic_float3_float2_float2_int2();
9507
+    void textureGradOffset_generic_float4_float2_float2_int2();
9508
+    void textureGradOffset_depth2d_float3_float2_float2_int2();
9509
+    void textureGradOffset_depth2darray_float4_float2_float2_int2();
9510
+    void textureGradOffset_depthcube_float4_float3_float3_int3();
9511
+    void textureGradOffset_texturecube_float3_float3_float3_int3();
9512
+    void textureLod();
9513
+    void textureLod_generic_float2();
9514
+    void textureLod_generic_float3();
9515
+    void textureLod_depth2d_float3();
9516
+    void textureLod_texture2darray_float3();
9517
+    void textureLod_texture2darray_float4();
9518
+    void textureLodOffset();
9519
+    void textureOffset();
9520
+    void textureProj();
9521
+    void textureProjGrad();
9522
+    void textureProjGrad_generic_float3_float2_float2();
9523
+    void textureProjGrad_generic_float4_float2_float2();
9524
+    void textureProjGrad_depth2d_float4_float2_float2();
9525
+    void textureProjGrad_texture3d_float4_float3_float3();
9526
+    void textureProjGradOffset();
9527
+    void textureProjGradOffset_generic_float3_float2_float2_int2();
9528
+    void textureProjGradOffset_generic_float4_float2_float2_int2();
9529
+    void textureProjGradOffset_depth2d_float4_float2_float2_int2();
9530
+    void textureProjGradOffset_texture3d_float4_float3_float3_int3();
9531
+    void textureProjLod();
9532
+    void textureProjLod_generic_float3();
9533
+    void textureProjLod_generic_float4();
9534
+    void textureProjLod_depth2d_float4();
9535
+    void textureProjLod_texture3d_float4();
9536
+    void textureProjLodOffset();
9537
+    void textureProjOffset();
9538
+    void textureSize();
9539
+
9540
+  private:
9541
+    TInfoSinkBase &mOut;
9542
+    std::unordered_set<LineTag> mEmitted;
9543
+    std::unordered_set<const TSymbol *> mHandled;
9544
+    const FuncToEmitter mFuncToEmitter = BuildFuncToEmitter();
9545
+};
9546
+
9547
+}  // anonymous namespace
9548
+
9549
+////////////////////////////////////////////////////////////////////////////////
9550
+
9551
+#define PROGRAM_PRELUDE_INCLUDE(header)             \
9552
+    void ProgramPrelude::include_##header()         \
9553
+    {                                               \
9554
+        if (emitGuard(__LINE__))                    \
9555
+        {                                           \
9556
+            mOut << ("#include <" #header ">\n\n"); \
9557
+        }                                           \
9558
+    }
9559
+
9560
+#define PROGRAM_PRELUDE_DECLARE(name, code, ...)                \
9561
+    void ProgramPrelude::name()                                 \
9562
+    {                                                           \
9563
+        ASSERT(code[0] == '\n');                                \
9564
+        if (emitGuard(__LINE__))                                \
9565
+        {                                                       \
9566
+            __VA_ARGS__; /* dependencies */                     \
9567
+            mOut << (static_cast<const char *>(code "\n") + 1); \
9568
+        }                                                       \
9569
+    }
9570
+
9571
+////////////////////////////////////////////////////////////////////////////////
9572
+
9573
+PROGRAM_PRELUDE_INCLUDE(metal_atomic)
9574
+PROGRAM_PRELUDE_INCLUDE(metal_common)
9575
+PROGRAM_PRELUDE_INCLUDE(metal_geometric)
9576
+PROGRAM_PRELUDE_INCLUDE(metal_graphics)
9577
+PROGRAM_PRELUDE_INCLUDE(metal_math)
9578
+PROGRAM_PRELUDE_INCLUDE(metal_matrix)
9579
+PROGRAM_PRELUDE_INCLUDE(metal_pack)
9580
+PROGRAM_PRELUDE_INCLUDE(metal_relational)
9581
+
9582
+////////////////////////////////////////////////////////////////////////////////
9583
+
9584
+PROGRAM_PRELUDE_DECLARE(ALWAYS_INLINE, R"(
9585
+#define ANGLE_ALWAYS_INLINE __attribute__((always_inline))
9586
+)")
9587
+
9588
+PROGRAM_PRELUDE_DECLARE(enable_if, R"(
9589
+template <bool B, typename T = void>
9590
+struct ANGLE_enable_if {};
9591
+template <typename T>
9592
+struct ANGLE_enable_if<true, T>
9593
+{
9594
+    using type = T;
9595
+};
9596
+template <bool B>
9597
+using ANGLE_enable_if_t = typename ANGLE_enable_if<B>::type;
9598
+)")
9599
+
9600
+PROGRAM_PRELUDE_DECLARE(scalar_of, R"(
9601
+template <typename T>
9602
+struct ANGLE_scalar_of
9603
+{
9604
+    using type = T;
9605
+};
9606
+template <typename T>
9607
+using ANGLE_scalar_of_t = typename ANGLE_scalar_of<T>::type;
9608
+)")
9609
+
9610
+PROGRAM_PRELUDE_DECLARE(is_scalar, R"(
9611
+template <typename T>
9612
+struct ANGLE_is_scalar {};
9613
+#define ANGLE_DEFINE_SCALAR(scalar) \
9614
+    template <> struct ANGLE_is_scalar<scalar> { enum { value = true }; }
9615
+ANGLE_DEFINE_SCALAR(bool);
9616
+ANGLE_DEFINE_SCALAR(char);
9617
+ANGLE_DEFINE_SCALAR(short);
9618
+ANGLE_DEFINE_SCALAR(int);
9619
+ANGLE_DEFINE_SCALAR(long);
9620
+ANGLE_DEFINE_SCALAR(uchar);
9621
+ANGLE_DEFINE_SCALAR(ushort);
9622
+ANGLE_DEFINE_SCALAR(uint);
9623
+ANGLE_DEFINE_SCALAR(ulong);
9624
+ANGLE_DEFINE_SCALAR(half);
9625
+ANGLE_DEFINE_SCALAR(float);
9626
+)")
9627
+
9628
+PROGRAM_PRELUDE_DECLARE(is_vector,
9629
+                        R"(
9630
+template <typename T>
9631
+struct ANGLE_is_vector
9632
+{
9633
+    enum { value = false };
9634
+};
9635
+#define ANGLE_DEFINE_VECTOR(scalar) \
9636
+    template <> struct ANGLE_is_vector<metal::scalar ## 2> { enum { value = true }; }; \
9637
+    template <> struct ANGLE_is_vector<metal::scalar ## 3> { enum { value = true }; }; \
9638
+    template <> struct ANGLE_is_vector<metal::scalar ## 4> { enum { value = true }; }; \
9639
+    template <> struct ANGLE_scalar_of<metal::scalar ## 2> { using type = scalar; }; \
9640
+    template <> struct ANGLE_scalar_of<metal::scalar ## 3> { using type = scalar; }; \
9641
+    template <> struct ANGLE_scalar_of<metal::scalar ## 4> { using type = scalar; }
9642
+ANGLE_DEFINE_VECTOR(bool);
9643
+ANGLE_DEFINE_VECTOR(char);
9644
+ANGLE_DEFINE_VECTOR(short);
9645
+ANGLE_DEFINE_VECTOR(int);
9646
+ANGLE_DEFINE_VECTOR(long);
9647
+ANGLE_DEFINE_VECTOR(uchar);
9648
+ANGLE_DEFINE_VECTOR(ushort);
9649
+ANGLE_DEFINE_VECTOR(uint);
9650
+ANGLE_DEFINE_VECTOR(ulong);
9651
+ANGLE_DEFINE_VECTOR(half);
9652
+ANGLE_DEFINE_VECTOR(float);
9653
+)",
9654
+                        scalar_of())
9655
+
9656
+PROGRAM_PRELUDE_DECLARE(is_matrix,
9657
+                        R"(
9658
+template <typename T>
9659
+struct ANGLE_is_matrix
9660
+{
9661
+    enum { value = false };
9662
+};
9663
+#define ANGLE_DEFINE_MATRIX(scalar) \
9664
+    template <> struct ANGLE_is_matrix<metal::scalar ## 2x2> { enum { value = true }; }; \
9665
+    template <> struct ANGLE_is_matrix<metal::scalar ## 2x3> { enum { value = true }; }; \
9666
+    template <> struct ANGLE_is_matrix<metal::scalar ## 2x4> { enum { value = true }; }; \
9667
+    template <> struct ANGLE_is_matrix<metal::scalar ## 3x2> { enum { value = true }; }; \
9668
+    template <> struct ANGLE_is_matrix<metal::scalar ## 3x3> { enum { value = true }; }; \
9669
+    template <> struct ANGLE_is_matrix<metal::scalar ## 3x4> { enum { value = true }; }; \
9670
+    template <> struct ANGLE_is_matrix<metal::scalar ## 4x2> { enum { value = true }; }; \
9671
+    template <> struct ANGLE_is_matrix<metal::scalar ## 4x3> { enum { value = true }; }; \
9672
+    template <> struct ANGLE_is_matrix<metal::scalar ## 4x4> { enum { value = true }; }; \
9673
+    template <> struct ANGLE_scalar_of<metal::scalar ## 2x2> { using type = scalar; }; \
9674
+    template <> struct ANGLE_scalar_of<metal::scalar ## 2x3> { using type = scalar; }; \
9675
+    template <> struct ANGLE_scalar_of<metal::scalar ## 2x4> { using type = scalar; }; \
9676
+    template <> struct ANGLE_scalar_of<metal::scalar ## 3x2> { using type = scalar; }; \
9677
+    template <> struct ANGLE_scalar_of<metal::scalar ## 3x3> { using type = scalar; }; \
9678
+    template <> struct ANGLE_scalar_of<metal::scalar ## 3x4> { using type = scalar; }; \
9679
+    template <> struct ANGLE_scalar_of<metal::scalar ## 4x2> { using type = scalar; }; \
9680
+    template <> struct ANGLE_scalar_of<metal::scalar ## 4x3> { using type = scalar; }; \
9681
+    template <> struct ANGLE_scalar_of<metal::scalar ## 4x4> { using type = scalar; }
9682
+ANGLE_DEFINE_MATRIX(half);
9683
+ANGLE_DEFINE_MATRIX(float);
9684
+)",
9685
+                        scalar_of())
9686
+
9687
+PROGRAM_PRELUDE_DECLARE(addressof,
9688
+                        R"(
9689
+template <typename T>
9690
+ANGLE_ALWAYS_INLINE thread T * ANGLE_addressof(thread T &ref)
9691
+{
9692
+    return &ref;
9693
+}
9694
+)")
9695
+
9696
+PROGRAM_PRELUDE_DECLARE(distance,
9697
+                        R"(
9698
+template <typename T, typename Enable = void>
9699
+struct ANGLE_distance_impl
9700
+{
9701
+    static ANGLE_ALWAYS_INLINE ANGLE_scalar_of_t<T> exec(T x, T y)
9702
+    {
9703
+        return metal::distance(x, y);
9704
+    }
9705
+};
9706
+template <typename T>
9707
+struct ANGLE_distance_impl<T, ANGLE_enable_if_t<ANGLE_is_scalar<T>::value>>
9708
+{
9709
+    static ANGLE_ALWAYS_INLINE T exec(T x, T y)
9710
+    {
9711
+        return metal::abs(x - y);
9712
+    }
9713
+};
9714
+template <typename T>
9715
+ANGLE_ALWAYS_INLINE ANGLE_scalar_of_t<T> ANGLE_distance(T x, T y)
9716
+{
9717
+    return ANGLE_distance_impl<T>::exec(x, y);
9718
+};
9719
+)",
9720
+                        include_metal_geometric(),
9721
+                        include_metal_math(),
9722
+                        enable_if(),
9723
+                        is_scalar(),
9724
+                        is_vector(),
9725
+                        is_matrix())
9726
+
9727
+PROGRAM_PRELUDE_DECLARE(length,
9728
+                        R"(
9729
+template <typename T, typename Enable = void>
9730
+struct ANGLE_length_impl
9731
+{
9732
+    static ANGLE_ALWAYS_INLINE ANGLE_scalar_of_t<T> exec(T x)
9733
+    {
9734
+        return metal::length(x);
9735
+    }
9736
+};
9737
+template <typename T>
9738
+struct ANGLE_length_impl<T, ANGLE_enable_if_t<ANGLE_is_scalar<T>::value>>
9739
+{
9740
+    static ANGLE_ALWAYS_INLINE T exec(T x)
9741
+    {
9742
+        return metal::abs(x);
9743
+    }
9744
+};
9745
+template <typename T>
9746
+ANGLE_ALWAYS_INLINE ANGLE_scalar_of_t<T> ANGLE_length(T x)
9747
+{
9748
+    return ANGLE_length_impl<T>::exec(x);
9749
+};
9750
+)",
9751
+                        include_metal_geometric(),
9752
+                        include_metal_math(),
9753
+                        enable_if(),
9754
+                        is_scalar(),
9755
+                        is_vector(),
9756
+                        is_matrix())
9757
+
9758
+PROGRAM_PRELUDE_DECLARE(dot,
9759
+                        R"(
9760
+template <typename T, typename Enable = void>
9761
+struct ANGLE_dot_impl
9762
+{
9763
+    static ANGLE_ALWAYS_INLINE ANGLE_scalar_of_t<T> exec(T x, T y)
9764
+    {
9765
+        return metal::dot(x, y);
9766
+    }
9767
+};
9768
+template <typename T>
9769
+struct ANGLE_dot_impl<T, ANGLE_enable_if_t<ANGLE_is_scalar<T>::value>>
9770
+{
9771
+    static ANGLE_ALWAYS_INLINE T exec(T x, T y)
9772
+    {
9773
+        return x * y;
9774
+    }
9775
+};
9776
+template <typename T>
9777
+ANGLE_ALWAYS_INLINE ANGLE_scalar_of_t<T> ANGLE_dot(T x, T y)
9778
+{
9779
+    return ANGLE_dot_impl<T>::exec(x, y);
9780
+};
9781
+)",
9782
+                        include_metal_geometric(),
9783
+                        enable_if(),
9784
+                        is_scalar(),
9785
+                        is_vector(),
9786
+                        is_matrix())
9787
+
9788
+PROGRAM_PRELUDE_DECLARE(normalize,
9789
+                        R"(
9790
+template <typename T, typename Enable = void>
9791
+struct ANGLE_normalize_impl
9792
+{
9793
+    static ANGLE_ALWAYS_INLINE T exec(T x)
9794
+    {
9795
+        return metal::normalize(x);
9796
+    }
9797
+};
9798
+template <typename T>
9799
+struct ANGLE_normalize_impl<T, ANGLE_enable_if_t<ANGLE_is_scalar<T>::value>>
9800
+{
9801
+    static ANGLE_ALWAYS_INLINE T exec(T x)
9802
+    {
9803
+        return ANGLE_sign(x);
9804
+    }
9805
+};
9806
+template <typename T>
9807
+ANGLE_ALWAYS_INLINE T ANGLE_normalize(T x)
9808
+{
9809
+    return ANGLE_normalize_impl<T>::exec(x);
9810
+};
9811
+)",
9812
+                        include_metal_common(),
9813
+                        include_metal_geometric(),
9814
+                        enable_if(),
9815
+                        is_scalar(),
9816
+                        is_vector(),
9817
+                        is_matrix(),
9818
+                        sign())
9819
+
9820
+PROGRAM_PRELUDE_DECLARE(faceforward,
9821
+                        R"(
9822
+template <typename T, typename Enable = void>
9823
+struct ANGLE_faceforward_impl
9824
+{
9825
+    static ANGLE_ALWAYS_INLINE T exec(T n, T i, T nref)
9826
+    {
9827
+        return metal::faceforward(n, i, nref);
9828
+    }
9829
+};
9830
+template <typename T>
9831
+struct ANGLE_faceforward_impl<T, ANGLE_enable_if_t<ANGLE_is_scalar<T>::value>>
9832
+{
9833
+    static ANGLE_ALWAYS_INLINE T exec(T n, T i, T nref)
9834
+    {
9835
+        return ANGLE_dot(nref, i) < T(0) ? n : -n;
9836
+    }
9837
+};
9838
+template <typename T>
9839
+ANGLE_ALWAYS_INLINE T ANGLE_faceforward(T n, T i, T nref)
9840
+{
9841
+    return ANGLE_faceforward_impl<T>::exec(n, i, nref);
9842
+};
9843
+)",
9844
+                        include_metal_geometric(),
9845
+                        enable_if(),
9846
+                        is_scalar(),
9847
+                        is_vector(),
9848
+                        is_matrix(),
9849
+                        dot())
9850
+
9851
+PROGRAM_PRELUDE_DECLARE(reflect,
9852
+                        R"(
9853
+template <typename T, typename Enable = void>
9854
+struct ANGLE_reflect_impl
9855
+{
9856
+    static ANGLE_ALWAYS_INLINE T exec(T i, T n)
9857
+    {
9858
+        return metal::reflect(i, n);
9859
+    }
9860
+};
9861
+template <typename T>
9862
+struct ANGLE_reflect_impl<T, ANGLE_enable_if_t<ANGLE_is_scalar<T>::value>>
9863
+{
9864
+    static ANGLE_ALWAYS_INLINE T exec(T i, T n)
9865
+    {
9866
+        return i - T(2) * ANGLE_dot(n, i) * n;
9867
+    }
9868
+};
9869
+template <typename T>
9870
+ANGLE_ALWAYS_INLINE T ANGLE_reflect(T i, T n)
9871
+{
9872
+    return ANGLE_reflect_impl<T>::exec(i, n);
9873
+};
9874
+)",
9875
+                        include_metal_geometric(),
9876
+                        enable_if(),
9877
+                        is_scalar(),
9878
+                        is_vector(),
9879
+                        is_matrix(),
9880
+                        dot())
9881
+
9882
+PROGRAM_PRELUDE_DECLARE(refract,
9883
+                        R"(
9884
+template <typename T, typename Enable = void>
9885
+struct ANGLE_refract_impl
9886
+{
9887
+    static ANGLE_ALWAYS_INLINE T exec(T i, T n, ANGLE_scalar_of_t<T> eta)
9888
+    {
9889
+        return metal::refract(i, n, eta);
9890
+    }
9891
+};
9892
+template <typename T>
9893
+struct ANGLE_refract_impl<T, ANGLE_enable_if_t<ANGLE_is_scalar<T>::value>>
9894
+{
9895
+    static ANGLE_ALWAYS_INLINE T exec(T i, T n, T eta)
9896
+    {
9897
+        auto dotNI = n * i;
9898
+        auto k = T(1) - eta * eta * (T(1) - dotNI * dotNI);
9899
+        if (k < T(0))
9900
+        {
9901
+            return T(0);
9902
+        }
9903
+        else
9904
+        {
9905
+            return eta * i - (eta * dotNI + metal::sqrt(k)) * n;
9906
+        }
9907
+    }
9908
+};
9909
+template <typename T>
9910
+ANGLE_ALWAYS_INLINE T ANGLE_refract(T i, T n, ANGLE_scalar_of_t<T> eta)
9911
+{
9912
+    return ANGLE_refract_impl<T>::exec(i, n, eta);
9913
+};
9914
+)",
9915
+                        include_metal_math(),
9916
+                        include_metal_geometric(),
9917
+                        enable_if(),
9918
+                        is_scalar(),
9919
+                        is_vector(),
9920
+                        is_matrix())
9921
+
9922
+PROGRAM_PRELUDE_DECLARE(sign,
9923
+                        R"(
9924
+template <typename T, typename Enable = void>
9925
+struct ANGLE_sign_impl
9926
+{
9927
+    static ANGLE_ALWAYS_INLINE T exec(T x)
9928
+    {
9929
+        return metal::sign(x);
9930
+    }
9931
+};
9932
+template <>
9933
+struct ANGLE_sign_impl<int>
9934
+{
9935
+    static ANGLE_ALWAYS_INLINE int exec(int x)
9936
+    {
9937
+        return (0 < x) - (x < 0);
9938
+    }
9939
+};
9940
+template <int N>
9941
+struct ANGLE_sign_impl<metal::vec<int, N>>
9942
+{
9943
+    static ANGLE_ALWAYS_INLINE metal::vec<int, N> exec(metal::vec<int, N> x)
9944
+    {
9945
+        metal::vec<int, N> s;
9946
+        for (int i = 0; i < N; ++i)
9947
+        {
9948
+            s[i] = ANGLE_sign_impl<int>::exec(x[i]);
9949
+        }
9950
+        return s;
9951
+    }
9952
+};
9953
+template <typename T>
9954
+ANGLE_ALWAYS_INLINE T ANGLE_sign(T x)
9955
+{
9956
+    return ANGLE_sign_impl<T>::exec(x);
9957
+};
9958
+)",
9959
+                        include_metal_common())
9960
+
9961
+PROGRAM_PRELUDE_DECLARE(atan,
9962
+                        R"(
9963
+template <typename T>
9964
+ANGLE_ALWAYS_INLINE T ANGLE_atan(T yOverX)
9965
+{
9966
+    return metal::atan(yOverX);
9967
+}
9968
+template <typename T>
9969
+ANGLE_ALWAYS_INLINE T ANGLE_atan(T y, T x)
9970
+{
9971
+    return metal::atan2(y, x);
9972
+}
9973
+)",
9974
+                        include_metal_math())
9975
+
9976
+PROGRAM_PRELUDE_DECLARE(degrees, R"(
9977
+template <typename T>
9978
+ANGLE_ALWAYS_INLINE T ANGLE_degrees(T x)
9979
+{
9980
+    return static_cast<T>(57.29577951308232) * x;
9981
+}
9982
+)")
9983
+
9984
+PROGRAM_PRELUDE_DECLARE(radians, R"(
9985
+template <typename T>
9986
+ANGLE_ALWAYS_INLINE T ANGLE_radians(T x)
9987
+{
9988
+    return static_cast<T>(1.7453292519943295e-2) * x;
9989
+}
9990
+)")
9991
+
9992
+PROGRAM_PRELUDE_DECLARE(mod,
9993
+                        R"(
9994
+template <typename X, typename Y>
9995
+ANGLE_ALWAYS_INLINE X ANGLE_mod(X x, Y y)
9996
+{
9997
+    return x - y * metal::floor(x / y);
9998
+}
9999
+)",
10000
+                        include_metal_math())
10001
+
10002
+PROGRAM_PRELUDE_DECLARE(pack_half_2x16,
10003
+                        R"(
10004
+ANGLE_ALWAYS_INLINE uint ANGLE_pack_half_2x16(float2 v)
10005
+{
10006
+    return as_type<uint>(half2(v));
10007
+}
10008
+)", )
10009
+
10010
+PROGRAM_PRELUDE_DECLARE(unpack_half_2x16,
10011
+                        R"(
10012
+ANGLE_ALWAYS_INLINE float2 ANGLE_unpack_half_2x16(uint x)
10013
+{
10014
+    return float2(as_type<half2>(x));
10015
+}
10016
+)", )
10017
+
10018
+PROGRAM_PRELUDE_DECLARE(matmulAssign, R"(
10019
+template <typename T, int N>
10020
+ANGLE_ALWAYS_INLINE thread metal::matrix<T, N, N> &operator*=(thread metal::matrix<T, N, N> &a, metal::matrix<T, N, N> b)
10021
+{
10022
+    a = a * b;
10023
+    return a;
10024
+}
10025
+)")
10026
+
10027
+PROGRAM_PRELUDE_DECLARE(postIncrementMatrix,
10028
+                        R"(
10029
+template <typename T, int Cols, int Rows>
10030
+ANGLE_ALWAYS_INLINE metal::matrix<T, Cols, Rows> operator++(thread metal::matrix<T, Cols, Rows> &a, int)
10031
+{
10032
+    auto b = a;
10033
+    a += T(1);
10034
+    return b;
10035
+}
10036
+)",
10037
+                        addMatrixScalarAssign())
10038
+
10039
+PROGRAM_PRELUDE_DECLARE(preIncrementMatrix,
10040
+                        R"(
10041
+template <typename T, int Cols, int Rows>
10042
+ANGLE_ALWAYS_INLINE thread metal::matrix<T, Cols, Rows> &operator++(thread metal::matrix<T, Cols, Rows> &a)
10043
+{
10044
+    a += T(1);
10045
+    return a;
10046
+}
10047
+)",
10048
+                        addMatrixScalarAssign())
10049
+
10050
+PROGRAM_PRELUDE_DECLARE(postDecrementMatrix,
10051
+                        R"(
10052
+template <typename T, int Cols, int Rows>
10053
+ANGLE_ALWAYS_INLINE metal::matrix<T, Cols, Rows> operator--(thread metal::matrix<T, Cols, Rows> &a, int)
10054
+{
10055
+    auto b = a;
10056
+    a -= T(1);
10057
+    return b;
10058
+}
10059
+)",
10060
+                        subMatrixScalarAssign())
10061
+
10062
+PROGRAM_PRELUDE_DECLARE(preDecrementMatrix,
10063
+                        R"(
10064
+template <typename T, int Cols, int Rows>
10065
+ANGLE_ALWAYS_INLINE thread metal::matrix<T, Cols, Rows> &operator--(thread metal::matrix<T, Cols, Rows> &a)
10066
+{
10067
+    a -= T(1);
10068
+    return a;
10069
+}
10070
+)",
10071
+                        subMatrixScalarAssign())
10072
+
10073
+PROGRAM_PRELUDE_DECLARE(negateMatrix,
10074
+                        R"(
10075
+template <typename T, int Cols, int Rows>
10076
+ANGLE_ALWAYS_INLINE metal::matrix<T, Cols, Rows> operator-(metal::matrix<T, Cols, Rows> m)
10077
+{
10078
+    for (size_t col = 0; col < Cols; ++col)
10079
+    {
10080
+        thread auto &mCol = m[col];
10081
+        mCol = -mCol;
10082
+    }
10083
+    return m;
10084
+}
10085
+)", )
10086
+
10087
+PROGRAM_PRELUDE_DECLARE(addMatrixScalarAssign, R"(
10088
+template <typename T, int Cols, int Rows>
10089
+ANGLE_ALWAYS_INLINE thread metal::matrix<T, Cols, Rows> &operator+=(thread metal::matrix<T, Cols, Rows> &m, T x)
10090
+{
10091
+    for (size_t col = 0; col < Cols; ++col)
10092
+    {
10093
+        m[col] += x;
10094
+    }
10095
+    return m;
10096
+}
10097
+)")
10098
+
10099
+PROGRAM_PRELUDE_DECLARE(addMatrixScalar,
10100
+                        R"(
10101
+template <typename T, int Cols, int Rows>
10102
+ANGLE_ALWAYS_INLINE metal::matrix<T, Cols, Rows> operator+(metal::matrix<T, Cols, Rows> m, T x)
10103
+{
10104
+    m += x;
10105
+    return m;
10106
+}
10107
+)",
10108
+                        addMatrixScalarAssign())
10109
+
10110
+PROGRAM_PRELUDE_DECLARE(subMatrixScalarAssign,
10111
+                        R"(
10112
+template <typename T, int Cols, int Rows>
10113
+ANGLE_ALWAYS_INLINE thread metal::matrix<T, Cols, Rows> &operator-=(thread metal::matrix<T, Cols, Rows> &m, T x)
10114
+{
10115
+    for (size_t col = 0; col < Cols; ++col)
10116
+    {
10117
+        m[col] -= x;
10118
+    }
10119
+    return m;
10120
+}
10121
+)", )
10122
+
10123
+PROGRAM_PRELUDE_DECLARE(subMatrixScalar,
10124
+                        R"(
10125
+template <typename T, int Cols, int Rows>
10126
+ANGLE_ALWAYS_INLINE metal::matrix<T, Cols, Rows> operator-(metal::matrix<T, Cols, Rows> m, T x)
10127
+{
10128
+    m -= x;
10129
+    return m;
10130
+}
10131
+)",
10132
+                        subMatrixScalarAssign())
10133
+
10134
+PROGRAM_PRELUDE_DECLARE(divMatrixScalarAssignFast,
10135
+                        R"(
10136
+template <typename T, int Cols, int Rows>
10137
+ANGLE_ALWAYS_INLINE thread metal::matrix<T, Cols, Rows> &operator/=(thread metal::matrix<T, Cols, Rows> &m, T x)
10138
+{
10139
+    x = T(1) / x;
10140
+    for (size_t col = 0; col < Cols; ++col)
10141
+    {
10142
+        m[col] *= x;
10143
+    }
10144
+    return m;
10145
+}
10146
+)", )
10147
+
10148
+PROGRAM_PRELUDE_DECLARE(divMatrixScalarAssign,
10149
+                        R"(
10150
+template <typename T, int Cols, int Rows>
10151
+ANGLE_ALWAYS_INLINE thread metal::matrix<T, Cols, Rows> &operator/=(thread metal::matrix<T, Cols, Rows> &m, T x)
10152
+{
10153
+    for (size_t col = 0; col < Cols; ++col)
10154
+    {
10155
+        m[col] /= x;
10156
+    }
10157
+    return m;
10158
+}
10159
+)", )
10160
+
10161
+PROGRAM_PRELUDE_DECLARE(divMatrixScalarFast,
10162
+                        R"(
10163
+#if __METAL_VERSION__ <= 220
10164
+template <typename T, int Cols, int Rows>
10165
+ANGLE_ALWAYS_INLINE metal::matrix<T, Cols, Rows> operator/(metal::matrix<T, Cols, Rows> m, T x)
10166
+{
10167
+    m /= x;
10168
+    return m;
10169
+}
10170
+#endif
10171
+)",
10172
+                        divMatrixScalarAssignFast())
10173
+
10174
+PROGRAM_PRELUDE_DECLARE(divMatrixScalar,
10175
+                        R"(
10176
+#if __METAL_VERSION__ <= 220
10177
+template <typename T, int Cols, int Rows>
10178
+ANGLE_ALWAYS_INLINE metal::matrix<T, Cols, Rows> operator/(metal::matrix<T, Cols, Rows> m, T x)
10179
+{
10180
+    m /= x;
10181
+    return m;
10182
+}
10183
+#endif
10184
+)",
10185
+                        divMatrixScalarAssign())
10186
+
10187
+PROGRAM_PRELUDE_DECLARE(componentWiseDivide, R"(
10188
+template <typename T, int Cols, int Rows>
10189
+ANGLE_ALWAYS_INLINE metal::matrix<T, Cols, Rows> operator/(metal::matrix<T, Cols, Rows> a, metal::matrix<T, Cols, Rows> b)
10190
+{
10191
+    for (size_t col = 0; col < Cols; ++col)
10192
+    {
10193
+        a[col] /= b[col];
10194
+    }
10195
+    return a;
10196
+}
10197
+)")
10198
+
10199
+PROGRAM_PRELUDE_DECLARE(componentWiseDivideAssign,
10200
+                        R"(
10201
+template <typename T, int Cols, int Rows>
10202
+ANGLE_ALWAYS_INLINE thread metal::matrix<T, Cols, Rows> &operator/=(thread metal::matrix<T, Cols, Rows> &a, metal::matrix<T, Cols, Rows> b)
10203
+{
10204
+    a = a / b;
10205
+    return a;
10206
+}
10207
+)",
10208
+                        componentWiseDivide())
10209
+
10210
+PROGRAM_PRELUDE_DECLARE(componentWiseMultiply, R"(
10211
+template <typename T, int Cols, int Rows>
10212
+ANGLE_ALWAYS_INLINE metal::matrix<T, Cols, Rows> ANGLE_componentWiseMultiply(metal::matrix<T, Cols, Rows> a, metal::matrix<T, Cols, Rows> b)
10213
+{
10214
+    for (size_t col = 0; col < Cols; ++col)
10215
+    {
10216
+        a[col] *= b[col];
10217
+    }
10218
+    return a;
10219
+}
10220
+)")
10221
+
10222
+PROGRAM_PRELUDE_DECLARE(outerProduct, R"(
10223
+template <typename T, int M, int N>
10224
+ANGLE_ALWAYS_INLINE metal::matrix<T, N, M> ANGLE_outerProduct(metal::vec<T, M> u, metal::vec<T, N> v)
10225
+{
10226
+    metal::matrix<T, N, M> o;
10227
+    for (size_t n = 0; n < N; ++n)
10228
+    {
10229
+        o[n] = u * v[n];
10230
+    }
10231
+    return o;
10232
+}
10233
+)")
10234
+
10235
+PROGRAM_PRELUDE_DECLARE(inverse2, R"(
10236
+template <typename T>
10237
+ANGLE_ALWAYS_INLINE metal::matrix<T, 2, 2> ANGLE_inverse(metal::matrix<T, 2, 2> m)
10238
+{
10239
+    metal::matrix<T, 2, 2> adj;
10240
+    adj[0][0] =  m[1][1];
10241
+    adj[0][1] = -m[0][1];
10242
+    adj[1][0] = -m[1][0];
10243
+    adj[1][1] =  m[0][0];
10244
+    T det = (adj[0][0] * m[0][0]) + (adj[0][1] * m[1][0]);
10245
+    return adj * (T(1) / det);
10246
+}
10247
+)")
10248
+
10249
+PROGRAM_PRELUDE_DECLARE(inverse3, R"(
10250
+template <typename T>
10251
+ANGLE_ALWAYS_INLINE metal::matrix<T, 3, 3> ANGLE_inverse(metal::matrix<T, 3, 3> m)
10252
+{
10253
+    T a = m[1][1] * m[2][2] - m[2][1] * m[1][2];
10254
+    T b = m[1][0] * m[2][2];
10255
+    T c = m[1][2] * m[2][0];
10256
+    T d = m[1][0] * m[2][1];
10257
+    T det = m[0][0] * (a) -
10258
+            m[0][1] * (b - c) +
10259
+            m[0][2] * (d - m[1][1] * m[2][0]);
10260
+    det = T(1) / det;
10261
+    metal::matrix<T, 3, 3> minv;
10262
+    minv[0][0] = (a) * det;
10263
+    minv[0][1] = (m[0][2] * m[2][1] - m[0][1] * m[2][2]) * det;
10264
+    minv[0][2] = (m[0][1] * m[1][2] - m[0][2] * m[1][1]) * det;
10265
+    minv[1][0] = (c - b) * det;
10266
+    minv[1][1] = (m[0][0] * m[2][2] - m[0][2] * m[2][0]) * det;
10267
+    minv[1][2] = (m[1][0] * m[0][2] - m[0][0] * m[1][2]) * det;
10268
+    minv[2][0] = (d - m[2][0] * m[1][1]) * det;
10269
+    minv[2][1] = (m[2][0] * m[0][1] - m[0][0] * m[2][1]) * det;
10270
+    minv[2][2] = (m[0][0] * m[1][1] - m[1][0] * m[0][1]) * det;
10271
+    return minv;
10272
+}
10273
+)")
10274
+
10275
+PROGRAM_PRELUDE_DECLARE(inverse4, R"(
10276
+template <typename T>
10277
+ANGLE_ALWAYS_INLINE metal::matrix<T, 4, 4> ANGLE_inverse(metal::matrix<T, 4, 4> m)
10278
+{
10279
+    T A2323 = m[2][2] * m[3][3] - m[2][3] * m[3][2];
10280
+    T A1323 = m[2][1] * m[3][3] - m[2][3] * m[3][1];
10281
+    T A1223 = m[2][1] * m[3][2] - m[2][2] * m[3][1];
10282
+    T A0323 = m[2][0] * m[3][3] - m[2][3] * m[3][0];
10283
+    T A0223 = m[2][0] * m[3][2] - m[2][2] * m[3][0];
10284
+    T A0123 = m[2][0] * m[3][1] - m[2][1] * m[3][0];
10285
+    T A2313 = m[1][2] * m[3][3] - m[1][3] * m[3][2];
10286
+    T A1313 = m[1][1] * m[3][3] - m[1][3] * m[3][1];
10287
+    T A1213 = m[1][1] * m[3][2] - m[1][2] * m[3][1];
10288
+    T A2312 = m[1][2] * m[2][3] - m[1][3] * m[2][2];
10289
+    T A1312 = m[1][1] * m[2][3] - m[1][3] * m[2][1];
10290
+    T A1212 = m[1][1] * m[2][2] - m[1][2] * m[2][1];
10291
+    T A0313 = m[1][0] * m[3][3] - m[1][3] * m[3][0];
10292
+    T A0213 = m[1][0] * m[3][2] - m[1][2] * m[3][0];
10293
+    T A0312 = m[1][0] * m[2][3] - m[1][3] * m[2][0];
10294
+    T A0212 = m[1][0] * m[2][2] - m[1][2] * m[2][0];
10295
+    T A0113 = m[1][0] * m[3][1] - m[1][1] * m[3][0];
10296
+    T A0112 = m[1][0] * m[2][1] - m[1][1] * m[2][0];
10297
+    T a = m[1][1] * A2323 - m[1][2] * A1323 + m[1][3] * A1223;
10298
+    T b = m[1][0] * A2323 - m[1][2] * A0323 + m[1][3] * A0223;
10299
+    T c = m[1][0] * A1323 - m[1][1] * A0323 + m[1][3] * A0123;
10300
+    T d = m[1][0] * A1223 - m[1][1] * A0223 + m[1][2] * A0123;
10301
+    T det = m[0][0] * ( a )
10302
+          - m[0][1] * ( b )
10303
+          + m[0][2] * ( c )
10304
+          - m[0][3] * ( d );
10305
+    det = T(1) / det;
10306
+    metal::matrix<T, 4, 4> im;
10307
+    im[0][0] = det *   ( a );
10308
+    im[0][1] = det * - ( m[0][1] * A2323 - m[0][2] * A1323 + m[0][3] * A1223 );
10309
+    im[0][2] = det *   ( m[0][1] * A2313 - m[0][2] * A1313 + m[0][3] * A1213 );
10310
+    im[0][3] = det * - ( m[0][1] * A2312 - m[0][2] * A1312 + m[0][3] * A1212 );
10311
+    im[1][0] = det * - ( b );
10312
+    im[1][1] = det *   ( m[0][0] * A2323 - m[0][2] * A0323 + m[0][3] * A0223 );
10313
+    im[1][2] = det * - ( m[0][0] * A2313 - m[0][2] * A0313 + m[0][3] * A0213 );
10314
+    im[1][3] = det *   ( m[0][0] * A2312 - m[0][2] * A0312 + m[0][3] * A0212 );
10315
+    im[2][0] = det *   ( c );
10316
+    im[2][1] = det * - ( m[0][0] * A1323 - m[0][1] * A0323 + m[0][3] * A0123 );
10317
+    im[2][2] = det *   ( m[0][0] * A1313 - m[0][1] * A0313 + m[0][3] * A0113 );
10318
+    im[2][3] = det * - ( m[0][0] * A1312 - m[0][1] * A0312 + m[0][3] * A0112 );
10319
+    im[3][0] = det * - ( d );
10320
+    im[3][1] = det *   ( m[0][0] * A1223 - m[0][1] * A0223 + m[0][2] * A0123 );
10321
+    im[3][2] = det * - ( m[0][0] * A1213 - m[0][1] * A0213 + m[0][2] * A0113 );
10322
+    im[3][3] = det *   ( m[0][0] * A1212 - m[0][1] * A0212 + m[0][2] * A0112 );
10323
+    return im;
10324
+}
10325
+)")
10326
+
10327
+PROGRAM_PRELUDE_DECLARE(equalArray,
10328
+                        R"(
10329
+template <typename T, size_t N>
10330
+ANGLE_ALWAYS_INLINE bool ANGLE_equal(metal::array<T, N> u, metal::array<T, N> v)
10331
+{
10332
+    for(size_t i = 0; i < N; i++)
10333
+        if (u[i] != v[i]) return false;
10334
+    return true;
10335
+}
10336
+)")
10337
+
10338
+PROGRAM_PRELUDE_DECLARE(notEqualArray,
10339
+                        R"(
10340
+template <typename T, size_t N>
10341
+ANGLE_ALWAYS_INLINE bool ANGLE_notEqual(metal::array<T, N> u, metal::array<T, N> v)
10342
+{
10343
+    return !ANGLE_equal(u,v);
10344
+}
10345
+)",
10346
+                        equalArray())
10347
+
10348
+PROGRAM_PRELUDE_DECLARE(equalVector,
10349
+                        R"(
10350
+template <typename T, int N>
10351
+ANGLE_ALWAYS_INLINE bool ANGLE_equal(metal::vec<T, N> u, metal::vec<T, N> v)
10352
+{
10353
+    return metal::all(u == v);
10354
+}
10355
+)",
10356
+                        include_metal_math())
10357
+
10358
+PROGRAM_PRELUDE_DECLARE(equalMatrix,
10359
+                        R"(
10360
+template <typename T, int C, int R>
10361
+ANGLE_ALWAYS_INLINE bool ANGLE_equal(metal::matrix<T, C, R> a, metal::matrix<T, C, R> b)
10362
+{
10363
+    for (int c = 0; c < C; ++c)
10364
+    {
10365
+        if (!ANGLE_equal(a[c], b[c]))
10366
+        {
10367
+            return false;
10368
+        }
10369
+    }
10370
+    return true;
10371
+}
10372
+)",
10373
+                        equalVector())
10374
+
10375
+PROGRAM_PRELUDE_DECLARE(notEqualVector,
10376
+                        R"(
10377
+template <typename T, int N>
10378
+ANGLE_ALWAYS_INLINE bool ANGLE_notEqual(metal::vec<T, N> u, metal::vec<T, N> v)
10379
+{
10380
+    return !ANGLE_equal(u, v);
10381
+}
10382
+)",
10383
+                        equalVector())
10384
+
10385
+PROGRAM_PRELUDE_DECLARE(notEqualStruct,
10386
+                        R"(
10387
+template <typename T>
10388
+ANGLE_ALWAYS_INLINE bool ANGLE_notEqualStruct(thread const T &a, thread const T &b)
10389
+{
10390
+    return !ANGLE_equal(a, b);
10391
+}
10392
+)",
10393
+                        equalVector(),
10394
+                        equalMatrix())
10395
+
10396
+PROGRAM_PRELUDE_DECLARE(vectorElemRef, R"(
10397
+template <typename T, int N>
10398
+struct ANGLE_VectorElemRef
10399
+{
10400
+    thread metal::vec<T, N> &mVec;
10401
+    T mRef;
10402
+    const int mIndex;
10403
+    ~ANGLE_VectorElemRef() { mVec[mIndex] = mRef; }
10404
+    ANGLE_VectorElemRef(thread metal::vec<T, N> &vec, int index)
10405
+        : mVec(vec), mRef(vec[index]), mIndex(index)
10406
+    {}
10407
+    operator thread T &() { return mRef; }
10408
+};
10409
+template <typename T, int N>
10410
+ANGLE_ALWAYS_INLINE ANGLE_VectorElemRef<T, N> ANGLE_elem_ref(thread metal::vec<T, N> &vec, int index)
10411
+{
10412
+    return ANGLE_VectorElemRef<T, N>(vec, index);
10413
+}
10414
+)")
10415
+
10416
+PROGRAM_PRELUDE_DECLARE(swizzleRef,
10417
+                        R"(
10418
+template <typename T, int VN, int SN>
10419
+struct ANGLE_SwizzleRef
10420
+{
10421
+    thread metal::vec<T, VN> &mVec;
10422
+    metal::vec<T, SN> mRef;
10423
+    int mIndices[SN];
10424
+    ~ANGLE_SwizzleRef()
10425
+    {
10426
+        for (int i = 0; i < SN; ++i)
10427
+        {
10428
+            const int j = mIndices[i];
10429
+            mVec[j] = mRef[i];
10430
+        }
10431
+    }
10432
+    ANGLE_SwizzleRef(thread metal::vec<T, N> &vec, thread const int *indices)
10433
+        : mVec(vec)
10434
+    {
10435
+        for (int i = 0; i < SN; ++i)
10436
+        {
10437
+            const int j = indices[i];
10438
+            mIndices[i] = j;
10439
+            mRef[i] = mVec[j];
10440
+        }
10441
+    }
10442
+    operator thread metal::vec<T, SN> &() { return mRef; }
10443
+};
10444
+template <typename T, int N>
10445
+ANGLE_ALWAYS_INLINE ANGLE_VectorElemRef<T, N> ANGLE_swizzle_ref(thread metal::vec<T, N> &vec, int i0)
10446
+{
10447
+    return ANGLE_VectorElemRef<T, N>(vec, index);
10448
+}
10449
+template <typename T, int N>
10450
+ANGLE_ALWAYS_INLINE ANGLE_SwizzleRef<T, N, 2> ANGLE_swizzle_ref(thread metal::vec<T, N> &vec, int i0, int i1)
10451
+{
10452
+    const int is[] = { i0, i1 };
10453
+    return ANGLE_SwizzleRef<T, N, 2>(vec, is);
10454
+}
10455
+template <typename T, int N>
10456
+ANGLE_ALWAYS_INLINE ANGLE_SwizzleRef<T, N, 3> ANGLE_swizzle_ref(thread metal::vec<T, N> &vec, int i0, int i1, int i2)
10457
+{
10458
+    const int is[] = { i0, i1, i2 };
10459
+    return ANGLE_SwizzleRef<T, N, 3>(vec, is);
10460
+}
10461
+template <typename T, int N>
10462
+ANGLE_ALWAYS_INLINE ANGLE_SwizzleRef<T, N, 4> ANGLE_swizzle_ref(thread metal::vec<T, N> &vec, int i0, int i1, int i2, int i3)
10463
+{
10464
+    const int is[] = { i0, i1, i2, i3 };
10465
+    return ANGLE_SwizzleRef<T, N, 4>(vec, is);
10466
+}
10467
+)",
10468
+                        vectorElemRef())
10469
+
10470
+PROGRAM_PRELUDE_DECLARE(out, R"(
10471
+template <typename T>
10472
+struct ANGLE_Out
10473
+{
10474
+    T mTemp;
10475
+    thread T &mDest;
10476
+    ~ANGLE_Out() { mDest = mTemp; }
10477
+    ANGLE_Out(thread T &dest)
10478
+        : mDest(dest)
10479
+    {}
10480
+    operator thread T &() { return mTemp; }
10481
+};
10482
+template <typename T>
10483
+ANGLE_ALWAYS_INLINE ANGLE_Out<T> ANGLE_out(thread T &dest)
10484
+{
10485
+    return ANGLE_Out<T>(dest);
10486
+}
10487
+)")
10488
+
10489
+PROGRAM_PRELUDE_DECLARE(inout, R"(
10490
+template <typename T>
10491
+struct ANGLE_InOut
10492
+{
10493
+    T mTemp;
10494
+    thread T &mDest;
10495
+    ~ANGLE_InOut() { mDest = mTemp; }
10496
+    ANGLE_InOut(thread T &dest)
10497
+        : mTemp(dest), mDest(dest)
10498
+    {}
10499
+    operator thread T &() { return mTemp; }
10500
+};
10501
+template <typename T>
10502
+ANGLE_ALWAYS_INLINE ANGLE_InOut<T> ANGLE_inout(thread T &dest)
10503
+{
10504
+    return ANGLE_InOut<T>(dest);
10505
+}
10506
+)")
10507
+
10508
+PROGRAM_PRELUDE_DECLARE(flattenArray, R"(
10509
+template <typename T>
10510
+struct ANGLE_flatten_impl
10511
+{
10512
+    static ANGLE_ALWAYS_INLINE thread T *exec(thread T &x)
10513
+    {
10514
+        return &x;
10515
+    }
10516
+};
10517
+template <typename T, size_t N>
10518
+struct ANGLE_flatten_impl<metal::array<T, N>>
10519
+{
10520
+    static ANGLE_ALWAYS_INLINE auto exec(thread metal::array<T, N> &arr) -> T
10521
+    {
10522
+        return ANGLE_flatten_impl<T>::exec(arr[0]);
10523
+    }
10524
+};
10525
+template <typename T, size_t N>
10526
+ANGLE_ALWAYS_INLINE auto ANGLE_flatten(thread metal::array<T, N> &arr) -> T
10527
+{
10528
+    return ANGLE_flatten_impl<T>::exec(arr[0]);
10529
+}
10530
+)")
10531
+
10532
+PROGRAM_PRELUDE_DECLARE(castVector, R"(
10533
+template <typename T, int N1, int N2>
10534
+struct ANGLE_castVector {};
10535
+template <typename T, int N>
10536
+struct ANGLE_castVector<T, N, N>
10537
+{
10538
+    static ANGLE_ALWAYS_INLINE metal::vec<T, N> exec(thread metal::vec<T, N> const &v)
10539
+    {
10540
+        return v;
10541
+    }
10542
+};
10543
+template <typename T>
10544
+struct ANGLE_castVector<T, 2, 3>
10545
+{
10546
+    static ANGLE_ALWAYS_INLINE metal::vec<T, 2> exec(thread metal::vec<T, 3> const &v)
10547
+    {
10548
+        return v.xy;
10549
+    }
10550
+};
10551
+template <typename T>
10552
+struct ANGLE_castVector<T, 2, 4>
10553
+{
10554
+    static ANGLE_ALWAYS_INLINE metal::vec<T, 2> exec(thread metal::vec<T, 4> const &v)
10555
+    {
10556
+        return v.xy;
10557
+    }
10558
+};
10559
+template <typename T>
10560
+struct ANGLE_castVector<T, 3, 4>
10561
+{
10562
+    static ANGLE_ALWAYS_INLINE metal::vec<T, 3> exec(thread metal::vec<T, 4> const &v)
10563
+    {
10564
+        return as_type<metal::vec<T, 3>>(v);
10565
+    }
10566
+};
10567
+template <int N1, int N2, typename T>
10568
+ANGLE_ALWAYS_INLINE metal::vec<T, N1> ANGLE_cast(thread metal::vec<T, N2> const &v)
10569
+{
10570
+    return ANGLE_castVector<T, N1, N2>::exec(v);
10571
+}
10572
+)")
10573
+
10574
+PROGRAM_PRELUDE_DECLARE(castMatrix,
10575
+                        R"(
10576
+template <typename T, int C1, int R1, int C2, int R2, typename Enable = void>
10577
+struct ANGLE_castMatrix
10578
+{
10579
+    static ANGLE_ALWAYS_INLINE metal::matrix<T, C1, R1> exec(thread metal::matrix<T, C2, R2> const &m2)
10580
+    {
10581
+        metal::matrix<T, C1, R1> m1;
10582
+        const int MinC = C1 <= C2 ? C1 : C2;
10583
+        const int MinR = R1 <= R2 ? R1 : R2;
10584
+        for (int c = 0; c < MinC; ++c)
10585
+        {
10586
+            for (int r = 0; r < MinR; ++r)
10587
+            {
10588
+                m1[c][r] = m2[c][r];
10589
+            }
10590
+            for (int r = R2; r < R1; ++r)
10591
+            {
10592
+                m1[c][r] = c == r ? T(1) : T(0);
10593
+            }
10594
+        }
10595
+        for (int c = C2; c < C1; ++c)
10596
+        {
10597
+            for (int r = 0; r < R1; ++r)
10598
+            {
10599
+                m1[c][r] = c == r ? T(1) : T(0);
10600
+            }
10601
+        }
10602
+        return m1;
10603
+    }
10604
+};
10605
+template <typename T, int C1, int R1, int C2, int R2>
10606
+struct ANGLE_castMatrix<T, C1, R1, C2, R2, ANGLE_enable_if_t<(C1 <= C2 && R1 <= R2)>>
10607
+{
10608
+    static ANGLE_ALWAYS_INLINE metal::matrix<T, C1, R1> exec(thread metal::matrix<T, C2, R2> const &m2)
10609
+    {
10610
+        metal::matrix<T, C1, R1> m1;
10611
+        for (size_t c = 0; c < C1; ++c)
10612
+        {
10613
+            m1[c] = ANGLE_cast<R1>(m2[c]);
10614
+        }
10615
+        return m1;
10616
+    }
10617
+};
10618
+template <int C1, int R1, int C2, int R2, typename T>
10619
+ANGLE_ALWAYS_INLINE metal::matrix<T, C1, R1> ANGLE_cast(thread metal::matrix<T, C2, R2> const &m)
10620
+{
10621
+    return ANGLE_castMatrix<T, C1, R1, C2, R2>::exec(m);
10622
+};
10623
+)",
10624
+                        enable_if(),
10625
+                        castVector())
10626
+
10627
+PROGRAM_PRELUDE_DECLARE(tensor, R"(
10628
+template <typename T, size_t... DS>
10629
+struct ANGLE_tensor_traits;
10630
+template <typename T, size_t D>
10631
+struct ANGLE_tensor_traits<T, D>
10632
+{
10633
+    enum : size_t { outer_dim = D };
10634
+    using inner_type = T;
10635
+    using outer_type = inner_type[D];
10636
+};
10637
+template <typename T, size_t D, size_t... DS>
10638
+struct ANGLE_tensor_traits<T, D, DS...>
10639
+{
10640
+    enum : size_t { outer_dim = D };
10641
+    using inner_type = typename ANGLE_tensor_traits<T, DS...>::outer_type;
10642
+    using outer_type = inner_type[D];
10643
+};
10644
+template <size_t D, typename value_type_, typename inner_type_>
10645
+struct ANGLE_tensor_impl
10646
+{
10647
+    enum : size_t { outer_dim = D };
10648
+    using value_type = value_type_;
10649
+    using inner_type = inner_type_;
10650
+    using outer_type = inner_type[D];
10651
+    outer_type _data;
10652
+    ANGLE_ALWAYS_INLINE size_t size() const { return outer_dim; }
10653
+    ANGLE_ALWAYS_INLINE inner_type &operator[](size_t i) { return _data[i]; }
10654
+    ANGLE_ALWAYS_INLINE const inner_type &operator[](size_t i) const { return _data[i]; }
10655
+};
10656
+template <typename T, size_t... DS>
10657
+using ANGLE_tensor = ANGLE_tensor_impl<
10658
+    ANGLE_tensor_traits<T, DS...>::outer_dim,
10659
+    T,
10660
+    typename ANGLE_tensor_traits<T, DS...>::inner_type>;
10661
+)")
10662
+
10663
+PROGRAM_PRELUDE_DECLARE(gradient,
10664
+                        R"(
10665
+template <int N>
10666
+struct ANGLE_gradient_traits;
10667
+template <>
10668
+struct ANGLE_gradient_traits<2> { using type = metal::gradient2d; };
10669
+template <>
10670
+struct ANGLE_gradient_traits<3> { using type = metal::gradient3d; };
10671
+
10672
+template <int N>
10673
+using ANGLE_gradient = typename ANGLE_gradient_traits<N>::type;
10674
+)")
10675
+
10676
+PROGRAM_PRELUDE_DECLARE(textureEnv,
10677
+                        R"(
10678
+template <typename T>
10679
+struct ANGLE_TextureEnv
10680
+{
10681
+    thread T *texture;
10682
+    thread metal::sampler *sampler;
10683
+};
10684
+)")
10685
+
10686
+PROGRAM_PRELUDE_DECLARE(functionConstants,
10687
+                        R"(
10688
+#define ANGLE_SAMPLE_COMPARE_GRADIENT_INDEX 0
10689
+#define ANGLE_SAMPLE_COMPARE_LOD_INDEX      1
10690
+#define ANGLE_RASTERIZATION_DISCARD_INDEX   2
10691
+
10692
+constant bool ANGLE_UseSampleCompareGradient [[function_constant(ANGLE_SAMPLE_COMPARE_GRADIENT_INDEX)]];
10693
+constant bool ANGLE_UseSampleCompareLod      [[function_constant(ANGLE_SAMPLE_COMPARE_LOD_INDEX)]];
10694
+constant bool ANGLE_RasterizationDiscard     [[function_constant(ANGLE_RASTERIZATION_DISCARD_INDEX)]];
10695
+)")
10696
+
10697
+PROGRAM_PRELUDE_DECLARE(texelFetch,
10698
+                        R"(
10699
+#define ANGLE_texelFetch(env, ...) ANGLE_texelFetch_impl(*env.texture, __VA_ARGS__)
10700
+
10701
+template <typename Texture>
10702
+ANGLE_ALWAYS_INLINE auto ANGLE_texelFetch_impl(
10703
+    thread Texture &texture,
10704
+    thread metal::int2 const &coord,
10705
+    uint level)
10706
+{
10707
+    return texture.read(uint2(coord), level);
10708
+}
10709
+
10710
+template <typename Texture>
10711
+ANGLE_ALWAYS_INLINE auto ANGLE_texelFetch_impl(
10712
+    thread Texture &texture,
10713
+    thread metal::int3 const &coord,
10714
+    uint level)
10715
+{
10716
+    return texture.read(uint3(coord), level);
10717
+}
10718
+
10719
+template <typename T>
10720
+ANGLE_ALWAYS_INLINE auto ANGLE_texelFetch_impl(
10721
+    thread metal::texture2d_array<T> &texture,
10722
+    thread metal::int3 const &coord,
10723
+    uint level)
10724
+{
10725
+    return texture.read(uint2(coord.xy), uint(coord.z), level);
10726
+}
10727
+)",
10728
+                        textureEnv())
10729
+
10730
+PROGRAM_PRELUDE_DECLARE(texelFetchOffset,
10731
+                        R"(
10732
+#define ANGLE_texelFetchOffset(env, ...) ANGLE_texelFetchOffset_impl(*env.texture, __VA_ARGS__)
10733
+
10734
+template <typename Texture>
10735
+ANGLE_ALWAYS_INLINE auto ANGLE_texelFetchOffset_impl(
10736
+    thread Texture &texture,
10737
+    thread metal::int2 const &coord,
10738
+    uint level,
10739
+    thread metal::int2 const &offset)
10740
+{
10741
+    return texture.read(uint2(coord + offset), level);
10742
+}
10743
+
10744
+template <typename Texture>
10745
+ANGLE_ALWAYS_INLINE auto ANGLE_texelFetchOffset_impl(
10746
+    thread Texture &texture,
10747
+    thread metal::int3 const &coord,
10748
+    uint level,
10749
+    thread metal::int3 const &offset)
10750
+{
10751
+    return texture.read(uint3(coord + offset), level);
10752
+}
10753
+
10754
+template <typename T>
10755
+ANGLE_ALWAYS_INLINE auto ANGLE_texelFetchOffset_impl(
10756
+    thread metal::texture2d_array<T> &texture,
10757
+    thread metal::int3 const &coord,
10758
+    uint level,
10759
+    thread metal::int2 const &offset)
10760
+{
10761
+    return texture.read(uint2(coord.xy + offset), uint(coord.z), level);
10762
+}
10763
+)",
10764
+                        textureEnv())
10765
+
10766
+PROGRAM_PRELUDE_DECLARE(texture,
10767
+                        R"(
10768
+#define ANGLE_texture(env, ...) ANGLE_texture_impl(*env.texture, *env.sampler, __VA_ARGS__)
10769
+)",
10770
+                        textureEnv())
10771
+
10772
+PROGRAM_PRELUDE_DECLARE(texture_generic_float2,
10773
+                        R"(
10774
+template <typename Texture>
10775
+ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
10776
+    thread Texture &texture,
10777
+    thread metal::sampler const &sampler,
10778
+    thread metal::float2 const &coord)
10779
+{
10780
+    return texture.sample(sampler, coord);
10781
+}
10782
+)",
10783
+                        texture())
10784
+
10785
+PROGRAM_PRELUDE_DECLARE(texture_generic_float2_float,
10786
+                        R"(
10787
+template <typename Texture>
10788
+ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
10789
+    thread Texture &texture,
10790
+    thread metal::sampler const &sampler,
10791
+    thread metal::float2 const &coord,
10792
+    float bias)
10793
+{
10794
+    return texture.sample(sampler, coord, metal::bias(bias));
10795
+}
10796
+)",
10797
+                        texture())
10798
+
10799
+PROGRAM_PRELUDE_DECLARE(texture_generic_float3,
10800
+                        R"(
10801
+template <typename Texture>
10802
+ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
10803
+    thread Texture &texture,
10804
+    thread metal::sampler const &sampler,
10805
+    thread metal::float3 const &coord)
10806
+{
10807
+    return texture.sample(sampler, coord);
10808
+}
10809
+)",
10810
+                        texture())
10811
+
10812
+PROGRAM_PRELUDE_DECLARE(texture_generic_float3_float,
10813
+                        R"(
10814
+template <typename Texture>
10815
+ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
10816
+    thread Texture &texture,
10817
+    thread metal::sampler const &sampler,
10818
+    thread metal::float3 const &coord,
10819
+    float bias)
10820
+{
10821
+    return texture.sample(sampler, coord, metal::bias(bias));
10822
+}
10823
+)",
10824
+                        texture())
10825
+
10826
+PROGRAM_PRELUDE_DECLARE(texture_depth2d_float3,
10827
+                        R"(
10828
+template <typename T>
10829
+ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
10830
+    thread metal::depth2d<T> &texture,
10831
+    thread metal::sampler const &sampler,
10832
+    thread metal::float3 const &coord)
10833
+{
10834
+    return texture.sample(sampler, coord.xy);
10835
+}
10836
+)",
10837
+                        texture())
10838
+
10839
+PROGRAM_PRELUDE_DECLARE(texture_depth2d_float3_float,
10840
+                        R"(
10841
+template <typename T>
10842
+ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
10843
+    thread metal::depth2d<T> &texture,
10844
+    thread metal::sampler const &sampler,
10845
+    thread metal::float3 const &coord,
10846
+    float bias)
10847
+{
10848
+    return texture.sample(sampler, coord.xy, metal::bias(bias));
10849
+}
10850
+)",
10851
+                        texture())
10852
+
10853
+PROGRAM_PRELUDE_DECLARE(texture_depth2darray_float4,
10854
+                        R"(
10855
+template <typename T>
10856
+ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
10857
+    thread metal::depth2d_array<T> &texture,
10858
+    thread metal::sampler const &sampler,
10859
+    thread metal::float4 const &coord)
10860
+{
10861
+    return texture.sample_compare(sampler, coord.xy, uint(metal::round(coord.z)), coord.w);
10862
+}
10863
+)",
10864
+                        texture())
10865
+
10866
+PROGRAM_PRELUDE_DECLARE(texture_depth2darray_float4_float,
10867
+                        R"(
10868
+template <typename T>
10869
+ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
10870
+    thread metal::depth2d_array<T> &texture,
10871
+    thread metal::sampler const &sampler,
10872
+    thread metal::float4 const &coord,
10873
+    float compare)
10874
+{
10875
+    return texture.sample_compare(sampler, coord.xyz, uint(metal::round(coord.w)), compare);
10876
+}
10877
+)",
10878
+                        texture())
10879
+
10880
+PROGRAM_PRELUDE_DECLARE(texture_depthcube_float4,
10881
+                        R"(
10882
+template <typename T>
10883
+ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
10884
+    thread metal::depthcube<T> &texture,
10885
+    thread metal::sampler const &sampler,
10886
+    thread metal::float4 const &coord)
10887
+{
10888
+    return texture.sample(sampler, coord.xyz);
10889
+}
10890
+)",
10891
+                        texture())
10892
+
10893
+PROGRAM_PRELUDE_DECLARE(texture_depthcube_float4_float,
10894
+                        R"(
10895
+template <typename T>
10896
+ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
10897
+    thread metal::depthcube<T> &texture,
10898
+    thread metal::sampler const &sampler,
10899
+    thread metal::float4 const &coord,
10900
+    float bias)
10901
+{
10902
+    return texture.sample(sampler, coord.xyz, metal::bias(bias));
10903
+}
10904
+)",
10905
+                        texture())
10906
+
10907
+PROGRAM_PRELUDE_DECLARE(texture_texture2darray_float3,
10908
+                        R"(
10909
+template <typename T>
10910
+ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
10911
+    thread metal::texture2d_array<T> &texture,
10912
+    thread metal::sampler const &sampler,
10913
+    thread metal::float3 const &coord)
10914
+{
10915
+    return texture.sample(sampler, coord.xy, uint(metal::round(coord.z)));
10916
+}
10917
+)",
10918
+                        texture())
10919
+
10920
+PROGRAM_PRELUDE_DECLARE(texture_texture2darray_float3_float,
10921
+                        R"(
10922
+template <typename T>
10923
+ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
10924
+    thread metal::texture2d_array<T> &texture,
10925
+    thread metal::sampler const &sampler,
10926
+    thread metal::float3 const &coord,
10927
+    float bias)
10928
+{
10929
+    return texture.sample(sampler, coord.xy, uint(metal::round(coord.z)), metal::bias(bias));
10930
+}
10931
+)",
10932
+                        texture())
10933
+
10934
+PROGRAM_PRELUDE_DECLARE(texture_texture2darray_float4,
10935
+                        R"(
10936
+template <typename T>
10937
+ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
10938
+    thread metal::texture2d_array<T> &texture,
10939
+    thread metal::sampler const &sampler,
10940
+    thread metal::float4 const &coord)
10941
+{
10942
+    return texture.sample(sampler, coord.xyz, uint(metal::round(coord.w)));
10943
+}
10944
+)",
10945
+                        texture())
10946
+
10947
+PROGRAM_PRELUDE_DECLARE(texture_texture2darray_float4_float,
10948
+                        R"(
10949
+template <typename T>
10950
+ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
10951
+    thread metal::texture2d_array<T> &texture,
10952
+    thread metal::sampler const &sampler,
10953
+    thread metal::float4 const &coord,
10954
+    float bias)
10955
+{
10956
+    return texture.sample(sampler, coord.xyz, uint(metal::round(coord.w)), metal::bias(bias));
10957
+}
10958
+)",
10959
+                        texture())
10960
+
10961
+PROGRAM_PRELUDE_DECLARE(texture1DLod,
10962
+                        R"(
10963
+#define ANGLE_texture1DLod(env, ...) ANGLE_texture1DLod_impl(*env.texture, *env.sampler, __VA_ARGS__)
10964
+
10965
+template <typename Texture>
10966
+ANGLE_ALWAYS_INLINE auto ANGLE_texture1DLod_impl(
10967
+    thread Texture &texture,
10968
+    thread metal::sampler const &sampler,
10969
+    thread float const &coord,
10970
+    float level)
10971
+{
10972
+    return texture.sample(sampler, coord, metal::level(level));
10973
+}
10974
+)",
10975
+                        textureEnv())
10976
+
10977
+PROGRAM_PRELUDE_DECLARE(texture1DProj,
10978
+                        R"(
10979
+#define ANGLE_texture1DProj(env, ...) ANGLE_texture1DProj_impl(*env.texture, *env.sampler, __VA_ARGS__)
10980
+
10981
+template <typename Texture>
10982
+ANGLE_ALWAYS_INLINE auto ANGLE_texture1DProj_impl(
10983
+    thread Texture &texture,
10984
+    thread metal::sampler const &sampler,
10985
+    thread metal::float2 const &coord,
10986
+    float bias = 0)
10987
+{
10988
+    return texture.sample(sampler, coord.x/coord.y, metal::bias(bias));
10989
+}
10990
+
10991
+template <typename Texture>
10992
+ANGLE_ALWAYS_INLINE auto ANGLE_texture1DProj_impl(
10993
+    thread Texture &texture,
10994
+    thread metal::sampler const &sampler,
10995
+    thread metal::float4 const &coord,
10996
+    float bias = 0)
10997
+{
10998
+    return texture.sample(sampler, coord.x/coord.w, metal::bias(bias));
10999
+}
11000
+)",
11001
+                        textureEnv())
11002
+
11003
+PROGRAM_PRELUDE_DECLARE(texture1DProjLod,
11004
+                        R"(
11005
+#define ANGLE_texture1DProjLod(env, ...) ANGLE_texture1DProjLod_impl(*env.texture, *env.sampler, __VA_ARGS__)
11006
+
11007
+template <typename Texture>
11008
+ANGLE_ALWAYS_INLINE auto ANGLE_texture1DProjLod_impl(
11009
+    thread Texture &texture,
11010
+    thread metal::sampler const &sampler,
11011
+    thread metal::float2 const &coord,
11012
+    float level)
11013
+{
11014
+    return texture.sample(sampler, coord.x/coord.y, metal::level(level));
11015
+}
11016
+
11017
+template <typename Texture>
11018
+ANGLE_ALWAYS_INLINE auto ANGLE_texture1DProjLod_impl(
11019
+    thread Texture &texture,
11020
+    thread metal::sampler const &sampler,
11021
+    thread metal::float4 const &coord,
11022
+    float level)
11023
+{
11024
+    return texture.sample(sampler, coord.x/coord.w, metal::level(level));
11025
+}
11026
+)",
11027
+                        textureEnv())
11028
+
11029
+PROGRAM_PRELUDE_DECLARE(texture2D,
11030
+                        R"(
11031
+#define ANGLE_texture2D(env, ...) ANGLE_texture2D_impl(*env.texture, *env.sampler, __VA_ARGS__)
11032
+
11033
+template <typename Texture>
11034
+ANGLE_ALWAYS_INLINE auto ANGLE_texture2D_impl(
11035
+    thread Texture &texture,
11036
+    thread metal::sampler const &sampler,
11037
+    thread metal::float2 const &coord)
11038
+{
11039
+    return texture.sample(sampler, coord);
11040
+}
11041
+
11042
+template <typename Texture>
11043
+ANGLE_ALWAYS_INLINE auto ANGLE_texture2D_impl(
11044
+    thread Texture &texture,
11045
+    thread metal::sampler const &sampler,
11046
+    thread metal::float2 const &coord,
11047
+    float bias)
11048
+{
11049
+    return texture.sample(sampler, coord, metal::bias(bias));
11050
+}
11051
+
11052
+template <typename Texture>
11053
+ANGLE_ALWAYS_INLINE auto ANGLE_texture2D_impl(
11054
+    thread Texture &texture,
11055
+    thread metal::sampler const &sampler,
11056
+    thread metal::float3 const &coord)
11057
+{
11058
+    return texture.sample(sampler, coord);
11059
+}
11060
+
11061
+template <typename Texture>
11062
+ANGLE_ALWAYS_INLINE auto ANGLE_texture2D_impl(
11063
+    thread Texture &texture,
11064
+    thread metal::sampler const &sampler,
11065
+    thread metal::float3 const &coord,
11066
+    float bias)
11067
+{
11068
+    return texture.sample(sampler, coord, metal::bias(bias));
11069
+}
11070
+)",
11071
+                        textureEnv())
11072
+
11073
+PROGRAM_PRELUDE_DECLARE(texture2DLod,
11074
+                        R"(
11075
+#define ANGLE_texture2DLod(env, ...) ANGLE_texture2DLod_impl(*env.texture, *env.sampler, __VA_ARGS__)
11076
+
11077
+template <typename Texture>
11078
+ANGLE_ALWAYS_INLINE auto ANGLE_texture2DLod_impl(
11079
+    thread Texture &texture,
11080
+    thread metal::sampler const &sampler,
11081
+    thread metal::float2 const &coord,
11082
+    float level)
11083
+{
11084
+    return texture.sample(sampler, coord, metal::level(level));
11085
+}
11086
+)",
11087
+                        textureEnv())
11088
+
11089
+PROGRAM_PRELUDE_DECLARE(texture2DProj,
11090
+                        R"(
11091
+#define ANGLE_texture2DProj(env, ...) ANGLE_texture2DProj_impl(*env.texture, *env.sampler, __VA_ARGS__)
11092
+
11093
+template <typename Texture>
11094
+ANGLE_ALWAYS_INLINE auto ANGLE_texture2DProj_impl(
11095
+    thread Texture &texture,
11096
+    thread metal::sampler const &sampler,
11097
+    thread metal::float3 const &coord,
11098
+    float bias = 0)
11099
+{
11100
+    return texture.sample(sampler, coord.xy/coord.z, metal::bias(bias));
11101
+}
11102
+
11103
+template <typename Texture>
11104
+ANGLE_ALWAYS_INLINE auto ANGLE_texture2DProj_impl(
11105
+    thread Texture &texture,
11106
+    thread metal::sampler const &sampler,
11107
+    thread metal::float4 const &coord,
11108
+    float bias = 0)
11109
+{
11110
+    return texture.sample(sampler, coord.xy/coord.w, metal::bias(bias));
11111
+}
11112
+)",
11113
+                        textureEnv())
11114
+
11115
+PROGRAM_PRELUDE_DECLARE(texture2DProjLod,
11116
+                        R"(
11117
+#define ANGLE_texture2DProjLod(env, ...) ANGLE_texture2DProjLod_impl(*env.texture, *env.sampler, __VA_ARGS__)
11118
+
11119
+template <typename Texture>
11120
+ANGLE_ALWAYS_INLINE auto ANGLE_texture2DProjLod_impl(
11121
+    thread Texture &texture,
11122
+    thread metal::sampler const &sampler,
11123
+    thread metal::float3 const &coord,
11124
+    float level)
11125
+{
11126
+    return texture.sample(sampler, coord.xy/coord.z, metal::level(level));
11127
+}
11128
+
11129
+template <typename Texture>
11130
+ANGLE_ALWAYS_INLINE auto ANGLE_texture2DProjLod_impl(
11131
+    thread Texture &texture,
11132
+    thread metal::sampler const &sampler,
11133
+    thread metal::float4 const &coord,
11134
+    float level)
11135
+{
11136
+    return texture.sample(sampler, coord.xy/coord.w, metal::level(level));
11137
+}
11138
+)",
11139
+                        textureEnv())
11140
+
11141
+PROGRAM_PRELUDE_DECLARE(texture3DLod,
11142
+                        R"(
11143
+#define ANGLE_texture3DLod(env, ...) ANGLE_texture3DLod_impl(*env.texture, *env.sampler, __VA_ARGS__)
11144
+
11145
+template <typename Texture>
11146
+ANGLE_ALWAYS_INLINE auto ANGLE_texture3DLod_impl(
11147
+    thread Texture &texture,
11148
+    thread metal::sampler const &sampler,
11149
+    thread metal::float3 const &coord,
11150
+    float level)
11151
+{
11152
+    return texture.sample(sampler, coord, metal::level(level));
11153
+}
11154
+)",
11155
+                        textureEnv())
11156
+
11157
+PROGRAM_PRELUDE_DECLARE(texture3DProj,
11158
+                        R"(
11159
+#define ANGLE_texture3DProj(env, ...) ANGLE_texture3DProj_impl(*env.texture, *env.sampler, __VA_ARGS__)
11160
+
11161
+template <typename Texture>
11162
+ANGLE_ALWAYS_INLINE auto ANGLE_texture3DProj_impl(
11163
+    thread Texture &texture,
11164
+    thread metal::sampler const &sampler,
11165
+    thread metal::float4 const &coord,
11166
+    float bias = 0)
11167
+{
11168
+    return texture.sample(sampler, coord.xyz/coord.w, metal::bias(bias));
11169
+}
11170
+)",
11171
+                        textureEnv())
11172
+
11173
+PROGRAM_PRELUDE_DECLARE(texture3DProjLod,
11174
+                        R"(
11175
+#define ANGLE_texture3DProjLod(env, ...) ANGLE_texture3DProjLod_impl(*env.texture, *env.sampler, __VA_ARGS__)
11176
+
11177
+template <typename Texture>
11178
+ANGLE_ALWAYS_INLINE auto ANGLE_texture3DProjLod_impl(
11179
+    thread Texture &texture,
11180
+    thread metal::sampler const &sampler,
11181
+    thread metal::float4 const &coord,
11182
+    float level)
11183
+{
11184
+    return texture.sample(sampler, coord.xyz/coord.w, metal::level(level));
11185
+}
11186
+)",
11187
+                        textureEnv())
11188
+
11189
+PROGRAM_PRELUDE_DECLARE(textureCube,
11190
+                        R"(
11191
+#define ANGLE_textureCube(env, ...) ANGLE_textureCube_impl(*env.texture, *env.sampler, __VA_ARGS__)
11192
+
11193
+template <typename Texture>
11194
+ANGLE_ALWAYS_INLINE auto ANGLE_textureCube_impl(
11195
+    thread Texture &texture,
11196
+    thread metal::sampler const &sampler,
11197
+    thread metal::float3 const &coord)
11198
+{
11199
+    return texture.sample(sampler, coord);
11200
+}
11201
+
11202
+template <typename Texture>
11203
+ANGLE_ALWAYS_INLINE auto ANGLE_textureCube_impl(
11204
+    thread Texture &texture,
11205
+    thread metal::sampler const &sampler,
11206
+    thread metal::float3 const &coord,
11207
+    float bias)
11208
+{
11209
+    return texture.sample(sampler, coord, metal::bias(bias));
11210
+}
11211
+)",
11212
+                        textureEnv())
11213
+
11214
+PROGRAM_PRELUDE_DECLARE(textureCubeLod,
11215
+                        R"(
11216
+#define ANGLE_textureCubeLod(env, ...) ANGLE_textureCubeLod_impl(*env.texture, *env.sampler, __VA_ARGS__)
11217
+
11218
+template <typename Texture>
11219
+ANGLE_ALWAYS_INLINE auto ANGLE_textureCubeLod_impl(
11220
+    thread Texture &texture,
11221
+    thread metal::sampler const &sampler,
11222
+    thread metal::float3 const &coord,
11223
+    float level)
11224
+{
11225
+    return texture.sample(sampler, coord, metal::level(level));
11226
+}
11227
+)",
11228
+                        textureEnv())
11229
+
11230
+PROGRAM_PRELUDE_DECLARE(textureCubeProj,
11231
+                        R"(
11232
+#define ANGLE_textureCubeProj(env, ...) ANGLE_textureCubeProj_impl(*env.texture, *env.sampler, __VA_ARGS__)
11233
+
11234
+template <typename Texture>
11235
+ANGLE_ALWAYS_INLINE auto ANGLE_textureCubeProj_impl(
11236
+    thread Texture &texture,
11237
+    thread metal::sampler const &sampler,
11238
+    thread metal::float4 const &coord,
11239
+    float bias = 0)
11240
+{
11241
+    return texture.sample(sampler, coord.xyz/coord.w, metal::bias(bias));
11242
+}
11243
+)",
11244
+                        textureEnv())
11245
+
11246
+PROGRAM_PRELUDE_DECLARE(textureCubeProjLod,
11247
+                        R"(
11248
+#define ANGLE_textureCubeProjLod(env, ...) ANGLE_textureCubeProjLod_impl(*env.texture, *env.sampler, __VA_ARGS__)
11249
+
11250
+template <typename Texture>
11251
+ANGLE_ALWAYS_INLINE auto ANGLE_textureCubeProjLod_impl(
11252
+    thread Texture &texture,
11253
+    thread metal::sampler const &sampler,
11254
+    thread metal::float4 const &coord,
11255
+    float level)
11256
+{
11257
+    return texture.sample(sampler, coord.xyz/coord.w, metal::level(level));
11258
+}
11259
+)",
11260
+                        textureEnv())
11261
+
11262
+PROGRAM_PRELUDE_DECLARE(textureGrad,
11263
+                        R"(
11264
+#define ANGLE_textureGrad(env, ...) ANGLE_textureGrad_impl(*env.texture, *env.sampler, __VA_ARGS__)
11265
+)",
11266
+                        textureEnv())
11267
+
11268
+PROGRAM_PRELUDE_DECLARE(textureGrad_generic_floatN_floatN_floatN,
11269
+                        R"(
11270
+template <typename Texture, int N>
11271
+ANGLE_ALWAYS_INLINE auto ANGLE_textureGrad_impl(
11272
+    thread Texture &texture,
11273
+    thread metal::sampler const &sampler,
11274
+    thread metal::vec<float, N> const &coord,
11275
+    thread metal::vec<float, N> const &dPdx,
11276
+    thread metal::vec<float, N> const &dPdy)
11277
+{
11278
+    return texture.sample(sampler, coord, ANGLE_gradient<N>(dPdx, dPdy));
11279
+}
11280
+)",
11281
+                        gradient(),
11282
+                        textureGrad())
11283
+
11284
+PROGRAM_PRELUDE_DECLARE(textureGrad_generic_float3_float2_float2,
11285
+                        R"(
11286
+template <typename Texture>
11287
+ANGLE_ALWAYS_INLINE auto ANGLE_textureGrad_impl(
11288
+    thread Texture &texture,
11289
+    thread metal::sampler const &sampler,
11290
+    thread metal::float3 const &coord,
11291
+    thread metal::float2 const &dPdx,
11292
+    thread metal::float2 const &dPdy)
11293
+{
11294
+    return texture.sample(sampler, coord.xy, uint(metal::round(coord.z)), metal::gradient2d(dPdx, dPdy));
11295
+}
11296
+)",
11297
+                        textureGrad())
11298
+
11299
+PROGRAM_PRELUDE_DECLARE(textureGrad_generic_float4_float2_float2,
11300
+                        R"(
11301
+template <typename Texture>
11302
+ANGLE_ALWAYS_INLINE auto ANGLE_textureGrad_impl(
11303
+    thread Texture &texture,
11304
+    thread metal::sampler const &sampler,
11305
+    thread metal::float4 const &coord,
11306
+    thread metal::float2 const &dPdx,
11307
+    thread metal::float2 const &dPdy)
11308
+{
11309
+    return texture.sample(sampler, coord.xy, uint(metal::round(coord.z)), metal::gradient2d(dPdx, dPdy));
11310
+}
11311
+)",
11312
+                        textureGrad())
11313
+
11314
+PROGRAM_PRELUDE_DECLARE(textureGrad_depth2d_float3_float2_float2,
11315
+                        R"(
11316
+template <typename T>
11317
+ANGLE_ALWAYS_INLINE auto ANGLE_textureGrad_impl(
11318
+    thread metal::depth2d<T> &texture,
11319
+    thread metal::sampler const &sampler,
11320
+    thread metal::float3 const &coord,
11321
+    thread metal::float2 const &dPdx,
11322
+    thread metal::float2 const &dPdy)
11323
+{
11324
+    if (ANGLE_UseSampleCompareGradient)
11325
+    {
11326
+        return static_cast<T>(texture.sample_compare(sampler, coord.xy, coord.z, metal::gradient2d(dPdx, dPdy)));
11327
+    }
11328
+    else
11329
+    {
11330
+        return static_cast<T>(texture.sample(sampler, coord.xy, metal::gradient2d(dPdx, dPdy)) > coord.z);
11331
+    }
11332
+}
11333
+)",
11334
+                        functionConstants(),
11335
+                        textureGrad())
11336
+
11337
+PROGRAM_PRELUDE_DECLARE(textureGrad_depth2darray_float4_float2_float2,
11338
+                        R"(
11339
+template <typename T>
11340
+ANGLE_ALWAYS_INLINE auto ANGLE_textureGrad_impl(
11341
+    thread metal::depth2d_array<T> &texture,
11342
+    thread metal::sampler const &sampler,
11343
+    thread metal::float4 const &coord,
11344
+    thread metal::float2 const &dPdx,
11345
+    thread metal::float2 const &dPdy)
11346
+{
11347
+    if (ANGLE_UseSampleCompareGradient)
11348
+    {
11349
+        return static_cast<T>(texture.sample_compare(sampler, coord.xy, uint(metal::round(coord.z)), coord.w, metal::gradient2d(dPdx, dPdy)));
11350
+    }
11351
+    else
11352
+    {
11353
+        return static_cast<T>(texture.sample(sampler, coord.xy, uint(metal::round(coord.z)), metal::gradient2d(dPdx, dPdy)) > coord.w);
11354
+    }
11355
+}
11356
+)",
11357
+                        functionConstants(),
11358
+                        textureGrad())
11359
+
11360
+PROGRAM_PRELUDE_DECLARE(textureGrad_depthcube_float4_float3_float3,
11361
+                        R"(
11362
+template <typename T>
11363
+ANGLE_ALWAYS_INLINE auto ANGLE_textureGrad_impl(
11364
+    thread metal::depthcube<T> &texture,
11365
+    thread metal::sampler const &sampler,
11366
+    thread metal::float4 const &coord,
11367
+    thread metal::float3 const &dPdx,
11368
+    thread metal::float3 const &dPdy)
11369
+{
11370
+    if (ANGLE_UseSampleCompareGradient)
11371
+    {
11372
+        return static_cast<T>(texture.sample_compare(sampler, coord.xyz, coord.w, metal::gradientcube(dPdx, dPdy)));
11373
+    }
11374
+    else
11375
+    {
11376
+        return static_cast<T>(texture.sample(sampler, coord.xyz, metal::gradientcube(dPdx, dPdy)) > coord.w);
11377
+    }
11378
+}
11379
+)",
11380
+                        functionConstants(),
11381
+                        textureGrad())
11382
+
11383
+PROGRAM_PRELUDE_DECLARE(textureGrad_texturecube_float3_float3_float3,
11384
+                        R"(
11385
+template <typename T>
11386
+ANGLE_ALWAYS_INLINE auto ANGLE_textureGrad_impl(
11387
+    thread metal::texturecube<T> &texture,
11388
+    thread metal::sampler const &sampler,
11389
+    thread metal::float3 const &coord,
11390
+    thread metal::float3 const &dPdx,
11391
+    thread metal::float3 const &dPdy)
11392
+{
11393
+    return texture.sample(sampler, coord, metal::gradientcube(dPdx, dPdy));
11394
+}
11395
+)",
11396
+                        textureGrad())
11397
+
11398
+PROGRAM_PRELUDE_DECLARE(textureGradOffset,
11399
+                        R"(
11400
+#define ANGLE_textureGradOffset(env, ...) ANGLE_textureGradOffset_impl(*env.texture, *env.sampler, __VA_ARGS__)
11401
+)",
11402
+                        textureEnv())
11403
+
11404
+PROGRAM_PRELUDE_DECLARE(textureGradOffset_generic_floatN_floatN_floatN_intN,
11405
+                        R"(
11406
+template <typename Texture, int N>
11407
+ANGLE_ALWAYS_INLINE auto ANGLE_textureGradOffset_impl(
11408
+    thread Texture &texture,
11409
+    thread metal::sampler const &sampler,
11410
+    thread metal::vec<float, N> const &coord,
11411
+    thread metal::vec<float, N> const &dPdx,
11412
+    thread metal::vec<float, N> const &dPdy,
11413
+    thread metal::vec<int, N> const &offset)
11414
+{
11415
+    return texture.sample(sampler, coord, ANGLE_gradient<N>(dPdx, dPdy), offset);
11416
+}
11417
+)",
11418
+                        gradient(),
11419
+                        textureGradOffset())
11420
+
11421
+PROGRAM_PRELUDE_DECLARE(textureGradOffset_generic_float3_float2_float2_int2,
11422
+                        R"(
11423
+template <typename Texture>
11424
+ANGLE_ALWAYS_INLINE auto ANGLE_textureGradOffset_impl(
11425
+    thread Texture &texture,
11426
+    thread metal::sampler const &sampler,
11427
+    thread metal::float3 const &coord,
11428
+    thread metal::float2 const &dPdx,
11429
+    thread metal::float2 const &dPdy,
11430
+    thread metal::int2 const &offset)
11431
+{
11432
+    return texture.sample(sampler, coord.xy, uint(metal::round(coord.z)), metal::gradient2d(dPdx, dPdy), offset);
11433
+}
11434
+)",
11435
+                        textureGradOffset())
11436
+
11437
+PROGRAM_PRELUDE_DECLARE(textureGradOffset_generic_float4_float2_float2_int2,
11438
+                        R"(
11439
+template <typename Texture>
11440
+ANGLE_ALWAYS_INLINE auto ANGLE_textureGradOffset_impl(
11441
+    thread Texture &texture,
11442
+    thread metal::sampler const &sampler,
11443
+    thread metal::float4 const &coord,
11444
+    thread metal::float2 const &dPdx,
11445
+    thread metal::float2 const &dPdy,
11446
+    thread metal::int2 const &offset)
11447
+{
11448
+    return texture.sample(sampler, coord.xy, uint(metal::round(coord.z)), metal::gradient2d(dPdx, dPdy), offset);
11449
+}
11450
+)",
11451
+                        textureGradOffset())
11452
+
11453
+PROGRAM_PRELUDE_DECLARE(textureGradOffset_depth2d_float3_float2_float2_int2,
11454
+                        R"(
11455
+template <typename T>
11456
+ANGLE_ALWAYS_INLINE auto ANGLE_textureGradOffset_impl(
11457
+    thread metal::depth2d<T> &texture,
11458
+    thread metal::sampler const &sampler,
11459
+    thread metal::float3 const &coord,
11460
+    thread metal::float2 const &dPdx,
11461
+    thread metal::float2 const &dPdy,
11462
+    thread metal::int2 const &offset)
11463
+{
11464
+    if (ANGLE_UseSampleCompareGradient)
11465
+    {
11466
+        return static_cast<T>(texture.sample_compare(sampler, coord.xy, coord.z, metal::gradient2d(dPdx, dPdy), offset));
11467
+    }
11468
+    else
11469
+    {
11470
+        return static_cast<T>(texture.sample(sampler, coord.xy, metal::gradient2d(dPdx, dPdy), offset) > coord.z);
11471
+    }
11472
+}
11473
+)",
11474
+                        functionConstants(),
11475
+                        textureGradOffset())
11476
+
11477
+PROGRAM_PRELUDE_DECLARE(textureGradOffset_depth2darray_float4_float2_float2_int2,
11478
+                        R"(
11479
+template <typename T>
11480
+ANGLE_ALWAYS_INLINE auto ANGLE_textureGradOffset_impl(
11481
+    thread metal::depth2d_array<T> &texture,
11482
+    thread metal::sampler const &sampler,
11483
+    thread metal::float4 const &coord,
11484
+    thread metal::float2 const &dPdx,
11485
+    thread metal::float2 const &dPdy,
11486
+    thread metal::int2 const &offset)
11487
+{
11488
+    if (ANGLE_UseSampleCompareGradient)
11489
+    {
11490
+        return static_cast<T>(texture.sample_compare(sampler, coord.xy, uint(metal::round(coord.z)), coord.w, metal::gradient2d(dPdx, dPdy), offset));
11491
+    }
11492
+    else
11493
+    {
11494
+        return static_cast<T>(texture.sample(sampler, coord.xy, uint(metal::round(coord.z)), metal::gradient2d(dPdx, dPdy), offset) > coord.w);
11495
+    }
11496
+}
11497
+)",
11498
+                        functionConstants(),
11499
+                        textureGradOffset())
11500
+
11501
+PROGRAM_PRELUDE_DECLARE(textureGradOffset_depthcube_float4_float3_float3_int3,
11502
+                        R"(
11503
+template <typename T>
11504
+ANGLE_ALWAYS_INLINE auto ANGLE_textureGradOffset_impl(
11505
+    thread metal::depthcube<T> &texture,
11506
+    thread metal::sampler const &sampler,
11507
+    thread metal::float4 const &coord,
11508
+    thread metal::float3 const &dPdx,
11509
+    thread metal::float3 const &dPdy,
11510
+    thread metal::int3 const &offset)
11511
+{
11512
+    return texture.sample(sampler, coord.xyz, metal::gradientcube(dPdx, dPdy), offset);
11513
+}
11514
+)",
11515
+                        textureGradOffset())
11516
+
11517
+PROGRAM_PRELUDE_DECLARE(textureGradOffset_texturecube_float3_float3_float3_int3,
11518
+                        R"(
11519
+template <typename T>
11520
+ANGLE_ALWAYS_INLINE auto ANGLE_textureGradOffset_impl(
11521
+    thread metal::texturecube<T> &texture,
11522
+    thread metal::sampler const &sampler,
11523
+    thread metal::float3 const &coord,
11524
+    thread metal::float3 const &dPdx,
11525
+    thread metal::float3 const &dPdy,
11526
+    thread metal::int3 const &offset)
11527
+{
11528
+    return texture.sample(sampler, coord, metal::gradientcube(dPdx, dPdy), offset);
11529
+}
11530
+)",
11531
+                        textureGradOffset())
11532
+
11533
+PROGRAM_PRELUDE_DECLARE(textureLod,
11534
+                        R"(
11535
+#define ANGLE_textureLod(env, ...) ANGLE_textureLod_impl(*env.texture, *env.sampler, __VA_ARGS__)
11536
+)",
11537
+                        textureEnv())
11538
+
11539
+PROGRAM_PRELUDE_DECLARE(textureLod_generic_float2,
11540
+                        R"(
11541
+template <typename Texture>
11542
+ANGLE_ALWAYS_INLINE auto ANGLE_textureLod_impl(
11543
+    thread Texture &texture,
11544
+    thread metal::sampler const &sampler,
11545
+    thread metal::float2 const &coord,
11546
+    float level)
11547
+{
11548
+    return texture.sample(sampler, coord, metal::level(level));
11549
+}
11550
+)",
11551
+                        textureLod())
11552
+
11553
+PROGRAM_PRELUDE_DECLARE(textureLod_generic_float3,
11554
+                        R"(
11555
+template <typename Texture>
11556
+ANGLE_ALWAYS_INLINE auto ANGLE_textureLod_impl(
11557
+    thread Texture &texture,
11558
+    thread metal::sampler const &sampler,
11559
+    thread metal::float3 const &coord,
11560
+    float level)
11561
+{
11562
+    return texture.sample(sampler, coord, metal::level(level));
11563
+}
11564
+)",
11565
+                        textureLod())
11566
+
11567
+PROGRAM_PRELUDE_DECLARE(textureLod_depth2d_float3,
11568
+                        R"(
11569
+template <typename T>
11570
+ANGLE_ALWAYS_INLINE auto ANGLE_textureLod_impl(
11571
+    thread metal::depth2d<T> &texture,
11572
+    thread metal::sampler const &sampler,
11573
+    thread metal::float3 const &coord,
11574
+    float level)
11575
+{
11576
+    if (ANGLE_UseSampleCompareLod)
11577
+    {
11578
+        return static_cast<T>(texture.sample_compare(sampler, coord.xy, coord.z, metal::level(level)));
11579
+    }
11580
+    else
11581
+    {
11582
+        return static_cast<T>(texture.sample(sampler, coord.xy, metal::level(level)) > coord.z);
11583
+    }
11584
+}
11585
+)",
11586
+                        functionConstants(),
11587
+                        textureLod())
11588
+
11589
+PROGRAM_PRELUDE_DECLARE(textureLod_texture2darray_float3,
11590
+                        R"(
11591
+template <typename T>
11592
+ANGLE_ALWAYS_INLINE auto ANGLE_textureLod_impl(
11593
+    thread metal::texture2d_array<T> &texture,
11594
+    thread metal::sampler const &sampler,
11595
+    thread metal::float3 const &coord,
11596
+    float level)
11597
+{
11598
+    return texture.sample(sampler, coord.xy, uint(metal::round(coord.z)), metal::level(level));
11599
+}
11600
+)",
11601
+                        textureLod())
11602
+
11603
+PROGRAM_PRELUDE_DECLARE(textureLod_texture2darray_float4,
11604
+                        R"(
11605
+template <typename T>
11606
+ANGLE_ALWAYS_INLINE auto ANGLE_textureLod_impl(
11607
+    thread metal::texture2d_array<T> &texture,
11608
+    thread metal::sampler const &sampler,
11609
+    thread metal::float4 const &coord,
11610
+    float level)
11611
+{
11612
+    return texture.sample(sampler, coord.xyz, uint(metal::round(coord.w)), metal::level(level));
11613
+}
11614
+)",
11615
+                        textureLod())
11616
+
11617
+PROGRAM_PRELUDE_DECLARE(textureLodOffset,
11618
+                        R"(
11619
+#define ANGLE_textureLodOffset(env, ...) ANGLE_textureLodOffset_impl(*env.texture, *env.sampler, __VA_ARGS__)
11620
+
11621
+template <typename Texture>
11622
+ANGLE_ALWAYS_INLINE auto ANGLE_textureLodOffset_impl(
11623
+    thread Texture &texture,
11624
+    thread metal::sampler const &sampler,
11625
+    thread metal::float2 const &coord,
11626
+    float level,
11627
+    thread int2 const &offset)
11628
+{
11629
+    return texture.sample(sampler, coord, metal::level(level), offset);
11630
+}
11631
+
11632
+template <typename Texture>
11633
+ANGLE_ALWAYS_INLINE auto ANGLE_textureLodOffset_impl(
11634
+    thread Texture &texture,
11635
+    thread metal::sampler const &sampler,
11636
+    thread metal::float3 const &coord,
11637
+    float level,
11638
+    thread int3 const &offset)
11639
+{
11640
+    return texture.sample(sampler, coord, metal::level(level), offset);
11641
+}
11642
+
11643
+template <typename T>
11644
+ANGLE_ALWAYS_INLINE auto ANGLE_textureLodOffset_impl(
11645
+    thread metal::depth2d<T> &texture,
11646
+    thread metal::sampler const &sampler,
11647
+    thread metal::float3 const &coord,
11648
+    float level,
11649
+    thread int2 const &offset)
11650
+{
11651
+    if (ANGLE_UseSampleCompareLod)
11652
+    {
11653
+        return static_cast<T>(texture.sample_compare(sampler, coord.xy, coord.z, metal::level(level), offset));
11654
+    }
11655
+    else
11656
+    {
11657
+        return static_cast<T>(texture.sample(sampler, coord.xy, metal::level(level), offset) > coord.z);
11658
+    }
11659
+}
11660
+
11661
+template <typename T>
11662
+ANGLE_ALWAYS_INLINE auto ANGLE_textureLodOffset_impl(
11663
+    thread metal::texture2d_array<T> &texture,
11664
+    thread metal::sampler const &sampler,
11665
+    thread metal::float3 const &coord,
11666
+    float level,
11667
+    thread int2 const &offset)
11668
+{
11669
+    return texture.sample(sampler, coord.xy, uint(metal::round(coord.z)), metal::level(level), offset);
11670
+}
11671
+
11672
+template <typename T>
11673
+ANGLE_ALWAYS_INLINE auto ANGLE_textureLodOffset_impl(
11674
+    thread metal::texture2d_array<T> &texture,
11675
+    thread metal::sampler const &sampler,
11676
+    thread metal::float4 const &coord,
11677
+    float level,
11678
+    thread int3 const &offset)
11679
+{
11680
+    return texture.sample(sampler, coord.xyz, uint(metal::round(coord.w)), metal::level(level), offset);
11681
+}
11682
+)",
11683
+                        functionConstants(),
11684
+                        textureEnv())
11685
+
11686
+PROGRAM_PRELUDE_DECLARE(textureOffset,
11687
+                        R"(
11688
+#define ANGLE_textureOffset(env, ...) ANGLE_textureOffset_impl(*env.texture, *env.sampler, __VA_ARGS__)
11689
+
11690
+template <typename Texture>
11691
+ANGLE_ALWAYS_INLINE auto ANGLE_textureOffset_impl(
11692
+    thread Texture &texture,
11693
+    thread metal::sampler const &sampler,
11694
+    thread float2 const &coord,
11695
+    thread int2 const &offset)
11696
+{
11697
+    return texture.sample(sampler, coord, offset);
11698
+}
11699
+
11700
+template <typename Texture>
11701
+ANGLE_ALWAYS_INLINE auto ANGLE_textureOffset_impl(
11702
+    thread Texture &texture,
11703
+    thread metal::sampler const &sampler,
11704
+    thread float2 const &coord,
11705
+    thread int2 const &offset,
11706
+    float bias)
11707
+{
11708
+    return texture.sample(sampler, coord, metal::bias(bias), offset);
11709
+}
11710
+
11711
+template <typename Texture>
11712
+ANGLE_ALWAYS_INLINE auto ANGLE_textureOffset_impl(
11713
+    thread Texture &texture,
11714
+    thread metal::sampler const &sampler,
11715
+    thread float3 const &coord,
11716
+    thread int2 const &offset)
11717
+{
11718
+    return texture.sample(sampler, coord.xy, uint(metal::round(coord.z)), offset);
11719
+}
11720
+
11721
+template <typename Texture>
11722
+ANGLE_ALWAYS_INLINE auto ANGLE_textureOffset_impl(
11723
+    thread Texture &texture,
11724
+    thread metal::sampler const &sampler,
11725
+    thread float3 const &coord,
11726
+    thread int2 const &offset,
11727
+    float bias)
11728
+{
11729
+    return texture.sample(sampler, coord.xy, uint(metal::round(coord.z)), metal::bias(bias), offset);
11730
+}
11731
+
11732
+template <typename Texture>
11733
+ANGLE_ALWAYS_INLINE auto ANGLE_textureOffset_impl(
11734
+    thread Texture &texture,
11735
+    thread metal::sampler const &sampler,
11736
+    thread float3 const &coord,
11737
+    thread int3 const &offset)
11738
+{
11739
+    return texture.sample(sampler, coord, offset);
11740
+}
11741
+
11742
+template <typename Texture>
11743
+ANGLE_ALWAYS_INLINE auto ANGLE_textureOffset_impl(
11744
+    thread Texture &texture,
11745
+    thread metal::sampler const &sampler,
11746
+    thread float3 const &coord,
11747
+    thread int3 const &offset,
11748
+    float bias)
11749
+{
11750
+    return texture.sample(sampler, coord, metal::bias(bias), offset);
11751
+}
11752
+
11753
+template <typename T>
11754
+ANGLE_ALWAYS_INLINE auto ANGLE_textureOffset_impl(
11755
+    thread metal::depth2d<T> &texture,
11756
+    thread metal::sampler const &sampler,
11757
+    thread float3 const &coord,
11758
+    thread int2 const &offset)
11759
+{
11760
+    return texture.sample(sampler, coord.xy, offset);
11761
+}
11762
+
11763
+template <typename T>
11764
+ANGLE_ALWAYS_INLINE auto ANGLE_textureOffset_impl(
11765
+    thread metal::depth2d<T> &texture,
11766
+    thread metal::sampler const &sampler,
11767
+    thread float3 const &coord,
11768
+    thread int2 const &offset,
11769
+    float bias)
11770
+{
11771
+    return texture.sample(sampler, coord.xy, metal::bias(bias), offset);
11772
+}
11773
+)",
11774
+                        textureEnv())
11775
+
11776
+PROGRAM_PRELUDE_DECLARE(textureProj,
11777
+                        R"(
11778
+#define ANGLE_textureProj(env, ...) ANGLE_textureProj_impl(*env.texture, *env.sampler, __VA_ARGS__)
11779
+
11780
+template <typename Texture>
11781
+ANGLE_ALWAYS_INLINE auto ANGLE_textureProj_impl(
11782
+    thread Texture &texture,
11783
+    thread metal::sampler const &sampler,
11784
+    thread metal::float3 const &coord,
11785
+    float bias = 0)
11786
+{
11787
+    return texture.sample(sampler, coord.xy/coord.z, metal::bias(bias));
11788
+}
11789
+
11790
+template <typename Texture>
11791
+ANGLE_ALWAYS_INLINE auto ANGLE_textureProj_impl(
11792
+    thread Texture &texture,
11793
+    thread metal::sampler const &sampler,
11794
+    thread metal::float4 const &coord,
11795
+    float bias = 0)
11796
+{
11797
+    return texture.sample(sampler, coord.xy/coord.w, metal::bias(bias));
11798
+}
11799
+
11800
+template <typename T>
11801
+ANGLE_ALWAYS_INLINE auto ANGLE_textureProj_impl(
11802
+    thread metal::texture3d<T> &texture,
11803
+    thread metal::sampler const &sampler,
11804
+    thread metal::float4 const &coord,
11805
+    float bias = 0)
11806
+{
11807
+    return texture.sample(sampler, coord.xyz/coord.w, metal::bias(bias));
11808
+}
11809
+)",
11810
+                        textureEnv())
11811
+
11812
+PROGRAM_PRELUDE_DECLARE(textureProjGrad,
11813
+                        R"(
11814
+#define ANGLE_textureProjGrad(env, ...) ANGLE_textureProjGrad_impl(*env.texture, *env.sampler, __VA_ARGS__)
11815
+)",
11816
+                        textureEnv())
11817
+
11818
+PROGRAM_PRELUDE_DECLARE(textureProjGrad_generic_float3_float2_float2,
11819
+                        R"(
11820
+template <typename Texture>
11821
+ANGLE_ALWAYS_INLINE auto ANGLE_textureProjGrad_impl(
11822
+    thread Texture &texture,
11823
+    thread metal::sampler const &sampler,
11824
+    thread metal::float3 const &coord,
11825
+    thread metal::float2 const &dPdx,
11826
+    thread metal::float2 const &dPdy)
11827
+{
11828
+    return texture.sample(sampler, coord.xy/coord.z, metal::gradient2d(dPdx, dPdy));
11829
+}
11830
+)",
11831
+                        textureProjGrad())
11832
+
11833
+PROGRAM_PRELUDE_DECLARE(textureProjGrad_generic_float4_float2_float2,
11834
+                        R"(
11835
+template <typename Texture>
11836
+ANGLE_ALWAYS_INLINE auto ANGLE_textureProjGrad_impl(
11837
+    thread Texture &texture,
11838
+    thread metal::sampler const &sampler,
11839
+    thread metal::float4 const &coord,
11840
+    thread metal::float2 const &dPdx,
11841
+    thread metal::float2 const &dPdy)
11842
+{
11843
+    return texture.sample(sampler, coord.xy/coord.w, metal::gradient2d(dPdx, dPdy));
11844
+}
11845
+)",
11846
+                        textureProjGrad())
11847
+
11848
+PROGRAM_PRELUDE_DECLARE(textureProjGrad_depth2d_float4_float2_float2,
11849
+                        R"(
11850
+template <typename T>
11851
+ANGLE_ALWAYS_INLINE auto ANGLE_textureProjGrad_impl(
11852
+    thread metal::depth2d<T> &texture,
11853
+    thread metal::sampler const &sampler,
11854
+    thread metal::float4 const &coord,
11855
+    thread metal::float2 const &dPdx,
11856
+    thread metal::float2 const &dPdy)
11857
+{
11858
+    if (ANGLE_UseSampleCompareGradient)
11859
+    {
11860
+        return static_cast<T>(texture.sample_compare(sampler, coord.xy/coord.w, coord.z/coord.w, metal::gradient2d(dPdx, dPdy)));
11861
+    }
11862
+    else
11863
+    {
11864
+        return static_cast<T>(texture.sample(sampler, coord.xy/coord.w, metal::gradient2d(dPdx, dPdy)) > coord.z/coord.w);
11865
+    }
11866
+}
11867
+)",
11868
+                        functionConstants(),
11869
+                        textureProjGrad())
11870
+
11871
+PROGRAM_PRELUDE_DECLARE(textureProjGrad_texture3d_float4_float3_float3,
11872
+                        R"(
11873
+template <typename T>
11874
+ANGLE_ALWAYS_INLINE auto ANGLE_textureProjGrad_impl(
11875
+    thread metal::texture3d<T> &texture,
11876
+    thread metal::sampler const &sampler,
11877
+    thread metal::float4 const &coord,
11878
+    thread metal::float3 const &dPdx,
11879
+    thread metal::float3 const &dPdy)
11880
+{
11881
+    return texture.sample(sampler, coord.xyz/coord.w, metal::gradient3d(dPdx, dPdy));
11882
+}
11883
+)",
11884
+                        textureProjGrad())
11885
+
11886
+PROGRAM_PRELUDE_DECLARE(textureProjGradOffset,
11887
+                        R"(
11888
+#define ANGLE_textureProjGradOffset(env, ...) ANGLE_textureProjGradOffset_impl(*env.texture, *env.sampler, __VA_ARGS__)
11889
+)",
11890
+                        textureEnv())
11891
+
11892
+PROGRAM_PRELUDE_DECLARE(textureProjGradOffset_generic_float3_float2_float2_int2,
11893
+                        R"(
11894
+template <typename Texture>
11895
+ANGLE_ALWAYS_INLINE auto ANGLE_textureProjGradOffset_impl(
11896
+    thread Texture &texture,
11897
+    thread metal::sampler const &sampler,
11898
+    thread metal::float3 const &coord,
11899
+    thread metal::float2 const &dPdx,
11900
+    thread metal::float2 const &dPdy,
11901
+    thread int2 const &offset)
11902
+{
11903
+    return texture.sample(sampler, coord.xy/coord.z, metal::gradient2d(dPdx, dPdy), offset);
11904
+}
11905
+)",
11906
+                        textureProjGradOffset())
11907
+
11908
+PROGRAM_PRELUDE_DECLARE(textureProjGradOffset_generic_float4_float2_float2_int2,
11909
+                        R"(
11910
+template <typename Texture>
11911
+ANGLE_ALWAYS_INLINE auto ANGLE_textureProjGradOffset_impl(
11912
+    thread Texture &texture,
11913
+    thread metal::sampler const &sampler,
11914
+    thread metal::float4 const &coord,
11915
+    thread metal::float2 const &dPdx,
11916
+    thread metal::float2 const &dPdy,
11917
+    thread int2 const &offset)
11918
+{
11919
+    return texture.sample(sampler, coord.xy/coord.w, metal::gradient2d(dPdx, dPdy), offset);
11920
+}
11921
+)",
11922
+                        textureProjGradOffset())
11923
+
11924
+PROGRAM_PRELUDE_DECLARE(textureProjGradOffset_depth2d_float4_float2_float2_int2,
11925
+                        R"(
11926
+template <typename T>
11927
+ANGLE_ALWAYS_INLINE auto ANGLE_textureProjGradOffset_impl(
11928
+    thread metal::depth2d<T> &texture,
11929
+    thread metal::sampler const &sampler,
11930
+    thread metal::float4 const &coord,
11931
+    thread metal::float2 const &dPdx,
11932
+    thread metal::float2 const &dPdy,
11933
+    thread int2 const &offset)
11934
+{
11935
+    if (ANGLE_UseSampleCompareGradient)
11936
+    {
11937
+        return static_cast<T>(texture.sample_compare(sampler, coord.xy/coord.w, coord.z/coord.w, metal::gradient2d(dPdx, dPdy), offset));
11938
+    }
11939
+    else
11940
+    {
11941
+        return static_cast<T>(texture.sample(sampler, coord.xy/coord.w, metal::gradient2d(dPdx, dPdy), offset) > coord.z/coord.w);
11942
+    }
11943
+}
11944
+)",
11945
+                        functionConstants(),
11946
+                        textureProjGradOffset())
11947
+
11948
+PROGRAM_PRELUDE_DECLARE(textureProjGradOffset_texture3d_float4_float3_float3_int3,
11949
+                        R"(
11950
+template <typename T>
11951
+ANGLE_ALWAYS_INLINE auto ANGLE_textureProjGradOffset_impl(
11952
+    thread metal::texture3d<T> &texture,
11953
+    thread metal::sampler const &sampler,
11954
+    thread metal::float4 const &coord,
11955
+    thread metal::float3 const &dPdx,
11956
+    thread metal::float3 const &dPdy,
11957
+    thread int3 const &offset)
11958
+{
11959
+    return texture.sample(sampler, coord.xyz/coord.w, metal::gradient3d(dPdx, dPdy), offset);
11960
+}
11961
+)",
11962
+                        textureProjGradOffset())
11963
+
11964
+PROGRAM_PRELUDE_DECLARE(textureProjLod,
11965
+                        R"(
11966
+#define ANGLE_textureProjLod(env, ...) ANGLE_textureProjLod_impl(*env.texture, *env.sampler, __VA_ARGS__)
11967
+)",
11968
+                        textureEnv())
11969
+
11970
+PROGRAM_PRELUDE_DECLARE(textureProjLod_generic_float3,
11971
+                        R"(
11972
+template <typename Texture>
11973
+ANGLE_ALWAYS_INLINE auto ANGLE_textureProjLod_impl(
11974
+    thread Texture &texture,
11975
+    thread metal::sampler const &sampler,
11976
+    thread metal::float3 const &coord,
11977
+    float level)
11978
+{
11979
+    return texture.sample(sampler, coord.xy/coord.z, metal::level(level));
11980
+}
11981
+)",
11982
+                        textureProjLod())
11983
+
11984
+PROGRAM_PRELUDE_DECLARE(textureProjLod_generic_float4,
11985
+                        R"(
11986
+template <typename Texture>
11987
+ANGLE_ALWAYS_INLINE auto ANGLE_textureProjLod_impl(
11988
+    thread Texture &texture,
11989
+    thread metal::sampler const &sampler,
11990
+    thread metal::float4 const &coord,
11991
+    float level)
11992
+{
11993
+    return texture.sample(sampler, coord.xy/coord.w, metal::level(level));
11994
+}
11995
+)",
11996
+                        textureProjLod())
11997
+
11998
+PROGRAM_PRELUDE_DECLARE(textureProjLod_depth2d_float4,
11999
+                        R"(
12000
+template <typename T>
12001
+ANGLE_ALWAYS_INLINE auto ANGLE_textureProjLod_impl(
12002
+    thread metal::depth2d<T> &texture,
12003
+    thread metal::sampler const &sampler,
12004
+    thread metal::float4 const &coord,
12005
+    float level)
12006
+{
12007
+    if (ANGLE_UseSampleCompareLod)
12008
+    {
12009
+        return static_cast<T>(texture.sample_compare(sampler, coord.xy/coord.w, coord.z/coord.w, metal::level(level)));
12010
+    }
12011
+    else
12012
+    {
12013
+        return static_cast<T>(texture.sample(sampler, coord.xy/coord.w, metal::level(level)) > coord.z/coord.w);
12014
+    }
12015
+}
12016
+)",
12017
+                        functionConstants(),
12018
+                        textureProjLod())
12019
+
12020
+PROGRAM_PRELUDE_DECLARE(textureProjLod_texture3d_float4,
12021
+                        R"(
12022
+template <typename T>
12023
+ANGLE_ALWAYS_INLINE auto ANGLE_textureProjLod_impl(
12024
+    thread metal::texture3d<T> &texture,
12025
+    thread metal::sampler const &sampler,
12026
+    thread metal::float4 const &coord,
12027
+    float level)
12028
+{
12029
+    return texture.sample(sampler, coord.xyz/coord.w, metal::level(level));
12030
+}
12031
+)",
12032
+                        textureProjLod())
12033
+
12034
+PROGRAM_PRELUDE_DECLARE(textureProjLodOffset,
12035
+                        R"(
12036
+#define ANGLE_textureProjLodOffset(env, ...) ANGLE_textureProjLodOffset_impl(*env.texture, *env.sampler, __VA_ARGS__)
12037
+
12038
+template <typename Texture>
12039
+ANGLE_ALWAYS_INLINE auto ANGLE_textureProjLodOffset_impl(
12040
+    thread Texture &texture,
12041
+    thread metal::sampler const &sampler,
12042
+    thread metal::float3 const &coord,
12043
+    float level,
12044
+    thread int2 const &offset)
12045
+{
12046
+    return texture.sample(sampler, coord.xy/coord.z, metal::level(level), offset);
12047
+}
12048
+
12049
+template <typename Texture>
12050
+ANGLE_ALWAYS_INLINE auto ANGLE_textureProjLodOffset_impl(
12051
+    thread Texture &texture,
12052
+    thread metal::sampler const &sampler,
12053
+    thread metal::float4 const &coord,
12054
+    float level,
12055
+    thread int2 const &offset)
12056
+{
12057
+    return texture.sample(sampler, coord.xy/coord.w, metal::level(level), offset);
12058
+}
12059
+
12060
+template <typename T>
12061
+ANGLE_ALWAYS_INLINE auto ANGLE_textureProjLodOffset_impl(
12062
+    thread metal::depth2d<T> &texture,
12063
+    thread metal::sampler const &sampler,
12064
+    thread metal::float4 const &coord,
12065
+    float level,
12066
+    thread int2 const &offset)
12067
+{
12068
+    if (ANGLE_UseSampleCompareLod)
12069
+    {
12070
+        return static_cast<T>(texture.sample_compare(sampler, coord.xy/coord.w, coord.z/coord.w, metal::level(level), offset));
12071
+    }
12072
+    else
12073
+    {
12074
+        return static_cast<T>(texture.sample(sampler, coord.xy/coord.w, metal::level(level), offset) > coord.z/coord.w);
12075
+    }
12076
+}
12077
+
12078
+template <typename T>
12079
+ANGLE_ALWAYS_INLINE auto ANGLE_textureProjLodOffset_impl(
12080
+    thread metal::texture3d<T> &texture,
12081
+    thread metal::sampler const &sampler,
12082
+    thread metal::float4 const &coord,
12083
+    float level,
12084
+    thread int3 const &offset)
12085
+{
12086
+    return texture.sample(sampler, coord.xyz/coord.w, metal::level(level), offset);
12087
+}
12088
+)",
12089
+                        functionConstants(),
12090
+                        textureEnv())
12091
+
12092
+PROGRAM_PRELUDE_DECLARE(textureProjOffset,
12093
+                        R"(
12094
+#define ANGLE_textureProjOffset(env, ...) ANGLE_textureProjOffset_impl(*env.texture, *env.sampler, __VA_ARGS__)
12095
+
12096
+template <typename Texture>
12097
+ANGLE_ALWAYS_INLINE auto ANGLE_textureProjOffset_impl(
12098
+    thread Texture &texture,
12099
+    thread metal::sampler const &sampler,
12100
+    thread metal::float3 const &coord,
12101
+    thread int2 const &offset,
12102
+    float bias = 0)
12103
+{
12104
+    return texture.sample(sampler, coord.xy/coord.z, metal::bias(bias), offset);
12105
+}
12106
+
12107
+template <typename Texture>
12108
+ANGLE_ALWAYS_INLINE auto ANGLE_textureProjOffset_impl(
12109
+    thread Texture &texture,
12110
+    thread metal::sampler const &sampler,
12111
+    thread metal::float4 const &coord,
12112
+    thread int2 const &offset,
12113
+    float bias = 0)
12114
+{
12115
+    return texture.sample(sampler, coord.xy/coord.w, metal::bias(bias), offset);
12116
+}
12117
+
12118
+template <typename T>
12119
+ANGLE_ALWAYS_INLINE auto ANGLE_textureProjOffset_impl(
12120
+    thread metal::texture3d<T> &texture,
12121
+    thread metal::sampler const &sampler,
12122
+    thread metal::float4 const &coord,
12123
+    thread int3 const &offset,
12124
+    float bias = 0)
12125
+{
12126
+    return texture.sample(sampler, coord.xyz/coord.w, metal::bias(bias), offset);
12127
+}
12128
+)",
12129
+                        textureEnv())
12130
+
12131
+PROGRAM_PRELUDE_DECLARE(textureSize,
12132
+                        R"(
12133
+#define ANGLE_textureSize(env, ...) ANGLE_textureSize_impl(*env.texture, __VA_ARGS__)
12134
+
12135
+template <typename Texture>
12136
+ANGLE_ALWAYS_INLINE auto ANGLE_textureSize_impl(
12137
+    thread Texture &texture,
12138
+    int level)
12139
+{
12140
+    return int2(texture.get_width(uint(level)), texture.get_height(uint(level)));
12141
+}
12142
+
12143
+template <typename T>
12144
+ANGLE_ALWAYS_INLINE auto ANGLE_textureSize_impl(
12145
+    thread metal::texture3d<T> &texture,
12146
+    int level)
12147
+{
12148
+    return int3(texture.get_width(uint(level)), texture.get_height(uint(level)), texture.get_depth(uint(level)));
12149
+}
12150
+
12151
+template <typename T>
12152
+ANGLE_ALWAYS_INLINE auto ANGLE_textureSize_impl(
12153
+    thread metal::depth2d_array<T> &texture,
12154
+    int level)
12155
+{
12156
+    return int3(texture.get_width(uint(level)), texture.get_height(uint(level)), texture.get_array_size());
12157
+}
12158
+
12159
+template <typename T>
12160
+ANGLE_ALWAYS_INLINE auto ANGLE_textureSize_impl(
12161
+    thread metal::texture2d_array<T> &texture,
12162
+    int level)
12163
+{
12164
+    return int3(texture.get_width(uint(level)), texture.get_height(uint(level)), texture.get_array_size());
12165
+}
12166
+)",
12167
+                        textureEnv())
12168
+
12169
+////////////////////////////////////////////////////////////////////////////////
12170
+
12171
+// Returned Name is valid for as long as `buffer` is still alive.
12172
+// Returns false if no template args exist.
12173
+// Returns false if buffer is not large enough.
12174
+//
12175
+// Example:
12176
+//  "foo<1,2>" --> "foo<>"
12177
+static std::pair<Name, bool> MaskTemplateArgs(const Name &name, size_t bufferSize, char *buffer)
12178
+{
12179
+    const char *begin = name.rawName().data();
12180
+    const char *end   = strchr(begin, '<');
12181
+    if (!end)
12182
+    {
12183
+        return {{}, false};
12184
+    }
12185
+    size_t n = end - begin;
12186
+    if (n + 3 > bufferSize)
12187
+    {
12188
+        return {{}, false};
12189
+    }
12190
+    for (size_t i = 0; i < n; ++i)
12191
+    {
12192
+        buffer[i] = begin[i];
12193
+    }
12194
+    buffer[n + 0] = '<';
12195
+    buffer[n + 1] = '>';
12196
+    buffer[n + 2] = '\0';
12197
+    return {Name(buffer, name.symbolType()), true};
12198
+}
12199
+
12200
+ProgramPrelude::FuncToEmitter ProgramPrelude::BuildFuncToEmitter()
12201
+{
12202
+#define EMIT_METHOD(method) \
12203
+    [](ProgramPrelude &pp, const TFunction &) -> void { return pp.method(); }
12204
+    FuncToEmitter map;
12205
+
12206
+    auto put = [&](Name name, FuncEmitter emitter) {
12207
+        FuncEmitter &dest = map[name];
12208
+        ASSERT(!dest);
12209
+        dest = emitter;
12210
+    };
12211
+
12212
+    auto putAngle = [&](const char *nameStr, FuncEmitter emitter) {
12213
+        Name name(nameStr, SymbolType::AngleInternal);
12214
+        put(name, emitter);
12215
+    };
12216
+
12217
+    auto putBuiltIn = [&](const char *nameStr, FuncEmitter emitter) {
12218
+        Name name(nameStr, SymbolType::BuiltIn);
12219
+        put(name, emitter);
12220
+    };
12221
+
12222
+    putAngle("addressof", EMIT_METHOD(addressof));
12223
+    putAngle("cast<>", EMIT_METHOD(castMatrix));
12224
+    putAngle("elem_ref", EMIT_METHOD(vectorElemRef));
12225
+    putAngle("flatten", EMIT_METHOD(flattenArray));
12226
+    putAngle("inout", EMIT_METHOD(inout));
12227
+    putAngle("out", EMIT_METHOD(out));
12228
+    putAngle("swizzle_ref", EMIT_METHOD(swizzleRef));
12229
+
12230
+    putBuiltIn("texelFetch", EMIT_METHOD(texelFetch));
12231
+    putBuiltIn("texelFetchOffset", EMIT_METHOD(texelFetchOffset));
12232
+    putBuiltIn("texture", [](ProgramPrelude &pp, const TFunction &func) {
12233
+        const ImmutableString textureName =
12234
+            GetTextureTypeName(func.getParam(0)->getType().getBasicType()).rawName();
12235
+        const TType &coord          = func.getParam(1)->getType();
12236
+        const TBasicType coordBasic = coord.getBasicType();
12237
+        const int coordN            = coord.getNominalSize();
12238
+        const bool bias             = func.getParamCount() >= 3;
12239
+        if (textureName.beginsWith("metal::depth2d<"))
12240
+        {
12241
+            if (coordBasic == TBasicType::EbtFloat && coordN == 3)
12242
+            {
12243
+                if (bias)
12244
+                {
12245
+                    return pp.texture_depth2d_float3_float();
12246
+                }
12247
+                return pp.texture_depth2d_float3();
12248
+            }
12249
+        }
12250
+        if (textureName.beginsWith("metal::depthcube<"))
12251
+        {
12252
+            if (coordBasic == TBasicType::EbtFloat && coordN == 4)
12253
+            {
12254
+                if (bias)
12255
+                {
12256
+                    return pp.texture_depthcube_float4_float();
12257
+                }
12258
+                return pp.texture_depthcube_float4();
12259
+            }
12260
+        }
12261
+        if (textureName.beginsWith("metal::depth2d_array<"))
12262
+        {
12263
+            if (coordBasic == TBasicType::EbtFloat && coordN == 4)
12264
+            {
12265
+                if (bias)
12266
+                {
12267
+                    return pp.texture_depth2darray_float4_float();
12268
+                }
12269
+                return pp.texture_depth2darray_float4();
12270
+            }
12271
+        }
12272
+        if (textureName.beginsWith("metal::texture2d_array<"))
12273
+        {
12274
+            if (coordBasic == TBasicType::EbtFloat && coordN == 3)
12275
+            {
12276
+                if (bias)
12277
+                {
12278
+                    return pp.texture_texture2darray_float3_float();
12279
+                }
12280
+                return pp.texture_texture2darray_float3();
12281
+            }
12282
+            if (coordBasic == TBasicType::EbtFloat && coordN == 4)
12283
+            {
12284
+                if (bias)
12285
+                {
12286
+                    return pp.texture_texture2darray_float4_float();
12287
+                }
12288
+                return pp.texture_texture2darray_float4();
12289
+            }
12290
+        }
12291
+        if (coordBasic == TBasicType::EbtFloat && coordN == 2)
12292
+        {
12293
+            if (bias)
12294
+            {
12295
+                return pp.texture_generic_float2_float();
12296
+            }
12297
+            return pp.texture_generic_float2();
12298
+        }
12299
+        if (coordBasic == TBasicType::EbtFloat && coordN == 3)
12300
+        {
12301
+            if (bias)
12302
+            {
12303
+                return pp.texture_generic_float3_float();
12304
+            }
12305
+            return pp.texture_generic_float3();
12306
+        }
12307
+        TODO();
12308
+    });
12309
+    putBuiltIn("texture1DLod", EMIT_METHOD(texture1DLod));
12310
+    putBuiltIn("texture1DProj", EMIT_METHOD(texture1DProj));
12311
+    putBuiltIn("texture1DProjLod", EMIT_METHOD(texture1DProjLod));
12312
+    putBuiltIn("texture2D", EMIT_METHOD(texture2D));
12313
+    putBuiltIn("texture2DLod", EMIT_METHOD(texture2DLod));
12314
+    putBuiltIn("texture2DProj", EMIT_METHOD(texture2DProj));
12315
+    putBuiltIn("texture3DLod", EMIT_METHOD(texture3DLod));
12316
+    putBuiltIn("texture3DProj", EMIT_METHOD(texture3DProj));
12317
+    putBuiltIn("texture3DProjLod", EMIT_METHOD(texture3DProjLod));
12318
+    putBuiltIn("textureCube", EMIT_METHOD(textureCube));
12319
+    putBuiltIn("textureCubeLod", EMIT_METHOD(textureCubeLod));
12320
+    putBuiltIn("textureCubeProj", EMIT_METHOD(textureCubeProj));
12321
+    putBuiltIn("textureCubeProjLod", EMIT_METHOD(textureCubeProjLod));
12322
+    putBuiltIn("texture2DProjLod", EMIT_METHOD(texture2DProjLod));
12323
+    putBuiltIn("textureGrad", [](ProgramPrelude &pp, const TFunction &func) {
12324
+        const ImmutableString textureName =
12325
+            GetTextureTypeName(func.getParam(0)->getType().getBasicType()).rawName();
12326
+        const TType &coord          = func.getParam(1)->getType();
12327
+        const TBasicType coordBasic = coord.getBasicType();
12328
+        const int coordN            = coord.getNominalSize();
12329
+        const TType &dPdx           = func.getParam(2)->getType();
12330
+        const int dPdxN             = dPdx.getNominalSize();
12331
+        if (textureName.beginsWith("metal::depth2d<"))
12332
+        {
12333
+            if (coordBasic == TBasicType::EbtFloat && coordN == 3 && dPdxN == 2)
12334
+            {
12335
+                return pp.textureGrad_depth2d_float3_float2_float2();
12336
+            }
12337
+        }
12338
+        if (textureName.beginsWith("metal::depth2d_array<"))
12339
+        {
12340
+            if (coordBasic == TBasicType::EbtFloat && coordN == 4 && dPdxN == 2)
12341
+            {
12342
+                return pp.textureGrad_depth2darray_float4_float2_float2();
12343
+            }
12344
+        }
12345
+        if (textureName.beginsWith("metal::depthcube<"))
12346
+        {
12347
+            if (coordBasic == TBasicType::EbtFloat && coordN == 4 && dPdxN == 3)
12348
+            {
12349
+                return pp.textureGrad_depthcube_float4_float3_float3();
12350
+            }
12351
+        }
12352
+        if (textureName.beginsWith("metal::texturecube<"))
12353
+        {
12354
+            if (coordBasic == TBasicType::EbtFloat && coordN == 3 && dPdxN == 3)
12355
+            {
12356
+                return pp.textureGrad_texturecube_float3_float3_float3();
12357
+            }
12358
+        }
12359
+        if (coordBasic == TBasicType::EbtFloat && coordN == 3 && dPdxN == 2)
12360
+        {
12361
+            return pp.textureGrad_generic_float3_float2_float2();
12362
+        }
12363
+        if (coordBasic == TBasicType::EbtFloat && coordN == 4 && dPdxN == 2)
12364
+        {
12365
+            return pp.textureGrad_generic_float4_float2_float2();
12366
+        }
12367
+        if (coordBasic == TBasicType::EbtFloat && coordN == dPdxN)
12368
+        {
12369
+            return pp.textureGrad_generic_floatN_floatN_floatN();
12370
+        }
12371
+        TODO();
12372
+    });
12373
+    putBuiltIn("textureGradOffset", [](ProgramPrelude &pp, const TFunction &func) {
12374
+        const ImmutableString textureName =
12375
+            GetTextureTypeName(func.getParam(0)->getType().getBasicType()).rawName();
12376
+        const TType &coord          = func.getParam(1)->getType();
12377
+        const TBasicType coordBasic = coord.getBasicType();
12378
+        const int coordN            = coord.getNominalSize();
12379
+        const TType &dPdx           = func.getParam(2)->getType();
12380
+        const int dPdxN             = dPdx.getNominalSize();
12381
+        if (textureName.beginsWith("metal::depth2d<"))
12382
+        {
12383
+            if (coordBasic == TBasicType::EbtFloat && coordN == 3 && dPdxN == 2)
12384
+            {
12385
+                return pp.textureGradOffset_depth2d_float3_float2_float2_int2();
12386
+            }
12387
+        }
12388
+        if (textureName.beginsWith("metal::depth2d_array<"))
12389
+        {
12390
+            if (coordBasic == TBasicType::EbtFloat && coordN == 4 && dPdxN == 2)
12391
+            {
12392
+                return pp.textureGradOffset_depth2darray_float4_float2_float2_int2();
12393
+            }
12394
+        }
12395
+        if (textureName.beginsWith("metal::depthcube<"))
12396
+        {
12397
+            if (coordBasic == TBasicType::EbtFloat && coordN == 4 && dPdxN == 3)
12398
+            {
12399
+                return pp.textureGradOffset_depthcube_float4_float3_float3_int3();
12400
+            }
12401
+        }
12402
+        if (textureName.beginsWith("metal::texturecube<"))
12403
+        {
12404
+            if (coordBasic == TBasicType::EbtFloat && coordN == 3 && dPdxN == 3)
12405
+            {
12406
+                return pp.textureGradOffset_texturecube_float3_float3_float3_int3();
12407
+            }
12408
+        }
12409
+        if (coordBasic == TBasicType::EbtFloat && coordN == 3 && dPdxN == 2)
12410
+        {
12411
+            return pp.textureGradOffset_generic_float3_float2_float2_int2();
12412
+        }
12413
+        if (coordBasic == TBasicType::EbtFloat && coordN == 4 && dPdxN == 2)
12414
+        {
12415
+            return pp.textureGradOffset_generic_float4_float2_float2_int2();
12416
+        }
12417
+        if (coordBasic == TBasicType::EbtFloat && coordN == dPdxN)
12418
+        {
12419
+            return pp.textureGradOffset_generic_floatN_floatN_floatN_intN();
12420
+        }
12421
+        TODO();
12422
+    });
12423
+    putBuiltIn("textureLod", [](ProgramPrelude &pp, const TFunction &func) {
12424
+        const ImmutableString textureName =
12425
+            GetTextureTypeName(func.getParam(0)->getType().getBasicType()).rawName();
12426
+        const TType &coord          = func.getParam(1)->getType();
12427
+        const TBasicType coordBasic = coord.getBasicType();
12428
+        const int coordN            = coord.getNominalSize();
12429
+        if (textureName.beginsWith("metal::depth2d<"))
12430
+        {
12431
+            if (coordBasic == TBasicType::EbtFloat && coordN == 3)
12432
+            {
12433
+                return pp.textureLod_depth2d_float3();
12434
+            }
12435
+        }
12436
+        if (textureName.beginsWith("metal::texture2d_array<"))
12437
+        {
12438
+            if (coordBasic == TBasicType::EbtFloat && coordN == 3)
12439
+            {
12440
+                return pp.textureLod_texture2darray_float3();
12441
+            }
12442
+            if (coordBasic == TBasicType::EbtFloat && coordN == 4)
12443
+            {
12444
+                return pp.textureLod_texture2darray_float4();
12445
+            }
12446
+        }
12447
+        if (coordBasic == TBasicType::EbtFloat && coordN == 2)
12448
+        {
12449
+            return pp.textureLod_generic_float2();
12450
+        }
12451
+        if (coordBasic == TBasicType::EbtFloat && coordN == 3)
12452
+        {
12453
+            return pp.textureLod_generic_float3();
12454
+        }
12455
+        TODO();
12456
+    });
12457
+    putBuiltIn("textureLodOffset", EMIT_METHOD(textureLodOffset));
12458
+    putBuiltIn("textureOffset", EMIT_METHOD(textureOffset));
12459
+    putBuiltIn("textureProj", EMIT_METHOD(textureProj));
12460
+    putBuiltIn("textureProjGrad", [](ProgramPrelude &pp, const TFunction &func) {
12461
+        const ImmutableString textureName =
12462
+            GetTextureTypeName(func.getParam(0)->getType().getBasicType()).rawName();
12463
+        const TType &coord          = func.getParam(1)->getType();
12464
+        const TBasicType coordBasic = coord.getBasicType();
12465
+        const int coordN            = coord.getNominalSize();
12466
+        const TType &dPdx           = func.getParam(2)->getType();
12467
+        const int dPdxN             = dPdx.getNominalSize();
12468
+        if (textureName.beginsWith("metal::depth2d<"))
12469
+        {
12470
+            if (coordBasic == TBasicType::EbtFloat && coordN == 4 && dPdxN == 2)
12471
+            {
12472
+                return pp.textureProjGrad_depth2d_float4_float2_float2();
12473
+            }
12474
+        }
12475
+        if (textureName.beginsWith("metal::texture3d<"))
12476
+        {
12477
+            if (coordBasic == TBasicType::EbtFloat && coordN == 4 && dPdxN == 3)
12478
+            {
12479
+                return pp.textureProjGrad_texture3d_float4_float3_float3();
12480
+            }
12481
+        }
12482
+        if (coordBasic == TBasicType::EbtFloat && coordN == 3 && dPdxN == 2)
12483
+        {
12484
+            return pp.textureProjGrad_generic_float3_float2_float2();
12485
+        }
12486
+        if (coordBasic == TBasicType::EbtFloat && coordN == 4 && dPdxN == 2)
12487
+        {
12488
+            return pp.textureProjGrad_generic_float4_float2_float2();
12489
+        }
12490
+        TODO();
12491
+    });
12492
+    putBuiltIn("textureProjGradOffset", [](ProgramPrelude &pp, const TFunction &func) {
12493
+        const ImmutableString textureName =
12494
+            GetTextureTypeName(func.getParam(0)->getType().getBasicType()).rawName();
12495
+        const TType &coord          = func.getParam(1)->getType();
12496
+        const TBasicType coordBasic = coord.getBasicType();
12497
+        const int coordN            = coord.getNominalSize();
12498
+        const TType &dPdx           = func.getParam(2)->getType();
12499
+        const int dPdxN             = dPdx.getNominalSize();
12500
+        if (textureName.beginsWith("metal::depth2d<"))
12501
+        {
12502
+            if (coordBasic == TBasicType::EbtFloat && coordN == 4 && dPdxN == 2)
12503
+            {
12504
+                return pp.textureProjGradOffset_depth2d_float4_float2_float2_int2();
12505
+            }
12506
+        }
12507
+        if (textureName.beginsWith("metal::texture3d<"))
12508
+        {
12509
+            if (coordBasic == TBasicType::EbtFloat && coordN == 4 && dPdxN == 3)
12510
+            {
12511
+                return pp.textureProjGradOffset_texture3d_float4_float3_float3_int3();
12512
+            }
12513
+        }
12514
+        if (coordBasic == TBasicType::EbtFloat && coordN == 3 && dPdxN == 2)
12515
+        {
12516
+            return pp.textureProjGradOffset_generic_float3_float2_float2_int2();
12517
+        }
12518
+        if (coordBasic == TBasicType::EbtFloat && coordN == 4 && dPdxN == 2)
12519
+        {
12520
+            return pp.textureProjGradOffset_generic_float4_float2_float2_int2();
12521
+        }
12522
+        TODO();
12523
+    });
12524
+    putBuiltIn("textureProjLod", [](ProgramPrelude &pp, const TFunction &func) {
12525
+        const ImmutableString textureName =
12526
+            GetTextureTypeName(func.getParam(0)->getType().getBasicType()).rawName();
12527
+        const TType &coord          = func.getParam(1)->getType();
12528
+        const TBasicType coordBasic = coord.getBasicType();
12529
+        const int coordN            = coord.getNominalSize();
12530
+        if (textureName.beginsWith("metal::depth2d<"))
12531
+        {
12532
+            if (coordBasic == TBasicType::EbtFloat && coordN == 4)
12533
+            {
12534
+                return pp.textureProjLod_depth2d_float4();
12535
+            }
12536
+        }
12537
+        if (textureName.beginsWith("metal::texture3d<"))
12538
+        {
12539
+            if (coordBasic == TBasicType::EbtFloat && coordN == 4)
12540
+            {
12541
+                return pp.textureProjLod_texture3d_float4();
12542
+            }
12543
+        }
12544
+        if (coordBasic == TBasicType::EbtFloat && coordN == 3)
12545
+        {
12546
+            return pp.textureProjLod_generic_float3();
12547
+        }
12548
+        if (coordBasic == TBasicType::EbtFloat && coordN == 4)
12549
+        {
12550
+            return pp.textureProjLod_generic_float4();
12551
+        }
12552
+        TODO();
12553
+    });
12554
+    putBuiltIn("textureProjLodOffset", EMIT_METHOD(textureProjLodOffset));
12555
+    putBuiltIn("textureProjOffset", EMIT_METHOD(textureProjOffset));
12556
+    putBuiltIn("textureSize", EMIT_METHOD(textureSize));
12557
+
12558
+    return map;
12559
+
12560
+#undef EMIT_METHOD
12561
+}
12562
+
12563
+void ProgramPrelude::visitOperator(TOperator op,
12564
+                                   const TFunction *func,
12565
+                                   const TType *argType0,
12566
+                                   const TType *argType1)
12567
+{
12568
+    switch (op)
12569
+    {
12570
+        case TOperator::EOpRadians:
12571
+            radians();
12572
+            break;
12573
+        case TOperator::EOpDegrees:
12574
+            degrees();
12575
+            break;
12576
+        case TOperator::EOpAtan:
12577
+            atan();
12578
+            break;
12579
+        case TOperator::EOpMod:
12580
+            mod();
12581
+            break;
12582
+        case TOperator::EOpRefract:
12583
+            refract();
12584
+            break;
12585
+        case TOperator::EOpDistance:
12586
+            distance();
12587
+            break;
12588
+        case TOperator::EOpLength:
12589
+            length();
12590
+            break;
12591
+        case TOperator::EOpDot:
12592
+            dot();
12593
+            break;
12594
+        case TOperator::EOpNormalize:
12595
+            normalize();
12596
+            break;
12597
+        case TOperator::EOpFaceforward:
12598
+            faceforward();
12599
+            break;
12600
+        case TOperator::EOpReflect:
12601
+            reflect();
12602
+            break;
12603
+
12604
+        case TOperator::EOpSin:
12605
+        case TOperator::EOpCos:
12606
+        case TOperator::EOpTan:
12607
+        case TOperator::EOpAsin:
12608
+        case TOperator::EOpAcos:
12609
+        case TOperator::EOpSinh:
12610
+        case TOperator::EOpCosh:
12611
+        case TOperator::EOpTanh:
12612
+        case TOperator::EOpAsinh:
12613
+        case TOperator::EOpAcosh:
12614
+        case TOperator::EOpAtanh:
12615
+        case TOperator::EOpAbs:
12616
+        case TOperator::EOpFma:
12617
+        case TOperator::EOpPow:
12618
+        case TOperator::EOpExp:
12619
+        case TOperator::EOpExp2:
12620
+        case TOperator::EOpLog:
12621
+        case TOperator::EOpLog2:
12622
+        case TOperator::EOpSqrt:
12623
+        case TOperator::EOpFloor:
12624
+        case TOperator::EOpTrunc:
12625
+        case TOperator::EOpCeil:
12626
+        case TOperator::EOpFract:
12627
+        case TOperator::EOpRound:
12628
+        case TOperator::EOpRoundEven:
12629
+        case TOperator::EOpModf:
12630
+        case TOperator::EOpLdexp:
12631
+        case TOperator::EOpFrexp:
12632
+        case TOperator::EOpInversesqrt:
12633
+            include_metal_math();
12634
+            break;
12635
+
12636
+        case TOperator::EOpEqual:
12637
+            if (argType0->isVector() && argType1->isVector())
12638
+            {
12639
+                equalVector();
12640
+            }
12641
+            // Even if Arg0 is a vector or matrix, it could also be an array.
12642
+            if (argType0->isArray() && argType1->isArray())
12643
+            {
12644
+                equalArray();
12645
+            }
12646
+            break;
12647
+
12648
+        case TOperator::EOpNotEqual:
12649
+            if (argType0->isVector() && argType1->isVector())
12650
+            {
12651
+                notEqualVector();
12652
+            }
12653
+            else if (argType0->getStruct() && argType1->getStruct())
12654
+            {
12655
+                notEqualStruct();
12656
+            }
12657
+            // Same as above.
12658
+            if (argType0->isArray() && argType1->isArray())
12659
+            {
12660
+                notEqualArray();
12661
+            }
12662
+            break;
12663
+
12664
+        case TOperator::EOpCross:
12665
+            include_metal_geometric();
12666
+            break;
12667
+
12668
+        case TOperator::EOpSign:
12669
+            sign();
12670
+            break;
12671
+
12672
+        case TOperator::EOpClamp:
12673
+        case TOperator::EOpMin:
12674
+        case TOperator::EOpMax:
12675
+        case TOperator::EOpMix:
12676
+        case TOperator::EOpStep:
12677
+        case TOperator::EOpSmoothstep:
12678
+            include_metal_common();
12679
+            break;
12680
+
12681
+        case TOperator::EOpAll:
12682
+        case TOperator::EOpAny:
12683
+        case TOperator::EOpIsnan:
12684
+        case TOperator::EOpIsinf:
12685
+            include_metal_relational();
12686
+            break;
12687
+
12688
+        case TOperator::EOpDFdx:
12689
+        case TOperator::EOpDFdy:
12690
+        case TOperator::EOpFwidth:
12691
+            include_metal_graphics();
12692
+            break;
12693
+
12694
+        case TOperator::EOpTranspose:
12695
+        case TOperator::EOpDeterminant:
12696
+            include_metal_matrix();
12697
+            break;
12698
+
12699
+        case TOperator::EOpAdd:
12700
+            if (argType0->isMatrix() && argType1->isScalar())
12701
+            {
12702
+                addMatrixScalar();
12703
+            }
12704
+            break;
12705
+
12706
+        case TOperator::EOpSub:
12707
+            if (argType0->isMatrix() && argType1->isScalar())
12708
+            {
12709
+                subMatrixScalar();
12710
+            }
12711
+            break;
12712
+
12713
+        case TOperator::EOpDiv:
12714
+            if (argType0->isMatrix())
12715
+            {
12716
+                if (argType1->isMatrix())
12717
+                {
12718
+                    componentWiseDivide();
12719
+                }
12720
+                else if (argType1->isScalar())
12721
+                {
12722
+                    divMatrixScalar();
12723
+                }
12724
+            }
12725
+            break;
12726
+
12727
+        case TOperator::EOpDivAssign:
12728
+            if (argType0->isMatrix() && argType1->isMatrix())
12729
+            {
12730
+                componentWiseDivideAssign();
12731
+            }
12732
+            break;
12733
+
12734
+        case TOperator::EOpMulMatrixComponentWise:
12735
+            if (argType0->isMatrix() && argType1->isMatrix())
12736
+            {
12737
+                componentWiseMultiply();
12738
+            }
12739
+            break;
12740
+
12741
+        case TOperator::EOpOuterProduct:
12742
+            outerProduct();
12743
+            break;
12744
+
12745
+        case TOperator::EOpInverse:
12746
+            switch (argType0->getCols())
12747
+            {
12748
+                case 2:
12749
+                    inverse2();
12750
+                    break;
12751
+                case 3:
12752
+                    inverse3();
12753
+                    break;
12754
+                case 4:
12755
+                    inverse4();
12756
+                    break;
12757
+                default:
12758
+                    LOGIC_ERROR();
12759
+            }
12760
+            break;
12761
+
12762
+        case TOperator::EOpMatrixTimesMatrixAssign:
12763
+            matmulAssign();
12764
+            break;
12765
+
12766
+        case TOperator::EOpPreIncrement:
12767
+            if (argType0->isMatrix())
12768
+            {
12769
+                preIncrementMatrix();
12770
+            }
12771
+            break;
12772
+
12773
+        case TOperator::EOpPostIncrement:
12774
+            if (argType0->isMatrix())
12775
+            {
12776
+                postIncrementMatrix();
12777
+            }
12778
+            break;
12779
+
12780
+        case TOperator::EOpPreDecrement:
12781
+            if (argType0->isMatrix())
12782
+            {
12783
+                preDecrementMatrix();
12784
+            }
12785
+            break;
12786
+
12787
+        case TOperator::EOpPostDecrement:
12788
+            if (argType0->isMatrix())
12789
+            {
12790
+                postDecrementMatrix();
12791
+            }
12792
+            break;
12793
+
12794
+            break;
12795
+
12796
+        case TOperator::EOpNegative:
12797
+            if (argType0->isMatrix())
12798
+            {
12799
+                negateMatrix();
12800
+            }
12801
+            break;
12802
+
12803
+        case TOperator::EOpComma:
12804
+        case TOperator::EOpAssign:
12805
+        case TOperator::EOpInitialize:
12806
+        case TOperator::EOpAddAssign:
12807
+        case TOperator::EOpSubAssign:
12808
+        case TOperator::EOpMulAssign:
12809
+        case TOperator::EOpIModAssign:
12810
+        case TOperator::EOpBitShiftLeftAssign:
12811
+        case TOperator::EOpBitShiftRightAssign:
12812
+        case TOperator::EOpBitwiseAndAssign:
12813
+        case TOperator::EOpBitwiseXorAssign:
12814
+        case TOperator::EOpBitwiseOrAssign:
12815
+        case TOperator::EOpMul:
12816
+        case TOperator::EOpIMod:
12817
+        case TOperator::EOpBitShiftLeft:
12818
+        case TOperator::EOpBitShiftRight:
12819
+        case TOperator::EOpBitwiseAnd:
12820
+        case TOperator::EOpBitwiseXor:
12821
+        case TOperator::EOpBitwiseOr:
12822
+        case TOperator::EOpLessThan:
12823
+        case TOperator::EOpGreaterThan:
12824
+        case TOperator::EOpLessThanEqual:
12825
+        case TOperator::EOpGreaterThanEqual:
12826
+        case TOperator::EOpLessThanComponentWise:
12827
+        case TOperator::EOpLessThanEqualComponentWise:
12828
+        case TOperator::EOpGreaterThanEqualComponentWise:
12829
+        case TOperator::EOpGreaterThanComponentWise:
12830
+        case TOperator::EOpLogicalOr:
12831
+        case TOperator::EOpLogicalXor:
12832
+        case TOperator::EOpLogicalAnd:
12833
+        case TOperator::EOpPositive:
12834
+        case TOperator::EOpLogicalNot:
12835
+        case TOperator::EOpLogicalNotComponentWise:
12836
+        case TOperator::EOpBitwiseNot:
12837
+        case TOperator::EOpVectorTimesScalarAssign:
12838
+        case TOperator::EOpVectorTimesMatrixAssign:
12839
+        case TOperator::EOpMatrixTimesScalarAssign:
12840
+        case TOperator::EOpVectorTimesScalar:
12841
+        case TOperator::EOpVectorTimesMatrix:
12842
+        case TOperator::EOpMatrixTimesVector:
12843
+        case TOperator::EOpMatrixTimesScalar:
12844
+        case TOperator::EOpMatrixTimesMatrix:
12845
+        case TOperator::EOpReturn:
12846
+        case TOperator::EOpBreak:
12847
+        case TOperator::EOpContinue:
12848
+        case TOperator::EOpEqualComponentWise:
12849
+        case TOperator::EOpNotEqualComponentWise:
12850
+        case TOperator::EOpIndexDirect:
12851
+        case TOperator::EOpIndexIndirect:
12852
+        case TOperator::EOpIndexDirectStruct:
12853
+        case TOperator::EOpIndexDirectInterfaceBlock:
12854
+        case TOperator::EOpFloatBitsToInt:
12855
+        case TOperator::EOpIntBitsToFloat:
12856
+        case TOperator::EOpUintBitsToFloat:
12857
+        case TOperator::EOpFloatBitsToUint:
12858
+        case TOperator::EOpNull:
12859
+            // do nothing
12860
+            break;
12861
+
12862
+        case TOperator::EOpKill:
12863
+            include_metal_graphics();
12864
+            break;
12865
+
12866
+        case TOperator::EOpPackUnorm2x16:
12867
+        case TOperator::EOpPackSnorm2x16:
12868
+        case TOperator::EOpPackUnorm4x8:
12869
+        case TOperator::EOpPackSnorm4x8:
12870
+        case TOperator::EOpUnpackSnorm2x16:
12871
+        case TOperator::EOpUnpackUnorm2x16:
12872
+        case TOperator::EOpUnpackUnorm4x8:
12873
+        case TOperator::EOpUnpackSnorm4x8:
12874
+            include_metal_pack();
12875
+            break;
12876
+
12877
+        case TOperator::EOpPackHalf2x16:
12878
+            pack_half_2x16();
12879
+            break;
12880
+        case TOperator::EOpUnpackHalf2x16:
12881
+            unpack_half_2x16();
12882
+            break;
12883
+
12884
+        case TOperator::EOpBitfieldExtract:
12885
+        case TOperator::EOpBitfieldInsert:
12886
+        case TOperator::EOpBitfieldReverse:
12887
+        case TOperator::EOpBitCount:
12888
+        case TOperator::EOpFindLSB:
12889
+        case TOperator::EOpFindMSB:
12890
+        case TOperator::EOpUaddCarry:
12891
+        case TOperator::EOpUsubBorrow:
12892
+        case TOperator::EOpUmulExtended:
12893
+        case TOperator::EOpImulExtended:
12894
+        case TOperator::EOpBarrier:
12895
+        case TOperator::EOpMemoryBarrier:
12896
+        case TOperator::EOpMemoryBarrierAtomicCounter:
12897
+        case TOperator::EOpMemoryBarrierBuffer:
12898
+        case TOperator::EOpMemoryBarrierImage:
12899
+        case TOperator::EOpMemoryBarrierShared:
12900
+        case TOperator::EOpGroupMemoryBarrier:
12901
+        case TOperator::EOpAtomicAdd:
12902
+        case TOperator::EOpAtomicMin:
12903
+        case TOperator::EOpAtomicMax:
12904
+        case TOperator::EOpAtomicAnd:
12905
+        case TOperator::EOpAtomicOr:
12906
+        case TOperator::EOpAtomicXor:
12907
+        case TOperator::EOpAtomicExchange:
12908
+        case TOperator::EOpAtomicCompSwap:
12909
+        case TOperator::EOpEmitVertex:
12910
+        case TOperator::EOpEndPrimitive:
12911
+        case TOperator::EOpFTransform:
12912
+        case TOperator::EOpPackDouble2x32:
12913
+        case TOperator::EOpUnpackDouble2x32:
12914
+        case TOperator::EOpArrayLength:
12915
+            TODO();
12916
+            break;
12917
+
12918
+        case TOperator::EOpConstruct:
12919
+            ASSERT(!func);
12920
+            break;
12921
+
12922
+        case TOperator::EOpCallFunctionInAST:
12923
+        case TOperator::EOpCallInternalRawFunction:
12924
+        case TOperator::EOpCallBuiltInFunction:
12925
+            ASSERT(func);
12926
+            if (mHandled.insert(func).second)
12927
+            {
12928
+                const Name name(*func);
12929
+                const auto end = mFuncToEmitter.end();
12930
+                auto iter      = mFuncToEmitter.find(name);
12931
+                if (iter == end)
12932
+                {
12933
+                    char buffer[32];
12934
+                    auto mask = MaskTemplateArgs(name, sizeof(buffer), buffer);
12935
+                    if (mask.second)
12936
+                    {
12937
+                        iter = mFuncToEmitter.find(mask.first);
12938
+                    }
12939
+                }
12940
+                if (iter != end)
12941
+                {
12942
+                    const auto &emitter = iter->second;
12943
+                    emitter(*this, *func);
12944
+                }
12945
+            }
12946
+            break;
12947
+    }
12948
+}
12949
+
12950
+void ProgramPrelude::visitVariable(const Name &name, const TType &type)
12951
+{
12952
+    if (const TStructure *s = type.getStruct())
12953
+    {
12954
+        const Name typeName(*s);
12955
+        if (typeName.beginsWith(Name("TextureEnv<")))
12956
+        {
12957
+            textureEnv();
12958
+        }
12959
+    }
12960
+    else
12961
+    {
12962
+        if (name == constant_names::kRasterizationDiscardEnabled)
12963
+        {
12964
+            functionConstants();
12965
+        }
12966
+    }
12967
+}
12968
+
12969
+void ProgramPrelude::visitVariable(const TVariable &var)
12970
+{
12971
+    if (mHandled.insert(&var).second)
12972
+    {
12973
+        visitVariable(Name(var), var.getType());
12974
+    }
12975
+}
12976
+
12977
+void ProgramPrelude::visitStructure(const TStructure &s)
12978
+{
12979
+    if (mHandled.insert(&s).second)
12980
+    {
12981
+        for (const TField *field : s.fields())
12982
+        {
12983
+            const TType &type = *field->type();
12984
+            visitVariable(Name(*field), type);
12985
+        }
12986
+    }
12987
+}
12988
+
12989
+bool ProgramPrelude::visitBinary(Visit visit, TIntermBinary *node)
12990
+{
12991
+    const TType &leftType  = node->getLeft()->getType();
12992
+    const TType &rightType = node->getRight()->getType();
12993
+    visitOperator(node->getOp(), nullptr, &leftType, &rightType);
12994
+    return true;
12995
+}
12996
+
12997
+bool ProgramPrelude::visitUnary(Visit visit, TIntermUnary *node)
12998
+{
12999
+    const TType &argType = node->getOperand()->getType();
13000
+    visitOperator(node->getOp(), nullptr, &argType);
13001
+    return true;
13002
+}
13003
+
13004
+bool ProgramPrelude::visitAggregate(Visit visit, TIntermAggregate *node)
13005
+{
13006
+    const size_t argCount = node->getChildCount();
13007
+
13008
+    auto getArgType = [node, argCount](size_t index) -> const TType & {
13009
+        ASSERT(index < argCount);
13010
+        TIntermTyped *arg = node->getChildNode(index)->getAsTyped();
13011
+        ASSERT(arg);
13012
+        return arg->getType();
13013
+    };
13014
+
13015
+    const TFunction *func = node->getFunction();
13016
+
13017
+    switch (node->getChildCount())
13018
+    {
13019
+        case 0:
13020
+        {
13021
+            visitOperator(node->getOp(), func, nullptr);
13022
+        }
13023
+        break;
13024
+
13025
+        case 1:
13026
+        {
13027
+            const TType &argType0 = getArgType(0);
13028
+            visitOperator(node->getOp(), func, &argType0);
13029
+        }
13030
+        break;
13031
+
13032
+        case 2:
13033
+        {
13034
+            const TType &argType0 = getArgType(0);
13035
+            const TType &argType1 = getArgType(1);
13036
+            visitOperator(node->getOp(), func, &argType0, &argType1);
13037
+        }
13038
+        break;
13039
+
13040
+        default:
13041
+        {
13042
+            const TType &argType0 = getArgType(0);
13043
+            const TType &argType1 = getArgType(1);
13044
+            visitOperator(node->getOp(), func, &argType0, &argType1);
13045
+        }
13046
+        break;
13047
+    }
13048
+
13049
+    return true;
13050
+}
13051
+
13052
+bool ProgramPrelude::visitDeclaration(Visit, TIntermDeclaration *node)
13053
+{
13054
+    Declaration decl  = ViewDeclaration(*node);
13055
+    const TType &type = decl.symbol.getType();
13056
+    if (type.isStructSpecifier())
13057
+    {
13058
+        const TStructure *s = type.getStruct();
13059
+        ASSERT(s);
13060
+        visitStructure(*s);
13061
+    }
13062
+    return true;
13063
+}
13064
+
13065
+void ProgramPrelude::visitSymbol(TIntermSymbol *node)
13066
+{
13067
+    visitVariable(node->variable());
13068
+}
13069
+
13070
+bool sh::EmitProgramPrelude(TIntermBlock &root, TInfoSinkBase &out, const ProgramPreludeConfig &ppc)
13071
+{
13072
+    ProgramPrelude programPrelude(out, ppc);
13073
+    root.traverse(&programPrelude);
13074
+    return true;
13075
+}
13076
diff --git a/src/compiler/translator/TranslatorMetalDirect/ProgramPrelude.h b/src/compiler/translator/TranslatorMetalDirect/ProgramPrelude.h
13077
new file mode 100644
13078
index 0000000..e00413f
13079
--- /dev/null
13080
+++ b/src/compiler/translator/TranslatorMetalDirect/ProgramPrelude.h
13081
@@ -0,0 +1,35 @@
13082
+//
13083
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
13084
+// Use of this source code is governed by a BSD-style license that can be
13085
+// found in the LICENSE file.
13086
+//
13087
+
13088
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_PROGRAMPRELUDE_H_
13089
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_PROGRAMPRELUDE_H_
13090
+
13091
+#include <unordered_set>
13092
+
13093
+#include "common/angleutils.h"
13094
+
13095
+namespace sh
13096
+{
13097
+
13098
+class TInfoSinkBase;
13099
+class TIntermBlock;
13100
+
13101
+struct ProgramPreludeConfig
13102
+{
13103
+    bool hasStructEq = false;
13104
+};
13105
+
13106
+// This emits fixed helper Metal code directly without adding code to the AST. This walks the AST to
13107
+// figure out the required what prelude MSL code is needed for various things in the AST. You can
13108
+// think of this as effectively inlining various portions of a helper library into the emitted
13109
+// Metal program.
13110
+ANGLE_NO_DISCARD bool EmitProgramPrelude(TIntermBlock &root,
13111
+                                         TInfoSinkBase &out,
13112
+                                         const ProgramPreludeConfig &ppc);
13113
+
13114
+}  // namespace sh
13115
+
13116
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_PROGRAMPRELUDE_H_
13117
diff --git a/src/compiler/translator/TranslatorMetalDirect/ReduceInterfaceBlocks.cpp b/src/compiler/translator/TranslatorMetalDirect/ReduceInterfaceBlocks.cpp
13118
new file mode 100644
13119
index 0000000..aa81696
13120
--- /dev/null
13121
+++ b/src/compiler/translator/TranslatorMetalDirect/ReduceInterfaceBlocks.cpp
13122
@@ -0,0 +1,130 @@
13123
+//
13124
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
13125
+// Use of this source code is governed by a BSD-style license that can be
13126
+// found in the LICENSE file.
13127
+//
13128
+
13129
+#include <algorithm>
13130
+#include <unordered_map>
13131
+
13132
+#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
13133
+#include "compiler/translator/TranslatorMetalDirect/ReduceInterfaceBlocks.h"
13134
+#include "compiler/translator/tree_ops/SeparateDeclarations.h"
13135
+#include "compiler/translator/tree_util/IntermRebuild.h"
13136
+
13137
+using namespace sh;
13138
+
13139
+////////////////////////////////////////////////////////////////////////////////
13140
+
13141
+namespace
13142
+{
13143
+
13144
+class Reducer : public TIntermRebuild
13145
+{
13146
+    std::unordered_map<const TInterfaceBlock *, std::map<ImmutableString, const TVariable *>>
13147
+        mLiftedMap;
13148
+    std::unordered_map<const TVariable *, const TVariable *> mInstanceMap;
13149
+
13150
+  public:
13151
+    Reducer(TCompiler &compiler) : TIntermRebuild(compiler, true, false) {}
13152
+
13153
+    PreResult visitDeclarationPre(TIntermDeclaration &declNode) override
13154
+    {
13155
+        ASSERT(declNode.getChildCount() == 1);
13156
+        TIntermNode &node = *declNode.getChildNode(0);
13157
+
13158
+        if (TIntermSymbol *symbolNode = node.getAsSymbolNode())
13159
+        {
13160
+            const TVariable &var        = symbolNode->variable();
13161
+            const TType &type           = var.getType();
13162
+            const SymbolType symbolType = var.symbolType();
13163
+            if (const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock())
13164
+            {
13165
+                if (symbolType == SymbolType::Empty)
13166
+                {
13167
+                    auto &nameToVar = mLiftedMap[interfaceBlock];
13168
+                    std::vector<TIntermNode *> replacements;
13169
+                    for (TField *field : interfaceBlock->fields())
13170
+                    {
13171
+                        auto &liftedType = CloneType(*field->type());
13172
+                        ASSERT(liftedType.getQualifier() == TQualifier::EvqUniform ||
13173
+                               liftedType.getQualifier() == TQualifier::EvqGlobal);
13174
+                        liftedType.setQualifier(TQualifier::EvqUniform);
13175
+                        auto *liftedVar = new TVariable(&mSymbolTable, field->name(), &liftedType,
13176
+                                                        field->symbolType());
13177
+
13178
+                        nameToVar[field->name()] = liftedVar;
13179
+
13180
+                        replacements.push_back(
13181
+                            new TIntermDeclaration{new TIntermSymbol(liftedVar)});
13182
+                    }
13183
+                    return PreResult::Multi(std::move(replacements));
13184
+                }
13185
+                else
13186
+                {
13187
+                    ASSERT(type.getQualifier() == TQualifier::EvqUniform);
13188
+
13189
+                    auto &structure =
13190
+                        *new TStructure(&mSymbolTable, interfaceBlock->name(),
13191
+                                        &interfaceBlock->fields(), interfaceBlock->symbolType());
13192
+                    auto &structVar = CreateStructTypeVariable(mSymbolTable, structure);
13193
+                    auto &instanceVar =
13194
+                        CreateInstanceVariable(mSymbolTable, structure, Name(var),
13195
+                                               TQualifier::EvqUniform, &type.getArraySizes());
13196
+
13197
+                    mInstanceMap[&var] = &instanceVar;
13198
+
13199
+                    TIntermNode *replacements[] = {
13200
+                        new TIntermDeclaration{new TIntermSymbol(&structVar)},
13201
+                        new TIntermDeclaration{new TIntermSymbol(&instanceVar)}};
13202
+                    return PreResult::Multi(std::begin(replacements), std::end(replacements));
13203
+                }
13204
+            }
13205
+        }
13206
+
13207
+        return {declNode, VisitBits::Neither};
13208
+    }
13209
+
13210
+    PreResult visitSymbolPre(TIntermSymbol &symbolNode) override
13211
+    {
13212
+        const TVariable &var = symbolNode.variable();
13213
+        {
13214
+            auto it = mInstanceMap.find(&var);
13215
+            if (it != mInstanceMap.end())
13216
+            {
13217
+                return *new TIntermSymbol(it->second);
13218
+            }
13219
+        }
13220
+        if (const TInterfaceBlock *ib = var.getType().getInterfaceBlock())
13221
+        {
13222
+            auto it = mLiftedMap.find(ib);
13223
+            if (it != mLiftedMap.end())
13224
+            {
13225
+                auto *liftedVar = it->second[var.name()];
13226
+                ASSERT(liftedVar);
13227
+                return *new TIntermSymbol(liftedVar);
13228
+            }
13229
+        }
13230
+        return symbolNode;
13231
+    }
13232
+};
13233
+
13234
+}  // anonymous namespace
13235
+
13236
+////////////////////////////////////////////////////////////////////////////////
13237
+
13238
+bool sh::ReduceInterfaceBlocks(TCompiler &compiler, TIntermBlock &root)
13239
+{
13240
+    Reducer reducer(compiler);
13241
+    if (!reducer.rebuildRoot(root))
13242
+    {
13243
+        return false;
13244
+    }
13245
+
13246
+    if (!SeparateDeclarations(&compiler, &root))
13247
+    {
13248
+        return false;
13249
+    }
13250
+
13251
+    return true;
13252
+}
13253
diff --git a/src/compiler/translator/TranslatorMetalDirect/ReduceInterfaceBlocks.h b/src/compiler/translator/TranslatorMetalDirect/ReduceInterfaceBlocks.h
13254
new file mode 100644
13255
index 0000000..3695cba
13256
--- /dev/null
13257
+++ b/src/compiler/translator/TranslatorMetalDirect/ReduceInterfaceBlocks.h
13258
@@ -0,0 +1,35 @@
13259
+//
13260
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
13261
+// Use of this source code is governed by a BSD-style license that can be
13262
+// found in the LICENSE file.
13263
+//
13264
+
13265
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REDUCEINTERFACEBLOCKS_H_
13266
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REDUCEINTERFACEBLOCKS_H_
13267
+
13268
+#include "common/angleutils.h"
13269
+#include "compiler/translator/Compiler.h"
13270
+
13271
+namespace sh
13272
+{
13273
+
13274
+// This rewrites interface block declarations only.
13275
+//
13276
+// Access of interface blocks is not rewritten (e.g. TOperator::EOpIndexDirectInterfaceBlock). //
13277
+// XXX: ^ Still true?
13278
+//
13279
+// Example:
13280
+//  uniform Foo { int x; };
13281
+// Becomes:
13282
+//  uniform int x;
13283
+//
13284
+// Example:
13285
+//  uniform Foo { int x; } foo;
13286
+// Becomes:
13287
+//  struct Foo { int x; }; uniform Foo x;
13288
+//
13289
+ANGLE_NO_DISCARD bool ReduceInterfaceBlocks(TCompiler &compiler, TIntermBlock &root);
13290
+
13291
+}  // namespace sh
13292
+
13293
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REDUCEINTERFACEBLOCKS_H_
13294
diff --git a/src/compiler/translator/TranslatorMetalDirect/Reference.h b/src/compiler/translator/TranslatorMetalDirect/Reference.h
13295
new file mode 100644
13296
index 0000000..4b5d86c
13297
--- /dev/null
13298
+++ b/src/compiler/translator/TranslatorMetalDirect/Reference.h
13299
@@ -0,0 +1,50 @@
13300
+//
13301
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
13302
+// Use of this source code is governed by a BSD-style license that can be
13303
+// found in the LICENSE file.
13304
+//
13305
+
13306
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REFERENCE_H_
13307
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REFERENCE_H_
13308
+
13309
+namespace sh
13310
+{
13311
+
13312
+// Similar to std::reference_wrapper, but also lifts comparison operators.
13313
+template <typename T>
13314
+class Ref
13315
+{
13316
+  public:
13317
+    Ref(const Ref &) = default;
13318
+    Ref(Ref &&)      = default;
13319
+    Ref(T &ref) : mPtr(&ref) {}
13320
+
13321
+    Ref &operator=(const Ref &) = default;
13322
+    Ref &operator=(Ref &&) = default;
13323
+
13324
+    bool operator==(const Ref &other) const { return *mPtr == *other.mPtr; }
13325
+    bool operator!=(const Ref &other) const { return *mPtr != *other.mPtr; }
13326
+    bool operator<=(const Ref &other) const { return *mPtr <= *other.mPtr; }
13327
+    bool operator>=(const Ref &other) const { return *mPtr >= *other.mPtr; }
13328
+    bool operator<(const Ref &other) const { return *mPtr < *other.mPtr; }
13329
+    bool operator>(const Ref &other) const { return *mPtr > *other.mPtr; }
13330
+
13331
+    T &get() { return *mPtr; }
13332
+    T const &get() const { return *mPtr; }
13333
+
13334
+    operator T &() { return *mPtr; }
13335
+    operator T const &() const { return *mPtr; }
13336
+
13337
+    operator T *() { return *mPtr; }
13338
+    operator T const *() const { return *mPtr; }
13339
+
13340
+  private:
13341
+    T *mPtr;
13342
+};
13343
+
13344
+template <typename T>
13345
+using CRef = Ref<T const>;
13346
+
13347
+}  // namespace sh
13348
+
13349
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REFERENCE_H_
13350
diff --git a/src/compiler/translator/TranslatorMetalDirect/RewriteCaseDeclarations.cpp b/src/compiler/translator/TranslatorMetalDirect/RewriteCaseDeclarations.cpp
13351
new file mode 100644
13352
index 0000000..c778177
13353
--- /dev/null
13354
+++ b/src/compiler/translator/TranslatorMetalDirect/RewriteCaseDeclarations.cpp
13355
@@ -0,0 +1,91 @@
13356
+//
13357
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
13358
+// Use of this source code is governed by a BSD-style license that can be
13359
+// found in the LICENSE file.
13360
+//
13361
+
13362
+#include "compiler/translator/TranslatorMetalDirect/RewriteCaseDeclarations.h"
13363
+#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
13364
+#include "compiler/translator/tree_util/IntermRebuild.h"
13365
+
13366
+using namespace sh;
13367
+
13368
+////////////////////////////////////////////////////////////////////////////////
13369
+
13370
+namespace
13371
+{
13372
+
13373
+class Rewriter : public TIntermRebuild
13374
+{
13375
+    std::vector<std::vector<const TVariable *>> mDeclaredVarStack;
13376
+
13377
+  public:
13378
+    Rewriter(TCompiler &compiler) : TIntermRebuild(compiler, true, true) {}
13379
+
13380
+    ~Rewriter() override { ASSERT(mDeclaredVarStack.empty()); }
13381
+
13382
+  private:
13383
+    PreResult visitSwitchPre(TIntermSwitch &node) override
13384
+    {
13385
+        mDeclaredVarStack.emplace_back();
13386
+        return node;
13387
+    }
13388
+
13389
+    PostResult visitSwitchPost(TIntermSwitch &node) override
13390
+    {
13391
+        ASSERT(!mDeclaredVarStack.empty());
13392
+        const auto vars = std::move(mDeclaredVarStack.back());
13393
+        mDeclaredVarStack.pop_back();
13394
+        if (!vars.empty())
13395
+        {
13396
+            auto &block = *new TIntermBlock();
13397
+            for (const TVariable *var : vars)
13398
+            {
13399
+                block.appendStatement(new TIntermDeclaration{var});
13400
+            }
13401
+            block.appendStatement(&node);
13402
+            return block;
13403
+        }
13404
+        return node;
13405
+    }
13406
+
13407
+    PreResult visitDeclarationPre(TIntermDeclaration &node) override
13408
+    {
13409
+        if (!mDeclaredVarStack.empty())
13410
+        {
13411
+            TIntermNode *parent = getParentNode();
13412
+            if (parent->getAsBlock())
13413
+            {
13414
+                TIntermNode *grandparent = getParentNode(1);
13415
+                if (grandparent && grandparent->getAsSwitchNode())
13416
+                {
13417
+                    Declaration decl = ViewDeclaration(node);
13418
+                    mDeclaredVarStack.back().push_back(&decl.symbol.variable());
13419
+                    if (decl.initExpr)
13420
+                    {
13421
+                        return *new TIntermBinary(TOperator::EOpAssign, &decl.symbol,
13422
+                                                  decl.initExpr);
13423
+                    }
13424
+                    else
13425
+                    {
13426
+                        return nullptr;
13427
+                    }
13428
+                }
13429
+            }
13430
+        }
13431
+        return node;
13432
+    }
13433
+};
13434
+
13435
+}  // anonymous namespace
13436
+
13437
+////////////////////////////////////////////////////////////////////////////////
13438
+
13439
+bool sh::RewriteCaseDeclarations(TCompiler &compiler, TIntermBlock &root)
13440
+{
13441
+    if (!Rewriter(compiler).rebuildRoot(root))
13442
+    {
13443
+        return false;
13444
+    }
13445
+    return true;
13446
+}
13447
diff --git a/src/compiler/translator/TranslatorMetalDirect/RewriteCaseDeclarations.h b/src/compiler/translator/TranslatorMetalDirect/RewriteCaseDeclarations.h
13448
new file mode 100644
13449
index 0000000..e5a8821
13450
--- /dev/null
13451
+++ b/src/compiler/translator/TranslatorMetalDirect/RewriteCaseDeclarations.h
13452
@@ -0,0 +1,50 @@
13453
+//
13454
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
13455
+// Use of this source code is governed by a BSD-style license that can be
13456
+// found in the LICENSE file.
13457
+//
13458
+
13459
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITECASEDECLARATIONS_H_
13460
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITECASEDECLARATIONS_H_
13461
+
13462
+#include "common/angleutils.h"
13463
+#include "compiler/translator/Compiler.h"
13464
+
13465
+namespace sh
13466
+{
13467
+
13468
+// EXAMPLE
13469
+//    switch (expr)
13470
+//    {
13471
+//      case 0:
13472
+//        int x = 0;
13473
+//        break;
13474
+//      case 1:
13475
+//        int y = 0;
13476
+//        {
13477
+//          int z = 0;
13478
+//        }
13479
+//        break;
13480
+//    }
13481
+// Becomes
13482
+//    {
13483
+//      int x;
13484
+//      int y;
13485
+//      switch (expr)
13486
+//      {
13487
+//        case 0:
13488
+//          x = 0;
13489
+//          break;
13490
+//        case 1:
13491
+//          y = 0;
13492
+//          {
13493
+//            int z = 0;
13494
+//          }
13495
+//          break;
13496
+//      }
13497
+//    }
13498
+ANGLE_NO_DISCARD bool RewriteCaseDeclarations(TCompiler &compiler, TIntermBlock &root);
13499
+
13500
+}  // namespace sh
13501
+
13502
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITECASEDECLARATIONS_H_
13503
diff --git a/src/compiler/translator/TranslatorMetalDirect/RewriteGlobalQualifierDecls.cpp b/src/compiler/translator/TranslatorMetalDirect/RewriteGlobalQualifierDecls.cpp
13504
new file mode 100644
13505
index 0000000..4ad5a36
13506
--- /dev/null
13507
+++ b/src/compiler/translator/TranslatorMetalDirect/RewriteGlobalQualifierDecls.cpp
13508
@@ -0,0 +1,114 @@
13509
+//
13510
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
13511
+// Use of this source code is governed by a BSD-style license that can be
13512
+// found in the LICENSE file.
13513
+//
13514
+
13515
+#include "compiler/translator/TranslatorMetalDirect/RewriteGlobalQualifierDecls.h"
13516
+#include "compiler/translator/TranslatorMetalDirect/Debug.h"
13517
+#include "compiler/translator/tree_util/IntermRebuild.h"
13518
+
13519
+using namespace sh;
13520
+
13521
+namespace
13522
+{
13523
+
13524
+class FindDeclaredGlobals : public TIntermRebuild
13525
+{
13526
+  public:
13527
+    std::unordered_set<const TVariable *> mDeclaredGlobals;
13528
+
13529
+    FindDeclaredGlobals(TCompiler &compiler) : TIntermRebuild(compiler, true, false) {}
13530
+
13531
+    PreResult visitDeclarationPre(TIntermDeclaration &declNode) override
13532
+    {
13533
+        TIntermNode *declaratorNode = declNode.getChildNode(0);
13534
+        TIntermSymbol *symbolNode   = nullptr;
13535
+
13536
+        if (TIntermBinary *initNode = declaratorNode->getAsBinaryNode())
13537
+        {
13538
+            symbolNode = initNode->getLeft()->getAsSymbolNode();
13539
+        }
13540
+        else
13541
+        {
13542
+            symbolNode = declaratorNode->getAsSymbolNode();
13543
+        }
13544
+
13545
+        ASSERT(symbolNode);
13546
+        const TVariable &var = symbolNode->variable();
13547
+
13548
+        mDeclaredGlobals.insert(&var);
13549
+
13550
+        return {declNode, VisitBits::Neither};
13551
+    }
13552
+
13553
+    PreResult visitFunctionDefinitionPre(TIntermFunctionDefinition &node) override
13554
+    {
13555
+        return {node, VisitBits::Neither};
13556
+    }
13557
+};
13558
+
13559
+class Rewriter : public TIntermRebuild
13560
+{
13561
+    const std::unordered_set<const TVariable *> &mDeclaredGlobals;
13562
+    Invariants &mOutInvariants;
13563
+
13564
+  public:
13565
+    Rewriter(TCompiler &compiler,
13566
+             const std::unordered_set<const TVariable *> &declaredGlobals,
13567
+             Invariants &outInvariants)
13568
+        : TIntermRebuild(compiler, true, false),
13569
+          mDeclaredGlobals(declaredGlobals),
13570
+          mOutInvariants(outInvariants)
13571
+    {}
13572
+
13573
+    PreResult visitGlobalQualifierDeclarationPre(
13574
+        TIntermGlobalQualifierDeclaration &gqDeclNode) override
13575
+    {
13576
+        TIntermSymbol &symbolNode = *gqDeclNode.getSymbol();
13577
+        const TVariable &var      = symbolNode.variable();
13578
+
13579
+        if (gqDeclNode.isInvariant())
13580
+        {
13581
+            mOutInvariants.insert(var);
13582
+        }
13583
+
13584
+        if (mDeclaredGlobals.find(&var) == mDeclaredGlobals.end())
13585
+        {
13586
+            return *new TIntermDeclaration{&symbolNode};
13587
+        }
13588
+        return nullptr;
13589
+    }
13590
+
13591
+    PreResult visitDeclarationPre(TIntermDeclaration &node) override
13592
+    {
13593
+        return {node, VisitBits::Neither};
13594
+    }
13595
+
13596
+    PreResult visitFunctionDefinitionPre(TIntermFunctionDefinition &node) override
13597
+    {
13598
+        return {node, VisitBits::Neither};
13599
+    }
13600
+};
13601
+
13602
+}  // anonymous namespace
13603
+
13604
+bool sh::RewriteGlobalQualifierDecls(TCompiler &compiler,
13605
+                                     TIntermBlock &root,
13606
+                                     Invariants &outInvariants)
13607
+{
13608
+    FindDeclaredGlobals fdg(compiler);
13609
+    if (!fdg.rebuildRoot(root))
13610
+    {
13611
+        LOGIC_ERROR();
13612
+        return false;
13613
+    }
13614
+
13615
+    Rewriter rewriter(compiler, fdg.mDeclaredGlobals, outInvariants);
13616
+    if (!rewriter.rebuildRoot(root))
13617
+    {
13618
+        return false;
13619
+    }
13620
+
13621
+    return true;
13622
+}
13623
diff --git a/src/compiler/translator/TranslatorMetalDirect/RewriteGlobalQualifierDecls.h b/src/compiler/translator/TranslatorMetalDirect/RewriteGlobalQualifierDecls.h
13624
new file mode 100644
13625
index 0000000..9131bca
13626
--- /dev/null
13627
+++ b/src/compiler/translator/TranslatorMetalDirect/RewriteGlobalQualifierDecls.h
13628
@@ -0,0 +1,48 @@
13629
+//
13630
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
13631
+// Use of this source code is governed by a BSD-style license that can be
13632
+// found in the LICENSE file.
13633
+//
13634
+
13635
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEGLOBALQUALIFIERDECLS_H_
13636
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEGLOBALQUALIFIERDECLS_H_
13637
+
13638
+#include <unordered_set>
13639
+
13640
+#include "compiler/translator/Compiler.h"
13641
+
13642
+namespace sh
13643
+{
13644
+
13645
+// Tracks TVariables and TFields that are marked as "invariant".
13646
+class Invariants
13647
+{
13648
+  public:
13649
+    void insert(const TVariable &var) { mInvariants.insert(&var); }
13650
+
13651
+    void insert(const TField &field) { mInvariants.insert(&field); }
13652
+
13653
+    bool contains(const TVariable &var) const
13654
+    {
13655
+        return mInvariants.find(&var) != mInvariants.end();
13656
+    }
13657
+
13658
+    bool contains(const TField &field) const
13659
+    {
13660
+        return mInvariants.find(&field) != mInvariants.end();
13661
+    }
13662
+
13663
+  private:
13664
+    std::unordered_set<const void *> mInvariants;
13665
+};
13666
+
13667
+// This rewrites TIntermGlobalQualifierDeclarations as TIntermDeclarations.
13668
+// `outInvariants` is populated with the information that would otherwise be lost by such a
13669
+// transform.
13670
+ANGLE_NO_DISCARD bool RewriteGlobalQualifierDecls(TCompiler &compiler,
13671
+                                                  TIntermBlock &root,
13672
+                                                  Invariants &outInvariants);
13673
+
13674
+}  // namespace sh
13675
+
13676
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEGLOBALQUALIFIERDECLS_H_
13677
diff --git a/src/compiler/translator/TranslatorMetalDirect/RewriteKeywords.cpp b/src/compiler/translator/TranslatorMetalDirect/RewriteKeywords.cpp
13678
new file mode 100644
13679
index 0000000..e014f40
13680
--- /dev/null
13681
+++ b/src/compiler/translator/TranslatorMetalDirect/RewriteKeywords.cpp
13682
@@ -0,0 +1,434 @@
13683
+//
13684
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
13685
+// Use of this source code is governed by a BSD-style license that can be
13686
+// found in the LICENSE file.
13687
+//
13688
+
13689
+#include <cctype>
13690
+#include <cstring>
13691
+#include <limits>
13692
+#include <unordered_map>
13693
+#include <unordered_set>
13694
+
13695
+#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
13696
+#include "compiler/translator/TranslatorMetalDirect/Debug.h"
13697
+#include "compiler/translator/TranslatorMetalDirect/RewriteKeywords.h"
13698
+#include "compiler/translator/tree_util/IntermRebuild.h"
13699
+
13700
+using namespace sh;
13701
+
13702
+////////////////////////////////////////////////////////////////////////////////
13703
+
13704
+namespace
13705
+{
13706
+
13707
+template <typename T>
13708
+using Remapping = std::unordered_map<const T *, const T *>;
13709
+
13710
+class Rewriter : public TIntermRebuild
13711
+{
13712
+  private:
13713
+    const std::set<ImmutableString> &mKeywords;
13714
+    IdGen &mIdGen;
13715
+    Remapping<TField> modifiedFields;
13716
+    Remapping<TFieldList> mFieldLists;
13717
+    Remapping<TFunction> mFunctions;
13718
+    Remapping<TInterfaceBlock> mInterfaceBlocks;
13719
+    Remapping<TStructure> mStructures;
13720
+    Remapping<TVariable> mVariables;
13721
+    std::string mNewNameBuffer;
13722
+
13723
+  private:
13724
+    template <typename T>
13725
+    ImmutableString maybeCreateNewName(T const &object)
13726
+    {
13727
+        if (needsRenaming(object, false))
13728
+        {
13729
+            return mIdGen.createNewName(Name(object)).rawName();
13730
+        }
13731
+        return Name(object).rawName();
13732
+    }
13733
+
13734
+    const TField *createRenamed(const TField &field)
13735
+    {
13736
+        auto *renamed =
13737
+            new TField(const_cast<TType *>(&getRenamedOrOriginal(*field.type())),
13738
+                       maybeCreateNewName(field), field.line(), SymbolType::AngleInternal);
13739
+
13740
+        return renamed;
13741
+    }
13742
+
13743
+    const TFieldList *createRenamed(const TFieldList &fieldList)
13744
+    {
13745
+        auto *renamed = new TFieldList();
13746
+        for (const TField *field : fieldList)
13747
+        {
13748
+            renamed->push_back(const_cast<TField *>(&getRenamedOrOriginal(*field)));
13749
+        }
13750
+        return renamed;
13751
+    }
13752
+
13753
+    const TFunction *createRenamed(const TFunction &function)
13754
+    {
13755
+        auto *renamed =
13756
+            new TFunction(&mSymbolTable, maybeCreateNewName(function), SymbolType::AngleInternal,
13757
+                          &getRenamedOrOriginal(function.getReturnType()),
13758
+                          function.isKnownToNotHaveSideEffects());
13759
+
13760
+        const size_t paramCount = function.getParamCount();
13761
+        for (size_t i = 0; i < paramCount; ++i)
13762
+        {
13763
+            const TVariable &param = *function.getParam(i);
13764
+            renamed->addParameter(&getRenamedOrOriginal(param));
13765
+        }
13766
+
13767
+        if (function.isDefined())
13768
+        {
13769
+            renamed->setDefined();
13770
+        }
13771
+
13772
+        if (function.hasPrototypeDeclaration())
13773
+        {
13774
+            renamed->setHasPrototypeDeclaration();
13775
+        }
13776
+
13777
+        return renamed;
13778
+    }
13779
+
13780
+    const TInterfaceBlock *createRenamed(const TInterfaceBlock &interfaceBlock)
13781
+    {
13782
+        TLayoutQualifier layoutQualifier = TLayoutQualifier::Create();
13783
+        layoutQualifier.blockStorage     = interfaceBlock.blockStorage();
13784
+        layoutQualifier.binding          = interfaceBlock.blockBinding();
13785
+
13786
+        auto *renamed =
13787
+            new TInterfaceBlock(&mSymbolTable, maybeCreateNewName(interfaceBlock),
13788
+                                &getRenamedOrOriginal(interfaceBlock.fields()), layoutQualifier,
13789
+                                SymbolType::AngleInternal, interfaceBlock.extension());
13790
+
13791
+        return renamed;
13792
+    }
13793
+
13794
+    const TStructure *createRenamed(const TStructure &structure)
13795
+    {
13796
+        auto *renamed =
13797
+            new TStructure(&mSymbolTable, maybeCreateNewName(structure),
13798
+                           &getRenamedOrOriginal(structure.fields()), SymbolType::AngleInternal);
13799
+
13800
+        renamed->setAtGlobalScope(structure.atGlobalScope());
13801
+
13802
+        return renamed;
13803
+    }
13804
+
13805
+    const TType *createRenamed(const TType &type)
13806
+    {
13807
+        TType *renamed;
13808
+
13809
+        if (const TStructure *structure = type.getStruct())
13810
+        {
13811
+            renamed = new TType(&getRenamedOrOriginal(*structure), type.isStructSpecifier());
13812
+        }
13813
+        else if (const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock())
13814
+        {
13815
+            renamed = new TType(&getRenamedOrOriginal(*interfaceBlock), type.getQualifier(),
13816
+                                type.getLayoutQualifier());
13817
+        }
13818
+        else
13819
+        {
13820
+            LOGIC_ERROR();  // Can't rename built-in types.
13821
+            renamed = nullptr;
13822
+        }
13823
+
13824
+        if (type.isArray())
13825
+        {
13826
+            renamed->makeArrays(type.getArraySizes());
13827
+        }
13828
+        renamed->setPrecise(type.isPrecise());
13829
+        renamed->setInvariant(type.isInvariant());
13830
+        renamed->setMemoryQualifier(type.getMemoryQualifier());
13831
+        renamed->setLayoutQualifier(type.getLayoutQualifier());
13832
+
13833
+        return renamed;
13834
+    }
13835
+
13836
+    const TVariable *createRenamed(const TVariable &variable)
13837
+    {
13838
+        auto *renamed = new TVariable(&mSymbolTable, maybeCreateNewName(variable),
13839
+                                      &getRenamedOrOriginal(variable.getType()),
13840
+                                      SymbolType::AngleInternal, variable.extension());
13841
+
13842
+        return renamed;
13843
+    }
13844
+
13845
+    template <typename T>
13846
+    const T *tryGetRenamedImpl(const T &object, Remapping<T> *remapping)
13847
+    {
13848
+        if (!needsRenaming(object, true))
13849
+        {
13850
+            return nullptr;
13851
+        }
13852
+
13853
+        if (remapping)
13854
+        {
13855
+            auto it = remapping->find(&object);
13856
+            if (it != remapping->end())
13857
+            {
13858
+                return it->second;
13859
+            }
13860
+        }
13861
+
13862
+        const T *renamedObject = createRenamed(object);
13863
+
13864
+        if (remapping)
13865
+        {
13866
+            (*remapping)[&object] = renamedObject;
13867
+        }
13868
+
13869
+        return renamedObject;
13870
+    }
13871
+
13872
+    const TField *tryGetRenamed(const TField &field)
13873
+    {
13874
+        return tryGetRenamedImpl(field, &modifiedFields);
13875
+    }
13876
+
13877
+    const TFieldList *tryGetRenamed(const TFieldList &fieldList)
13878
+    {
13879
+        return tryGetRenamedImpl(fieldList, &mFieldLists);
13880
+    }
13881
+
13882
+    const TFunction *tryGetRenamed(const TFunction &func)
13883
+    {
13884
+        return tryGetRenamedImpl(func, &mFunctions);
13885
+    }
13886
+
13887
+    const TInterfaceBlock *tryGetRenamed(const TInterfaceBlock &interfaceBlock)
13888
+    {
13889
+        return tryGetRenamedImpl(interfaceBlock, &mInterfaceBlocks);
13890
+    }
13891
+
13892
+    const TStructure *tryGetRenamed(const TStructure &structure)
13893
+    {
13894
+        return tryGetRenamedImpl(structure, &mStructures);
13895
+    }
13896
+
13897
+    const TType *tryGetRenamed(const TType &type)
13898
+    {
13899
+        return tryGetRenamedImpl(type, static_cast<Remapping<TType> *>(nullptr));
13900
+    }
13901
+
13902
+    const TVariable *tryGetRenamed(const TVariable &variable)
13903
+    {
13904
+        return tryGetRenamedImpl(variable, &mVariables);
13905
+    }
13906
+
13907
+    template <typename T>
13908
+    const T &getRenamedOrOriginal(const T &object)
13909
+    {
13910
+        const T *renamed = tryGetRenamed(object);
13911
+        if (renamed)
13912
+        {
13913
+            return *renamed;
13914
+        }
13915
+        return object;
13916
+    }
13917
+
13918
+    template <typename T>
13919
+    bool needsRenamingImpl(const T &object) const
13920
+    {
13921
+        const SymbolType symbolType = object.symbolType();
13922
+        switch (symbolType)
13923
+        {
13924
+            case SymbolType::BuiltIn:
13925
+            case SymbolType::AngleInternal:
13926
+            case SymbolType::Empty:
13927
+                return false;
13928
+
13929
+            case SymbolType::UserDefined:
13930
+                break;
13931
+        }
13932
+
13933
+        const ImmutableString name = Name(object).rawName();
13934
+        if (mKeywords.find(name) != mKeywords.end())
13935
+        {
13936
+            return true;
13937
+        }
13938
+
13939
+        if (name.beginsWith(kAngleInternalPrefix))
13940
+        {
13941
+            return true;
13942
+        }
13943
+
13944
+        return false;
13945
+    }
13946
+
13947
+    bool needsRenaming(const TField &field, bool recursive) const
13948
+    {
13949
+        return needsRenamingImpl(field) || (recursive && needsRenaming(*field.type(), true));
13950
+    }
13951
+
13952
+    bool needsRenaming(const TFieldList &fieldList, bool recursive) const
13953
+    {
13954
+        ASSERT(recursive);
13955
+        for (const TField *field : fieldList)
13956
+        {
13957
+            if (needsRenaming(*field, true))
13958
+            {
13959
+                return true;
13960
+            }
13961
+        }
13962
+        return false;
13963
+    }
13964
+
13965
+    bool needsRenaming(const TFunction &function, bool recursive) const
13966
+    {
13967
+        if (needsRenamingImpl(function))
13968
+        {
13969
+            return true;
13970
+        }
13971
+
13972
+        if (!recursive)
13973
+        {
13974
+            return false;
13975
+        }
13976
+
13977
+        const size_t paramCount = function.getParamCount();
13978
+        for (size_t i = 0; i < paramCount; ++i)
13979
+        {
13980
+            const TVariable &param = *function.getParam(i);
13981
+            if (needsRenaming(param, true))
13982
+            {
13983
+                return true;
13984
+            }
13985
+        }
13986
+
13987
+        return false;
13988
+    }
13989
+
13990
+    bool needsRenaming(const TInterfaceBlock &interfaceBlock, bool recursive) const
13991
+    {
13992
+        return needsRenamingImpl(interfaceBlock) ||
13993
+               (recursive && needsRenaming(interfaceBlock.fields(), true));
13994
+    }
13995
+
13996
+    bool needsRenaming(const TStructure &structure, bool recursive) const
13997
+    {
13998
+        return needsRenamingImpl(structure) ||
13999
+               (recursive && needsRenaming(structure.fields(), true));
14000
+    }
14001
+
14002
+    bool needsRenaming(const TType &type, bool recursive) const
14003
+    {
14004
+        if (const TStructure *structure = type.getStruct())
14005
+        {
14006
+            return needsRenaming(*structure, recursive);
14007
+        }
14008
+        else if (const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock())
14009
+        {
14010
+            return needsRenaming(*interfaceBlock, recursive);
14011
+        }
14012
+        else
14013
+        {
14014
+            return false;
14015
+        }
14016
+    }
14017
+
14018
+    bool needsRenaming(const TVariable &variable, bool recursive) const
14019
+    {
14020
+        return needsRenamingImpl(variable) ||
14021
+               (recursive && needsRenaming(variable.getType(), true));
14022
+    }
14023
+
14024
+  public:
14025
+    Rewriter(TCompiler &compiler, IdGen &idGen, const std::set<ImmutableString> &keywords)
14026
+        : TIntermRebuild(compiler, false, true), mKeywords(keywords), mIdGen(idGen)
14027
+    {}
14028
+
14029
+    PostResult visitSymbol(TIntermSymbol &symbolNode)
14030
+    {
14031
+        const TVariable &var = symbolNode.variable();
14032
+        if (needsRenaming(var, true))
14033
+        {
14034
+            const TVariable &rVar = getRenamedOrOriginal(var);
14035
+            return *new TIntermSymbol(&rVar);
14036
+        }
14037
+        return symbolNode;
14038
+    }
14039
+
14040
+    PostResult visitFunctionPrototype(TIntermFunctionPrototype &funcProtoNode)
14041
+    {
14042
+        const TFunction &func = *funcProtoNode.getFunction();
14043
+        if (needsRenaming(func, true))
14044
+        {
14045
+            const TFunction &rFunc = getRenamedOrOriginal(func);
14046
+            return *new TIntermFunctionPrototype(&rFunc);
14047
+        }
14048
+        return funcProtoNode;
14049
+    }
14050
+
14051
+    PostResult visitFunctionDefinitionPost(TIntermFunctionDefinition &funcDefNode) override
14052
+    {
14053
+        TIntermFunctionPrototype &funcProtoNode = *funcDefNode.getFunctionPrototype();
14054
+        const TFunction &func                   = *funcProtoNode.getFunction();
14055
+        if (needsRenaming(func, true))
14056
+        {
14057
+            const TFunction &rFunc = getRenamedOrOriginal(func);
14058
+            auto *rFuncProtoNode   = new TIntermFunctionPrototype(&rFunc);
14059
+            return *new TIntermFunctionDefinition(rFuncProtoNode, funcDefNode.getBody());
14060
+        }
14061
+        return funcDefNode;
14062
+    }
14063
+
14064
+    PostResult visitAggregatePost(TIntermAggregate &aggregateNode) override
14065
+    {
14066
+        if (aggregateNode.isConstructor())
14067
+        {
14068
+            const TType &type = aggregateNode.getType();
14069
+            if (needsRenaming(type, true))
14070
+            {
14071
+                const TType &rType = getRenamedOrOriginal(type);
14072
+                return TIntermAggregate::CreateConstructor(rType, aggregateNode.getSequence());
14073
+            }
14074
+        }
14075
+        else
14076
+        {
14077
+            const TFunction &func = *aggregateNode.getFunction();
14078
+            if (needsRenaming(func, true))
14079
+            {
14080
+                const TFunction &rFunc = getRenamedOrOriginal(func);
14081
+                switch (aggregateNode.getOp())
14082
+                {
14083
+                    case TOperator::EOpCallFunctionInAST:
14084
+                        return TIntermAggregate::CreateFunctionCall(rFunc,
14085
+                                                                    aggregateNode.getSequence());
14086
+
14087
+                    case TOperator::EOpCallInternalRawFunction:
14088
+                        return TIntermAggregate::CreateRawFunctionCall(rFunc,
14089
+                                                                       aggregateNode.getSequence());
14090
+
14091
+                    default:
14092
+                        return TIntermAggregate::CreateBuiltInFunctionCall(
14093
+                            rFunc, aggregateNode.getSequence());
14094
+                }
14095
+            }
14096
+        }
14097
+        return aggregateNode;
14098
+    }
14099
+};
14100
+
14101
+}  // anonymous namespace
14102
+
14103
+////////////////////////////////////////////////////////////////////////////////
14104
+
14105
+bool sh::RewriteKeywords(TCompiler &compiler,
14106
+                         TIntermBlock &root,
14107
+                         IdGen &idGen,
14108
+                         const std::set<ImmutableString> &keywords)
14109
+{
14110
+    Rewriter rewriter(compiler, idGen, keywords);
14111
+    if (!rewriter.rebuildRoot(root))
14112
+    {
14113
+        return false;
14114
+    }
14115
+    return true;
14116
+}
14117
diff --git a/src/compiler/translator/TranslatorMetalDirect/RewriteKeywords.h b/src/compiler/translator/TranslatorMetalDirect/RewriteKeywords.h
14118
new file mode 100644
14119
index 0000000..b162bc7
14120
--- /dev/null
14121
+++ b/src/compiler/translator/TranslatorMetalDirect/RewriteKeywords.h
14122
@@ -0,0 +1,27 @@
14123
+//
14124
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
14125
+// Use of this source code is governed by a BSD-style license that can be
14126
+// found in the LICENSE file.
14127
+//
14128
+
14129
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEKEYWORDS_H_
14130
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEKEYWORDS_H_
14131
+
14132
+#include <set>
14133
+
14134
+#include "common/angleutils.h"
14135
+#include "compiler/translator/Compiler.h"
14136
+#include "compiler/translator/TranslatorMetalDirect/IdGen.h"
14137
+
14138
+namespace sh
14139
+{
14140
+
14141
+// This walks the tree and renames all names that conflict with the input `keywords`.
14142
+ANGLE_NO_DISCARD bool RewriteKeywords(TCompiler &compiler,
14143
+                                      TIntermBlock &root,
14144
+                                      IdGen &idGen,
14145
+                                      const std::set<ImmutableString> &keywords);
14146
+
14147
+}  // namespace sh
14148
+
14149
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEKEYWORDS_H_
14150
diff --git a/src/compiler/translator/TranslatorMetalDirect/RewriteOutArgs.cpp b/src/compiler/translator/TranslatorMetalDirect/RewriteOutArgs.cpp
14151
new file mode 100644
14152
index 0000000..91c037d
14153
--- /dev/null
14154
+++ b/src/compiler/translator/TranslatorMetalDirect/RewriteOutArgs.cpp
14155
@@ -0,0 +1,204 @@
14156
+//
14157
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
14158
+// Use of this source code is governed by a BSD-style license that can be
14159
+// found in the LICENSE file.
14160
+//
14161
+
14162
+#include "compiler/translator/TranslatorMetalDirect/RewriteOutArgs.h"
14163
+#include "compiler/translator/tree_util/IntermRebuild.h"
14164
+
14165
+using namespace sh;
14166
+
14167
+namespace
14168
+{
14169
+
14170
+template <typename T>
14171
+class SmallMultiSet
14172
+{
14173
+  public:
14174
+    struct Entry
14175
+    {
14176
+        T elem;
14177
+        size_t count;
14178
+    };
14179
+
14180
+    const Entry *find(const T &x) const
14181
+    {
14182
+        for (auto &entry : mEntries)
14183
+        {
14184
+            if (x == entry.elem)
14185
+            {
14186
+                return &entry;
14187
+            }
14188
+        }
14189
+        return nullptr;
14190
+    }
14191
+
14192
+    size_t multiplicity(const T &x) const
14193
+    {
14194
+        const Entry *entry = find(x);
14195
+        return entry ? entry->count : 0;
14196
+    }
14197
+
14198
+    const Entry &insert(const T &x)
14199
+    {
14200
+        Entry *entry = findMutable(x);
14201
+        if (entry)
14202
+        {
14203
+            ++entry->count;
14204
+            return *entry;
14205
+        }
14206
+        else
14207
+        {
14208
+            mEntries.push_back({x, 1});
14209
+            return mEntries.back();
14210
+        }
14211
+    }
14212
+
14213
+    void clear() { mEntries.clear(); }
14214
+
14215
+    bool empty() const { return mEntries.empty(); }
14216
+
14217
+    size_t uniqueSize() const { return mEntries.size(); }
14218
+
14219
+  private:
14220
+    ANGLE_INLINE Entry *findMutable(const T &x) { return const_cast<Entry *>(find(x)); }
14221
+
14222
+  private:
14223
+    std::vector<Entry> mEntries;
14224
+};
14225
+
14226
+const TVariable *GetVariable(TIntermNode &node)
14227
+{
14228
+    TIntermTyped *tyNode = node.getAsTyped();
14229
+    ASSERT(tyNode);
14230
+    if (TIntermSymbol *symbol = tyNode->getAsSymbolNode())
14231
+    {
14232
+        return &symbol->variable();
14233
+    }
14234
+    return nullptr;
14235
+}
14236
+
14237
+class Rewriter : public TIntermRebuild
14238
+{
14239
+    SmallMultiSet<const TVariable *> mVarBuffer;  // reusable buffer
14240
+    SymbolEnv &mSymbolEnv;
14241
+
14242
+  public:
14243
+    ~Rewriter() override { ASSERT(mVarBuffer.empty()); }
14244
+
14245
+    Rewriter(TCompiler &compiler, SymbolEnv &symbolEnv)
14246
+        : TIntermRebuild(compiler, false, true), mSymbolEnv(symbolEnv)
14247
+    {}
14248
+
14249
+    PostResult visitAggregatePost(TIntermAggregate &aggregateNode) override
14250
+    {
14251
+        ASSERT(mVarBuffer.empty());
14252
+
14253
+        const TFunction *func = aggregateNode.getFunction();
14254
+        if (!func)
14255
+        {
14256
+            return aggregateNode;
14257
+        }
14258
+
14259
+        TIntermSequence &args = *aggregateNode.getSequence();
14260
+        size_t argCount       = args.size();
14261
+
14262
+        auto getParamQualifier = [&](size_t i) {
14263
+            const TVariable &param     = *func->getParam(i);
14264
+            const TType &paramType     = param.getType();
14265
+            const TQualifier paramQual = paramType.getQualifier();
14266
+            switch (paramQual)
14267
+            {
14268
+                case TQualifier::EvqOut:
14269
+                case TQualifier::EvqInOut:
14270
+                    if (!mSymbolEnv.isReference(param))
14271
+                    {
14272
+                        mSymbolEnv.markAsReference(param, AddressSpace::Thread);
14273
+                    }
14274
+                    break;
14275
+                default:
14276
+                    break;
14277
+            }
14278
+            return paramQual;
14279
+        };
14280
+
14281
+        bool mightAlias = false;
14282
+
14283
+        for (size_t i = 0; i < argCount; ++i)
14284
+        {
14285
+            const TQualifier paramQual = getParamQualifier(i);
14286
+
14287
+            switch (paramQual)
14288
+            {
14289
+                case TQualifier::EvqOut:
14290
+                case TQualifier::EvqInOut:
14291
+                {
14292
+                    const TVariable *var = GetVariable(*args[i]);
14293
+                    if (mVarBuffer.insert(var).count > 1)
14294
+                    {
14295
+                        mightAlias = true;
14296
+                        i          = argCount;
14297
+                    }
14298
+                }
14299
+                break;
14300
+
14301
+                default:
14302
+                    break;
14303
+            }
14304
+        }
14305
+
14306
+        const bool hasIndeterminateVar = mVarBuffer.find(nullptr);
14307
+
14308
+        if (!mightAlias)
14309
+        {
14310
+            mightAlias = hasIndeterminateVar && mVarBuffer.uniqueSize() > 1;
14311
+        }
14312
+
14313
+        if (mightAlias)
14314
+        {
14315
+            for (size_t i = 0; i < argCount; ++i)
14316
+            {
14317
+                TIntermTyped *arg = args[i]->getAsTyped();
14318
+                ASSERT(arg);
14319
+                const TVariable *var       = GetVariable(*arg);
14320
+                const TQualifier paramQual = getParamQualifier(i);
14321
+
14322
+                if (hasIndeterminateVar || mVarBuffer.multiplicity(var) > 1)
14323
+                {
14324
+                    switch (paramQual)
14325
+                    {
14326
+                        case TQualifier::EvqOut:
14327
+                            args[i] = &mSymbolEnv.callFunctionOverload(Name("out"), arg->getType(),
14328
+                                                                       *new TIntermSequence{arg});
14329
+                            break;
14330
+
14331
+                        case TQualifier::EvqInOut:
14332
+                            args[i] = &mSymbolEnv.callFunctionOverload(
14333
+                                Name("inout"), arg->getType(), *new TIntermSequence{arg});
14334
+                            break;
14335
+
14336
+                        default:
14337
+                            break;
14338
+                    }
14339
+                }
14340
+            }
14341
+        }
14342
+
14343
+        mVarBuffer.clear();
14344
+
14345
+        return aggregateNode;
14346
+    }
14347
+};
14348
+
14349
+}  // anonymous namespace
14350
+
14351
+bool sh::RewriteOutArgs(TCompiler &compiler, TIntermBlock &root, SymbolEnv &symbolEnv)
14352
+{
14353
+    Rewriter rewriter(compiler, symbolEnv);
14354
+    if (!rewriter.rebuildRoot(root))
14355
+    {
14356
+        return false;
14357
+    }
14358
+    return true;
14359
+}
14360
diff --git a/src/compiler/translator/TranslatorMetalDirect/RewriteOutArgs.h b/src/compiler/translator/TranslatorMetalDirect/RewriteOutArgs.h
14361
new file mode 100644
14362
index 0000000..982b747
14363
--- /dev/null
14364
+++ b/src/compiler/translator/TranslatorMetalDirect/RewriteOutArgs.h
14365
@@ -0,0 +1,33 @@
14366
+//
14367
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
14368
+// Use of this source code is governed by a BSD-style license that can be
14369
+// found in the LICENSE file.
14370
+//
14371
+
14372
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEOUTARGS_H_
14373
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEOUTARGS_H_
14374
+
14375
+#include "compiler/translator/Compiler.h"
14376
+#include "compiler/translator/TranslatorMetalDirect/ProgramPrelude.h"
14377
+#include "compiler/translator/TranslatorMetalDirect/SymbolEnv.h"
14378
+
14379
+namespace sh
14380
+{
14381
+
14382
+// e.g.:
14383
+//    /*void foo(out int x, inout int y)*/
14384
+//    foo(z, w);
14385
+// becomes
14386
+//    foo(Out(z), InOut(w));
14387
+// unless `z` and `w` are detected to never alias.
14388
+// The translated example effectively behaves the same as:
14389
+//    int _1;
14390
+//    int _2 = w;
14391
+//    foo(_1, _2);
14392
+//    z = _1;
14393
+//    w = _2;
14394
+ANGLE_NO_DISCARD bool RewriteOutArgs(TCompiler &compiler, TIntermBlock &root, SymbolEnv &symbolEnv);
14395
+
14396
+}  // namespace sh
14397
+
14398
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEOUTARGS_H_
14399
diff --git a/src/compiler/translator/TranslatorMetalDirect/RewritePipelines.cpp b/src/compiler/translator/TranslatorMetalDirect/RewritePipelines.cpp
14400
new file mode 100644
14401
index 0000000..3637e23
14402
--- /dev/null
14403
+++ b/src/compiler/translator/TranslatorMetalDirect/RewritePipelines.cpp
14404
@@ -0,0 +1,938 @@
14405
+//
14406
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
14407
+// Use of this source code is governed by a BSD-style license that can be
14408
+// found in the LICENSE file.
14409
+//
14410
+
14411
+#include <cstring>
14412
+#include <unordered_map>
14413
+#include <unordered_set>
14414
+
14415
+#include "compiler/translator/TranslatorMetalDirect.h"
14416
+#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
14417
+#include "compiler/translator/TranslatorMetalDirect/DiscoverDependentFunctions.h"
14418
+#include "compiler/translator/TranslatorMetalDirect/IdGen.h"
14419
+#include "compiler/translator/TranslatorMetalDirect/MapSymbols.h"
14420
+#include "compiler/translator/TranslatorMetalDirect/Pipeline.h"
14421
+#include "compiler/translator/TranslatorMetalDirect/RewritePipelines.h"
14422
+#include "compiler/translator/tree_ops/PruneNoOps.h"
14423
+#include "compiler/translator/tree_util/FindMain.h"
14424
+#include "compiler/translator/tree_util/IntermRebuild.h"
14425
+#include "compiler/translator/tree_util/IntermTraverse.h"
14426
+
14427
+using namespace sh;
14428
+
14429
+////////////////////////////////////////////////////////////////////////////////
14430
+
14431
+namespace
14432
+{
14433
+
14434
+using VariableSet  = std::unordered_set<const TVariable *>;
14435
+using VariableList = std::vector<const TVariable *>;
14436
+
14437
+////////////////////////////////////////////////////////////////////////////////
14438
+
14439
+struct PipelineStructInfo
14440
+{
14441
+    VariableSet pipelineVariables;
14442
+    PipelineScoped<TStructure> pipelineStruct;
14443
+    const TFunction *funcOriginalToModified = nullptr;
14444
+    const TFunction *funcModifiedToOriginal = nullptr;
14445
+
14446
+    bool isEmpty() const
14447
+    {
14448
+        if (pipelineStruct.isTotallyEmpty())
14449
+        {
14450
+            ASSERT(pipelineVariables.empty());
14451
+            return true;
14452
+        }
14453
+        else
14454
+        {
14455
+            ASSERT(pipelineStruct.isTotallyFull());
14456
+            ASSERT(!pipelineVariables.empty());
14457
+            return false;
14458
+        }
14459
+    }
14460
+};
14461
+
14462
+class GeneratePipelineStruct : private TIntermRebuild
14463
+{
14464
+  private:
14465
+    const Pipeline &mPipeline;
14466
+    SymbolEnv &mSymbolEnv;
14467
+    Invariants &mInvariants;
14468
+    VariableList mPipelineVariableList;
14469
+    IdGen &mIdGen;
14470
+    PipelineStructInfo mInfo;
14471
+
14472
+  public:
14473
+    static bool Exec(PipelineStructInfo &out,
14474
+                     TCompiler &compiler,
14475
+                     TIntermBlock &root,
14476
+                     IdGen &idGen,
14477
+                     const Pipeline &pipeline,
14478
+                     SymbolEnv &symbolEnv,
14479
+                     Invariants &invariants)
14480
+    {
14481
+        GeneratePipelineStruct self(compiler, idGen, pipeline, symbolEnv, invariants);
14482
+        if (!self.exec(root))
14483
+        {
14484
+            return false;
14485
+        }
14486
+        out = self.mInfo;
14487
+        return true;
14488
+    }
14489
+
14490
+  private:
14491
+    GeneratePipelineStruct(TCompiler &compiler,
14492
+                           IdGen &idGen,
14493
+                           const Pipeline &pipeline,
14494
+                           SymbolEnv &symbolEnv,
14495
+                           Invariants &invariants)
14496
+        : TIntermRebuild(compiler, true, true),
14497
+          mPipeline(pipeline),
14498
+          mSymbolEnv(symbolEnv),
14499
+          mInvariants(invariants),
14500
+          mIdGen(idGen)
14501
+    {}
14502
+
14503
+    bool exec(TIntermBlock &root)
14504
+    {
14505
+        if (!rebuildRoot(root))
14506
+        {
14507
+            return false;
14508
+        }
14509
+
14510
+        if (mInfo.pipelineVariables.empty())
14511
+        {
14512
+            return true;
14513
+        }
14514
+
14515
+        TIntermSequence seq;
14516
+
14517
+        const TStructure &pipelineStruct = [&]() -> const TStructure & {
14518
+            if (mPipeline.globalInstanceVar)
14519
+            {
14520
+                return *mPipeline.globalInstanceVar->getType().getStruct();
14521
+            }
14522
+            else
14523
+            {
14524
+                return createInternalPipelineStruct(root, seq);
14525
+            }
14526
+        }();
14527
+
14528
+        ModifiedStructMachineries modifiedMachineries;
14529
+        const bool modified = TryCreateModifiedStruct(
14530
+            mSymbolEnv, mIdGen, mPipeline.externalStructModifyConfig(), pipelineStruct,
14531
+            mPipeline.getStructTypeName(Pipeline::Variant::Modified), modifiedMachineries);
14532
+
14533
+        if (modified)
14534
+        {
14535
+            ASSERT(mPipeline.type != Pipeline::Type::Texture);
14536
+            ASSERT(!mPipeline.globalInstanceVar);  // This shouldn't happen by construction.
14537
+
14538
+            auto getFunction = [](sh::TIntermFunctionDefinition *funcDecl) {
14539
+                return funcDecl ? funcDecl->getFunction() : nullptr;
14540
+            };
14541
+
14542
+            const size_t size = modifiedMachineries.size();
14543
+            ASSERT(size > 0);
14544
+            for (size_t i = 0; i < size; ++i)
14545
+            {
14546
+                const ModifiedStructMachinery &machinery = modifiedMachineries.at(i);
14547
+                ASSERT(machinery.modifiedStruct);
14548
+
14549
+                seq.push_back(new TIntermDeclaration{
14550
+                    &CreateStructTypeVariable(mSymbolTable, *machinery.modifiedStruct)});
14551
+
14552
+                if (mPipeline.isPipelineOut())
14553
+                {
14554
+                    ASSERT(machinery.funcOriginalToModified);
14555
+                    ASSERT(!machinery.funcModifiedToOriginal);
14556
+                    seq.push_back(machinery.funcOriginalToModified);
14557
+                }
14558
+                else
14559
+                {
14560
+                    ASSERT(machinery.funcModifiedToOriginal);
14561
+                    ASSERT(!machinery.funcOriginalToModified);
14562
+                    seq.push_back(machinery.funcModifiedToOriginal);
14563
+                }
14564
+
14565
+                if (i == size - 1)
14566
+                {
14567
+                    mInfo.funcOriginalToModified = getFunction(machinery.funcOriginalToModified);
14568
+                    mInfo.funcModifiedToOriginal = getFunction(machinery.funcModifiedToOriginal);
14569
+
14570
+                    mInfo.pipelineStruct.internal = &pipelineStruct;
14571
+                    mInfo.pipelineStruct.external =
14572
+                        modified ? machinery.modifiedStruct : &pipelineStruct;
14573
+                }
14574
+            }
14575
+        }
14576
+        else
14577
+        {
14578
+            mInfo.pipelineStruct.internal = &pipelineStruct;
14579
+            mInfo.pipelineStruct.external = &pipelineStruct;
14580
+        }
14581
+
14582
+        root.insertChildNodes(FindMainIndex(&root), seq);
14583
+
14584
+        return true;
14585
+    }
14586
+
14587
+  private:
14588
+    PreResult visitFunctionDefinitionPre(TIntermFunctionDefinition &node) override
14589
+    {
14590
+        return {node, VisitBits::Neither};
14591
+    }
14592
+
14593
+    PostResult visitDeclarationPost(TIntermDeclaration &declNode) override
14594
+    {
14595
+        Declaration decl     = ViewDeclaration(declNode);
14596
+        const TVariable &var = decl.symbol.variable();
14597
+
14598
+        if (mPipeline.uses(var))
14599
+        {
14600
+            ASSERT(mInfo.pipelineVariables.find(&var) == mInfo.pipelineVariables.end());
14601
+            mInfo.pipelineVariables.insert(&var);
14602
+            mPipelineVariableList.push_back(&var);
14603
+            return nullptr;
14604
+        }
14605
+
14606
+        return declNode;
14607
+    }
14608
+
14609
+    const TStructure &createInternalPipelineStruct(TIntermBlock &root, TIntermSequence &outDeclSeq)
14610
+    {
14611
+        auto &fields = *new TFieldList();
14612
+
14613
+        switch (mPipeline.type)
14614
+        {
14615
+            case Pipeline::Type::Texture:
14616
+            {
14617
+                for (const TVariable *var : mPipelineVariableList)
14618
+                {
14619
+                    ASSERT(!mInvariants.contains(*var));
14620
+                    const TType &varType         = var->getType();
14621
+                    const TBasicType samplerType = varType.getBasicType();
14622
+
14623
+                    const TStructure &textureEnv = mSymbolEnv.getTextureEnv(samplerType);
14624
+                    auto *textureEnvType         = new TType(&textureEnv, false);
14625
+                    if (varType.isArray())
14626
+                    {
14627
+                        textureEnvType->makeArrays(varType.getArraySizes());
14628
+                    }
14629
+
14630
+                    fields.push_back(
14631
+                        new TField(textureEnvType, var->name(), kNoSourceLoc, var->symbolType()));
14632
+                }
14633
+            }
14634
+            break;
14635
+
14636
+            default:
14637
+            {
14638
+                for (const TVariable *var : mPipelineVariableList)
14639
+                {
14640
+                    auto &type  = CloneType(var->getType());
14641
+                    auto *field = new TField(&type, var->name(), kNoSourceLoc, var->symbolType());
14642
+                    fields.push_back(field);
14643
+
14644
+                    if (mInvariants.contains(*var))
14645
+                    {
14646
+                        mInvariants.insert(*field);
14647
+                    }
14648
+                }
14649
+            }
14650
+            break;
14651
+        }
14652
+
14653
+        Name pipelineStructName = mPipeline.getStructTypeName(Pipeline::Variant::Original);
14654
+        auto &s = *new TStructure(&mSymbolTable, pipelineStructName.rawName(), &fields,
14655
+                                  pipelineStructName.symbolType());
14656
+
14657
+        outDeclSeq.push_back(new TIntermDeclaration{&CreateStructTypeVariable(mSymbolTable, s)});
14658
+
14659
+        return s;
14660
+    }
14661
+};
14662
+
14663
+////////////////////////////////////////////////////////////////////////////////
14664
+
14665
+PipelineScoped<TVariable> CreatePipelineMainLocalVar(TSymbolTable &symbolTable,
14666
+                                                     const Pipeline &pipeline,
14667
+                                                     PipelineScoped<TStructure> pipelineStruct)
14668
+{
14669
+    ASSERT(pipelineStruct.isTotallyFull());
14670
+
14671
+    PipelineScoped<TVariable> pipelineMainLocalVar;
14672
+
14673
+    auto populateExternalMainLocalVar = [&]() {
14674
+        ASSERT(!pipelineMainLocalVar.external);
14675
+        pipelineMainLocalVar.external = &CreateInstanceVariable(
14676
+            symbolTable, *pipelineStruct.external,
14677
+            pipeline.getStructInstanceName(pipelineStruct.isUniform()
14678
+                                               ? Pipeline::Variant::Original
14679
+                                               : Pipeline::Variant::Modified));
14680
+    };
14681
+
14682
+    auto populateDistinctInternalMainLocalVar = [&]() {
14683
+        ASSERT(!pipelineMainLocalVar.internal);
14684
+        pipelineMainLocalVar.internal =
14685
+            &CreateInstanceVariable(symbolTable, *pipelineStruct.internal,
14686
+                                    pipeline.getStructInstanceName(Pipeline::Variant::Original));
14687
+    };
14688
+
14689
+    if (pipeline.type == Pipeline::Type::InstanceId)
14690
+    {
14691
+        populateDistinctInternalMainLocalVar();
14692
+    }
14693
+    else if (pipeline.alwaysRequiresLocalVariableDeclarationInMain())
14694
+    {
14695
+        populateExternalMainLocalVar();
14696
+
14697
+        if (pipelineStruct.isUniform())
14698
+        {
14699
+            pipelineMainLocalVar.internal = pipelineMainLocalVar.external;
14700
+        }
14701
+        else
14702
+        {
14703
+            populateDistinctInternalMainLocalVar();
14704
+        }
14705
+    }
14706
+    else if (!pipelineStruct.isUniform())
14707
+    {
14708
+        populateDistinctInternalMainLocalVar();
14709
+    }
14710
+
14711
+    return pipelineMainLocalVar;
14712
+}
14713
+
14714
+class PipelineFunctionEnv
14715
+{
14716
+  private:
14717
+    TCompiler &mCompiler;
14718
+    SymbolEnv &mSymbolEnv;
14719
+    TSymbolTable &mSymbolTable;
14720
+    IdGen &mIdGen;
14721
+    const Pipeline &mPipeline;
14722
+    const std::unordered_set<const TFunction *> &mPipelineFunctions;
14723
+    const PipelineScoped<TStructure> mPipelineStruct;
14724
+    PipelineScoped<TVariable> &mPipelineMainLocalVar;
14725
+
14726
+    std::unordered_map<const TFunction *, const TFunction *> mFuncMap;
14727
+
14728
+  public:
14729
+    PipelineFunctionEnv(TCompiler &compiler,
14730
+                        SymbolEnv &symbolEnv,
14731
+                        IdGen &idGen,
14732
+                        const Pipeline &pipeline,
14733
+                        const std::unordered_set<const TFunction *> &pipelineFunctions,
14734
+                        PipelineScoped<TStructure> pipelineStruct,
14735
+                        PipelineScoped<TVariable> &pipelineMainLocalVar)
14736
+        : mCompiler(compiler),
14737
+          mSymbolEnv(symbolEnv),
14738
+          mSymbolTable(symbolEnv.symbolTable()),
14739
+          mIdGen(idGen),
14740
+          mPipeline(pipeline),
14741
+          mPipelineFunctions(pipelineFunctions),
14742
+          mPipelineStruct(pipelineStruct),
14743
+          mPipelineMainLocalVar(pipelineMainLocalVar)
14744
+    {}
14745
+
14746
+    bool isOriginalPipelineFunction(const TFunction &func) const
14747
+    {
14748
+        return mPipelineFunctions.find(&func) != mPipelineFunctions.end();
14749
+    }
14750
+
14751
+    bool isUpdatedPipelineFunction(const TFunction &func) const
14752
+    {
14753
+        auto it = mFuncMap.find(&func);
14754
+        if (it == mFuncMap.end())
14755
+        {
14756
+            return false;
14757
+        }
14758
+        return &func == it->second;
14759
+    }
14760
+
14761
+    const TFunction &getUpdatedFunction(const TFunction &func)
14762
+    {
14763
+        ASSERT(isOriginalPipelineFunction(func) || isUpdatedPipelineFunction(func));
14764
+
14765
+        const TFunction *newFunc;
14766
+
14767
+        auto it = mFuncMap.find(&func);
14768
+        if (it == mFuncMap.end())
14769
+        {
14770
+            const bool isMain = func.isMain();
14771
+
14772
+            if (isMain && mPipeline.isPipelineOut())
14773
+            {
14774
+                ASSERT(func.getReturnType().getBasicType() == TBasicType::EbtVoid);
14775
+                newFunc = &CloneFunctionAndChangeReturnType(mSymbolTable, nullptr, func,
14776
+                                                            *mPipelineStruct.external);
14777
+            }
14778
+            else if (isMain && (mPipeline.type == Pipeline::Type::InvocationVertexGlobals ||
14779
+                                mPipeline.type == Pipeline::Type::InvocationFragmentGlobals))
14780
+            {
14781
+                std::vector<const TVariable *> variables;
14782
+                for (const TField *field : mPipelineStruct.external->fields())
14783
+                {
14784
+                    variables.push_back(new TVariable(&mSymbolTable, field->name(), field->type(),
14785
+                                                      field->symbolType()));
14786
+                }
14787
+                newFunc = &CloneFunctionAndAppendParams(mSymbolTable, nullptr, func, variables);
14788
+            }
14789
+            else if (isMain && mPipeline.type == Pipeline::Type::Texture)
14790
+            {
14791
+                std::vector<const TVariable *> variables;
14792
+                TranslatorMetalReflection *reflection =
14793
+                    ((sh::TranslatorMetalDirect *)&mCompiler)->getTranslatorMetalReflection();
14794
+                for (const TField *field : mPipelineStruct.external->fields())
14795
+                {
14796
+                    const TStructure *textureEnv = field->type()->getStruct();
14797
+                    ASSERT(textureEnv && textureEnv->fields().size() == 2);
14798
+                    for (const TField *subfield : textureEnv->fields())
14799
+                    {
14800
+                        const Name name = mIdGen.createNewName({field->name(), subfield->name()});
14801
+                        TType &type     = *new TType(*subfield->type());
14802
+                        ASSERT(!type.isArray());
14803
+                        type.makeArrays(field->type()->getArraySizes());
14804
+                        auto *var =
14805
+                            new TVariable(&mSymbolTable, name.rawName(), &type, name.symbolType());
14806
+                        variables.push_back(var);
14807
+                        reflection->addOriginalName(var->uniqueId().get(), field->name().data());
14808
+                    }
14809
+                }
14810
+                newFunc = &CloneFunctionAndAppendParams(mSymbolTable, nullptr, func, variables);
14811
+            }
14812
+            else if (isMain && mPipeline.type == Pipeline::Type::InstanceId)
14813
+            {
14814
+                Name name = mPipeline.getStructInstanceName(Pipeline::Variant::Modified);
14815
+                auto *var = new TVariable(&mSymbolTable, name.rawName(),
14816
+                                          new TType(TBasicType::EbtUInt), name.symbolType());
14817
+                newFunc   = &CloneFunctionAndPrependParam(mSymbolTable, nullptr, func, *var);
14818
+                mSymbolEnv.markAsReference(*var, mPipeline.externalAddressSpace());
14819
+                mPipelineMainLocalVar.external = var;
14820
+            }
14821
+            else if (isMain && mPipeline.alwaysRequiresLocalVariableDeclarationInMain())
14822
+            {
14823
+                ASSERT(mPipelineMainLocalVar.isTotallyFull());
14824
+                newFunc = &func;
14825
+            }
14826
+            else
14827
+            {
14828
+                const TVariable *var;
14829
+                AddressSpace addressSpace;
14830
+
14831
+                if (isMain && !mPipelineMainLocalVar.isUniform())
14832
+                {
14833
+                    var = &CreateInstanceVariable(
14834
+                        mSymbolTable, *mPipelineStruct.external,
14835
+                        mPipeline.getStructInstanceName(Pipeline::Variant::Modified));
14836
+                    addressSpace = mPipeline.externalAddressSpace();
14837
+                }
14838
+                else
14839
+                {
14840
+                    var = &CreateInstanceVariable(
14841
+                        mSymbolTable, *mPipelineStruct.internal,
14842
+                        mPipeline.getStructInstanceName(Pipeline::Variant::Original));
14843
+                    addressSpace = mPipelineMainLocalVar.isUniform()
14844
+                                       ? mPipeline.externalAddressSpace()
14845
+                                       : AddressSpace::Thread;
14846
+                }
14847
+
14848
+                bool markAsReference = true;
14849
+                if (isMain)
14850
+                {
14851
+                    switch (mPipeline.type)
14852
+                    {
14853
+                        case Pipeline::Type::VertexIn:
14854
+                        case Pipeline::Type::FragmentIn:
14855
+                            markAsReference = false;
14856
+                            break;
14857
+
14858
+                        default:
14859
+                            break;
14860
+                    }
14861
+                }
14862
+
14863
+                if (markAsReference)
14864
+                {
14865
+                    mSymbolEnv.markAsReference(*var, addressSpace);
14866
+                }
14867
+
14868
+                newFunc = &CloneFunctionAndPrependParam(mSymbolTable, nullptr, func, *var);
14869
+            }
14870
+
14871
+            mFuncMap[&func]   = newFunc;
14872
+            mFuncMap[newFunc] = newFunc;
14873
+        }
14874
+        else
14875
+        {
14876
+            newFunc = it->second;
14877
+        }
14878
+
14879
+        return *newFunc;
14880
+    }
14881
+
14882
+    TIntermFunctionPrototype *createUpdatedFunctionPrototype(
14883
+        TIntermFunctionPrototype &funcProtoNode)
14884
+    {
14885
+        const TFunction &func = *funcProtoNode.getFunction();
14886
+        if (!isOriginalPipelineFunction(func) && !isUpdatedPipelineFunction(func))
14887
+        {
14888
+            return nullptr;
14889
+        }
14890
+        const TFunction &newFunc = getUpdatedFunction(func);
14891
+        return new TIntermFunctionPrototype(&newFunc);
14892
+    }
14893
+};
14894
+
14895
+class UpdatePipelineFunctions : private TIntermRebuild
14896
+{
14897
+  private:
14898
+    const Pipeline &mPipeline;
14899
+    const PipelineScoped<TStructure> mPipelineStruct;
14900
+    PipelineScoped<TVariable> &mPipelineMainLocalVar;
14901
+    SymbolEnv &mSymbolEnv;
14902
+    PipelineFunctionEnv mEnv;
14903
+    const TFunction *mFuncOriginalToModified;
14904
+    const TFunction *mFuncModifiedToOriginal;
14905
+
14906
+  public:
14907
+    static bool ThreadPipeline(TCompiler &compiler,
14908
+                               TIntermBlock &root,
14909
+                               const Pipeline &pipeline,
14910
+                               const std::unordered_set<const TFunction *> &pipelineFunctions,
14911
+                               PipelineScoped<TStructure> pipelineStruct,
14912
+                               PipelineScoped<TVariable> &pipelineMainLocalVar,
14913
+                               IdGen &idGen,
14914
+                               SymbolEnv &symbolEnv,
14915
+                               const TFunction *funcOriginalToModified,
14916
+                               const TFunction *funcModifiedToOriginal)
14917
+    {
14918
+        UpdatePipelineFunctions self(compiler, pipeline, pipelineFunctions, pipelineStruct,
14919
+                                     pipelineMainLocalVar, idGen, symbolEnv, funcOriginalToModified,
14920
+                                     funcModifiedToOriginal);
14921
+        if (!self.rebuildRoot(root))
14922
+        {
14923
+            return false;
14924
+        }
14925
+        return true;
14926
+    }
14927
+
14928
+  private:
14929
+    UpdatePipelineFunctions(TCompiler &compiler,
14930
+                            const Pipeline &pipeline,
14931
+                            const std::unordered_set<const TFunction *> &pipelineFunctions,
14932
+                            PipelineScoped<TStructure> pipelineStruct,
14933
+                            PipelineScoped<TVariable> &pipelineMainLocalVar,
14934
+                            IdGen &idGen,
14935
+                            SymbolEnv &symbolEnv,
14936
+                            const TFunction *funcOriginalToModified,
14937
+                            const TFunction *funcModifiedToOriginal)
14938
+        : TIntermRebuild(compiler, false, true),
14939
+          mPipeline(pipeline),
14940
+          mPipelineStruct(pipelineStruct),
14941
+          mPipelineMainLocalVar(pipelineMainLocalVar),
14942
+          mSymbolEnv(symbolEnv),
14943
+          mEnv(compiler,
14944
+               symbolEnv,
14945
+               idGen,
14946
+               pipeline,
14947
+               pipelineFunctions,
14948
+               pipelineStruct,
14949
+               mPipelineMainLocalVar),
14950
+          mFuncOriginalToModified(funcOriginalToModified),
14951
+          mFuncModifiedToOriginal(funcModifiedToOriginal)
14952
+    {
14953
+        ASSERT(mPipelineStruct.isTotallyFull());
14954
+    }
14955
+
14956
+    const TVariable &getInternalPipelineVariable(const TFunction &pipelineFunc)
14957
+    {
14958
+        if (pipelineFunc.isMain() && (mPipeline.alwaysRequiresLocalVariableDeclarationInMain() ||
14959
+                                      !mPipelineMainLocalVar.isUniform()))
14960
+        {
14961
+            ASSERT(mPipelineMainLocalVar.internal);
14962
+            return *mPipelineMainLocalVar.internal;
14963
+        }
14964
+        else
14965
+        {
14966
+            ASSERT(pipelineFunc.getParamCount() > 0);
14967
+            return *pipelineFunc.getParam(0);
14968
+        }
14969
+    }
14970
+
14971
+    const TVariable &getExternalPipelineVariable(const TFunction &mainFunc)
14972
+    {
14973
+        ASSERT(mainFunc.isMain());
14974
+        if (mPipelineMainLocalVar.external)
14975
+        {
14976
+            return *mPipelineMainLocalVar.external;
14977
+        }
14978
+        else
14979
+        {
14980
+            ASSERT(mainFunc.getParamCount() > 0);
14981
+            return *mainFunc.getParam(0);
14982
+        }
14983
+    }
14984
+
14985
+    PostResult visitAggregatePost(TIntermAggregate &callNode) override
14986
+    {
14987
+        if (callNode.isConstructor())
14988
+        {
14989
+            return callNode;
14990
+        }
14991
+        else
14992
+        {
14993
+            const TFunction &oldCalledFunc = *callNode.getFunction();
14994
+            if (!mEnv.isOriginalPipelineFunction(oldCalledFunc))
14995
+            {
14996
+                return callNode;
14997
+            }
14998
+            const TFunction &newCalledFunc = mEnv.getUpdatedFunction(oldCalledFunc);
14999
+
15000
+            const TFunction *oldOwnerFunc = getParentFunction();
15001
+            ASSERT(oldOwnerFunc);
15002
+            const TFunction &newOwnerFunc = mEnv.getUpdatedFunction(*oldOwnerFunc);
15003
+
15004
+            return *TIntermAggregate::CreateFunctionCall(
15005
+                newCalledFunc, &CloneSequenceAndPrepend(
15006
+                                   *callNode.getSequence(),
15007
+                                   *new TIntermSymbol(&getInternalPipelineVariable(newOwnerFunc))));
15008
+        }
15009
+    }
15010
+
15011
+    PostResult visitFunctionPrototypePost(TIntermFunctionPrototype &funcProtoNode) override
15012
+    {
15013
+        TIntermFunctionPrototype *newFuncProtoNode =
15014
+            mEnv.createUpdatedFunctionPrototype(funcProtoNode);
15015
+        if (newFuncProtoNode == nullptr)
15016
+        {
15017
+            return funcProtoNode;
15018
+        }
15019
+        return *newFuncProtoNode;
15020
+    }
15021
+
15022
+    PostResult visitFunctionDefinitionPost(TIntermFunctionDefinition &funcDefNode) override
15023
+    {
15024
+        if (funcDefNode.getFunction()->isMain())
15025
+        {
15026
+            return visitMain(funcDefNode);
15027
+        }
15028
+        else
15029
+        {
15030
+            return visitNonMain(funcDefNode);
15031
+        }
15032
+    }
15033
+
15034
+    TIntermNode &visitNonMain(TIntermFunctionDefinition &funcDefNode)
15035
+    {
15036
+        TIntermFunctionPrototype &funcProtoNode = *funcDefNode.getFunctionPrototype();
15037
+        ASSERT(!funcProtoNode.getFunction()->isMain());
15038
+
15039
+        TIntermFunctionPrototype *newFuncProtoNode =
15040
+            mEnv.createUpdatedFunctionPrototype(funcProtoNode);
15041
+        if (newFuncProtoNode == nullptr)
15042
+        {
15043
+            return funcDefNode;
15044
+        }
15045
+
15046
+        const TFunction &func = *newFuncProtoNode->getFunction();
15047
+        ASSERT(!func.isMain());
15048
+
15049
+        TIntermBlock *body = funcDefNode.getBody();
15050
+
15051
+        return *new TIntermFunctionDefinition(newFuncProtoNode, body);
15052
+    }
15053
+
15054
+    TIntermNode &visitMain(TIntermFunctionDefinition &funcDefNode)
15055
+    {
15056
+        TIntermFunctionPrototype &funcProtoNode = *funcDefNode.getFunctionPrototype();
15057
+        ASSERT(funcProtoNode.getFunction()->isMain());
15058
+
15059
+        TIntermFunctionPrototype *newFuncProtoNode =
15060
+            mEnv.createUpdatedFunctionPrototype(funcProtoNode);
15061
+        if (newFuncProtoNode == nullptr)
15062
+        {
15063
+            return funcDefNode;
15064
+        }
15065
+
15066
+        const TFunction &func = *newFuncProtoNode->getFunction();
15067
+        ASSERT(func.isMain());
15068
+
15069
+        auto callModifiedToOriginal = [&](TIntermBlock &body) {
15070
+            ASSERT(mPipelineMainLocalVar.internal);
15071
+            if (!mPipeline.isPipelineOut())
15072
+            {
15073
+                ASSERT(mFuncModifiedToOriginal);
15074
+                auto *m = new TIntermSymbol(&getExternalPipelineVariable(func));
15075
+                auto *o = new TIntermSymbol(mPipelineMainLocalVar.internal);
15076
+                body.appendStatement(TIntermAggregate::CreateFunctionCall(
15077
+                    *mFuncModifiedToOriginal, new TIntermSequence{m, o}));
15078
+            }
15079
+        };
15080
+
15081
+        auto callOriginalToModified = [&](TIntermBlock &body) {
15082
+            ASSERT(mPipelineMainLocalVar.internal);
15083
+            if (mPipeline.isPipelineOut())
15084
+            {
15085
+                ASSERT(mFuncOriginalToModified);
15086
+                auto *o = new TIntermSymbol(mPipelineMainLocalVar.internal);
15087
+                auto *m = new TIntermSymbol(&getExternalPipelineVariable(func));
15088
+                body.appendStatement(TIntermAggregate::CreateFunctionCall(
15089
+                    *mFuncOriginalToModified, new TIntermSequence{o, m}));
15090
+            }
15091
+        };
15092
+
15093
+        TIntermBlock *body = funcDefNode.getBody();
15094
+
15095
+        if (mPipeline.alwaysRequiresLocalVariableDeclarationInMain())
15096
+        {
15097
+            ASSERT(mPipelineMainLocalVar.isTotallyFull());
15098
+
15099
+            auto *newBody = new TIntermBlock();
15100
+            newBody->appendStatement(new TIntermDeclaration{mPipelineMainLocalVar.internal});
15101
+
15102
+            if (mPipeline.type == Pipeline::Type::InvocationVertexGlobals ||
15103
+                mPipeline.type == Pipeline::Type::InvocationFragmentGlobals)
15104
+            {
15105
+                // Populate struct instance with references to global pipeline variables.
15106
+                for (const TField *field : mPipelineStruct.external->fields())
15107
+                {
15108
+                    auto *var        = new TVariable(&mSymbolTable, field->name(), field->type(),
15109
+                                              field->symbolType());
15110
+                    auto *symbol     = new TIntermSymbol(var);
15111
+                    auto &accessNode = AccessField(*mPipelineMainLocalVar.internal, var->name());
15112
+                    auto *assignNode = new TIntermBinary(TOperator::EOpAssign, &accessNode, symbol);
15113
+                    newBody->appendStatement(assignNode);
15114
+                }
15115
+            }
15116
+            else if (mPipeline.type == Pipeline::Type::Texture)
15117
+            {
15118
+                const TFieldList &fields = mPipelineStruct.external->fields();
15119
+
15120
+                ASSERT(func.getParamCount() >= 2 * fields.size());
15121
+                size_t paramIndex = func.getParamCount() - 2 * fields.size();
15122
+
15123
+                for (const TField *field : fields)
15124
+                {
15125
+                    const TVariable &textureParam = *func.getParam(paramIndex++);
15126
+                    const TVariable &samplerParam = *func.getParam(paramIndex++);
15127
+
15128
+                    auto go = [&](TIntermTyped &env, const int *index) {
15129
+                        TIntermTyped &textureField = AccessField(
15130
+                            AccessIndex(*env.deepCopy(), index), ImmutableString("texture"));
15131
+                        TIntermTyped &samplerField = AccessField(
15132
+                            AccessIndex(*env.deepCopy(), index), ImmutableString("sampler"));
15133
+
15134
+                        auto mkAssign = [&](TIntermTyped &field, const TVariable &param) {
15135
+                            return new TIntermBinary(TOperator::EOpAssign, &field,
15136
+                                                     &mSymbolEnv.callFunctionOverload(
15137
+                                                         Name("addressof"), field.getType(),
15138
+                                                         *new TIntermSequence{&AccessIndex(
15139
+                                                             *new TIntermSymbol(&param), index)}));
15140
+                        };
15141
+
15142
+                        newBody->appendStatement(mkAssign(textureField, textureParam));
15143
+                        newBody->appendStatement(mkAssign(samplerField, samplerParam));
15144
+                    };
15145
+
15146
+                    TIntermTyped &env = AccessField(*mPipelineMainLocalVar.internal, field->name());
15147
+                    const TType &envType = env.getType();
15148
+
15149
+                    if (envType.isArray())
15150
+                    {
15151
+                        ASSERT(!envType.isArrayOfArrays());
15152
+                        const auto n = static_cast<int>(envType.getArraySizeProduct());
15153
+                        for (int i = 0; i < n; ++i)
15154
+                        {
15155
+                            go(env, &i);
15156
+                        }
15157
+                    }
15158
+                    else
15159
+                    {
15160
+                        go(env, nullptr);
15161
+                    }
15162
+                }
15163
+            }
15164
+            else if (mPipeline.type == Pipeline::Type::InstanceId)
15165
+            {
15166
+                newBody->appendStatement(new TIntermBinary(
15167
+                    TOperator::EOpAssign,
15168
+                    &AccessFieldByIndex(*new TIntermSymbol(&getInternalPipelineVariable(func)), 0),
15169
+                    &AsType(mSymbolEnv, *new TType(TBasicType::EbtInt),
15170
+                            *new TIntermSymbol(&getExternalPipelineVariable(func)))));
15171
+            }
15172
+            else if (!mPipelineMainLocalVar.isUniform())
15173
+            {
15174
+                newBody->appendStatement(new TIntermDeclaration{mPipelineMainLocalVar.external});
15175
+                callModifiedToOriginal(*newBody);
15176
+            }
15177
+
15178
+            newBody->appendStatement(body);
15179
+
15180
+            if (!mPipelineMainLocalVar.isUniform())
15181
+            {
15182
+                callOriginalToModified(*newBody);
15183
+            }
15184
+
15185
+            if (mPipeline.isPipelineOut())
15186
+            {
15187
+                newBody->appendStatement(new TIntermBranch(
15188
+                    TOperator::EOpReturn, new TIntermSymbol(mPipelineMainLocalVar.external)));
15189
+            }
15190
+
15191
+            body = newBody;
15192
+        }
15193
+        else if (!mPipelineMainLocalVar.isUniform())
15194
+        {
15195
+            ASSERT(!mPipelineMainLocalVar.external);
15196
+            ASSERT(mPipelineMainLocalVar.internal);
15197
+
15198
+            auto *newBody = new TIntermBlock();
15199
+            newBody->appendStatement(new TIntermDeclaration{mPipelineMainLocalVar.internal});
15200
+            callModifiedToOriginal(*newBody);
15201
+            newBody->appendStatement(body);
15202
+            callOriginalToModified(*newBody);
15203
+            body = newBody;
15204
+        }
15205
+
15206
+        return *new TIntermFunctionDefinition(newFuncProtoNode, body);
15207
+    }
15208
+};
15209
+
15210
+////////////////////////////////////////////////////////////////////////////////
15211
+
15212
+bool UpdatePipelineSymbols(Pipeline::Type pipelineType,
15213
+                           TCompiler &compiler,
15214
+                           TIntermBlock &root,
15215
+                           SymbolEnv &symbolEnv,
15216
+                           const VariableSet &pipelineVariables,
15217
+                           PipelineScoped<TVariable> pipelineMainLocalVar)
15218
+{
15219
+    auto map = [&](const TFunction *owner, TIntermSymbol &symbol) -> TIntermNode & {
15220
+        const TVariable &var = symbol.variable();
15221
+        if (pipelineVariables.find(&var) == pipelineVariables.end())
15222
+        {
15223
+            return symbol;
15224
+        }
15225
+        ASSERT(owner);
15226
+        const TVariable *structInstanceVar;
15227
+        if (owner->isMain())
15228
+        {
15229
+            ASSERT(pipelineMainLocalVar.internal);
15230
+            structInstanceVar = pipelineMainLocalVar.internal;
15231
+        }
15232
+        else
15233
+        {
15234
+            ASSERT(owner->getParamCount() > 0);
15235
+            structInstanceVar = owner->getParam(0);
15236
+        }
15237
+        ASSERT(structInstanceVar);
15238
+        return AccessField(*structInstanceVar, var.name());
15239
+    };
15240
+    return MapSymbols(compiler, root, map);
15241
+}
15242
+
15243
+////////////////////////////////////////////////////////////////////////////////
15244
+
15245
+bool RewritePipeline(TCompiler &compiler,
15246
+                     TIntermBlock &root,
15247
+                     IdGen &idGen,
15248
+                     const Pipeline &pipeline,
15249
+                     SymbolEnv &symbolEnv,
15250
+                     Invariants &invariants,
15251
+                     PipelineScoped<TStructure> &outStruct)
15252
+{
15253
+    ASSERT(outStruct.isTotallyEmpty());
15254
+
15255
+    TSymbolTable &symbolTable = compiler.getSymbolTable();
15256
+
15257
+    PipelineStructInfo psi;
15258
+    if (!GeneratePipelineStruct::Exec(psi, compiler, root, idGen, pipeline, symbolEnv, invariants))
15259
+    {
15260
+        return false;
15261
+    }
15262
+
15263
+    if (psi.isEmpty())
15264
+    {
15265
+        return true;
15266
+    }
15267
+
15268
+    const auto pipelineFunctions = DiscoverDependentFunctions(root, [&](const TVariable &var) {
15269
+        return psi.pipelineVariables.find(&var) != psi.pipelineVariables.end();
15270
+    });
15271
+
15272
+    auto pipelineMainLocalVar =
15273
+        CreatePipelineMainLocalVar(symbolTable, pipeline, psi.pipelineStruct);
15274
+
15275
+    if (!UpdatePipelineFunctions::ThreadPipeline(
15276
+            compiler, root, pipeline, pipelineFunctions, psi.pipelineStruct, pipelineMainLocalVar,
15277
+            idGen, symbolEnv, psi.funcOriginalToModified, psi.funcModifiedToOriginal))
15278
+    {
15279
+        return false;
15280
+    }
15281
+
15282
+    if (!pipeline.globalInstanceVar)
15283
+    {
15284
+        if (!UpdatePipelineSymbols(pipeline.type, compiler, root, symbolEnv, psi.pipelineVariables,
15285
+                                   pipelineMainLocalVar))
15286
+        {
15287
+            return false;
15288
+        }
15289
+    }
15290
+
15291
+    if (!PruneNoOps(&compiler, &root, &compiler.getSymbolTable()))
15292
+    {
15293
+        return false;
15294
+    }
15295
+
15296
+    outStruct = psi.pipelineStruct;
15297
+    return true;
15298
+}
15299
+
15300
+}  // anonymous namespace
15301
+
15302
+bool sh::RewritePipelines(TCompiler &compiler,
15303
+                          TIntermBlock &root,
15304
+                          IdGen &idGen,
15305
+                          const TVariable &angleUniformsGlobalInstanceVar,
15306
+                          SymbolEnv &symbolEnv,
15307
+                          Invariants &invariants,
15308
+                          PipelineStructs &outStructs)
15309
+{
15310
+    struct Info
15311
+    {
15312
+        Pipeline::Type pipelineType;
15313
+        PipelineScoped<TStructure> &outStruct;
15314
+        const TVariable *globalInstanceVar;
15315
+    };
15316
+
15317
+    Info infos[] = {
15318
+        {Pipeline::Type::InstanceId, outStructs.instanceId, nullptr},
15319
+        {Pipeline::Type::Texture, outStructs.texture, nullptr},
15320
+        {Pipeline::Type::NonConstantGlobals, outStructs.nonConstantGlobals, nullptr},
15321
+        {Pipeline::Type::AngleUniforms, outStructs.angleUniforms, &angleUniformsGlobalInstanceVar},
15322
+        {Pipeline::Type::UserUniforms, outStructs.userUniforms, nullptr},
15323
+        {Pipeline::Type::VertexIn, outStructs.vertexIn, nullptr},
15324
+        {Pipeline::Type::VertexOut, outStructs.vertexOut, nullptr},
15325
+        {Pipeline::Type::FragmentIn, outStructs.fragmentIn, nullptr},
15326
+        {Pipeline::Type::FragmentOut, outStructs.fragmentOut, nullptr},
15327
+        {Pipeline::Type::InvocationVertexGlobals, outStructs.invocationVertexGlobals, nullptr},
15328
+        {Pipeline::Type::InvocationFragmentGlobals, outStructs.invocationFragmentGlobals, nullptr},
15329
+    };
15330
+
15331
+    for (Info &info : infos)
15332
+    {
15333
+        Pipeline pipeline{info.pipelineType, info.globalInstanceVar};
15334
+        if (!RewritePipeline(compiler, root, idGen, pipeline, symbolEnv, invariants,
15335
+                             info.outStruct))
15336
+        {
15337
+            return false;
15338
+        }
15339
+    }
15340
+
15341
+    return true;
15342
+}
15343
diff --git a/src/compiler/translator/TranslatorMetalDirect/RewritePipelines.h b/src/compiler/translator/TranslatorMetalDirect/RewritePipelines.h
15344
new file mode 100644
15345
index 0000000..791ba82
15346
--- /dev/null
15347
+++ b/src/compiler/translator/TranslatorMetalDirect/RewritePipelines.h
15348
@@ -0,0 +1,45 @@
15349
+//
15350
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
15351
+// Use of this source code is governed by a BSD-style license that can be
15352
+// found in the LICENSE file.
15353
+//
15354
+
15355
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEPIPELINES_H_
15356
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEPIPELINES_H_
15357
+
15358
+#include "common/angleutils.h"
15359
+#include "compiler/translator/Compiler.h"
15360
+#include "compiler/translator/TranslatorMetalDirect/IdGen.h"
15361
+#include "compiler/translator/TranslatorMetalDirect/Pipeline.h"
15362
+#include "compiler/translator/TranslatorMetalDirect/RewriteGlobalQualifierDecls.h"
15363
+#include "compiler/translator/TranslatorMetalDirect/SymbolEnv.h"
15364
+
15365
+namespace sh
15366
+{
15367
+
15368
+// This rewrites all pipelines.
15369
+//
15370
+// For each pipeline:
15371
+//    - Discover all variables that are used by the pipeline
15372
+//    - Move the variables into an internal pipeline struct instance and update old variables to be
15373
+//      member access instead.
15374
+//    - Dependency inject the internal pipeline struct to all functions that access variables from
15375
+//      the struct.
15376
+//    - A new external pipeline struct is created if needed for impedance reasons. Otherwise the
15377
+//      external and internal pipeline structs are the same.
15378
+//    - Add `main` parameter or return value for the external pipeline struct as needed.
15379
+//    - Inside `main`, map the external struct to the internal struct if they differ and is provided
15380
+//      as a parameter to `main`.
15381
+//    - Inside `main`, map the internal struct to the external struct if they differ and is returned
15382
+//      from `main`.
15383
+ANGLE_NO_DISCARD bool RewritePipelines(TCompiler &compiler,
15384
+                                       TIntermBlock &root,
15385
+                                       IdGen &idGen,
15386
+                                       const TVariable &angleUniformsGlobalInstanceVar,
15387
+                                       SymbolEnv &symbolEnv,
15388
+                                       Invariants &invariants,
15389
+                                       PipelineStructs &outStructs);
15390
+
15391
+}  // namespace sh
15392
+
15393
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEPIPELINES_H_
15394
diff --git a/src/compiler/translator/TranslatorMetalDirect/RewriteUnaddressableReferences.cpp b/src/compiler/translator/TranslatorMetalDirect/RewriteUnaddressableReferences.cpp
15395
new file mode 100644
15396
index 0000000..e77c1a5
15397
--- /dev/null
15398
+++ b/src/compiler/translator/TranslatorMetalDirect/RewriteUnaddressableReferences.cpp
15399
@@ -0,0 +1,376 @@
15400
+//
15401
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
15402
+// Use of this source code is governed by a BSD-style license that can be
15403
+// found in the LICENSE file.
15404
+//
15405
+
15406
+#include "compiler/translator/TranslatorMetalDirect/RewriteUnaddressableReferences.h"
15407
+#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
15408
+#include "compiler/translator/TranslatorMetalDirect/Debug.h"
15409
+#include "compiler/translator/tree_util/AsNode.h"
15410
+#include "compiler/translator/tree_util/IntermRebuild.h"
15411
+
15412
+using namespace sh;
15413
+
15414
+namespace
15415
+{
15416
+
15417
+bool IsOutParam(const TType &paramType)
15418
+{
15419
+    const TQualifier qual = paramType.getQualifier();
15420
+    switch (qual)
15421
+    {
15422
+        case TQualifier::EvqInOut:
15423
+        case TQualifier::EvqOut:
15424
+            return true;
15425
+
15426
+        default:
15427
+            return false;
15428
+    }
15429
+}
15430
+
15431
+bool IsVectorAccess(TIntermBinary &binary)
15432
+{
15433
+    TOperator op = binary.getOp();
15434
+    switch (op)
15435
+    {
15436
+        case TOperator::EOpIndexDirect:
15437
+        case TOperator::EOpIndexIndirect:
15438
+            break;
15439
+
15440
+        default:
15441
+            return false;
15442
+    }
15443
+
15444
+    const TType &leftType = binary.getLeft()->getType();
15445
+    if (!leftType.isVector() || leftType.isArray())
15446
+    {
15447
+        return false;
15448
+    }
15449
+
15450
+    ASSERT(IsScalarBasicType(binary.getType()));
15451
+
15452
+    return true;
15453
+}
15454
+
15455
+bool IsVectorAccess(TIntermNode &node)
15456
+{
15457
+    if (auto *bin = node.getAsBinaryNode())
15458
+    {
15459
+        return IsVectorAccess(*bin);
15460
+    }
15461
+    return false;
15462
+}
15463
+
15464
+// Differs from IsAssignment in that it does not include (++) or (--).
15465
+bool IsAssignEqualsSign(TOperator op)
15466
+{
15467
+    switch (op)
15468
+    {
15469
+        case TOperator::EOpAssign:
15470
+        case TOperator::EOpInitialize:
15471
+        case TOperator::EOpAddAssign:
15472
+        case TOperator::EOpSubAssign:
15473
+        case TOperator::EOpMulAssign:
15474
+        case TOperator::EOpVectorTimesMatrixAssign:
15475
+        case TOperator::EOpVectorTimesScalarAssign:
15476
+        case TOperator::EOpMatrixTimesScalarAssign:
15477
+        case TOperator::EOpMatrixTimesMatrixAssign:
15478
+        case TOperator::EOpDivAssign:
15479
+        case TOperator::EOpIModAssign:
15480
+        case TOperator::EOpBitShiftLeftAssign:
15481
+        case TOperator::EOpBitShiftRightAssign:
15482
+        case TOperator::EOpBitwiseAndAssign:
15483
+        case TOperator::EOpBitwiseXorAssign:
15484
+        case TOperator::EOpBitwiseOrAssign:
15485
+            return true;
15486
+
15487
+        default:
15488
+            return false;
15489
+    }
15490
+}
15491
+
15492
+// Only includes ($=) style assigns, where ($) is a binary op.
15493
+bool IsCompoundAssign(TOperator op)
15494
+{
15495
+    switch (op)
15496
+    {
15497
+        case TOperator::EOpAddAssign:
15498
+        case TOperator::EOpSubAssign:
15499
+        case TOperator::EOpMulAssign:
15500
+        case TOperator::EOpVectorTimesMatrixAssign:
15501
+        case TOperator::EOpVectorTimesScalarAssign:
15502
+        case TOperator::EOpMatrixTimesScalarAssign:
15503
+        case TOperator::EOpMatrixTimesMatrixAssign:
15504
+        case TOperator::EOpDivAssign:
15505
+        case TOperator::EOpIModAssign:
15506
+        case TOperator::EOpBitShiftLeftAssign:
15507
+        case TOperator::EOpBitShiftRightAssign:
15508
+        case TOperator::EOpBitwiseAndAssign:
15509
+        case TOperator::EOpBitwiseXorAssign:
15510
+        case TOperator::EOpBitwiseOrAssign:
15511
+            return true;
15512
+
15513
+        default:
15514
+            return false;
15515
+    }
15516
+}
15517
+
15518
+bool ReturnsReference(TOperator op)
15519
+{
15520
+    switch (op)
15521
+    {
15522
+        case TOperator::EOpAssign:
15523
+        case TOperator::EOpInitialize:
15524
+        case TOperator::EOpAddAssign:
15525
+        case TOperator::EOpSubAssign:
15526
+        case TOperator::EOpMulAssign:
15527
+        case TOperator::EOpVectorTimesMatrixAssign:
15528
+        case TOperator::EOpVectorTimesScalarAssign:
15529
+        case TOperator::EOpMatrixTimesScalarAssign:
15530
+        case TOperator::EOpMatrixTimesMatrixAssign:
15531
+        case TOperator::EOpDivAssign:
15532
+        case TOperator::EOpIModAssign:
15533
+        case TOperator::EOpBitShiftLeftAssign:
15534
+        case TOperator::EOpBitShiftRightAssign:
15535
+        case TOperator::EOpBitwiseAndAssign:
15536
+        case TOperator::EOpBitwiseXorAssign:
15537
+        case TOperator::EOpBitwiseOrAssign:
15538
+
15539
+        case TOperator::EOpPostIncrement:
15540
+        case TOperator::EOpPostDecrement:
15541
+        case TOperator::EOpPreIncrement:
15542
+        case TOperator::EOpPreDecrement:
15543
+
15544
+        case TOperator::EOpIndexDirect:
15545
+        case TOperator::EOpIndexIndirect:
15546
+        case TOperator::EOpIndexDirectStruct:
15547
+        case TOperator::EOpIndexDirectInterfaceBlock:
15548
+
15549
+            return true;
15550
+
15551
+        default:
15552
+            return false;
15553
+    }
15554
+}
15555
+
15556
+TIntermTyped &DecomposeCompoundAssignment(TIntermBinary &node)
15557
+{
15558
+    TOperator op = node.getOp();
15559
+    switch (op)
15560
+    {
15561
+        case TOperator::EOpAddAssign:
15562
+            op = TOperator::EOpAdd;
15563
+            break;
15564
+        case TOperator::EOpSubAssign:
15565
+            op = TOperator::EOpSub;
15566
+            break;
15567
+        case TOperator::EOpMulAssign:
15568
+            op = TOperator::EOpMul;
15569
+            break;
15570
+        case TOperator::EOpVectorTimesMatrixAssign:
15571
+            op = TOperator::EOpVectorTimesMatrix;
15572
+            break;
15573
+        case TOperator::EOpVectorTimesScalarAssign:
15574
+            op = TOperator::EOpVectorTimesScalar;
15575
+            break;
15576
+        case TOperator::EOpMatrixTimesScalarAssign:
15577
+            op = TOperator::EOpMatrixTimesScalar;
15578
+            break;
15579
+        case TOperator::EOpMatrixTimesMatrixAssign:
15580
+            op = TOperator::EOpMatrixTimesMatrix;
15581
+            break;
15582
+        case TOperator::EOpDivAssign:
15583
+            op = TOperator::EOpDiv;
15584
+            break;
15585
+        case TOperator::EOpIModAssign:
15586
+            op = TOperator::EOpIMod;
15587
+            break;
15588
+        case TOperator::EOpBitShiftLeftAssign:
15589
+            op = TOperator::EOpBitShiftLeft;
15590
+            break;
15591
+        case TOperator::EOpBitShiftRightAssign:
15592
+            op = TOperator::EOpBitShiftRight;
15593
+            break;
15594
+        case TOperator::EOpBitwiseAndAssign:
15595
+            op = TOperator::EOpBitwiseAnd;
15596
+            break;
15597
+        case TOperator::EOpBitwiseXorAssign:
15598
+            op = TOperator::EOpBitwiseXor;
15599
+            break;
15600
+        case TOperator::EOpBitwiseOrAssign:
15601
+            op = TOperator::EOpBitwiseOr;
15602
+            break;
15603
+        default:
15604
+            LOGIC_ERROR();
15605
+    }
15606
+
15607
+    // This assumes SeparateCompoundExpressions has already been called.
15608
+    // This assumption allows this code to not need to introduce temporaries.
15609
+    //
15610
+    // e.g. dont have to worry about:
15611
+    //      vec[hasSideEffect()] *= 4
15612
+    // becoming
15613
+    //      vec[hasSideEffect()] = vec[hasSideEffect()] * 4
15614
+
15615
+    TIntermTyped *left  = node.getLeft();
15616
+    TIntermTyped *right = node.getRight();
15617
+    return *new TIntermBinary(TOperator::EOpAssign, left->deepCopy(),
15618
+                              new TIntermBinary(op, left, right));
15619
+}
15620
+
15621
+class Rewriter1 : public TIntermRebuild
15622
+{
15623
+  public:
15624
+    Rewriter1(TCompiler &compiler) : TIntermRebuild(compiler, false, true) {}
15625
+
15626
+    PostResult visitBinaryPost(TIntermBinary &binaryNode) override
15627
+    {
15628
+        const TOperator op = binaryNode.getOp();
15629
+        if (IsCompoundAssign(op))
15630
+        {
15631
+            TIntermTyped &left = *binaryNode.getLeft();
15632
+            if (left.getAsSwizzleNode() || IsVectorAccess(left))
15633
+            {
15634
+                return DecomposeCompoundAssignment(binaryNode);
15635
+            }
15636
+        }
15637
+        return binaryNode;
15638
+    }
15639
+};
15640
+
15641
+class Rewriter2 : public TIntermRebuild
15642
+{
15643
+    std::vector<bool> mRequiresAddressingStack;
15644
+    SymbolEnv &mSymbolEnv;
15645
+
15646
+  private:
15647
+    bool requiresAddressing() const
15648
+    {
15649
+        if (mRequiresAddressingStack.empty())
15650
+        {
15651
+            return false;
15652
+        }
15653
+        return mRequiresAddressingStack.back();
15654
+    }
15655
+
15656
+  public:
15657
+    ~Rewriter2() override { ASSERT(mRequiresAddressingStack.empty()); }
15658
+
15659
+    Rewriter2(TCompiler &compiler, SymbolEnv &symbolEnv)
15660
+        : TIntermRebuild(compiler, true, true), mSymbolEnv(symbolEnv)
15661
+    {}
15662
+
15663
+    PreResult visitAggregatePre(TIntermAggregate &aggregateNode) override
15664
+    {
15665
+        const TFunction *func = aggregateNode.getFunction();
15666
+        if (!func)
15667
+        {
15668
+            return aggregateNode;
15669
+        }
15670
+
15671
+        TIntermSequence &args = *aggregateNode.getSequence();
15672
+        size_t argCount       = args.size();
15673
+
15674
+        for (size_t i = 0; i < argCount; ++i)
15675
+        {
15676
+            const TVariable &param = *func->getParam(i);
15677
+            const TType &paramType = param.getType();
15678
+            TIntermNode *arg       = args[i];
15679
+            ASSERT(arg);
15680
+
15681
+            mRequiresAddressingStack.push_back(IsOutParam(paramType));
15682
+            args[i] = rebuild(*arg).single();
15683
+            ASSERT(args[i]);
15684
+            ASSERT(!mRequiresAddressingStack.empty());
15685
+            mRequiresAddressingStack.pop_back();
15686
+        }
15687
+
15688
+        return {aggregateNode, VisitBits::Neither};
15689
+    }
15690
+
15691
+    PostResult visitSwizzlePost(TIntermSwizzle &swizzleNode) override
15692
+    {
15693
+        if (!requiresAddressing())
15694
+        {
15695
+            return swizzleNode;
15696
+        }
15697
+
15698
+        TIntermTyped &vecNode         = *swizzleNode.getOperand();
15699
+        const TQualifierList &offsets = swizzleNode.getSwizzleOffsets();
15700
+        ASSERT(!offsets.empty());
15701
+        ASSERT(offsets.size() <= 4);
15702
+
15703
+        auto &args = *new TIntermSequence();
15704
+        args.reserve(offsets.size() + 1);
15705
+        args.push_back(&vecNode);
15706
+        for (int offset : offsets)
15707
+        {
15708
+            args.push_back(new TIntermConstantUnion(new TConstantUnion(offset),
15709
+                                                    *new TType(TBasicType::EbtInt)));
15710
+        }
15711
+
15712
+        return mSymbolEnv.callFunctionOverload(Name("swizzle_ref"), swizzleNode.getType(), args);
15713
+    }
15714
+
15715
+    PreResult visitBinaryPre(TIntermBinary &binaryNode) override
15716
+    {
15717
+        const TOperator op = binaryNode.getOp();
15718
+
15719
+        const bool isAccess = IsVectorAccess(binaryNode);
15720
+
15721
+        const bool disableTop   = !ReturnsReference(op) || !requiresAddressing();
15722
+        const bool disableLeft  = disableTop;
15723
+        const bool disableRight = disableTop || isAccess || IsAssignEqualsSign(op);
15724
+
15725
+        auto traverse = [&](TIntermTyped &node, const bool disable) -> TIntermTyped & {
15726
+            if (disable)
15727
+            {
15728
+                mRequiresAddressingStack.push_back(false);
15729
+            }
15730
+            auto *newNode = asNode<TIntermTyped>(rebuild(node).single());
15731
+            ASSERT(newNode);
15732
+            if (disable)
15733
+            {
15734
+                mRequiresAddressingStack.pop_back();
15735
+            }
15736
+            return *newNode;
15737
+        };
15738
+
15739
+        TIntermTyped &leftNode  = *binaryNode.getLeft();
15740
+        TIntermTyped &rightNode = *binaryNode.getRight();
15741
+
15742
+        TIntermTyped &newLeft  = traverse(leftNode, disableLeft);
15743
+        TIntermTyped &newRight = traverse(rightNode, disableRight);
15744
+
15745
+        if (!isAccess || disableTop)
15746
+        {
15747
+            if (&leftNode == &newLeft && &rightNode == &newRight)
15748
+            {
15749
+                return {&binaryNode, VisitBits::Neither};
15750
+            }
15751
+            return {*new TIntermBinary(op, &newLeft, &newRight), VisitBits::Neither};
15752
+        }
15753
+
15754
+        return {mSymbolEnv.callFunctionOverload(Name("elem_ref"), binaryNode.getType(),
15755
+                                                *new TIntermSequence{&newLeft, &newRight}),
15756
+                VisitBits::Neither};
15757
+    }
15758
+};
15759
+
15760
+}  // anonymous namespace
15761
+
15762
+bool sh::RewriteUnaddressableReferences(TCompiler &compiler,
15763
+                                        TIntermBlock &root,
15764
+                                        SymbolEnv &symbolEnv)
15765
+{
15766
+    if (!Rewriter1(compiler).rebuildRoot(root))
15767
+    {
15768
+        return false;
15769
+    }
15770
+    if (!Rewriter2(compiler, symbolEnv).rebuildRoot(root))
15771
+    {
15772
+        return false;
15773
+    }
15774
+    return true;
15775
+}
15776
diff --git a/src/compiler/translator/TranslatorMetalDirect/RewriteUnaddressableReferences.h b/src/compiler/translator/TranslatorMetalDirect/RewriteUnaddressableReferences.h
15777
new file mode 100644
15778
index 0000000..77da984
15779
--- /dev/null
15780
+++ b/src/compiler/translator/TranslatorMetalDirect/RewriteUnaddressableReferences.h
15781
@@ -0,0 +1,31 @@
15782
+//
15783
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
15784
+// Use of this source code is governed by a BSD-style license that can be
15785
+// found in the LICENSE file.
15786
+//
15787
+
15788
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEUNADDRESSABLEREFERENCES_H_
15789
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEUNADDRESSABLEREFERENCES_H_
15790
+
15791
+#include "compiler/translator/Compiler.h"
15792
+#include "compiler/translator/TranslatorMetalDirect/ProgramPrelude.h"
15793
+#include "compiler/translator/TranslatorMetalDirect/SymbolEnv.h"
15794
+
15795
+namespace sh
15796
+{
15797
+
15798
+// Given:
15799
+//   void foo(out x);
15800
+// It is possible for the following to be legal in GLSL but not in Metal:
15801
+//   foo(expression);
15802
+// This can happen in cases where `expression` is a vector swizzle or vector element access.
15803
+// This rewrite functionality introduces temporaries that serve as proxies to be passed to the
15804
+// out/inout parameters as needed. The corresponding expressions get populated with their
15805
+// proxies after the function call.
15806
+ANGLE_NO_DISCARD bool RewriteUnaddressableReferences(TCompiler &compiler,
15807
+                                                     TIntermBlock &root,
15808
+                                                     SymbolEnv &symbolEnv);
15809
+
15810
+}  // namespace sh
15811
+
15812
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEUNADDRESSABLEREFERENCES_H_
15813
diff --git a/src/compiler/translator/TranslatorMetalDirect/SeparateCompoundExpressions.cpp b/src/compiler/translator/TranslatorMetalDirect/SeparateCompoundExpressions.cpp
15814
new file mode 100644
15815
index 0000000..5a7b373
15816
--- /dev/null
15817
+++ b/src/compiler/translator/TranslatorMetalDirect/SeparateCompoundExpressions.cpp
15818
@@ -0,0 +1,655 @@
15819
+//
15820
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
15821
+// Use of this source code is governed by a BSD-style license that can be
15822
+// found in the LICENSE file.
15823
+//
15824
+
15825
+#include <unordered_map>
15826
+
15827
+#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
15828
+#include "compiler/translator/TranslatorMetalDirect/Debug.h"
15829
+#include "compiler/translator/TranslatorMetalDirect/EnvironmentVariable.h"
15830
+#include "compiler/translator/TranslatorMetalDirect/SeparateCompoundExpressions.h"
15831
+#include "compiler/translator/tree_ops/SimplifyLoopConditions.h"
15832
+#include "compiler/translator/tree_util/IntermRebuild.h"
15833
+
15834
+using namespace sh;
15835
+
15836
+////////////////////////////////////////////////////////////////////////////////
15837
+
15838
+namespace
15839
+{
15840
+
15841
+bool IsIndex(TOperator op)
15842
+{
15843
+    switch (op)
15844
+    {
15845
+        case TOperator::EOpIndexDirect:
15846
+        case TOperator::EOpIndexDirectInterfaceBlock:
15847
+        case TOperator::EOpIndexDirectStruct:
15848
+        case TOperator::EOpIndexIndirect:
15849
+            return true;
15850
+        default:
15851
+            return false;
15852
+    }
15853
+}
15854
+
15855
+bool IsIndex(TIntermTyped &expr)
15856
+{
15857
+    if (auto *binary = expr.getAsBinaryNode())
15858
+    {
15859
+        return IsIndex(binary->getOp());
15860
+    }
15861
+    return expr.getAsSwizzleNode();
15862
+}
15863
+
15864
+bool ViewBinaryChain(TOperator op, TIntermTyped &node, std::vector<TIntermTyped *> &out)
15865
+{
15866
+    TIntermBinary *binary = node.getAsBinaryNode();
15867
+    if (!binary || binary->getOp() != op)
15868
+    {
15869
+        return false;
15870
+    }
15871
+
15872
+    TIntermTyped *left  = binary->getLeft();
15873
+    TIntermTyped *right = binary->getRight();
15874
+
15875
+    if (!ViewBinaryChain(op, *left, out))
15876
+    {
15877
+        out.push_back(left);
15878
+    }
15879
+
15880
+    if (!ViewBinaryChain(op, *right, out))
15881
+    {
15882
+        out.push_back(right);
15883
+    }
15884
+
15885
+    return true;
15886
+}
15887
+
15888
+std::vector<TIntermTyped *> ViewBinaryChain(TIntermBinary &node)
15889
+{
15890
+    std::vector<TIntermTyped *> chain;
15891
+    ViewBinaryChain(node.getOp(), node, chain);
15892
+    ASSERT(chain.size() >= 2);
15893
+    return chain;
15894
+}
15895
+
15896
+class PrePass : public TIntermRebuild
15897
+{
15898
+  public:
15899
+    PrePass(TCompiler &compiler) : TIntermRebuild(compiler, true, true) {}
15900
+
15901
+  private:
15902
+    // Change chains of
15903
+    //      x OP y OP z
15904
+    // to
15905
+    //      x OP (y OP z)
15906
+    // regardless of original parenthesization.
15907
+    TIntermTyped &reassociateRight(TIntermBinary &node)
15908
+    {
15909
+        const TOperator op                = node.getOp();
15910
+        std::vector<TIntermTyped *> chain = ViewBinaryChain(node);
15911
+
15912
+        TIntermTyped *result = chain.back();
15913
+        chain.pop_back();
15914
+        ASSERT(result);
15915
+
15916
+        const auto begin = chain.rbegin();
15917
+        const auto end   = chain.rend();
15918
+
15919
+        for (auto iter = begin; iter != end; ++iter)
15920
+        {
15921
+            TIntermTyped *part = *iter;
15922
+            ASSERT(part);
15923
+            TIntermNode *temp = rebuild(*part).single();
15924
+            ASSERT(temp);
15925
+            part = temp->getAsTyped();
15926
+            ASSERT(part);
15927
+            result = new TIntermBinary(op, part, result);
15928
+        }
15929
+        return *result;
15930
+    }
15931
+
15932
+  private:
15933
+    PreResult visitBinaryPre(TIntermBinary &node) override
15934
+    {
15935
+        const TOperator op = node.getOp();
15936
+        if (op == TOperator::EOpLogicalAnd || op == TOperator::EOpLogicalOr)
15937
+        {
15938
+            return {reassociateRight(node), VisitBits::Neither};
15939
+        }
15940
+        return node;
15941
+    }
15942
+};
15943
+
15944
+class Separator : public TIntermRebuild
15945
+{
15946
+    IdGen &mIdGen;
15947
+    std::vector<std::vector<TIntermNode *>> mStmtsStack;
15948
+    std::vector<std::unordered_map<const TVariable *, TIntermDeclaration *>> mBindingMapStack;
15949
+    std::unordered_map<TIntermTyped *, TIntermTyped *> mExprMap;
15950
+    std::unordered_set<TIntermDeclaration *> mMaskedDecls;
15951
+
15952
+  public:
15953
+    Separator(TCompiler &compiler, SymbolEnv &symbolEnv, IdGen &idGen)
15954
+        : TIntermRebuild(compiler, true, true), mIdGen(idGen)
15955
+    {}
15956
+
15957
+    ~Separator() override
15958
+    {
15959
+        ASSERT(mStmtsStack.empty());
15960
+        ASSERT(mExprMap.empty());
15961
+        ASSERT(mBindingMapStack.empty());
15962
+    }
15963
+
15964
+  private:
15965
+    std::vector<TIntermNode *> &getCurrStmts()
15966
+    {
15967
+        ASSERT(!mStmtsStack.empty());
15968
+        return mStmtsStack.back();
15969
+    }
15970
+
15971
+    std::unordered_map<const TVariable *, TIntermDeclaration *> &getCurrBindingMap()
15972
+    {
15973
+        ASSERT(!mBindingMapStack.empty());
15974
+        return mBindingMapStack.back();
15975
+    }
15976
+
15977
+    void pushStmt(TIntermNode &node) { getCurrStmts().push_back(&node); }
15978
+
15979
+    bool isTerminalExpr(TIntermNode &node)
15980
+    {
15981
+        NodeType nodeType = getNodeType(node);
15982
+        switch (nodeType)
15983
+        {
15984
+            case NodeType::Symbol:
15985
+            case NodeType::ConstantUnion:
15986
+                return true;
15987
+            default:
15988
+                return false;
15989
+        }
15990
+    }
15991
+
15992
+    TIntermTyped *pullMappedExpr(TIntermTyped *node, bool allowBacktrack)
15993
+    {
15994
+        TIntermTyped *expr;
15995
+
15996
+        {
15997
+            auto iter = mExprMap.find(node);
15998
+            if (iter == mExprMap.end())
15999
+            {
16000
+                return node;
16001
+            }
16002
+            ASSERT(node);
16003
+            expr = iter->second;
16004
+            ASSERT(expr);
16005
+            mExprMap.erase(iter);
16006
+        }
16007
+
16008
+        if (allowBacktrack)
16009
+        {
16010
+            auto &bindingMap = getCurrBindingMap();
16011
+            while (TIntermSymbol *symbol = expr->getAsSymbolNode())
16012
+            {
16013
+                const TVariable &var = symbol->variable();
16014
+                auto iter            = bindingMap.find(&var);
16015
+                if (iter == bindingMap.end())
16016
+                {
16017
+                    return expr;
16018
+                }
16019
+                ASSERT(var.symbolType() == SymbolType::AngleInternal);
16020
+                TIntermDeclaration *decl = iter->second;
16021
+                ASSERT(decl);
16022
+                expr = ViewDeclaration(*decl).initExpr;
16023
+                ASSERT(expr);
16024
+                bindingMap.erase(iter);
16025
+                mMaskedDecls.insert(decl);
16026
+            }
16027
+        }
16028
+
16029
+        return expr;
16030
+    }
16031
+
16032
+    bool isStandaloneExpr(TIntermTyped &expr)
16033
+    {
16034
+        if (getParentNode()->getAsBlock())
16035
+        {
16036
+            return true;
16037
+        }
16038
+        ASSERT(expr.getType().getBasicType() != TBasicType::EbtVoid);
16039
+        return false;
16040
+    }
16041
+
16042
+    void pushBinding(TIntermTyped &oldExpr, TIntermTyped &newExpr)
16043
+    {
16044
+        if (isStandaloneExpr(newExpr))
16045
+        {
16046
+            pushStmt(newExpr);
16047
+            return;
16048
+        }
16049
+        if (IsIndex(newExpr))
16050
+        {
16051
+            mExprMap[&oldExpr] = &newExpr;
16052
+            return;
16053
+        }
16054
+        auto &bindingMap = getCurrBindingMap();
16055
+        const Name name  = mIdGen.createNewName("");
16056
+        auto *var =
16057
+            new TVariable(&mSymbolTable, name.rawName(), &newExpr.getType(), name.symbolType());
16058
+        auto *decl = new TIntermDeclaration(var, &newExpr);
16059
+        pushStmt(*decl);
16060
+        mExprMap[&oldExpr] = new TIntermSymbol(var);
16061
+        bindingMap[var]    = decl;
16062
+    }
16063
+
16064
+    void pushStacks()
16065
+    {
16066
+        mStmtsStack.emplace_back();
16067
+        mBindingMapStack.emplace_back();
16068
+    }
16069
+
16070
+    void popStacks()
16071
+    {
16072
+        ASSERT(!mBindingMapStack.empty());
16073
+        ASSERT(!mStmtsStack.empty());
16074
+        ASSERT(mStmtsStack.back().empty());
16075
+        mBindingMapStack.pop_back();
16076
+        mStmtsStack.pop_back();
16077
+    }
16078
+
16079
+    void pushStmtsIntoBlock(TIntermBlock &block, std::vector<TIntermNode *> &stmts)
16080
+    {
16081
+        TIntermSequence &seq = *block.getSequence();
16082
+        for (TIntermNode *stmt : stmts)
16083
+        {
16084
+            if (TIntermDeclaration *decl = stmt->getAsDeclarationNode())
16085
+            {
16086
+                auto iter = mMaskedDecls.find(decl);
16087
+                if (iter != mMaskedDecls.end())
16088
+                {
16089
+                    mMaskedDecls.erase(iter);
16090
+                    continue;
16091
+                }
16092
+            }
16093
+            seq.push_back(stmt);
16094
+        }
16095
+    }
16096
+
16097
+    TIntermBlock &buildBlockWithTailAssign(const TVariable &var, TIntermTyped &newExpr)
16098
+    {
16099
+        std::vector<TIntermNode *> stmts = std::move(getCurrStmts());
16100
+        popStacks();
16101
+
16102
+        auto &block = *new TIntermBlock();
16103
+        auto &seq   = *block.getSequence();
16104
+        seq.reserve(1 + stmts.size());
16105
+        pushStmtsIntoBlock(block, stmts);
16106
+        seq.push_back(new TIntermBinary(TOperator::EOpAssign, new TIntermSymbol(&var), &newExpr));
16107
+
16108
+        return block;
16109
+    }
16110
+
16111
+  private:
16112
+    PreResult visitBlockPre(TIntermBlock &node) override
16113
+    {
16114
+        pushStacks();
16115
+        return node;
16116
+    }
16117
+
16118
+    PostResult visitBlockPost(TIntermBlock &node) override
16119
+    {
16120
+        std::vector<TIntermNode *> stmts = std::move(getCurrStmts());
16121
+        popStacks();
16122
+
16123
+        TIntermSequence &seq = *node.getSequence();
16124
+        seq.clear();
16125
+        seq.reserve(stmts.size());
16126
+        pushStmtsIntoBlock(node, stmts);
16127
+
16128
+        TIntermNode *parent = getParentNode();
16129
+        if (parent && parent->getAsBlock())
16130
+        {
16131
+            pushStmt(node);
16132
+        }
16133
+
16134
+        return node;
16135
+    }
16136
+
16137
+    PreResult visitDeclarationPre(TIntermDeclaration &node) override
16138
+    {
16139
+        Declaration decl = ViewDeclaration(node);
16140
+        if (!decl.initExpr || isTerminalExpr(*decl.initExpr))
16141
+        {
16142
+            pushStmt(node);
16143
+            return {node, VisitBits::Neither};
16144
+        }
16145
+        return node;
16146
+    }
16147
+
16148
+    PostResult visitDeclarationPost(TIntermDeclaration &node) override
16149
+    {
16150
+        Declaration decl = ViewDeclaration(node);
16151
+        ASSERT(decl.symbol.variable().symbolType() != SymbolType::Empty);
16152
+        ASSERT(!decl.symbol.variable().getType().isStructSpecifier());
16153
+
16154
+        TIntermTyped *newInitExpr = pullMappedExpr(decl.initExpr, true);
16155
+        if (decl.initExpr == newInitExpr)
16156
+        {
16157
+            pushStmt(node);
16158
+        }
16159
+        else
16160
+        {
16161
+            auto &newNode = *new TIntermDeclaration();
16162
+            newNode.appendDeclarator(
16163
+                new TIntermBinary(TOperator::EOpInitialize, &decl.symbol, newInitExpr));
16164
+            pushStmt(newNode);
16165
+        }
16166
+        return node;
16167
+    }
16168
+
16169
+    PostResult visitUnaryPost(TIntermUnary &node) override
16170
+    {
16171
+        TIntermTyped *expr    = node.getOperand();
16172
+        TIntermTyped *newExpr = pullMappedExpr(expr, false);
16173
+        if (expr == newExpr)
16174
+        {
16175
+            pushBinding(node, node);
16176
+        }
16177
+        else
16178
+        {
16179
+            pushBinding(node, *new TIntermUnary(node.getOp(), newExpr, node.getFunction()));
16180
+        }
16181
+        return node;
16182
+    }
16183
+
16184
+    PreResult visitBinaryPre(TIntermBinary &node) override
16185
+    {
16186
+        const TOperator op = node.getOp();
16187
+        if (op == TOperator::EOpLogicalAnd || op == TOperator::EOpLogicalOr)
16188
+        {
16189
+            TIntermTyped *left  = node.getLeft();
16190
+            TIntermTyped *right = node.getRight();
16191
+
16192
+            PostResult leftResult = rebuild(*left);
16193
+            ASSERT(leftResult.single());
16194
+
16195
+            pushStacks();
16196
+            PostResult rightResult = rebuild(*right);
16197
+            ASSERT(rightResult.single());
16198
+
16199
+            return {node, VisitBits::Post};
16200
+        }
16201
+
16202
+        return node;
16203
+    }
16204
+
16205
+    PostResult visitBinaryPost(TIntermBinary &node) override
16206
+    {
16207
+        const TOperator op = node.getOp();
16208
+        if (op == TOperator::EOpInitialize && getParentNode()->getAsDeclarationNode())
16209
+        {
16210
+            // Special case is handled by visitDeclarationPost
16211
+            return node;
16212
+        }
16213
+
16214
+        TIntermTyped *left  = node.getLeft();
16215
+        TIntermTyped *right = node.getRight();
16216
+
16217
+        if (op == TOperator::EOpLogicalAnd || op == TOperator::EOpLogicalOr)
16218
+        {
16219
+            const Name name = mIdGen.createNewName("");
16220
+            auto *var = new TVariable(&mSymbolTable, name.rawName(), new TType(TBasicType::EbtBool),
16221
+                                      name.symbolType());
16222
+
16223
+            TIntermTyped *newRight   = pullMappedExpr(right, true);
16224
+            TIntermBlock *rightBlock = &buildBlockWithTailAssign(*var, *newRight);
16225
+            TIntermTyped *newLeft    = pullMappedExpr(left, true);
16226
+
16227
+            TIntermTyped *cond = new TIntermSymbol(var);
16228
+            if (op == TOperator::EOpLogicalOr)
16229
+            {
16230
+                cond = new TIntermUnary(TOperator::EOpLogicalNot, cond, nullptr);
16231
+            }
16232
+
16233
+            pushStmt(*new TIntermDeclaration(var, newLeft));
16234
+            pushStmt(*new TIntermIfElse(cond, rightBlock, nullptr));
16235
+            if (!isStandaloneExpr(node))
16236
+            {
16237
+                mExprMap[&node] = new TIntermSymbol(var);
16238
+            }
16239
+
16240
+            return node;
16241
+        }
16242
+
16243
+        const bool isAssign    = IsAssignment(op);
16244
+        TIntermTyped *newLeft  = pullMappedExpr(left, false);
16245
+        TIntermTyped *newRight = pullMappedExpr(right, isAssign);
16246
+
16247
+        if (op == TOperator::EOpComma)
16248
+        {
16249
+            pushBinding(node, *newRight);
16250
+            return node;
16251
+        }
16252
+        else
16253
+        {
16254
+            TIntermBinary *newNode;
16255
+            if (left == newLeft && right == newRight)
16256
+            {
16257
+                newNode = &node;
16258
+            }
16259
+            else
16260
+            {
16261
+                newNode = new TIntermBinary(op, newLeft, newRight);
16262
+            }
16263
+            pushBinding(node, *newNode);
16264
+            return node;
16265
+        }
16266
+    }
16267
+
16268
+    PreResult visitTernaryPre(TIntermTernary &node) override
16269
+    {
16270
+        PostResult condResult = rebuild(*node.getCondition());
16271
+        ASSERT(condResult.single());
16272
+
16273
+        pushStacks();
16274
+        PostResult thenResult = rebuild(*node.getTrueExpression());
16275
+        ASSERT(thenResult.single());
16276
+
16277
+        pushStacks();
16278
+        PostResult elseResult = rebuild(*node.getFalseExpression());
16279
+        ASSERT(elseResult.single());
16280
+
16281
+        return {node, VisitBits::Post};
16282
+    }
16283
+
16284
+    PostResult visitTernaryPost(TIntermTernary &node) override
16285
+    {
16286
+        TIntermTyped *cond  = node.getCondition();
16287
+        TIntermTyped *then  = node.getTrueExpression();
16288
+        TIntermTyped *else_ = node.getFalseExpression();
16289
+
16290
+        const Name name = mIdGen.createNewName("");
16291
+        auto *var =
16292
+            new TVariable(&mSymbolTable, name.rawName(), &node.getType(), name.symbolType());
16293
+
16294
+        TIntermTyped *newElse   = pullMappedExpr(else_, false);
16295
+        TIntermBlock *elseBlock = &buildBlockWithTailAssign(*var, *newElse);
16296
+        TIntermTyped *newThen   = pullMappedExpr(then, true);
16297
+        TIntermBlock *thenBlock = &buildBlockWithTailAssign(*var, *newThen);
16298
+        TIntermTyped *newCond   = pullMappedExpr(cond, true);
16299
+
16300
+        pushStmt(*new TIntermDeclaration{var});
16301
+        pushStmt(*new TIntermIfElse(newCond, thenBlock, elseBlock));
16302
+        if (!isStandaloneExpr(node))
16303
+        {
16304
+            mExprMap[&node] = new TIntermSymbol(var);
16305
+        }
16306
+
16307
+        return node;
16308
+    }
16309
+
16310
+    PostResult visitSwizzlePost(TIntermSwizzle &node) override
16311
+    {
16312
+        TIntermTyped *expr    = node.getOperand();
16313
+        TIntermTyped *newExpr = pullMappedExpr(expr, false);
16314
+        if (expr == newExpr)
16315
+        {
16316
+            pushBinding(node, node);
16317
+        }
16318
+        else
16319
+        {
16320
+            pushBinding(node, *new TIntermSwizzle(newExpr, node.getSwizzleOffsets()));
16321
+        }
16322
+        return node;
16323
+    }
16324
+
16325
+    PostResult visitAggregatePost(TIntermAggregate &node) override
16326
+    {
16327
+        TIntermSequence &args = *node.getSequence();
16328
+        for (TIntermNode *&arg : args)
16329
+        {
16330
+            TIntermTyped *targ = arg->getAsTyped();
16331
+            ASSERT(targ);
16332
+            arg = pullMappedExpr(targ, false);
16333
+        }
16334
+        pushBinding(node, node);
16335
+        return node;
16336
+    }
16337
+
16338
+    PostResult visitPreprocessorDirectivePost(TIntermPreprocessorDirective &node) override
16339
+    {
16340
+        pushStmt(node);
16341
+        return node;
16342
+    }
16343
+
16344
+    PostResult visitFunctionPrototypePost(TIntermFunctionPrototype &node) override
16345
+    {
16346
+        if (!getParentFunction())
16347
+        {
16348
+            pushStmt(node);
16349
+        }
16350
+        return node;
16351
+    }
16352
+
16353
+    PreResult visitCasePre(TIntermCase &node) override
16354
+    {
16355
+        if (TIntermTyped *cond = node.getCondition())
16356
+        {
16357
+            ASSERT(isTerminalExpr(*cond));
16358
+        }
16359
+        pushStmt(node);
16360
+        return {node, VisitBits::Neither};
16361
+    }
16362
+
16363
+    PostResult visitSwitchPost(TIntermSwitch &node) override
16364
+    {
16365
+        TIntermTyped *init    = node.getInit();
16366
+        TIntermTyped *newInit = pullMappedExpr(init, false);
16367
+        if (init == newInit)
16368
+        {
16369
+            pushStmt(node);
16370
+        }
16371
+        else
16372
+        {
16373
+            pushStmt(*new TIntermSwitch(newInit, node.getStatementList()));
16374
+        }
16375
+
16376
+        return node;
16377
+    }
16378
+
16379
+    PostResult visitFunctionDefinitionPost(TIntermFunctionDefinition &node) override
16380
+    {
16381
+        pushStmt(node);
16382
+        return node;
16383
+    }
16384
+
16385
+    PostResult visitIfElsePost(TIntermIfElse &node) override
16386
+    {
16387
+        TIntermTyped *cond    = node.getCondition();
16388
+        TIntermTyped *newCond = pullMappedExpr(cond, false);
16389
+        if (cond == newCond)
16390
+        {
16391
+            pushStmt(node);
16392
+        }
16393
+        else
16394
+        {
16395
+            pushStmt(*new TIntermIfElse(newCond, node.getTrueBlock(), node.getFalseBlock()));
16396
+        }
16397
+        return node;
16398
+    }
16399
+
16400
+    PostResult visitBranchPost(TIntermBranch &node) override
16401
+    {
16402
+        TIntermTyped *expr    = node.getExpression();
16403
+        TIntermTyped *newExpr = pullMappedExpr(expr, false);
16404
+        if (expr == newExpr)
16405
+        {
16406
+            pushStmt(node);
16407
+        }
16408
+        else
16409
+        {
16410
+            pushStmt(*new TIntermBranch(node.getFlowOp(), newExpr));
16411
+        }
16412
+        return node;
16413
+    }
16414
+
16415
+    PreResult visitLoopPre(TIntermLoop &node) override
16416
+    {
16417
+        if (!rebuildInPlace(*node.getBody()))
16418
+        {
16419
+            LOGIC_ERROR();
16420
+        }
16421
+        pushStmt(node);
16422
+        return {node, VisitBits::Neither};
16423
+    }
16424
+
16425
+    PostResult visitConstantUnionPost(TIntermConstantUnion &node) override
16426
+    {
16427
+        const TType &type = node.getType();
16428
+        if (!type.isScalar())
16429
+        {
16430
+            pushBinding(node, node);
16431
+        }
16432
+        return node;
16433
+    }
16434
+
16435
+    PostResult visitGlobalQualifierDeclarationPost(TIntermGlobalQualifierDeclaration &node) override
16436
+    {
16437
+        ASSERT(false);  // These should be scrubbed from AST before rewriter is called.
16438
+        pushStmt(node);
16439
+        return node;
16440
+    }
16441
+};
16442
+
16443
+}  // anonymous namespace
16444
+
16445
+////////////////////////////////////////////////////////////////////////////////
16446
+
16447
+bool sh::SeparateCompoundExpressions(TCompiler &compiler,
16448
+                                     SymbolEnv &symbolEnv,
16449
+                                     IdGen &idGen,
16450
+                                     TIntermBlock &root)
16451
+{
16452
+    if (readBoolEnvVar("GMT_DISABLE_SEPARATE_COMPOUND_EXPRESSIONS"))
16453
+    {
16454
+        return true;
16455
+    }
16456
+
16457
+    if (!SimplifyLoopConditions(&compiler, &root, &compiler.getSymbolTable()))
16458
+    {
16459
+        return false;
16460
+    }
16461
+
16462
+    if (!PrePass(compiler).rebuildRoot(root))
16463
+    {
16464
+        return false;
16465
+    }
16466
+
16467
+    if (!Separator(compiler, symbolEnv, idGen).rebuildRoot(root))
16468
+    {
16469
+        return false;
16470
+    }
16471
+
16472
+    return true;
16473
+}
16474
diff --git a/src/compiler/translator/TranslatorMetalDirect/SeparateCompoundExpressions.h b/src/compiler/translator/TranslatorMetalDirect/SeparateCompoundExpressions.h
16475
new file mode 100644
16476
index 0000000..5e40a55
16477
--- /dev/null
16478
+++ b/src/compiler/translator/TranslatorMetalDirect/SeparateCompoundExpressions.h
16479
@@ -0,0 +1,47 @@
16480
+//
16481
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
16482
+// Use of this source code is governed by a BSD-style license that can be
16483
+// found in the LICENSE file.
16484
+//
16485
+
16486
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_SEPARATECOMPOUNDEXPRESSIONS_H_
16487
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_SEPARATECOMPOUNDEXPRESSIONS_H_
16488
+
16489
+#include "common/angleutils.h"
16490
+#include "compiler/translator/Compiler.h"
16491
+#include "compiler/translator/TranslatorMetalDirect/IdGen.h"
16492
+#include "compiler/translator/TranslatorMetalDirect/SymbolEnv.h"
16493
+
16494
+namespace sh
16495
+{
16496
+
16497
+// Transforms code to (usually) have most one non-terminal expression per statement.
16498
+// This also rewrites (&&), (||), and (?:) into raw if/if-not/if-else statements, respectively.
16499
+//
16500
+// e.g.
16501
+//    int x = 6 + foo(y, bar());
16502
+// becomes
16503
+//    auto _1 = bar();
16504
+//    auto _2 = foo(y, _1);
16505
+//    auto _3 = 6 + _2;
16506
+//    int x = _3;
16507
+//
16508
+// WARNING:
16509
+//    - This does not rewrite object indexing operators as a whole (e.g. foo.x, foo[x]), but will
16510
+//      rewrite the arguments to the operator (when applicable).
16511
+//      e.g.
16512
+//        foo(getVec()[i + 2] + 1);
16513
+//      becomes
16514
+//        auto _1 = getVec();
16515
+//        auto _2 = i + 2;
16516
+//        auto _3 = _1[_2] + 1; // Index operator remains in (+) expr here.
16517
+//        foo(_3);
16518
+//
16519
+ANGLE_NO_DISCARD bool SeparateCompoundExpressions(TCompiler &compiler,
16520
+                                                  SymbolEnv &symbolEnv,
16521
+                                                  IdGen &idGen,
16522
+                                                  TIntermBlock &root);
16523
+
16524
+}  // namespace sh
16525
+
16526
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_SEPARATECOMPOUNDEXPRESSIONS_H_
16527
diff --git a/src/compiler/translator/TranslatorMetalDirect/SeparateCompoundStructDeclarations.cpp b/src/compiler/translator/TranslatorMetalDirect/SeparateCompoundStructDeclarations.cpp
16528
new file mode 100644
16529
index 0000000..4ba8c6d
16530
--- /dev/null
16531
+++ b/src/compiler/translator/TranslatorMetalDirect/SeparateCompoundStructDeclarations.cpp
16532
@@ -0,0 +1,77 @@
16533
+//
16534
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
16535
+// Use of this source code is governed by a BSD-style license that can be
16536
+// found in the LICENSE file.
16537
+//
16538
+
16539
+#include <algorithm>
16540
+
16541
+#include "compiler/translator/TranslatorMetalDirect/SeparateCompoundStructDeclarations.h"
16542
+#include "compiler/translator/tree_ops/SeparateDeclarations.h"
16543
+#include "compiler/translator/tree_util/IntermTraverse.h"
16544
+
16545
+using namespace sh;
16546
+
16547
+////////////////////////////////////////////////////////////////////////////////
16548
+
16549
+namespace
16550
+{
16551
+
16552
+class Separator : public TIntermTraverser
16553
+{
16554
+  public:
16555
+    Separator(TSymbolTable &symbolTable) : TIntermTraverser(false, false, true, &symbolTable) {}
16556
+
16557
+    bool visitDeclaration(Visit, TIntermDeclaration *declNode) override
16558
+    {
16559
+        ASSERT(declNode->getChildCount() == 1);
16560
+        TIntermNode &node = *declNode->getChildNode(0);
16561
+
16562
+        if (TIntermSymbol *symbolNode = node.getAsSymbolNode())
16563
+        {
16564
+            const TVariable &var        = symbolNode->variable();
16565
+            const TType &type           = var.getType();
16566
+            const SymbolType symbolType = var.symbolType();
16567
+            if (type.isStructSpecifier() && symbolType != SymbolType::Empty)
16568
+            {
16569
+                const TStructure *structure = type.getStruct();
16570
+                auto *structVar             = new TVariable(mSymbolTable, ImmutableString(""),
16571
+                                                new TType(structure, true), SymbolType::Empty);
16572
+
16573
+                auto *instanceType = new TType(structure, false);
16574
+                instanceType->setQualifier(type.getQualifier());
16575
+                auto *instanceVar = new TVariable(mSymbolTable, var.name(), instanceType,
16576
+                                                  symbolType, var.extension());
16577
+
16578
+                TIntermSequence replacements;
16579
+                replacements.push_back(new TIntermSymbol(structVar));
16580
+                replacements.push_back(new TIntermSymbol(instanceVar));
16581
+                mMultiReplacements.push_back(
16582
+                    NodeReplaceWithMultipleEntry(declNode, symbolNode, std::move(replacements)));
16583
+            }
16584
+        }
16585
+
16586
+        return false;
16587
+    }
16588
+};
16589
+
16590
+}  // anonymous namespace
16591
+
16592
+////////////////////////////////////////////////////////////////////////////////
16593
+
16594
+bool sh::SeparateCompoundStructDeclarations(TCompiler &compiler, TIntermBlock &root)
16595
+{
16596
+    Separator separator(compiler.getSymbolTable());
16597
+    root.traverse(&separator);
16598
+    if (!separator.updateTree(&compiler, &root))
16599
+    {
16600
+        return false;
16601
+    }
16602
+
16603
+    if (!SeparateDeclarations(&compiler, &root))
16604
+    {
16605
+        return false;
16606
+    }
16607
+
16608
+    return true;
16609
+}
16610
diff --git a/src/compiler/translator/TranslatorMetalDirect/SeparateCompoundStructDeclarations.h b/src/compiler/translator/TranslatorMetalDirect/SeparateCompoundStructDeclarations.h
16611
new file mode 100644
16612
index 0000000..0712e80
16613
--- /dev/null
16614
+++ b/src/compiler/translator/TranslatorMetalDirect/SeparateCompoundStructDeclarations.h
16615
@@ -0,0 +1,24 @@
16616
+//
16617
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
16618
+// Use of this source code is governed by a BSD-style license that can be
16619
+// found in the LICENSE file.
16620
+//
16621
+
16622
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_SEPARATECOMPOUNDSTRUCTDECLARATIONS_H_
16623
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_SEPARATECOMPOUNDSTRUCTDECLARATIONS_H_
16624
+
16625
+#include "common/angleutils.h"
16626
+#include "compiler/translator/Compiler.h"
16627
+
16628
+namespace sh
16629
+{
16630
+
16631
+// Example:
16632
+//  struct Foo { int x; } foo;
16633
+// Becomes:
16634
+//  struct Foo {int x; }; Foo foo;
16635
+ANGLE_NO_DISCARD bool SeparateCompoundStructDeclarations(TCompiler &compiler, TIntermBlock &root);
16636
+
16637
+}  // namespace sh
16638
+
16639
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_SEPARATECOMPOUNDSTRUCTDECLARATIONS_H_
16640
diff --git a/src/compiler/translator/TranslatorMetalDirect/SkippingTraverser.h b/src/compiler/translator/TranslatorMetalDirect/SkippingTraverser.h
16641
new file mode 100644
16642
index 0000000..ff49dad
16643
--- /dev/null
16644
+++ b/src/compiler/translator/TranslatorMetalDirect/SkippingTraverser.h
16645
@@ -0,0 +1,47 @@
16646
+//
16647
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
16648
+// Use of this source code is governed by a BSD-style license that can be
16649
+// found in the LICENSE file.
16650
+//
16651
+
16652
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_SKIPPINGTRAVERSER_H_
16653
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_SKIPPINGTRAVERSER_H_
16654
+
16655
+#include "compiler/translator/tree_util/IntermTraverse.h"
16656
+
16657
+namespace sh
16658
+{
16659
+
16660
+// A TIntermTraverser that skips traversing childen by default.
16661
+class SkippingTraverser : public TIntermTraverser
16662
+{
16663
+  public:
16664
+    SkippingTraverser(bool preVisit_,
16665
+                      bool inVisit_,
16666
+                      bool postVisit_,
16667
+                      TSymbolTable *symbolTable = nullptr)
16668
+        : TIntermTraverser(preVisit_, inVisit_, postVisit_, symbolTable)
16669
+    {}
16670
+
16671
+    bool visitSwizzle(Visit, TIntermSwizzle *) { return false; }
16672
+    bool visitUnary(Visit, TIntermUnary *) { return false; }
16673
+    bool visitBinary(Visit, TIntermBinary *) { return false; }
16674
+    bool visitTernary(Visit, TIntermTernary *) { return false; }
16675
+    bool visitIfElse(Visit, TIntermIfElse *) { return false; }
16676
+    bool visitSwitch(Visit, TIntermSwitch *) { return false; }
16677
+    bool visitCase(Visit, TIntermCase *) { return false; }
16678
+    bool visitFunctionDefinition(Visit, TIntermFunctionDefinition *) { return false; }
16679
+    bool visitAggregate(Visit, TIntermAggregate *) { return false; }
16680
+    bool visitBlock(Visit, TIntermBlock *) { return false; }
16681
+    bool visitDeclaration(Visit, TIntermDeclaration *) { return false; }
16682
+    bool visitLoop(Visit, TIntermLoop *) { return false; }
16683
+    bool visitBranch(Visit, TIntermBranch *) { return false; }
16684
+    bool visitGlobalQualifierDeclaration(Visit, TIntermGlobalQualifierDeclaration *)
16685
+    {
16686
+        return false;
16687
+    }
16688
+};
16689
+
16690
+}  // namespace sh
16691
+
16692
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_SKIPPINGTRAVERSER_H_
16693
diff --git a/src/compiler/translator/TranslatorMetalDirect/SymbolEnv.cpp b/src/compiler/translator/TranslatorMetalDirect/SymbolEnv.cpp
16694
new file mode 100644
16695
index 0000000..4753dac
16696
--- /dev/null
16697
+++ b/src/compiler/translator/TranslatorMetalDirect/SymbolEnv.cpp
16698
@@ -0,0 +1,681 @@
16699
+//
16700
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
16701
+// Use of this source code is governed by a BSD-style license that can be
16702
+// found in the LICENSE file.
16703
+//
16704
+
16705
+#include <algorithm>
16706
+#include <limits>
16707
+
16708
+#include "compiler/translator/ImmutableStringBuilder.h"
16709
+#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
16710
+#include "compiler/translator/TranslatorMetalDirect/Debug.h"
16711
+#include "compiler/translator/TranslatorMetalDirect/SymbolEnv.h"
16712
+#include "compiler/translator/tree_util/IntermRebuild.h"
16713
+
16714
+using namespace sh;
16715
+
16716
+////////////////////////////////////////////////////////////////////////////////
16717
+
16718
+constexpr AddressSpace kAddressSpaces[] = {
16719
+    AddressSpace::Constant,
16720
+    AddressSpace::Device,
16721
+    AddressSpace::Thread,
16722
+};
16723
+
16724
+char const *sh::toString(AddressSpace space)
16725
+{
16726
+    switch (space)
16727
+    {
16728
+        case AddressSpace::Constant:
16729
+            return "constant";
16730
+        case AddressSpace::Device:
16731
+            return "device";
16732
+        case AddressSpace::Thread:
16733
+            return "thread";
16734
+    }
16735
+}
16736
+
16737
+////////////////////////////////////////////////////////////////////////////////
16738
+
16739
+using NameToStruct = std::map<Name, const TStructure *>;
16740
+
16741
+class StructFinder : TIntermRebuild
16742
+{
16743
+    NameToStruct nameToStruct;
16744
+
16745
+    StructFinder(TCompiler &compiler) : TIntermRebuild(compiler, true, false) {}
16746
+
16747
+    PreResult visitDeclarationPre(TIntermDeclaration &node) override
16748
+    {
16749
+        Declaration decl     = ViewDeclaration(node);
16750
+        const TVariable &var = decl.symbol.variable();
16751
+        const TType &type    = var.getType();
16752
+
16753
+        if (var.symbolType() == SymbolType::Empty && type.isStructSpecifier())
16754
+        {
16755
+            const TStructure *s = type.getStruct();
16756
+            ASSERT(s);
16757
+            const Name name(*s);
16758
+            const TStructure *&z = nameToStruct[name];
16759
+            ASSERT(!z);
16760
+            z = s;
16761
+        }
16762
+
16763
+        return node;
16764
+    }
16765
+
16766
+    PreResult visitFunctionDefinitionPre(TIntermFunctionDefinition &node) override
16767
+    {
16768
+        return {node, VisitBits::Neither};
16769
+    }
16770
+
16771
+  public:
16772
+    static NameToStruct FindStructs(TCompiler &compiler, TIntermBlock &root)
16773
+    {
16774
+        StructFinder finder(compiler);
16775
+        if (!finder.rebuildRoot(root))
16776
+        {
16777
+            LOGIC_ERROR();
16778
+        }
16779
+        return std::move(finder.nameToStruct);
16780
+    }
16781
+};
16782
+
16783
+////////////////////////////////////////////////////////////////////////////////
16784
+
16785
+TemplateArg::TemplateArg(bool value) : mKind(Kind::Bool), mValue(value) {}
16786
+
16787
+TemplateArg::TemplateArg(int value) : mKind(Kind::Int), mValue(value) {}
16788
+
16789
+TemplateArg::TemplateArg(unsigned value) : mKind(Kind::UInt), mValue(value) {}
16790
+
16791
+TemplateArg::TemplateArg(const TType &value) : mKind(Kind::Type), mValue(value) {}
16792
+
16793
+bool TemplateArg::operator==(const TemplateArg &other) const
16794
+{
16795
+    if (mKind != other.mKind)
16796
+    {
16797
+        return false;
16798
+    }
16799
+
16800
+    switch (mKind)
16801
+    {
16802
+        case Kind::Bool:
16803
+            return mValue.b == other.mValue.b;
16804
+        case Kind::Int:
16805
+            return mValue.i == other.mValue.i;
16806
+        case Kind::UInt:
16807
+            return mValue.u == other.mValue.u;
16808
+        case Kind::Type:
16809
+            return *mValue.t == *other.mValue.t;
16810
+    }
16811
+}
16812
+
16813
+bool TemplateArg::operator<(const TemplateArg &other) const
16814
+{
16815
+    if (mKind < other.mKind)
16816
+    {
16817
+        return true;
16818
+    }
16819
+
16820
+    if (mKind > other.mKind)
16821
+    {
16822
+        return false;
16823
+    }
16824
+
16825
+    switch (mKind)
16826
+    {
16827
+        case Kind::Bool:
16828
+            return mValue.b < other.mValue.b;
16829
+        case Kind::Int:
16830
+            return mValue.i < other.mValue.i;
16831
+        case Kind::UInt:
16832
+            return mValue.u < other.mValue.u;
16833
+        case Kind::Type:
16834
+            return *mValue.t < *other.mValue.t;
16835
+    }
16836
+}
16837
+
16838
+////////////////////////////////////////////////////////////////////////////////
16839
+
16840
+bool SymbolEnv::TemplateName::operator==(const TemplateName &other) const
16841
+{
16842
+    return baseName == other.baseName && templateArgs == other.templateArgs;
16843
+}
16844
+
16845
+bool SymbolEnv::TemplateName::operator<(const TemplateName &other) const
16846
+{
16847
+    if (baseName < other.baseName)
16848
+    {
16849
+        return true;
16850
+    }
16851
+    if (other.baseName < baseName)
16852
+    {
16853
+        return false;
16854
+    }
16855
+    return templateArgs < other.templateArgs;
16856
+}
16857
+
16858
+bool SymbolEnv::TemplateName::empty() const
16859
+{
16860
+    return baseName.empty() && templateArgs.empty();
16861
+}
16862
+
16863
+void SymbolEnv::TemplateName::clear()
16864
+{
16865
+    baseName = Name();
16866
+    templateArgs.clear();
16867
+}
16868
+
16869
+Name SymbolEnv::TemplateName::fullName(std::string &buffer) const
16870
+{
16871
+    ASSERT(buffer.empty());
16872
+
16873
+    if (templateArgs.empty())
16874
+    {
16875
+        return baseName;
16876
+    }
16877
+
16878
+    static constexpr size_t n = std::max({
16879
+        std::numeric_limits<unsigned>::digits10,  //
16880
+        std::numeric_limits<int>::digits10,       //
16881
+        5,                                        // max_length("true", "false")
16882
+    });
16883
+
16884
+    buffer.reserve(baseName.rawName().length() + (n + 2) * templateArgs.size() + 1);
16885
+    buffer += baseName.rawName().data();
16886
+
16887
+    if (!templateArgs.empty())
16888
+    {
16889
+        buffer += "<";
16890
+
16891
+        bool first = true;
16892
+        char argBuffer[n + 1];
16893
+        for (const TemplateArg &arg : templateArgs)
16894
+        {
16895
+            if (first)
16896
+            {
16897
+                first = false;
16898
+            }
16899
+            else
16900
+            {
16901
+                buffer += ", ";
16902
+            }
16903
+
16904
+            const TemplateArg::Value value = arg.value();
16905
+            const TemplateArg::Kind kind   = arg.kind();
16906
+            switch (kind)
16907
+            {
16908
+                case TemplateArg::Kind::Bool:
16909
+                    if (value.b)
16910
+                    {
16911
+                        buffer += "true";
16912
+                    }
16913
+                    else
16914
+                    {
16915
+                        buffer += "false";
16916
+                    }
16917
+                    break;
16918
+
16919
+                case TemplateArg::Kind::Int:
16920
+                    sprintf(argBuffer, "%i", value.i);
16921
+                    buffer += argBuffer;
16922
+                    break;
16923
+
16924
+                case TemplateArg::Kind::UInt:
16925
+                    sprintf(argBuffer, "%u", value.u);
16926
+                    buffer += argBuffer;
16927
+                    break;
16928
+
16929
+                case TemplateArg::Kind::Type:
16930
+                {
16931
+                    const TType &type = *value.t;
16932
+                    if (const TStructure *s = type.getStruct())
16933
+                    {
16934
+                        buffer += s->name().data();
16935
+                    }
16936
+                    else if (HasScalarBasicType(type))
16937
+                    {
16938
+                        ASSERT(!type.isArray());  // TODO
16939
+                        buffer += type.getBasicString();
16940
+                        if (type.isVector())
16941
+                        {
16942
+                            sprintf(argBuffer, "%i", type.getNominalSize());
16943
+                            buffer += argBuffer;
16944
+                        }
16945
+                        else if (type.isMatrix())
16946
+                        {
16947
+                            sprintf(argBuffer, "%i", type.getCols());
16948
+                            buffer += argBuffer;
16949
+                            buffer += "x";
16950
+                            sprintf(argBuffer, "%i", type.getRows());
16951
+                            buffer += argBuffer;
16952
+                        }
16953
+                    }
16954
+                }
16955
+                break;
16956
+            }
16957
+        }
16958
+
16959
+        buffer += ">";
16960
+    }
16961
+
16962
+    const ImmutableString name(buffer);
16963
+    buffer.clear();
16964
+
16965
+    return Name(name, baseName.symbolType());
16966
+}
16967
+
16968
+void SymbolEnv::TemplateName::assign(const Name &name, size_t argCount, const TemplateArg *args)
16969
+{
16970
+    baseName = name;
16971
+    templateArgs.clear();
16972
+    for (size_t i = 0; i < argCount; ++i)
16973
+    {
16974
+        templateArgs.push_back(args[i]);
16975
+    }
16976
+}
16977
+
16978
+////////////////////////////////////////////////////////////////////////////////
16979
+
16980
+SymbolEnv::SymbolEnv(TCompiler &compiler, TIntermBlock &root)
16981
+    : mSymbolTable(compiler.getSymbolTable()),
16982
+      mNameToStruct(StructFinder::FindStructs(compiler, root))
16983
+{}
16984
+
16985
+const TStructure &SymbolEnv::remap(const TStructure &s) const
16986
+{
16987
+    const Name name(s);
16988
+    auto iter = mNameToStruct.find(name);
16989
+    if (iter == mNameToStruct.end())
16990
+    {
16991
+        return s;
16992
+    }
16993
+    const TStructure &z = *iter->second;
16994
+    return z;
16995
+}
16996
+
16997
+const TStructure *SymbolEnv::remap(const TStructure *s) const
16998
+{
16999
+    if (s)
17000
+    {
17001
+        return &remap(*s);
17002
+    }
17003
+    return nullptr;
17004
+}
17005
+
17006
+const TFunction &SymbolEnv::getFunctionOverloadImpl()
17007
+{
17008
+    ASSERT(!mReusableSigBuffer.empty());
17009
+
17010
+    SigToFunc &sigToFunc = mOverloads[mReusableTemplateNameBuffer];
17011
+    TFunction *&func     = sigToFunc[mReusableSigBuffer];
17012
+
17013
+    if (!func)
17014
+    {
17015
+        const TType &returnType = mReusableSigBuffer.back();
17016
+        mReusableSigBuffer.pop_back();
17017
+
17018
+        const Name name = mReusableTemplateNameBuffer.fullName(mReusableStringBuffer);
17019
+
17020
+        func = new TFunction(&mSymbolTable, name.rawName(), name.symbolType(), &returnType, false);
17021
+        for (const TType &paramType : mReusableSigBuffer)
17022
+        {
17023
+            func->addParameter(
17024
+                new TVariable(&mSymbolTable, kEmptyImmutableString, &paramType, SymbolType::Empty));
17025
+        }
17026
+    }
17027
+
17028
+    mReusableSigBuffer.clear();
17029
+    mReusableTemplateNameBuffer.clear();
17030
+
17031
+    return *func;
17032
+}
17033
+
17034
+const TFunction &SymbolEnv::getFunctionOverload(const Name &name,
17035
+                                                const TType &returnType,
17036
+                                                size_t paramCount,
17037
+                                                const TType **paramTypes,
17038
+                                                size_t templateArgCount,
17039
+                                                const TemplateArg *templateArgs)
17040
+{
17041
+    ASSERT(mReusableSigBuffer.empty());
17042
+    ASSERT(mReusableTemplateNameBuffer.empty());
17043
+
17044
+    for (size_t i = 0; i < paramCount; ++i)
17045
+    {
17046
+        mReusableSigBuffer.push_back(*paramTypes[i]);
17047
+    }
17048
+    mReusableSigBuffer.push_back(returnType);
17049
+    mReusableTemplateNameBuffer.assign(name, templateArgCount, templateArgs);
17050
+    return getFunctionOverloadImpl();
17051
+}
17052
+
17053
+TIntermAggregate &SymbolEnv::callFunctionOverload(const Name &name,
17054
+                                                  const TType &returnType,
17055
+                                                  TIntermSequence &args,
17056
+                                                  size_t templateArgCount,
17057
+                                                  const TemplateArg *templateArgs)
17058
+{
17059
+    ASSERT(mReusableSigBuffer.empty());
17060
+    ASSERT(mReusableTemplateNameBuffer.empty());
17061
+
17062
+    for (TIntermNode *arg : args)
17063
+    {
17064
+        TIntermTyped *targ = arg->getAsTyped();
17065
+        ASSERT(targ);
17066
+        mReusableSigBuffer.push_back(targ->getType());
17067
+    }
17068
+    mReusableSigBuffer.push_back(returnType);
17069
+    mReusableTemplateNameBuffer.assign(name, templateArgCount, templateArgs);
17070
+    const TFunction &func = getFunctionOverloadImpl();
17071
+    return *TIntermAggregate::CreateRawFunctionCall(func, &args);
17072
+}
17073
+
17074
+const TStructure &SymbolEnv::newStructure(const Name &name, TFieldList &fields)
17075
+{
17076
+    ASSERT(name.symbolType() == SymbolType::AngleInternal);
17077
+
17078
+    TStructure *&s = mAngleStructs[name.rawName()];
17079
+    ASSERT(!s);
17080
+    s = new TStructure(&mSymbolTable, name.rawName(), &fields, name.symbolType());
17081
+    return *s;
17082
+}
17083
+
17084
+const TStructure &SymbolEnv::getTextureEnv(TBasicType samplerType)
17085
+{
17086
+    ASSERT(IsSampler(samplerType));
17087
+    const TStructure *&env = mTextureEnvs[samplerType];
17088
+    if (env == nullptr)
17089
+    {
17090
+        auto *textureType = new TType(samplerType);
17091
+        auto *texture     = new TField(textureType, ImmutableString("texture"), kNoSourceLoc,
17092
+                                   SymbolType::UserDefined);
17093
+        markAsPointer(*texture, AddressSpace::Thread);
17094
+
17095
+        auto *sampler =
17096
+            new TField(new TType(&getSamplerStruct(), false), ImmutableString("sampler"),
17097
+                       kNoSourceLoc, SymbolType::UserDefined);
17098
+        markAsPointer(*sampler, AddressSpace::Thread);
17099
+
17100
+        std::string envName;
17101
+        envName += "TextureEnv<";
17102
+        envName += GetTextureTypeName(samplerType).rawName().data();
17103
+        envName += ">";
17104
+
17105
+        env = &newStructure(Name(envName, SymbolType::AngleInternal),
17106
+                            *new TFieldList{texture, sampler});
17107
+    }
17108
+    return *env;
17109
+}
17110
+
17111
+const TStructure &SymbolEnv::getSamplerStruct()
17112
+{
17113
+    if (!mSampler)
17114
+    {
17115
+        mSampler = new TStructure(&mSymbolTable, ImmutableString("metal::sampler"),
17116
+                                  new TFieldList(), SymbolType::UserDefined);
17117
+    }
17118
+    return *mSampler;
17119
+}
17120
+
17121
+void SymbolEnv::markSpace(VarField x,
17122
+                          AddressSpace space,
17123
+                          std::unordered_map<VarField, AddressSpace> &map)
17124
+{
17125
+    // It is in principle permissible to have references to pointers or multiple pointers, but this
17126
+    // is not required for now and would require code changes to get right.
17127
+    ASSERT(!isPointer(x));
17128
+    ASSERT(!isReference(x));
17129
+
17130
+    map[x] = space;
17131
+}
17132
+
17133
+const AddressSpace *SymbolEnv::isSpace(VarField x,
17134
+                                       const std::unordered_map<VarField, AddressSpace> &map) const
17135
+{
17136
+    const auto iter = map.find(x);
17137
+    if (iter == map.end())
17138
+    {
17139
+        return nullptr;
17140
+    }
17141
+    const AddressSpace space = iter->second;
17142
+    const auto index         = static_cast<std::underlying_type_t<AddressSpace>>(space);
17143
+    return &kAddressSpaces[index];
17144
+}
17145
+
17146
+void SymbolEnv::markAsPointer(VarField x, AddressSpace space)
17147
+{
17148
+    return markSpace(x, space, mPointers);
17149
+}
17150
+
17151
+void SymbolEnv::markAsReference(VarField x, AddressSpace space)
17152
+{
17153
+    return markSpace(x, space, mReferences);
17154
+}
17155
+
17156
+const AddressSpace *SymbolEnv::isPointer(VarField x) const
17157
+{
17158
+    return isSpace(x, mPointers);
17159
+}
17160
+
17161
+const AddressSpace *SymbolEnv::isReference(VarField x) const
17162
+{
17163
+    return isSpace(x, mReferences);
17164
+}
17165
+
17166
+void SymbolEnv::markAsPacked(const TField &field)
17167
+{
17168
+    mPackedFields.insert(&field);
17169
+}
17170
+
17171
+bool SymbolEnv::isPacked(const TField &field) const
17172
+{
17173
+    return mPackedFields.find(&field) != mPackedFields.end();
17174
+}
17175
+
17176
+static TBasicType GetTextureBasicType(TBasicType basicType)
17177
+{
17178
+    ASSERT(IsSampler(basicType));
17179
+
17180
+    switch (basicType)
17181
+    {
17182
+        case EbtSampler2D:
17183
+        case EbtSampler3D:
17184
+        case EbtSamplerCube:
17185
+        case EbtSampler2DArray:
17186
+        case EbtSamplerExternalOES:
17187
+        case EbtSamplerExternal2DY2YEXT:
17188
+        case EbtSampler2DRect:
17189
+        case EbtSampler2DMS:
17190
+        case EbtSampler2DMSArray:
17191
+        case EbtSamplerVideoWEBGL:
17192
+        case EbtSampler2DShadow:
17193
+        case EbtSamplerCubeShadow:
17194
+        case EbtSampler2DArrayShadow:
17195
+        case EbtSampler1D:
17196
+        case EbtSampler1DArray:
17197
+        case EbtSampler1DArrayShadow:
17198
+        case EbtSamplerBuffer:
17199
+        case EbtSamplerCubeArray:
17200
+        case EbtSamplerCubeArrayShadow:
17201
+        case EbtSampler1DShadow:
17202
+        case EbtSampler2DRectShadow:
17203
+            return TBasicType::EbtFloat;
17204
+
17205
+        case EbtISampler2D:
17206
+        case EbtISampler3D:
17207
+        case EbtISamplerCube:
17208
+        case EbtISampler2DArray:
17209
+        case EbtISampler2DMS:
17210
+        case EbtISampler2DMSArray:
17211
+        case EbtISampler1D:
17212
+        case EbtISampler1DArray:
17213
+        case EbtISampler2DRect:
17214
+        case EbtISamplerBuffer:
17215
+        case EbtISamplerCubeArray:
17216
+            return TBasicType::EbtInt;
17217
+
17218
+        case EbtUSampler2D:
17219
+        case EbtUSampler3D:
17220
+        case EbtUSamplerCube:
17221
+        case EbtUSampler2DArray:
17222
+        case EbtUSampler2DMS:
17223
+        case EbtUSampler2DMSArray:
17224
+        case EbtUSampler1D:
17225
+        case EbtUSampler1DArray:
17226
+        case EbtUSampler2DRect:
17227
+        case EbtUSamplerBuffer:
17228
+        case EbtUSamplerCubeArray:
17229
+            return TBasicType::EbtUInt;
17230
+
17231
+        default:
17232
+            LOGIC_ERROR();
17233
+            return TBasicType::EbtVoid;
17234
+    }
17235
+}
17236
+
17237
+Name sh::GetTextureTypeName(TBasicType samplerType)
17238
+{
17239
+    ASSERT(IsSampler(samplerType));
17240
+
17241
+    const TBasicType textureType = GetTextureBasicType(samplerType);
17242
+    const char *name;
17243
+
17244
+#define HANDLE_TEXTURE_NAME(baseName)                \
17245
+    do                                               \
17246
+    {                                                \
17247
+        switch (textureType)                         \
17248
+        {                                            \
17249
+            case TBasicType::EbtFloat:               \
17250
+                name = "metal::" baseName "<float>"; \
17251
+                break;                               \
17252
+            case TBasicType::EbtInt:                 \
17253
+                name = "metal::" baseName "<int>";   \
17254
+                break;                               \
17255
+            case TBasicType::EbtUInt:                \
17256
+                name = "metal::" baseName "<uint>";  \
17257
+                break;                               \
17258
+            default:                                 \
17259
+                LOGIC_ERROR();                       \
17260
+                name = nullptr;                      \
17261
+                break;                               \
17262
+        }                                            \
17263
+    } while (false)
17264
+
17265
+    switch (samplerType)
17266
+    {
17267
+        // 1d
17268
+        case EbtSampler1D:  // Desktop GLSL sampler type:
17269
+        case EbtISampler1D:
17270
+        case EbtUSampler1D:
17271
+            HANDLE_TEXTURE_NAME("texture1d");
17272
+            break;
17273
+
17274
+        // 1d array
17275
+        case EbtSampler1DArray:
17276
+        case EbtISampler1DArray:
17277
+        case EbtUSampler1DArray:
17278
+            HANDLE_TEXTURE_NAME("texture1d_array");
17279
+            break;
17280
+
17281
+        // Buffer textures
17282
+        case EbtSamplerBuffer:
17283
+        case EbtISamplerBuffer:
17284
+        case EbtUSamplerBuffer:
17285
+            HANDLE_TEXTURE_NAME("texture_buffer");
17286
+            break;
17287
+
17288
+        // 2d textures
17289
+        case EbtSampler2D:
17290
+        case EbtISampler2D:
17291
+        case EbtUSampler2D:
17292
+        case EbtSampler2DRect:
17293
+        case EbtUSampler2DRect:
17294
+        case EbtISampler2DRect:
17295
+            HANDLE_TEXTURE_NAME("texture2d");
17296
+            break;
17297
+
17298
+        // 3d textures
17299
+        case EbtSampler3D:
17300
+        case EbtISampler3D:
17301
+        case EbtUSampler3D:
17302
+            HANDLE_TEXTURE_NAME("texture3d");
17303
+            break;
17304
+
17305
+        // Cube textures
17306
+        case EbtSamplerCube:
17307
+        case EbtISamplerCube:
17308
+        case EbtUSamplerCube:
17309
+            HANDLE_TEXTURE_NAME("texturecube");
17310
+            break;
17311
+
17312
+        // 2d array textures
17313
+        case EbtSampler2DArray:
17314
+        case EbtUSampler2DArray:
17315
+        case EbtISampler2DArray:
17316
+            HANDLE_TEXTURE_NAME("texture2d_array");
17317
+            break;
17318
+
17319
+        case EbtSampler2DMS:
17320
+        case EbtISampler2DMS:
17321
+        case EbtUSampler2DMS:
17322
+            HANDLE_TEXTURE_NAME("texture2d_ms");
17323
+            break;
17324
+
17325
+        case EbtSampler2DMSArray:
17326
+        case EbtISampler2DMSArray:
17327
+        case EbtUSampler2DMSArray:
17328
+            HANDLE_TEXTURE_NAME("texture2d_ms_array");
17329
+            break;
17330
+
17331
+        // cube array
17332
+        case EbtSamplerCubeArray:
17333
+        case EbtISamplerCubeArray:
17334
+        case EbtUSamplerCubeArray:
17335
+            HANDLE_TEXTURE_NAME("texturecube_array");
17336
+            break;
17337
+
17338
+        // Shadow
17339
+        case EbtSampler1DShadow:
17340
+        case EbtSampler1DArrayShadow:
17341
+            TODO();
17342
+            HANDLE_TEXTURE_NAME("TODO");
17343
+            break;
17344
+
17345
+        case EbtSampler2DRectShadow:
17346
+        case EbtSampler2DShadow:
17347
+            HANDLE_TEXTURE_NAME("depth2d");
17348
+            break;
17349
+
17350
+        case EbtSamplerCubeShadow:
17351
+            HANDLE_TEXTURE_NAME("depthcube");
17352
+            break;
17353
+
17354
+        case EbtSampler2DArrayShadow:
17355
+            HANDLE_TEXTURE_NAME("depth2d_array");
17356
+            break;
17357
+
17358
+        case EbtSamplerCubeArrayShadow:
17359
+            HANDLE_TEXTURE_NAME("depthcube_array");
17360
+            break;
17361
+
17362
+        // Extentions
17363
+        case EbtSamplerExternalOES:       // Only valid if OES_EGL_image_external exists:
17364
+        case EbtSamplerExternal2DY2YEXT:  // Only valid if GL_EXT_YUV_target exists:
17365
+        case EbtSamplerVideoWEBGL:
17366
+            TODO();
17367
+            HANDLE_TEXTURE_NAME("TODO");
17368
+            break;
17369
+
17370
+        default:
17371
+            LOGIC_ERROR();
17372
+            name = nullptr;
17373
+            break;
17374
+    }
17375
+
17376
+#undef HANDLE_TEXTURE_NAME
17377
+
17378
+    return Name(name, SymbolType::UserDefined);
17379
+}
17380
diff --git a/src/compiler/translator/TranslatorMetalDirect/SymbolEnv.h b/src/compiler/translator/TranslatorMetalDirect/SymbolEnv.h
17381
new file mode 100644
17382
index 0000000..4c9645e
17383
--- /dev/null
17384
+++ b/src/compiler/translator/TranslatorMetalDirect/SymbolEnv.h
17385
@@ -0,0 +1,218 @@
17386
+//
17387
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
17388
+// Use of this source code is governed by a BSD-style license that can be
17389
+// found in the LICENSE file.
17390
+//
17391
+
17392
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_SYMBOLENV_H_
17393
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_SYMBOLENV_H_
17394
+
17395
+#include <unordered_set>
17396
+
17397
+#include "compiler/translator/Compiler.h"
17398
+#include "compiler/translator/TranslatorMetalDirect/Name.h"
17399
+#include "compiler/translator/TranslatorMetalDirect/Reference.h"
17400
+#include "compiler/translator/Types.h"
17401
+
17402
+namespace sh
17403
+{
17404
+
17405
+enum class AddressSpace
17406
+{
17407
+    Constant,
17408
+    Device,
17409
+    Thread,
17410
+};
17411
+
17412
+char const *toString(AddressSpace space);
17413
+
17414
+class VarField
17415
+{
17416
+  public:
17417
+    VarField(const TVariable &var) : mVariable(&var) {}
17418
+    VarField(const TField &field) : mField(&field) {}
17419
+
17420
+    ANGLE_INLINE const TVariable *variable() const { return mVariable; }
17421
+
17422
+    ANGLE_INLINE const TField *field() const { return mField; }
17423
+
17424
+    ANGLE_INLINE bool operator==(const VarField &other) const
17425
+    {
17426
+        return mVariable == other.mVariable && mField == other.mField;
17427
+    }
17428
+
17429
+  private:
17430
+    const TVariable *mVariable = nullptr;
17431
+    const TField *mField       = nullptr;
17432
+};
17433
+
17434
+}  // namespace sh
17435
+
17436
+namespace std
17437
+{
17438
+
17439
+template <>
17440
+struct hash<sh::VarField>
17441
+{
17442
+    size_t operator()(const sh::VarField &x) const
17443
+    {
17444
+        const sh::TVariable *var = x.variable();
17445
+        if (var)
17446
+        {
17447
+            return std::hash<const sh::TVariable *>()(var);
17448
+        }
17449
+        const sh::TField *field = x.field();
17450
+        return std::hash<const sh::TField *>()(field);
17451
+    }
17452
+};
17453
+
17454
+}  // namespace std
17455
+
17456
+namespace sh
17457
+{
17458
+
17459
+class TemplateArg
17460
+{
17461
+  public:
17462
+    enum class Kind
17463
+    {
17464
+        Bool,
17465
+        Int,
17466
+        UInt,
17467
+        Type,
17468
+    };
17469
+
17470
+    union Value
17471
+    {
17472
+        Value(bool value) : b(value) {}
17473
+        Value(int value) : i(value) {}
17474
+        Value(unsigned value) : u(value) {}
17475
+        Value(const TType &value) : t(&value) {}
17476
+
17477
+        bool b;
17478
+        int i;
17479
+        unsigned u;
17480
+        const TType *t;
17481
+    };
17482
+
17483
+    TemplateArg(bool value);
17484
+    TemplateArg(int value);
17485
+    TemplateArg(unsigned value);
17486
+    TemplateArg(const TType &value);
17487
+
17488
+    bool operator==(const TemplateArg &other) const;
17489
+    bool operator<(const TemplateArg &other) const;
17490
+
17491
+    Kind kind() const { return mKind; }
17492
+    Value value() const { return mValue; }
17493
+
17494
+  public:
17495
+    Kind mKind;
17496
+    Value mValue;
17497
+};
17498
+
17499
+// An environment for creating and uniquely sharing TSymbol objects.
17500
+class SymbolEnv
17501
+{
17502
+    class TemplateName
17503
+    {
17504
+        Name baseName;
17505
+        std::vector<TemplateArg> templateArgs;
17506
+
17507
+      public:
17508
+        bool operator==(const TemplateName &other) const;
17509
+        bool operator<(const TemplateName &other) const;
17510
+
17511
+        bool empty() const;
17512
+        void clear();
17513
+
17514
+        Name fullName(std::string &buffer) const;
17515
+
17516
+        void assign(const Name &name, size_t argCount, const TemplateArg *args);
17517
+    };
17518
+
17519
+    using TypeRef        = CRef<TType>;
17520
+    using Sig            = std::vector<TypeRef>;  // Param0, Param1, ... ParamN, Return
17521
+    using SigToFunc      = std::map<Sig, TFunction *>;
17522
+    using Overloads      = std::map<TemplateName, SigToFunc>;
17523
+    using AngleStructs   = std::map<ImmutableString, TStructure *>;
17524
+    using TextureStructs = std::map<TBasicType, TStructure *>;
17525
+
17526
+  public:
17527
+    SymbolEnv(TCompiler &compiler, TIntermBlock &root);
17528
+
17529
+    TSymbolTable &symbolTable() { return mSymbolTable; }
17530
+
17531
+    // There exist Angle rewrites that can lead to incoherent structs
17532
+    //
17533
+    // Example
17534
+    //    struct A { ... }
17535
+    //    struct B { A' a; } // A' has same name as A but is not identical.
17536
+    // becomes
17537
+    //    struct A { ... }
17538
+    //    struct B { A a; }
17539
+    //
17540
+    // This notably happens when A contains a sampler in the original GLSL code but is rewritten to
17541
+    // not have a sampler, yet the A' struct field still contains the sampler field.
17542
+    const TStructure &remap(const TStructure &s) const;
17543
+
17544
+    // Like `TStructure &remap(const TStructure &s)` but additionally maps null to null.
17545
+    const TStructure *remap(const TStructure *s) const;
17546
+
17547
+    const TFunction &getFunctionOverload(const Name &name,
17548
+                                         const TType &returnType,
17549
+                                         size_t paramCount,
17550
+                                         const TType **paramTypes,
17551
+                                         size_t templateArgCount         = 0,
17552
+                                         const TemplateArg *templateArgs = nullptr);
17553
+
17554
+    TIntermAggregate &callFunctionOverload(const Name &name,
17555
+                                           const TType &returnType,
17556
+                                           TIntermSequence &args,
17557
+                                           size_t templateArgCount         = 0,
17558
+                                           const TemplateArg *templateArgs = nullptr);
17559
+
17560
+    const TStructure &newStructure(const Name &name, TFieldList &fields);
17561
+
17562
+    const TStructure &getTextureEnv(TBasicType samplerType);
17563
+    const TStructure &getSamplerStruct();
17564
+
17565
+    void markAsPointer(VarField x, AddressSpace space);
17566
+    const AddressSpace *isPointer(VarField x) const;
17567
+
17568
+    void markAsReference(VarField x, AddressSpace space);
17569
+    const AddressSpace *isReference(VarField x) const;
17570
+
17571
+    void markAsPacked(const TField &field);
17572
+    bool isPacked(const TField &field) const;
17573
+
17574
+  private:
17575
+    const TFunction &getFunctionOverloadImpl();
17576
+
17577
+    void markSpace(VarField x, AddressSpace space, std::unordered_map<VarField, AddressSpace> &map);
17578
+    const AddressSpace *isSpace(VarField x,
17579
+                                const std::unordered_map<VarField, AddressSpace> &map) const;
17580
+
17581
+  private:
17582
+    TSymbolTable &mSymbolTable;
17583
+
17584
+    std::map<Name, const TStructure *> mNameToStruct;
17585
+    Overloads mOverloads;
17586
+    Sig mReusableSigBuffer;
17587
+    TemplateName mReusableTemplateNameBuffer;
17588
+    std::string mReusableStringBuffer;
17589
+
17590
+    AngleStructs mAngleStructs;
17591
+    std::unordered_map<TBasicType, const TStructure *> mTextureEnvs;
17592
+    const TStructure *mSampler = nullptr;
17593
+
17594
+    std::unordered_map<VarField, AddressSpace> mPointers;
17595
+    std::unordered_map<VarField, AddressSpace> mReferences;
17596
+    std::unordered_set<const TField *> mPackedFields;
17597
+};
17598
+
17599
+Name GetTextureTypeName(TBasicType samplerType);
17600
+
17601
+}  // namespace sh
17602
+
17603
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_SYMBOLENV_H_
17604
diff --git a/src/compiler/translator/TranslatorMetalDirect/ToposortStructs.cpp b/src/compiler/translator/TranslatorMetalDirect/ToposortStructs.cpp
17605
new file mode 100644
17606
index 0000000..9843332
17607
--- /dev/null
17608
+++ b/src/compiler/translator/TranslatorMetalDirect/ToposortStructs.cpp
17609
@@ -0,0 +1,383 @@
17610
+//
17611
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
17612
+// Use of this source code is governed by a BSD-style license that can be
17613
+// found in the LICENSE file.
17614
+//
17615
+
17616
+#include <functional>
17617
+#include <unordered_map>
17618
+#include <unordered_set>
17619
+#include <vector>
17620
+
17621
+#include "compiler/translator/ImmutableStringBuilder.h"
17622
+#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
17623
+#include "compiler/translator/TranslatorMetalDirect/Debug.h"
17624
+#include "compiler/translator/TranslatorMetalDirect/ToposortStructs.h"
17625
+#include "compiler/translator/tree_util/IntermNode_util.h"
17626
+#include "compiler/translator/tree_util/IntermTraverse.h"
17627
+
17628
+using namespace sh;
17629
+
17630
+////////////////////////////////////////////////////////////////////////////////
17631
+
17632
+namespace
17633
+{
17634
+
17635
+template <typename T>
17636
+using Edges = std::unordered_set<T>;
17637
+
17638
+template <typename T>
17639
+using Graph = std::unordered_map<T, Edges<T>>;
17640
+
17641
+void BuildGraphImpl(SymbolEnv &symbolEnv, Graph<const TStructure *> &g, const TStructure *s)
17642
+{
17643
+    if (g.find(s) != g.end())
17644
+    {
17645
+        return;
17646
+    }
17647
+
17648
+    Edges<const TStructure *> &es = g[s];
17649
+
17650
+    const TFieldList &fs = s->fields();
17651
+    for (const TField *f : fs)
17652
+    {
17653
+        if (const TStructure *z = symbolEnv.remap(f->type()->getStruct()))
17654
+        {
17655
+            es.insert(z);
17656
+            BuildGraphImpl(symbolEnv, g, z);
17657
+            Edges<const TStructure *> &ez = g[z];
17658
+            es.insert(ez.begin(), ez.end());
17659
+        }
17660
+    }
17661
+}
17662
+
17663
+Graph<const TStructure *> BuildGraph(SymbolEnv &symbolEnv,
17664
+                                     const std::vector<const TStructure *> &structs)
17665
+{
17666
+    Graph<const TStructure *> g;
17667
+    for (const TStructure *s : structs)
17668
+    {
17669
+        BuildGraphImpl(symbolEnv, g, s);
17670
+    }
17671
+    return g;
17672
+}
17673
+
17674
+// Algorthm: https://en.wikipedia.org/wiki/Topological_sorting#Depth-first_search
17675
+template <typename T>
17676
+std::vector<T> Toposort(const Graph<T> &g)
17677
+{
17678
+    // nodes with temporary mark
17679
+    std::unordered_set<T> temps;
17680
+
17681
+    // nodes without permanent mark
17682
+    std::unordered_set<T> invPerms;
17683
+    for (const auto &entry : g)
17684
+    {
17685
+        invPerms.insert(entry.first);
17686
+    }
17687
+
17688
+    // L ← Empty list that will contain the sorted elements
17689
+    std::vector<T> L;
17690
+
17691
+    // function visit(node n)
17692
+    std::function<void(T)> visit = [&](T n) -> void {
17693
+        // if n has a permanent mark then
17694
+        if (invPerms.find(n) == invPerms.end())
17695
+        {
17696
+            // return
17697
+            return;
17698
+        }
17699
+        // if n has a temporary mark then
17700
+        if (temps.find(n) != temps.end())
17701
+        {
17702
+            // stop   (not a DAG)
17703
+            LOGIC_ERROR();
17704
+        }
17705
+
17706
+        // mark n with a temporary mark
17707
+        temps.insert(n);
17708
+
17709
+        // for each node m with an edge from n to m do
17710
+        auto enIter = g.find(n);
17711
+        ASSERT(enIter != g.end());
17712
+        const Edges<T> &en = enIter->second;
17713
+        for (T m : en)
17714
+        {
17715
+            // visit(m)
17716
+            visit(m);
17717
+        }
17718
+
17719
+        // remove temporary mark from n
17720
+        temps.erase(n);
17721
+        // mark n with a permanent mark
17722
+        invPerms.erase(n);
17723
+        // add n to head of L
17724
+        L.push_back(n);
17725
+    };
17726
+
17727
+    // while exists nodes without a permanent mark do
17728
+    while (!invPerms.empty())
17729
+    {
17730
+        // select an unmarked node n
17731
+        T n = *invPerms.begin();
17732
+        // visit(n)
17733
+        visit(n);
17734
+    }
17735
+
17736
+    return L;
17737
+}
17738
+
17739
+TIntermFunctionDefinition *CreateStructEqualityFunction(TSymbolTable &symbolTable,
17740
+                                                        const TStructure &aStructType)
17741
+{
17742
+    ////////////////////
17743
+
17744
+    auto &funcEquality =
17745
+        *new TFunction(&symbolTable, ImmutableString("equal"), SymbolType::AngleInternal,
17746
+                       new TType(TBasicType::EbtBool), true);
17747
+    auto &aStruct = CreateInstanceVariable(symbolTable, aStructType, Name("a"));
17748
+    auto &bStruct = CreateInstanceVariable(symbolTable, aStructType, Name("b"));
17749
+    funcEquality.addParameter(&aStruct);
17750
+    funcEquality.addParameter(&bStruct);
17751
+
17752
+    auto &bodyEquality = *new TIntermBlock();
17753
+    std::vector<TIntermTyped *> andNodes;
17754
+    ////////////////////
17755
+
17756
+    const TFieldList &aFields = aStructType.fields();
17757
+    const size_t size         = aFields.size();
17758
+
17759
+    auto testEquality = [&](TIntermTyped &a, TIntermTyped &b) -> TIntermTyped * {
17760
+        ASSERT(a.getType() == b.getType());
17761
+        const TType &type = a.getType();
17762
+        if (type.isVector() || type.isMatrix() || type.getStruct())
17763
+        {
17764
+            auto *func =
17765
+                new TFunction(&symbolTable, ImmutableString("equal"), SymbolType::AngleInternal,
17766
+                              new TType(TBasicType::EbtBool), true);
17767
+            return TIntermAggregate::CreateFunctionCall(*func, new TIntermSequence{&a, &b});
17768
+        }
17769
+        else
17770
+        {
17771
+            return new TIntermBinary(TOperator::EOpEqual, &a, &b);
17772
+        }
17773
+    };
17774
+
17775
+    for (size_t idx = 0; idx < size; ++idx)
17776
+    {
17777
+        const TField &aField    = *aFields[idx];
17778
+        const TType &aFieldType = *aField.type();
17779
+        auto &aFieldName        = aField.name();
17780
+
17781
+        if (aFieldType.isArray())
17782
+        {
17783
+            ASSERT(!aFieldType.isArrayOfArrays());  // TODO
17784
+            int dim = aFieldType.getOutermostArraySize();
17785
+            for (int d = 0; d < dim; ++d)
17786
+            {
17787
+                auto &aAccess = AccessIndex(AccessField(aStruct, aFieldName), d);
17788
+                auto &bAccess = AccessIndex(AccessField(bStruct, aFieldName), d);
17789
+                auto *eqNode  = testEquality(bAccess, aAccess);
17790
+                andNodes.push_back(eqNode);
17791
+            }
17792
+        }
17793
+        else
17794
+        {
17795
+            auto &aAccess = AccessField(aStruct, aFieldName);
17796
+            auto &bAccess = AccessField(bStruct, aFieldName);
17797
+            auto *eqNode  = testEquality(bAccess, aAccess);
17798
+            andNodes.push_back(eqNode);
17799
+        }
17800
+    }
17801
+
17802
+    ASSERT(andNodes.size() > 0);  // Empty structs are not allowed in GLSL
17803
+    TIntermTyped *outNode = andNodes.back();
17804
+    andNodes.pop_back();
17805
+    for (TIntermTyped *andNode : andNodes)
17806
+    {
17807
+        outNode = new TIntermBinary(TOperator::EOpLogicalAnd, andNode, outNode);
17808
+    }
17809
+    bodyEquality.appendStatement(new TIntermBranch(TOperator::EOpReturn, outNode));
17810
+    auto *funcProtoEquality = new TIntermFunctionPrototype(&funcEquality);
17811
+    return new TIntermFunctionDefinition(funcProtoEquality, &bodyEquality);
17812
+}
17813
+
17814
+struct DeclaredStructure
17815
+{
17816
+    TIntermDeclaration *declNode;
17817
+    TIntermFunctionDefinition *equalityFunctionDefinition;
17818
+    const TStructure *structure;
17819
+};
17820
+
17821
+bool GetAsDeclaredStructure(SymbolEnv &symbolEnv,
17822
+                            TIntermNode &node,
17823
+                            DeclaredStructure &out,
17824
+                            TSymbolTable &symbolTable,
17825
+                            const std::unordered_set<const TStructure *> &usedStructs)
17826
+{
17827
+    if (TIntermDeclaration *declNode = node.getAsDeclarationNode())
17828
+    {
17829
+        ASSERT(declNode->getChildCount() == 1);
17830
+        TIntermNode &node = *declNode->getChildNode(0);
17831
+
17832
+        if (TIntermSymbol *symbolNode = node.getAsSymbolNode())
17833
+        {
17834
+            const TVariable &var = symbolNode->variable();
17835
+            const TType &type    = var.getType();
17836
+            if (const TStructure *structure = symbolEnv.remap(type.getStruct()))
17837
+            {
17838
+                if (type.isStructSpecifier())
17839
+                {
17840
+                    out.declNode  = declNode;
17841
+                    out.structure = structure;
17842
+                    out.equalityFunctionDefinition =
17843
+                        usedStructs.find(structure) == usedStructs.end()
17844
+                            ? nullptr
17845
+                            : CreateStructEqualityFunction(symbolTable, *structure);
17846
+                    return true;
17847
+                }
17848
+            }
17849
+        }
17850
+    }
17851
+    return false;
17852
+}
17853
+
17854
+class FindStructEqualityUse : public TIntermTraverser
17855
+{
17856
+  public:
17857
+    SymbolEnv &mSymbolEnv;
17858
+    std::unordered_set<const TStructure *> mUsedStructs;
17859
+
17860
+    FindStructEqualityUse(SymbolEnv &symbolEnv)
17861
+        : TIntermTraverser(false, false, true), mSymbolEnv(symbolEnv)
17862
+    {}
17863
+
17864
+    bool visitBinary(Visit, TIntermBinary *binary) override
17865
+    {
17866
+        const TOperator op = binary->getOp();
17867
+
17868
+        switch (op)
17869
+        {
17870
+            case TOperator::EOpEqual:
17871
+            case TOperator::EOpNotEqual:
17872
+            {
17873
+                const TType &leftType  = binary->getLeft()->getType();
17874
+                const TType &rightType = binary->getRight()->getType();
17875
+                ASSERT(leftType.getStruct() == rightType.getStruct());
17876
+                if (const TStructure *structure = mSymbolEnv.remap(leftType.getStruct()))
17877
+                {
17878
+                    useStruct(*structure);
17879
+                }
17880
+            }
17881
+            break;
17882
+
17883
+            default:
17884
+                break;
17885
+        }
17886
+
17887
+        return true;
17888
+    }
17889
+
17890
+  private:
17891
+    void useStruct(const TStructure &structure)
17892
+    {
17893
+        if (mUsedStructs.insert(&structure).second)
17894
+        {
17895
+            for (const TField *field : structure.fields())
17896
+            {
17897
+                if (const TStructure *subStruct = mSymbolEnv.remap(field->type()->getStruct()))
17898
+                {
17899
+                    useStruct(*subStruct);
17900
+                }
17901
+            }
17902
+        }
17903
+    }
17904
+};
17905
+
17906
+}  // anonymous namespace
17907
+
17908
+////////////////////////////////////////////////////////////////////////////////
17909
+
17910
+bool sh::ToposortStructs(TCompiler &compiler,
17911
+                         SymbolEnv &symbolEnv,
17912
+                         TIntermBlock &root,
17913
+                         ProgramPreludeConfig &ppc)
17914
+{
17915
+    FindStructEqualityUse finder(symbolEnv);
17916
+    root.traverse(&finder);
17917
+    ppc.hasStructEq = !finder.mUsedStructs.empty();
17918
+
17919
+    DeclaredStructure declaredStruct;
17920
+    std::vector<DeclaredStructure> declaredStructs;
17921
+    std::vector<TIntermNode *> nonStructStmtNodes;
17922
+
17923
+    {
17924
+        const size_t stmtCount = root.getChildCount();
17925
+        for (size_t i = 0; i < stmtCount; ++i)
17926
+        {
17927
+            TIntermNode &stmtNode = *root.getChildNode(i);
17928
+            if (GetAsDeclaredStructure(symbolEnv, stmtNode, declaredStruct,
17929
+                                       compiler.getSymbolTable(), finder.mUsedStructs))
17930
+            {
17931
+                declaredStructs.push_back(declaredStruct);
17932
+            }
17933
+            else
17934
+            {
17935
+                nonStructStmtNodes.push_back(&stmtNode);
17936
+            }
17937
+        }
17938
+    }
17939
+
17940
+    {
17941
+        std::vector<const TStructure *> structs;
17942
+        std::unordered_map<const TStructure *, DeclaredStructure> rawToDeclared;
17943
+
17944
+        for (const DeclaredStructure &d : declaredStructs)
17945
+        {
17946
+            structs.push_back(d.structure);
17947
+            ASSERT(rawToDeclared.find(d.structure) == rawToDeclared.end());
17948
+            rawToDeclared[d.structure] = d;
17949
+        }
17950
+
17951
+        // Note: Graph may contain more than only explicitly declared structures.
17952
+        Graph<const TStructure *> g                   = BuildGraph(symbolEnv, structs);
17953
+        std::vector<const TStructure *> sortedStructs = Toposort(g);
17954
+        ASSERT(declaredStructs.size() <= sortedStructs.size());
17955
+
17956
+        declaredStructs.clear();
17957
+        for (const TStructure *s : sortedStructs)
17958
+        {
17959
+            auto it = rawToDeclared.find(s);
17960
+            if (it != rawToDeclared.end())
17961
+            {
17962
+                auto &d = it->second;
17963
+                ASSERT(d.declNode);
17964
+                declaredStructs.push_back(d);
17965
+            }
17966
+        }
17967
+    }
17968
+
17969
+    {
17970
+        TIntermSequence newStmtNodes;
17971
+
17972
+        for (DeclaredStructure &declaredStruct : declaredStructs)
17973
+        {
17974
+            ASSERT(declaredStruct.declNode);
17975
+            newStmtNodes.push_back(declaredStruct.declNode);
17976
+            if (declaredStruct.equalityFunctionDefinition)
17977
+            {
17978
+                newStmtNodes.push_back(declaredStruct.equalityFunctionDefinition);
17979
+            }
17980
+        }
17981
+
17982
+        for (TIntermNode *stmtNode : nonStructStmtNodes)
17983
+        {
17984
+            ASSERT(stmtNode);
17985
+            newStmtNodes.push_back(stmtNode);
17986
+        }
17987
+
17988
+        *root.getSequence() = newStmtNodes;
17989
+    }
17990
+
17991
+    return compiler.validateAST(&root);
17992
+}
17993
diff --git a/src/compiler/translator/TranslatorMetalDirect/ToposortStructs.h b/src/compiler/translator/TranslatorMetalDirect/ToposortStructs.h
17994
new file mode 100644
17995
index 0000000..a3908e3
17996
--- /dev/null
17997
+++ b/src/compiler/translator/TranslatorMetalDirect/ToposortStructs.h
17998
@@ -0,0 +1,27 @@
17999
+//
18000
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
18001
+// Use of this source code is governed by a BSD-style license that can be
18002
+// found in the LICENSE file.
18003
+//
18004
+
18005
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_TOPOSORTSTRUCTS_H_
18006
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_TOPOSORTSTRUCTS_H_
18007
+
18008
+#include "common/angleutils.h"
18009
+#include "compiler/translator/Compiler.h"
18010
+#include "compiler/translator/TranslatorMetalDirect/ProgramPrelude.h"
18011
+#include "compiler/translator/TranslatorMetalDirect/SymbolEnv.h"
18012
+
18013
+namespace sh
18014
+{
18015
+
18016
+// Does a toposort on structs based on type dependencies.
18017
+// Struct type declarations are moved to the top of the root block.
18018
+ANGLE_NO_DISCARD bool ToposortStructs(TCompiler &compiler,
18019
+                                      SymbolEnv &symbolEnv,
18020
+                                      TIntermBlock &root,
18021
+                                      ProgramPreludeConfig &ppc);
18022
+
18023
+}  // namespace sh
18024
+
18025
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_TOPOSORTSTRUCTS_H_
18026
diff --git a/src/compiler/translator/TranslatorMetalDirect/WrapMain.cpp b/src/compiler/translator/TranslatorMetalDirect/WrapMain.cpp
18027
new file mode 100644
18028
index 0000000..014bc63
18029
--- /dev/null
18030
+++ b/src/compiler/translator/TranslatorMetalDirect/WrapMain.cpp
18031
@@ -0,0 +1,94 @@
18032
+//
18033
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
18034
+// Use of this source code is governed by a BSD-style license that can be
18035
+// found in the LICENSE file.
18036
+//
18037
+
18038
+#include "compiler/translator/TranslatorMetalDirect/WrapMain.h"
18039
+#include "compiler/translator/Compiler.h"
18040
+#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
18041
+
18042
+using namespace sh;
18043
+
18044
+////////////////////////////////////////////////////////////////////////////////
18045
+
18046
+namespace
18047
+{
18048
+
18049
+class Wrapper : public TIntermTraverser
18050
+{
18051
+  private:
18052
+    IdGen &mIdGen;
18053
+
18054
+  public:
18055
+    Wrapper(TSymbolTable &symbolTable, IdGen &idGen)
18056
+        : TIntermTraverser(false, false, true, &symbolTable), mIdGen(idGen)
18057
+    {}
18058
+
18059
+    bool visitBlock(Visit, TIntermBlock *blockNode) override
18060
+    {
18061
+        if (blockNode != getRootNode())
18062
+        {
18063
+            return true;
18064
+        }
18065
+
18066
+        for (TIntermNode *node : *blockNode->getSequence())
18067
+        {
18068
+            if (TIntermFunctionDefinition *funcDefNode = node->getAsFunctionDefinition())
18069
+            {
18070
+                const TFunction &func = *funcDefNode->getFunction();
18071
+                if (func.isMain())
18072
+                {
18073
+                    visitMain(*blockNode, funcDefNode);
18074
+                    break;
18075
+                }
18076
+            }
18077
+        }
18078
+
18079
+        return true;
18080
+    }
18081
+
18082
+  private:
18083
+    void visitMain(TIntermBlock &root, TIntermFunctionDefinition *funcDefNode)
18084
+    {
18085
+        const TFunction &func = *funcDefNode->getFunction();
18086
+        ASSERT(func.isMain());
18087
+        ASSERT(func.getReturnType().getBasicType() == TBasicType::EbtVoid);
18088
+        ASSERT(func.getParamCount() == 0);
18089
+
18090
+        const TFunction &externalMainFunc = *funcDefNode->getFunction();
18091
+        const TFunction &internalMainFunc = CloneFunction(*mSymbolTable, mIdGen, externalMainFunc);
18092
+
18093
+        TIntermFunctionPrototype *externalMainProto = funcDefNode->getFunctionPrototype();
18094
+        TIntermFunctionPrototype *internalMainProto =
18095
+            new TIntermFunctionPrototype(&internalMainFunc);
18096
+
18097
+        TIntermBlock *externalMainBody = new TIntermBlock();
18098
+        externalMainBody->appendStatement(
18099
+            TIntermAggregate::CreateFunctionCall(internalMainFunc, new TIntermSequence()));
18100
+
18101
+        TIntermBlock *internalMainBody = funcDefNode->getBody();
18102
+
18103
+        TIntermFunctionDefinition *externalMainDef =
18104
+            new TIntermFunctionDefinition(externalMainProto, externalMainBody);
18105
+        TIntermFunctionDefinition *internalMainDef =
18106
+            new TIntermFunctionDefinition(internalMainProto, internalMainBody);
18107
+
18108
+        mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(
18109
+            &root, funcDefNode, TIntermSequence{internalMainDef, externalMainDef}));
18110
+    }
18111
+};
18112
+
18113
+}  // namespace
18114
+
18115
+bool sh::WrapMain(TCompiler &compiler, IdGen &idGen, TIntermBlock &root)
18116
+{
18117
+    TSymbolTable &symbolTable = compiler.getSymbolTable();
18118
+    Wrapper wrapper(symbolTable, idGen);
18119
+    root.traverse(&wrapper);
18120
+    if (!wrapper.updateTree(&compiler, &root))
18121
+    {
18122
+        return false;
18123
+    }
18124
+    return true;
18125
+}
18126
diff --git a/src/compiler/translator/TranslatorMetalDirect/WrapMain.h b/src/compiler/translator/TranslatorMetalDirect/WrapMain.h
18127
new file mode 100644
18128
index 0000000..5b0edff
18129
--- /dev/null
18130
+++ b/src/compiler/translator/TranslatorMetalDirect/WrapMain.h
18131
@@ -0,0 +1,28 @@
18132
+//
18133
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
18134
+// Use of this source code is governed by a BSD-style license that can be
18135
+// found in the LICENSE file.
18136
+//
18137
+
18138
+#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_WRAPMAIN_H_
18139
+#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_WRAPMAIN_H_
18140
+
18141
+#include "compiler/translator/TranslatorMetalDirect/IdGen.h"
18142
+#include "compiler/translator/tree_util/IntermTraverse.h"
18143
+
18144
+namespace sh
18145
+{
18146
+
18147
+// Changes
18148
+//    void main(args) { main-body }
18149
+// To
18150
+//    void FRESH_NAME(args) { main-body }
18151
+//    void main(args) { FRESH_NAME(args); }
18152
+//
18153
+// This transformation is useful if the original `main` has multiple return paths because this
18154
+// reduces down to a single path in the new `main`. Nice for inserting cleanup code in `main`.
18155
+ANGLE_NO_DISCARD bool WrapMain(TCompiler &compiler, IdGen &idGen, TIntermBlock &root);
18156
+
18157
+}  // namespace sh
18158
+
18159
+#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_WRAPMAIN_H_
18160
diff --git a/src/compiler/translator/TranslatorMetalUtils.cpp b/src/compiler/translator/TranslatorMetalUtils.cpp
18161
new file mode 100644
18162
index 0000000..e0a8bf3
18163
--- /dev/null
18164
+++ b/src/compiler/translator/TranslatorMetalUtils.cpp
18165
@@ -0,0 +1,305 @@
18166
+//
18167
+// Copyright 2002 The ANGLE Project Authors. All rights reserved.
18168
+// Use of this source code is governed by a BSD-style license that can be
18169
+// found in the LICENSE file.
18170
+//
18171
+
18172
+#if defined(_MSC_VER)
18173
+#    pragma warning(disable : 4718)
18174
+#endif
18175
+#include "compiler/translator/TranslatorMetalUtils.h"
18176
+#include <algorithm>
18177
+#include <climits>
18178
+#include "compiler/translator/HashNames.h"
18179
+#include "compiler/translator/ImmutableString.h"
18180
+#include "compiler/translator/InfoSink.h"
18181
+#include "compiler/translator/IntermNode.h"
18182
+#include "compiler/translator/SymbolTable.h"
18183
+#include "compiler/translator/Types.h"
18184
+
18185
+namespace sh
18186
+{
18187
+
18188
+const char *getBasicMetalString(const TType *t)
18189
+{
18190
+    switch (t->getBasicType())
18191
+    {
18192
+        case EbtVoid:
18193
+            return "void";
18194
+        case EbtFloat:
18195
+            return "float";
18196
+        case EbtInt:
18197
+            return "int";
18198
+        case EbtUInt:
18199
+            return "uint";
18200
+        case EbtBool:
18201
+            return "bool";
18202
+        case EbtYuvCscStandardEXT:
18203
+            return "yuvCscStandardEXT";
18204
+        case EbtSampler2D:
18205
+            return "sampler2D";
18206
+        case EbtSampler3D:
18207
+            return "sampler3D";
18208
+        case EbtSamplerCube:
18209
+            return "samplerCube";
18210
+        case EbtSamplerExternalOES:
18211
+            return "samplerExternalOES";
18212
+        case EbtSamplerExternal2DY2YEXT:
18213
+            return "__samplerExternal2DY2YEXT";
18214
+        case EbtSampler2DRect:
18215
+            return "sampler2DRect";
18216
+        case EbtSampler2DArray:
18217
+            return "sampler2DArray";
18218
+        case EbtSampler2DMS:
18219
+            return "sampler2DMS";
18220
+        case EbtSampler2DMSArray:
18221
+            return "sampler2DMSArray";
18222
+        case EbtSamplerCubeArray:
18223
+            return "samplerCubeArray";
18224
+        case EbtISampler2D:
18225
+            return "isampler2D";
18226
+        case EbtISampler3D:
18227
+            return "isampler3D";
18228
+        case EbtISamplerCube:
18229
+            return "isamplerCube";
18230
+        case EbtISampler2DArray:
18231
+            return "isampler2DArray";
18232
+        case EbtISampler2DMS:
18233
+            return "isampler2DMS";
18234
+        case EbtISampler2DMSArray:
18235
+            return "isampler2DMSArray";
18236
+        case EbtISamplerCubeArray:
18237
+            return "isamplerCubeArray";
18238
+        case EbtUSampler2D:
18239
+            return "usampler2D";
18240
+        case EbtUSampler3D:
18241
+            return "usampler3D";
18242
+        case EbtUSamplerCube:
18243
+            return "usamplerCube";
18244
+        case EbtUSampler2DArray:
18245
+            return "usampler2DArray";
18246
+        case EbtUSampler2DMS:
18247
+            return "usampler2DMS";
18248
+        case EbtUSampler2DMSArray:
18249
+            return "usampler2DMSArray";
18250
+        case EbtUSamplerCubeArray:
18251
+            return "usamplerCubeArray";
18252
+        case EbtSampler2DShadow:
18253
+            return "sampler2DShadow";
18254
+        case EbtSamplerCubeShadow:
18255
+            return "samplerCubeShadow";
18256
+        case EbtSampler2DArrayShadow:
18257
+            return "sampler2DArrayShadow";
18258
+        case EbtSamplerCubeArrayShadow:
18259
+            return "samplerCubeArrayShadow";
18260
+        case EbtStruct:
18261
+            return "structure";
18262
+        case EbtInterfaceBlock:
18263
+            return "interface block";
18264
+        case EbtImage2D:
18265
+            return "texture2d";
18266
+        case EbtIImage2D:
18267
+            return "texture2d<int>";
18268
+        case EbtUImage2D:
18269
+            return "texture2d<uint>";
18270
+        case EbtImage3D:
18271
+            return "texture3d";
18272
+        case EbtIImage3D:
18273
+            return "texture3d<int>";
18274
+        case EbtUImage3D:
18275
+            return "texture3d<uint>";
18276
+        case EbtImage2DArray:
18277
+            if (t->isUnsizedArray())
18278
+            {
18279
+                return "array_ref<texture2d>";
18280
+            }
18281
+            else
18282
+            {
18283
+                return "NOT_IMPLEMENTED";
18284
+            }
18285
+        case EbtIImage2DArray:
18286
+            if (t->isUnsizedArray())
18287
+            {
18288
+                return "array_ref<texture2d<int>>";
18289
+            }
18290
+            else
18291
+            {
18292
+                return "NOT_IMPLEMENTED";
18293
+            }
18294
+        case EbtUImage2DArray:
18295
+            if (t->isUnsizedArray())
18296
+            {
18297
+                return "array_ref<texture2d<uint>>";
18298
+            }
18299
+            else
18300
+            {
18301
+                return "NOT_IMPLEMENTED";
18302
+            }
18303
+        case EbtImageCube:
18304
+            return "texturecube";
18305
+        case EbtIImageCube:
18306
+            return "texturecube<int>";
18307
+        case EbtUImageCube:
18308
+            return "texturecube<uint>";
18309
+        case EbtImageCubeArray:
18310
+            if (t->isUnsizedArray())
18311
+            {
18312
+                return "array_ref<texturecube>";
18313
+            }
18314
+            else
18315
+            {
18316
+                return "NOT_IMPLEMENTED";
18317
+            }
18318
+        case EbtIImageCubeArray:
18319
+            if (t->isUnsizedArray())
18320
+            {
18321
+                return "array_ref<texturecube<int>>";
18322
+            }
18323
+            else
18324
+            {
18325
+                return "NOT_IMPLEMENTED";
18326
+            }
18327
+        case EbtUImageCubeArray:
18328
+            if (t->isUnsizedArray())
18329
+            {
18330
+                return "array_ref<texturecube<uint>>";
18331
+            }
18332
+            else
18333
+            {
18334
+                return "NOT_IMPLEMENTED";
18335
+            }
18336
+        case EbtAtomicCounter:
18337
+            return "atomic_uint";
18338
+        case EbtSamplerVideoWEBGL:
18339
+            return "$samplerVideoWEBGL";
18340
+        default:
18341
+            UNREACHABLE();
18342
+            return "unknown type";
18343
+    }
18344
+}
18345
+
18346
+const char *getBuiltInMetalTypeNameString(const TType *t)
18347
+{
18348
+    if (t->isMatrix())
18349
+    {
18350
+        switch (t->getCols())
18351
+        {
18352
+            case 2:
18353
+                switch (t->getRows())
18354
+                {
18355
+                    case 2:
18356
+                        return "float2";
18357
+                    case 3:
18358
+                        return "float2x3";
18359
+                    case 4:
18360
+                        return "float2x4";
18361
+                    default:
18362
+                        UNREACHABLE();
18363
+                        return nullptr;
18364
+                }
18365
+            case 3:
18366
+                switch (t->getRows())
18367
+                {
18368
+                    case 2:
18369
+                        return "float3x2";
18370
+                    case 3:
18371
+                        return "float3";
18372
+                    case 4:
18373
+                        return "float3x4";
18374
+                    default:
18375
+                        UNREACHABLE();
18376
+                        return nullptr;
18377
+                }
18378
+            case 4:
18379
+                switch (t->getRows())
18380
+                {
18381
+                    case 2:
18382
+                        return "float4x2";
18383
+                    case 3:
18384
+                        return "float4x3";
18385
+                    case 4:
18386
+                        return "float4";
18387
+                    default:
18388
+                        UNREACHABLE();
18389
+                        return nullptr;
18390
+                }
18391
+            default:
18392
+                UNREACHABLE();
18393
+                return nullptr;
18394
+        }
18395
+    }
18396
+    if (t->isVector())
18397
+    {
18398
+        switch (t->getBasicType())
18399
+        {
18400
+            case EbtFloat:
18401
+                switch (t->getNominalSize())
18402
+                {
18403
+                    case 2:
18404
+                        return "float2";
18405
+                    case 3:
18406
+                        return "float3";
18407
+                    case 4:
18408
+                        return "float4";
18409
+                    default:
18410
+                        UNREACHABLE();
18411
+                        return nullptr;
18412
+                }
18413
+            case EbtInt:
18414
+                switch (t->getNominalSize())
18415
+                {
18416
+                    case 2:
18417
+                        return "int2";
18418
+                    case 3:
18419
+                        return "int3";
18420
+                    case 4:
18421
+                        return "int4";
18422
+                    default:
18423
+                        UNREACHABLE();
18424
+                        return nullptr;
18425
+                }
18426
+            case EbtBool:
18427
+                switch (t->getNominalSize())
18428
+                {
18429
+                    case 2:
18430
+                        return "bool2";
18431
+                    case 3:
18432
+                        return "bool3";
18433
+                    case 4:
18434
+                        return "bool4";
18435
+                    default:
18436
+                        UNREACHABLE();
18437
+                        return nullptr;
18438
+                }
18439
+            case EbtUInt:
18440
+                switch (t->getNominalSize())
18441
+                {
18442
+                    case 2:
18443
+                        return "uint2";
18444
+                    case 3:
18445
+                        return "uint3";
18446
+                    case 4:
18447
+                        return "uint4";
18448
+                    default:
18449
+                        UNREACHABLE();
18450
+                        return nullptr;
18451
+                }
18452
+            default:
18453
+                UNREACHABLE();
18454
+                return nullptr;
18455
+        }
18456
+    }
18457
+    ASSERT(t->getBasicType() != EbtStruct);
18458
+    ASSERT(t->getBasicType() != EbtInterfaceBlock);
18459
+    return getBasicMetalString(t);
18460
+}
18461
+
18462
+ImmutableString GetMetalTypeName(const TType &type, ShHashFunction64 hashFunction, NameMap *nameMap)
18463
+{
18464
+    if (type.getBasicType() == EbtStruct)
18465
+        return HashName(type.getStruct(), hashFunction, nameMap);
18466
+    else
18467
+        return ImmutableString(getBuiltInMetalTypeNameString(&type));
18468
+}
18469
+
18470
+}  // namespace sh
18471
diff --git a/src/compiler/translator/TranslatorMetalUtils.h b/src/compiler/translator/TranslatorMetalUtils.h
18472
new file mode 100644
18473
index 0000000..ce3ce3c
18474
--- /dev/null
18475
+++ b/src/compiler/translator/TranslatorMetalUtils.h
18476
@@ -0,0 +1,31 @@
18477
+//
18478
+// Copyright 2002 The ANGLE Project Authors. All rights reserved.
18479
+// Use of this source code is governed by a BSD-style license that can be
18480
+// found in the LICENSE file.
18481
+//
18482
+
18483
+#ifndef TRANSLATOR_METAL_UTILS_H_
18484
+#define TRANSLATOR_METAL_UTILS_H_
18485
+
18486
+#include "common/angleutils.h"
18487
+#include "common/debug.h"
18488
+#include "compiler/translator/BaseTypes.h"
18489
+#include "compiler/translator/Common.h"
18490
+#include "compiler/translator/HashNames.h"
18491
+#include "compiler/translator/ImmutableString.h"
18492
+#include "compiler/translator/SymbolUniqueId.h"
18493
+#include "compiler/translator/Types.h"
18494
+namespace sh
18495
+{
18496
+
18497
+const char *getBasicMetalString(const TType *t);
18498
+
18499
+const char *getBuiltInMetalTypeNameString(const TType *t);
18500
+
18501
+ImmutableString GetMetalTypeName(const TType &type,
18502
+                                 ShHashFunction64 hashFunction,
18503
+                                 NameMap *nameMap);
18504
+
18505
+}  // namespace sh
18506
+
18507
+#endif  // TRANSLATOR_METAL_UTILS_H_
18508
diff --git a/src/compiler/translator/TranslatorVulkan.cpp b/src/compiler/translator/TranslatorVulkan.cpp
18509
index 201cbc9..c5ec67d 100644
18510
--- a/src/compiler/translator/TranslatorVulkan.cpp
18511
+++ b/src/compiler/translator/TranslatorVulkan.cpp
18512
@@ -163,6 +163,8 @@ class DeclareDefaultUniformsTraverser : public TIntermTraverser
18513
 constexpr ImmutableString kFlippedPointCoordName    = ImmutableString("flippedPointCoord");
18514
 constexpr ImmutableString kFlippedFragCoordName     = ImmutableString("flippedFragCoord");
18515
 constexpr ImmutableString kEmulatedDepthRangeParams = ImmutableString("ANGLEDepthRangeParams");
18516
+constexpr ImmutableString kUniformsBlockName        = ImmutableString("ANGLEUniformBlock");
18517
+constexpr ImmutableString kUniformsVarName          = ImmutableString("ANGLEUniforms");
18518
 
18519
 constexpr gl::ShaderMap<const char *> kDefaultUniformNames = {
18520
     {gl::ShaderType::Vertex, vk::kDefaultUniformsNameVS},
18521
@@ -450,9 +452,9 @@ const TVariable *AddGraphicsDriverUniformsToShader(TIntermBlock *root,
18522
                             additionalFields.end());
18523
 
18524
     // Define a driver uniform block "ANGLEUniformBlock" with instance name "ANGLEUniforms".
18525
-    return DeclareInterfaceBlock(
18526
-        root, symbolTable, driverFieldList, EvqUniform, TMemoryQualifier::Create(), 0,
18527
-        ImmutableString(vk::kDriverUniformsBlockName), ImmutableString(vk::kDriverUniformsVarName));
18528
+    return DeclareInterfaceBlock(root, symbolTable, driverFieldList, EvqUniform,
18529
+                                 TMemoryQualifier::Create(), 0, kUniformsBlockName,
18530
+                                 kUniformsVarName);
18531
 }
18532
 
18533
 const TVariable *AddComputeDriverUniformsToShader(TIntermBlock *root, TSymbolTable *symbolTable)
18534
diff --git a/src/compiler/translator/Types.h b/src/compiler/translator/Types.h
18535
index a3e0399..8f6fc46 100644
18536
--- a/src/compiler/translator/Types.h
18537
+++ b/src/compiler/translator/Types.h
18538
@@ -232,6 +232,7 @@ class TType
18539
 
18540
     bool isVector() const { return primarySize > 1 && secondarySize == 1; }
18541
     bool isVectorArray() const { return primarySize > 1 && secondarySize == 1 && isArray(); }
18542
+    bool isRank0() const { return primarySize == 1 && secondarySize == 1; }
18543
     bool isScalar() const
18544
     {
18545
         return primarySize == 1 && secondarySize == 1 && !mStructure && !isArray();
18546
diff --git a/src/compiler/translator/ValidateAST.cpp b/src/compiler/translator/ValidateAST.cpp
18547
index 76a8bc2..ba4d6f3 100644
18548
--- a/src/compiler/translator/ValidateAST.cpp
18549
+++ b/src/compiler/translator/ValidateAST.cpp
18550
@@ -76,12 +76,7 @@ ValidateAST::ValidateAST(TIntermNode *root,
18551
                          TDiagnostics *diagnostics,
18552
                          const ValidateASTOptions &options)
18553
     : TIntermTraverser(true, false, true, nullptr), mOptions(options), mDiagnostics(diagnostics)
18554
-{
18555
-    if (mOptions.validateSingleParent)
18556
-    {
18557
-        mParent[root] = nullptr;
18558
-    }
18559
-}
18560
+{}
18561
 
18562
 void ValidateAST::visitNode(Visit visit, TIntermNode *node)
18563
 {
18564
@@ -91,11 +86,12 @@ void ValidateAST::visitNode(Visit visit, TIntermNode *node)
18565
         for (size_t i = 0; i < childCount; ++i)
18566
         {
18567
             TIntermNode *child   = node->getChildNode(i);
18568
-            if (mParent.find(child) != mParent.end())
18569
+            TIntermNode *&parent = mParent[child];
18570
+            if (parent)
18571
             {
18572
                 // If child is visited twice but through the same parent, the problem is in one of
18573
                 // the ancestors.
18574
-                if (mParent[child] != node)
18575
+                if (parent != node)
18576
                 {
18577
                     mDiagnostics->error(node->getLine(), "Found child with two parents",
18578
                                         "<validateSingleParent>");
18579
@@ -103,17 +99,17 @@ void ValidateAST::visitNode(Visit visit, TIntermNode *node)
18580
                 }
18581
             }
18582
 
18583
-            mParent[child] = node;
18584
+            parent = node;
18585
         }
18586
     }
18587
 }
18588
 
18589
-void ValidateAST::expectNonNullChildren(Visit visit, TIntermNode *node, size_t least_count)
18590
+void ValidateAST::expectNonNullChildren(Visit visit, TIntermNode *node, size_t leastCount)
18591
 {
18592
     if (visit == PreVisit && mOptions.validateNullNodes)
18593
     {
18594
         size_t childCount = node->getChildCount();
18595
-        if (childCount < least_count)
18596
+        if (childCount < leastCount)
18597
         {
18598
             mDiagnostics->error(node->getLine(), "Too few children", "<validateNullNodes>");
18599
             mNullNodesFailed = true;
18600
diff --git a/src/compiler/translator/glslang_tab_autogen.cpp b/src/compiler/translator/glslang_tab_autogen.cpp
18601
index 130b98a..33b83db 100644
18602
--- a/src/compiler/translator/glslang_tab_autogen.cpp
18603
+++ b/src/compiler/translator/glslang_tab_autogen.cpp
18604
@@ -1,5 +1,7 @@
18605
 /* A Bison parser, made by GNU Bison 3.3.2.  */
18606
 
18607
+/* Apple Note: For the avoidance of doubt, Apple elects to distribute this file under the terms of the BSD license. */
18608
+
18609
 /* Bison implementation for Yacc-like parsers in C
18610
 
18611
    Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2019 Free Software Foundation,
18612
diff --git a/src/compiler/translator/glslang_tab_autogen.h b/src/compiler/translator/glslang_tab_autogen.h
18613
index 5306032..0250300 100644
18614
--- a/src/compiler/translator/glslang_tab_autogen.h
18615
+++ b/src/compiler/translator/glslang_tab_autogen.h
18616
@@ -1,5 +1,7 @@
18617
 /* A Bison parser, made by GNU Bison 3.3.2.  */
18618
 
18619
+/* Apple Note: For the avoidance of doubt, Apple elects to distribute this file under the terms of the BSD license. */
18620
+
18621
 /* Bison interface for Yacc-like parsers in C
18622
 
18623
    Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2019 Free Software Foundation,
18624
diff --git a/src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp b/src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp
18625
index dfa23aa..bbc8dcd 100644
18626
--- a/src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp
18627
+++ b/src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp
18628
@@ -53,7 +53,8 @@ void GetDeferredInitializers(TIntermDeclaration *declaration,
18629
         ASSERT(symbolNode);
18630
         TIntermTyped *expression = init->getRight();
18631
 
18632
-        if (expression->getQualifier() != EvqConst || !expression->hasConstantValue())
18633
+        if (expression->getQualifier() != EvqConst || !expression->hasConstantValue() ||
18634
+            symbolNode->getQualifier() == EvqGlobal)
18635
         {
18636
             // For variables which are not constant, defer their real initialization until
18637
             // after we initialize uniforms.
18638
diff --git a/src/compiler/translator/tree_ops/PruneEmptyCases.cpp b/src/compiler/translator/tree_ops/PruneEmptyCases.cpp
18639
index 289de21..2ee8239 100644
18640
--- a/src/compiler/translator/tree_ops/PruneEmptyCases.cpp
18641
+++ b/src/compiler/translator/tree_ops/PruneEmptyCases.cpp
18642
@@ -17,7 +17,7 @@ namespace sh
18643
 namespace
18644
 {
18645
 
18646
-bool AreEmptyBlocks(TIntermSequence *statements);
18647
+bool AreEmptyBlocks(const TIntermSequence *statements);
18648
 
18649
 bool IsEmptyBlock(TIntermNode *node)
18650
 {
18651
@@ -37,7 +37,7 @@ bool IsEmptyBlock(TIntermNode *node)
18652
 
18653
 // Return true if all statements in "statements" consist only of empty blocks and no-op statements.
18654
 // Returns true also if there are no statements.
18655
-bool AreEmptyBlocks(TIntermSequence *statements)
18656
+bool AreEmptyBlocks(const TIntermSequence *statements)
18657
 {
18658
     for (size_t i = 0u; i < statements->size(); ++i)
18659
     {
18660
diff --git a/src/compiler/translator/tree_ops/RemoveSwitchFallThrough.cpp b/src/compiler/translator/tree_ops/RemoveSwitchFallThrough.cpp
18661
index 4500aea..dd8dd54 100644
18662
--- a/src/compiler/translator/tree_ops/RemoveSwitchFallThrough.cpp
18663
+++ b/src/compiler/translator/tree_ops/RemoveSwitchFallThrough.cpp
18664
@@ -44,7 +44,7 @@ class RemoveSwitchFallThroughTraverser : public TIntermTraverser
18665
     bool visitLoop(Visit, TIntermLoop *node) override;
18666
     bool visitBranch(Visit, TIntermBranch *node) override;
18667
 
18668
-    void outputSequence(TIntermSequence *sequence, size_t startIndex);
18669
+    void outputSequence(const TIntermSequence *sequence, size_t startIndex);
18670
     void handlePreviousCase();
18671
 
18672
     TIntermBlock *mStatementList;
18673
@@ -153,11 +153,13 @@ bool RemoveSwitchFallThroughTraverser::visitSwitch(Visit, TIntermSwitch *node)
18674
     return false;
18675
 }
18676
 
18677
-void RemoveSwitchFallThroughTraverser::outputSequence(TIntermSequence *sequence, size_t startIndex)
18678
+void RemoveSwitchFallThroughTraverser::outputSequence(const TIntermSequence *sequence,
18679
+                                                      size_t startIndex)
18680
 {
18681
+    auto &outSeq = *mStatementListOut->getSequence();
18682
     for (size_t i = startIndex; i < sequence->size(); ++i)
18683
     {
18684
-        mStatementListOut->getSequence()->push_back(sequence->at(i));
18685
+        outSeq.push_back(sequence->at(i));
18686
     }
18687
 }
18688
 
18689
diff --git a/src/compiler/translator/tree_ops/SimplifyLoopConditions.cpp b/src/compiler/translator/tree_ops/SimplifyLoopConditions.cpp
18690
index 7414540..0c2aa8f 100644
18691
--- a/src/compiler/translator/tree_ops/SimplifyLoopConditions.cpp
18692
+++ b/src/compiler/translator/tree_ops/SimplifyLoopConditions.cpp
18693
@@ -21,10 +21,17 @@ namespace sh
18694
 namespace
18695
 {
18696
 
18697
+struct LoopInfo
18698
+{
18699
+    const TVariable *conditionVariable = nullptr;
18700
+    TIntermTyped *condition            = nullptr;
18701
+    TIntermTyped *expression           = nullptr;
18702
+};
18703
+
18704
 class SimplifyLoopConditionsTraverser : public TLValueTrackingTraverser
18705
 {
18706
   public:
18707
-    SimplifyLoopConditionsTraverser(unsigned int conditionsToSimplifyMask,
18708
+    SimplifyLoopConditionsTraverser(const IntermNodePatternMatcher *conditionsToSimplify,
18709
                                     TSymbolTable *symbolTable);
18710
 
18711
     void traverseLoop(TIntermLoop *node) override;
18712
@@ -34,6 +41,7 @@ class SimplifyLoopConditionsTraverser : public TLValueTrackingTraverser
18713
     bool visitAggregate(Visit visit, TIntermAggregate *node) override;
18714
     bool visitTernary(Visit visit, TIntermTernary *node) override;
18715
     bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
18716
+    bool visitBranch(Visit visit, TIntermBranch *node) override;
18717
 
18718
     bool foundLoopToChange() const { return mFoundLoopToChange; }
18719
 
18720
@@ -42,16 +50,19 @@ class SimplifyLoopConditionsTraverser : public TLValueTrackingTraverser
18721
     // found.
18722
     bool mFoundLoopToChange;
18723
     bool mInsideLoopInitConditionOrExpression;
18724
-    IntermNodePatternMatcher mConditionsToSimplify;
18725
+    const IntermNodePatternMatcher *mConditionsToSimplify;
18726
+
18727
+  private:
18728
+    LoopInfo mLoop;
18729
 };
18730
 
18731
 SimplifyLoopConditionsTraverser::SimplifyLoopConditionsTraverser(
18732
-    unsigned int conditionsToSimplifyMask,
18733
+    const IntermNodePatternMatcher *conditionsToSimplify,
18734
     TSymbolTable *symbolTable)
18735
     : TLValueTrackingTraverser(true, false, false, symbolTable),
18736
       mFoundLoopToChange(false),
18737
       mInsideLoopInitConditionOrExpression(false),
18738
-      mConditionsToSimplify(conditionsToSimplifyMask)
18739
+      mConditionsToSimplify(conditionsToSimplify)
18740
 {}
18741
 
18742
 // If we're inside a loop initialization, condition, or expression, we check for expressions that
18743
@@ -68,7 +79,8 @@ bool SimplifyLoopConditionsTraverser::visitUnary(Visit visit, TIntermUnary *node
18744
     if (mFoundLoopToChange)
18745
         return false;  // Already decided to change this loop.
18746
 
18747
-    mFoundLoopToChange = mConditionsToSimplify.match(node);
18748
+    ASSERT(mConditionsToSimplify);
18749
+    mFoundLoopToChange = mConditionsToSimplify->match(node);
18750
     return !mFoundLoopToChange;
18751
 }
18752
 
18753
@@ -80,7 +92,9 @@ bool SimplifyLoopConditionsTraverser::visitBinary(Visit visit, TIntermBinary *no
18754
     if (mFoundLoopToChange)
18755
         return false;  // Already decided to change this loop.
18756
 
18757
-    mFoundLoopToChange = mConditionsToSimplify.match(node, getParentNode(), isLValueRequiredHere());
18758
+    ASSERT(mConditionsToSimplify);
18759
+    mFoundLoopToChange =
18760
+        mConditionsToSimplify->match(node, getParentNode(), isLValueRequiredHere());
18761
     return !mFoundLoopToChange;
18762
 }
18763
 
18764
@@ -92,7 +106,8 @@ bool SimplifyLoopConditionsTraverser::visitAggregate(Visit visit, TIntermAggrega
18765
     if (mFoundLoopToChange)
18766
         return false;  // Already decided to change this loop.
18767
 
18768
-    mFoundLoopToChange = mConditionsToSimplify.match(node, getParentNode());
18769
+    ASSERT(mConditionsToSimplify);
18770
+    mFoundLoopToChange = mConditionsToSimplify->match(node, getParentNode());
18771
     return !mFoundLoopToChange;
18772
 }
18773
 
18774
@@ -104,7 +119,8 @@ bool SimplifyLoopConditionsTraverser::visitTernary(Visit visit, TIntermTernary *
18775
     if (mFoundLoopToChange)
18776
         return false;  // Already decided to change this loop.
18777
 
18778
-    mFoundLoopToChange = mConditionsToSimplify.match(node);
18779
+    ASSERT(mConditionsToSimplify);
18780
+    mFoundLoopToChange = mConditionsToSimplify->match(node);
18781
     return !mFoundLoopToChange;
18782
 }
18783
 
18784
@@ -116,10 +132,35 @@ bool SimplifyLoopConditionsTraverser::visitDeclaration(Visit visit, TIntermDecla
18785
     if (mFoundLoopToChange)
18786
         return false;  // Already decided to change this loop.
18787
 
18788
-    mFoundLoopToChange = mConditionsToSimplify.match(node);
18789
+    ASSERT(mConditionsToSimplify);
18790
+    mFoundLoopToChange = mConditionsToSimplify->match(node);
18791
     return !mFoundLoopToChange;
18792
 }
18793
 
18794
+bool SimplifyLoopConditionsTraverser::visitBranch(Visit visit, TIntermBranch *node)
18795
+{
18796
+    if (node->getFlowOp() == EOpContinue && (mLoop.condition || mLoop.expression))
18797
+    {
18798
+        TIntermBlock *parent = getParentNode()->getAsBlock();
18799
+        ASSERT(parent);
18800
+        TIntermSequence seq;
18801
+        if (mLoop.expression)
18802
+        {
18803
+            seq.push_back(mLoop.expression->deepCopy());
18804
+        }
18805
+        if (mLoop.condition)
18806
+        {
18807
+            ASSERT(mLoop.conditionVariable);
18808
+            seq.push_back(
18809
+                CreateTempAssignmentNode(mLoop.conditionVariable, mLoop.condition->deepCopy()));
18810
+        }
18811
+        seq.push_back(node);
18812
+        mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(parent, node, std::move(seq)));
18813
+    }
18814
+
18815
+    return true;
18816
+}
18817
+
18818
 void SimplifyLoopConditionsTraverser::traverseLoop(TIntermLoop *node)
18819
 {
18820
     // Mark that we're inside a loop condition or expression, and determine if the loop needs to be
18821
@@ -128,7 +169,7 @@ void SimplifyLoopConditionsTraverser::traverseLoop(TIntermLoop *node)
18822
     ScopedNodeInTraversalPath addToPath(this, node);
18823
 
18824
     mInsideLoopInitConditionOrExpression = true;
18825
-    mFoundLoopToChange                   = false;
18826
+    mFoundLoopToChange                   = !mConditionsToSimplify;
18827
 
18828
     if (!mFoundLoopToChange && node->getInit())
18829
     {
18830
@@ -147,22 +188,54 @@ void SimplifyLoopConditionsTraverser::traverseLoop(TIntermLoop *node)
18831
 
18832
     mInsideLoopInitConditionOrExpression = false;
18833
 
18834
+    const LoopInfo prevLoop = mLoop;
18835
+
18836
     if (mFoundLoopToChange)
18837
     {
18838
         const TType *boolType   = StaticType::Get<EbtBool, EbpUndefined, EvqTemporary, 1, 1>();
18839
-        TVariable *conditionVariable = CreateTempVariable(mSymbolTable, boolType);
18840
+        mLoop.conditionVariable = CreateTempVariable(mSymbolTable, boolType);
18841
+        mLoop.condition         = node->getCondition();
18842
+        mLoop.expression        = node->getExpression();
18843
 
18844
         // Replace the loop condition with a boolean variable that's updated on each iteration.
18845
         TLoopType loopType = node->getType();
18846
         if (loopType == ELoopWhile)
18847
+        {
18848
+            ASSERT(!mLoop.expression);
18849
+
18850
+            if (mLoop.condition->getAsSymbolNode())
18851
+            {
18852
+                // Mask continue statement condition variable update.
18853
+                mLoop.condition = nullptr;
18854
+            }
18855
+            else if (mLoop.condition->getAsConstantUnion())
18856
+            {
18857
+                // Transform:
18858
+                //   while (expr) { body; }
18859
+                // into
18860
+                //   bool s0 = expr;
18861
+                //   while (s0) { body; }
18862
+                TIntermDeclaration *tempInitDeclaration =
18863
+                    CreateTempInitDeclarationNode(mLoop.conditionVariable, mLoop.condition);
18864
+                insertStatementInParentBlock(tempInitDeclaration);
18865
+
18866
+                node->setCondition(CreateTempSymbolNode(mLoop.conditionVariable));
18867
+
18868
+                // Mask continue statement condition variable update.
18869
+                mLoop.condition = nullptr;
18870
+            }
18871
+            else
18872
             {
18873
                 // Transform:
18874
                 //   while (expr) { body; }
18875
                 // into
18876
                 //   bool s0 = expr;
18877
                 //   while (s0) { { body; } s0 = expr; }
18878
+                //
18879
+                // Local case statements are transformed into:
18880
+                //   s0 = expr; continue;
18881
                 TIntermDeclaration *tempInitDeclaration =
18882
-                CreateTempInitDeclarationNode(conditionVariable, node->getCondition()->deepCopy());
18883
+                    CreateTempInitDeclarationNode(mLoop.conditionVariable, mLoop.condition);
18884
                 insertStatementInParentBlock(tempInitDeclaration);
18885
 
18886
                 TIntermBlock *newBody = new TIntermBlock();
18887
@@ -171,28 +244,60 @@ void SimplifyLoopConditionsTraverser::traverseLoop(TIntermLoop *node)
18888
                     newBody->getSequence()->push_back(node->getBody());
18889
                 }
18890
                 newBody->getSequence()->push_back(
18891
-                CreateTempAssignmentNode(conditionVariable, node->getCondition()->deepCopy()));
18892
+                    CreateTempAssignmentNode(mLoop.conditionVariable, mLoop.condition->deepCopy()));
18893
 
18894
                 // Can't use queueReplacement to replace old body, since it may have been nullptr.
18895
                 // It's safe to do the replacements in place here - the new body will still be
18896
                 // traversed, but that won't create any problems.
18897
                 node->setBody(newBody);
18898
-            node->setCondition(CreateTempSymbolNode(conditionVariable));
18899
+                node->setCondition(CreateTempSymbolNode(mLoop.conditionVariable));
18900
+            }
18901
         }
18902
         else if (loopType == ELoopDoWhile)
18903
+        {
18904
+            ASSERT(!mLoop.expression);
18905
+
18906
+            if (mLoop.condition->getAsSymbolNode())
18907
+            {
18908
+                // Mask continue statement condition variable update.
18909
+                mLoop.condition = nullptr;
18910
+            }
18911
+            else if (mLoop.condition->getAsConstantUnion())
18912
+            {
18913
+                // Transform:
18914
+                //   do {
18915
+                //     body;
18916
+                //   } while (expr);
18917
+                // into
18918
+                //   bool s0 = expr;
18919
+                //   do {
18920
+                //     body;
18921
+                //   } while (s0);
18922
+                TIntermDeclaration *tempInitDeclaration =
18923
+                    CreateTempInitDeclarationNode(mLoop.conditionVariable, mLoop.condition);
18924
+                insertStatementInParentBlock(tempInitDeclaration);
18925
+
18926
+                node->setCondition(CreateTempSymbolNode(mLoop.conditionVariable));
18927
+
18928
+                // Mask continue statement condition variable update.
18929
+                mLoop.condition = nullptr;
18930
+            }
18931
+            else
18932
             {
18933
                 // Transform:
18934
                 //   do {
18935
                 //     body;
18936
                 //   } while (expr);
18937
                 // into
18938
-            //   bool s0 = true;
18939
+                //   bool s0;
18940
                 //   do {
18941
                 //     { body; }
18942
                 //     s0 = expr;
18943
                 //   } while (s0);
18944
+                // Local case statements are transformed into:
18945
+                //   s0 = expr; continue;
18946
                 TIntermDeclaration *tempInitDeclaration =
18947
-                CreateTempInitDeclarationNode(conditionVariable, CreateBoolNode(true));
18948
+                    CreateTempDeclarationNode(mLoop.conditionVariable);
18949
                 insertStatementInParentBlock(tempInitDeclaration);
18950
 
18951
                 TIntermBlock *newBody = new TIntermBlock();
18952
@@ -201,15 +306,68 @@ void SimplifyLoopConditionsTraverser::traverseLoop(TIntermLoop *node)
18953
                     newBody->getSequence()->push_back(node->getBody());
18954
                 }
18955
                 newBody->getSequence()->push_back(
18956
-                CreateTempAssignmentNode(conditionVariable, node->getCondition()->deepCopy()));
18957
+                    CreateTempAssignmentNode(mLoop.conditionVariable, mLoop.condition));
18958
 
18959
                 // Can't use queueReplacement to replace old body, since it may have been nullptr.
18960
                 // It's safe to do the replacements in place here - the new body will still be
18961
                 // traversed, but that won't create any problems.
18962
                 node->setBody(newBody);
18963
-            node->setCondition(CreateTempSymbolNode(conditionVariable));
18964
+                node->setCondition(CreateTempSymbolNode(mLoop.conditionVariable));
18965
+            }
18966
         }
18967
         else if (loopType == ELoopFor)
18968
+        {
18969
+            if (!mLoop.condition)
18970
+            {
18971
+                mLoop.condition = CreateBoolNode(true);
18972
+            }
18973
+
18974
+            TIntermLoop *whileLoop;
18975
+            TIntermBlock *loopScope            = new TIntermBlock();
18976
+            TIntermSequence *loopScopeSequence = loopScope->getSequence();
18977
+
18978
+            // Insert "init;"
18979
+            if (node->getInit())
18980
+            {
18981
+                loopScopeSequence->push_back(node->getInit());
18982
+            }
18983
+
18984
+            if (mLoop.condition->getAsSymbolNode())
18985
+            {
18986
+                // Move the loop condition inside the loop.
18987
+                // Transform:
18988
+                //   for (init; expr; exprB) { body; }
18989
+                // into
18990
+                //   {
18991
+                //     init;
18992
+                //     while (expr) {
18993
+                //       { body; }
18994
+                //       exprB;
18995
+                //     }
18996
+                //   }
18997
+                //
18998
+                // Local case statements are transformed into:
18999
+                //   exprB; continue;
19000
+
19001
+                // Insert "{ body; }" in the while loop
19002
+                TIntermBlock *whileLoopBody = new TIntermBlock();
19003
+                if (node->getBody())
19004
+                {
19005
+                    whileLoopBody->getSequence()->push_back(node->getBody());
19006
+                }
19007
+                // Insert "exprB;" in the while loop
19008
+                if (node->getExpression())
19009
+                {
19010
+                    whileLoopBody->getSequence()->push_back(node->getExpression());
19011
+                }
19012
+                // Create "while(expr) { whileLoopBody }"
19013
+                whileLoop =
19014
+                    new TIntermLoop(ELoopWhile, nullptr, mLoop.condition, nullptr, whileLoopBody);
19015
+
19016
+                // Mask continue statement condition variable update.
19017
+                mLoop.condition = nullptr;
19018
+            }
19019
+            else if (mLoop.condition->getAsConstantUnion())
19020
             {
19021
                 // Move the loop condition inside the loop.
19022
                 // Transform:
19023
@@ -221,31 +379,56 @@ void SimplifyLoopConditionsTraverser::traverseLoop(TIntermLoop *node)
19024
                 //     while (s0) {
19025
                 //       { body; }
19026
                 //       exprB;
19027
-            //       s0 = expr;
19028
                 //     }
19029
                 //   }
19030
-            TIntermBlock *loopScope            = new TIntermBlock();
19031
-            TIntermSequence *loopScopeSequence = loopScope->getSequence();
19032
+                //
19033
+                // Local case statements are transformed into:
19034
+                //   exprB; continue;
19035
 
19036
-            // Insert "init;"
19037
-            if (node->getInit())
19038
+                // Insert "bool s0 = expr;"
19039
+                loopScopeSequence->push_back(
19040
+                    CreateTempInitDeclarationNode(mLoop.conditionVariable, mLoop.condition));
19041
+                // Insert "{ body; }" in the while loop
19042
+                TIntermBlock *whileLoopBody = new TIntermBlock();
19043
+                if (node->getBody())
19044
                 {
19045
-                loopScopeSequence->push_back(node->getInit());
19046
+                    whileLoopBody->getSequence()->push_back(node->getBody());
19047
                 }
19048
-
19049
-            // Insert "bool s0 = expr;" if applicable, "bool s0 = true;" otherwise
19050
-            TIntermTyped *conditionInitializer = nullptr;
19051
-            if (node->getCondition())
19052
+                // Insert "exprB;" in the while loop
19053
+                if (node->getExpression())
19054
                 {
19055
-                conditionInitializer = node->getCondition()->deepCopy();
19056
+                    whileLoopBody->getSequence()->push_back(node->getExpression());
19057
+                }
19058
+                // Create "while(s0) { whileLoopBody }"
19059
+                whileLoop = new TIntermLoop(ELoopWhile, nullptr,
19060
+                                            CreateTempSymbolNode(mLoop.conditionVariable), nullptr,
19061
+                                            whileLoopBody);
19062
+
19063
+                // Mask continue statement condition variable update.
19064
+                mLoop.condition = nullptr;
19065
             }
19066
             else
19067
             {
19068
-                conditionInitializer = CreateBoolNode(true);
19069
-            }
19070
-            loopScopeSequence->push_back(
19071
-                CreateTempInitDeclarationNode(conditionVariable, conditionInitializer));
19072
+                // Move the loop condition inside the loop.
19073
+                // Transform:
19074
+                //   for (init; expr; exprB) { body; }
19075
+                // into
19076
+                //   {
19077
+                //     init;
19078
+                //     bool s0 = expr;
19079
+                //     while (s0) {
19080
+                //       { body; }
19081
+                //       exprB;
19082
+                //       s0 = expr;
19083
+                //     }
19084
+                //   }
19085
+                //
19086
+                // Local case statements are transformed into:
19087
+                //   exprB; s0 = expr; continue;
19088
 
19089
+                // Insert "bool s0 = expr;"
19090
+                loopScopeSequence->push_back(
19091
+                    CreateTempInitDeclarationNode(mLoop.conditionVariable, mLoop.condition));
19092
                 // Insert "{ body; }" in the while loop
19093
                 TIntermBlock *whileLoopBody = new TIntermBlock();
19094
                 if (node->getBody())
19095
@@ -258,23 +441,21 @@ void SimplifyLoopConditionsTraverser::traverseLoop(TIntermLoop *node)
19096
                     whileLoopBody->getSequence()->push_back(node->getExpression());
19097
                 }
19098
                 // Insert "s0 = expr;" in the while loop
19099
-            if (node->getCondition())
19100
-            {
19101
                 whileLoopBody->getSequence()->push_back(
19102
-                    CreateTempAssignmentNode(conditionVariable, node->getCondition()->deepCopy()));
19103
+                    CreateTempAssignmentNode(mLoop.conditionVariable, mLoop.condition->deepCopy()));
19104
+                // Create "while(s0) { whileLoopBody }"
19105
+                whileLoop = new TIntermLoop(ELoopWhile, nullptr,
19106
+                                            CreateTempSymbolNode(mLoop.conditionVariable), nullptr,
19107
+                                            whileLoopBody);
19108
             }
19109
 
19110
-            // Create "while(s0) { whileLoopBody }"
19111
-            TIntermLoop *whileLoop =
19112
-                new TIntermLoop(ELoopWhile, nullptr, CreateTempSymbolNode(conditionVariable),
19113
-                                nullptr, whileLoopBody);
19114
             loopScope->getSequence()->push_back(whileLoop);
19115
             queueReplacement(loopScope, OriginalNode::IS_DROPPED);
19116
 
19117
             // After this the old body node will be traversed and loops inside it may be
19118
-            // transformed. This is fine, since the old body node will still be in the AST after the
19119
-            // transformation that's queued here, and transforming loops inside it doesn't need to
19120
-            // know the exact post-transform path to it.
19121
+            // transformed. This is fine, since the old body node will still be in the AST after
19122
+            // the transformation that's queued here, and transforming loops inside it doesn't
19123
+            // need to know the exact post-transform path to it.
19124
         }
19125
     }
19126
 
19127
@@ -283,16 +464,26 @@ void SimplifyLoopConditionsTraverser::traverseLoop(TIntermLoop *node)
19128
     // We traverse the body of the loop even if the loop is transformed.
19129
     if (node->getBody())
19130
         node->getBody()->traverse(this);
19131
+
19132
+    mLoop = prevLoop;
19133
 }
19134
 
19135
 }  // namespace
19136
 
19137
+bool SimplifyLoopConditions(TCompiler *compiler, TIntermNode *root, TSymbolTable *symbolTable)
19138
+{
19139
+    SimplifyLoopConditionsTraverser traverser(nullptr, symbolTable);
19140
+    root->traverse(&traverser);
19141
+    return traverser.updateTree(compiler, root);
19142
+}
19143
+
19144
 bool SimplifyLoopConditions(TCompiler *compiler,
19145
                             TIntermNode *root,
19146
                             unsigned int conditionsToSimplifyMask,
19147
                             TSymbolTable *symbolTable)
19148
 {
19149
-    SimplifyLoopConditionsTraverser traverser(conditionsToSimplifyMask, symbolTable);
19150
+    IntermNodePatternMatcher conditionsToSimplify(conditionsToSimplifyMask);
19151
+    SimplifyLoopConditionsTraverser traverser(&conditionsToSimplify, symbolTable);
19152
     root->traverse(&traverser);
19153
     return traverser.updateTree(compiler, root);
19154
 }
19155
diff --git a/src/compiler/translator/tree_ops/SimplifyLoopConditions.h b/src/compiler/translator/tree_ops/SimplifyLoopConditions.h
19156
index 4cdede6..68b98f8 100644
19157
--- a/src/compiler/translator/tree_ops/SimplifyLoopConditions.h
19158
+++ b/src/compiler/translator/tree_ops/SimplifyLoopConditions.h
19159
@@ -19,6 +19,10 @@ class TCompiler;
19160
 class TIntermNode;
19161
 class TSymbolTable;
19162
 
19163
+ANGLE_NO_DISCARD bool SimplifyLoopConditions(TCompiler *compiler,
19164
+                                             TIntermNode *root,
19165
+                                             TSymbolTable *symbolTable);
19166
+
19167
 ANGLE_NO_DISCARD bool SimplifyLoopConditions(TCompiler *compiler,
19168
                                              TIntermNode *root,
19169
                                              unsigned int conditionsToSimplify,
19170
diff --git a/src/compiler/translator/tree_util/AsNode.h b/src/compiler/translator/tree_util/AsNode.h
19171
new file mode 100644
19172
index 0000000..1c6de18
19173
--- /dev/null
19174
+++ b/src/compiler/translator/tree_util/AsNode.h
19175
@@ -0,0 +1,212 @@
19176
+//
19177
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
19178
+// Use of this source code is governed by a BSD-style license that can be
19179
+// found in the LICENSE file.
19180
+//
19181
+
19182
+#ifndef COMPILER_TRANSLATOR_TREEUTIL_INTERMASNODE_H_
19183
+#define COMPILER_TRANSLATOR_TREEUTIL_INTERMASNODE_H_
19184
+
19185
+#include "common/angleutils.h"
19186
+#include "compiler/translator/IntermNode.h"
19187
+
19188
+#include <utility>
19189
+
19190
+namespace sh
19191
+{
19192
+
19193
+namespace priv
19194
+{
19195
+
19196
+template <typename T>
19197
+struct AsNode
19198
+{};
19199
+
19200
+template <>
19201
+struct AsNode<TIntermNode>
19202
+{
19203
+    static ANGLE_INLINE TIntermNode *exec(TIntermNode *node) { return node; }
19204
+};
19205
+
19206
+template <>
19207
+struct AsNode<TIntermTyped>
19208
+{
19209
+    static ANGLE_INLINE TIntermTyped *exec(TIntermNode *node)
19210
+    {
19211
+        return node ? node->getAsTyped() : nullptr;
19212
+    }
19213
+};
19214
+
19215
+template <>
19216
+struct AsNode<TIntermSymbol>
19217
+{
19218
+    static ANGLE_INLINE TIntermSymbol *exec(TIntermNode *node)
19219
+    {
19220
+        return node ? node->getAsSymbolNode() : nullptr;
19221
+    }
19222
+};
19223
+
19224
+template <>
19225
+struct AsNode<TIntermConstantUnion>
19226
+{
19227
+    static ANGLE_INLINE TIntermConstantUnion *exec(TIntermNode *node)
19228
+    {
19229
+        return node ? node->getAsConstantUnion() : nullptr;
19230
+    }
19231
+};
19232
+
19233
+template <>
19234
+struct AsNode<TIntermFunctionPrototype>
19235
+{
19236
+    static ANGLE_INLINE TIntermFunctionPrototype *exec(TIntermNode *node)
19237
+    {
19238
+        return node ? node->getAsFunctionPrototypeNode() : nullptr;
19239
+    }
19240
+};
19241
+
19242
+template <>
19243
+struct AsNode<TIntermPreprocessorDirective>
19244
+{
19245
+    static ANGLE_INLINE TIntermPreprocessorDirective *exec(TIntermNode *node)
19246
+    {
19247
+        return node ? node->getAsPreprocessorDirective() : nullptr;
19248
+    }
19249
+};
19250
+
19251
+template <>
19252
+struct AsNode<TIntermSwizzle>
19253
+{
19254
+    static ANGLE_INLINE TIntermSwizzle *exec(TIntermNode *node)
19255
+    {
19256
+        return node ? node->getAsSwizzleNode() : nullptr;
19257
+    }
19258
+};
19259
+
19260
+template <>
19261
+struct AsNode<TIntermBinary>
19262
+{
19263
+    static ANGLE_INLINE TIntermBinary *exec(TIntermNode *node)
19264
+    {
19265
+        return node ? node->getAsBinaryNode() : nullptr;
19266
+    }
19267
+};
19268
+
19269
+template <>
19270
+struct AsNode<TIntermUnary>
19271
+{
19272
+    static ANGLE_INLINE TIntermUnary *exec(TIntermNode *node)
19273
+    {
19274
+        return node ? node->getAsUnaryNode() : nullptr;
19275
+    }
19276
+};
19277
+
19278
+template <>
19279
+struct AsNode<TIntermTernary>
19280
+{
19281
+    static ANGLE_INLINE TIntermTernary *exec(TIntermNode *node)
19282
+    {
19283
+        return node ? node->getAsTernaryNode() : nullptr;
19284
+    }
19285
+};
19286
+
19287
+template <>
19288
+struct AsNode<TIntermIfElse>
19289
+{
19290
+    static ANGLE_INLINE TIntermIfElse *exec(TIntermNode *node)
19291
+    {
19292
+        return node ? node->getAsIfElseNode() : nullptr;
19293
+    }
19294
+};
19295
+
19296
+template <>
19297
+struct AsNode<TIntermSwitch>
19298
+{
19299
+    static ANGLE_INLINE TIntermSwitch *exec(TIntermNode *node)
19300
+    {
19301
+        return node ? node->getAsSwitchNode() : nullptr;
19302
+    }
19303
+};
19304
+
19305
+template <>
19306
+struct AsNode<TIntermCase>
19307
+{
19308
+    static ANGLE_INLINE TIntermCase *exec(TIntermNode *node)
19309
+    {
19310
+        return node ? node->getAsCaseNode() : nullptr;
19311
+    }
19312
+};
19313
+
19314
+template <>
19315
+struct AsNode<TIntermFunctionDefinition>
19316
+{
19317
+    static ANGLE_INLINE TIntermFunctionDefinition *exec(TIntermNode *node)
19318
+    {
19319
+        return node ? node->getAsFunctionDefinition() : nullptr;
19320
+    }
19321
+};
19322
+
19323
+template <>
19324
+struct AsNode<TIntermAggregate>
19325
+{
19326
+    static ANGLE_INLINE TIntermAggregate *exec(TIntermNode *node)
19327
+    {
19328
+        return node ? node->getAsAggregate() : nullptr;
19329
+    }
19330
+};
19331
+
19332
+template <>
19333
+struct AsNode<TIntermBlock>
19334
+{
19335
+    static ANGLE_INLINE TIntermBlock *exec(TIntermNode *node)
19336
+    {
19337
+        return node ? node->getAsBlock() : nullptr;
19338
+    }
19339
+};
19340
+
19341
+template <>
19342
+struct AsNode<TIntermGlobalQualifierDeclaration>
19343
+{
19344
+    static ANGLE_INLINE TIntermGlobalQualifierDeclaration *exec(TIntermNode *node)
19345
+    {
19346
+        return node ? node->getAsGlobalQualifierDeclarationNode() : nullptr;
19347
+    }
19348
+};
19349
+
19350
+template <>
19351
+struct AsNode<TIntermDeclaration>
19352
+{
19353
+    static ANGLE_INLINE TIntermDeclaration *exec(TIntermNode *node)
19354
+    {
19355
+        return node ? node->getAsDeclarationNode() : nullptr;
19356
+    }
19357
+};
19358
+
19359
+template <>
19360
+struct AsNode<TIntermLoop>
19361
+{
19362
+    static ANGLE_INLINE TIntermLoop *exec(TIntermNode *node)
19363
+    {
19364
+        return node ? node->getAsLoopNode() : nullptr;
19365
+    }
19366
+};
19367
+
19368
+template <>
19369
+struct AsNode<TIntermBranch>
19370
+{
19371
+    static ANGLE_INLINE TIntermBranch *exec(TIntermNode *node)
19372
+    {
19373
+        return node ? node->getAsBranchNode() : nullptr;
19374
+    }
19375
+};
19376
+
19377
+}  // namespace priv
19378
+
19379
+template <typename T>
19380
+ANGLE_INLINE T *asNode(TIntermNode *node)
19381
+{
19382
+    return priv::AsNode<T>::exec(node);
19383
+}
19384
+
19385
+}  // namespace sh
19386
+
19387
+#endif  // COMPILER_TRANSLATOR_TREEUTIL_INTERMASNODE_H_
19388
diff --git a/src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp b/src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp
19389
index d08c386..acc7892 100644
19390
--- a/src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp
19391
+++ b/src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp
19392
@@ -65,7 +65,7 @@ bool IntermNodePatternMatcher::IsDynamicIndexingOfSwizzledVector(TIntermBinary *
19393
     return IsDynamicIndexingOfVectorOrMatrix(node) && node->getLeft()->getAsSwizzleNode();
19394
 }
19395
 
19396
-bool IntermNodePatternMatcher::matchInternal(TIntermBinary *node, TIntermNode *parentNode)
19397
+bool IntermNodePatternMatcher::matchInternal(TIntermBinary *node, TIntermNode *parentNode) const
19398
 {
19399
     if ((mMask & kExpressionReturningArray) != 0)
19400
     {
19401
@@ -87,7 +87,7 @@ bool IntermNodePatternMatcher::matchInternal(TIntermBinary *node, TIntermNode *p
19402
     return false;
19403
 }
19404
 
19405
-bool IntermNodePatternMatcher::match(TIntermUnary *node)
19406
+bool IntermNodePatternMatcher::match(TIntermUnary *node) const
19407
 {
19408
     if ((mMask & kArrayLengthMethod) != 0)
19409
     {
19410
@@ -99,7 +99,7 @@ bool IntermNodePatternMatcher::match(TIntermUnary *node)
19411
     return false;
19412
 }
19413
 
19414
-bool IntermNodePatternMatcher::match(TIntermBinary *node, TIntermNode *parentNode)
19415
+bool IntermNodePatternMatcher::match(TIntermBinary *node, TIntermNode *parentNode) const
19416
 {
19417
     // L-value tracking information is needed to check for dynamic indexing in L-value.
19418
     // Traversers that don't track l-values can still use this class and match binary nodes with
19419
@@ -110,7 +110,7 @@ bool IntermNodePatternMatcher::match(TIntermBinary *node, TIntermNode *parentNod
19420
 
19421
 bool IntermNodePatternMatcher::match(TIntermBinary *node,
19422
                                      TIntermNode *parentNode,
19423
-                                     bool isLValueRequiredHere)
19424
+                                     bool isLValueRequiredHere) const
19425
 {
19426
     if (matchInternal(node, parentNode))
19427
     {
19428
@@ -126,7 +126,7 @@ bool IntermNodePatternMatcher::match(TIntermBinary *node,
19429
     return false;
19430
 }
19431
 
19432
-bool IntermNodePatternMatcher::match(TIntermAggregate *node, TIntermNode *parentNode)
19433
+bool IntermNodePatternMatcher::match(TIntermAggregate *node, TIntermNode *parentNode) const
19434
 {
19435
     if ((mMask & kExpressionReturningArray) != 0)
19436
     {
19437
@@ -161,7 +161,7 @@ bool IntermNodePatternMatcher::match(TIntermAggregate *node, TIntermNode *parent
19438
     return false;
19439
 }
19440
 
19441
-bool IntermNodePatternMatcher::match(TIntermTernary *node)
19442
+bool IntermNodePatternMatcher::match(TIntermTernary *node) const
19443
 {
19444
     if ((mMask & kUnfoldedShortCircuitExpression) != 0)
19445
     {
19446
@@ -170,7 +170,7 @@ bool IntermNodePatternMatcher::match(TIntermTernary *node)
19447
     return false;
19448
 }
19449
 
19450
-bool IntermNodePatternMatcher::match(TIntermDeclaration *node)
19451
+bool IntermNodePatternMatcher::match(TIntermDeclaration *node) const
19452
 {
19453
     if ((mMask & kMultiDeclaration) != 0)
19454
     {
19455
diff --git a/src/compiler/translator/tree_util/IntermNodePatternMatcher.h b/src/compiler/translator/tree_util/IntermNodePatternMatcher.h
19456
index e9c4bcf..6f3d873 100644
19457
--- a/src/compiler/translator/tree_util/IntermNodePatternMatcher.h
19458
+++ b/src/compiler/translator/tree_util/IntermNodePatternMatcher.h
19459
@@ -28,52 +28,52 @@ class IntermNodePatternMatcher
19460
     static bool IsDynamicIndexingOfVectorOrMatrix(TIntermBinary *node);
19461
     static bool IsDynamicIndexingOfSwizzledVector(TIntermBinary *node);
19462
 
19463
-    enum PatternType
19464
+    enum PatternType : unsigned int
19465
     {
19466
         // Matches expressions that are unfolded to if statements by UnfoldShortCircuitToIf
19467
-        kUnfoldedShortCircuitExpression = 0x0001,
19468
+        kUnfoldedShortCircuitExpression = 1u << 0u,
19469
 
19470
         // Matches expressions that return arrays with the exception of simple statements where a
19471
         // constructor or function call result is assigned.
19472
-        kExpressionReturningArray = 0x0001 << 1,
19473
+        kExpressionReturningArray = 1u << 1u,
19474
 
19475
         // Matches dynamic indexing of vectors or matrices in l-values.
19476
-        kDynamicIndexingOfVectorOrMatrixInLValue = 0x0001 << 2,
19477
+        kDynamicIndexingOfVectorOrMatrixInLValue = 1u << 2u,
19478
 
19479
         // Matches declarations with more than one declared variables.
19480
-        kMultiDeclaration = 0x0001 << 3,
19481
+        kMultiDeclaration = 1u << 3u,
19482
 
19483
         // Matches declarations of arrays.
19484
-        kArrayDeclaration = 0x0001 << 4,
19485
+        kArrayDeclaration = 1u << 4u,
19486
 
19487
         // Matches declarations of structs where the struct type does not have a name.
19488
-        kNamelessStructDeclaration = 0x0001 << 5,
19489
+        kNamelessStructDeclaration = 1u << 5u,
19490
 
19491
         // Matches array length() method.
19492
-        kArrayLengthMethod = 0x0001 << 6,
19493
+        kArrayLengthMethod = 1u << 6u,
19494
 
19495
         // Matches a vector or matrix constructor whose arguments are scalarized by the
19496
         // SH_SCALARIZE_VEC_OR_MAT_CONSTRUCTOR_ARGUMENTS workaround.
19497
-        kScalarizedVecOrMatConstructor = 0x0001 << 7
19498
+        kScalarizedVecOrMatConstructor = 1u << 7u,
19499
     };
19500
     IntermNodePatternMatcher(const unsigned int mask);
19501
 
19502
-    bool match(TIntermUnary *node);
19503
+    bool match(TIntermUnary *node) const;
19504
 
19505
-    bool match(TIntermBinary *node, TIntermNode *parentNode);
19506
+    bool match(TIntermBinary *node, TIntermNode *parentNode) const;
19507
 
19508
     // Use this version for checking binary node matches in case you're using flag
19509
     // kDynamicIndexingOfVectorOrMatrixInLValue.
19510
-    bool match(TIntermBinary *node, TIntermNode *parentNode, bool isLValueRequiredHere);
19511
+    bool match(TIntermBinary *node, TIntermNode *parentNode, bool isLValueRequiredHere) const;
19512
 
19513
-    bool match(TIntermAggregate *node, TIntermNode *parentNode);
19514
-    bool match(TIntermTernary *node);
19515
-    bool match(TIntermDeclaration *node);
19516
+    bool match(TIntermAggregate *node, TIntermNode *parentNode) const;
19517
+    bool match(TIntermTernary *node) const;
19518
+    bool match(TIntermDeclaration *node) const;
19519
 
19520
   private:
19521
     const unsigned int mMask;
19522
 
19523
-    bool matchInternal(TIntermBinary *node, TIntermNode *parentNode);
19524
+    bool matchInternal(TIntermBinary *node, TIntermNode *parentNode) const;
19525
 };
19526
 
19527
 }  // namespace sh
19528
diff --git a/src/compiler/translator/tree_util/IntermNode_util.cpp b/src/compiler/translator/tree_util/IntermNode_util.cpp
19529
index 6ab13ba..d3e1fca 100644
19530
--- a/src/compiler/translator/tree_util/IntermNode_util.cpp
19531
+++ b/src/compiler/translator/tree_util/IntermNode_util.cpp
19532
@@ -224,6 +224,50 @@ TVariable *DeclareTempVariable(TSymbolTable *symbolTable,
19533
     return variable;
19534
 }
19535
 
19536
+std::pair<const TVariable *, const TVariable *> DeclareStructure(
19537
+    TIntermBlock *root,
19538
+    TSymbolTable *symbolTable,
19539
+    TFieldList *fieldList,
19540
+    TQualifier qualifier,
19541
+    const TMemoryQualifier &memoryQualifier,
19542
+    uint32_t arraySize,
19543
+    const ImmutableString &structTypeName,
19544
+    const ImmutableString *structInstanceName)
19545
+{
19546
+    TStructure *structure =
19547
+        new TStructure(symbolTable, structTypeName, fieldList, SymbolType::AngleInternal);
19548
+
19549
+    auto makeStructureType = [&](bool isStructSpecifier) {
19550
+        TType *structureType = new TType(structure, isStructSpecifier);
19551
+        structureType->setQualifier(qualifier);
19552
+        structureType->setMemoryQualifier(memoryQualifier);
19553
+        if (arraySize > 0)
19554
+        {
19555
+            structureType->makeArray(arraySize);
19556
+        }
19557
+        return structureType;
19558
+    };
19559
+
19560
+    TIntermSequence insertSequence;
19561
+
19562
+    TVariable *typeVar = new TVariable(symbolTable, kEmptyImmutableString, makeStructureType(true),
19563
+                                       SymbolType::Empty);
19564
+    insertSequence.push_back(new TIntermDeclaration{typeVar});
19565
+
19566
+    TVariable *instanceVar = nullptr;
19567
+    if (structInstanceName)
19568
+    {
19569
+        instanceVar = new TVariable(symbolTable, *structInstanceName, makeStructureType(false),
19570
+                                    SymbolType::AngleInternal);
19571
+        insertSequence.push_back(new TIntermDeclaration{instanceVar});
19572
+    }
19573
+
19574
+    size_t firstFunctionIndex = FindFirstFunctionDefinitionIndex(root);
19575
+    root->insertChildNodes(firstFunctionIndex, insertSequence);
19576
+
19577
+    return {typeVar, instanceVar};
19578
+}
19579
+
19580
 const TVariable *DeclareInterfaceBlock(TIntermBlock *root,
19581
                                        TSymbolTable *symbolTable,
19582
                                        TFieldList *fieldList,
19583
diff --git a/src/compiler/translator/tree_util/IntermNode_util.h b/src/compiler/translator/tree_util/IntermNode_util.h
19584
index 39b86dd..f5d1c93 100644
19585
--- a/src/compiler/translator/tree_util/IntermNode_util.h
19586
+++ b/src/compiler/translator/tree_util/IntermNode_util.h
19587
@@ -45,6 +45,15 @@ TVariable *DeclareTempVariable(TSymbolTable *symbolTable,
19588
                                TIntermTyped *initializer,
19589
                                TQualifier qualifier,
19590
                                TIntermDeclaration **declarationOut);
19591
+std::pair<const TVariable *, const TVariable *> DeclareStructure(
19592
+    TIntermBlock *root,
19593
+    TSymbolTable *symbolTable,
19594
+    TFieldList *fieldList,
19595
+    TQualifier qualifier,
19596
+    const TMemoryQualifier &memoryQualifier,
19597
+    uint32_t arraySize,
19598
+    const ImmutableString &structTypeName,
19599
+    const ImmutableString *structInstanceName);
19600
 const TVariable *DeclareInterfaceBlock(TIntermBlock *root,
19601
                                        TSymbolTable *symbolTable,
19602
                                        TFieldList *fieldList,
19603
diff --git a/src/compiler/translator/tree_util/IntermRebuild.cpp b/src/compiler/translator/tree_util/IntermRebuild.cpp
19604
new file mode 100644
19605
index 0000000..d883473
19606
--- /dev/null
19607
+++ b/src/compiler/translator/tree_util/IntermRebuild.cpp
19608
@@ -0,0 +1,1028 @@
19609
+//
19610
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
19611
+// Use of this source code is governed by a BSD-style license that can be
19612
+// found in the LICENSE file.
19613
+//
19614
+
19615
+#include <algorithm>
19616
+
19617
+#include "compiler/translator/Compiler.h"
19618
+#include "compiler/translator/SymbolTable.h"
19619
+#include "compiler/translator/tree_util/AsNode.h"
19620
+#include "compiler/translator/tree_util/IntermRebuild.h"
19621
+
19622
+#define GUARD2(cond, failVal) \
19623
+    do                        \
19624
+    {                         \
19625
+        if (!(cond))          \
19626
+        {                     \
19627
+            return failVal;   \
19628
+        }                     \
19629
+    } while (false)
19630
+
19631
+#define GUARD(cond) GUARD2(cond, nullptr)
19632
+
19633
+namespace sh
19634
+{
19635
+
19636
+template <typename T, typename U>
19637
+ANGLE_INLINE bool AllBits(T haystack, U needle)
19638
+{
19639
+    return (haystack & needle) == needle;
19640
+}
19641
+
19642
+template <typename T, typename U>
19643
+ANGLE_INLINE bool AnyBits(T haystack, U needle)
19644
+{
19645
+    return (haystack & needle) != 0;
19646
+}
19647
+
19648
+////////////////////////////////////////////////////////////////////////////////
19649
+
19650
+TIntermRebuild::BaseResult::BaseResult(BaseResult &other)
19651
+    : mAction(other.mAction),
19652
+      mVisit(other.mVisit),
19653
+      mSingle(other.mSingle),
19654
+      mMulti(std::move(other.mMulti))
19655
+{}
19656
+
19657
+TIntermRebuild::BaseResult::BaseResult(TIntermNode &node, VisitBits visit)
19658
+    : mAction(Action::ReplaceSingle), mVisit(visit), mSingle(&node)
19659
+{}
19660
+
19661
+TIntermRebuild::BaseResult::BaseResult(TIntermNode *node, VisitBits visit)
19662
+    : mAction(node ? Action::ReplaceSingle : Action::Drop),
19663
+      mVisit(node ? visit : VisitBits::Neither),
19664
+      mSingle(node)
19665
+{}
19666
+
19667
+TIntermRebuild::BaseResult::BaseResult(nullptr_t)
19668
+    : mAction(Action::Drop), mVisit(VisitBits::Neither), mSingle(nullptr)
19669
+{}
19670
+
19671
+TIntermRebuild::BaseResult::BaseResult(Fail)
19672
+    : mAction(Action::Fail), mVisit(VisitBits::Neither), mSingle(nullptr)
19673
+{}
19674
+
19675
+TIntermRebuild::BaseResult::BaseResult(std::vector<TIntermNode *> &&nodes)
19676
+    : mAction(Action::ReplaceMulti),
19677
+      mVisit(VisitBits::Neither),
19678
+      mSingle(nullptr),
19679
+      mMulti(std::move(nodes))
19680
+{}
19681
+
19682
+void TIntermRebuild::BaseResult::moveAssignImpl(BaseResult &other)
19683
+{
19684
+    mAction = other.mAction;
19685
+    mVisit  = other.mVisit;
19686
+    mSingle = other.mSingle;
19687
+    mMulti  = std::move(other.mMulti);
19688
+}
19689
+
19690
+TIntermRebuild::BaseResult TIntermRebuild::BaseResult::Multi(std::vector<TIntermNode *> &&nodes)
19691
+{
19692
+    auto it = std::remove(nodes.begin(), nodes.end(), nullptr);
19693
+    nodes.erase(it, nodes.end());
19694
+    return std::move(nodes);
19695
+}
19696
+
19697
+bool TIntermRebuild::BaseResult::isFail() const
19698
+{
19699
+    return mAction == Action::Fail;
19700
+}
19701
+
19702
+bool TIntermRebuild::BaseResult::isDrop() const
19703
+{
19704
+    return mAction == Action::Drop;
19705
+}
19706
+
19707
+TIntermNode *TIntermRebuild::BaseResult::single() const
19708
+{
19709
+    return mSingle;
19710
+}
19711
+
19712
+const std::vector<TIntermNode *> *TIntermRebuild::BaseResult::multi() const
19713
+{
19714
+    if (mAction == Action::ReplaceMulti)
19715
+    {
19716
+        return &mMulti;
19717
+    }
19718
+    return nullptr;
19719
+}
19720
+
19721
+////////////////////////////////////////////////////////////////////////////////
19722
+
19723
+using PreResult = TIntermRebuild::PreResult;
19724
+
19725
+PreResult::PreResult(TIntermNode &node, VisitBits visit) : BaseResult(node, visit) {}
19726
+PreResult::PreResult(TIntermNode *node, VisitBits visit) : BaseResult(node, visit) {}
19727
+PreResult::PreResult(nullptr_t) : BaseResult(nullptr) {}
19728
+PreResult::PreResult(Fail) : BaseResult(Fail()) {}
19729
+
19730
+PreResult::PreResult(BaseResult &&other) : BaseResult(other) {}
19731
+PreResult::PreResult(PreResult &&other) : BaseResult(other) {}
19732
+
19733
+void PreResult::operator=(PreResult &&other)
19734
+{
19735
+    moveAssignImpl(other);
19736
+}
19737
+
19738
+////////////////////////////////////////////////////////////////////////////////
19739
+
19740
+using PostResult = TIntermRebuild::PostResult;
19741
+
19742
+PostResult::PostResult(TIntermNode &node) : BaseResult(node, VisitBits::Neither) {}
19743
+PostResult::PostResult(TIntermNode *node) : BaseResult(node, VisitBits::Neither) {}
19744
+PostResult::PostResult(nullptr_t) : BaseResult(nullptr) {}
19745
+PostResult::PostResult(Fail) : BaseResult(Fail()) {}
19746
+
19747
+PostResult::PostResult(PostResult &&other) : BaseResult(other) {}
19748
+PostResult::PostResult(BaseResult &&other) : BaseResult(other) {}
19749
+
19750
+void PostResult::operator=(PostResult &&other)
19751
+{
19752
+    moveAssignImpl(other);
19753
+}
19754
+
19755
+////////////////////////////////////////////////////////////////////////////////
19756
+
19757
+TIntermRebuild::TIntermRebuild(TCompiler &compiler, bool preVisit, bool postVisit)
19758
+    : mCompiler(compiler),
19759
+      mSymbolTable(compiler.getSymbolTable()),
19760
+      mPreVisit(preVisit),
19761
+      mPostVisit(postVisit)
19762
+{
19763
+    ASSERT(preVisit || postVisit);
19764
+}
19765
+
19766
+TIntermRebuild::~TIntermRebuild()
19767
+{
19768
+    ASSERT(!mNodeStack.value);
19769
+    ASSERT(!mNodeStack.tail);
19770
+}
19771
+
19772
+const TFunction *TIntermRebuild::getParentFunction() const
19773
+{
19774
+    return mParentFunc;
19775
+}
19776
+
19777
+TIntermNode *TIntermRebuild::getParentNode(size_t offset) const
19778
+{
19779
+    ASSERT(mNodeStack.tail);
19780
+    auto parent = *mNodeStack.tail;
19781
+    while (offset > 0)
19782
+    {
19783
+        --offset;
19784
+        ASSERT(parent.tail);
19785
+        parent = *parent.tail;
19786
+    }
19787
+    return parent.value;
19788
+}
19789
+
19790
+bool TIntermRebuild::rebuildRoot(TIntermBlock &root)
19791
+{
19792
+    if (!rebuildInPlace(root))
19793
+    {
19794
+        return false;
19795
+    }
19796
+    return mCompiler.validateAST(&root);
19797
+}
19798
+
19799
+bool TIntermRebuild::rebuildInPlace(TIntermAggregate &node)
19800
+{
19801
+    return rebuildInPlaceImpl(node);
19802
+}
19803
+
19804
+bool TIntermRebuild::rebuildInPlace(TIntermBlock &node)
19805
+{
19806
+    return rebuildInPlaceImpl(node);
19807
+}
19808
+
19809
+bool TIntermRebuild::rebuildInPlace(TIntermDeclaration &node)
19810
+{
19811
+    return rebuildInPlaceImpl(node);
19812
+}
19813
+
19814
+template <typename Node>
19815
+bool TIntermRebuild::rebuildInPlaceImpl(Node &node)
19816
+{
19817
+    auto *newNode = traverseAnyAs<Node>(node);
19818
+    if (!newNode)
19819
+    {
19820
+        return false;
19821
+    }
19822
+
19823
+    if (newNode != &node)
19824
+    {
19825
+        *node.getSequence() = std::move(*newNode->getSequence());
19826
+    }
19827
+
19828
+    return true;
19829
+}
19830
+
19831
+PostResult TIntermRebuild::rebuild(TIntermNode &node)
19832
+{
19833
+    return traverseAny(node);
19834
+}
19835
+
19836
+////////////////////////////////////////////////////////////////////////////////
19837
+
19838
+template <typename Node>
19839
+Node *TIntermRebuild::traverseAnyAs(TIntermNode &node)
19840
+{
19841
+    PostResult result(traverseAny(node));
19842
+    if (result.mAction == Action::Fail || !result.mSingle)
19843
+    {
19844
+        return nullptr;
19845
+    }
19846
+    return asNode<Node>(result.mSingle);
19847
+}
19848
+
19849
+template <typename Node>
19850
+bool TIntermRebuild::traverseAnyAs(TIntermNode &node, Node *&out)
19851
+{
19852
+    PostResult result(traverseAny(node));
19853
+    if (result.mAction == Action::Fail || result.mAction == Action::ReplaceMulti)
19854
+    {
19855
+        return false;
19856
+    }
19857
+    if (!result.mSingle)
19858
+    {
19859
+        return true;
19860
+    }
19861
+    out = asNode<Node>(result.mSingle);
19862
+    return out;
19863
+}
19864
+
19865
+bool TIntermRebuild::traverseAggregateBaseChildren(TIntermAggregateBase &node)
19866
+{
19867
+    auto *const children = node.getSequence();
19868
+    ASSERT(children);
19869
+    TIntermSequence newChildren;
19870
+
19871
+    for (TIntermNode *child : *children)
19872
+    {
19873
+        ASSERT(child);
19874
+        PostResult result(traverseAny(*child));
19875
+
19876
+        switch (result.mAction)
19877
+        {
19878
+            case Action::ReplaceSingle:
19879
+                newChildren.push_back(result.mSingle);
19880
+                break;
19881
+
19882
+            case Action::ReplaceMulti:
19883
+                for (TIntermNode *newNode : result.mMulti)
19884
+                {
19885
+                    if (newNode)
19886
+                    {
19887
+                        newChildren.push_back(newNode);
19888
+                    }
19889
+                }
19890
+                break;
19891
+
19892
+            case Action::Drop:
19893
+                break;
19894
+
19895
+            case Action::Fail:
19896
+                return false;
19897
+        }
19898
+    }
19899
+
19900
+    *children = std::move(newChildren);
19901
+
19902
+    return true;
19903
+}
19904
+
19905
+////////////////////////////////////////////////////////////////////////////////
19906
+
19907
+struct TIntermRebuild::NodeStackGuard
19908
+{
19909
+    ConsList<TIntermNode *> oldNodeStack;
19910
+    ConsList<TIntermNode *> &nodeStack;
19911
+    NodeStackGuard(ConsList<TIntermNode *> &nodeStack)
19912
+        : oldNodeStack(nodeStack), nodeStack(nodeStack)
19913
+    {}
19914
+    ~NodeStackGuard() { nodeStack = oldNodeStack; }
19915
+};
19916
+
19917
+PostResult TIntermRebuild::traverseAny(TIntermNode &originalNode)
19918
+{
19919
+    PreResult preResult = traversePre(originalNode);
19920
+    if (!preResult.mSingle)
19921
+    {
19922
+        ASSERT(preResult.mVisit == VisitBits::Neither);
19923
+        return std::move(preResult);
19924
+    }
19925
+
19926
+    TIntermNode *currNode       = preResult.mSingle;
19927
+    const VisitBits visit       = preResult.mVisit;
19928
+    const NodeType currNodeType = getNodeType(*currNode);
19929
+
19930
+    currNode = traverseChildren(currNodeType, originalNode, *currNode, visit);
19931
+    if (!currNode)
19932
+    {
19933
+        return Fail();
19934
+    }
19935
+
19936
+    return traversePost(currNodeType, originalNode, *currNode, visit);
19937
+}
19938
+
19939
+PreResult TIntermRebuild::traversePre(TIntermNode &originalNode)
19940
+{
19941
+    if (!mPreVisit)
19942
+    {
19943
+        return {originalNode, VisitBits::Both};
19944
+    }
19945
+
19946
+    NodeStackGuard guard(mNodeStack);
19947
+    mNodeStack = {&originalNode, &guard.oldNodeStack};
19948
+
19949
+    const NodeType originalNodeType = getNodeType(originalNode);
19950
+
19951
+    switch (originalNodeType)
19952
+    {
19953
+        case NodeType::Unknown:
19954
+            ASSERT(false);
19955
+            return Fail();
19956
+        case NodeType::Symbol:
19957
+            return visitSymbolPre(*originalNode.getAsSymbolNode());
19958
+        case NodeType::ConstantUnion:
19959
+            return visitConstantUnionPre(*originalNode.getAsConstantUnion());
19960
+        case NodeType::FunctionPrototype:
19961
+            return visitFunctionPrototypePre(*originalNode.getAsFunctionPrototypeNode());
19962
+        case NodeType::PreprocessorDirective:
19963
+            return visitPreprocessorDirectivePre(*originalNode.getAsPreprocessorDirective());
19964
+        case NodeType::Unary:
19965
+            return visitUnaryPre(*originalNode.getAsUnaryNode());
19966
+        case NodeType::Binary:
19967
+            return visitBinaryPre(*originalNode.getAsBinaryNode());
19968
+        case NodeType::Ternary:
19969
+            return visitTernaryPre(*originalNode.getAsTernaryNode());
19970
+        case NodeType::Swizzle:
19971
+            return visitSwizzlePre(*originalNode.getAsSwizzleNode());
19972
+        case NodeType::IfElse:
19973
+            return visitIfElsePre(*originalNode.getAsIfElseNode());
19974
+        case NodeType::Switch:
19975
+            return visitSwitchPre(*originalNode.getAsSwitchNode());
19976
+        case NodeType::Case:
19977
+            return visitCasePre(*originalNode.getAsCaseNode());
19978
+        case NodeType::FunctionDefinition:
19979
+            return visitFunctionDefinitionPre(*originalNode.getAsFunctionDefinition());
19980
+        case NodeType::Aggregate:
19981
+            return visitAggregatePre(*originalNode.getAsAggregate());
19982
+        case NodeType::Block:
19983
+            return visitBlockPre(*originalNode.getAsBlock());
19984
+        case NodeType::GlobalQualifierDeclaration:
19985
+            return visitGlobalQualifierDeclarationPre(
19986
+                *originalNode.getAsGlobalQualifierDeclarationNode());
19987
+        case NodeType::Declaration:
19988
+            return visitDeclarationPre(*originalNode.getAsDeclarationNode());
19989
+        case NodeType::Loop:
19990
+            return visitLoopPre(*originalNode.getAsLoopNode());
19991
+        case NodeType::Branch:
19992
+            return visitBranchPre(*originalNode.getAsBranchNode());
19993
+    }
19994
+}
19995
+
19996
+TIntermNode *TIntermRebuild::traverseChildren(NodeType currNodeType,
19997
+                                              const TIntermNode &originalNode,
19998
+                                              TIntermNode &currNode,
19999
+                                              VisitBits visit)
20000
+{
20001
+    if (!AnyBits(visit, VisitBits::Children))
20002
+    {
20003
+        return &currNode;
20004
+    }
20005
+
20006
+    if (AnyBits(visit, VisitBits::ChildrenRequiresSame) && &originalNode != &currNode)
20007
+    {
20008
+        return &currNode;
20009
+    }
20010
+
20011
+    NodeStackGuard guard(mNodeStack);
20012
+    mNodeStack = {&currNode, &guard.oldNodeStack};
20013
+
20014
+    switch (currNodeType)
20015
+    {
20016
+        case NodeType::Unknown:
20017
+            ASSERT(false);
20018
+            return nullptr;
20019
+        case NodeType::Symbol:
20020
+            return &currNode;
20021
+        case NodeType::ConstantUnion:
20022
+            return &currNode;
20023
+        case NodeType::FunctionPrototype:
20024
+            return &currNode;
20025
+        case NodeType::PreprocessorDirective:
20026
+            return &currNode;
20027
+        case NodeType::Unary:
20028
+            return traverseUnaryChildren(*currNode.getAsUnaryNode());
20029
+        case NodeType::Binary:
20030
+            return traverseBinaryChildren(*currNode.getAsBinaryNode());
20031
+        case NodeType::Ternary:
20032
+            return traverseTernaryChildren(*currNode.getAsTernaryNode());
20033
+        case NodeType::Swizzle:
20034
+            return traverseSwizzleChildren(*currNode.getAsSwizzleNode());
20035
+        case NodeType::IfElse:
20036
+            return traverseIfElseChildren(*currNode.getAsIfElseNode());
20037
+        case NodeType::Switch:
20038
+            return traverseSwitchChildren(*currNode.getAsSwitchNode());
20039
+        case NodeType::Case:
20040
+            return traverseCaseChildren(*currNode.getAsCaseNode());
20041
+        case NodeType::FunctionDefinition:
20042
+            return traverseFunctionDefinitionChildren(*currNode.getAsFunctionDefinition());
20043
+        case NodeType::Aggregate:
20044
+            return traverseAggregateChildren(*currNode.getAsAggregate());
20045
+        case NodeType::Block:
20046
+            return traverseBlockChildren(*currNode.getAsBlock());
20047
+        case NodeType::GlobalQualifierDeclaration:
20048
+            return traverseGlobalQualifierDeclarationChildren(
20049
+                *currNode.getAsGlobalQualifierDeclarationNode());
20050
+        case NodeType::Declaration:
20051
+            return traverseDeclarationChildren(*currNode.getAsDeclarationNode());
20052
+        case NodeType::Loop:
20053
+            return traverseLoopChildren(*currNode.getAsLoopNode());
20054
+        case NodeType::Branch:
20055
+            return traverseBranchChildren(*currNode.getAsBranchNode());
20056
+    }
20057
+}
20058
+
20059
+PostResult TIntermRebuild::traversePost(NodeType currNodeType,
20060
+                                        const TIntermNode &originalNode,
20061
+                                        TIntermNode &currNode,
20062
+                                        VisitBits visit)
20063
+{
20064
+    if (!mPostVisit)
20065
+    {
20066
+        return currNode;
20067
+    }
20068
+
20069
+    if (!AnyBits(visit, VisitBits::Post))
20070
+    {
20071
+        return currNode;
20072
+    }
20073
+
20074
+    if (AnyBits(visit, VisitBits::PostRequiresSame) && &originalNode != &currNode)
20075
+    {
20076
+        return currNode;
20077
+    }
20078
+
20079
+    NodeStackGuard guard(mNodeStack);
20080
+    mNodeStack = {&currNode, &guard.oldNodeStack};
20081
+
20082
+    switch (currNodeType)
20083
+    {
20084
+        case NodeType::Unknown:
20085
+            ASSERT(false);
20086
+            return Fail();
20087
+        case NodeType::Symbol:
20088
+            return visitSymbolPost(*currNode.getAsSymbolNode());
20089
+        case NodeType::ConstantUnion:
20090
+            return visitConstantUnionPost(*currNode.getAsConstantUnion());
20091
+        case NodeType::FunctionPrototype:
20092
+            return visitFunctionPrototypePost(*currNode.getAsFunctionPrototypeNode());
20093
+        case NodeType::PreprocessorDirective:
20094
+            return visitPreprocessorDirectivePost(*currNode.getAsPreprocessorDirective());
20095
+        case NodeType::Unary:
20096
+            return visitUnaryPost(*currNode.getAsUnaryNode());
20097
+        case NodeType::Binary:
20098
+            return visitBinaryPost(*currNode.getAsBinaryNode());
20099
+        case NodeType::Ternary:
20100
+            return visitTernaryPost(*currNode.getAsTernaryNode());
20101
+        case NodeType::Swizzle:
20102
+            return visitSwizzlePost(*currNode.getAsSwizzleNode());
20103
+        case NodeType::IfElse:
20104
+            return visitIfElsePost(*currNode.getAsIfElseNode());
20105
+        case NodeType::Switch:
20106
+            return visitSwitchPost(*currNode.getAsSwitchNode());
20107
+        case NodeType::Case:
20108
+            return visitCasePost(*currNode.getAsCaseNode());
20109
+        case NodeType::FunctionDefinition:
20110
+            return visitFunctionDefinitionPost(*currNode.getAsFunctionDefinition());
20111
+        case NodeType::Aggregate:
20112
+            return visitAggregatePost(*currNode.getAsAggregate());
20113
+        case NodeType::Block:
20114
+            return visitBlockPost(*currNode.getAsBlock());
20115
+        case NodeType::GlobalQualifierDeclaration:
20116
+            return visitGlobalQualifierDeclarationPost(
20117
+                *currNode.getAsGlobalQualifierDeclarationNode());
20118
+        case NodeType::Declaration:
20119
+            return visitDeclarationPost(*currNode.getAsDeclarationNode());
20120
+        case NodeType::Loop:
20121
+            return visitLoopPost(*currNode.getAsLoopNode());
20122
+        case NodeType::Branch:
20123
+            return visitBranchPost(*currNode.getAsBranchNode());
20124
+    }
20125
+}
20126
+
20127
+////////////////////////////////////////////////////////////////////////////////
20128
+
20129
+TIntermNode *TIntermRebuild::traverseAggregateChildren(TIntermAggregate &node)
20130
+{
20131
+    if (traverseAggregateBaseChildren(node))
20132
+    {
20133
+        return &node;
20134
+    }
20135
+    return nullptr;
20136
+}
20137
+
20138
+TIntermNode *TIntermRebuild::traverseBlockChildren(TIntermBlock &node)
20139
+{
20140
+    if (traverseAggregateBaseChildren(node))
20141
+    {
20142
+        return &node;
20143
+    }
20144
+    return nullptr;
20145
+}
20146
+
20147
+TIntermNode *TIntermRebuild::traverseDeclarationChildren(TIntermDeclaration &node)
20148
+{
20149
+    if (traverseAggregateBaseChildren(node))
20150
+    {
20151
+        return &node;
20152
+    }
20153
+    return nullptr;
20154
+}
20155
+
20156
+TIntermNode *TIntermRebuild::traverseSwizzleChildren(TIntermSwizzle &node)
20157
+{
20158
+    auto *const operand = node.getOperand();
20159
+    ASSERT(operand);
20160
+
20161
+    auto *newOperand = traverseAnyAs<TIntermTyped>(*operand);
20162
+    GUARD(newOperand);
20163
+
20164
+    if (newOperand != operand)
20165
+    {
20166
+        return new TIntermSwizzle(newOperand, node.getSwizzleOffsets());
20167
+    }
20168
+
20169
+    return &node;
20170
+}
20171
+
20172
+TIntermNode *TIntermRebuild::traverseBinaryChildren(TIntermBinary &node)
20173
+{
20174
+    auto *const left = node.getLeft();
20175
+    ASSERT(left);
20176
+    auto *const right = node.getRight();
20177
+    ASSERT(right);
20178
+
20179
+    auto *const newLeft = traverseAnyAs<TIntermTyped>(*left);
20180
+    GUARD(newLeft);
20181
+    auto *const newRight = traverseAnyAs<TIntermTyped>(*right);
20182
+    GUARD(newRight);
20183
+
20184
+    if (newLeft != left || newRight != right)
20185
+    {
20186
+        TOperator op = node.getOp();
20187
+        switch (op)
20188
+        {
20189
+            case TOperator::EOpIndexDirectStruct:
20190
+            {
20191
+                if (newLeft->getType().getInterfaceBlock())
20192
+                {
20193
+                    op = TOperator::EOpIndexDirectInterfaceBlock;
20194
+                }
20195
+            }
20196
+            break;
20197
+
20198
+            case TOperator::EOpIndexDirectInterfaceBlock:
20199
+            {
20200
+                if (newLeft->getType().getStruct())
20201
+                {
20202
+                    op = TOperator::EOpIndexDirectStruct;
20203
+                }
20204
+            }
20205
+            break;
20206
+
20207
+            case TOperator::EOpComma:
20208
+                return TIntermBinary::CreateComma(newLeft, newRight, mCompiler.getShaderVersion());
20209
+
20210
+            default:
20211
+                break;
20212
+        }
20213
+
20214
+        return new TIntermBinary(op, newLeft, newRight);
20215
+    }
20216
+
20217
+    return &node;
20218
+}
20219
+
20220
+TIntermNode *TIntermRebuild::traverseUnaryChildren(TIntermUnary &node)
20221
+{
20222
+    auto *const operand = node.getOperand();
20223
+    ASSERT(operand);
20224
+
20225
+    auto *const newOperand = traverseAnyAs<TIntermTyped>(*operand);
20226
+    GUARD(newOperand);
20227
+
20228
+    if (newOperand != operand)
20229
+    {
20230
+        return new TIntermUnary(node.getOp(), newOperand, node.getFunction());
20231
+    }
20232
+
20233
+    return &node;
20234
+}
20235
+
20236
+TIntermNode *TIntermRebuild::traverseTernaryChildren(TIntermTernary &node)
20237
+{
20238
+    auto *const cond = node.getCondition();
20239
+    ASSERT(cond);
20240
+    auto *const true_ = node.getTrueExpression();
20241
+    ASSERT(true_);
20242
+    auto *const false_ = node.getFalseExpression();
20243
+    ASSERT(false_);
20244
+
20245
+    auto *const newCond = traverseAnyAs<TIntermTyped>(*cond);
20246
+    GUARD(newCond);
20247
+    auto *const newTrue = traverseAnyAs<TIntermTyped>(*true_);
20248
+    GUARD(newTrue);
20249
+    auto *const newFalse = traverseAnyAs<TIntermTyped>(*false_);
20250
+    GUARD(newFalse);
20251
+
20252
+    if (newCond != cond || newTrue != true_ || newFalse != false_)
20253
+    {
20254
+        return new TIntermTernary(newCond, newTrue, newFalse);
20255
+    }
20256
+
20257
+    return &node;
20258
+}
20259
+
20260
+TIntermNode *TIntermRebuild::traverseIfElseChildren(TIntermIfElse &node)
20261
+{
20262
+    auto *const cond = node.getCondition();
20263
+    ASSERT(cond);
20264
+    auto *const true_  = node.getTrueBlock();
20265
+    auto *const false_ = node.getFalseBlock();
20266
+
20267
+    auto *const newCond = traverseAnyAs<TIntermTyped>(*cond);
20268
+    GUARD(newCond);
20269
+    TIntermBlock *newTrue = nullptr;
20270
+    if (true_)
20271
+    {
20272
+        GUARD(traverseAnyAs(*true_, newTrue));
20273
+    }
20274
+    TIntermBlock *newFalse = nullptr;
20275
+    if (false_)
20276
+    {
20277
+        GUARD(traverseAnyAs(*false_, newFalse));
20278
+    }
20279
+
20280
+    if (newCond != cond || newTrue != true_ || newFalse != false_)
20281
+    {
20282
+        return new TIntermIfElse(newCond, newTrue, newFalse);
20283
+    }
20284
+
20285
+    return &node;
20286
+}
20287
+
20288
+TIntermNode *TIntermRebuild::traverseSwitchChildren(TIntermSwitch &node)
20289
+{
20290
+    auto *const init = node.getInit();
20291
+    ASSERT(init);
20292
+    auto *const stmts = node.getStatementList();
20293
+    ASSERT(stmts);
20294
+
20295
+    auto *const newInit = traverseAnyAs<TIntermTyped>(*init);
20296
+    GUARD(newInit);
20297
+    auto *const newStmts = traverseAnyAs<TIntermBlock>(*stmts);
20298
+    GUARD(newStmts);
20299
+
20300
+    if (newInit != init || newStmts != stmts)
20301
+    {
20302
+        return new TIntermSwitch(newInit, newStmts);
20303
+    }
20304
+
20305
+    return &node;
20306
+}
20307
+
20308
+TIntermNode *TIntermRebuild::traverseCaseChildren(TIntermCase &node)
20309
+{
20310
+    auto *const cond = node.getCondition();
20311
+
20312
+    TIntermTyped *newCond = nullptr;
20313
+    if (cond)
20314
+    {
20315
+        GUARD(traverseAnyAs(*cond, newCond));
20316
+    }
20317
+
20318
+    if (newCond != cond)
20319
+    {
20320
+        return new TIntermCase(newCond);
20321
+    }
20322
+
20323
+    return &node;
20324
+}
20325
+
20326
+TIntermNode *TIntermRebuild::traverseFunctionDefinitionChildren(TIntermFunctionDefinition &node)
20327
+{
20328
+    GUARD(!mParentFunc);  // Function definitions cannot be nested.
20329
+    mParentFunc = node.getFunction();
20330
+    struct OnExit
20331
+    {
20332
+        const TFunction *&parentFunc;
20333
+        OnExit(const TFunction *&parentFunc) : parentFunc(parentFunc) {}
20334
+        ~OnExit() { parentFunc = nullptr; }
20335
+    } onExit(mParentFunc);
20336
+
20337
+    auto *const proto = node.getFunctionPrototype();
20338
+    ASSERT(proto);
20339
+    auto *const body = node.getBody();
20340
+    ASSERT(body);
20341
+
20342
+    auto *const newProto = traverseAnyAs<TIntermFunctionPrototype>(*proto);
20343
+    GUARD(newProto);
20344
+    auto *const newBody = traverseAnyAs<TIntermBlock>(*body);
20345
+    GUARD(newBody);
20346
+
20347
+    if (newProto != proto || newBody != body)
20348
+    {
20349
+        return new TIntermFunctionDefinition(newProto, newBody);
20350
+    }
20351
+
20352
+    return &node;
20353
+}
20354
+
20355
+TIntermNode *TIntermRebuild::traverseGlobalQualifierDeclarationChildren(
20356
+    TIntermGlobalQualifierDeclaration &node)
20357
+{
20358
+    auto *const symbol = node.getSymbol();
20359
+    ASSERT(symbol);
20360
+
20361
+    auto *const newSymbol = traverseAnyAs<TIntermSymbol>(*symbol);
20362
+    GUARD(newSymbol);
20363
+
20364
+    if (newSymbol != symbol)
20365
+    {
20366
+        return new TIntermGlobalQualifierDeclaration(newSymbol, node.isPrecise(), node.getLine());
20367
+    }
20368
+
20369
+    return &node;
20370
+}
20371
+
20372
+TIntermNode *TIntermRebuild::traverseLoopChildren(TIntermLoop &node)
20373
+{
20374
+    const TLoopType loopType = node.getType();
20375
+
20376
+    auto *const init = node.getInit();
20377
+    auto *const cond = node.getCondition();
20378
+    auto *const expr = node.getExpression();
20379
+    auto *const body = node.getBody();
20380
+    ASSERT(body);
20381
+
20382
+#if defined(ANGLE_ENABLE_ASSERTS)
20383
+    switch (loopType)
20384
+    {
20385
+        case TLoopType::ELoopFor:
20386
+            break;
20387
+        case TLoopType::ELoopWhile:
20388
+        case TLoopType::ELoopDoWhile:
20389
+            ASSERT(cond);
20390
+            ASSERT(!init && !expr);
20391
+            break;
20392
+    }
20393
+#endif
20394
+
20395
+    auto *const newBody = traverseAnyAs<TIntermBlock>(*body);
20396
+    GUARD(newBody);
20397
+    TIntermNode *newInit = nullptr;
20398
+    if (init)
20399
+    {
20400
+        GUARD(traverseAnyAs(*init, newInit));
20401
+    }
20402
+    TIntermTyped *newCond = nullptr;
20403
+    if (cond)
20404
+    {
20405
+        GUARD(traverseAnyAs(*cond, newCond));
20406
+    }
20407
+    TIntermTyped *newExpr = nullptr;
20408
+    if (expr)
20409
+    {
20410
+        GUARD(traverseAnyAs(*expr, newExpr));
20411
+    }
20412
+
20413
+    if (newInit != init || newCond != cond || newExpr != expr || newBody != body)
20414
+    {
20415
+        switch (loopType)
20416
+        {
20417
+            case TLoopType::ELoopFor:
20418
+                GUARD(newBody);
20419
+                break;
20420
+            case TLoopType::ELoopWhile:
20421
+            case TLoopType::ELoopDoWhile:
20422
+                GUARD(newCond && newBody);
20423
+                GUARD(!newInit && !newExpr);
20424
+                break;
20425
+        }
20426
+        return new TIntermLoop(loopType, newInit, newCond, newExpr, newBody);
20427
+    }
20428
+
20429
+    return &node;
20430
+}
20431
+
20432
+TIntermNode *TIntermRebuild::traverseBranchChildren(TIntermBranch &node)
20433
+{
20434
+    auto *const expr = node.getExpression();
20435
+
20436
+    TIntermTyped *newExpr = nullptr;
20437
+    if (expr)
20438
+    {
20439
+        GUARD(traverseAnyAs<TIntermTyped>(*expr, newExpr));
20440
+    }
20441
+
20442
+    if (newExpr != expr)
20443
+    {
20444
+        return new TIntermBranch(node.getFlowOp(), newExpr);
20445
+    }
20446
+
20447
+    return &node;
20448
+}
20449
+
20450
+////////////////////////////////////////////////////////////////////////////////
20451
+
20452
+PreResult TIntermRebuild::visitSymbolPre(TIntermSymbol &node)
20453
+{
20454
+    return {node, VisitBits::Both};
20455
+}
20456
+
20457
+PreResult TIntermRebuild::visitConstantUnionPre(TIntermConstantUnion &node)
20458
+{
20459
+    return {node, VisitBits::Both};
20460
+}
20461
+
20462
+PreResult TIntermRebuild::visitFunctionPrototypePre(TIntermFunctionPrototype &node)
20463
+{
20464
+    return {node, VisitBits::Both};
20465
+}
20466
+
20467
+PreResult TIntermRebuild::visitPreprocessorDirectivePre(TIntermPreprocessorDirective &node)
20468
+{
20469
+    return {node, VisitBits::Both};
20470
+}
20471
+
20472
+PreResult TIntermRebuild::visitUnaryPre(TIntermUnary &node)
20473
+{
20474
+    return {node, VisitBits::Both};
20475
+}
20476
+
20477
+PreResult TIntermRebuild::visitBinaryPre(TIntermBinary &node)
20478
+{
20479
+    return {node, VisitBits::Both};
20480
+}
20481
+
20482
+PreResult TIntermRebuild::visitTernaryPre(TIntermTernary &node)
20483
+{
20484
+    return {node, VisitBits::Both};
20485
+}
20486
+
20487
+PreResult TIntermRebuild::visitSwizzlePre(TIntermSwizzle &node)
20488
+{
20489
+    return {node, VisitBits::Both};
20490
+}
20491
+
20492
+PreResult TIntermRebuild::visitIfElsePre(TIntermIfElse &node)
20493
+{
20494
+    return {node, VisitBits::Both};
20495
+}
20496
+
20497
+PreResult TIntermRebuild::visitSwitchPre(TIntermSwitch &node)
20498
+{
20499
+    return {node, VisitBits::Both};
20500
+}
20501
+
20502
+PreResult TIntermRebuild::visitCasePre(TIntermCase &node)
20503
+{
20504
+    return {node, VisitBits::Both};
20505
+}
20506
+
20507
+PreResult TIntermRebuild::visitLoopPre(TIntermLoop &node)
20508
+{
20509
+    return {node, VisitBits::Both};
20510
+}
20511
+
20512
+PreResult TIntermRebuild::visitBranchPre(TIntermBranch &node)
20513
+{
20514
+    return {node, VisitBits::Both};
20515
+}
20516
+
20517
+PreResult TIntermRebuild::visitDeclarationPre(TIntermDeclaration &node)
20518
+{
20519
+    return {node, VisitBits::Both};
20520
+}
20521
+
20522
+PreResult TIntermRebuild::visitBlockPre(TIntermBlock &node)
20523
+{
20524
+    return {node, VisitBits::Both};
20525
+}
20526
+
20527
+PreResult TIntermRebuild::visitAggregatePre(TIntermAggregate &node)
20528
+{
20529
+    return {node, VisitBits::Both};
20530
+}
20531
+
20532
+PreResult TIntermRebuild::visitFunctionDefinitionPre(TIntermFunctionDefinition &node)
20533
+{
20534
+    return {node, VisitBits::Both};
20535
+}
20536
+
20537
+PreResult TIntermRebuild::visitGlobalQualifierDeclarationPre(
20538
+    TIntermGlobalQualifierDeclaration &node)
20539
+{
20540
+    return {node, VisitBits::Both};
20541
+}
20542
+
20543
+////////////////////////////////////////////////////////////////////////////////
20544
+
20545
+PostResult TIntermRebuild::visitSymbolPost(TIntermSymbol &node)
20546
+{
20547
+    return node;
20548
+}
20549
+
20550
+PostResult TIntermRebuild::visitConstantUnionPost(TIntermConstantUnion &node)
20551
+{
20552
+    return node;
20553
+}
20554
+
20555
+PostResult TIntermRebuild::visitFunctionPrototypePost(TIntermFunctionPrototype &node)
20556
+{
20557
+    return node;
20558
+}
20559
+
20560
+PostResult TIntermRebuild::visitPreprocessorDirectivePost(TIntermPreprocessorDirective &node)
20561
+{
20562
+    return node;
20563
+}
20564
+
20565
+PostResult TIntermRebuild::visitUnaryPost(TIntermUnary &node)
20566
+{
20567
+    return node;
20568
+}
20569
+
20570
+PostResult TIntermRebuild::visitBinaryPost(TIntermBinary &node)
20571
+{
20572
+    return node;
20573
+}
20574
+
20575
+PostResult TIntermRebuild::visitTernaryPost(TIntermTernary &node)
20576
+{
20577
+    return node;
20578
+}
20579
+
20580
+PostResult TIntermRebuild::visitSwizzlePost(TIntermSwizzle &node)
20581
+{
20582
+    return node;
20583
+}
20584
+
20585
+PostResult TIntermRebuild::visitIfElsePost(TIntermIfElse &node)
20586
+{
20587
+    return node;
20588
+}
20589
+
20590
+PostResult TIntermRebuild::visitSwitchPost(TIntermSwitch &node)
20591
+{
20592
+    return node;
20593
+}
20594
+
20595
+PostResult TIntermRebuild::visitCasePost(TIntermCase &node)
20596
+{
20597
+    return node;
20598
+}
20599
+
20600
+PostResult TIntermRebuild::visitLoopPost(TIntermLoop &node)
20601
+{
20602
+    return node;
20603
+}
20604
+
20605
+PostResult TIntermRebuild::visitBranchPost(TIntermBranch &node)
20606
+{
20607
+    return node;
20608
+}
20609
+
20610
+PostResult TIntermRebuild::visitDeclarationPost(TIntermDeclaration &node)
20611
+{
20612
+    return node;
20613
+}
20614
+
20615
+PostResult TIntermRebuild::visitBlockPost(TIntermBlock &node)
20616
+{
20617
+    return node;
20618
+}
20619
+
20620
+PostResult TIntermRebuild::visitAggregatePost(TIntermAggregate &node)
20621
+{
20622
+    return node;
20623
+}
20624
+
20625
+PostResult TIntermRebuild::visitFunctionDefinitionPost(TIntermFunctionDefinition &node)
20626
+{
20627
+    return node;
20628
+}
20629
+
20630
+PostResult TIntermRebuild::visitGlobalQualifierDeclarationPost(
20631
+    TIntermGlobalQualifierDeclaration &node)
20632
+{
20633
+    return node;
20634
+}
20635
+
20636
+}  // namespace sh
20637
diff --git a/src/compiler/translator/tree_util/IntermRebuild.h b/src/compiler/translator/tree_util/IntermRebuild.h
20638
new file mode 100644
20639
index 0000000..3097e40
20640
--- /dev/null
20641
+++ b/src/compiler/translator/tree_util/IntermRebuild.h
20642
@@ -0,0 +1,328 @@
20643
+//
20644
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
20645
+// Use of this source code is governed by a BSD-style license that can be
20646
+// found in the LICENSE file.
20647
+//
20648
+
20649
+#ifndef COMPILER_TRANSLATOR_TREEUTIL_INTERMREBUILD_H_
20650
+#define COMPILER_TRANSLATOR_TREEUTIL_INTERMREBUILD_H_
20651
+
20652
+#include "compiler/translator/tree_util/IntermTraverse.h"
20653
+#include "compiler/translator/tree_util/NodeType.h"
20654
+
20655
+namespace sh
20656
+{
20657
+
20658
+// Walks the tree to rebuild nodes.
20659
+// This class is intended to be derived with overridden visitXXX functions.
20660
+//
20661
+// Each visitXXX function that does not have a Visit parameter simply has the visitor called
20662
+// exactly once, regardless of (preVisit) or (postVisit) values.
20663
+
20664
+// Each visitXXX function that has a Visit parameter behaves as follows:
20665
+//    * If (preVisit):
20666
+//      - The node is visited before children are traversed.
20667
+//      - The returned value is used to replace the visited node. The returned value may be the same
20668
+//        as the original node.
20669
+//      - If multiple nodes are returned, children and post visits of the returned nodes are not
20670
+//        preformed, even if it is a singleton collection.
20671
+//    * If (childVisit)
20672
+//      - If any new children are returned, the node is automatically rebuilt with the new children
20673
+//        before post visit.
20674
+//      - Depending on the type of the node, null children may be discarded.
20675
+//      - Ill-typed children cause rebuild errors. Ill-typed means the node to automatically rebuild
20676
+//        cannot accept a child of a certain type as input to its constructor.
20677
+//      - Only instances of TIntermAggregateBase can accept Multi results for any of its children.
20678
+//        If supplied, the nodes are spliced children at the spot of the original child.
20679
+//    * If (postVisit)
20680
+//      - The node is visited after any children are traversed.
20681
+//      - Only after such a rebuild (or lack thereof), the post-visit is performed.
20682
+//
20683
+// Nodes in visit functions are allowed to be modified in place, including TIntermAggregateBase
20684
+// child sequences.
20685
+//
20686
+// The default implementations of all the visitXXX functions support full pre and post traversal
20687
+// without modifying the visited nodes.
20688
+//
20689
+class TIntermRebuild : angle::NonCopyable
20690
+{
20691
+
20692
+    enum class Action
20693
+    {
20694
+        ReplaceSingle,
20695
+        ReplaceMulti,
20696
+        Drop,
20697
+        Fail,
20698
+    };
20699
+
20700
+  public:
20701
+    struct Fail
20702
+    {};
20703
+
20704
+    enum VisitBits : size_t
20705
+    {
20706
+        // No bits are set.
20707
+        Empty = 0u,
20708
+
20709
+        // Allow visit of returned node's children.
20710
+        Children = 1u << 0u,
20711
+
20712
+        // Allow post visit of returned node.
20713
+        Post = 1u << 1u,
20714
+
20715
+        // If (Children) bit, only visit if the returned node is the same as the original node.
20716
+        ChildrenRequiresSame = 1u << 2u,
20717
+
20718
+        // If (Post) bit, only visit if the returned node is the same as the original node.
20719
+        PostRequiresSame = 1u << 3u,
20720
+
20721
+        RequireSame  = ChildrenRequiresSame | PostRequiresSame,
20722
+        Neither      = Empty,
20723
+        Both         = Children | Post,
20724
+        BothWhenSame = Both | RequireSame,
20725
+    };
20726
+
20727
+  private:
20728
+    struct NodeStackGuard;
20729
+
20730
+    template <typename T>
20731
+    struct ConsList
20732
+    {
20733
+        T value;
20734
+        ConsList<T> *tail;
20735
+    };
20736
+
20737
+    class BaseResult
20738
+    {
20739
+        BaseResult(const BaseResult &) = delete;
20740
+        BaseResult &operator=(const BaseResult &) = delete;
20741
+
20742
+      public:
20743
+        BaseResult(BaseResult &&other) = default;
20744
+        BaseResult(BaseResult &other);  // For subclass move constructor impls
20745
+        BaseResult(TIntermNode &node, VisitBits visit);
20746
+        BaseResult(TIntermNode *node, VisitBits visit);
20747
+        BaseResult(nullptr_t);
20748
+        BaseResult(Fail);
20749
+        BaseResult(std::vector<TIntermNode *> &&nodes);
20750
+
20751
+        void moveAssignImpl(BaseResult &other);  // For subclass move assign impls
20752
+
20753
+        static BaseResult Multi(std::vector<TIntermNode *> &&nodes);
20754
+
20755
+        template <typename Iter>
20756
+        static BaseResult Multi(Iter nodesBegin, Iter nodesEnd)
20757
+        {
20758
+            std::vector<TIntermNode *> nodes;
20759
+            for (Iter nodesCurr = nodesBegin; nodesCurr != nodesEnd; ++nodesCurr)
20760
+            {
20761
+                nodes.push_back(*nodesCurr);
20762
+            }
20763
+            return std::move(nodes);
20764
+        }
20765
+
20766
+        bool isFail() const;
20767
+        bool isDrop() const;
20768
+        TIntermNode *single() const;
20769
+        const std::vector<TIntermNode *> *multi() const;
20770
+
20771
+      public:
20772
+        Action mAction;
20773
+        VisitBits mVisit;
20774
+        TIntermNode *mSingle;
20775
+        std::vector<TIntermNode *> mMulti;
20776
+    };
20777
+
20778
+  public:
20779
+    class PreResult : private BaseResult
20780
+    {
20781
+        friend class TIntermRebuild;
20782
+
20783
+      public:
20784
+        PreResult(PreResult &&other);
20785
+        PreResult(TIntermNode &node, VisitBits visit = VisitBits::BothWhenSame);
20786
+        PreResult(TIntermNode *node, VisitBits visit = VisitBits::BothWhenSame);
20787
+        PreResult(nullptr_t);  // Used to drop a node.
20788
+        PreResult(Fail);       // Used to signal failure.
20789
+
20790
+        void operator=(PreResult &&other);
20791
+
20792
+        static PreResult Multi(std::vector<TIntermNode *> &&nodes)
20793
+        {
20794
+            return BaseResult::Multi(std::move(nodes));
20795
+        }
20796
+
20797
+        template <typename Iter>
20798
+        static PreResult Multi(Iter nodesBegin, Iter nodesEnd)
20799
+        {
20800
+            return BaseResult::Multi(nodesBegin, nodesEnd);
20801
+        }
20802
+
20803
+        using BaseResult::isDrop;
20804
+        using BaseResult::isFail;
20805
+        using BaseResult::multi;
20806
+        using BaseResult::single;
20807
+
20808
+      private:
20809
+        PreResult(BaseResult &&other);
20810
+    };
20811
+
20812
+    class PostResult : private BaseResult
20813
+    {
20814
+        friend class TIntermRebuild;
20815
+
20816
+      public:
20817
+        PostResult(PostResult &&other);
20818
+        PostResult(TIntermNode &node);
20819
+        PostResult(TIntermNode *node);
20820
+        PostResult(nullptr_t);  // Used to drop a node
20821
+        PostResult(Fail);       // Used to signal failure.
20822
+
20823
+        void operator=(PostResult &&other);
20824
+
20825
+        static PostResult Multi(std::vector<TIntermNode *> &&nodes)
20826
+        {
20827
+            return BaseResult::Multi(std::move(nodes));
20828
+        }
20829
+
20830
+        template <typename Iter>
20831
+        static PostResult Multi(Iter nodesBegin, Iter nodesEnd)
20832
+        {
20833
+            return BaseResult::Multi(nodesBegin, nodesEnd);
20834
+        }
20835
+
20836
+        using BaseResult::isDrop;
20837
+        using BaseResult::isFail;
20838
+        using BaseResult::multi;
20839
+        using BaseResult::single;
20840
+
20841
+      private:
20842
+        PostResult(BaseResult &&other);
20843
+    };
20844
+
20845
+  public:
20846
+    TIntermRebuild(TCompiler &compiler, bool preVisit, bool postVisit);
20847
+
20848
+    virtual ~TIntermRebuild();
20849
+
20850
+    // Rebuilds the tree starting at the provided root. If a new node would be returned for the
20851
+    // root, the root node's children become that of the new node instead. Returns false if failure
20852
+    // occurred.
20853
+    ANGLE_NO_DISCARD bool rebuildRoot(TIntermBlock &root);
20854
+
20855
+  protected:
20856
+    virtual PreResult visitSymbolPre(TIntermSymbol &node);
20857
+    virtual PreResult visitConstantUnionPre(TIntermConstantUnion &node);
20858
+    virtual PreResult visitFunctionPrototypePre(TIntermFunctionPrototype &node);
20859
+    virtual PreResult visitPreprocessorDirectivePre(TIntermPreprocessorDirective &node);
20860
+    virtual PreResult visitUnaryPre(TIntermUnary &node);
20861
+    virtual PreResult visitBinaryPre(TIntermBinary &node);
20862
+    virtual PreResult visitTernaryPre(TIntermTernary &node);
20863
+    virtual PreResult visitSwizzlePre(TIntermSwizzle &node);
20864
+    virtual PreResult visitIfElsePre(TIntermIfElse &node);
20865
+    virtual PreResult visitSwitchPre(TIntermSwitch &node);
20866
+    virtual PreResult visitCasePre(TIntermCase &node);
20867
+    virtual PreResult visitLoopPre(TIntermLoop &node);
20868
+    virtual PreResult visitBranchPre(TIntermBranch &node);
20869
+    virtual PreResult visitDeclarationPre(TIntermDeclaration &node);
20870
+    virtual PreResult visitBlockPre(TIntermBlock &node);
20871
+    virtual PreResult visitAggregatePre(TIntermAggregate &node);
20872
+    virtual PreResult visitFunctionDefinitionPre(TIntermFunctionDefinition &node);
20873
+    virtual PreResult visitGlobalQualifierDeclarationPre(TIntermGlobalQualifierDeclaration &node);
20874
+
20875
+    virtual PostResult visitSymbolPost(TIntermSymbol &node);
20876
+    virtual PostResult visitConstantUnionPost(TIntermConstantUnion &node);
20877
+    virtual PostResult visitFunctionPrototypePost(TIntermFunctionPrototype &node);
20878
+    virtual PostResult visitPreprocessorDirectivePost(TIntermPreprocessorDirective &node);
20879
+    virtual PostResult visitUnaryPost(TIntermUnary &node);
20880
+    virtual PostResult visitBinaryPost(TIntermBinary &node);
20881
+    virtual PostResult visitTernaryPost(TIntermTernary &node);
20882
+    virtual PostResult visitSwizzlePost(TIntermSwizzle &node);
20883
+    virtual PostResult visitIfElsePost(TIntermIfElse &node);
20884
+    virtual PostResult visitSwitchPost(TIntermSwitch &node);
20885
+    virtual PostResult visitCasePost(TIntermCase &node);
20886
+    virtual PostResult visitLoopPost(TIntermLoop &node);
20887
+    virtual PostResult visitBranchPost(TIntermBranch &node);
20888
+    virtual PostResult visitDeclarationPost(TIntermDeclaration &node);
20889
+    virtual PostResult visitBlockPost(TIntermBlock &node);
20890
+    virtual PostResult visitAggregatePost(TIntermAggregate &node);
20891
+    virtual PostResult visitFunctionDefinitionPost(TIntermFunctionDefinition &node);
20892
+    virtual PostResult visitGlobalQualifierDeclarationPost(TIntermGlobalQualifierDeclaration &node);
20893
+
20894
+    // Can be used to rebuild a specific node during a traversal. Useful for fine control of
20895
+    // rebuilding a node's children.
20896
+    ANGLE_NO_DISCARD PostResult rebuild(TIntermNode &node);
20897
+
20898
+    // Rebuilds the provided node in place. If a new node would be returned, the old node's children
20899
+    // become that of the new node instead. Returns false if failure occurred.
20900
+    ANGLE_NO_DISCARD bool rebuildInPlace(TIntermAggregate &node);
20901
+
20902
+    // Rebuilds the provided node in place. If a new node would be returned, the old node's children
20903
+    // become that of the new node instead. Returns false if failure occurred.
20904
+    ANGLE_NO_DISCARD bool rebuildInPlace(TIntermBlock &node);
20905
+
20906
+    // Rebuilds the provided node in place. If a new node would be returned, the old node's children
20907
+    // become that of the new node instead. Returns false if failure occurred.
20908
+    ANGLE_NO_DISCARD bool rebuildInPlace(TIntermDeclaration &node);
20909
+
20910
+    // If currently at or below a function declaration body, this returns the function that encloses
20911
+    // the currently visited node. (This returns null if at a function declaration node.)
20912
+    const TFunction *getParentFunction() const;
20913
+
20914
+    TIntermNode *getParentNode(size_t offset = 0) const;
20915
+
20916
+  private:
20917
+    template <typename Node>
20918
+    ANGLE_NO_DISCARD bool rebuildInPlaceImpl(Node &node);
20919
+
20920
+    PostResult traverseAny(TIntermNode &node);
20921
+
20922
+    template <typename Node>
20923
+    Node *traverseAnyAs(TIntermNode &node);
20924
+
20925
+    template <typename Node>
20926
+    bool traverseAnyAs(TIntermNode &node, Node *&out);
20927
+
20928
+    PreResult traversePre(TIntermNode &originalNode);
20929
+    TIntermNode *traverseChildren(NodeType currNodeType,
20930
+                                  const TIntermNode &originalNode,
20931
+                                  TIntermNode &currNode,
20932
+                                  VisitBits visit);
20933
+    PostResult traversePost(NodeType nodeType,
20934
+                            const TIntermNode &originalNode,
20935
+                            TIntermNode &currNode,
20936
+                            VisitBits visit);
20937
+
20938
+    bool traverseAggregateBaseChildren(TIntermAggregateBase &node);
20939
+
20940
+    TIntermNode *traverseUnaryChildren(TIntermUnary &node);
20941
+    TIntermNode *traverseBinaryChildren(TIntermBinary &node);
20942
+    TIntermNode *traverseTernaryChildren(TIntermTernary &node);
20943
+    TIntermNode *traverseSwizzleChildren(TIntermSwizzle &node);
20944
+    TIntermNode *traverseIfElseChildren(TIntermIfElse &node);
20945
+    TIntermNode *traverseSwitchChildren(TIntermSwitch &node);
20946
+    TIntermNode *traverseCaseChildren(TIntermCase &node);
20947
+    TIntermNode *traverseLoopChildren(TIntermLoop &node);
20948
+    TIntermNode *traverseBranchChildren(TIntermBranch &node);
20949
+    TIntermNode *traverseDeclarationChildren(TIntermDeclaration &node);
20950
+    TIntermNode *traverseBlockChildren(TIntermBlock &node);
20951
+    TIntermNode *traverseAggregateChildren(TIntermAggregate &node);
20952
+    TIntermNode *traverseFunctionDefinitionChildren(TIntermFunctionDefinition &node);
20953
+    TIntermNode *traverseGlobalQualifierDeclarationChildren(
20954
+        TIntermGlobalQualifierDeclaration &node);
20955
+
20956
+  protected:
20957
+    TCompiler &mCompiler;
20958
+    TSymbolTable &mSymbolTable;
20959
+    const TFunction *mParentFunc = nullptr;
20960
+    GetNodeType getNodeType;
20961
+
20962
+  private:
20963
+    ConsList<TIntermNode *> mNodeStack{nullptr, nullptr};
20964
+    bool mPreVisit;
20965
+    bool mPostVisit;
20966
+};
20967
+
20968
+}  // namespace sh
20969
+
20970
+#endif  // COMPILER_TRANSLATOR_TREEUTIL_INTERMREBUILD_H_
20971
diff --git a/src/compiler/translator/tree_util/NodeType.h b/src/compiler/translator/tree_util/NodeType.h
20972
new file mode 100644
20973
index 0000000..a59e5af
20974
--- /dev/null
20975
+++ b/src/compiler/translator/tree_util/NodeType.h
20976
@@ -0,0 +1,155 @@
20977
+//
20978
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
20979
+// Use of this source code is governed by a BSD-style license that can be
20980
+// found in the LICENSE file.
20981
+//
20982
+
20983
+#ifndef COMPILER_TRANSLATOR_TREEUTIL_NODETYPE_H_
20984
+#define COMPILER_TRANSLATOR_TREEUTIL_NODETYPE_H_
20985
+
20986
+#include "compiler/translator/tree_util/IntermTraverse.h"
20987
+
20988
+namespace sh
20989
+{
20990
+
20991
+enum class NodeType
20992
+{
20993
+    Unknown,
20994
+    Symbol,
20995
+    ConstantUnion,
20996
+    FunctionPrototype,
20997
+    PreprocessorDirective,
20998
+    Unary,
20999
+    Binary,
21000
+    Ternary,
21001
+    Swizzle,
21002
+    IfElse,
21003
+    Switch,
21004
+    Case,
21005
+    FunctionDefinition,
21006
+    Aggregate,
21007
+    Block,
21008
+    GlobalQualifierDeclaration,
21009
+    Declaration,
21010
+    Loop,
21011
+    Branch,
21012
+};
21013
+
21014
+// This is a function like object instead of a function that stack allocates this because
21015
+// TIntermTraverser is a heavy object to construct.
21016
+class GetNodeType : private TIntermTraverser
21017
+{
21018
+    NodeType nodeType;
21019
+
21020
+  public:
21021
+    GetNodeType() : TIntermTraverser(true, false, false) {}
21022
+
21023
+    NodeType operator()(TIntermNode &node)
21024
+    {
21025
+        node.visit(Visit::PreVisit, this);
21026
+        return nodeType;
21027
+    }
21028
+
21029
+  private:
21030
+    void visitSymbol(TIntermSymbol *) override { nodeType = NodeType::Symbol; }
21031
+
21032
+    void visitConstantUnion(TIntermConstantUnion *) override { nodeType = NodeType::ConstantUnion; }
21033
+
21034
+    void visitFunctionPrototype(TIntermFunctionPrototype *) override
21035
+    {
21036
+        nodeType = NodeType::FunctionPrototype;
21037
+    }
21038
+
21039
+    void visitPreprocessorDirective(TIntermPreprocessorDirective *) override
21040
+    {
21041
+        nodeType = NodeType::PreprocessorDirective;
21042
+    }
21043
+
21044
+    bool visitSwizzle(Visit, TIntermSwizzle *) override
21045
+    {
21046
+        nodeType = NodeType::Swizzle;
21047
+        return false;
21048
+    }
21049
+
21050
+    bool visitBinary(Visit, TIntermBinary *) override
21051
+    {
21052
+        nodeType = NodeType::Binary;
21053
+        return false;
21054
+    }
21055
+
21056
+    bool visitUnary(Visit, TIntermUnary *) override
21057
+    {
21058
+        nodeType = NodeType::Unary;
21059
+        return false;
21060
+    }
21061
+
21062
+    bool visitTernary(Visit, TIntermTernary *) override
21063
+    {
21064
+        nodeType = NodeType::Ternary;
21065
+        return false;
21066
+    }
21067
+
21068
+    bool visitIfElse(Visit, TIntermIfElse *) override
21069
+    {
21070
+        nodeType = NodeType::IfElse;
21071
+        return false;
21072
+    }
21073
+
21074
+    bool visitSwitch(Visit, TIntermSwitch *) override
21075
+    {
21076
+        nodeType = NodeType::Switch;
21077
+        return false;
21078
+    }
21079
+
21080
+    bool visitCase(Visit, TIntermCase *) override
21081
+    {
21082
+        nodeType = NodeType::Case;
21083
+        return false;
21084
+    }
21085
+
21086
+    bool visitFunctionDefinition(Visit, TIntermFunctionDefinition *) override
21087
+    {
21088
+        nodeType = NodeType::FunctionDefinition;
21089
+        return false;
21090
+    }
21091
+
21092
+    bool visitAggregate(Visit, TIntermAggregate *) override
21093
+    {
21094
+        nodeType = NodeType::Aggregate;
21095
+        return false;
21096
+    }
21097
+
21098
+    bool visitBlock(Visit, TIntermBlock *) override
21099
+    {
21100
+        nodeType = NodeType::Block;
21101
+        return false;
21102
+    }
21103
+
21104
+    bool visitGlobalQualifierDeclaration(Visit, TIntermGlobalQualifierDeclaration *) override
21105
+    {
21106
+        nodeType = NodeType::GlobalQualifierDeclaration;
21107
+        return false;
21108
+    }
21109
+
21110
+    bool visitDeclaration(Visit, TIntermDeclaration *) override
21111
+    {
21112
+        nodeType = NodeType::Declaration;
21113
+        return false;
21114
+    }
21115
+
21116
+    bool visitLoop(Visit, TIntermLoop *) override
21117
+    {
21118
+        nodeType = NodeType::Loop;
21119
+        return false;
21120
+    }
21121
+
21122
+    bool visitBranch(Visit, TIntermBranch *) override
21123
+    {
21124
+        nodeType = NodeType::Branch;
21125
+        return false;
21126
+    }
21127
+};
21128
+
21129
+}  // namespace sh
21130
+
21131
+#endif  // COMPILER_TRANSLATOR_TREEUTIL_NODETYPE_H_
21132
diff --git a/src/compiler/translator/util.cpp b/src/compiler/translator/util.cpp
21133
index 346470e..582ddc7 100644
21134
--- a/src/compiler/translator/util.cpp
21135
+++ b/src/compiler/translator/util.cpp
21136
@@ -804,6 +804,10 @@ bool IsOutputMetal(ShShaderOutput output)
21137
 {
21138
     return output == SH_GLSL_METAL_OUTPUT;
21139
 }
21140
+bool IsOutputMetalDirect(ShShaderOutput output)
21141
+{
21142
+    return output == SH_MSL_METAL_OUTPUT;
21143
+}
21144
 
21145
 bool IsInShaderStorageBlock(TIntermTyped *node)
21146
 {
21147
diff --git a/src/compiler/translator/util.h b/src/compiler/translator/util.h
21148
index 53ee755..f9ae9bb 100644
21149
--- a/src/compiler/translator/util.h
21150
+++ b/src/compiler/translator/util.h
21151
@@ -77,6 +77,7 @@ bool IsOutputGLSL(ShShaderOutput output);
21152
 bool IsOutputHLSL(ShShaderOutput output);
21153
 bool IsOutputVulkan(ShShaderOutput output);
21154
 bool IsOutputMetal(ShShaderOutput output);
21155
+bool IsOutputMetalDirect(ShShaderOutput output);
21156
 
21157
 bool IsInShaderStorageBlock(TIntermTyped *node);
21158
 
21159
diff --git a/src/gpu_info_util/SystemInfo.cpp b/src/gpu_info_util/SystemInfo.cpp
21160
index f748949..54c3db5 100644
21161
--- a/src/gpu_info_util/SystemInfo.cpp
21162
+++ b/src/gpu_info_util/SystemInfo.cpp
21163
@@ -47,6 +47,8 @@ std::string VendorName(VendorID vendor)
21164
             return "Vivante";
21165
         case kVendorID_VMWare:
21166
             return "VMWare";
21167
+        case kVendorID_Apple:
21168
+            return "Apple";
21169
         default:
21170
             return "Unknown (" + std::to_string(vendor) + ")";
21171
     }
21172
@@ -160,6 +162,11 @@ bool IsVivante(VendorID vendorId)
21173
     return vendorId == kVendorID_Vivante;
21174
 }
21175
 
21176
+bool IsApple(VendorID vendorId)
21177
+{
21178
+    return vendorId == kVendorID_Apple;
21179
+}
21180
+
21181
 bool ParseAMDBrahmaDriverVersion(const std::string &content, std::string *version)
21182
 {
21183
     const size_t begin = content.find_first_of("0123456789");
21184
diff --git a/src/gpu_info_util/SystemInfo.h b/src/gpu_info_util/SystemInfo.h
21185
index ad17698..509a1e9 100644
21186
--- a/src/gpu_info_util/SystemInfo.h
21187
+++ b/src/gpu_info_util/SystemInfo.h
21188
@@ -67,9 +67,8 @@ struct SystemInfo
21189
     bool isAMDSwitchable = false;
21190
     // Only true on dual-GPU Mac laptops.
21191
     bool isMacSwitchable = false;
21192
-    // Only true on Apple Silicon Macs when running iOS binaries.
21193
-    // See https://developer.apple.com/documentation/foundation/nsprocessinfo/3608556-iosapponmac
21194
-    bool isiOSAppOnMac = false;
21195
+    // Only true on Apple Silicon Macs when running in macCatalyst.
21196
+    bool needsEAGLOnMac   = false;
21197
 
21198
     // Only available on Android
21199
     std::string machineManufacturer;
21200
@@ -99,6 +98,7 @@ constexpr VendorID kVendorID_Intel    = 0x8086;
21201
 constexpr VendorID kVendorID_NVIDIA   = 0x10DE;
21202
 constexpr VendorID kVendorID_Qualcomm = 0x5143;
21203
 constexpr VendorID kVendorID_VMWare   = 0x15ad;
21204
+constexpr VendorID kVendorID_Apple    = 0x106B;
21205
 
21206
 // Known non-PCI (i.e. Khronos-registered) vendor IDs
21207
 constexpr VendorID kVendorID_Vivante     = 0x10001;
21208
@@ -124,6 +124,7 @@ bool IsSwiftshader(VendorID vendorId);
21209
 bool IsVeriSilicon(VendorID vendorId);
21210
 bool IsVMWare(VendorID vendorId);
21211
 bool IsVivante(VendorID vendorId);
21212
+bool IsApple(VendorID vendorId);
21213
 
21214
 // Use a heuristic to attempt to find the GPU used for 3D graphics. Sets activeGPUIndex,
21215
 // isOptimus, and isAMDSwitchable.
21216
diff --git a/src/gpu_info_util/SystemInfo_apple.mm b/src/gpu_info_util/SystemInfo_apple.mm
21217
index c7756f6..1500fff 100644
21218
--- a/src/gpu_info_util/SystemInfo_apple.mm
21219
+++ b/src/gpu_info_util/SystemInfo_apple.mm
21220
@@ -1,5 +1,5 @@
21221
 //
21222
-// Copyright 2020 The ANGLE Project Authors. All rights reserved.
21223
+// Copyright 2020 Apple, Inc. All rights reserved.
21224
 // Use of this source code is governed by a BSD-style license that can be
21225
 // found in the LICENSE file.
21226
 //
21227
diff --git a/src/gpu_info_util/SystemInfo_ios.cpp b/src/gpu_info_util/SystemInfo_ios.cpp
21228
index 323af2c..7a9d9fa 100644
21229
--- a/src/gpu_info_util/SystemInfo_ios.cpp
21230
+++ b/src/gpu_info_util/SystemInfo_ios.cpp
21231
@@ -18,8 +18,16 @@ namespace angle
21232
 bool GetSystemInfo_ios(SystemInfo *info)
21233
 {
21234
     {
21235
+        //        GPUDeviceInfo deviceInfo;
21236
+        //        deviceInfo.vendorId      = kVendorID_Apple;
21237
+        //        deviceInfo.deviceId      = 0;
21238
+        //        deviceInfo.driverVendor  = "Apple";
21239
+        //        deviceInfo.driverVersion = "0.0";
21240
+        //        deviceInfo.driverDate    = "1/1/1970";
21241
+
21242
         // TODO(anglebug.com/4275): Get the actual system version.
21243
         info->machineModelVersion = "0.0";
21244
+        // info->gpus.push_back(deviceInfo);
21245
     }
21246
 
21247
     return true;
21248
diff --git a/src/gpu_info_util/SystemInfo_macos.mm b/src/gpu_info_util/SystemInfo_macos.mm
21249
index b1cd055..c5e039e 100644
21250
--- a/src/gpu_info_util/SystemInfo_macos.mm
21251
+++ b/src/gpu_info_util/SystemInfo_macos.mm
21252
@@ -322,6 +322,10 @@ bool GetSystemInfo_mac(SystemInfo *info)
21253
         info->isMacSwitchable = true;
21254
     }
21255
     
21256
+#if defined(ANGLE_PLATFORM_MACCATALYST) && defined(ANGLE_CPU_ARM64)
21257
+    info->needsEAGLOnMac = true;
21258
+#endif
21259
+
21260
     return true;
21261
 }
21262
 
21263
diff --git a/src/libANGLE/Caps.cpp b/src/libANGLE/Caps.cpp
21264
index f906783..7931009 100644
21265
--- a/src/libANGLE/Caps.cpp
21266
+++ b/src/libANGLE/Caps.cpp
21267
@@ -170,8 +170,8 @@ static bool GetFormatSupportBase(const TextureCapsMap &textureCaps,
21268
 {
21269
     for (size_t i = 0; i < requiredFormatsSize; i++)
21270
     {
21271
-        const TextureCaps &cap = textureCaps.get(requiredFormats[i]);
21272
 
21273
+        const TextureCaps &cap = textureCaps.get(requiredFormats[i]);
21274
         if (requiresTexturing && !cap.texturable)
21275
         {
21276
             return false;
21277
@@ -462,7 +462,6 @@ static bool DetermineASTCLDRTextureSupport(const TextureCapsMap &textureCaps)
21278
         GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR,  GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR,
21279
         GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR,
21280
     };
21281
-
21282
     return GetFormatSupport(textureCaps, requiredFormats, true, true, false, false, false);
21283
 }
21284
 
21285
diff --git a/src/libANGLE/Display.cpp b/src/libANGLE/Display.cpp
21286
index dde4337..657814f 100644
21287
--- a/src/libANGLE/Display.cpp
21288
+++ b/src/libANGLE/Display.cpp
21289
@@ -181,7 +181,13 @@ EGLAttrib GetDisplayTypeFromEnvironment()
21290
         return EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE;
21291
     }
21292
 #endif
21293
+#if defined(ANGLE_ENABLE_METAL)
21294
+    if (angleDefaultEnv == "metal")
21295
+    {
21296
+        return EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE;
21297
+    }
21298
 
21299
+#endif
21300
 #if defined(ANGLE_ENABLE_D3D11)
21301
     return EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE;
21302
 #elif defined(ANGLE_ENABLE_D3D9)
21303
@@ -1325,6 +1331,47 @@ Error Display::makeCurrent(gl::Context *previousContext,
21304
     return NoError();
21305
 }
21306
 
21307
+Error Display::makeCurrent(const Thread *thread,
21308
+                           egl::Surface *drawSurface,
21309
+                           egl::Surface *readSurface,
21310
+                           gl::Context *context)
21311
+{
21312
+    if (!mInitialized)
21313
+    {
21314
+        return NoError();
21315
+    }
21316
+
21317
+    gl::Context *previousContext = thread->getContext();
21318
+    if (previousContext)
21319
+    {
21320
+        ANGLE_TRY(previousContext->unMakeCurrent(this));
21321
+    }
21322
+
21323
+    ANGLE_TRY(mImplementation->makeCurrent(this, drawSurface, readSurface, context));
21324
+
21325
+    if (context != nullptr)
21326
+    {
21327
+        ANGLE_TRY(context->makeCurrent(this, drawSurface, readSurface));
21328
+    }
21329
+
21330
+    // Tick all the scratch buffers to make sure they get cleaned up eventually if they stop being
21331
+    // used.
21332
+    {
21333
+        std::lock_guard<std::mutex> lock(mScratchBufferMutex);
21334
+
21335
+        for (angle::ScratchBuffer &scatchBuffer : mScratchBuffers)
21336
+        {
21337
+            scatchBuffer.tick();
21338
+        }
21339
+        for (angle::ScratchBuffer &zeroFilledBuffer : mZeroFilledBuffers)
21340
+        {
21341
+            zeroFilledBuffer.tick();
21342
+        }
21343
+    }
21344
+
21345
+    return NoError();
21346
+}
21347
+
21348
 Error Display::restoreLostDevice()
21349
 {
21350
     for (ContextSet::iterator ctx = mContextSet.begin(); ctx != mContextSet.end(); ctx++)
21351
diff --git a/src/libANGLE/Display.h b/src/libANGLE/Display.h
21352
index 4ac6336..16faf2b 100644
21353
--- a/src/libANGLE/Display.h
21354
+++ b/src/libANGLE/Display.h
21355
@@ -166,6 +166,11 @@ class Display final : public LabeledObject,
21356
                         const AttributeMap &attribs,
21357
                         gl::Context **outContext);
21358
 
21359
+    Error makeCurrent(const Thread *thread,
21360
+                      Surface *drawSurface,
21361
+                      Surface *readSurface,
21362
+                      gl::Context *context);
21363
+
21364
     Error createSync(const gl::Context *currentContext,
21365
                      EGLenum type,
21366
                      const AttributeMap &attribs,
21367
diff --git a/src/libANGLE/Program.h b/src/libANGLE/Program.h
21368
index fe3ec28..ba9267a 100644
21369
--- a/src/libANGLE/Program.h
21370
+++ b/src/libANGLE/Program.h
21371
@@ -276,6 +276,11 @@ class ProgramState final : angle::NonCopyable
21372
     {
21373
         return mExecutable->getLinkedTransformFeedbackVaryings();
21374
     }
21375
+    void setLinkedTransformFeedbackVaryings(
21376
+        const std::vector<TransformFeedbackVarying> _mLinkedTransformFeedbackVaryings) const
21377
+    {
21378
+        return mExecutable->setLinkedTransformFeedbackVaryings(_mLinkedTransformFeedbackVaryings);
21379
+    }
21380
     const std::vector<GLsizei> &getTransformFeedbackStrides() const
21381
     {
21382
         return mExecutable->getTransformFeedbackStrides();
21383
diff --git a/src/libANGLE/ProgramExecutable.h b/src/libANGLE/ProgramExecutable.h
21384
index 950832b..48f3bd2 100644
21385
--- a/src/libANGLE/ProgramExecutable.h
21386
+++ b/src/libANGLE/ProgramExecutable.h
21387
@@ -229,6 +229,11 @@ class ProgramExecutable final : public angle::Subject
21388
     {
21389
         return mLinkedTransformFeedbackVaryings;
21390
     }
21391
+    void setLinkedTransformFeedbackVaryings(
21392
+        const std::vector<TransformFeedbackVarying> _mLinkedTransformFeedbackVaryings)
21393
+    {
21394
+        mLinkedTransformFeedbackVaryings = _mLinkedTransformFeedbackVaryings;
21395
+    }
21396
     GLint getTransformFeedbackBufferMode() const { return mTransformFeedbackBufferMode; }
21397
     GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const
21398
     {
21399
diff --git a/src/libANGLE/Shader.cpp b/src/libANGLE/Shader.cpp
21400
index 6f9a78a..96006d9 100644
21401
--- a/src/libANGLE/Shader.cpp
21402
+++ b/src/libANGLE/Shader.cpp
21403
@@ -655,7 +655,9 @@ std::string Shader::getTransformFeedbackVaryingMappedName(const std::string &tfV
21404
             {
21405
                 GLuint fieldIndex = 0;
21406
                 const auto *field = varying.findField(tfVaryingName, &fieldIndex);
21407
-                ASSERT(field != nullptr && !field->isStruct() && !field->isArray());
21408
+                if (!field)
21409
+                    continue;
21410
+                ASSERT(!field->isStruct() && !field->isArray());
21411
                 return varying.mappedName + "." + field->mappedName;
21412
             }
21413
         }
21414
diff --git a/src/libANGLE/State.cpp b/src/libANGLE/State.cpp
21415
index 7b08d8d..a804486 100644
21416
--- a/src/libANGLE/State.cpp
21417
+++ b/src/libANGLE/State.cpp
21418
@@ -6,6 +6,9 @@
21419
 
21420
 // State.cpp: Implements the State class, encapsulating raw GL state.
21421
 
21422
+// Older clang versions have a false positive on this warning here.
21423
+#pragma clang diagnostic ignored "-Wglobal-constructors"
21424
+
21425
 #include "libANGLE/State.h"
21426
 
21427
 #include <string.h>
21428
diff --git a/src/libANGLE/formatutils.cpp b/src/libANGLE/formatutils.cpp
21429
index 3f9f37d..5e628f2 100644
21430
--- a/src/libANGLE/formatutils.cpp
21431
+++ b/src/libANGLE/formatutils.cpp
21432
@@ -1034,7 +1034,7 @@ static InternalFormatInfoMap BuildInternalFormatInfoMap()
21433
     angle::SystemInfo info;
21434
     if (angle::GetSystemInfo(&info))
21435
     {
21436
-        if (info.isiOSAppOnMac)
21437
+        if (info.needsEAGLOnMac)
21438
         {
21439
             // Using OpenGLES.framework.
21440
             AddRGBAFormat(&map, GL_BGRA_EXT,       false,  8,  8,  8,  8, 0, GL_BGRA_EXT,       GL_UNSIGNED_BYTE,               GL_UNSIGNED_NORMALIZED, false, RequireES<2, 0>,                                  AlwaysSupported, RequireES<2, 0>,                                NeverSupported, NeverSupported);
21441
diff --git a/src/libANGLE/renderer/driver_utils.cpp b/src/libANGLE/renderer/driver_utils.cpp
21442
index d4c6aed..22364b3 100644
21443
--- a/src/libANGLE/renderer/driver_utils.cpp
21444
+++ b/src/libANGLE/renderer/driver_utils.cpp
21445
@@ -205,7 +205,7 @@ bool operator>=(const OSVersion &a, const OSVersion &b)
21446
            std::tie(b.majorVersion, b.minorVersion, b.patchVersion);
21447
 }
21448
 
21449
-#if !defined(ANGLE_PLATFORM_APPLE)
21450
+#if !defined(ANGLE_PLATFORM_MACOS)
21451
 OSVersion GetMacOSVersion()
21452
 {
21453
     // Return a default version
21454
@@ -213,6 +213,14 @@ OSVersion GetMacOSVersion()
21455
 }
21456
 #endif
21457
 
21458
+#if !defined(ANGLE_PLATFORM_IOS)
21459
+OSVersion GetiOSVersion()
21460
+{
21461
+    // Return a default version
21462
+    return OSVersion(0, 0, 0);
21463
+}
21464
+#endif
21465
+
21466
 #if defined(ANGLE_PLATFORM_LINUX)
21467
 bool ParseLinuxOSVersion(const char *version, int *major, int *minor, int *patch)
21468
 {
21469
diff --git a/src/libANGLE/renderer/driver_utils.h b/src/libANGLE/renderer/driver_utils.h
21470
index 2619bc3..78772ae 100644
21471
--- a/src/libANGLE/renderer/driver_utils.h
21472
+++ b/src/libANGLE/renderer/driver_utils.h
21473
@@ -167,6 +167,15 @@ inline bool IsApple()
21474
 #endif
21475
 }
21476
 
21477
+inline bool IsMac()
21478
+{
21479
+#if defined(ANGLE_PLATFORM_APPLE) && defined(ANGLE_PLATFORM_MACOS)
21480
+    return true;
21481
+#else
21482
+    return false;
21483
+#endif
21484
+}
21485
+
21486
 inline bool IsFuchsia()
21487
 {
21488
 #if defined(ANGLE_PLATFORM_FUCHSIA)
21489
@@ -204,6 +213,8 @@ bool operator>=(const OSVersion &a, const OSVersion &b);
21490
 
21491
 OSVersion GetMacOSVersion();
21492
 
21493
+OSVersion GetiOSVersion();
21494
+
21495
 OSVersion GetLinuxOSVersion();
21496
 
21497
 inline bool IsAndroid()
21498
diff --git a/src/libANGLE/renderer/driver_utils_ios.mm b/src/libANGLE/renderer/driver_utils_ios.mm
21499
new file mode 100644
21500
index 0000000..e7a845c
21501
--- /dev/null
21502
+++ b/src/libANGLE/renderer/driver_utils_ios.mm
21503
@@ -0,0 +1,28 @@
21504
+//
21505
+// Copyright 2019 The ANGLE Project Authors. All rights reserved.
21506
+// Use of this source code is governed by a BSD-style license that can be
21507
+// found in the LICENSE file.
21508
+//
21509
+
21510
+// driver_utils_ios.mm : provides ios-specific information about current driver.
21511
+
21512
+#include "libANGLE/renderer/driver_utils.h"
21513
+
21514
+#import <Foundation/Foundation.h>
21515
+
21516
+namespace rx
21517
+{
21518
+
21519
+OSVersion GetiOSVersion()
21520
+{
21521
+    OSVersion result;
21522
+
21523
+    NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion];
21524
+    result.majorVersion              = static_cast<int>(version.majorVersion);
21525
+    result.minorVersion              = static_cast<int>(version.minorVersion);
21526
+    result.patchVersion              = static_cast<int>(version.patchVersion);
21527
+
21528
+    return result;
21529
+}
21530
+
21531
+}
21532
diff --git a/src/libANGLE/renderer/driver_utils_mac.mm b/src/libANGLE/renderer/driver_utils_mac.mm
21533
index 3af46fc..9b53eb7 100644
21534
--- a/src/libANGLE/renderer/driver_utils_mac.mm
21535
+++ b/src/libANGLE/renderer/driver_utils_mac.mm
21536
@@ -13,6 +13,7 @@
21537
 namespace rx
21538
 {
21539
 
21540
+#if !TARGET_OS_IOS
21541
 OSVersion GetMacOSVersion()
21542
 {
21543
     OSVersion result;
21544
@@ -24,5 +25,5 @@ OSVersion GetMacOSVersion()
21545
 
21546
     return result;
21547
 }
21548
-
21549
+#endif
21550
 }
21551
diff --git a/src/libANGLE/renderer/gl/SoftLinking_apple.h b/src/libANGLE/renderer/gl/SoftLinking_apple.h
21552
new file mode 100644
21553
index 0000000..ef3a6d7
21554
--- /dev/null
21555
+++ b/src/libANGLE/renderer/gl/SoftLinking_apple.h
21556
@@ -0,0 +1,112 @@
21557
+//
21558
+// Copyright 2020 Apple, Inc. All rights reserved.
21559
+// Use of this source code is governed by a BSD-style license that can be
21560
+// found in the LICENSE file.
21561
+//
21562
+
21563
+// SoftLinking_apple.cpp: Macros for soft-linking Frameworks and Functions.
21564
+
21565
+#ifndef SOFT_LINKING_APPLE_H_
21566
+#define SOFT_LINKING_APPLE_H_
21567
+
21568
+#include "common/platform.h"
21569
+
21570
+#if defined(ANGLE_PLATFORM_APPLE)
21571
+
21572
+#    include "common/debug.h"
21573
+
21574
+#    import <dispatch/dispatch.h>
21575
+#    import <dlfcn.h>
21576
+#    import <objc/runtime.h>
21577
+
21578
+#    define RELEASE_ASSERT(expression, message)                                               \
21579
+        (expression                                                                           \
21580
+             ? static_cast<void>(0)                                                           \
21581
+             : (FATAL() << "\t! Assert failed in " << __FUNCTION__ << " (" << __FILE__ << ":" \
21582
+                        << __LINE__ << "): " << #expression << "\n\t! Message: " << message))
21583
+
21584
+#    ifdef __cplusplus
21585
+#        define EXTERN_C_BEGIN extern "C" {
21586
+#        define EXTERN_C_END }
21587
+#    else
21588
+#        define EXTERN_C_BEGIN
21589
+#        define EXTERN_C_END
21590
+#    endif
21591
+
21592
+#    define SOFT_LINK_FRAMEWORK_HEADER(framework) extern void *framework##Library();
21593
+
21594
+#    define SOFT_LINK_FRAMEWORK_SOURCE(framework)                                               \
21595
+        void *framework##Library()                                                              \
21596
+        {                                                                                       \
21597
+            static dispatch_once_t once   = 0;                                                  \
21598
+            static void *frameworkLibrary = NULL;                                               \
21599
+            dispatch_once(&once, ^{                                                             \
21600
+              frameworkLibrary = dlopen(                                                        \
21601
+                  "/System/Library/Frameworks/" #framework ".framework/" #framework, RTLD_NOW); \
21602
+              RELEASE_ASSERT(frameworkLibrary, "Unable to load " #framework ".framework");      \
21603
+            });                                                                                 \
21604
+            return frameworkLibrary;                                                            \
21605
+        }
21606
+
21607
+#    define SOFT_LINK_FUNCTION_HEADER(framework, functionName, resultType, parameterDeclarations, \
21608
+                                      parameterNames)                                             \
21609
+        EXTERN_C_BEGIN                                                                            \
21610
+        resultType functionName parameterDeclarations;                                            \
21611
+        EXTERN_C_END                                                                              \
21612
+        extern resultType init##framework##functionName parameterDeclarations;                    \
21613
+        extern resultType(*softLink##framework##functionName) parameterDeclarations;              \
21614
+        inline __attribute__((__always_inline__)) resultType functionName parameterDeclarations   \
21615
+        {                                                                                         \
21616
+            return softLink##framework##functionName parameterNames;                              \
21617
+        }
21618
+
21619
+#    define SOFT_LINK_FUNCTION_SOURCE(framework, functionName, resultType, parameterDeclarations,  \
21620
+                                      parameterNames)                                              \
21621
+        resultType(*softLink##framework##functionName) parameterDeclarations =                     \
21622
+            init##framework##functionName;                                                         \
21623
+        resultType init##framework##functionName parameterDeclarations                             \
21624
+        {                                                                                          \
21625
+            static dispatch_once_t once;                                                           \
21626
+            dispatch_once(&once, ^{                                                                \
21627
+              softLink##framework##functionName =                                                  \
21628
+                  (resultType(*) parameterDeclarations)dlsym(framework##Library(), #functionName); \
21629
+            });                                                                                    \
21630
+            return softLink##framework##functionName parameterNames;                               \
21631
+        }
21632
+
21633
+#    define SOFT_LINK_CLASS_HEADER(className)    \
21634
+        @class className;                        \
21635
+        extern Class (*get##className##Class)(); \
21636
+        className *alloc##className##Instance(); \
21637
+        inline className *alloc##className##Instance() { return [get##className##Class() alloc]; }
21638
+
21639
+#    define SOFT_LINK_CLASS(framework, className)                                       \
21640
+        @class className;                                                               \
21641
+        static Class init##className();                                                 \
21642
+        Class (*get##className##Class)() = init##className;                             \
21643
+        static Class class##className;                                                  \
21644
+                                                                                        \
21645
+        static Class className##Function() { return class##className; }                 \
21646
+                                                                                        \
21647
+        static Class init##className()                                                  \
21648
+        {                                                                               \
21649
+            static dispatch_once_t once;                                                \
21650
+            dispatch_once(&once, ^{                                                     \
21651
+              framework##Library();                                                     \
21652
+              class##className = objc_getClass(#className);                             \
21653
+              RELEASE_ASSERT(class##className, "objc_getClass failed for " #className); \
21654
+              get##className##Class = className##Function;                              \
21655
+            });                                                                         \
21656
+            return class##className;                                                    \
21657
+        }                                                                               \
21658
+        _Pragma("clang diagnostic push")                                                \
21659
+            _Pragma("clang diagnostic ignored \"-Wunused-function\"") static className  \
21660
+                *alloc##className##Instance()                                           \
21661
+        {                                                                               \
21662
+            return [get##className##Class() alloc];                                     \
21663
+        }                                                                               \
21664
+        _Pragma("clang diagnostic pop")
21665
+
21666
+#endif  // defined(ANGLE_PLATFORM_APPLE)
21667
+
21668
+#endif  // SOFT_LINKING_APPLE_H_
21669
diff --git a/src/libANGLE/renderer/gl/apple/DisplayApple_api.cpp b/src/libANGLE/renderer/gl/apple/DisplayApple_api.cpp
21670
index de216fb..55dcd90 100644
21671
--- a/src/libANGLE/renderer/gl/apple/DisplayApple_api.cpp
21672
+++ b/src/libANGLE/renderer/gl/apple/DisplayApple_api.cpp
21673
@@ -10,6 +10,7 @@
21674
 #ifndef LIBANGLE_RENDERER_GL_APPLE_DISPLAYAPPLE_API_H_
21675
 #define LIBANGLE_RENDERER_GL_APPLE_DISPLAYAPPLE_API_H_
21676
 
21677
+#include "gpu_info_util/SystemInfo.h"
21678
 #include "libANGLE/renderer/DisplayImpl.h"
21679
 
21680
 #if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
21681
@@ -33,11 +34,10 @@ DisplayImpl *CreateDisplayCGLOrEAGL(const egl::DisplayState &state)
21682
     angle::SystemInfo info;
21683
     if (!angle::GetSystemInfo(&info))
21684
     {
21685
-        impl = nullptr;
21686
-        break;
21687
+        return nullptr;
21688
     }
21689
 
21690
-    if (info.isiOSAppOnMac)
21691
+    if (info.needsEAGLOnMac)
21692
     {
21693
         return new rx::DisplayEAGL(state);
21694
     }
21695
diff --git a/src/libANGLE/renderer/gl/cgl/CGLFunctions.cpp b/src/libANGLE/renderer/gl/cgl/CGLFunctions.cpp
21696
new file mode 100644
21697
index 0000000..e95c0f6
21698
--- /dev/null
21699
+++ b/src/libANGLE/renderer/gl/cgl/CGLFunctions.cpp
21700
@@ -0,0 +1,77 @@
21701
+//
21702
+// Copyright 2020 Apple, Inc. All rights reserved.
21703
+// Use of this source code is governed by a BSD-style license that can be
21704
+// found in the LICENSE file.
21705
+//
21706
+
21707
+// CGLFunctions.cpp: Exposing the soft-linked CGL interface.
21708
+
21709
+#include "libANGLE/renderer/gl/cgl/CGLFunctions.h"
21710
+#include "common/platform.h"
21711
+
21712
+#if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
21713
+
21714
+SOFT_LINK_FRAMEWORK_SOURCE(OpenGL)
21715
+
21716
+SOFT_LINK_FUNCTION_SOURCE(OpenGL,
21717
+                          CGLChoosePixelFormat,
21718
+                          CGLError,
21719
+                          (const CGLPixelFormatAttribute *attribs,
21720
+                           CGLPixelFormatObj *pix,
21721
+                           GLint *npix),
21722
+                          (attribs, pix, npix))
21723
+SOFT_LINK_FUNCTION_SOURCE(OpenGL,
21724
+                          CGLCreateContext,
21725
+                          CGLError,
21726
+                          (CGLPixelFormatObj pix, CGLContextObj share, CGLContextObj *ctx),
21727
+                          (pix, share, ctx))
21728
+SOFT_LINK_FUNCTION_SOURCE(
21729
+    OpenGL,
21730
+    CGLDescribePixelFormat,
21731
+    CGLError,
21732
+    (CGLPixelFormatObj pix, GLint pix_num, CGLPixelFormatAttribute attrib, GLint *value),
21733
+    (pix, pix_num, attrib, value))
21734
+SOFT_LINK_FUNCTION_SOURCE(OpenGL, CGLDestroyContext, CGLError, (CGLContextObj ctx), (ctx))
21735
+SOFT_LINK_FUNCTION_SOURCE(OpenGL, CGLDestroyPixelFormat, CGLError, (CGLPixelFormatObj pix), (pix))
21736
+SOFT_LINK_FUNCTION_SOURCE(OpenGL, CGLErrorString, const char *, (CGLError error), (error))
21737
+SOFT_LINK_FUNCTION_SOURCE(OpenGL, CGLReleaseContext, void, (CGLContextObj ctx), (ctx))
21738
+SOFT_LINK_FUNCTION_SOURCE(OpenGL, CGLSetCurrentContext, CGLError, (CGLContextObj ctx), (ctx))
21739
+SOFT_LINK_FUNCTION_SOURCE(OpenGL,
21740
+                          CGLSetVirtualScreen,
21741
+                          CGLError,
21742
+                          (CGLContextObj ctx, GLint screen),
21743
+                          (ctx, screen))
21744
+SOFT_LINK_FUNCTION_SOURCE(
21745
+    OpenGL,
21746
+    CGLTexImageIOSurface2D,
21747
+    CGLError,
21748
+    (CGLContextObj ctx,
21749
+     GLenum target,
21750
+     GLenum internal_format,
21751
+     GLsizei width,
21752
+     GLsizei height,
21753
+     GLenum format,
21754
+     GLenum type,
21755
+     IOSurfaceRef ioSurface,
21756
+     GLuint plane),
21757
+    (ctx, target, internal_format, width, height, format, type, ioSurface, plane))
21758
+SOFT_LINK_FUNCTION_SOURCE(OpenGL, CGLUpdateContext, CGLError, (CGLContextObj ctx), (ctx))
21759
+
21760
+SOFT_LINK_FUNCTION_SOURCE(
21761
+    OpenGL,
21762
+    CGLDescribeRenderer,
21763
+    CGLError,
21764
+    (CGLRendererInfoObj rend, GLint rend_num, CGLRendererProperty prop, GLint *value),
21765
+    (rend, rend_num, prop, value))
21766
+SOFT_LINK_FUNCTION_SOURCE(OpenGL,
21767
+                          CGLDestroyRendererInfo,
21768
+                          CGLError,
21769
+                          (CGLRendererInfoObj rend),
21770
+                          (rend))
21771
+SOFT_LINK_FUNCTION_SOURCE(OpenGL,
21772
+                          CGLQueryRendererInfo,
21773
+                          CGLError,
21774
+                          (GLuint display_mask, CGLRendererInfoObj *rend, GLint *nrend),
21775
+                          (display_mask, rend, nrend))
21776
+
21777
+#endif  // defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
21778
diff --git a/src/libANGLE/renderer/gl/cgl/CGLFunctions.h b/src/libANGLE/renderer/gl/cgl/CGLFunctions.h
21779
new file mode 100644
21780
index 0000000..a6b871e
21781
--- /dev/null
21782
+++ b/src/libANGLE/renderer/gl/cgl/CGLFunctions.h
21783
@@ -0,0 +1,84 @@
21784
+//
21785
+// Copyright 2020 Apple, Inc. All rights reserved.
21786
+// Use of this source code is governed by a BSD-style license that can be
21787
+// found in the LICENSE file.
21788
+//
21789
+
21790
+// CGLFunctions.h: Exposing the soft-linked CGL interface.
21791
+
21792
+#ifndef CGL_FUNCTIONS_H_
21793
+#define CGL_FUNCTIONS_H_
21794
+
21795
+#include "common/platform.h"
21796
+
21797
+#if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
21798
+
21799
+#    include <OpenGL/OpenGL.h>
21800
+
21801
+#    include "libANGLE/renderer/gl/SoftLinking_apple.h"
21802
+
21803
+SOFT_LINK_FRAMEWORK_HEADER(OpenGL)
21804
+
21805
+SOFT_LINK_FUNCTION_HEADER(OpenGL,
21806
+                          CGLChoosePixelFormat,
21807
+                          CGLError,
21808
+                          (const CGLPixelFormatAttribute *attribs,
21809
+                           CGLPixelFormatObj *pix,
21810
+                           GLint *npix),
21811
+                          (attribs, pix, npix))
21812
+SOFT_LINK_FUNCTION_HEADER(OpenGL,
21813
+                          CGLCreateContext,
21814
+                          CGLError,
21815
+                          (CGLPixelFormatObj pix, CGLContextObj share, CGLContextObj *ctx),
21816
+                          (pix, share, ctx))
21817
+SOFT_LINK_FUNCTION_HEADER(
21818
+    OpenGL,
21819
+    CGLDescribePixelFormat,
21820
+    CGLError,
21821
+    (CGLPixelFormatObj pix, GLint pix_num, CGLPixelFormatAttribute attrib, GLint *value),
21822
+    (pix, pix_num, attrib, value))
21823
+SOFT_LINK_FUNCTION_HEADER(
21824
+    OpenGL,
21825
+    CGLDescribeRenderer,
21826
+    CGLError,
21827
+    (CGLRendererInfoObj rend, GLint rend_num, CGLRendererProperty prop, GLint *value),
21828
+    (rend, rend_num, prop, value))
21829
+SOFT_LINK_FUNCTION_HEADER(OpenGL, CGLDestroyContext, CGLError, (CGLContextObj ctx), (ctx))
21830
+SOFT_LINK_FUNCTION_HEADER(OpenGL, CGLDestroyPixelFormat, CGLError, (CGLPixelFormatObj pix), (pix))
21831
+SOFT_LINK_FUNCTION_HEADER(OpenGL,
21832
+                          CGLDestroyRendererInfo,
21833
+                          CGLError,
21834
+                          (CGLRendererInfoObj rend),
21835
+                          (rend))
21836
+SOFT_LINK_FUNCTION_HEADER(OpenGL, CGLErrorString, const char *, (CGLError error), (error))
21837
+SOFT_LINK_FUNCTION_HEADER(OpenGL,
21838
+                          CGLQueryRendererInfo,
21839
+                          CGLError,
21840
+                          (GLuint display_mask, CGLRendererInfoObj *rend, GLint *nrend),
21841
+                          (display_mask, rend, nrend))
21842
+SOFT_LINK_FUNCTION_HEADER(OpenGL, CGLReleaseContext, void, (CGLContextObj ctx), (ctx))
21843
+SOFT_LINK_FUNCTION_HEADER(OpenGL, CGLSetCurrentContext, CGLError, (CGLContextObj ctx), (ctx))
21844
+SOFT_LINK_FUNCTION_HEADER(OpenGL,
21845
+                          CGLSetVirtualScreen,
21846
+                          CGLError,
21847
+                          (CGLContextObj ctx, GLint screen),
21848
+                          (ctx, screen))
21849
+SOFT_LINK_FUNCTION_HEADER(
21850
+    OpenGL,
21851
+    CGLTexImageIOSurface2D,
21852
+    CGLError,
21853
+    (CGLContextObj ctx,
21854
+     GLenum target,
21855
+     GLenum internal_format,
21856
+     GLsizei width,
21857
+     GLsizei height,
21858
+     GLenum format,
21859
+     GLenum type,
21860
+     IOSurfaceRef ioSurface,
21861
+     GLuint plane),
21862
+    (ctx, target, internal_format, width, height, format, type, ioSurface, plane))
21863
+SOFT_LINK_FUNCTION_HEADER(OpenGL, CGLUpdateContext, CGLError, (CGLContextObj ctx), (ctx))
21864
+
21865
+#endif  // defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
21866
+
21867
+#endif  // CGL_FUNCTIONS_H_
21868
diff --git a/src/libANGLE/renderer/gl/cgl/ContextCGL.cpp b/src/libANGLE/renderer/gl/cgl/ContextCGL.cpp
21869
index bdf5597..be99b85 100644
21870
--- a/src/libANGLE/renderer/gl/cgl/ContextCGL.cpp
21871
+++ b/src/libANGLE/renderer/gl/cgl/ContextCGL.cpp
21872
@@ -13,6 +13,8 @@
21873
 #include "libANGLE/Display.h"
21874
 #include "libANGLE/renderer/gl/cgl/DisplayCGL.h"
21875
 
21876
+#if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
21877
+
21878
 namespace rx
21879
 {
21880
 
21881
@@ -63,3 +65,5 @@ void ContextCGL::onDestroy(const gl::Context *context)
21882
 }
21883
 
21884
 }  // namespace rx
21885
+
21886
+#endif  // defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
21887
\ No newline at end of file
21888
diff --git a/src/libANGLE/renderer/gl/cgl/DisplayCGL.mm b/src/libANGLE/renderer/gl/cgl/DisplayCGL.mm
21889
index b5a631a..90e8058 100644
21890
--- a/src/libANGLE/renderer/gl/cgl/DisplayCGL.mm
21891
+++ b/src/libANGLE/renderer/gl/cgl/DisplayCGL.mm
21892
@@ -29,6 +29,8 @@
21893
 #    include "libANGLE/renderer/gl/cgl/WindowSurfaceCGL.h"
21894
 #    include "platform/PlatformMethods.h"
21895
 
21896
+#    include "libANGLE/renderer/gl/cgl/CGLFunctions.h"
21897
+
21898
 namespace
21899
 {
21900
 
21901
@@ -163,9 +165,10 @@ static void SetGPUByRegistryID(CGLContextObj contextObj,
21902
     mEGLDisplay = display;
21903
 
21904
     angle::SystemInfo info;
21905
-    // It's legal for GetSystemInfo to return false and thereby
21906
-    // contain incomplete information.
21907
-    (void)angle::GetSystemInfo(&info);
21908
+    if (!angle::GetSystemInfo(&info))
21909
+    {
21910
+        return egl::EglNotInitialized() << "Unable to query ANGLE's SystemInfo.";
21911
+    }
21912
 
21913
     // This code implements the effect of the
21914
     // disableGPUSwitchingSupport workaround in FeaturesGL.
21915
@@ -440,7 +443,7 @@ static void SetGPUByRegistryID(CGLContextObj contextObj,
21916
 
21917
 bool DisplayCGL::isValidNativeWindow(EGLNativeWindowType window) const
21918
 {
21919
-    NSObject *layer = (__bridge NSObject *)window;
21920
+    NSObject *layer = reinterpret_cast<NSObject *>(window);
21921
     return [layer isKindOfClass:[CALayer class]];
21922
 }
21923
 
21924
diff --git a/src/libANGLE/renderer/gl/eagl/DisplayEAGL.mm b/src/libANGLE/renderer/gl/eagl/DisplayEAGL.mm
21925
index a795037..c55ae7f 100644
21926
--- a/src/libANGLE/renderer/gl/eagl/DisplayEAGL.mm
21927
+++ b/src/libANGLE/renderer/gl/eagl/DisplayEAGL.mm
21928
@@ -27,6 +27,8 @@
21929
 #    import <QuartzCore/QuartzCore.h>
21930
 #    import <dlfcn.h>
21931
 
21932
+#    import "libANGLE/renderer/gl/eagl/EAGLFunctions.h"
21933
+
21934
 namespace
21935
 {
21936
 
21937
@@ -64,9 +66,10 @@
21938
     mEGLDisplay = display;
21939
 
21940
     angle::SystemInfo info;
21941
-    // It's legal for GetSystemInfo to return false and thereby
21942
-    // contain incomplete information.
21943
-    (void)angle::GetSystemInfo(&info);
21944
+    if (!angle::GetSystemInfo(&info))
21945
+    {
21946
+        return egl::EglNotInitialized() << "Unable to query ANGLE's SystemInfo.";
21947
+    }
21948
 
21949
     mContext = [allocEAGLContextInstance() initWithAPI:kEAGLRenderingAPIOpenGLES3];
21950
     if (mContext == nullptr)
21951
@@ -113,6 +116,7 @@
21952
     if (mContext != nullptr)
21953
     {
21954
         [getEAGLContextClass() setCurrentContext:nil];
21955
+        [mContext release];
21956
         mContext = nullptr;
21957
         mThreadsWithContextCurrent.clear();
21958
     }
21959
@@ -275,7 +279,7 @@
21960
 
21961
 bool DisplayEAGL::isValidNativeWindow(EGLNativeWindowType window) const
21962
 {
21963
-    NSObject *layer = (__bridge NSObject *)window;
21964
+    NSObject *layer = reinterpret_cast<NSObject *>(window);
21965
     return [layer isKindOfClass:[CALayer class]];
21966
 }
21967
 
21968
@@ -311,9 +315,8 @@
21969
     outExtensions->surfacelessContext    = true;
21970
     outExtensions->deviceQuery           = true;
21971
 
21972
-    // Contexts are virtualized so textures ans semaphores can be shared globally
21973
+    // Contexts are virtualized so textures can be shared globally
21974
     outExtensions->displayTextureShareGroup = true;
21975
-    outExtensions->displaySemaphoreShareGroup = true;
21976
 
21977
     outExtensions->powerPreference = false;
21978
 
21979
diff --git a/src/libANGLE/renderer/gl/eagl/EAGLFunctions.h b/src/libANGLE/renderer/gl/eagl/EAGLFunctions.h
21980
new file mode 100644
21981
index 0000000..9212513
21982
--- /dev/null
21983
+++ b/src/libANGLE/renderer/gl/eagl/EAGLFunctions.h
21984
@@ -0,0 +1,30 @@
21985
+//
21986
+// Copyright 2020 Apple, Inc. All rights reserved.
21987
+// Use of this source code is governed by a BSD-style license that can be
21988
+// found in the LICENSE file.
21989
+//
21990
+
21991
+// EAGLFunctions.h: Exposing the soft-linked EAGL interface.
21992
+
21993
+#ifndef EAGL_FUNCTIONS_H_
21994
+#define EAGL_FUNCTIONS_H_
21995
+
21996
+#include "common/platform.h"
21997
+
21998
+#if (defined(ANGLE_PLATFORM_IOS) && !defined(ANGLE_PLATFORM_MACCATALYST)) || \
21999
+    (defined(ANGLE_PLATFORM_MACCATALYST) && defined(ANGLE_CPU_ARM64))
22000
+
22001
+#    import <OpenGLES/EAGL.h>
22002
+#    import <OpenGLES/EAGLDrawable.h>
22003
+#    import <OpenGLES/EAGLIOSurface.h>
22004
+
22005
+#    include "libANGLE/renderer/gl/SoftLinking_apple.h"
22006
+
22007
+SOFT_LINK_FRAMEWORK_HEADER(OpenGLES)
22008
+
22009
+SOFT_LINK_CLASS_HEADER(EAGLContext)
22010
+
22011
+#endif  // (defined(ANGLE_PLATFORM_IOS) && !defined(ANGLE_PLATFORM_MACCATALYST)) ||
22012
+        // (defined(ANGLE_PLATFORM_MACCATALYST) && defined(ANGLE_CPU_ARM64))
22013
+
22014
+#endif  // CGL_FUNCTIONS_H_
22015
diff --git a/src/libANGLE/renderer/gl/eagl/EAGLFunctions.mm b/src/libANGLE/renderer/gl/eagl/EAGLFunctions.mm
22016
new file mode 100644
22017
index 0000000..0b1eb70
22018
--- /dev/null
22019
+++ b/src/libANGLE/renderer/gl/eagl/EAGLFunctions.mm
22020
@@ -0,0 +1,25 @@
22021
+//
22022
+// Copyright 2020 Apple, Inc. All rights reserved.
22023
+// Use of this source code is governed by a BSD-style license that can be
22024
+// found in the LICENSE file.
22025
+//
22026
+
22027
+// EAGLFunctions.cpp: Exposing the soft-linked EAGL interface.
22028
+
22029
+#include "common/platform.h"
22030
+
22031
+#if (defined(ANGLE_PLATFORM_IOS) && !defined(ANGLE_PLATFORM_MACCATALYST)) || \
22032
+    (defined(ANGLE_PLATFORM_MACCATALYST) && defined(ANGLE_CPU_ARM64))
22033
+
22034
+#    import <OpenGLES/EAGL.h>
22035
+#    import <OpenGLES/EAGLDrawable.h>
22036
+#    import <OpenGLES/EAGLIOSurface.h>
22037
+
22038
+#    include "libANGLE/renderer/gl/SoftLinking_apple.h"
22039
+
22040
+SOFT_LINK_FRAMEWORK_SOURCE(OpenGLES)
22041
+
22042
+SOFT_LINK_CLASS(OpenGLES, EAGLContext)
22043
+
22044
+#endif  // (defined(ANGLE_PLATFORM_IOS) && !defined(ANGLE_PLATFORM_MACCATALYST)) ||
22045
+        // (defined(ANGLE_PLATFORM_MACCATALYST) && defined(ANGLE_CPU_ARM64))
22046
\ No newline at end of file
297
diff --git a/src/libANGLE/renderer/gl/eagl/FunctionsEAGL.h b/src/libANGLE/renderer/gl/eagl/FunctionsEAGL.h
22047
diff --git a/src/libANGLE/renderer/gl/eagl/FunctionsEAGL.h b/src/libANGLE/renderer/gl/eagl/FunctionsEAGL.h
298
index ece235a..ae0207b 100644
22048
index ece235a..ae0207b 100644
299
--- a/src/libANGLE/renderer/gl/eagl/FunctionsEAGL.h
22049
--- a/src/libANGLE/renderer/gl/eagl/FunctionsEAGL.h
Lines 302-361 index ece235a..ae0207b 100644 a/Source/ThirdParty/ANGLE/changes.diff_sec4
302
 #    import <OpenGLES/EAGLDrawable.h>
22052
 #    import <OpenGLES/EAGLDrawable.h>
303
 #    import <OpenGLES/EAGLIOSurface.h>
22053
 #    import <OpenGLES/EAGLIOSurface.h>
304
 
22054
 
305
-#    include "libANGLE/renderer/gl/apple/SoftLinking.h"
22055
-#    include "libANGLE/renderer/gl/apple/SoftLinking.h"
306
+#    include "common/apple/SoftLinking.h"
22056
+#    include "common/apple/SoftLinking.h"
22057
 
22058
 SOFT_LINK_FRAMEWORK_HEADER(OpenGLES)
22059
 
22060
diff --git a/src/libANGLE/renderer/gl/eagl/FunctionsEAGL.mm b/src/libANGLE/renderer/gl/eagl/FunctionsEAGL.mm
22061
index 7779792..076d072 100644
22062
--- a/src/libANGLE/renderer/gl/eagl/FunctionsEAGL.mm
22063
+++ b/src/libANGLE/renderer/gl/eagl/FunctionsEAGL.mm
22064
@@ -14,7 +14,7 @@
22065
 #    import <OpenGLES/EAGLDrawable.h>
22066
 #    import <OpenGLES/EAGLIOSurface.h>
22067
 
22068
-#    include "libANGLE/renderer/gl/apple/SoftLinking.h"
22069
+#    include "common/apple/SoftLinking.h"
22070
 
22071
 SOFT_LINK_FRAMEWORK_SOURCE(OpenGLES)
22072
 
22073
diff --git a/src/libANGLE/renderer/gl/eagl/IOSurfaceSurfaceEAGL.mm b/src/libANGLE/renderer/gl/eagl/IOSurfaceSurfaceEAGL.mm
22074
index f16c3e7..e309a86 100644
22075
--- a/src/libANGLE/renderer/gl/eagl/IOSurfaceSurfaceEAGL.mm
22076
+++ b/src/libANGLE/renderer/gl/eagl/IOSurfaceSurfaceEAGL.mm
22077
@@ -83,8 +83,8 @@ int FindIOSurfaceFormatIndex(GLenum internalFormat, GLenum type)
22078
       mWidth(0),
22079
       mHeight(0),
22080
       mPlane(0),
22081
-      mRowStrideInPixels(0),
22082
       mFormatIndex(-1),
22083
+      mRowStrideInPixels(0),
22084
       mAlphaInitialized(false)
22085
 {
22086
     // Keep reference to the IOSurface so it doesn't get deleted while the pbuffer exists.
22087
diff --git a/src/libANGLE/renderer/gl/renderergl_utils.cpp b/src/libANGLE/renderer/gl/renderergl_utils.cpp
22088
index 99772c4..11f47e6 100644
22089
--- a/src/libANGLE/renderer/gl/renderergl_utils.cpp
22090
+++ b/src/libANGLE/renderer/gl/renderergl_utils.cpp
22091
@@ -1358,7 +1358,7 @@ void GenerateCaps(const FunctionsGL *functions,
22092
 
22093
 #if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
22094
     angle::SystemInfo info;
22095
-    if (angle::GetSystemInfo(&info) && !info.isiOSAppOnMac)
22096
+    if (angle::GetSystemInfo(&info) && !info.needsEAGLOnMac)
22097
     {
22098
         VendorID vendor = GetVendorID(functions);
22099
         if ((IsAMD(vendor) || IsIntel(vendor)) && *maxSupportedESVersion >= gl::Version(3, 0))
22100
diff --git a/src/libANGLE/renderer/glslang_wrapper_utils.cpp b/src/libANGLE/renderer/glslang_wrapper_utils.cpp
22101
index d70ae58..615dd44 100644
22102
--- a/src/libANGLE/renderer/glslang_wrapper_utils.cpp
22103
+++ b/src/libANGLE/renderer/glslang_wrapper_utils.cpp
22104
@@ -281,9 +281,11 @@ std::string SubstituteTransformFeedbackMarkers(const std::string &originalSource
22105
                                                const std::string &xfbOut)
22106
 {
22107
     const size_t xfbDeclMarkerStart = originalSource.find(kXfbDeclMarker);
22108
+    ASSERT(xfbDeclMarkerStart != std::string::npos);
22109
     const size_t xfbDeclMarkerEnd = xfbDeclMarkerStart + ConstStrLen(kXfbDeclMarker);
22110
 
22111
     const size_t xfbOutMarkerStart = originalSource.find(kXfbOutMarker, xfbDeclMarkerStart);
22112
+    ASSERT(xfbOutMarkerStart != std::string::npos);
22113
     const size_t xfbOutMarkerEnd = xfbOutMarkerStart + ConstStrLen(kXfbOutMarker);
22114
 
22115
     // The shader is the following form:
22116
@@ -362,7 +364,8 @@ void GenerateTransformFeedbackEmulationOutputs(const GlslangSourceOptions &optio
22117
                                                const gl::ProgramState &programState,
22118
                                                GlslangProgramInterfaceInfo *programInterfaceInfo,
22119
                                                std::string *vertexShader,
22120
-                                               ShaderInterfaceVariableInfoMap *variableInfoMapOut)
22121
+                                               ShaderInterfaceVariableInfoMap *variableInfoMapOut,
22122
+                                               bool earlyReturn)
22123
 {
22124
     const std::vector<gl::TransformFeedbackVarying> &varyings =
22125
         programState.getLinkedTransformFeedbackVaryings();
22126
@@ -413,6 +416,10 @@ void GenerateTransformFeedbackEmulationOutputs(const GlslangSourceOptions &optio
22127
             outputOffset += info.columnCount * info.rowCount * varying.size();
22128
         }
22129
     }
22130
+    if (earlyReturn)
22131
+    {
22132
+        xfbOut += "return;";
22133
+    }
22134
     xfbOut += "}\n";
22135
 
22136
     *vertexShader = SubstituteTransformFeedbackMarkers(*vertexShader, xfbDecl, xfbOut);
22137
@@ -3368,11 +3375,6 @@ std::string GlslangGetMappedSamplerName(const std::string &originalName)
22138
     return samplerName;
22139
 }
22140
 
22141
-std::string GetXfbBufferName(const uint32_t bufferIndex)
22142
-{
22143
-    return "xfbBuffer" + Str(bufferIndex);
22144
-}
22145
-
22146
 void GlslangGenTransformFeedbackEmulationOutputs(const GlslangSourceOptions &options,
22147
                                                  const gl::ProgramState &programState,
22148
                                                  GlslangProgramInterfaceInfo *programInterfaceInfo,
22149
@@ -3380,7 +3382,7 @@ void GlslangGenTransformFeedbackEmulationOutputs(const GlslangSourceOptions &opt
22150
                                                  ShaderInterfaceVariableInfoMap *variableInfoMapOut)
22151
 {
22152
     GenerateTransformFeedbackEmulationOutputs(options, programState, programInterfaceInfo,
22153
-                                              vertexShader, variableInfoMapOut);
22154
+                                              vertexShader, variableInfoMapOut, false);
22155
 }
22156
 
22157
 void GlslangAssignLocations(const GlslangSourceOptions &options,
22158
@@ -3428,6 +3430,57 @@ void GlslangAssignLocations(const GlslangSourceOptions &options,
22159
                              variableInfoMapOut);
22160
 }
22161
 
22162
+std::string GetXfbBufferName(const uint32_t bufferIndex)
22163
+{
22164
+    return "xfbBuffer" + Str(bufferIndex);
22165
+}
22166
+
22167
+
22168
+void GlslangAssignLocations(GlslangSourceOptions &options,
22169
+                            const gl::ProgramExecutable &programExecutable,
22170
+                            const gl::ShaderType shaderType,
22171
+                            GlslangProgramInterfaceInfo *programInterfaceInfo,
22172
+                            ShaderMapInterfaceVariableInfoMap *variableInfoMapOut)
22173
+{
22174
+    // Assign outputs to the fragment shader, if any.
22175
+    if ((shaderType == gl::ShaderType::Fragment) &&
22176
+        programExecutable.hasLinkedShaderStage(gl::ShaderType::Fragment))
22177
+    {
22178
+        AssignOutputLocations(programExecutable, gl::ShaderType::Fragment,
22179
+                              &(*variableInfoMapOut)[gl::ShaderType::Fragment]);
22180
+    }
22181
+
22182
+    // Assign attributes to the vertex shader, if any.
22183
+    if ((shaderType == gl::ShaderType::Vertex) &&
22184
+        programExecutable.hasLinkedShaderStage(gl::ShaderType::Vertex))
22185
+    {
22186
+        AssignAttributeLocations(programExecutable, gl::ShaderType::Vertex,
22187
+                                 &(*variableInfoMapOut)[gl::ShaderType::Vertex]);
22188
+    }
22189
+
22190
+    if (!programExecutable.hasLinkedShaderStage(gl::ShaderType::Compute))
22191
+    {
22192
+        // Assign varying locations.
22193
+        AssignVaryingLocations(options, programExecutable, shaderType, programInterfaceInfo,
22194
+                               variableInfoMapOut);
22195
+
22196
+        if (!programExecutable.getLinkedTransformFeedbackVaryings().empty() &&
22197
+            options.supportsTransformFeedbackExtension && (shaderType == gl::ShaderType::Vertex))
22198
+        {
22199
+            AssignTransformFeedbackExtensionQualifiers(
22200
+                programExecutable, programInterfaceInfo->locationsUsedForXfbExtension,
22201
+                gl::ShaderType::Vertex, &(*variableInfoMapOut)[gl::ShaderType::Vertex]);
22202
+        }
22203
+    }
22204
+
22205
+    AssignUniformBindings(options, programExecutable, shaderType, programInterfaceInfo,
22206
+                          variableInfoMapOut);
22207
+    AssignTextureBindings(options, programExecutable, shaderType, programInterfaceInfo,
22208
+                          variableInfoMapOut);
22209
+    AssignNonTextureBindings(options, programExecutable, shaderType, programInterfaceInfo,
22210
+                             variableInfoMapOut);
22211
+}
22212
+
22213
 void GlslangGetShaderSource(const GlslangSourceOptions &options,
22214
                             const gl::ProgramState &programState,
22215
                             const gl::ProgramLinkedResources &resources,
22216
@@ -3462,7 +3515,8 @@ void GlslangGetShaderSource(const GlslangSourceOptions &options,
22217
             {
22218
                 GenerateTransformFeedbackEmulationOutputs(
22219
                     options, programState, programInterfaceInfo, vertexSource,
22220
-                    &(*variableInfoMapOut)[gl::ShaderType::Vertex]);
22221
+                    &(*variableInfoMapOut)[gl::ShaderType::Vertex],
22222
+                    options.transformFeedbackEarlyReturn);
22223
             }
22224
             else
22225
             {
22226
diff --git a/src/libANGLE/renderer/glslang_wrapper_utils.h b/src/libANGLE/renderer/glslang_wrapper_utils.h
22227
index 2bd2c61..60248cd 100644
22228
--- a/src/libANGLE/renderer/glslang_wrapper_utils.h
22229
+++ b/src/libANGLE/renderer/glslang_wrapper_utils.h
22230
@@ -51,6 +51,7 @@ struct GlslangSourceOptions
22231
     bool supportsTransformFeedbackExtension = false;
22232
     bool emulateTransformFeedback           = false;
22233
     bool emulateBresenhamLines              = false;
22234
+    bool transformFeedbackEarlyReturn       = false;
22235
 };
22236
 
22237
 using SpirvBlob = std::vector<uint32_t>;
22238
diff --git a/src/libANGLE/renderer/load_functions_data.json b/src/libANGLE/renderer/load_functions_data.json
22239
index 8c3fd05..7bcded0 100644
22240
--- a/src/libANGLE/renderer/load_functions_data.json
22241
+++ b/src/libANGLE/renderer/load_functions_data.json
22242
@@ -672,6 +672,9 @@
22243
     "D32_FLOAT_S8X24_UINT": {
22244
       "GL_UNSIGNED_INT_24_8": "LoadD24S8ToD32FS8X24",
22245
       "GL_UNSIGNED_INT": "LoadD32ToD32FX32"
22246
+    },
22247
+    "D32_FLOAT": {
22248
+      "GL_UNSIGNED_INT": "LoadD24S8ToD32F"
22249
     }
22250
   },
22251
   "GL_R32I": {
22252
diff --git a/src/libANGLE/renderer/load_functions_table_autogen.cpp b/src/libANGLE/renderer/load_functions_table_autogen.cpp
22253
index 20e706f..2ef01ca 100644
22254
--- a/src/libANGLE/renderer/load_functions_table_autogen.cpp
22255
+++ b/src/libANGLE/renderer/load_functions_table_autogen.cpp
22256
@@ -446,8 +446,7 @@ LoadImageFunctionInfo COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGB_UNORM_B
22257
     }
22258
 }
22259
 
22260
-LoadImageFunctionInfo COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2_to_ETC2_R8G8B8A1_UNORM_BLOCK(
22261
-    GLenum type)
22262
+LoadImageFunctionInfo COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2_to_ETC2_R8G8B8A1_UNORM_BLOCK(GLenum type)
22263
 {
22264
     switch (type)
22265
     {
22266
@@ -471,8 +470,7 @@ LoadImageFunctionInfo COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2_to_R8G8B8A8_UNORM
22267
     }
22268
 }
22269
 
22270
-LoadImageFunctionInfo
22271
-COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGBA_UNORM_BLOCK(GLenum type)
22272
+LoadImageFunctionInfo COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGBA_UNORM_BLOCK(GLenum type)
22273
 {
22274
     switch (type)
22275
     {
22276
@@ -1312,8 +1310,7 @@ LoadImageFunctionInfo COMPRESSED_SRGB8_ETC2_to_R8G8B8A8_UNORM_SRGB(GLenum type)
22277
     }
22278
 }
22279
 
22280
-LoadImageFunctionInfo COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGB_UNORM_SRGB_BLOCK(
22281
-    GLenum type)
22282
+LoadImageFunctionInfo COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGB_UNORM_SRGB_BLOCK(GLenum type)
22283
 {
22284
     switch (type)
22285
     {
22286
@@ -1325,8 +1322,7 @@ LoadImageFunctionInfo COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGB_UNORM_
22287
     }
22288
 }
22289
 
22290
-LoadImageFunctionInfo COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2_to_ETC2_R8G8B8A1_SRGB_BLOCK(
22291
-    GLenum type)
22292
+LoadImageFunctionInfo COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2_to_ETC2_R8G8B8A1_SRGB_BLOCK(GLenum type)
22293
 {
22294
     switch (type)
22295
     {
22296
@@ -1350,9 +1346,7 @@ LoadImageFunctionInfo COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2_to_R8G8B8A8_UNOR
22297
     }
22298
 }
22299
 
22300
-LoadImageFunctionInfo
22301
-COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGBA_UNORM_SRGB_BLOCK(
22302
-    GLenum type)
22303
+LoadImageFunctionInfo COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGBA_UNORM_SRGB_BLOCK(GLenum type)
22304
 {
22305
     switch (type)
22306
     {
22307
@@ -1510,6 +1504,18 @@ LoadImageFunctionInfo DEPTH_COMPONENT24_to_D24_UNORM_X8_UINT(GLenum type)
22308
     }
22309
 }
22310
 
22311
+LoadImageFunctionInfo DEPTH_COMPONENT24_to_D32_FLOAT(GLenum type)
22312
+{
22313
+    switch (type)
22314
+    {
22315
+        case GL_UNSIGNED_INT:
22316
+            return LoadImageFunctionInfo(LoadD24S8ToD32F, true);
22317
+        default:
22318
+            UNREACHABLE();
22319
+            return LoadImageFunctionInfo(UnreachableLoadFunction, true);
22320
+    }
22321
+}
22322
+
22323
 LoadImageFunctionInfo DEPTH_COMPONENT24_to_D32_FLOAT_S8X24_UINT(GLenum type)
22324
 {
22325
     switch (type)
22326
@@ -3624,6 +3630,8 @@ LoadFunctionMap GetLoadFunctionsMap(GLenum internalFormat, FormatID angleFormat)
22327
                     return DEPTH_COMPONENT24_to_D24_UNORM_S8_UINT;
22328
                 case FormatID::D24_UNORM_X8_UINT:
22329
                     return DEPTH_COMPONENT24_to_D24_UNORM_X8_UINT;
22330
+                case FormatID::D32_FLOAT:
22331
+                    return DEPTH_COMPONENT24_to_D32_FLOAT;
22332
                 case FormatID::D32_FLOAT_S8X24_UINT:
22333
                     return DEPTH_COMPONENT24_to_D32_FLOAT_S8X24_UINT;
22334
                 default:
22335
diff --git a/src/libANGLE/renderer/metal/BUILD.gn b/src/libANGLE/renderer/metal/BUILD.gn
22336
index 868c476..0d50d81 100644
22337
--- a/src/libANGLE/renderer/metal/BUILD.gn
22338
+++ b/src/libANGLE/renderer/metal/BUILD.gn
22339
@@ -6,7 +6,7 @@
22340
 
22341
 import("../../../../gni/angle.gni")
22342
 
22343
-assert(is_mac)
22344
+assert(is_mac || is_ios)
22345
 assert(angle_enable_metal)
22346
 
22347
 _metal_backend_sources = [
22348
@@ -21,6 +21,8 @@ _metal_backend_sources = [
22349
   "DisplayMtl_api.h",
22350
   "FrameBufferMtl.h",
22351
   "FrameBufferMtl.mm",
22352
+  "IOSurfaceSurfaceMtl.h",
22353
+  "IOSurfaceSurfaceMtl.mm",
22354
   "ProgramMtl.h",
22355
   "ProgramMtl.mm",
22356
   "QueryMtl.h",
22357
@@ -52,6 +54,8 @@ _metal_backend_sources = [
22358
   "mtl_format_table_autogen.mm",
22359
   "mtl_format_utils.h",
22360
   "mtl_format_utils.mm",
22361
+  "mtl_glslang_mtl_utils.h",
22362
+  "mtl_glslang_mtl_utils.mm",
22363
   "mtl_glslang_utils.h",
22364
   "mtl_glslang_utils.mm",
22365
   "mtl_occlusion_query_pool.h",
22366
@@ -65,12 +69,11 @@ _metal_backend_sources = [
22367
   "mtl_utils.h",
22368
   "mtl_utils.mm",
22369
   "shaders/constants.h",
22370
-  "shaders/format_autogen.h",
22371
-  "shaders/mtl_default_shaders_src_autogen.inc",
22372
+  "shaders/mtl_default_shaders_src_autogen.inc"
22373
 ]
22374
 
22375
 config("angle_metal_backend_config") {
22376
-  defines = [ "ANGLE_ENABLE_METAL" ]
22377
+  defines = [ "ANGLE_ENABLE_METAL", "ANGLE_ENABLE_METAL_SPIRV" ]
22378
   ldflags = [
22379
     "-weak_framework",
22380
     "Metal",
22381
@@ -96,12 +99,16 @@ angle_source_set("angle_metal_backend") {
22382
     "${angle_root}:libANGLE_headers",
22383
   ]
22384
 
22385
-  deps = [ "${angle_spirv_cross_dir}/gn:spirv_cross_sources" ]
22386
+  deps = [
22387
+    "$angle_spirv_tools_dir:spvtools_val",
22388
+    "${angle_spirv_cross_dir}/gn:spirv_cross_sources",
22389
+  ]
22390
 
22391
   objc_flags = [
22392
     "-Wno-nullability-completeness",
22393
     "-Wno-unguarded-availability",
22394
     "-fno-objc-arc",
22395
+    "-Wno-extra-semi-stmt",
22396
   ]
22397
   cflags_objc += objc_flags
22398
   cflags_objcc += objc_flags
22399
diff --git a/src/libANGLE/renderer/metal/BufferMtl.h b/src/libANGLE/renderer/metal/BufferMtl.h
22400
index 762549e..9f9ec6c 100644
22401
--- a/src/libANGLE/renderer/metal/BufferMtl.h
22402
+++ b/src/libANGLE/renderer/metal/BufferMtl.h
22403
@@ -152,10 +152,15 @@ class BufferMtl : public BufferImpl, public BufferHolderMtl
22404
 
22405
     ConversionBufferMtl *getUniformConversionBuffer(ContextMtl *context, size_t offset);
22406
 
22407
+    // NOTE(hqle): If the buffer is modifed by GPU, this function must be explicitly
22408
+    // called.
22409
+    void markConversionBuffersDirty();
22410
+
22411
     size_t size() const { return static_cast<size_t>(mState.getSize()); }
22412
 
22413
   private:
22414
     angle::Result setDataImpl(const gl::Context *context,
22415
+                              gl::BufferBinding target,
22416
                               const void *data,
22417
                               size_t size,
22418
                               gl::BufferUsage usage);
22419
@@ -167,20 +172,24 @@ class BufferMtl : public BufferImpl, public BufferHolderMtl
22420
     angle::Result commitShadowCopy(const gl::Context *context);
22421
     angle::Result commitShadowCopy(const gl::Context *context, size_t size);
22422
 
22423
-    void markConversionBuffersDirty();
22424
-
22425
     void clearConversionBuffers();
22426
+
22427
     bool clientShadowCopyDataNeedSync(ContextMtl *contextMtl);
22428
     void ensureShadowCopySyncedFromGPU(ContextMtl *contextMtl);
22429
     uint8_t *syncAndObtainShadowCopy(ContextMtl *contextMtl);
22430
 
22431
+    // Convenient method
22432
+    const uint8_t *getClientShadowCopyData(const gl::Context *context)
22433
+    {
22434
+        return getClientShadowCopyData(mtl::GetImpl(context));
22435
+    }
22436
     // Client side shadow buffer
22437
     angle::MemoryBuffer mShadowCopy;
22438
 
22439
     // GPU side buffers pool
22440
     mtl::BufferPool mBufferPool;
22441
 
22442
-    // A cache of converted buffer data.
22443
+    // A cache of converted vertex data.
22444
     std::vector<VertexConversionBufferMtl> mVertexConversionBuffers;
22445
 
22446
     std::vector<IndexConversionBufferMtl> mIndexConversionBuffers;
22447
diff --git a/src/libANGLE/renderer/metal/BufferMtl.mm b/src/libANGLE/renderer/metal/BufferMtl.mm
22448
index 64c7de8..8096996 100644
22449
--- a/src/libANGLE/renderer/metal/BufferMtl.mm
22450
+++ b/src/libANGLE/renderer/metal/BufferMtl.mm
22451
@@ -23,6 +23,10 @@
22452
 // Start with a fairly small buffer size. We can increase this dynamically as we convert more data.
22453
 constexpr size_t kConvertedElementArrayBufferInitialSize = 1024 * 8;
22454
 
22455
+// The max size that we will use buffer pool for dynamic update.
22456
+// If the buffer size exceeds this limit, we will use only one buffer instead of using the pool.
22457
+constexpr size_t kDynamicBufferPoolMaxBufSize = 128 * 1024;
22458
+
22459
 template <typename IndexType>
22460
 angle::Result GetFirstLastIndices(const IndexType *indices,
22461
                                   size_t count,
22462
@@ -105,7 +109,7 @@
22463
                                  size_t intendedSize,
22464
                                  gl::BufferUsage usage)
22465
 {
22466
-    return setDataImpl(context, data, intendedSize, usage);
22467
+    return setDataImpl(context, target, data, intendedSize, usage);
22468
 }
22469
 
22470
 angle::Result BufferMtl::setSubData(const gl::Context *context,
22471
@@ -164,7 +168,8 @@
22472
 {
22473
     if (access & GL_MAP_INVALIDATE_BUFFER_BIT)
22474
     {
22475
-        ANGLE_TRY(setDataImpl(context, nullptr, size(), mState.getUsage()));
22476
+        ANGLE_TRY(setDataImpl(context, gl::BufferBinding::InvalidEnum, nullptr, size(),
22477
+                              mState.getUsage()));
22478
     }
22479
 
22480
     if (mapPtr)
22481
@@ -395,6 +400,7 @@
22482
 }
22483
 
22484
 angle::Result BufferMtl::setDataImpl(const gl::Context *context,
22485
+                                     gl::BufferBinding target,
22486
                                      const void *data,
22487
                                      size_t intendedSize,
22488
                                      gl::BufferUsage usage)
22489
@@ -413,6 +419,13 @@
22490
 
22491
     size_t adjustedSize = std::max<size_t>(1, intendedSize);
22492
 
22493
+    // Ensures no validation layer issues in std140 with data types like vec3 being 12 bytes vs 16
22494
+    // in MSL.
22495
+    if (target == gl::BufferBinding::Uniform)
22496
+    {
22497
+        adjustedSize = roundUpPow2(adjustedSize, (size_t)16);
22498
+    }
22499
+
22500
     size_t maxBuffers;
22501
     switch (usage)
22502
     {
22503
@@ -427,7 +440,7 @@
22504
         default:
22505
             // dynamic buffer, allow up to 10 update per frame/encoding without
22506
             // waiting for GPU.
22507
-            if (adjustedSize <= mtl::kSharedMemBufferMaxBufSizeHint)
22508
+            if (adjustedSize <= kDynamicBufferPoolMaxBufSize)
22509
             {
22510
                 maxBuffers = 10;
22511
                 mBufferPool.setAlwaysUseSharedMem();
22512
diff --git a/src/libANGLE/renderer/metal/CompilerMtl.mm b/src/libANGLE/renderer/metal/CompilerMtl.mm
22513
index a586670..3e29b4d 100644
22514
--- a/src/libANGLE/renderer/metal/CompilerMtl.mm
22515
+++ b/src/libANGLE/renderer/metal/CompilerMtl.mm
22516
@@ -10,6 +10,7 @@
22517
 #include "libANGLE/renderer/metal/CompilerMtl.h"
22518
 
22519
 #include "common/debug.h"
22520
+#include "compiler/translator/TranslatorMetalDirect/EnvironmentVariable.h"
22521
 
22522
 namespace rx
22523
 {
22524
@@ -20,7 +21,16 @@
22525
 
22526
 ShShaderOutput CompilerMtl::getTranslatorOutputType() const
22527
 {
22528
+    if (sh::readBoolEnvVar("ANGLE_GEN_MTL_WITH_SPIRV"))
22529
+    {
22530
+        // We want to return GL output first, we can't actually
22531
+        // get MSL code until link time. Translation time is too early
22532
         return SH_GLSL_METAL_OUTPUT;
22533
+    }
22534
+    else
22535
+    {
22536
+        return SH_MSL_METAL_OUTPUT;
22537
+    }
22538
 }
22539
 
22540
 }  // namespace rx
22541
diff --git a/src/libANGLE/renderer/metal/ContextMtl.h b/src/libANGLE/renderer/metal/ContextMtl.h
22542
index 1687c8c..2f39371 100644
22543
--- a/src/libANGLE/renderer/metal/ContextMtl.h
22544
+++ b/src/libANGLE/renderer/metal/ContextMtl.h
22545
@@ -29,8 +29,8 @@ class FramebufferMtl;
22546
 class VertexArrayMtl;
22547
 class ProgramMtl;
22548
 class RenderTargetMtl;
22549
-class WindowSurfaceMtl;
22550
-class TransformFeedbackMtl;
22551
+class SurfaceMtlProtocol;
22552
+class BufferMtl;
22553
 
22554
 class ContextMtl : public ContextImpl, public mtl::Context
22555
 {
22556
@@ -85,7 +85,7 @@ class ContextMtl : public ContextImpl, public mtl::Context
22557
                                                   GLsizei count,
22558
                                                   gl::DrawElementsType type,
22559
                                                   const void *indices,
22560
-                                                  GLsizei instanceCount,
22561
+                                                  GLsizei instances,
22562
                                                   GLint baseVertex) override;
22563
     angle::Result drawElementsInstancedBaseVertexBaseInstance(const gl::Context *context,
22564
                                                               gl::PrimitiveMode mode,
22565
@@ -157,6 +157,12 @@ class ContextMtl : public ContextImpl, public mtl::Context
22566
                                                                    const GLint *baseVertices,
22567
                                                                    const GLuint *baseInstances,
22568
                                                                    GLsizei drawcount) override;
22569
+    angle::Result drawElementsSimpleTypesPrimitiveRestart(const gl::Context *context,
22570
+                                                          gl::PrimitiveMode mode,
22571
+                                                          GLsizei count,
22572
+                                                          gl::DrawElementsType type,
22573
+                                                          const void *indices,
22574
+                                                          GLsizei instances);
22575
 
22576
     // Device loss
22577
     gl::GraphicsResetStatus getResetStatus() override;
22578
@@ -196,6 +202,8 @@ class ContextMtl : public ContextImpl, public mtl::Context
22579
     const gl::Extensions &getNativeExtensions() const override;
22580
     const gl::Limitations &getNativeLimitations() const override;
22581
 
22582
+    const ProgramMtl *getProgram() const { return mProgram; }
22583
+
22584
     // Shader creation
22585
     CompilerImpl *createCompiler() override;
22586
     ShaderImpl *createShader(const gl::ShaderState &state) override;
22587
@@ -249,12 +257,24 @@ class ContextMtl : public ContextImpl, public mtl::Context
22588
     angle::Result memoryBarrier(const gl::Context *context, GLbitfield barriers) override;
22589
     angle::Result memoryBarrierByRegion(const gl::Context *context, GLbitfield barriers) override;
22590
 
22591
+    void invalidateCurrentTransformFeedbackBuffers();
22592
+    void onTransformFeedbackStateChanged();
22593
+    angle::Result onBeginTransformFeedback(
22594
+        size_t bufferCount,
22595
+        const gl::TransformFeedbackBuffersArray<BufferMtl *> &buffers);
22596
+
22597
+    void onEndTransformFeedback();
22598
+    angle::Result onPauseTransformFeedback();
22599
+
22600
+    void populateTransformFeedbackBufferSet(
22601
+        size_t bufferCount,
22602
+        const gl::TransformFeedbackBuffersArray<BufferMtl *> &buffers);
22603
     // override mtl::ErrorHandler
22604
     void handleError(GLenum error,
22605
                      const char *file,
22606
                      const char *function,
22607
                      unsigned int line) override;
22608
-    void handleError(NSError *_Nullable error,
22609
+    void handleError(NSError *error,
22610
                      const char *file,
22611
                      const char *function,
22612
                      unsigned int line) override;
22613
@@ -272,12 +292,12 @@ class ContextMtl : public ContextImpl, public mtl::Context
22614
     void onDrawFrameBufferChangedState(const gl::Context *context,
22615
                                        FramebufferMtl *framebuffer,
22616
                                        bool renderPassChanged);
22617
-    void onBackbufferResized(const gl::Context *context, WindowSurfaceMtl *backbuffer);
22618
+    void onBackbufferResized(const gl::Context *context, SurfaceMtlProtocol *backbuffer);
22619
 
22620
     // Invoke by QueryMtl
22621
-    angle::Result onOcclusionQueryBegin(const gl::Context *context, QueryMtl *query);
22622
-    void onOcclusionQueryEnd(const gl::Context *context, QueryMtl *query);
22623
-    void onOcclusionQueryDestroy(const gl::Context *context, QueryMtl *query);
22624
+    angle::Result onOcclusionQueryBegan(const gl::Context *context, QueryMtl *query);
22625
+    void onOcclusionQueryEnded(const gl::Context *context, QueryMtl *query);
22626
+    void onOcclusionQueryDestroyed(const gl::Context *context, QueryMtl *query);
22627
 
22628
     // Useful for temporarily pause then restart occlusion query during clear/blit with draw.
22629
     bool hasActiveOcclusionQuery() const { return mOcclusionQuery; }
22630
@@ -367,7 +387,7 @@ class ContextMtl : public ContextImpl, public mtl::Context
22631
                             GLsizei instanceCount,
22632
                             gl::DrawElementsType indexTypeOrNone,
22633
                             const void *indices,
22634
-                            bool xfbPass);
22635
+                            bool transformFeedbackDraw);
22636
 
22637
     angle::Result drawTriFanArrays(const gl::Context *context,
22638
                                    GLint first,
22639
@@ -417,6 +437,18 @@ class ContextMtl : public ContextImpl, public mtl::Context
22640
                                    const void *indices,
22641
                                    GLsizei instanceCount);
22642
 
22643
+    void execDrawInstanced(MTLPrimitiveType primitiveType,
22644
+                           uint32_t vertexStart,
22645
+                           uint32_t vertexCount,
22646
+                           uint32_t instances);
22647
+
22648
+    void execDrawIndexedInstanced(MTLPrimitiveType primitiveType,
22649
+                                  uint32_t indexCount,
22650
+                                  MTLIndexType indexType,
22651
+                                  const mtl::BufferRef &indexBuffer,
22652
+                                  size_t bufferOffset,
22653
+                                  uint32_t instances);
22654
+
22655
     void updateExtendedState(const gl::State &glState);
22656
 
22657
     void updateViewport(FramebufferMtl *framebufferMtl,
22658
@@ -442,6 +474,7 @@ class ContextMtl : public ContextImpl, public mtl::Context
22659
     angle::Result fillDriverXFBUniforms(GLint drawCallFirstVertex,
22660
                                         uint32_t verticesPerInstance,
22661
                                         uint32_t skippedInstances);
22662
+    angle::Result handleDirtyGraphicsTransformFeedbackBuffersEmulation(const gl::Context *context);
22663
     angle::Result handleDirtyDepthStencilState(const gl::Context *context);
22664
     angle::Result handleDirtyDepthBias(const gl::Context *context);
22665
     angle::Result handleDirtyRenderPass(const gl::Context *context);
22666
@@ -470,6 +503,7 @@ class ContextMtl : public ContextImpl, public mtl::Context
22667
         DIRTY_BIT_RENDER_PIPELINE,
22668
         DIRTY_BIT_UNIFORM_BUFFERS_BINDING,
22669
         DIRTY_BIT_RASTERIZER_DISCARD,
22670
+        DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS,
22671
         DIRTY_BIT_MAX,
22672
     };
22673
 
22674
@@ -488,7 +522,7 @@ class ContextMtl : public ContextImpl, public mtl::Context
22675
         uint32_t xfbActiveUnpaused;
22676
         uint32_t xfbVerticesPerDraw;
22677
         // NOTE: Explicit padding. Fill in with useful data when needed in the future.
22678
-        int32_t padding[3];
22679
+        int32_t padding_0[3];
22680
 
22681
         int32_t xfbBufferOffsets[4];
22682
         uint32_t acbBufferOffsets[4];
22683
@@ -508,12 +542,15 @@ class ContextMtl : public ContextImpl, public mtl::Context
22684
 
22685
         uint32_t coverageMask;
22686
 
22687
-        float padding2[3];
22688
+        int32_t emulatedInstanceID;
22689
+
22690
+        // NOTE: Explicit padding. Fill in with useful data when needed in the future.
22691
+        int32_t padding_1[2];
22692
     };
22693
 
22694
     struct DefaultAttribute
22695
     {
22696
-        uint8_t values[sizeof(float) * 4];
22697
+        float values[4];
22698
     };
22699
 
22700
     mtl::OcclusionQueryPool mOcclusionQueryPool;
22701
@@ -522,6 +559,13 @@ class ContextMtl : public ContextImpl, public mtl::Context
22702
     mtl::RenderCommandEncoder mRenderEncoder;
22703
     mtl::BlitCommandEncoder mBlitEncoder;
22704
     mtl::ComputeCommandEncoder mComputeEncoder;
22705
+    // TODO(jcunningham):
22706
+    // Cache the current draw call's firstVertex to be passed to
22707
+    // TransformFeedbackMtl::getBufferOffsets.  We should switch
22708
+    // to using gl_BaseVertex -> base_vertex in MSL
22709
+    GLint mXfbBaseVertex;
22710
+    // Cache the current draw call's vertex count as well to support instanced draw calls
22711
+    GLuint mXfbVertexCountPerInstance;
22712
 
22713
     // Cached back-end objects
22714
     FramebufferMtl *mDrawFramebuffer = nullptr;
22715
@@ -554,6 +598,8 @@ class ContextMtl : public ContextImpl, public mtl::Context
22716
     mtl::BufferPool mTriFanIndexBuffer;
22717
     // one buffer can be reused for any starting vertex in DrawArrays()
22718
     mtl::BufferRef mTriFanArraysIndexBuffer;
22719
+    //
22720
+    mtl::BufferPool mPrimitiveRestartBuffer;
22721
 
22722
     // Dummy texture to be used for transform feedback only pass.
22723
     mtl::TextureRef mDummyXFBRenderTexture;
22724
@@ -562,6 +608,9 @@ class ContextMtl : public ContextImpl, public mtl::Context
22725
 
22726
     DefaultAttribute mDefaultAttributes[mtl::kMaxVertexAttribs];
22727
 
22728
+    // Transform feedback buffers.
22729
+    std::unordered_set<const BufferMtl *> mCurrentTransformFeedbackBuffers;
22730
+
22731
     IncompleteTextureSet mIncompleteTextures;
22732
     bool mIncompleteTexturesInitialized = false;
22733
 };
22734
diff --git a/src/libANGLE/renderer/metal/ContextMtl.mm b/src/libANGLE/renderer/metal/ContextMtl.mm
22735
index 27e6978..45a0928 100644
22736
--- a/src/libANGLE/renderer/metal/ContextMtl.mm
22737
+++ b/src/libANGLE/renderer/metal/ContextMtl.mm
22738
@@ -44,25 +44,6 @@
22739
 constexpr uint32_t kMaxTriFanLineLoopBuffersPerFrame = 10;
22740
 #endif
22741
 
22742
-#define ANGLE_MTL_XFB_DRAW(DRAW_PROC)                                                       \
22743
-    if (!mState.isTransformFeedbackActiveUnpaused())                                        \
22744
-    {                                                                                       \
22745
-        /* Normal draw call */                                                              \
22746
-        DRAW_PROC(false);                                                                   \
22747
-    }                                                                                       \
22748
-    else                                                                                    \
22749
-    {                                                                                       \
22750
-        /* First pass: write to XFB buffers in vertex shader, fragment shader inactive */   \
22751
-        DRAW_PROC(true);                                                                    \
22752
-        if (!mState.isRasterizerDiscardEnabled())                                           \
22753
-        {                                                                                   \
22754
-            /* Second pass: full rasterization: vertex shader + fragment shader are active. \
22755
-               Vertex shader writes to stage output but won't write to XFB buffers */       \
22756
-            invalidateRenderPipeline();                                                     \
22757
-            DRAW_PROC(false);                                                               \
22758
-        }                                                                                   \
22759
-    }
22760
-
22761
 angle::Result AllocateTriangleFanBufferFromPool(ContextMtl *context,
22762
                                                 GLsizei vertexCount,
22763
                                                 mtl::BufferPool *pool,
22764
@@ -84,7 +65,7 @@
22765
     return angle::Result::Continue;
22766
 }
22767
 
22768
-angle::Result AllocateLineLoopBufferFromPool(ContextMtl *context,
22769
+angle::Result AllocateBufferFromPool(ContextMtl *context,
22770
                                      GLsizei indicesToReserve,
22771
                                      mtl::BufferPool *pool,
22772
                                      mtl::BufferRef *bufferOut,
22773
@@ -105,12 +86,7 @@ bool NeedToInvertDepthRange(float near, float far)
22774
     return near > far;
22775
 }
22776
 
22777
-bool IsTransformFeedbackOnly(const gl::State &glState)
22778
-{
22779
-    return glState.isTransformFeedbackActiveUnpaused() && glState.isRasterizerDiscardEnabled();
22780
-}
22781
-
22782
-std::string ConvertMarkerToString(GLsizei length, const char *marker)
22783
+std::string ConvertMarkerToCpp(GLsizei length, const char *marker)
22784
 {
22785
     std::string cppString;
22786
     if (length == 0)
22787
@@ -173,7 +149,7 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
22788
                     {indexTypeOrNone, vertexOrIndexCount, indices, mLineLoopIndexBuffer, 0}));
22789
         }
22790
 
22791
-        ANGLE_TRY(indexBufferPool->commit(mContextMtl));
22792
+        ANGLE_TRY(indexBufferPool->commit(mContextMtl, false));
22793
 
22794
         return angle::Result::Continue;
22795
     }
22796
@@ -191,7 +167,8 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
22797
       mCmdBuffer(&display->cmdQueue()),
22798
       mRenderEncoder(&mCmdBuffer, mOcclusionQueryPool),
22799
       mBlitEncoder(&mCmdBuffer),
22800
-      mComputeEncoder(&mCmdBuffer)
22801
+      mComputeEncoder(&mCmdBuffer),
22802
+      mXfbVertexCountPerInstance(0)
22803
 {}
22804
 
22805
 ContextMtl::~ContextMtl() {}
22806
@@ -208,6 +185,8 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
22807
     mLineLoopLastSegmentIndexBuffer.initialize(this, 2 * sizeof(uint32_t),
22808
                                                mtl::kIndexBufferOffsetAlignment,
22809
                                                kMaxTriFanLineLoopBuffersPerFrame);
22810
+    mPrimitiveRestartBuffer.initialize(this, 0, mtl::kIndexBufferOffsetAlignment,
22811
+                                       kMaxTriFanLineLoopBuffersPerFrame);
22812
 
22813
     return angle::Result::Continue;
22814
 }
22815
@@ -227,23 +206,20 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
22816
 
22817
 angle::Result ContextMtl::ensureIncompleteTexturesCreated(const gl::Context *context)
22818
 {
22819
-    if (ANGLE_LIKELY(mIncompleteTexturesInitialized))
22820
+    if (ANGLE_UNLIKELY(!mIncompleteTexturesInitialized))
22821
     {
22822
-        return angle::Result::Continue;
22823
-    }
22824
-    constexpr gl::TextureType supportedTextureTypes[] = {gl::TextureType::_2D, gl::TextureType::_3D,
22825
-                                                         gl::TextureType::_2DArray,
22826
+        constexpr gl::TextureType supportedTextureTypes[] = {
22827
+            gl::TextureType::_2D, gl::TextureType::_2DArray, gl::TextureType::_3D,
22828
             gl::TextureType::CubeMap};
22829
-    for (gl::TextureType texType : supportedTextureTypes)
22830
+        for (auto texType : supportedTextureTypes)
22831
         {
22832
             gl::Texture *texture;
22833
-        ANGLE_TRY(mIncompleteTextures.getIncompleteTexture(context, texType, nullptr, &texture));
22834
-
22835
-        TextureMtl *textureMtl                      = mtl::GetImpl(texture);
22836
-        textureMtl->getNativeTexture()->get().label = @"IncompleteTexture";
22837
+            ANGLE_UNUSED_VARIABLE(texture);
22838
+            ANGLE_TRY(
22839
+                mIncompleteTextures.getIncompleteTexture(context, texType, nullptr, &texture));
22840
         }
22841
         mIncompleteTexturesInitialized = true;
22842
-
22843
+    }
22844
     return angle::Result::Continue;
22845
 }
22846
 
22847
@@ -282,7 +258,17 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
22848
             this, {0, static_cast<uint32_t>(count), mTriFanArraysIndexBuffer, 0}));
22849
     }
22850
 
22851
-    ASSERT(!getState().isTransformFeedbackActiveUnpaused());
22852
+    if (mState.isTransformFeedbackActiveUnpaused())
22853
+    {
22854
+        ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, first, count, instances,
22855
+                            gl::DrawElementsType::InvalidEnum, reinterpret_cast<const void *>(0),
22856
+                            true));
22857
+        // Draw with the zero starting index buffer, shift the vertex index using baseVertex
22858
+        // instanced draw:
22859
+        mRenderEncoder.drawIndexedInstancedBaseVertex(MTLPrimitiveTypeTriangle, genIndicesCount,
22860
+                                                      MTLIndexTypeUInt32, mTriFanArraysIndexBuffer,
22861
+                                                      0, instances, first);
22862
+    }
22863
 
22864
     ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, first, count, instances,
22865
                         gl::DrawElementsType::InvalidEnum, reinterpret_cast<const void *>(0),
22866
@@ -311,16 +297,23 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
22867
         this, {static_cast<uint32_t>(first), static_cast<uint32_t>(count), genIdxBuffer,
22868
                genIdxBufferOffset}));
22869
 
22870
-    ANGLE_TRY(mTriFanIndexBuffer.commit(this));
22871
+    ANGLE_TRY(mTriFanIndexBuffer.commit(this, false));
22872
 
22873
-    ASSERT(!getState().isTransformFeedbackActiveUnpaused());
22874
+    if (mState.isTransformFeedbackActiveUnpaused())
22875
+    {
22876
+        ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, first, count, instances,
22877
+                            gl::DrawElementsType::InvalidEnum, reinterpret_cast<const void *>(0),
22878
+                            true));
22879
 
22880
+        execDrawIndexedInstanced(MTLPrimitiveTypeTriangle, genIndicesCount, MTLIndexTypeUInt32,
22881
+                                 genIdxBuffer, genIdxBufferOffset, instances);
22882
+    }
22883
     ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, first, count, instances,
22884
                         gl::DrawElementsType::InvalidEnum, reinterpret_cast<const void *>(0),
22885
                         false));
22886
 
22887
-    mRenderEncoder.drawIndexed(MTLPrimitiveTypeTriangle, genIndicesCount, MTLIndexTypeUInt32,
22888
-                               genIdxBuffer, genIdxBufferOffset);
22889
+    execDrawIndexedInstanced(MTLPrimitiveTypeTriangle, genIndicesCount, MTLIndexTypeUInt32,
22890
+                             genIdxBuffer, genIdxBufferOffset, instances);
22891
 
22892
     return angle::Result::Continue;
22893
 }
22894
@@ -368,22 +361,27 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
22895
     uint32_t genIdxBufferOffset;
22896
     uint32_t genIndicesCount = count + 1;
22897
 
22898
-    ANGLE_TRY(AllocateLineLoopBufferFromPool(this, genIndicesCount, &mLineLoopIndexBuffer,
22899
-                                             &genIdxBuffer, &genIdxBufferOffset));
22900
+    ANGLE_TRY(AllocateBufferFromPool(this, genIndicesCount, &mLineLoopIndexBuffer, &genIdxBuffer,
22901
+                                     &genIdxBufferOffset));
22902
     ANGLE_TRY(getDisplay()->getUtils().generateLineLoopBufferFromArrays(
22903
         this, {static_cast<uint32_t>(first), static_cast<uint32_t>(count), genIdxBuffer,
22904
                genIdxBufferOffset}));
22905
 
22906
-    ANGLE_TRY(mLineLoopIndexBuffer.commit(this));
22907
+    ANGLE_TRY(mLineLoopIndexBuffer.commit(this, false));
22908
 
22909
-    ASSERT(!getState().isTransformFeedbackActiveUnpaused());
22910
+    if (mState.isTransformFeedbackActiveUnpaused())
22911
+    {
22912
+        ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::LineLoop, first, count, instances,
22913
+                            gl::DrawElementsType::InvalidEnum, nullptr, true));
22914
 
22915
+        execDrawIndexedInstanced(MTLPrimitiveTypeLineStrip, genIndicesCount, MTLIndexTypeUInt32,
22916
+                                 genIdxBuffer, genIdxBufferOffset, instances);
22917
+    }
22918
     ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::LineLoop, first, count, instances,
22919
                         gl::DrawElementsType::InvalidEnum, nullptr, false));
22920
 
22921
-    mRenderEncoder.drawIndexedInstanced(MTLPrimitiveTypeLineStrip, genIndicesCount,
22922
-                                        MTLIndexTypeUInt32, genIdxBuffer, genIdxBufferOffset,
22923
-                                        instances);
22924
+    execDrawIndexedInstanced(MTLPrimitiveTypeLineStrip, genIndicesCount, MTLIndexTypeUInt32,
22925
+                             genIdxBuffer, genIdxBufferOffset, instances);
22926
 
22927
     return angle::Result::Continue;
22928
 }
22929
@@ -413,21 +411,33 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
22930
 
22931
     MTLPrimitiveType mtlType = mtl::GetPrimitiveType(mode);
22932
 
22933
-#define DRAW_GENERIC_ARRAY(xfbPass)                                                                \
22934
-    ANGLE_TRY(setupDraw(context, mode, first, count, instances, gl::DrawElementsType::InvalidEnum, \
22935
-                        nullptr, xfbPass));                                                        \
22936
-                                                                                                   \
22937
-    if (instances == 0)                                                                            \
22938
-    {                                                                                              \
22939
-        /* This method is called from normal drawArrays() */                                       \
22940
-        mRenderEncoder.draw(mtlType, first, count);                                                \
22941
-    }                                                                                              \
22942
-    else                                                                                           \
22943
-    {                                                                                              \
22944
-        mRenderEncoder.drawInstanced(mtlType, first, count, instanceCount);                        \
22945
+    if (mState.isTransformFeedbackActiveUnpaused())
22946
+    {
22947
+        ANGLE_TRY(setupDraw(context, mode, first, count, instances,
22948
+                            gl::DrawElementsType::InvalidEnum, nullptr, true));
22949
+
22950
+        if (instances == 0)
22951
+        {
22952
+            // This method is called from normal drawArrays()
22953
+            mRenderEncoder.draw(mtlType, first, count);
22954
+        }
22955
+        else
22956
+        {
22957
+            execDrawInstanced(mtlType, first, count, instanceCount);
22958
+        }
22959
     }
22960
+    ANGLE_TRY(setupDraw(context, mode, first, count, instances, gl::DrawElementsType::InvalidEnum,
22961
+                        nullptr, false));
22962
 
22963
-    ANGLE_MTL_XFB_DRAW(DRAW_GENERIC_ARRAY)
22964
+    if (instances == 0)
22965
+    {
22966
+        // This method is called from normal drawArrays()
22967
+        mRenderEncoder.draw(mtlType, first, count);
22968
+    }
22969
+    else
22970
+    {
22971
+        execDrawInstanced(mtlType, first, count, instanceCount);
22972
+    }
22973
 
22974
     return angle::Result::Continue;
22975
 }
22976
@@ -480,16 +490,25 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
22977
                                                     &genIdxBufferOffset, &genIndicesCount));
22978
 
22979
         ANGLE_TRY(getDisplay()->getUtils().generateTriFanBufferFromElementsArray(
22980
-            this, {type, count, indices, genIdxBuffer, genIdxBufferOffset, primitiveRestart}));
22981
+            this, {type, count, indices, genIdxBuffer, genIdxBufferOffset, primitiveRestart},
22982
+            &genIndicesCount));
22983
 
22984
-        ANGLE_TRY(mTriFanIndexBuffer.commit(this));
22985
+        ANGLE_TRY(mTriFanIndexBuffer.commit(this, false));
22986
+
22987
+        if (mState.isTransformFeedbackActiveUnpaused())
22988
+        {
22989
+            ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, 0, count, instances, type,
22990
+                                indices, true));
22991
+
22992
+            execDrawIndexedInstanced(MTLPrimitiveTypeTriangle, genIndicesCount, MTLIndexTypeUInt32,
22993
+                                     genIdxBuffer, genIdxBufferOffset, instances);
22994
+        }
22995
 
22996
         ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, 0, count, instances, type,
22997
                             indices, false));
22998
 
22999
-        mRenderEncoder.drawIndexedInstanced(MTLPrimitiveTypeTriangle, genIndicesCount,
23000
-                                            MTLIndexTypeUInt32, genIdxBuffer, genIdxBufferOffset,
23001
-                                            instances);
23002
+        execDrawIndexedInstanced(MTLPrimitiveTypeTriangle, genIndicesCount, MTLIndexTypeUInt32,
23003
+                                 genIdxBuffer, genIdxBufferOffset, instances);
23004
 
23005
         return angle::Result::Continue;
23006
     }  // if (count > 3)
23007
@@ -532,27 +551,87 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23008
         uint32_t genIdxBufferOffset;
23009
         uint32_t reservedIndices = count * 2;
23010
         uint32_t genIndicesCount;
23011
-        ANGLE_TRY(AllocateLineLoopBufferFromPool(this, reservedIndices, &mLineLoopIndexBuffer,
23012
+        ANGLE_TRY(AllocateBufferFromPool(this, reservedIndices, &mLineLoopIndexBuffer,
23013
                                          &genIdxBuffer, &genIdxBufferOffset));
23014
 
23015
         ANGLE_TRY(getDisplay()->getUtils().generateLineLoopBufferFromElementsArray(
23016
             this, {type, count, indices, genIdxBuffer, genIdxBufferOffset, primitiveRestart},
23017
             &genIndicesCount));
23018
 
23019
-        ANGLE_TRY(mLineLoopIndexBuffer.commit(this));
23020
+        ANGLE_TRY(mLineLoopIndexBuffer.commit(this, false));
23021
+
23022
+        if (mState.isTransformFeedbackActiveUnpaused())
23023
+        {
23024
+            ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::LineLoop, 0, count, instances, type,
23025
+                                indices, true));
23026
+
23027
+            execDrawIndexedInstanced(MTLPrimitiveTypeLineStrip, genIndicesCount, MTLIndexTypeUInt32,
23028
+                                     genIdxBuffer, genIdxBufferOffset, instances);
23029
+        }
23030
 
23031
         ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::LineLoop, 0, count, instances, type,
23032
                             indices, false));
23033
 
23034
-        mRenderEncoder.drawIndexedInstanced(MTLPrimitiveTypeLineStrip, genIndicesCount,
23035
-                                            MTLIndexTypeUInt32, genIdxBuffer, genIdxBufferOffset,
23036
-                                            instances);
23037
+        execDrawIndexedInstanced(MTLPrimitiveTypeLineStrip, genIndicesCount, MTLIndexTypeUInt32,
23038
+                                 genIdxBuffer, genIdxBufferOffset, instances);
23039
 
23040
         return angle::Result::Continue;
23041
     }  // if (count >= 2)
23042
     return drawElementsInstanced(context, gl::PrimitiveMode::Lines, count, type, indices,
23043
                                  instances);
23044
 }
23045
+angle::Result ContextMtl::drawElementsSimpleTypesPrimitiveRestart(const gl::Context *context,
23046
+                                                                  gl::PrimitiveMode mode,
23047
+                                                                  GLsizei count,
23048
+                                                                  gl::DrawElementsType type,
23049
+                                                                  const void *indices,
23050
+                                                                  GLsizei instances)
23051
+{
23052
+
23053
+    mtl::BufferRef genIdxBuffer;
23054
+    uint32_t genIdxBufferOffset;
23055
+    uint32_t reservedIndices = count;
23056
+    size_t genIndicesCount;
23057
+    ANGLE_TRY(AllocateBufferFromPool(this, reservedIndices, &mPrimitiveRestartBuffer, &genIdxBuffer,
23058
+                                     &genIdxBufferOffset));
23059
+    switch (mode)
23060
+    {
23061
+        case gl::PrimitiveMode::Points:
23062
+            ANGLE_TRY(getDisplay()->getUtils().generatePrimitiveRestartPointsBuffer(
23063
+                this, {type, count, indices, genIdxBuffer, genIdxBufferOffset, true},
23064
+                &genIndicesCount));
23065
+            break;
23066
+        case gl::PrimitiveMode::Lines:
23067
+            ANGLE_TRY(getDisplay()->getUtils().generatePrimitiveRestartLinesBuffer(
23068
+                this, {type, count, indices, genIdxBuffer, genIdxBufferOffset, true},
23069
+                &genIndicesCount));
23070
+            break;
23071
+        case gl::PrimitiveMode::Triangles:
23072
+            ANGLE_TRY(getDisplay()->getUtils().generatePrimitiveRestartTrianglesBuffer(
23073
+                this, {type, count, indices, genIdxBuffer, genIdxBufferOffset, true},
23074
+                &genIndicesCount));
23075
+            break;
23076
+        default:
23077
+            UNREACHABLE();
23078
+            return angle::Result::Stop;
23079
+    }
23080
+    ANGLE_TRY(mPrimitiveRestartBuffer.commit(this));
23081
+    MTLPrimitiveType mtlType = mtl::GetPrimitiveType(mode);
23082
+    if (mState.isTransformFeedbackActiveUnpaused())
23083
+    {
23084
+        ANGLE_TRY(setupDraw(context, mode, 0, count, instances, type,
23085
+                            reinterpret_cast<const void *>(0), true));
23086
+
23087
+        execDrawIndexedInstanced(mtlType, (uint32_t)genIndicesCount, MTLIndexTypeUInt32,
23088
+                                 genIdxBuffer, genIdxBufferOffset, instances);
23089
+    }
23090
+    ANGLE_TRY(setupDraw(context, mode, 0, count, instances, type, indices, false));
23091
+
23092
+    execDrawIndexedInstanced(mtlType, (uint32_t)genIndicesCount, MTLIndexTypeUInt32, genIdxBuffer,
23093
+                             genIdxBufferOffset, instances);
23094
+
23095
+    return angle::Result::Continue;
23096
+}
23097
 
23098
 angle::Result ContextMtl::drawElementsImpl(const gl::Context *context,
23099
                                            gl::PrimitiveMode mode,
23100
@@ -563,7 +642,6 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23101
 {
23102
     // Real instances count. Zero means this is not instanced draw.
23103
     GLsizei instanceCount = instances ? instances : 1;
23104
-
23105
     if (mCullAllPolygons && gl::IsPolygonMode(mode))
23106
     {
23107
         return angle::Result::Continue;
23108
@@ -577,18 +655,39 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23109
     {
23110
         return drawLineLoopElements(context, count, type, indices, instanceCount);
23111
     }
23112
-
23113
     mtl::BufferRef idxBuffer;
23114
     size_t convertedOffset             = 0;
23115
     gl::DrawElementsType convertedType = type;
23116
+    size_t convertedCount              = (size_t)count;
23117
 
23118
-    ANGLE_TRY(mVertexArray->getIndexBuffer(context, type, count, indices, &idxBuffer,
23119
-                                           &convertedOffset, &convertedType));
23120
+    ANGLE_TRY(mVertexArray->getIndexBuffer(context, type, mode, count, indices, &idxBuffer,
23121
+                                           &convertedOffset, &convertedType, &convertedCount));
23122
 
23123
     ASSERT(idxBuffer);
23124
     ASSERT((convertedOffset % mtl::kIndexBufferOffsetAlignment) == 0);
23125
+    uint32_t convertedCounti32 = (uint32_t)convertedCount;
23126
+    if (mState.isTransformFeedbackActiveUnpaused())
23127
+    {
23128
+        ANGLE_TRY(setupDraw(context, mode, 0, convertedCounti32, instances, type, indices, true));
23129
+        MTLPrimitiveType mtlType = mtl::GetPrimitiveType(mode);
23130
 
23131
-    ANGLE_TRY(setupDraw(context, mode, 0, count, instances, type, indices, false));
23132
+        MTLIndexType mtlIdxType = mtl::GetIndexType(convertedType);
23133
+
23134
+        if (instances == 0)
23135
+        {
23136
+            // Normal draw
23137
+            mRenderEncoder.drawIndexed(mtlType, convertedCounti32, mtlIdxType, idxBuffer,
23138
+                                       convertedOffset);
23139
+        }
23140
+        else
23141
+        {
23142
+            // Instanced draw
23143
+            execDrawIndexedInstanced(mtlType, convertedCounti32, mtlIdxType, idxBuffer,
23144
+                                     convertedOffset, instanceCount);
23145
+        }
23146
+    }
23147
+
23148
+    ANGLE_TRY(setupDraw(context, mode, 0, convertedCounti32, instances, type, indices, false));
23149
 
23150
     MTLPrimitiveType mtlType = mtl::GetPrimitiveType(mode);
23151
 
23152
@@ -597,12 +696,13 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23153
     if (instances == 0)
23154
     {
23155
         // Normal draw
23156
-        mRenderEncoder.drawIndexed(mtlType, count, mtlIdxType, idxBuffer, convertedOffset);
23157
+        mRenderEncoder.drawIndexed(mtlType, convertedCounti32, mtlIdxType, idxBuffer,
23158
+                                   convertedOffset);
23159
     }
23160
     else
23161
     {
23162
         // Instanced draw
23163
-        mRenderEncoder.drawIndexedInstanced(mtlType, count, mtlIdxType, idxBuffer, convertedOffset,
23164
+        execDrawIndexedInstanced(mtlType, convertedCounti32, mtlIdxType, idxBuffer, convertedOffset,
23165
                                  instanceCount);
23166
     }
23167
 
23168
@@ -625,7 +725,6 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23169
                                                  const void *indices,
23170
                                                  GLint baseVertex)
23171
 {
23172
-    // NOTE(hqle): ES 3.2
23173
     UNIMPLEMENTED();
23174
     return angle::Result::Stop;
23175
 }
23176
@@ -649,10 +748,9 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23177
                                                           GLsizei count,
23178
                                                           gl::DrawElementsType type,
23179
                                                           const void *indices,
23180
-                                                          GLsizei instanceCount,
23181
+                                                          GLsizei instances,
23182
                                                           GLint baseVertex)
23183
 {
23184
-    // NOTE(hqle): ES 3.2
23185
     UNIMPLEMENTED();
23186
     return angle::Result::Stop;
23187
 }
23188
@@ -669,7 +767,6 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23189
     UNIMPLEMENTED();
23190
     return angle::Result::Stop;
23191
 }
23192
-
23193
 angle::Result ContextMtl::drawRangeElements(const gl::Context *context,
23194
                                             gl::PrimitiveMode mode,
23195
                                             GLuint start,
23196
@@ -690,7 +787,6 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23197
                                                       const void *indices,
23198
                                                       GLint baseVertex)
23199
 {
23200
-    // NOTE(hqle): ES 3.2
23201
     UNIMPLEMENTED();
23202
     return angle::Result::Stop;
23203
 }
23204
@@ -713,6 +809,64 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23205
     return angle::Result::Stop;
23206
 }
23207
 
23208
+void ContextMtl::execDrawInstanced(MTLPrimitiveType primitiveType,
23209
+                                   uint32_t vertexStart,
23210
+                                   uint32_t vertexCount,
23211
+                                   uint32_t instances)
23212
+{
23213
+    if (getDisplay()->getFeatures().hasBaseVertexInstancedDraw.enabled)
23214
+    {
23215
+        mRenderEncoder.drawInstanced(primitiveType, vertexStart, vertexCount, instances);
23216
+    }
23217
+    else
23218
+    {
23219
+        mRenderEncoder.draw(primitiveType, vertexStart, vertexCount);
23220
+        for (uint32_t inst = 1; inst < instances; ++inst)
23221
+        {
23222
+            mDriverUniforms.emulatedInstanceID = inst;
23223
+
23224
+            mRenderEncoder.setVertexData(mDriverUniforms, mtl::kDriverUniformsBindingIndex);
23225
+
23226
+            mVertexArray->emulateInstanceDrawStep(&mRenderEncoder, inst);
23227
+
23228
+            mRenderEncoder.draw(primitiveType, vertexStart, vertexCount);
23229
+        }
23230
+        // Reset instance ID to zero
23231
+        mVertexArray->emulateInstanceDrawStep(&mRenderEncoder, 0);
23232
+    }
23233
+}
23234
+
23235
+void ContextMtl::execDrawIndexedInstanced(MTLPrimitiveType primitiveType,
23236
+                                          uint32_t indexCount,
23237
+                                          MTLIndexType indexType,
23238
+                                          const mtl::BufferRef &indexBuffer,
23239
+                                          size_t bufferOffset,
23240
+                                          uint32_t instances)
23241
+{
23242
+    if (getDisplay()->getFeatures().hasBaseVertexInstancedDraw.enabled)
23243
+    {
23244
+        mRenderEncoder.drawIndexedInstanced(primitiveType, indexCount, indexType, indexBuffer,
23245
+                                            bufferOffset, instances);
23246
+    }
23247
+    else
23248
+    {
23249
+        mRenderEncoder.drawIndexed(primitiveType, indexCount, indexType, indexBuffer, bufferOffset);
23250
+        for (uint32_t inst = 1; inst < instances; ++inst)
23251
+        {
23252
+            mDriverUniforms.emulatedInstanceID = inst;
23253
+
23254
+            mRenderEncoder.setVertexData(mDriverUniforms, mtl::kDriverUniformsBindingIndex);
23255
+
23256
+            mVertexArray->emulateInstanceDrawStep(&mRenderEncoder, inst);
23257
+
23258
+            mRenderEncoder.drawIndexed(primitiveType, indexCount, indexType, indexBuffer,
23259
+                                       bufferOffset);
23260
+        }
23261
+        // Reset instance ID to zero
23262
+        mVertexArray->emulateInstanceDrawStep(&mRenderEncoder, 0);
23263
+    }
23264
+}
23265
+
23266
 angle::Result ContextMtl::multiDrawArrays(const gl::Context *context,
23267
                                           gl::PrimitiveMode mode,
23268
                                           const GLint *firsts,
23269
@@ -802,15 +956,15 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23270
 // EXT_debug_marker
23271
 angle::Result ContextMtl::insertEventMarker(GLsizei length, const char *marker)
23272
 {
23273
+    mCmdBuffer.insertDebugSign(ConvertMarkerToCpp(length, marker));
23274
     return angle::Result::Continue;
23275
 }
23276
 
23277
 angle::Result ContextMtl::pushGroupMarker(GLsizei length, const char *marker)
23278
 {
23279
-    mCmdBuffer.pushDebugGroup(ConvertMarkerToString(length, marker));
23280
+    mCmdBuffer.pushDebugGroup(ConvertMarkerToCpp(length, marker));
23281
     return angle::Result::Continue;
23282
 }
23283
-
23284
 angle::Result ContextMtl::popGroupMarker()
23285
 {
23286
     mCmdBuffer.popDebugGroup();
23287
@@ -1155,10 +1309,12 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23288
 {
23289
     return new QueryMtl(type);
23290
 }
23291
+
23292
 FenceNVImpl *ContextMtl::createFenceNV()
23293
 {
23294
     return new FenceNVMtl();
23295
 }
23296
+
23297
 SyncImpl *ContextMtl::createSync()
23298
 {
23299
     return new SyncMtl();
23300
@@ -1205,6 +1361,69 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23301
     return nullptr;
23302
 }
23303
 
23304
+void ContextMtl::invalidateCurrentTransformFeedbackBuffers()
23305
+{
23306
+    if (getDisplay()->getFeatures().emulateTransformFeedback.enabled)
23307
+    {
23308
+        mDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
23309
+    }
23310
+}
23311
+
23312
+void ContextMtl::onTransformFeedbackStateChanged()
23313
+{
23314
+    if (getDisplay()->getFeatures().emulateTransformFeedback.enabled)
23315
+    {
23316
+        invalidateDriverUniforms();
23317
+    }
23318
+}
23319
+
23320
+angle::Result ContextMtl::onBeginTransformFeedback(
23321
+    size_t bufferCount,
23322
+    const gl::TransformFeedbackBuffersArray<BufferMtl *> &buffers)
23323
+{
23324
+    onTransformFeedbackStateChanged();
23325
+
23326
+    for (size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
23327
+    {
23328
+        if (mCurrentTransformFeedbackBuffers.count(buffers[bufferIndex]) != 0)
23329
+        {
23330
+            endEncoding(mRenderEncoder);
23331
+            break;
23332
+        }
23333
+    }
23334
+
23335
+    populateTransformFeedbackBufferSet(bufferCount, buffers);
23336
+
23337
+    return angle::Result::Continue;
23338
+}
23339
+
23340
+void ContextMtl::populateTransformFeedbackBufferSet(
23341
+    size_t bufferCount,
23342
+    const gl::TransformFeedbackBuffersArray<BufferMtl *> &buffers)
23343
+{
23344
+    for (size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
23345
+    {
23346
+        mCurrentTransformFeedbackBuffers.insert(buffers[bufferIndex]);
23347
+    }
23348
+}
23349
+
23350
+void ContextMtl::onEndTransformFeedback()
23351
+{
23352
+    if (getDisplay()->getFeatures().emulateTransformFeedback.enabled)
23353
+    {
23354
+        onTransformFeedbackStateChanged();
23355
+    }
23356
+}
23357
+
23358
+angle::Result ContextMtl::onPauseTransformFeedback()
23359
+{
23360
+    if (getDisplay()->getFeatures().emulateTransformFeedback.enabled)
23361
+    {
23362
+        onTransformFeedbackStateChanged();
23363
+    }
23364
+    return angle::Result::Continue;
23365
+}
23366
+
23367
 angle::Result ContextMtl::dispatchCompute(const gl::Context *context,
23368
                                           GLuint numGroupsX,
23369
                                           GLuint numGroupsY,
23370
@@ -1331,6 +1550,11 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23371
     return getDisplay()->getPixelFormat(angleFormatId);
23372
 }
23373
 
23374
+const mtl::FormatCaps &ContextMtl::getNativeFormatCaps(MTLPixelFormat mtlFormat) const
23375
+{
23376
+    return getDisplay()->getNativeFormatCaps(mtlFormat);
23377
+}
23378
+
23379
 // See mtl::FormatTable::getVertexFormat()
23380
 const mtl::VertexFormat &ContextMtl::getVertexFormat(angle::FormatID angleFormatId,
23381
                                                      bool tightlyPacked) const
23382
@@ -1338,11 +1562,6 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23383
     return getDisplay()->getVertexFormat(angleFormatId, tightlyPacked);
23384
 }
23385
 
23386
-const mtl::FormatCaps &ContextMtl::getNativeFormatCaps(MTLPixelFormat mtlFormat) const
23387
-{
23388
-    return getDisplay()->getNativeFormatCaps(mtlFormat);
23389
-}
23390
-
23391
 angle::Result ContextMtl::getIncompleteTexture(const gl::Context *context,
23392
                                                gl::TextureType type,
23393
                                                gl::Texture **textureOut)
23394
@@ -1362,6 +1581,22 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23395
 
23396
     // Resolve visibility results
23397
     mOcclusionQueryPool.resolveVisibilityResults(this);
23398
+
23399
+    mCurrentTransformFeedbackBuffers.clear();
23400
+
23401
+    // Reset serials for XFB if active.
23402
+    if (mState.isTransformFeedbackActiveUnpaused())
23403
+    {
23404
+        const gl::ProgramExecutable *executable = mState.getProgramExecutable();
23405
+        ASSERT(executable);
23406
+        size_t xfbBufferCount = executable->getTransformFeedbackBufferCount();
23407
+
23408
+        TransformFeedbackMtl *transformFeedbackMtl =
23409
+            mtl::GetImpl(mState.getCurrentTransformFeedback());
23410
+
23411
+        populateTransformFeedbackBufferSet(xfbBufferCount,
23412
+                                           transformFeedbackMtl->getBufferHandles());
23413
+    }
23414
 }
23415
 
23416
 void ContextMtl::endEncoding(bool forceSaveRenderPassContent)
23417
@@ -1390,7 +1625,7 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23418
 
23419
 void ContextMtl::flushCommandBufer()
23420
 {
23421
-    if (!mCmdBuffer.ready())
23422
+    if (!mCmdBuffer.valid())
23423
     {
23424
         return;
23425
     }
23426
@@ -1454,6 +1689,27 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23427
     // Need to re-apply everything on next draw call.
23428
     mDirtyBits.set();
23429
 
23430
+    id<MTLDevice> metalDevice = getDisplay()->getMetalDevice();
23431
+    if (mtl::DeviceHasMaximumRenderTargetSize(metalDevice))
23432
+    {
23433
+        MTLRenderPassDescriptor *objCDesc = [MTLRenderPassDescriptor renderPassDescriptor];
23434
+        desc.convertToMetalDesc(objCDesc);
23435
+        NSUInteger maxSize = mtl::GetMaxRenderTargetSizeForDeviceInBytes(metalDevice);
23436
+        NSUInteger renderTargetSize =
23437
+            ComputeTotalSizeUsedForMTLRenderPassDescriptor(objCDesc, this, metalDevice);
23438
+        if (renderTargetSize > maxSize)
23439
+        {
23440
+            NSString *errorString =
23441
+                [NSString stringWithFormat:@"This set of render targets requires %lu bytes of "
23442
+                                           @"pixel storage. This device supports %lu bytes.",
23443
+                                           renderTargetSize, maxSize];
23444
+            NSError *err = [NSError errorWithDomain:@"MTLValidationError"
23445
+                                               code:-1
23446
+                                           userInfo:@{NSLocalizedDescriptionKey : errorString}];
23447
+            this->handleError(err, __FILE__, ANGLE_FUNCTION, __LINE__);
23448
+            return nil;
23449
+        }
23450
+    }
23451
     return &mRenderEncoder.restart(desc);
23452
 }
23453
 
23454
@@ -1467,9 +1723,10 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23455
 
23456
     mtl::RenderPassDesc rpDesc;
23457
 
23458
-    rpDesc.colorAttachments[0].texture      = textureTarget;
23459
-    rpDesc.colorAttachments[0].level        = index.getNativeLevel();
23460
-    rpDesc.colorAttachments[0].sliceOrDepth = index.hasLayer() ? index.getLayerIndex() : 0;
23461
+    rpDesc.colorAttachments[0].renderTarget->texture = textureTarget;
23462
+    rpDesc.colorAttachments[0].renderTarget->level   = index.getNativeLevel();
23463
+    rpDesc.colorAttachments[0].renderTarget->sliceOrDepth =
23464
+        index.hasLayer() ? index.getLayerIndex() : 0;
23465
     rpDesc.numColorAttachments = 1;
23466
     rpDesc.sampleCount         = textureTarget->samples();
23467
 
23468
@@ -1536,12 +1793,12 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23469
 
23470
 void ContextMtl::ensureCommandBufferReady()
23471
 {
23472
-    if (!mCmdBuffer.ready())
23473
+    if (!mCmdBuffer.valid())
23474
     {
23475
         mCmdBuffer.restart();
23476
     }
23477
 
23478
-    ASSERT(mCmdBuffer.ready());
23479
+    ASSERT(mCmdBuffer.valid());
23480
 }
23481
 
23482
 void ContextMtl::updateViewport(FramebufferMtl *framebufferMtl,
23483
@@ -1677,7 +1934,7 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23484
     }
23485
 }
23486
 
23487
-void ContextMtl::onBackbufferResized(const gl::Context *context, WindowSurfaceMtl *backbuffer)
23488
+void ContextMtl::onBackbufferResized(const gl::Context *context, SurfaceMtlProtocol *backbuffer)
23489
 {
23490
     const gl::State &glState    = getState();
23491
     FramebufferMtl *framebuffer = mtl::GetImpl(glState.getDrawFramebuffer());
23492
@@ -1686,10 +1943,13 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23493
         return;
23494
     }
23495
 
23496
+    updateViewport(framebuffer, glState.getViewport(), glState.getNearPlane(),
23497
+                   glState.getFarPlane());
23498
+    updateScissor(glState);
23499
     onDrawFrameBufferChangedState(context, framebuffer, true);
23500
 }
23501
 
23502
-angle::Result ContextMtl::onOcclusionQueryBegin(const gl::Context *context, QueryMtl *query)
23503
+angle::Result ContextMtl::onOcclusionQueryBegan(const gl::Context *context, QueryMtl *query)
23504
 {
23505
     ASSERT(mOcclusionQuery == nullptr);
23506
     mOcclusionQuery = query;
23507
@@ -1706,7 +1966,7 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23508
 
23509
     return angle::Result::Continue;
23510
 }
23511
-void ContextMtl::onOcclusionQueryEnd(const gl::Context *context, QueryMtl *query)
23512
+void ContextMtl::onOcclusionQueryEnded(const gl::Context *context, QueryMtl *query)
23513
 {
23514
     ASSERT(mOcclusionQuery == query);
23515
 
23516
@@ -1718,7 +1978,7 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23517
 
23518
     mOcclusionQuery = nullptr;
23519
 }
23520
-void ContextMtl::onOcclusionQueryDestroy(const gl::Context *context, QueryMtl *query)
23521
+void ContextMtl::onOcclusionQueryDestroyed(const gl::Context *context, QueryMtl *query)
23522
 {
23523
     if (query->getAllocatedVisibilityOffsets().empty())
23524
     {
23525
@@ -1726,7 +1986,7 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23526
     }
23527
     if (mOcclusionQuery == query)
23528
     {
23529
-        onOcclusionQueryEnd(context, query);
23530
+        onOcclusionQueryEnded(context, query);
23531
     }
23532
     mOcclusionQueryPool.deallocateQueryOffset(this, query);
23533
 }
23534
@@ -1770,20 +2030,6 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23535
     return angle::Result::Continue;
23536
 }
23537
 
23538
-void ContextMtl::onTransformFeedbackActive(const gl::Context *context, TransformFeedbackMtl *xfb)
23539
-{
23540
-    // NOTE(hqle): We have to end current render pass to enable synchronization before XFB
23541
-    // buffers could be used as vertex input. Consider a better approach.
23542
-    endEncoding(true);
23543
-}
23544
-
23545
-void ContextMtl::onTransformFeedbackInactive(const gl::Context *context, TransformFeedbackMtl *xfb)
23546
-{
23547
-    // NOTE(hqle): We have to end current render pass to enable synchronization before XFB
23548
-    // buffers could be used as vertex input. Consider a better approach.
23549
-    endEncoding(true);
23550
-}
23551
-
23552
 void ContextMtl::queueEventSignal(const mtl::SharedEventRef &event, uint64_t value)
23553
 {
23554
     ensureCommandBufferReady();
23555
@@ -1842,10 +2088,19 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23556
                                     GLsizei instances,
23557
                                     gl::DrawElementsType indexTypeOrNone,
23558
                                     const void *indices,
23559
-                                    bool xfbPass)
23560
+                                    bool transformFeedbackDraw)
23561
 {
23562
     ASSERT(mProgram);
23563
 
23564
+    // Update transform feedback offsets on every draw call.
23565
+    if (mState.isTransformFeedbackActiveUnpaused())
23566
+    {
23567
+        ASSERT(firstVertex != -1);
23568
+        mXfbBaseVertex             = firstVertex;
23569
+        mXfbVertexCountPerInstance = vertexOrIndexCount;
23570
+        invalidateDriverUniforms();
23571
+    }
23572
+
23573
     // instances=0 means no instanced draw.
23574
     GLsizei instanceCount = instances ? instances : 1;
23575
 
23576
@@ -1862,20 +2117,6 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23577
         ANGLE_TRY(handleDirtyActiveTextures(context));
23578
     }
23579
 
23580
-    if (mDirtyBits.test(DIRTY_BIT_RASTERIZER_DISCARD))
23581
-    {
23582
-        if (getState().isTransformFeedbackActiveUnpaused())
23583
-        {
23584
-            // If XFB is active we need to reset render pass since we could use a dummy render
23585
-            // target if only XFB is needed.
23586
-            invalidateState(context);
23587
-        }
23588
-        else
23589
-        {
23590
-            invalidateRenderPipeline();
23591
-        }
23592
-    }
23593
-
23594
     if (!mRenderEncoder.valid())
23595
     {
23596
         // re-apply everything
23597
@@ -1884,7 +2125,11 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23598
 
23599
     if (mDirtyBits.test(DIRTY_BIT_DRAW_FRAMEBUFFER))
23600
     {
23601
-        ANGLE_TRY(handleDirtyRenderPass(context));
23602
+        // Start new render command encoder
23603
+        ANGLE_MTL_TRY(this, mDrawFramebuffer->ensureRenderPassStarted(context));
23604
+
23605
+        // re-apply everything
23606
+        invalidateState(context);
23607
     }
23608
 
23609
     if (mOcclusionQuery && mOcclusionQueryPool.getNumRenderPassAllocatedQueries() == 0)
23610
@@ -1894,17 +2139,11 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23611
         ANGLE_TRY(startOcclusionQueryInRenderPass(mOcclusionQuery, false));
23612
     }
23613
 
23614
-    bool isPipelineDescChanged;
23615
-    ANGLE_TRY(checkIfPipelineChanged(context, mode, xfbPass, &isPipelineDescChanged));
23616
+    bool changedPipeline;
23617
+    ANGLE_TRY(checkIfPipelineChanged(context, mode, mState.isTransformFeedbackActive(),
23618
+                                     &changedPipeline));
23619
 
23620
     bool uniformBuffersDirty = false;
23621
-
23622
-    if (IsTransformFeedbackOnly(getState()))
23623
-    {
23624
-        // Filter out unneeded dirty bits
23625
-        filterOutXFBOnlyDirtyBits(context);
23626
-    }
23627
-
23628
     for (size_t bit : mDirtyBits)
23629
     {
23630
         switch (bit)
23631
@@ -1953,8 +2192,10 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23632
             case DIRTY_BIT_UNIFORM_BUFFERS_BINDING:
23633
                 uniformBuffersDirty = true;
23634
                 break;
23635
+            case DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS:
23636
+                ANGLE_TRY(handleDirtyGraphicsTransformFeedbackBuffersEmulation(context));
23637
+                break;
23638
             case DIRTY_BIT_RASTERIZER_DISCARD:
23639
-                // Already handled.
23640
                 break;
23641
             default:
23642
                 UNREACHABLE();
23643
@@ -1962,71 +2203,20 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23644
         }
23645
     }
23646
 
23647
-    if (xfbPass && !mDirtyBits.test(DIRTY_BIT_DRIVER_UNIFORMS))
23648
-    {
23649
-        // If handleDirtyDriverUniforms() was not called and this is XFB pass, we still need to
23650
-        // update XFB related uniforms
23651
-        ANGLE_TRY(
23652
-            fillDriverXFBUniforms(firstVertex, vertexOrIndexCount, /** skippedInstances */ 0));
23653
-        mRenderEncoder.setVertexData(mDriverUniforms, mtl::kDriverUniformsBindingIndex);
23654
-    }
23655
-
23656
     mDirtyBits.reset();
23657
 
23658
-    ANGLE_TRY(mProgram->setupDraw(context, &mRenderEncoder, mRenderPipelineDesc,
23659
-                                  isPipelineDescChanged, textureChanged, uniformBuffersDirty));
23660
-
23661
-    return angle::Result::Continue;
23662
-}
23663
-
23664
-void ContextMtl::filterOutXFBOnlyDirtyBits(const gl::Context *context)
23665
-{
23666
-    ASSERT(IsTransformFeedbackOnly(getState()));
23667
-
23668
-    ASSERT(mRenderEncoder.renderPassDesc().colorAttachments[0].texture == mDummyXFBRenderTexture);
23669
-
23670
-    // In transform feedback only pass, only vertex shader's related states are needed.
23671
-    constexpr size_t kUnneededBits =
23672
-        angle::Bit<size_t>(DIRTY_BIT_DEPTH_STENCIL_DESC) |
23673
-        angle::Bit<size_t>(DIRTY_BIT_DEPTH_BIAS) | angle::Bit<size_t>(DIRTY_BIT_STENCIL_REF) |
23674
-        angle::Bit<size_t>(DIRTY_BIT_BLEND_COLOR) | angle::Bit<size_t>(DIRTY_BIT_VIEWPORT) |
23675
-        angle::Bit<size_t>(DIRTY_BIT_SCISSOR) | angle::Bit<size_t>(DIRTY_BIT_CULL_MODE) |
23676
-        angle::Bit<size_t>(DIRTY_BIT_WINDING);
23677
-
23678
-    mDirtyBits &= ~kUnneededBits;
23679
-}
23680
-
23681
-angle::Result ContextMtl::handleDirtyRenderPass(const gl::Context *context)
23682
-{
23683
-    if (!IsTransformFeedbackOnly(mState))
23684
+    if (transformFeedbackDraw)
23685
     {
23686
-        // Start new render command encoder
23687
-        ANGLE_MTL_TRY(this, mDrawFramebuffer->ensureRenderPassStarted(context));
23688
-    }
23689
-    else
23690
-    {
23691
-        // XFB is active and rasterization is disabled. Use dummy render target.
23692
-        // We currently need to end the render pass when XFB is activated/deactivated so using
23693
-        // a small dummy render target would make the render pass ending very cheap.
23694
-        if (!mDummyXFBRenderTexture)
23695
-        {
23696
-            ANGLE_TRY(mtl::Texture::Make2DTexture(this,
23697
-                                                  getPixelFormat(angle::FormatID::R8G8B8A8_UNORM),
23698
-                                                  1, 1, 1, true, false, &mDummyXFBRenderTexture));
23699
-        }
23700
-        mtl::RenderCommandEncoder *encoder = getTextureRenderCommandEncoder(
23701
-            mDummyXFBRenderTexture,
23702
-            mtl::ImageNativeIndex::FromBaseZeroGLIndex(gl::ImageIndex::Make2D(0)));
23703
-        encoder->setColorLoadAction(MTLLoadActionDontCare, MTLClearColor(), 0);
23704
-        encoder->setColorStoreAction(MTLStoreActionDontCare);
23705
-
23706
-#ifndef NDEBUG
23707
-        encoder->setLabel(@"TransformFeedbackOnlyPass");
23708
-#endif
23709
+        mtl::RenderUtils &utils = getDisplay()->getUtils();
23710
+        angle::Result result =
23711
+            utils.createTransformFeedbackPSO(context, &mRenderEncoder, mRenderPipelineDesc);
23712
+        ANGLE_UNUSED_VARIABLE(result);
23713
+        assert(result == angle::Result::Continue);
23714
+        changedPipeline = true;
23715
     }
23716
 
23717
-    // re-apply everything
23718
-    invalidateState(context);
23719
+    ANGLE_TRY(mProgram->setupDraw(context, &mRenderEncoder, mRenderPipelineDesc, changedPipeline,
23720
+                                  textureChanged, uniformBuffersDirty, transformFeedbackDraw));
23721
 
23722
     return angle::Result::Continue;
23723
 }
23724
@@ -2034,10 +2224,10 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23725
 angle::Result ContextMtl::handleDirtyActiveTextures(const gl::Context *context)
23726
 {
23727
     const gl::State &glState                = mState;
23728
-    const gl::Program *program = glState.getProgram();
23729
+    const gl::ProgramExecutable *executable = context->getState().getProgramExecutable();
23730
 
23731
     const gl::ActiveTexturesCache &textures     = glState.getActiveTexturesCache();
23732
-    const gl::ActiveTextureMask &activeTextures = program->getExecutable().getActiveSamplersMask();
23733
+    const gl::ActiveTextureMask &activeTextures = executable->getActiveSamplersMask();
23734
 
23735
     for (size_t textureUnit : activeTextures)
23736
     {
23737
@@ -2067,6 +2257,7 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23738
     }
23739
 
23740
     ASSERT(mRenderEncoder.valid());
23741
+    mRenderEncoder.setFragmentData(mDefaultAttributes, mtl::kDefaultAttribsBindingIndex);
23742
     mRenderEncoder.setVertexData(mDefaultAttributes, mtl::kDefaultAttribsBindingIndex);
23743
 
23744
     mDirtyDefaultAttribsMask.reset();
23745
@@ -2120,9 +2311,6 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23746
     }
23747
     mDriverUniforms.coverageMask = coverageMask;
23748
 
23749
-    ANGLE_TRY(
23750
-        fillDriverXFBUniforms(drawCallFirstVertex, verticesPerInstance, /** skippedInstances */ 0));
23751
-
23752
     ASSERT(mRenderEncoder.valid());
23753
     mRenderEncoder.setFragmentData(mDriverUniforms, mtl::kDriverUniformsBindingIndex);
23754
     mRenderEncoder.setVertexData(mDriverUniforms, mtl::kDriverUniformsBindingIndex);
23755
@@ -2130,25 +2318,33 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23756
     return angle::Result::Continue;
23757
 }
23758
 
23759
-angle::Result ContextMtl::fillDriverXFBUniforms(GLint drawCallFirstVertex,
23760
-                                                uint32_t verticesPerInstance,
23761
-                                                uint32_t skippedInstances)
23762
+angle::Result ContextMtl::handleDirtyGraphicsTransformFeedbackBuffersEmulation(
23763
+    const gl::Context *context)
23764
 {
23765
-    gl::TransformFeedback *transformFeedback = getState().getCurrentTransformFeedback();
23766
+    const gl::ProgramExecutable *executable = mState.getProgramExecutable();
23767
+    ASSERT(executable);
23768
 
23769
-    mDriverUniforms.xfbActiveUnpaused = getState().isTransformFeedbackActiveUnpaused();
23770
-    if (!transformFeedback || !mDriverUniforms.xfbActiveUnpaused)
23771
+    if (!executable->hasTransformFeedbackOutput() || !mState.isTransformFeedbackActive())
23772
     {
23773
         return angle::Result::Continue;
23774
     }
23775
 
23776
-    mDriverUniforms.xfbVerticesPerDraw = verticesPerInstance;
23777
+    TransformFeedbackMtl *transformFeedbackMtl = mtl::GetImpl(mState.getCurrentTransformFeedback());
23778
+    size_t bufferCount                         = executable->getTransformFeedbackBufferCount();
23779
+    const gl::TransformFeedbackBuffersArray<BufferMtl *> &bufferHandles =
23780
+        transformFeedbackMtl->getBufferHandles();
23781
 
23782
-    TransformFeedbackMtl *transformFeedbackMtl = mtl::GetImpl(transformFeedback);
23783
+    for (size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
23784
+    {
23785
+        BufferMtl *bufferHandle = bufferHandles[bufferIndex];
23786
+        ASSERT(bufferHandle);
23787
+        ASSERT(mRenderEncoder.valid());
23788
+        mRenderEncoder.setBufferForWrite(
23789
+            gl::ShaderType::Vertex, bufferHandle->getCurrentBuffer(), 0,
23790
+            mtl::kTransformFeedbackBindingIndex + (uint32_t)bufferIndex);
23791
+    }
23792
 
23793
-    return transformFeedbackMtl->getBufferOffsets(this, drawCallFirstVertex,
23794
-                                                  verticesPerInstance * skippedInstances,
23795
-                                                  mDriverUniforms.xfbBufferOffsets);
23796
+    return angle::Result::Continue;
23797
 }
23798
 
23799
 angle::Result ContextMtl::handleDirtyDepthStencilState(const gl::Context *context)
23800
@@ -2159,13 +2355,13 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23801
     mtl::DepthStencilDesc dsDesc              = mDepthStencilDesc;
23802
     const mtl::RenderPassDesc &renderPassDesc = mRenderEncoder.renderPassDesc();
23803
 
23804
-    if (!renderPassDesc.depthAttachment.texture)
23805
+    if (!renderPassDesc.depthAttachment.texture())
23806
     {
23807
         dsDesc.depthWriteEnabled    = false;
23808
         dsDesc.depthCompareFunction = MTLCompareFunctionAlways;
23809
     }
23810
 
23811
-    if (!renderPassDesc.stencilAttachment.texture)
23812
+    if (!renderPassDesc.stencilAttachment.texture())
23813
     {
23814
         dsDesc.frontFaceStencil.reset();
23815
         dsDesc.backFaceStencil.reset();
23816
@@ -2196,8 +2392,8 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23817
 
23818
 angle::Result ContextMtl::checkIfPipelineChanged(const gl::Context *context,
23819
                                                  gl::PrimitiveMode primitiveMode,
23820
-                                                 bool xfbPass,
23821
-                                                 bool *isPipelineDescChanged)
23822
+                                                 bool xbfPass,
23823
+                                                 bool *pipelineDescChanged)
23824
 {
23825
     ASSERT(mRenderEncoder.valid());
23826
     mtl::PrimitiveTopologyClass topologyClass = mtl::GetPrimitiveTopologyClass(primitiveMode);
23827
@@ -2216,24 +2412,10 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23828
         renderPassDesc.populateRenderPipelineOutputDesc(mBlendDesc,
23829
                                                         &mRenderPipelineDesc.outputDescriptor);
23830
 
23831
-        if (xfbPass)
23832
-        {
23833
-            // In XFB pass, we disable fragment shader.
23834
-            mRenderPipelineDesc.rasterizationType = mtl::RenderPipelineRasterization::Disabled;
23835
-        }
23836
-        else if (mState.isRasterizerDiscardEnabled())
23837
-        {
23838
-            // If XFB is not active and rasterizer discard is enabled, we need to emulate the
23839
-            // discard. Because in this case, vertex shader might write to stage output values and
23840
-            // Metal doesn't allow rasterization to be disabled.
23841
-            mRenderPipelineDesc.rasterizationType =
23842
-                mtl::RenderPipelineRasterization::EmulatedDiscard;
23843
-        }
23844
-        else
23845
-        {
23846
-            mRenderPipelineDesc.rasterizationType = mtl::RenderPipelineRasterization::Enabled;
23847
-        }
23848
         mRenderPipelineDesc.inputPrimitiveTopology = topologyClass;
23849
+        mRenderPipelineDesc.rasterizationType =
23850
+            (mState.isRasterizerDiscardEnabled() ? mtl::RenderPipelineRasterization::EmulatedDiscard
23851
+                                                 : mtl::RenderPipelineRasterization::Enabled);
23852
         mRenderPipelineDesc.alphaToCoverageEnabled = mState.isSampleAlphaToCoverageEnabled();
23853
         mRenderPipelineDesc.emulateCoverageMask    = mState.isSampleCoverageEnabled();
23854
 
23855
@@ -2241,7 +2423,7 @@ bool IsTransformFeedbackOnly(const gl::State &glState)
23856
             mDrawFramebuffer->getState().getEnabledDrawBuffers());
23857
     }
23858
 
23859
-    *isPipelineDescChanged = rppChange;
23860
+    *pipelineDescChanged = rppChange;
23861
 
23862
     return angle::Result::Continue;
23863
 }
23864
diff --git a/src/libANGLE/renderer/metal/DisplayMtl.h b/src/libANGLE/renderer/metal/DisplayMtl.h
23865
index b00de1b..2417122 100644
23866
--- a/src/libANGLE/renderer/metal/DisplayMtl.h
23867
+++ b/src/libANGLE/renderer/metal/DisplayMtl.h
23868
@@ -52,6 +52,10 @@ class DisplayMtl : public DisplayImpl
23869
 
23870
     egl::Error waitClient(const gl::Context *context) override;
23871
     egl::Error waitNative(const gl::Context *context, EGLint engine) override;
23872
+    egl::Error validateClientBuffer(const egl::Config *configuration,
23873
+                                    EGLenum buftype,
23874
+                                    EGLClientBuffer clientBuffer,
23875
+                                    const egl::AttributeMap &attribs) const override;
23876
 
23877
     SurfaceImpl *createWindowSurface(const egl::SurfaceState &state,
23878
                                      EGLNativeWindowType window,
23879
@@ -96,11 +100,6 @@ class DisplayMtl : public DisplayImpl
23880
 
23881
     bool isValidNativeWindow(EGLNativeWindowType window) const override;
23882
 
23883
-    egl::Error validateClientBuffer(const egl::Config *configuration,
23884
-                                    EGLenum buftype,
23885
-                                    EGLClientBuffer clientBuffer,
23886
-                                    const egl::AttributeMap &attribs) const override;
23887
-
23888
     egl::ConfigSet generateConfigs() override;
23889
 
23890
     std::string getRendererDescription() const;
23891
@@ -165,6 +164,8 @@ class DisplayMtl : public DisplayImpl
23892
     void initializeExtensions() const;
23893
     void initializeTextureCaps() const;
23894
     void initializeFeatures();
23895
+    void initializeLimitations();
23896
+
23897
     angle::Result initializeShaderLibrary();
23898
 
23899
     mtl::AutoObjCPtr<id<MTLDevice>> mMetalDevice = nil;
23900
diff --git a/src/libANGLE/renderer/metal/DisplayMtl.mm b/src/libANGLE/renderer/metal/DisplayMtl.mm
23901
index 247d76a..c159c05 100644
23902
--- a/src/libANGLE/renderer/metal/DisplayMtl.mm
23903
+++ b/src/libANGLE/renderer/metal/DisplayMtl.mm
23904
@@ -8,12 +8,14 @@
23905
 
23906
 #include "libANGLE/renderer/metal/DisplayMtl.h"
23907
 
23908
+#include "common/system_utils.h"
23909
 #include "gpu_info_util/SystemInfo.h"
23910
 #include "libANGLE/Context.h"
23911
 #include "libANGLE/Display.h"
23912
 #include "libANGLE/Surface.h"
23913
 #include "libANGLE/renderer/glslang_wrapper_utils.h"
23914
 #include "libANGLE/renderer/metal/ContextMtl.h"
23915
+#include "libANGLE/renderer/metal/IOSurfaceSurfaceMtl.h"
23916
 #include "libANGLE/renderer/metal/SurfaceMtl.h"
23917
 #include "libANGLE/renderer/metal/SyncMtl.h"
23918
 #include "libANGLE/renderer/metal/mtl_common.h"
23919
@@ -22,9 +24,62 @@
23920
 
23921
 #include "EGL/eglext.h"
23922
 
23923
+#if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
23924
+constexpr char kANGLEPreferredDeviceEnv[] = "ANGLE_PREFERRED_DEVICE";
23925
+#endif
23926
+constexpr char kANGLETransformFeedbackEnv[] = "ANGLE_METAL_XFB_ENABLE";
23927
+
23928
 namespace rx
23929
 {
23930
 
23931
+static EGLint GetDepthSize(GLint internalformat)
23932
+{
23933
+    switch (internalformat)
23934
+    {
23935
+        case GL_STENCIL_INDEX8:
23936
+            return 0;
23937
+        case GL_DEPTH_COMPONENT16:
23938
+            return 16;
23939
+        case GL_DEPTH_COMPONENT24:
23940
+            return 24;
23941
+        case GL_DEPTH_COMPONENT32_OES:
23942
+            return 32;
23943
+        case GL_DEPTH_COMPONENT32F:
23944
+            return 32;
23945
+        case GL_DEPTH24_STENCIL8:
23946
+            return 24;
23947
+        case GL_DEPTH32F_STENCIL8:
23948
+            return 32;
23949
+        default:
23950
+            //    UNREACHABLE(internalformat);
23951
+            return 0;
23952
+    }
23953
+}
23954
+
23955
+static EGLint GetStencilSize(GLint internalformat)
23956
+{
23957
+    switch (internalformat)
23958
+    {
23959
+        case GL_STENCIL_INDEX8:
23960
+            return 8;
23961
+        case GL_DEPTH_COMPONENT16:
23962
+            return 0;
23963
+        case GL_DEPTH_COMPONENT24:
23964
+            return 0;
23965
+        case GL_DEPTH_COMPONENT32_OES:
23966
+            return 0;
23967
+        case GL_DEPTH_COMPONENT32F:
23968
+            return 0;
23969
+        case GL_DEPTH24_STENCIL8:
23970
+            return 8;
23971
+        case GL_DEPTH32F_STENCIL8:
23972
+            return 8;
23973
+        default:
23974
+            //    UNREACHABLE(internalformat);
23975
+            return 0;
23976
+    }
23977
+}
23978
+
23979
 bool IsMetalDisplayAvailable()
23980
 {
23981
     // We only support macos 10.13+ and 11 for now. Since they are requirements for Metal 2.0.
23982
@@ -57,7 +112,7 @@ bool IsMetalDisplayAvailable()
23983
 };
23984
 
23985
 DisplayMtl::DisplayMtl(const egl::DisplayState &state)
23986
-    : DisplayImpl(state), mUtils(this), mGlslangInitialized(false)
23987
+    : DisplayImpl(state), mStateCache(mFeatures), mUtils(this)
23988
 {}
23989
 
23990
 DisplayMtl::~DisplayMtl() {}
23991
@@ -78,10 +133,27 @@ bool IsMetalDisplayAvailable()
23992
 {
23993
     ANGLE_MTL_OBJC_SCOPE
23994
     {
23995
-        mMetalDevice = [MTLCreateSystemDefaultDevice() ANGLE_MTL_AUTORELEASE];
23996
+#if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
23997
+        const std::string anglePreferredDevice = angle::GetEnvironmentVar(kANGLEPreferredDeviceEnv);
23998
+        if (anglePreferredDevice != "")
23999
+        {
24000
+            NSArray<id<MTLDevice>> *devices = [MTLCopyAllDevices() ANGLE_MTL_AUTORELEASE];
24001
+            for (id<MTLDevice> device in devices)
24002
+            {
24003
+                if ([device.name.lowercaseString
24004
+                        containsString:[NSString stringWithUTF8String:anglePreferredDevice.c_str()]
24005
+                                           .lowercaseString])
24006
+                {
24007
+                    NSLog(@"Using Metal Device: %@", [device name]);
24008
+                    mMetalDevice = [device ANGLE_MTL_AUTORELEASE];
24009
+                    break;
24010
+                }
24011
+            }
24012
+        }
24013
+#endif
24014
         if (!mMetalDevice)
24015
         {
24016
-            return angle::Result::Stop;
24017
+            mMetalDevice = [MTLCreateSystemDefaultDevice() ANGLE_MTL_AUTORELEASE];
24018
         }
24019
 
24020
         mMetalDeviceVendorId = mtl::GetDeviceVendorId(mMetalDevice);
24021
@@ -89,12 +161,13 @@ bool IsMetalDisplayAvailable()
24022
         mCmdQueue.set([[mMetalDevice.get() newCommandQueue] ANGLE_MTL_AUTORELEASE]);
24023
 
24024
         mCapsInitialized = false;
24025
-
24026
+#if ANGLE_ENABLE_METAL_SPIRV
24027
         if (!mGlslangInitialized)
24028
         {
24029
             GlslangInitialize();
24030
             mGlslangInitialized = true;
24031
         }
24032
+#endif
24033
 
24034
         if (!mState.featuresAllDisabled)
24035
         {
24036
@@ -120,12 +193,13 @@ bool IsMetalDisplayAvailable()
24037
     mCapsInitialized = false;
24038
 
24039
     mMetalDeviceVendorId = 0;
24040
-
24041
+#if ANGLE_ENABLE_METAL_SPIRV
24042
     if (mGlslangInitialized)
24043
     {
24044
         GlslangRelease();
24045
         mGlslangInitialized = false;
24046
     }
24047
+#endif
24048
 }
24049
 
24050
 bool DisplayMtl::testDeviceLost()
24051
@@ -171,6 +245,15 @@ bool IsMetalDisplayAvailable()
24052
     return egl::NoError();
24053
 }
24054
 
24055
+egl::Error DisplayMtl::validateClientBuffer(const egl::Config *configuration,
24056
+                                            EGLenum buftype,
24057
+                                            EGLClientBuffer clientBuffer,
24058
+                                            const egl::AttributeMap &attribs) const
24059
+{
24060
+    // TODO: Fill out properly
24061
+    return egl::NoError();
24062
+}
24063
+
24064
 egl::Error DisplayMtl::waitNative(const gl::Context *context, EGLint engine)
24065
 {
24066
     UNIMPLEMENTED();
24067
@@ -187,7 +270,8 @@ bool IsMetalDisplayAvailable()
24068
 SurfaceImpl *DisplayMtl::createPbufferSurface(const egl::SurfaceState &state,
24069
                                               const egl::AttributeMap &attribs)
24070
 {
24071
-    return new PBufferSurfaceMtl(this, state, attribs);
24072
+    UNIMPLEMENTED();
24073
+    return static_cast<SurfaceImpl *>(0);
24074
 }
24075
 
24076
 SurfaceImpl *DisplayMtl::createPbufferFromClientBuffer(const egl::SurfaceState &state,
24077
@@ -195,15 +279,7 @@ bool IsMetalDisplayAvailable()
24078
                                                        EGLClientBuffer clientBuffer,
24079
                                                        const egl::AttributeMap &attribs)
24080
 {
24081
-    switch (buftype)
24082
-    {
24083
-        case EGL_IOSURFACE_ANGLE:
24084
     return new IOSurfaceSurfaceMtl(this, state, clientBuffer, attribs);
24085
-            break;
24086
-        default:
24087
-            UNREACHABLE();
24088
-    }
24089
-    return nullptr;
24090
 }
24091
 
24092
 SurfaceImpl *DisplayMtl::createPixmapSurface(const egl::SurfaceState &state,
24093
@@ -240,17 +316,12 @@ bool IsMetalDisplayAvailable()
24094
     return nullptr;
24095
 }
24096
 
24097
-ShareGroupImpl *DisplayMtl::createShareGroup()
24098
-{
24099
-    return new ShareGroupMtl();
24100
-}
24101
-
24102
 gl::Version DisplayMtl::getMaxSupportedESVersion() const
24103
 {
24104
     // NOTE(hqle): Supports GLES 3.0 on iOS GPU family 4+ for now.
24105
     if (supportsEitherGPUFamily(4, 1))
24106
     {
24107
-        return mtl::kMaxSupportedGLVersion;
24108
+        return gl::Version(3, 0);
24109
     }
24110
     return gl::Version(2, 0);
24111
 }
24112
@@ -265,6 +336,11 @@ bool IsMetalDisplayAvailable()
24113
     return new EGLSyncMtl(attribs);
24114
 }
24115
 
24116
+ShareGroupImpl *DisplayMtl::createShareGroup()
24117
+{
24118
+    return new ShareGroupImpl();
24119
+}
24120
+
24121
 egl::Error DisplayMtl::makeCurrent(egl::Display *display,
24122
                                    egl::Surface *drawSurface,
24123
                                    egl::Surface *readSurface,
24124
@@ -326,7 +402,7 @@ bool IsMetalDisplayAvailable()
24125
     config.transparentType = EGL_NONE;
24126
 
24127
     // Pbuffer
24128
-    config.bindToTextureTarget = EGL_TEXTURE_2D;
24129
+    config.bindToTextureTarget = EGL_TEXTURE_RECTANGLE_ANGLE;
24130
     config.maxPBufferWidth     = 4096;
24131
     config.maxPBufferHeight    = 4096;
24132
     config.maxPBufferPixels    = 4096 * 4096;
24133
@@ -361,13 +437,6 @@ bool IsMetalDisplayAvailable()
24134
 
24135
     config.colorComponentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
24136
 
24137
-    constexpr int samplesSupported[] = {0, 4};
24138
-
24139
-    for (int samples : samplesSupported)
24140
-    {
24141
-        config.samples       = samples;
24142
-        config.sampleBuffers = (samples == 0) ? 0 : 1;
24143
-
24144
     // Buffer sizes
24145
     config.redSize    = 8;
24146
     config.greenSize  = 8;
24147
@@ -375,28 +444,12 @@ bool IsMetalDisplayAvailable()
24148
     config.alphaSize  = 8;
24149
     config.bufferSize = config.redSize + config.greenSize + config.blueSize + config.alphaSize;
24150
 
24151
-        // With DS
24152
-        config.depthSize   = 24;
24153
-        config.stencilSize = 8;
24154
-
24155
-        configs.add(config);
24156
-
24157
-        // With D
24158
-        config.depthSize   = 24;
24159
-        config.stencilSize = 0;
24160
-        configs.add(config);
24161
-
24162
-        // With S
24163
-        config.depthSize   = 0;
24164
-        config.stencilSize = 8;
24165
+    // Tests like dEQP-GLES2.functional.depth_range.* assume EGL_DEPTH_SIZE is properly set even if
24166
+    // renderConfig attributes are set to glu::RenderConfig::DONT_CARE
24167
+    config.depthSize   = GetDepthSize(config.depthStencilFormat);
24168
+    config.stencilSize = GetStencilSize(config.depthStencilFormat);
24169
     configs.add(config);
24170
 
24171
-        // No DS
24172
-        config.depthSize   = 0;
24173
-        config.stencilSize = 0;
24174
-        configs.add(config);
24175
-    }
24176
-
24177
     return configs;
24178
 }
24179
 
24180
@@ -409,26 +462,6 @@ bool IsMetalDisplayAvailable()
24181
     }
24182
 }
24183
 
24184
-egl::Error DisplayMtl::validateClientBuffer(const egl::Config *configuration,
24185
-                                            EGLenum buftype,
24186
-                                            EGLClientBuffer clientBuffer,
24187
-                                            const egl::AttributeMap &attribs) const
24188
-{
24189
-    switch (buftype)
24190
-    {
24191
-        case EGL_IOSURFACE_ANGLE:
24192
-            if (!IOSurfaceSurfaceMtl::ValidateAttributes(clientBuffer, attribs))
24193
-            {
24194
-                return egl::EglBadAttribute();
24195
-            }
24196
-            break;
24197
-        default:
24198
-            UNREACHABLE();
24199
-            return egl::EglBadAttribute();
24200
-    }
24201
-    return egl::NoError();
24202
-}
24203
-
24204
 std::string DisplayMtl::getRendererDescription() const
24205
 {
24206
     ANGLE_MTL_OBJC_SCOPE
24207
@@ -512,10 +545,16 @@ bool IsMetalDisplayAvailable()
24208
     mNativeCaps.maxRenderbufferSize   = mNativeCaps.max2DTextureSize;
24209
     mNativeCaps.minAliasedPointSize   = 1;
24210
     // NOTE(hqle): Metal has some problems drawing big point size even though
24211
-    // Metal-Feature-Set-Tables.pdf says that max supported point size is 511. We limit it to 64 for
24212
-    // now.
24213
-    // http://anglebug.com/4816
24214
+    // Metal-Feature-Set-Tables.pdf says that max supported point size is 511. We limit it to 255
24215
+    // on Intel and 64 on AMD for now.
24216
+    if ([mMetalDevice.get().name rangeOfString:@"Intel"].location != NSNotFound)
24217
+    {
24218
+        mNativeCaps.maxAliasedPointSize = 255;
24219
+    }
24220
+    else
24221
+    {
24222
         mNativeCaps.maxAliasedPointSize = 64;
24223
+    }
24224
 
24225
     mNativeCaps.minAliasedLineWidth = 1.0f;
24226
     mNativeCaps.maxAliasedLineWidth = 1.0f;
24227
@@ -615,6 +654,9 @@ bool IsMetalDisplayAvailable()
24228
     mNativeCaps.maxTransformFeedbackSeparateComponents =
24229
         gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS;
24230
 
24231
+    // GL_OES_get_program_binary
24232
+    mNativeCaps.programBinaryFormats.push_back(GL_PROGRAM_BINARY_ANGLE);
24233
+
24234
     // GL_APPLE_clip_distance
24235
     mNativeCaps.maxClipDistances = 8;
24236
 
24237
@@ -647,6 +689,15 @@ bool IsMetalDisplayAvailable()
24238
     mNativeExtensions.textureBorderClampOES  = false;  // not implemented yet
24239
     mNativeExtensions.translatedShaderSource = true;
24240
     mNativeExtensions.discardFramebuffer     = true;
24241
+    // Not implemented but expose
24242
+    mNativeExtensions.textureRectangle = true;
24243
+
24244
+    // EXT_multisampled_render_to_texture
24245
+    if (mFeatures.allowMultisampleStoreAndResolve.enabled &&
24246
+        mFeatures.hasDepthAutoResolve.enabled && mFeatures.hasStencilAutoResolve.enabled)
24247
+    {
24248
+        mNativeExtensions.multisampledRenderToTexture = true;
24249
+    }
24250
 
24251
     // Enable EXT_blend_minmax
24252
     mNativeExtensions.blendMinMax = true;
24253
@@ -662,8 +713,8 @@ bool IsMetalDisplayAvailable()
24254
     mNativeExtensions.semaphore   = false;
24255
     mNativeExtensions.semaphoreFd = false;
24256
 
24257
-    mNativeExtensions.instancedArraysANGLE = mFeatures.hasBaseVertexInstancedDraw.enabled;
24258
-    mNativeExtensions.instancedArraysEXT   = mNativeExtensions.instancedArraysANGLE;
24259
+    mNativeExtensions.instancedArraysANGLE = true;
24260
+    mNativeExtensions.instancedArraysEXT   = true;
24261
 
24262
     mNativeExtensions.robustBufferAccessBehavior = false;
24263
 
24264
@@ -686,6 +737,9 @@ bool IsMetalDisplayAvailable()
24265
 
24266
     mNativeExtensions.elementIndexUintOES = true;
24267
 
24268
+    // GL_OES_get_program_binary
24269
+    mNativeExtensions.getProgramBinaryOES = true;
24270
+
24271
     // GL_APPLE_clip_distance
24272
     mNativeExtensions.clipDistanceAPPLE = true;
24273
 
24274
@@ -713,11 +767,17 @@ bool IsMetalDisplayAvailable()
24275
 
24276
     // Re-verify texture extensions.
24277
     mNativeExtensions.setTextureExtensionSupport(mNativeTextureCaps);
24278
-
24279
+    // Modify extensions based off of support
24280
     // Disable all depth buffer and stencil buffer readback extensions until we need them
24281
     mNativeExtensions.readDepthNV         = false;
24282
     mNativeExtensions.readStencilNV       = false;
24283
     mNativeExtensions.depthBufferFloat2NV = false;
24284
+    mNativeExtensions.textureCompressionASTCLDRKHR &= supportsIOSGPUFamily(2);
24285
+}
24286
+
24287
+void DisplayMtl::initializeLimitations()
24288
+{
24289
+    mNativeLimitations.noVertexAttributeAliasing = true;
24290
 }
24291
 
24292
 void DisplayMtl::initializeFeatures()
24293
@@ -779,6 +839,9 @@ bool IsMetalDisplayAvailable()
24294
     ANGLE_FEATURE_CONDITION((&mFeatures), allowSeparatedDepthStencilBuffers,
24295
                             !isOSX && !isCatalyst && !isSimulator);
24296
 
24297
+    mFeatures.emulateTransformFeedback.enabled =
24298
+        angle::GetEnvironmentVar(kANGLETransformFeedbackEnv)[0] == '1';
24299
+
24300
     angle::PlatformMethods *platform = ANGLEPlatformCurrent();
24301
     platform->overrideFeaturesMtl(platform, &mFeatures);
24302
 
24303
@@ -787,6 +850,27 @@ bool IsMetalDisplayAvailable()
24304
 
24305
 angle::Result DisplayMtl::initializeShaderLibrary()
24306
 {
24307
+    #ifdef ANGLE_METAL_XCODE_BUILDS_SHADERS
24308
+        mDefaultShadersAsyncInfo.reset(new DefaultShaderAsyncInfoMtl);
24309
+        
24310
+    
24311
+        NSString *path = [NSBundle bundleWithIdentifier:@"com.apple.WebKit"].bundlePath;
24312
+        NSError * error = nullptr;
24313
+        mDefaultShadersAsyncInfo->defaultShaders = [getMetalDevice() newDefaultLibraryWithBundle:[NSBundle bundleWithPath:path] error:&error];
24314
+
24315
+        if (error && !mDefaultShadersAsyncInfo->defaultShaders)
24316
+        {
24317
+            ANGLE_MTL_OBJC_SCOPE
24318
+            {
24319
+                ERR() << "Internal error: newDefaultLibraryWithBundle failed. " << error.localizedDescription.UTF8String;
24320
+            }
24321
+            mDefaultShadersAsyncInfo->defaultShadersCompileError = std::move(error);
24322
+            return angle::Result::Stop;
24323
+                 
24324
+        }
24325
+        mDefaultShadersAsyncInfo->compiled = true;
24326
+        
24327
+    #else
24328
     mDefaultShadersAsyncInfo.reset(new DefaultShaderAsyncInfoMtl);
24329
 
24330
     // Create references to async info struct since it might be released in terminate(), but the
24331
@@ -815,7 +899,7 @@ bool IsMetalDisplayAvailable()
24332
 
24333
         [nsSource ANGLE_MTL_AUTORELEASE];
24334
     }
24335
-
24336
+    #endif
24337
     return angle::Result::Continue;
24338
 }
24339
 
24340
diff --git a/src/libANGLE/renderer/metal/FrameBufferMtl.h b/src/libANGLE/renderer/metal/FrameBufferMtl.h
24341
index b458bd9..5e5cce9 100644
24342
--- a/src/libANGLE/renderer/metal/FrameBufferMtl.h
24343
+++ b/src/libANGLE/renderer/metal/FrameBufferMtl.h
24344
@@ -23,12 +23,14 @@ namespace mtl
24345
 class RenderCommandEncoder;
24346
 }  // namespace mtl
24347
 class ContextMtl;
24348
-class WindowSurfaceMtl;
24349
+class SurfaceMtl;
24350
 
24351
 class FramebufferMtl : public FramebufferImpl
24352
 {
24353
   public:
24354
-    FramebufferMtl(const gl::FramebufferState &state, bool flipY, WindowSurfaceMtl *backbuffer);
24355
+    explicit FramebufferMtl(const gl::FramebufferState &state,
24356
+                            bool flipY,
24357
+                            SurfaceMtlProtocol *backbuffer);
24358
     ~FramebufferMtl() override;
24359
     void destroy(const gl::Context *context) override;
24360
 
24361
@@ -97,7 +99,7 @@ class FramebufferMtl : public FramebufferImpl
24362
 
24363
     gl::Rectangle getCompleteRenderArea() const;
24364
     int getSamples() const;
24365
-    WindowSurfaceMtl *getAttachedBackbuffer() const { return mBackbuffer; }
24366
+    SurfaceMtlProtocol *getAttachedBackbuffer() const { return mBackbuffer; }
24367
 
24368
     bool renderPassHasStarted(ContextMtl *contextMtl) const;
24369
     mtl::RenderCommandEncoder *ensureRenderPassStarted(const gl::Context *context);
24370
@@ -162,6 +164,10 @@ class FramebufferMtl : public FramebufferImpl
24371
     mtl::RenderCommandEncoder *ensureRenderPassStarted(const gl::Context *context,
24372
                                                        const mtl::RenderPassDesc &desc);
24373
 
24374
+    void overrideClearColor(const mtl::TextureRef &texture,
24375
+                            MTLClearColor clearColor,
24376
+                            MTLClearColor *colorOut);
24377
+
24378
     angle::Result updateColorRenderTarget(const gl::Context *context, size_t colorIndexGL);
24379
     angle::Result updateDepthRenderTarget(const gl::Context *context);
24380
     angle::Result updateStencilRenderTarget(const gl::Context *context);
24381
@@ -169,11 +175,37 @@ class FramebufferMtl : public FramebufferImpl
24382
                                            const gl::FramebufferAttachment *attachment,
24383
                                            RenderTargetMtl **cachedRenderTarget);
24384
 
24385
+    // This function either returns the render target's texture itself if the texture is readable
24386
+    // or create a copy of that texture that is readable if not. This function is typically used
24387
+    // for packed depth stencil where reading stencil requires a stencil view. However if a texture
24388
+    // has both render target, pixel format view & shader readable usage flags, there will be
24389
+    // some glitches happen in Metal framework.
24390
+    // So the solution is creating a depth stencil texture without pixel format view flag but has
24391
+    // render target flag, then during blitting process, this texture is copied to another
24392
+    // intermidiate texture having pixel format view flag, but not render target flag.
24393
+    angle::Result getReadableViewForRenderTarget(const gl::Context *context,
24394
+                                                 const RenderTargetMtl &rtt,
24395
+                                                 const gl::Rectangle &readArea,
24396
+                                                 mtl::TextureRef *readableDepthView,
24397
+                                                 mtl::TextureRef *readableStencilView,
24398
+                                                 uint32_t *readableViewLevel,
24399
+                                                 uint32_t *readableViewLayer,
24400
+                                                 gl::Rectangle *readableViewArea);
24401
+
24402
     angle::Result readPixelsToPBO(const gl::Context *context,
24403
                                   const gl::Rectangle &area,
24404
                                   const PackPixelsParams &packPixelsParams,
24405
                                   const RenderTargetMtl *renderTarget) const;
24406
 
24407
+    angle::Result readPixelsToBuffer(const gl::Context *context,
24408
+                                     const gl::Rectangle &area,
24409
+                                     const RenderTargetMtl *renderTarget,
24410
+                                     bool reverseRowOrder,
24411
+                                     const angle::Format &dstAngleFormat,
24412
+                                     uint32_t dstBufferOffset,
24413
+                                     uint32_t dstBufferRowPitch,
24414
+                                     const mtl::BufferRef *dstBuffer) const;
24415
+
24416
     // NOTE: we cannot use RenderTargetCache here because it doesn't support separate
24417
     // depth & stencil attachments as of now. Separate depth & stencil could be useful to
24418
     // save spaces on iOS devices. See doc/PackedDepthStencilSupport.md.
24419
@@ -189,8 +221,10 @@ class FramebufferMtl : public FramebufferImpl
24420
     // as by a compute pass.
24421
     bool mRenderPassCleanStart = false;
24422
 
24423
-    WindowSurfaceMtl *mBackbuffer = nullptr;
24424
+    SurfaceMtlProtocol *mBackbuffer = nullptr;
24425
     const bool mFlipY               = false;
24426
+
24427
+    mtl::BufferRef mReadPixelBuffer;
24428
 };
24429
 }  // namespace rx
24430
 
24431
diff --git a/src/libANGLE/renderer/metal/FrameBufferMtl.mm b/src/libANGLE/renderer/metal/FrameBufferMtl.mm
24432
index 84e4227..d71de72 100644
24433
--- a/src/libANGLE/renderer/metal/FrameBufferMtl.mm
24434
+++ b/src/libANGLE/renderer/metal/FrameBufferMtl.mm
24435
@@ -33,12 +33,30 @@ void OverrideMTLClearColor(const mtl::TextureRef &texture,
24436
     *colorOut =
24437
         mtl::EmulatedAlphaClearColor(clearColor.toMTLClearColor(), texture->getColorWritableMask());
24438
 }
24439
+
24440
+const gl::InternalFormat &GetReadAttachmentInfo(const gl::Context *context,
24441
+                                                RenderTargetMtl *renderTarget)
24442
+{
24443
+    GLenum implFormat;
24444
+
24445
+    if (renderTarget && renderTarget->getFormat())
24446
+    {
24447
+        implFormat = renderTarget->getFormat()->actualAngleFormat().fboImplementationInternalFormat;
24448
+    }
24449
+    else
24450
+    {
24451
+        implFormat = GL_NONE;
24452
+    }
24453
+
24454
+    return gl::GetSizedInternalFormatInfo(implFormat);
24455
+}
24456
+
24457
 }
24458
 
24459
 // FramebufferMtl implementation
24460
 FramebufferMtl::FramebufferMtl(const gl::FramebufferState &state,
24461
                                bool flipY,
24462
-                               WindowSurfaceMtl *backbuffer)
24463
+                               SurfaceMtlProtocol *backbuffer)
24464
     : FramebufferImpl(state), mBackbuffer(backbuffer), mFlipY(flipY)
24465
 {
24466
     reset();
24467
@@ -55,6 +73,8 @@ void OverrideMTLClearColor(const mtl::TextureRef &texture,
24468
     mDepthRenderTarget = mStencilRenderTarget = nullptr;
24469
 
24470
     mRenderPassFirstColorAttachmentFormat = nullptr;
24471
+
24472
+    mReadPixelBuffer = nullptr;
24473
 }
24474
 
24475
 void FramebufferMtl::destroy(const gl::Context *context)
24476
@@ -122,7 +142,6 @@ void OverrideMTLClearColor(const mtl::TextureRef &texture,
24477
                                             const GLfloat *values)
24478
 {
24479
     mtl::ClearRectParams clearOpts;
24480
-
24481
     gl::DrawBufferMask clearColorBuffers;
24482
     if (buffer == GL_DEPTH)
24483
     {
24484
@@ -133,7 +152,6 @@ void OverrideMTLClearColor(const mtl::TextureRef &texture,
24485
         clearColorBuffers.set(drawbuffer);
24486
         clearOpts.clearColor = mtl::ClearColorValue(values[0], values[1], values[2], values[3]);
24487
     }
24488
-
24489
     return clearImpl(context, clearColorBuffers, &clearOpts);
24490
 }
24491
 angle::Result FramebufferMtl::clearBufferuiv(const gl::Context *context,
24492
@@ -146,7 +164,6 @@ void OverrideMTLClearColor(const mtl::TextureRef &texture,
24493
 
24494
     mtl::ClearRectParams clearOpts;
24495
     clearOpts.clearColor =  mtl::ClearColorValue(values[0], values[1], values[2], values[3]);
24496
-
24497
     return clearImpl(context, clearColorBuffers, &clearOpts);
24498
 }
24499
 angle::Result FramebufferMtl::clearBufferiv(const gl::Context *context,
24500
@@ -159,7 +176,7 @@ void OverrideMTLClearColor(const mtl::TextureRef &texture,
24501
     gl::DrawBufferMask clearColorBuffers;
24502
     if (buffer == GL_STENCIL)
24503
     {
24504
-        clearOpts.clearStencil = values[0] & mtl::kStencilMaskAll;
24505
+        clearOpts.clearStencil = gl::clamp(values[0], 0, static_cast<GLint>(mtl::kStencilMaskAll));
24506
     }
24507
     else
24508
     {
24509
@@ -177,7 +194,7 @@ void OverrideMTLClearColor(const mtl::TextureRef &texture,
24510
 {
24511
     mtl::ClearRectParams clearOpts;
24512
     clearOpts.clearDepth   = depth;
24513
-    clearOpts.clearStencil = stencil & mtl::kStencilMaskAll;
24514
+    clearOpts.clearStencil = gl::clamp(stencil, 0, static_cast<GLint>(mtl::kStencilMaskAll));
24515
 
24516
     return clearImpl(context, gl::DrawBufferMask(), &clearOpts);
24517
 }
24518
@@ -185,12 +202,7 @@ void OverrideMTLClearColor(const mtl::TextureRef &texture,
24519
 const gl::InternalFormat &FramebufferMtl::getImplementationColorReadFormat(
24520
     const gl::Context *context) const
24521
 {
24522
-    ContextMtl *contextMtl   = mtl::GetImpl(context);
24523
-    GLenum sizedFormat       = mState.getReadAttachment()->getFormat().info->sizedInternalFormat;
24524
-    angle::FormatID formatID = angle::Format::InternalFormatToID(sizedFormat);
24525
-    const mtl::Format &mtlFormat = contextMtl->getDisplay()->getPixelFormat(formatID);
24526
-    GLenum implFormat            = mtlFormat.actualAngleFormat().fboImplementationInternalFormat;
24527
-    return gl::GetSizedInternalFormatInfo(implFormat);
24528
+    return GetReadAttachmentInfo(context, getColorReadRenderTarget(context));
24529
 }
24530
 
24531
 angle::Result FramebufferMtl::readPixels(const gl::Context *context,
24532
@@ -590,6 +602,9 @@ PackPixelsParams params(flippedArea, angleFormat, outputPitch, pack.reverseRowOr
24533
         {
24534
             contextMtl->onDrawFrameBufferChangedState(context, this, renderPassChanged);
24535
         }
24536
+
24537
+        // Recreate pixel reading buffer if needed in future.
24538
+        mReadPixelBuffer = nullptr;
24539
     }
24540
 
24541
     return angle::Result::Continue;
24542
@@ -748,7 +763,7 @@ PackPixelsParams params(flippedArea, angleFormat, outputPitch, pack.reverseRowOr
24543
 
24544
 void FramebufferMtl::onFrameEnd(const gl::Context *context)
24545
 {
24546
-    if (!mBackbuffer)
24547
+    if (!mBackbuffer || mBackbuffer->preserveBuffer())
24548
     {
24549
         return;
24550
     }
24551
@@ -812,6 +827,92 @@ PackPixelsParams params(flippedArea, angleFormat, outputPitch, pack.reverseRowOr
24552
     return angle::Result::Continue;
24553
 }
24554
 
24555
+angle::Result FramebufferMtl::getReadableViewForRenderTarget(
24556
+    const gl::Context *context,
24557
+    const RenderTargetMtl &rtt,
24558
+    const gl::Rectangle &readArea,
24559
+    mtl::TextureRef *readableDepthViewOut,
24560
+    mtl::TextureRef *readableStencilViewOut,
24561
+    uint32_t *readableViewLevel,
24562
+    uint32_t *readableViewLayer,
24563
+    gl::Rectangle *readableViewArea)
24564
+{
24565
+    ContextMtl *contextMtl     = mtl::GetImpl(context);
24566
+    mtl::TextureRef srcTexture = rtt.getTexture();
24567
+    uint32_t level             = rtt.getLevelIndex().get();
24568
+    uint32_t slice             = rtt.getLayerIndex();
24569
+
24570
+    // NOTE(hqle): slice is not used atm.
24571
+    ASSERT(slice == 0);
24572
+
24573
+    bool readStencil = readableStencilViewOut;
24574
+
24575
+    if (!srcTexture)
24576
+    {
24577
+        if (readableDepthViewOut)
24578
+        {
24579
+            *readableDepthViewOut = nullptr;
24580
+        }
24581
+        if (readableStencilViewOut)
24582
+        {
24583
+            *readableStencilViewOut = nullptr;
24584
+        }
24585
+        *readableViewArea = readArea;
24586
+        return angle::Result::Continue;
24587
+    }
24588
+
24589
+    bool skipCopy = srcTexture->isShaderReadable();
24590
+    if (rtt.getFormat()->hasDepthAndStencilBits() && readStencil)
24591
+    {
24592
+        // If the texture is packed depth stencil, and we need stencil view,
24593
+        // then it must support creating different format view.
24594
+        skipCopy = skipCopy && srcTexture->supportFormatView();
24595
+    }
24596
+
24597
+    if (skipCopy)
24598
+    {
24599
+        // Texture supports stencil view, just use it directly
24600
+        if (readableDepthViewOut)
24601
+        {
24602
+            *readableDepthViewOut = srcTexture;
24603
+        }
24604
+        if (readableStencilViewOut)
24605
+        {
24606
+            *readableStencilViewOut = srcTexture;
24607
+        }
24608
+        *readableViewLevel = level;
24609
+        *readableViewLayer = slice;
24610
+        *readableViewArea  = readArea;
24611
+    }
24612
+    else
24613
+    {
24614
+        ASSERT(srcTexture->textureType() != MTLTextureType3D);
24615
+
24616
+        // Texture doesn't support stencil view or not shader readable, copy to an interminate
24617
+        // texture that supports stencil view and shader read.
24618
+        mtl::TextureRef formatableView = srcTexture->getReadableCopy(
24619
+            contextMtl, contextMtl->getBlitCommandEncoder(), level, slice,
24620
+            MTLRegionMake2D(readArea.x, readArea.y, readArea.width, readArea.height));
24621
+
24622
+        ANGLE_CHECK_GL_ALLOC(contextMtl, formatableView);
24623
+
24624
+        if (readableDepthViewOut)
24625
+        {
24626
+            *readableDepthViewOut = formatableView;
24627
+        }
24628
+        if (readableStencilViewOut)
24629
+        {
24630
+            *readableStencilViewOut = formatableView->getStencilView();
24631
+        }
24632
+
24633
+        *readableViewLevel = 0;
24634
+        *readableViewLayer = 0;
24635
+        *readableViewArea  = gl::Rectangle(0, 0, readArea.width, readArea.height);
24636
+    }
24637
+
24638
+    return angle::Result::Continue;
24639
+}
24640
+
24641
 angle::Result FramebufferMtl::prepareRenderPass(const gl::Context *context,
24642
                                                 mtl::RenderPassDesc *pDescOut)
24643
 {
24644
@@ -832,9 +933,9 @@ PackPixelsParams params(flippedArea, angleFormat, outputPitch, pack.reverseRowOr
24645
         if (colorRenderTarget)
24646
         {
24647
             colorRenderTarget->toRenderPassAttachmentDesc(&colorAttachment);
24648
+            desc.sampleCount = std::max(desc.sampleCount, colorRenderTarget->getRenderSamples());
24649
 
24650
             desc.numColorAttachments = std::max(desc.numColorAttachments, colorIndexGL + 1);
24651
-            desc.sampleCount = std::max(desc.sampleCount, colorRenderTarget->getRenderSamples());
24652
 
24653
             if (!mRenderPassFirstColorAttachmentFormat)
24654
             {
24655
@@ -862,22 +963,29 @@ PackPixelsParams params(flippedArea, angleFormat, outputPitch, pack.reverseRowOr
24656
         mDepthRenderTarget->toRenderPassAttachmentDesc(&desc.depthAttachment);
24657
         desc.sampleCount = std::max(desc.sampleCount, mDepthRenderTarget->getRenderSamples());
24658
     }
24659
-    else
24660
-    {
24661
-        desc.depthAttachment.reset();
24662
-    }
24663
 
24664
     if (mStencilRenderTarget)
24665
     {
24666
         mStencilRenderTarget->toRenderPassAttachmentDesc(&desc.stencilAttachment);
24667
         desc.sampleCount = std::max(desc.sampleCount, mStencilRenderTarget->getRenderSamples());
24668
     }
24669
+
24670
+    return angle::Result::Continue;
24671
+}
24672
+
24673
+// Override clear color based on texture's write mask
24674
+void FramebufferMtl::overrideClearColor(const mtl::TextureRef &texture,
24675
+                                        MTLClearColor clearColor,
24676
+                                        MTLClearColor *colorOut)
24677
+{
24678
+    if (texture)
24679
+    {
24680
+        *colorOut = mtl::EmulatedAlphaClearColor(clearColor, texture->getColorWritableMask());
24681
+    }
24682
     else
24683
     {
24684
-        desc.stencilAttachment.reset();
24685
+        *colorOut = clearColor;
24686
     }
24687
-
24688
-    return angle::Result::Continue;
24689
 }
24690
 
24691
 angle::Result FramebufferMtl::clearWithLoadOp(const gl::Context *context,
24692
@@ -923,7 +1031,7 @@ PackPixelsParams params(flippedArea, angleFormat, outputPitch, pack.reverseRowOr
24693
 
24694
         mtl::RenderPassColorAttachmentDesc &colorAttachment =
24695
             tempDesc.colorAttachments[colorIndexGL];
24696
-        const mtl::TextureRef &texture = colorAttachment.texture;
24697
+        const mtl::TextureRef &texture = colorAttachment.texture();
24698
 
24699
         if (clearColorBuffers.test(colorIndexGL))
24700
         {
24701
@@ -966,7 +1074,7 @@ PackPixelsParams params(flippedArea, angleFormat, outputPitch, pack.reverseRowOr
24702
 
24703
         mtl::RenderPassColorAttachmentDesc &colorAttachment =
24704
             mRenderPassDesc.colorAttachments[colorIndexGL];
24705
-        const mtl::TextureRef &texture = colorAttachment.texture;
24706
+        const mtl::TextureRef &texture = colorAttachment.texture();
24707
 
24708
         if (clearColorBuffers.test(colorIndexGL))
24709
         {
24710
@@ -1193,8 +1301,9 @@ PackPixelsParams params(flippedArea, angleFormat, outputPitch, pack.reverseRowOr
24711
     gl::Rectangle flippedArea = glArea;
24712
     if (mFlipY)
24713
     {
24714
-        flippedArea.y = readRT->getTexture()->height(readRT->getLevelIndex()) - flippedArea.y -
24715
-                        flippedArea.height;
24716
+        flippedArea.y =
24717
+            readRT->getTexture()->height(readRT->getLevelIndex()) -
24718
+            flippedArea.y - flippedArea.height;
24719
     }
24720
 
24721
     return flippedArea;
24722
@@ -1211,7 +1320,6 @@ PackPixelsParams params(flippedArea, angleFormat, outputPitch, pack.reverseRowOr
24723
     {
24724
         return angle::Result::Continue;
24725
     }
24726
-
24727
     if (packPixelsParams.packBuffer)
24728
     {
24729
         return readPixelsToPBO(context, area, packPixelsParams, renderTarget);
24730
@@ -1279,19 +1387,36 @@ PackPixelsParams params(flippedArea, angleFormat, outputPitch, pack.reverseRowOr
24731
 
24732
     ANGLE_MTL_CHECK(contextMtl, packPixelsParams.offset <= std::numeric_limits<uint32_t>::max(),
24733
                     GL_INVALID_OPERATION);
24734
-    const uint32_t dstBufferOffset      = static_cast<uint32_t>(packPixelsParams.offset);
24735
-    const uint32_t dstBufferRowPitch    = packPixelsParams.outputPitch;
24736
-    const angle::Format &dstAngleFormat = *packPixelsParams.destFormat;
24737
-    const bool reverseRowOrder          = packPixelsParams.reverseRowOrder;
24738
+    uint32_t offset = static_cast<uint32_t>(packPixelsParams.offset);
24739
 
24740
     BufferMtl *packBufferMtl = mtl::GetImpl(packPixelsParams.packBuffer);
24741
     mtl::BufferRef dstBuffer = packBufferMtl->getCurrentBuffer();
24742
 
24743
+    return readPixelsToBuffer(context, area, renderTarget, packPixelsParams.reverseRowOrder,
24744
+                              *packPixelsParams.destFormat, offset, packPixelsParams.outputPitch,
24745
+                              &dstBuffer);
24746
+}
24747
+
24748
+angle::Result FramebufferMtl::readPixelsToBuffer(const gl::Context *context,
24749
+                                                 const gl::Rectangle &area,
24750
+                                                 const RenderTargetMtl *renderTarget,
24751
+                                                 bool reverseRowOrder,
24752
+                                                 const angle::Format &dstAngleFormat,
24753
+                                                 uint32_t dstBufferOffset,
24754
+                                                 uint32_t dstBufferRowPitch,
24755
+                                                 const mtl::BufferRef *pDstBuffer) const
24756
+{
24757
+    ASSERT(renderTarget);
24758
+
24759
+    ContextMtl *contextMtl = mtl::GetImpl(context);
24760
+
24761
     const mtl::Format &readFormat        = *renderTarget->getFormat();
24762
     const angle::Format &readAngleFormat = readFormat.actualAngleFormat();
24763
 
24764
     mtl::TextureRef texture = renderTarget->getTexture();
24765
 
24766
+    const mtl::BufferRef &dstBuffer = *pDstBuffer;
24767
+
24768
     if (dstAngleFormat.id != readAngleFormat.id || texture->samples() > 1 ||
24769
         (dstBufferOffset % dstAngleFormat.pixelBytes) ||
24770
         (dstBufferOffset % mtl::kTextureToBufferBlittingAlignment))
24771
@@ -1359,8 +1484,8 @@ PackPixelsParams params(flippedArea, angleFormat, outputPitch, pack.reverseRowOr
24772
 
24773
             uint32_t bufferRowOffset = dstBufferOffset;
24774
             // Copy pixels row by row
24775
-            for (int r = startRow, copiedRows = 0; copiedRows < area.height;
24776
-                 ++copiedRows, --r, bufferRowOffset += dstBufferRowPitch)
24777
+            for (int r = startRow, i = 0; i < area.height;
24778
+                 ++i, --r, bufferRowOffset += dstBufferRowPitch)
24779
             {
24780
                 srcRowRegion.y = r;
24781
 
24782
@@ -1375,5 +1500,4 @@ PackPixelsParams params(flippedArea, angleFormat, outputPitch, pack.reverseRowOr
24783
 
24784
     return angle::Result::Continue;
24785
 }
24786
-
24787
 }
24788
diff --git a/src/libANGLE/renderer/metal/IOSurfaceSurfaceMtl.h b/src/libANGLE/renderer/metal/IOSurfaceSurfaceMtl.h
24789
new file mode 100644
24790
index 0000000..9548e5d
24791
--- /dev/null
24792
+++ b/src/libANGLE/renderer/metal/IOSurfaceSurfaceMtl.h
24793
@@ -0,0 +1,126 @@
24794
+//
24795
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
24796
+// Use of this source code is governed by a BSD-style license that can be
24797
+// found in the LICENSE file.
24798
+//
24799
+
24800
+#ifndef LIBANGLE_RENDERER_METAL_IOSURFACESURFACEMTL_H_
24801
+#define LIBANGLE_RENDERER_METAL_IOSURFACESURFACEMTL_H_
24802
+
24803
+#include <IOSurface/IOSurfaceRef.h>
24804
+#include "libANGLE/renderer/SurfaceImpl.h"
24805
+#include "libANGLE/renderer/metal/DisplayMtl.h"
24806
+#include "libANGLE/renderer/metal/SurfaceMtl.h"
24807
+
24808
+namespace metal
24809
+{
24810
+class AttributeMap;
24811
+}  // namespace metal
24812
+
24813
+namespace rx
24814
+{
24815
+
24816
+class DisplayMTL;
24817
+
24818
+class IOSurfaceSurfaceMtl : public SurfaceMtlProtocol
24819
+{
24820
+  public:
24821
+    IOSurfaceSurfaceMtl(DisplayMtl *display,
24822
+                        const egl::SurfaceState &state,
24823
+                        EGLClientBuffer buffer,
24824
+                        const egl::AttributeMap &attribs);
24825
+    ~IOSurfaceSurfaceMtl() override;
24826
+
24827
+    void destroy(const egl::Display *display) override;
24828
+
24829
+    egl::Error initialize(const egl::Display *display) override;
24830
+    FramebufferImpl *createDefaultFramebuffer(const gl::Context *context,
24831
+                                              const gl::FramebufferState &state) override;
24832
+
24833
+    egl::Error makeCurrent(const gl::Context *context) override;
24834
+    egl::Error unMakeCurrent(const gl::Context *context) override;
24835
+    egl::Error swap(const gl::Context *context) override;
24836
+    egl::Error postSubBuffer(const gl::Context *context,
24837
+                             EGLint x,
24838
+                             EGLint y,
24839
+                             EGLint width,
24840
+                             EGLint height) override;
24841
+
24842
+    egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) override;
24843
+    egl::Error bindTexImage(const gl::Context *context,
24844
+                            gl::Texture *texture,
24845
+                            EGLint buffer) override;
24846
+    egl::Error releaseTexImage(const gl::Context *context, EGLint buffer) override;
24847
+    egl::Error getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) override;
24848
+    egl::Error getMscRate(EGLint *numerator, EGLint *denominator) override;
24849
+    void setSwapInterval(EGLint interval) override;
24850
+    void setFixedWidth(EGLint width) override;
24851
+    void setFixedHeight(EGLint height) override;
24852
+
24853
+    // Width can change when the client window resizes.
24854
+    EGLint getWidth() const override;
24855
+    // Height can change when the client window resizes.
24856
+    EGLint getHeight() const override;
24857
+
24858
+    EGLint isPostSubBufferSupported() const override;
24859
+    EGLint getSwapBehavior() const override;
24860
+
24861
+    angle::Result getAttachmentRenderTarget(const gl::Context *context,
24862
+                                            GLenum binding,
24863
+                                            const gl::ImageIndex &imageIndex,
24864
+                                            GLsizei samples,
24865
+                                            FramebufferAttachmentRenderTarget **rtOut) override;
24866
+
24867
+    angle::Result ensureCurrentDrawableObtained(const gl::Context *context) override;
24868
+    angle::Result ensureCurrentDrawableObtained(const gl::Context *context,
24869
+                                                bool *newDrawableOut) override;
24870
+    int getSamples() const override { return 1; }
24871
+    bool preserveBuffer() const override { return false; }
24872
+    mtl::TextureRef getTexture(const gl::Context *context);
24873
+    bool hasRobustResourceInit() const override { return false; }
24874
+    angle::Result ensureColorTextureReadyForReadPixels(const gl::Context *context) override
24875
+    {
24876
+        return angle::Result::Continue;
24877
+    }
24878
+    const mtl::TextureRef &getColorTexture() override { return mIOSurfaceTexture; }
24879
+
24880
+  private:
24881
+    angle::Result ensureTextureCreated(const gl::Context *context);
24882
+    angle::Result createBackingTexture(const gl::Context *context);
24883
+    angle::Result createTexture(const gl::Context *context,
24884
+                                const mtl::Format &format,
24885
+                                uint32_t width,
24886
+                                uint32_t height,
24887
+                                bool renderTargetOnly,
24888
+                                mtl::TextureRef *textureOut);
24889
+
24890
+    angle::Result initializeAlphaChannel(const gl::Context *context, GLuint texture);
24891
+
24892
+#if defined(ANGLE_PLATFORM_IOS_SIMULATOR)
24893
+    IOSurfaceLockOptions getIOSurfaceLockOptions() const;
24894
+#endif
24895
+
24896
+    ContextMtl *contextMTL;
24897
+    IOSurfaceRef mIOSurface;
24898
+    mtl::TextureRef mIOSurfaceTexture;
24899
+    mtl::TextureRef mIOSurfaceTextureView;
24900
+    mtl::Format mFormat;
24901
+    mtl::Format mInternalFormat;
24902
+    RenderTargetMtl mRenderTarget;
24903
+    bool mIOSurfaceTextureCreated;
24904
+    int mWidth;
24905
+    int mHeight;
24906
+    int mPlane;
24907
+    int mFormatIndex;
24908
+    int mRowStrideInPixels;
24909
+
24910
+#if defined(ANGLE_PLATFORM_IOS_SIMULATOR)
24911
+    GLuint mBoundTextureID;
24912
+    bool mUploadFromIOSurface;
24913
+    bool mReadbackToIOSurface;
24914
+#endif
24915
+};
24916
+
24917
+}  // namespace rx
24918
+
24919
+#endif  // LIBANGLE_RENDERER_GL_EAGL_IOSURFACESURFACEEAGL_H_
24920
diff --git a/src/libANGLE/renderer/metal/IOSurfaceSurfaceMtl.mm b/src/libANGLE/renderer/metal/IOSurfaceSurfaceMtl.mm
24921
new file mode 100644
24922
index 0000000..8b94859
24923
--- /dev/null
24924
+++ b/src/libANGLE/renderer/metal/IOSurfaceSurfaceMtl.mm
24925
@@ -0,0 +1,467 @@
24926
+//
24927
+// Copyright 2019 The ANGLE Project Authors. All rights reserved.
24928
+// Use of this source code is governed by a BSD-style license that can be
24929
+// found in the LICENSE file.
24930
+//
24931
+// IOSurfaceSurfaceMtl.mm:
24932
+//    Implements the class methods for IOSurfaceSurfaceMtl.
24933
+//
24934
+
24935
+#include "libANGLE/renderer/metal/IOSurfaceSurfaceMtl.h"
24936
+
24937
+#include <TargetConditionals.h>
24938
+
24939
+#include "libANGLE/Display.h"
24940
+#include "libANGLE/Surface.h"
24941
+#include "libANGLE/renderer/metal/ContextMtl.h"
24942
+#include "libANGLE/renderer/metal/DisplayMtl.h"
24943
+#include "libANGLE/renderer/metal/FrameBufferMtl.h"
24944
+#include "libANGLE/renderer/metal/mtl_format_utils.h"
24945
+
24946
+// Compiler can turn on programmatical frame capture in release build by defining
24947
+// ANGLE_METAL_FRAME_CAPTURE flag.
24948
+#if defined(NDEBUG) && !defined(ANGLE_METAL_FRAME_CAPTURE)
24949
+#    define ANGLE_METAL_FRAME_CAPTURE_ENABLED 0
24950
+#else
24951
+#    define ANGLE_METAL_FRAME_CAPTURE_ENABLED 1
24952
+#endif
24953
+namespace rx
24954
+{
24955
+
24956
+namespace
24957
+{
24958
+
24959
+struct IOSurfaceFormatInfo
24960
+{
24961
+    GLenum internalFormat;
24962
+    GLenum type;
24963
+    angle::FormatID pixelFormat;
24964
+    angle::FormatID internalPixelFormat;
24965
+};
24966
+
24967
+static const IOSurfaceFormatInfo kIOSurfaceFormats[] = {
24968
+    {GL_RED, GL_UNSIGNED_BYTE, angle::FormatID::R8_UNORM, angle::FormatID::R8_UNORM},
24969
+    {GL_R16UI, GL_UNSIGNED_SHORT, angle::FormatID::R16G16_UINT, angle::FormatID::R16G16_UINT},
24970
+    {GL_RG, GL_UNSIGNED_BYTE, angle::FormatID::R8G8_UNORM, angle::FormatID::R8G8_UNORM},
24971
+    {GL_RGB, GL_UNSIGNED_BYTE, angle::FormatID::R8G8B8A8_UNORM, angle::FormatID::B8G8R8A8_UNORM},
24972
+    {GL_BGRA_EXT, GL_UNSIGNED_BYTE, angle::FormatID::B8G8R8A8_UNORM,
24973
+     angle::FormatID::B8G8R8A8_UNORM},
24974
+    {GL_RGB10_A2, GL_UNSIGNED_INT_2_10_10_10_REV, angle::FormatID::R10G10B10A2_UNORM,
24975
+     angle::FormatID::R10G10B10A2_UNORM},
24976
+    {GL_RGBA, GL_HALF_FLOAT, angle::FormatID::R16G16B16A16_FLOAT,
24977
+     angle::FormatID::R16G16B16A16_FLOAT},
24978
+};
24979
+
24980
+int FindIOSurfaceFormatIndex(GLenum internalFormat, GLenum type)
24981
+{
24982
+    for (size_t i = 0; i < static_cast<size_t>(ArraySize(kIOSurfaceFormats)); ++i)
24983
+    {
24984
+        const auto &formatInfo = kIOSurfaceFormats[i];
24985
+        if (formatInfo.internalFormat == internalFormat && formatInfo.type == type)
24986
+        {
24987
+            return static_cast<int>(i);
24988
+        }
24989
+    }
24990
+    return -1;
24991
+}
24992
+
24993
+// TODO(jcunningham) : refactor this and surfacemtl to reduce copy+pasted code
24994
+
24995
+ANGLE_MTL_UNUSED
24996
+bool IsFrameCaptureEnabled()
24997
+{
24998
+#if !ANGLE_METAL_FRAME_CAPTURE_ENABLED
24999
+    return false;
25000
+#else
25001
+    // We only support frame capture programmatically if the ANGLE_METAL_FRAME_CAPTURE
25002
+    // environment flag is set. Otherwise, it will slow down the rendering. This allows user to
25003
+    // finely control whether they want to capture the frame for particular application or not.
25004
+    auto var                  = std::getenv("ANGLE_METAL_FRAME_CAPTURE");
25005
+    static const bool enabled = var ? (strcmp(var, "1") == 0) : false;
25006
+
25007
+    return enabled;
25008
+#endif
25009
+}
25010
+
25011
+ANGLE_MTL_UNUSED
25012
+std::string GetMetalCaptureFile()
25013
+{
25014
+#if !ANGLE_METAL_FRAME_CAPTURE_ENABLED
25015
+    return "";
25016
+#else
25017
+    auto var                   = std::getenv("ANGLE_METAL_FRAME_CAPTURE_FILE");
25018
+    const std::string filePath = var ? var : "";
25019
+
25020
+    return filePath;
25021
+#endif
25022
+}
25023
+
25024
+ANGLE_MTL_UNUSED
25025
+size_t MaxAllowedFrameCapture()
25026
+{
25027
+#if !ANGLE_METAL_FRAME_CAPTURE_ENABLED
25028
+    return 0;
25029
+#else
25030
+    auto var                      = std::getenv("ANGLE_METAL_FRAME_CAPTURE_MAX");
25031
+    static const size_t maxFrames = var ? std::atoi(var) : 100;
25032
+
25033
+    return maxFrames;
25034
+#endif
25035
+}
25036
+
25037
+ANGLE_MTL_UNUSED
25038
+size_t MinAllowedFrameCapture()
25039
+{
25040
+#if !ANGLE_METAL_FRAME_CAPTURE_ENABLED
25041
+    return 0;
25042
+#else
25043
+    auto var                     = std::getenv("ANGLE_METAL_FRAME_CAPTURE_MIN");
25044
+    static const size_t minFrame = var ? std::atoi(var) : 0;
25045
+
25046
+    return minFrame;
25047
+#endif
25048
+}
25049
+
25050
+ANGLE_MTL_UNUSED
25051
+bool FrameCaptureDeviceScope()
25052
+{
25053
+#if !ANGLE_METAL_FRAME_CAPTURE_ENABLED
25054
+    return false;
25055
+#else
25056
+    auto var                      = std::getenv("ANGLE_METAL_FRAME_CAPTURE_SCOPE");
25057
+    static const bool scopeDevice = var ? (strcmp(var, "device") == 0) : false;
25058
+
25059
+    return scopeDevice;
25060
+#endif
25061
+}
25062
+
25063
+ANGLE_MTL_UNUSED
25064
+std::atomic<size_t> gFrameCaptured(0);
25065
+
25066
+ANGLE_MTL_UNUSED
25067
+void StartFrameCapture(id<MTLDevice> metalDevice, id<MTLCommandQueue> metalCmdQueue)
25068
+{
25069
+#if ANGLE_METAL_FRAME_CAPTURE_ENABLED
25070
+    if (!IsFrameCaptureEnabled())
25071
+    {
25072
+        return;
25073
+    }
25074
+
25075
+    if (gFrameCaptured >= MaxAllowedFrameCapture())
25076
+    {
25077
+        return;
25078
+    }
25079
+
25080
+    MTLCaptureManager *captureManager = [MTLCaptureManager sharedCaptureManager];
25081
+    if (captureManager.isCapturing)
25082
+    {
25083
+        return;
25084
+    }
25085
+
25086
+    gFrameCaptured++;
25087
+
25088
+    if (gFrameCaptured < MinAllowedFrameCapture())
25089
+    {
25090
+        return;
25091
+    }
25092
+
25093
+#    ifdef __MAC_10_15
25094
+    if (ANGLE_APPLE_AVAILABLE_XCI(10.15, 13.0, 13))
25095
+    {
25096
+        MTLCaptureDescriptor *captureDescriptor = [[MTLCaptureDescriptor alloc] init];
25097
+        captureDescriptor.captureObject         = metalDevice;
25098
+        const std::string filePath              = GetMetalCaptureFile();
25099
+        if (filePath != "")
25100
+        {
25101
+            const std::string numberedPath =
25102
+                filePath + std::to_string(gFrameCaptured - 1) + ".gputrace";
25103
+            captureDescriptor.destination = MTLCaptureDestinationGPUTraceDocument;
25104
+            captureDescriptor.outputURL =
25105
+                [NSURL fileURLWithPath:[NSString stringWithUTF8String:numberedPath.c_str()]
25106
+                           isDirectory:false];
25107
+        }
25108
+        else
25109
+        {
25110
+            // This will pause execution only if application is being debugged inside Xcode
25111
+            captureDescriptor.destination = MTLCaptureDestinationDeveloperTools;
25112
+        }
25113
+
25114
+        NSError *error;
25115
+        if (![captureManager startCaptureWithDescriptor:captureDescriptor error:&error])
25116
+        {
25117
+            NSLog(@"Failed to start capture, error %@", error);
25118
+        }
25119
+    }
25120
+    else
25121
+#    endif  // __MAC_10_15
25122
+        if (ANGLE_APPLE_AVAILABLE_XCI(10.15, 13.0, 13))
25123
+    {
25124
+        MTLCaptureDescriptor *captureDescriptor = [[MTLCaptureDescriptor alloc] init];
25125
+        captureDescriptor.captureObject         = metalDevice;
25126
+
25127
+        NSError *error;
25128
+        if (![captureManager startCaptureWithDescriptor:captureDescriptor error:&error])
25129
+        {
25130
+            NSLog(@"Failed to start capture, error %@", error);
25131
+        }
25132
+    }
25133
+#endif  // ANGLE_METAL_FRAME_CAPTURE_ENABLED
25134
+}
25135
+
25136
+void StartFrameCapture(ContextMtl *context)
25137
+{
25138
+    StartFrameCapture(context->getMetalDevice(), context->cmdQueue().get());
25139
+}
25140
+
25141
+void StopFrameCapture()
25142
+{
25143
+#if ANGLE_METAL_FRAME_CAPTURE_ENABLED
25144
+    if (!IsFrameCaptureEnabled())
25145
+    {
25146
+        return;
25147
+    }
25148
+    MTLCaptureManager *captureManager = [MTLCaptureManager sharedCaptureManager];
25149
+    if (captureManager.isCapturing)
25150
+    {
25151
+        [captureManager stopCapture];
25152
+    }
25153
+#endif
25154
+}
25155
+
25156
+}  // anonymous namespace
25157
+
25158
+IOSurfaceSurfaceMtl::IOSurfaceSurfaceMtl(DisplayMtl *display,
25159
+                                         const egl::SurfaceState &state,
25160
+                                         EGLClientBuffer buffer,
25161
+                                         const egl::AttributeMap &attribs)
25162
+    : SurfaceMtlProtocol(state)
25163
+{
25164
+    // Keep reference to the IOSurface so it doesn't get deleted while the pbuffer exists.
25165
+    mIOSurface = reinterpret_cast<IOSurfaceRef>(buffer);
25166
+    CFRetain(mIOSurface);
25167
+
25168
+    // Extract attribs useful for the call to EAGLTexImageIOSurface2D
25169
+    mWidth  = static_cast<int>(attribs.get(EGL_WIDTH));
25170
+    mHeight = static_cast<int>(attribs.get(EGL_HEIGHT));
25171
+    mPlane  = static_cast<int>(attribs.get(EGL_IOSURFACE_PLANE_ANGLE));
25172
+    // Hopefully the number of bytes per row is always an integer number of pixels. We use
25173
+    // glReadPixels to fill the IOSurface in the simulator and it can only support strides that are
25174
+    // an integer number of pixels.
25175
+    ASSERT(IOSurfaceGetBytesPerRowOfPlane(mIOSurface, mPlane) %
25176
+               IOSurfaceGetBytesPerElementOfPlane(mIOSurface, mPlane) ==
25177
+           0);
25178
+    mRowStrideInPixels = static_cast<int>(IOSurfaceGetBytesPerRowOfPlane(mIOSurface, mPlane) /
25179
+                                          IOSurfaceGetBytesPerElementOfPlane(mIOSurface, mPlane));
25180
+
25181
+    EGLAttrib internalFormat = attribs.get(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE);
25182
+    EGLAttrib type           = attribs.get(EGL_TEXTURE_TYPE_ANGLE);
25183
+    mFormatIndex =
25184
+        FindIOSurfaceFormatIndex(static_cast<GLenum>(internalFormat), static_cast<GLenum>(type));
25185
+    ASSERT(mFormatIndex >= 0);
25186
+    mFormat         = display->getPixelFormat(kIOSurfaceFormats[mFormatIndex].pixelFormat);
25187
+    mInternalFormat = display->getPixelFormat(kIOSurfaceFormats[mFormatIndex].internalPixelFormat);
25188
+}
25189
+
25190
+IOSurfaceSurfaceMtl::~IOSurfaceSurfaceMtl()
25191
+{
25192
+    StopFrameCapture();
25193
+    if (mIOSurface != nullptr)
25194
+    {
25195
+        CFRelease(mIOSurface);
25196
+        mIOSurface = nullptr;
25197
+    }
25198
+}
25199
+
25200
+void IOSurfaceSurfaceMtl::destroy(const egl::Display *display) {}
25201
+
25202
+egl::Error IOSurfaceSurfaceMtl::initialize(const egl::Display *display)
25203
+{
25204
+    DisplayMtl *displayMtl    = mtl::GetImpl(display);
25205
+    id<MTLDevice> metalDevice = displayMtl->getMetalDevice();
25206
+
25207
+    StartFrameCapture(metalDevice, displayMtl->cmdQueue().get());
25208
+    return egl::NoError();
25209
+}
25210
+
25211
+FramebufferImpl *IOSurfaceSurfaceMtl::createDefaultFramebuffer(const gl::Context *context,
25212
+                                                               const gl::FramebufferState &state)
25213
+{
25214
+    auto fbo = new FramebufferMtl(state, /* flipY */ true, /* backbuffer */ this);
25215
+    return fbo;
25216
+}
25217
+
25218
+egl::Error IOSurfaceSurfaceMtl::makeCurrent(const gl::Context *context)
25219
+{
25220
+    ContextMtl *contextMtl = mtl::GetImpl(context);
25221
+    StartFrameCapture(contextMtl);
25222
+    return egl::NoError();
25223
+}
25224
+
25225
+egl::Error IOSurfaceSurfaceMtl::unMakeCurrent(const gl::Context *context)
25226
+{
25227
+    StopFrameCapture();
25228
+    return egl::NoError();
25229
+}
25230
+
25231
+egl::Error IOSurfaceSurfaceMtl::swap(const gl::Context *context)
25232
+{
25233
+    StopFrameCapture();
25234
+    ContextMtl *contextMtl = mtl::GetImpl(context);
25235
+    StartFrameCapture(contextMtl);
25236
+    return egl::NoError();
25237
+}
25238
+
25239
+egl::Error IOSurfaceSurfaceMtl::postSubBuffer(const gl::Context *context,
25240
+                                              EGLint x,
25241
+                                              EGLint y,
25242
+                                              EGLint width,
25243
+                                              EGLint height)
25244
+{
25245
+    UNIMPLEMENTED();
25246
+    return egl::EglBadAccess();
25247
+}
25248
+
25249
+egl::Error IOSurfaceSurfaceMtl::querySurfacePointerANGLE(EGLint attribute, void **value)
25250
+{
25251
+    UNIMPLEMENTED();
25252
+    return egl::EglBadAccess();
25253
+}
25254
+
25255
+egl::Error IOSurfaceSurfaceMtl::bindTexImage(const gl::Context *context,
25256
+                                             gl::Texture *texture,
25257
+                                             EGLint buffer)
25258
+{
25259
+
25260
+    angle::Result res = createBackingTexture(context);
25261
+    if (res == angle::Result::Continue)
25262
+        return egl::NoError();
25263
+    else
25264
+        return egl::EglBadAccess();
25265
+}
25266
+
25267
+egl::Error IOSurfaceSurfaceMtl::releaseTexImage(const gl::Context *context, EGLint buffer)
25268
+{
25269
+    // This will need implementation
25270
+    ContextMtl *contextMtl = mtl::GetImpl(context);
25271
+    if (contextMtl->flush(context) == angle::Result::Continue)
25272
+    {
25273
+        mIOSurfaceTextureCreated = false;
25274
+        return egl::NoError();
25275
+    }
25276
+    return egl::EglBadAccess();
25277
+}
25278
+
25279
+egl::Error IOSurfaceSurfaceMtl::getSyncValues(EGLuint64KHR *ust,
25280
+                                              EGLuint64KHR *msc,
25281
+                                              EGLuint64KHR *sbc)
25282
+{
25283
+    UNIMPLEMENTED();
25284
+    return egl::EglBadAccess();
25285
+}
25286
+
25287
+egl::Error IOSurfaceSurfaceMtl::getMscRate(EGLint *numerator, EGLint *denominator)
25288
+{
25289
+    UNIMPLEMENTED();
25290
+    return egl::EglBadAccess();
25291
+}
25292
+
25293
+void IOSurfaceSurfaceMtl::setSwapInterval(EGLint interval)
25294
+{
25295
+    UNIMPLEMENTED();
25296
+}
25297
+
25298
+void IOSurfaceSurfaceMtl::setFixedWidth(EGLint width)
25299
+{
25300
+    UNIMPLEMENTED();
25301
+}
25302
+
25303
+void IOSurfaceSurfaceMtl::setFixedHeight(EGLint height)
25304
+{
25305
+    UNIMPLEMENTED();
25306
+}
25307
+
25308
+// width and height can change with client window resizing
25309
+EGLint IOSurfaceSurfaceMtl::getWidth() const
25310
+{
25311
+    return static_cast<EGLint>(mWidth);
25312
+}
25313
+
25314
+EGLint IOSurfaceSurfaceMtl::getHeight() const
25315
+{
25316
+    return static_cast<EGLint>(mHeight);
25317
+}
25318
+
25319
+EGLint IOSurfaceSurfaceMtl::isPostSubBufferSupported() const
25320
+{
25321
+    return EGL_FALSE;
25322
+}
25323
+
25324
+EGLint IOSurfaceSurfaceMtl::getSwapBehavior() const
25325
+{
25326
+    return EGL_BUFFER_DESTROYED;
25327
+}
25328
+
25329
+angle::Result IOSurfaceSurfaceMtl::getAttachmentRenderTarget(
25330
+    const gl::Context *context,
25331
+    GLenum binding,
25332
+    const gl::ImageIndex &imageIndex,
25333
+    GLsizei samples,
25334
+    FramebufferAttachmentRenderTarget **rtOut)
25335
+{
25336
+    ANGLE_TRY(ensureTextureCreated(context));
25337
+    *rtOut = &mRenderTarget;
25338
+    return angle::Result::Continue;
25339
+}
25340
+
25341
+angle::Result IOSurfaceSurfaceMtl::ensureCurrentDrawableObtained(const gl::Context *context, bool *newDrawableOut)
25342
+{
25343
+    return angle::Result::Continue;
25344
+}
25345
+angle::Result IOSurfaceSurfaceMtl::ensureCurrentDrawableObtained(const gl::Context *context)
25346
+{
25347
+    return angle::Result::Continue;
25348
+}
25349
+
25350
+angle::Result IOSurfaceSurfaceMtl::createBackingTexture(const gl::Context *context)
25351
+{
25352
+    mtl::TextureRef mTemporarySurfaceRef;
25353
+    ANGLE_TRY(createTexture(context, mFormat, mWidth, mHeight, false, &mTemporarySurfaceRef));
25354
+    // Create texture view around the base format of the texture.
25355
+    mIOSurfaceTexture =
25356
+        mTemporarySurfaceRef->createViewWithDifferentFormat(MTLPixelFormatBGRA8Unorm);
25357
+    mRenderTarget.set(mIOSurfaceTexture, mtl::kZeroNativeMipLevel, 0, mInternalFormat);
25358
+    mIOSurfaceTextureCreated = true;
25359
+    return angle::Result::Continue;
25360
+}
25361
+
25362
+angle::Result IOSurfaceSurfaceMtl::ensureTextureCreated(const gl::Context *context)
25363
+{
25364
+    if (!mIOSurfaceTextureCreated)
25365
+    {
25366
+        return createBackingTexture(context);
25367
+    }
25368
+    return angle::Result::Continue;
25369
+}
25370
+
25371
+mtl::TextureRef IOSurfaceSurfaceMtl::getTexture(const gl::Context *context)
25372
+{
25373
+    if (ensureCurrentDrawableObtained(context) == angle::Result::Continue)
25374
+    {
25375
+        return mIOSurfaceTexture;
25376
+    }
25377
+    return nullptr;
25378
+}
25379
+
25380
+angle::Result IOSurfaceSurfaceMtl::createTexture(const gl::Context *context,
25381
+                                                 const mtl::Format &format,
25382
+                                                 uint32_t width,
25383
+                                                 uint32_t height,
25384
+                                                 bool renderTargetOnly,
25385
+                                                 mtl::TextureRef *textureOut)
25386
+{
25387
+    ContextMtl *contextMtl = mtl::GetImpl(context);
25388
+    ANGLE_TRY(mtl::Texture::MakeIOSurfaceTexture(contextMtl, format, width, height, mIOSurface,
25389
+                                                 mPlane, textureOut));
25390
+    return angle::Result::Continue;
25391
+}
25392
+}
25393
diff --git a/src/libANGLE/renderer/metal/ProgramMtl.h b/src/libANGLE/renderer/metal/ProgramMtl.h
25394
index 389ece7..eb9bb01 100644
25395
--- a/src/libANGLE/renderer/metal/ProgramMtl.h
25396
+++ b/src/libANGLE/renderer/metal/ProgramMtl.h
25397
@@ -20,12 +20,13 @@
25398
 #include "libANGLE/renderer/glslang_wrapper_utils.h"
25399
 #include "libANGLE/renderer/metal/mtl_buffer_pool.h"
25400
 #include "libANGLE/renderer/metal/mtl_command_buffer.h"
25401
-#include "libANGLE/renderer/metal/mtl_glslang_utils.h"
25402
+#include "libANGLE/renderer/metal/mtl_glslang_mtl_utils.h"
25403
 #include "libANGLE/renderer/metal/mtl_resources.h"
25404
 #include "libANGLE/renderer/metal/mtl_state_cache.h"
25405
 
25406
 namespace rx
25407
 {
25408
+#define SHADER_ENTRY_NAME @"main0"
25409
 class ContextMtl;
25410
 
25411
 struct ProgramArgumentBufferEncoderMtl
25412
@@ -134,6 +135,10 @@ class ProgramMtl : public ProgramImpl, public mtl::RenderPipelineCacheSpecialize
25413
     bool hasSpecializedShader(gl::ShaderType shaderType,
25414
                               const mtl::RenderPipelineDesc &renderPipelineDesc) override;
25415
 
25416
+    angle::Result createMslShaderLib(mtl::Context *context,
25417
+                                     gl::ShaderType shaderType,
25418
+                                     gl::InfoLog &infoLog,
25419
+                                     mtl::TranslatedShaderInfo *translatedMslInfo);
25420
     // Calls this before drawing, changedPipelineDesc is passed when vertex attributes desc and/or
25421
     // shader program changed.
25422
     angle::Result setupDraw(const gl::Context *glContext,
25423
@@ -141,7 +146,12 @@ class ProgramMtl : public ProgramImpl, public mtl::RenderPipelineCacheSpecialize
25424
                             const mtl::RenderPipelineDesc &pipelineDesc,
25425
                             bool pipelineDescChanged,
25426
                             bool forceTexturesSetting,
25427
-                            bool uniformBuffersDirty);
25428
+                            bool uniformBuffersDirty,
25429
+                            bool transformFeedbackDraw);
25430
+
25431
+    std::string getXfbMslSource() const { return mXfbMslSource; }
25432
+
25433
+    mtl::RenderPipelineCache *mMetalXfbRenderPipelineCache;
25434
 
25435
   private:
25436
     template <int cols, int rows>
25437
@@ -156,6 +166,11 @@ class ProgramMtl : public ProgramImpl, public mtl::RenderPipelineCacheSpecialize
25438
     void setUniformImpl(GLint location, GLsizei count, const T *v, GLenum entryPointType);
25439
 
25440
     angle::Result initDefaultUniformBlocks(const gl::Context *glContext);
25441
+    angle::Result resizeDefaultUniformBlocksMemory(const gl::Context *glContext,
25442
+                                                   const gl::ShaderMap<size_t> &requiredBufferSize);
25443
+    void saveDefaultUniformBlocksInfo(gl::BinaryOutputStream *stream);
25444
+    angle::Result loadDefaultUniformBlocksInfo(const gl::Context *glContext,
25445
+                                               gl::BinaryInputStream *stream);
25446
 
25447
     angle::Result commitUniforms(ContextMtl *context, mtl::RenderCommandEncoder *cmdEncoder);
25448
     angle::Result updateTextures(const gl::Context *glContext,
25449
@@ -177,21 +192,33 @@ class ProgramMtl : public ProgramImpl, public mtl::RenderPipelineCacheSpecialize
25450
         const std::vector<gl::InterfaceBlock> &blocks,
25451
         gl::ShaderType shaderType);
25452
 
25453
-    angle::Result updateXfbBuffers(ContextMtl *context,
25454
-                                   mtl::RenderCommandEncoder *cmdEncoder,
25455
-                                   const mtl::RenderPipelineDesc &pipelineDesc);
25456
-
25457
     void reset(ContextMtl *context);
25458
 
25459
+    void saveTranslatedShaders(gl::BinaryOutputStream *stream);
25460
+    void loadTranslatedShaders(gl::BinaryInputStream *stream);
25461
+
25462
+    void saveShaderInternalInfo(gl::BinaryOutputStream *stream);
25463
+    void loadShaderInternalInfo(gl::BinaryInputStream *stream);
25464
+
25465
+#if ANGLE_ENABLE_METAL_SPIRV
25466
+
25467
+    angle::Result linkImplSpirv(const gl::Context *glContext,
25468
+                                const gl::ProgramLinkedResources &resources,
25469
+                                gl::InfoLog &infoLog);
25470
+#endif
25471
+
25472
+    angle::Result linkImplDirect(const gl::Context *glContext,
25473
+                                 const gl::ProgramLinkedResources &resources,
25474
+                                 gl::InfoLog &infoLog);
25475
+
25476
     void linkResources(const gl::ProgramLinkedResources &resources);
25477
     angle::Result linkImpl(const gl::Context *glContext,
25478
                            const gl::ProgramLinkedResources &resources,
25479
                            gl::InfoLog &infoLog);
25480
 
25481
-    angle::Result createMslShaderLib(mtl::Context *context,
25482
-                                     gl::ShaderType shaderType,
25483
-                                     gl::InfoLog &infoLog,
25484
-                                     mtl::TranslatedShaderInfo *translatedMslInfo);
25485
+    angle::Result linkTranslatedShaders(const gl::Context *glContext,
25486
+                                        gl::BinaryInputStream *stream,
25487
+                                        gl::InfoLog &infoLog);
25488
 
25489
     // State for the default uniform blocks.
25490
     struct DefaultUniformBlock final : private angle::NonCopyable
25491
@@ -230,6 +257,7 @@ class ProgramMtl : public ProgramImpl, public mtl::RenderPipelineCacheSpecialize
25492
     // Cached references of current shader variants.
25493
     gl::ShaderMap<ProgramShaderObjVariantMtl *> mCurrentShaderVariants;
25494
 
25495
+    ShaderMapInterfaceVariableInfoMap mVariableInfoMap;
25496
     // Scratch data:
25497
     // Legalized buffers and their offsets. For example, uniform buffer's offset=1 is not a valid
25498
     // offset, it will be converted to legal offset and the result is stored in this array.
25499
@@ -238,7 +266,10 @@ class ProgramMtl : public ProgramImpl, public mtl::RenderPipelineCacheSpecialize
25500
     // into an argument buffer.
25501
     std::vector<uint32_t> mArgumentBufferRenderStageUsages;
25502
 
25503
+    uint32_t mShadowCompareModes[mtl::kMaxShaderSamplers] = {0};
25504
+
25505
     mtl::RenderPipelineCache mMetalRenderPipelineCache;
25506
+    std::string mXfbMslSource;
25507
 };
25508
 
25509
 }  // namespace rx
25510
diff --git a/src/libANGLE/renderer/metal/ProgramMtl.mm b/src/libANGLE/renderer/metal/ProgramMtl.mm
25511
index 50e2f63..6da8664 100644
25512
--- a/src/libANGLE/renderer/metal/ProgramMtl.mm
25513
+++ b/src/libANGLE/renderer/metal/ProgramMtl.mm
25514
@@ -14,25 +14,31 @@
25515
 #include <sstream>
25516
 
25517
 #include "common/debug.h"
25518
+#include "compiler/translator/TranslatorMetal.h"
25519
+#include "compiler/translator/TranslatorMetalDirect.h"
25520
+#include "compiler/translator/TranslatorMetalDirect/EnvironmentVariable.h"
25521
 #include "libANGLE/Context.h"
25522
 #include "libANGLE/ProgramLinkedResources.h"
25523
 #include "libANGLE/renderer/metal/BufferMtl.h"
25524
 #include "libANGLE/renderer/metal/ContextMtl.h"
25525
 #include "libANGLE/renderer/metal/DisplayMtl.h"
25526
 #include "libANGLE/renderer/metal/TextureMtl.h"
25527
-#include "libANGLE/renderer/metal/mtl_glslang_utils.h"
25528
+#include "libANGLE/renderer/metal/mtl_glslang_mtl_utils.h"
25529
 #include "libANGLE/renderer/metal/mtl_utils.h"
25530
 #include "libANGLE/renderer/renderer_utils.h"
25531
 
25532
+#if ANGLE_ENABLE_METAL_SPIRV
25533
+#    include "libANGLE/renderer/metal/mtl_glslang_utils.h"
25534
+#endif
25535
+
25536
 namespace rx
25537
 {
25538
 
25539
 namespace
25540
 {
25541
-
25542
-#define SHADER_ENTRY_NAME @"main0"
25543
+#if ANGLE_ENABLE_METAL_SPIRV
25544
 constexpr char kSpirvCrossSpecConstSuffix[] = "_tmp";
25545
-
25546
+#endif
25547
 template <typename T>
25548
 class ScopedAutoClearVector
25549
 {
25550
@@ -78,6 +84,7 @@ void InitDefaultUniformBlock(const std::vector<sh::Uniform> &uniforms,
25551
 
25552
     size_t blockSize = blockEncoder.getCurrentOffset();
25553
 
25554
+    // TODO(jmadill): I think we still need a valid block for the pipeline even if zero sized.
25555
     if (blockSize == 0)
25556
     {
25557
         *blockSizeOut = 0;
25558
@@ -228,11 +235,16 @@ void InitArgumentBufferEncoder(mtl::Context *context,
25559
 
25560
 ProgramMtl::DefaultUniformBlock::~DefaultUniformBlock() = default;
25561
 
25562
-ProgramMtl::ProgramMtl(const gl::ProgramState &state)
25563
-    : ProgramImpl(state), mMetalRenderPipelineCache(this)
25564
-{}
25565
+ProgramMtl::ProgramMtl(const gl::ProgramState &state) : ProgramImpl(state),
25566
+    mMetalRenderPipelineCache(this)
25567
+{
25568
+    mMetalXfbRenderPipelineCache = new mtl::RenderPipelineCache();
25569
+}
25570
 
25571
-ProgramMtl::~ProgramMtl() {}
25572
+ProgramMtl::~ProgramMtl()
25573
+{
25574
+    delete mMetalXfbRenderPipelineCache;
25575
+}
25576
 
25577
 void ProgramMtl::destroy(const gl::Context *context)
25578
 {
25579
@@ -262,25 +274,46 @@ void InitArgumentBufferEncoder(mtl::Context *context,
25580
     {
25581
         var.reset(context);
25582
     }
25583
-
25584
     mMetalRenderPipelineCache.clear();
25585
+    mMetalXfbRenderPipelineCache->clear();
25586
+}
25587
+
25588
+void ProgramMtl::saveTranslatedShaders(gl::BinaryOutputStream *stream)
25589
+{
25590
+    // Write out shader sources for all shader types
25591
+    for (const gl::ShaderType shaderType : gl::AllShaderTypes())
25592
+    {
25593
+        stream->writeString(mMslShaderTranslateInfo[shaderType].metalShaderSource);
25594
+    }
25595
+    stream->writeString(mXfbMslSource);
25596
+}
25597
+
25598
+void ProgramMtl::loadTranslatedShaders(gl::BinaryInputStream *stream)
25599
+{
25600
+    // Read in shader sources for all shader types
25601
+    for (const gl::ShaderType shaderType : gl::AllShaderTypes())
25602
+    {
25603
+        mMslShaderTranslateInfo[shaderType].metalShaderSource = stream->readString();
25604
+    }
25605
+    mXfbMslSource = stream->readString();
25606
 }
25607
 
25608
 std::unique_ptr<rx::LinkEvent> ProgramMtl::load(const gl::Context *context,
25609
                                                 gl::BinaryInputStream *stream,
25610
                                                 gl::InfoLog &infoLog)
25611
 {
25612
-    // NOTE(hqle): support binary shader
25613
-    UNIMPLEMENTED();
25614
-    return std::make_unique<LinkEventDone>(angle::Result::Stop);
25615
+
25616
+    return std::make_unique<LinkEventDone>(linkTranslatedShaders(context, stream, infoLog));
25617
 }
25618
 
25619
 void ProgramMtl::save(const gl::Context *context, gl::BinaryOutputStream *stream)
25620
 {
25621
-    // NOTE(hqle): support binary shader
25622
-    UNIMPLEMENTED();
25623
+    saveTranslatedShaders(stream);
25624
+    saveShaderInternalInfo(stream);
25625
+    saveDefaultUniformBlocksInfo(stream);
25626
 }
25627
 
25628
+
25629
 void ProgramMtl::setBinaryRetrievableHint(bool retrievable)
25630
 {
25631
     UNIMPLEMENTED();
25632
@@ -294,7 +327,7 @@ void InitArgumentBufferEncoder(mtl::Context *context,
25633
 std::unique_ptr<LinkEvent> ProgramMtl::link(const gl::Context *context,
25634
                                             const gl::ProgramLinkedResources &resources,
25635
                                             gl::InfoLog &infoLog,
25636
-                                            const gl::ProgramMergedVaryings & /* mergedVaryings */)
25637
+                                            const gl::ProgramMergedVaryings &mergedVaryings)
25638
 {
25639
     // Link resources before calling GetShaderSource to make sure they are ready for the set/binding
25640
     // assignment done in that function.
25641
@@ -304,7 +337,8 @@ void InitArgumentBufferEncoder(mtl::Context *context,
25642
     return std::make_unique<LinkEventDone>(linkImpl(context, resources, infoLog));
25643
 }
25644
 
25645
-angle::Result ProgramMtl::linkImpl(const gl::Context *glContext,
25646
+#if ANGLE_ENABLE_METAL_SPIRV
25647
+angle::Result ProgramMtl::linkImplSpirv(const gl::Context *glContext,
25648
                                    const gl::ProgramLinkedResources &resources,
25649
                                    gl::InfoLog &infoLog)
25650
 {
25651
@@ -355,6 +389,75 @@ void InitArgumentBufferEncoder(mtl::Context *context,
25652
 
25653
     return angle::Result::Continue;
25654
 }
25655
+#endif
25656
+
25657
+angle::Result ProgramMtl::linkImplDirect(const gl::Context *glContext,
25658
+                                   const gl::ProgramLinkedResources &resources,
25659
+                                   gl::InfoLog &infoLog)
25660
+{
25661
+    ContextMtl *contextMtl = mtl::GetImpl(glContext);
25662
+
25663
+    reset(contextMtl);
25664
+    ANGLE_TRY(initDefaultUniformBlocks(glContext));
25665
+    ShaderMapInterfaceVariableInfoMap variableInfoMap;
25666
+
25667
+    gl::ShaderMap<std::string> shaderSources;
25668
+    gl::ShaderMap<std::string> translatedMslShaders;
25669
+    mtl::MSLGetShaderSource(mState, resources, &shaderSources, &variableInfoMap);
25670
+
25671
+    ANGLE_TRY(mtl::GlslangGetMSL(glContext, mState, contextMtl->getCaps(), shaderSources,
25672
+                                 variableInfoMap, &mMslShaderTranslateInfo,
25673
+                                 &translatedMslShaders,
25674
+                                 mState.getExecutable().getTransformFeedbackBufferCount()));
25675
+
25676
+
25677
+    for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
25678
+    {
25679
+        // Create actual Metal shader
25680
+        ANGLE_TRY(
25681
+            createMslShaderLib(contextMtl, shaderType, infoLog, &mMslShaderTranslateInfo[shaderType]));
25682
+    }
25683
+    return angle::Result::Continue;
25684
+}
25685
+
25686
+angle::Result ProgramMtl::linkImpl(const gl::Context *glContext,
25687
+                                   const gl::ProgramLinkedResources &resources,
25688
+                                   gl::InfoLog &infoLog)
25689
+{
25690
+    // TODO: We need some way of toggling this.
25691
+#if ANGLE_ENABLE_METAL_SPIRV
25692
+    if (sh::readBoolEnvVar("ANGLE_GEN_MTL_WITH_SPIRV"))
25693
+    {
25694
+       return linkImplSpirv(glContext, resources, infoLog);
25695
+    }
25696
+    else
25697
+#endif
25698
+    {
25699
+       return linkImplDirect(glContext, resources, infoLog);
25700
+    }
25701
+}
25702
+
25703
+
25704
+angle::Result ProgramMtl::linkTranslatedShaders(const gl::Context *glContext,
25705
+                                                gl::BinaryInputStream *stream,
25706
+                                                gl::InfoLog &infoLog)
25707
+{
25708
+    ContextMtl *contextMtl = mtl::GetImpl(glContext);
25709
+    // NOTE(hqle): No transform feedbacks for now, since we only support ES 2.0 atm
25710
+
25711
+    reset(contextMtl);
25712
+
25713
+    loadTranslatedShaders(stream);
25714
+    loadShaderInternalInfo(stream);
25715
+    ANGLE_TRY(loadDefaultUniformBlocksInfo(glContext, stream));
25716
+
25717
+    ANGLE_TRY(createMslShaderLib(contextMtl, gl::ShaderType::Vertex, infoLog,
25718
+                              &mMslShaderTranslateInfo[gl::ShaderType::Vertex]));
25719
+    ANGLE_TRY(createMslShaderLib(contextMtl, gl::ShaderType::Fragment, infoLog,
25720
+                              &mMslShaderTranslateInfo[gl::ShaderType::Fragment]));
25721
+
25722
+    return angle::Result::Continue;
25723
+}
25724
 
25725
 void ProgramMtl::linkResources(const gl::ProgramLinkedResources &resources)
25726
 {
25727
@@ -366,8 +469,6 @@ void InitArgumentBufferEncoder(mtl::Context *context,
25728
 
25729
 angle::Result ProgramMtl::initDefaultUniformBlocks(const gl::Context *glContext)
25730
 {
25731
-    ContextMtl *contextMtl = mtl::GetImpl(glContext);
25732
-
25733
     // Process vertex and fragment uniforms into std140 packing.
25734
     gl::ShaderMap<sh::BlockLayoutMap> layoutMap;
25735
     gl::ShaderMap<size_t> requiredBufferSize;
25736
@@ -426,6 +527,15 @@ void InitArgumentBufferEncoder(mtl::Context *context,
25737
         }
25738
     }
25739
 
25740
+    return resizeDefaultUniformBlocksMemory(glContext, requiredBufferSize);
25741
+}
25742
+
25743
+angle::Result ProgramMtl::resizeDefaultUniformBlocksMemory(
25744
+    const gl::Context *glContext,
25745
+    const gl::ShaderMap<size_t> &requiredBufferSize)
25746
+{
25747
+    ContextMtl *contextMtl = mtl::GetImpl(glContext);
25748
+
25749
     for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
25750
     {
25751
         if (requiredBufferSize[shaderType] > 0)
25752
@@ -453,6 +563,9 @@ void InitArgumentBufferEncoder(mtl::Context *context,
25753
                                                id<MTLFunction> *shaderOut)
25754
 {
25755
     static_assert(YES == 1, "YES should have value of 1");
25756
+    #if ANGLE_ENABLE_METAL_SPIRV
25757
+        static const bool useSpirv = sh::readBoolEnvVar("ANGLE_GEN_MTL_WITH_SPIRV");
25758
+    #endif
25759
 
25760
     mtl::TranslatedShaderInfo *translatedMslInfo = &mMslShaderTranslateInfo[shaderType];
25761
     ProgramShaderObjVariantMtl *shaderVariant;
25762
@@ -490,9 +603,22 @@ void InitArgumentBufferEncoder(mtl::Context *context,
25763
             BOOL emulateDiscard = renderPipelineDesc.rasterizationType ==
25764
                                   mtl::RenderPipelineRasterization::EmulatedDiscard;
25765
 
25766
-            NSString *discardEnabledStr =
25767
-                [NSString stringWithFormat:@"%s%s", sh::mtl::kRasterizerDiscardEnabledConstName,
25768
+            NSString *discardEnabledStr;
25769
+#if ANGLE_ENABLE_METAL_SPIRV
25770
+            if (useSpirv)
25771
+            {
25772
+                discardEnabledStr = [NSString
25773
+                    stringWithFormat:@"%s%s",
25774
+                                     sh::TranslatorMetal::GetRasterizationDiscardEnabledConstName(),
25775
                                      kSpirvCrossSpecConstSuffix];
25776
+            }
25777
+            else
25778
+#endif
25779
+            {
25780
+                discardEnabledStr =
25781
+                    [NSString stringWithUTF8String:sh::TranslatorMetalDirect::
25782
+                                                       GetRasterizationDiscardEnabledConstName()];
25783
+            }
25784
 
25785
             funcConstants = [[MTLFunctionConstantValues alloc] init];
25786
             [funcConstants setConstantValue:&emulateDiscard
25787
@@ -515,9 +641,22 @@ void InitArgumentBufferEncoder(mtl::Context *context,
25788
 
25789
         ANGLE_MTL_OBJC_SCOPE
25790
         {
25791
-            NSString *coverageMaskEnabledStr =
25792
-                [NSString stringWithFormat:@"%s%s", sh::mtl::kCoverageMaskEnabledConstName,
25793
+            NSString *coverageMaskEnabledStr;
25794
+#if ANGLE_ENABLE_METAL_SPIRV
25795
+            if (useSpirv)
25796
+            {
25797
+                coverageMaskEnabledStr = [NSString
25798
+                    stringWithFormat:@"%s%s",
25799
+                                     sh::TranslatorMetal::GetCoverageMaskEnabledConstName(),
25800
                                      kSpirvCrossSpecConstSuffix];
25801
+            }
25802
+            else
25803
+#endif
25804
+            {
25805
+                coverageMaskEnabledStr =
25806
+                    [NSString stringWithUTF8String:sh::TranslatorMetalDirect::
25807
+                                                       GetCoverageMaskEnabledConstName()];
25808
+            }
25809
 
25810
             funcConstants = [[MTLFunctionConstantValues alloc] init];
25811
             [funcConstants setConstantValue:&emulateCoverageMask
25812
@@ -555,6 +694,7 @@ void InitArgumentBufferEncoder(mtl::Context *context,
25813
 
25814
     return angle::Result::Continue;
25815
 }
25816
+
25817
 bool ProgramMtl::hasSpecializedShader(gl::ShaderType shaderType,
25818
                                       const mtl::RenderPipelineDesc &renderPipelineDesc)
25819
 {
25820
@@ -592,6 +732,93 @@ void InitArgumentBufferEncoder(mtl::Context *context,
25821
     }
25822
 }
25823
 
25824
+void ProgramMtl::saveDefaultUniformBlocksInfo(gl::BinaryOutputStream *stream)
25825
+{
25826
+    // Serializes the uniformLayout data of mDefaultUniformBlocks
25827
+    for (gl::ShaderType shaderType : gl::AllShaderTypes())
25828
+    {
25829
+        const size_t uniformCount = mDefaultUniformBlocks[shaderType].uniformLayout.size();
25830
+        stream->writeInt<size_t>(uniformCount);
25831
+        for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
25832
+        {
25833
+            sh::BlockMemberInfo &blockInfo =
25834
+                mDefaultUniformBlocks[shaderType].uniformLayout[uniformIndex];
25835
+            gl::WriteBlockMemberInfo(stream, blockInfo);
25836
+        }
25837
+    }
25838
+
25839
+    // Serializes required uniform block memory sizes
25840
+    for (gl::ShaderType shaderType : gl::AllShaderTypes())
25841
+    {
25842
+        stream->writeInt(mDefaultUniformBlocks[shaderType].uniformData.size());
25843
+    }
25844
+}
25845
+
25846
+angle::Result ProgramMtl::loadDefaultUniformBlocksInfo(const gl::Context *glContext,
25847
+                                                       gl::BinaryInputStream *stream)
25848
+{
25849
+    gl::ShaderMap<size_t> requiredBufferSize;
25850
+    requiredBufferSize.fill(0);
25851
+
25852
+    // Deserializes the uniformLayout data of mDefaultUniformBlocks
25853
+    for (gl::ShaderType shaderType : gl::AllShaderTypes())
25854
+    {
25855
+        const size_t uniformCount = stream->readInt<size_t>();
25856
+        for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
25857
+        {
25858
+            sh::BlockMemberInfo blockInfo;
25859
+            gl::LoadBlockMemberInfo(stream, &blockInfo);
25860
+            mDefaultUniformBlocks[shaderType].uniformLayout.push_back(blockInfo);
25861
+        }
25862
+    }
25863
+
25864
+    // Deserializes required uniform block memory sizes
25865
+    for (gl::ShaderType shaderType : gl::AllShaderTypes())
25866
+    {
25867
+        requiredBufferSize[shaderType] = stream->readInt<size_t>();
25868
+    }
25869
+
25870
+    return resizeDefaultUniformBlocksMemory(glContext, requiredBufferSize);
25871
+}
25872
+
25873
+void ProgramMtl::saveShaderInternalInfo(gl::BinaryOutputStream *stream)
25874
+{
25875
+    for (gl::ShaderType shaderType : gl::AllShaderTypes())
25876
+    {
25877
+        stream->writeInt<int>(mMslShaderTranslateInfo[shaderType].hasUBOArgumentBuffer);
25878
+        for (const mtl::SamplerBinding &binding :
25879
+             mMslShaderTranslateInfo[shaderType].actualSamplerBindings)
25880
+        {
25881
+            stream->writeInt<uint32_t>(binding.textureBinding);
25882
+            stream->writeInt<uint32_t>(binding.samplerBinding);
25883
+        }
25884
+
25885
+        for (uint32_t uboBinding : mMslShaderTranslateInfo[shaderType].actualUBOBindings)
25886
+        {
25887
+            stream->writeInt<uint32_t>(uboBinding);
25888
+        }
25889
+    }
25890
+}
25891
+
25892
+void ProgramMtl::loadShaderInternalInfo(gl::BinaryInputStream *stream)
25893
+{
25894
+    for (gl::ShaderType shaderType : gl::AllShaderTypes())
25895
+    {
25896
+        mMslShaderTranslateInfo[shaderType].hasUBOArgumentBuffer = stream->readInt<int>() != 0;
25897
+        for (mtl::SamplerBinding &binding :
25898
+             mMslShaderTranslateInfo[shaderType].actualSamplerBindings)
25899
+        {
25900
+            binding.textureBinding = stream->readInt<uint32_t>();
25901
+            binding.samplerBinding = stream->readInt<uint32_t>();
25902
+        }
25903
+
25904
+        for (uint32_t &uboBinding : mMslShaderTranslateInfo[shaderType].actualUBOBindings)
25905
+        {
25906
+            uboBinding = stream->readInt<uint32_t>();
25907
+        }
25908
+    }
25909
+}
25910
+
25911
 GLboolean ProgramMtl::validate(const gl::Caps &caps, gl::InfoLog *infoLog)
25912
 {
25913
     // No-op. The spec is very vague about the behavior of validation.
25914
@@ -877,14 +1104,25 @@ void InitArgumentBufferEncoder(mtl::Context *context,
25915
                                     const mtl::RenderPipelineDesc &pipelineDesc,
25916
                                     bool pipelineDescChanged,
25917
                                     bool forceTexturesSetting,
25918
-                                    bool uniformBuffersDirty)
25919
+                                    bool uniformBuffersDirty,
25920
+                                    bool transformFeedbackDraw)
25921
 {
25922
     ContextMtl *context = mtl::GetImpl(glContext);
25923
     if (pipelineDescChanged)
25924
     {
25925
         // Render pipeline state needs to be changed
25926
-        id<MTLRenderPipelineState> pipelineState =
25927
-            mMetalRenderPipelineCache.getRenderPipelineState(context, pipelineDesc);
25928
+        id<MTLRenderPipelineState> pipelineState = nil;
25929
+        if (transformFeedbackDraw)
25930
+        {
25931
+            mtl::RenderPipelineDesc xfbPipelineDesc = mtl::RenderPipelineDesc(pipelineDesc);
25932
+            xfbPipelineDesc.rasterizationType    = mtl::RenderPipelineRasterization::Disabled;
25933
+            pipelineState =
25934
+                mMetalXfbRenderPipelineCache->getRenderPipelineState(context, xfbPipelineDesc);
25935
+        }
25936
+        else
25937
+        {
25938
+            pipelineState = mMetalRenderPipelineCache.getRenderPipelineState(context, pipelineDesc);
25939
+        }
25940
         if (!pipelineState)
25941
         {
25942
             // Error already logged inside getRenderPipelineState()
25943
@@ -913,11 +1151,6 @@ void InitArgumentBufferEncoder(mtl::Context *context,
25944
         ANGLE_TRY(updateUniformBuffers(context, cmdEncoder, pipelineDesc));
25945
     }
25946
 
25947
-    if (pipelineDescChanged)
25948
-    {
25949
-        ANGLE_TRY(updateXfbBuffers(context, cmdEncoder, pipelineDesc));
25950
-    }
25951
-
25952
     return angle::Result::Continue;
25953
 }
25954
 
25955
@@ -950,8 +1183,10 @@ void InitArgumentBufferEncoder(mtl::Context *context,
25956
 {
25957
     ContextMtl *contextMtl                  = mtl::GetImpl(glContext);
25958
     const auto &glState                     = glContext->getState();
25959
+    const gl::ProgramExecutable *executable = glContext->getState().getProgramExecutable();
25960
 
25961
     const gl::ActiveTexturesCache &completeTextures = glState.getActiveTexturesCache();
25962
+    const gl::ActiveTextureTypeArray &textureTypes  = executable->getActiveSamplerTypes();
25963
 
25964
     for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
25965
     {
25966
@@ -964,6 +1199,8 @@ void InitArgumentBufferEncoder(mtl::Context *context,
25967
         const mtl::TranslatedShaderInfo &shaderInfo =
25968
             *mCurrentShaderVariants[shaderType]->translatedSrcInfo;
25969
 
25970
+        bool hasDepthSampler = false;
25971
+
25972
         for (uint32_t textureIndex = 0; textureIndex < mState.getSamplerBindings().size();
25973
              ++textureIndex)
25974
         {
25975
@@ -975,7 +1212,6 @@ void InitArgumentBufferEncoder(mtl::Context *context,
25976
                 continue;
25977
             }
25978
 
25979
-            gl::TextureType textureType = samplerBinding.textureType;
25980
 
25981
             for (uint32_t arrayElement = 0; arrayElement < samplerBinding.boundTextureUnits.size();
25982
                  ++arrayElement)
25983
@@ -983,6 +1219,7 @@ void InitArgumentBufferEncoder(mtl::Context *context,
25984
                 GLuint textureUnit          = samplerBinding.boundTextureUnits[arrayElement];
25985
                 gl::Texture *texture        = completeTextures[textureUnit];
25986
                 gl::Sampler *sampler        = contextMtl->getState().getSampler(textureUnit);
25987
+                gl::TextureType textureType = textureTypes[textureUnit];
25988
                 uint32_t textureSlot        = mslBinding.textureBinding + arrayElement;
25989
                 uint32_t samplerSlot        = mslBinding.samplerBinding + arrayElement;
25990
                 if (!texture)
25991
@@ -994,24 +1231,21 @@ void InitArgumentBufferEncoder(mtl::Context *context,
25992
                 TextureMtl *textureMtl = mtl::GetImpl(texture);
25993
                 if (samplerBinding.format == gl::SamplerFormat::Shadow)
25994
                 {
25995
-                    // http://anglebug.com/5107
25996
-                    // Metal doesn't support a compare mode where sampling a shadow sampler could
25997
-                    // return a same value as if sampling from a normal sampler.
25998
-                    // Supporting this could require hacking spirv-cross to change sample_compare()
25999
-                    // to sample().
26000
-                    if (ANGLE_UNLIKELY(samplerState->getCompareMode() != GL_COMPARE_REF_TO_TEXTURE))
26001
-                    {
26002
-                        ERR() << "GL_TEXTURE_COMPARE_MODE != GL_COMPARE_REF_TO_TEXTURE is not "
26003
-                                 "supported";
26004
-                        ANGLE_MTL_TRY(contextMtl,
26005
-                                      samplerState->getCompareMode() == GL_COMPARE_REF_TO_TEXTURE);
26006
-                    }
26007
+                    hasDepthSampler                  = true;
26008
+                    mShadowCompareModes[textureSlot] = mtl::MslGetShaderShadowCompareMode(
26009
+                        samplerState->getCompareMode(), samplerState->getCompareFunc());
26010
                 }
26011
 
26012
                 ANGLE_TRY(textureMtl->bindToShader(glContext, cmdEncoder, shaderType, sampler,
26013
                                                    textureSlot, samplerSlot));
26014
             }  // for array elements
26015
         }      // for sampler bindings
26016
+
26017
+        if (hasDepthSampler)
26018
+        {
26019
+            cmdEncoder->setData(shaderType, mShadowCompareModes,
26020
+                                mtl::kShadowSamplerCompareModesBindingIndex);
26021
+        }
26022
     }  // for shader types
26023
 
26024
     return angle::Result::Continue;
26025
@@ -1040,11 +1274,6 @@ void InitArgumentBufferEncoder(mtl::Context *context,
26026
 
26027
     for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
26028
     {
26029
-        if (!mCurrentShaderVariants[shaderType])
26030
-        {
26031
-            continue;
26032
-        }
26033
-
26034
         if (mCurrentShaderVariants[shaderType]->translatedSrcInfo->hasUBOArgumentBuffer)
26035
         {
26036
             ANGLE_TRY(
26037
@@ -1149,8 +1378,6 @@ void InitArgumentBufferEncoder(mtl::Context *context,
26038
     gl::ShaderType shaderType)
26039
 {
26040
     const gl::State &glState = context->getState();
26041
-    const mtl::TranslatedShaderInfo &shaderInfo =
26042
-        *mCurrentShaderVariants[shaderType]->translatedSrcInfo;
26043
     for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex)
26044
     {
26045
         const gl::InterfaceBlock &block = blocks[bufferIndex];
26046
@@ -1162,7 +1389,8 @@ void InitArgumentBufferEncoder(mtl::Context *context,
26047
             continue;
26048
         }
26049
 
26050
-        uint32_t actualBufferIdx = shaderInfo.actualUBOBindings[bufferIndex];
26051
+        uint32_t actualBufferIdx =
26052
+            mMslShaderTranslateInfo[shaderType].actualUBOBindings[bufferIndex];
26053
 
26054
         if (actualBufferIdx >= mtl::kMaxShaderBuffers)
26055
         {
26056
@@ -1199,12 +1427,12 @@ void InitArgumentBufferEncoder(mtl::Context *context,
26057
     [bufferEncoder.metalArgBufferEncoder setArgumentBuffer:argumentBuffer->get()
26058
                                                     offset:argumentBufferOffset];
26059
 
26060
-    static_assert(MTLRenderStageVertex == (0x1 << static_cast<uint32_t>(gl::ShaderType::Vertex)),
26061
-                  "Expected gl ShaderType enum and Metal enum to relative to each other");
26062
-    static_assert(
26063
-        MTLRenderStageFragment == (0x1 << static_cast<uint32_t>(gl::ShaderType::Fragment)),
26064
-        "Expected gl ShaderType enum and Metal enum to relative to each other");
26065
-    auto mtlRenderStage = static_cast<MTLRenderStages>(0x1 << static_cast<uint32_t>(shaderType));
26066
+    constexpr gl::ShaderMap<MTLRenderStages> kShaderStageMap = {
26067
+        {gl::ShaderType::Vertex, mtl::kRenderStageVertex},
26068
+        {gl::ShaderType::Fragment, mtl::kRenderStageFragment},
26069
+    };
26070
+
26071
+    auto mtlRenderStage = kShaderStageMap[shaderType];
26072
 
26073
     for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex)
26074
     {
26075
@@ -1239,49 +1467,4 @@ void InitArgumentBufferEncoder(mtl::Context *context,
26076
     return angle::Result::Continue;
26077
 }
26078
 
26079
-angle::Result ProgramMtl::updateXfbBuffers(ContextMtl *context,
26080
-                                           mtl::RenderCommandEncoder *cmdEncoder,
26081
-                                           const mtl::RenderPipelineDesc &pipelineDesc)
26082
-{
26083
-    const gl::State &glState                 = context->getState();
26084
-    gl::TransformFeedback *transformFeedback = glState.getCurrentTransformFeedback();
26085
-
26086
-    if (pipelineDesc.rasterizationEnabled() || !glState.isTransformFeedbackActiveUnpaused() ||
26087
-        ANGLE_UNLIKELY(!transformFeedback))
26088
-    {
26089
-        // XFB output can only be used with rasterization disabled.
26090
-        return angle::Result::Continue;
26091
-    }
26092
-
26093
-    size_t xfbBufferCount = glState.getProgramExecutable()->getTransformFeedbackBufferCount();
26094
-
26095
-    ASSERT(xfbBufferCount > 0);
26096
-    ASSERT(mState.getTransformFeedbackBufferMode() != GL_INTERLEAVED_ATTRIBS ||
26097
-           xfbBufferCount == 1);
26098
-
26099
-    for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
26100
-    {
26101
-        uint32_t actualBufferIdx = mMslXfbOnlyVertexShaderInfo.actualXFBBindings[bufferIndex];
26102
-
26103
-        if (actualBufferIdx >= mtl::kMaxShaderBuffers)
26104
-        {
26105
-            continue;
26106
-        }
26107
-
26108
-        const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
26109
-            transformFeedback->getIndexedBuffer(bufferIndex);
26110
-        gl::Buffer *buffer = bufferBinding.get();
26111
-        ASSERT((bufferBinding.getOffset() % 4) == 0);
26112
-        ASSERT(buffer != nullptr);
26113
-
26114
-        BufferMtl *bufferMtl = mtl::GetImpl(buffer);
26115
-
26116
-        // Use offset=0, actual offset will be set in Driver Uniform inside ContextMtl.
26117
-        cmdEncoder->setBufferForWrite(gl::ShaderType::Vertex, bufferMtl->getCurrentBuffer(), 0,
26118
-                                      actualBufferIdx);
26119
-    }
26120
-
26121
-    return angle::Result::Continue;
26122
-}
26123
-
26124
 }  // namespace rx
26125
diff --git a/src/libANGLE/renderer/metal/QueryMtl.h b/src/libANGLE/renderer/metal/QueryMtl.h
26126
index 21854f6..278f1df 100644
26127
--- a/src/libANGLE/renderer/metal/QueryMtl.h
26128
+++ b/src/libANGLE/renderer/metal/QueryMtl.h
26129
@@ -1,5 +1,5 @@
26130
 //
26131
-// Copyright 2020 The ANGLE Project Authors. All rights reserved.
26132
+// Copyright (c) 2020 The ANGLE Project Authors. All rights reserved.
26133
 // Use of this source code is governed by a BSD-style license that can be
26134
 // found in the LICENSE file.
26135
 //
26136
@@ -98,8 +98,7 @@ class QueryMtl : public QueryImpl
26137
     const mtl::BufferRef &getVisibilityResultBuffer() const { return mVisibilityResultBuffer; }
26138
     // Reset the occlusion query result stored in buffer to zero
26139
     void resetVisibilityResult(ContextMtl *contextMtl);
26140
-
26141
-    void onTransformFeedbackEnd(const gl::Context *context);
26142
+    void onTransformFeedbackEnd(GLsizeiptr primitivesDrawn);
26143
 
26144
   private:
26145
     template <typename T>
26146
@@ -108,8 +107,13 @@ class QueryMtl : public QueryImpl
26147
     // List of offsets in the render pass's occlusion query pool buffer allocated for this query
26148
     VisibilityBufferOffsetsMtl mVisibilityBufferOffsets;
26149
     mtl::BufferRef mVisibilityResultBuffer;
26150
+    // Used with TransformFeedbackPrimitivesWritten when transform feedback is emulated.
26151
+    size_t mTransformFeedbackPrimitivesDrawn;
26152
 
26153
-    size_t mTransformFeedbackPrimitivesDrawn = 0;
26154
+    // TODO(jcunningham): currently only used for mTransformFeedbackPrimitivesDrawn
26155
+    // but can be used for rest of results
26156
+    uint64_t mCachedResult;
26157
+    bool mCachedResultValid;
26158
 };
26159
 
26160
 }  // namespace rx
26161
diff --git a/src/libANGLE/renderer/metal/QueryMtl.mm b/src/libANGLE/renderer/metal/QueryMtl.mm
26162
index f5e9bf3..ab0e7bf 100644
26163
--- a/src/libANGLE/renderer/metal/QueryMtl.mm
26164
+++ b/src/libANGLE/renderer/metal/QueryMtl.mm
26165
@@ -1,5 +1,5 @@
26166
 //
26167
-// Copyright 2020 The ANGLE Project Authors. All rights reserved.
26168
+// Copyright (c) 2020 The ANGLE Project Authors. All rights reserved.
26169
 // Use of this source code is governed by a BSD-style license that can be
26170
 // found in the LICENSE file.
26171
 //
26172
@@ -13,7 +13,12 @@
26173
 
26174
 namespace rx
26175
 {
26176
-QueryMtl::QueryMtl(gl::QueryType type) : QueryImpl(type) {}
26177
+QueryMtl::QueryMtl(gl::QueryType type)
26178
+    : QueryImpl(type),
26179
+      mTransformFeedbackPrimitivesDrawn(0),
26180
+      mCachedResult(0),
26181
+      mCachedResultValid(false)
26182
+{}
26183
 
26184
 QueryMtl::~QueryMtl() {}
26185
 
26186
@@ -22,13 +27,14 @@
26187
     ContextMtl *contextMtl = mtl::GetImpl(context);
26188
     if (!getAllocatedVisibilityOffsets().empty())
26189
     {
26190
-        contextMtl->onOcclusionQueryDestroy(context, this);
26191
+        contextMtl->onOcclusionQueryDestroyed(context, this);
26192
     }
26193
     mVisibilityResultBuffer = nullptr;
26194
 }
26195
 
26196
 angle::Result QueryMtl::begin(const gl::Context *context)
26197
 {
26198
+    mCachedResultValid     = false;
26199
     ContextMtl *contextMtl = mtl::GetImpl(context);
26200
     switch (getType())
26201
     {
26202
@@ -47,7 +53,7 @@
26203
                 }
26204
             }
26205
 
26206
-            ANGLE_TRY(contextMtl->onOcclusionQueryBegin(context, this));
26207
+            ANGLE_TRY(contextMtl->onOcclusionQueryBegan(context, this));
26208
             break;
26209
         case gl::QueryType::TransformFeedbackPrimitivesWritten:
26210
             mTransformFeedbackPrimitivesDrawn = 0;
26211
@@ -66,12 +72,22 @@
26212
     {
26213
         case gl::QueryType::AnySamples:
26214
         case gl::QueryType::AnySamplesConservative:
26215
-            contextMtl->onOcclusionQueryEnd(context, this);
26216
+            contextMtl->onOcclusionQueryEnded(context, this);
26217
             break;
26218
         case gl::QueryType::TransformFeedbackPrimitivesWritten:
26219
+        {
26220
+            mCachedResult = mTransformFeedbackPrimitivesDrawn;
26221
+
26222
             // There could be transform feedback in progress, so add the primitives drawn so far
26223
             // from the current transform feedback object.
26224
-            onTransformFeedbackEnd(context);
26225
+            gl::TransformFeedback *transformFeedback =
26226
+                context->getState().getCurrentTransformFeedback();
26227
+            if (transformFeedback)
26228
+            {
26229
+                mCachedResult += transformFeedback->getPrimitivesDrawn();
26230
+            }
26231
+            mCachedResultValid = true;
26232
+        }
26233
         break;
26234
         default:
26235
             UNIMPLEMENTED();
26236
@@ -110,7 +126,7 @@
26237
         }
26238
         break;
26239
         case gl::QueryType::TransformFeedbackPrimitivesWritten:
26240
-            *params = static_cast<T>(mTransformFeedbackPrimitivesDrawn);
26241
+            *params = static_cast<T>(mCachedResult);
26242
             break;
26243
         default:
26244
             UNIMPLEMENTED();
26245
@@ -137,7 +153,7 @@
26246
             *available = !mVisibilityResultBuffer->isBeingUsedByGPU(contextMtl);
26247
             break;
26248
         case gl::QueryType::TransformFeedbackPrimitivesWritten:
26249
-            *available = true;
26250
+            *available = mCachedResultValid;
26251
             break;
26252
         default:
26253
             UNIMPLEMENTED();
26254
@@ -175,13 +191,9 @@
26255
     mVisibilityResultBuffer->syncContent(contextMtl, blitEncoder);
26256
 }
26257
 
26258
-void QueryMtl::onTransformFeedbackEnd(const gl::Context *context)
26259
+void QueryMtl::onTransformFeedbackEnd(GLsizeiptr primitivesDrawn)
26260
 {
26261
-    gl::TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback();
26262
-    if (transformFeedback)
26263
-    {
26264
-        mTransformFeedbackPrimitivesDrawn += transformFeedback->getPrimitivesDrawn();
26265
-    }
26266
+    mTransformFeedbackPrimitivesDrawn += primitivesDrawn;
26267
 }
26268
 
26269
 }
26270
diff --git a/src/libANGLE/renderer/metal/RenderBufferMtl.h b/src/libANGLE/renderer/metal/RenderBufferMtl.h
26271
index 6fd7b1b..053020c 100644
26272
--- a/src/libANGLE/renderer/metal/RenderBufferMtl.h
26273
+++ b/src/libANGLE/renderer/metal/RenderBufferMtl.h
26274
@@ -57,6 +57,7 @@ class RenderbufferMtl : public RenderbufferImpl
26275
 
26276
     mtl::Format mFormat;
26277
     mtl::TextureRef mTexture;
26278
+    mtl::TextureRef mImplicitMSTexture;
26279
     RenderTargetMtl mRenderTarget;
26280
 };
26281
 
26282
diff --git a/src/libANGLE/renderer/metal/RenderBufferMtl.mm b/src/libANGLE/renderer/metal/RenderBufferMtl.mm
26283
index 63d6f4b..2f9b5f6 100644
26284
--- a/src/libANGLE/renderer/metal/RenderBufferMtl.mm
26285
+++ b/src/libANGLE/renderer/metal/RenderBufferMtl.mm
26286
@@ -28,6 +28,7 @@
26287
 void RenderbufferMtl::releaseTexture()
26288
 {
26289
     mTexture           = nullptr;
26290
+    mImplicitMSTexture = nullptr;
26291
 }
26292
 
26293
 angle::Result RenderbufferMtl::setStorageImpl(const gl::Context *context,
26294
@@ -42,8 +43,9 @@
26295
     {
26296
         // Check against the state if we need to recreate the storage.
26297
         if (internalformat != mState.getFormat().info->internalFormat ||
26298
-            width != mState.getWidth() || height != mState.getHeight() ||
26299
-            samples != mState.getSamples())
26300
+            static_cast<GLsizei>(width) != mState.getWidth() ||
26301
+            static_cast<GLsizei>(height) != mState.getHeight() ||
26302
+            static_cast<GLsizei>(samples) != mState.getSamples())
26303
         {
26304
             releaseTexture();
26305
         }
26306
@@ -72,30 +74,62 @@
26307
 
26308
     if ((mTexture == nullptr || !mTexture->valid()) && (width != 0 && height != 0))
26309
     {
26310
-        if (actualSamples == 1)
26311
+        if (actualSamples == 1 || (mFormat.hasDepthAndStencilBits() && mFormat.getCaps().resolve))
26312
         {
26313
-            ANGLE_TRY(mtl::Texture::Make2DTexture(contextMtl, mFormat, width, height, 1, false,
26314
-                                                  mFormat.hasDepthAndStencilBits(), &mTexture));
26315
+            ANGLE_TRY(mtl::Texture::Make2DTexture(contextMtl, mFormat, static_cast<uint32_t>(width),
26316
+                                                  static_cast<uint32_t>(height), 1,
26317
+                                                  /* renderTargetOnly */ false,
26318
+                                                  /* allowFormatView */ false, &mTexture));
26319
+
26320
+            // Use implicit resolve for depth stencil texture whenever possible. This is because
26321
+            // for depth stencil texture, if stencil needs to be blitted, a formatted clone has
26322
+            // to be created. And it is expensive to clone a multisample texture.
26323
+            if (actualSamples > 1)
26324
+            {
26325
+                // This format must supports implicit resolve
26326
+                ASSERT(mFormat.getCaps().resolve);
26327
+
26328
+                ANGLE_TRY(mtl::Texture::Make2DMSTexture(
26329
+                    contextMtl, mFormat, static_cast<uint32_t>(width),
26330
+                    static_cast<uint32_t>(height), actualSamples,
26331
+                    /* renderTargetOnly */ true,
26332
+                    /* allowFormatView */ false, &mImplicitMSTexture));
26333
+            }
26334
         }
26335
         else
26336
         {
26337
-            ANGLE_TRY(mtl::Texture::Make2DMSTexture(
26338
-                contextMtl, mFormat, width, height, actualSamples,
26339
+            ANGLE_TRY(mtl::Texture::Make2DMSTexture(contextMtl, mFormat,
26340
+                                                    static_cast<uint32_t>(width),
26341
+                                                    static_cast<uint32_t>(height), actualSamples,
26342
                                                     /* renderTargetOnly */ false,
26343
-                /* allowFormatView */ mFormat.hasDepthAndStencilBits(), &mTexture));
26344
+                                                    /* allowFormatView */ false, &mTexture));
26345
         }
26346
 
26347
-        mRenderTarget.set(mTexture, mtl::kZeroNativeMipLevel, 0, mFormat);
26348
+        mRenderTarget.setWithImplicitMSTexture(mTexture, mImplicitMSTexture, mtl::kZeroNativeMipLevel, 0, mFormat);
26349
 
26350
         // For emulated channels that GL texture intends to not have,
26351
         // we need to initialize their content.
26352
         bool emulatedChannels = mtl::IsFormatEmulated(mFormat);
26353
         if (emulatedChannels)
26354
         {
26355
-            auto index = mtl::ImageNativeIndex::FromBaseZeroGLIndex(gl::ImageIndex::Make2D(0));
26356
+            gl::ImageIndex index;
26357
 
26358
-            ANGLE_TRY(mtl::InitializeTextureContents(context, mTexture, mFormat, index));
26359
+            if (actualSamples > 1)
26360
+            {
26361
+                index = gl::ImageIndex::Make2DMultisample();
26362
+            }
26363
+            else
26364
+            {
26365
+                index = gl::ImageIndex::Make2D(0);
26366
+            }
26367
+
26368
+            ANGLE_TRY(mtl::InitializeTextureContents(context, mTexture, mFormat, mtl::ImageNativeIndex(index, 0)));
26369
+            if (mImplicitMSTexture)
26370
+            {
26371
+                ANGLE_TRY(mtl::InitializeTextureContents(context, mImplicitMSTexture, mFormat,
26372
+                                                         mtl::ImageNativeIndex(gl::ImageIndex::Make2DMultisample(), 0)));
26373
             }
26374
+        }  // if (emulatedChannels)
26375
     }
26376
 
26377
     return angle::Result::Continue;
26378
@@ -133,7 +167,6 @@
26379
                                                          GLsizei samples,
26380
                                                          FramebufferAttachmentRenderTarget **rtOut)
26381
 {
26382
-    // NOTE(hqle): Support MSAA.
26383
     ASSERT(mTexture && mTexture->valid());
26384
     *rtOut = &mRenderTarget;
26385
     return angle::Result::Continue;
26386
diff --git a/src/libANGLE/renderer/metal/RenderTargetMtl.h b/src/libANGLE/renderer/metal/RenderTargetMtl.h
26387
index baf4e4d..0c57517 100644
26388
--- a/src/libANGLE/renderer/metal/RenderTargetMtl.h
26389
+++ b/src/libANGLE/renderer/metal/RenderTargetMtl.h
26390
@@ -46,20 +46,18 @@ class RenderTargetMtl final : public FramebufferAttachmentRenderTarget
26391
     void duplicateFrom(const RenderTargetMtl &src);
26392
     void reset();
26393
 
26394
-    mtl::TextureRef getTexture() const { return mTexture.lock(); }
26395
-    mtl::TextureRef getImplicitMSTexture() const { return mImplicitMSTexture.lock(); }
26396
-    const mtl::MipmapNativeLevel &getLevelIndex() const { return mLevelIndex; }
26397
-    uint32_t getLayerIndex() const { return mLayerIndex; }
26398
+    mtl::TextureRef getTexture() const { return mTextureRenderTargetInfo->getTextureRef(); }
26399
+    mtl::TextureRef getImplicitMSTexture() const { return mTextureRenderTargetInfo->getImplicitMSTextureRef(); }
26400
+    const mtl::MipmapNativeLevel &getLevelIndex() const { return mTextureRenderTargetInfo->level; }
26401
+    uint32_t getLayerIndex() const { return mTextureRenderTargetInfo->sliceOrDepth; }
26402
     uint32_t getRenderSamples() const;
26403
     const mtl::Format *getFormat() const { return mFormat; }
26404
 
26405
     void toRenderPassAttachmentDesc(mtl::RenderPassAttachmentDesc *rpaDescOut) const;
26406
 
26407
   private:
26408
-    mtl::TextureWeakRef mTexture;
26409
-    mtl::TextureWeakRef mImplicitMSTexture;
26410
-    mtl::MipmapNativeLevel mLevelIndex = mtl::kZeroNativeMipLevel;
26411
-    uint32_t mLayerIndex               = 0;
26412
+// This is shared pointer to avoid crashing when texture deleted after bound to a frame buffer.
26413
+    std::shared_ptr<mtl::RenderPassAttachmentTextureTargetDesc> mTextureRenderTargetInfo;
26414
     const mtl::Format *mFormat = nullptr;
26415
 };
26416
 }  // namespace rx
26417
diff --git a/src/libANGLE/renderer/metal/RenderTargetMtl.mm b/src/libANGLE/renderer/metal/RenderTargetMtl.mm
26418
index e89e761..e126dbb 100644
26419
--- a/src/libANGLE/renderer/metal/RenderTargetMtl.mm
26420
+++ b/src/libANGLE/renderer/metal/RenderTargetMtl.mm
26421
@@ -11,7 +11,10 @@
26422
 
26423
 namespace rx
26424
 {
26425
-RenderTargetMtl::RenderTargetMtl() {}
26426
+RenderTargetMtl::RenderTargetMtl() :
26427
+  mTextureRenderTargetInfo(std::make_shared<mtl::RenderPassAttachmentTextureTargetDesc>()),
26428
+  mFormat(nullptr)
26429
+{}
26430
 
26431
 RenderTargetMtl::~RenderTargetMtl()
26432
 {
26433
@@ -19,10 +22,7 @@
26434
 }
26435
 
26436
 RenderTargetMtl::RenderTargetMtl(RenderTargetMtl &&other)
26437
-    : mTexture(std::move(other.mTexture)),
26438
-      mImplicitMSTexture(std::move(other.mImplicitMSTexture)),
26439
-      mLevelIndex(other.mLevelIndex),
26440
-      mLayerIndex(other.mLayerIndex)
26441
+    : mTextureRenderTargetInfo(std::move(other.mTextureRenderTargetInfo))
26442
 {}
26443
 
26444
 void RenderTargetMtl::set(const mtl::TextureRef &texture,
26445
@@ -39,21 +39,21 @@
26446
                                                uint32_t layer,
26447
                                                const mtl::Format &format)
26448
 {
26449
-    mTexture           = texture;
26450
-    mImplicitMSTexture = implicitMSTexture;
26451
-    mLevelIndex        = level;
26452
-    mLayerIndex        = layer;
26453
+    mTextureRenderTargetInfo->texture           = texture;
26454
+    mTextureRenderTargetInfo->implicitMSTexture = implicitMSTexture;
26455
+    mTextureRenderTargetInfo->level        = level;
26456
+    mTextureRenderTargetInfo->sliceOrDepth        = layer;
26457
     mFormat            = &format;
26458
 }
26459
 
26460
 void RenderTargetMtl::setTexture(const mtl::TextureRef &texture)
26461
 {
26462
-    mTexture = texture;
26463
+    mTextureRenderTargetInfo->texture = texture;
26464
 }
26465
 
26466
 void RenderTargetMtl::setImplicitMSTexture(const mtl::TextureRef &implicitMSTexture)
26467
 {
26468
-    mImplicitMSTexture = implicitMSTexture;
26469
+    mTextureRenderTargetInfo->implicitMSTexture = implicitMSTexture;
26470
 }
26471
 
26472
 void RenderTargetMtl::duplicateFrom(const RenderTargetMtl &src)
26473
@@ -64,25 +64,19 @@
26474
 
26475
 void RenderTargetMtl::reset()
26476
 {
26477
-    mTexture.reset();
26478
-    mImplicitMSTexture.reset();
26479
-    mLevelIndex = mtl::kZeroNativeMipLevel;
26480
-    mLayerIndex = 0;
26481
+    mTextureRenderTargetInfo->texture.reset();
26482
+    mTextureRenderTargetInfo->implicitMSTexture.reset();
26483
+    mTextureRenderTargetInfo->level        = mtl::kZeroNativeMipLevel;
26484
+    mTextureRenderTargetInfo->sliceOrDepth = 0;
26485
     mFormat                                = nullptr;
26486
 }
26487
 
26488
 uint32_t RenderTargetMtl::getRenderSamples() const
26489
 {
26490
-    mtl::TextureRef implicitMSTex = getImplicitMSTexture();
26491
-    mtl::TextureRef tex           = getTexture();
26492
-    return implicitMSTex ? implicitMSTex->samples() : (tex ? tex->samples() : 1);
26493
+    return mTextureRenderTargetInfo->getRenderSamples();
26494
 }
26495
 void RenderTargetMtl::toRenderPassAttachmentDesc(mtl::RenderPassAttachmentDesc *rpaDescOut) const
26496
 {
26497
-    rpaDescOut->texture           = mTexture.lock();
26498
-    rpaDescOut->implicitMSTexture = mImplicitMSTexture.lock();
26499
-    rpaDescOut->level             = mLevelIndex;
26500
-    rpaDescOut->sliceOrDepth      = mLayerIndex;
26501
-    rpaDescOut->blendable         = mFormat ? mFormat->getCaps().blendable : false;
26502
+    rpaDescOut->renderTarget = mTextureRenderTargetInfo;
26503
 }
26504
 }
26505
diff --git a/src/libANGLE/renderer/metal/ShaderMtl.h b/src/libANGLE/renderer/metal/ShaderMtl.h
26506
index 7b2cfd5..52e91af 100644
26507
--- a/src/libANGLE/renderer/metal/ShaderMtl.h
26508
+++ b/src/libANGLE/renderer/metal/ShaderMtl.h
26509
@@ -11,8 +11,8 @@
26510
 
26511
 #include <map>
26512
 
26513
+#include "compiler/translator/TranslatorMetalDirect.h"
26514
 #include "libANGLE/renderer/ShaderImpl.h"
26515
-
26516
 namespace rx
26517
 {
26518
 
26519
@@ -26,7 +26,19 @@ class ShaderMtl : public ShaderImpl
26520
                                                   gl::ShCompilerInstance *compilerInstance,
26521
                                                   ShCompileOptions options) override;
26522
 
26523
+    sh::TranslatorMetalReflection *getTranslatorMetalReflection()
26524
+    {
26525
+        return &translatorMetalReflection;
26526
+    }
26527
     std::string getDebugInfo() const override;
26528
+
26529
+    sh::TranslatorMetalReflection translatorMetalReflection = {};
26530
+
26531
+  private:
26532
+    std::shared_ptr<WaitableCompileEvent> compileImplMtl(const gl::Context *context,
26533
+                                                         gl::ShCompilerInstance *compilerInstance,
26534
+                                                         const std::string &source,
26535
+                                                         ShCompileOptions compileOptions);
26536
 };
26537
 
26538
 }  // namespace rx
26539
diff --git a/src/libANGLE/renderer/metal/ShaderMtl.mm b/src/libANGLE/renderer/metal/ShaderMtl.mm
26540
index f909fb5..ad01dbf 100644
26541
--- a/src/libANGLE/renderer/metal/ShaderMtl.mm
26542
+++ b/src/libANGLE/renderer/metal/ShaderMtl.mm
26543
@@ -10,8 +10,13 @@
26544
 #include "libANGLE/renderer/metal/ShaderMtl.h"
26545
 
26546
 #include "common/debug.h"
26547
+#include "compiler/translator/TranslatorMetal.h"
26548
+#include "compiler/translator/TranslatorMetalDirect.h"
26549
 #include "libANGLE/Context.h"
26550
+#include "libANGLE/Shader.h"
26551
+#include "libANGLE/WorkerThread.h"
26552
 #include "libANGLE/renderer/metal/ContextMtl.h"
26553
+#include "libANGLE/renderer/metal/DisplayMtl.h"
26554
 
26555
 namespace rx
26556
 {
26557
@@ -20,10 +25,100 @@
26558
 
26559
 ShaderMtl::~ShaderMtl() {}
26560
 
26561
+class TranslateTask : public angle::Closure
26562
+{
26563
+  public:
26564
+    TranslateTask(ShHandle handle, ShCompileOptions options, const std::string &source)
26565
+        : mHandle(handle), mOptions(options), mSource(source), mResult(false)
26566
+    {}
26567
+
26568
+    void operator()() override
26569
+    {
26570
+        const char *source = mSource.c_str();
26571
+        mResult            = sh::Compile(mHandle, &source, 1, mOptions);
26572
+    }
26573
+
26574
+    bool getResult() { return mResult; }
26575
+
26576
+    ShHandle getHandle() { return mHandle; }
26577
+
26578
+  private:
26579
+    ShHandle mHandle;
26580
+    ShCompileOptions mOptions;
26581
+    std::string mSource;
26582
+    bool mResult;
26583
+};
26584
+
26585
+class MTLWaitableCompileEventImpl final : public WaitableCompileEvent
26586
+{
26587
+  public:
26588
+    MTLWaitableCompileEventImpl(ShaderMtl *shader,
26589
+                                std::shared_ptr<angle::WaitableEvent> waitableEvent,
26590
+                                std::shared_ptr<TranslateTask> translateTask)
26591
+        : WaitableCompileEvent(waitableEvent), mTranslateTask(translateTask), mShader(shader)
26592
+    {}
26593
+
26594
+    bool getResult() override { return mTranslateTask->getResult(); }
26595
+
26596
+    bool postTranslate(std::string *infoLog) override
26597
+    {
26598
+        sh::TShHandleBase *base    = static_cast<sh::TShHandleBase *>(mTranslateTask->getHandle());
26599
+        auto translatorMetalDirect = base->getAsTranslatorMetalDirect();
26600
+        if (translatorMetalDirect != nullptr)
26601
+        {
26602
+            // Copy reflection from translation.
26603
+            mShader->translatorMetalReflection =
26604
+                *(translatorMetalDirect->getTranslatorMetalReflection());
26605
+            translatorMetalDirect->getTranslatorMetalReflection()->reset();
26606
+        }
26607
+        return true;
26608
+    }
26609
+
26610
+  private:
26611
+    std::shared_ptr<TranslateTask> mTranslateTask;
26612
+    ShaderMtl *mShader;
26613
+};
26614
+
26615
+std::shared_ptr<WaitableCompileEvent> ShaderMtl::compileImplMtl(
26616
+    const gl::Context *context,
26617
+    gl::ShCompilerInstance *compilerInstance,
26618
+    const std::string &source,
26619
+    ShCompileOptions compileOptions)
26620
+{
26621
+#if defined(ANGLE_ENABLE_ASSERTS)
26622
+    compileOptions |= SH_VALIDATE_AST;
26623
+#endif
26624
+
26625
+    auto workerThreadPool = context->getWorkerThreadPool();
26626
+    auto translateTask =
26627
+        std::make_shared<TranslateTask>(compilerInstance->getHandle(), compileOptions, source);
26628
+
26629
+    return std::make_shared<MTLWaitableCompileEventImpl>(
26630
+        this, angle::WorkerThreadPool::PostWorkerTask(workerThreadPool, translateTask),
26631
+        translateTask);
26632
+}
26633
+
26634
 std::shared_ptr<WaitableCompileEvent> ShaderMtl::compile(const gl::Context *context,
26635
                                                          gl::ShCompilerInstance *compilerInstance,
26636
                                                          ShCompileOptions options)
26637
 {
26638
+    ContextMtl *contextMtl = mtl::GetImpl(context);
26639
+    if (getState().getShaderType() == gl::ShaderType::Vertex &&
26640
+        !contextMtl->getDisplay()->getFeatures().hasBaseVertexInstancedDraw.enabled)
26641
+    {
26642
+        // Emulate gl_InstanceID
26643
+        sh::TShHandleBase *base = static_cast<sh::TShHandleBase *>(compilerInstance->getHandle());
26644
+        auto translatorMetalDirect = base->getAsTranslatorMetalDirect();
26645
+        if (translatorMetalDirect == nullptr)
26646
+        {
26647
+            auto translatorMetal = static_cast<sh::TranslatorMetal *>(base->getAsCompiler());
26648
+            translatorMetal->enableEmulatedInstanceID(true);
26649
+        }
26650
+        else
26651
+        {
26652
+            translatorMetalDirect->enableEmulatedInstanceID(true);
26653
+        }
26654
+    }
26655
     ShCompileOptions compileOptions = SH_INITIALIZE_UNINITIALIZED_LOCALS;
26656
 
26657
     bool isWebGL = context->getExtensions().webglCompatibility;
26658
@@ -33,8 +128,11 @@
26659
     }
26660
 
26661
     compileOptions |= SH_CLAMP_POINT_SIZE;
26662
+#if defined(ANGLE_PLATFORM_IOS) && !defined(ANGLE_PLATFORM_MACCATALYST)
26663
+    compileOptions |= SH_CLAMP_FRAG_DEPTH;
26664
+#endif
26665
 
26666
-    return compileImpl(context, compilerInstance, mState.getSource(), compileOptions | options);
26667
+    return compileImplMtl(context, compilerInstance, getState().getSource(), compileOptions | options);
26668
 }
26669
 
26670
 std::string ShaderMtl::getDebugInfo() const
26671
diff --git a/src/libANGLE/renderer/metal/SurfaceMtl.h b/src/libANGLE/renderer/metal/SurfaceMtl.h
26672
index 9e84f88..0adc360 100644
26673
--- a/src/libANGLE/renderer/metal/SurfaceMtl.h
26674
+++ b/src/libANGLE/renderer/metal/SurfaceMtl.h
26675
@@ -24,7 +24,27 @@ namespace rx
26676
 
26677
 class DisplayMtl;
26678
 
26679
-class SurfaceMtl : public SurfaceImpl
26680
+class SurfaceMtlProtocol : public SurfaceImpl
26681
+{
26682
+  public:
26683
+    SurfaceMtlProtocol(const egl::SurfaceState &state) : SurfaceImpl(state) {}
26684
+    virtual int getSamples() const      = 0;
26685
+    virtual bool preserveBuffer() const = 0;
26686
+
26687
+    virtual angle::Result getAttachmentRenderTarget(const gl::Context *context,
26688
+                                                    GLenum binding,
26689
+                                                    const gl::ImageIndex &imageIndex,
26690
+                                                    GLsizei samples,
26691
+                                                    FramebufferAttachmentRenderTarget **rtOut) override = 0;
26692
+
26693
+    virtual bool hasRobustResourceInit() const = 0;
26694
+    virtual angle::Result ensureCurrentDrawableObtained(const gl::Context *context) = 0;
26695
+    virtual angle::Result ensureCurrentDrawableObtained(const gl::Context *context, bool *newDrawableOut) = 0;
26696
+    virtual angle::Result ensureColorTextureReadyForReadPixels(const gl::Context *context) = 0;
26697
+    virtual const mtl::TextureRef & getColorTexture() = 0;
26698
+};
26699
+
26700
+class SurfaceMtl : public SurfaceMtlProtocol
26701
 {
26702
   public:
26703
     SurfaceMtl(DisplayMtl *display,
26704
@@ -67,11 +87,11 @@ class SurfaceMtl : public SurfaceImpl
26705
     angle::Result initializeContents(const gl::Context *context,
26706
                                      const gl::ImageIndex &imageIndex) override;
26707
 
26708
-    const mtl::TextureRef &getColorTexture() { return mColorTexture; }
26709
+    const mtl::TextureRef &getColorTexture() override { return mColorTexture; }
26710
     const mtl::Format &getColorFormat() const { return mColorFormat; }
26711
-    int getSamples() const { return mSamples; }
26712
+    int getSamples() const override { return mSamples; }
26713
 
26714
-    bool hasRobustResourceInit() const { return mRobustResourceInit; }
26715
+    bool hasRobustResourceInit() const override { return mRobustResourceInit; }
26716
 
26717
     angle::Result getAttachmentRenderTarget(const gl::Context *context,
26718
                                             GLenum binding,
26719
@@ -144,13 +164,14 @@ class WindowSurfaceMtl : public SurfaceMtl
26720
                                             GLsizei samples,
26721
                                             FramebufferAttachmentRenderTarget **rtOut) override;
26722
 
26723
+    angle::Result ensureCurrentDrawableObtained(const gl::Context *context) override;
26724
     angle::Result ensureCurrentDrawableObtained(const gl::Context *context,
26725
-                                                bool *newDrawableOut /** nullable */);
26726
+                                                bool *newDrawableOut /** nullable */) override;
26727
 
26728
     // Ensure the the texture returned from getColorTexture() is ready for glReadPixels(). This
26729
     // implicitly calls ensureCurrentDrawableObtained().
26730
-    angle::Result ensureColorTextureReadyForReadPixels(const gl::Context *context);
26731
-
26732
+    angle::Result ensureColorTextureReadyForReadPixels(const gl::Context *context) override;
26733
+    bool preserveBuffer() const override { return mRetainBuffer; }
26734
   private:
26735
     angle::Result swapImpl(const gl::Context *context);
26736
     angle::Result obtainNextDrawable(const gl::Context *context);
26737
@@ -168,6 +189,8 @@ class WindowSurfaceMtl : public SurfaceMtl
26738
     // event. We don't use mMetalLayer.drawableSize directly since it might be changed internally by
26739
     // metal runtime.
26740
     CGSize mCurrentKnownDrawableSize;
26741
+
26742
+    bool mRetainBuffer = false;
26743
 };
26744
 
26745
 // Offscreen surface, base class of PBuffer, IOSurface.
26746
@@ -212,37 +235,5 @@ class PBufferSurfaceMtl : public OffscreenSurfaceMtl
26747
     void setFixedHeight(EGLint height) override;
26748
 };
26749
 
26750
-// Offscreen created from IOSurface
26751
-class IOSurfaceSurfaceMtl : public OffscreenSurfaceMtl
26752
-{
26753
-  public:
26754
-    IOSurfaceSurfaceMtl(DisplayMtl *display,
26755
-                        const egl::SurfaceState &state,
26756
-                        EGLClientBuffer buffer,
26757
-                        const egl::AttributeMap &attribs);
26758
-    ~IOSurfaceSurfaceMtl() override;
26759
-
26760
-    egl::Error bindTexImage(const gl::Context *context,
26761
-                            gl::Texture *texture,
26762
-                            EGLint buffer) override;
26763
-    egl::Error releaseTexImage(const gl::Context *context, EGLint buffer) override;
26764
-
26765
-    angle::Result getAttachmentRenderTarget(const gl::Context *context,
26766
-                                            GLenum binding,
26767
-                                            const gl::ImageIndex &imageIndex,
26768
-                                            GLsizei samples,
26769
-                                            FramebufferAttachmentRenderTarget **rtOut) override;
26770
-
26771
-    static bool ValidateAttributes(EGLClientBuffer buffer, const egl::AttributeMap &attribs);
26772
-
26773
-  private:
26774
-    angle::Result ensureColorTextureCreated(const gl::Context *context);
26775
-
26776
-    IOSurfaceRef mIOSurface;
26777
-    NSUInteger mIOSurfacePlane;
26778
-    int mIOSurfaceFormatIdx;
26779
-};
26780
-
26781
 }  // namespace rx
26782
-
26783
 #endif /* LIBANGLE_RENDERER_METAL_SURFACEMTL_H_ */
26784
diff --git a/src/libANGLE/renderer/metal/SurfaceMtl.mm b/src/libANGLE/renderer/metal/SurfaceMtl.mm
26785
index 303fb16..c9ee24b 100644
26786
--- a/src/libANGLE/renderer/metal/SurfaceMtl.mm
26787
+++ b/src/libANGLE/renderer/metal/SurfaceMtl.mm
26788
@@ -33,55 +33,19 @@
26789
 {
26790
 
26791
 #define ANGLE_TO_EGL_TRY(EXPR)                                 \
26792
-    do                                                         \
26793
-    {                                                          \
26794
+do                                                         \
26795
+{                                                          \
26796
     if (ANGLE_UNLIKELY((EXPR) != angle::Result::Continue)) \
26797
     {                                                      \
26798
         return egl::EglBadSurface();                       \
26799
     }                                                      \
26800
-    } while (0)
26801
+} while (0)
26802
 
26803
 constexpr angle::FormatID kDefaultFrameBufferDepthFormatId   = angle::FormatID::D32_FLOAT;
26804
 constexpr angle::FormatID kDefaultFrameBufferStencilFormatId = angle::FormatID::S8_UINT;
26805
 constexpr angle::FormatID kDefaultFrameBufferDepthStencilFormatId =
26806
     angle::FormatID::D24_UNORM_S8_UINT;
26807
 
26808
-struct IOSurfaceFormatInfo
26809
-{
26810
-    GLenum internalFormat;
26811
-    GLenum type;
26812
-    size_t componentBytes;
26813
-
26814
-    angle::FormatID nativeAngleFormatId;
26815
-};
26816
-
26817
-// clang-format off
26818
-// NOTE(hqle): Support R16_UINT once GLES3 is complete.
26819
-constexpr std::array<IOSurfaceFormatInfo, 8> kIOSurfaceFormats = {{
26820
-    {GL_RED,      GL_UNSIGNED_BYTE,               1, angle::FormatID::R8_UNORM},
26821
-    {GL_RED,      GL_UNSIGNED_SHORT,              2, angle::FormatID::R16_UNORM},
26822
-    {GL_RG,       GL_UNSIGNED_BYTE,               2, angle::FormatID::R8G8_UNORM},
26823
-    {GL_RG,       GL_UNSIGNED_SHORT,              4, angle::FormatID::R16G16_UNORM},
26824
-    {GL_RGB,      GL_UNSIGNED_BYTE,               4, angle::FormatID::B8G8R8A8_UNORM},
26825
-    {GL_BGRA_EXT, GL_UNSIGNED_BYTE,               4, angle::FormatID::B8G8R8A8_UNORM},
26826
-    {GL_RGBA,     GL_HALF_FLOAT,                  8, angle::FormatID::R16G16B16A16_FLOAT},
26827
-    {GL_RGB10_A2, GL_UNSIGNED_INT_2_10_10_10_REV, 4, angle::FormatID::B10G10R10A2_UNORM},
26828
-}};
26829
-// clang-format on
26830
-
26831
-int FindIOSurfaceFormatIndex(GLenum internalFormat, GLenum type)
26832
-{
26833
-    for (int i = 0; i < static_cast<int>(kIOSurfaceFormats.size()); ++i)
26834
-    {
26835
-        const auto &formatInfo = kIOSurfaceFormats[i];
26836
-        if (formatInfo.internalFormat == internalFormat && formatInfo.type == type)
26837
-        {
26838
-            return i;
26839
-        }
26840
-    }
26841
-    return -1;
26842
-}
26843
-
26844
 angle::Result CreateOrResizeTexture(const gl::Context *context,
26845
                                     const mtl::Format &format,
26846
                                     uint32_t width,
26847
@@ -128,6 +92,19 @@ bool IsFrameCaptureEnabled()
26848
 #endif
26849
 }
26850
 
26851
+ANGLE_MTL_UNUSED
26852
+std::string GetMetalCaptureFile()
26853
+{
26854
+#if !ANGLE_METAL_FRAME_CAPTURE_ENABLED
26855
+    return "";
26856
+#else
26857
+    auto var                   = std::getenv("ANGLE_METAL_FRAME_CAPTURE_FILE");
26858
+    const std::string filePath = var ? var : "";
26859
+
26860
+    return filePath;
26861
+#endif
26862
+}
26863
+
26864
 ANGLE_MTL_UNUSED
26865
 size_t MaxAllowedFrameCapture()
26866
 {
26867
@@ -202,6 +179,21 @@ void StartFrameCapture(id<MTLDevice> metalDevice, id<MTLCommandQueue> metalCmdQu
26868
     {
26869
         MTLCaptureDescriptor *captureDescriptor = [[MTLCaptureDescriptor alloc] init];
26870
         captureDescriptor.captureObject         = metalDevice;
26871
+        const std::string filePath              = GetMetalCaptureFile();
26872
+        if (filePath != "")
26873
+        {
26874
+            const std::string numberedPath =
26875
+                filePath + std::to_string(gFrameCaptured - 1) + ".gputrace";
26876
+            captureDescriptor.destination = MTLCaptureDestinationGPUTraceDocument;
26877
+            captureDescriptor.outputURL =
26878
+                [NSURL fileURLWithPath:[NSString stringWithUTF8String:numberedPath.c_str()]
26879
+                           isDirectory:false];
26880
+        }
26881
+        else
26882
+        {
26883
+            // This will pause execution only if application is being debugged inside Xcode
26884
+            captureDescriptor.destination = MTLCaptureDestinationDeveloperTools;
26885
+        }
26886
 
26887
         NSError *error;
26888
         if (![captureManager startCaptureWithDescriptor:captureDescriptor error:&error])
26889
@@ -211,14 +203,15 @@ void StartFrameCapture(id<MTLDevice> metalDevice, id<MTLCommandQueue> metalCmdQu
26890
     }
26891
     else
26892
 #    endif  // __MAC_10_15
26893
+        if (ANGLE_APPLE_AVAILABLE_XCI(10.15, 13.0, 13))
26894
     {
26895
-        if (FrameCaptureDeviceScope())
26896
-        {
26897
-            [captureManager startCaptureWithDevice:metalDevice];
26898
-        }
26899
-        else
26900
+        MTLCaptureDescriptor *captureDescriptor = [[MTLCaptureDescriptor alloc] init];
26901
+        captureDescriptor.captureObject         = metalDevice;
26902
+
26903
+        NSError *error;
26904
+        if (![captureManager startCaptureWithDescriptor:captureDescriptor error:&error])
26905
         {
26906
-            [captureManager startCaptureWithCommandQueue:metalCmdQueue];
26907
+            NSLog(@"Failed to start capture, error %@", error);
26908
         }
26909
     }
26910
 #endif  // ANGLE_METAL_FRAME_CAPTURE_ENABLED
26911
@@ -245,11 +238,10 @@ void StopFrameCapture()
26912
 }
26913
 }
26914
 
26915
-// SurfaceMtl implementation
26916
 SurfaceMtl::SurfaceMtl(DisplayMtl *display,
26917
                        const egl::SurfaceState &state,
26918
                        const egl::AttributeMap &attribs)
26919
-    : SurfaceImpl(state)
26920
+    : SurfaceMtlProtocol(state)
26921
 {
26922
     mRobustResourceInit =
26923
         attribs.get(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE, EGL_FALSE) == EGL_TRUE;
26924
@@ -693,6 +685,10 @@ void StopFrameCapture()
26925
     return SurfaceMtl::getAttachmentRenderTarget(context, binding, imageIndex, samples, rtOut);
26926
 }
26927
 
26928
+angle::Result WindowSurfaceMtl::ensureCurrentDrawableObtained(const gl::Context *context)
26929
+{
26930
+    return ensureCurrentDrawableObtained(context, nullptr);
26931
+}
26932
 angle::Result WindowSurfaceMtl::ensureCurrentDrawableObtained(const gl::Context *context,
26933
                                                               bool *newDrawableOut)
26934
 {
26935
@@ -943,157 +939,5 @@ void StopFrameCapture()
26936
     mSize.height = height;
26937
 }
26938
 
26939
-// IOSurfaceSurfaceMtl implementation.
26940
-IOSurfaceSurfaceMtl::IOSurfaceSurfaceMtl(DisplayMtl *display,
26941
-                                         const egl::SurfaceState &state,
26942
-                                         EGLClientBuffer buffer,
26943
-                                         const egl::AttributeMap &attribs)
26944
-    : OffscreenSurfaceMtl(display, state, attribs), mIOSurface((__bridge IOSurfaceRef)(buffer))
26945
-{
26946
-    CFRetain(mIOSurface);
26947
-
26948
-    mIOSurfacePlane = static_cast<int>(attribs.get(EGL_IOSURFACE_PLANE_ANGLE));
26949
-
26950
-    EGLAttrib internalFormat = attribs.get(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE);
26951
-    EGLAttrib type           = attribs.get(EGL_TEXTURE_TYPE_ANGLE);
26952
-    mIOSurfaceFormatIdx =
26953
-        FindIOSurfaceFormatIndex(static_cast<GLenum>(internalFormat), static_cast<GLenum>(type));
26954
-    ASSERT(mIOSurfaceFormatIdx >= 0);
26955
-
26956
-    mColorFormat =
26957
-        display->getPixelFormat(kIOSurfaceFormats[mIOSurfaceFormatIdx].nativeAngleFormatId);
26958
-}
26959
-IOSurfaceSurfaceMtl::~IOSurfaceSurfaceMtl()
26960
-{
26961
-    if (mIOSurface != nullptr)
26962
-    {
26963
-        CFRelease(mIOSurface);
26964
-        mIOSurface = nullptr;
26965
-    }
26966
-}
26967
-
26968
-egl::Error IOSurfaceSurfaceMtl::bindTexImage(const gl::Context *context,
26969
-                                             gl::Texture *texture,
26970
-                                             EGLint buffer)
26971
-{
26972
-    ContextMtl *contextMtl = mtl::GetImpl(context);
26973
-    StartFrameCapture(contextMtl);
26974
-
26975
-    // Initialize offscreen texture if needed:
26976
-    ANGLE_TO_EGL_TRY(ensureColorTextureCreated(context));
26977
-
26978
-    return OffscreenSurfaceMtl::bindTexImage(context, texture, buffer);
26979
-}
26980
-
26981
-egl::Error IOSurfaceSurfaceMtl::releaseTexImage(const gl::Context *context, EGLint buffer)
26982
-{
26983
-    egl::Error re = OffscreenSurfaceMtl::releaseTexImage(context, buffer);
26984
-    StopFrameCapture();
26985
-    return re;
26986
-}
26987
-
26988
-angle::Result IOSurfaceSurfaceMtl::getAttachmentRenderTarget(
26989
-    const gl::Context *context,
26990
-    GLenum binding,
26991
-    const gl::ImageIndex &imageIndex,
26992
-    GLsizei samples,
26993
-    FramebufferAttachmentRenderTarget **rtOut)
26994
-{
26995
-    // Initialize offscreen texture if needed:
26996
-    ANGLE_TRY(ensureColorTextureCreated(context));
26997
-
26998
-    return OffscreenSurfaceMtl::getAttachmentRenderTarget(context, binding, imageIndex, samples,
26999
-                                                          rtOut);
27000
-}
27001
-
27002
-angle::Result IOSurfaceSurfaceMtl::ensureColorTextureCreated(const gl::Context *context)
27003
-{
27004
-    if (mColorTexture)
27005
-    {
27006
-        return angle::Result::Continue;
27007
-    }
27008
-    ContextMtl *contextMtl = mtl::GetImpl(context);
27009
-    ANGLE_MTL_OBJC_SCOPE
27010
-    {
27011
-        auto texDesc =
27012
-            [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:mColorFormat.metalFormat
27013
-                                                               width:mSize.width
27014
-                                                              height:mSize.height
27015
-                                                           mipmapped:NO];
27016
-
27017
-        texDesc.usage = MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget;
27018
-
27019
-        id<MTLTexture> texture =
27020
-            [contextMtl->getMetalDevice() newTextureWithDescriptor:texDesc
27021
-                                                         iosurface:mIOSurface
27022
-                                                             plane:mIOSurfacePlane];
27023
-
27024
-        mColorTexture = mtl::Texture::MakeFromMetal([texture ANGLE_MTL_AUTORELEASE]);
27025
-    }
27026
-
27027
-    mColorRenderTarget.set(mColorTexture, mtl::kZeroNativeMipLevel, 0, mColorFormat);
27028
-
27029
-    if (kIOSurfaceFormats[mIOSurfaceFormatIdx].internalFormat == GL_RGB)
27030
-    {
27031
-        // This format has emulated alpha channel. Initialize texture's alpha channel to 1.0.
27032
-        const mtl::Format &rgbClearFormat =
27033
-            contextMtl->getPixelFormat(angle::FormatID::R8G8B8_UNORM);
27034
-        ANGLE_TRY(mtl::InitializeTextureContentsGPU(
27035
-            context, mColorTexture, rgbClearFormat,
27036
-            mtl::ImageNativeIndex::FromBaseZeroGLIndex(gl::ImageIndex::Make2D(0)),
27037
-            MTLColorWriteMaskAlpha));
27038
-
27039
-        // Disable subsequent rendering to alpha channel.
27040
-        mColorTexture->setColorWritableMask(MTLColorWriteMaskAll & (~MTLColorWriteMaskAlpha));
27041
-    }
27042
-
27043
-    return angle::Result::Continue;
27044
-}
27045
-
27046
-// static
27047
-bool IOSurfaceSurfaceMtl::ValidateAttributes(EGLClientBuffer buffer,
27048
-                                             const egl::AttributeMap &attribs)
27049
-{
27050
-    IOSurfaceRef ioSurface = (__bridge IOSurfaceRef)(buffer);
27051
-
27052
-    // The plane must exist for this IOSurface. IOSurfaceGetPlaneCount can return 0 for non-planar
27053
-    // ioSurfaces but we will treat non-planar like it is a single plane.
27054
-    size_t surfacePlaneCount = std::max(size_t(1), IOSurfaceGetPlaneCount(ioSurface));
27055
-    EGLAttrib plane          = attribs.get(EGL_IOSURFACE_PLANE_ANGLE);
27056
-    if (plane < 0 || static_cast<size_t>(plane) >= surfacePlaneCount)
27057
-    {
27058
-        return false;
27059
-    }
27060
-
27061
-    // The width height specified must be at least (1, 1) and at most the plane size
27062
-    EGLAttrib width  = attribs.get(EGL_WIDTH);
27063
-    EGLAttrib height = attribs.get(EGL_HEIGHT);
27064
-    if (width <= 0 || static_cast<size_t>(width) > IOSurfaceGetWidthOfPlane(ioSurface, plane) ||
27065
-        height <= 0 || static_cast<size_t>(height) > IOSurfaceGetHeightOfPlane(ioSurface, plane))
27066
-    {
27067
-        return false;
27068
-    }
27069
-
27070
-    // Find this IOSurface format
27071
-    EGLAttrib internalFormat = attribs.get(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE);
27072
-    EGLAttrib type           = attribs.get(EGL_TEXTURE_TYPE_ANGLE);
27073
-
27074
-    int formatIndex =
27075
-        FindIOSurfaceFormatIndex(static_cast<GLenum>(internalFormat), static_cast<GLenum>(type));
27076
-
27077
-    if (formatIndex < 0)
27078
-    {
27079
-        return false;
27080
-    }
27081
-
27082
-    // Check that the format matches this IOSurface plane
27083
-    if (IOSurfaceGetBytesPerElementOfPlane(ioSurface, plane) !=
27084
-        kIOSurfaceFormats[formatIndex].componentBytes)
27085
-    {
27086
-        return false;
27087
-    }
27088
-
27089
-    return true;
27090
-}
27091
 
27092
 }
27093
diff --git a/src/libANGLE/renderer/metal/SyncMtl.h b/src/libANGLE/renderer/metal/SyncMtl.h
27094
index 62f96ee..f4bcae9 100644
27095
--- a/src/libANGLE/renderer/metal/SyncMtl.h
27096
+++ b/src/libANGLE/renderer/metal/SyncMtl.h
27097
@@ -1,5 +1,5 @@
27098
 //
27099
-// Copyright 2020 The ANGLE Project Authors. All rights reserved.
27100
+// Copyright (c) 2020 The ANGLE Project Authors. All rights reserved.
27101
 // Use of this source code is governed by a BSD-style license that can be
27102
 // found in the LICENSE file.
27103
 //
27104
@@ -33,7 +33,7 @@ namespace mtl
27105
 
27106
 // Common class to be used by both SyncImpl and EGLSyncImpl.
27107
 // NOTE: SharedEvent is only declared on iOS 12.0+ or mac 10.14+
27108
-#if ANGLE_MTL_EVENT_AVAILABLE
27109
+#if defined(__IPHONE_12_0) || defined(__MAC_10_14)
27110
 class Sync
27111
 {
27112
   public:
27113
@@ -59,7 +59,7 @@ class Sync
27114
     std::shared_ptr<std::condition_variable> mCv;
27115
     std::shared_ptr<std::mutex> mLock;
27116
 };
27117
-#else   // #if ANGLE_MTL_EVENT_AVAILABLE
27118
+#else   // #if defined(__IPHONE_12_0) || defined(__MAC_10_14)
27119
 class Sync
27120
 {
27121
   public:
27122
@@ -90,7 +90,7 @@ class Sync
27123
         return angle::Result::Stop;
27124
     }
27125
 };
27126
-#endif  // #if ANGLE_MTL_EVENT_AVAILABLE
27127
+#endif  // #if defined(__IPHONE_12_0) || defined(__MAC_10_14)
27128
 }  // namespace mtl
27129
 
27130
 class FenceNVMtl : public FenceNVImpl
27131
@@ -98,9 +98,7 @@ class FenceNVMtl : public FenceNVImpl
27132
   public:
27133
     FenceNVMtl();
27134
     ~FenceNVMtl() override;
27135
-
27136
     void onDestroy(const gl::Context *context) override;
27137
-
27138
     angle::Result set(const gl::Context *context, GLenum condition) override;
27139
     angle::Result test(const gl::Context *context, GLboolean *outFinished) override;
27140
     angle::Result finish(const gl::Context *context) override;
27141
@@ -152,6 +150,8 @@ class EGLSyncMtl final : public EGLSyncImpl
27142
                           EGLint flags) override;
27143
     egl::Error getStatus(const egl::Display *display, EGLint *outStatus) override;
27144
 
27145
+    egl::Error dupNativeFenceFD(const egl::Display *display, EGLint *result) const override;
27146
+
27147
   private:
27148
     mtl::Sync mSync;
27149
 };
27150
diff --git a/src/libANGLE/renderer/metal/SyncMtl.mm b/src/libANGLE/renderer/metal/SyncMtl.mm
27151
index dff8003..f8f3ee6 100644
27152
--- a/src/libANGLE/renderer/metal/SyncMtl.mm
27153
+++ b/src/libANGLE/renderer/metal/SyncMtl.mm
27154
@@ -1,5 +1,5 @@
27155
 //
27156
-// Copyright 2020 The ANGLE Project Authors. All rights reserved.
27157
+// Copyright (c) 2020 The ANGLE Project Authors. All rights reserved.
27158
 // Use of this source code is governed by a BSD-style license that can be
27159
 // found in the LICENSE file.
27160
 //
27161
@@ -22,7 +22,7 @@
27162
 namespace mtl
27163
 {
27164
 // SharedEvent is only available on iOS 12.0+ or mac 10.14+
27165
-#if ANGLE_MTL_EVENT_AVAILABLE
27166
+#if defined(__IPHONE_12_0) || defined(__MAC_10_14)
27167
 Sync::Sync() {}
27168
 Sync::~Sync() {}
27169
 
27170
@@ -87,7 +87,7 @@
27171
     // onDestroy(), but the callback might still not be fired yet.
27172
     std::shared_ptr<std::condition_variable> cvRef = mCv;
27173
     std::shared_ptr<std::mutex> lockRef            = mLock;
27174
-
27175
+#if ANGLE_MTL_EVENT_AVAILABLE
27176
     AutoObjCObj<MTLSharedEventListener> eventListener =
27177
         contextMtl->getDisplay()->getOrCreateSharedEventListener();
27178
     [mMetalSharedEvent.get() notifyListener:eventListener
27179
@@ -106,6 +106,7 @@
27180
 
27181
     ASSERT(mMetalSharedEvent.get().signaledValue >= mSetCounter);
27182
     *outResult = GL_CONDITION_SATISFIED;
27183
+#endif
27184
 
27185
     return angle::Result::Continue;
27186
 }
27187
@@ -118,7 +119,7 @@
27188
     *signaled = mMetalSharedEvent.get().signaledValue >= mSetCounter;
27189
     return angle::Result::Continue;
27190
 }
27191
-#endif  // #if ANGLE_MTL_EVENT_AVAILABLE
27192
+#endif  // #if defined(__IPHONE_12_0) || defined(__MAC_10_14)
27193
 }  // namespace mtl
27194
 
27195
 // FenceNVMtl implementation
27196
@@ -128,7 +129,8 @@
27197
 
27198
 void FenceNVMtl::onDestroy(const gl::Context *context)
27199
 {
27200
-    mSync.onDestroy();
27201
+    UNIMPLEMENTED();
27202
+    return;
27203
 }
27204
 
27205
 angle::Result FenceNVMtl::set(const gl::Context *context, GLenum condition)
27206
@@ -307,4 +309,10 @@
27207
     return egl::NoError();
27208
 }
27209
 
27210
+egl::Error EGLSyncMtl::dupNativeFenceFD(const egl::Display *display, EGLint *result) const
27211
+{
27212
+    UNREACHABLE();
27213
+    return egl::EglBadDisplay();
27214
+}
27215
+
27216
 }
27217
diff --git a/src/libANGLE/renderer/metal/TextureMtl.h b/src/libANGLE/renderer/metal/TextureMtl.h
27218
index 5c2141b..5f4b2d4 100644
27219
--- a/src/libANGLE/renderer/metal/TextureMtl.h
27220
+++ b/src/libANGLE/renderer/metal/TextureMtl.h
27221
@@ -15,9 +15,9 @@
27222
 #include "common/PackedEnums.h"
27223
 #include "libANGLE/renderer/TextureImpl.h"
27224
 #include "libANGLE/renderer/metal/RenderTargetMtl.h"
27225
+#include "libANGLE/renderer/metal/SurfaceMtl.h"
27226
 #include "libANGLE/renderer/metal/mtl_command_buffer.h"
27227
 #include "libANGLE/renderer/metal/mtl_resources.h"
27228
-
27229
 namespace rx
27230
 {
27231
 
27232
@@ -32,6 +32,8 @@ class TextureMtl : public TextureImpl
27233
 {
27234
   public:
27235
     TextureMtl(const gl::TextureState &state);
27236
+    // Texture  view
27237
+    TextureMtl(const TextureMtl &mtl, GLenum format);
27238
     ~TextureMtl() override;
27239
     void onDestroy(const gl::Context *context) override;
27240
 
27241
@@ -193,6 +195,7 @@ class TextureMtl : public TextureImpl
27242
     ImageDefinitionMtl &getImageDefinition(const gl::ImageIndex &imageIndex);
27243
     RenderTargetMtl &getRenderTarget(const gl::ImageIndex &imageIndex);
27244
     bool isIndexWithinMinMaxLevels(const gl::ImageIndex &imageIndex) const;
27245
+    mtl::TextureRef &getImplicitMSTexture(const gl::ImageIndex &imageIndex);
27246
 
27247
     // If levels = 0, this function will create full mipmaps texture.
27248
     angle::Result setStorageImpl(const gl::Context *context,
27249
@@ -312,8 +315,9 @@ class TextureMtl : public TextureImpl
27250
     angle::Result generateMipmapCPU(const gl::Context *context);
27251
 
27252
     mtl::Format mFormat;
27253
+    SurfaceMtlProtocol *mBoundSurface = nil;
27254
     // The real texture used by Metal draw calls.
27255
-    mtl::TextureRef mNativeTexture;
27256
+    mtl::TextureRef mNativeTexture         = nil;
27257
     id<MTLSamplerState> mMetalSamplerState = nil;
27258
 
27259
     // Number of slices
27260
@@ -323,18 +327,14 @@ class TextureMtl : public TextureImpl
27261
     // Once the images array is complete, they will be transferred to real texture object.
27262
     // NOTE:
27263
     //  - The second dimension is indexed by configured base level + actual native level
27264
-    //  - For Cube map, there will be at most 6 entries in the mTexImageDefs table, one for each
27265
-    //  face. This is because the Cube map's image is defined per face & per level.
27266
+    //  - For Cube map, there will be at most 6 entries in the map table, one for each face. This is
27267
+    //  because the Cube map's image is defined per face & per level.
27268
     //  - For other texture types, there will be only one entry in the map table. All other textures
27269
     //  except Cube map has texture image defined per level (all slices included).
27270
+    //  - These three variables' second dimension are indexed by image index (base level included).
27271
     std::map<int, gl::TexLevelArray<ImageDefinitionMtl>> mTexImageDefs;
27272
-
27273
-    // Render Target per slice/depth/cube face.
27274
-    // - For 2D texture: There will be one key entry in the map.
27275
-    // - For Cube map: There will be at most 6 key entries.
27276
-    // - For array/3D texture: There will be at most slices/depths number of key entries.
27277
-    // - The second dimension is indexed by configured base level + actual native level
27278
     std::map<int, gl::TexLevelArray<RenderTargetMtl>> mPerLayerRenderTargets;
27279
+    std::map<int, gl::TexLevelArray<mtl::TextureRef>> mImplicitMSTextures;
27280
 
27281
     // Mipmap views are indexed by native level (ignored base level):
27282
     mtl::NativeTexLevelArray mNativeLevelViews;
27283
diff --git a/src/libANGLE/renderer/metal/TextureMtl.mm b/src/libANGLE/renderer/metal/TextureMtl.mm
27284
index 623c104..3b1c8af 100644
27285
--- a/src/libANGLE/renderer/metal/TextureMtl.mm
27286
+++ b/src/libANGLE/renderer/metal/TextureMtl.mm
27287
@@ -20,8 +20,8 @@
27288
 #include "libANGLE/renderer/metal/ContextMtl.h"
27289
 #include "libANGLE/renderer/metal/DisplayMtl.h"
27290
 #include "libANGLE/renderer/metal/FrameBufferMtl.h"
27291
+#include "libANGLE/renderer/metal/IOSurfaceSurfaceMtl.h"
27292
 #include "libANGLE/renderer/metal/SamplerMtl.h"
27293
-#include "libANGLE/renderer/metal/SurfaceMtl.h"
27294
 #include "libANGLE/renderer/metal/mtl_common.h"
27295
 #include "libANGLE/renderer/metal/mtl_format_utils.h"
27296
 #include "libANGLE/renderer/metal/mtl_utils.h"
27297
@@ -534,6 +534,10 @@ GLenum OverrideSwizzleValue(const gl::Context *context,
27298
 
27299
 angle::Result TextureMtl::ensureTextureCreated(const gl::Context *context)
27300
 {
27301
+    if (mBoundSurface)
27302
+    {
27303
+        return angle::Result::Continue;
27304
+    }
27305
     if (mNativeTexture)
27306
     {
27307
         return angle::Result::Continue;
27308
@@ -1207,25 +1211,15 @@ GLenum OverrideSwizzleValue(const gl::Context *context,
27309
 
27310
 angle::Result TextureMtl::bindTexImage(const gl::Context *context, egl::Surface *surface)
27311
 {
27312
-    releaseTexture(true);
27313
-
27314
-    auto pBuffer     = GetImplAs<OffscreenSurfaceMtl>(surface);
27315
-    mNativeTexture   = pBuffer->getColorTexture();
27316
-    mFormat          = pBuffer->getColorFormat();
27317
-    gl::Extents size = mNativeTexture->sizeAt0();
27318
-    mIsPow2          = gl::isPow2(size.width) && gl::isPow2(size.height) && gl::isPow2(size.depth);
27319
-    ANGLE_TRY(ensureSamplerStateCreated(context));
27320
-
27321
-    // Tell context to rebind textures
27322
-    ContextMtl *contextMtl = mtl::GetImpl(context);
27323
-    contextMtl->invalidateCurrentTextures();
27324
-
27325
+    IOSurfaceSurfaceMtl *surfaceMtl = (IOSurfaceSurfaceMtl *)mtl::GetImpl(surface);
27326
+    mBoundSurface                   = surfaceMtl;
27327
     return angle::Result::Continue;
27328
 }
27329
 
27330
 angle::Result TextureMtl::releaseTexImage(const gl::Context *context)
27331
 {
27332
-    releaseTexture(true);
27333
+    mBoundSurface = nil;
27334
+
27335
     return angle::Result::Continue;
27336
 }
27337
 
27338
@@ -1235,6 +1229,12 @@ GLenum OverrideSwizzleValue(const gl::Context *context,
27339
                                                     GLsizei samples,
27340
                                                     FramebufferAttachmentRenderTarget **rtOut)
27341
 {
27342
+    if (mBoundSurface)
27343
+    {
27344
+        ANGLE_TRY(
27345
+            mBoundSurface->getAttachmentRenderTarget(context, binding, imageIndex, samples, rtOut));
27346
+        return angle::Result::Continue;
27347
+    }
27348
     ANGLE_TRY(ensureTextureCreated(context));
27349
 
27350
     ContextMtl *contextMtl = mtl::GetImpl(context);
27351
diff --git a/src/libANGLE/renderer/metal/TransformFeedbackMtl.h b/src/libANGLE/renderer/metal/TransformFeedbackMtl.h
27352
index aa45bf9..20a2c20 100644
27353
--- a/src/libANGLE/renderer/metal/TransformFeedbackMtl.h
27354
+++ b/src/libANGLE/renderer/metal/TransformFeedbackMtl.h
27355
@@ -10,12 +10,20 @@
27356
 #ifndef LIBANGLE_RENDERER_METAL_TRANSFORMFEEDBACKMTL_H_
27357
 #define LIBANGLE_RENDERER_METAL_TRANSFORMFEEDBACKMTL_H_
27358
 
27359
+#include <Metal/Metal.h>
27360
 #include "libANGLE/renderer/TransformFeedbackImpl.h"
27361
+#include "libANGLE/renderer/metal/BufferMtl.h"
27362
+#include "libANGLE/renderer/metal/mtl_resources.h"
27363
 
27364
-namespace rx
27365
+typedef uint64_t MtlDeviceSize;
27366
+
27367
+namespace gl
27368
 {
27369
+class ProgramState;
27370
+}  // namespace gl
27371
 
27372
-class ContextMtl;
27373
+namespace rx
27374
+{
27375
 
27376
 class TransformFeedbackMtl : public TransformFeedbackImpl
27377
 {
27378
@@ -32,17 +40,23 @@ class TransformFeedbackMtl : public TransformFeedbackImpl
27379
                                     size_t index,
27380
                                     const gl::OffsetBindingPointer<gl::Buffer> &binding) override;
27381
 
27382
-    // Params:
27383
-    // - drawCallFirstVertex is first vertex used by glDrawArrays*. This is important because
27384
-    // gl_VertexIndex is starting from this.
27385
-    // - skippedVertices is number of skipped vertices (useful for multiple metal draws per GL draw
27386
-    // call).
27387
-    angle::Result getBufferOffsets(ContextMtl *contextMtl,
27388
+    void getBufferOffsets(ContextMtl *contextMtl,
27389
                           GLint drawCallFirstVertex,
27390
-                                   uint32_t skippedVertices,
27391
-                                   int32_t *offsetsOut);
27392
+                          int32_t *offsetsOut,
27393
+                          size_t offsetsSize) const;
27394
+
27395
+    const gl::TransformFeedbackBuffersArray<BufferMtl *> &getBufferHandles() const
27396
+    {
27397
+        return mBufferHandles;
27398
+    }
27399
 
27400
   private:
27401
+    gl::TransformFeedbackBuffersArray<BufferMtl *> mBufferHandles;
27402
+    gl::TransformFeedbackBuffersArray<MtlDeviceSize> mBufferOffsets;
27403
+    gl::TransformFeedbackBuffersArray<MtlDeviceSize> mBufferSizes;
27404
+
27405
+    // Aligned offset for emulation. Could be smaller than offset.
27406
+    gl::TransformFeedbackBuffersArray<MtlDeviceSize> mAlignedBufferOffsets;
27407
 };
27408
 
27409
 }  // namespace rx
27410
diff --git a/src/libANGLE/renderer/metal/TransformFeedbackMtl.mm b/src/libANGLE/renderer/metal/TransformFeedbackMtl.mm
27411
index d940c3d..de7a909 100644
27412
--- a/src/libANGLE/renderer/metal/TransformFeedbackMtl.mm
27413
+++ b/src/libANGLE/renderer/metal/TransformFeedbackMtl.mm
27414
@@ -8,18 +8,27 @@
27415
 //
27416
 
27417
 #include "libANGLE/renderer/metal/TransformFeedbackMtl.h"
27418
+#include "libANGLE/renderer/metal/BufferMtl.h"
27419
+#include "libANGLE/renderer/metal/ContextMtl.h"
27420
+#include "libANGLE/renderer/metal/DisplayMtl.h"
27421
+#include "libANGLE/renderer/metal/ProgramMtl.h"
27422
+#include "libANGLE/renderer/metal/QueryMtl.h"
27423
+#include "libANGLE/renderer/metal/mtl_common.h"
27424
 
27425
-#include "common/debug.h"
27426
 #include "libANGLE/Context.h"
27427
 #include "libANGLE/Query.h"
27428
-#include "libANGLE/renderer/metal/ContextMtl.h"
27429
-#include "libANGLE/renderer/metal/QueryMtl.h"
27430
+
27431
+#include "common/debug.h"
27432
 
27433
 namespace rx
27434
 {
27435
 
27436
 TransformFeedbackMtl::TransformFeedbackMtl(const gl::TransformFeedbackState &state)
27437
-    : TransformFeedbackImpl(state)
27438
+    : TransformFeedbackImpl(state),
27439
+      mBufferHandles{},
27440
+      mBufferOffsets{},
27441
+      mBufferSizes{},
27442
+      mAlignedBufferOffsets{}
27443
 {}
27444
 
27445
 TransformFeedbackMtl::~TransformFeedbackMtl() {}
27446
@@ -27,40 +36,79 @@
27447
 angle::Result TransformFeedbackMtl::begin(const gl::Context *context,
27448
                                           gl::PrimitiveMode primitiveMode)
27449
 {
27450
-    mtl::GetImpl(context)->onTransformFeedbackActive(context, this);
27451
+    ContextMtl *contextMtl = mtl::GetImpl(context);
27452
+    // Not currently supported with msl compiler
27453
+    if (!contextMtl->getDisplay()->getFeatures().emulateTransformFeedback.enabled)
27454
+    {
27455
+        return angle::Result::Stop;
27456
+    }
27457
 
27458
-    return angle::Result::Continue;
27459
+    const gl::ProgramExecutable *executable = contextMtl->getState().getProgramExecutable();
27460
+    ASSERT(executable);
27461
+    size_t xfbBufferCount = executable->getTransformFeedbackBufferCount();
27462
+
27463
+    for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
27464
+    {
27465
+        const gl::OffsetBindingPointer<gl::Buffer> &binding = mState.getIndexedBuffer(bufferIndex);
27466
+        ASSERT(binding.get());
27467
+
27468
+        BufferMtl *bufferMtl = mtl::GetImpl(binding.get());
27469
+
27470
+        assert(bufferMtl);
27471
+        mBufferOffsets[bufferIndex] = binding.getOffset();
27472
+        mBufferSizes[bufferIndex]   = gl::GetBoundBufferAvailableSize(binding);
27473
+        mBufferHandles[bufferIndex] = bufferMtl;
27474
+
27475
+        ASSERT(contextMtl->getDisplay()->getFeatures().emulateTransformFeedback.enabled);
27476
+        const MtlDeviceSize offsetAlignment = mtl::kUniformBufferSettingOffsetMinAlignment;
27477
+
27478
+        // Make sure there's no possible under/overflow with binding size.
27479
+        static_assert(sizeof(MtlDeviceSize) >= sizeof(binding.getSize()),
27480
+                      "MtlDeviceSize too small");
27481
+
27482
+        // Set the offset as close as possible to the requested offset while remaining aligned.
27483
+        mAlignedBufferOffsets[bufferIndex] =
27484
+            (mBufferOffsets[bufferIndex] / offsetAlignment) * offsetAlignment;
27485
+    }
27486
+
27487
+    return contextMtl->onBeginTransformFeedback(xfbBufferCount, mBufferHandles);
27488
 }
27489
 
27490
 angle::Result TransformFeedbackMtl::end(const gl::Context *context)
27491
 {
27492
+    ContextMtl *contextMtl = mtl::GetImpl(context);
27493
+    // Not currently supported with msl compiler
27494
+    if (!contextMtl->getDisplay()->getFeatures().emulateTransformFeedback.enabled)
27495
+    {
27496
+        return angle::Result::Stop;
27497
+    }
27498
+
27499
+    // If there's an active transform feedback query, accumulate the primitives drawn.
27500
     const gl::State &glState = context->getState();
27501
     gl::Query *transformFeedbackQuery =
27502
         glState.getActiveQuery(gl::QueryType::TransformFeedbackPrimitivesWritten);
27503
+
27504
     if (transformFeedbackQuery)
27505
     {
27506
-        mtl::GetImpl(transformFeedbackQuery)->onTransformFeedbackEnd(context);
27507
+        mtl::GetImpl(transformFeedbackQuery)->onTransformFeedbackEnd(mState.getPrimitivesDrawn());
27508
     }
27509
-
27510
-    mtl::GetImpl(context)->onTransformFeedbackInactive(context, this);
27511
-
27512
+    contextMtl->onEndTransformFeedback();
27513
     return angle::Result::Continue;
27514
 }
27515
 
27516
 angle::Result TransformFeedbackMtl::pause(const gl::Context *context)
27517
 {
27518
-    // When XFB is paused, OpenGL allows XFB buffers to be bound for other purposes. We need to call
27519
-    // onTransformFeedbackInactive() to issue a sync.
27520
-    mtl::GetImpl(context)->onTransformFeedbackInactive(context, this);
27521
-
27522
-    return angle::Result::Continue;
27523
+    ContextMtl *contextMtl = mtl::GetImpl(context);
27524
+    return contextMtl->onPauseTransformFeedback();
27525
 }
27526
 
27527
 angle::Result TransformFeedbackMtl::resume(const gl::Context *context)
27528
 {
27529
-    mtl::GetImpl(context)->onTransformFeedbackActive(context, this);
27530
-
27531
-    return angle::Result::Continue;
27532
+    ContextMtl *contextMtl                  = mtl::GetImpl(context);
27533
+    const gl::ProgramExecutable *executable = contextMtl->getState().getProgramExecutable();
27534
+    ASSERT(executable);
27535
+    size_t xfbBufferCount = executable->getTransformFeedbackBufferCount();
27536
+    return contextMtl->onBeginTransformFeedback(xfbBufferCount, mBufferHandles);
27537
 }
27538
 
27539
 angle::Result TransformFeedbackMtl::bindIndexedBuffer(
27540
@@ -68,17 +116,20 @@
27541
     size_t index,
27542
     const gl::OffsetBindingPointer<gl::Buffer> &binding)
27543
 {
27544
-    // Do nothing for now
27545
+    UNIMPLEMENTED();
27546
 
27547
     return angle::Result::Continue;
27548
 }
27549
 
27550
-angle::Result TransformFeedbackMtl::getBufferOffsets(ContextMtl *contextMtl,
27551
+void TransformFeedbackMtl::getBufferOffsets(ContextMtl *contextMtl,
27552
                                             GLint drawCallFirstVertex,
27553
-                                                     uint32_t skippedVertices,
27554
-                                                     int32_t *offsetsOut)
27555
+                                            int32_t *offsetsOut,
27556
+                                            size_t offsetsSize) const
27557
 {
27558
-    int64_t verticesDrawn = static_cast<int64_t>(mState.getVerticesDrawn()) + skippedVertices;
27559
+    if (!contextMtl->getDisplay()->getFeatures().emulateTransformFeedback.enabled)
27560
+        return;
27561
+
27562
+    GLsizeiptr verticesDrawn = mState.getVerticesDrawn();
27563
     const std::vector<GLsizei> &bufferStrides =
27564
         mState.getBoundProgram()->getTransformFeedbackStrides();
27565
     const gl::ProgramExecutable *executable = contextMtl->getState().getProgramExecutable();
27566
@@ -87,27 +138,25 @@
27567
 
27568
     ASSERT(xfbBufferCount > 0);
27569
 
27570
+    // The caller should make sure the offsets array has enough space.  The maximum possible
27571
+    // number of outputs is gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS.
27572
+    ASSERT(offsetsSize >= xfbBufferCount);
27573
+
27574
     for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
27575
     {
27576
-        const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
27577
-            mState.getIndexedBuffer(bufferIndex);
27578
-
27579
-        ASSERT((bufferBinding.getOffset() % 4) == 0);
27580
-
27581
-        // Offset the gl_VertexIndex by drawCallFirstVertex
27582
+        int64_t offsetFromDescriptor =
27583
+            static_cast<int64_t>(mBufferOffsets[bufferIndex] - mAlignedBufferOffsets[bufferIndex]);
27584
         int64_t drawCallVertexOffset = static_cast<int64_t>(verticesDrawn) - drawCallFirstVertex;
27585
 
27586
         int64_t writeOffset =
27587
-            (bufferBinding.getOffset() + drawCallVertexOffset * bufferStrides[bufferIndex]) /
27588
+            (offsetFromDescriptor + drawCallVertexOffset * bufferStrides[bufferIndex]) /
27589
             static_cast<int64_t>(sizeof(uint32_t));
27590
 
27591
         offsetsOut[bufferIndex] = static_cast<int32_t>(writeOffset);
27592
 
27593
-        // Check for overflow.
27594
-        ANGLE_CHECK_GL_ALLOC(contextMtl, offsetsOut[bufferIndex] == writeOffset);
27595
+        // Assert on overflow.  For now, support transform feedback up to 2GB.
27596
+        ASSERT(offsetsOut[bufferIndex] == writeOffset);
27597
     }
27598
-
27599
-    return angle::Result::Continue;
27600
 }
27601
 
27602
 }  // namespace rx
27603
diff --git a/src/libANGLE/renderer/metal/VertexArrayMtl.h b/src/libANGLE/renderer/metal/VertexArrayMtl.h
27604
index c2fb846..fe6b5f7 100644
27605
--- a/src/libANGLE/renderer/metal/VertexArrayMtl.h
27606
+++ b/src/libANGLE/renderer/metal/VertexArrayMtl.h
27607
@@ -43,8 +43,9 @@ class VertexArrayMtl : public VertexArrayImpl
27608
                                       const void *indices);
27609
 
27610
     // vertexDescChanged is both input and output, the input value if is true, will force new
27611
-    // mtl::VertexDesc to be returned via vertexDescOut. Otherwise, it is only returned when the
27612
-    // vertex array is dirty
27613
+    // mtl::VertexDesc to be returned via vertexDescOut. This typically happens when active shader
27614
+    // program is changed.
27615
+    // Otherwise, it is only returned when the vertex array is dirty.
27616
     angle::Result setupDraw(const gl::Context *glContext,
27617
                             mtl::RenderCommandEncoder *cmdEncoder,
27618
                             bool *vertexDescChanged,
27619
@@ -52,11 +53,24 @@ class VertexArrayMtl : public VertexArrayImpl
27620
 
27621
     angle::Result getIndexBuffer(const gl::Context *glContext,
27622
                                  gl::DrawElementsType indexType,
27623
+                                 gl::PrimitiveMode primitiveMode,
27624
                                  size_t indexCount,
27625
                                  const void *sourcePointer,
27626
                                  mtl::BufferRef *idxBufferOut,
27627
                                  size_t *idxBufferOffsetOut,
27628
-                                 gl::DrawElementsType *indexTypeOut);
27629
+                                 gl::DrawElementsType *indexTypeOut,
27630
+                                 size_t *indexBufferCountOut);
27631
+
27632
+    // Use to emulate instanced draw for instance <instanceId>.
27633
+    // The typical call sequence for emulated instance draw is:
27634
+    // - setupDraw()
27635
+    // - draw.
27636
+    // - emulateInstanceDrawStep(1)
27637
+    // - draw.
27638
+    // - emulateInstanceDrawStep(n)
27639
+    // - draw.
27640
+    // - emulateInstanceDrawStep(0)
27641
+    void emulateInstanceDrawStep(mtl::RenderCommandEncoder *cmdEncoder, uint32_t instanceId);
27642
 
27643
   private:
27644
     void reset(ContextMtl *context);
27645
@@ -72,15 +86,19 @@ class VertexArrayMtl : public VertexArrayImpl
27646
 
27647
     angle::Result convertIndexBuffer(const gl::Context *glContext,
27648
                                      gl::DrawElementsType indexType,
27649
+                                     gl::PrimitiveMode mode,
27650
                                      size_t offset,
27651
                                      mtl::BufferRef *idxBufferOut,
27652
-                                     size_t *idxBufferOffsetOut);
27653
+                                     size_t *idxBufferOffsetOut,
27654
+                                     size_t *indexBufferCountOut);
27655
     angle::Result streamIndexBufferFromClient(const gl::Context *glContext,
27656
                                               gl::DrawElementsType indexType,
27657
+                                              gl::PrimitiveMode primitiveType,
27658
                                               size_t indexCount,
27659
                                               const void *sourcePointer,
27660
                                               mtl::BufferRef *idxBufferOut,
27661
-                                              size_t *idxBufferOffsetOut);
27662
+                                              size_t *idxBufferOffsetOut,
27663
+                                              size_t *idxBufferCountOut);
27664
 
27665
     angle::Result convertIndexBufferGPU(const gl::Context *glContext,
27666
                                         gl::DrawElementsType indexType,
27667
@@ -117,7 +135,20 @@ class VertexArrayMtl : public VertexArrayImpl
27668
     gl::AttribArray<BufferHolderMtl *> mCurrentArrayBuffers;
27669
     gl::AttribArray<SimpleWeakBufferHolderMtl> mConvertedArrayBufferHolders;
27670
     gl::AttribArray<size_t> mCurrentArrayBufferOffsets;
27671
+
27672
+    // Size to be uploaded as inline constant data. Used for client vertex attribute's data that
27673
+    // is small enough that we can send directly as inline constant data instead of streaming
27674
+    // through a buffer.
27675
+    gl::AttribArray<size_t> mCurrentArrayInlineDataSizes;
27676
+    // Array of host buffers storing converted data for client attributes that are small enough.
27677
+    gl::AttribArray<angle::MemoryBuffer> mConvertedClientSmallArrays;
27678
+    gl::AttribArray<const uint8_t *> mCurrentArrayInlineDataPointers;
27679
+    // Max size of inline constant data that can be used for client vertex attribute.
27680
+    size_t mInlineDataMaxSize;
27681
+
27682
+    // Stride per vertex attribute
27683
     gl::AttribArray<GLuint> mCurrentArrayBufferStrides;
27684
+    // Format per vertex attribute
27685
     gl::AttribArray<const mtl::VertexFormat *> mCurrentArrayBufferFormats;
27686
 
27687
     const mtl::VertexFormat &mDefaultFloatVertexFormat;
27688
@@ -127,6 +158,8 @@ class VertexArrayMtl : public VertexArrayImpl
27689
     mtl::BufferPool mDynamicVertexData;
27690
     mtl::BufferPool mDynamicIndexData;
27691
 
27692
+    std::vector<uint32_t> mEmulatedInstanceAttribs;
27693
+
27694
     bool mVertexArrayDirty = true;
27695
 };
27696
 }  // namespace rx
27697
diff --git a/src/libANGLE/renderer/metal/VertexArrayMtl.mm b/src/libANGLE/renderer/metal/VertexArrayMtl.mm
27698
index cd961c1..02195d8 100644
27699
--- a/src/libANGLE/renderer/metal/VertexArrayMtl.mm
27700
+++ b/src/libANGLE/renderer/metal/VertexArrayMtl.mm
27701
@@ -8,6 +8,9 @@
27702
 //
27703
 
27704
 #include "libANGLE/renderer/metal/VertexArrayMtl.h"
27705
+
27706
+#include <TargetConditionals.h>
27707
+
27708
 #include "libANGLE/renderer/metal/BufferMtl.h"
27709
 #include "libANGLE/renderer/metal/ContextMtl.h"
27710
 #include "libANGLE/renderer/metal/DisplayMtl.h"
27711
@@ -76,15 +79,15 @@ size_t GetIndexConvertedBufferSize(gl::DrawElementsType indexType, size_t indexC
27712
                               const uint8_t *sourcePointer,
27713
                               gl::DrawElementsType indexType,
27714
                               size_t indexCount,
27715
+                              gl::PrimitiveMode mode,
27716
                               bool primitiveRestartEnabled,
27717
                               mtl::BufferRef *bufferOut,
27718
-                              size_t *bufferOffsetOut)
27719
+                              size_t *bufferOffsetOut,
27720
+                              size_t *indexCountOut)
27721
 {
27722
     dynamicBuffer->releaseInFlightBuffers(contextMtl);
27723
-
27724
     const size_t amount = GetIndexConvertedBufferSize(indexType, indexCount);
27725
     GLubyte *dst        = nullptr;
27726
-
27727
     ANGLE_TRY(
27728
         dynamicBuffer->allocate(contextMtl, amount, &dst, bufferOut, bufferOffsetOut, nullptr));
27729
 
27730
@@ -121,6 +124,7 @@ size_t GetIndexConvertedBufferSize(gl::DrawElementsType indexType, size_t indexC
27731
     {
27732
         memcpy(dst, sourcePointer, amount);
27733
     }
27734
+    *indexCountOut = indexCount;
27735
     ANGLE_TRY(dynamicBuffer->commit(contextMtl));
27736
 
27737
     return angle::Result::Continue;
27738
@@ -208,6 +212,30 @@ inline void SetDefaultVertexBufferLayout(mtl::VertexBufferLayoutDesc *layout)
27739
         format = &mDefaultFloatVertexFormat;
27740
     }
27741
 
27742
+    for (size_t &inlineDataSize : mCurrentArrayInlineDataSizes)
27743
+    {
27744
+        inlineDataSize = 0;
27745
+    }
27746
+
27747
+    for (angle::MemoryBuffer &convertedClientArray : mConvertedClientSmallArrays)
27748
+    {
27749
+        convertedClientArray.clear();
27750
+    }
27751
+
27752
+    for (const uint8_t *&clientPointer : mCurrentArrayInlineDataPointers)
27753
+    {
27754
+        clientPointer = nullptr;
27755
+    }
27756
+
27757
+    if (context->getDisplay()->getFeatures().allowInlineConstVertexData.enabled)
27758
+    {
27759
+        mInlineDataMaxSize = mtl::kInlineConstDataMaxSize;
27760
+    }
27761
+    else
27762
+    {
27763
+        mInlineDataMaxSize = 0;
27764
+    }
27765
+
27766
     mVertexArrayDirty = true;
27767
 }
27768
 
27769
@@ -315,22 +343,28 @@ inline void SetDefaultVertexBufferLayout(mtl::VertexBufferLayoutDesc *layout)
27770
 }
27771
 
27772
 // vertexDescChanged is both input and output, the input value if is true, will force new
27773
-// mtl::VertexDesc to be returned via vertexDescOut. Otherwise, it is only returned when the
27774
-// vertex array is dirty
27775
+// mtl::VertexDesc to be returned via vertexDescOut. This typically happens when active shader
27776
+// program is changed.
27777
+// Otherwise, it is only returned when the vertex array is dirty.
27778
 angle::Result VertexArrayMtl::setupDraw(const gl::Context *glContext,
27779
                                         mtl::RenderCommandEncoder *cmdEncoder,
27780
                                         bool *vertexDescChanged,
27781
                                         mtl::VertexDesc *vertexDescOut)
27782
 {
27783
+    // NOTE(hqle): consider only updating dirty attributes
27784
     bool dirty = mVertexArrayDirty || *vertexDescChanged;
27785
 
27786
     if (dirty)
27787
     {
27788
+        ContextMtl *contextMtl = mtl::GetImpl(glContext);
27789
+
27790
         mVertexArrayDirty = false;
27791
+        mEmulatedInstanceAttribs.clear();
27792
 
27793
-        const gl::ProgramState &programState = glContext->getState().getProgram()->getState();
27794
+        const gl::ProgramExecutable *executable = glContext->getState().getProgramExecutable();
27795
         const gl::AttributesMask &programActiveAttribsMask =
27796
-            glContext->getState().getProgram()->getExecutable().getActiveAttribLocationsMask();
27797
+            executable->getActiveAttribLocationsMask();
27798
+        const gl::ProgramState &programState = glContext->getState().getProgram()->getState();
27799
 
27800
         const std::vector<gl::VertexAttribute> &attribs = mState.getVertexAttributes();
27801
         const std::vector<gl::VertexBinding> &bindings  = mState.getVertexBindings();
27802
@@ -360,8 +394,7 @@ inline void SetDefaultVertexBufferLayout(mtl::VertexBufferLayoutDesc *layout)
27803
             const gl::VertexBinding &binding = bindings[attrib.bindingIndex];
27804
 
27805
             bool attribEnabled = attrib.enabled;
27806
-            if (attribEnabled &&
27807
-                (!mCurrentArrayBuffers[v] || !mCurrentArrayBuffers[v]->getCurrentBuffer()))
27808
+            if (attribEnabled && !mCurrentArrayBuffers[v] && !mCurrentArrayInlineDataPointers[v])
27809
             {
27810
                 // Disable it to avoid crash.
27811
                 attribEnabled = false;
27812
@@ -369,33 +402,30 @@ inline void SetDefaultVertexBufferLayout(mtl::VertexBufferLayoutDesc *layout)
27813
 
27814
             if (!attribEnabled)
27815
             {
27816
-                // Use default attribute
27817
+                desc.attributes[v].bufferIndex = mtl::kDefaultAttribsBindingIndex;
27818
+                desc.attributes[v].offset      = v * mtl::kDefaultAttributeSize;
27819
                 // Need to find the attribute having the exact binding location = v in the program
27820
                 // inputs list to retrieve its coresponding data type:
27821
                 const std::vector<sh::ShaderVariable> &programInputs =
27822
                     programState.getProgramInputs();
27823
                 std::vector<sh::ShaderVariable>::const_iterator attribInfoIte = std::find_if(
27824
                     begin(programInputs), end(programInputs), [v](const sh::ShaderVariable &sv) {
27825
-                        return static_cast<uint32_t>(sv.location) == v;
27826
+                        return static_cast<uint32_t>(sv.location) <= v &&
27827
+                               v < static_cast<uint32_t>(sv.location) +
27828
+                                       gl::VariableAttributeCount(sv.type);
27829
                     });
27830
 
27831
-                if (attribInfoIte == end(programInputs))
27832
+                ASSERT(attribInfoIte != end(programInputs));
27833
+                switch (gl::VariableComponentType(attribInfoIte->type))
27834
                 {
27835
-                    // Most likely this is array element with index > 0.
27836
-                    // Already handled when encounter first element.
27837
-                    continue;
27838
-                }
27839
-
27840
-                uint32_t arraySize;
27841
-                MTLVertexFormat format;
27842
-
27843
-                getVertexAttribFormatAndArraySize(*attribInfoIte, &format, &arraySize);
27844
-
27845
-                for (uint32_t vaIdx = v; vaIdx < v + arraySize; ++vaIdx)
27846
-                {
27847
-                    desc.attributes[vaIdx].bufferIndex = mtl::kDefaultAttribsBindingIndex;
27848
-                    desc.attributes[vaIdx].offset      = vaIdx * mtl::kDefaultAttributeSize;
27849
-                    desc.attributes[vaIdx].format      = format;
27850
+                    case GL_INT:
27851
+                        desc.attributes[v].format = mDefaultIntVertexFormat.metalFormat;
27852
+                        break;
27853
+                    case GL_UNSIGNED_INT:
27854
+                        desc.attributes[v].format = mDefaultUIntVertexFormat.metalFormat;
27855
+                        break;
27856
+                    default:
27857
+                        desc.attributes[v].format = mDefaultFloatVertexFormat.metalFormat;
27858
                 }
27859
             }
27860
             else
27861
@@ -417,17 +447,35 @@ inline void SetDefaultVertexBufferLayout(mtl::VertexBufferLayoutDesc *layout)
27862
                     desc.layouts[bufferIdx].stepFunction = MTLVertexStepFunctionPerVertex;
27863
                     desc.layouts[bufferIdx].stepRate     = 1;
27864
                 }
27865
-                else
27866
+                else if (contextMtl->getDisplay()->getFeatures().hasBaseVertexInstancedDraw.enabled)
27867
                 {
27868
                     desc.layouts[bufferIdx].stepFunction = MTLVertexStepFunctionPerInstance;
27869
                     desc.layouts[bufferIdx].stepRate     = binding.getDivisor();
27870
                 }
27871
+                else
27872
+                {
27873
+                    // Emulate instance attribute
27874
+                    mEmulatedInstanceAttribs.push_back(v);
27875
+                    desc.layouts[bufferIdx].stepFunction = MTLVertexStepFunctionConstant;
27876
+                    desc.layouts[bufferIdx].stepRate     = 0;
27877
+                }
27878
+
27879
                 desc.layouts[bufferIdx].stride = mCurrentArrayBufferStrides[v];
27880
 
27881
+                if (mCurrentArrayBuffers[v])
27882
+                {
27883
                     cmdEncoder->setVertexBuffer(mCurrentArrayBuffers[v]->getCurrentBuffer(),
27884
                                                 bufferOffset, bufferIdx);
27885
                 }
27886
+                else
27887
+                {
27888
+                    // No buffer specified, use the client memory directly as inline constant data
27889
+                    ASSERT(mCurrentArrayInlineDataSizes[v] <= mInlineDataMaxSize);
27890
+                    cmdEncoder->setVertexBytes(mCurrentArrayInlineDataPointers[v],
27891
+                                               mCurrentArrayInlineDataSizes[v], bufferIdx);
27892
+                }
27893
             }
27894
+        }  // for (v)
27895
     }
27896
 
27897
     *vertexDescChanged = dirty;
27898
@@ -435,6 +483,42 @@ inline void SetDefaultVertexBufferLayout(mtl::VertexBufferLayoutDesc *layout)
27899
     return angle::Result::Continue;
27900
 }
27901
 
27902
+void VertexArrayMtl::emulateInstanceDrawStep(mtl::RenderCommandEncoder *cmdEncoder,
27903
+                                             uint32_t instanceId)
27904
+{
27905
+
27906
+    const std::vector<gl::VertexAttribute> &attribs = mState.getVertexAttributes();
27907
+    const std::vector<gl::VertexBinding> &bindings  = mState.getVertexBindings();
27908
+
27909
+    for (uint32_t instanceAttribIdx : mEmulatedInstanceAttribs)
27910
+    {
27911
+        uint32_t bufferIdx               = mtl::kVboBindingIndexStart + instanceAttribIdx;
27912
+        const auto &attrib               = attribs[instanceAttribIdx];
27913
+        const gl::VertexBinding &binding = bindings[attrib.bindingIndex];
27914
+        uint32_t offset =
27915
+            instanceId / binding.getDivisor() * mCurrentArrayBufferStrides[instanceAttribIdx];
27916
+        if (mCurrentArrayBuffers[instanceAttribIdx])
27917
+        {
27918
+            offset += static_cast<uint32_t>(mCurrentArrayBufferOffsets[instanceAttribIdx]);
27919
+
27920
+            cmdEncoder->setVertexBuffer(mCurrentArrayBuffers[instanceAttribIdx]->getCurrentBuffer(),
27921
+                                        offset, bufferIdx);
27922
+        }
27923
+        else
27924
+        {
27925
+            // No buffer specified, use the client memory directly as inline constant data
27926
+            ASSERT(mCurrentArrayInlineDataSizes[instanceAttribIdx] <= mInlineDataMaxSize);
27927
+            if (offset > mCurrentArrayInlineDataSizes[instanceAttribIdx])
27928
+            {
27929
+                offset = static_cast<uint32_t>(mCurrentArrayInlineDataSizes[instanceAttribIdx]);
27930
+            }
27931
+            cmdEncoder->setVertexBytes(mCurrentArrayInlineDataPointers[instanceAttribIdx] + offset,
27932
+                                       mCurrentArrayInlineDataSizes[instanceAttribIdx] - offset,
27933
+                                       bufferIdx);
27934
+        }
27935
+    }
27936
+}
27937
+
27938
 angle::Result VertexArrayMtl::updateClientAttribs(const gl::Context *context,
27939
                                                   GLint firstVertex,
27940
                                                   GLsizei vertexOrIndexCount,
27941
@@ -463,10 +547,7 @@ inline void SetDefaultVertexBufferLayout(mtl::VertexBufferLayoutDesc *layout)
27942
         const gl::VertexBinding &binding  = bindings[attrib.bindingIndex];
27943
         ASSERT(attrib.enabled && binding.getBuffer().get() == nullptr);
27944
 
27945
-        GLuint stride;
27946
-        const mtl::VertexFormat &vertexFormat =
27947
-            GetVertexConversionFormat(contextMtl, attrib.format->id, &stride);
27948
-
27949
+        // Source client memory pointer
27950
         const uint8_t *src = static_cast<const uint8_t *>(attrib.pointer);
27951
         ASSERT(src);
27952
 
27953
@@ -484,22 +565,76 @@ inline void SetDefaultVertexBufferLayout(mtl::VertexBufferLayoutDesc *layout)
27954
             startElement = 0;
27955
             elementCount = UnsignedCeilDivide(instanceCount, binding.getDivisor());
27956
         }
27957
+        size_t bytesIntendedToUse = (startElement + elementCount) * binding.getStride();
27958
+
27959
+        const mtl::VertexFormat &format = contextMtl->getVertexFormat(attrib.format->id, false);
27960
+        bool needStreaming              = format.actualFormatId != format.intendedFormatId ||
27961
+                             (binding.getStride() % mtl::kVertexAttribBufferStrideAlignment) != 0 ||
27962
+                             (binding.getStride() < format.actualAngleFormat().pixelBytes) ||
27963
+                             bytesIntendedToUse > mInlineDataMaxSize;
27964
+
27965
+        if (!needStreaming)
27966
+        {
27967
+            // Data will be uploaded directly as inline constant data
27968
+            mCurrentArrayBuffers[attribIndex]            = nullptr;
27969
+            mCurrentArrayInlineDataPointers[attribIndex] = src;
27970
+            mCurrentArrayInlineDataSizes[attribIndex]    = bytesIntendedToUse;
27971
+            mCurrentArrayBufferOffsets[attribIndex]      = 0;
27972
+            mCurrentArrayBufferFormats[attribIndex]      = &format;
27973
+            mCurrentArrayBufferStrides[attribIndex]      = binding.getStride();
27974
+        }
27975
+        else
27976
+        {
27977
+            GLuint convertedStride;
27978
+            // Need to stream the client vertex data to a buffer.
27979
+            const mtl::VertexFormat &streamFormat =
27980
+                GetVertexConversionFormat(contextMtl, attrib.format->id, &convertedStride);
27981
+
27982
             // Allocate space for startElement + elementCount so indexing will work.  If we don't
27983
             // start at zero all the indices will be off.
27984
             // Only elementCount vertices will be used by the upcoming draw so that is all we copy.
27985
-        size_t bytesToAllocate = (startElement + elementCount) * stride;
27986
+            size_t bytesToAllocate = (startElement + elementCount) * convertedStride;
27987
             src += startElement * binding.getStride();
27988
-        size_t destOffset = startElement * stride;
27989
+            size_t destOffset = startElement * convertedStride;
27990
 
27991
-        mDynamicVertexData.updateAlignment(contextMtl, vertexFormat.actualAngleFormat().pixelBytes);
27992
-        ANGLE_TRY(StreamVertexData(
27993
-            contextMtl, &mDynamicVertexData, src, bytesToAllocate, destOffset, elementCount,
27994
-            binding.getStride(), vertexFormat.vertexLoadFunction,
27995
-            &mConvertedArrayBufferHolders[attribIndex], &mCurrentArrayBufferOffsets[attribIndex]));
27996
+            mCurrentArrayBufferFormats[attribIndex] = &streamFormat;
27997
+            mCurrentArrayBufferStrides[attribIndex] = convertedStride;
27998
+
27999
+            if (bytesToAllocate <= mInlineDataMaxSize)
28000
+            {
28001
+                // If the data is small enough, use host memory instead of creating GPU buffer. To
28002
+                // avoid synchronizing access to GPU buffer that is still in use.
28003
+                angle::MemoryBuffer &convertedClientArray =
28004
+                    mConvertedClientSmallArrays[attribIndex];
28005
+                if (bytesToAllocate > convertedClientArray.size())
28006
+                {
28007
+                    ANGLE_CHECK_GL_ALLOC(contextMtl, convertedClientArray.resize(bytesToAllocate));
28008
+                }
28009
+
28010
+                ASSERT(streamFormat.vertexLoadFunction);
28011
+                streamFormat.vertexLoadFunction(src, binding.getStride(), elementCount,
28012
+                                                convertedClientArray.data() + destOffset);
28013
+
28014
+                mCurrentArrayBuffers[attribIndex]            = nullptr;
28015
+                mCurrentArrayInlineDataPointers[attribIndex] = convertedClientArray.data();
28016
+                mCurrentArrayInlineDataSizes[attribIndex]    = bytesToAllocate;
28017
+                mCurrentArrayBufferOffsets[attribIndex]      = 0;
28018
+            }
28019
+            else
28020
+            {
28021
+                // Stream the client data to a GPU buffer. Synchronization might happen if buffer is
28022
+                // in use.
28023
+                mDynamicVertexData.updateAlignment(contextMtl,
28024
+                                                   streamFormat.actualAngleFormat().pixelBytes);
28025
+                ANGLE_TRY(StreamVertexData(contextMtl, &mDynamicVertexData, src, bytesToAllocate,
28026
+                                           destOffset, elementCount, binding.getStride(),
28027
+                                           streamFormat.vertexLoadFunction,
28028
+                                           &mConvertedArrayBufferHolders[attribIndex],
28029
+                                           &mCurrentArrayBufferOffsets[attribIndex]));
28030
 
28031
                 mCurrentArrayBuffers[attribIndex] = &mConvertedArrayBufferHolders[attribIndex];
28032
-        mCurrentArrayBufferFormats[attribIndex] = &vertexFormat;
28033
-        mCurrentArrayBufferStrides[attribIndex] = stride;
28034
+            }
28035
+        }  // if (needStreaming)
28036
     }
28037
 
28038
     mVertexArrayDirty = true;
28039
@@ -526,7 +661,7 @@ inline void SetDefaultVertexBufferLayout(mtl::VertexBufferLayoutDesc *layout)
28040
             bool needConversion =
28041
                 format.actualFormatId != format.intendedFormatId ||
28042
                 (binding.getOffset() % format.actualAngleFormat().pixelBytes) != 0 ||
28043
-                (binding.getOffset() % mtl::kVertexAttribBufferStrideAlignment) != 0 ||
28044
+                (binding.getOffset() % 4) != 0 ||
28045
                 (binding.getStride() < format.actualAngleFormat().pixelBytes) ||
28046
                 (binding.getStride() % mtl::kVertexAttribBufferStrideAlignment) != 0;
28047
 
28048
@@ -563,19 +698,21 @@ inline void SetDefaultVertexBufferLayout(mtl::VertexBufferLayoutDesc *layout)
28049
 
28050
 angle::Result VertexArrayMtl::getIndexBuffer(const gl::Context *context,
28051
                                              gl::DrawElementsType type,
28052
+                                             gl::PrimitiveMode mode,
28053
                                              size_t count,
28054
                                              const void *indices,
28055
                                              mtl::BufferRef *idxBufferOut,
28056
                                              size_t *idxBufferOffsetOut,
28057
-                                             gl::DrawElementsType *indexTypeOut)
28058
+                                             gl::DrawElementsType *indexTypeOut,
28059
+                                             size_t *indexBufferCountOut)
28060
 {
28061
     const gl::Buffer *glElementArrayBuffer = getState().getElementArrayBuffer();
28062
 
28063
     size_t convertedOffset = reinterpret_cast<size_t>(indices);
28064
     if (!glElementArrayBuffer)
28065
     {
28066
-        ANGLE_TRY(streamIndexBufferFromClient(context, type, count, indices, idxBufferOut,
28067
-                                              idxBufferOffsetOut));
28068
+        ANGLE_TRY(streamIndexBufferFromClient(context, type, mode, count, indices, idxBufferOut,
28069
+                                              idxBufferOffsetOut, indexBufferCountOut));
28070
     }
28071
     else
28072
     {
28073
@@ -583,8 +720,8 @@ inline void SetDefaultVertexBufferLayout(mtl::VertexBufferLayoutDesc *layout)
28074
                               (convertedOffset % mtl::kIndexBufferOffsetAlignment) != 0;
28075
         if (needConversion)
28076
         {
28077
-            ANGLE_TRY(convertIndexBuffer(context, type, convertedOffset, idxBufferOut,
28078
-                                         idxBufferOffsetOut));
28079
+            ANGLE_TRY(convertIndexBuffer(context, type, mode, convertedOffset, idxBufferOut,
28080
+                                         idxBufferOffsetOut, indexBufferCountOut));
28081
         }
28082
         else
28083
         {
28084
@@ -592,6 +729,7 @@ inline void SetDefaultVertexBufferLayout(mtl::VertexBufferLayoutDesc *layout)
28085
             BufferMtl *bufferMtl = mtl::GetImpl(glElementArrayBuffer);
28086
             *idxBufferOut        = bufferMtl->getCurrentBuffer();
28087
             *idxBufferOffsetOut  = convertedOffset;
28088
+            *indexBufferCountOut = count;
28089
         }
28090
     }
28091
 
28092
@@ -607,9 +745,11 @@ inline void SetDefaultVertexBufferLayout(mtl::VertexBufferLayoutDesc *layout)
28093
 
28094
 angle::Result VertexArrayMtl::convertIndexBuffer(const gl::Context *glContext,
28095
                                                  gl::DrawElementsType indexType,
28096
+                                                 gl::PrimitiveMode mode,
28097
                                                  size_t offset,
28098
                                                  mtl::BufferRef *idxBufferOut,
28099
-                                                 size_t *idxBufferOffsetOut)
28100
+                                                 size_t *idxBufferOffsetOut,
28101
+                                                 size_t *indexBufferCountOut)
28102
 {
28103
     size_t offsetModulo = offset % mtl::kIndexBufferOffsetAlignment;
28104
     ASSERT(offsetModulo != 0 || indexType == gl::DrawElementsType::UnsignedByte);
28105
@@ -638,15 +778,15 @@ inline void SetDefaultVertexBufferLayout(mtl::VertexBufferLayoutDesc *layout)
28106
     }
28107
 
28108
     size_t indexCount = GetIndexCount(idxBuffer, offsetModulo, indexType);
28109
-
28110
-    if (!contextMtl->getDisplay()->getFeatures().hasCheapRenderPass.enabled &&
28111
-        contextMtl->getRenderCommandEncoder())
28112
+    if ((!contextMtl->getDisplay()->getFeatures().breakRenderPassIsCheap.enabled &&
28113
+         contextMtl->getRenderCommandEncoder()))
28114
     {
28115
         // We shouldn't use GPU to convert when we are in a middle of a render pass.
28116
         ANGLE_TRY(StreamIndexData(contextMtl, &conversion->data,
28117
                                   idxBuffer->getClientShadowCopyData(contextMtl) + offsetModulo,
28118
-                                  indexType, indexCount, glState.isPrimitiveRestartEnabled(),
28119
-                                  &conversion->convertedBuffer, &conversion->convertedOffset));
28120
+                                  indexType, indexCount, mode, glState.isPrimitiveRestartEnabled(),
28121
+                                  &conversion->convertedBuffer, &conversion->convertedOffset,
28122
+                                  indexBufferCountOut));
28123
     }
28124
     else
28125
     {
28126
@@ -695,18 +835,20 @@ inline void SetDefaultVertexBufferLayout(mtl::VertexBufferLayoutDesc *layout)
28127
 
28128
 angle::Result VertexArrayMtl::streamIndexBufferFromClient(const gl::Context *context,
28129
                                                           gl::DrawElementsType indexType,
28130
+                                                          gl::PrimitiveMode mode,
28131
                                                           size_t indexCount,
28132
                                                           const void *sourcePointer,
28133
                                                           mtl::BufferRef *idxBufferOut,
28134
-                                                          size_t *idxBufferOffsetOut)
28135
+                                                          size_t *idxBufferOffsetOut,
28136
+                                                          size_t *idxBufferCountOut)
28137
 {
28138
     ASSERT(getState().getElementArrayBuffer() == nullptr);
28139
     ContextMtl *contextMtl = mtl::GetImpl(context);
28140
 
28141
     auto srcData = static_cast<const uint8_t *>(sourcePointer);
28142
-    ANGLE_TRY(StreamIndexData(contextMtl, &mDynamicIndexData, srcData, indexType, indexCount,
28143
+    ANGLE_TRY(StreamIndexData(contextMtl, &mDynamicIndexData, srcData, indexType, indexCount, mode,
28144
                               context->getState().isPrimitiveRestartEnabled(), idxBufferOut,
28145
-                              idxBufferOffsetOut));
28146
+                              idxBufferOffsetOut, idxBufferCountOut));
28147
 
28148
     return angle::Result::Continue;
28149
 }
28150
@@ -744,7 +886,6 @@ inline void SetDefaultVertexBufferLayout(mtl::VertexBufferLayoutDesc *layout)
28151
     // Has the content of the buffer has changed since last conversion?
28152
     if (!conversion->dirty)
28153
     {
28154
-        // Buffer's data hasn't been changed. Re-use last converted results
28155
         mConvertedArrayBufferHolders[attribIndex].set(conversion->convertedBuffer);
28156
         mCurrentArrayBufferOffsets[attribIndex] = conversion->convertedOffset;
28157
 
28158
@@ -761,7 +902,7 @@ inline void SetDefaultVertexBufferLayout(mtl::VertexBufferLayoutDesc *layout)
28159
     bool canExpandComponentsOnGPU = convertedFormat.actualSameGLType;
28160
 
28161
     if (contextMtl->getRenderCommandEncoder() &&
28162
-        !contextMtl->getDisplay()->getFeatures().hasCheapRenderPass.enabled &&
28163
+        !contextMtl->getDisplay()->getFeatures().breakRenderPassIsCheap.enabled &&
28164
         !contextMtl->getDisplay()->getFeatures().hasExplicitMemBarrier.enabled)
28165
     {
28166
         // Cannot use GPU to convert when we are in a middle of a render pass.
28167
@@ -792,6 +933,9 @@ inline void SetDefaultVertexBufferLayout(mtl::VertexBufferLayoutDesc *layout)
28168
     conversion->convertedBuffer = mConvertedArrayBufferHolders[attribIndex].getCurrentBuffer();
28169
     conversion->convertedOffset = mCurrentArrayBufferOffsets[attribIndex];
28170
 
28171
+    ASSERT(conversion->dirty);
28172
+    conversion->dirty = false;
28173
+
28174
 #ifndef NDEBUG
28175
     ANGLE_MTL_OBJC_SCOPE
28176
     {
28177
@@ -801,9 +945,6 @@ inline void SetDefaultVertexBufferLayout(mtl::VertexBufferLayoutDesc *layout)
28178
     }
28179
 #endif
28180
 
28181
-    ASSERT(conversion->dirty);
28182
-    conversion->dirty = false;
28183
-
28184
     return angle::Result::Continue;
28185
 }
28186
 
28187
diff --git a/src/libANGLE/renderer/metal/doc/APPLE_clip_distance.md b/src/libANGLE/renderer/metal/doc/APPLE_clip_distance.md
28188
index fa073ae..13afdc3 100644
28189
--- a/src/libANGLE/renderer/metal/doc/APPLE_clip_distance.md
28190
+++ b/src/libANGLE/renderer/metal/doc/APPLE_clip_distance.md
28191
@@ -6,6 +6,31 @@ level side. Writing to `gl_ClipDistance[i]` in shader will be ignored if it is d
28192
 doesn't have any equivalent API to disable/enable the writing, though writing to a `clip_distance`
28193
 variable automatically enables it.
28194
 
28195
-To emulate this enabling/disabling API, the Metal back-end uses a similar implementation as what
28196
-[Vulkan back-end does](../../vulkan/doc/APPLE_clip_distance.md). Please refer to that document for
28197
-more details.
28198
+To implement this enabling/disabling API in Metal back-end:
28199
+
28200
+- The shader compiler will translate each `gl_ClipDistance[i]` assignment to an assignment to
28201
+  `ANGLEClipDistance[i]` variable.
28202
+- A special driver uniform variable `clipDistancesEnabled` will contain one bit flag for each
28203
+  enabled `gl_ClipDistance[i]`. This variable supports up to 32 `gl_ClipDistance` indices.
28204
+- At the end of vertex shader, the enabled `gl_ClipDistance[i]` will be assigned the respective
28205
+  value from `ANGLEClipDistance[i]`. On the other hand, those disabled elements will be assigned
28206
+  zero value. This step is described in the following code:
28207
+    ```
28208
+    for (int index : arraylength(gl_ClipDistance))
28209
+    {
28210
+        if (ANGLEUniforms.clipDistancesEnabled & (0x1 << index))
28211
+            gl_ClipDistance[index] = ANGLEClipDistance[index];
28212
+        else
28213
+            gl_ClipDistance[index] = 0;
28214
+    }
28215
+    ```
28216
+- Some minor optimizations:
28217
+    - Only those indices that are referenced in the original code will be used in if else block
28218
+      above.
28219
+    - Those elements whose index not referenced in the original code will be zeroised instead.
28220
+    - If the original code only uses up to an index < `gl_MaxClipDistances`, then
28221
+      the loop will have at most `index+1` iterations. If there is at least one index not being
28222
+      integral constant value known at compile time then declared size of `gl_ClipDistance`
28223
+      will be the loop size.
28224
+    - Finally, if the original code doesn't use `gl_ClipDistance`, then all the steps above will be
28225
+      omitted.
28226
\ No newline at end of file
28227
diff --git a/src/libANGLE/renderer/metal/gen_mtl_format_table.py b/src/libANGLE/renderer/metal/gen_mtl_format_table.py
28228
index 3ce142e..6eab409 100644
28229
--- a/src/libANGLE/renderer/metal/gen_mtl_format_table.py
28230
+++ b/src/libANGLE/renderer/metal/gen_mtl_format_table.py
28231
@@ -48,7 +48,6 @@ namespace mtl
28232
 void Format::init(const DisplayMtl *display, angle::FormatID intendedFormatId_)
28233
 {{
28234
     this->intendedFormatId = intendedFormatId_;
28235
-
28236
     id<MTLDevice> metalDevice = display->getMetalDevice();
28237
 
28238
     // Actual conversion
28239
@@ -109,6 +108,23 @@ image_format_assign_template2 = """
28240
                 this->initFunction = {init_function_fallback};
28241
             }}
28242
 """
28243
+#D16 is fully supported on  Apple3+. However, on
28244
+#previous  versions of Apple hardware, some operations can cause
28245
+#undefined behavior.
28246
+image_format_assign_template3 = """
28247
+            if ([metalDevice supportsFamily:MTLGPUFamilyApple3])
28248
+            {{
28249
+                this->metalFormat = {mtl_format};
28250
+                this->actualFormatId = angle::FormatID::{actual_angle_format};
28251
+                this->initFunction = {init_function};
28252
+            }}
28253
+            else
28254
+            {{
28255
+                this->metalFormat = {mtl_format_fallback};
28256
+                this->actualFormatId = angle::FormatID::{actual_angle_format_fallback};
28257
+                this->initFunction = {init_function_fallback};
28258
+            }}
28259
+"""
28260
 
28261
 case_image_format_template1 = """        case angle::FormatID::{angle_format}:
28262
             {image_format_assign}
28263
@@ -213,6 +229,8 @@ def get_vertex_copy_function_and_default_alpha(src_format, dst_format):
28264
 
28265
 
28266
 # Generate format conversion switch case (generic case)
28267
+
28268
+
28269
 def gen_image_map_switch_case(angle_format, actual_angle_format_info, angle_to_mtl_map,
28270
                               assign_gen_func):
28271
     if isinstance(actual_angle_format_info, dict):
28272
@@ -255,6 +273,8 @@ def gen_image_map_switch_case(angle_format, actual_angle_format_info, angle_to_m
28273
 
28274
 
28275
 # Generate format conversion switch case (simple case)
28276
+
28277
+
28278
 def gen_image_map_switch_simple_case(angle_format, actual_angle_format_info, angle_to_gl,
28279
                                      angle_to_mtl_map):
28280
 
28281
@@ -270,6 +290,8 @@ def gen_image_map_switch_simple_case(angle_format, actual_angle_format_info, ang
28282
 
28283
 
28284
 # Generate format conversion switch case (Mac case)
28285
+
28286
+
28287
 def gen_image_map_switch_mac_case(angle_format, actual_angle_format_info, angle_to_gl,
28288
                                   angle_to_mtl_map, mac_fallbacks):
28289
     gl_format = angle_to_gl[angle_format]
28290
@@ -301,11 +323,43 @@ def gen_image_map_switch_mac_case(angle_format, actual_angle_format_info, angle_
28291
                                      gen_format_assign_code)
28292
 
28293
 
28294
+def gen_image_map_switch_ios_case(angle_format, actual_angle_format_info, angle_to_gl,
28295
+                                  angle_to_mtl_map, ios_fallbacks):
28296
+    gl_format = angle_to_gl[angle_format]
28297
+
28298
+    def gen_format_assign_code(actual_angle_format, angle_to_mtl_map):
28299
+        if actual_angle_format in ios_fallbacks:
28300
+            # This format (Depth16Uniform) requires fallback when iOS hardware does not fully support depth16.
28301
+            # Fallback format:
28302
+            actual_angle_format_fallback = ios_fallbacks[actual_angle_format]
28303
+            # return if else block:
28304
+            return image_format_assign_template3.format(
28305
+                actual_angle_format=actual_angle_format,
28306
+                mtl_format=angle_to_mtl_map[actual_angle_format],
28307
+                init_function=angle_format_utils.get_internal_format_initializer(
28308
+                    gl_format, actual_angle_format),
28309
+                actual_angle_format_fallback=actual_angle_format_fallback,
28310
+                mtl_format_fallback=angle_to_mtl_map[actual_angle_format_fallback],
28311
+                init_function_fallback=angle_format_utils.get_internal_format_initializer(
28312
+                    gl_format, actual_angle_format_fallback))
28313
+        else:
28314
+            # return ordinary block:
28315
+            return image_format_assign_template1.format(
28316
+                actual_angle_format=actual_angle_format,
28317
+                mtl_format=angle_to_mtl_map[actual_angle_format],
28318
+                init_function=angle_format_utils.get_internal_format_initializer(
28319
+                    gl_format, actual_angle_format))
28320
+
28321
+    return gen_image_map_switch_case(angle_format, actual_angle_format_info, angle_to_mtl_map,
28322
+                                     gen_format_assign_code)
28323
+
28324
+
28325
 def gen_image_map_switch_string(image_table, angle_to_gl):
28326
     angle_override = image_table["override"]
28327
     mac_override = image_table["override_mac"]
28328
     ios_override = image_table["override_ios"]
28329
-    mac_fallbacks = image_table["d24s8_fallbacks_mac"]
28330
+    mac_fallbacks = image_table["fallbacks_mac"]
28331
+    ios_fallbacks = image_table["fallbacks_ios"]
28332
     angle_to_mtl = image_table["map"]
28333
     mac_specific_map = image_table["map_mac"]
28334
     ios_specific_map = image_table["map_ios"]
28335
@@ -322,8 +376,8 @@ def gen_image_map_switch_string(image_table, angle_to_gl):
28336
     def gen_image_map_switch_common_case(angle_format, actual_angle_format):
28337
         mac_case = gen_image_map_switch_mac_case(angle_format, actual_angle_format, angle_to_gl,
28338
                                                  mac_angle_to_mtl, mac_fallbacks)
28339
-        non_mac_case = gen_image_map_switch_simple_case(angle_format, actual_angle_format,
28340
-                                                        angle_to_gl, angle_to_mtl)
28341
+        non_mac_case = gen_image_map_switch_ios_case(angle_format, actual_angle_format,
28342
+                                                     angle_to_gl, angle_to_mtl, ios_fallbacks)
28343
         if mac_case == non_mac_case:
28344
             return mac_case
28345
 
28346
diff --git a/src/libANGLE/renderer/metal/mtl_buffer_pool.h b/src/libANGLE/renderer/metal/mtl_buffer_pool.h
28347
index 2079fd7..204ebb9 100644
28348
--- a/src/libANGLE/renderer/metal/mtl_buffer_pool.h
28349
+++ b/src/libANGLE/renderer/metal/mtl_buffer_pool.h
28350
@@ -81,7 +81,7 @@ class BufferPool
28351
                            bool *newBufferAllocatedOut = nullptr);
28352
 
28353
     // After a sequence of CPU writes, call commit to ensure the data is visible to the device.
28354
-    angle::Result commit(ContextMtl *contextMtl);
28355
+    angle::Result commit(ContextMtl *contextMtl, bool flushEntireBuffer = false);
28356
 
28357
     // This releases all the buffers that have been allocated since this was last called.
28358
     void releaseInFlightBuffers(ContextMtl *contextMtl);
28359
@@ -114,7 +114,6 @@ class BufferPool
28360
     angle::Result allocateNewBuffer(ContextMtl *contextMtl);
28361
     void destroyBufferList(ContextMtl *contextMtl, std::deque<BufferRef> *buffers);
28362
     angle::Result finalizePendingBuffer(ContextMtl *contextMtl);
28363
-
28364
     size_t mInitialSize;
28365
     BufferRef mBuffer;
28366
     uint32_t mNextAllocationOffset;
28367
@@ -127,7 +126,7 @@ class BufferPool
28368
 
28369
     size_t mBuffersAllocated;
28370
     size_t mMaxBuffers;
28371
-    BufferPoolMemPolicy mMemPolicy;
28372
+    BufferPoolMemPolicy mMemPolicy = BufferPoolMemPolicy::Auto;
28373
     bool mAlwaysAllocateNewBuffer;
28374
 };
28375
 
28376
diff --git a/src/libANGLE/renderer/metal/mtl_buffer_pool.mm b/src/libANGLE/renderer/metal/mtl_buffer_pool.mm
28377
index 04238ef..a58b5a5 100644
28378
--- a/src/libANGLE/renderer/metal/mtl_buffer_pool.mm
28379
+++ b/src/libANGLE/renderer/metal/mtl_buffer_pool.mm
28380
@@ -250,11 +250,18 @@
28381
     return angle::Result::Continue;
28382
 }
28383
 
28384
-angle::Result BufferPool::commit(ContextMtl *contextMtl)
28385
+angle::Result BufferPool::commit(ContextMtl *contextMtl, bool flushEntireBuffer)
28386
 {
28387
     if (mBuffer && mNextAllocationOffset > mLastFlushOffset)
28388
+    {
28389
+        if (flushEntireBuffer)
28390
+        {
28391
+            mBuffer->flush(contextMtl, 0, mLastFlushOffset);
28392
+        }
28393
+        else
28394
         {
28395
             mBuffer->flush(contextMtl, mLastFlushOffset, mNextAllocationOffset - mLastFlushOffset);
28396
+        }
28397
         mLastFlushOffset = mNextAllocationOffset;
28398
     }
28399
     return angle::Result::Continue;
28400
diff --git a/src/libANGLE/renderer/metal/mtl_command_buffer.h b/src/libANGLE/renderer/metal/mtl_command_buffer.h
28401
index 55ff649..3aa826a 100644
28402
--- a/src/libANGLE/renderer/metal/mtl_command_buffer.h
28403
+++ b/src/libANGLE/renderer/metal/mtl_command_buffer.h
28404
@@ -102,7 +102,7 @@ class CommandBuffer final : public WrappedObject<id<MTLCommandBuffer>>, angle::N
28405
 
28406
     // Return true if command buffer can be encoded into. Return false if it has been committed
28407
     // and hasn't been restarted.
28408
-    bool ready() const;
28409
+    bool valid() const;
28410
     void commit();
28411
     // wait for committed command buffer to finish.
28412
     void finish();
28413
@@ -115,6 +115,8 @@ class CommandBuffer final : public WrappedObject<id<MTLCommandBuffer>>, angle::N
28414
 
28415
     void queueEventSignal(const mtl::SharedEventRef &event, uint64_t value);
28416
     void serverWaitEvent(const mtl::SharedEventRef &event, uint64_t value);
28417
+
28418
+    void insertDebugSign(const std::string &marker);
28419
     void pushDebugGroup(const std::string &marker);
28420
     void popDebugGroup();
28421
 
28422
@@ -128,7 +130,7 @@ class CommandBuffer final : public WrappedObject<id<MTLCommandBuffer>>, angle::N
28423
     void set(id<MTLCommandBuffer> metalBuffer);
28424
     void cleanup();
28425
 
28426
-    bool readyImpl() const;
28427
+    bool validImpl() const;
28428
     void commitImpl();
28429
     void forceEndingCurrentEncoder();
28430
 
28431
@@ -149,6 +151,7 @@ class CommandBuffer final : public WrappedObject<id<MTLCommandBuffer>>, angle::N
28432
 
28433
     mutable std::mutex mLock;
28434
 
28435
+    std::vector<std::string> mPendingDebugSigns;
28436
     std::vector<std::pair<mtl::SharedEventRef, uint64_t>> mPendingSignalEvents;
28437
 
28438
     std::vector<std::string> mDebugGroups;
28439
@@ -176,6 +179,8 @@ class CommandEncoder : public WrappedObject<id<MTLCommandEncoder>>, angle::NonCo
28440
     CommandEncoder &markResourceBeingWrittenByGPU(const BufferRef &buffer);
28441
     CommandEncoder &markResourceBeingWrittenByGPU(const TextureRef &texture);
28442
 
28443
+    void insertDebugSign(NSString *label);
28444
+
28445
     virtual void pushDebugGroup(NSString *label);
28446
     virtual void popDebugGroup();
28447
 
28448
@@ -189,6 +194,8 @@ class CommandEncoder : public WrappedObject<id<MTLCommandEncoder>>, angle::NonCo
28449
 
28450
     void set(id<MTLCommandEncoder> metalCmdEncoder);
28451
 
28452
+    virtual void insertDebugSignImpl(NSString *marker);
28453
+
28454
   private:
28455
     const Type mType;
28456
     CommandBuffer &mCmdBuffer;
28457
@@ -201,7 +208,7 @@ class IntermediateCommandStream
28458
     template <typename T>
28459
     inline IntermediateCommandStream &push(const T &val)
28460
     {
28461
-        const uint8_t *ptr = reinterpret_cast<const uint8_t *>(&val);
28462
+        auto ptr = reinterpret_cast<const uint8_t *>(&val);
28463
         mBuffer.insert(mBuffer.end(), ptr, ptr + sizeof(T));
28464
         return *this;
28465
     }
28466
@@ -217,7 +224,7 @@ class IntermediateCommandStream
28467
     {
28468
         ASSERT(mReadPtr <= mBuffer.size() - sizeof(T));
28469
         T re;
28470
-        uint8_t *ptr = reinterpret_cast<uint8_t *>(&re);
28471
+        auto ptr = reinterpret_cast<uint8_t *>(&re);
28472
         std::copy(mBuffer.data() + mReadPtr, mBuffer.data() + mReadPtr + sizeof(T), ptr);
28473
         return re;
28474
     }
28475
@@ -225,7 +232,7 @@ class IntermediateCommandStream
28476
     template <typename T>
28477
     inline T fetch()
28478
     {
28479
-        T re = peek<T>();
28480
+        auto re = peek<T>();
28481
         mReadPtr += sizeof(T);
28482
         return re;
28483
     }
28484
@@ -233,7 +240,7 @@ class IntermediateCommandStream
28485
     inline const uint8_t *fetch(size_t bytes)
28486
     {
28487
         ASSERT(mReadPtr <= mBuffer.size() - bytes);
28488
-        size_t cur = mReadPtr;
28489
+        auto cur = mReadPtr;
28490
         mReadPtr += bytes;
28491
         return mBuffer.data() + cur;
28492
     }
28493
@@ -479,12 +486,16 @@ class RenderCommandEncoder final : public CommandEncoder
28494
     {
28495
         return static_cast<id<MTLRenderCommandEncoder>>(CommandEncoder::get());
28496
     }
28497
+    void insertDebugSignImpl(NSString *label) override;
28498
 
28499
     void initAttachmentWriteDependencyAndScissorRect(const RenderPassAttachmentDesc &attachment);
28500
+    void initWriteDependency(const TextureRef &texture);
28501
 
28502
     void finalizeLoadStoreAction(MTLRenderPassAttachmentDescriptor *objCRenderPassAttachment);
28503
 
28504
     void encodeMetalEncoder();
28505
+    void simulateDiscardFramebuffer();
28506
+    void endEncodingImpl(bool considerDiscardSimulation);
28507
 
28508
     RenderCommandEncoder &commonSetBuffer(gl::ShaderType shaderType,
28509
                                           id<MTLBuffer> mtlBuffer,
28510
@@ -560,11 +571,20 @@ class BlitCommandEncoder final : public CommandEncoder
28511
                                     uint32_t sliceCount,
28512
                                     uint32_t levelCount);
28513
 
28514
+    BlitCommandEncoder &copyTexture(const TextureRef &src,
28515
+                                    uint32_t srcSlice,
28516
+                                    uint32_t srcLevel,
28517
+                                    const TextureRef &dst,
28518
+                                    uint32_t dstSlice,
28519
+                                    uint32_t dstLevel,
28520
+                                    uint32_t sliceCount,
28521
+                                    uint32_t levelCount);
28522
+
28523
     BlitCommandEncoder &fillBuffer(const BufferRef &buffer, NSRange range, uint8_t value);
28524
 
28525
     BlitCommandEncoder &generateMipmapsForTexture(const TextureRef &texture);
28526
-    BlitCommandEncoder &synchronizeResource(Buffer *bufferPtr);
28527
-    BlitCommandEncoder &synchronizeResource(Texture *texturePtr);
28528
+    BlitCommandEncoder &synchronizeResource(const BufferRef &buffer);
28529
+    BlitCommandEncoder &synchronizeResource(const TextureRef &texture);
28530
 
28531
   private:
28532
     id<MTLBlitCommandEncoder> get()
28533
diff --git a/src/libANGLE/renderer/metal/mtl_command_buffer.mm b/src/libANGLE/renderer/metal/mtl_command_buffer.mm
28534
index 4433b02..b4a3347 100644
28535
--- a/src/libANGLE/renderer/metal/mtl_command_buffer.mm
28536
+++ b/src/libANGLE/renderer/metal/mtl_command_buffer.mm
28537
@@ -11,6 +11,9 @@
28538
 #include "libANGLE/renderer/metal/mtl_command_buffer.h"
28539
 
28540
 #include <cassert>
28541
+#if ANGLE_MTL_SIMULATE_DISCARD_FRAMEBUFFER
28542
+#    include <random>
28543
+#endif
28544
 
28545
 #include "common/debug.h"
28546
 #include "libANGLE/renderer/metal/mtl_occlusion_query_pool.h"
28547
@@ -65,6 +68,7 @@
28548
     PROC(SetVisibilityResultMode)        \
28549
     PROC(UseResource)                    \
28550
     PROC(MemoryBarrierWithResource)      \
28551
+    PROC(InsertDebugsign)                \
28552
     PROC(PushDebugGroup)                 \
28553
     PROC(PopDebugGroup)
28554
 
28555
@@ -85,42 +89,42 @@ void InvalidCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *
28556
 void SetRenderPipelineStateCmd(id<MTLRenderCommandEncoder> encoder,
28557
                                IntermediateCommandStream *stream)
28558
 {
28559
-    id<MTLRenderPipelineState> state = stream->fetch<id<MTLRenderPipelineState>>();
28560
+    auto state = stream->fetch<id<MTLRenderPipelineState>>();
28561
     [encoder setRenderPipelineState:state];
28562
     [state ANGLE_MTL_RELEASE];
28563
 }
28564
 
28565
 void SetTriangleFillModeCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
28566
 {
28567
-    MTLTriangleFillMode mode = stream->fetch<MTLTriangleFillMode>();
28568
+    auto mode = stream->fetch<MTLTriangleFillMode>();
28569
     [encoder setTriangleFillMode:mode];
28570
 }
28571
 
28572
 void SetFrontFacingWindingCmd(id<MTLRenderCommandEncoder> encoder,
28573
                               IntermediateCommandStream *stream)
28574
 {
28575
-    MTLWinding winding = stream->fetch<MTLWinding>();
28576
+    auto winding = stream->fetch<MTLWinding>();
28577
     [encoder setFrontFacingWinding:winding];
28578
 }
28579
 
28580
 void SetCullModeCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
28581
 {
28582
-    MTLCullMode mode = stream->fetch<MTLCullMode>();
28583
+    auto mode = stream->fetch<MTLCullMode>();
28584
     [encoder setCullMode:mode];
28585
 }
28586
 
28587
 void SetDepthStencilStateCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
28588
 {
28589
-    id<MTLDepthStencilState> state = stream->fetch<id<MTLDepthStencilState>>();
28590
+    auto state = stream->fetch<id<MTLDepthStencilState>>();
28591
     [encoder setDepthStencilState:state];
28592
     [state ANGLE_MTL_RELEASE];
28593
 }
28594
 
28595
 void SetDepthBiasCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
28596
 {
28597
-    float depthBias  = stream->fetch<float>();
28598
-    float slopeScale = stream->fetch<float>();
28599
-    float clamp      = stream->fetch<float>();
28600
+    auto depthBias  = stream->fetch<float>();
28601
+    auto slopeScale = stream->fetch<float>();
28602
+    auto clamp      = stream->fetch<float>();
28603
     [encoder setDepthBias:depthBias slopeScale:slopeScale clamp:clamp];
28604
 }
28605
 
28606
@@ -134,13 +138,13 @@ void SetStencilRefValsCmd(id<MTLRenderCommandEncoder> encoder, IntermediateComma
28607
 
28608
 void SetViewportCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
28609
 {
28610
-    MTLViewport viewport = stream->fetch<MTLViewport>();
28611
+    auto viewport = stream->fetch<MTLViewport>();
28612
     [encoder setViewport:viewport];
28613
 }
28614
 
28615
 void SetScissorRectCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
28616
 {
28617
-    MTLScissorRect rect = stream->fetch<MTLScissorRect>();
28618
+    auto rect = stream->fetch<MTLScissorRect>();
28619
     [encoder setScissorRect:rect];
28620
 }
28621
 
28622
@@ -155,9 +159,9 @@ void SetBlendColorCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
28623
 
28624
 void SetVertexBufferCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
28625
 {
28626
-    id<MTLBuffer> buffer = stream->fetch<id<MTLBuffer>>();
28627
-    uint32_t offset      = stream->fetch<uint32_t>();
28628
-    uint32_t index       = stream->fetch<uint32_t>();
28629
+    auto buffer = stream->fetch<id<MTLBuffer>>();
28630
+    auto offset = stream->fetch<uint32_t>();
28631
+    auto index  = stream->fetch<uint32_t>();
28632
     [encoder setVertexBuffer:buffer offset:offset atIndex:index];
28633
     [buffer ANGLE_MTL_RELEASE];
28634
 }
28635
@@ -165,26 +169,26 @@ void SetVertexBufferCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommand
28636
 void SetVertexBufferOffsetCmd(id<MTLRenderCommandEncoder> encoder,
28637
                               IntermediateCommandStream *stream)
28638
 {
28639
-    uint32_t offset = stream->fetch<uint32_t>();
28640
-    uint32_t index  = stream->fetch<uint32_t>();
28641
+    auto offset = stream->fetch<uint32_t>();
28642
+    auto index  = stream->fetch<uint32_t>();
28643
     [encoder setVertexBufferOffset:offset atIndex:index];
28644
 }
28645
 
28646
 void SetVertexBytesCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
28647
 {
28648
-    size_t size          = stream->fetch<size_t>();
28649
-    const uint8_t *bytes = stream->fetch(size);
28650
-    uint32_t index       = stream->fetch<uint32_t>();
28651
+    auto size  = stream->fetch<size_t>();
28652
+    auto bytes = stream->fetch(size);
28653
+    auto index = stream->fetch<uint32_t>();
28654
     [encoder setVertexBytes:bytes length:size atIndex:index];
28655
 }
28656
 
28657
 void SetVertexSamplerStateCmd(id<MTLRenderCommandEncoder> encoder,
28658
                               IntermediateCommandStream *stream)
28659
 {
28660
-    id<MTLSamplerState> state = stream->fetch<id<MTLSamplerState>>();
28661
+    auto state        = stream->fetch<id<MTLSamplerState>>();
28662
     float lodMinClamp = stream->fetch<float>();
28663
     float lodMaxClamp = stream->fetch<float>();
28664
-    uint32_t index            = stream->fetch<uint32_t>();
28665
+    auto index        = stream->fetch<uint32_t>();
28666
     [encoder setVertexSamplerState:state
28667
                        lodMinClamp:lodMinClamp
28668
                        lodMaxClamp:lodMaxClamp
28669
@@ -195,17 +199,17 @@ void SetVertexSamplerStateCmd(id<MTLRenderCommandEncoder> encoder,
28670
 
28671
 void SetVertexTextureCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
28672
 {
28673
-    id<MTLTexture> texture = stream->fetch<id<MTLTexture>>();
28674
-    uint32_t index         = stream->fetch<uint32_t>();
28675
+    auto texture = stream->fetch<id<MTLTexture>>();
28676
+    auto index   = stream->fetch<uint32_t>();
28677
     [encoder setVertexTexture:texture atIndex:index];
28678
     [texture ANGLE_MTL_RELEASE];
28679
 }
28680
 
28681
 void SetFragmentBufferCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
28682
 {
28683
-    id<MTLBuffer> buffer = stream->fetch<id<MTLBuffer>>();
28684
-    uint32_t offset      = stream->fetch<uint32_t>();
28685
-    uint32_t index       = stream->fetch<uint32_t>();
28686
+    auto buffer = stream->fetch<id<MTLBuffer>>();
28687
+    auto offset = stream->fetch<uint32_t>();
28688
+    auto index  = stream->fetch<uint32_t>();
28689
     [encoder setFragmentBuffer:buffer offset:offset atIndex:index];
28690
     [buffer ANGLE_MTL_RELEASE];
28691
 }
28692
@@ -213,26 +217,26 @@ void SetFragmentBufferCmd(id<MTLRenderCommandEncoder> encoder, IntermediateComma
28693
 void SetFragmentBufferOffsetCmd(id<MTLRenderCommandEncoder> encoder,
28694
                                 IntermediateCommandStream *stream)
28695
 {
28696
-    uint32_t offset = stream->fetch<uint32_t>();
28697
-    uint32_t index  = stream->fetch<uint32_t>();
28698
+    auto offset = stream->fetch<uint32_t>();
28699
+    auto index  = stream->fetch<uint32_t>();
28700
     [encoder setFragmentBufferOffset:offset atIndex:index];
28701
 }
28702
 
28703
 void SetFragmentBytesCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
28704
 {
28705
-    size_t size          = stream->fetch<size_t>();
28706
-    const uint8_t *bytes = stream->fetch(size);
28707
-    uint32_t index       = stream->fetch<uint32_t>();
28708
+    auto size  = stream->fetch<size_t>();
28709
+    auto bytes = stream->fetch(size);
28710
+    auto index = stream->fetch<uint32_t>();
28711
     [encoder setFragmentBytes:bytes length:size atIndex:index];
28712
 }
28713
 
28714
 void SetFragmentSamplerStateCmd(id<MTLRenderCommandEncoder> encoder,
28715
                                 IntermediateCommandStream *stream)
28716
 {
28717
-    id<MTLSamplerState> state = stream->fetch<id<MTLSamplerState>>();
28718
+    auto state        = stream->fetch<id<MTLSamplerState>>();
28719
     float lodMinClamp = stream->fetch<float>();
28720
     float lodMaxClamp = stream->fetch<float>();
28721
-    uint32_t index            = stream->fetch<uint32_t>();
28722
+    auto index        = stream->fetch<uint32_t>();
28723
     [encoder setFragmentSamplerState:state
28724
                          lodMinClamp:lodMinClamp
28725
                          lodMaxClamp:lodMaxClamp
28726
@@ -242,26 +246,26 @@ void SetFragmentSamplerStateCmd(id<MTLRenderCommandEncoder> encoder,
28727
 
28728
 void SetFragmentTextureCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
28729
 {
28730
-    id<MTLTexture> texture = stream->fetch<id<MTLTexture>>();
28731
-    uint32_t index         = stream->fetch<uint32_t>();
28732
+    auto texture = stream->fetch<id<MTLTexture>>();
28733
+    auto index   = stream->fetch<uint32_t>();
28734
     [encoder setFragmentTexture:texture atIndex:index];
28735
     [texture ANGLE_MTL_RELEASE];
28736
 }
28737
 
28738
 void DrawCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
28739
 {
28740
-    MTLPrimitiveType primitiveType = stream->fetch<MTLPrimitiveType>();
28741
-    uint32_t vertexStart           = stream->fetch<uint32_t>();
28742
-    uint32_t vertexCount           = stream->fetch<uint32_t>();
28743
+    auto primitiveType = stream->fetch<MTLPrimitiveType>();
28744
+    auto vertexStart   = stream->fetch<uint32_t>();
28745
+    auto vertexCount   = stream->fetch<uint32_t>();
28746
     [encoder drawPrimitives:primitiveType vertexStart:vertexStart vertexCount:vertexCount];
28747
 }
28748
 
28749
 void DrawInstancedCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
28750
 {
28751
-    MTLPrimitiveType primitiveType = stream->fetch<MTLPrimitiveType>();
28752
-    uint32_t vertexStart           = stream->fetch<uint32_t>();
28753
-    uint32_t vertexCount           = stream->fetch<uint32_t>();
28754
-    uint32_t instances             = stream->fetch<uint32_t>();
28755
+    auto primitiveType = stream->fetch<MTLPrimitiveType>();
28756
+    auto vertexStart   = stream->fetch<uint32_t>();
28757
+    auto vertexCount   = stream->fetch<uint32_t>();
28758
+    auto instances     = stream->fetch<uint32_t>();
28759
     [encoder drawPrimitives:primitiveType
28760
                 vertexStart:vertexStart
28761
                 vertexCount:vertexCount
28762
@@ -270,11 +274,11 @@ void DrawInstancedCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
28763
 
28764
 void DrawIndexedCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
28765
 {
28766
-    MTLPrimitiveType primitiveType = stream->fetch<MTLPrimitiveType>();
28767
-    uint32_t indexCount            = stream->fetch<uint32_t>();
28768
-    MTLIndexType indexType         = stream->fetch<MTLIndexType>();
28769
-    id<MTLBuffer> indexBuffer      = stream->fetch<id<MTLBuffer>>();
28770
-    size_t bufferOffset            = stream->fetch<size_t>();
28771
+    auto primitiveType = stream->fetch<MTLPrimitiveType>();
28772
+    auto indexCount    = stream->fetch<uint32_t>();
28773
+    auto indexType     = stream->fetch<MTLIndexType>();
28774
+    auto indexBuffer   = stream->fetch<id<MTLBuffer>>();
28775
+    auto bufferOffset  = stream->fetch<size_t>();
28776
     [encoder drawIndexedPrimitives:primitiveType
28777
                         indexCount:indexCount
28778
                          indexType:indexType
28779
@@ -285,12 +289,12 @@ void DrawIndexedCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStre
28780
 
28781
 void DrawIndexedInstancedCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
28782
 {
28783
-    MTLPrimitiveType primitiveType = stream->fetch<MTLPrimitiveType>();
28784
-    uint32_t indexCount            = stream->fetch<uint32_t>();
28785
-    MTLIndexType indexType         = stream->fetch<MTLIndexType>();
28786
-    id<MTLBuffer> indexBuffer      = stream->fetch<id<MTLBuffer>>();
28787
-    size_t bufferOffset            = stream->fetch<size_t>();
28788
-    uint32_t instances             = stream->fetch<uint32_t>();
28789
+    auto primitiveType = stream->fetch<MTLPrimitiveType>();
28790
+    auto indexCount    = stream->fetch<uint32_t>();
28791
+    auto indexType     = stream->fetch<MTLIndexType>();
28792
+    auto indexBuffer   = stream->fetch<id<MTLBuffer>>();
28793
+    auto bufferOffset  = stream->fetch<size_t>();
28794
+    auto instances     = stream->fetch<uint32_t>();
28795
     [encoder drawIndexedPrimitives:primitiveType
28796
                         indexCount:indexCount
28797
                          indexType:indexType
28798
@@ -303,13 +307,13 @@ void DrawIndexedInstancedCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCo
28799
 void DrawIndexedInstancedBaseVertexCmd(id<MTLRenderCommandEncoder> encoder,
28800
                                        IntermediateCommandStream *stream)
28801
 {
28802
-    MTLPrimitiveType primitiveType = stream->fetch<MTLPrimitiveType>();
28803
-    uint32_t indexCount            = stream->fetch<uint32_t>();
28804
-    MTLIndexType indexType         = stream->fetch<MTLIndexType>();
28805
-    id<MTLBuffer> indexBuffer      = stream->fetch<id<MTLBuffer>>();
28806
-    size_t bufferOffset            = stream->fetch<size_t>();
28807
-    uint32_t instances             = stream->fetch<uint32_t>();
28808
-    uint32_t baseVertex            = stream->fetch<uint32_t>();
28809
+    auto primitiveType = stream->fetch<MTLPrimitiveType>();
28810
+    auto indexCount    = stream->fetch<uint32_t>();
28811
+    auto indexType     = stream->fetch<MTLIndexType>();
28812
+    auto indexBuffer   = stream->fetch<id<MTLBuffer>>();
28813
+    auto bufferOffset  = stream->fetch<size_t>();
28814
+    auto instances     = stream->fetch<uint32_t>();
28815
+    auto baseVertex    = stream->fetch<uint32_t>();
28816
     [encoder drawIndexedPrimitives:primitiveType
28817
                         indexCount:indexCount
28818
                          indexType:indexType
28819
@@ -324,16 +328,16 @@ void DrawIndexedInstancedBaseVertexCmd(id<MTLRenderCommandEncoder> encoder,
28820
 void SetVisibilityResultModeCmd(id<MTLRenderCommandEncoder> encoder,
28821
                                 IntermediateCommandStream *stream)
28822
 {
28823
-    MTLVisibilityResultMode mode = stream->fetch<MTLVisibilityResultMode>();
28824
-    size_t offset                = stream->fetch<size_t>();
28825
+    auto mode   = stream->fetch<MTLVisibilityResultMode>();
28826
+    auto offset = stream->fetch<size_t>();
28827
     [encoder setVisibilityResultMode:mode offset:offset];
28828
 }
28829
 
28830
 void UseResourceCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
28831
 {
28832
-    id<MTLResource> resource = stream->fetch<id<MTLResource>>();
28833
-    MTLResourceUsage usage   = stream->fetch<MTLResourceUsage>();
28834
-    mtl::RenderStages stages = stream->fetch<mtl::RenderStages>();
28835
+    auto resource = stream->fetch<id<MTLResource>>();
28836
+    auto usage    = stream->fetch<MTLResourceUsage>();
28837
+    auto stages   = stream->fetch<mtl::RenderStages>();
28838
     ANGLE_UNUSED_VARIABLE(stages);
28839
 #if defined(__IPHONE_13_0) || defined(__MAC_10_15)
28840
     if (ANGLE_APPLE_AVAILABLE_XCI(10.15, 13.0, 13.0))
28841
@@ -351,9 +355,9 @@ void UseResourceCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStre
28842
 void MemoryBarrierWithResourceCmd(id<MTLRenderCommandEncoder> encoder,
28843
                                   IntermediateCommandStream *stream)
28844
 {
28845
-    id<MTLResource> resource = stream->fetch<id<MTLResource>>();
28846
-    mtl::RenderStages after  = stream->fetch<mtl::RenderStages>();
28847
-    mtl::RenderStages before = stream->fetch<mtl::RenderStages>();
28848
+    auto resource = stream->fetch<id<MTLResource>>();
28849
+    auto after    = stream->fetch<mtl::RenderStages>();
28850
+    auto before   = stream->fetch<mtl::RenderStages>();
28851
     ANGLE_UNUSED_VARIABLE(after);
28852
     ANGLE_UNUSED_VARIABLE(before);
28853
 #if defined(__MAC_10_14) && (TARGET_OS_OSX || TARGET_OS_MACCATALYST)
28854
@@ -368,9 +372,16 @@ void MemoryBarrierWithResourceCmd(id<MTLRenderCommandEncoder> encoder,
28855
     [resource ANGLE_MTL_RELEASE];
28856
 }
28857
 
28858
+void InsertDebugsignCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
28859
+{
28860
+    auto label = stream->fetch<NSString *>();
28861
+    [encoder insertDebugSignpost:label];
28862
+    [label ANGLE_MTL_RELEASE];
28863
+}
28864
+
28865
 void PushDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
28866
 {
28867
-    NSString *label = stream->fetch<NSString *>();
28868
+    auto label = stream->fetch<NSString *>();
28869
     [encoder pushDebugGroup:label];
28870
     [label ANGLE_MTL_RELEASE];
28871
 }
28872
@@ -388,7 +399,7 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
28873
 
28874
 NSString *cppLabelToObjC(const std::string &marker)
28875
 {
28876
-    NSString *label = [NSString stringWithUTF8String:marker.c_str()];
28877
+    auto label = [NSString stringWithUTF8String:marker.c_str()];
28878
     if (!label)
28879
     {
28880
         // This can happen if the string is not a valid ascii string.
28881
@@ -396,7 +407,6 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
28882
     }
28883
     return label;
28884
 }
28885
-
28886
 }
28887
 
28888
 // CommandQueue implementation
28889
@@ -565,11 +575,11 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
28890
     cleanup();
28891
 }
28892
 
28893
-bool CommandBuffer::ready() const
28894
+bool CommandBuffer::valid() const
28895
 {
28896
     std::lock_guard<std::mutex> lg(mLock);
28897
 
28898
-    return readyImpl();
28899
+    return validImpl();
28900
 }
28901
 
28902
 void CommandBuffer::commit()
28903
@@ -598,7 +608,7 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
28904
 
28905
     std::lock_guard<std::mutex> lg(mLock);
28906
 
28907
-    if (!readyImpl())
28908
+    if (!validImpl())
28909
     {
28910
         return;
28911
     }
28912
@@ -620,7 +630,7 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
28913
 
28914
     std::lock_guard<std::mutex> lg(mLock);
28915
 
28916
-    if (!readyImpl())
28917
+    if (!validImpl())
28918
     {
28919
         return;
28920
     }
28921
@@ -647,57 +657,57 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
28922
     ASSERT(metalCmdBuffer);
28923
 }
28924
 
28925
-void CommandBuffer::queueEventSignal(const mtl::SharedEventRef &event, uint64_t value)
28926
+void CommandBuffer::insertDebugSign(const std::string &marker)
28927
 {
28928
-    std::lock_guard<std::mutex> lg(mLock);
28929
-
28930
-    ASSERT(readyImpl());
28931
-
28932
-    if (mActiveCommandEncoder && mActiveCommandEncoder->getType() == CommandEncoder::RENDER)
28933
+    mtl::CommandEncoder *currentEncoder = mActiveCommandEncoder;
28934
+    if (currentEncoder)
28935
     {
28936
-        // We cannot set event when there is an active render pass, defer the setting until the
28937
-        // pass end.
28938
-        mPendingSignalEvents.push_back({event, value});
28939
+        ANGLE_MTL_OBJC_SCOPE
28940
+        {
28941
+            auto label = cppLabelToObjC(marker);
28942
+            currentEncoder->insertDebugSign(label);
28943
+        }
28944
     }
28945
     else
28946
     {
28947
-        setEventImpl(event, value);
28948
+        mPendingDebugSigns.push_back(marker);
28949
     }
28950
 }
28951
 
28952
-void CommandBuffer::serverWaitEvent(const mtl::SharedEventRef &event, uint64_t value)
28953
+void CommandBuffer::pushDebugGroup(const std::string &marker)
28954
 {
28955
-    std::lock_guard<std::mutex> lg(mLock);
28956
-    ASSERT(readyImpl());
28957
-
28958
-    waitEventImpl(event, value);
28959
+    // NOTE(hqle): to implement this
28960
 }
28961
 
28962
-void CommandBuffer::pushDebugGroup(const std::string &marker)
28963
+void CommandBuffer::popDebugGroup()
28964
 {
28965
-    mDebugGroups.push_back(marker);
28966
+    // NOTE(hqle): to implement this
28967
+}
28968
 
28969
+void CommandBuffer::queueEventSignal(const mtl::SharedEventRef &event, uint64_t value)
28970
+{
28971
     std::lock_guard<std::mutex> lg(mLock);
28972
 
28973
-    if (readyImpl())
28974
+    ASSERT(validImpl());
28975
+
28976
+    if (mActiveCommandEncoder && mActiveCommandEncoder->getType() == CommandEncoder::RENDER)
28977
     {
28978
-        pushDebugGroupImpl(marker);
28979
+        // We cannot set event when there is an active render pass, defer the setting until the
28980
+        // pass end.
28981
+        mPendingSignalEvents.push_back({event, value});
28982
     }
28983
-}
28984
-
28985
-void CommandBuffer::popDebugGroup()
28986
-{
28987
-    if (!mDebugGroups.empty())
28988
+    else
28989
     {
28990
-        mDebugGroups.pop_back();
28991
+        setEventImpl(event, value);
28992
     }
28993
+}
28994
 
28995
+void CommandBuffer::serverWaitEvent(const mtl::SharedEventRef &event, uint64_t value)
28996
+{
28997
     std::lock_guard<std::mutex> lg(mLock);
28998
+    ASSERT(validImpl());
28999
 
29000
-    if (readyImpl())
29001
-    {
29002
-        return;
29003
-    }
29004
+    waitEventImpl(event, value);
29005
 }
29006
 
29007
 /** private use only */
29008
@@ -709,6 +719,15 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
29009
 void CommandBuffer::setActiveCommandEncoder(CommandEncoder *encoder)
29010
 {
29011
     mActiveCommandEncoder = encoder;
29012
+    for (auto &marker : mPendingDebugSigns)
29013
+    {
29014
+        ANGLE_MTL_OBJC_SCOPE
29015
+        {
29016
+            auto label = cppLabelToObjC(marker);
29017
+            encoder->insertDebugSign(label);
29018
+        }
29019
+    }
29020
+    mPendingDebugSigns.clear();
29021
 }
29022
 
29023
 void CommandBuffer::invalidateActiveCommandEncoder(CommandEncoder *encoder)
29024
@@ -729,7 +748,7 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
29025
     ParentClass::set(nil);
29026
 }
29027
 
29028
-bool CommandBuffer::readyImpl() const
29029
+bool CommandBuffer::validImpl() const
29030
 {
29031
     if (!ParentClass::valid())
29032
     {
29033
@@ -741,7 +760,7 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
29034
 
29035
 void CommandBuffer::commitImpl()
29036
 {
29037
-    if (!readyImpl())
29038
+    if (!validImpl())
29039
     {
29040
         return;
29041
     }
29042
@@ -889,6 +908,17 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
29043
     [get() popDebugGroup];
29044
 }
29045
 
29046
+void CommandEncoder::insertDebugSign(NSString *label)
29047
+{
29048
+    insertDebugSignImpl(label);
29049
+}
29050
+
29051
+void CommandEncoder::insertDebugSignImpl(NSString *label)
29052
+{
29053
+    // Default implementation
29054
+    [get() insertDebugSignpost:label];
29055
+}
29056
+
29057
 // RenderCommandEncoderShaderStates implementation
29058
 RenderCommandEncoderShaderStates::RenderCommandEncoderShaderStates()
29059
 {
29060
@@ -951,6 +981,9 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
29061
     {
29062
         shaderStates.reset();
29063
     }
29064
+
29065
+    visibilityResultMode         = MTLVisibilityResultModeDisabled;
29066
+    visibilityResultBufferOffset = 0;
29067
 }
29068
 
29069
 // RenderCommandEncoder implemtation
29070
@@ -1014,11 +1047,12 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
29071
     {
29072
         if (objCRenderPassAttachment.storeAction == MTLStoreActionStore)
29073
         {
29074
-            // NOTE(hqle): Currently if the store action with implicit MS texture is
29075
-            // MTLStoreActionStore, it is automatically convert to store and resolve action. It
29076
-            // might introduce unnecessary overhead. Consider an improvement such as only store the
29077
-            // MS texture, and resolve only at the end of real render pass (not render pass the is
29078
-            // interrupted by compute pass) or before glBlitFramebuffer operation starts.
29079
+            // NOTE(hqle): Currently if the store action with implicit MS texture is MTLStoreAction,
29080
+            // it is automatically convert to store and resolve action. It might introduce
29081
+            // unnecessary overhead.
29082
+            // Consider an improvement such as only store the MS texture, and resolve only at
29083
+            // the end of real render pass (not render pass the was interrupted by compute pass)
29084
+            // or before glBlitFramebuffer operation starts.
29085
             objCRenderPassAttachment.storeAction = MTLStoreActionStoreAndMultisampleResolve;
29086
         }
29087
         else if (objCRenderPassAttachment.storeAction == MTLStoreActionDontCare)
29088
@@ -1036,6 +1070,11 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
29089
 }
29090
 
29091
 void RenderCommandEncoder::endEncoding()
29092
+{
29093
+    endEncodingImpl(true);
29094
+}
29095
+
29096
+void RenderCommandEncoder::endEncodingImpl(bool considerDiscardSimulation)
29097
 {
29098
     if (!valid())
29099
         return;
29100
@@ -1050,11 +1089,11 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
29101
         finalizeLoadStoreAction(objCRenderPassDesc.colorAttachments[i]);
29102
     }
29103
 
29104
-    // Update depth store action set between restart() and endEncoding()
29105
+    // Update store action set between restart() and endEncoding()
29106
     objCRenderPassDesc.depthAttachment.storeAction = mRenderPassDesc.depthAttachment.storeAction;
29107
     finalizeLoadStoreAction(objCRenderPassDesc.depthAttachment);
29108
 
29109
-    // Update stencil store action set between restart() and endEncoding()
29110
+    // Update store action set between restart() and endEncoding()
29111
     objCRenderPassDesc.stencilAttachment.storeAction =
29112
         mRenderPassDesc.stencilAttachment.storeAction;
29113
     finalizeLoadStoreAction(objCRenderPassDesc.stencilAttachment);
29114
@@ -1075,26 +1114,78 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
29115
 
29116
     CommandEncoder::endEncoding();
29117
 
29118
+#if ANGLE_MTL_SIMULATE_DISCARD_FRAMEBUFFER
29119
+    if (considerDiscardSimulation)
29120
+    {
29121
+        simulateDiscardFramebuffer();
29122
+    }
29123
+#endif
29124
+
29125
     // reset state
29126
     mRenderPassDesc = RenderPassDesc();
29127
     mStateCache.reset();
29128
 }
29129
 
29130
-inline void RenderCommandEncoder::initAttachmentWriteDependencyAndScissorRect(
29131
-    const RenderPassAttachmentDesc &attachment)
29132
+inline void RenderCommandEncoder::initWriteDependency(const TextureRef &texture)
29133
 {
29134
-    TextureRef texture = attachment.texture;
29135
     if (texture)
29136
     {
29137
         cmdBuffer().setWriteDependency(texture);
29138
+    }
29139
+}
29140
+
29141
+void RenderCommandEncoder::simulateDiscardFramebuffer()
29142
+{
29143
+    // Simulate true framebuffer discard operation by clearing the framebuffer
29144
+#if ANGLE_MTL_SIMULATE_DISCARD_FRAMEBUFFER
29145
+    std::random_device rd;   // Will be used to obtain a seed for the random number engine
29146
+    std::mt19937 gen(rd());  // Standard mersenne_twister_engine seeded with rd()
29147
+    std::uniform_real_distribution<float> dis(0.0, 1.0f);
29148
+    bool hasDiscard = false;
29149
+    for (uint32_t i = 0; i < mRenderPassDesc.numColorAttachments; ++i)
29150
+    {
29151
+        if (mRenderPassDesc.colorAttachments[i].storeAction == MTLStoreActionDontCare)
29152
+        {
29153
+            hasDiscard                                     = true;
29154
+            mRenderPassDesc.colorAttachments[i].loadAction = MTLLoadActionClear;
29155
+            mRenderPassDesc.colorAttachments[i].clearColor =
29156
+                MTLClearColorMake(dis(gen), dis(gen), dis(gen), dis(gen));
29157
+        }
29158
+        else
29159
+        {
29160
+            mRenderPassDesc.colorAttachments[i].loadAction = MTLLoadActionLoad;
29161
+        }
29162
+    }
29163
+
29164
+    if (mRenderPassDesc.depthAttachment.storeAction == MTLStoreActionDontCare)
29165
+    {
29166
+        hasDiscard                                 = true;
29167
+        mRenderPassDesc.depthAttachment.loadAction = MTLLoadActionClear;
29168
+        mRenderPassDesc.depthAttachment.clearDepth = dis(gen);
29169
+    }
29170
+    else
29171
+    {
29172
+        mRenderPassDesc.depthAttachment.loadAction = MTLLoadActionLoad;
29173
+    }
29174
 
29175
-        const MipmapNativeLevel &mipLevel = attachment.level;
29176
+    if (mRenderPassDesc.stencilAttachment.storeAction == MTLStoreActionDontCare)
29177
+    {
29178
+        hasDiscard                                     = true;
29179
+        mRenderPassDesc.stencilAttachment.loadAction   = MTLLoadActionClear;
29180
+        mRenderPassDesc.stencilAttachment.clearStencil = rand();
29181
+    }
29182
+    else
29183
+    {
29184
+        mRenderPassDesc.stencilAttachment.loadAction = MTLLoadActionLoad;
29185
+    }
29186
 
29187
-        mRenderPassMaxScissorRect.width =
29188
-            std::min<NSUInteger>(mRenderPassMaxScissorRect.width, texture->width(mipLevel));
29189
-        mRenderPassMaxScissorRect.height =
29190
-            std::min<NSUInteger>(mRenderPassMaxScissorRect.height, texture->height(mipLevel));
29191
+    if (hasDiscard)
29192
+    {
29193
+        auto tmpDesc = mRenderPassDesc;
29194
+        restart(tmpDesc);
29195
+        endEncodingImpl(false);
29196
     }
29197
+#endif  // ANGLE_MTL_SIMULATE_DISCARD_FRAMEBUFFER
29198
 }
29199
 
29200
 void RenderCommandEncoder::encodeMetalEncoder()
29201
@@ -1102,7 +1193,7 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
29202
     ANGLE_MTL_OBJC_SCOPE
29203
     {
29204
         ANGLE_MTL_LOG("Creating new render command encoder with desc: %@",
29205
-                      mCachedRenderPassDescObjC.get());
29206
+                      [mCachedRenderPassDescObjC description]);
29207
 
29208
         id<MTLRenderCommandEncoder> metalCmdEncoder =
29209
             [cmdBuffer().get() renderCommandEncoderWithDescriptor:mCachedRenderPassDescObjC];
29210
@@ -1110,7 +1201,11 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
29211
         set(metalCmdEncoder);
29212
 
29213
         // Verify that it was created successfully
29214
-        ASSERT(metalCmdEncoder);
29215
+        ASSERT(get());
29216
+
29217
+        // Work-around driver bug on iOS devices: stencil must be explicitly set to zero
29218
+        // even if the doc says the default value is already zero.
29219
+        [metalCmdEncoder setStencilReferenceValue:0];
29220
 
29221
         if (mLabel)
29222
         {
29223
@@ -1119,7 +1214,7 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
29224
 
29225
         while (mCommands.good())
29226
         {
29227
-            CmdType cmdType            = mCommands.fetch<CmdType>();
29228
+            auto cmdType               = mCommands.fetch<CmdType>();
29229
             CommandEncoderFunc encoder = gCommandEncoders[static_cast<int>(cmdType)];
29230
             encoder(metalCmdEncoder, &mCommands);
29231
         }
29232
@@ -1142,41 +1237,34 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
29233
         endEncoding();
29234
     }
29235
 
29236
-    if (!cmdBuffer().ready())
29237
+    if (!cmdBuffer().valid())
29238
     {
29239
         reset();
29240
         return *this;
29241
     }
29242
 
29243
-    mLabel.reset();
29244
-
29245
     mRenderPassDesc = desc;
29246
     mRecording      = true;
29247
     mHasDrawCalls   = false;
29248
-    mRenderPassMaxScissorRect = {.x      = 0,
29249
-                                 .y      = 0,
29250
-                                 .width  = std::numeric_limits<NSUInteger>::max(),
29251
-                                 .height = std::numeric_limits<NSUInteger>::max()};
29252
 
29253
-    // Set writing dependency & constrain the scissor rect
29254
+    // mask writing dependency & set appropriate store options
29255
     for (uint32_t i = 0; i < mRenderPassDesc.numColorAttachments; ++i)
29256
     {
29257
-        initAttachmentWriteDependencyAndScissorRect(mRenderPassDesc.colorAttachments[i]);
29258
+        initWriteDependency(mRenderPassDesc.colorAttachments[i].texture());
29259
     }
29260
 
29261
-    initAttachmentWriteDependencyAndScissorRect(mRenderPassDesc.depthAttachment);
29262
+    initWriteDependency(mRenderPassDesc.depthAttachment.texture());
29263
 
29264
-    initAttachmentWriteDependencyAndScissorRect(mRenderPassDesc.stencilAttachment);
29265
+    initWriteDependency(mRenderPassDesc.stencilAttachment.texture());
29266
 
29267
     // Convert to Objective-C descriptor
29268
     mRenderPassDesc.convertToMetalDesc(mCachedRenderPassDescObjC);
29269
 
29270
-    // The actual Objective-C encoder will be created later in endEncoding(), we do so in
29271
-    // order to be able to sort the commands or do the preprocessing before the actual
29272
-    // encoding.
29273
+    // The actual Objective-C encoder will be created later in endEncoding(), we do so in order
29274
+    // to be able to sort the commands or do the preprocessing before the actual encoding.
29275
 
29276
-    // Since we defer the native encoder creation, we need to explicitly tell command buffer
29277
-    // that this object is the active encoder:
29278
+    // Since we defer the native encoder creation, we need to explicitly tell command buffer that
29279
+    // this object is the active encoder:
29280
     cmdBuffer().setActiveCommandEncoder(this);
29281
 
29282
     return *this;
29283
@@ -1302,16 +1390,6 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
29284
     {
29285
         return *this;
29286
     }
29287
-
29288
-    if (ANGLE_UNLIKELY(rect.x + rect.width > mRenderPassMaxScissorRect.width ||
29289
-                       rect.y + rect.height > mRenderPassMaxScissorRect.height))
29290
-    {
29291
-        WARN() << "Out of bound scissor rect detected " << rect.x << " " << rect.y << " "
29292
-               << rect.width << " " << rect.height;
29293
-        // Out of bound rect will crash the metal runtime, ignore it.
29294
-        return *this;
29295
-    }
29296
-
29297
     mStateCache.scissorRect = rect;
29298
 
29299
     mCommands.push(CmdType::SetScissorRect).push(rect);
29300
@@ -1383,7 +1461,7 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
29301
             return *this;
29302
         }
29303
 
29304
-        // If buffer already bound but with different offset, then update the offset only.
29305
+        // If buffer already bound but with different offset, then update the offer only.
29306
         shaderStates.bufferOffsets[index] = offset;
29307
 
29308
         mCommands.push(static_cast<CmdType>(mSetBufferOffsetCmds[shaderType]))
29309
@@ -1490,12 +1568,6 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
29310
                                                  uint32_t vertexStart,
29311
                                                  uint32_t vertexCount)
29312
 {
29313
-    if (ANGLE_UNLIKELY(!mStateCache.renderPipeline))
29314
-    {
29315
-        // Ignore draw call if there is no render pipeline state set prior to this.
29316
-        return *this;
29317
-    }
29318
-
29319
     mHasDrawCalls = true;
29320
     mCommands.push(CmdType::Draw).push(primitiveType).push(vertexStart).push(vertexCount);
29321
 
29322
@@ -1507,12 +1579,6 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
29323
                                                           uint32_t vertexCount,
29324
                                                           uint32_t instances)
29325
 {
29326
-    if (ANGLE_UNLIKELY(!mStateCache.renderPipeline))
29327
-    {
29328
-        // Ignore draw call if there is no render pipeline state set prior to this.
29329
-        return *this;
29330
-    }
29331
-
29332
     mHasDrawCalls = true;
29333
     mCommands.push(CmdType::DrawInstanced)
29334
         .push(primitiveType)
29335
@@ -1529,13 +1595,7 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
29336
                                                         const BufferRef &indexBuffer,
29337
                                                         size_t bufferOffset)
29338
 {
29339
-    if (ANGLE_UNLIKELY(!mStateCache.renderPipeline))
29340
-    {
29341
-        // Ignore draw call if there is no render pipeline state set prior to this.
29342
-        return *this;
29343
-    }
29344
-
29345
-    if (ANGLE_UNLIKELY(!indexBuffer))
29346
+    if (!indexBuffer)
29347
     {
29348
         return *this;
29349
     }
29350
@@ -1560,13 +1620,7 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
29351
                                                                  size_t bufferOffset,
29352
                                                                  uint32_t instances)
29353
 {
29354
-    if (ANGLE_UNLIKELY(!mStateCache.renderPipeline))
29355
-    {
29356
-        // Ignore draw call if there is no render pipeline state set prior to this.
29357
-        return *this;
29358
-    }
29359
-
29360
-    if (ANGLE_UNLIKELY(!indexBuffer))
29361
+    if (!indexBuffer)
29362
     {
29363
         return *this;
29364
     }
29365
@@ -1594,13 +1648,7 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
29366
     uint32_t instances,
29367
     uint32_t baseVertex)
29368
 {
29369
-    if (ANGLE_UNLIKELY(!mStateCache.renderPipeline))
29370
-    {
29371
-        // Ignore draw call if there is no render pipeline state set prior to this.
29372
-        return *this;
29373
-    }
29374
-
29375
-    if (ANGLE_UNLIKELY(!indexBuffer))
29376
+    if (!indexBuffer)
29377
     {
29378
         return *this;
29379
     }
29380
@@ -1673,6 +1721,12 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
29381
     return *this;
29382
 }
29383
 
29384
+void RenderCommandEncoder::insertDebugSignImpl(NSString *label)
29385
+{
29386
+    // Defer the insertion until endEncoding()
29387
+    mCommands.push(CmdType::InsertDebugsign).push([label ANGLE_MTL_RETAIN]);
29388
+}
29389
+
29390
 void RenderCommandEncoder::pushDebugGroup(NSString *label)
29391
 {
29392
     // Defer the insertion until endEncoding()
29393
@@ -1799,7 +1853,7 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
29394
             return *this;
29395
         }
29396
 
29397
-        if (!cmdBuffer().ready())
29398
+        if (!cmdBuffer().valid())
29399
         {
29400
             reset();
29401
             return *this;
29402
@@ -1962,6 +2016,66 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
29403
     return *this;
29404
 }
29405
 
29406
+BlitCommandEncoder &BlitCommandEncoder::copyTexture(const TextureRef &src,
29407
+                                                    uint32_t srcStartSlice,
29408
+                                                    uint32_t srcStartLevel,
29409
+                                                    const TextureRef &dst,
29410
+                                                    uint32_t dstStartSlice,
29411
+                                                    uint32_t dstStartLevel,
29412
+                                                    uint32_t sliceCount,
29413
+                                                    uint32_t levelCount)
29414
+{
29415
+    if (!src || !dst)
29416
+    {
29417
+        return *this;
29418
+    }
29419
+
29420
+    cmdBuffer().setReadDependency(src);
29421
+    cmdBuffer().setWriteDependency(dst);
29422
+
29423
+#if defined(__IPHONE_13_0) || defined(__MAC_10_15)
29424
+    if (ANGLE_APPLE_AVAILABLE_XCI(10.15, 13.0, 13.0))
29425
+    {
29426
+        [get() copyFromTexture:src->get()
29427
+                   sourceSlice:srcStartSlice
29428
+                   sourceLevel:srcStartLevel
29429
+                     toTexture:dst->get()
29430
+              destinationSlice:dstStartSlice
29431
+              destinationLevel:dstStartLevel
29432
+                    sliceCount:sliceCount
29433
+                    levelCount:levelCount];
29434
+    }
29435
+    else
29436
+#endif
29437
+    {
29438
+        MTLOrigin origin = MTLOriginMake(0, 0, 0);
29439
+        for (uint32_t slice = 0; slice < sliceCount; ++slice)
29440
+        {
29441
+            uint32_t srcSlice = srcStartSlice + slice;
29442
+            uint32_t dstSlice = dstStartSlice + slice;
29443
+            for (uint32_t level = 0; level < levelCount; ++level)
29444
+            {
29445
+                mtl::MipmapNativeLevel srcLevel = mtl::MipmapNativeLevel(srcStartLevel + level);
29446
+                uint32_t dstLevel = dstStartLevel + level;
29447
+                MTLSize srcSize =
29448
+                    MTLSizeMake(src->width(srcLevel), src->height(srcLevel), src->depth(srcLevel));
29449
+
29450
+                [get() copyFromTexture:src->get()
29451
+                           sourceSlice:srcSlice
29452
+                           sourceLevel:srcLevel.get()
29453
+                          sourceOrigin:origin
29454
+                            sourceSize:srcSize
29455
+                             toTexture:dst->get()
29456
+                      destinationSlice:dstSlice
29457
+                      destinationLevel:dstLevel
29458
+                     destinationOrigin:origin];
29459
+            }
29460
+        }
29461
+    }
29462
+
29463
+    return *this;
29464
+}
29465
+
29466
 BlitCommandEncoder &BlitCommandEncoder::generateMipmapsForTexture(const TextureRef &texture)
29467
 {
29468
     if (!texture)
29469
@@ -1974,7 +2088,7 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
29470
 
29471
     return *this;
29472
 }
29473
-BlitCommandEncoder &BlitCommandEncoder::synchronizeResource(Buffer *buffer)
29474
+BlitCommandEncoder &BlitCommandEncoder::synchronizeResource(const BufferRef &buffer)
29475
 {
29476
     if (!buffer)
29477
     {
29478
@@ -1989,7 +2103,7 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
29479
 #endif
29480
     return *this;
29481
 }
29482
-BlitCommandEncoder &BlitCommandEncoder::synchronizeResource(Texture *texture)
29483
+BlitCommandEncoder &BlitCommandEncoder::synchronizeResource(const TextureRef &texture)
29484
 {
29485
     if (!texture)
29486
     {
29487
@@ -2028,7 +2142,7 @@ void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt
29488
             return *this;
29489
         }
29490
 
29491
-        if (!cmdBuffer().ready())
29492
+        if (!cmdBuffer().valid())
29493
         {
29494
             reset();
29495
             return *this;
29496
diff --git a/src/libANGLE/renderer/metal/mtl_common.h b/src/libANGLE/renderer/metal/mtl_common.h
29497
index 97ccb93..3fc5e39 100644
29498
--- a/src/libANGLE/renderer/metal/mtl_common.h
29499
+++ b/src/libANGLE/renderer/metal/mtl_common.h
29500
@@ -27,9 +27,18 @@
29501
 #include "libANGLE/angletypes.h"
29502
 
29503
 #if TARGET_OS_IPHONE
29504
+#    if !defined(__IPHONE_11_0)
29505
+#        define __IPHONE_11_0 110000
29506
+#    endif
29507
 #    if !defined(ANGLE_IOS_DEPLOY_TARGET)
29508
 #        define ANGLE_IOS_DEPLOY_TARGET __IPHONE_11_0
29509
 #    endif
29510
+#    if !defined(__IPHONE_OS_VERSION_MAX_ALLOWED)
29511
+#        define __IPHONE_OS_VERSION_MAX_ALLOWED __IPHONE_11_0
29512
+#    endif
29513
+#    if !defined(__TV_OS_VERSION_MAX_ALLOWED)
29514
+#        define __TV_OS_VERSION_MAX_ALLOWED __IPHONE_11_0
29515
+#    endif
29516
 #endif
29517
 
29518
 #if !defined(TARGET_OS_MACCATALYST)
29519
@@ -66,6 +75,7 @@ namespace egl
29520
 {
29521
 class Display;
29522
 class Image;
29523
+class Surface;
29524
 }  // namespace egl
29525
 
29526
 #define ANGLE_GL_OBJECTS_X(PROC) \
29527
@@ -102,6 +112,7 @@ class TextureMtl;
29528
 class ProgramMtl;
29529
 class SamplerMtl;
29530
 class TransformFeedbackMtl;
29531
+class SurfaceMtlProtocol;
29532
 
29533
 ANGLE_GL_OBJECTS_X(ANGLE_PRE_DECLARE_MTL_OBJECT)
29534
 
29535
@@ -128,7 +139,8 @@ constexpr size_t kDefaultAttributeSize = 4 * sizeof(float);
29536
 // Metal limits
29537
 constexpr uint32_t kMaxShaderBuffers     = 31;
29538
 constexpr uint32_t kMaxShaderSamplers    = 16;
29539
-constexpr size_t kDefaultUniformsMaxSize = 4 * 1024;
29540
+constexpr size_t kInlineConstDataMaxSize = 4 * 1024;
29541
+constexpr size_t kDefaultUniformsMaxSize = kInlineConstDataMaxSize;
29542
 constexpr uint32_t kMaxViewports         = 1;
29543
 
29544
 constexpr uint32_t kVertexAttribBufferStrideAlignment = 4;
29545
@@ -142,7 +154,7 @@ constexpr uint32_t kIndexBufferOffsetAlignment       = 4;
29546
 constexpr uint32_t kArgumentBufferOffsetAlignment    = kUniformBufferSettingOffsetMinAlignment;
29547
 constexpr uint32_t kTextureToBufferBlittingAlignment = 256;
29548
 
29549
-// Front end binding limits
29550
+// Font end binding limits
29551
 constexpr uint32_t kMaxGLSamplerBindings = 2 * kMaxShaderSamplers;
29552
 constexpr uint32_t kMaxGLUBOBindings     = 2 * kMaxShaderUBOs;
29553
 
29554
@@ -155,21 +167,23 @@ constexpr uint32_t kDefaultAttribsBindingIndex = kVboBindingIndexStart + kMaxVer
29555
 constexpr uint32_t kDriverUniformsBindingIndex = kDefaultAttribsBindingIndex + 1;
29556
 // Binding index for default uniforms:
29557
 constexpr uint32_t kDefaultUniformsBindingIndex = kDefaultAttribsBindingIndex + 3;
29558
-// Binding index for UBO's argument buffer or starting discrete slot
29559
-constexpr uint32_t kUBOArgumentBufferBindingIndex = kDefaultUniformsBindingIndex + 1;
29560
+// Binding index for Transform Feedback Buffers (4)
29561
+constexpr uint32_t kTransformFeedbackBindingIndex = kDefaultUniformsBindingIndex + 1;
29562
+// Binding index for shadow samplers' compare modes
29563
+constexpr uint32_t kShadowSamplerCompareModesBindingIndex = kTransformFeedbackBindingIndex + 4;
29564
+// Binding index for UBO's argument buffer
29565
+constexpr uint32_t kUBOArgumentBufferBindingIndex = kShadowSamplerCompareModesBindingIndex + 1;
29566
 
29567
-constexpr uint32_t kStencilMaskAll = 0xff;  // Only 8 bits stencil is supported
29568
+constexpr uint32_t kStencilMaskAll = 0xff;  // Only 8 bit stencil is supported
29569
 
29570
 // This special constant is used to indicate that a particular vertex descriptor's buffer layout
29571
 // index is unused.
29572
 constexpr MTLVertexStepFunction kVertexStepFunctionInvalid =
29573
     static_cast<MTLVertexStepFunction>(0xff);
29574
 
29575
-constexpr int kEmulatedAlphaValue = 1;
29576
-
29577
-constexpr size_t kOcclusionQueryResultSize = sizeof(uint64_t);
29578
+constexpr float kEmulatedAlphaValue = 1.0f;
29579
 
29580
-constexpr gl::Version kMaxSupportedGLVersion = gl::Version(3, 0);
29581
+constexpr uint32_t kOcclusionQueryResultSize = sizeof(uint64_t);
29582
 
29583
 // Work-around the enum is not available on macOS
29584
 #if TARGET_OS_OSX || TARGET_OS_MACCATALYST
29585
@@ -179,13 +193,11 @@ constexpr MTLBlitOption kBlitOptionRowLinearPVRTC          = MTLBlitOptionRowLin
29586
 #endif
29587
 
29588
 #if defined(__IPHONE_13_0) || defined(__MAC_10_15)
29589
-#    define ANGLE_MTL_SWIZZLE_AVAILABLE 1
29590
 using TextureSwizzleChannels                   = MTLTextureSwizzleChannels;
29591
 using RenderStages                             = MTLRenderStages;
29592
 constexpr MTLRenderStages kRenderStageVertex   = MTLRenderStageVertex;
29593
 constexpr MTLRenderStages kRenderStageFragment = MTLRenderStageFragment;
29594
 #else
29595
-#    define ANGLE_MTL_SWIZZLE_AVAILABLE 0
29596
 using TextureSwizzleChannels                               = int;
29597
 using RenderStages                                         = int;
29598
 constexpr RenderStages kRenderStageVertex                  = 1;
29599
@@ -219,12 +231,16 @@ struct ImplTypeHelper<egl::Display>
29600
 {
29601
     using ImplType = DisplayMtl;
29602
 };
29603
-
29604
+template <>
29605
+struct ImplTypeHelper<egl::Surface>
29606
+{
29607
+    using ImplType = SurfaceMtlProtocol;
29608
+};
29609
 template <typename T>
29610
 using GetImplType = typename ImplTypeHelper<T>::ImplType;
29611
 
29612
 template <typename T>
29613
-GetImplType<T> *GetImpl(const T *_Nonnull glObject)
29614
+GetImplType<T> *GetImpl(const T *glObject)
29615
 {
29616
     return GetImplAs<GetImplType<T>>(glObject);
29617
 }
29618
@@ -346,21 +362,16 @@ using AutoObjCObj = AutoObjCPtr<T *>;
29619
 
29620
 // NOTE: SharedEvent is only declared on iOS 12.0+ or mac 10.14+
29621
 #if defined(__IPHONE_12_0) || defined(__MAC_10_14)
29622
-#    define ANGLE_MTL_EVENT_AVAILABLE 1
29623
 using SharedEventRef = AutoObjCPtr<id<MTLSharedEvent>>;
29624
 #else
29625
-#    define ANGLE_MTL_EVENT_AVAILABLE 0
29626
 using SharedEventRef                                       = AutoObjCObj<NSObject>;
29627
 #endif
29628
 
29629
 // The native image index used by Metal back-end,  the image index uses native mipmap level instead
29630
 // of "virtual" level modified by OpenGL's base level.
29631
 using MipmapNativeLevel = gl::LevelIndexWrapper<uint32_t>;
29632
-
29633
 constexpr MipmapNativeLevel kZeroNativeMipLevel(0);
29634
-
29635
 class ImageNativeIndexIterator;
29636
-
29637
 class ImageNativeIndex final
29638
 {
29639
   public:
29640
@@ -370,55 +381,42 @@ class ImageNativeIndex final
29641
         mNativeIndex = gl::ImageIndex::MakeFromType(src.getType(), src.getLevelIndex() - baseLevel,
29642
                                                     src.getLayerIndex(), src.getLayerCount());
29643
     }
29644
-
29645
     static ImageNativeIndex FromBaseZeroGLIndex(const gl::ImageIndex &src)
29646
     {
29647
         return ImageNativeIndex(src, 0);
29648
     }
29649
-
29650
     MipmapNativeLevel getNativeLevel() const
29651
     {
29652
         return MipmapNativeLevel(mNativeIndex.getLevelIndex());
29653
     }
29654
-
29655
     gl::TextureType getType() const { return mNativeIndex.getType(); }
29656
     GLint getLayerIndex() const { return mNativeIndex.getLayerIndex(); }
29657
     GLint getLayerCount() const { return mNativeIndex.getLayerCount(); }
29658
     GLint cubeMapFaceIndex() const { return mNativeIndex.cubeMapFaceIndex(); }
29659
-
29660
     bool isLayered() const { return mNativeIndex.isLayered(); }
29661
     bool hasLayer() const { return mNativeIndex.hasLayer(); }
29662
     bool has3DLayer() const { return mNativeIndex.has3DLayer(); }
29663
     bool usesTex3D() const { return mNativeIndex.usesTex3D(); }
29664
-
29665
     bool valid() const { return mNativeIndex.valid(); }
29666
-
29667
     ImageNativeIndexIterator getLayerIterator(GLint layerCount) const;
29668
-
29669
   private:
29670
     gl::ImageIndex mNativeIndex;
29671
 };
29672
-
29673
 class ImageNativeIndexIterator final
29674
 {
29675
   public:
29676
     ImageNativeIndex next() { return ImageNativeIndex(mNativeIndexIte.next(), 0); }
29677
     ImageNativeIndex current() const { return ImageNativeIndex(mNativeIndexIte.current(), 0); }
29678
     bool hasNext() const { return mNativeIndexIte.hasNext(); }
29679
-
29680
   private:
29681
     // This class is only constructable from ImageNativeIndex
29682
     friend class ImageNativeIndex;
29683
-
29684
     explicit ImageNativeIndexIterator(const gl::ImageIndexIterator &baseZeroSrc)
29685
         : mNativeIndexIte(baseZeroSrc)
29686
     {}
29687
-
29688
     gl::ImageIndexIterator mNativeIndexIte;
29689
 };
29690
-
29691
 using ClearColorValueBytes = std::array<uint8_t, 4 * sizeof(float)>;
29692
-
29693
 class ClearColorValue
29694
 {
29695
   public:
29696
@@ -437,22 +435,15 @@ class ClearColorValue
29697
     constexpr ClearColorValue(const ClearColorValue &src)
29698
         : mType(src.mType), mValueBytes(src.mValueBytes)
29699
     {}
29700
-
29701
     MTLClearColor toMTLClearColor() const;
29702
-
29703
     PixelType getType() const { return mType; }
29704
-
29705
     const ClearColorValueBytes &getValueBytes() const { return mValueBytes; }
29706
-
29707
     ClearColorValue &operator=(const ClearColorValue &src);
29708
-
29709
     void setAsFloat(float r, float g, float b, float a);
29710
     void setAsInt(int32_t r, int32_t g, int32_t b, int32_t a);
29711
     void setAsUInt(uint32_t r, uint32_t g, uint32_t b, uint32_t a);
29712
-
29713
   private:
29714
     PixelType mType;
29715
-
29716
     union
29717
     {
29718
         struct
29719
@@ -467,7 +458,6 @@ class ClearColorValue
29720
         {
29721
             uint32_t mRedU, mGreenU, mBlueU, mAlphaU;
29722
         };
29723
-
29724
         ClearColorValueBytes mValueBytes;
29725
     };
29726
 };
29727
@@ -483,7 +473,7 @@ class ErrorHandler
29728
                              const char *function,
29729
                              unsigned int line) = 0;
29730
 
29731
-    virtual void handleError(NSError *_Nullable error,
29732
+    virtual void handleError(NSError *error,
29733
                              const char *file,
29734
                              const char *function,
29735
                              unsigned int line) = 0;
29736
@@ -493,7 +483,7 @@ class Context : public ErrorHandler
29737
 {
29738
   public:
29739
     Context(DisplayMtl *displayMtl);
29740
-    _Nullable id<MTLDevice> getMetalDevice() const;
29741
+    id<MTLDevice> getMetalDevice() const;
29742
     mtl::CommandQueue &cmdQueue();
29743
 
29744
     DisplayMtl *getDisplay() const { return mDisplay; }
29745
diff --git a/src/libANGLE/renderer/metal/mtl_constants.h b/src/libANGLE/renderer/metal/mtl_constants.h
29746
new file mode 100644
29747
index 0000000..a20b2cd
29748
--- /dev/null
29749
+++ b/src/libANGLE/renderer/metal/mtl_constants.h
29750
@@ -0,0 +1,73 @@
29751
+//
29752
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
29753
+// Use of this source code is governed by a BSD-style license that can be
29754
+// found in the LICENSE file.
29755
+//
29756
+// mtl_common.h:
29757
+//      Declares numerical constants used in Metal.
29758
+//      error handler base class.
29759
+//
29760
+
29761
+#ifndef LIBANGLE_RENDERER_METAL_MTL_CONSTANTS_H
29762
+#define LIBANGLE_RENDERER_METAL_MTL_CONSTANTS_H
29763
+#include "libANGLE/Constants.h"
29764
+#include "libANGLE/Version.h"
29765
+#include "libANGLE/angletypes.h"
29766
+
29767
+namespace rx
29768
+{
29769
+namespace mtl
29770
+{
29771
+
29772
+// NOTE(hqle): support variable max number of vertex attributes
29773
+constexpr uint32_t kMaxVertexAttribs = gl::MAX_VERTEX_ATTRIBS;
29774
+// NOTE(hqle): support variable max number of render targets
29775
+constexpr uint32_t kMaxRenderTargets = 4;
29776
+
29777
+constexpr uint32_t kMaxShaderUBOs = 12;
29778
+constexpr uint32_t kMaxUBOSize    = 16384;
29779
+
29780
+constexpr size_t kDefaultAttributeSize = 4 * sizeof(float);
29781
+
29782
+// Metal limits
29783
+constexpr uint32_t kMaxShaderBuffers     = 31;
29784
+constexpr uint32_t kMaxShaderSamplers    = 16;
29785
+constexpr size_t kInlineConstDataMaxSize = 4 * 1024;
29786
+constexpr size_t kDefaultUniformsMaxSize = kInlineConstDataMaxSize;
29787
+constexpr uint32_t kMaxViewports         = 1;
29788
+
29789
+constexpr uint32_t kVertexAttribBufferStrideAlignment = 4;
29790
+// Alignment requirement for offset passed to setVertex|FragmentBuffer
29791
+#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
29792
+constexpr uint32_t kUniformBufferSettingOffsetMinAlignment = 256;
29793
+#else
29794
+constexpr uint32_t kUniformBufferSettingOffsetMinAlignment = 4;
29795
+#endif
29796
+constexpr uint32_t kIndexBufferOffsetAlignment       = 4;
29797
+constexpr uint32_t kTextureToBufferBlittingAlignment = 256;
29798
+
29799
+// Font end binding limits
29800
+constexpr uint32_t kMaxGLSamplerBindings = 2 * kMaxShaderSamplers;
29801
+constexpr uint32_t kMaxGLUBOBindings     = 2 * kMaxShaderUBOs;
29802
+
29803
+// Binding index start for vertex data buffers:
29804
+constexpr uint32_t kVboBindingIndexStart = 0;
29805
+
29806
+// Binding index for default attribute buffer:
29807
+constexpr uint32_t kDefaultAttribsBindingIndex = kVboBindingIndexStart + kMaxVertexAttribs;
29808
+// Binding index for driver uniforms:
29809
+constexpr uint32_t kDriverUniformsBindingIndex = kDefaultAttribsBindingIndex + 1;
29810
+// Binding index for default uniforms:
29811
+constexpr uint32_t kDefaultUniformsBindingIndex = kDefaultAttribsBindingIndex + 3;
29812
+// Binding index for Transform Feedback Buffers (4)
29813
+constexpr uint32_t kTransformFeedbackBindingIndex = kDefaultUniformsBindingIndex + 1;
29814
+// Binding index for shadow samplers' compare modes
29815
+constexpr uint32_t kShadowSamplerCompareModesBindingIndex = kTransformFeedbackBindingIndex + 4;
29816
+// Binding index for UBO's argument buffer
29817
+constexpr uint32_t kUBOArgumentBufferBindingIndex = kShadowSamplerCompareModesBindingIndex + 1;
29818
+
29819
+constexpr uint32_t kStencilMaskAll = 0xff;  // Only 8 bits stencil is supported
29820
+
29821
+}  // namespace mtl
29822
+}  // namespace rx
29823
+#endif
29824
diff --git a/src/libANGLE/renderer/metal/mtl_format_map.json b/src/libANGLE/renderer/metal/mtl_format_map.json
29825
index 4a12a90..2da7421 100644
29826
--- a/src/libANGLE/renderer/metal/mtl_format_map.json
29827
+++ b/src/libANGLE/renderer/metal/mtl_format_map.json
29828
@@ -74,11 +74,11 @@
29829
             "D32_FLOAT": "MTLPixelFormatDepth32Float",
29830
             "S8_UINT": "MTLPixelFormatStencil8",
29831
             "D32_FLOAT_S8X24_UINT": "MTLPixelFormatDepth32Float_Stencil8",
29832
-            "B10G10R10A2_UNORM": "MTLPixelFormatBGR10A2Unorm",
29833
             "R10G10B10A2_UINT": "MTLPixelFormatRGB10A2Uint",
29834
             "R10G10B10A2_UNORM": "MTLPixelFormatRGB10A2Unorm",
29835
             "R11G11B10_FLOAT": "MTLPixelFormatRG11B10Float",
29836
-            "R9G9B9E5_SHAREDEXP": "MTLPixelFormatRGB9E5Float"
29837
+            "R9G9B9E5_SHAREDEXP": "MTLPixelFormatRGB9E5Float",
29838
+            "D16_UNORM": "MTLPixelFormatDepth16Unorm"
29839
         },
29840
         "map_ios": {
29841
             "R5G6B5_UNORM": "MTLPixelFormatB5G6R5Unorm",
29842
@@ -92,6 +92,7 @@
29843
             "PVRTC1_RGB_4BPP_UNORM_SRGB_BLOCK": "MTLPixelFormatPVRTC_RGB_4BPP_sRGB",
29844
             "PVRTC1_RGBA_2BPP_UNORM_SRGB_BLOCK": "MTLPixelFormatPVRTC_RGBA_2BPP_sRGB",
29845
             "PVRTC1_RGBA_4BPP_UNORM_SRGB_BLOCK": "MTLPixelFormatPVRTC_RGBA_4BPP_sRGB",
29846
+            "ETC1_R8G8B8_UNORM_BLOCK": "MTLPixelFormatETC2_RGB8",
29847
             "ETC2_R8G8B8_UNORM_BLOCK": "MTLPixelFormatETC2_RGB8",
29848
             "ETC2_R8G8B8_SRGB_BLOCK": "MTLPixelFormatETC2_RGB8_sRGB",
29849
             "ETC2_R8G8B8A1_UNORM_BLOCK": "MTLPixelFormatETC2_RGB8A1",
29850
@@ -100,39 +101,38 @@
29851
             "ETC2_R8G8B8A8_SRGB_BLOCK": "MTLPixelFormatEAC_RGBA8_sRGB",
29852
             "EAC_R11_UNORM_BLOCK": "MTLPixelFormatEAC_R11Unorm",
29853
             "EAC_R11_SNORM_BLOCK": "MTLPixelFormatEAC_R11Snorm",
29854
-            "EAC_R11G11_UNORM_BLOCK": "MTLPixelFormatEAC_RG11Unorm",
29855
+            "EAC_R11G11_UNORM_BLOCK": "MTLPixelFormatEAC_R11Unorm",
29856
             "EAC_R11G11_SNORM_BLOCK": "MTLPixelFormatEAC_RG11Snorm",
29857
-            "ASTC_4x4_UNORM_BLOCK": "MTLPixelFormatASTC_4x4_LDR",
29858
-            "ASTC_4x4_SRGB_BLOCK": "MTLPixelFormatASTC_4x4_sRGB",
29859
-            "ASTC_5x4_UNORM_BLOCK": "MTLPixelFormatASTC_5x4_LDR",
29860
-            "ASTC_5x4_SRGB_BLOCK": "MTLPixelFormatASTC_5x4_sRGB",
29861
-            "ASTC_5x5_UNORM_BLOCK": "MTLPixelFormatASTC_5x5_LDR",
29862
-            "ASTC_5x5_SRGB_BLOCK": "MTLPixelFormatASTC_5x5_sRGB",
29863
-            "ASTC_6x5_UNORM_BLOCK": "MTLPixelFormatASTC_6x5_LDR",
29864
-            "ASTC_6x5_SRGB_BLOCK": "MTLPixelFormatASTC_6x5_sRGB",
29865
-            "ASTC_6x6_UNORM_BLOCK": "MTLPixelFormatASTC_6x6_LDR",
29866
-            "ASTC_6x6_SRGB_BLOCK": "MTLPixelFormatASTC_6x6_sRGB",
29867
-            "ASTC_8x5_UNORM_BLOCK": "MTLPixelFormatASTC_8x5_LDR",
29868
-            "ASTC_8x5_SRGB_BLOCK": "MTLPixelFormatASTC_8x5_sRGB",
29869
-            "ASTC_8x6_UNORM_BLOCK": "MTLPixelFormatASTC_8x6_LDR",
29870
-            "ASTC_8x6_SRGB_BLOCK": "MTLPixelFormatASTC_8x6_sRGB",
29871
-            "ASTC_8x8_UNORM_BLOCK": "MTLPixelFormatASTC_8x8_LDR",
29872
-            "ASTC_8x8_SRGB_BLOCK": "MTLPixelFormatASTC_8x8_sRGB",
29873
-            "ASTC_10x5_UNORM_BLOCK": "MTLPixelFormatASTC_10x5_LDR",
29874
-            "ASTC_10x5_SRGB_BLOCK": "MTLPixelFormatASTC_10x5_sRGB",
29875
-            "ASTC_10x6_UNORM_BLOCK": "MTLPixelFormatASTC_10x6_LDR",
29876
-            "ASTC_10x6_SRGB_BLOCK": "MTLPixelFormatASTC_10x6_sRGB",
29877
-            "ASTC_10x8_UNORM_BLOCK": "MTLPixelFormatASTC_10x8_LDR",
29878
-            "ASTC_10x8_SRGB_BLOCK": "MTLPixelFormatASTC_10x8_sRGB",
29879
-            "ASTC_10x10_UNORM_BLOCK": "MTLPixelFormatASTC_10x10_LDR",
29880
-            "ASTC_10x10_SRGB_BLOCK": "MTLPixelFormatASTC_10x10_sRGB",
29881
-            "ASTC_12x10_UNORM_BLOCK": "MTLPixelFormatASTC_12x10_LDR",
29882
-            "ASTC_12x10_SRGB_BLOCK": "MTLPixelFormatASTC_12x10_sRGB",
29883
-            "ASTC_12x12_UNORM_BLOCK": "MTLPixelFormatASTC_12x12_LDR",
29884
-            "ASTC_12x12_SRGB_BLOCK": "MTLPixelFormatASTC_12x12_sRGB"
29885
+            "ASTC_4x4_SRGB_BLOCK" : "MTLPixelFormatASTC_4x4_sRGB",
29886
+            "ASTC_5x4_SRGB_BLOCK" : "MTLPixelFormatASTC_5x4_sRGB",
29887
+            "ASTC_5x5_SRGB_BLOCK" : "MTLPixelFormatASTC_5x5_sRGB",
29888
+            "ASTC_6x5_SRGB_BLOCK" : "MTLPixelFormatASTC_6x5_sRGB",
29889
+            "ASTC_6x6_SRGB_BLOCK" : "MTLPixelFormatASTC_6x6_sRGB",
29890
+            "ASTC_8x5_SRGB_BLOCK" : "MTLPixelFormatASTC_8x5_sRGB",
29891
+            "ASTC_8x6_SRGB_BLOCK" : "MTLPixelFormatASTC_8x6_sRGB",
29892
+            "ASTC_8x8_SRGB_BLOCK" : "MTLPixelFormatASTC_8x8_sRGB",
29893
+            "ASTC_10x5_SRGB_BLOCK" : "MTLPixelFormatASTC_10x5_sRGB",
29894
+            "ASTC_10x6_SRGB_BLOCK" : "MTLPixelFormatASTC_10x6_sRGB",
29895
+            "ASTC_10x8_SRGB_BLOCK" : "MTLPixelFormatASTC_10x8_sRGB",
29896
+            "ASTC_10x10_SRGB_BLOCK" : "MTLPixelFormatASTC_10x10_sRGB",
29897
+            "ASTC_12x10_SRGB_BLOCK" : "MTLPixelFormatASTC_12x10_sRGB",
29898
+            "ASTC_12x12_SRGB_BLOCK" : "MTLPixelFormatASTC_12x12_sRGB",
29899
+            "ASTC_4x4_UNORM_BLOCK" : "MTLPixelFormatASTC_4x4_LDR",
29900
+            "ASTC_5x4_UNORM_BLOCK" : "MTLPixelFormatASTC_5x4_LDR",
29901
+            "ASTC_5x5_UNORM_BLOCK" : "MTLPixelFormatASTC_5x5_LDR",
29902
+            "ASTC_6x5_UNORM_BLOCK" : "MTLPixelFormatASTC_6x5_LDR",
29903
+            "ASTC_6x6_UNORM_BLOCK" : "MTLPixelFormatASTC_6x6_LDR",
29904
+            "ASTC_8x5_UNORM_BLOCK" : "MTLPixelFormatASTC_8x5_LDR",
29905
+            "ASTC_8x6_UNORM_BLOCK" : "MTLPixelFormatASTC_8x6_LDR",
29906
+            "ASTC_8x8_UNORM_BLOCK" : "MTLPixelFormatASTC_8x8_LDR",
29907
+            "ASTC_10x5_UNORM_BLOCK" : "MTLPixelFormatASTC_10x5_LDR",
29908
+            "ASTC_10x6_UNORM_BLOCK" : "MTLPixelFormatASTC_10x6_LDR",
29909
+            "ASTC_10x8_UNORM_BLOCK" : "MTLPixelFormatASTC_10x8_LDR",
29910
+            "ASTC_10x10_UNORM_BLOCK" : "MTLPixelFormatASTC_10x10_LDR",
29911
+            "ASTC_12x10_UNORM_BLOCK" : "MTLPixelFormatASTC_12x10_LDR",
29912
+            "ASTC_12x12_UNORM_BLOCK" : "MTLPixelFormatASTC_12x12_LDR"
29913
         },
29914
         "map_mac": {
29915
-            "D16_UNORM": "MTLPixelFormatDepth16Unorm",
29916
             "D24_UNORM_S8_UINT": "MTLPixelFormatDepth24Unorm_Stencil8",
29917
             "BC1_RGBA_UNORM_BLOCK": "MTLPixelFormatBC1_RGBA",
29918
             "BC1_RGBA_UNORM_SRGB_BLOCK": "MTLPixelFormatBC1_RGBA_sRGB",
29919
@@ -175,9 +175,7 @@
29920
             "D32_UNORM": "D32_FLOAT"
29921
         },
29922
         "override_ios": {
29923
-            "D24_UNORM_S8_UINT": "D32_FLOAT_S8X24_UINT",
29924
-            "D16_UNORM": "D32_FLOAT",
29925
-            "ETC1_R8G8B8_UNORM_BLOCK": "ETC2_R8G8B8_UNORM_BLOCK"
29926
+            "D24_UNORM_S8_UINT": "D32_FLOAT_S8X24_UINT"
29927
         },
29928
         "override_mac": {
29929
             "R5G6B5_UNORM": "R8G8B8A8_UNORM",
29930
@@ -203,7 +201,8 @@
29931
             "EAC_R11G11_UNORM_BLOCK": "R16G16_UNORM",
29932
             "EAC_R11G11_SNORM_BLOCK": "R16G16_SNORM"
29933
         },
29934
-        "d24s8_fallbacks_mac": {
29935
+        "fallbacks_mac": {
29936
+            "B8G8R8A8_UNORM": "R8G8B8A8_UNORM",
29937
             "D24_UNORM_S8_UINT": "D32_FLOAT_S8X24_UINT"
29938
         },
29939
         "caps": {
29940
diff --git a/src/libANGLE/renderer/metal/mtl_format_table_autogen.mm b/src/libANGLE/renderer/metal/mtl_format_table_autogen.mm
29941
index c21c593..d3ea5b0 100644
29942
--- a/src/libANGLE/renderer/metal/mtl_format_table_autogen.mm
29943
+++ b/src/libANGLE/renderer/metal/mtl_format_table_autogen.mm
29944
@@ -28,7 +28,6 @@
29945
 void Format::init(const DisplayMtl *display, angle::FormatID intendedFormatId_)
29946
 {
29947
     this->intendedFormatId    = intendedFormatId_;
29948
-
29949
     id<MTLDevice> metalDevice = display->getMetalDevice();
29950
 
29951
     // Actual conversion
29952
@@ -43,15 +42,26 @@
29953
             this->swizzled = false;
29954
             break;
29955
 
29956
-        case angle::FormatID::B10G10R10A2_UNORM:
29957
+#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
29958
+        case angle::FormatID::B8G8R8A8_UNORM:
29959
 
29960
-            this->metalFormat    = MTLPixelFormatBGR10A2Unorm;
29961
-            this->actualFormatId = angle::FormatID::B10G10R10A2_UNORM;
29962
+            if (metalDevice.depth24Stencil8PixelFormatSupported)
29963
+            {
29964
+                this->metalFormat    = MTLPixelFormatBGRA8Unorm;
29965
+                this->actualFormatId = angle::FormatID::B8G8R8A8_UNORM;
29966
+                this->initFunction   = nullptr;
29967
+            }
29968
+            else
29969
+            {
29970
+                this->metalFormat    = MTLPixelFormatRGBA8Unorm;
29971
+                this->actualFormatId = angle::FormatID::R8G8B8A8_UNORM;
29972
                 this->initFunction   = nullptr;
29973
+            }
29974
 
29975
             this->swizzled = false;
29976
             break;
29977
 
29978
+#else  // TARGET_OS_OSX || TARGET_OS_MACCATALYST
29979
         case angle::FormatID::B8G8R8A8_UNORM:
29980
 
29981
             this->metalFormat    = MTLPixelFormatBGRA8Unorm;
29982
@@ -61,6 +71,7 @@
29983
             this->swizzled = false;
29984
             break;
29985
 
29986
+#endif  // TARGET_OS_OSX || TARGET_OS_MACCATALYST
29987
         case angle::FormatID::B8G8R8A8_UNORM_SRGB:
29988
 
29989
             this->metalFormat    = MTLPixelFormatBGRA8Unorm_sRGB;
29990
@@ -70,6 +81,36 @@
29991
             this->swizzled = false;
29992
             break;
29993
 
29994
+#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
29995
+        case angle::FormatID::D16_UNORM:
29996
+
29997
+            this->metalFormat    = MTLPixelFormatDepth16Unorm;
29998
+            this->actualFormatId = angle::FormatID::D16_UNORM;
29999
+            this->initFunction   = nullptr;
30000
+
30001
+            this->swizzled = false;
30002
+            break;
30003
+
30004
+#else  // TARGET_OS_OSX || TARGET_OS_MACCATALYST
30005
+        case angle::FormatID::D16_UNORM:
30006
+
30007
+            if ([metalDevice supportsFamily:MTLGPUFamilyApple3])
30008
+            {
30009
+                this->metalFormat    = MTLPixelFormatDepth16Unorm;
30010
+                this->actualFormatId = angle::FormatID::D16_UNORM;
30011
+                this->initFunction   = nullptr;
30012
+            }
30013
+            else
30014
+            {
30015
+                this->metalFormat    = MTLPixelFormatDepth32Float;
30016
+                this->actualFormatId = angle::FormatID::D32_FLOAT;
30017
+                this->initFunction   = nullptr;
30018
+            }
30019
+
30020
+            this->swizzled = false;
30021
+            break;
30022
+
30023
+#endif  // TARGET_OS_OSX || TARGET_OS_MACCATALYST
30024
         case angle::FormatID::D32_FLOAT:
30025
 
30026
             this->metalFormat    = MTLPixelFormatDepth32Float;
30027
@@ -815,15 +856,6 @@
30028
             this->swizzled = false;
30029
             break;
30030
 
30031
-        case angle::FormatID::D16_UNORM:
30032
-
30033
-            this->metalFormat    = MTLPixelFormatDepth16Unorm;
30034
-            this->actualFormatId = angle::FormatID::D16_UNORM;
30035
-            this->initFunction   = nullptr;
30036
-
30037
-            this->swizzled = false;
30038
-            break;
30039
-
30040
         case angle::FormatID::D24_UNORM_S8_UINT:
30041
 
30042
             if (metalDevice.depth24Stencil8PixelFormatSupported &&
30043
@@ -1281,7 +1313,7 @@
30044
 
30045
         case angle::FormatID::EAC_R11G11_UNORM_BLOCK:
30046
 
30047
-            this->metalFormat    = MTLPixelFormatEAC_RG11Unorm;
30048
+            this->metalFormat    = MTLPixelFormatEAC_R11Unorm;
30049
             this->actualFormatId = angle::FormatID::EAC_R11G11_UNORM_BLOCK;
30050
             this->initFunction   = nullptr;
30051
 
30052
@@ -1306,6 +1338,15 @@
30053
             this->swizzled = false;
30054
             break;
30055
 
30056
+        case angle::FormatID::ETC1_R8G8B8_UNORM_BLOCK:
30057
+
30058
+            this->metalFormat    = MTLPixelFormatETC2_RGB8;
30059
+            this->actualFormatId = angle::FormatID::ETC1_R8G8B8_UNORM_BLOCK;
30060
+            this->initFunction   = nullptr;
30061
+
30062
+            this->swizzled = false;
30063
+            break;
30064
+
30065
         case angle::FormatID::ETC2_R8G8B8A1_SRGB_BLOCK:
30066
 
30067
             this->metalFormat    = MTLPixelFormatETC2_RGB8A1_sRGB;
30068
@@ -1459,15 +1500,6 @@
30069
             this->swizzled = false;
30070
             break;
30071
 
30072
-        case angle::FormatID::D16_UNORM:
30073
-
30074
-            this->metalFormat    = MTLPixelFormatDepth32Float;
30075
-            this->actualFormatId = angle::FormatID::D32_FLOAT;
30076
-            this->initFunction   = nullptr;
30077
-
30078
-            this->swizzled = false;
30079
-            break;
30080
-
30081
         case angle::FormatID::D24_UNORM_S8_UINT:
30082
 
30083
             this->metalFormat    = MTLPixelFormatDepth32Float_Stencil8;
30084
@@ -1477,15 +1509,6 @@
30085
             this->swizzled = false;
30086
             break;
30087
 
30088
-        case angle::FormatID::ETC1_R8G8B8_UNORM_BLOCK:
30089
-
30090
-            this->metalFormat    = MTLPixelFormatETC2_RGB8;
30091
-            this->actualFormatId = angle::FormatID::ETC2_R8G8B8_UNORM_BLOCK;
30092
-            this->initFunction   = nullptr;
30093
-
30094
-            this->swizzled = false;
30095
-            break;
30096
-
30097
 #endif  // TARGET_OS_OSX || TARGET_OS_MACCATALYST
30098
         default:
30099
             this->metalFormat    = MTLPixelFormatInvalid;
30100
diff --git a/src/libANGLE/renderer/metal/mtl_format_utils.h b/src/libANGLE/renderer/metal/mtl_format_utils.h
30101
index bbb27d4..f39681d 100644
30102
--- a/src/libANGLE/renderer/metal/mtl_format_utils.h
30103
+++ b/src/libANGLE/renderer/metal/mtl_format_utils.h
30104
@@ -55,6 +55,11 @@ struct FormatCaps
30105
     bool blendable            = false;
30106
     bool multisample          = false;  // can be used as MSAA target
30107
     bool resolve              = false;  // Can be used as resolve target
30108
+    bool compressed           = false;
30109
+    NSUInteger pixelBytes     = 0;
30110
+    NSUInteger pixelBytesMSAA = 0;
30111
+    NSUInteger channels       = 0;
30112
+    uint8_t alignment         = 0;
30113
 };
30114
 
30115
 // Pixel format
30116
@@ -143,6 +148,7 @@ class FormatTable final : angle::NonCopyable
30117
   private:
30118
     void initNativeFormatCapsAutogen(const DisplayMtl *display);
30119
     void initNativeFormatCaps(const DisplayMtl *display);
30120
+
30121
     void setFormatCaps(MTLPixelFormat formatId,
30122
                        bool filterable,
30123
                        bool writable,
30124
@@ -150,6 +156,17 @@ class FormatTable final : angle::NonCopyable
30125
                        bool multisample,
30126
                        bool resolve,
30127
                        bool colorRenderable);
30128
+
30129
+    void setFormatCaps(MTLPixelFormat formatId,
30130
+                       bool filterable,
30131
+                       bool writable,
30132
+                       bool blendable,
30133
+                       bool multisample,
30134
+                       bool resolve,
30135
+                       bool colorRenderable,
30136
+                       NSUInteger bytesPerChannel,
30137
+                       NSUInteger channels);
30138
+
30139
     void setFormatCaps(MTLPixelFormat formatId,
30140
                        bool filterable,
30141
                        bool writable,
30142
@@ -159,8 +176,24 @@ class FormatTable final : angle::NonCopyable
30143
                        bool colorRenderable,
30144
                        bool depthRenderable);
30145
 
30146
+    void setFormatCaps(MTLPixelFormat formatId,
30147
+                       bool filterable,
30148
+                       bool writable,
30149
+                       bool blendable,
30150
+                       bool multisample,
30151
+                       bool resolve,
30152
+                       bool colorRenderable,
30153
+                       bool depthRenderable,
30154
+                       NSUInteger bytesPerChannel,
30155
+                       NSUInteger channels);
30156
+
30157
     void setCompressedFormatCaps(MTLPixelFormat formatId, bool filterable);
30158
 
30159
+    void adjustFormatCapsForDevice(id<MTLDevice> device,
30160
+                                   MTLPixelFormat id,
30161
+                                   bool supportsiOS2,
30162
+                                   bool supportsiOS4);
30163
+
30164
     std::array<Format, angle::kNumANGLEFormats> mPixelFormatTable;
30165
     std::unordered_map<MTLPixelFormat, FormatCaps> mNativePixelFormatCapsTable;
30166
     // One for tightly packed buffers, one for general cases.
30167
diff --git a/src/libANGLE/renderer/metal/mtl_format_utils.mm b/src/libANGLE/renderer/metal/mtl_format_utils.mm
30168
index fb1d5ca..416ad5c 100644
30169
--- a/src/libANGLE/renderer/metal/mtl_format_utils.mm
30170
+++ b/src/libANGLE/renderer/metal/mtl_format_utils.mm
30171
@@ -77,8 +77,8 @@ void GenerateTextureCapsMap(const FormatTable &formatTable,
30172
             textureCaps.renderbuffer =
30173
                 mtlFormat.getCaps().colorRenderable || mtlFormat.getCaps().depthRenderable;
30174
             textureCaps.texturable        = true;
30175
-            textureCaps.blendable         = mtlFormat.getCaps().blendable;
30176
             textureCaps.textureAttachment = textureCaps.renderbuffer;
30177
+            textureCaps.blendable         = mtlFormat.getCaps().blendable;
30178
         }
30179
 
30180
         if (formatCaps.multisample)
30181
@@ -148,12 +148,6 @@ void GenerateTextureCapsMap(const FormatTable &formatTable,
30182
         // WebGL allows unswizzled mapping when swizzling is not available. No need to convert.
30183
         return false;
30184
     }
30185
-    if (srcFormatId == angle::FormatID::ETC1_R8G8B8_UNORM_BLOCK &&
30186
-        actualFormatId == angle::FormatID::ETC2_R8G8B8_UNORM_BLOCK)
30187
-    {
30188
-        // ETC1 RGB & ETC2 RGB are technically the same.
30189
-        return false;
30190
-    }
30191
     return srcFormatId != actualFormatId;
30192
 }
30193
 
30194
@@ -192,8 +186,7 @@ void GenerateTextureCapsMap(const FormatTable &formatTable,
30195
         mPixelFormatTable[i].init(display, formatId);
30196
         mPixelFormatTable[i].caps = &mNativePixelFormatCapsTable[mPixelFormatTable[i].metalFormat];
30197
 
30198
-        if (!mPixelFormatTable[i].caps->depthRenderable &&
30199
-            mPixelFormatTable[i].actualFormatId != mPixelFormatTable[i].intendedFormatId)
30200
+        if (mPixelFormatTable[i].actualFormatId != mPixelFormatTable[i].intendedFormatId)
30201
         {
30202
             mPixelFormatTable[i].textureLoadFunctions = angle::GetLoadFunctionsMap(
30203
                 mPixelFormatTable[i].intendedAngleFormat().glInternalFormat,
30204
@@ -204,6 +197,19 @@ void GenerateTextureCapsMap(const FormatTable &formatTable,
30205
         mVertexFormatTables[1][i].init(formatId, true);
30206
     }
30207
 
30208
+    // NOTE(hqle): Work-around AMD's issue that D24S8 format sometimes returns zero during sampling:
30209
+    if (display->getRendererDescription().find("AMD") != std::string::npos)
30210
+    {
30211
+        // Fallback to D32_FLOAT_S8X24_UINT.
30212
+        Format &format =
30213
+            mPixelFormatTable[static_cast<uint32_t>(angle::FormatID::D24_UNORM_S8_UINT)];
30214
+        format.actualFormatId       = angle::FormatID::D32_FLOAT_S8X24_UINT;
30215
+        format.metalFormat          = MTLPixelFormatDepth32Float_Stencil8;
30216
+        format.initFunction         = nullptr;
30217
+        format.textureLoadFunctions = nullptr;
30218
+        format.caps = &mNativePixelFormatCapsTable[MTLPixelFormatDepth32Float_Stencil8];
30219
+    }
30220
+
30221
     return angle::Result::Continue;
30222
 }
30223
 
30224
@@ -239,10 +245,23 @@ void GenerateTextureCapsMap(const FormatTable &formatTable,
30225
                                 bool colorRenderable)
30226
 {
30227
     setFormatCaps(formatId, filterable, writable, blendable, multisample, resolve, colorRenderable,
30228
-                  false);
30229
+                  false, 0);
30230
+}
30231
+void FormatTable::setFormatCaps(MTLPixelFormat formatId,
30232
+                                bool filterable,
30233
+                                bool writable,
30234
+                                bool blendable,
30235
+                                bool multisample,
30236
+                                bool resolve,
30237
+                                bool colorRenderable,
30238
+                                NSUInteger pixelBytes,
30239
+                                NSUInteger channels)
30240
+{
30241
+    setFormatCaps(formatId, filterable, writable, blendable, multisample, resolve, colorRenderable,
30242
+                  false, pixelBytes, channels);
30243
 }
30244
 
30245
-void FormatTable::setFormatCaps(MTLPixelFormat id,
30246
+void FormatTable::setFormatCaps(MTLPixelFormat formatId,
30247
                                 bool filterable,
30248
                                 bool writable,
30249
                                 bool blendable,
30250
@@ -250,6 +269,20 @@ void GenerateTextureCapsMap(const FormatTable &formatTable,
30251
                                 bool resolve,
30252
                                 bool colorRenderable,
30253
                                 bool depthRenderable)
30254
+{
30255
+    setFormatCaps(formatId, filterable, writable, blendable, multisample, resolve, colorRenderable,
30256
+                  depthRenderable, 0, 0);
30257
+}
30258
+void FormatTable::setFormatCaps(MTLPixelFormat id,
30259
+                                bool filterable,
30260
+                                bool writable,
30261
+                                bool blendable,
30262
+                                bool multisample,
30263
+                                bool resolve,
30264
+                                bool colorRenderable,
30265
+                                bool depthRenderable,
30266
+                                NSUInteger pixelBytes,
30267
+                                NSUInteger channels)
30268
 {
30269
     mNativePixelFormatCapsTable[id].filterable      = filterable;
30270
     mNativePixelFormatCapsTable[id].writable        = writable;
30271
@@ -258,6 +291,11 @@ void GenerateTextureCapsMap(const FormatTable &formatTable,
30272
     mNativePixelFormatCapsTable[id].blendable       = blendable;
30273
     mNativePixelFormatCapsTable[id].multisample     = multisample;
30274
     mNativePixelFormatCapsTable[id].resolve         = resolve;
30275
+    mNativePixelFormatCapsTable[id].pixelBytes      = pixelBytes;
30276
+    mNativePixelFormatCapsTable[id].pixelBytesMSAA  = pixelBytes;
30277
+    mNativePixelFormatCapsTable[id].channels        = channels;
30278
+    if (channels != 0)
30279
+        mNativePixelFormatCapsTable[id].alignment = MAX(pixelBytes / channels, 1U);
30280
 }
30281
 
30282
 void FormatTable::setCompressedFormatCaps(MTLPixelFormat formatId, bool filterable)
30283
@@ -265,9 +303,274 @@ void GenerateTextureCapsMap(const FormatTable &formatTable,
30284
     setFormatCaps(formatId, filterable, false, false, false, false, false, false);
30285
 }
30286
 
30287
+void FormatTable::adjustFormatCapsForDevice(id<MTLDevice> device,
30288
+                                            MTLPixelFormat id,
30289
+                                            bool supportsiOS2,
30290
+                                            bool supportsiOS4)
30291
+{
30292
+#if !(TARGET_OS_OSX || TARGET_OS_MACCATALYST)
30293
+
30294
+    NSUInteger pixelBytesRender     = mNativePixelFormatCapsTable[id].pixelBytes;
30295
+    NSUInteger pixelBytesRenderMSAA = mNativePixelFormatCapsTable[id].pixelBytesMSAA;
30296
+    NSUInteger alignment            = mNativePixelFormatCapsTable[id].alignment;
30297
+
30298
+// Override the current pixelBytesRender
30299
+#    define SPECIFIC(_pixelFormat, _pixelBytesRender)                                            \
30300
+        case _pixelFormat:                                                                       \
30301
+            pixelBytesRender     = _pixelBytesRender;                                            \
30302
+            pixelBytesRenderMSAA = _pixelBytesRender;                                            \
30303
+            alignment =                                                                          \
30304
+                supportsiOS4 ? _pixelBytesRender / mNativePixelFormatCapsTable[id].channels : 4; \
30305
+            break
30306
+// Override the current pixel bytes render, and MSAA
30307
+#    define SPECIFIC_MSAA(_pixelFormat, _pixelBytesRender, _pixelBytesRenderMSAA)                \
30308
+        case _pixelFormat:                                                                       \
30309
+            pixelBytesRender     = _pixelBytesRender;                                            \
30310
+            pixelBytesRenderMSAA = _pixelBytesRenderMSAA;                                        \
30311
+            alignment =                                                                          \
30312
+                supportsiOS4 ? _pixelBytesRender / mNativePixelFormatCapsTable[id].channels : 4; \
30313
+            break
30314
+// Override the current pixelBytesRender, and alignment
30315
+#    define SPECIFIC_ALIGN(_pixelFormat, _pixelBytesRender, _alignment) \
30316
+        case _pixelFormat:                                              \
30317
+            pixelBytesRender     = _pixelBytesRender;                   \
30318
+            pixelBytesRenderMSAA = _pixelBytesRender;                   \
30319
+            alignment            = _alignment;                          \
30320
+            break
30321
+
30322
+    if (!mNativePixelFormatCapsTable[id].compressed)
30323
+    {
30324
+        // On AppleGPUFamily4+, there is no 4byte minimum requirement for render targets
30325
+        uint32_t minSize     = supportsiOS4 ? 1U : 4U;
30326
+        pixelBytesRender     = MAX(mNativePixelFormatCapsTable[id].pixelBytes, minSize);
30327
+        pixelBytesRenderMSAA = pixelBytesRender;
30328
+        alignment =
30329
+            supportsiOS4 ? MAX(pixelBytesRender / mNativePixelFormatCapsTable[id].channels, 1U) : 4;
30330
+    }
30331
+
30332
+    // This list of tables starts from a general multi-platform table,
30333
+    // to specific platforms (i.e. ios2, ios4) inheriting from the previous tables
30334
+
30335
+    // Start off with the general case
30336
+    switch ((NSUInteger)id)
30337
+    {
30338
+        SPECIFIC(MTLPixelFormatB5G6R5Unorm, 4U);
30339
+        SPECIFIC(MTLPixelFormatA1BGR5Unorm, 4U);
30340
+        SPECIFIC(MTLPixelFormatABGR4Unorm, 4U);
30341
+        SPECIFIC(MTLPixelFormatBGR5A1Unorm, 4U);
30342
+
30343
+        SPECIFIC(MTLPixelFormatRGBA8Unorm, 4U);
30344
+        SPECIFIC(MTLPixelFormatBGRA8Unorm, 4U);
30345
+
30346
+        SPECIFIC_MSAA(MTLPixelFormatRGBA8Unorm_sRGB, 4U, 8U);
30347
+        SPECIFIC_MSAA(MTLPixelFormatBGRA8Unorm_sRGB, 4U, 8U);
30348
+        SPECIFIC_MSAA(MTLPixelFormatRGBA8Snorm, 4U, 8U);
30349
+        SPECIFIC_MSAA(MTLPixelFormatRGB10A2Uint, 4U, 8U);
30350
+
30351
+        SPECIFIC(MTLPixelFormatRGB10A2Unorm, 8U);
30352
+        SPECIFIC(MTLPixelFormatBGR10A2Unorm, 8U);
30353
+
30354
+        SPECIFIC(MTLPixelFormatRG11B10Float, 8U);
30355
+
30356
+        SPECIFIC(MTLPixelFormatRGB9E5Float, 8U);
30357
+
30358
+        SPECIFIC(MTLPixelFormatStencil8, 1U);
30359
+    }
30360
+
30361
+    // Override based ios2
30362
+    if (supportsiOS2)
30363
+    {
30364
+        switch ((NSUInteger)id)
30365
+        {
30366
+            SPECIFIC(MTLPixelFormatB5G6R5Unorm, 8U);
30367
+            SPECIFIC(MTLPixelFormatA1BGR5Unorm, 8U);
30368
+            SPECIFIC(MTLPixelFormatABGR4Unorm, 8U);
30369
+            SPECIFIC(MTLPixelFormatBGR5A1Unorm, 8U);
30370
+            SPECIFIC_MSAA(MTLPixelFormatRGBA8Unorm, 4U, 8U);
30371
+            SPECIFIC_MSAA(MTLPixelFormatBGRA8Unorm, 4U, 8U);
30372
+        }
30373
+    }
30374
+
30375
+    // Override based on ios4
30376
+    if (supportsiOS4)
30377
+    {
30378
+        switch ((NSUInteger)id)
30379
+        {
30380
+            SPECIFIC_ALIGN(MTLPixelFormatB5G6R5Unorm, 6U, 2U);
30381
+            SPECIFIC(MTLPixelFormatRGBA8Unorm, 4U);
30382
+            SPECIFIC(MTLPixelFormatBGRA8Unorm, 4U);
30383
+
30384
+            SPECIFIC(MTLPixelFormatRGBA8Unorm_sRGB, 4U);
30385
+            SPECIFIC(MTLPixelFormatBGRA8Unorm_sRGB, 4U);
30386
+
30387
+            SPECIFIC(MTLPixelFormatRGBA8Snorm, 4U);
30388
+
30389
+            SPECIFIC_ALIGN(MTLPixelFormatRGB10A2Unorm, 4U, 4U);
30390
+            SPECIFIC_ALIGN(MTLPixelFormatBGR10A2Unorm, 4U, 4U);
30391
+            SPECIFIC(MTLPixelFormatRGB10A2Uint, 8U);
30392
+
30393
+            SPECIFIC_ALIGN(MTLPixelFormatRG11B10Float, 4U, 4U);
30394
+
30395
+            SPECIFIC_ALIGN(MTLPixelFormatRGB9E5Float, 4U, 4U);
30396
+        }
30397
+    }
30398
+    mNativePixelFormatCapsTable[id].pixelBytes     = pixelBytesRender;
30399
+    mNativePixelFormatCapsTable[id].pixelBytesMSAA = pixelBytesRenderMSAA;
30400
+    mNativePixelFormatCapsTable[id].alignment      = alignment;
30401
+
30402
+#    undef SPECIFIC
30403
+#    undef SPECIFIC_ALIGN
30404
+#    undef SPECIFIC_MSAA
30405
+#endif
30406
+    // macOS does not need to perform any additoinal adjustment. These values are only used to check
30407
+    // valid MRT sizes on iOS.
30408
+}
30409
+
30410
 void FormatTable::initNativeFormatCaps(const DisplayMtl *display)
30411
 {
30412
-    initNativeFormatCapsAutogen(display);
30413
+    const angle::FeaturesMtl &featuresMtl = display->getFeatures();
30414
+    // Skip auto resolve if either hasDepth/StencilAutoResolve or allowMultisampleStoreAndResolve
30415
+    // feature are disabled.
30416
+    bool supportDepthAutoResolve = featuresMtl.hasDepthAutoResolve.enabled &&
30417
+                                   featuresMtl.allowMultisampleStoreAndResolve.enabled;
30418
+    bool supportStencilAutoResolve = featuresMtl.hasStencilAutoResolve.enabled &&
30419
+                                     featuresMtl.allowMultisampleStoreAndResolve.enabled;
30420
+    bool supportDepthStencilAutoResolve = supportDepthAutoResolve && supportStencilAutoResolve;
30421
+
30422
+    // Source: https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
30423
+    // clang-format off
30424
+
30425
+    //            |  formatId                  | filterable    |  writable  |  blendable |  multisample |  resolve                              | colorRenderable | bytesPerChannel | channel
30426
+    setFormatCaps(MTLPixelFormatA8Unorm,        true,            false,       false,          false,       false,                                false, 1U, 1U);
30427
+    setFormatCaps(MTLPixelFormatR8Unorm,        true,            true,        true,           true,        true,                                 true,  1U, 1U);
30428
+    setFormatCaps(MTLPixelFormatR8Snorm,        true,            true,        true,           true,      display->supportsEitherGPUFamily(2, 1),  true,  1U, 1U);
30429
+    setFormatCaps(MTLPixelFormatR16Unorm,       true,            true,        true,           true,      display->supportsEitherGPUFamily(1, 1),        true,  2U, 1U);
30430
+    setFormatCaps(MTLPixelFormatR16Snorm,       true,            true,        true,           true,      display->supportsEitherGPUFamily(1, 1),        true,  2U, 1U);
30431
+    setFormatCaps(MTLPixelFormatRG8Unorm,       true,            true,        true,           true,        true,                                 true,  1U, 1U);
30432
+    setFormatCaps(MTLPixelFormatRG8Snorm,       true,            true,        true,           true,      display->supportsEitherGPUFamily(2, 1),  true,  2U, 2U);
30433
+    setFormatCaps(MTLPixelFormatRG16Unorm,      true,            true,        true,           true,      display->supportsEitherGPUFamily(1, 1),        true,  4U, 2U);
30434
+    setFormatCaps(MTLPixelFormatRG16Snorm,      true,            true,        true,           true,      display->supportsEitherGPUFamily(1, 1),        true,  4U, 2U);
30435
+    setFormatCaps(MTLPixelFormatRGBA16Unorm,    true,            true,        true,           true,      display->supportsEitherGPUFamily(1, 1),        true,  8U, 4U);
30436
+    setFormatCaps(MTLPixelFormatRGBA16Snorm,    true,            true,        true,           true,      display->supportsEitherGPUFamily(1, 1),        true,  8U, 4U);
30437
+    setFormatCaps(MTLPixelFormatRGBA16Float,    true,            true,        true,           true,        true,                                 true,  8U, 4U);
30438
+
30439
+    //            |  formatId                      | filterable    |  writable                         |  blendable |  multisample |  resolve                              | colorRenderable |
30440
+    setFormatCaps(MTLPixelFormatRGBA8Unorm,          true,            true,                               true,           true,        true,                                    true,   4U, 4U);
30441
+    setFormatCaps(MTLPixelFormatRGBA8Unorm_sRGB,     true,          display->supportsIOSGPUFamily(2),      true,           true,        true,                                    true,   4U, 4U);
30442
+    setFormatCaps(MTLPixelFormatRGBA8Snorm,          true,            true,                               true,           true,     display->supportsEitherGPUFamily(2, 1),      true,   4U, 4U);
30443
+    setFormatCaps(MTLPixelFormatBGRA8Unorm,          true,            true,                               true,           true,        true,                                    true,   4U, 4U);
30444
+    setFormatCaps(MTLPixelFormatBGRA8Unorm_sRGB,     true,          display->supportsIOSGPUFamily(2),      true,           true,        true,                                    true,   4U, 4U);
30445
+
30446
+    //            |  formatId              | filterable                    |  writable  |  blendable |  multisample |  resolve                              | colorRenderable |
30447
+    setFormatCaps(MTLPixelFormatR16Float,       true,                          true,        true,           true,        true,                                 true,    2U, 1U);
30448
+    setFormatCaps(MTLPixelFormatRG16Float,      true,                          true,        true,           true,        true,                                 true,    4U, 2U);
30449
+    setFormatCaps(MTLPixelFormatR32Float,    display->supportsEitherGPUFamily(1,1),  true,        true,           true,      display->supportsEitherGPUFamily(1,1),        true,    4U, 1U);
30450
+
30451
+#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST
30452
+    //            |  formatId                  | filterable    |  writable  |  blendable |  multisample |  resolve   | colorRenderable |
30453
+    setFormatCaps(MTLPixelFormatB5G6R5Unorm,      true,            false,        true,           true,        true,      true,  2U, 3U);
30454
+    setFormatCaps(MTLPixelFormatABGR4Unorm,       true,            false,        true,           true,        true,      true,  2U, 4U);
30455
+    setFormatCaps(MTLPixelFormatBGR5A1Unorm,      true,            false,        true,           true,        true,      true,  2U, 4U);
30456
+    setFormatCaps(MTLPixelFormatA1BGR5Unorm,      true,            false,        true,           true,        true,      true,  2U, 4U);
30457
+#endif
30458
+
30459
+    //            |  formatId                  | filterable    |  writable                                 |  blendable |  multisample |  resolve   | colorRenderable |
30460
+    setFormatCaps(MTLPixelFormatBGR10A2Unorm,     true,         display->supportsEitherGPUFamily(3, 1),       true,           true,        true,      true,  4U, 4U);
30461
+    setFormatCaps(MTLPixelFormatRGB10A2Unorm,     true,         display->supportsEitherGPUFamily(3, 1),       true,           true,        true,      true,  4U, 4U);
30462
+    setFormatCaps(MTLPixelFormatRGB10A2Uint,      false,        display->supportsEitherGPUFamily(3, 1),       false,          true,        false,     true,  4U, 4U);
30463
+    setFormatCaps(MTLPixelFormatRG11B10Float,     true,         display->supportsEitherGPUFamily(3, 1),       true,           true,        true,      true,  4U, 3U);
30464
+
30465
+    //            |  formatId                  | filterable    |  writable                         |  blendable                     |  multisample                    |  resolve                       | colorRenderable                 |
30466
+    setFormatCaps(MTLPixelFormatRGB9E5Float,       true,          display->supportsIOSGPUFamily(3),  display->supportsIOSGPUFamily(1),  display->supportsIOSGPUFamily(1), display->supportsIOSGPUFamily(1), display->supportsIOSGPUFamily(1), 4U, 3U);
30467
+
30468
+    //            |  formatId               | filterable    |  writable  |  blendable  |  multisample                        |  resolve      | colorRenderable |
30469
+    setFormatCaps(MTLPixelFormatR8Uint,        false,           true,        false,          true,                             false,         true, 1U, 1U);
30470
+    setFormatCaps(MTLPixelFormatR8Sint,        false,           true,        false,          true,                             false,         true, 1U, 1U);
30471
+    setFormatCaps(MTLPixelFormatR16Uint,       false,           true,        false,          true,                             false,         true, 2U, 1U);
30472
+    setFormatCaps(MTLPixelFormatR16Sint,       false,           true,        false,          true,                             false,         true, 4U, 1U);
30473
+    setFormatCaps(MTLPixelFormatRG8Uint,       false,           true,        false,          true,                             false,         true, 2U, 2U);
30474
+    setFormatCaps(MTLPixelFormatRG8Sint,       false,           true,        false,          true,                             false,         true, 2U, 2U);
30475
+    setFormatCaps(MTLPixelFormatR32Uint,       false,           true,        false,          display->supportsEitherGPUFamily(1,1),  false,         true, 4U, 1U);
30476
+    setFormatCaps(MTLPixelFormatR32Sint,       false,           true,        false,          display->supportsEitherGPUFamily(1,1),  false,         true, 4U, 1U);
30477
+    setFormatCaps(MTLPixelFormatRG16Uint,      false,           true,        false,          true,                             false,         true, 4U, 2U);
30478
+    setFormatCaps(MTLPixelFormatRG16Sint,      false,           true,        false,          true,                             false,         true, 4U, 2U);
30479
+    setFormatCaps(MTLPixelFormatRGBA8Uint,     false,           true,        false,          true,                             false,         true, 4U, 1U);
30480
+    setFormatCaps(MTLPixelFormatRGBA8Sint,     false,           true,        false,          true,                             false,         true, 4U, 1U);
30481
+    setFormatCaps(MTLPixelFormatRG32Uint,      false,           true,        false,          display->supportsEitherGPUFamily(1,1),  false,         true, 8U, 2U);
30482
+    setFormatCaps(MTLPixelFormatRG32Sint,      false,           true,        false,          display->supportsEitherGPUFamily(1,1),  false,         true, 8U, 2U);
30483
+    setFormatCaps(MTLPixelFormatRGBA16Uint,    false,           true,        false,          true,                             false,         true, 8U, 4U);
30484
+    setFormatCaps(MTLPixelFormatRGBA16Sint,    false,           true,        false,          true,                             false,         true, 8U, 4U);
30485
+    setFormatCaps(MTLPixelFormatRGBA32Uint,    false,           true,        false,          display->supportsEitherGPUFamily(1,1),  false,         true, 16U, 4U);
30486
+    setFormatCaps(MTLPixelFormatRGBA32Sint,    false,           true,        false,          display->supportsEitherGPUFamily(1,1),  false,         true, 16U, 4U);
30487
+
30488
+    //            |  formatId                   | filterable                      |  writable  |  blendable                     |  multisample                     |  resolve                         | colorRenderable |
30489
+    setFormatCaps(MTLPixelFormatRG32Float,       display->supportsEitherGPUFamily(1,1),   true,        true,                            display->supportsEitherGPUFamily(1,1),  display->supportsEitherGPUFamily(1,1),         true,  8U, 2U);
30490
+    setFormatCaps(MTLPixelFormatRGBA32Float,     display->supportsEitherGPUFamily(1,1),   true,        display->supportsEitherGPUFamily(1,1), display->supportsEitherGPUFamily(1,1),  display->supportsEitherGPUFamily(1,1),         true,  16U, 4U);
30491
+
30492
+    //            |  formatId                           | filterable                       |  writable  |  blendable |  multisample |  resolve                                | colorRenderable | depthRenderable                    |
30493
+    setFormatCaps(MTLPixelFormatDepth32Float,               display->supportsEitherGPUFamily(1,1),   false,        false,           true,    supportDepthAutoResolve,                    false,            true,  4U, 1U);
30494
+    setFormatCaps(MTLPixelFormatStencil8,                   false,                             false,        false,           true,    false,                                      false,            true,  1U, 1U);
30495
+    setFormatCaps(MTLPixelFormatDepth32Float_Stencil8,      display->supportsEitherGPUFamily(1,1),   false,        false,           true,    supportDepthStencilAutoResolve,             false,            true,  8U, 2U);
30496
+//ToDo: @available on 13.0
30497
+    setFormatCaps(MTLPixelFormatDepth16Unorm,               true,                              false,        false,           true,    supportDepthAutoResolve,                    false,            true,  2U, 1U);
30498
+#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
30499
+    setFormatCaps(MTLPixelFormatDepth24Unorm_Stencil8,      display->supportsEitherGPUFamily(1,1),   false,        false,           true,    supportDepthStencilAutoResolve,             false,            display->supportsEitherGPUFamily(1,1), 4U, 2U);
30500
+
30501
+    setCompressedFormatCaps(MTLPixelFormatBC1_RGBA, true);
30502
+    setCompressedFormatCaps(MTLPixelFormatBC1_RGBA_sRGB, true);
30503
+    setCompressedFormatCaps(MTLPixelFormatBC2_RGBA, true);
30504
+    setCompressedFormatCaps(MTLPixelFormatBC2_RGBA_sRGB, true);
30505
+    setCompressedFormatCaps(MTLPixelFormatBC3_RGBA, true);
30506
+    setCompressedFormatCaps(MTLPixelFormatBC3_RGBA_sRGB, true);
30507
+#else
30508
+    setCompressedFormatCaps(MTLPixelFormatPVRTC_RGB_2BPP, true);
30509
+    setCompressedFormatCaps(MTLPixelFormatPVRTC_RGB_2BPP_sRGB, true);
30510
+    setCompressedFormatCaps(MTLPixelFormatPVRTC_RGB_4BPP, true);
30511
+    setCompressedFormatCaps(MTLPixelFormatPVRTC_RGB_4BPP_sRGB, true);
30512
+    setCompressedFormatCaps(MTLPixelFormatPVRTC_RGBA_2BPP, true);
30513
+    setCompressedFormatCaps(MTLPixelFormatPVRTC_RGBA_2BPP_sRGB, true);
30514
+    setCompressedFormatCaps(MTLPixelFormatPVRTC_RGBA_4BPP, true);
30515
+    setCompressedFormatCaps(MTLPixelFormatPVRTC_RGBA_4BPP_sRGB, true);
30516
+    setCompressedFormatCaps(MTLPixelFormatEAC_R11Unorm, true);
30517
+    setCompressedFormatCaps(MTLPixelFormatEAC_R11Snorm, true);
30518
+    setCompressedFormatCaps(MTLPixelFormatEAC_RG11Unorm, true);
30519
+    setCompressedFormatCaps(MTLPixelFormatEAC_RG11Snorm, true);
30520
+    setCompressedFormatCaps(MTLPixelFormatEAC_RGBA8, true);
30521
+    setCompressedFormatCaps(MTLPixelFormatEAC_RGBA8_sRGB, true);
30522
+    setCompressedFormatCaps(MTLPixelFormatETC2_RGB8, true);
30523
+    setCompressedFormatCaps(MTLPixelFormatETC2_RGB8_sRGB, true);
30524
+    setCompressedFormatCaps(MTLPixelFormatETC2_RGB8A1, true);
30525
+    setCompressedFormatCaps(MTLPixelFormatETC2_RGB8A1_sRGB, true);
30526
+    setCompressedFormatCaps(MTLPixelFormatASTC_4x4_sRGB, true);
30527
+    setCompressedFormatCaps(MTLPixelFormatASTC_5x4_sRGB, true);
30528
+    setCompressedFormatCaps(MTLPixelFormatASTC_5x5_sRGB, true);
30529
+    setCompressedFormatCaps(MTLPixelFormatASTC_6x5_sRGB, true);
30530
+    setCompressedFormatCaps(MTLPixelFormatASTC_6x6_sRGB, true);
30531
+    setCompressedFormatCaps(MTLPixelFormatASTC_8x5_sRGB, true);
30532
+    setCompressedFormatCaps(MTLPixelFormatASTC_8x6_sRGB, true);
30533
+    setCompressedFormatCaps(MTLPixelFormatASTC_8x8_sRGB, true);
30534
+    setCompressedFormatCaps(MTLPixelFormatASTC_10x5_sRGB, true);
30535
+    setCompressedFormatCaps(MTLPixelFormatASTC_10x6_sRGB, true);
30536
+    setCompressedFormatCaps(MTLPixelFormatASTC_10x8_sRGB, true);
30537
+    setCompressedFormatCaps(MTLPixelFormatASTC_10x10_sRGB, true);
30538
+    setCompressedFormatCaps(MTLPixelFormatASTC_12x10_sRGB, true);
30539
+    setCompressedFormatCaps(MTLPixelFormatASTC_12x12_sRGB, true);
30540
+    setCompressedFormatCaps(MTLPixelFormatASTC_4x4_LDR, true);
30541
+    setCompressedFormatCaps(MTLPixelFormatASTC_5x4_LDR, true);
30542
+    setCompressedFormatCaps(MTLPixelFormatASTC_5x5_LDR, true);
30543
+    setCompressedFormatCaps(MTLPixelFormatASTC_6x5_LDR, true);
30544
+    setCompressedFormatCaps(MTLPixelFormatASTC_6x6_LDR, true);
30545
+    setCompressedFormatCaps(MTLPixelFormatASTC_8x5_LDR, true);
30546
+    setCompressedFormatCaps(MTLPixelFormatASTC_8x6_LDR, true);
30547
+    setCompressedFormatCaps(MTLPixelFormatASTC_8x8_LDR, true);
30548
+    setCompressedFormatCaps(MTLPixelFormatASTC_10x5_LDR, true);
30549
+    setCompressedFormatCaps(MTLPixelFormatASTC_10x6_LDR, true);
30550
+    setCompressedFormatCaps(MTLPixelFormatASTC_10x8_LDR, true);
30551
+    setCompressedFormatCaps(MTLPixelFormatASTC_10x10_LDR, true);
30552
+    setCompressedFormatCaps(MTLPixelFormatASTC_12x10_LDR, true);
30553
+    setCompressedFormatCaps(MTLPixelFormatASTC_12x12_LDR, true);
30554
+#endif
30555
+    // clang-format on
30556
 }
30557
 
30558
 }  // namespace mtl
30559
diff --git a/src/libANGLE/renderer/metal/mtl_glslang_mtl_utils.h b/src/libANGLE/renderer/metal/mtl_glslang_mtl_utils.h
30560
new file mode 100644
30561
index 0000000..dbc1099
30562
--- /dev/null
30563
+++ b/src/libANGLE/renderer/metal/mtl_glslang_mtl_utils.h
30564
@@ -0,0 +1,57 @@
30565
+//
30566
+//  mtl_glslang_mtl_utils.h
30567
+//  ANGLE
30568
+//
30569
+//  Created by Kyle Piddington on 11/10/20.
30570
+//
30571
+
30572
+#ifndef mtl_glslang_mtl_utils_h
30573
+#define mtl_glslang_mtl_utils_h
30574
+#include "libANGLE/Context.h"
30575
+#include "libANGLE/renderer/ProgramImpl.h"
30576
+#include "libANGLE/renderer/glslang_wrapper_utils.h"
30577
+#include "libANGLE/renderer/metal/mtl_common.h"
30578
+
30579
+namespace rx
30580
+{
30581
+namespace mtl
30582
+{
30583
+struct SamplerBinding
30584
+{
30585
+    uint32_t textureBinding = 0;
30586
+    uint32_t samplerBinding = 0;
30587
+};
30588
+
30589
+struct TranslatedShaderInfo
30590
+{
30591
+    void reset();
30592
+    // Translated Metal source code
30593
+    std::string metalShaderSource;
30594
+    // Metal library compiled from source code above. Used by ProgramMtl.
30595
+    AutoObjCPtr<id<MTLLibrary>> metalLibrary;
30596
+    std::array<SamplerBinding, kMaxGLSamplerBindings> actualSamplerBindings;
30597
+    std::array<uint32_t, kMaxGLUBOBindings> actualUBOBindings;
30598
+    std::array<uint32_t, kMaxShaderXFBs> actualXFBBindings;
30599
+    bool hasUBOArgumentBuffer;
30600
+};
30601
+void MSLGetShaderSource(const gl::ProgramState &programState,
30602
+                        const gl::ProgramLinkedResources &resources,
30603
+                        gl::ShaderMap<std::string> *shaderSourcesOut,
30604
+                        ShaderMapInterfaceVariableInfoMap *variableInfoMapOut);
30605
+
30606
+angle::Result GlslangGetMSL(const gl::Context *glContext,
30607
+                            const gl::ProgramState &programState,
30608
+                            const gl::Caps &glCaps,
30609
+                            const gl::ShaderMap<std::string> &shaderSources,
30610
+                            const ShaderMapInterfaceVariableInfoMap &variableInfoMap,
30611
+                            gl::ShaderMap<TranslatedShaderInfo> *mslShaderInfoOut,
30612
+                            gl::ShaderMap<std::string> *mslCodeOut,
30613
+                            size_t xfbBufferCount);
30614
+
30615
+// Get equivalent shadow compare mode that is used in translated msl shader.
30616
+uint MslGetShaderShadowCompareMode(GLenum mode, GLenum func);
30617
+
30618
+}  // namespace mtl
30619
+}  // namespace rx
30620
+
30621
+#endif /* mtl_glslang_mtl_utils_h */
30622
diff --git a/src/libANGLE/renderer/metal/mtl_glslang_mtl_utils.mm b/src/libANGLE/renderer/metal/mtl_glslang_mtl_utils.mm
30623
new file mode 100644
30624
index 0000000..35f5bef
30625
--- /dev/null
30626
+++ b/src/libANGLE/renderer/metal/mtl_glslang_mtl_utils.mm
30627
@@ -0,0 +1,241 @@
30628
+//
30629
+//  mgl_glslang_mtl_utils.m
30630
+//  ANGLE (static)
30631
+//
30632
+//  Created by Kyle Piddington on 11/10/20.
30633
+//
30634
+
30635
+#import <Foundation/Foundation.h>
30636
+
30637
+#include "compiler/translator/TranslatorMetalDirect.h"
30638
+#include "libANGLE/renderer/metal/ShaderMtl.h"
30639
+#include "libANGLE/renderer/metal/mtl_glslang_mtl_utils.h"
30640
+
30641
+namespace rx
30642
+{
30643
+namespace mtl
30644
+{
30645
+
30646
+void TranslatedShaderInfo::reset()
30647
+{
30648
+    metalShaderSource.clear();
30649
+    metalLibrary         = nil;
30650
+    hasUBOArgumentBuffer = false;
30651
+    for (mtl::SamplerBinding &binding : actualSamplerBindings)
30652
+    {
30653
+        binding.textureBinding = mtl::kMaxShaderSamplers;
30654
+    }
30655
+
30656
+    for (uint32_t &binding : actualUBOBindings)
30657
+    {
30658
+        binding = mtl::kMaxShaderBuffers;
30659
+    }
30660
+
30661
+    for (uint32_t &binding : actualXFBBindings)
30662
+    {
30663
+        binding = mtl::kMaxShaderBuffers;
30664
+    }
30665
+}
30666
+
30667
+// Original mapping of front end from sampler name to multiple sampler slots (in form of
30668
+// slot:count pair)
30669
+using OriginalSamplerBindingMap =
30670
+    std::unordered_map<std::string, std::vector<std::pair<uint32_t, uint32_t>>>;
30671
+
30672
+bool MappedSamplerNameNeedsUserDefinedPrefix(const std::string &originalName)
30673
+{
30674
+    return originalName.find('.') == std::string::npos;
30675
+}
30676
+
30677
+static std::string MSLGetMappedSamplerName(const std::string &originalName)
30678
+{
30679
+    std::string samplerName = originalName;
30680
+
30681
+    // Samplers in structs are extracted.
30682
+    std::replace(samplerName.begin(), samplerName.end(), '.', '_');
30683
+
30684
+    // Remove array elements
30685
+    auto out = samplerName.begin();
30686
+    for (auto in = samplerName.begin(); in != samplerName.end(); in++)
30687
+    {
30688
+        if (*in == '[')
30689
+        {
30690
+            while (*in != ']')
30691
+            {
30692
+                in++;
30693
+                ASSERT(in != samplerName.end());
30694
+            }
30695
+        }
30696
+        else
30697
+        {
30698
+            *out++ = *in;
30699
+        }
30700
+    }
30701
+
30702
+    samplerName.erase(out, samplerName.end());
30703
+
30704
+    if (MappedSamplerNameNeedsUserDefinedPrefix(originalName))
30705
+    {
30706
+        samplerName = sh::kUserDefinedNamePrefix + samplerName;
30707
+    }
30708
+
30709
+    return samplerName;
30710
+}
30711
+
30712
+void MSLGetShaderSource(const gl::ProgramState &programState,
30713
+                        const gl::ProgramLinkedResources &resources,
30714
+                        gl::ShaderMap<std::string> *shaderSourcesOut,
30715
+                        ShaderMapInterfaceVariableInfoMap *variableInfoMapOut)
30716
+{
30717
+    for (const gl::ShaderType shaderType : gl::AllShaderTypes())
30718
+    {
30719
+        gl::Shader *glShader            = programState.getAttachedShader(shaderType);
30720
+        (*shaderSourcesOut)[shaderType] = glShader ? glShader->getTranslatedSource() : "";
30721
+    }
30722
+}
30723
+
30724
+void GetAssignedSamplerBindings(const sh::TranslatorMetalReflection *reflection,
30725
+                                const OriginalSamplerBindingMap &originalBindings,
30726
+                                std::unordered_set<std::string> &structSamplers,
30727
+                                std::array<SamplerBinding, mtl::kMaxGLSamplerBindings> *bindings)
30728
+{
30729
+    for (auto &sampler : reflection->getSamplerBindings())
30730
+    {
30731
+        const std::string &name          = sampler.first;
30732
+        const uint32_t actualSamplerSlot = (uint32_t)reflection->getSamplerBinding(name);
30733
+        const uint32_t actualTextureSlot = (uint32_t)reflection->getTextureBinding(name);
30734
+
30735
+        // Assign sequential index for subsequent array elements
30736
+        const bool structSampler = structSamplers.find(name) != structSamplers.end();
30737
+        const std::string mappedName =
30738
+            structSampler ? name : MSLGetMappedSamplerName(sh::kUserDefinedNamePrefix + name);
30739
+        auto original = originalBindings.find(mappedName);
30740
+        if (original != originalBindings.end())
30741
+        {
30742
+            const std::vector<std::pair<uint32_t, uint32_t>> &resOrignalBindings =
30743
+                originalBindings.at(mappedName);
30744
+            uint32_t currentTextureSlot = actualTextureSlot;
30745
+            uint32_t currentSamplerSlot = actualSamplerSlot;
30746
+            for (const std::pair<uint32_t, uint32_t> &originalBindingRange : resOrignalBindings)
30747
+            {
30748
+                SamplerBinding &actualBinding = bindings->at(originalBindingRange.first);
30749
+                actualBinding.textureBinding  = currentTextureSlot;
30750
+                actualBinding.samplerBinding  = currentSamplerSlot;
30751
+
30752
+                currentTextureSlot += originalBindingRange.second;
30753
+                currentSamplerSlot += originalBindingRange.second;
30754
+            }
30755
+        }
30756
+    }
30757
+}
30758
+
30759
+sh::TranslatorMetalReflection *getReflectionFromShader(gl::Shader *shader)
30760
+{
30761
+    ShaderMtl *shaderInstance = static_cast<ShaderMtl *>(shader->getImplementation());
30762
+    return shaderInstance->getTranslatorMetalReflection();
30763
+}
30764
+
30765
+sh::TranslatorMetalReflection *getReflectionFromCompiler(gl::Compiler *compiler,
30766
+                                                         gl::ShaderType type)
30767
+{
30768
+    auto compilerInstance      = compiler->getInstance(type);
30769
+    sh::TShHandleBase *base    = static_cast<sh::TShHandleBase *>(compilerInstance.getHandle());
30770
+    auto translatorMetalDirect = base->getAsTranslatorMetalDirect();
30771
+    compiler->putInstance(std::move(compilerInstance));
30772
+    return translatorMetalDirect->getTranslatorMetalReflection();
30773
+}
30774
+
30775
+angle::Result GlslangGetMSL(const gl::Context *glContext,
30776
+                            const gl::ProgramState &programState,
30777
+                            const gl::Caps &glCaps,
30778
+                            const gl::ShaderMap<std::string> &shaderSources,
30779
+                            const ShaderMapInterfaceVariableInfoMap &variableInfoMap,
30780
+                            gl::ShaderMap<TranslatedShaderInfo> *mslShaderInfoOut,
30781
+                            gl::ShaderMap<std::string> *mslCodeOut,
30782
+                            size_t xfbBufferCount)
30783
+{
30784
+    // Retrieve original uniform buffer bindings generated by front end. We will need to do a remap.
30785
+    std::unordered_map<std::string, uint32_t> uboOriginalBindings;
30786
+    const std::vector<gl::InterfaceBlock> &blocks = programState.getUniformBlocks();
30787
+    for (uint32_t bufferIdx = 0; bufferIdx < blocks.size(); ++bufferIdx)
30788
+    {
30789
+        const gl::InterfaceBlock &block = blocks[bufferIdx];
30790
+        if (!uboOriginalBindings.count(block.mappedName))
30791
+        {
30792
+            uboOriginalBindings[block.mappedName] = bufferIdx;
30793
+        }
30794
+    }
30795
+    // Retrieve original sampler bindings produced by front end.
30796
+    OriginalSamplerBindingMap originalSamplerBindings;
30797
+    const std::vector<gl::SamplerBinding> &samplerBindings = programState.getSamplerBindings();
30798
+    const std::vector<gl::LinkedUniform> &uniforms         = programState.getUniforms();
30799
+
30800
+    std::unordered_set<std::string> structSamplers = {};
30801
+
30802
+    for (uint32_t textureIndex = 0; textureIndex < samplerBindings.size(); ++textureIndex)
30803
+    {
30804
+        const gl::SamplerBinding &samplerBinding = samplerBindings[textureIndex];
30805
+        uint32_t uniformIndex = programState.getUniformIndexFromSamplerIndex(textureIndex);
30806
+        const gl::LinkedUniform &samplerUniform = uniforms[uniformIndex];
30807
+        bool isSamplerInStruct        = samplerUniform.name.find('.') != std::string::npos;
30808
+        std::string mappedSamplerName = isSamplerInStruct
30809
+                                            ? MSLGetMappedSamplerName(samplerUniform.name)
30810
+                                            : MSLGetMappedSamplerName(samplerUniform.mappedName);
30811
+        // These need to be prefixed later seperately
30812
+        if (isSamplerInStruct)
30813
+            structSamplers.insert(mappedSamplerName);
30814
+        originalSamplerBindings[mappedSamplerName].push_back(
30815
+            {textureIndex, static_cast<uint32_t>(samplerBinding.boundTextureUnits.size())});
30816
+    }
30817
+    for (gl::ShaderType type : {gl::ShaderType::Vertex, gl::ShaderType::Fragment})
30818
+    {
30819
+        (*mslCodeOut)[type]                         = shaderSources[type];
30820
+        (*mslShaderInfoOut)[type].metalShaderSource = shaderSources[type];
30821
+        gl::Shader *shader                        = programState.getAttachedShader(type);
30822
+        sh::TranslatorMetalReflection *reflection = getReflectionFromShader(shader);
30823
+        // Retrieve automatic texture slot assignments
30824
+        if (originalSamplerBindings.size() > 0)
30825
+        {
30826
+            GetAssignedSamplerBindings(reflection, originalSamplerBindings, structSamplers,
30827
+                                       &mslShaderInfoOut->at(type).actualSamplerBindings);
30828
+        }
30829
+        reflection->reset();
30830
+    }
30831
+    return angle::Result::Continue;
30832
+}
30833
+
30834
+uint MslGetShaderShadowCompareMode(GLenum mode, GLenum func)
30835
+{
30836
+    // See SpirvToMslCompiler::emit_header()
30837
+    if (mode == GL_NONE)
30838
+    {
30839
+        return 0;
30840
+    }
30841
+    else
30842
+    {
30843
+        switch (func)
30844
+        {
30845
+            case GL_LESS:
30846
+                return 1;
30847
+            case GL_LEQUAL:
30848
+                return 2;
30849
+            case GL_GREATER:
30850
+                return 3;
30851
+            case GL_GEQUAL:
30852
+                return 4;
30853
+            case GL_NEVER:
30854
+                return 5;
30855
+            case GL_ALWAYS:
30856
+                return 6;
30857
+            case GL_EQUAL:
30858
+                return 7;
30859
+            case GL_NOTEQUAL:
30860
+                return 8;
30861
+            default:
30862
+                UNREACHABLE();
30863
+                return 1;
30864
+        }
30865
+    }
30866
+}
30867
+}  // namespace mtl
30868
+}  // namespace rx
30869
diff --git a/src/libANGLE/renderer/metal/mtl_glslang_utils.h b/src/libANGLE/renderer/metal/mtl_glslang_utils.h
30870
index 13c97ee..c02446a 100644
30871
--- a/src/libANGLE/renderer/metal/mtl_glslang_utils.h
30872
+++ b/src/libANGLE/renderer/metal/mtl_glslang_utils.h
30873
@@ -14,33 +14,11 @@
30874
 #include "libANGLE/renderer/ProgramImpl.h"
30875
 #include "libANGLE/renderer/glslang_wrapper_utils.h"
30876
 #include "libANGLE/renderer/metal/mtl_common.h"
30877
-
30878
+#include "libANGLE/renderer/metal/mtl_glslang_mtl_utils.h"
30879
 namespace rx
30880
 {
30881
 namespace mtl
30882
 {
30883
-
30884
-struct SamplerBinding
30885
-{
30886
-    uint32_t textureBinding = 0;
30887
-    uint32_t samplerBinding = 0;
30888
-};
30889
-
30890
-struct TranslatedShaderInfo
30891
-{
30892
-    void reset();
30893
-
30894
-    // Translated Metal source code
30895
-    std::string metalShaderSource;
30896
-    // Metal library compiled from source code above. Used by ProgramMtl.
30897
-    AutoObjCPtr<id<MTLLibrary>> metalLibrary;
30898
-
30899
-    std::array<SamplerBinding, kMaxGLSamplerBindings> actualSamplerBindings;
30900
-    std::array<uint32_t, kMaxGLUBOBindings> actualUBOBindings;
30901
-    std::array<uint32_t, kMaxShaderXFBs> actualXFBBindings;
30902
-    bool hasUBOArgumentBuffer;
30903
-};
30904
-
30905
 // - shaderSourcesOut is result GLSL code per shader stage when XFB emulation is turned off.
30906
 // - xfbOnlyShaderSourceOut will contain vertex shader's GLSL code when XFB emulation is turned on.
30907
 void GlslangGetShaderSource(const gl::ProgramState &programState,
30908
@@ -57,6 +35,13 @@ angle::Result GlslangGetShaderSpirvCode(ErrorHandler *context,
30909
                                         const ShaderMapInterfaceVariableInfoMap &variableInfoMap,
30910
                                         gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut);
30911
 
30912
+angle::Result MSLGetShaderSpirvCode(ErrorHandler *context,
30913
+                                    const gl::ShaderBitSet &linkedShaderStages,
30914
+                                    const gl::Caps &glCaps,
30915
+                                    const gl::ShaderMap<std::string> &shaderSources,
30916
+                                    const ShaderMapInterfaceVariableInfoMap &variableInfoMap,
30917
+                                    gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut);
30918
+
30919
 // Translate from SPIR-V code to Metal shader source code.
30920
 // - spirvShaderCode is SPIRV code per shader stage when XFB emulation is turned off.
30921
 // - xfbOnlySpirvCode is  vertex shader's SPIRV code when XFB emulation is turned on.
30922
@@ -70,6 +55,23 @@ angle::Result SpirvCodeToMsl(Context *context,
30923
                              gl::ShaderMap<TranslatedShaderInfo> *mslShaderInfoOut,
30924
                              TranslatedShaderInfo *mslXfbOnlyShaderInfoOut /** nullable */);
30925
 
30926
+void MSLGetShaderSource(const gl::ProgramState &programState,
30927
+                        const gl::ProgramLinkedResources &resources,
30928
+                        gl::ShaderMap<std::string> *shaderSourcesOut,
30929
+                        ShaderMapInterfaceVariableInfoMap *variableInfoMapOut);
30930
+
30931
+angle::Result GlslangGetMSL(Context *context,
30932
+                            const gl::ShaderBitSet &linkedShaderStages,
30933
+                            const gl::Caps &glCaps,
30934
+                            const gl::ShaderMap<std::string> &shaderSources,
30935
+                            const ShaderMapInterfaceVariableInfoMap &variableInfoMap,
30936
+                            gl::ShaderMap<TranslatedShaderInfo> *mslShaderInfoOut,
30937
+                            gl::ShaderMap<std::string> *mslCodeOut,
30938
+                            size_t xfbBufferCount);
30939
+
30940
+// Get equivalent shadow compare mode that is used in translated msl shader.
30941
+uint MslGetShaderShadowCompareMode(GLenum mode, GLenum func);
30942
+
30943
 }  // namespace mtl
30944
 }  // namespace rx
30945
 
30946
diff --git a/src/libANGLE/renderer/metal/mtl_glslang_utils.mm b/src/libANGLE/renderer/metal/mtl_glslang_utils.mm
30947
index caa0e56..4cf717a 100644
30948
--- a/src/libANGLE/renderer/metal/mtl_glslang_utils.mm
30949
+++ b/src/libANGLE/renderer/metal/mtl_glslang_utils.mm
30950
@@ -13,6 +13,7 @@
30951
 #include <spirv_msl.hpp>
30952
 
30953
 #include "common/apple_platform_utils.h"
30954
+#include "compiler/translator/TranslatorMetal.h"
30955
 #include "libANGLE/renderer/glslang_wrapper_utils.h"
30956
 #include "libANGLE/renderer/metal/DisplayMtl.h"
30957
 
30958
@@ -22,12 +23,13 @@
30959
 {
30960
 namespace
30961
 {
30962
-
30963
 constexpr uint32_t kGlslangTextureDescSet              = 0;
30964
 constexpr uint32_t kGlslangDefaultUniformAndXfbDescSet = 1;
30965
 constexpr uint32_t kGlslangDriverUniformsDescSet       = 2;
30966
 constexpr uint32_t kGlslangShaderResourceDescSet       = 3;
30967
 
30968
+constexpr char kShadowSamplerCompareModesVarName[] = "ANGLEShadowCompareModes";
30969
+
30970
 // Original mapping of front end from sampler name to multiple sampler slots (in form of
30971
 // slot:count pair)
30972
 using OriginalSamplerBindingMap =
30973
@@ -56,9 +58,13 @@ void ResetGlslangProgramInterfaceInfo(GlslangProgramInterfaceInfo *programInterf
30974
     static_assert(kDriverUniformsBindingIndex != 0, "kDriverUniformsBindingIndex must not be 0");
30975
 }
30976
 
30977
+
30978
 GlslangSourceOptions CreateSourceOptions()
30979
 {
30980
     GlslangSourceOptions options;
30981
+    options.emulateTransformFeedback = true;
30982
+    // We can early out in the MSL once transform feedback is written
30983
+    options.transformFeedbackEarlyReturn = true;
30984
     return options;
30985
 }
30986
 
30987
@@ -79,8 +85,8 @@ GlslangSourceOptions CreateSourceOptions()
30988
 void BindBuffers(spirv_cross::CompilerMSL *compiler,
30989
                  const spirv_cross::SmallVector<spirv_cross::Resource> &resources,
30990
                  gl::ShaderType shaderType,
30991
-                 const std::unordered_map<std::string, uint32_t> &uboOriginalBindings,
30992
-                 const std::unordered_map<uint32_t, uint32_t> &xfbOriginalBindings,
30993
+                 const angle::HashMap<std::string, uint32_t> &uboOriginalBindings,
30994
+                 const angle::HashMap<uint32_t, uint32_t> &xfbOriginalBindings,
30995
                  std::array<uint32_t, kMaxGLUBOBindings> *uboBindingsRemapOut,
30996
                  std::array<uint32_t, kMaxShaderXFBs> *xfbBindingRemapOut,
30997
                  bool *uboArgumentBufferUsed)
30998
@@ -253,30 +259,50 @@ void GetAssignedSamplerBindings(const spirv_cross::CompilerMSL &compilerMsl,
30999
     }
31000
 }
31001
 
31002
-std::string PostProcessTranslatedMsl(const std::string &translatedSource)
31003
+std::string PostProcessTranslatedMsl(bool hasDepthSampler, const std::string &translatedSource)
31004
 {
31005
+    std::string source;
31006
+    if (hasDepthSampler)
31007
+    {
31008
+        // Add ANGLEShadowCompareModes variable to main(), We need to add here because it is the
31009
+        // only way without modifying spirv-cross.
31010
+        std::regex mainDeclareRegex(
31011
+            R"(((vertex|fragment|kernel)\s+[_a-zA-Z0-9<>]+\s+main[^\(]*\())");
31012
+        std::string mainDeclareReplaceStr = std::string("$1constant uniform<uint> *") +
31013
+                                            kShadowSamplerCompareModesVarName + "[[buffer(" +
31014
+                                            Str(kShadowSamplerCompareModesBindingIndex) + ")]], ";
31015
+        source = std::regex_replace(translatedSource, mainDeclareRegex, mainDeclareReplaceStr);
31016
+    }
31017
+    else
31018
+    {
31019
+        source = translatedSource;
31020
+    }
31021
+
31022
     // Add function_constant attribute to gl_SampleMask.
31023
     // Even though this varying is only used when ANGLECoverageMaskEnabled is true,
31024
     // the spirv-cross doesn't assign function_constant attribute to it. Thus it won't be dead-code
31025
     // removed when ANGLECoverageMaskEnabled=false.
31026
     std::string sampleMaskReplaceStr = std::string("[[sample_mask, function_constant(") +
31027
-                                       sh::mtl::kCoverageMaskEnabledConstName + ")]]";
31028
+                                       sh::TranslatorMetal::GetCoverageMaskEnabledConstName() +
31029
+                                       ")]]";
31030
 
31031
     // This replaces "gl_SampleMask [[sample_mask]]"
31032
     //          with "gl_SampleMask [[sample_mask, function_constant(ANGLECoverageMaskEnabled)]]"
31033
     std::regex sampleMaskDeclareRegex(R"(\[\s*\[\s*sample_mask\s*\]\s*\])");
31034
-    return std::regex_replace(translatedSource, sampleMaskDeclareRegex, sampleMaskReplaceStr);
31035
+    return std::regex_replace(source, sampleMaskDeclareRegex, sampleMaskReplaceStr);
31036
 }
31037
 
31038
 // Customized spirv-cross compiler
31039
 class SpirvToMslCompiler : public spirv_cross::CompilerMSL
31040
 {
31041
   public:
31042
-    SpirvToMslCompiler(std::vector<uint32_t> &&spriv) : spirv_cross::CompilerMSL(spriv) {}
31043
+    SpirvToMslCompiler(Context *context, std::vector<uint32_t> &&spriv)
31044
+        : spirv_cross::CompilerMSL(spriv), mContext(context)
31045
+    {}
31046
 
31047
     void compileEx(gl::ShaderType shaderType,
31048
-                   const std::unordered_map<std::string, uint32_t> &uboOriginalBindings,
31049
-                   const std::unordered_map<uint32_t, uint32_t> &xfbOriginalBindings,
31050
+                   const angle::HashMap<std::string, uint32_t> &uboOriginalBindings,
31051
+                   const angle::HashMap<uint32_t, uint32_t> &xfbOriginalBindings,
31052
                    const OriginalSamplerBindingMap &originalSamplerBindings,
31053
                    TranslatedShaderInfo *mslShaderInfoOut)
31054
     {
31055
@@ -328,8 +354,7 @@ void compileEx(gl::ShaderType shaderType,
31056
             // Force discrete slot bindings for textures, default uniforms & driver uniforms
31057
             // instead of using argument buffer.
31058
             spirv_cross::CompilerMSL::add_discrete_descriptor_set(kGlslangTextureDescSet);
31059
-            spirv_cross::CompilerMSL::add_discrete_descriptor_set(
31060
-                kGlslangDefaultUniformAndXfbDescSet);
31061
+            spirv_cross::CompilerMSL::add_discrete_descriptor_set(kGlslangDefaultUniformAndXfbDescSet);
31062
             spirv_cross::CompilerMSL::add_discrete_descriptor_set(kGlslangDriverUniformsDescSet);
31063
         }
31064
         else
31065
@@ -340,21 +365,732 @@ void compileEx(gl::ShaderType shaderType,
31066
 
31067
         spirv_cross::CompilerMSL::set_msl_options(compOpt);
31068
 
31069
+        addBuiltInResources();
31070
+        analyzeShaderVariables();
31071
+
31072
         // Actual compilation
31073
         mslShaderInfoOut->metalShaderSource =
31074
-            PostProcessTranslatedMsl(spirv_cross::CompilerMSL::compile());
31075
+            PostProcessTranslatedMsl(mHasDepthSampler, spirv_cross::CompilerMSL::compile());
31076
 
31077
         // Retrieve automatic texture slot assignments
31078
         GetAssignedSamplerBindings(*this, originalSamplerBindings,
31079
                                    &mslShaderInfoOut->actualSamplerBindings);
31080
     }
31081
+
31082
+  private:
31083
+    // Override CompilerMSL
31084
+    void emit_header() override
31085
+    {
31086
+        spirv_cross::CompilerMSL::emit_header();
31087
+        if (!mHasDepthSampler)
31088
+        {
31089
+            return;
31090
+        }
31091
+        // Work around code for these issues:
31092
+        // - spriv_cross always translates shadow texture's sampling to sample_compare() and doesn't
31093
+        // take into account GL_TEXTURE_COMPARE_MODE=GL_NONE.
31094
+        // - on macOS, explicit level of detail parameter is not supported in sample_compare().
31095
+        // - on devices prior to iOS GPU family 3, changing sampler's compare mode outside shader is
31096
+        // not supported.
31097
+        if (!mContext->getDisplay()->getFeatures().allowRuntimeSamplerCompareMode.enabled)
31098
+        {
31099
+            statement("#define ANGLE_MTL_NO_SAMPLER_RUNTIME_COMPARE_MODE");
31100
+        }
31101
+
31102
+        statement("enum class ANGLECompareMode : uint");
31103
+        statement("{");
31104
+        statement("    None = 0,");
31105
+        statement("    Less,");
31106
+        statement("    LessEqual,");
31107
+        statement("    Greater,");
31108
+        statement("    GreaterEqual,");
31109
+        statement("    Never,");
31110
+        statement("    Always,");
31111
+        statement("    Equal,");
31112
+        statement("    NotEqual,");
31113
+        statement("};");
31114
+        statement("");
31115
+
31116
+        statement("template <typename T, typename UniformOrUInt>");
31117
+        statement("inline T ANGLEcompare(T depth, T dref, UniformOrUInt compareMode)");
31118
+        statement("{");
31119
+        statement("   ANGLECompareMode mode = static_cast<ANGLECompareMode>(compareMode);");
31120
+        statement("   switch (mode)");
31121
+        statement("   {");
31122
+        statement("        case ANGLECompareMode::Less:");
31123
+        statement("            return dref < depth;");
31124
+        statement("        case ANGLECompareMode::LessEqual:");
31125
+        statement("            return dref <= depth;");
31126
+        statement("        case ANGLECompareMode::Greater:");
31127
+        statement("            return dref > depth;");
31128
+        statement("        case ANGLECompareMode::GreaterEqual:");
31129
+        statement("            return dref >= depth;");
31130
+        statement("        case ANGLECompareMode::Never:");
31131
+        statement("            return 0;");
31132
+        statement("        case ANGLECompareMode::Always:");
31133
+        statement("            return 1;");
31134
+        statement("        case ANGLECompareMode::Equal:");
31135
+        statement("            return dref == depth;");
31136
+        statement("        case ANGLECompareMode::NotEqual:");
31137
+        statement("            return dref != depth;");
31138
+        statement("        default:");
31139
+        statement("            return 1;");
31140
+        statement("   }");
31141
+        statement("}");
31142
+        statement("");
31143
+
31144
+        statement("// Wrapper functions for shadow texture functions");
31145
+        // 2D PCF sampling
31146
+        statement("template <typename T, typename Opt, typename UniformOrUInt>");
31147
+        statement("inline T ANGLEtexturePCF(depth2d<T> texture, sampler s, float2 coord, float "
31148
+                  "compare_value, Opt options, int2 offset, UniformOrUInt shadowCompareMode)");
31149
+        statement("{");
31150
+        statement("#if defined(__METAL_MACOS__)");
31151
+        statement("    float2 dims = float2(texture.get_width(), texture.get_height());");
31152
+        statement("    float2 imgCoord = coord * dims;");
31153
+        statement("    float2 texelSize = 1.0 / dims;");
31154
+        statement("    float2 weight = fract(imgCoord);");
31155
+        statement("    float tl = ANGLEcompare(texture.sample(s, coord, options, offset), "
31156
+                  "compare_value, shadowCompareMode);");
31157
+        statement("    float tr = ANGLEcompare(texture.sample(s, coord + float2(texelSize.x, 0.0), "
31158
+                  "options, offset), compare_value, shadowCompareMode);");
31159
+        statement("    float bl = ANGLEcompare(texture.sample(s, coord + float2(0.0, texelSize.y), "
31160
+                  "options, offset), compare_value, shadowCompareMode);");
31161
+        statement("    float br = ANGLEcompare(texture.sample(s, coord + texelSize, options, "
31162
+                  "offset), compare_value, shadowCompareMode);");
31163
+        statement("    float top = mix(tl, tr, weight.x);");
31164
+        statement("    float bottom = mix(bl, br, weight.x);");
31165
+        statement("    return mix(top, bottom, weight.y);");
31166
+        statement("#else  // if defined(__METAL_MACOS__)");
31167
+        statement("    return ANGLEcompare(texture.sample(s, coord, options, offset), "
31168
+                  "compare_value, shadowCompareMode);");
31169
+        statement("#endif  // if defined(__METAL_MACOS__)");
31170
+        statement("}");
31171
+        statement("");
31172
+
31173
+        // Cube PCF sampling
31174
+        statement("template <typename T, typename Opt, typename UniformOrUInt>");
31175
+        statement("inline T ANGLEtexturePCF(depthcube<T> texture, sampler s, float3 coord, float "
31176
+                  "compare_value, Opt options, UniformOrUInt shadowCompareMode)");
31177
+        statement("{");
31178
+        statement("    // NOTE(hqle): to implement");
31179
+        statement("    return ANGLEcompare(texture.sample(s, coord, options), compare_value, "
31180
+                  "shadowCompareMode);");
31181
+        statement("}");
31182
+        statement("");
31183
+
31184
+        // 2D array PCF sampling
31185
+        statement("template <typename T, typename Opt, typename UniformOrUInt>");
31186
+        statement(
31187
+            "inline T ANGLEtexturePCF(depth2d_array<T> texture, sampler s, float2 coord, uint "
31188
+            "array, float compare_value, Opt options, int2 offset, UniformOrUInt "
31189
+            "shadowCompareMode)");
31190
+        statement("{");
31191
+        statement("#if defined(__METAL_MACOS__)");
31192
+        statement("    float2 dims = float2(texture.get_width(), texture.get_height());");
31193
+        statement("    float2 imgCoord = coord * dims;");
31194
+        statement("    float2 texelSize = 1.0 / dims;");
31195
+        statement("    float2 weight = fract(imgCoord);");
31196
+        statement("    float tl = ANGLEcompare(texture.sample(s, coord, array, options, offset), "
31197
+                  "compare_value, shadowCompareMode);");
31198
+        statement("    float tr = ANGLEcompare(texture.sample(s, coord + float2(texelSize.x, 0.0), "
31199
+                  "array, options, offset), compare_value, shadowCompareMode);");
31200
+        statement("    float bl = ANGLEcompare(texture.sample(s, coord + float2(0.0, texelSize.y), "
31201
+                  "array, options, offset), compare_value, shadowCompareMode);");
31202
+        statement("    float br = ANGLEcompare(texture.sample(s, coord + texelSize, array, "
31203
+                  "options, offset), compare_value, shadowCompareMode);");
31204
+        statement("    float top = mix(tl, tr, weight.x);");
31205
+        statement("    float bottom = mix(bl, br, weight.x);");
31206
+        statement("    return mix(top, bottom, weight.y);");
31207
+        statement("#else  // if defined(__METAL_MACOS__)");
31208
+        statement("    return ANGLEcompare(texture.sample(s, coord, array, options, offset), "
31209
+                  "compare_value, shadowCompareMode);");
31210
+        statement("#endif  // if defined(__METAL_MACOS__)");
31211
+        statement("}");
31212
+        statement("");
31213
+
31214
+        // 2D texture's sample_compare() wrapper
31215
+        statement("template <typename T, typename Opt, typename UniformOrUInt>");
31216
+        statement("inline T ANGLEtextureCompare(depth2d<T> texture, sampler s, float2 coord, float "
31217
+                  "compare_value, Opt options, int2 offset, UniformOrUInt shadowCompareMode)");
31218
+        statement("{");
31219
+        statement(
31220
+            "#if defined(__METAL_MACOS__) || defined(ANGLE_MTL_NO_SAMPLER_RUNTIME_COMPARE_MODE)");
31221
+        statement("    return ANGLEtexturePCF(texture, s, coord, compare_value, options, offset, "
31222
+                  "shadowCompareMode);");
31223
+        statement("#else");
31224
+        statement("    return texture.sample_compare(s, coord, compare_value, options, offset);");
31225
+        statement("#endif");
31226
+        statement("}");
31227
+        statement("");
31228
+
31229
+        statement("template <typename T, typename Opt, typename UniformOrUInt>");
31230
+        statement("inline T ANGLEtextureCompare(depth2d<T> texture, sampler s, float2 coord, float "
31231
+                  "compare_value, Opt options, UniformOrUInt shadowCompareMode)");
31232
+        statement("{");
31233
+        statement("    return ANGLEtextureCompare(texture, s, coord, compare_value, options, "
31234
+                  "int2(0), shadowCompareMode);");
31235
+        statement("}");
31236
+        statement("");
31237
+
31238
+        statement("template <typename T, typename UniformOrUInt>");
31239
+        statement("inline T ANGLEtextureCompare(depth2d<T> texture, sampler s, float2 coord, float "
31240
+                  "compare_value, int2 offset, UniformOrUInt shadowCompareMode)");
31241
+        statement("{");
31242
+        statement("#if defined(ANGLE_MTL_NO_SAMPLER_RUNTIME_COMPARE_MODE)");
31243
+        statement("    return ANGLEtexturePCF(texture, s, coord, compare_value, level(0), offset, "
31244
+                  "shadowCompareMode);");
31245
+        statement("#else");
31246
+        statement("    return texture.sample_compare(s, coord, compare_value, offset);");
31247
+        statement("#endif");
31248
+        statement("}");
31249
+        statement("");
31250
+
31251
+        // Cube texture's sample_compare() wrapper
31252
+        statement("template <typename T, typename Opt, typename UniformOrUInt>");
31253
+        statement(
31254
+            "inline T ANGLEtextureCompare(depthcube<T> texture, sampler s, float3 coord, float "
31255
+            "compare_value, Opt options, UniformOrUInt shadowCompareMode)");
31256
+        statement("{");
31257
+        statement(
31258
+            "#if defined(__METAL_MACOS__) || defined(ANGLE_MTL_NO_SAMPLER_RUNTIME_COMPARE_MODE)");
31259
+        statement("    return ANGLEtexturePCF(texture, s, coord, compare_value, options, "
31260
+                  "shadowCompareMode);");
31261
+        statement("#else");
31262
+        statement("    return texture.sample_compare(s, coord, compare_value, options);");
31263
+        statement("#endif");
31264
+        statement("}");
31265
+        statement("");
31266
+
31267
+        statement("template <typename T, typename UniformOrUInt>");
31268
+        statement(
31269
+            "inline T ANGLEtextureCompare(depthcube<T> texture, sampler s, float3 coord, float "
31270
+            "compare_value, UniformOrUInt shadowCompareMode)");
31271
+        statement("{");
31272
+        statement("#if defined(ANGLE_MTL_NO_SAMPLER_RUNTIME_COMPARE_MODE)");
31273
+        statement("    return ANGLEtexturePCF(texture, s, coord, compare_value, level(0), "
31274
+                  "shadowCompareMode);");
31275
+        statement("#else");
31276
+        statement("    return texture.sample_compare(s, coord, compare_value);");
31277
+        statement("#endif");
31278
+        statement("}");
31279
+        statement("");
31280
+
31281
+        // 2D array texture's sample_compare() wrapper
31282
+        statement("template <typename T, typename Opt, typename UniformOrUInt>");
31283
+        statement("inline T ANGLEtextureCompare(depth2d_array<T> texture, sampler s, float2 coord, "
31284
+                  "uint array, float compare_value, Opt options, int2 offset, UniformOrUInt "
31285
+                  "shadowCompareMode)");
31286
+        statement("{");
31287
+        statement(
31288
+            "#if defined(__METAL_MACOS__) || defined(ANGLE_MTL_NO_SAMPLER_RUNTIME_COMPARE_MODE)");
31289
+        statement("    return ANGLEtexturePCF(texture, s, coord, array, compare_value, options, "
31290
+                  "offset, shadowCompareMode);");
31291
+        statement("#else");
31292
+        statement(
31293
+            "    return texture.sample_compare(s, coord, array, compare_value, options, offset);");
31294
+        statement("#endif");
31295
+        statement("}");
31296
+        statement("");
31297
+
31298
+        statement("template <typename T, typename Opt, typename UniformOrUInt>");
31299
+        statement("inline T ANGLEtextureCompare(depth2d_array<T> texture, sampler s, float2 coord, "
31300
+                  "uint array, float compare_value, Opt options, UniformOrUInt shadowCompareMode)");
31301
+        statement("{");
31302
+        statement("    return ANGLEtextureCompare(texture, s, coord, array, compare_value, "
31303
+                  "options, int2(0), shadowCompareMode);");
31304
+        statement("}");
31305
+        statement("");
31306
+
31307
+        statement("template <typename T, typename UniformOrUInt>");
31308
+        statement("inline T ANGLEtextureCompare(depth2d_array<T> texture, sampler s, float2 coord, "
31309
+                  "uint array, float compare_value, int2 offset, UniformOrUInt "
31310
+                  "shadowCompareMode)");
31311
+        statement("{");
31312
+        statement("#if defined(ANGLE_MTL_NO_SAMPLER_RUNTIME_COMPARE_MODE)");
31313
+        statement("    return ANGLEtexturePCF(texture, s, coord, array, compare_value, level(0), "
31314
+                  "offset, shadowCompareMode);");
31315
+        statement("#else");
31316
+        statement("    return texture.sample_compare(s, coord, array, compare_value, offset);");
31317
+        statement("#endif");
31318
+        statement("}");
31319
+        statement("");
31320
+
31321
+        // 2D texture's generic sampling function
31322
+        statement("// Wrapper functions for shadow texture functions");
31323
+        statement("template <typename T, typename UniformOrUInt>");
31324
+        statement("inline T ANGLEtexture(depth2d<T> texture, sampler s, float2 coord, int2 offset, "
31325
+                  "float compare_value, UniformOrUInt shadowCompareMode)");
31326
+        statement("{");
31327
+        statement("    if (shadowCompareMode)");
31328
+        statement("    {");
31329
+        statement("        return ANGLEtextureCompare(texture, s, coord, compare_value, offset, "
31330
+                  "shadowCompareMode);");
31331
+        statement("    }");
31332
+        statement("    else");
31333
+        statement("    {");
31334
+        statement("        return texture.sample(s, coord, offset);");
31335
+        statement("    }");
31336
+        statement("}");
31337
+        statement("");
31338
+
31339
+        statement("template <typename T, typename UniformOrUInt>");
31340
+        statement("inline T ANGLEtexture(depth2d<T> texture, sampler s, float2 coord, float "
31341
+                  "compare_value, UniformOrUInt shadowCompareMode)");
31342
+        statement("{");
31343
+        statement("    return ANGLEtexture(texture, s, coord, int2(0), compare_value, "
31344
+                  "shadowCompareMode);");
31345
+        statement("}");
31346
+        statement("");
31347
+
31348
+        statement("template <typename T, typename Opt, typename UniformOrUInt>");
31349
+        statement("inline T ANGLEtexture(depth2d<T> texture, sampler s, float2 coord, Opt options, "
31350
+                  "int2 offset, float compare_value, UniformOrUInt shadowCompareMode)");
31351
+        statement("{");
31352
+        statement("    if (shadowCompareMode)");
31353
+        statement("    {");
31354
+        statement("        return ANGLEtextureCompare(texture, s, coord, compare_value, options, "
31355
+                  "offset, shadowCompareMode);");
31356
+        statement("    }");
31357
+        statement("    else");
31358
+        statement("    {");
31359
+        statement("        return texture.sample(s, coord, options, offset);");
31360
+        statement("    }");
31361
+        statement("}");
31362
+        statement("");
31363
+
31364
+        statement("template <typename T, typename Opt, typename UniformOrUInt>");
31365
+        statement("inline T ANGLEtexture(depth2d<T> texture, sampler s, float2 coord, Opt options, "
31366
+                  "float compare_value, UniformOrUInt shadowCompareMode)");
31367
+        statement("{");
31368
+        statement("    return ANGLEtexture(texture, s, coord, options, int2(0), compare_value, "
31369
+                  "shadowCompareMode);");
31370
+        statement("}");
31371
+        statement("");
31372
+
31373
+        // Cube texture's generic sampling function
31374
+        statement("template <typename T, typename UniformOrUInt>");
31375
+        statement("inline T ANGLEtexture(depthcube<T> texture, sampler s, float3 coord, float "
31376
+                  "compare_value, UniformOrUInt shadowCompareMode)");
31377
+        statement("{");
31378
+        statement("    if (shadowCompareMode)");
31379
+        statement("    {");
31380
+        statement("        return ANGLEtextureCompare(texture, s, coord, compare_value, "
31381
+                  "shadowCompareMode);");
31382
+        statement("    }");
31383
+        statement("    else");
31384
+        statement("    {");
31385
+        statement("        return texture.sample(s, coord);");
31386
+        statement("    }");
31387
+        statement("}");
31388
+        statement("");
31389
+
31390
+        statement("template <typename T, typename Opt, typename UniformOrUInt>");
31391
+        statement("inline T ANGLEtexture(depthcube<T> texture, sampler s, float2 coord, Opt "
31392
+                  "options, float compare_value, UniformOrUInt shadowCompareMode)");
31393
+        statement("{");
31394
+        statement("    if (shadowCompareMode)");
31395
+        statement("    {");
31396
+        statement("        return ANGLEtextureCompare(texture, s, coord, compare_value, options, "
31397
+                  "shadowCompareMode);");
31398
+        statement("    }");
31399
+        statement("    else");
31400
+        statement("    {");
31401
+        statement("        return texture.sample(s, coord, options);");
31402
+        statement("    }");
31403
+        statement("}");
31404
+        statement("");
31405
+
31406
+        // 2D array texture's generic sampling function
31407
+        statement("template <typename T, typename UniformOrUInt>");
31408
+        statement("inline T ANGLEtexture(depth2d_array<T> texture, sampler s, float2 coord, uint "
31409
+                  "array, int2 offset, "
31410
+                  "float compare_value, UniformOrUInt shadowCompareMode)");
31411
+        statement("{");
31412
+        statement("    if (shadowCompareMode)");
31413
+        statement("    {");
31414
+        statement("        return ANGLEtextureCompare(texture, s, coord, array, compare_value, "
31415
+                  "offset, shadowCompareMode);");
31416
+        statement("    }");
31417
+        statement("    else");
31418
+        statement("    {");
31419
+        statement("        return texture.sample(s, coord, array, offset);");
31420
+        statement("    }");
31421
+        statement("}");
31422
+        statement("");
31423
+
31424
+        statement("template <typename T, typename UniformOrUInt>");
31425
+        statement("inline T ANGLEtexture(depth2d_array<T> texture, sampler s, float2 coord, uint "
31426
+                  "array, float compare_value, UniformOrUInt shadowCompareMode)");
31427
+        statement("{");
31428
+        statement("    return ANGLEtexture(texture, s, coord, array, int2(0), compare_value, "
31429
+                  "shadowCompareMode);");
31430
+        statement("}");
31431
+        statement("");
31432
+
31433
+        statement("template <typename T, typename Opt, typename UniformOrUInt>");
31434
+        statement("inline T ANGLEtexture(depth2d_array<T> texture, sampler s, float2 coord, uint "
31435
+                  "array, Opt options, int2 offset, "
31436
+                  "float compare_value, UniformOrUInt shadowCompareMode)");
31437
+        statement("{");
31438
+        statement("    if (shadowCompareMode)");
31439
+        statement("    {");
31440
+        statement("        return ANGLEtextureCompare(texture, s, coord, array, compare_value, "
31441
+                  "options, offset, shadowCompareMode);");
31442
+        statement("    }");
31443
+        statement("    else");
31444
+        statement("    {");
31445
+        statement("        return texture.sample(s, coord, array, options, offset);");
31446
+        statement("    }");
31447
+        statement("}");
31448
+        statement("");
31449
+
31450
+        statement("template <typename T, typename Opt, typename UniformOrUInt>");
31451
+        statement("inline T ANGLEtexture(depth2d_array<T> texture, sampler s, float2 coord, uint "
31452
+                  "array, Opt options, float compare_value, UniformOrUInt shadowCompareMode)");
31453
+        statement("{");
31454
+        statement("    return ANGLEtexture(texture, s, coord, array, options, int2(0), "
31455
+                  "compare_value, shadowCompareMode);");
31456
+        statement("}");
31457
+        statement("");
31458
+    }
31459
+
31460
+    std::string to_function_name(spirv_cross::VariableID img,
31461
+                                 const spirv_cross::SPIRType &imgType,
31462
+                                 bool isFetch,
31463
+                                 bool isGather,
31464
+                                 bool isProj,
31465
+                                 bool hasArrayOffsets,
31466
+                                 bool hasOffset,
31467
+                                 bool hasGrad,
31468
+                                 bool hasDref,
31469
+                                 uint32_t lod,
31470
+                                 uint32_t minLod) override
31471
+    {
31472
+        if (!hasDref)
31473
+        {
31474
+            return spirv_cross::CompilerMSL::to_function_name(img, imgType, isFetch, isGather,
31475
+                                                              isProj, hasArrayOffsets, hasOffset,
31476
+                                                              hasGrad, hasDref, lod, minLod);
31477
+        }
31478
+
31479
+        // Use custom ANGLEtexture function instead of using built-in sample_compare()
31480
+        return "ANGLEtexture";
31481
+    }
31482
+
31483
+    std::string to_function_args(spirv_cross::VariableID img,
31484
+                                 const spirv_cross::SPIRType &imgType,
31485
+                                 bool isFetch,
31486
+                                 bool isGather,
31487
+                                 bool isProj,
31488
+                                 uint32_t coord,
31489
+                                 uint32_t coordComponents,
31490
+                                 uint32_t dref,
31491
+                                 uint32_t gradX,
31492
+                                 uint32_t gradY,
31493
+                                 uint32_t lod,
31494
+                                 uint32_t coffset,
31495
+                                 uint32_t offset,
31496
+                                 uint32_t bias,
31497
+                                 uint32_t comp,
31498
+                                 uint32_t sample,
31499
+                                 uint32_t minlod,
31500
+                                 bool *pForward) override
31501
+    {
31502
+        bool forward;
31503
+        std::string argsWithoutDref = spirv_cross::CompilerMSL::to_function_args(
31504
+            img, imgType, isFetch, isGather, isProj, coord, coordComponents, 0, gradX, gradY, lod,
31505
+            coffset, offset, bias, comp, sample, minlod, &forward);
31506
+
31507
+        if (!dref)
31508
+        {
31509
+            if (pForward)
31510
+            {
31511
+                *pForward = forward;
31512
+            }
31513
+            return argsWithoutDref;
31514
+        }
31515
+        // Convert to arguments to ANGLEtexture.
31516
+        std::string args = to_expression(img);
31517
+        args += ", ";
31518
+        args += argsWithoutDref;
31519
+        args += ", ";
31520
+
31521
+        forward                               = forward && should_forward(dref);
31522
+        const spirv_cross::SPIRType &drefType = expression_type(dref);
31523
+        std::string drefExpr;
31524
+        uint32_t altCoordComponent = 0;
31525
+        switch (imgType.image.dim)
31526
+        {
31527
+            case spv::Dim2D:
31528
+                altCoordComponent = 2;
31529
+                break;
31530
+            case spv::Dim3D:
31531
+            case spv::DimCube:
31532
+                altCoordComponent = 3;
31533
+                break;
31534
+            default:
31535
+                UNREACHABLE();
31536
+                break;
31537
+        }
31538
+        if (isProj)
31539
+            drefExpr = spirv_cross::join(to_enclosed_expression(dref), " / ",
31540
+                                         to_extract_component_expression(coord, altCoordComponent));
31541
+        else
31542
+            drefExpr = to_expression(dref);
31543
+
31544
+        if (drefType.basetype == spirv_cross::SPIRType::Half)
31545
+            drefExpr = convert_to_f32(drefExpr, 1);
31546
+
31547
+        args += drefExpr;
31548
+        args += ", ";
31549
+        args += toShadowCompareModeExpression(img);
31550
+
31551
+        if (pForward)
31552
+        {
31553
+            *pForward = forward;
31554
+        }
31555
+
31556
+        return args;
31557
+    }
31558
+
31559
+    // Override function prototype emitter to insert shadow compare mode flag to come
31560
+    // together with the shadow sampler. NOTE(hqle): This is just 90% copy of spirv_msl's code.
31561
+    // The better way is modifying and creating a PR on spirv-cross repo directly. But this should
31562
+    // be a work around solution for now.
31563
+    void emit_function_prototype(spirv_cross::SPIRFunction &func,
31564
+                                 const spirv_cross::Bitset &) override
31565
+    {
31566
+        // Turn off clang-format to easier compare with original code
31567
+        // clang-format off
31568
+        using namespace spirv_cross;
31569
+        using namespace spv;
31570
+        using namespace std;
31571
+
31572
+        if (func.self != ir.default_entry_point)
31573
+            add_function_overload(func);
31574
+
31575
+        local_variable_names = resource_names;
31576
+        string decl;
31577
+
31578
+        processing_entry_point = func.self == ir.default_entry_point;
31579
+
31580
+        // Metal helper functions must be static force-inline otherwise they will cause problems when linked together in a single Metallib.
31581
+        if (!processing_entry_point)
31582
+            statement("static inline __attribute__((always_inline))");
31583
+
31584
+        auto &type = get<SPIRType>(func.return_type);
31585
+
31586
+        if (!type.array.empty() && msl_options.force_native_arrays)
31587
+        {
31588
+            // We cannot return native arrays in MSL, so "return" through an out variable.
31589
+            decl += "void";
31590
+        }
31591
+        else
31592
+        {
31593
+            decl += func_type_decl(type);
31594
+        }
31595
+
31596
+        decl += " ";
31597
+        decl += to_name(func.self);
31598
+        decl += "(";
31599
+
31600
+        if (!type.array.empty() && msl_options.force_native_arrays)
31601
+        {
31602
+            // Fake arrays returns by writing to an out array instead.
31603
+            decl += "thread ";
31604
+            decl += type_to_glsl(type);
31605
+            decl += " (&SPIRV_Cross_return_value)";
31606
+            decl += type_to_array_glsl(type);
31607
+            if (!func.arguments.empty())
31608
+                decl += ", ";
31609
+        }
31610
+
31611
+        if (processing_entry_point)
31612
+        {
31613
+            if (msl_options.argument_buffers)
31614
+                decl += entry_point_args_argument_buffer(!func.arguments.empty());
31615
+            else
31616
+                decl += entry_point_args_classic(!func.arguments.empty());
31617
+
31618
+            // If entry point function has variables that require early declaration,
31619
+            // ensure they each have an empty initializer, creating one if needed.
31620
+            // This is done at this late stage because the initialization expression
31621
+            // is cleared after each compilation pass.
31622
+            for (auto var_id : vars_needing_early_declaration)
31623
+            {
31624
+                auto &ed_var = get<SPIRVariable>(var_id);
31625
+                ID &initializer = ed_var.initializer;
31626
+                if (!initializer)
31627
+                    initializer = ir.increase_bound_by(1);
31628
+
31629
+                // Do not override proper initializers.
31630
+                if (ir.ids[initializer].get_type() == TypeNone || ir.ids[initializer].get_type() == TypeExpression)
31631
+                    set<SPIRExpression>(ed_var.initializer, "{}", ed_var.basetype, true);
31632
+            }
31633
+        }
31634
+
31635
+        for (auto &arg : func.arguments)
31636
+        {
31637
+            uint32_t name_id = arg.id;
31638
+
31639
+            auto *var = maybe_get<SPIRVariable>(arg.id);
31640
+            if (var)
31641
+            {
31642
+                // If we need to modify the name of the variable, make sure we modify the original variable.
31643
+                // Our alias is just a shadow variable.
31644
+                if (arg.alias_global_variable && var->basevariable)
31645
+                    name_id = var->basevariable;
31646
+
31647
+                var->parameter = &arg; // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
31648
+            }
31649
+
31650
+            add_local_variable_name(name_id);
31651
+
31652
+            decl += argument_decl(arg);
31653
+
31654
+            bool is_dynamic_img_sampler = has_extended_decoration(arg.id, SPIRVCrossDecorationDynamicImageSampler);
31655
+
31656
+            auto &arg_type = get<SPIRType>(arg.type);
31657
+            if (arg_type.basetype == SPIRType::SampledImage && !is_dynamic_img_sampler)
31658
+            {
31659
+                // Manufacture automatic plane args for multiplanar texture
31660
+                uint32_t planes = 1;
31661
+                if (auto *constexpr_sampler = find_constexpr_sampler(name_id))
31662
+                    if (constexpr_sampler->ycbcr_conversion_enable)
31663
+                        planes = constexpr_sampler->planes;
31664
+                for (uint32_t i = 1; i < planes; i++)
31665
+                    decl += join(", ", argument_decl(arg), plane_name_suffix, i);
31666
+
31667
+                // Manufacture automatic sampler arg for SampledImage texture
31668
+                if (arg_type.image.dim != DimBuffer)
31669
+                    decl += join(", thread const ", sampler_type(arg_type), " ", to_sampler_expression(arg.id));
31670
+            }
31671
+
31672
+            // Manufacture automatic swizzle arg.
31673
+            if (msl_options.swizzle_texture_samples && has_sampled_images && is_sampled_image_type(arg_type) &&
31674
+                !is_dynamic_img_sampler)
31675
+            {
31676
+                bool arg_is_array = !arg_type.array.empty();
31677
+                decl += join(", constant uint", arg_is_array ? "* " : "& ", to_swizzle_expression(arg.id));
31678
+            }
31679
+
31680
+            if (buffers_requiring_array_length.count(name_id))
31681
+            {
31682
+                bool arg_is_array = !arg_type.array.empty();
31683
+                decl += join(", constant uint", arg_is_array ? "* " : "& ", to_buffer_size_expression(name_id));
31684
+            }
31685
+
31686
+            if (is_sampled_image_type(arg_type) && arg_type.image.depth)
31687
+            {
31688
+                bool arg_is_array = !arg_type.array.empty();
31689
+                // Insert shadow compare mode flag to the argument sequence:
31690
+                decl += join(", constant uniform<uint>", arg_is_array ? "* " : "& ",
31691
+                             toShadowCompareModeExpression(arg.id));
31692
+            }
31693
+
31694
+            if (&arg != &func.arguments.back())
31695
+                decl += ", ";
31696
+        }
31697
+
31698
+        decl += ")";
31699
+        statement(decl);
31700
+
31701
+        // clang-format on
31702
+    }
31703
+
31704
+    // Override function call arguments passing generator to insert shadow compare mode flag to come
31705
+    // together with the shadow sampler
31706
+    std::string to_func_call_arg(const spirv_cross::SPIRFunction::Parameter &arg,
31707
+                                 uint32_t id) override
31708
+    {
31709
+        std::string arg_str = spirv_cross::CompilerMSL::to_func_call_arg(arg, id);
31710
+
31711
+        const spirv_cross::SPIRType &type = expression_type(id);
31712
+
31713
+        if (is_sampled_image_type(type) && type.image.depth)
31714
+        {
31715
+            // Insert shadow compare mode flag to the argument sequence:
31716
+            // Need to check the base variable in case we need to apply a qualified alias.
31717
+            uint32_t var_id = 0;
31718
+            auto *var       = maybe_get<spirv_cross::SPIRVariable>(id);
31719
+            if (var)
31720
+                var_id = var->basevariable;
31721
+
31722
+            arg_str += ", " + toShadowCompareModeExpression(var_id ? var_id : id);
31723
+        }
31724
+        return arg_str;
31725
+    }
31726
+
31727
+    // Additional functions
31728
+    void addBuiltInResources()
31729
+    {
31730
+        uint32_t varId = build_constant_uint_array_pointer();
31731
+        set_name(varId, kShadowSamplerCompareModesVarName);
31732
+        // This should never match anything.
31733
+        set_decoration(varId, spv::DecorationDescriptorSet, kShadowSamplerCompareModesBindingIndex);
31734
+        set_decoration(varId, spv::DecorationBinding, 0);
31735
+        set_extended_decoration(varId, spirv_cross::SPIRVCrossDecorationResourceIndexPrimary, 0);
31736
+        mANGLEShadowCompareModesVarId = varId;
31737
+    }
31738
+
31739
+    void analyzeShaderVariables()
31740
+    {
31741
+        ir.for_each_typed_id<spirv_cross::SPIRVariable>([this](uint32_t,
31742
+                                                               spirv_cross::SPIRVariable &var) {
31743
+            const spirv_cross::SPIRType &type = get_variable_data_type(var);
31744
+            uint32_t varId                    = var.self;
31745
+
31746
+            if (var.storage == spv::StorageClassUniformConstant && !is_hidden_variable(var))
31747
+            {
31748
+                if (is_sampled_image_type(type) && type.image.depth)
31749
+                {
31750
+                    mHasDepthSampler = true;
31751
+
31752
+                    auto &entry_func = this->get<spirv_cross::SPIRFunction>(ir.default_entry_point);
31753
+                    entry_func.fixup_hooks_in.push_back([this, &type, &var, varId]() {
31754
+                        bool isArrayType = !type.array.empty();
31755
+
31756
+                        statement("constant uniform<uint>", isArrayType ? "* " : "& ",
31757
+                                  toShadowCompareModeExpression(varId),
31758
+                                  isArrayType ? " = &" : " = ",
31759
+                                  to_name(mANGLEShadowCompareModesVarId), "[",
31760
+                                  spirv_cross::convert_to_string(
31761
+                                      get_metal_resource_index(var, spirv_cross::SPIRType::Image)),
31762
+                                  "];");
31763
+                    });
31764
+                }
31765
+            }
31766
+        });
31767
+    }
31768
+
31769
+    std::string toShadowCompareModeExpression(uint32_t id)
31770
+    {
31771
+        constexpr char kCompareModeSuffix[] = "_CompMode";
31772
+        auto *combined                      = maybe_get<spirv_cross::SPIRCombinedImageSampler>(id);
31773
+
31774
+        std::string expr = to_expression(combined ? combined->image : spirv_cross::VariableID(id));
31775
+        auto index       = expr.find_first_of('[');
31776
+
31777
+        if (index == std::string::npos)
31778
+            return expr + kCompareModeSuffix;
31779
+        else
31780
+        {
31781
+            auto imageExpr = expr.substr(0, index);
31782
+            auto arrayExpr = expr.substr(index);
31783
+            return imageExpr + kCompareModeSuffix + arrayExpr;
31784
+        }
31785
+    }
31786
+
31787
+    Context *mContext;
31788
+    uint32_t mANGLEShadowCompareModesVarId = 0;
31789
+    bool mHasDepthSampler                  = false;
31790
 };
31791
 
31792
-angle::Result ConvertSpirvToMsl(
31793
-    Context *context,
31794
+angle::Result ConvertSpirvToMsl(Context *context,
31795
                                 gl::ShaderType shaderType,
31796
-    const std::unordered_map<std::string, uint32_t> &uboOriginalBindings,
31797
-    const std::unordered_map<uint32_t, uint32_t> &xfbOriginalBindings,
31798
+                                const angle::HashMap<std::string, uint32_t> &uboOriginalBindings,
31799
+                                const angle::HashMap<uint32_t, uint32_t> &xfbOriginalBindings,
31800
                                 const OriginalSamplerBindingMap &originalSamplerBindings,
31801
                                 std::vector<uint32_t> *sprivCode,
31802
                                 TranslatedShaderInfo *translatedShaderInfoOut)
31803
@@ -364,7 +1100,7 @@ void compileEx(gl::ShaderType shaderType,
31804
         return angle::Result::Continue;
31805
     }
31806
 
31807
-    SpirvToMslCompiler compilerMsl(std::move(*sprivCode));
31808
+    SpirvToMslCompiler compilerMsl(context, std::move(*sprivCode));
31809
 
31810
     // NOTE(hqle): spirv-cross uses exceptions to report error, what should we do here
31811
     // in case of error?
31812
@@ -431,12 +1167,13 @@ void GlslangGetShaderSource(const gl::ProgramState &programState,
31813
             options, programState, &xfbOnlyInterfaceInfo, xfbOnlyShaderSourceOut,
31814
             &xfbOnlyVariableMaps[gl::ShaderType::Vertex]);
31815
 
31816
-        GlslangAssignLocations(options, programState.getExecutable(), gl::ShaderType::Vertex,
31817
-                               &xfbOnlyInterfaceInfo, &xfbOnlyVariableMaps);
31818
+        GlslangAssignLocations(options, programState.getExecutable(), gl::ShaderType::Vertex, &xfbOnlyInterfaceInfo,
31819
+                               &xfbOnlyVariableMaps);
31820
         *xfbOnlyVSVariableInfoMapOut = std::move(xfbOnlyVariableMaps[gl::ShaderType::Vertex]);
31821
     }
31822
 }
31823
 
31824
+
31825
 angle::Result GlslangGetShaderSpirvCode(ErrorHandler *context,
31826
                                         const gl::ShaderBitSet &linkedShaderStages,
31827
                                         const gl::Caps &glCaps,
31828
@@ -478,7 +1215,7 @@ void GlslangGetShaderSource(const gl::ProgramState &programState,
31829
                              TranslatedShaderInfo *mslXfbOnlyShaderInfoOut /** nullable */)
31830
 {
31831
     // Retrieve original uniform buffer bindings generated by front end. We will need to do a remap.
31832
-    std::unordered_map<std::string, uint32_t> uboOriginalBindings;
31833
+    angle::HashMap<std::string, uint32_t> uboOriginalBindings;
31834
     const std::vector<gl::InterfaceBlock> &blocks = programState.getUniformBlocks();
31835
     for (uint32_t bufferIdx = 0; bufferIdx < blocks.size(); ++bufferIdx)
31836
     {
31837
@@ -489,7 +1226,7 @@ void GlslangGetShaderSource(const gl::ProgramState &programState,
31838
         }
31839
     }
31840
     // Retrieve original XFB buffers bindings produced by front end.
31841
-    std::unordered_map<uint32_t, uint32_t> xfbOriginalBindings;
31842
+    angle::HashMap<uint32_t, uint32_t> xfbOriginalBindings;
31843
     for (uint32_t bufferIdx = 0; bufferIdx < kMaxShaderXFBs; ++bufferIdx)
31844
     {
31845
         std::string bufferName = rx::GetXfbBufferName(bufferIdx);
31846
@@ -533,6 +1270,5 @@ void GlslangGetShaderSource(const gl::ProgramState &programState,
31847
 
31848
     return angle::Result::Continue;
31849
 }
31850
-
31851
 }  // namespace mtl
31852
 }  // namespace rx
31853
diff --git a/src/libANGLE/renderer/metal/mtl_occlusion_query_pool.h b/src/libANGLE/renderer/metal/mtl_occlusion_query_pool.h
31854
index 87dc217..f857034 100644
31855
--- a/src/libANGLE/renderer/metal/mtl_occlusion_query_pool.h
31856
+++ b/src/libANGLE/renderer/metal/mtl_occlusion_query_pool.h
31857
@@ -1,5 +1,5 @@
31858
 //
31859
-// Copyright 2020 The ANGLE Project Authors. All rights reserved.
31860
+// Copyright (c) 2020 The ANGLE Project Authors. All rights reserved.
31861
 // Use of this source code is governed by a BSD-style license that can be
31862
 // found in the LICENSE file.
31863
 //
31864
diff --git a/src/libANGLE/renderer/metal/mtl_occlusion_query_pool.mm b/src/libANGLE/renderer/metal/mtl_occlusion_query_pool.mm
31865
index 368dbf4..7cc8990 100644
31866
--- a/src/libANGLE/renderer/metal/mtl_occlusion_query_pool.mm
31867
+++ b/src/libANGLE/renderer/metal/mtl_occlusion_query_pool.mm
31868
@@ -1,5 +1,5 @@
31869
 //
31870
-// Copyright 2020 The ANGLE Project Authors. All rights reserved.
31871
+// Copyright (c) 2020 The ANGLE Project Authors. All rights reserved.
31872
 // Use of this source code is governed by a BSD-style license that can be
31873
 // found in the LICENSE file.
31874
 //
31875
@@ -52,8 +52,7 @@
31876
     {
31877
         // First allocation
31878
         ANGLE_TRY(Buffer::MakeBufferWithResOpt(contextMtl, MTLResourceStorageModePrivate,
31879
-                                               kOcclusionQueryResultSize, nullptr,
31880
-                                               &mRenderPassResultsPool));
31881
+                                     kOcclusionQueryResultSize, nullptr, &mRenderPassResultsPool));
31882
         mRenderPassResultsPool->get().label = @"OcclusionQueryPool";
31883
     }
31884
     else if (currentOffset + kOcclusionQueryResultSize > mRenderPassResultsPool->size())
31885
@@ -88,6 +87,12 @@
31886
     if (currentOffset == 0)
31887
     {
31888
         mResetFirstQuery = clearOldValue;
31889
+        if (!clearOldValue && !contextMtl->getDisplay()->getFeatures().allowBufferReadWrite.enabled)
31890
+        {
31891
+            // If old value of first query needs to be retained and device doesn't support buffer
31892
+            // read-write, we need an additional offset to store the old value of the query.
31893
+            return allocateQueryOffset(contextMtl, query, false);
31894
+        }
31895
     }
31896
 
31897
     return angle::Result::Continue;
31898
@@ -113,9 +118,33 @@
31899
     }
31900
 
31901
     RenderUtils &utils              = contextMtl->getDisplay()->getUtils();
31902
+    BlitCommandEncoder *blitEncoder = nullptr;
31903
+    // Combine the values stored in the offsets allocated for first query
31904
+    if (mAllocatedQueries[0])
31905
+    {
31906
+        const BufferRef &dstBuf = mAllocatedQueries[0]->getVisibilityResultBuffer();
31907
+        const VisibilityBufferOffsetsMtl &allocatedOffsets =
31908
+            mAllocatedQueries[0]->getAllocatedVisibilityOffsets();
31909
+        if (!mResetFirstQuery &&
31910
+            !contextMtl->getDisplay()->getFeatures().allowBufferReadWrite.enabled)
31911
+        {
31912
+            // If we cannot read and write to the same buffer in shader. We need to copy the old
31913
+            // value of first query to first offset allocated for it.
31914
+            blitEncoder = contextMtl->getBlitCommandEncoder();
31915
+            blitEncoder->copyBuffer(dstBuf, 0, mRenderPassResultsPool, allocatedOffsets.front(),
31916
+                                    kOcclusionQueryResultSize);
31917
+            utils.combineVisibilityResult(contextMtl, false, allocatedOffsets,
31918
+                                          mRenderPassResultsPool, dstBuf);
31919
+        }
31920
+        else
31921
+        {
31922
+            utils.combineVisibilityResult(contextMtl, !mResetFirstQuery, allocatedOffsets,
31923
+                                          mRenderPassResultsPool, dstBuf);
31924
+        }
31925
+    }
31926
 
31927
     // Combine the values stored in the offsets allocated for each of the remaining queries
31928
-    for (size_t i = 0; i < mAllocatedQueries.size(); ++i)
31929
+    for (size_t i = 1; i < mAllocatedQueries.size(); ++i)
31930
     {
31931
         QueryMtl *query = mAllocatedQueries[i];
31932
         if (!query)
31933
@@ -126,12 +155,12 @@
31934
         const BufferRef &dstBuf = mAllocatedQueries[i]->getVisibilityResultBuffer();
31935
         const VisibilityBufferOffsetsMtl &allocatedOffsets =
31936
             mAllocatedQueries[i]->getAllocatedVisibilityOffsets();
31937
-        utils.combineVisibilityResult(contextMtl, /** keepOldValue */ i == 0 && !mResetFirstQuery,
31938
-                                      allocatedOffsets, mRenderPassResultsPool, dstBuf);
31939
+        utils.combineVisibilityResult(contextMtl, false, allocatedOffsets, mRenderPassResultsPool,
31940
+                                      dstBuf);
31941
     }
31942
 
31943
     // Request synchronization and cleanup
31944
-    BlitCommandEncoder *blitEncoder = contextMtl->getBlitCommandEncoder();
31945
+    blitEncoder = contextMtl->getBlitCommandEncoder();
31946
     for (size_t i = 0; i < mAllocatedQueries.size(); ++i)
31947
     {
31948
         QueryMtl *query = mAllocatedQueries[i];
31949
diff --git a/src/libANGLE/renderer/metal/mtl_render_utils.h b/src/libANGLE/renderer/metal/mtl_render_utils.h
31950
index 6b967de..d0a4837 100644
31951
--- a/src/libANGLE/renderer/metal/mtl_render_utils.h
31952
+++ b/src/libANGLE/renderer/metal/mtl_render_utils.h
31953
@@ -6,6 +6,8 @@
31954
 // mtl_render_utils.h:
31955
 //    Defines the class interface for RenderUtils, which contains many utility functions and shaders
31956
 //    for converting, blitting, copying as well as generating data, and many more.
31957
+// NOTE(hqle): Consider splitting this class into multiple classes each doing different utilities.
31958
+// This class has become too big.
31959
 //
31960
 
31961
 #ifndef LIBANGLE_RENDERER_METAL_MTL_RENDER_UTILS_H_
31962
@@ -89,6 +91,8 @@ struct ColorBlitParams : public BlitParams
31963
 struct DepthStencilBlitParams : public BlitParams
31964
 {
31965
     TextureRef srcStencil;
31966
+    uint32_t srcStencilLevel = 0;
31967
+    uint32_t srcStencilLayer = 0;
31968
 };
31969
 
31970
 // Stencil blit via an intermediate buffer. NOTE: source depth texture parameter is ignored.
31971
@@ -309,21 +313,17 @@ class IndexGeneratorUtils final : angle::NonCopyable
31972
   public:
31973
     void onDestroy();
31974
 
31975
-    // Convert index buffer.
31976
     angle::Result convertIndexBufferGPU(ContextMtl *contextMtl,
31977
                                         const IndexConversionParams &params);
31978
-    // Generate triangle fan index buffer for glDrawArrays().
31979
     angle::Result generateTriFanBufferFromArrays(ContextMtl *contextMtl,
31980
                                                  const TriFanOrLineLoopFromArrayParams &params);
31981
     // Generate triangle fan index buffer for glDrawElements().
31982
     angle::Result generateTriFanBufferFromElementsArray(ContextMtl *contextMtl,
31983
-                                                        const IndexGenerationParams &params);
31984
+                                                        const IndexGenerationParams &params,
31985
+                                                        uint32_t *indicesGenerated);
31986
 
31987
-    // Generate line loop index buffer for glDrawArrays().
31988
     angle::Result generateLineLoopBufferFromArrays(ContextMtl *contextMtl,
31989
                                                    const TriFanOrLineLoopFromArrayParams &params);
31990
-    // Generate line loop's last segment index buffer for glDrawArrays().
31991
-    // This is used when primitive restart is not enabled.
31992
     angle::Result generateLineLoopLastSegment(ContextMtl *contextMtl,
31993
                                               uint32_t firstVertex,
31994
                                               uint32_t lastVertex,
31995
@@ -340,6 +340,18 @@ class IndexGeneratorUtils final : angle::NonCopyable
31996
     angle::Result generateLineLoopLastSegmentFromElementsArray(ContextMtl *contextMtl,
31997
                                                                const IndexGenerationParams &params);
31998
 
31999
+    angle::Result generatePrimitiveRestartPointsBuffer(ContextMtl *contextMtl,
32000
+                                                       const IndexGenerationParams &params,
32001
+                                                       size_t *indicesGenerated);
32002
+
32003
+    angle::Result generatePrimitiveRestartLinesBuffer(ContextMtl *contextMtl,
32004
+                                                      const IndexGenerationParams &params,
32005
+                                                      size_t *indicesGenerated);
32006
+
32007
+    angle::Result generatePrimitiveRestartTrianglesBuffer(ContextMtl *contextMtl,
32008
+                                                          const IndexGenerationParams &params,
32009
+                                                          size_t *indicesGenerated);
32010
+
32011
   private:
32012
     // Index generator compute pipelines:
32013
     //  - First dimension: index type.
32014
@@ -348,7 +360,6 @@ class IndexGeneratorUtils final : angle::NonCopyable
32015
         std::array<std::array<AutoObjCPtr<id<MTLComputePipelineState>>, 2>,
32016
                    angle::EnumSize<gl::DrawElementsType>()>;
32017
 
32018
-    // Get compute pipeline to convert index between buffers.
32019
     AutoObjCPtr<id<MTLComputePipelineState>> getIndexConversionPipeline(
32020
         ContextMtl *contextMtl,
32021
         gl::DrawElementsType srcType,
32022
@@ -375,7 +386,8 @@ class IndexGeneratorUtils final : angle::NonCopyable
32023
         // Must be multiples of kIndexBufferOffsetAlignment
32024
         uint32_t dstOffset);
32025
     angle::Result generateTriFanBufferFromElementsArrayCPU(ContextMtl *contextMtl,
32026
-                                                           const IndexGenerationParams &params);
32027
+                                                           const IndexGenerationParams &params,
32028
+                                                           uint32_t *indicesGenerated);
32029
 
32030
     angle::Result generateLineLoopBufferFromElementsArrayGPU(
32031
         ContextMtl *contextMtl,
32032
@@ -393,6 +405,11 @@ class IndexGeneratorUtils final : angle::NonCopyable
32033
         ContextMtl *contextMtl,
32034
         const IndexGenerationParams &params);
32035
 
32036
+    angle::Result generatePrimitiveRestartBuffer(ContextMtl *contextMtl,
32037
+                                                 unsigned numVerticesPerPrimitive,
32038
+                                                 const IndexGenerationParams &params,
32039
+                                                 size_t *indicesGenerated);
32040
+
32041
     IndexConversionPipelineArray mIndexConversionPipelineCaches;
32042
 
32043
     IndexConversionPipelineArray mTriFanFromElemArrayGeneratorPipelineCaches;
32044
@@ -429,7 +446,7 @@ class MipmapUtils final : angle::NonCopyable
32045
   public:
32046
     void onDestroy();
32047
 
32048
-    // Compute based mipmap generation. Only possible for 3D texture for now.
32049
+    // Compute based mipmap generation.
32050
     angle::Result generateMipmapCS(ContextMtl *contextMtl,
32051
                                    const TextureRef &srcTexture,
32052
                                    bool sRGBMipmap,
32053
@@ -437,9 +454,15 @@ class MipmapUtils final : angle::NonCopyable
32054
 
32055
   private:
32056
     void ensure3DMipGeneratorPipelineInitialized(ContextMtl *contextMtl);
32057
+    void ensure2DMipGeneratorPipelineInitialized(ContextMtl *contextMtl);
32058
+    void ensure2DArrayMipGeneratorPipelineInitialized(ContextMtl *contextMtl);
32059
+    void ensureCubeMipGeneratorPipelineInitialized(ContextMtl *contextMtl);
32060
 
32061
     // Mipmaps generating compute pipeline:
32062
     AutoObjCPtr<id<MTLComputePipelineState>> m3DMipGeneratorPipeline;
32063
+    AutoObjCPtr<id<MTLComputePipelineState>> m2DMipGeneratorPipeline;
32064
+    AutoObjCPtr<id<MTLComputePipelineState>> m2DArrayMipGeneratorPipeline;
32065
+    AutoObjCPtr<id<MTLComputePipelineState>> mCubeMipGeneratorPipeline;
32066
 };
32067
 
32068
 // Util class for handling pixels copy between buffers and textures
32069
@@ -543,6 +566,21 @@ class VertexFormatConversionUtils final : angle::NonCopyable
32070
     RenderPipelineCache mComponentsExpandRenderPipelineCache;
32071
 };
32072
 
32073
+// Util class for handling transform feedback
32074
+    class TransformFeedbackUtils
32075
+{
32076
+  public:
32077
+    void onDestroy();
32078
+    AutoObjCPtr<id<MTLRenderPipelineState>> getTransformFeedbackRenderPipeline(
32079
+        ContextMtl *contextMtl,
32080
+        RenderCommandEncoder *cmdEncoder,
32081
+        mtl::RenderPipelineDesc &pipelineDesc);
32082
+
32083
+  private:
32084
+    AutoObjCPtr<id<MTLLibrary>> createMslXfbLibrary(ContextMtl *contextMtl,
32085
+                                                    const std::string &translatedMsl);
32086
+};
32087
+
32088
 // RenderUtils: container class of various util classes above
32089
 class RenderUtils : public Context, angle::NonCopyable
32090
 {
32091
@@ -587,7 +625,8 @@ class RenderUtils : public Context, angle::NonCopyable
32092
     angle::Result generateTriFanBufferFromArrays(ContextMtl *contextMtl,
32093
                                                  const TriFanOrLineLoopFromArrayParams &params);
32094
     angle::Result generateTriFanBufferFromElementsArray(ContextMtl *contextMtl,
32095
-                                                        const IndexGenerationParams &params);
32096
+                                                        const IndexGenerationParams &params,
32097
+                                                        uint32_t *indicesGenerated);
32098
 
32099
     angle::Result generateLineLoopBufferFromArrays(ContextMtl *contextMtl,
32100
                                                    const TriFanOrLineLoopFromArrayParams &params);
32101
@@ -639,6 +678,19 @@ class RenderUtils : public Context, angle::NonCopyable
32102
                                                  RenderCommandEncoder *renderEncoder,
32103
                                                  const angle::Format &srcAngleFormat,
32104
                                                  const VertexFormatConvertParams &params);
32105
+    angle::Result createTransformFeedbackPSO(const gl::Context *context,
32106
+                                             RenderCommandEncoder *renderEncoder,
32107
+                                             mtl::RenderPipelineDesc &pipelineDesc);
32108
+
32109
+    angle::Result generatePrimitiveRestartPointsBuffer(ContextMtl *contextMtl,
32110
+                                                       const IndexGenerationParams &params,
32111
+                                                       size_t *indicesGenerated);
32112
+    angle::Result generatePrimitiveRestartLinesBuffer(ContextMtl *contextMtl,
32113
+                                                      const IndexGenerationParams &params,
32114
+                                                      size_t *indicesGenerated);
32115
+    angle::Result generatePrimitiveRestartTrianglesBuffer(ContextMtl *contextMtl,
32116
+                                                          const IndexGenerationParams &params,
32117
+                                                          size_t *indicesGenerated);
32118
 
32119
   private:
32120
     // override ErrorHandler
32121
@@ -646,7 +698,7 @@ class RenderUtils : public Context, angle::NonCopyable
32122
                      const char *file,
32123
                      const char *function,
32124
                      unsigned int line) override;
32125
-    void handleError(NSError *_Nullable error,
32126
+    void handleError(NSError *error,
32127
                      const char *file,
32128
                      const char *function,
32129
                      unsigned int line) override;
32130
@@ -662,6 +714,7 @@ class RenderUtils : public Context, angle::NonCopyable
32131
     MipmapUtils mMipmapUtils;
32132
     std::array<CopyPixelsUtils, angle::EnumSize<PixelType>()> mCopyPixelsUtils;
32133
     VertexFormatConversionUtils mVertexFormatUtils;
32134
+    TransformFeedbackUtils mTransformFeedbackUtils;
32135
 };
32136
 
32137
 }  // namespace mtl
32138
diff --git a/src/libANGLE/renderer/metal/mtl_render_utils.mm b/src/libANGLE/renderer/metal/mtl_render_utils.mm
32139
index d224801..32b33ca 100644
32140
--- a/src/libANGLE/renderer/metal/mtl_render_utils.mm
32141
+++ b/src/libANGLE/renderer/metal/mtl_render_utils.mm
32142
@@ -15,6 +15,7 @@
32143
 #include "libANGLE/renderer/metal/BufferMtl.h"
32144
 #include "libANGLE/renderer/metal/ContextMtl.h"
32145
 #include "libANGLE/renderer/metal/DisplayMtl.h"
32146
+#include "libANGLE/renderer/metal/ProgramMtl.h"
32147
 #include "libANGLE/renderer/metal/QueryMtl.h"
32148
 #include "libANGLE/renderer/metal/mtl_common.h"
32149
 #include "libANGLE/renderer/metal/mtl_utils.h"
32150
@@ -54,10 +55,12 @@
32151
     float srcTexCoords[3][2];
32152
     int srcLevel         = 0;
32153
     int srcLayer         = 0;
32154
+    int srcLevel2        = 0;
32155
+    int srcLayer2        = 0;
32156
     uint8_t dstFlipX     = 0;
32157
     uint8_t dstFlipY     = 0;
32158
     uint8_t dstLuminance = 0;  // dest texture is luminace
32159
-    uint8_t padding[13];
32160
+    uint8_t padding[9];
32161
 };
32162
 
32163
 struct BlitStencilToBufferParamsUniform
32164
@@ -90,7 +93,7 @@
32165
     uint8_t padding[7];
32166
 };
32167
 
32168
-// See libANGLE/renderer/metal/shaders/visibility.metal
32169
+// See libANGLE/renderer/metal/shaders/misc.metal
32170
 struct CombineVisibilityResultUniform
32171
 {
32172
     uint32_t startOffset;
32173
@@ -99,12 +102,11 @@
32174
 };
32175
 
32176
 // See libANGLE/renderer/metal/shaders/gen_mipmap.metal
32177
-struct GenerateMipmapUniform
32178
+struct Generate3DMipmapUniform
32179
 {
32180
     uint32_t srcLevel;
32181
     uint32_t numMipmapsToGenerate;
32182
-    uint8_t sRGB;
32183
-    uint8_t padding[7];
32184
+    uint32_t padding[2];
32185
 };
32186
 
32187
 // See libANGLE/renderer/metal/shaders/copy_buffer.metal
32188
@@ -156,19 +158,36 @@
32189
 // exiting block.
32190
 struct ScopedDisableOcclusionQuery
32191
 {
32192
-    ScopedDisableOcclusionQuery(ContextMtl *contextMtl, angle::Result *resultOut)
32193
-        : mContextMtl(contextMtl), mResultOut(resultOut)
32194
+    ScopedDisableOcclusionQuery(ContextMtl *contextMtl,
32195
+                                RenderCommandEncoder *encoder,
32196
+                                angle::Result *resultOut)
32197
+        : mContextMtl(contextMtl), mEncoder(encoder), mResultOut(resultOut)
32198
+    {
32199
+#ifndef NDEBUG
32200
+        if (contextMtl->hasActiveOcclusionQuery())
32201
         {
32202
+            encoder->pushDebugGroup(@"Disabled OcclusionQuery");
32203
+        }
32204
+#endif
32205
         // temporarily disable occlusion query
32206
         contextMtl->disableActiveOcclusionQueryInRenderPass();
32207
     }
32208
     ~ScopedDisableOcclusionQuery()
32209
     {
32210
         *mResultOut = mContextMtl->restartActiveOcclusionQueryInRenderPass();
32211
+#ifndef NDEBUG
32212
+        if (mContextMtl->hasActiveOcclusionQuery())
32213
+        {
32214
+            mEncoder->popDebugGroup();
32215
+        }
32216
+#else
32217
+        ANGLE_UNUSED_VARIABLE(mEncoder);
32218
+#endif
32219
     }
32220
 
32221
   private:
32222
     ContextMtl *mContextMtl;
32223
+    RenderCommandEncoder *mEncoder;
32224
 
32225
     angle::Result *mResultOut;
32226
 };
32227
@@ -219,66 +238,43 @@ void GetBlitTexCoords(uint32_t srcWidth,
32228
                                           bool primitiveRestartEnabled,
32229
                                           const T *indices,
32230
                                           const BufferRef &dstBuffer,
32231
-                                          uint32_t dstOffset)
32232
+                                          uint32_t dstOffset,
32233
+                                          uint32_t *indicesGenerated)
32234
 {
32235
     ASSERT(count > 2);
32236
-
32237
-    uint32_t genIndicesCount;
32238
-    ANGLE_TRY(mtl::GetTriangleFanIndicesCount(contextMtl, count, &genIndicesCount));
32239
-
32240
     constexpr T kSrcPrimitiveRestartIndex = std::numeric_limits<T>::max();
32241
-    const uint32_t kDstPrimitiveRestartIndex = std::numeric_limits<uint32_t>::max();
32242
-
32243
+    GLsizei dstTriangle                   = 0;
32244
     uint32_t *dstPtr = reinterpret_cast<uint32_t *>(dstBuffer->map(contextMtl) + dstOffset);
32245
-    T triFirstIdx    = 0;  // Vertex index of trianlge's 1st vertex
32246
-    T srcPrevIdx     = 0;  // Vertex index of trianlge's 2nd vertex
32247
+    T triFirstIdx, srcPrevIdx;
32248
     memcpy(&triFirstIdx, indices, sizeof(triFirstIdx));
32249
+    memcpy(&srcPrevIdx, indices + 1, sizeof(srcPrevIdx));
32250
 
32251
     if (primitiveRestartEnabled)
32252
     {
32253
-        // triFirstIdxLoc: Location of current triangle's fist vertex in source buffer.
32254
         GLsizei triFirstIdxLoc = 0;
32255
         while (triFirstIdx == kSrcPrimitiveRestartIndex)
32256
         {
32257
-            memcpy(&dstPtr[triFirstIdxLoc++], &kDstPrimitiveRestartIndex,
32258
-                   sizeof(kDstPrimitiveRestartIndex));
32259
+            ++triFirstIdxLoc;
32260
             memcpy(&triFirstIdx, indices + triFirstIdxLoc, sizeof(triFirstIdx));
32261
         }
32262
 
32263
-        if (triFirstIdxLoc + 2 >= count)
32264
-        {
32265
-            // Not enough indices.
32266
-            for (GLsizei i = triFirstIdxLoc; i < count; ++i)
32267
-            {
32268
-                memcpy(&dstPtr[i], &kDstPrimitiveRestartIndex, sizeof(kDstPrimitiveRestartIndex));
32269
-            }
32270
-        }
32271
-        else if (triFirstIdxLoc + 1 < count)
32272
-        {
32273
-            memcpy(&srcPrevIdx, indices + triFirstIdxLoc + 1, sizeof(srcPrevIdx));
32274
-        }
32275
-
32276
         for (GLsizei i = triFirstIdxLoc + 2; i < count; ++i)
32277
         {
32278
             uint32_t triIndices[3];
32279
-
32280
             T srcIdx;
32281
             memcpy(&srcIdx, indices + i, sizeof(srcIdx));
32282
+            bool completeTriangle = true;
32283
             if (srcPrevIdx == kSrcPrimitiveRestartIndex || srcIdx == kSrcPrimitiveRestartIndex)
32284
             {
32285
-                // Incomplete triangle.
32286
-                triIndices[0]  = kDstPrimitiveRestartIndex;
32287
-                triIndices[1]  = kDstPrimitiveRestartIndex;
32288
-                triIndices[2]  = kDstPrimitiveRestartIndex;
32289
+                // Incomplete triangle. Move to next triangle and set triFirstIndex
32290
                 triFirstIdx      = srcIdx;
32291
                 triFirstIdxLoc   = i;
32292
+                completeTriangle = false;
32293
             }
32294
             else if (i < triFirstIdxLoc + 2)
32295
             {
32296
-                // Incomplete triangle
32297
-                triIndices[0] = kDstPrimitiveRestartIndex;
32298
-                triIndices[1] = kDstPrimitiveRestartIndex;
32299
-                triIndices[2] = kDstPrimitiveRestartIndex;
32300
+                // Incomplete triangle, move to next triangle
32301
+                completeTriangle = false;
32302
             }
32303
             else
32304
             {
32305
@@ -286,15 +282,16 @@ void GetBlitTexCoords(uint32_t srcWidth,
32306
                 triIndices[1] = srcPrevIdx;
32307
                 triIndices[2] = srcIdx;
32308
             }
32309
+            if (completeTriangle)
32310
+            {
32311
+                memcpy(dstPtr + 3 * dstTriangle, triIndices, sizeof(triIndices));
32312
+                ++dstTriangle;
32313
+            }
32314
             srcPrevIdx = srcIdx;
32315
-
32316
-            memcpy(dstPtr + 3 * (i - 2), triIndices, sizeof(triIndices));
32317
         }
32318
     }
32319
     else
32320
     {
32321
-        memcpy(&srcPrevIdx, indices + 1, sizeof(srcPrevIdx));
32322
-
32323
         for (GLsizei i = 2; i < count; ++i)
32324
         {
32325
             T srcIdx;
32326
@@ -306,14 +303,68 @@ void GetBlitTexCoords(uint32_t srcWidth,
32327
             triIndices[2] = srcIdx;
32328
             srcPrevIdx    = srcIdx;
32329
 
32330
-            memcpy(dstPtr + 3 * (i - 2), triIndices, sizeof(triIndices));
32331
+            memcpy(dstPtr + 3 * dstTriangle, triIndices, sizeof(triIndices));
32332
+            ++dstTriangle;
32333
         }
32334
     }
32335
-    dstBuffer->unmapAndFlushSubset(contextMtl, dstOffset, genIndicesCount * sizeof(uint32_t));
32336
+    if (indicesGenerated)
32337
+        *indicesGenerated = dstTriangle * 3;
32338
+    dstBuffer->unmap(contextMtl);
32339
 
32340
     return angle::Result::Continue;
32341
 }
32342
 
32343
+template <typename T>
32344
+angle::Result GenPrimitiveRestartBuffer(ContextMtl *contextMtl,
32345
+                                        GLsizei count,
32346
+                                        GLsizei indicesPerPrimitive,
32347
+                                        const T *indices,
32348
+                                        const BufferRef &dstBuffer,
32349
+                                        uint32_t dstOffset,
32350
+                                        size_t *indicesGenerated)
32351
+{
32352
+    constexpr T kSrcPrimitiveRestartIndex = std::numeric_limits<T>::max();
32353
+    uint32_t *dstPtr     = reinterpret_cast<uint32_t *>(dstBuffer->map(contextMtl) + dstOffset);
32354
+    GLsizei readValueLoc = 0;
32355
+    T readValue          = 0;
32356
+    uint32_t dstIdx      = 0;
32357
+    memcpy(&readValue, indices, sizeof(readValue));
32358
+    while (readValue == kSrcPrimitiveRestartIndex)
32359
+    {
32360
+
32361
+        ++readValueLoc;
32362
+        memcpy(&readValue, indices + readValueLoc, sizeof(readValue));
32363
+    }
32364
+    while (readValueLoc + indicesPerPrimitive <= count)
32365
+    {
32366
+
32367
+        uint32_t primIndicies[3];
32368
+        bool foundPrimitive = true;
32369
+        for (int k = 0; k < indicesPerPrimitive; ++k)
32370
+        {
32371
+            memcpy(&readValue, indices + readValueLoc, sizeof(readValue));
32372
+            ++readValueLoc;
32373
+            if (readValue == kSrcPrimitiveRestartIndex)
32374
+            {
32375
+                foundPrimitive = false;
32376
+                break;
32377
+            }
32378
+            else
32379
+            {
32380
+                primIndicies[k] = (uint32_t)readValue;
32381
+            }
32382
+        }
32383
+        if (foundPrimitive)
32384
+        {
32385
+            memcpy(&dstPtr[dstIdx], primIndicies, (indicesPerPrimitive) * sizeof(uint32_t));
32386
+            dstIdx += indicesPerPrimitive;
32387
+        }
32388
+    }
32389
+    if (indicesGenerated)
32390
+        *indicesGenerated = dstIdx;
32391
+    return angle::Result::Continue;
32392
+}
32393
+
32394
 template <typename T>
32395
 angle::Result GenLineLoopFromClientElements(ContextMtl *contextMtl,
32396
                                             GLsizei count,
32397
@@ -328,14 +379,11 @@ void GetBlitTexCoords(uint32_t srcWidth,
32398
     const uint32_t kDstPrimitiveRestartIndex = std::numeric_limits<uint32_t>::max();
32399
 
32400
     uint32_t *dstPtr = reinterpret_cast<uint32_t *>(dstBuffer->map(contextMtl) + dstOffset);
32401
-    // lineLoopFirstIdx: value of of current line loop's first vertex index. Can change when
32402
-    // encounter a primitive restart index.
32403
     T lineLoopFirstIdx;
32404
     memcpy(&lineLoopFirstIdx, indices, sizeof(lineLoopFirstIdx));
32405
 
32406
     if (primitiveRestartEnabled)
32407
     {
32408
-        // lineLoopFirstIdxLoc: location of current line loop's first vertex in the source buffer.
32409
         GLsizei lineLoopFirstIdxLoc = 0;
32410
         while (lineLoopFirstIdx == kSrcPrimitiveRestartIndex)
32411
         {
32412
@@ -344,15 +392,12 @@ void GetBlitTexCoords(uint32_t srcWidth,
32413
             memcpy(&lineLoopFirstIdx, indices + lineLoopFirstIdxLoc, sizeof(lineLoopFirstIdx));
32414
         }
32415
 
32416
-        // dstIdx : value of index to be written to dest buffer
32417
         uint32_t dstIdx = lineLoopFirstIdx;
32418
         memcpy(&dstPtr[lineLoopFirstIdxLoc], &dstIdx, sizeof(dstIdx));
32419
-        // dstWritten: number of indices written to dest buffer
32420
         uint32_t dstWritten = lineLoopFirstIdxLoc + 1;
32421
 
32422
         for (GLsizei i = lineLoopFirstIdxLoc + 1; i < count; ++i)
32423
         {
32424
-            // srcIdx : value of index from source buffer
32425
             T srcIdx;
32426
             memcpy(&srcIdx, indices + i, sizeof(srcIdx));
32427
             if (srcIdx == kSrcPrimitiveRestartIndex)
32428
@@ -400,7 +445,7 @@ void GetBlitTexCoords(uint32_t srcWidth,
32429
 
32430
         *indicesGenerated = count + 1;
32431
     }
32432
-    dstBuffer->unmapAndFlushSubset(contextMtl, dstOffset, (*indicesGenerated) * sizeof(uint32_t));
32433
+    dstBuffer->unmap(contextMtl);
32434
 
32435
     return angle::Result::Continue;
32436
 }
32437
@@ -472,7 +517,7 @@ void EnsureComputePipelineInitialized(DisplayMtl *display,
32438
     ANGLE_MTL_OBJC_SCOPE
32439
     {
32440
         id<MTLDevice> metalDevice = display->getMetalDevice();
32441
-        id<MTLLibrary> shaderLib  = display->getDefaultShadersLib();
32442
+        auto shaderLib            = display->getDefaultShadersLib();
32443
         NSError *err              = nil;
32444
         id<MTLFunction> shader    = [shaderLib newFunctionWithName:functionName];
32445
 
32446
@@ -512,7 +557,7 @@ void EnsureSpecializedComputePipelineInitialized(
32447
     ANGLE_MTL_OBJC_SCOPE
32448
     {
32449
         id<MTLDevice> metalDevice = display->getMetalDevice();
32450
-        id<MTLLibrary> shaderLib  = display->getDefaultShadersLib();
32451
+        auto shaderLib            = display->getDefaultShadersLib();
32452
         NSError *err              = nil;
32453
 
32454
         id<MTLFunction> shader = [shaderLib newFunctionWithName:functionName
32455
@@ -538,6 +583,7 @@ void EnsureSpecializedComputePipelineInitialized(
32456
 ANGLE_INLINE
32457
 void EnsureVertexShaderOnlyPipelineCacheInitialized(Context *context,
32458
                                                     NSString *vertexFunctionName,
32459
+                                                    id<MTLLibrary> shaderLib,
32460
                                                     RenderPipelineCache *pipelineCacheOut)
32461
 {
32462
     RenderPipelineCache &pipelineCache = *pipelineCacheOut;
32463
@@ -549,8 +595,6 @@ void EnsureVertexShaderOnlyPipelineCacheInitialized(Context *context,
32464
 
32465
     ANGLE_MTL_OBJC_SCOPE
32466
     {
32467
-        DisplayMtl *display      = context->getDisplay();
32468
-        id<MTLLibrary> shaderLib = display->getDefaultShadersLib();
32469
         id<MTLFunction> shader = [shaderLib newFunctionWithName:vertexFunctionName];
32470
 
32471
         ASSERT([shader ANGLE_MTL_AUTORELEASE]);
32472
@@ -570,7 +614,9 @@ void EnsureSpecializedVertexShaderOnlyPipelineCacheInitialized(
32473
     if (!funcConstants)
32474
     {
32475
         // Non specialized constants provided, use default creation function.
32476
-        EnsureVertexShaderOnlyPipelineCacheInitialized(context, vertexFunctionName,
32477
+        DisplayMtl *display = context->getDisplay();
32478
+        auto shaderLib      = display->getDefaultShadersLib();
32479
+        EnsureVertexShaderOnlyPipelineCacheInitialized(context, vertexFunctionName, shaderLib,
32480
                                                        pipelineCacheOut);
32481
         return;
32482
     }
32483
@@ -585,7 +631,7 @@ void EnsureSpecializedVertexShaderOnlyPipelineCacheInitialized(
32484
     ANGLE_MTL_OBJC_SCOPE
32485
     {
32486
         DisplayMtl *display = context->getDisplay();
32487
-        id<MTLLibrary> shaderLib = display->getDefaultShadersLib();
32488
+        auto shaderLib      = display->getDefaultShadersLib();
32489
         NSError *err        = nil;
32490
 
32491
         id<MTLFunction> shader = [shaderLib newFunctionWithName:vertexFunctionName
32492
@@ -615,6 +661,22 @@ RenderPipelineDesc GetComputingVertexShaderOnlyRenderPipelineDesc(RenderCommandE
32493
     return pipelineDesc;
32494
 }
32495
 
32496
+// Get pipeline descriptor for render pipeline that contains vertex shader acting as transform
32497
+// feedback.
32498
+ANGLE_INLINE
32499
+RenderPipelineDesc GetTransformFeedbackRenderPipelineDesc(RenderCommandEncoder *cmdEncoder,
32500
+                                                          mtl::RenderPipelineDesc &pipelineDesc)
32501
+{
32502
+    RenderPipelineDesc xfbPipelineDesc   = RenderPipelineDesc(pipelineDesc);
32503
+    const RenderPassDesc &renderPassDesc = cmdEncoder->renderPassDesc();
32504
+
32505
+    renderPassDesc.populateRenderPipelineOutputDesc(&pipelineDesc.outputDescriptor);
32506
+    xfbPipelineDesc.rasterizationType   = RenderPipelineRasterization::Disabled;
32507
+    xfbPipelineDesc.inputPrimitiveTopology = kPrimitiveTopologyClassPoint;
32508
+
32509
+    return xfbPipelineDesc;
32510
+}
32511
+
32512
 template <typename T>
32513
 void ClearRenderPipelineCacheArray(T *pipelineCacheArray)
32514
 {
32515
@@ -712,9 +774,15 @@ void SetupBlitWithDrawUniformData(RenderCommandEncoder *cmdEncoder,
32516
     uniformParams.srcLayer = params.srcLayer;
32517
     if (isColorBlit)
32518
     {
32519
-        const ColorBlitParams *colorParams = static_cast<const ColorBlitParams *>(&params);
32520
+        const auto colorParams     = static_cast<const ColorBlitParams *>(&params);
32521
         uniformParams.dstLuminance = colorParams->dstLuminance ? 1 : 0;
32522
     }
32523
+    else
32524
+    {
32525
+        const auto dsParams     = static_cast<const DepthStencilBlitParams *>(&params);
32526
+        uniformParams.srcLevel2 = dsParams->srcStencilLevel;
32527
+        uniformParams.srcLayer2 = dsParams->srcStencilLayer;
32528
+    }
32529
 
32530
     // Compute source texCoords
32531
     uint32_t srcWidth = 0, srcHeight = 0;
32532
@@ -727,8 +795,8 @@ void SetupBlitWithDrawUniformData(RenderCommandEncoder *cmdEncoder,
32533
     {
32534
         const DepthStencilBlitParams *dsParams =
32535
             static_cast<const DepthStencilBlitParams *>(&params);
32536
-        srcWidth  = dsParams->srcStencil->width(dsParams->srcLevel);
32537
-        srcHeight = dsParams->srcStencil->height(dsParams->srcLevel);
32538
+        srcWidth  = dsParams->srcStencil->width(mtl::MipmapNativeLevel(dsParams->srcStencilLevel));
32539
+        srcHeight = dsParams->srcStencil->height(mtl::MipmapNativeLevel(dsParams->srcStencilLevel));
32540
     }
32541
     else
32542
     {
32543
@@ -739,8 +807,8 @@ void SetupBlitWithDrawUniformData(RenderCommandEncoder *cmdEncoder,
32544
     GetBlitTexCoords(srcWidth, srcHeight, params.srcRect, params.srcYFlipped, params.unpackFlipX,
32545
                      params.unpackFlipY, &u0, &v0, &u1, &v1);
32546
 
32547
-    float du = u1 - u0;
32548
-    float dv = v1 - v0;
32549
+    auto du = u1 - u0;
32550
+    auto dv = v1 - v0;
32551
 
32552
     // lower left
32553
     uniformParams.srcTexCoords[0][0] = u0;
32554
@@ -844,19 +912,21 @@ ANGLE_INLINE void SetPipelineState(ComputeCommandEncoder *encoder,
32555
 // StencilBlitViaBufferParams implementation
32556
 StencilBlitViaBufferParams::StencilBlitViaBufferParams() {}
32557
 
32558
-StencilBlitViaBufferParams::StencilBlitViaBufferParams(const DepthStencilBlitParams &srcIn)
32559
+StencilBlitViaBufferParams::StencilBlitViaBufferParams(const DepthStencilBlitParams &srcParams)
32560
 {
32561
-    dstTextureSize = srcIn.dstTextureSize;
32562
-    dstRect        = srcIn.dstRect;
32563
-    dstScissorRect = srcIn.dstScissorRect;
32564
-    dstFlipY       = srcIn.dstFlipY;
32565
-    dstFlipX       = srcIn.dstFlipX;
32566
-    srcRect        = srcIn.srcRect;
32567
-    srcYFlipped    = srcIn.srcYFlipped;
32568
-    unpackFlipX    = srcIn.unpackFlipX;
32569
-    unpackFlipY    = srcIn.unpackFlipY;
32570
+    dstTextureSize = srcParams.dstTextureSize;
32571
+    dstRect        = srcParams.dstRect;
32572
+    dstScissorRect = srcParams.dstScissorRect;
32573
+    dstFlipY       = srcParams.dstFlipY;
32574
+    dstFlipX       = srcParams.dstFlipX;
32575
+    srcRect        = srcParams.srcRect;
32576
+    srcYFlipped    = srcParams.srcYFlipped;
32577
+    unpackFlipX    = srcParams.unpackFlipX;
32578
+    unpackFlipY    = srcParams.unpackFlipY;
32579
 
32580
-    srcStencil = srcIn.srcStencil;
32581
+    srcStencil      = srcParams.srcStencil;
32582
+    srcStencilLevel = srcParams.srcStencilLevel;
32583
+    srcStencilLayer = srcParams.srcStencilLayer;
32584
 }
32585
 
32586
 // RenderUtils implementation
32587
@@ -903,6 +973,7 @@ ANGLE_INLINE void SetPipelineState(ComputeCommandEncoder *encoder,
32588
     }
32589
 }
32590
 
32591
+
32592
 // override ErrorHandler
32593
 void RenderUtils::handleError(GLenum glErrorCode,
32594
                               const char *file,
32595
@@ -1016,9 +1087,10 @@ ANGLE_INLINE void SetPipelineState(ComputeCommandEncoder *encoder,
32596
 }
32597
 angle::Result RenderUtils::generateTriFanBufferFromElementsArray(
32598
     ContextMtl *contextMtl,
32599
-    const IndexGenerationParams &params)
32600
+    const IndexGenerationParams &params,
32601
+    uint32_t *indicesGenerated)
32602
 {
32603
-    return mIndexUtils.generateTriFanBufferFromElementsArray(contextMtl, params);
32604
+    return mIndexUtils.generateTriFanBufferFromElementsArray(contextMtl, params, indicesGenerated);
32605
 }
32606
 
32607
 angle::Result RenderUtils::generateLineLoopBufferFromArrays(
32608
@@ -1050,6 +1122,26 @@ ANGLE_INLINE void SetPipelineState(ComputeCommandEncoder *encoder,
32609
 {
32610
     return mIndexUtils.generateLineLoopLastSegmentFromElementsArray(contextMtl, params);
32611
 }
32612
+angle::Result RenderUtils::generatePrimitiveRestartPointsBuffer(ContextMtl *contextMtl,
32613
+                                                                const IndexGenerationParams &params,
32614
+                                                                size_t *indicesGenerated)
32615
+{
32616
+    return mIndexUtils.generatePrimitiveRestartPointsBuffer(contextMtl, params, indicesGenerated);
32617
+}
32618
+angle::Result RenderUtils::generatePrimitiveRestartLinesBuffer(ContextMtl *contextMtl,
32619
+                                                               const IndexGenerationParams &params,
32620
+                                                               size_t *indicesGenerated)
32621
+{
32622
+    return mIndexUtils.generatePrimitiveRestartLinesBuffer(contextMtl, params, indicesGenerated);
32623
+}
32624
+angle::Result RenderUtils::generatePrimitiveRestartTrianglesBuffer(
32625
+    ContextMtl *contextMtl,
32626
+    const IndexGenerationParams &params,
32627
+    size_t *indicesGenerated)
32628
+{
32629
+    return mIndexUtils.generatePrimitiveRestartTrianglesBuffer(contextMtl, params,
32630
+                                                               indicesGenerated);
32631
+}
32632
 
32633
 void RenderUtils::combineVisibilityResult(
32634
     ContextMtl *contextMtl,
32635
@@ -1121,6 +1213,21 @@ ANGLE_INLINE void SetPipelineState(ComputeCommandEncoder *encoder,
32636
                                                              params);
32637
 }
32638
 
32639
+angle::Result RenderUtils::createTransformFeedbackPSO(const gl::Context *context,
32640
+                                                      RenderCommandEncoder *renderEncoder,
32641
+                                                      mtl::RenderPipelineDesc &pipelineDesc)
32642
+{
32643
+    ContextMtl *contextMtl = mtl::GetImpl(context);
32644
+    // Create and cache the PSO
32645
+    auto pso = mTransformFeedbackUtils.getTransformFeedbackRenderPipeline(contextMtl, renderEncoder,
32646
+                                                                          pipelineDesc);
32647
+    if (pso)
32648
+    {
32649
+        return angle::Result::Continue;
32650
+    }
32651
+    return angle::Result::Stop;
32652
+}
32653
+
32654
 // ClearUtils implementation
32655
 ClearUtils::ClearUtils(const std::string &fragmentShaderName)
32656
     : mFragmentShaderName(fragmentShaderName)
32657
@@ -1287,11 +1394,11 @@ ANGLE_INLINE void SetPipelineState(ComputeCommandEncoder *encoder,
32658
     {
32659
         overridedParams.clearColor.reset();
32660
     }
32661
-    if (!renderPassDesc.depthAttachment.texture)
32662
+    if (!renderPassDesc.depthAttachment.texture())
32663
     {
32664
         overridedParams.clearDepth.reset();
32665
     }
32666
-    if (!renderPassDesc.stencilAttachment.texture)
32667
+    if (!renderPassDesc.stencilAttachment.texture())
32668
     {
32669
         overridedParams.clearStencil.reset();
32670
     }
32671
@@ -1307,7 +1414,7 @@ ANGLE_INLINE void SetPipelineState(ComputeCommandEncoder *encoder,
32672
     angle::Result result;
32673
     {
32674
         // Need to disable occlusion query, otherwise clearing will affect the occlusion counting
32675
-        ScopedDisableOcclusionQuery disableOcclusionQuery(contextMtl, &result);
32676
+        ScopedDisableOcclusionQuery disableOcclusionQuery(contextMtl, cmdEncoder, &result);
32677
         // Draw the screen aligned triangle
32678
         cmdEncoder->draw(MTLPrimitiveTypeTriangle, 0, 3);
32679
     }
32680
@@ -1481,7 +1588,7 @@ ANGLE_INLINE void SetPipelineState(ComputeCommandEncoder *encoder,
32681
     angle::Result result;
32682
     {
32683
         // Need to disable occlusion query, otherwise blitting will affect the occlusion counting
32684
-        ScopedDisableOcclusionQuery disableOcclusionQuery(contextMtl, &result);
32685
+        ScopedDisableOcclusionQuery disableOcclusionQuery(contextMtl, cmdEncoder, &result);
32686
         // Draw the screen aligned triangle
32687
         cmdEncoder->draw(MTLPrimitiveTypeTriangle, 0, 3);
32688
     }
32689
@@ -1703,7 +1810,7 @@ ANGLE_INLINE void SetPipelineState(ComputeCommandEncoder *encoder,
32690
     angle::Result result;
32691
     {
32692
         // Need to disable occlusion query, otherwise blitting will affect the occlusion counting
32693
-        ScopedDisableOcclusionQuery disableOcclusionQuery(contextMtl, &result);
32694
+        ScopedDisableOcclusionQuery disableOcclusionQuery(contextMtl, cmdEncoder, &result);
32695
         // Draw the screen aligned triangle
32696
         cmdEncoder->draw(MTLPrimitiveTypeTriangle, 0, 3);
32697
     }
32698
@@ -2002,7 +2109,8 @@ ANGLE_INLINE void SetPipelineState(ComputeCommandEncoder *encoder,
32699
 
32700
 angle::Result IndexGeneratorUtils::generateTriFanBufferFromElementsArray(
32701
     ContextMtl *contextMtl,
32702
-    const IndexGenerationParams &params)
32703
+    const IndexGenerationParams &params,
32704
+    uint32_t *indicesGenerated)
32705
 {
32706
     const gl::VertexArray *vertexArray = contextMtl->getState().getVertexArray();
32707
     const gl::Buffer *elementBuffer    = vertexArray->getElementArrayBuffer();
32708
@@ -2013,13 +2121,14 @@ ANGLE_INLINE void SetPipelineState(ComputeCommandEncoder *encoder,
32709
         ANGLE_CHECK(contextMtl, srcOffset <= std::numeric_limits<uint32_t>::max(),
32710
                     "Index offset is too large", GL_INVALID_VALUE);
32711
         if (params.primitiveRestartEnabled ||
32712
-            (!contextMtl->getDisplay()->getFeatures().hasCheapRenderPass.enabled &&
32713
+            (!contextMtl->getDisplay()->getFeatures().breakRenderPassIsCheap.enabled &&
32714
              contextMtl->getRenderCommandEncoder()))
32715
         {
32716
             IndexGenerationParams cpuPathParams = params;
32717
             cpuPathParams.indices =
32718
                 elementBufferMtl->getClientShadowCopyData(contextMtl) + srcOffset;
32719
-            return generateTriFanBufferFromElementsArrayCPU(contextMtl, cpuPathParams);
32720
+            return generateTriFanBufferFromElementsArrayCPU(contextMtl, cpuPathParams,
32721
+                                                            indicesGenerated);
32722
         }
32723
         else
32724
         {
32725
@@ -2030,7 +2139,7 @@ ANGLE_INLINE void SetPipelineState(ComputeCommandEncoder *encoder,
32726
     }
32727
     else
32728
     {
32729
-        return generateTriFanBufferFromElementsArrayCPU(contextMtl, params);
32730
+        return generateTriFanBufferFromElementsArrayCPU(contextMtl, params, indicesGenerated);
32731
     }
32732
 }
32733
 
32734
@@ -2074,22 +2183,23 @@ ANGLE_INLINE void SetPipelineState(ComputeCommandEncoder *encoder,
32735
 
32736
 angle::Result IndexGeneratorUtils::generateTriFanBufferFromElementsArrayCPU(
32737
     ContextMtl *contextMtl,
32738
-    const IndexGenerationParams &params)
32739
+    const IndexGenerationParams &params,
32740
+    uint32_t *genIndices)
32741
 {
32742
     switch (params.srcType)
32743
     {
32744
         case gl::DrawElementsType::UnsignedByte:
32745
             return GenTriFanFromClientElements(
32746
                 contextMtl, params.indexCount, params.primitiveRestartEnabled,
32747
-                static_cast<const uint8_t *>(params.indices), params.dstBuffer, params.dstOffset);
32748
+                static_cast<const uint8_t *>(params.indices), params.dstBuffer, params.dstOffset, genIndices);
32749
         case gl::DrawElementsType::UnsignedShort:
32750
             return GenTriFanFromClientElements(
32751
                 contextMtl, params.indexCount, params.primitiveRestartEnabled,
32752
-                static_cast<const uint16_t *>(params.indices), params.dstBuffer, params.dstOffset);
32753
+                static_cast<const uint16_t *>(params.indices), params.dstBuffer, params.dstOffset, genIndices);
32754
         case gl::DrawElementsType::UnsignedInt:
32755
             return GenTriFanFromClientElements(
32756
                 contextMtl, params.indexCount, params.primitiveRestartEnabled,
32757
-                static_cast<const uint32_t *>(params.indices), params.dstBuffer, params.dstOffset);
32758
+                static_cast<const uint32_t *>(params.indices), params.dstBuffer, params.dstOffset, genIndices);
32759
         default:
32760
             UNREACHABLE();
32761
     }
32762
@@ -2301,6 +2411,56 @@ ANGLE_INLINE void SetPipelineState(ComputeCommandEncoder *encoder,
32763
     return generateLineLoopLastSegment(contextMtl, first, last, params.dstBuffer, params.dstOffset);
32764
 }
32765
 
32766
+angle::Result IndexGeneratorUtils::generatePrimitiveRestartBuffer(
32767
+    ContextMtl *contextMtl,
32768
+    unsigned numVerticesPerPrimitive,
32769
+    const IndexGenerationParams &params,
32770
+    size_t *indicesGenerated)
32771
+{
32772
+    switch (params.srcType)
32773
+    {
32774
+        case gl::DrawElementsType::UnsignedByte:
32775
+            return GenPrimitiveRestartBuffer(contextMtl, params.indexCount, numVerticesPerPrimitive,
32776
+                                             static_cast<const uint8_t *>(params.indices),
32777
+                                             params.dstBuffer, params.dstOffset, indicesGenerated);
32778
+        case gl::DrawElementsType::UnsignedShort:
32779
+            return GenPrimitiveRestartBuffer(contextMtl, params.indexCount, numVerticesPerPrimitive,
32780
+                                             static_cast<const uint16_t *>(params.indices),
32781
+                                             params.dstBuffer, params.dstOffset, indicesGenerated);
32782
+        case gl::DrawElementsType::UnsignedInt:
32783
+            return GenPrimitiveRestartBuffer(contextMtl, params.indexCount, numVerticesPerPrimitive,
32784
+                                             static_cast<const uint32_t *>(params.indices),
32785
+                                             params.dstBuffer, params.dstOffset, indicesGenerated);
32786
+        default:
32787
+            UNREACHABLE();
32788
+            return angle::Result::Stop;
32789
+    }
32790
+}
32791
+
32792
+angle::Result IndexGeneratorUtils::generatePrimitiveRestartTrianglesBuffer(
32793
+    ContextMtl *contextMtl,
32794
+    const IndexGenerationParams &params,
32795
+    size_t *indicesGenerated)
32796
+{
32797
+    return generatePrimitiveRestartBuffer(contextMtl, 3, params, indicesGenerated);
32798
+}
32799
+
32800
+angle::Result IndexGeneratorUtils::generatePrimitiveRestartLinesBuffer(
32801
+    ContextMtl *contextMtl,
32802
+    const IndexGenerationParams &params,
32803
+    size_t *indicesGenerated)
32804
+{
32805
+    return generatePrimitiveRestartBuffer(contextMtl, 2, params, indicesGenerated);
32806
+}
32807
+
32808
+angle::Result IndexGeneratorUtils::generatePrimitiveRestartPointsBuffer(
32809
+    ContextMtl *contextMtl,
32810
+    const IndexGenerationParams &params,
32811
+    size_t *indicesGenerated)
32812
+{
32813
+    return generatePrimitiveRestartBuffer(contextMtl, 1, params, indicesGenerated);
32814
+}
32815
+
32816
 // VisibilityResultUtils implementation
32817
 void VisibilityResultUtils::onDestroy()
32818
 {
32819
@@ -2376,6 +2536,9 @@ ANGLE_INLINE void SetPipelineState(ComputeCommandEncoder *encoder,
32820
 void MipmapUtils::onDestroy()
32821
 {
32822
     m3DMipGeneratorPipeline      = nil;
32823
+    m2DMipGeneratorPipeline      = nil;
32824
+    m2DArrayMipGeneratorPipeline = nil;
32825
+    mCubeMipGeneratorPipeline    = nil;
32826
 }
32827
 
32828
 void MipmapUtils::ensure3DMipGeneratorPipelineInitialized(ContextMtl *contextMtl)
32829
@@ -2384,66 +2547,78 @@ ANGLE_INLINE void SetPipelineState(ComputeCommandEncoder *encoder,
32830
                                      &m3DMipGeneratorPipeline);
32831
 }
32832
 
32833
+void MipmapUtils::ensure2DMipGeneratorPipelineInitialized(ContextMtl *contextMtl)
32834
+{
32835
+    EnsureComputePipelineInitialized(contextMtl->getDisplay(), @"generate2DMipmaps",
32836
+                                     &m2DMipGeneratorPipeline);
32837
+}
32838
+
32839
+void MipmapUtils::ensure2DArrayMipGeneratorPipelineInitialized(ContextMtl *contextMtl)
32840
+{
32841
+    EnsureComputePipelineInitialized(contextMtl->getDisplay(), @"generate2DArrayMipmaps",
32842
+                                     &m2DArrayMipGeneratorPipeline);
32843
+}
32844
+
32845
+void MipmapUtils::ensureCubeMipGeneratorPipelineInitialized(ContextMtl *contextMtl)
32846
+{
32847
+    EnsureComputePipelineInitialized(contextMtl->getDisplay(), @"generateCubeMipmaps",
32848
+                                     &mCubeMipGeneratorPipeline);
32849
+}
32850
+
32851
 angle::Result MipmapUtils::generateMipmapCS(ContextMtl *contextMtl,
32852
                                             const TextureRef &srcTexture,
32853
                                             bool sRGBMipmap,
32854
-                                            NativeTexLevelArray *mipmapOutputViews)
32855
+                                            NativeTexLevelArray * mipmapOutputViews)
32856
 {
32857
-    // Only support 3D texture for now.
32858
-    ASSERT(srcTexture->textureType() == MTLTextureType3D);
32859
+    ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder();
32860
+    ASSERT(cmdEncoder);
32861
 
32862
     MTLSize threadGroupSize;
32863
     uint32_t slices = 1;
32864
-    id<MTLComputePipelineState> computePipeline = nil;
32865
-
32866
+    switch (srcTexture->textureType())
32867
+    {
32868
+        case MTLTextureType2D:
32869
+            ensure2DMipGeneratorPipelineInitialized(contextMtl);
32870
+            cmdEncoder->setComputePipelineState(m2DMipGeneratorPipeline);
32871
+            threadGroupSize = MTLSizeMake(kGenerateMipThreadGroupSizePerDim,
32872
+                                          kGenerateMipThreadGroupSizePerDim, 1);
32873
+            break;
32874
+        case MTLTextureType2DArray:
32875
+            ensure2DArrayMipGeneratorPipelineInitialized(contextMtl);
32876
+            cmdEncoder->setComputePipelineState(m2DArrayMipGeneratorPipeline);
32877
+            slices          = srcTexture->arrayLength();
32878
+            threadGroupSize = MTLSizeMake(kGenerateMipThreadGroupSizePerDim,
32879
+                                          kGenerateMipThreadGroupSizePerDim, 1);
32880
+            break;
32881
+        case MTLTextureTypeCube:
32882
+            ensureCubeMipGeneratorPipelineInitialized(contextMtl);
32883
+            cmdEncoder->setComputePipelineState(mCubeMipGeneratorPipeline);
32884
+            slices          = 6;
32885
+            threadGroupSize = MTLSizeMake(kGenerateMipThreadGroupSizePerDim,
32886
+                                          kGenerateMipThreadGroupSizePerDim, 1);
32887
+            break;
32888
+        case MTLTextureType3D:
32889
             ensure3DMipGeneratorPipelineInitialized(contextMtl);
32890
-    computePipeline = m3DMipGeneratorPipeline;
32891
+            cmdEncoder->setComputePipelineState(m3DMipGeneratorPipeline);
32892
             threadGroupSize =
32893
                 MTLSizeMake(kGenerateMipThreadGroupSizePerDim, kGenerateMipThreadGroupSizePerDim,
32894
                             kGenerateMipThreadGroupSizePerDim);
32895
-
32896
-    // The compute shader supports up to 4 mipmaps generated per pass.
32897
-    // See shaders/gen_mipmap.metal
32898
-    uint32_t maxMipsPerBatch = 4;
32899
-
32900
-    if (threadGroupSize.width * threadGroupSize.height * threadGroupSize.depth >
32901
-            computePipeline.maxTotalThreadsPerThreadgroup ||
32902
-        ANGLE_UNLIKELY(
32903
-            !contextMtl->getDisplay()->getFeatures().allowGenMultipleMipsPerPass.enabled))
32904
-    {
32905
-        // Multiple mipmaps generation is not supported due to hardware's thread group size limits.
32906
-        // Fallback to generate one mip per pass and reduce thread group size.
32907
-        if (ANGLE_UNLIKELY(threadGroupSize.width * threadGroupSize.height >
32908
-                           computePipeline.maxTotalThreadsPerThreadgroup))
32909
-        {
32910
-            // Even with reduced thread group size, we cannot proceed.
32911
-            // HACK: use blit command encoder to generate mipmaps if it is not possible
32912
-            // to use compute shader due to hardware limits.
32913
-            BlitCommandEncoder *blitEncoder = contextMtl->getBlitCommandEncoder();
32914
-            blitEncoder->generateMipmapsForTexture(srcTexture);
32915
-            return angle::Result::Continue;
32916
-        }
32917
-
32918
-        threadGroupSize.depth = 1;
32919
-        maxMipsPerBatch       = 1;
32920
+            break;
32921
+        default:
32922
+            UNREACHABLE();
32923
     }
32924
 
32925
-    ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder();
32926
-    ASSERT(cmdEncoder);
32927
-    cmdEncoder->setComputePipelineState(computePipeline);
32928
-
32929
-    GenerateMipmapUniform options;
32930
+    Generate3DMipmapUniform options;
32931
+    uint32_t maxMipsPerBatch = 4;
32932
 
32933
     uint32_t remainMips = srcTexture->mipmapLevels() - 1;
32934
-    MipmapNativeLevel batchSrcLevel = kZeroNativeMipLevel;
32935
-    options.srcLevel                = batchSrcLevel.get();
32936
-    options.sRGB                    = sRGBMipmap;
32937
+    options.srcLevel    = 0;
32938
 
32939
     cmdEncoder->setTexture(srcTexture, 0);
32940
     cmdEncoder->markResourceBeingWrittenByGPU(srcTexture);
32941
     while (remainMips)
32942
     {
32943
-        const TextureRef &firstMipView = mipmapOutputViews->at(batchSrcLevel + 1);
32944
+        const TextureRef &firstMipView = mipmapOutputViews->at(mtl::MipmapNativeLevel(options.srcLevel + 1));
32945
         gl::Extents size               = firstMipView->sizeAt0();
32946
         bool isPow2 = gl::isPow2(size.width) && gl::isPow2(size.height) && gl::isPow2(size.depth);
32947
 
32948
@@ -2461,20 +2636,18 @@ ANGLE_INLINE void SetPipelineState(ComputeCommandEncoder *encoder,
32949
 
32950
         for (uint32_t i = 1; i <= options.numMipmapsToGenerate; ++i)
32951
         {
32952
-            cmdEncoder->setTexture(mipmapOutputViews->at(batchSrcLevel + i), i);
32953
+            cmdEncoder->setTexture(mipmapOutputViews->at(mtl::MipmapNativeLevel(options.srcLevel + i)), i);
32954
         }
32955
 
32956
         uint32_t threadsPerZ = std::max(slices, firstMipView->depthAt0());
32957
 
32958
-        DispatchCompute(
32959
-            contextMtl, cmdEncoder,
32960
+        DispatchCompute(contextMtl, cmdEncoder,
32961
                         /** allowNonUniform */ false,
32962
                         MTLSizeMake(firstMipView->widthAt0(), firstMipView->heightAt0(), threadsPerZ),
32963
                         threadGroupSize);
32964
 
32965
         remainMips -= options.numMipmapsToGenerate;
32966
-        batchSrcLevel    = batchSrcLevel + options.numMipmapsToGenerate;
32967
-        options.srcLevel = batchSrcLevel.get();
32968
+        options.srcLevel += options.numMipmapsToGenerate;
32969
     }
32970
 
32971
     return angle::Result::Continue;
32972
@@ -2504,8 +2677,7 @@ ANGLE_INLINE void SetPipelineState(ComputeCommandEncoder *encoder,
32973
     int shaderTextureType = GetShaderTextureType(texture);
32974
     int index2 = mtl_shader::kTextureTypeCount * (bufferWrite ? 1 : 0) + shaderTextureType;
32975
 
32976
-    AutoObjCPtr<id<MTLComputePipelineState>> &cache =
32977
-        mPixelsCopyPipelineCaches[formatIDValue][index2];
32978
+    auto &cache = mPixelsCopyPipelineCaches[formatIDValue][index2];
32979
 
32980
     if (!cache)
32981
     {
32982
@@ -2783,7 +2955,10 @@ ANGLE_INLINE void SetPipelineState(ComputeCommandEncoder *encoder,
32983
 VertexFormatConversionUtils::getComponentsExpandRenderPipeline(ContextMtl *contextMtl,
32984
                                                                RenderCommandEncoder *cmdEncoder)
32985
 {
32986
+    DisplayMtl *display = contextMtl->getDisplay();
32987
+    auto shaderLib      = display->getDefaultShadersLib();
32988
     EnsureVertexShaderOnlyPipelineCacheInitialized(contextMtl, @"expandVertexFormatComponentsVS",
32989
+                                                   shaderLib,
32990
                                                    &mComponentsExpandRenderPipelineCache);
32991
 
32992
     RenderPipelineDesc pipelineDesc = GetComputingVertexShaderOnlyRenderPipelineDesc(cmdEncoder);
32993
@@ -2797,8 +2972,7 @@ ANGLE_INLINE void SetPipelineState(ComputeCommandEncoder *encoder,
32994
 {
32995
     int formatIDValue = static_cast<int>(srcAngleFormat.id);
32996
 
32997
-    AutoObjCPtr<id<MTLComputePipelineState>> &cache =
32998
-        mConvertToFloatCompPipelineCaches[formatIDValue];
32999
+    auto &cache = mConvertToFloatCompPipelineCaches[formatIDValue];
33000
 
33001
     if (!cache)
33002
     {
33003
@@ -2849,5 +3023,53 @@ ANGLE_INLINE void SetPipelineState(ComputeCommandEncoder *encoder,
33004
     return cache.getRenderPipelineState(contextMtl, pipelineDesc);
33005
 }
33006
 
33007
+AutoObjCPtr<id<MTLLibrary>> TransformFeedbackUtils::createMslXfbLibrary(
33008
+    ContextMtl *contextMtl,
33009
+    const std::string &translatedMsl)
33010
+{
33011
+    ANGLE_MTL_OBJC_SCOPE
33012
+    {
33013
+        DisplayMtl *display     = contextMtl->getDisplay();
33014
+        id<MTLDevice> mtlDevice = display->getMetalDevice();
33015
+
33016
+        // Convert to actual binary shader
33017
+        mtl::AutoObjCPtr<NSError *> err = nil;
33018
+        mtl::AutoObjCPtr<id<MTLLibrary>> mtlShaderLib =
33019
+            mtl::CreateShaderLibrary(mtlDevice, translatedMsl, &err);
33020
+        if (err && !mtlShaderLib)
33021
+        {
33022
+            NSLog(@"%@", err.get());
33023
+            assert(0);
33024
+        }
33025
+        return mtlShaderLib;
33026
+    }
33027
+}
33028
+
33029
+AutoObjCPtr<id<MTLRenderPipelineState>> TransformFeedbackUtils::getTransformFeedbackRenderPipeline(
33030
+    ContextMtl *contextMtl,
33031
+    RenderCommandEncoder *cmdEncoder,
33032
+    mtl::RenderPipelineDesc &pipelineDesc)
33033
+{
33034
+    const ProgramMtl *programMtl = mtl::GetImpl(contextMtl->getState().getProgram());
33035
+    RenderPipelineCache &cache   = *programMtl->mMetalXfbRenderPipelineCache;
33036
+
33037
+    if (!cache.getVertexShader())
33038
+    {
33039
+        // Pipeline cache not intialized, do it now:
33040
+        ANGLE_MTL_OBJC_SCOPE
33041
+        {
33042
+            auto shaderLib = createMslXfbLibrary(contextMtl, programMtl->getXfbMslSource());
33043
+            // Non specialized constants provided, use default creation function.
33044
+            EnsureVertexShaderOnlyPipelineCacheInitialized(contextMtl, SHADER_ENTRY_NAME, shaderLib,
33045
+                                                           &cache);
33046
+        }
33047
+    }
33048
+
33049
+    RenderPipelineDesc xfbPipelineDesc =
33050
+        GetTransformFeedbackRenderPipelineDesc(cmdEncoder, pipelineDesc);
33051
+
33052
+    return cache.getRenderPipelineState(contextMtl, xfbPipelineDesc);
33053
+}
33054
+
33055
 }  // namespace mtl
33056
 }  // namespace rx
33057
diff --git a/src/libANGLE/renderer/metal/mtl_resources.h b/src/libANGLE/renderer/metal/mtl_resources.h
33058
index f220650..2e3334d 100644
33059
--- a/src/libANGLE/renderer/metal/mtl_resources.h
33060
+++ b/src/libANGLE/renderer/metal/mtl_resources.h
33061
@@ -63,7 +63,6 @@ class Resource : angle::NonCopyable
33062
     bool isCPUReadMemNeedSync() const { return mUsageRef->cpuReadMemNeedSync; }
33063
     void resetCPUReadMemNeedSync() { mUsageRef->cpuReadMemNeedSync = false; }
33064
 
33065
-    // These functions are useful for BufferMtl to know whether it should update the shadow copy
33066
     bool isCPUReadMemDirty() const { return mUsageRef->cpuReadMemDirty; }
33067
     void resetCPUReadMemDirty() { mUsageRef->cpuReadMemDirty = false; }
33068
 
33069
@@ -81,7 +80,7 @@ class Resource : angle::NonCopyable
33070
         uint64_t cmdBufferQueueSerial = 0;
33071
 
33072
         // This flag means the resource was issued to be modified by GPU, if CPU wants to read
33073
-        // its content, explicit synchronization call must be invoked.
33074
+        // its content, explicit synchornization call must be invoked.
33075
         bool cpuReadMemNeedSync = false;
33076
 
33077
         // This flag is useful for BufferMtl to know whether it should update the shadow copy
33078
@@ -110,6 +109,13 @@ class Texture final : public Resource,
33079
                                        bool allowFormatView,
33080
                                        TextureRef *refOut);
33081
 
33082
+    // On macOS, memory will still be allocated for this texture.
33083
+    static angle::Result MakeMemoryLess2DTexture(ContextMtl *context,
33084
+                                                 const Format &format,
33085
+                                                 uint32_t width,
33086
+                                                 uint32_t height,
33087
+                                                 TextureRef *refOut);
33088
+
33089
     static angle::Result MakeCubeTexture(ContextMtl *context,
33090
                                          const Format &format,
33091
                                          uint32_t size,
33092
@@ -147,10 +153,21 @@ class Texture final : public Resource,
33093
                                        bool allowFormatView,
33094
                                        TextureRef *refOut);
33095
 
33096
+    static angle::Result MakeIOSurfaceTexture(ContextMtl *context,
33097
+                                              const Format &format,
33098
+                                              uint32_t width,
33099
+                                              uint32_t height,
33100
+                                              IOSurfaceRef ref,
33101
+                                              uint32_t plane,
33102
+                                              TextureRef *refOut);
33103
+
33104
     static TextureRef MakeFromMetal(id<MTLTexture> metalTexture);
33105
 
33106
     // Allow CPU to read & write data directly to this texture?
33107
     bool isCPUAccessible() const;
33108
+    // Allow shaders to read/sample this texture?
33109
+    // Texture created with renderTargetOnly flag won't be readable
33110
+    bool isShaderReadable() const;
33111
 
33112
     bool supportFormatView() const;
33113
 
33114
@@ -218,16 +235,29 @@ class Texture final : public Resource,
33115
     MTLColorWriteMask getColorWritableMask() const { return *mColorWritableMask; }
33116
     void setColorWritableMask(MTLColorWriteMask mask) { *mColorWritableMask = mask; }
33117
 
33118
-    // Get linear color space view. Only usable for sRGB textures.
33119
-    TextureRef getLinearColorView();
33120
+    // Get reading copy. Used for reading non-readable texture or reading stencil value from
33121
+    // packed depth & stencil texture.
33122
+    // NOTE: this only copies 1 depth slice of the 3D texture.
33123
+    // The texels will be copied to region(0, 0, 0, areaToCopy.size) of the returned texture.
33124
+    // The returned pointer will be retained by the original texture object.
33125
+    // Calling getReadableCopy() will overwrite previously returned texture.
33126
+    TextureRef getReadableCopy(ContextMtl *context,
33127
+                               mtl::BlitCommandEncoder *encoder,
33128
+                               const uint32_t levelToCopy,
33129
+                               const uint32_t sliceToCopy,
33130
+                               const MTLRegion &areaToCopy);
33131
+
33132
+    void releaseReadableCopy();
33133
 
33134
     // Get stencil view
33135
     TextureRef getStencilView();
33136
+    //Get linear color
33137
+    TextureRef getLinearColorView();
33138
 
33139
     // Change the wrapped metal object. Special case for swapchain image
33140
     void set(id<MTLTexture> metalTexture);
33141
 
33142
-    // sync content between CPU and GPU
33143
+    // Explicitly sync content between CPU and GPU
33144
     void syncContent(ContextMtl *context, mtl::BlitCommandEncoder *encoder);
33145
 
33146
   private:
33147
@@ -241,12 +271,41 @@ class Texture final : public Resource,
33148
                                      bool allowFormatView,
33149
                                      TextureRef *refOut);
33150
 
33151
+    static angle::Result MakeTexture(ContextMtl *context,
33152
+                                     const Format &mtlFormat,
33153
+                                     MTLTextureDescriptor *desc,
33154
+                                     uint32_t mips,
33155
+                                     bool renderTargetOnly,
33156
+                                     bool allowFormatView,
33157
+                                     bool memoryLess,
33158
+                                     TextureRef *refOut);
33159
+
33160
+    static angle::Result MakeTexture(ContextMtl *context,
33161
+                                     const Format &mtlFormat,
33162
+                                     MTLTextureDescriptor *desc,
33163
+                                     IOSurfaceRef surfaceRef,
33164
+                                     NSUInteger slice,
33165
+                                     bool renderTargetOnly,
33166
+                                     TextureRef *refOut);
33167
+
33168
     Texture(id<MTLTexture> metalTexture);
33169
     Texture(ContextMtl *context,
33170
             MTLTextureDescriptor *desc,
33171
             uint32_t mips,
33172
             bool renderTargetOnly,
33173
             bool allowFormatView);
33174
+    Texture(ContextMtl *context,
33175
+            MTLTextureDescriptor *desc,
33176
+            uint32_t mips,
33177
+            bool renderTargetOnly,
33178
+            bool allowFormatView,
33179
+            bool memoryLess);
33180
+
33181
+    Texture(ContextMtl *context,
33182
+            MTLTextureDescriptor *desc,
33183
+            IOSurfaceRef iosurface,
33184
+            NSUInteger plane,
33185
+            bool renderTargetOnly);
33186
 
33187
     // Create a texture view
33188
     Texture(Texture *original, MTLPixelFormat format);
33189
@@ -264,9 +323,14 @@ class Texture final : public Resource,
33190
     TextureRef mLinearColorView;
33191
 
33192
     TextureRef mStencilView;
33193
+    //Readable copy of texture
33194
+    TextureRef mReadCopy;
33195
+
33196
 };
33197
 
33198
-class Buffer final : public Resource, public WrappedObject<id<MTLBuffer>>
33199
+class Buffer final : public Resource,
33200
+                     public WrappedObject<id<MTLBuffer>>,
33201
+                     public std::enable_shared_from_this<Buffer>
33202
 {
33203
   public:
33204
     static angle::Result MakeBuffer(ContextMtl *context,
33205
diff --git a/src/libANGLE/renderer/metal/mtl_resources.mm b/src/libANGLE/renderer/metal/mtl_resources.mm
33206
index 9bee475..d0475ae 100644
33207
--- a/src/libANGLE/renderer/metal/mtl_resources.mm
33208
+++ b/src/libANGLE/renderer/metal/mtl_resources.mm
33209
@@ -34,20 +34,22 @@ inline NSUInteger GetMipSize(NSUInteger baseSize, const MipmapNativeLevel level)
33210
 // Asynchronously synchronize the content of a resource between GPU memory and its CPU cache.
33211
 // NOTE: This operation doesn't finish immediately upon function's return.
33212
 template <class T>
33213
-void InvokeCPUMemSync(ContextMtl *context, mtl::BlitCommandEncoder *blitEncoder, T *resource)
33214
+void SyncContent(ContextMtl *context,
33215
+                 mtl::BlitCommandEncoder *blitEncoder,
33216
+                 const std::shared_ptr<T> &resource)
33217
 {
33218
 #if TARGET_OS_OSX || TARGET_OS_MACCATALYST
33219
     if (blitEncoder)
33220
     {
33221
         blitEncoder->synchronizeResource(resource);
33222
+
33223
         resource->resetCPUReadMemNeedSync();
33224
     }
33225
 #endif
33226
 }
33227
-// Ensure that a resource's CPU cache will be synchronized after GPU finishes its modifications on
33228
-// the resource.
33229
+
33230
 template <class T>
33231
-void EnsureCPUMemWillBeSynced(ContextMtl *context, T *resource)
33232
+void EnsureContentSynced(ContextMtl *context, const std::shared_ptr<T> &resource)
33233
 {
33234
 #if TARGET_OS_OSX || TARGET_OS_MACCATALYST
33235
     // Make sure GPU & CPU contents are synchronized.
33236
@@ -56,7 +58,7 @@ void EnsureCPUMemWillBeSynced(ContextMtl *context, T *resource)
33237
     if (resource->get().storageMode == MTLStorageModeManaged && resource->isCPUReadMemNeedSync())
33238
     {
33239
         mtl::BlitCommandEncoder *blitEncoder = context->getBlitCommandEncoder();
33240
-        InvokeCPUMemSync(context, blitEncoder, resource);
33241
+        SyncContent(context, blitEncoder, resource);
33242
     }
33243
 #endif
33244
 }
33245
@@ -122,6 +124,24 @@ void EnsureCPUMemWillBeSynced(ContextMtl *context, T *resource)
33246
     }  // ANGLE_MTL_OBJC_SCOPE
33247
 }
33248
 
33249
+/** static */
33250
+angle::Result Texture::MakeMemoryLess2DTexture(ContextMtl *context,
33251
+                                               const Format &format,
33252
+                                               uint32_t width,
33253
+                                               uint32_t height,
33254
+                                               TextureRef *refOut)
33255
+{
33256
+    ANGLE_MTL_OBJC_SCOPE
33257
+    {
33258
+        MTLTextureDescriptor *desc =
33259
+            [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:format.metalFormat
33260
+                                                               width:width
33261
+                                                              height:height
33262
+                                                           mipmapped:NO];
33263
+
33264
+        return MakeTexture(context, format, desc, 1, true, false, true, refOut);
33265
+    }  // ANGLE_MTL_OBJC_SCOPE
33266
+}
33267
 /** static */
33268
 angle::Result Texture::MakeCubeTexture(ContextMtl *context,
33269
                                        const Format &format,
33270
@@ -223,6 +243,23 @@ void EnsureCPUMemWillBeSynced(ContextMtl *context, T *resource)
33271
         return MakeTexture(context, format, desc, mips, renderTargetOnly, allowFormatView, refOut);
33272
     }  // ANGLE_MTL_OBJC_SCOPE
33273
 }
33274
+angle::Result Texture::MakeIOSurfaceTexture(ContextMtl *context,
33275
+                                            const Format &format,
33276
+                                            uint32_t width,
33277
+                                            uint32_t height,
33278
+                                            IOSurfaceRef ref,
33279
+                                            uint32_t plane,
33280
+                                            TextureRef *refOut)
33281
+{
33282
+    MTLTextureDescriptor *desc = [[MTLTextureDescriptor new] ANGLE_MTL_AUTORELEASE];
33283
+    desc.textureType           = MTLTextureType2D;
33284
+    desc.pixelFormat           = format.metalFormat;
33285
+    desc.width                 = width;
33286
+    desc.height                = height;
33287
+    desc.mipmapLevelCount      = 1;
33288
+    desc.sampleCount           = 1;
33289
+    return MakeTexture(context, format, desc, ref, plane, NO, refOut);
33290
+}
33291
 
33292
 /** static */
33293
 angle::Result Texture::MakeTexture(ContextMtl *context,
33294
@@ -233,7 +270,42 @@ void EnsureCPUMemWillBeSynced(ContextMtl *context, T *resource)
33295
                                    bool allowFormatView,
33296
                                    TextureRef *refOut)
33297
 {
33298
-    refOut->reset(new Texture(context, desc, mips, renderTargetOnly, allowFormatView));
33299
+    return MakeTexture(context, mtlFormat, desc, mips, renderTargetOnly, allowFormatView, false,
33300
+                       refOut);
33301
+}
33302
+
33303
+angle::Result Texture::MakeTexture(ContextMtl *context,
33304
+                                   const Format &mtlFormat,
33305
+                                   MTLTextureDescriptor *desc,
33306
+                                   uint32_t mips,
33307
+                                   bool renderTargetOnly,
33308
+                                   bool allowFormatView,
33309
+                                   bool memoryLess,
33310
+                                   TextureRef *refOut)
33311
+{
33312
+    refOut->reset(new Texture(context, desc, mips, renderTargetOnly, allowFormatView, memoryLess));
33313
+
33314
+    if (!refOut || !refOut->get())
33315
+    {
33316
+        ANGLE_MTL_CHECK(context, false, GL_OUT_OF_MEMORY);
33317
+    }
33318
+    if (!mtlFormat.hasDepthAndStencilBits())
33319
+    {
33320
+        refOut->get()->setColorWritableMask(GetEmulatedColorWriteMask(mtlFormat));
33321
+    }
33322
+
33323
+    return angle::Result::Continue;
33324
+}
33325
+
33326
+angle::Result Texture::MakeTexture(ContextMtl *context,
33327
+                                   const Format &mtlFormat,
33328
+                                   MTLTextureDescriptor *desc,
33329
+                                   IOSurfaceRef surfaceRef,
33330
+                                   NSUInteger slice,
33331
+                                   bool renderTargetOnly,
33332
+                                   TextureRef *refOut)
33333
+{
33334
+    refOut->reset(new Texture(context, desc, surfaceRef, slice, renderTargetOnly));
33335
 
33336
     if (!(*refOut) || !(*refOut)->get())
33337
     {
33338
@@ -264,6 +336,15 @@ void EnsureCPUMemWillBeSynced(ContextMtl *context, T *resource)
33339
                  uint32_t mips,
33340
                  bool renderTargetOnly,
33341
                  bool allowFormatView)
33342
+    : Texture(context, desc, mips, renderTargetOnly, allowFormatView, false)
33343
+{}
33344
+
33345
+Texture::Texture(ContextMtl *context,
33346
+                 MTLTextureDescriptor *desc,
33347
+                 uint32_t mips,
33348
+                 bool renderTargetOnly,
33349
+                 bool allowFormatView,
33350
+                 bool memoryLess)
33351
     : mColorWritableMask(std::make_shared<MTLColorWriteMask>(MTLColorWriteMaskAll))
33352
 {
33353
     ANGLE_MTL_OBJC_SCOPE
33354
@@ -283,7 +364,15 @@ void EnsureCPUMemWillBeSynced(ContextMtl *context, T *resource)
33355
             desc.usage |= MTLTextureUsageRenderTarget;
33356
         }
33357
 
33358
-        if (context->getNativeFormatCaps(desc.pixelFormat).depthRenderable ||
33359
+        if (memoryLess)
33360
+        {
33361
+#if (TARGET_OS_IOS || TARGET_OS_TV) && !TARGET_OS_MACCATALYST
33362
+            desc.resourceOptions = MTLResourceStorageModeMemoryless;
33363
+#else
33364
+            desc.resourceOptions = MTLResourceStorageModePrivate;
33365
+#endif
33366
+        }
33367
+        else if (context->getNativeFormatCaps(desc.pixelFormat).depthRenderable ||
33368
                  desc.textureType == MTLTextureType2DMultisample)
33369
         {
33370
             // Metal doesn't support host access to depth stencil texture's data
33371
@@ -310,6 +399,46 @@ void EnsureCPUMemWillBeSynced(ContextMtl *context, T *resource)
33372
     }
33373
 }
33374
 
33375
+Texture::Texture(ContextMtl *context,
33376
+                 MTLTextureDescriptor *desc,
33377
+                 IOSurfaceRef iosurface,
33378
+                 NSUInteger plane,
33379
+                 bool renderTargetOnly)
33380
+    : mColorWritableMask(std::make_shared<MTLColorWriteMask>(MTLColorWriteMaskAll))
33381
+{
33382
+    ANGLE_MTL_OBJC_SCOPE
33383
+    {
33384
+        id<MTLDevice> metalDevice = context->getMetalDevice();
33385
+
33386
+        // Every texture will support being rendered for now
33387
+        desc.usage = MTLTextureUsagePixelFormatView;
33388
+
33389
+        if (context->getNativeFormatCaps(desc.pixelFormat).isRenderable())
33390
+        {
33391
+            desc.usage |= MTLTextureUsageRenderTarget;
33392
+        }
33393
+
33394
+#if (TARGET_OS_IOS || TARGET_OS_TV) && !TARGET_OS_MACCATALYST
33395
+        desc.resourceOptions = MTLResourceStorageModeShared;
33396
+#else
33397
+        desc.resourceOptions = MTLResourceStorageModeManaged;
33398
+#endif
33399
+
33400
+        if (!renderTargetOnly)
33401
+        {
33402
+            desc.usage = desc.usage | MTLTextureUsageShaderRead;
33403
+            if (context->getNativeFormatCaps(desc.pixelFormat).writable)
33404
+            {
33405
+                desc.usage = desc.usage | MTLTextureUsageShaderWrite;
33406
+            }
33407
+        }
33408
+        id<MTLTexture> iosurfTexture = [metalDevice newTextureWithDescriptor:desc
33409
+                                                                   iosurface:iosurface
33410
+                                                                       plane:plane];
33411
+        set([iosurfTexture ANGLE_MTL_AUTORELEASE]);
33412
+    }
33413
+}
33414
+
33415
 Texture::Texture(Texture *original, MTLPixelFormat format)
33416
     : Resource(original),
33417
       mColorWritableMask(original->mColorWritableMask)  // Share color write mask property
33418
@@ -341,7 +470,7 @@ void EnsureCPUMemWillBeSynced(ContextMtl *context, T *resource)
33419
     : Resource(original),
33420
       mColorWritableMask(original->mColorWritableMask)  // Share color write mask property
33421
 {
33422
-#if ANGLE_MTL_SWIZZLE_AVAILABLE
33423
+#if defined(__IPHONE_13_0) || defined(__MAC_10_15)
33424
     ANGLE_MTL_OBJC_SCOPE
33425
     {
33426
         auto view = [original->get()
33427
@@ -360,12 +489,12 @@ void EnsureCPUMemWillBeSynced(ContextMtl *context, T *resource)
33428
 
33429
 void Texture::syncContent(ContextMtl *context, mtl::BlitCommandEncoder *blitEncoder)
33430
 {
33431
-    InvokeCPUMemSync(context, blitEncoder, this);
33432
+    SyncContent(context, blitEncoder, shared_from_this());
33433
 }
33434
 
33435
 void Texture::syncContentIfNeeded(ContextMtl *context)
33436
 {
33437
-    EnsureCPUMemWillBeSynced(context, this);
33438
+    EnsureContentSynced(context, shared_from_this());
33439
 }
33440
 
33441
 bool Texture::isCPUAccessible() const
33442
@@ -379,6 +508,11 @@ void EnsureCPUMemWillBeSynced(ContextMtl *context, T *resource)
33443
     return get().storageMode == MTLStorageModeShared;
33444
 }
33445
 
33446
+bool Texture::isShaderReadable() const
33447
+{
33448
+    return get().usage & MTLTextureUsageShaderRead;
33449
+}
33450
+
33451
 bool Texture::supportFormatView() const
33452
 {
33453
     return get().usage & MTLTextureUsagePixelFormatView;
33454
@@ -514,12 +648,14 @@ void EnsureCPUMemWillBeSynced(ContextMtl *context, T *resource)
33455
     ASSERT(supportFormatView());
33456
     return TextureRef(new Texture(this, format));
33457
 }
33458
+
33459
 TextureRef Texture::createViewWithCompatibleFormat(MTLPixelFormat format)
33460
 {
33461
-    // No need for ASSERT(supportFormatView());
33462
     return TextureRef(new Texture(this, format));
33463
 }
33464
 
33465
+
33466
+
33467
 TextureRef Texture::createSwizzleView(const TextureSwizzleChannels &swizzle)
33468
 {
33469
 #if ANGLE_MTL_SWIZZLE_AVAILABLE
33470
@@ -652,6 +788,48 @@ void EnsureCPUMemWillBeSynced(ContextMtl *context, T *resource)
33471
     return mLinearColorView;
33472
 }
33473
 
33474
+TextureRef Texture::getReadableCopy(ContextMtl *context,
33475
+                                    mtl::BlitCommandEncoder *encoder,
33476
+                                    const uint32_t levelToCopy,
33477
+                                    const uint32_t sliceToCopy,
33478
+                                    const MTLRegion &areaToCopy)
33479
+{
33480
+    gl::Extents firstLevelSize = size(kZeroNativeMipLevel);
33481
+    if (!mReadCopy || mReadCopy->get().width < static_cast<size_t>(firstLevelSize.width) ||
33482
+        mReadCopy->get().height < static_cast<size_t>(firstLevelSize.height))
33483
+    {
33484
+        // Create a texture that big enough to store the first level data and any smaller level
33485
+        ANGLE_MTL_OBJC_SCOPE
33486
+        {
33487
+            auto desc            = [[MTLTextureDescriptor new] ANGLE_MTL_AUTORELEASE];
33488
+            desc.textureType     = get().textureType;
33489
+            desc.pixelFormat     = get().pixelFormat;
33490
+            desc.width           = firstLevelSize.width;
33491
+            desc.height          = firstLevelSize.height;
33492
+            desc.depth           = 1;
33493
+            desc.arrayLength     = 1;
33494
+            desc.resourceOptions = MTLResourceStorageModePrivate;
33495
+            desc.sampleCount     = get().sampleCount;
33496
+            desc.usage           = MTLTextureUsageShaderRead | MTLTextureUsagePixelFormatView;
33497
+
33498
+            id<MTLTexture> mtlTexture = [context->getMetalDevice() newTextureWithDescriptor:desc];
33499
+            mReadCopy.reset(new Texture(mtlTexture));
33500
+        }  // ANGLE_MTL_OBJC_SCOPE
33501
+    }
33502
+
33503
+    ASSERT(encoder);
33504
+
33505
+    encoder->copyTexture(shared_from_this(), sliceToCopy, levelToCopy, mReadCopy, 0,
33506
+                         0, 1, 1);
33507
+
33508
+    return mReadCopy;
33509
+}
33510
+
33511
+void Texture::releaseReadableCopy()
33512
+{
33513
+    mReadCopy = nullptr;
33514
+}
33515
+
33516
 TextureRef Texture::getStencilView()
33517
 {
33518
     if (mStencilView)
33519
@@ -799,7 +977,7 @@ void EnsureCPUMemWillBeSynced(ContextMtl *context, T *resource)
33520
 
33521
 void Buffer::syncContent(ContextMtl *context, mtl::BlitCommandEncoder *blitEncoder)
33522
 {
33523
-    InvokeCPUMemSync(context, blitEncoder, this);
33524
+    SyncContent(context, blitEncoder, shared_from_this());
33525
 }
33526
 
33527
 const uint8_t *Buffer::mapReadOnly(ContextMtl *context)
33528
@@ -820,7 +998,7 @@ void EnsureCPUMemWillBeSynced(ContextMtl *context, T *resource)
33529
     {
33530
         CommandQueue &cmdQueue = context->cmdQueue();
33531
 
33532
-        EnsureCPUMemWillBeSynced(context, this);
33533
+        EnsureContentSynced(context, shared_from_this());
33534
 
33535
         if (this->isBeingUsedByGPU(context))
33536
         {
33537
diff --git a/src/libANGLE/renderer/metal/mtl_state_cache.h b/src/libANGLE/renderer/metal/mtl_state_cache.h
33538
index 768c369..e6bf71d 100644
33539
--- a/src/libANGLE/renderer/metal/mtl_state_cache.h
33540
+++ b/src/libANGLE/renderer/metal/mtl_state_cache.h
33541
@@ -22,6 +22,11 @@
33542
 
33543
 static inline bool operator==(const MTLClearColor &lhs, const MTLClearColor &rhs);
33544
 
33545
+namespace angle
33546
+{
33547
+struct FeaturesMtl;
33548
+}
33549
+
33550
 namespace rx
33551
 {
33552
 class ContextMtl;
33553
@@ -223,7 +228,8 @@ struct RenderPipelineOutputDesc
33554
 };
33555
 
33556
 // Some SDK levels don't declare MTLPrimitiveTopologyClass. Needs to do compile time check here:
33557
-#if !(TARGET_OS_OSX || TARGET_OS_MACCATALYST) && ANGLE_IOS_DEPLOY_TARGET < __IPHONE_12_0
33558
+#if !(TARGET_OS_OSX || TARGET_OS_MACCATALYST) && \
33559
+    (!defined(__IPHONE_12_0) || ANGLE_IOS_DEPLOY_TARGET < __IPHONE_12_0)
33560
 #    define ANGLE_MTL_PRIMITIVE_TOPOLOGY_CLASS_AVAILABLE 0
33561
 using PrimitiveTopologyClass                                     = uint32_t;
33562
 constexpr PrimitiveTopologyClass kPrimitiveTopologyClassTriangle = 0;
33563
@@ -267,9 +273,7 @@ struct alignas(4) RenderPipelineDesc
33564
     RenderPipelineDesc &operator=(const RenderPipelineDesc &src);
33565
 
33566
     bool operator==(const RenderPipelineDesc &rhs) const;
33567
-
33568
     size_t hash() const;
33569
-
33570
     bool rasterizationEnabled() const;
33571
 
33572
     VertexDesc vertexDescriptor;
33573
@@ -288,6 +292,27 @@ struct alignas(4) RenderPipelineDesc
33574
     bool emulateCoverageMask : 1;
33575
 };
33576
 
33577
+struct RenderPassAttachmentTextureTargetDesc
33578
+{
33579
+    TextureRef getTextureRef() const { return texture.lock(); }
33580
+    TextureRef getImplicitMSTextureRef() const { return implicitMSTexture.lock(); }
33581
+    bool hasImplicitMSTexture() const { return !implicitMSTexture.expired(); }
33582
+    uint32_t getRenderSamples() const
33583
+    {
33584
+        TextureRef tex   = getTextureRef();
33585
+        TextureRef msTex = getImplicitMSTextureRef();
33586
+        return msTex ? msTex->samples() : (tex ? tex->samples() : 1);
33587
+    }
33588
+
33589
+    TextureWeakRef texture;
33590
+    // Implicit multisample texture that will be rendered into and discarded at the end of
33591
+    // a render pass. Its result will be resolved into normal texture above.
33592
+    TextureWeakRef implicitMSTexture;
33593
+    MipmapNativeLevel level = kZeroNativeMipLevel;
33594
+    uint32_t sliceOrDepth   = 0;
33595
+    bool blendable          = true;
33596
+};
33597
+
33598
 struct RenderPassAttachmentDesc
33599
 {
33600
     RenderPassAttachmentDesc();
33601
@@ -297,18 +322,34 @@ struct RenderPassAttachmentDesc
33602
     bool equalIgnoreLoadStoreOptions(const RenderPassAttachmentDesc &other) const;
33603
     bool operator==(const RenderPassAttachmentDesc &other) const;
33604
 
33605
-    ANGLE_INLINE bool hasImplicitMSTexture() const { return implicitMSTexture.get(); }
33606
-
33607
-    TextureRef texture;
33608
-    // Implicit multisample texture that will be rendered into and discarded at the end of
33609
-    // a render pass. Its result will be resolved into normal texture above.
33610
-    TextureRef implicitMSTexture;
33611
-    MipmapNativeLevel level;
33612
-    uint32_t sliceOrDepth;
33613
-
33614
-    // This attachment is blendable or not.
33615
-    bool blendable;
33616
+    ANGLE_INLINE TextureRef texture() const
33617
+    {
33618
+        return renderTarget ? renderTarget->getTextureRef() : nullptr;
33619
+    }
33620
+    ANGLE_INLINE TextureRef implicitMSTexture() const
33621
+    {
33622
+        return renderTarget ? renderTarget->getImplicitMSTextureRef() : nullptr;
33623
+    }
33624
+    ANGLE_INLINE bool hasImplicitMSTexture() const
33625
+    {
33626
+        return renderTarget ? renderTarget->hasImplicitMSTexture() : false;
33627
+    }
33628
+    ANGLE_INLINE uint32_t renderSamples() const
33629
+    {
33630
+        return renderTarget ? renderTarget->getRenderSamples() : 1;
33631
+    }
33632
+    ANGLE_INLINE MipmapNativeLevel level() const
33633
+    {
33634
+        return renderTarget ? renderTarget->level : kZeroNativeMipLevel;
33635
+    }
33636
+    ANGLE_INLINE uint32_t sliceOrDepth() const
33637
+    {
33638
+        return renderTarget ? renderTarget->sliceOrDepth : 0;
33639
+    }
33640
+    ANGLE_INLINE bool blendable() const { return renderTarget ? renderTarget->blendable : false; }
33641
 
33642
+    // This is shared pointer to avoid crashing when texture deleted after bound to a frame buffer.
33643
+    std::shared_ptr<RenderPassAttachmentTextureTargetDesc> renderTarget;
33644
     MTLLoadAction loadAction;
33645
     MTLStoreAction storeAction;
33646
     MTLStoreActionOptions storeActionOptions;
33647
@@ -354,6 +395,11 @@ struct RenderPassStencilAttachmentDesc : public RenderPassAttachmentDesc
33648
     uint32_t clearStencil = 0;
33649
 };
33650
 
33651
+//
33652
+// This is C++ equivalent of Objective-C MTLRenderPassDescriptor.
33653
+// We could use MTLRenderPassDescriptor directly, however, using C++ struct has benefits of fast
33654
+// copy, stack allocation, inlined comparing function, etc.
33655
+//
33656
 struct RenderPassDesc
33657
 {
33658
     RenderPassColorAttachmentDesc colorAttachments[kMaxRenderTargets];
33659
@@ -417,7 +463,6 @@ class RenderPipelineCacheSpecializeShaderFactory
33660
 {
33661
   public:
33662
     virtual ~RenderPipelineCacheSpecializeShaderFactory() = default;
33663
-
33664
     // Get specialized shader for the render pipeline cache.
33665
     virtual angle::Result getSpecializedShader(Context *context,
33666
                                                gl::ShaderType shaderType,
33667
@@ -429,7 +474,7 @@ class RenderPipelineCacheSpecializeShaderFactory
33668
                                       const RenderPipelineDesc &renderPipelineDesc) = 0;
33669
 };
33670
 
33671
-// Render pipeline state cache per shader program.
33672
+// render pipeline state cache per shader program
33673
 class RenderPipelineCache final : angle::NonCopyable
33674
 {
33675
   public:
33676
@@ -459,6 +504,7 @@ class RenderPipelineCache final : angle::NonCopyable
33677
     AutoObjCPtr<id<MTLFunction>> mVertexShader;
33678
     // Non-specialized fragment shader
33679
     AutoObjCPtr<id<MTLFunction>> mFragmentShader;
33680
+    // On shader with emulated rasterization discard, one without
33681
 
33682
   private:
33683
     void clearPipelineStates();
33684
@@ -477,14 +523,13 @@ class RenderPipelineCache final : angle::NonCopyable
33685
     // One table with default attrib and one table without.
33686
     std::unordered_map<RenderPipelineDesc, AutoObjCPtr<id<MTLRenderPipelineState>>>
33687
         mRenderPipelineStates[2];
33688
-
33689
     RenderPipelineCacheSpecializeShaderFactory *mSpecializedShaderFactory;
33690
 };
33691
 
33692
 class StateCache final : angle::NonCopyable
33693
 {
33694
   public:
33695
-    StateCache();
33696
+    StateCache(const angle::FeaturesMtl &features);
33697
     ~StateCache();
33698
 
33699
     // Null depth stencil state has depth/stecil read & write disabled.
33700
@@ -502,6 +547,8 @@ class StateCache final : angle::NonCopyable
33701
     void clear();
33702
 
33703
   private:
33704
+    const angle::FeaturesMtl &mFeatures;
33705
+
33706
     AutoObjCPtr<id<MTLDepthStencilState>> mNullDepthStencilState = nil;
33707
     std::unordered_map<DepthStencilDesc, AutoObjCPtr<id<MTLDepthStencilState>>> mDepthStencilStates;
33708
     std::unordered_map<SamplerDesc, AutoObjCPtr<id<MTLSamplerState>>> mSamplerStates;
33709
diff --git a/src/libANGLE/renderer/metal/mtl_state_cache.mm b/src/libANGLE/renderer/metal/mtl_state_cache.mm
33710
index 1cf237a..45c719d 100644
33711
--- a/src/libANGLE/renderer/metal/mtl_state_cache.mm
33712
+++ b/src/libANGLE/renderer/metal/mtl_state_cache.mm
33713
@@ -17,6 +17,7 @@
33714
 #include "libANGLE/renderer/metal/ContextMtl.h"
33715
 #include "libANGLE/renderer/metal/mtl_resources.h"
33716
 #include "libANGLE/renderer/metal/mtl_utils.h"
33717
+#include "platform/FeaturesMtl.h"
33718
 
33719
 #define ANGLE_OBJC_CP_PROPERTY(DST, SRC, PROPERTY) \
33720
     (DST).PROPERTY = static_cast<__typeof__((DST).PROPERTY)>(ToObjC((SRC).PROPERTY))
33721
@@ -182,10 +183,10 @@ inline T ToObjC(const T p)
33722
     return textureRef ? textureRef->get() : nil;
33723
 }
33724
 
33725
-void BaseRenderPassAttachmentDescToObjC(const RenderPassAttachmentDesc &src,
33726
-                                        MTLRenderPassAttachmentDescriptor *dst)
33727
+void BaseRenderPassAttachmentDescToObjC(MTLRenderPassAttachmentDescriptor *dst,
33728
+                                        const RenderPassAttachmentDesc &src)
33729
 {
33730
-    const TextureRef &implicitMsTexture = src.implicitMSTexture;
33731
+    auto implicitMsTexture = src.implicitMSTexture();
33732
 
33733
     if (implicitMsTexture)
33734
     {
33735
@@ -193,31 +194,31 @@ void BaseRenderPassAttachmentDescToObjC(const RenderPassAttachmentDesc &src,
33736
         dst.level          = 0;
33737
         dst.slice          = 0;
33738
         dst.depthPlane     = 0;
33739
-        dst.resolveTexture = ToObjC(src.texture);
33740
-        dst.resolveLevel   = src.level.get();
33741
+        dst.resolveTexture = ToObjC(src.texture());
33742
+        dst.resolveLevel   = src.level().get();
33743
         if (dst.resolveTexture.textureType == MTLTextureType3D)
33744
         {
33745
-            dst.resolveDepthPlane = src.sliceOrDepth;
33746
+            dst.resolveDepthPlane = src.sliceOrDepth();
33747
             dst.resolveSlice      = 0;
33748
         }
33749
         else
33750
         {
33751
-            dst.resolveSlice      = src.sliceOrDepth;
33752
+            dst.resolveSlice      = src.sliceOrDepth();
33753
             dst.resolveDepthPlane = 0;
33754
         }
33755
     }
33756
     else
33757
     {
33758
-        dst.texture = ToObjC(src.texture);
33759
-        dst.level   = src.level.get();
33760
+        dst.texture = ToObjC(src.texture());
33761
+        dst.level   = src.level().get();
33762
         if (dst.texture.textureType == MTLTextureType3D)
33763
         {
33764
-            dst.depthPlane = src.sliceOrDepth;
33765
+            dst.depthPlane = src.sliceOrDepth();
33766
             dst.slice      = 0;
33767
         }
33768
         else
33769
         {
33770
-            dst.slice      = src.sliceOrDepth;
33771
+            dst.slice      = src.sliceOrDepth();
33772
             dst.depthPlane = 0;
33773
         }
33774
         dst.resolveTexture    = nil;
33775
@@ -231,26 +232,26 @@ void BaseRenderPassAttachmentDescToObjC(const RenderPassAttachmentDesc &src,
33776
     ANGLE_OBJC_CP_PROPERTY(dst, src, storeActionOptions);
33777
 }
33778
 
33779
-void ToObjC(const RenderPassColorAttachmentDesc &desc,
33780
-            MTLRenderPassColorAttachmentDescriptor *objCDesc)
33781
+void ToObjC(MTLRenderPassColorAttachmentDescriptor *objCDesc,
33782
+            const RenderPassColorAttachmentDesc &desc)
33783
 {
33784
-    BaseRenderPassAttachmentDescToObjC(desc, objCDesc);
33785
+    BaseRenderPassAttachmentDescToObjC(objCDesc, desc);
33786
 
33787
     ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, clearColor);
33788
 }
33789
 
33790
-void ToObjC(const RenderPassDepthAttachmentDesc &desc,
33791
-            MTLRenderPassDepthAttachmentDescriptor *objCDesc)
33792
+void ToObjC(MTLRenderPassDepthAttachmentDescriptor *objCDesc,
33793
+            const RenderPassDepthAttachmentDesc &desc)
33794
 {
33795
-    BaseRenderPassAttachmentDescToObjC(desc, objCDesc);
33796
+    BaseRenderPassAttachmentDescToObjC(objCDesc, desc);
33797
 
33798
     ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, clearDepth);
33799
 }
33800
 
33801
-void ToObjC(const RenderPassStencilAttachmentDesc &desc,
33802
-            MTLRenderPassStencilAttachmentDescriptor *objCDesc)
33803
+void ToObjC(MTLRenderPassStencilAttachmentDescriptor *objCDesc,
33804
+            const RenderPassStencilAttachmentDesc &desc)
33805
 {
33806
-    BaseRenderPassAttachmentDescToObjC(desc, objCDesc);
33807
+    BaseRenderPassAttachmentDescToObjC(objCDesc, desc);
33808
 
33809
     ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, clearStencil);
33810
 }
33811
@@ -696,11 +697,7 @@ void ToObjC(const RenderPassStencilAttachmentDesc &desc,
33812
 
33813
 void RenderPassAttachmentDesc::reset()
33814
 {
33815
-    texture.reset();
33816
-    implicitMSTexture.reset();
33817
-    level              = mtl::kZeroNativeMipLevel;
33818
-    sliceOrDepth       = 0;
33819
-    blendable          = false;
33820
+    renderTarget       = nullptr;
33821
     loadAction         = MTLLoadActionLoad;
33822
     storeAction        = MTLStoreActionStore;
33823
     storeActionOptions = MTLStoreActionOptionNone;
33824
@@ -709,8 +706,9 @@ void ToObjC(const RenderPassStencilAttachmentDesc &desc,
33825
 bool RenderPassAttachmentDesc::equalIgnoreLoadStoreOptions(
33826
     const RenderPassAttachmentDesc &other) const
33827
 {
33828
-    return texture == other.texture && implicitMSTexture == other.implicitMSTexture &&
33829
-           level == other.level && sliceOrDepth == other.sliceOrDepth;
33830
+    return renderTarget == other.renderTarget ||
33831
+           (texture() == other.texture() && level() == other.level() &&
33832
+            sliceOrDepth() == other.sliceOrDepth());
33833
 }
33834
 
33835
 bool RenderPassAttachmentDesc::operator==(const RenderPassAttachmentDesc &other) const
33836
@@ -723,6 +721,30 @@ void ToObjC(const RenderPassStencilAttachmentDesc &desc,
33837
     return loadAction == other.loadAction && storeAction == other.storeAction &&
33838
            storeActionOptions == other.storeActionOptions;
33839
 }
33840
+// Convert to Metal object
33841
+void RenderPassDesc::convertToMetalDesc(MTLRenderPassDescriptor *objCDesc) const
33842
+{
33843
+    ANGLE_MTL_OBJC_SCOPE
33844
+    {
33845
+        for (uint32_t i = 0; i < numColorAttachments; ++i)
33846
+        {
33847
+            ToObjC(objCDesc.colorAttachments[i], colorAttachments[i]);
33848
+        }
33849
+        for (uint32_t i = numColorAttachments; i < kMaxRenderTargets; ++i)
33850
+        {
33851
+            // Inactive render target
33852
+            objCDesc.colorAttachments[i].texture     = nil;
33853
+            objCDesc.colorAttachments[i].level       = 0;
33854
+            objCDesc.colorAttachments[i].slice       = 0;
33855
+            objCDesc.colorAttachments[i].depthPlane  = 0;
33856
+            objCDesc.colorAttachments[i].loadAction  = MTLLoadActionDontCare;
33857
+            objCDesc.colorAttachments[i].storeAction = MTLStoreActionDontCare;
33858
+        }
33859
+
33860
+        ToObjC(objCDesc.depthAttachment, depthAttachment);
33861
+        ToObjC(objCDesc.stencilAttachment, stencilAttachment);
33862
+    }
33863
+}
33864
 
33865
 void RenderPassDesc::populateRenderPipelineOutputDesc(RenderPipelineOutputDesc *outDesc) const
33866
 {
33867
@@ -742,19 +764,19 @@ void ToObjC(const RenderPassStencilAttachmentDesc &desc,
33868
 void RenderPassDesc::populateRenderPipelineOutputDesc(const BlendDesc &blendState,
33869
                                                       RenderPipelineOutputDesc *outDesc) const
33870
 {
33871
-    RenderPipelineOutputDesc &outputDescriptor = *outDesc;
33872
+    auto &outputDescriptor               = *outDesc;
33873
     outputDescriptor.numColorAttachments = this->numColorAttachments;
33874
     outputDescriptor.sampleCount         = this->sampleCount;
33875
     for (uint32_t i = 0; i < this->numColorAttachments; ++i)
33876
     {
33877
         auto &renderPassColorAttachment = this->colorAttachments[i];
33878
-        auto texture                    = renderPassColorAttachment.texture;
33879
+        auto texture                    = renderPassColorAttachment.texture();
33880
 
33881
         if (texture)
33882
         {
33883
             // Copy parameters from blend state
33884
             outputDescriptor.colorAttachments[i].update(blendState);
33885
-            if (!renderPassColorAttachment.blendable)
33886
+            if (!renderPassColorAttachment.blendable())
33887
             {
33888
                 // Disable blending if the attachment's render target doesn't support blending.
33889
                 outputDescriptor.colorAttachments[i].blendingEnabled = false;
33890
@@ -781,11 +803,11 @@ void ToObjC(const RenderPassStencilAttachmentDesc &desc,
33891
         outputDescriptor.colorAttachments[i].reset();
33892
     }
33893
 
33894
-    auto depthTexture = this->depthAttachment.texture;
33895
+    auto depthTexture = this->depthAttachment.texture();
33896
     outputDescriptor.depthAttachmentPixelFormat =
33897
         depthTexture ? depthTexture->pixelFormat() : MTLPixelFormatInvalid;
33898
 
33899
-    auto stencilTexture = this->stencilAttachment.texture;
33900
+    auto stencilTexture = this->stencilAttachment.texture();
33901
     outputDescriptor.stencilAttachmentPixelFormat =
33902
         stencilTexture ? stencilTexture->pixelFormat() : MTLPixelFormatInvalid;
33903
 }
33904
@@ -831,42 +853,21 @@ void ToObjC(const RenderPassStencilAttachmentDesc &desc,
33905
     return depthAttachment == other.depthAttachment && stencilAttachment == other.stencilAttachment;
33906
 }
33907
 
33908
-// Convert to Metal object
33909
-void RenderPassDesc::convertToMetalDesc(MTLRenderPassDescriptor *objCDesc) const
33910
-{
33911
-    ANGLE_MTL_OBJC_SCOPE
33912
-    {
33913
-        for (uint32_t i = 0; i < numColorAttachments; ++i)
33914
-        {
33915
-            ToObjC(colorAttachments[i], objCDesc.colorAttachments[i]);
33916
-        }
33917
-        for (uint32_t i = numColorAttachments; i < kMaxRenderTargets; ++i)
33918
-        {
33919
-            // Inactive render target
33920
-            objCDesc.colorAttachments[i].texture     = nil;
33921
-            objCDesc.colorAttachments[i].level       = 0;
33922
-            objCDesc.colorAttachments[i].slice       = 0;
33923
-            objCDesc.colorAttachments[i].depthPlane  = 0;
33924
-            objCDesc.colorAttachments[i].loadAction  = MTLLoadActionDontCare;
33925
-            objCDesc.colorAttachments[i].storeAction = MTLStoreActionDontCare;
33926
-        }
33927
-
33928
-        ToObjC(depthAttachment, objCDesc.depthAttachment);
33929
-        ToObjC(stencilAttachment, objCDesc.stencilAttachment);
33930
-    }
33931
-}
33932
-
33933
 // RenderPipelineCache implementation
33934
-RenderPipelineCache::RenderPipelineCache() : RenderPipelineCache(nullptr) {}
33935
+RenderPipelineCache::RenderPipelineCache() : RenderPipelineCache(nullptr) {
33936
+}
33937
 
33938
 RenderPipelineCache::RenderPipelineCache(
33939
     RenderPipelineCacheSpecializeShaderFactory *specializedShaderFactory)
33940
     : mSpecializedShaderFactory(specializedShaderFactory)
33941
-{}
33942
+{
33943
+
33944
+}
33945
 
33946
 RenderPipelineCache::~RenderPipelineCache() {}
33947
 
33948
-void RenderPipelineCache::setVertexShader(Context *context, id<MTLFunction> shader)
33949
+void RenderPipelineCache::setVertexShader(Context *context,
33950
+                                          id<MTLFunction> shader)
33951
 {
33952
     mVertexShader.retainAssign(shader);
33953
 
33954
@@ -879,7 +880,8 @@ void ToObjC(const RenderPassStencilAttachmentDesc &desc,
33955
     recreatePipelineStates(context);
33956
 }
33957
 
33958
-void RenderPipelineCache::setFragmentShader(Context *context, id<MTLFunction> shader)
33959
+void RenderPipelineCache::setFragmentShader(Context *context,
33960
+                                            id<MTLFunction> shader)
33961
 {
33962
     mFragmentShader.retainAssign(shader);
33963
 
33964
@@ -929,10 +931,6 @@ void ToObjC(const RenderPassStencilAttachmentDesc &desc,
33965
 {
33966
     AutoObjCPtr<id<MTLRenderPipelineState>> newState =
33967
         createRenderPipelineState(context, desc, insertDefaultAttribLayout);
33968
-    if (!newState)
33969
-    {
33970
-        return nil;
33971
-    }
33972
 
33973
     int tableIdx = insertDefaultAttribLayout ? 1 : 0;
33974
     auto re      = mRenderPipelineStates[tableIdx].insert(std::make_pair(desc, newState));
33975
@@ -944,6 +942,7 @@ void ToObjC(const RenderPassStencilAttachmentDesc &desc,
33976
     return re.first->second;
33977
 }
33978
 
33979
+
33980
 AutoObjCPtr<id<MTLRenderPipelineState>> RenderPipelineCache::createRenderPipelineState(
33981
     Context *context,
33982
     const RenderPipelineDesc &originalDesc,
33983
@@ -959,7 +958,6 @@ void ToObjC(const RenderPassStencilAttachmentDesc &desc,
33984
             desc.emulateCoverageMask    = false;
33985
             desc.alphaToCoverageEnabled = false;
33986
         }
33987
-
33988
         // Choose shader variant
33989
         id<MTLFunction> vertShader = nil;
33990
         id<MTLFunction> fragShader = nil;
33991
@@ -1004,7 +1002,25 @@ void ToObjC(const RenderPassStencilAttachmentDesc &desc,
33992
 
33993
         // Convert to Objective-C desc:
33994
         AutoObjCObj<MTLRenderPipelineDescriptor> objCDesc = ToObjC(vertShader, fragShader, desc);
33995
-
33996
+        // Validate Render Pipeline State:
33997
+        if (DeviceHasMaximumRenderTargetSize(metalDevice))
33998
+        {
33999
+            NSUInteger maxSize = GetMaxRenderTargetSizeForDeviceInBytes(metalDevice);
34000
+            NSUInteger renderTargetSize =
34001
+                ComputeTotalSizeUsedForMTLRenderPipelineDescriptor(objCDesc, context, metalDevice);
34002
+            if (renderTargetSize > maxSize)
34003
+            {
34004
+                NSString *errorString =
34005
+                    [NSString stringWithFormat:@"This set of render targets requires %lu bytes of "
34006
+                                               @"pixel storage. This device supports %lu bytes.",
34007
+                                               renderTargetSize, maxSize];
34008
+                NSError *err = [NSError errorWithDomain:@"MTLValidationError"
34009
+                                                   code:-1
34010
+                                               userInfo:@{NSLocalizedDescriptionKey : errorString}];
34011
+                context->handleError(err, __FILE__, ANGLE_FUNCTION, __LINE__);
34012
+                return nil;
34013
+            }
34014
+        }
34015
         // Special attribute slot for default attribute
34016
         if (insertDefaultAttribLayout)
34017
         {
34018
@@ -1032,6 +1048,7 @@ void ToObjC(const RenderPassStencilAttachmentDesc &desc,
34019
     }
34020
 }
34021
 
34022
+
34023
 void RenderPipelineCache::recreatePipelineStates(Context *context)
34024
 {
34025
     for (int hasDefaultAttrib = 0; hasDefaultAttrib <= 1; ++hasDefaultAttrib)
34026
@@ -1062,7 +1079,7 @@ void ToObjC(const RenderPassStencilAttachmentDesc &desc,
34027
 }
34028
 
34029
 // StateCache implementation
34030
-StateCache::StateCache() {}
34031
+StateCache::StateCache(const angle::FeaturesMtl &features) : mFeatures(features) {}
34032
 
34033
 StateCache::~StateCache() {}
34034
 
34035
@@ -1113,6 +1130,11 @@ void ToObjC(const RenderPassStencilAttachmentDesc &desc,
34036
         if (ite == mSamplerStates.end())
34037
         {
34038
             AutoObjCObj<MTLSamplerDescriptor> objCDesc = ToObjC(desc);
34039
+            if (!mFeatures.allowRuntimeSamplerCompareMode.enabled)
34040
+            {
34041
+                // Runtime sampler compare mode is not supported, fallback to never.
34042
+                objCDesc.get().compareFunction = MTLCompareFunctionNever;
34043
+            }
34044
             AutoObjCPtr<id<MTLSamplerState>> newState =
34045
                 [[metalDevice newSamplerStateWithDescriptor:objCDesc] ANGLE_MTL_AUTORELEASE];
34046
 
34047
diff --git a/src/libANGLE/renderer/metal/mtl_utils.h b/src/libANGLE/renderer/metal/mtl_utils.h
34048
index a84ac73..805729e 100644
34049
--- a/src/libANGLE/renderer/metal/mtl_utils.h
34050
+++ b/src/libANGLE/renderer/metal/mtl_utils.h
34051
@@ -135,15 +135,30 @@ MTLTextureSwizzle GetTextureSwizzle(GLenum swizzle);
34052
 
34053
 // Get color write mask for a specified format. Some formats such as RGB565 doesn't have alpha
34054
 // channel but is emulated by a RGBA8 format, we need to disable alpha write for this format.
34055
-// - isFormatEmulated: if the format is emulated, this pointer will store a true value.
34056
-MTLColorWriteMask GetEmulatedColorWriteMask(const mtl::Format &mtlFormat, bool *isFormatEmulated);
34057
+// - emulatedChannelsOut: if the format is emulated, this pointer will store a true value.
34058
+MTLColorWriteMask GetEmulatedColorWriteMask(const mtl::Format &mtlFormat,
34059
+                                            bool *emulatedChannelsOut);
34060
 MTLColorWriteMask GetEmulatedColorWriteMask(const mtl::Format &mtlFormat);
34061
 bool IsFormatEmulated(const mtl::Format &mtlFormat);
307
 
34062
 
308
 SOFT_LINK_FRAMEWORK_HEADER(OpenGLES)
34063
+NSUInteger GetMaxRenderTargetSizeForDeviceInBytes(id<MTLDevice> device);
34064
+NSUInteger GetMaxNumberOfRenderTargetsForDevice(id<MTLDevice> device);
34065
+bool DeviceHasMaximumRenderTargetSize(id<MTLDevice> device);
34066
+
34067
 // Useful to set clear color for texture originally having no alpha in GL, but backend's format
34068
 // has alpha channel.
34069
 MTLClearColor EmulatedAlphaClearColor(MTLClearColor color, MTLColorWriteMask colorMask);
309
 
34070
 
310
diff --git a/src/libANGLE/renderer/gl/eagl/FunctionsEAGL.mm b/src/libANGLE/renderer/gl/eagl/FunctionsEAGL.mm
34071
+
311
index 7779792..076d072 100644
34072
+NSUInteger ComputeTotalSizeUsedForMTLRenderPassDescriptor(const MTLRenderPassDescriptor *descriptor,
312
--- a/src/libANGLE/renderer/gl/eagl/FunctionsEAGL.mm
34073
+                                                          const Context *context,
313
+++ b/src/libANGLE/renderer/gl/eagl/FunctionsEAGL.mm
34074
+                                                          id<MTLDevice> device);
314
@@ -14,7 +14,7 @@
34075
+
315
 #    import <OpenGLES/EAGLDrawable.h>
34076
+NSUInteger ComputeTotalSizeUsedForMTLRenderPipelineDescriptor(
316
 #    import <OpenGLES/EAGLIOSurface.h>
34077
+    const MTLRenderPipelineDescriptor *descriptor,
34078
+    const Context *context,
34079
+    id<MTLDevice> device);
34080
+
34081
 gl::Box MTLRegionToGLBox(const MTLRegion &mtlRegion);
317
 
34082
 
318
-#    include "libANGLE/renderer/gl/apple/SoftLinking.h"
34083
 MipmapNativeLevel GetNativeMipLevel(GLuint level, GLuint base);
319
+#    include "common/apple/SoftLinking.h"
34084
diff --git a/src/libANGLE/renderer/metal/mtl_utils.mm b/src/libANGLE/renderer/metal/mtl_utils.mm
34085
index 076e609..009af5a 100644
34086
--- a/src/libANGLE/renderer/metal/mtl_utils.mm
34087
+++ b/src/libANGLE/renderer/metal/mtl_utils.mm
34088
@@ -10,9 +10,11 @@
320
 
34089
 
321
 SOFT_LINK_FRAMEWORK_SOURCE(OpenGLES)
34090
 #include "libANGLE/renderer/metal/mtl_utils.h"
322
 
34091
 
323
diff --git a/src/libANGLE/renderer/gl/eagl/IOSurfaceSurfaceEAGL.mm b/src/libANGLE/renderer/gl/eagl/IOSurfaceSurfaceEAGL.mm
34092
+#include <Availability.h>
324
index f16c3e7..45e6d0f 100644
34093
 #include <TargetConditionals.h>
325
--- a/src/libANGLE/renderer/gl/eagl/IOSurfaceSurfaceEAGL.mm
326
+++ b/src/libANGLE/renderer/gl/eagl/IOSurfaceSurfaceEAGL.mm
327
@@ -206,7 +206,9 @@ egl::Error IOSurfaceSurfaceEAGL::bindTexImage(const gl::Context *context,
328
         // TODO(kbr): possibly more state to be set here, including setting any
329
         // pixel unpack buffer to 0 when using ES 3.0 contexts.
330
         gl::PixelUnpackState defaultUnpackState;
331
-        stateManager->setPixelUnpackState(defaultUnpackState);
332
+        if (IsError(stateManager->setPixelUnpackState(context, defaultUnpackState))) {
333
+            return egl::EglBadState() << "Failed to set pixel unpack state.";
334
+        }
335
         textureData = IOSurfaceGetBaseAddress(mIOSurface);
336
     }
337
 
338
@@ -238,7 +240,9 @@ egl::Error IOSurfaceSurfaceEAGL::releaseTexImage(const gl::Context *context, EGL
339
         gl::PixelPackState state;
340
         state.rowLength = mRowStrideInPixels;
341
         state.alignment = 1;
342
-        stateManager->setPixelPackState(state);
343
+        if (IsError(stateManager->setPixelPackState(context, state))) {
344
+            return egl::EglBadState() << "Failed to set pixel unpack state.";
345
+        }
346
         // TODO(kbr): possibly more state to be set here, including setting any
347
         // pixel pack buffer to 0 when using ES 3.0 contexts.
348
         const auto &format = kIOSurfaceFormats[mFormatIndex];
349
diff --git a/src/libANGLE/renderer/gl/renderergl_utils.cpp b/src/libANGLE/renderer/gl/renderergl_utils.cpp
350
index 99772c4..11f47e6 100644
351
--- a/src/libANGLE/renderer/gl/renderergl_utils.cpp
352
+++ b/src/libANGLE/renderer/gl/renderergl_utils.cpp
353
@@ -1358,7 +1358,7 @@ void GenerateCaps(const FunctionsGL *functions,
354
 
34094
 
355
 #if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
34095
 #include "common/MemoryBuffer.h"
356
     angle::SystemInfo info;
34096
+#include "common/system_utils.h"
357
-    if (angle::GetSystemInfo(&info) && !info.isiOSAppOnMac)
34097
 #include "gpu_info_util/SystemInfo.h"
358
+    if (angle::GetSystemInfo(&info) && !info.needsEAGLOnMac)
34098
 #include "libANGLE/renderer/metal/ContextMtl.h"
34099
 #include "libANGLE/renderer/metal/DisplayMtl.h"
34100
@@ -24,6 +26,8 @@
34101
 namespace mtl
34102
 {
34103
 
34104
+constexpr char kANGLEPrintMSLEnv[] = "ANGLE_METAL_PRINT_MSL_ENABLE";
34105
+
34106
 namespace
34107
 {
34108
 
34109
@@ -103,24 +107,43 @@ GLint GetSliceOrDepth(const ImageNativeIndex &index)
34110
                                         const ImageNativeIndex &index)
34111
 {
34112
     ASSERT(texture && texture->valid());
34113
-    // Only one slice can be initialized at a time.
34114
-    ASSERT(!index.isLayered() || index.getType() == gl::TextureType::_3D);
34115
     ContextMtl *contextMtl = mtl::GetImpl(context);
34116
 
34117
+    const angle::Format &actualAngleFormat           = textureObjFormat.actualAngleFormat();
34118
     const gl::InternalFormat &intendedInternalFormat = textureObjFormat.intendedInternalFormat();
34119
 
34120
     // This function is called in many places to initialize the content of a texture.
34121
-    // So it's better we do the initial check here instead of let the callers do it themselves:
34122
-    if (!textureObjFormat.valid() || intendedInternalFormat.compressed)
34123
+    // So it's better we do the sanity check here instead of let the callers do it themselves:
34124
+    if (!textureObjFormat.valid() || actualAngleFormat.isBlock || actualAngleFormat.depthBits > 0 ||
34125
+        actualAngleFormat.stencilBits > 0)
359
     {
34126
     {
360
         VendorID vendor = GetVendorID(functions);
34127
+        // If dst format is compressed, ignore.
361
         if ((IsAMD(vendor) || IsIntel(vendor)) && *maxSupportedESVersion >= gl::Version(3, 0))
34128
         return angle::Result::Continue;
34129
     }
34130
 
34131
     gl::Extents size = texture->size(index);
34132
 
34133
-    // Intiialize the content to black
34134
-    GLint layer, startDepth;
34135
-    GetSliceAndDepth(index, &layer, &startDepth);
34136
+    // Intialize the content to black
34137
+    GLint layer      = 0;
34138
+    GLint startDepth = 0;
34139
+    if (index.hasLayer())
34140
+    {
34141
+        switch (index.getType())
34142
+        {
34143
+            case gl::TextureType::CubeMap:
34144
+                layer = index.cubeMapFaceIndex();
34145
+                break;
34146
+            case gl::TextureType::_2DArray:
34147
+                layer = index.getLayerIndex();
34148
+                break;
34149
+            case gl::TextureType::_3D:
34150
+                startDepth = index.getLayerIndex();
34151
+                break;
34152
+            default:
34153
+                UNREACHABLE();
34154
+                break;
34155
+        }
34156
+    }
34157
 
34158
     if (texture->isCPUAccessible() && index.getType() != gl::TextureType::_2DMultisample &&
34159
         index.getType() != gl::TextureType::_2DMultisampleArray)
34160
@@ -136,6 +159,13 @@ GLint GetSliceOrDepth(const ImageNativeIndex &index)
34161
         }
34162
         else
34163
         {
34164
+            if (!textureObjFormat.valid() || intendedInternalFormat.compressed ||
34165
+                intendedInternalFormat.depthBits > 0 || intendedInternalFormat.stencilBits > 0)
34166
+            {
34167
+                // If source format is compressed, ignore.
34168
+                return angle::Result::Continue;
34169
+            }
34170
+
34171
             const angle::Format &srcFormat = angle::Format::Get(
34172
                 intendedInternalFormat.alphaBits > 0 ? angle::FormatID::R8G8B8A8_UNORM
34173
                                                      : angle::FormatID::R8G8B8_UNORM);
34174
@@ -165,7 +195,7 @@ GLint GetSliceOrDepth(const ImageNativeIndex &index)
34175
                                        conversionRow.data(), dstRowPitch);
34176
             }
34177
         }
34178
-    }
34179
+    }  // if (texture->isCPUAccessible())
34180
     else
34181
     {
34182
         ANGLE_TRY(InitializeTextureContentsGPU(context, texture, textureObjFormat, index,
34183
@@ -210,7 +240,7 @@ GLint GetSliceOrDepth(const ImageNativeIndex &index)
34184
     RenderTargetMtl tempRtt;
34185
     tempRtt.set(texture, index.getNativeLevel(), sliceOrDepth, textureObjFormat);
34186
 
34187
-    int clearAlpha = 0;
34188
+    float clearAlpha = 0;
34189
     if (!textureObjFormat.intendedAngleFormat().alphaBits)
34190
     {
34191
         // if intended format doesn't have alpha, set it to 1.0.
34192
@@ -240,11 +270,11 @@ GLint GetSliceOrDepth(const ImageNativeIndex &index)
34193
         ClearColorValue clearColor;
34194
         if (angleFormat.isSint())
34195
         {
34196
-            clearColor.setAsInt(0, 0, 0, clearAlpha);
34197
+            clearColor.setAsInt(0, 0, 0, (int)clearAlpha);
34198
         }
34199
         else if (angleFormat.isUint())
34200
         {
34201
-            clearColor.setAsUInt(0, 0, 0, clearAlpha);
34202
+            clearColor.setAsUInt(0, 0, 0, (int)clearAlpha);
34203
         }
34204
         else
34205
         {
34206
@@ -283,17 +313,17 @@ GLint GetSliceOrDepth(const ImageNativeIndex &index)
34207
     rpDesc.sampleCount = texture->samples();
34208
     if (angleFormat.depthBits)
34209
     {
34210
-        rpDesc.depthAttachment.texture      = texture;
34211
-        rpDesc.depthAttachment.level        = level;
34212
-        rpDesc.depthAttachment.sliceOrDepth = layer;
34213
+        rpDesc.depthAttachment.renderTarget->texture      = texture;
34214
+        rpDesc.depthAttachment.renderTarget->level        = level;
34215
+        rpDesc.depthAttachment.renderTarget->sliceOrDepth = layer;
34216
         rpDesc.depthAttachment.loadAction   = MTLLoadActionClear;
34217
         rpDesc.depthAttachment.clearDepth   = 1.0;
34218
     }
34219
     if (angleFormat.stencilBits)
34220
     {
34221
-        rpDesc.stencilAttachment.texture      = texture;
34222
-        rpDesc.stencilAttachment.level        = level;
34223
-        rpDesc.stencilAttachment.sliceOrDepth = layer;
34224
+        rpDesc.stencilAttachment.renderTarget->texture      = texture;
34225
+        rpDesc.stencilAttachment.renderTarget->level        = level;
34226
+        rpDesc.stencilAttachment.renderTarget->sliceOrDepth = layer;
34227
         rpDesc.stencilAttachment.loadAction   = MTLLoadActionClear;
34228
     }
34229
 
34230
@@ -456,6 +486,30 @@ uint32_t GetDeviceVendorId(id<MTLDevice> metalDevice)
34231
     return CreateShaderLibrary(metalDevice, source.c_str(), source.size(), error);
34232
 }
34233
 
34234
+#if 0
34235
+static MTLLanguageVersion GetHighestSupportedMSLVersion()
34236
+{
34237
+    // https://developer.apple.com/documentation/metal/mtllanguageversion?language=objc
34238
+    if (ANGLE_APPLE_AVAILABLE_XCI(11.0, 14.0, 14.0))
34239
+        return MTLLanguageVersion2_3;
34240
+    if (ANGLE_APPLE_AVAILABLE_XCI(10.15, 13.0, 13.0))
34241
+        return MTLLanguageVersion2_2;
34242
+    if (ANGLE_APPLE_AVAILABLE_XCI(10.15, 13.0, 12.0))
34243
+        return MTLLanguageVersion2_1;
34244
+    if (ANGLE_APPLE_AVAILABLE_XCI(10.13, 13.0, 11.0))
34245
+        return MTLLanguageVersion2_0;
34246
+    if (ANGLE_APPLE_AVAILABLE_XCI(10.12, 13.0, 10.0))
34247
+        return MTLLanguageVersion1_2;
34248
+    if (ANGLE_APPLE_AVAILABLE_XCI(10.11, 13.0, 9.0))
34249
+        return MTLLanguageVersion1_1;
34250
+#    if TARGET_OS_IOS
34251
+    if (ANGLE_APPLE_AVAILABLE_I(9.0))
34252
+        return MTLLanguageVersion1_0;
34253
+#    endif
34254
+    return MTLLanguageVersion1_1;
34255
+}
34256
+#endif
34257
+
34258
 AutoObjCPtr<id<MTLLibrary>> CreateShaderLibrary(id<MTLDevice> metalDevice,
34259
                                                 const char *source,
34260
                                                 size_t sourceLen,
34261
@@ -469,8 +523,25 @@ uint32_t GetDeviceVendorId(id<MTLDevice> metalDevice)
34262
                                                      encoding:NSUTF8StringEncoding
34263
                                                  freeWhenDone:NO];
34264
         auto options     = [[[MTLCompileOptions alloc] init] ANGLE_MTL_AUTORELEASE];
34265
+        // Mark all positions in VS with attribute invariant as non-optimizable
34266
+#if (defined(__MAC_11_0) && __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_11_0) ||        \
34267
+    (defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0) || \
34268
+    (defined(__TVOS_14_0) && __TV_OS_VERSION_MAX_ALLOWED >= __TVOS_14_0)
34269
+        options.preserveInvariance = true;
34270
+#else
34271
+        // No preserveInvariance available compiling from source, so just disable fastmath.
34272
+        options.fastMathEnabled = false;
34273
+#endif
34274
+        // TODO(jcunningham): workaround for intel driver not preserving invariance on all shaders
34275
+        if ([metalDevice.name rangeOfString:@"Intel"].location != NSNotFound)
34276
+        {
34277
+            options.fastMathEnabled = false;
34278
+        }
34279
         auto library = [metalDevice newLibraryWithSource:nsSource options:options error:&nsError];
34280
-
34281
+        if (angle::GetEnvironmentVar(kANGLEPrintMSLEnv)[0] == '1')
34282
+        {
34283
+            NSLog(@"%@\n", nsSource);
34284
+        }
34285
         [nsSource ANGLE_MTL_AUTORELEASE];
34286
 
34287
         *errorOut = std::move(nsError);
34288
@@ -772,15 +843,15 @@ MTLTextureSwizzle GetTextureSwizzle(GLenum swizzle)
34289
 }
34290
 #endif
34291
 
34292
-MTLColorWriteMask GetEmulatedColorWriteMask(const mtl::Format &mtlFormat, bool *isEmulatedOut)
34293
+MTLColorWriteMask GetEmulatedColorWriteMask(const mtl::Format &mtlFormat, bool *emulatedChannelsOut)
34294
 {
34295
     const angle::Format &intendedFormat = mtlFormat.intendedAngleFormat();
34296
     const angle::Format &actualFormat   = mtlFormat.actualAngleFormat();
34297
-    bool isFormatEmulated               = false;
34298
+    bool emulatedChannels               = false;
34299
     MTLColorWriteMask colorWritableMask = MTLColorWriteMaskAll;
34300
     if (intendedFormat.alphaBits == 0 && actualFormat.alphaBits)
34301
     {
34302
-        isFormatEmulated = true;
34303
+        emulatedChannels = true;
34304
         // Disable alpha write to this texture
34305
         colorWritableMask = colorWritableMask & (~MTLColorWriteMaskAlpha);
34306
     }
34307
@@ -788,41 +859,41 @@ MTLColorWriteMask GetEmulatedColorWriteMask(const mtl::Format &mtlFormat, bool *
34308
     {
34309
         if (intendedFormat.redBits == 0 && actualFormat.redBits)
34310
         {
34311
-            isFormatEmulated = true;
34312
+            emulatedChannels = true;
34313
             // Disable red write to this texture
34314
             colorWritableMask = colorWritableMask & (~MTLColorWriteMaskRed);
34315
         }
34316
         if (intendedFormat.greenBits == 0 && actualFormat.greenBits)
34317
         {
34318
-            isFormatEmulated = true;
34319
+            emulatedChannels = true;
34320
             // Disable green write to this texture
34321
             colorWritableMask = colorWritableMask & (~MTLColorWriteMaskGreen);
34322
         }
34323
         if (intendedFormat.blueBits == 0 && actualFormat.blueBits)
34324
         {
34325
-            isFormatEmulated = true;
34326
+            emulatedChannels = true;
34327
             // Disable blue write to this texture
34328
             colorWritableMask = colorWritableMask & (~MTLColorWriteMaskBlue);
34329
         }
34330
     }
34331
 
34332
-    *isEmulatedOut = isFormatEmulated;
34333
+    *emulatedChannelsOut = emulatedChannels;
34334
 
34335
     return colorWritableMask;
34336
 }
34337
 
34338
 MTLColorWriteMask GetEmulatedColorWriteMask(const mtl::Format &mtlFormat)
34339
 {
34340
-    // Ignore isFormatEmulated boolean value
34341
-    bool isFormatEmulated;
34342
-    return GetEmulatedColorWriteMask(mtlFormat, &isFormatEmulated);
34343
+    // Ignore emulatedChannels boolean value
34344
+    bool emulatedChannels;
34345
+    return GetEmulatedColorWriteMask(mtlFormat, &emulatedChannels);
34346
 }
34347
 
34348
 bool IsFormatEmulated(const mtl::Format &mtlFormat)
34349
 {
34350
-    bool isFormatEmulated;
34351
-    (void)GetEmulatedColorWriteMask(mtlFormat, &isFormatEmulated);
34352
-    return isFormatEmulated;
34353
+    bool emulatedChannels;
34354
+    (void)GetEmulatedColorWriteMask(mtlFormat, &emulatedChannels);
34355
+    return emulatedChannels;
34356
 }
34357
 
34358
 MTLClearColor EmulatedAlphaClearColor(MTLClearColor color, MTLColorWriteMask colorMask)
34359
@@ -837,6 +908,151 @@ MTLClearColor EmulatedAlphaClearColor(MTLClearColor color, MTLColorWriteMask col
34360
     return re;
34361
 }
34362
 
34363
+NSUInteger GetMaxRenderTargetSizeForDeviceInBytes(id<MTLDevice> device)
34364
+{
34365
+    if ([device supportsFamily:MTLGPUFamilyApple4])
34366
+    {
34367
+        return 64;
34368
+    }
34369
+    else if ([device supportsFamily:MTLGPUFamilyApple2])
34370
+    {
34371
+        return 32;
34372
+    }
34373
+    else
34374
+    {
34375
+        return 16;
34376
+    }
34377
+}
34378
+
34379
+NSUInteger GetMaxNumberOfRenderTargetsForDevice(id<MTLDevice> device)
34380
+{
34381
+    if ([device supportsFamily:MTLGPUFamilyApple2] || [device supportsFamily:MTLGPUFamilyMac1])
34382
+    {
34383
+        return 8;
34384
+    }
34385
+    else
34386
+    {
34387
+        return 4;
34388
+    }
34389
+}
34390
+
34391
+bool DeviceHasMaximumRenderTargetSize(id<MTLDevice> device)
34392
+{
34393
+    return [device supportsFamily:MTLGPUFamilyApple1];
34394
+}
34395
+
34396
+static NSUInteger getNextLocationForFormat(const FormatCaps &caps,
34397
+                                           bool isMSAA,
34398
+                                           NSUInteger currentRenderTargetSize)
34399
+{
34400
+    assert(!caps.compressed);
34401
+    uint8_t alignment         = caps.alignment;
34402
+    NSUInteger pixelBytes     = caps.pixelBytes;
34403
+    NSUInteger pixelBytesMSAA = caps.pixelBytesMSAA;
34404
+    pixelBytes                = isMSAA ? pixelBytesMSAA : pixelBytes;
34405
+
34406
+    currentRenderTargetSize = (currentRenderTargetSize + (alignment - 1)) & ~(alignment - 1);
34407
+    currentRenderTargetSize += pixelBytes;
34408
+    return currentRenderTargetSize;
34409
+}
34410
+
34411
+NSUInteger ComputeTotalSizeUsedForMTLRenderPassDescriptor(const MTLRenderPassDescriptor *descriptor,
34412
+                                                          const Context *context,
34413
+                                                          id<MTLDevice> device)
34414
+{
34415
+    NSUInteger currentRenderTargetSize = 0;
34416
+
34417
+    for (NSUInteger i = 0; i < GetMaxNumberOfRenderTargetsForDevice(device); i++)
34418
+    {
34419
+        MTLPixelFormat pixelFormat = descriptor.colorAttachments[i].texture.pixelFormat;
34420
+        bool isMsaa                = descriptor.colorAttachments[i].texture.sampleCount > 1;
34421
+        if (pixelFormat != MTLPixelFormatInvalid)
34422
+        {
34423
+            const FormatCaps &caps = context->getDisplay()->getNativeFormatCaps(pixelFormat);
34424
+            currentRenderTargetSize =
34425
+                getNextLocationForFormat(caps, isMsaa, currentRenderTargetSize);
34426
+        }
34427
+    }
34428
+    if (descriptor.depthAttachment.texture.pixelFormat ==
34429
+        descriptor.stencilAttachment.texture.pixelFormat)
34430
+    {
34431
+        bool isMsaa = descriptor.depthAttachment.texture.sampleCount > 1;
34432
+        if (descriptor.depthAttachment.texture.pixelFormat != MTLPixelFormatInvalid)
34433
+        {
34434
+            const FormatCaps &caps = context->getDisplay()->getNativeFormatCaps(
34435
+                descriptor.depthAttachment.texture.pixelFormat);
34436
+            currentRenderTargetSize =
34437
+                getNextLocationForFormat(caps, isMsaa, currentRenderTargetSize);
34438
+        }
34439
+    }
34440
+    else
34441
+    {
34442
+        if (descriptor.depthAttachment.texture.pixelFormat != MTLPixelFormatInvalid)
34443
+        {
34444
+            bool isMsaa            = descriptor.depthAttachment.texture.sampleCount > 1;
34445
+            const FormatCaps &caps = context->getDisplay()->getNativeFormatCaps(
34446
+                descriptor.depthAttachment.texture.pixelFormat);
34447
+            currentRenderTargetSize =
34448
+                getNextLocationForFormat(caps, isMsaa, currentRenderTargetSize);
34449
+        }
34450
+        if (descriptor.stencilAttachment.texture.pixelFormat != MTLPixelFormatInvalid)
34451
+        {
34452
+            bool isMsaa            = descriptor.stencilAttachment.texture.sampleCount > 1;
34453
+            const FormatCaps &caps = context->getDisplay()->getNativeFormatCaps(
34454
+                descriptor.stencilAttachment.texture.pixelFormat);
34455
+            currentRenderTargetSize =
34456
+                getNextLocationForFormat(caps, isMsaa, currentRenderTargetSize);
34457
+        }
34458
+    }
34459
+    return currentRenderTargetSize;
34460
+}
34461
+NSUInteger ComputeTotalSizeUsedForMTLRenderPipelineDescriptor(
34462
+    const MTLRenderPipelineDescriptor *descriptor,
34463
+    const Context *context,
34464
+    id<MTLDevice> device)
34465
+{
34466
+    NSUInteger currentRenderTargetSize = 0;
34467
+    bool isMsaa                        = descriptor.sampleCount > 1;
34468
+    for (NSUInteger i = 0; i < GetMaxNumberOfRenderTargetsForDevice(device); i++)
34469
+    {
34470
+        MTLRenderPipelineColorAttachmentDescriptor *color = descriptor.colorAttachments[i];
34471
+        if (color.pixelFormat != MTLPixelFormatInvalid)
34472
+        {
34473
+            const FormatCaps &caps = context->getDisplay()->getNativeFormatCaps(color.pixelFormat);
34474
+            currentRenderTargetSize =
34475
+                getNextLocationForFormat(caps, isMsaa, currentRenderTargetSize);
34476
+        }
34477
+    }
34478
+    if (descriptor.depthAttachmentPixelFormat == descriptor.stencilAttachmentPixelFormat)
34479
+    {
34480
+        if (descriptor.depthAttachmentPixelFormat != MTLPixelFormatInvalid)
34481
+        {
34482
+            const FormatCaps &caps =
34483
+                context->getDisplay()->getNativeFormatCaps(descriptor.depthAttachmentPixelFormat);
34484
+            currentRenderTargetSize =
34485
+                getNextLocationForFormat(caps, isMsaa, currentRenderTargetSize);
34486
+        }
34487
+    }
34488
+    else
34489
+    {
34490
+        if (descriptor.depthAttachmentPixelFormat != MTLPixelFormatInvalid)
34491
+        {
34492
+            const FormatCaps &caps =
34493
+                context->getDisplay()->getNativeFormatCaps(descriptor.depthAttachmentPixelFormat);
34494
+            currentRenderTargetSize =
34495
+                getNextLocationForFormat(caps, isMsaa, currentRenderTargetSize);
34496
+        }
34497
+        if (descriptor.stencilAttachmentPixelFormat != MTLPixelFormatInvalid)
34498
+        {
34499
+            const FormatCaps &caps =
34500
+                context->getDisplay()->getNativeFormatCaps(descriptor.stencilAttachmentPixelFormat);
34501
+            currentRenderTargetSize =
34502
+                getNextLocationForFormat(caps, isMsaa, currentRenderTargetSize);
34503
+        }
34504
+    }
34505
+    return currentRenderTargetSize;
34506
+}
34507
+
34508
 gl::Box MTLRegionToGLBox(const MTLRegion &mtlRegion)
34509
 {
34510
     return gl::Box(static_cast<int>(mtlRegion.origin.x), static_cast<int>(mtlRegion.origin.y),
34511
diff --git a/src/libANGLE/renderer/metal/shaders/blit.metal b/src/libANGLE/renderer/metal/shaders/blit.metal
34512
index 4272c4f..2a9bb5d 100644
34513
--- a/src/libANGLE/renderer/metal/shaders/blit.metal
34514
+++ b/src/libANGLE/renderer/metal/shaders/blit.metal
34515
@@ -334,7 +334,7 @@ kernel void blitStencilToBufferCS(ushort2 gIndices [[thread_position_in_grid]],
34516
 }
34517
 
34518
 // Fragment's stencil output is only available since Metal 2.1
34519
-@@#if __METAL_VERSION__ >= 210
34520
+#if __METAL_VERSION__ >= 210
34521
 
34522
 struct FragmentStencilOut
34523
 {
34524
@@ -397,4 +397,4 @@ fragment FragmentDepthStencilOut blitDepthStencilFS(
34525
                       srcStencilTextureCube, input.texCoords, options.srcLevel, options.srcLayer);
34526
     return re;
34527
 }
34528
-@@#endif  // __METAL_VERSION__ >= 210
34529
+#endif  // __METAL_VERSION__ >= 210
34530
diff --git a/src/libANGLE/renderer/metal/shaders/common.h b/src/libANGLE/renderer/metal/shaders/common.h
34531
index 68c7745..e6673b5 100644
34532
--- a/src/libANGLE/renderer/metal/shaders/common.h
34533
+++ b/src/libANGLE/renderer/metal/shaders/common.h
34534
@@ -10,8 +10,8 @@
34535
 
34536
 // clang-format off
34537
 #ifndef SKIP_STD_HEADERS
34538
-@@#    include <simd/simd.h>
34539
-@@#    include <metal_stdlib>
34540
+#    include <simd/simd.h>
34541
+#    include <metal_stdlib>
34542
 #endif
34543
 
34544
 #include "constants.h"
34545
diff --git a/src/libANGLE/renderer/metal/shaders/copy_buffer.metal b/src/libANGLE/renderer/metal/shaders/copy_buffer.metal
34546
index df7c4c9..1b408d8 100644
34547
--- a/src/libANGLE/renderer/metal/shaders/copy_buffer.metal
34548
+++ b/src/libANGLE/renderer/metal/shaders/copy_buffer.metal
34549
@@ -4,22 +4,22 @@
34550
 // found in the LICENSE file.
34551
 //
34552
 // copy_buffer.metal: implements compute shader that copy formatted data from buffer to texture,
34553
-// and from texture to buffer.
34554
+// from texture to buffer and from buffer to buffer.
34555
 // NOTE(hqle): This file is a bit hard to read but there are a lot of repeated works, and it would
34556
 // be a pain to implement without the use of macros.
34557
 //
34558
 
34559
-@@#include <metal_pack>
34560
+#include <metal_pack>
34561
 
34562
 #include "common.h"
34563
 #include "format_autogen.h"
34564
 
34565
 using namespace rx::mtl_shader;
34566
 
34567
-constant int kCopyFormatType [[function_constant(10)]];
34568
+constant int kCopyFormatType [[function_constant(1)]];
34569
 
34570
 /* -------- copy pixel data between buffer and texture ---------*/
34571
-constant int kCopyTextureType [[function_constant(20)]];
34572
+constant int kCopyTextureType [[function_constant(2)]];
34573
 constant bool kCopyTextureType2D      = kCopyTextureType == kTextureType2D;
34574
 constant bool kCopyTextureType2DArray = kCopyTextureType == kTextureType2DArray;
34575
 constant bool kCopyTextureType2DMS    = kCopyTextureType == kTextureType2DMultisample;
34576
diff --git a/src/libANGLE/renderer/metal/shaders/format_autogen.h b/src/libANGLE/renderer/metal/shaders/format_autogen.h
34577
index a17ead3..b991e48 100644
34578
--- a/src/libANGLE/renderer/metal/shaders/format_autogen.h
34579
+++ b/src/libANGLE/renderer/metal/shaders/format_autogen.h
34580
@@ -245,5 +245,5 @@ enum
34581
 
34582
 }
34583
 
34584
-}  // namespace mtl_shader
34585
-}  // namespace rx
34586
+}
34587
+}
34588
diff --git a/src/libANGLE/renderer/metal/shaders/gen_indices.metal b/src/libANGLE/renderer/metal/shaders/gen_indices.metal
34589
index 2d8353b..eed61ea 100644
34590
--- a/src/libANGLE/renderer/metal/shaders/gen_indices.metal
34591
+++ b/src/libANGLE/renderer/metal/shaders/gen_indices.metal
34592
@@ -56,10 +56,10 @@ inline uint getIndexUnalignedU32(constant uchar *input, uint offset, uint idx)
34593
     return input0 | (input1 << 8) | (input2 << 16) | (input3 << 24);
34594
 }
34595
 
34596
-kernel void convertIndexU8ToU16(uint idx[[thread_position_in_grid]],
34597
-                                constant IndexConversionParams &options[[buffer(0)]],
34598
-                                constant uchar *input[[buffer(1)]],
34599
-                                device ushort *output[[buffer(2)]])
34600
+kernel void convertIndexU8ToU16(uint idx [[thread_position_in_grid]],
34601
+                                constant IndexConversionParams &options [[buffer(0)]],
34602
+                                constant uchar *input [[buffer(1)]],
34603
+                                device ushort *output [[buffer(2)]])
34604
 {
34605
     ANGLE_IDX_CONVERSION_GUARD(idx, options);
34606
 
34607
@@ -75,12 +75,13 @@ kernel void convertIndexU8ToU16(uint idx[[thread_position_in_grid]],
34608
     }
34609
 }
34610
 
34611
-kernel void convertIndexU16(
34612
-    uint idx[[thread_position_in_grid]],
34613
-    constant IndexConversionParams &options[[buffer(0)]],
34614
-    constant uchar *input[[ buffer(1), function_constant(kSourceBufferUnaligned) ]],
34615
-    constant ushort *inputAligned[[ buffer(1), function_constant(kSourceBufferAligned) ]],
34616
-    device ushort *output[[buffer(2)]])
34617
+kernel void convertIndexU16(uint idx [[thread_position_in_grid]],
34618
+                            constant IndexConversionParams &options [[buffer(0)]],
34619
+                            constant uchar *input
34620
+                            [[buffer(1), function_constant(kSourceBufferUnaligned)]],
34621
+                            constant ushort *inputAligned
34622
+                            [[buffer(1), function_constant(kSourceBufferAligned)]],
34623
+                            device ushort *output [[buffer(2)]])
34624
 {
34625
     ANGLE_IDX_CONVERSION_GUARD(idx, options);
34626
 
34627
@@ -96,12 +97,13 @@ kernel void convertIndexU16(
34628
     output[idx] = value;
34629
 }
34630
 
34631
-kernel void convertIndexU32(
34632
-    uint idx[[thread_position_in_grid]],
34633
-    constant IndexConversionParams &options[[buffer(0)]],
34634
-    constant uchar *input[[ buffer(1), function_constant(kSourceBufferUnaligned) ]],
34635
-    constant uint *inputAligned[[ buffer(1), function_constant(kSourceBufferAligned) ]],
34636
-    device uint *output[[buffer(2)]])
34637
+kernel void convertIndexU32(uint idx [[thread_position_in_grid]],
34638
+                            constant IndexConversionParams &options [[buffer(0)]],
34639
+                            constant uchar *input
34640
+                            [[buffer(1), function_constant(kSourceBufferUnaligned)]],
34641
+                            constant uint *inputAligned
34642
+                            [[buffer(1), function_constant(kSourceBufferAligned)]],
34643
+                            device uint *output [[buffer(2)]])
34644
 {
34645
     ANGLE_IDX_CONVERSION_GUARD(idx, options);
34646
 
34647
@@ -140,9 +142,9 @@ kernel void genTriFanIndicesFromArray(uint idx [[thread_position_in_grid]],
34648
 
34649
 inline uint getIndexU32(uint offset,
34650
                         uint idx,
34651
-                        constant uchar *inputU8[[function_constant(kUseSourceBufferU8)]],
34652
-                        constant ushort *inputU16[[function_constant(kUseSourceBufferU16)]],
34653
-                        constant uint *inputU32[[function_constant(kUseSourceBufferU32)]])
34654
+                        constant uchar *inputU8 [[function_constant(kUseSourceBufferU8)]],
34655
+                        constant ushort *inputU16 [[function_constant(kUseSourceBufferU16)]],
34656
+                        constant uint *inputU32 [[function_constant(kUseSourceBufferU32)]])
34657
 {
34658
     if (kUseSourceBufferU8)
34659
     {
34660
@@ -170,13 +172,15 @@ inline uint getIndexU32(uint offset,
34661
 // NOTE(hqle): triangle fan indices generation doesn't support primitive restart.
34662
 // Generate triangle fan indices from an indices buffer. indexCount options indicates number
34663
 // of indices starting from the 3rd.
34664
-kernel void genTriFanIndicesFromElements(
34665
-    uint idx[[thread_position_in_grid]],
34666
-    constant IndexConversionParams &options[[buffer(0)]],
34667
-    constant uchar *inputU8[[ buffer(1), function_constant(kUseSourceBufferU8) ]],
34668
-    constant ushort *inputU16[[ buffer(1), function_constant(kUseSourceBufferU16) ]],
34669
-    constant uint *inputU32[[ buffer(1), function_constant(kUseSourceBufferU32) ]],
34670
-    device uint *output[[buffer(2)]])
34671
+kernel void genTriFanIndicesFromElements(uint idx [[thread_position_in_grid]],
34672
+                                         constant IndexConversionParams &options [[buffer(0)]],
34673
+                                         constant uchar *inputU8
34674
+                                         [[buffer(1), function_constant(kUseSourceBufferU8)]],
34675
+                                         constant ushort *inputU16
34676
+                                         [[buffer(1), function_constant(kUseSourceBufferU16)]],
34677
+                                         constant uint *inputU32
34678
+                                         [[buffer(1), function_constant(kUseSourceBufferU32)]],
34679
+                                         device uint *output [[buffer(2)]])
34680
 {
34681
     ANGLE_IDX_CONVERSION_GUARD(idx, options);
34682
 
34683
diff --git a/src/libANGLE/renderer/metal/shaders/gen_mipmap.metal b/src/libANGLE/renderer/metal/shaders/gen_mipmap.metal
34684
index b3a3675..f2338b2 100644
34685
--- a/src/libANGLE/renderer/metal/shaders/gen_mipmap.metal
34686
+++ b/src/libANGLE/renderer/metal/shaders/gen_mipmap.metal
34687
@@ -23,8 +23,6 @@ using namespace rx::mtl_shader;
34688
 
34689
 #define TEXEL_LOAD(index) float4(sR[index], sG[index], sB[index], sA[index])
34690
 
34691
-#define TO_LINEAR(texel) (options.sRGB ? sRGBtoLinear(texel) : texel)
34692
-
34693
 #define OUT_OF_BOUND_CHECK(edgeValue, targetValue, condition) \
34694
     (condition) ? (edgeValue) : (targetValue)
34695
 
34696
@@ -32,7 +30,6 @@ struct GenMipParams
34697
 {
34698
     uint srcLevel;
34699
     uint numMipLevelsToGen;
34700
-    bool sRGB;
34701
 };
34702
 
34703
 // NOTE(hqle): For numMipLevelsToGen > 1, this function assumes the texture is power of two. If it
34704
@@ -83,10 +80,6 @@ kernel void generate3DMipmaps(uint lIndex [[thread_index_in_threadgroup]],
34705
     // ---- Second mip level --------
34706
 
34707
     // Write to shared memory
34708
-    if (options.sRGB)
34709
-    {
34710
-        texel1 = linearToSRGB(texel1);
34711
-    }
34712
     TEXEL_STORE(lIndex, texel1);
34713
 
34714
     threadgroup_barrier(mem_flags::mem_threadgroup);
34715
@@ -119,7 +112,7 @@ kernel void generate3DMipmaps(uint lIndex [[thread_index_in_threadgroup]],
34716
 
34717
         texel1 = (texel1 + texel2 + texel3 + texel4 + texel5 + texel6 + texel7 + texel8) / 8.0;
34718
 
34719
-        dstMip2.write(TO_LINEAR(texel1), gIndices >> 1);
34720
+        dstMip2.write(texel1, gIndices >> 1);
34721
 
34722
         // Write to shared memory
34723
         TEXEL_STORE(lIndex, texel1);
34724
@@ -165,7 +158,7 @@ kernel void generate3DMipmaps(uint lIndex [[thread_index_in_threadgroup]],
34725
 
34726
         texel1 = (texel1 + texel2 + texel3 + texel4 + texel5 + texel6 + texel7 + texel8) / 8.0;
34727
 
34728
-        dstMip3.write(TO_LINEAR(texel1), gIndices >> 2);
34729
+        dstMip3.write(texel1, gIndices >> 2);
34730
 
34731
         // Write to shared memory
34732
         TEXEL_STORE(lIndex, texel1);
34733
@@ -211,6 +204,348 @@ kernel void generate3DMipmaps(uint lIndex [[thread_index_in_threadgroup]],
34734
 
34735
         texel1 = (texel1 + texel2 + texel3 + texel4 + texel5 + texel6 + texel7 + texel8) / 8.0;
34736
 
34737
-        dstMip4.write(TO_LINEAR(texel1), gIndices >> 3);
34738
+        dstMip4.write(texel1, gIndices >> 3);
34739
+    }
34740
+}
34741
+
34742
+kernel void generate2DMipmaps(uint lIndex [[thread_index_in_threadgroup]],
34743
+                              ushort2 gIndices [[thread_position_in_grid]],
34744
+                              texture2d<float> srcTexture [[texture(0)]],
34745
+                              texture2d<float, access::write> dstMip1 [[texture(1)]],
34746
+                              texture2d<float, access::write> dstMip2 [[texture(2)]],
34747
+                              texture2d<float, access::write> dstMip3 [[texture(3)]],
34748
+                              texture2d<float, access::write> dstMip4 [[texture(4)]],
34749
+                              constant GenMipParams &options [[buffer(0)]])
34750
+{
34751
+    uint firstMipLevel = options.srcLevel + 1;
34752
+    ushort2 mipSize =
34753
+        ushort2(srcTexture.get_width(firstMipLevel), srcTexture.get_height(firstMipLevel));
34754
+    bool validThread = gIndices.x < mipSize.x && gIndices.y < mipSize.y;
34755
+
34756
+    constexpr sampler textureSampler(mag_filter::linear, min_filter::linear, mip_filter::linear);
34757
+
34758
+    // NOTE(hqle): Use simd_group function whenever available. That could avoid barrier use.
34759
+
34760
+    // Use struct of array style to avoid bank conflict.
34761
+    threadgroup float sR[kThreadGroupXY];
34762
+    threadgroup float sG[kThreadGroupXY];
34763
+    threadgroup float sB[kThreadGroupXY];
34764
+    threadgroup float sA[kThreadGroupXY];
34765
+
34766
+    // ----- First mip level -------
34767
+    float4 texel1;
34768
+    if (validThread)
34769
+    {
34770
+        float2 texCoords = (float2(gIndices) + float2(0.5, 0.5)) / float2(mipSize);
34771
+        texel1           = srcTexture.sample(textureSampler, texCoords, level(options.srcLevel));
34772
+
34773
+        // Write to texture
34774
+        dstMip1.write(texel1, gIndices);
34775
+    }
34776
+    else
34777
+    {
34778
+        // This will invalidate all subsequent checks
34779
+        lIndex = 0xffffffff;
34780
+    }
34781
+
34782
+    if (options.numMipLevelsToGen == 1)
34783
+    {
34784
+        return;
34785
+    }
34786
+
34787
+    // ---- Second mip level --------
34788
+
34789
+    // Write to shared memory
34790
+    TEXEL_STORE(lIndex, texel1);
34791
+
34792
+    threadgroup_barrier(mem_flags::mem_threadgroup);
34793
+
34794
+    // Index must be even
34795
+    if ((lIndex & 0x09) == 0)  // (lIndex & b001001) == 0
34796
+    {
34797
+        bool2 atEdge = gIndices == (mipSize - ushort2(1));
34798
+
34799
+        // (x+1, y)
34800
+        // If the width of mip is 1, texel2 will equal to texel1:
34801
+        float4 texel2 = OUT_OF_BOUND_CHECK(texel1, TEXEL_LOAD(lIndex + 1), atEdge.x);
34802
+        // (x, y+1)
34803
+        float4 texel3 = OUT_OF_BOUND_CHECK(texel1, TEXEL_LOAD(lIndex + kThreadGroupX), atEdge.y);
34804
+        // (x+1, y+1)
34805
+        float4 texel4 = OUT_OF_BOUND_CHECK(texel2, TEXEL_LOAD(lIndex + (kThreadGroupX + 1)),
34806
+                                           atEdge.x | atEdge.y);
34807
+
34808
+        texel1 = (texel1 + texel2 + texel3 + texel4) / 4.0;
34809
+
34810
+        dstMip2.write(texel1, gIndices >> 1);
34811
+
34812
+        // Write to shared memory
34813
+        TEXEL_STORE(lIndex, texel1);
34814
+    }
34815
+
34816
+    if (options.numMipLevelsToGen == 2)
34817
+    {
34818
+        return;
34819
+    }
34820
+
34821
+    // ---- 3rd mip level --------
34822
+    threadgroup_barrier(mem_flags::mem_threadgroup);
34823
+
34824
+    // Index must be multiple of 4
34825
+    if ((lIndex & 0x1b) == 0)  // (lIndex & b011011) == 0
34826
+    {
34827
+        mipSize      = max(mipSize >> 1, ushort2(1));
34828
+        bool2 atEdge = (gIndices >> 1) == (mipSize - ushort2(1));
34829
+
34830
+        // (x+1, y)
34831
+        // If the width of mip is 1, texel2 will equal to texel1:
34832
+        float4 texel2 = OUT_OF_BOUND_CHECK(texel1, TEXEL_LOAD(lIndex + 2), atEdge.x);
34833
+        // (x, y+1)
34834
+        float4 texel3 =
34835
+            OUT_OF_BOUND_CHECK(texel1, TEXEL_LOAD(lIndex + 2 * kThreadGroupX), atEdge.y);
34836
+        // (x+1, y+1)
34837
+        float4 texel4 = OUT_OF_BOUND_CHECK(texel2, TEXEL_LOAD(lIndex + (2 * kThreadGroupX + 2)),
34838
+                                           atEdge.x | atEdge.y);
34839
+
34840
+        texel1 = (texel1 + texel2 + texel3 + texel4) / 4.0;
34841
+
34842
+        dstMip3.write(texel1, gIndices >> 2);
34843
+
34844
+        // Write to shared memory
34845
+        TEXEL_STORE(lIndex, texel1);
34846
+    }
34847
+
34848
+    if (options.numMipLevelsToGen == 3)
34849
+    {
34850
+        return;
34851
+    }
34852
+
34853
+    // ---- 4th mip level --------
34854
+    threadgroup_barrier(mem_flags::mem_threadgroup);
34855
+
34856
+    // Index must be multiple of 8
34857
+    if ((lIndex & 0x3f) == 0)  // (lIndex & b111111) == 0
34858
+    {
34859
+        mipSize      = max(mipSize >> 1, ushort2(1));
34860
+        bool2 atEdge = (gIndices >> 2) == (mipSize - ushort2(1));
34861
+
34862
+        // (x+1, y)
34863
+        // If the width of mip is 1, texel2 will equal to texel1:
34864
+        float4 texel2 = OUT_OF_BOUND_CHECK(texel1, TEXEL_LOAD(lIndex + 4), atEdge.x);
34865
+        // (x, y+1)
34866
+        float4 texel3 =
34867
+            OUT_OF_BOUND_CHECK(texel1, TEXEL_LOAD(lIndex + 4 * kThreadGroupX), atEdge.y);
34868
+        // (x+1, y+1)
34869
+        float4 texel4 = OUT_OF_BOUND_CHECK(texel2, TEXEL_LOAD(lIndex + (4 * kThreadGroupX + 4)),
34870
+                                           atEdge.x | atEdge.y);
34871
+
34872
+        texel1 = (texel1 + texel2 + texel3 + texel4) / 4.0;
34873
+
34874
+        dstMip4.write(texel1, gIndices >> 3);
34875
+    }
34876
+}
34877
+
34878
+template <typename TextureTypeR, typename TextureTypeW>
34879
+static __attribute__((always_inline)) void generateCubeOr2DArray2ndAndMoreMipmaps(
34880
+    uint lIndex,
34881
+    ushort3 gIndices,
34882
+    TextureTypeR srcTexture,
34883
+    TextureTypeW dstMip2,
34884
+    TextureTypeW dstMip3,
34885
+    TextureTypeW dstMip4,
34886
+    ushort2 mip1Size,
34887
+    float4 mip1Texel,
34888
+    threadgroup float *sR,
34889
+    threadgroup float *sG,
34890
+    threadgroup float *sB,
34891
+    threadgroup float *sA,
34892
+    constant GenMipParams &options)
34893
+{
34894
+    ushort2 mipSize = mip1Size;
34895
+    float4 texel1   = mip1Texel;
34896
+
34897
+    // ---- Second mip level --------
34898
+
34899
+    // Write to shared memory
34900
+    TEXEL_STORE(lIndex, texel1);
34901
+
34902
+    threadgroup_barrier(mem_flags::mem_threadgroup);
34903
+
34904
+    // Index must be even
34905
+    if ((lIndex & 0x09) == 0)  // (lIndex & b001001) == 0
34906
+    {
34907
+        bool2 atEdge = gIndices.xy == (mipSize - ushort2(1));
34908
+
34909
+        // (x+1, y)
34910
+        // If the width of mip is 1, texel2 will equal to texel1:
34911
+        float4 texel2 = OUT_OF_BOUND_CHECK(texel1, TEXEL_LOAD(lIndex + 1), atEdge.x);
34912
+        // (x, y+1)
34913
+        float4 texel3 = OUT_OF_BOUND_CHECK(texel1, TEXEL_LOAD(lIndex + kThreadGroupX), atEdge.y);
34914
+        // (x+1, y+1)
34915
+        float4 texel4 = OUT_OF_BOUND_CHECK(texel2, TEXEL_LOAD(lIndex + (kThreadGroupX + 1)),
34916
+                                           atEdge.x | atEdge.y);
34917
+
34918
+        texel1 = (texel1 + texel2 + texel3 + texel4) / 4.0;
34919
+
34920
+        dstMip2.write(texel1, gIndices.xy >> 1, gIndices.z);
34921
+
34922
+        // Write to shared memory
34923
+        TEXEL_STORE(lIndex, texel1);
34924
+    }
34925
+
34926
+    if (options.numMipLevelsToGen == 2)
34927
+    {
34928
+        return;
34929
+    }
34930
+
34931
+    // ---- 3rd mip level --------
34932
+    threadgroup_barrier(mem_flags::mem_threadgroup);
34933
+
34934
+    // Index must be multiple of 4
34935
+    if ((lIndex & 0x1b) == 0)  // (lIndex & b011011) == 0
34936
+    {
34937
+        mipSize      = max(mipSize >> 1, ushort2(1));
34938
+        bool2 atEdge = (gIndices.xy >> 1) == (mipSize - ushort2(1));
34939
+
34940
+        // (x+1, y)
34941
+        // If the width of mip is 1, texel2 will equal to texel1:
34942
+        float4 texel2 = OUT_OF_BOUND_CHECK(texel1, TEXEL_LOAD(lIndex + 2), atEdge.x);
34943
+        // (x, y+1)
34944
+        float4 texel3 =
34945
+            OUT_OF_BOUND_CHECK(texel1, TEXEL_LOAD(lIndex + 2 * kThreadGroupX), atEdge.y);
34946
+        // (x+1, y+1)
34947
+        float4 texel4 = OUT_OF_BOUND_CHECK(texel2, TEXEL_LOAD(lIndex + (2 * kThreadGroupX + 2)),
34948
+                                           atEdge.x | atEdge.y);
34949
+
34950
+        texel1 = (texel1 + texel2 + texel3 + texel4) / 4.0;
34951
+
34952
+        dstMip3.write(texel1, gIndices.xy >> 2, gIndices.z);
34953
+
34954
+        // Write to shared memory
34955
+        TEXEL_STORE(lIndex, texel1);
34956
     }
34957
+
34958
+    if (options.numMipLevelsToGen == 3)
34959
+    {
34960
+        return;
34961
+    }
34962
+
34963
+    // ---- 4th mip level --------
34964
+    threadgroup_barrier(mem_flags::mem_threadgroup);
34965
+
34966
+    // Index must be multiple of 8
34967
+    if ((lIndex & 0x3f) == 0)  // (lIndex & b111111) == 0
34968
+    {
34969
+        mipSize      = max(mipSize >> 1, ushort2(1));
34970
+        bool2 atEdge = (gIndices.xy >> 2) == (mipSize - ushort2(1));
34971
+
34972
+        // (x+1, y)
34973
+        // If the width of mip is 1, texel2 will equal to texel1:
34974
+        float4 texel2 = OUT_OF_BOUND_CHECK(texel1, TEXEL_LOAD(lIndex + 4), atEdge.x);
34975
+        // (x, y+1)
34976
+        float4 texel3 =
34977
+            OUT_OF_BOUND_CHECK(texel1, TEXEL_LOAD(lIndex + 4 * kThreadGroupX), atEdge.y);
34978
+        // (x+1, y+1)
34979
+        float4 texel4 = OUT_OF_BOUND_CHECK(texel2, TEXEL_LOAD(lIndex + (4 * kThreadGroupX + 4)),
34980
+                                           atEdge.x | atEdge.y);
34981
+
34982
+        texel1 = (texel1 + texel2 + texel3 + texel4) / 4.0;
34983
+
34984
+        dstMip4.write(texel1, gIndices.xy >> 3, gIndices.z);
34985
+    }
34986
+}
34987
+
34988
+kernel void generateCubeMipmaps(uint lIndex [[thread_index_in_threadgroup]],
34989
+                                ushort3 gIndices [[thread_position_in_grid]],
34990
+                                texturecube<float> srcTexture [[texture(0)]],
34991
+                                texturecube<float, access::write> dstMip1 [[texture(1)]],
34992
+                                texturecube<float, access::write> dstMip2 [[texture(2)]],
34993
+                                texturecube<float, access::write> dstMip3 [[texture(3)]],
34994
+                                texturecube<float, access::write> dstMip4 [[texture(4)]],
34995
+                                constant GenMipParams &options [[buffer(0)]])
34996
+{
34997
+    uint firstMipLevel = options.srcLevel + 1;
34998
+    ushort2 mip1Size =
34999
+        ushort2(srcTexture.get_width(firstMipLevel), srcTexture.get_height(firstMipLevel));
35000
+    bool validThread = gIndices.x < mip1Size.x && gIndices.y < mip1Size.y;
35001
+
35002
+    constexpr sampler textureSampler(mag_filter::linear, min_filter::linear, mip_filter::linear);
35003
+
35004
+    // ----- First mip level -------
35005
+    float4 mip1Texel;
35006
+    if (validThread)
35007
+    {
35008
+        float2 texCoords = (float2(gIndices.xy) + float2(0.5, 0.5)) / float2(mip1Size);
35009
+        mip1Texel = srcTexture.sample(textureSampler, cubeTexcoords(texCoords, int(gIndices.z)),
35010
+                                      level(options.srcLevel));
35011
+
35012
+        // Write to texture
35013
+        dstMip1.write(mip1Texel, gIndices.xy, gIndices.z);
35014
+    }
35015
+    else
35016
+    {
35017
+        // This will invalidate all subsequent checks
35018
+        lIndex = 0xffffffff;
35019
+    }
35020
+
35021
+    if (options.numMipLevelsToGen == 1)
35022
+    {
35023
+        return;
35024
+    }
35025
+
35026
+    // Use struct of array style to avoid bank conflict.
35027
+    threadgroup float sR[kThreadGroupXY];
35028
+    threadgroup float sG[kThreadGroupXY];
35029
+    threadgroup float sB[kThreadGroupXY];
35030
+    threadgroup float sA[kThreadGroupXY];
35031
+
35032
+    generateCubeOr2DArray2ndAndMoreMipmaps(lIndex, gIndices, srcTexture, dstMip2, dstMip3, dstMip4,
35033
+                                           mip1Size, mip1Texel, sR, sG, sB, sA, options);
35034
+}
35035
+
35036
+kernel void generate2DArrayMipmaps(uint lIndex [[thread_index_in_threadgroup]],
35037
+                                   ushort3 gIndices [[thread_position_in_grid]],
35038
+                                   texture2d_array<float> srcTexture [[texture(0)]],
35039
+                                   texture2d_array<float, access::write> dstMip1 [[texture(1)]],
35040
+                                   texture2d_array<float, access::write> dstMip2 [[texture(2)]],
35041
+                                   texture2d_array<float, access::write> dstMip3 [[texture(3)]],
35042
+                                   texture2d_array<float, access::write> dstMip4 [[texture(4)]],
35043
+                                   constant GenMipParams &options [[buffer(0)]])
35044
+{
35045
+    uint firstMipLevel = options.srcLevel + 1;
35046
+    ushort2 mip1Size =
35047
+        ushort2(srcTexture.get_width(firstMipLevel), srcTexture.get_height(firstMipLevel));
35048
+    bool validThread = gIndices.x < mip1Size.x && gIndices.y < mip1Size.y;
35049
+
35050
+    constexpr sampler textureSampler(mag_filter::linear, min_filter::linear, mip_filter::linear);
35051
+
35052
+    // ----- First mip level -------
35053
+    float4 mip1Texel;
35054
+    if (validThread)
35055
+    {
35056
+        float2 texCoords = (float2(gIndices.xy) + float2(0.5, 0.5)) / float2(mip1Size);
35057
+        mip1Texel =
35058
+            srcTexture.sample(textureSampler, texCoords, gIndices.z, level(options.srcLevel));
35059
+
35060
+        // Write to texture
35061
+        dstMip1.write(mip1Texel, gIndices.xy, gIndices.z);
35062
+    }
35063
+    else
35064
+    {
35065
+        // This will invalidate all subsequent checks
35066
+        lIndex = 0xffffffff;
35067
+    }
35068
+
35069
+    if (options.numMipLevelsToGen == 1)
35070
+    {
35071
+        return;
35072
+    }
35073
+
35074
+    // Use struct of array style to avoid bank conflict.
35075
+    threadgroup float sR[kThreadGroupXY];
35076
+    threadgroup float sG[kThreadGroupXY];
35077
+    threadgroup float sB[kThreadGroupXY];
35078
+    threadgroup float sA[kThreadGroupXY];
35079
+
35080
+    generateCubeOr2DArray2ndAndMoreMipmaps(lIndex, gIndices, srcTexture, dstMip2, dstMip3, dstMip4,
35081
+                                           mip1Size, mip1Texel, sR, sG, sB, sA, options);
35082
 }
35083
diff --git a/src/libANGLE/renderer/metal/shaders/visibility.metal b/src/libANGLE/renderer/metal/shaders/visibility.metal
35084
index 905c196..ad5860f 100644
35085
--- a/src/libANGLE/renderer/metal/shaders/visibility.metal
35086
+++ b/src/libANGLE/renderer/metal/shaders/visibility.metal
35087
@@ -6,7 +6,7 @@
35088
 
35089
 #include "common.h"
35090
 
35091
-constant bool kCombineWithExistingResult [[function_constant(1000)]];
35092
+constant bool kCombineWithExistingResult [[function_constant(1)]];
35093
 
35094
 // Combine the visibility result of current render pass with previous value from previous render
35095
 // pass
35096
diff --git a/src/libGLESv2/entry_points_egl.cpp b/src/libGLESv2/entry_points_egl.cpp
35097
index 755bd61..7d5ac58 100644
35098
--- a/src/libGLESv2/entry_points_egl.cpp
35099
+++ b/src/libGLESv2/entry_points_egl.cpp
35100
@@ -428,8 +428,6 @@ EGLBoolean EGLAPIENTRY EGL_DestroyContext(EGLDisplay dpy, EGLContext ctx)
35101
 
35102
     if (contextWasCurrent)
35103
     {
35104
-        ANGLE_EGL_TRY_RETURN(thread, display->makeCurrent(context, nullptr, nullptr, nullptr),
35105
-                             "eglDestroyContext", GetContextIfValid(display, context), EGL_FALSE);
35106
         SetContextCurrent(thread, nullptr);
35107
     }
35108
 
35109
@@ -466,8 +464,8 @@ EGLBoolean EGLAPIENTRY EGL_MakeCurrent(EGLDisplay dpy,
35110
     // Only call makeCurrent if the context or surfaces have changed.
35111
     if (previousDraw != drawSurface || previousRead != readSurface || previousContext != context)
35112
     {
35113
-        ANGLE_EGL_TRY_RETURN(
35114
-            thread, display->makeCurrent(previousContext, drawSurface, readSurface, context),
35115
+        ANGLE_EGL_TRY_RETURN(thread,
35116
+                             display->makeCurrent(thread, drawSurface, readSurface, context),
35117
                              "eglMakeCurrent", GetContextIfValid(display, context), EGL_FALSE);
35118
 
35119
         SetContextCurrent(thread, context);
35120
@@ -818,8 +816,8 @@ EGLBoolean EGLAPIENTRY EGL_ReleaseThread(void)
35121
         if (previousDraw != EGL_NO_SURFACE || previousRead != EGL_NO_SURFACE ||
35122
             previousContext != EGL_NO_CONTEXT)
35123
         {
35124
-            ANGLE_EGL_TRY_RETURN(
35125
-                thread, previousDisplay->makeCurrent(previousContext, nullptr, nullptr, nullptr),
35126
+            ANGLE_EGL_TRY_RETURN(thread,
35127
+                                 previousDisplay->makeCurrent(thread, nullptr, nullptr, nullptr),
35128
                                  "eglReleaseThread", nullptr, EGL_FALSE);
35129
         }
35130
         ANGLE_EGL_TRY_RETURN(thread, previousDisplay->releaseThread(), "eglReleaseThread",
35131
diff --git a/src/tests/deqp_support/deqp_egl_test_expectations.txt b/src/tests/deqp_support/deqp_egl_TestExpectations
35132
similarity index 100%
35133
rename from src/tests/deqp_support/deqp_egl_test_expectations.txt
35134
rename to src/tests/deqp_support/deqp_egl_TestExpectations
35135
diff --git a/src/tests/deqp_support/deqp_gles2_test_expectations.txt b/src/tests/deqp_support/deqp_gles2_TestExpectations
35136
similarity index 100%
35137
rename from src/tests/deqp_support/deqp_gles2_test_expectations.txt
35138
rename to src/tests/deqp_support/deqp_gles2_TestExpectations
35139
diff --git a/src/tests/deqp_support/deqp_gles31_test_expectations.txt b/src/tests/deqp_support/deqp_gles31_TestExpectations
35140
similarity index 100%
35141
rename from src/tests/deqp_support/deqp_gles31_test_expectations.txt
35142
rename to src/tests/deqp_support/deqp_gles31_TestExpectations
35143
diff --git a/src/tests/deqp_support/deqp_gles31_rotate_test_expectations.txt b/src/tests/deqp_support/deqp_gles31_rotate_TestExpectations
35144
similarity index 100%
35145
rename from src/tests/deqp_support/deqp_gles31_rotate_test_expectations.txt
35146
rename to src/tests/deqp_support/deqp_gles31_rotate_TestExpectations
35147
diff --git a/src/tests/deqp_support/deqp_gles3_test_expectations.txt b/src/tests/deqp_support/deqp_gles3_TestExpectations
35148
similarity index 100%
35149
rename from src/tests/deqp_support/deqp_gles3_test_expectations.txt
35150
rename to src/tests/deqp_support/deqp_gles3_TestExpectations
35151
diff --git a/src/tests/deqp_support/deqp_gles3_rotate_test_expectations.txt b/src/tests/deqp_support/deqp_gles3_rotate_TestExpectations
35152
similarity index 100%
35153
rename from src/tests/deqp_support/deqp_gles3_rotate_test_expectations.txt
35154
rename to src/tests/deqp_support/deqp_gles3_rotate_TestExpectations
35155
diff --git a/src/tests/deqp_support/deqp_khr_gles2_test_expectations.txt b/src/tests/deqp_support/deqp_khr_gles2_TestExpectations
35156
similarity index 100%
35157
rename from src/tests/deqp_support/deqp_khr_gles2_test_expectations.txt
35158
rename to src/tests/deqp_support/deqp_khr_gles2_TestExpectations
35159
diff --git a/src/tests/deqp_support/deqp_khr_gles31_test_expectations.txt b/src/tests/deqp_support/deqp_khr_gles31_TestExpectations
35160
similarity index 100%
35161
rename from src/tests/deqp_support/deqp_khr_gles31_test_expectations.txt
35162
rename to src/tests/deqp_support/deqp_khr_gles31_TestExpectations
35163
diff --git a/src/tests/deqp_support/deqp_khr_gles3_test_expectations.txt b/src/tests/deqp_support/deqp_khr_gles3_TestExpectations
35164
similarity index 100%
35165
rename from src/tests/deqp_support/deqp_khr_gles3_test_expectations.txt
35166
rename to src/tests/deqp_support/deqp_khr_gles3_TestExpectations
- a/Source/ThirdParty/ANGLE/include/GLSLANG/ShaderLang.h +3 lines
Lines 73-78 enum ShShaderOutput a/Source/ThirdParty/ANGLE/include/GLSLANG/ShaderLang.h_sec1
73
    // Output specialized GLSL to be fed to glslang for Vulkan SPIR to be cross compiled to Metal
73
    // Output specialized GLSL to be fed to glslang for Vulkan SPIR to be cross compiled to Metal
74
    // later.
74
    // later.
75
    SH_GLSL_METAL_OUTPUT = 0x8B4C,
75
    SH_GLSL_METAL_OUTPUT = 0x8B4C,
76
77
    // Output for MSL
78
    SH_MSL_METAL_OUTPUT = 0x8B4D,
76
};
79
};
77
80
78
// Compile options.
81
// Compile options.
- a/Source/ThirdParty/ANGLE/include/platform/FeaturesMtl.h -7 / +39 lines
Lines 27-33 struct FeaturesMtl : FeatureSetBase a/Source/ThirdParty/ANGLE/include/platform/FeaturesMtl.h_sec1
27
        "The renderer supports depth texture's filtering other than nearest", &members};
27
        "The renderer supports depth texture's filtering other than nearest", &members};
28
28
29
    // Support explicit memory barrier
29
    // Support explicit memory barrier
30
    Feature hasExplicitMemBarrier = {"has_explicit_mem_barrier_mtl", FeatureCategory::MetalFeatures,
30
    Feature hasExplicitMemBarrier = {"has_explicit_mem_barrier", FeatureCategory::MetalFeatures,
31
                                     "The renderer supports explicit memory barrier", &members};
31
                                     "The renderer supports explicit memory barrier", &members};
32
32
33
    // Some renderer can break render pass cheaply, i.e. desktop class GPUs.
33
    // Some renderer can break render pass cheaply, i.e. desktop class GPUs.
Lines 40-46 struct FeaturesMtl : FeatureSetBase a/Source/ThirdParty/ANGLE/include/platform/FeaturesMtl.h_sec2
40
        "The renderer supports non uniform compute shader dispatch's group size", &members};
40
        "The renderer supports non uniform compute shader dispatch's group size", &members};
41
41
42
    // fragment stencil output support
42
    // fragment stencil output support
43
    Feature hasStencilOutput = {"has_shader_stencil_output", FeatureCategory::MetalFeatures,
43
    Feature hasStencilOutput = {"has_stencil_output", FeatureCategory::MetalFeatures,
44
                                "The renderer supports stencil output from fragment shader",
44
                                "The renderer supports stencil output from fragment shader",
45
                                &members};
45
                                &members};
46
46
Lines 59-64 struct FeaturesMtl : FeatureSetBase a/Source/ThirdParty/ANGLE/include/platform/FeaturesMtl.h_sec3
59
    Feature hasEvents = {"has_mtl_events", FeatureCategory::MetalFeatures,
59
    Feature hasEvents = {"has_mtl_events", FeatureCategory::MetalFeatures,
60
                         "The renderer supports MTL(Shared)Event", &members};
60
                         "The renderer supports MTL(Shared)Event", &members};
61
61
62
    Feature allowInlineConstVertexData = {
63
        "allow_inline_const_vertex_data", FeatureCategory::MetalFeatures,
64
        "The renderer supports using inline constant data for small client vertex data", &members};
65
62
    // On macos, separate depth & stencil buffers are not supproted. However, on iOS devices,
66
    // On macos, separate depth & stencil buffers are not supproted. However, on iOS devices,
63
    // they are supproted:
67
    // they are supproted:
64
    Feature allowSeparatedDepthStencilBuffers = {
68
    Feature allowSeparatedDepthStencilBuffers = {
Lines 67-72 struct FeaturesMtl : FeatureSetBase a/Source/ThirdParty/ANGLE/include/platform/FeaturesMtl.h_sec4
67
        "whereas others such as macOS don't",
71
        "whereas others such as macOS don't",
68
        &members};
72
        &members};
69
73
74
    Feature allowRuntimeSamplerCompareMode = {
75
        "allow_runtime_sampler_compare_mode", FeatureCategory::MetalFeatures,
76
        "The renderer supports changing sampler's compare mode outside shaders", &members};
77
78
    Feature allowSamplerCompareGradient = {
79
        "allow_sampler_compare_gradient", FeatureCategory::MetalFeatures,
80
        "The renderer supports sample_compare with gradients", &members};
81
82
    Feature allowSamplerCompareLod = {"allow_sampler_compare_lod", FeatureCategory::MetalFeatures,
83
                                      "The renderer supports sample_compare with lod", &members};
84
85
    Feature allowBufferReadWrite = {"allow_buffer_read_write", FeatureCategory::MetalFeatures,
86
                                    "The renderer supports buffer read & write in the same shader",
87
                                    &members};
88
70
    Feature allowMultisampleStoreAndResolve = {
89
    Feature allowMultisampleStoreAndResolve = {
71
        "allow_msaa_store_and_resolve", FeatureCategory::MetalFeatures,
90
        "allow_msaa_store_and_resolve", FeatureCategory::MetalFeatures,
72
        "The renderer supports MSAA store and resolve in the same pass", &members};
91
        "The renderer supports MSAA store and resolve in the same pass", &members};
Lines 75-88 struct FeaturesMtl : FeatureSetBase a/Source/ThirdParty/ANGLE/include/platform/FeaturesMtl.h_sec5
75
        "gen_multiple_mips_per_pass", FeatureCategory::MetalFeatures,
94
        "gen_multiple_mips_per_pass", FeatureCategory::MetalFeatures,
76
        "The renderer supports generating multiple mipmaps per pass", &members};
95
        "The renderer supports generating multiple mipmaps per pass", &members};
77
96
97
    Feature forceD24S8AsUnsupported = {"force_d24s8_as_unsupported", FeatureCategory::MetalFeatures,
98
                                       "Force Depth24Stencil8 format as unsupported.", &members};
99
100
    Feature breakRenderPassIsCheap = {"break_render_pass_is_cheap", FeatureCategory::MetalFeatures,
101
                                      "Breaking render pass is a cheap operation", &members};
102
78
    Feature forceBufferGPUStorage = {
103
    Feature forceBufferGPUStorage = {
79
        "force_buffer_gpu_storage_mtl", FeatureCategory::MetalFeatures,
104
        "force_buffer_gpu_storage", FeatureCategory::MetalFeatures,
80
        "On systems that support both buffer's memory allocation on GPU and shared memory (such as "
105
        "On systems that support both buffer' memory allocation on GPU and shared memory (such as "
81
        "macOS), force using GPU memory allocation for buffers.",
106
        "macOS), force using GPU memory allocation for buffers everytime or not.",
82
        &members};
107
        &members};
83
108
84
    Feature forceD24S8AsUnsupported = {"force_d24s8_as_unsupported", FeatureCategory::MetalFeatures,
109
    Feature forceNonCSBaseMipmapGeneration = {
85
                                       "Force Depth24Stencil8 format as unsupported.", &members};
110
        "force_non_cs_mipmap_gen", FeatureCategory::MetalFeatures,
111
        "Turn this feature on to disallow Compute Shader based mipmap generation. Compute Shader "
112
        "based mipmap generation might cause GPU hang on some older iOS devices.",
113
        &members};
114
115
    Feature emulateTransformFeedback = {
116
        "emulate_transform_feedback", FeatureCategory::MetalFeatures,
117
        "Turn this on to allow transform feedback in Metal using a 2-pass VS for GLES3.", &members};
86
};
118
};
87
119
88
}  // namespace angle
120
}  // namespace angle
- a/Source/ThirdParty/ANGLE/src/common/PoolAlloc.cpp -1 / +1 lines
Lines 335-341 void PoolAllocator::unlock() a/Source/ThirdParty/ANGLE/src/common/PoolAlloc.cpp_sec1
335
void Allocation::checkAllocList() const
335
void Allocation::checkAllocList() const
336
{
336
{
337
    for (const Allocation *alloc = this; alloc != 0; alloc = alloc->mPrevAlloc)
337
    for (const Allocation *alloc = this; alloc != 0; alloc = alloc->mPrevAlloc)
338
        alloc->check();
338
        alloc->checkAlloc();
339
}
339
}
340
340
341
}  // namespace angle
341
}  // namespace angle
- a/Source/ThirdParty/ANGLE/src/common/PoolAlloc.h -1 / +1 lines
Lines 65-71 class Allocation a/Source/ThirdParty/ANGLE/src/common/PoolAlloc.h_sec1
65
#endif
65
#endif
66
    }
66
    }
67
67
68
    void check() const
68
    void checkAlloc() const
69
    {
69
    {
70
        checkGuardBlock(preGuard(), kGuardBlockBeginVal, "before");
70
        checkGuardBlock(preGuard(), kGuardBlockBeginVal, "before");
71
        checkGuardBlock(postGuard(), kGuardBlockEndVal, "after");
71
        checkGuardBlock(postGuard(), kGuardBlockEndVal, "after");
- a/Source/ThirdParty/ANGLE/src/common/apple_platform_utils.h -4 / +12 lines
Lines 15-38 a/Source/ThirdParty/ANGLE/src/common/apple_platform_utils.h_sec1
15
15
16
// TARGET_OS_MACCATALYST only available in MacSDK 10.15
16
// TARGET_OS_MACCATALYST only available in MacSDK 10.15
17
17
18
#if TARGET_OS_MACCATALYST
18
// ANGLE_APPLE_AVAILABLE_XCI: check if either of the 3 platforms (OSX/Catalyst/iOS) min verions is
19
// ANGLE_APPLE_AVAILABLE_XCI: check if either of the 3 platforms (OSX/Catalyst/iOS) min verions is
19
// available:
20
// available:
20
#if TARGET_OS_MACCATALYST
21
#    define ANGLE_APPLE_AVAILABLE_XCI(macVer, macCatalystVer, iOSVer) \
21
#    define ANGLE_APPLE_AVAILABLE_XCI(macVer, macCatalystVer, iOSVer) \
22
        @available(macOS macVer, macCatalyst macCatalystVer, iOS iOSVer, *)
22
        @available(macOS macVer, macCatalyst macCatalystVer, iOS iOSVer, *)
23
// ANGLE_APPLE_AVAILABLE_XC: check if either of the 2 platforms (OSX/Catalyst) min verions is
23
// ANGLE_APPLE_AVAILABLE_XC: check if either of the 2 platforms (OSX/Catalyst) min verions is
24
// available:
24
// available:
25
#    define ANGLE_APPLE_AVAILABLE_XC(macVer, macCatalystVer) \
25
#    define ANGLE_APPLE_AVAILABLE_XC(macVer, macCatalystVer) \
26
        @available(macOS macVer, macCatalyst macCatalystVer, *)
26
        @available(macOS macVer, macCatalyst macCatalystVer, *)
27
// ANGLE_APPLE_AVAILABLE_CI: check if either of the 2 platforms (Catalyst/iOS) min verions is
28
// available:
29
#    define ANGLE_APPLE_AVAILABLE_CI(macCatalystVer, iOSVer) \
30
        @available(macCatalyst macCatalystVer, iOS iOSVer, *)
27
#else
31
#else
28
#    define ANGLE_APPLE_AVAILABLE_XCI(macVer, macCatalystVer, iOSVer) \
32
#    define ANGLE_APPLE_AVAILABLE_XCI(macVer, macCatalystVer, iOSVer) \
29
        ANGLE_APPLE_AVAILABLE_XI(macVer, iOSVer)
33
        ANGLE_APPLE_AVAILABLE_XI(macVer, iOSVer)
30
// ANGLE_APPLE_AVAILABLE_XC: check if either of the 2 platforms (OSX/Catalyst) min verions is
34
31
// available:
32
#    define ANGLE_APPLE_AVAILABLE_XC(macVer, macCatalystVer) @available(macOS macVer, *)
35
#    define ANGLE_APPLE_AVAILABLE_XC(macVer, macCatalystVer) @available(macOS macVer, *)
36
#    define ANGLE_APPLE_AVAILABLE_CI(macCatalystVer, iOSVer) @available(iOS iOSVer, tvOS iOSVer, *)
33
#endif
37
#endif
34
38
35
// ANGLE_APPLE_AVAILABLE_XI: check if either of the 2 platforms (OSX/iOS) min verions is available:
39
// ANGLE_APPLE_AVAILABLE_XI: check if either of the 2 platforms (OSX/iOS) min verions is available:
36
#define ANGLE_APPLE_AVAILABLE_XI(macVer, iOSVer) @available(macOS macVer, iOS iOSVer, *)
40
#define ANGLE_APPLE_AVAILABLE_XI(macVer, iOSVer) \
41
    @available(macOS macVer, iOS iOSVer, tvOS iOSVer, *)
42
43
// ANGLE_APPLE_AVAILABLE_I: check if a particular iOS version is available
44
#define ANGLE_APPLE_AVAILABLE_I(iOSVer) @available(iOS iOSVer, tvOS iOSVer, *)
37
45
38
#endif
46
#endif
- a/Source/ThirdParty/ANGLE/src/common/debug.h -4 / +10 lines
Lines 313-322 std::ostream &FmtHex(std::ostream &os, T value) a/Source/ThirdParty/ANGLE/src/common/debug.h_sec1
313
313
314
// A macro asserting a condition and outputting failures to the debug log
314
// A macro asserting a condition and outputting failures to the debug log
315
#if defined(ANGLE_ENABLE_ASSERTS)
315
#if defined(ANGLE_ENABLE_ASSERTS)
316
#    define ASSERT(expression)                                                                \
316
#    define ASSERT(expression)                                                  \
317
        (expression ? static_cast<void>(0)                                                    \
317
        do                                                                      \
318
                    : (FATAL() << "\t! Assert failed in " << __FUNCTION__ << " (" << __FILE__ \
318
        {                                                                       \
319
                               << ":" << __LINE__ << "): " << #expression))
319
            if (!(expression))                                                  \
320
            {                                                                   \
321
                __builtin_debugtrap();                                          \
322
            }                                                                   \
323
            int x = 0; /* This forces sane breakpoint location at call site. */ \
324
            (void)x;                                                            \
325
        } while (false)
320
#else
326
#else
321
#    define ASSERT(condition) ANGLE_EAT_STREAM_PARAMETERS << !(condition)
327
#    define ASSERT(condition) ANGLE_EAT_STREAM_PARAMETERS << !(condition)
322
#endif  // defined(ANGLE_ENABLE_ASSERTS)
328
#endif  // defined(ANGLE_ENABLE_ASSERTS)
- a/Source/ThirdParty/ANGLE/src/common/platform.h -1 / +6 lines
Lines 132-142 a/Source/ThirdParty/ANGLE/src/common/platform.h_sec1
132
#    if defined(__arm64__) || defined(__aarch64__)
132
#    if defined(__arm64__) || defined(__aarch64__)
133
#        define ANGLE_CPU_ARM64 1
133
#        define ANGLE_CPU_ARM64 1
134
#    endif
134
#    endif
135
// EAGL should be enabled on iOS, but not Mac Catalyst unless it is running on Apple Silicon.
135
#    // EAGL should be enabled on iOS, but not Mac Catalyst unless it is running on Apple Silicon.
136
#    if (defined(ANGLE_PLATFORM_IOS) && !defined(ANGLE_PLATFORM_MACCATALYST)) || \
136
#    if (defined(ANGLE_PLATFORM_IOS) && !defined(ANGLE_PLATFORM_MACCATALYST)) || \
137
        (defined(ANGLE_PLATFORM_MACCATALYST) && defined(ANGLE_CPU_ARM64))
137
        (defined(ANGLE_PLATFORM_MACCATALYST) && defined(ANGLE_CPU_ARM64))
138
#        define ANGLE_ENABLE_EAGL
138
#        define ANGLE_ENABLE_EAGL
139
#    endif
139
#    endif
140
#    // Identify Metal API >= what shipped on macOS Catalina.
141
#    if (defined(ANGLE_PLATFORM_MACOS) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 101500) || \
142
        (defined(ANGLE_PLATFORM_IOS) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000)
143
#        define ANGLE_WITH_MODERN_METAL_API 1
144
#    endif
140
#endif
145
#endif
141
146
142
// Define ANGLE_WITH_ASAN macro.
147
// Define ANGLE_WITH_ASAN macro.
- a/Source/ThirdParty/ANGLE/src/common/system_utils_ios.mm +53 lines
Line 0 a/Source/ThirdParty/ANGLE/src/common/system_utils_ios.mm_sec1
1
//
2
// Copyright 2015 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
7
// system_utils_ios.mm: Implementation of iOS-specific functions for OSX
8
9
#include "system_utils.h"
10
11
#include <unistd.h>
12
13
#include <CoreServices/CoreServices.h>
14
#include <mach-o/dyld.h>
15
#include <mach/mach.h>
16
#include <mach/mach_time.h>
17
#include <array>
18
#include <cstdlib>
19
#include <vector>
20
21
#import <Foundation/Foundation.h>
22
23
namespace angle
24
{
25
std::string GetExecutablePath()
26
{
27
28
    NSString *executableString = [[NSBundle mainBundle] executablePath];
29
    std::string result([executableString UTF8String]);
30
    return result;
31
}
32
33
std::string GetExecutableDirectory()
34
{
35
    std::string executablePath = GetExecutablePath();
36
    size_t lastPathSepLoc      = executablePath.find_last_of("/");
37
    return (lastPathSepLoc != std::string::npos) ? executablePath.substr(0, lastPathSepLoc) : "";
38
}
39
40
const char *GetSharedLibraryExtension()
41
{
42
    return "dylib";
43
}
44
45
double GetCurrentTime()
46
{
47
    mach_timebase_info_data_t timebaseInfo;
48
    mach_timebase_info(&timebaseInfo);
49
50
    double secondCoeff = timebaseInfo.numer * 1e-9 / timebaseInfo.denom;
51
    return secondCoeff * mach_absolute_time();
52
}
53
}  // namespace angle
- a/Source/ThirdParty/ANGLE/src/common/utilities.cpp -5 / +44 lines
Lines 6-16 a/Source/ThirdParty/ANGLE/src/common/utilities.cpp_sec1
6
6
7
// utilities.cpp: Conversion functions and other utility routines.
7
// utilities.cpp: Conversion functions and other utility routines.
8
8
9
// Older clang versions have a false positive on this warning here.
10
#if defined(__clang__)
11
#pragma clang diagnostic ignored "-Wglobal-constructors"
12
#endif
13
14
#include "common/utilities.h"
9
#include "common/utilities.h"
15
#include "GLES3/gl3.h"
10
#include "GLES3/gl3.h"
16
#include "common/mathutil.h"
11
#include "common/mathutil.h"
Lines 476-481 int VariableColumnCount(GLenum type) a/Source/ThirdParty/ANGLE/src/common/utilities.cpp_sec2
476
471
477
    return 0;
472
    return 0;
478
}
473
}
474
/**
475
Determine the number of attribute slots used by a variable type
476
*/
477
int VariableAttributeCount(GLenum type)
478
{
479
    switch (type)
480
    {
481
        case GL_NONE:
482
            return 0;
483
        case GL_BOOL:
484
        case GL_FLOAT:
485
        case GL_INT:
486
        case GL_UNSIGNED_INT:
487
        case GL_BOOL_VEC2:
488
        case GL_FLOAT_VEC2:
489
        case GL_INT_VEC2:
490
        case GL_UNSIGNED_INT_VEC2:
491
        case GL_BOOL_VEC3:
492
        case GL_FLOAT_VEC3:
493
        case GL_INT_VEC3:
494
        case GL_UNSIGNED_INT_VEC3:
495
        case GL_BOOL_VEC4:
496
        case GL_FLOAT_VEC4:
497
        case GL_INT_VEC4:
498
        case GL_UNSIGNED_INT_VEC4:
499
            return 1;
500
        case GL_FLOAT_MAT2:
501
        case GL_FLOAT_MAT2x3:
502
        case GL_FLOAT_MAT2x4:
503
            return 2;
504
        case GL_FLOAT_MAT3:
505
        case GL_FLOAT_MAT3x2:
506
        case GL_FLOAT_MAT3x4:
507
            return 3;
508
        case GL_FLOAT_MAT4:
509
        case GL_FLOAT_MAT4x2:
510
        case GL_FLOAT_MAT4x3:
511
            return 4;
512
        default:
513
            UNREACHABLE();
514
    }
515
516
    return 0;
517
}
479
518
480
bool IsSamplerType(GLenum type)
519
bool IsSamplerType(GLenum type)
481
{
520
{
- a/Source/ThirdParty/ANGLE/src/common/utilities.h +1 lines
Lines 37-42 size_t VariableInternalSize(GLenum type); a/Source/ThirdParty/ANGLE/src/common/utilities.h_sec1
37
size_t VariableExternalSize(GLenum type);
37
size_t VariableExternalSize(GLenum type);
38
int VariableRowCount(GLenum type);
38
int VariableRowCount(GLenum type);
39
int VariableColumnCount(GLenum type);
39
int VariableColumnCount(GLenum type);
40
int VariableAttributeCount(GLenum type);
40
bool IsSamplerType(GLenum type);
41
bool IsSamplerType(GLenum type);
41
bool IsSamplerCubeType(GLenum type);
42
bool IsSamplerCubeType(GLenum type);
42
bool IsImageType(GLenum type);
43
bool IsImageType(GLenum type);
- a/Source/ThirdParty/ANGLE/src/compiler/translator/CodeGen.cpp -2 / +11 lines
Lines 21-28 a/Source/ThirdParty/ANGLE/src/compiler/translator/CodeGen.cpp_sec1
21
#endif  // ANGLE_ENABLE_VULKAN
21
#endif  // ANGLE_ENABLE_VULKAN
22
22
23
#ifdef ANGLE_ENABLE_METAL
23
#ifdef ANGLE_ENABLE_METAL
24
#    include "compiler/translator/TranslatorMetal.h"
24
#    include "compiler/translator/TranslatorMetalDirect.h"
25
#endif  // ANGLE_ENABLE_METAL
25
#endif  // ANGLE_ENABLE_METAL
26
#ifdef ANGLE_ENABLE_METAL_SPIRV
27
#    include "compiler/translator/TranslatorMetal.h"
28
#endif  // ANGLE_ENABLE_METAL_SPIRV
26
29
27
#include "compiler/translator/util.h"
30
#include "compiler/translator/util.h"
28
31
Lines 64-74 TCompiler *ConstructCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput a/Source/ThirdParty/ANGLE/src/compiler/translator/CodeGen.cpp_sec2
64
    }
67
    }
65
#endif  // ANGLE_ENABLE_VULKAN
68
#endif  // ANGLE_ENABLE_VULKAN
66
69
67
#ifdef ANGLE_ENABLE_METAL
70
#ifdef ANGLE_ENABLE_METAL_SPIRV
68
    if (IsOutputMetal(output))
71
    if (IsOutputMetal(output))
69
    {
72
    {
70
        return new TranslatorMetal(type, spec);
73
        return new TranslatorMetal(type, spec);
71
    }
74
    }
75
#endif
76
#ifdef ANGLE_ENABLE_METAL
77
    if (IsOutputMetalDirect(output))
78
    {
79
        return new TranslatorMetalDirect(type, spec, output);
80
    }
72
#endif  // ANGLE_ENABLE_METAL
81
#endif  // ANGLE_ENABLE_METAL
73
82
74
    // Unsupported compiler or unknown format. Return nullptr per the sh::ConstructCompiler API.
83
    // Unsupported compiler or unknown format. Return nullptr per the sh::ConstructCompiler API.
- a/Source/ThirdParty/ANGLE/src/compiler/translator/Common.h +2 lines
Lines 31-36 struct TSourceLoc a/Source/ThirdParty/ANGLE/src/compiler/translator/Common.h_sec1
31
    int last_line;
31
    int last_line;
32
};
32
};
33
33
34
constexpr TSourceLoc kNoSourceLoc{-1, -1, -1, -1};
35
34
//
36
//
35
// Put POOL_ALLOCATOR_NEW_DELETE in base classes to make them use this scheme.
37
// Put POOL_ALLOCATOR_NEW_DELETE in base classes to make them use this scheme.
36
//
38
//
- a/Source/ThirdParty/ANGLE/src/compiler/translator/Compiler.cpp -3 / +3 lines
Lines 722-730 bool TCompiler::checkAndSimplifyAST(TIntermBlock *root, a/Source/ThirdParty/ANGLE/src/compiler/translator/Compiler.cpp_sec1
722
        }
722
        }
723
    }
723
    }
724
724
725
    int simplifyScalarized = (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS)
725
    unsigned int simplifyScalarized = (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS)
726
                                 ? IntermNodePatternMatcher::kScalarizedVecOrMatConstructor
726
                                          ? IntermNodePatternMatcher::kScalarizedVecOrMatConstructor
727
                                 : 0;
727
                                          : 0;
728
728
729
    // Split multi declarations and remove calls to array length().
729
    // Split multi declarations and remove calls to array length().
730
    // Note that SimplifyLoopConditions needs to be run before any other AST transformations
730
    // Note that SimplifyLoopConditions needs to be run before any other AST transformations
- a/Source/ThirdParty/ANGLE/src/compiler/translator/Compiler.h +6 lines
Lines 35-40 class TParseContext; a/Source/ThirdParty/ANGLE/src/compiler/translator/Compiler.h_sec1
35
#ifdef ANGLE_ENABLE_HLSL
35
#ifdef ANGLE_ENABLE_HLSL
36
class TranslatorHLSL;
36
class TranslatorHLSL;
37
#endif  // ANGLE_ENABLE_HLSL
37
#endif  // ANGLE_ENABLE_HLSL
38
#ifdef ANGLE_ENABLE_METAL
39
class TranslatorMetalDirect;
40
#endif  // ANGLE_ENABLE_METAL
38
41
39
//
42
//
40
// Helper function to check if the shader type is GLSL.
43
// Helper function to check if the shader type is GLSL.
Lines 63-68 class TShHandleBase a/Source/ThirdParty/ANGLE/src/compiler/translator/Compiler.h_sec2
63
#ifdef ANGLE_ENABLE_HLSL
66
#ifdef ANGLE_ENABLE_HLSL
64
    virtual TranslatorHLSL *getAsTranslatorHLSL() { return 0; }
67
    virtual TranslatorHLSL *getAsTranslatorHLSL() { return 0; }
65
#endif  // ANGLE_ENABLE_HLSL
68
#endif  // ANGLE_ENABLE_HLSL
69
#ifdef ANGLE_ENABLE_METAL
70
    virtual TranslatorMetalDirect *getAsTranslatorMetalDirect() { return nullptr; }
71
#endif  // ANGLE_ENABLE_METAL
66
72
67
  protected:
73
  protected:
68
    // Memory allocator. Allocates and tracks memory required by the compiler.
74
    // Memory allocator. Allocates and tracks memory required by the compiler.
- a/Source/ThirdParty/ANGLE/src/compiler/translator/ConstantUnion.cpp -5 / +9 lines
Lines 67-77 bool IsValidShiftOffset(const TConstantUnion &rhs) a/Source/ThirdParty/ANGLE/src/compiler/translator/ConstantUnion.cpp_sec1
67
67
68
}  // anonymous namespace
68
}  // anonymous namespace
69
69
70
TConstantUnion::TConstantUnion()
70
TConstantUnion::TConstantUnion() : iConst(0), type(EbtVoid) {}
71
{
71
72
    iConst = 0;
72
TConstantUnion::TConstantUnion(int i) : iConst(i), type(EbtInt) {}
73
    type   = EbtVoid;
73
74
}
74
TConstantUnion::TConstantUnion(unsigned int u) : uConst(u), type(EbtUInt) {}
75
76
TConstantUnion::TConstantUnion(float f) : fConst(f), type(EbtFloat) {}
77
78
TConstantUnion::TConstantUnion(bool b) : bConst(b), type(EbtBool) {}
75
79
76
int TConstantUnion::getIConst() const
80
int TConstantUnion::getIConst() const
77
{
81
{
- a/Source/ThirdParty/ANGLE/src/compiler/translator/ConstantUnion.h +4 lines
Lines 20-25 class TConstantUnion a/Source/ThirdParty/ANGLE/src/compiler/translator/ConstantUnion.h_sec1
20
  public:
20
  public:
21
    POOL_ALLOCATOR_NEW_DELETE
21
    POOL_ALLOCATOR_NEW_DELETE
22
    TConstantUnion();
22
    TConstantUnion();
23
    TConstantUnion(int i);
24
    TConstantUnion(unsigned int u);
25
    TConstantUnion(float f);
26
    TConstantUnion(bool b);
23
27
24
    bool cast(TBasicType newType, const TConstantUnion &constant);
28
    bool cast(TBasicType newType, const TConstantUnion &constant);
25
29
- a/Source/ThirdParty/ANGLE/src/compiler/translator/IntermNode.cpp -11 / +53 lines
Lines 41-47 TPrecision GetHigherPrecision(TPrecision left, TPrecision right) a/Source/ThirdParty/ANGLE/src/compiler/translator/IntermNode.cpp_sec1
41
TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
41
TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
42
{
42
{
43
    TConstantUnion *constUnion = new TConstantUnion[size];
43
    TConstantUnion *constUnion = new TConstantUnion[size];
44
    for (unsigned int i = 0; i < size; ++i)
44
    for (size_t i = 0; i < size; ++i)
45
        constUnion[i] = constant;
45
        constUnion[i] = constant;
46
46
47
    return constUnion;
47
    return constUnion;
Lines 415-420 TIntermBlock::TIntermBlock(const TIntermBlock &node) a/Source/ThirdParty/ANGLE/src/compiler/translator/IntermNode.cpp_sec2
415
    }
415
    }
416
}
416
}
417
417
418
TIntermBlock::TIntermBlock(std::initializer_list<TIntermNode *> stmts)
419
{
420
    for (TIntermNode *stmt : stmts)
421
    {
422
        appendStatement(stmt);
423
    }
424
}
425
418
size_t TIntermBlock::getChildCount() const
426
size_t TIntermBlock::getChildCount() const
419
{
427
{
420
    return mStatements.size();
428
    return mStatements.size();
Lines 446-451 bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNo a/Source/ThirdParty/ANGLE/src/compiler/translator/IntermNode.cpp_sec3
446
    return false;
454
    return false;
447
}
455
}
448
456
457
TIntermDeclaration::TIntermDeclaration(const TVariable *var, TIntermTyped *initExpr)
458
{
459
    if (initExpr)
460
    {
461
        appendDeclarator(
462
            new TIntermBinary(TOperator::EOpInitialize, new TIntermSymbol(var), initExpr));
463
    }
464
    else
465
    {
466
        appendDeclarator(new TIntermSymbol(var));
467
    }
468
}
469
470
TIntermDeclaration::TIntermDeclaration(std::initializer_list<const TVariable *> declarators)
471
    : TIntermDeclaration()
472
{
473
    for (auto *d : declarators)
474
    {
475
        appendDeclarator(new TIntermSymbol(d));
476
    }
477
}
478
479
TIntermDeclaration::TIntermDeclaration(std::initializer_list<TIntermTyped *> declarators)
480
    : TIntermDeclaration()
481
{
482
    for (auto *d : declarators)
483
    {
484
        appendDeclarator(d);
485
    }
486
}
487
449
size_t TIntermDeclaration::getChildCount() const
488
size_t TIntermDeclaration::getChildCount() const
450
{
489
{
451
    return mDeclarators.size();
490
    return mDeclarators.size();
Lines 463-471 bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *re a/Source/ThirdParty/ANGLE/src/compiler/translator/IntermNode.cpp_sec4
463
502
464
bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
503
bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
465
{
504
{
466
    for (size_t ii = 0; ii < getSequence()->size(); ++ii)
505
    auto &seq = *getSequence();
506
    for (auto *&node : seq)
467
    {
507
    {
468
        REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
508
        REPLACE_IF_IS(node, TIntermNode, original, replacement);
469
    }
509
    }
470
    return false;
510
    return false;
471
}
511
}
Lines 473-484 bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TInte a/Source/ThirdParty/ANGLE/src/compiler/translator/IntermNode.cpp_sec5
473
bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
513
bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
474
                                                        const TIntermSequence &replacements)
514
                                                        const TIntermSequence &replacements)
475
{
515
{
476
    for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
516
    auto &seq = *getSequence();
517
    for (auto it = seq.begin(); it < seq.end(); ++it)
477
    {
518
    {
478
        if (*it == original)
519
        if (*it == original)
479
        {
520
        {
480
            it = getSequence()->erase(it);
521
            it = seq.erase(it);
481
            getSequence()->insert(it, replacements.begin(), replacements.end());
522
            seq.insert(it, replacements.begin(), replacements.end());
482
            return true;
523
            return true;
483
        }
524
        }
484
    }
525
    }
Lines 488-499 bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original, a/Source/ThirdParty/ANGLE/src/compiler/translator/IntermNode.cpp_sec6
488
bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
529
bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
489
                                            const TIntermSequence &insertions)
530
                                            const TIntermSequence &insertions)
490
{
531
{
491
    if (position > getSequence()->size())
532
    auto &seq = *getSequence();
533
    if (position > seq.size())
492
    {
534
    {
493
        return false;
535
        return false;
494
    }
536
    }
495
    auto it = getSequence()->begin() + position;
537
    auto it = seq.begin() + position;
496
    getSequence()->insert(it, insertions.begin(), insertions.end());
538
    seq.insert(it, insertions.begin(), insertions.end());
497
    return true;
539
    return true;
498
}
540
}
499
541
Lines 1040-1047 TIntermAggregate::TIntermAggregate(const TIntermAggregate &node) a/Source/ThirdParty/ANGLE/src/compiler/translator/IntermNode.cpp_sec7
1040
1082
1041
TIntermAggregate *TIntermAggregate::shallowCopy() const
1083
TIntermAggregate *TIntermAggregate::shallowCopy() const
1042
{
1084
{
1043
    TIntermSequence *copySeq = new TIntermSequence();
1085
    auto &seq                  = *getSequence();
1044
    copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
1086
    TIntermSequence *copySeq   = new TIntermSequence(seq.begin(), seq.end());
1045
    TIntermAggregate *copyNode = new TIntermAggregate(mFunction, mType, mOp, copySeq);
1087
    TIntermAggregate *copyNode = new TIntermAggregate(mFunction, mType, mOp, copySeq);
1046
    copyNode->setLine(mLine);
1088
    copyNode->setLine(mLine);
1047
    return copyNode;
1089
    return copyNode;
- a/Source/ThirdParty/ANGLE/src/compiler/translator/IntermNode.h +4 lines
Lines 674-679 class TIntermBlock : public TIntermNode, public TIntermAggregateBase a/Source/ThirdParty/ANGLE/src/compiler/translator/IntermNode.h_sec1
674
{
674
{
675
  public:
675
  public:
676
    TIntermBlock() : TIntermNode() {}
676
    TIntermBlock() : TIntermNode() {}
677
    TIntermBlock(std::initializer_list<TIntermNode *> stmts);
677
    ~TIntermBlock() override {}
678
    ~TIntermBlock() override {}
678
679
679
    TIntermBlock *getAsBlock() override { return this; }
680
    TIntermBlock *getAsBlock() override { return this; }
Lines 776-781 class TIntermDeclaration : public TIntermNode, public TIntermAggregateBase a/Source/ThirdParty/ANGLE/src/compiler/translator/IntermNode.h_sec2
776
{
777
{
777
  public:
778
  public:
778
    TIntermDeclaration() : TIntermNode() {}
779
    TIntermDeclaration() : TIntermNode() {}
780
    TIntermDeclaration(const TVariable *var, TIntermTyped *initExpr);
781
    TIntermDeclaration(std::initializer_list<const TVariable *> declarators);
782
    TIntermDeclaration(std::initializer_list<TIntermTyped *> declarators);
779
    ~TIntermDeclaration() override {}
783
    ~TIntermDeclaration() override {}
780
784
781
    TIntermDeclaration *getAsDeclarationNode() override { return this; }
785
    TIntermDeclaration *getAsDeclarationNode() override { return this; }
- a/Source/ThirdParty/ANGLE/src/compiler/translator/Symbol.cpp -1 / +2 lines
Lines 196-202 void TFunction::shareParameters(const TFunction &parametersSource) a/Source/ThirdParty/ANGLE/src/compiler/translator/Symbol.cpp_sec1
196
196
197
ImmutableString TFunction::buildMangledName() const
197
ImmutableString TFunction::buildMangledName() const
198
{
198
{
199
    std::string newName(name().data(), name().length());
199
    ImmutableString name = this->name();
200
    std::string newName(name.data(), name.length());
200
    newName += kFunctionMangledNameSeparator;
201
    newName += kFunctionMangledNameSeparator;
201
202
202
    for (size_t i = 0u; i < mParamCount; ++i)
203
    for (size_t i = 0u; i < mParamCount; ++i)
- a/Source/ThirdParty/ANGLE/src/compiler/translator/Symbol.h -1 / +1 lines
Lines 222-228 class TFunction : public TSymbol a/Source/ThirdParty/ANGLE/src/compiler/translator/Symbol.h_sec1
222
    TOperator getBuiltInOp() const { return mOp; }
222
    TOperator getBuiltInOp() const { return mOp; }
223
223
224
    void setDefined() { defined = true; }
224
    void setDefined() { defined = true; }
225
    bool isDefined() { return defined; }
225
    bool isDefined() const { return defined; }
226
    void setHasPrototypeDeclaration() { mHasPrototypeDeclaration = true; }
226
    void setHasPrototypeDeclaration() { mHasPrototypeDeclaration = true; }
227
    bool hasPrototypeDeclaration() const { return mHasPrototypeDeclaration; }
227
    bool hasPrototypeDeclaration() const { return mHasPrototypeDeclaration; }
228
228
- a/Source/ThirdParty/ANGLE/src/compiler/translator/SymbolTable_ESSL_autogen.cpp -2 / +2 lines
Lines 3568-3574 constexpr const TVariable *p10F10F10F[3] = {&BuiltInVariable::kpt10F, &BuiltInVa a/Source/ThirdParty/ANGLE/src/compiler/translator/SymbolTable_ESSL_autogen.cpp_sec1
3568
                                            &BuiltInVariable::kpt10F};
3568
                                            &BuiltInVariable::kpt10F};
3569
constexpr const TVariable *p20B00B00B[3] = {&BuiltInVariable::kpt20B, &BuiltInVariable::kpt00B,
3569
constexpr const TVariable *p20B00B00B[3] = {&BuiltInVariable::kpt20B, &BuiltInVariable::kpt00B,
3570
                                            &BuiltInVariable::kpt00B};
3570
                                            &BuiltInVariable::kpt00B};
3571
constexpr const TVariable *p20B00D[2]    = {&BuiltInVariable::kpt20B, &BuiltInVariable::kpt00D};
3571
constexpr const TVariable *p20B00D[2]       = {&BuiltInVariable::kpt20B, &BuiltInVariable::kpt00D};
3572
constexpr const TVariable *p20B00H[2]    = {&BuiltInVariable::kpt20B, &BuiltInVariable::kpt00H};
3572
constexpr const TVariable *p20B00H[2]    = {&BuiltInVariable::kpt20B, &BuiltInVariable::kpt00H};
3573
constexpr const TVariable *p20B10B[2]    = {&BuiltInVariable::kpt20B, &BuiltInVariable::kpt10B};
3573
constexpr const TVariable *p20B10B[2]    = {&BuiltInVariable::kpt20B, &BuiltInVariable::kpt10B};
3574
constexpr const TVariable *p20B20B00B[3] = {&BuiltInVariable::kpt20B, &BuiltInVariable::kpt20B,
3574
constexpr const TVariable *p20B20B00B[3] = {&BuiltInVariable::kpt20B, &BuiltInVariable::kpt20B,
Lines 3609-3615 constexpr const TVariable *p20F20F20F[3] = {&BuiltInVariable::kpt20F, &BuiltInVa a/Source/ThirdParty/ANGLE/src/compiler/translator/SymbolTable_ESSL_autogen.cpp_sec2
3609
                                            &BuiltInVariable::kpt20F};
3609
                                            &BuiltInVariable::kpt20F};
3610
constexpr const TVariable *p30B00B00B[3] = {&BuiltInVariable::kpt30B, &BuiltInVariable::kpt00B,
3610
constexpr const TVariable *p30B00B00B[3] = {&BuiltInVariable::kpt30B, &BuiltInVariable::kpt00B,
3611
                                            &BuiltInVariable::kpt00B};
3611
                                            &BuiltInVariable::kpt00B};
3612
constexpr const TVariable *p30B00D[2]    = {&BuiltInVariable::kpt30B, &BuiltInVariable::kpt00D};
3612
constexpr const TVariable *p30B00D[2]       = {&BuiltInVariable::kpt30B, &BuiltInVariable::kpt00D};
3613
constexpr const TVariable *p30B10B[2]    = {&BuiltInVariable::kpt30B, &BuiltInVariable::kpt10B};
3613
constexpr const TVariable *p30B10B[2]    = {&BuiltInVariable::kpt30B, &BuiltInVariable::kpt10B};
3614
constexpr const TVariable *p30B20B[2]    = {&BuiltInVariable::kpt30B, &BuiltInVariable::kpt20B};
3614
constexpr const TVariable *p30B20B[2]    = {&BuiltInVariable::kpt30B, &BuiltInVariable::kpt20B};
3615
constexpr const TVariable *p30B30B00B[3] = {&BuiltInVariable::kpt30B, &BuiltInVariable::kpt30B,
3615
constexpr const TVariable *p30B30B00B[3] = {&BuiltInVariable::kpt30B, &BuiltInVariable::kpt30B,
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetal.cpp -9 / +162 lines
Lines 41-48 const char kRasterizerDiscardEnabledConstName[] = "ANGLERasterizerDisabled"; a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetal.cpp_sec1
41
namespace
41
namespace
42
{
42
{
43
43
44
constexpr ImmutableString kRasterizationDiscardEnabledConstName =
45
    ImmutableString("ANGLERasterizationDisabled");
46
constexpr ImmutableString kCoverageMaskEnabledConstName =
47
    ImmutableString("ANGLECoverageMaskEnabled");
44
constexpr ImmutableString kCoverageMaskField       = ImmutableString("coverageMask");
48
constexpr ImmutableString kCoverageMaskField       = ImmutableString("coverageMask");
49
constexpr ImmutableString kEmuInstanceIDField      = ImmutableString("emulatedInstanceID");
45
constexpr ImmutableString kSampleMaskWriteFuncName = ImmutableString("ANGLEWriteSampleMask");
50
constexpr ImmutableString kSampleMaskWriteFuncName = ImmutableString("ANGLEWriteSampleMask");
51
constexpr ImmutableString kDiscardWrapperFuncName  = ImmutableString("ANGLEDiscardWrapper");
46
52
47
TIntermBinary *CreateDriverUniformRef(const TVariable *driverUniforms, const char *fieldName)
53
TIntermBinary *CreateDriverUniformRef(const TVariable *driverUniforms, const char *fieldName)
48
{
54
{
Lines 86-91 ANGLE_NO_DISCARD bool AppendVertexShaderPositionYCorrectionToMain(TCompiler *com a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetal.cpp_sec2
86
    return RunAtTheEndOfShader(compiler, root, assignment, symbolTable);
92
    return RunAtTheEndOfShader(compiler, root, assignment, symbolTable);
87
}
93
}
88
94
95
ANGLE_NO_DISCARD bool EmulateInstanceID(TCompiler *compiler,
96
                                        TIntermBlock *root,
97
                                        TSymbolTable *symbolTable,
98
                                        const TVariable *driverUniforms)
99
{
100
    // emuInstanceID
101
    TIntermBinary *emuInstanceID =
102
        CreateDriverUniformRef(driverUniforms, kEmuInstanceIDField.data());
103
104
    // Create a symbol reference to "gl_InstanceIndex"
105
    const TVariable *instanceID = BuiltInVariable::gl_InstanceIndex();
106
107
    return ReplaceVariableWithTyped(compiler, root, instanceID, emuInstanceID);
108
}
109
89
// Initialize unused varying outputs.
110
// Initialize unused varying outputs.
90
ANGLE_NO_DISCARD bool InitializeUnusedOutputs(TIntermBlock *root,
111
ANGLE_NO_DISCARD bool InitializeUnusedOutputs(TIntermBlock *root,
91
                                              TSymbolTable *symbolTable,
112
                                              TSymbolTable *symbolTable,
Lines 123-128 ANGLE_NO_DISCARD bool InitializeUnusedOutputs(TIntermBlock *root, a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetal.cpp_sec3
123
144
124
}  // anonymous namespace
145
}  // anonymous namespace
125
146
147
/** static */
148
const char *TranslatorMetal::GetCoverageMaskEnabledConstName()
149
{
150
    return kCoverageMaskEnabledConstName.data();
151
}
152
153
/** static */
154
const char *TranslatorMetal::GetRasterizationDiscardEnabledConstName()
155
{
156
    return kRasterizationDiscardEnabledConstName.data();
157
}
158
126
TranslatorMetal::TranslatorMetal(sh::GLenum type, ShShaderSpec spec) : TranslatorVulkan(type, spec)
159
TranslatorMetal::TranslatorMetal(sh::GLenum type, ShShaderSpec spec) : TranslatorVulkan(type, spec)
127
{}
160
{}
128
161
Lines 153-172 bool TranslatorMetal::translate(TIntermBlock *root, a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetal.cpp_sec4
153
    {
186
    {
154
        auto negFlipY = getDriverUniformNegFlipYRef(driverUniforms);
187
        auto negFlipY = getDriverUniformNegFlipYRef(driverUniforms);
155
188
189
        if (mEmulatedInstanceID)
190
        {
191
            // Emulate gl_InstanceID
192
            if (!EmulateInstanceID(this, root, &getSymbolTable(), driverUniforms))
193
            {
194
                return false;
195
            }
196
        }
197
156
        // Append gl_Position.y correction to main
198
        // Append gl_Position.y correction to main
157
        if (!AppendVertexShaderPositionYCorrectionToMain(this, root, &getSymbolTable(), negFlipY))
199
        if (!AppendVertexShaderPositionYCorrectionToMain(this, root, &getSymbolTable(), negFlipY))
158
        {
200
        {
159
            return false;
201
            return false;
160
        }
202
        }
161
203
162
        // Insert rasterizer discard logic
204
        // Insert rasterization discard logic
163
        if (!insertRasterizerDiscardLogic(root))
205
        if (!insertRasterizationDiscardLogic(root))
206
        {
207
            return false;
208
        }
209
    }
210
211
    // Initialize unused varying outputs to avoid spirv-cross dead-code removing them in later
212
    // stage. Only do this if SH_INIT_OUTPUT_VARIABLES is not specified.
213
    if ((getShaderType() == GL_VERTEX_SHADER || getShaderType() == GL_GEOMETRY_SHADER_EXT) &&
214
        !(compileOptions & SH_INIT_OUTPUT_VARIABLES))
215
    {
216
        InitVariableList list;
217
        for (const sh::ShaderVariable &var : mOutputVaryings)
218
        {
219
            if (!var.active)
220
            {
221
                list.push_back(var);
222
            }
223
        }
224
225
        if (!InitializeUnusedOutputs(root, &getSymbolTable(), list))
164
        {
226
        {
165
            return false;
227
            return false;
166
        }
228
        }
167
    }
229
    }
168
    else if (getShaderType() == GL_FRAGMENT_SHADER)
230
    else if (getShaderType() == GL_FRAGMENT_SHADER)
169
    {
231
    {
232
        // For non void MSL fragment functions replace discard
233
        // with ANGLEDiscardWrapper()
234
        if (mOutputVariables.size() > 0)
235
        {
236
            if (!replaceAllMainDiscardUses(root))
237
            {
238
                return false;
239
            }
240
        }
170
        if (!insertSampleMaskWritingLogic(root, driverUniforms))
241
        if (!insertSampleMaskWritingLogic(root, driverUniforms))
171
        {
242
        {
172
            return false;
243
            return false;
Lines 235-240 void TranslatorMetal::createAdditionalGraphicsDriverUniformFields(std::vector<TF a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetal.cpp_sec5
235
    TField *coverageMaskField =
306
    TField *coverageMaskField =
236
        new TField(new TType(EbtUInt), kCoverageMaskField, TSourceLoc(), SymbolType::AngleInternal);
307
        new TField(new TType(EbtUInt), kCoverageMaskField, TSourceLoc(), SymbolType::AngleInternal);
237
    fieldsOut->push_back(coverageMaskField);
308
    fieldsOut->push_back(coverageMaskField);
309
310
    if (mEmulatedInstanceID)
311
    {
312
        TField *emuInstanceIDField = new TField(new TType(EbtInt), kEmuInstanceIDField,
313
                                                TSourceLoc(), SymbolType::AngleInternal);
314
        fieldsOut->push_back(emuInstanceIDField);
315
    }
238
}
316
}
239
317
240
// Add sample_mask writing to main, guarded by the specialization constant
318
// Add sample_mask writing to main, guarded by the specialization constant
Lines 293-316 ANGLE_NO_DISCARD bool TranslatorMetal::insertSampleMaskWritingLogic(TIntermBlock a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetal.cpp_sec6
293
    return RunAtTheEndOfShader(this, root, ifCall, symbolTable);
371
    return RunAtTheEndOfShader(this, root, ifCall, symbolTable);
294
}
372
}
295
373
296
ANGLE_NO_DISCARD bool TranslatorMetal::insertRasterizerDiscardLogic(TIntermBlock *root)
374
ANGLE_NO_DISCARD bool TranslatorMetal::insertRasterizationDiscardLogic(TIntermBlock *root)
297
{
375
{
298
    TInfoSinkBase &sink       = getInfoSink().obj;
376
    TInfoSinkBase &sink       = getInfoSink().obj;
299
    TSymbolTable *symbolTable = &getSymbolTable();
377
    TSymbolTable *symbolTable = &getSymbolTable();
300
378
301
    // Insert rasterizationDisabled specialization constant.
379
    // Insert rasterizationDisabled specialization constant.
302
    sink << "layout (constant_id=0) const bool " << mtl::kRasterizerDiscardEnabledConstName;
380
    sink << "layout (constant_id=0) const bool " << kRasterizationDiscardEnabledConstName;
303
    sink << " = false;\n";
381
    sink << " = false;\n";
304
382
305
    // Create kRasterizerDiscardEnabledConstName variable reference.
383
    // Create kRasterizationDiscardEnabledConstName and kRasterizationDiscardFuncName variable
384
    // references.
306
    TType *boolType = new TType(EbtBool);
385
    TType *boolType = new TType(EbtBool);
307
    boolType->setQualifier(EvqConst);
386
    boolType->setQualifier(EvqConst);
308
    TVariable *discardEnabledVar =
387
    TVariable *discardEnabledVar = new TVariable(symbolTable, kRasterizationDiscardEnabledConstName,
309
        new TVariable(symbolTable, ImmutableString(mtl::kRasterizerDiscardEnabledConstName),
388
                                                 boolType, SymbolType::AngleInternal);
310
                      boolType, SymbolType::AngleInternal);
311
389
312
    // Insert this code to the end of main()
390
    // Insert this code to the end of main()
313
    // if (ANGLERasterizerDisabled)
391
    // if (ANGLERasterizationDisabled)
314
    // {
392
    // {
315
    //      gl_Position = vec4(-3.0, -3.0, -3.0, 1.0);
393
    //      gl_Position = vec4(-3.0, -3.0, -3.0, 1.0);
316
    // }
394
    // }
Lines 341-344 ANGLE_NO_DISCARD bool TranslatorMetal::insertRasterizerDiscardLogic(TIntermBlock a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetal.cpp_sec7
341
    return RunAtTheEndOfShader(this, root, ifCall, symbolTable);
419
    return RunAtTheEndOfShader(this, root, ifCall, symbolTable);
342
}
420
}
343
421
422
// If the MSL fragment shader is non-void, we need to ensure
423
// that there is a return at the end. The MSL compiler
424
// will error out if there's no return at the end, even if all
425
// paths lead to discard_fragment(). So wrap discard in a wrapper function.
426
// Fixes dEQP-GLES3.functional.shaders.discard.basic_always
427
ANGLE_NO_DISCARD bool TranslatorMetal::replaceAllMainDiscardUses(TIntermBlock *root)
428
{
429
    // before
430
    // void main (void)
431
    // {
432
    //     o_color = v_color;
433
    //     discard;
434
    // }
435
436
    // after
437
    // void ANGLEDiscardWrapper()
438
    // {
439
    //    discard;
440
    // }
441
    // void main (void)
442
    // {
443
    //     o_color = v_color;
444
    //     ANGLEDiscardWrapper();
445
    // }
446
447
    TIntermFunctionDefinition *main   = FindMain(root);
448
    TIntermBlock *mainBody            = main->getBody();
449
    TIntermSequence *functionSequence = mainBody->getSequence();
450
    TIntermAggregate *discardFunc     = nullptr;
451
    // Iterate over all branches in main function, and replace all uses
452
    // of discard with ANGLEDiscardWrapper().
453
    for (size_t index = 0; index < functionSequence->size(); ++index)
454
    {
455
        TIntermNode *functionNode = (*functionSequence)[index];
456
        TIntermBranch *branchNode = functionNode->getAsBranchNode();
457
        if (branchNode != nullptr)
458
        {
459
            if (branchNode->getFlowOp() == EOpKill)
460
            {
461
                if (discardFunc == nullptr)
462
                {
463
                    discardFunc = createDiscardWrapperFunc(root);
464
                }
465
                bool replaced = mainBody->replaceChildNode(branchNode, discardFunc);
466
                if (!replaced)
467
                {
468
                    return false;
469
                }
470
            }
471
        }
472
    }
473
    return validateAST(root);
474
}
475
476
// Create discard_wrapper function to ensure that SPIRV-Cross will always have a return at the end
477
// of fragment shaders
478
ANGLE_NO_DISCARD TIntermAggregate *TranslatorMetal::createDiscardWrapperFunc(TIntermBlock *root)
479
{
480
    TInfoSinkBase &sink       = getInfoSink().obj;
481
    TSymbolTable *symbolTable = &getSymbolTable();
482
483
    sink << "void " << kDiscardWrapperFuncName << "()\n";
484
    sink << "{\n";
485
    sink << "   discard;\n";
486
    sink << "}\n";
487
488
    TFunction *discardWrapperFunc =
489
        new TFunction(symbolTable, kDiscardWrapperFuncName, SymbolType::AngleInternal,
490
                      StaticType::GetBasic<EbtVoid>(), true);
491
492
    TIntermAggregate *callDiscardWrapperFunc =
493
        TIntermAggregate::CreateFunctionCall(*discardWrapperFunc, new TIntermSequence());
494
    return callDiscardWrapperFunc;
495
}
496
344
}  // namespace sh
497
}  // namespace sh
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetal.h -1 / +12 lines
Lines 25-30 class TranslatorMetal : public TranslatorVulkan a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetal.h_sec1
25
  public:
25
  public:
26
    TranslatorMetal(sh::GLenum type, ShShaderSpec spec);
26
    TranslatorMetal(sh::GLenum type, ShShaderSpec spec);
27
27
28
    static const char *GetCoverageMaskEnabledConstName();
29
    static const char *GetRasterizationDiscardEnabledConstName();
30
31
    void enableEmulatedInstanceID(bool e) { mEmulatedInstanceID = e; }
32
28
  protected:
33
  protected:
29
    ANGLE_NO_DISCARD bool translate(TIntermBlock *root,
34
    ANGLE_NO_DISCARD bool translate(TIntermBlock *root,
30
                                    ShCompileOptions compileOptions,
35
                                    ShCompileOptions compileOptions,
Lines 37-43 class TranslatorMetal : public TranslatorVulkan a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetal.h_sec2
37
42
38
    ANGLE_NO_DISCARD bool insertSampleMaskWritingLogic(TIntermBlock *root,
43
    ANGLE_NO_DISCARD bool insertSampleMaskWritingLogic(TIntermBlock *root,
39
                                                       const TVariable *driverUniforms);
44
                                                       const TVariable *driverUniforms);
40
    ANGLE_NO_DISCARD bool insertRasterizerDiscardLogic(TIntermBlock *root);
45
    ANGLE_NO_DISCARD bool insertRasterizationDiscardLogic(TIntermBlock *root);
46
47
    ANGLE_NO_DISCARD bool replaceAllMainDiscardUses(TIntermBlock *root);
48
49
    ANGLE_NO_DISCARD TIntermAggregate *createDiscardWrapperFunc(TIntermBlock *root);
50
51
    bool mEmulatedInstanceID = false;
41
};
52
};
42
53
43
}  // namespace sh
54
}  // namespace sh
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect.cpp +1439 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include "compiler/translator/TranslatorMetalDirect.h"
8
9
#include "angle_gl.h"
10
#include "common/utilities.h"
11
#include "compiler/translator/BuiltinsWorkaroundGLSL.h"
12
#include "compiler/translator/ImmutableStringBuilder.h"
13
#include "compiler/translator/OutputVulkanGLSL.h"
14
#include "compiler/translator/StaticType.h"
15
#include "compiler/translator/TranslatorMetalDirect/AddExplicitTypeCasts.h"
16
#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
17
#include "compiler/translator/TranslatorMetalDirect/ConstantNames.h"
18
#include "compiler/translator/TranslatorMetalDirect/EmitMetal.h"
19
#include "compiler/translator/TranslatorMetalDirect/HoistConstants.h"
20
#include "compiler/translator/TranslatorMetalDirect/Name.h"
21
#include "compiler/translator/TranslatorMetalDirect/ReduceInterfaceBlocks.h"
22
#include "compiler/translator/TranslatorMetalDirect/RewriteCaseDeclarations.h"
23
#include "compiler/translator/TranslatorMetalDirect/RewriteGlobalQualifierDecls.h"
24
#include "compiler/translator/TranslatorMetalDirect/RewriteKeywords.h"
25
#include "compiler/translator/TranslatorMetalDirect/RewriteOutArgs.h"
26
#include "compiler/translator/TranslatorMetalDirect/RewritePipelines.h"
27
#include "compiler/translator/TranslatorMetalDirect/RewriteUnaddressableReferences.h"
28
#include "compiler/translator/TranslatorMetalDirect/SeparateCompoundExpressions.h"
29
#include "compiler/translator/TranslatorMetalDirect/SeparateCompoundStructDeclarations.h"
30
#include "compiler/translator/TranslatorMetalDirect/SymbolEnv.h"
31
#include "compiler/translator/TranslatorMetalDirect/ToposortStructs.h"
32
#include "compiler/translator/TranslatorMetalDirect/WrapMain.h"
33
#include "compiler/translator/TranslatorMetalUtils.h"
34
#include "compiler/translator/tree_ops/InitializeVariables.h"
35
#include "compiler/translator/tree_ops/NameEmbeddedUniformStructs.h"
36
#include "compiler/translator/tree_ops/RemoveAtomicCounterBuiltins.h"
37
#include "compiler/translator/tree_ops/RemoveInactiveInterfaceVariables.h"
38
#include "compiler/translator/tree_ops/RewriteAtomicCounters.h"
39
#include "compiler/translator/tree_ops/RewriteCubeMapSamplersAs2DArray.h"
40
#include "compiler/translator/tree_ops/RewriteDfdy.h"
41
#include "compiler/translator/tree_ops/RewriteStructSamplers.h"
42
#include "compiler/translator/tree_util/BuiltIn.h"
43
#include "compiler/translator/tree_util/FindFunction.h"
44
#include "compiler/translator/tree_util/FindMain.h"
45
#include "compiler/translator/tree_util/FindSymbolNode.h"
46
#include "compiler/translator/tree_util/IntermNode_util.h"
47
#include "compiler/translator/tree_util/ReplaceClipDistanceVariable.h"
48
#include "compiler/translator/tree_util/ReplaceVariable.h"
49
#include "compiler/translator/tree_util/RunAtTheEndOfShader.h"
50
#include "compiler/translator/util.h"
51
52
namespace sh
53
{
54
55
namespace
56
{
57
58
constexpr Name kCoverageMaskField("coverageMask", SymbolType::UserDefined);
59
constexpr Name kEmuInstanceIDField("emulatedInstanceID", SymbolType::UserDefined);
60
#if 0
61
constexpr Name kSampleMaskWriteFuncName("WriteSampleMask");
62
constexpr Name kDiscardWrapperFuncName("DiscardWrapper");
63
#endif
64
constexpr Name kEmulatedDepthRangeParams("DepthRangeParams");
65
constexpr Name kUniformsBlockName("AngleUniforms");
66
constexpr Name kUniformsVarName("angleUniforms");
67
constexpr Name kFlippedPointCoordName("flippedPointCoord", SymbolType::UserDefined);
68
constexpr Name kFlippedFragCoordName("flippedFragCoord", SymbolType::UserDefined);
69
70
constexpr const char kViewport[]             = "viewport";
71
constexpr const char kHalfRenderArea[]       = "halfRenderArea";
72
constexpr const char kFlipXY[]               = "flipXY";
73
constexpr const char kNegFlipXY[]            = "negFlipXY";
74
constexpr const char kClipDistancesEnabled[] = "clipDistancesEnabled";
75
constexpr const char kXfbActiveUnpaused[]    = "xfbActiveUnpaused";
76
constexpr const char kXfbVerticesPerDraw[]   = "xfbVerticesPerDraw";
77
constexpr const char kXfbBufferOffsets[]     = "xfbBufferOffsets";
78
constexpr const char kAcbBufferOffsets[]     = "acbBufferOffsets";
79
constexpr const char kDepthRange[]           = "depthRange";
80
constexpr const char kPreRotation[]          = "preRotation";
81
constexpr const char kFragRotation[]         = "fragRotation";
82
83
constexpr const TVariable kgl_VertexIndexMetal(
84
    BuiltInId::gl_VertexIndex,
85
    ImmutableString("gl_VertexIndex"),
86
    SymbolType::BuiltIn,
87
    TExtension::UNDEFINED,
88
    StaticType::Get<EbtUInt, EbpHigh, EvqVertexID, 1, 1>());
89
90
constexpr size_t kNumGraphicsDriverUniforms                                                = 12;
91
constexpr std::array<const char *, kNumGraphicsDriverUniforms> kGraphicsDriverUniformNames = {
92
    {kViewport, kHalfRenderArea, kFlipXY, kNegFlipXY, kClipDistancesEnabled, kXfbActiveUnpaused,
93
     kXfbVerticesPerDraw, kXfbBufferOffsets, kAcbBufferOffsets, kDepthRange, kPreRotation,
94
     kFragRotation}};
95
96
constexpr size_t kNumComputeDriverUniforms                                               = 1;
97
constexpr std::array<const char *, kNumComputeDriverUniforms> kComputeDriverUniformNames = {
98
    {kAcbBufferOffsets}};
99
100
class DeclareStructTypesTraverser : public TIntermTraverser
101
{
102
  public:
103
    explicit DeclareStructTypesTraverser(TOutputMSL *outputMSL)
104
        : TIntermTraverser(true, false, false), mOutputMSL(outputMSL)
105
    {}
106
107
    bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
108
    {
109
        ASSERT(visit == PreVisit);
110
        if (!mInGlobalScope)
111
        {
112
            return false;
113
        }
114
115
        const TIntermSequence &sequence = *(node->getSequence());
116
        TIntermTyped *declarator        = sequence.front()->getAsTyped();
117
        const TType &type               = declarator->getType();
118
119
        if (type.isStructSpecifier())
120
        {
121
            const TStructure *structure = type.getStruct();
122
123
            // Embedded structs should be parsed away by now.
124
            ASSERT(structure->symbolType() != SymbolType::Empty);
125
            // outputMSL->writeStructType(structure);
126
127
            TIntermSymbol *symbolNode = declarator->getAsSymbolNode();
128
            if (symbolNode && symbolNode->variable().symbolType() == SymbolType::Empty)
129
            {
130
                // Remove the struct specifier declaration from the tree so it isn't parsed again.
131
                TIntermSequence emptyReplacement;
132
                mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), node,
133
                                                emptyReplacement);
134
            }
135
        }
136
        // TODO: REMOVE, used to remove 'unsued' warning
137
        mOutputMSL = nullptr;
138
139
        return false;
140
    }
141
142
  private:
143
    TOutputMSL *mOutputMSL;
144
};
145
146
class DeclareDefaultUniformsTraverser : public TIntermTraverser
147
{
148
  public:
149
    DeclareDefaultUniformsTraverser(TInfoSinkBase *sink,
150
                                    ShHashFunction64 hashFunction,
151
                                    NameMap *nameMap)
152
        : TIntermTraverser(true, true, true),
153
          mSink(sink),
154
          mHashFunction(hashFunction),
155
          mNameMap(nameMap),
156
          mInDefaultUniform(false)
157
    {}
158
159
    bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
160
    {
161
        const TIntermSequence &sequence = *(node->getSequence());
162
163
        // TODO(jmadill): Compound declarations.
164
        ASSERT(sequence.size() == 1);
165
166
        TIntermTyped *variable = sequence.front()->getAsTyped();
167
        const TType &type      = variable->getType();
168
        bool isUniform         = type.getQualifier() == EvqUniform && !type.isInterfaceBlock() &&
169
                         !IsOpaqueType(type.getBasicType());
170
171
        if (visit == PreVisit)
172
        {
173
            if (isUniform)
174
            {
175
                (*mSink) << "    " << GetTypeName(type, mHashFunction, mNameMap) << " ";
176
                mInDefaultUniform = true;
177
            }
178
        }
179
        else if (visit == InVisit)
180
        {
181
            mInDefaultUniform = isUniform;
182
        }
183
        else if (visit == PostVisit)
184
        {
185
            if (isUniform)
186
            {
187
                (*mSink) << ";\n";
188
189
                // Remove the uniform declaration from the tree so it isn't parsed again.
190
                TIntermSequence emptyReplacement;
191
                mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), node,
192
                                                emptyReplacement);
193
            }
194
195
            mInDefaultUniform = false;
196
        }
197
        return true;
198
    }
199
200
    void visitSymbol(TIntermSymbol *symbol) override
201
    {
202
        if (mInDefaultUniform)
203
        {
204
            const ImmutableString &name = symbol->variable().name();
205
            ASSERT(!name.beginsWith("gl_"));
206
            (*mSink) << HashName(&symbol->variable(), mHashFunction, mNameMap)
207
                     << ArrayString(symbol->getType());
208
        }
209
    }
210
211
  private:
212
    TInfoSinkBase *mSink;
213
    ShHashFunction64 mHashFunction;
214
    NameMap *mNameMap;
215
    bool mInDefaultUniform;
216
};
217
218
TIntermBinary *CreateDriverUniformRef(const TVariable &driverUniforms, const char *fieldName)
219
{
220
    size_t fieldIndex = FindFieldIndex(driverUniforms.getType().getStruct()->fields(), fieldName);
221
222
    TIntermSymbol *angleUniformsRef = new TIntermSymbol(&driverUniforms);
223
    TConstantUnion *uniformIndex    = new TConstantUnion;
224
    uniformIndex->setIConst(static_cast<int>(fieldIndex));
225
    TIntermConstantUnion *indexRef =
226
        new TIntermConstantUnion(uniformIndex, *StaticType::GetBasic<EbtInt>());
227
    return new TIntermBinary(EOpIndexDirectStruct, angleUniformsRef, indexRef);
228
}
229
230
#if 0
231
// Unlike Vulkan having auto viewport flipping extension, in Metal we have to flip gl_Position.y
232
// manually.
233
// This operation performs flipping the gl_Position.y using this expression:
234
// gl_Position.y = gl_Position.y * negViewportScaleY
235
ANGLE_NO_DISCARD bool AppendVertexShaderPositionYCorrectionToMain(TCompiler &compiler,
236
                                                                  TIntermBlock &root,
237
                                                                  TIntermSwizzle &negFlipY)
238
{
239
    TSymbolTable &symbolTable = compiler.getSymbolTable();
240
241
    // Create a symbol reference to "gl_Position"
242
    const TVariable *position  = BuiltInVariable::gl_Position();
243
    TIntermSymbol *positionRef = new TIntermSymbol(position);
244
245
    // Create a swizzle to "gl_Position.y"
246
    TVector<int> swizzleOffsetY;
247
    swizzleOffsetY.push_back(1);
248
    TIntermSwizzle *positionY = new TIntermSwizzle(positionRef, swizzleOffsetY);
249
250
    // Create the expression "gl_Position.y * negFlipY"
251
    TIntermBinary *inverseY = new TIntermBinary(EOpMul, positionY->deepCopy(), &negFlipY);
252
253
    // Create the assignment "gl_Position.y = gl_Position.y * negViewportScaleY
254
    TIntermTyped *positionYLHS = positionY->deepCopy();
255
    TIntermBinary *assignment  = new TIntermBinary(TOperator::EOpAssign, positionYLHS, inverseY);
256
257
    // Append the assignment as a statement at the end of the shader.
258
    return RunAtTheEndOfShader(&compiler, &root, assignment, &symbolTable);
259
}
260
#endif
261
262
#if 0
263
// Initialize unused varying outputs.
264
ANGLE_NO_DISCARD bool InitializeUnusedOutputs(TIntermBlock &root,
265
                                              TSymbolTable &symbolTable,
266
                                              const InitVariableList &unusedVars)
267
{
268
    if (unusedVars.empty())
269
    {
270
        return true;
271
    }
272
273
    TIntermSequence *insertSequence = new TIntermSequence;
274
275
    for (const sh::ShaderVariable &var : unusedVars)
276
    {
277
        ASSERT(!var.active);
278
        const TIntermSymbol *symbol = FindSymbolNode(&root, var.name);
279
        ASSERT(symbol);
280
281
        TIntermSequence *initCode = CreateInitCode(symbol, false, false, &symbolTable);
282
283
        insertSequence->insert(insertSequence->end(), initCode->begin(), initCode->end());
284
    }
285
286
    if (insertSequence)
287
    {
288
        TIntermFunctionDefinition *main = FindMain(&root);
289
        TIntermSequence *mainSequence   = main->getBody()->getSequence();
290
291
        // Insert init code at the start of main()
292
        mainSequence->insert(mainSequence->begin(), insertSequence->begin(), insertSequence->end());
293
    }
294
295
    return true;
296
}
297
#endif
298
299
const TVariable *AddComputeDriverUniformsToShader(TIntermBlock &root, TSymbolTable &symbolTable)
300
{
301
    // This field list mirrors the structure of ComputeDriverUniforms in ContextVk.cpp.
302
    TFieldList *driverFieldList = new TFieldList;
303
304
    const std::array<TType *, kNumComputeDriverUniforms> kDriverUniformTypes = {{
305
        new TType(EbtUInt, 4),
306
    }};
307
308
    for (size_t uniformIndex = 0; uniformIndex < kNumComputeDriverUniforms; ++uniformIndex)
309
    {
310
        TField *driverUniformField =
311
            new TField(kDriverUniformTypes[uniformIndex],
312
                       ImmutableString(kComputeDriverUniformNames[uniformIndex]), kNoSourceLoc,
313
                       SymbolType::AngleInternal);
314
        driverFieldList->push_back(driverUniformField);
315
    }
316
317
    return DeclareStructure(&root, &symbolTable, driverFieldList, EvqUniform,
318
                            TMemoryQualifier::Create(), 0, kUniformsBlockName.rawName(),
319
                            &kUniformsVarName.rawName())
320
        .second;
321
}
322
323
// The Add*DriverUniformsToShader operation adds an internal uniform block to a shader. The driver
324
// block is used to implement Vulkan-specific features and workarounds. Returns the driver uniforms
325
// variable.
326
//
327
// There are Graphics and Compute variations as they require different uniforms.
328
const TVariable *AddGraphicsDriverUniformsToShader(TIntermBlock &root,
329
                                                   TSymbolTable &symbolTable,
330
                                                   const std::vector<TField *> &additionalFields)
331
{
332
    // Init the depth range type.
333
    TFieldList *depthRangeParamsFields = new TFieldList();
334
    depthRangeParamsFields->push_back(new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1, 1),
335
                                                 ImmutableString("near"), kNoSourceLoc,
336
                                                 SymbolType::AngleInternal));
337
    depthRangeParamsFields->push_back(new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1, 1),
338
                                                 ImmutableString("far"), kNoSourceLoc,
339
                                                 SymbolType::AngleInternal));
340
    depthRangeParamsFields->push_back(new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1, 1),
341
                                                 ImmutableString("diff"), kNoSourceLoc,
342
                                                 SymbolType::AngleInternal));
343
    // This additional field might be used by subclass such as TranslatorMetal.
344
    depthRangeParamsFields->push_back(new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1, 1),
345
                                                 ImmutableString("reserved"), kNoSourceLoc,
346
                                                 SymbolType::AngleInternal));
347
348
    const TStructure *emulatedDepthRangeParams =
349
        DeclareStructure(&root, &symbolTable, depthRangeParamsFields, EvqGlobal,
350
                         TMemoryQualifier::Create(), 0, kEmulatedDepthRangeParams.rawName(),
351
                         nullptr)
352
            .first->getType()
353
            .getStruct();
354
355
    // This field list mirrors the structure of GraphicsDriverUniforms in ContextVk.cpp.
356
    TFieldList *driverFieldList = new TFieldList;
357
358
    const std::array<TType *, kNumGraphicsDriverUniforms> kDriverUniformTypes = {{
359
        new TType(EbtFloat, 4),
360
        new TType(EbtFloat, 2),
361
        new TType(EbtFloat, 2),
362
        new TType(EbtFloat, 2),
363
        new TType(EbtUInt),  // uint clipDistancesEnabled;  // 32 bits for 32 clip distances max
364
        new TType(EbtUInt),
365
        new TType(EbtUInt),
366
        // NOTE: There's a vec3 gap here that can be used in the future
367
        new TType(EbtInt, 4),
368
        new TType(EbtUInt, 4),
369
        new TType(emulatedDepthRangeParams, false),
370
        new TType(EbtFloat, 2, 4),
371
        new TType(EbtFloat, 2, 4),
372
    }};
373
374
    for (size_t uniformIndex = 0; uniformIndex < kNumGraphicsDriverUniforms; ++uniformIndex)
375
    {
376
        TField *driverUniformField =
377
            new TField(kDriverUniformTypes[uniformIndex],
378
                       ImmutableString(kGraphicsDriverUniformNames[uniformIndex]), kNoSourceLoc,
379
                       SymbolType::AngleInternal);
380
        driverFieldList->push_back(driverUniformField);
381
    }
382
383
    // Back-end specific fields
384
    driverFieldList->insert(driverFieldList->end(), additionalFields.begin(),
385
                            additionalFields.end());
386
387
    // Define a driver uniform block "ANGLEUniformBlock" with instance name "ANGLEUniforms".
388
    return DeclareStructure(&root, &symbolTable, driverFieldList, EvqUniform,
389
                            TMemoryQualifier::Create(), 0, kUniformsBlockName.rawName(),
390
                            &kUniformsVarName.rawName())
391
        .second;
392
}
393
394
// Declares a new variable to replace gl_DepthRange, its values are fed from a driver uniform.
395
ANGLE_NO_DISCARD bool ReplaceGLDepthRangeWithDriverUniform(TCompiler &compiler,
396
                                                           TIntermBlock &root,
397
                                                           const TVariable &driverUniforms)
398
{
399
    TSymbolTable &symbolTable = compiler.getSymbolTable();
400
401
    // Create a symbol reference to "gl_DepthRange"
402
    const TVariable *depthRangeVar = static_cast<const TVariable *>(
403
        symbolTable.findBuiltIn(ImmutableString("gl_DepthRange"), 0));
404
405
    // ANGLEUniforms.depthRange
406
    TIntermBinary *angleEmulatedDepthRangeRef = CreateDriverUniformRef(driverUniforms, kDepthRange);
407
408
    // Use this variable instead of gl_DepthRange everywhere.
409
    return ReplaceVariableWithTyped(&compiler, &root, depthRangeVar, angleEmulatedDepthRangeRef);
410
}
411
412
TIntermSequence *GetMainSequence(TIntermBlock &root)
413
{
414
    TIntermFunctionDefinition *main = FindMain(&root);
415
    return main->getBody()->getSequence();
416
}
417
418
ANGLE_NO_DISCARD bool AppendVertexShaderTransformFeedbackOutputToMain(TCompiler &compiler,
419
                                                                      TIntermBlock &root)
420
{
421
    TSymbolTable &symbolTable = compiler.getSymbolTable();
422
    TVariable *xfbPlaceholder = new TVariable(&symbolTable, ImmutableString("@@ XFB-OUT @@"),
423
                                              new TType(), SymbolType::AngleInternal);
424
425
    // Append the assignment as a statement at the end of the shader.
426
    return RunAtTheEndOfShader(&compiler, &root, new TIntermSymbol(xfbPlaceholder), &symbolTable);
427
}
428
429
// This operation performs the viewport depth translation needed by Vulkan. In GL the viewport
430
// transformation is slightly different - see the GL 2.0 spec section "2.12.1 Controlling the
431
// Viewport". In Vulkan the corresponding spec section is currently "23.4. Coordinate
432
// Transformations".
433
// The equations reduce to an expression:
434
//
435
//     z_vk = 0.5 * (w_gl + z_gl)
436
//
437
// where z_vk is the depth output of a Vulkan vertex shader and z_gl is the same for GL.
438
ANGLE_NO_DISCARD bool AppendVertexShaderDepthCorrectionToMain(TCompiler &compiler,
439
                                                              TIntermBlock &root)
440
{
441
    TSymbolTable &symbolTable = compiler.getSymbolTable();
442
443
    const TVariable *position  = BuiltInVariable::gl_Position();
444
    TIntermSymbol *positionRef = new TIntermSymbol(position);
445
446
    TVector<int> swizzleOffsetZ = {2};
447
    TIntermSwizzle *positionZ   = new TIntermSwizzle(positionRef, swizzleOffsetZ);
448
449
    TIntermConstantUnion *oneHalf = CreateFloatNode(0.5f);
450
451
    TVector<int> swizzleOffsetW = {3};
452
    TIntermSwizzle *positionW   = new TIntermSwizzle(positionRef->deepCopy(), swizzleOffsetW);
453
454
    // Create the expression "(gl_Position.z + gl_Position.w) * 0.5".
455
    TIntermBinary *zPlusW = new TIntermBinary(EOpAdd, positionZ->deepCopy(), positionW->deepCopy());
456
    TIntermBinary *halfZPlusW = new TIntermBinary(EOpMul, zPlusW, oneHalf->deepCopy());
457
458
    // Create the assignment "gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5"
459
    TIntermTyped *positionZLHS = positionZ->deepCopy();
460
    TIntermBinary *assignment  = new TIntermBinary(TOperator::EOpAssign, positionZLHS, halfZPlusW);
461
462
    // Append the assignment as a statement at the end of the shader.
463
    return RunAtTheEndOfShader(&compiler, &root, assignment, &symbolTable);
464
}
465
466
// This operation performs Android pre-rotation and y-flip.  For Android (and potentially other
467
// platforms), the device may rotate, such that the orientation of the application is rotated
468
// relative to the native orientation of the device.  This is corrected in part by multiplying
469
// gl_Position by a mat2.
470
// The equations reduce to an expression:
471
//
472
//     gl_Position.xy = gl_Position.xy * preRotation
473
ANGLE_NO_DISCARD bool AppendPreRotation(TCompiler &compiler,
474
                                        TIntermBlock &root,
475
                                        const TVariable &driverUniforms)
476
{
477
    TSymbolTable &symbolTable     = compiler.getSymbolTable();
478
    TIntermBinary *preRotationRef = CreateDriverUniformRef(driverUniforms, kPreRotation);
479
    TIntermSymbol *glPos          = new TIntermSymbol(BuiltInVariable::gl_Position());
480
    TVector<int> swizzleOffsetXY  = {0, 1};
481
    TIntermSwizzle *glPosXY       = new TIntermSwizzle(glPos, swizzleOffsetXY);
482
483
    // Create the expression "(gl_Position.xy * preRotation)"
484
    TIntermBinary *zRotated =
485
        new TIntermBinary(EOpMatrixTimesVector, preRotationRef->deepCopy(), glPosXY->deepCopy());
486
487
    // Create the assignment "gl_Position.xy = (gl_Position.xy * preRotation)"
488
    TIntermBinary *assignment =
489
        new TIntermBinary(TOperator::EOpAssign, glPosXY->deepCopy(), zRotated);
490
491
    // Append the assignment as a statement at the end of the shader.
492
    return RunAtTheEndOfShader(&compiler, &root, assignment, &symbolTable);
493
}
494
495
ANGLE_NO_DISCARD bool RotateAndFlipBuiltinVariable(TCompiler &compiler,
496
                                                   TIntermBlock &root,
497
                                                   TIntermSequence &insertSequence,
498
                                                   TIntermTyped &flipXY,
499
                                                   const TVariable &builtin,
500
                                                   const Name &flippedVariableName,
501
                                                   TIntermTyped &pivot,
502
                                                   TIntermTyped *fragRotation)
503
{
504
    TSymbolTable &symbolTable = compiler.getSymbolTable();
505
506
    // Create a symbol reference to 'builtin'.
507
    TIntermSymbol *builtinRef = new TIntermSymbol(&builtin);
508
509
    // Create a swizzle to "builtin.xy"
510
    TVector<int> swizzleOffsetXY = {0, 1};
511
    TIntermSwizzle *builtinXY    = new TIntermSwizzle(builtinRef, swizzleOffsetXY);
512
513
    // Create a symbol reference to our new variable that will hold the modified builtin.
514
    const TType *type = StaticType::GetForVec<EbtFloat>(
515
        EvqGlobal, static_cast<unsigned char>(builtin.getType().getNominalSize()));
516
    TVariable *replacementVar = new TVariable(&symbolTable, flippedVariableName.rawName(), type,
517
                                              flippedVariableName.symbolType());
518
    DeclareGlobalVariable(&root, replacementVar);
519
    TIntermSymbol *flippedBuiltinRef = new TIntermSymbol(replacementVar);
520
521
    // Use this new variable instead of 'builtin' everywhere.
522
    if (!ReplaceVariable(&compiler, &root, &builtin, replacementVar))
523
    {
524
        return false;
525
    }
526
527
    // Create the expression "(builtin.xy * fragRotation)"
528
    TIntermTyped *rotatedXY;
529
    if (fragRotation)
530
    {
531
        rotatedXY = new TIntermBinary(EOpMatrixTimesVector, fragRotation->deepCopy(),
532
                                      builtinXY->deepCopy());
533
    }
534
    else
535
    {
536
        // No rotation applied, use original variable.
537
        rotatedXY = builtinXY->deepCopy();
538
    }
539
540
    // Create the expression "(builtin.xy - pivot) * flipXY + pivot
541
    TIntermBinary *removePivot = new TIntermBinary(EOpSub, rotatedXY, &pivot);
542
    TIntermBinary *inverseXY   = new TIntermBinary(EOpMul, removePivot, &flipXY);
543
    TIntermBinary *plusPivot   = new TIntermBinary(EOpAdd, inverseXY, pivot.deepCopy());
544
545
    // Create the corrected variable and copy the value of the original builtin.
546
    TIntermSequence *sequence = new TIntermSequence();
547
    sequence->push_back(builtinRef->deepCopy());
548
    TIntermAggregate *aggregate = TIntermAggregate::CreateConstructor(builtin.getType(), sequence);
549
    TIntermBinary *assignment   = new TIntermBinary(EOpInitialize, flippedBuiltinRef, aggregate);
550
551
    // Create an assignment to the replaced variable's .xy.
552
    TIntermSwizzle *correctedXY =
553
        new TIntermSwizzle(flippedBuiltinRef->deepCopy(), swizzleOffsetXY);
554
    TIntermBinary *assignToY = new TIntermBinary(EOpAssign, correctedXY, plusPivot);
555
556
    // Add this assigment at the beginning of the main function
557
    {
558
        TIntermBinary *nodes[] = {assignment, assignToY};
559
        insertSequence.insert(insertSequence.begin(), std::begin(nodes), std::end(nodes));
560
    }
561
562
    return compiler.validateAST(&root);
563
}
564
565
ANGLE_NO_DISCARD bool InsertFragCoordCorrection(TCompiler &compiler,
566
                                                ShCompileOptions compileOptions,
567
                                                TIntermBlock &root,
568
                                                TIntermSequence &insertSequence,
569
                                                const TVariable &driverUniforms)
570
{
571
    TIntermBinary &flipXY       = *CreateDriverUniformRef(driverUniforms, kFlipXY);
572
    TIntermBinary &pivot        = *CreateDriverUniformRef(driverUniforms, kHalfRenderArea);
573
    TIntermBinary *fragRotation = (compileOptions & SH_ADD_PRE_ROTATION)
574
                                      ? CreateDriverUniformRef(driverUniforms, kFragRotation)
575
                                      : nullptr;
576
    return RotateAndFlipBuiltinVariable(compiler, root, insertSequence, flipXY,
577
                                        *BuiltInVariable::gl_FragCoord(), kFlippedFragCoordName,
578
                                        pivot, fragRotation);
579
}
580
581
TIntermBinary *GetDriverUniformDepthRangeReservedFieldRef(const TVariable &driverUniforms)
582
{
583
    TIntermBinary *depthRange = CreateDriverUniformRef(driverUniforms, kDepthRange);
584
585
    return new TIntermBinary(EOpIndexDirectStruct, depthRange, CreateIndexNode(3));
586
}
587
588
void DeclareRightBeforeMain(TIntermBlock &root, const TVariable &var)
589
{
590
    root.insertChildNodes(FindMainIndex(&root), {new TIntermDeclaration{&var}});
591
}
592
593
void AddFragColorDeclaration(TIntermBlock &root, TSymbolTable &symbolTable)
594
{
595
    root.insertChildNodes(FindMainIndex(&root),
596
                          TIntermSequence{new TIntermDeclaration{BuiltInVariable::gl_FragColor()}});
597
}
598
599
void AddFragDepthDeclaration(TIntermBlock &root, TSymbolTable &symbolTable)
600
{
601
    root.insertChildNodes(FindMainIndex(&root),
602
                          TIntermSequence{new TIntermDeclaration{BuiltInVariable::gl_FragDepth()}});
603
}
604
605
ANGLE_NO_DISCARD bool AddFragDataDeclaration(TCompiler &compiler, TIntermBlock &root)
606
{
607
    TSymbolTable &symbolTable = compiler.getSymbolTable();
608
    const int maxDrawBuffers  = compiler.getResources().MaxDrawBuffers;
609
    TType *gl_FragDataType    = new TType(EbtFloat, EbpMedium, EvqFragData, 4, 1);
610
    std::vector<const TVariable *> glFragDataSlots;
611
    TIntermSequence declareGLFragdataSequence;
612
613
    // Create gl_FragData_0,1,2,3
614
    for (int i = 0; i < maxDrawBuffers; i++)
615
    {
616
        ImmutableStringBuilder builder(strlen("gl_FragData_") + 2);
617
        builder << "gl_FragData_";
618
        builder.appendDecimal(i);
619
        const TVariable *glFragData =
620
            new TVariable(&symbolTable, builder, gl_FragDataType, SymbolType::AngleInternal,
621
                          TExtension::UNDEFINED);
622
        glFragDataSlots.push_back(glFragData);
623
        declareGLFragdataSequence.push_back(new TIntermDeclaration{glFragData});
624
    }
625
    root.insertChildNodes(FindMainIndex(&root), declareGLFragdataSequence);
626
627
    // Create an internal gl_FragData array type, compatible with indexing syntax.
628
    TType *gl_FragDataTypeArray = new TType(EbtFloat, EbpMedium, EvqGlobal, 4, 1);
629
    gl_FragDataTypeArray->makeArray(maxDrawBuffers);
630
    const TVariable *glFragDataGlobal = new TVariable(&symbolTable, ImmutableString("gl_FragData"),
631
                                                      gl_FragDataTypeArray, SymbolType::BuiltIn);
632
633
    DeclareGlobalVariable(&root, glFragDataGlobal);
634
    const TIntermSymbol *originalGLFragData = FindSymbolNode(&root, ImmutableString("gl_FragData"));
635
    ASSERT(originalGLFragData);
636
637
    // Replace gl_FragData() with our globally defined fragdata
638
    if (!ReplaceVariable(&compiler, &root, &(originalGLFragData->variable()), glFragDataGlobal))
639
    {
640
        return false;
641
    }
642
643
    // Assign each array attribute to an output
644
    TIntermBlock *insertSequence = new TIntermBlock();
645
    for (int i = 0; i < maxDrawBuffers; i++)
646
    {
647
        TIntermTyped *glFragDataSlot         = new TIntermSymbol(glFragDataSlots[i]);
648
        TIntermTyped *glFragDataGlobalSymbol = new TIntermSymbol(glFragDataGlobal);
649
        auto &access                         = AccessIndex(*glFragDataGlobalSymbol, i);
650
        TIntermBinary *assignment =
651
            new TIntermBinary(TOperator::EOpAssign, glFragDataSlot, &access);
652
        insertSequence->appendStatement(assignment);
653
    }
654
    return RunAtTheEndOfShader(&compiler, &root, insertSequence, &symbolTable);
655
}
656
657
ANGLE_NO_DISCARD bool EmulateInstanceID(TCompiler &compiler,
658
                                        TIntermBlock &root,
659
                                        const TVariable &driverUniforms)
660
{
661
    TIntermBinary *emuInstanceID =
662
        CreateDriverUniformRef(driverUniforms, kEmuInstanceIDField.rawName().data());
663
    const TVariable *instanceID = BuiltInVariable::gl_InstanceIndex();
664
    return ReplaceVariableWithTyped(&compiler, &root, instanceID, emuInstanceID);
665
}
666
667
// Unlike Vulkan having auto viewport flipping extension, in Metal we have to flip gl_Position.y
668
// manually.
669
// This operation performs flipping the gl_Position.y using this expression:
670
// gl_Position.y = gl_Position.y * negViewportScaleY
671
ANGLE_NO_DISCARD bool AppendVertexShaderPositionYCorrectionToMain(TCompiler &compiler,
672
                                                                  TIntermBlock &root,
673
                                                                  TIntermSwizzle &negFlipY)
674
{
675
    TSymbolTable &symbolTable = compiler.getSymbolTable();
676
677
    const TVariable *position  = BuiltInVariable::gl_Position();
678
    TIntermSymbol *positionRef = new TIntermSymbol(position);
679
680
    TVector<int> swizzleOffsetY;
681
    swizzleOffsetY.push_back(1);
682
    TIntermSwizzle *positionY = new TIntermSwizzle(positionRef, swizzleOffsetY);
683
684
    // Create the expression "gl_Position.y * negFlipY"
685
    TIntermBinary *inverseY = new TIntermBinary(EOpMul, positionY->deepCopy(), &negFlipY);
686
687
    // Create the assignment "gl_Position.y = gl_Position.y * negViewportScaleY
688
    TIntermTyped *positionYLHS = positionY->deepCopy();
689
    TIntermBinary *assignment  = new TIntermBinary(TOperator::EOpAssign, positionYLHS, inverseY);
690
691
    // Append the assignment as a statement at the end of the shader.
692
    return RunAtTheEndOfShader(&compiler, &root, assignment, &symbolTable);
693
}
694
695
}  // namespace
696
697
TranslatorMetalDirect::TranslatorMetalDirect(sh::GLenum type,
698
                                             ShShaderSpec spec,
699
                                             ShShaderOutput output)
700
    : TCompiler(type, spec, output)
701
{}
702
703
// static
704
const char *TranslatorMetalDirect::GetCoverageMaskEnabledConstName()
705
{
706
    return constant_names::kCoverageMaskEnabled.rawName().data();
707
}
708
709
// static
710
const char *TranslatorMetalDirect::GetRasterizationDiscardEnabledConstName()
711
{
712
    return constant_names::kRasterizationDiscardEnabled.rawName().data();
713
}
714
715
ANGLE_NO_DISCARD bool TranslatorMetalDirect::insertRasterizationDiscardLogic(TIntermBlock &root)
716
{
717
    TSymbolTable *symbolTable = &getSymbolTable();
718
719
    TType *boolType = new TType(EbtBool);
720
    boolType->setQualifier(EvqConst);
721
    TVariable *discardEnabledVar =
722
        new TVariable(symbolTable, constant_names::kRasterizationDiscardEnabled.rawName(), boolType,
723
                      constant_names::kRasterizationDiscardEnabled.symbolType());
724
725
    const TVariable *position  = BuiltInVariable::gl_Position();
726
    TIntermSymbol *positionRef = new TIntermSymbol(position);
727
728
    // Create vec4(-3, -3, -3, 1):
729
    auto vec4Type             = new TType(EbtFloat, 4);
730
    TIntermSequence *vec4Args = new TIntermSequence();
731
    vec4Args->push_back(CreateFloatNode(-3.0f));
732
    vec4Args->push_back(CreateFloatNode(-3.0f));
733
    vec4Args->push_back(CreateFloatNode(-3.0f));
734
    vec4Args->push_back(CreateFloatNode(1.0f));
735
    TIntermAggregate *constVarConstructor =
736
        TIntermAggregate::CreateConstructor(*vec4Type, vec4Args);
737
738
    // Create the assignment "gl_Position = vec4(-3, -3, -3, 1)"
739
    TIntermBinary *assignment =
740
        new TIntermBinary(TOperator::EOpAssign, positionRef->deepCopy(), constVarConstructor);
741
742
    TIntermBlock *discardBlock = new TIntermBlock;
743
    discardBlock->appendStatement(assignment);
744
745
    TIntermSymbol *discardEnabled = new TIntermSymbol(discardEnabledVar);
746
    TIntermIfElse *ifCall         = new TIntermIfElse(discardEnabled, discardBlock, nullptr);
747
748
    return RunAtTheEndOfShader(this, &root, ifCall, symbolTable);
749
}
750
751
// Metal needs to inverse the depth if depthRange is is reverse order, i.e. depth near > depth far
752
// This is achieved by multiply the depth value with scale value stored in
753
// driver uniform's depthRange.reserved
754
bool TranslatorMetalDirect::transformDepthBeforeCorrection(TIntermBlock &root,
755
                                                           const TVariable &driverUniforms)
756
{
757
    const TVariable *position  = BuiltInVariable::gl_Position();
758
    TIntermSymbol *positionRef = new TIntermSymbol(position);
759
760
    TVector<int> swizzleOffsetZ = {2};
761
    TIntermSwizzle *positionZ   = new TIntermSwizzle(positionRef, swizzleOffsetZ);
762
763
    TIntermBinary *viewportZScale = GetDriverUniformDepthRangeReservedFieldRef(driverUniforms);
764
765
    // Create the expression "gl_Position.z * depthRange.reserved".
766
    TIntermBinary *zScale = new TIntermBinary(EOpMul, positionZ->deepCopy(), viewportZScale);
767
768
    // Create the assignment "gl_Position.z = gl_Position.z * depthRange.reserved"
769
    TIntermTyped *positionZLHS = positionZ->deepCopy();
770
    TIntermBinary *assignment  = new TIntermBinary(TOperator::EOpAssign, positionZLHS, zScale);
771
772
    return RunAtTheEndOfShader(this, &root, assignment, &getSymbolTable());
773
}
774
775
void TranslatorMetalDirect::createAdditionalGraphicsDriverUniformFields(
776
    std::vector<TField *> &fieldsOut)
777
{
778
    // Add coverage mask to driver uniform. Metal doesn't have built-in GL_SAMPLE_COVERAGE_VALUE
779
    // equivalent functionality, needs to emulate it using fragment shader's [[sample_mask]] output
780
    // value.
781
    TField *coverageMaskField = new TField(new TType(EbtUInt), kCoverageMaskField.rawName(),
782
                                           kNoSourceLoc, kCoverageMaskField.symbolType());
783
    fieldsOut.push_back(coverageMaskField);
784
785
    if (mEmulatedInstanceID)
786
    {
787
        TField *emuInstanceIDField = new TField(new TType(EbtInt), kEmuInstanceIDField.rawName(),
788
                                                kNoSourceLoc, kEmuInstanceIDField.symbolType());
789
        fieldsOut.push_back(emuInstanceIDField);
790
    }
791
}
792
793
TIntermSwizzle *TranslatorMetalDirect::getDriverUniformNegFlipYRef(
794
    const TVariable &driverUniforms) const
795
{
796
    // Create a swizzle to "negFlipXY.y"
797
    TIntermBinary *negFlipXY    = CreateDriverUniformRef(driverUniforms, kNegFlipXY);
798
    TVector<int> swizzleOffsetY = {1};
799
    TIntermSwizzle *negFlipY    = new TIntermSwizzle(negFlipXY, swizzleOffsetY);
800
    return negFlipY;
801
}
802
803
static std::set<ImmutableString> GetMslKeywords()
804
{
805
    std::set<ImmutableString> keywords;
806
807
    keywords.emplace("alignas");
808
    keywords.emplace("alignof");
809
    keywords.emplace("as_type");
810
    keywords.emplace("auto");
811
    keywords.emplace("catch");
812
    keywords.emplace("char");
813
    keywords.emplace("class");
814
    keywords.emplace("const_cast");
815
    keywords.emplace("constant");
816
    keywords.emplace("constexpr");
817
    keywords.emplace("decltype");
818
    keywords.emplace("delete");
819
    keywords.emplace("device");
820
    keywords.emplace("dynamic_cast");
821
    keywords.emplace("enum");
822
    keywords.emplace("explicit");
823
    keywords.emplace("export");
824
    keywords.emplace("extern");
825
    keywords.emplace("fragment");
826
    keywords.emplace("friend");
827
    keywords.emplace("goto");
828
    keywords.emplace("half");
829
    keywords.emplace("inline");
830
    keywords.emplace("int16_t");
831
    keywords.emplace("int32_t");
832
    keywords.emplace("int64_t");
833
    keywords.emplace("int8_t");
834
    keywords.emplace("kernel");
835
    keywords.emplace("long");
836
    keywords.emplace("main0");
837
    keywords.emplace("metal");
838
    keywords.emplace("mutable");
839
    keywords.emplace("namespace");
840
    keywords.emplace("new");
841
    keywords.emplace("noexcept");
842
    keywords.emplace("nullptr_t");
843
    keywords.emplace("nullptr");
844
    keywords.emplace("operator");
845
    keywords.emplace("override");
846
    keywords.emplace("private");
847
    keywords.emplace("protected");
848
    keywords.emplace("ptrdiff_t");
849
    keywords.emplace("public");
850
    keywords.emplace("ray_data");
851
    keywords.emplace("register");
852
    keywords.emplace("short");
853
    keywords.emplace("signed");
854
    keywords.emplace("size_t");
855
    keywords.emplace("sizeof");
856
    keywords.emplace("stage_in");
857
    keywords.emplace("static_assert");
858
    keywords.emplace("static_cast");
859
    keywords.emplace("static");
860
    keywords.emplace("template");
861
    keywords.emplace("this");
862
    keywords.emplace("thread_local");
863
    keywords.emplace("thread");
864
    keywords.emplace("threadgroup_imageblock");
865
    keywords.emplace("threadgroup");
866
    keywords.emplace("throw");
867
    keywords.emplace("try");
868
    keywords.emplace("typedef");
869
    keywords.emplace("typeid");
870
    keywords.emplace("typename");
871
    keywords.emplace("uchar");
872
    keywords.emplace("uint16_t");
873
    keywords.emplace("uint32_t");
874
    keywords.emplace("uint64_t");
875
    keywords.emplace("uint8_t");
876
    keywords.emplace("union");
877
    keywords.emplace("unsigned");
878
    keywords.emplace("ushort");
879
    keywords.emplace("using");
880
    keywords.emplace("vertex");
881
    keywords.emplace("virtual");
882
    keywords.emplace("volatile");
883
    keywords.emplace("wchar_t");
884
885
    return keywords;
886
}
887
888
bool TranslatorMetalDirect::translateImpl(TIntermBlock &root, ShCompileOptions compileOptions)
889
{
890
    TSymbolTable &symbolTable = getSymbolTable();
891
    IdGen idGen;
892
    ProgramPreludeConfig ppc;
893
894
    if (!WrapMain(*this, idGen, root))
895
    {
896
        return false;
897
    }
898
899
    TInfoSinkBase &sink = getInfoSink().obj;
900
#if 0
901
    if (getShaderType() == GL_VERTEX_SHADER)
902
    {
903
        if (!ShaderBuiltinsWorkaround(this, &root, &symbolTable, compileOptions))
904
        {
905
            return false;
906
        }
907
    }
908
#endif
909
910
    // Strip any inactive variables from the program.
911
    if (!RemoveInactiveInterfaceVariables(this, &root, getAttributes(), getInputVaryings(),
912
                                          getOutputVariables(), getUniforms(),
913
                                          getInterfaceBlocks()))
914
    {
915
        return false;
916
    }
917
918
    // Write out default uniforms into a uniform block assigned to a specific set/binding.
919
    int defaultUniformCount           = 0;
920
    int aggregateTypesUsedForUniforms = 0;
921
    int atomicCounterCount            = 0;
922
    for (const auto &uniform : getUniforms())
923
    {
924
        if (!uniform.isBuiltIn() && uniform.active && !gl::IsOpaqueType(uniform.type))
925
        {
926
            ++defaultUniformCount;
927
        }
928
929
        if (uniform.isStruct() || uniform.isArrayOfArrays())
930
        {
931
            ++aggregateTypesUsedForUniforms;
932
        }
933
934
        if (uniform.active && gl::IsAtomicCounterType(uniform.type))
935
        {
936
            ++atomicCounterCount;
937
        }
938
    }
939
940
    if (aggregateTypesUsedForUniforms > 0)
941
    {
942
        if (!NameEmbeddedStructUniforms(this, &root, &symbolTable))
943
        {
944
            return false;
945
        }
946
947
        bool rewriteStructSamplersResult;
948
        int removedUniformsCount;
949
950
        if (compileOptions & SH_USE_OLD_REWRITE_STRUCT_SAMPLERS)
951
        {
952
            rewriteStructSamplersResult =
953
                RewriteStructSamplersOld(this, &root, &symbolTable, &removedUniformsCount);
954
        }
955
        else
956
        {
957
            rewriteStructSamplersResult =
958
                RewriteStructSamplers(this, &root, &symbolTable, &removedUniformsCount);
959
        }
960
961
        if (!rewriteStructSamplersResult)
962
        {
963
            return false;
964
        }
965
        defaultUniformCount -= removedUniformsCount;
966
967
#if 0
968
        // We must declare the struct types before using them.
969
        DeclareStructTypesTraverser structTypesTraverser(outputMSL);
970
        root->traverse(&structTypesTraverser);
971
        if (!structTypesTraverser.updateTree(this, root))
972
        {
973
            return false;
974
        }
975
#endif
976
    }
977
978
    if (compileOptions & SH_EMULATE_SEAMFUL_CUBE_MAP_SAMPLING)
979
    {
980
        if (!RewriteCubeMapSamplersAs2DArray(this, &root, &symbolTable,
981
                                             getShaderType() == GL_FRAGMENT_SHADER))
982
        {
983
            return false;
984
        }
985
    }
986
987
#if 0
988
    // Write default uniform block
989
    if (defaultUniformCount > 0)
990
    {
991
        gl::ShaderType shaderType = gl::FromGLenum<gl::ShaderType>(getShaderType());
992
        sink << "\nstruct " << kDefaultUniformNames[shaderType] << "\n{\n";
993
        DeclareDefaultUniformsTraverser defaultTraverser(&sink, getHashFunction(), &getNameMap());
994
        root->traverse(&defaultTraverser);
995
        if (!defaultTraverser.updateTree(this, root))
996
        {
997
            return false;
998
        }
999
1000
        sink << "};\n";
1001
    }
1002
#endif
1003
1004
    const TVariable &driverUniforms = *[&]() {
1005
        if (getShaderType() == GL_COMPUTE_SHADER)
1006
        {
1007
            return AddComputeDriverUniformsToShader(root, symbolTable);
1008
        }
1009
        else
1010
        {
1011
            std::vector<TField *> additionalFields;
1012
            createAdditionalGraphicsDriverUniformFields(additionalFields);
1013
            return AddGraphicsDriverUniformsToShader(root, symbolTable, additionalFields);
1014
        }
1015
    }();
1016
1017
    if (atomicCounterCount > 0)
1018
    {
1019
        // ANGLEUniforms.acbBufferOffsets
1020
        const TIntermBinary *acbBufferOffsets =
1021
            CreateDriverUniformRef(driverUniforms, kAcbBufferOffsets);
1022
1023
        if (!RewriteAtomicCounters(this, &root, &symbolTable, acbBufferOffsets))
1024
        {
1025
            return false;
1026
        }
1027
    }
1028
    else if (getShaderVersion() >= 310)
1029
    {
1030
        // Vulkan doesn't support Atomic Storage as a Storage Class, but we've seen
1031
        // cases where builtins are using it even with no active atomic counters.
1032
        // This pass simply removes those builtins in that scenario.
1033
        if (!RemoveAtomicCounterBuiltins(this, &root))
1034
        {
1035
            return false;
1036
        }
1037
    }
1038
1039
    if (getShaderType() != GL_COMPUTE_SHADER)
1040
    {
1041
        if (!ReplaceGLDepthRangeWithDriverUniform(*this, root, driverUniforms))
1042
        {
1043
            return false;
1044
        }
1045
1046
#if 0
1047
        // Add specialization constant declarations.  The default value of the specialization
1048
        // constant is irrelevant, as it will be set when creating the pipeline.
1049
        if (compileOptions & SH_ADD_BRESENHAM_LINE_RASTER_EMULATION)
1050
        {
1051
            sink << "layout(constant_id="
1052
                 << static_cast<uint32_t>(vk::SpecializationConstantId::LineRasterEmulation)
1053
                 << ") const bool " << kLineRasterEmulationSpecConstVarName << " = false;\n\n";
1054
        }
1055
#endif
1056
    }
1057
1058
    {
1059
        bool usesInstanceId = false;
1060
        for (const ShaderVariable &var : mAttributes)
1061
        {
1062
            if (var.isBuiltIn())
1063
            {
1064
                if (var.name == "gl_InstanceID")
1065
                {
1066
                    usesInstanceId = true;
1067
                }
1068
            }
1069
        }
1070
1071
        if (usesInstanceId)
1072
        {
1073
            root.insertChildNodes(
1074
                FindMainIndex(&root),
1075
                TIntermSequence{new TIntermDeclaration{BuiltInVariable::gl_InstanceID()}});
1076
        }
1077
    }
1078
1079
    // Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData
1080
    // if it's core profile shaders and they are used.
1081
    if (getShaderType() == GL_FRAGMENT_SHADER)
1082
    {
1083
        bool usesPointCoord  = false;
1084
        bool usesFragCoord   = false;
1085
        bool usesFrontFacing = false;
1086
        for (const ShaderVariable &inputVarying : mInputVaryings)
1087
        {
1088
            if (inputVarying.isBuiltIn())
1089
            {
1090
                if (inputVarying.name == "gl_PointCoord")
1091
                {
1092
                    usesPointCoord = true;
1093
                }
1094
                else if (inputVarying.name == "gl_FragCoord")
1095
                {
1096
                    usesFragCoord = true;
1097
                }
1098
                else if (inputVarying.name == "gl_FrontFacing")
1099
                {
1100
                    usesFrontFacing = true;
1101
                }
1102
            }
1103
        }
1104
1105
        bool usesFragColor = false;
1106
        bool usesFragData  = false;
1107
        bool usesFragDepth = false;
1108
        for (const ShaderVariable &outputVarying : mOutputVariables)
1109
        {
1110
            if (outputVarying.isBuiltIn())
1111
            {
1112
                if (outputVarying.name == "gl_FragColor")
1113
                {
1114
                    usesFragColor = true;
1115
                }
1116
                else if (outputVarying.name == "gl_FragData")
1117
                {
1118
                    usesFragData = true;
1119
                }
1120
                else if (outputVarying.name == "gl_FragDepth")
1121
                {
1122
                    usesFragDepth = true;
1123
                }
1124
            }
1125
        }
1126
1127
        if (usesFragColor && usesFragData)
1128
        {
1129
            return false;
1130
        }
1131
1132
        if (usesFragColor)
1133
        {
1134
            AddFragColorDeclaration(root, symbolTable);
1135
        }
1136
1137
        if (usesFragData)
1138
        {
1139
            if (!AddFragDataDeclaration(*this, root))
1140
            {
1141
                return false;
1142
            }
1143
        }
1144
1145
        if (usesFragDepth)
1146
        {
1147
            AddFragDepthDeclaration(root, symbolTable);
1148
        }
1149
1150
#if 0
1151
        if (compileOptions & SH_ADD_BRESENHAM_LINE_RASTER_EMULATION)
1152
        {
1153
            if (!AddBresenhamEmulationFS(this, compileOptions, sink, root, &symbolTable,
1154
                                         driverUniforms, usesFragCoord))
1155
            {
1156
                return false;
1157
            }
1158
        }
1159
#endif
1160
1161
        bool usePreRotation = compileOptions & SH_ADD_PRE_ROTATION;
1162
1163
        if (usesPointCoord)
1164
        {
1165
            TIntermBinary &flipXY       = *CreateDriverUniformRef(driverUniforms, kNegFlipXY);
1166
            TIntermConstantUnion &pivot = *CreateFloatNode(0.5f);
1167
            TIntermBinary *fragRotation =
1168
                usePreRotation ? CreateDriverUniformRef(driverUniforms, kFragRotation) : nullptr;
1169
            if (!RotateAndFlipBuiltinVariable(*this, root, *GetMainSequence(root), flipXY,
1170
                                              *BuiltInVariable::gl_PointCoord(),
1171
                                              kFlippedPointCoordName, pivot, fragRotation))
1172
            {
1173
                return false;
1174
            }
1175
            DeclareRightBeforeMain(root, *BuiltInVariable::gl_PointCoord());
1176
        }
1177
1178
        if (usesFragCoord)
1179
        {
1180
            if (!InsertFragCoordCorrection(*this, compileOptions, root, *GetMainSequence(root),
1181
                                           driverUniforms))
1182
            {
1183
                return false;
1184
            }
1185
            DeclareRightBeforeMain(root, *BuiltInVariable::gl_FragCoord());
1186
        }
1187
1188
        {
1189
            TIntermBinary *flipXY = CreateDriverUniformRef(driverUniforms, kFlipXY);
1190
            TIntermBinary *fragRotation =
1191
                usePreRotation ? CreateDriverUniformRef(driverUniforms, kFragRotation) : nullptr;
1192
            if (!RewriteDfdy(this, &root, symbolTable, getShaderVersion(), flipXY, fragRotation))
1193
            {
1194
                return false;
1195
            }
1196
        }
1197
1198
        if (usesFrontFacing)
1199
        {
1200
            DeclareRightBeforeMain(root, *BuiltInVariable::gl_FrontFacing());
1201
        }
1202
1203
        EmitEarlyFragmentTestsGLSL(*this, sink);
1204
    }
1205
    else if (getShaderType() == GL_VERTEX_SHADER)
1206
    {
1207
        DeclareRightBeforeMain(root, *BuiltInVariable::gl_Position());
1208
1209
        if (FindSymbolNode(&root, BuiltInVariable::gl_PointSize()->name()))
1210
        {
1211
            DeclareRightBeforeMain(root, *BuiltInVariable::gl_PointSize());
1212
        }
1213
1214
        if (FindSymbolNode(&root, BuiltInVariable::gl_VertexIndex()->name()))
1215
        {
1216
            if (!ReplaceVariable(this, &root, BuiltInVariable::gl_VertexIndex(),
1217
                                 &kgl_VertexIndexMetal))
1218
            {
1219
                return false;
1220
            }
1221
            DeclareRightBeforeMain(root, kgl_VertexIndexMetal);
1222
        }
1223
1224
#if 0
1225
        if (compileOptions & SH_ADD_BRESENHAM_LINE_RASTER_EMULATION)
1226
        {
1227
            if (!AddBresenhamEmulationVS(this, root, &symbolTable, driverUniforms))
1228
            {
1229
                return false;
1230
            }
1231
        }
1232
1233
        // Add a macro to declare transform feedback buffers.
1234
        sink << "@@ XFB-DECL @@\n\n";
1235
#endif
1236
1237
        // Append a macro for transform feedback substitution prior to modifying depth.
1238
        if (!AppendVertexShaderTransformFeedbackOutputToMain(*this, root))
1239
        {
1240
            return false;
1241
        }
1242
1243
        // Search for the gl_ClipDistance usage, if its used, we need to do some replacements.
1244
        bool useClipDistance = false;
1245
        for (const ShaderVariable &outputVarying : mOutputVaryings)
1246
        {
1247
            if (outputVarying.name == "gl_ClipDistance")
1248
            {
1249
                useClipDistance = true;
1250
                break;
1251
            }
1252
        }
1253
1254
        if (useClipDistance && !ReplaceClipDistanceAssignments(
1255
                                   this, &root, &symbolTable,
1256
                                   CreateDriverUniformRef(driverUniforms, kClipDistancesEnabled)))
1257
        {
1258
            return false;
1259
        }
1260
1261
        if (!transformDepthBeforeCorrection(root, driverUniforms))
1262
        {
1263
            return false;
1264
        }
1265
1266
        if (!AppendVertexShaderDepthCorrectionToMain(*this, root))
1267
        {
1268
            return false;
1269
        }
1270
1271
        if ((compileOptions & SH_ADD_PRE_ROTATION) != 0 &&
1272
            !AppendPreRotation(*this, root, driverUniforms))
1273
        {
1274
            return false;
1275
        }
1276
    }
1277
    else if (getShaderType() == GL_GEOMETRY_SHADER)
1278
    {
1279
        WriteGeometryShaderLayoutQualifiers(
1280
            sink, getGeometryShaderInputPrimitiveType(), getGeometryShaderInvocations(),
1281
            getGeometryShaderOutputPrimitiveType(), getGeometryShaderMaxVertices());
1282
    }
1283
    else
1284
    {
1285
        ASSERT(getShaderType() == GL_COMPUTE_SHADER);
1286
        EmitWorkGroupSizeGLSL(*this, sink);
1287
    }
1288
1289
    if (getShaderType() == GL_VERTEX_SHADER)
1290
    {
1291
        auto &negFlipY = *getDriverUniformNegFlipYRef(driverUniforms);
1292
1293
        if (mEmulatedInstanceID)
1294
        {
1295
            if (!EmulateInstanceID(*this, root, driverUniforms))
1296
            {
1297
                return false;
1298
            }
1299
        }
1300
1301
        if (!AppendVertexShaderPositionYCorrectionToMain(*this, root, negFlipY))
1302
        {
1303
            return false;
1304
        }
1305
1306
        if (!insertRasterizationDiscardLogic(root))
1307
        {
1308
            return false;
1309
        }
1310
    }
1311
1312
    if (!validateAST(&root))
1313
    {
1314
        return false;
1315
    }
1316
1317
    if (!RewriteKeywords(*this, root, idGen, GetMslKeywords()))
1318
    {
1319
        return false;
1320
    }
1321
1322
    if (!ReduceInterfaceBlocks(*this, root))
1323
    {
1324
        return false;
1325
    }
1326
1327
    if (!SeparateCompoundStructDeclarations(*this, root))
1328
    {
1329
        return false;
1330
    }
1331
1332
    // This is the largest size required to pass all the tests in
1333
    // (dEQP-GLES3.functional.shaders.large_constant_arrays)
1334
    // This value could in principle be smaller.
1335
    const size_t hoistThresholdSize = 256;
1336
    if (!HoistConstants(*this, root, idGen, hoistThresholdSize))
1337
    {
1338
        return false;
1339
    }
1340
1341
    Invariants invariants;
1342
    if (!RewriteGlobalQualifierDecls(*this, root, invariants))
1343
    {
1344
        return false;
1345
    }
1346
1347
    SymbolEnv symbolEnv(*this, root);
1348
1349
    if (!AddExplicitTypeCasts(*this, root, symbolEnv))
1350
    {
1351
        return false;
1352
    }
1353
1354
    PipelineStructs pipelineStructs;
1355
    if (!RewritePipelines(*this, root, idGen, driverUniforms, symbolEnv, invariants,
1356
                          pipelineStructs))
1357
    {
1358
        return false;
1359
    }
1360
1361
    if (!SeparateCompoundExpressions(*this, symbolEnv, idGen, root))
1362
    {
1363
        return false;
1364
    }
1365
1366
    if (!RewriteCaseDeclarations(*this, root))
1367
    {
1368
        return false;
1369
    }
1370
1371
    if (!RewriteUnaddressableReferences(*this, root, symbolEnv))
1372
    {
1373
        return false;
1374
    }
1375
1376
    if (!RewriteOutArgs(*this, root, symbolEnv))
1377
    {
1378
        return false;
1379
    }
1380
1381
    if (!ToposortStructs(*this, symbolEnv, root, ppc))
1382
    {
1383
        return false;
1384
    }
1385
1386
    if (!EmitMetal(*this, root, idGen, pipelineStructs, invariants, symbolEnv, ppc))
1387
    {
1388
        return false;
1389
    }
1390
1391
    ASSERT(validateAST(&root));
1392
1393
    return true;
1394
}
1395
1396
bool TranslatorMetalDirect::translate(TIntermBlock *root,
1397
                                      ShCompileOptions compileOptions,
1398
                                      PerformanceDiagnostics *perfDiagnostics)
1399
{
1400
    if (!root)
1401
    {
1402
        return false;
1403
    }
1404
1405
    TInfoSinkBase &sink = getInfoSink().obj;
1406
1407
    bool precisionEmulation = false;
1408
    if (!emulatePrecisionIfNeeded(root, sink, &precisionEmulation, SH_GLSL_VULKAN_OUTPUT))
1409
    {
1410
        return false;
1411
    }
1412
1413
#if 0
1414
    bool enablePrecision = ((compileOptions & SH_IGNORE_PRECISION_QUALIFIERS) == 0);
1415
1416
    TOutputMSL outputMSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(),
1417
                         &getSymbolTable(), getShaderType(), getShaderVersion(), getOutputType(),
1418
                         precisionEmulation, enablePrecision, compileOptions);
1419
#endif
1420
1421
    if (!translateImpl(*root, compileOptions))
1422
    {
1423
        return false;
1424
    }
1425
1426
#if 0
1427
    // Write translated shader.
1428
    root->traverse(outputMSL);
1429
#endif
1430
1431
    return true;
1432
}
1433
bool TranslatorMetalDirect::shouldFlattenPragmaStdglInvariantAll()
1434
{
1435
    // Not neccesary for MSL transformation.
1436
    return false;
1437
}
1438
1439
}  // namespace sh
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect.h +132 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_H_
9
10
#include "compiler/translator/Compiler.h"
11
12
namespace sh
13
{
14
class TOutputMSL;
15
16
typedef std::unordered_map<size_t, std::string> originalNamesMap;
17
typedef std::unordered_map<std::string, size_t> samplerBindingMap;
18
typedef std::unordered_map<std::string, size_t> textureBindingMap;
19
typedef std::unordered_map<std::string, size_t> uniformBufferBindingMap;
20
21
class TranslatorMetalReflection
22
{
23
  public:
24
    TranslatorMetalReflection() {}
25
    ~TranslatorMetalReflection() {}
26
27
    void addOriginalName(const size_t id, const std::string &name)
28
    {
29
        originalNames.insert({id, name});
30
    }
31
    void addSamplerBinding(const std::string &name, size_t samplerBinding)
32
    {
33
        samplerBindings.insert({name, samplerBinding});
34
    }
35
    void addTextureBinding(const std::string &name, size_t textureBinding)
36
    {
37
        textureBindings.insert({name, textureBinding});
38
    }
39
    void addUniformBufferBinding(const std::string &name, size_t uniformBufferBinding)
40
    {
41
        uniformBufferBindings.insert({name, uniformBufferBinding});
42
    }
43
    std::string getOriginalName(const size_t id) { return originalNames.at(id); }
44
    samplerBindingMap getSamplerBindings() const { return samplerBindings; }
45
    textureBindingMap getTextureBindings() const { return textureBindings; }
46
    uniformBufferBindingMap getUniformBufferBindings() const { return uniformBufferBindings; }
47
    size_t getSamplerBinding(const std::string &name) const
48
    {
49
        auto it = samplerBindings.find(name);
50
        if (it != samplerBindings.end())
51
        {
52
            return it->second;
53
        }
54
        ASSERT(0);
55
        return std::numeric_limits<size_t>::max();
56
    }
57
    size_t getTextureBinding(const std::string &name) const
58
    {
59
        auto it = textureBindings.find(name);
60
        if (it != textureBindings.end())
61
        {
62
            return it->second;
63
        }
64
        ASSERT(0);
65
        return std::numeric_limits<size_t>::max();
66
    }
67
    size_t getUniformBufferBinding(const std::string &name) const
68
    {
69
        auto it = uniformBufferBindings.find(name);
70
        if (it != uniformBufferBindings.end())
71
        {
72
            return it->second;
73
        }
74
        ASSERT(0);
75
        return std::numeric_limits<size_t>::max();
76
    }
77
    void reset()
78
    {
79
        originalNames.clear();
80
        samplerBindings.clear();
81
        textureBindings.clear();
82
        uniformBufferBindings.clear();
83
    }
84
85
  private:
86
    originalNamesMap originalNames;
87
    samplerBindingMap samplerBindings;
88
    textureBindingMap textureBindings;
89
    uniformBufferBindingMap uniformBufferBindings;
90
};
91
92
class TranslatorMetalDirect : public TCompiler
93
{
94
  public:
95
    TranslatorMetalDirect(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output);
96
97
#ifdef ANGLE_ENABLE_METAL
98
    TranslatorMetalDirect *getAsTranslatorMetalDirect() override { return this; }
99
#endif
100
101
    static const char *GetCoverageMaskEnabledConstName();
102
    static const char *GetRasterizationDiscardEnabledConstName();
103
104
    void enableEmulatedInstanceID(bool e) { mEmulatedInstanceID = e; }
105
    TranslatorMetalReflection *getTranslatorMetalReflection() { return &translatorMetalReflection; }
106
107
  protected:
108
    bool translate(TIntermBlock *root,
109
                   ShCompileOptions compileOptions,
110
                   PerformanceDiagnostics *perfDiagnostics) override;
111
112
    ANGLE_NO_DISCARD bool translateImpl(TIntermBlock &root, ShCompileOptions compileOptions);
113
114
    ANGLE_NO_DISCARD bool shouldFlattenPragmaStdglInvariantAll() override;
115
116
    ANGLE_NO_DISCARD bool transformDepthBeforeCorrection(TIntermBlock &root,
117
                                                         const TVariable &driverUniforms);
118
    ANGLE_NO_DISCARD bool insertRasterizationDiscardLogic(TIntermBlock &root);
119
120
    void createAdditionalGraphicsDriverUniformFields(std::vector<TField *> &fieldsOut);
121
122
    ANGLE_NO_DISCARD TIntermSwizzle *getDriverUniformNegFlipYRef(
123
        const TVariable &driverUniforms) const;
124
125
    bool mEmulatedInstanceID = false;
126
127
    TranslatorMetalReflection translatorMetalReflection = {};
128
};
129
130
}  // namespace sh
131
132
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/AddExplicitTypeCasts.cpp +95 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/AddExplicitTypeCasts.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include "compiler/translator/TranslatorMetalDirect/AddExplicitTypeCasts.h"
8
#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
9
#include "compiler/translator/tree_util/IntermRebuild.h"
10
11
using namespace sh;
12
13
namespace
14
{
15
16
class Rewriter : public TIntermRebuild
17
{
18
    SymbolEnv &mSymbolEnv;
19
20
  public:
21
    Rewriter(TCompiler &compiler, SymbolEnv &symbolEnv)
22
        : TIntermRebuild(compiler, false, true), mSymbolEnv(symbolEnv)
23
    {}
24
25
    PostResult visitAggregatePost(TIntermAggregate &callNode) override
26
    {
27
        const size_t argCount = callNode.getChildCount();
28
        const TType &retType  = callNode.getType();
29
30
        if (callNode.isConstructor())
31
        {
32
            if (IsScalarBasicType(retType))
33
            {
34
                if (argCount == 1)
35
                {
36
                    TIntermTyped &arg   = GetArg(callNode, 0);
37
                    const TType argType = arg.getType();
38
                    if (argType.isVector())
39
                    {
40
                        return CoerceSimple(retType, SubVector(arg, 0, 1));
41
                    }
42
                }
43
            }
44
            else if (retType.isVector())
45
            {
46
                if (argCount == 1)
47
                {
48
                    TIntermTyped &arg   = GetArg(callNode, 0);
49
                    const TType argType = arg.getType();
50
                    if (argType.isVector())
51
                    {
52
                        return CoerceSimple(retType, SubVector(arg, 0, retType.getNominalSize()));
53
                    }
54
                }
55
                for (size_t i = 0; i < argCount; ++i)
56
                {
57
                    TIntermTyped &arg = GetArg(callNode, i);
58
                    SetArg(callNode, i, CoerceSimple(retType.getBasicType(), arg));
59
                }
60
            }
61
            else if (retType.isMatrix())
62
            {
63
                if (argCount == 1)
64
                {
65
                    TIntermTyped &arg   = GetArg(callNode, 0);
66
                    const TType argType = arg.getType();
67
                    if (argType.isMatrix())
68
                    {
69
                        if (retType.getCols() != argType.getCols() ||
70
                            retType.getRows() != argType.getRows())
71
                        {
72
                            TemplateArg templateArgs[] = {retType.getCols(), retType.getRows()};
73
                            return mSymbolEnv.callFunctionOverload(
74
                                Name("cast"), retType, *new TIntermSequence{&arg}, 2, templateArgs);
75
                        }
76
                    }
77
                }
78
            }
79
        }
80
81
        return callNode;
82
    }
83
};
84
85
}  // anonymous namespace
86
87
bool sh::AddExplicitTypeCasts(TCompiler &compiler, TIntermBlock &root, SymbolEnv &symbolEnv)
88
{
89
    Rewriter rewriter(compiler, symbolEnv);
90
    if (!rewriter.rebuildRoot(root))
91
    {
92
        return false;
93
    }
94
    return true;
95
}
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/AddExplicitTypeCasts.h +24 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/AddExplicitTypeCasts.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_ADDEXPLICITTYPECASTS_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_ADDEXPLICITTYPECASTS_H_
9
10
#include "compiler/translator/Compiler.h"
11
#include "compiler/translator/TranslatorMetalDirect/ProgramPrelude.h"
12
#include "compiler/translator/TranslatorMetalDirect/SymbolEnv.h"
13
14
namespace sh
15
{
16
17
// Adds explicit type casts into the AST where casting is done implicitly.
18
ANGLE_NO_DISCARD bool AddExplicitTypeCasts(TCompiler &compiler,
19
                                           TIntermBlock &root,
20
                                           SymbolEnv &symbolEnv);
21
22
}  // namespace sh
23
24
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_ADDEXPLICITTYPECASTS_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/AstHelpers.cpp +474 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/AstHelpers.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include <cstring>
8
#include <numeric>
9
#include <unordered_map>
10
#include <unordered_set>
11
12
#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
13
14
using namespace sh;
15
16
////////////////////////////////////////////////////////////////////////////////
17
18
Declaration sh::ViewDeclaration(TIntermDeclaration &declNode)
19
{
20
    ASSERT(declNode.getChildCount() == 1);
21
    TIntermNode *childNode = declNode.getChildNode(0);
22
    ASSERT(childNode);
23
    TIntermSymbol *symbolNode;
24
    if ((symbolNode = childNode->getAsSymbolNode()))
25
    {
26
        return {*symbolNode, nullptr};
27
    }
28
    else
29
    {
30
        TIntermBinary *initNode = childNode->getAsBinaryNode();
31
        ASSERT(initNode);
32
        ASSERT(initNode->getOp() == TOperator::EOpInitialize);
33
        symbolNode = initNode->getLeft()->getAsSymbolNode();
34
        ASSERT(symbolNode);
35
        return {*symbolNode, initNode->getRight()};
36
    }
37
}
38
39
const TVariable &sh::CreateStructTypeVariable(TSymbolTable &symbolTable,
40
                                              const TStructure &structure)
41
{
42
    auto *type = new TType(&structure, true);
43
    auto *var  = new TVariable(&symbolTable, ImmutableString(""), type, SymbolType::Empty);
44
    return *var;
45
}
46
47
const TVariable &sh::CreateInstanceVariable(TSymbolTable &symbolTable,
48
                                            const TStructure &structure,
49
                                            const Name &name,
50
                                            TQualifier qualifier,
51
                                            const TSpan<const unsigned int> *arraySizes)
52
{
53
    auto *type = new TType(&structure, false);
54
    type->setQualifier(qualifier);
55
    if (arraySizes)
56
    {
57
        type->makeArrays(*arraySizes);
58
    }
59
    auto *var = new TVariable(&symbolTable, name.rawName(), type, name.symbolType());
60
    return *var;
61
}
62
63
static void AcquireFunctionExtras(TFunction &dest, const TFunction &src)
64
{
65
    if (src.isDefined())
66
    {
67
        dest.setDefined();
68
    }
69
70
    if (src.hasPrototypeDeclaration())
71
    {
72
        dest.setHasPrototypeDeclaration();
73
    }
74
}
75
76
TIntermSequence &sh::CloneSequenceAndPrepend(const TIntermSequence &seq, TIntermNode &node)
77
{
78
    auto *newSeq = new TIntermSequence();
79
    newSeq->push_back(&node);
80
81
    for (TIntermNode *oldNode : seq)
82
    {
83
        newSeq->push_back(oldNode);
84
    }
85
86
    return *newSeq;
87
}
88
89
void sh::AddParametersFrom(TFunction &dest, const TFunction &src)
90
{
91
    const size_t paramCount = src.getParamCount();
92
    for (size_t i = 0; i < paramCount; ++i)
93
    {
94
        const TVariable *var = src.getParam(i);
95
        dest.addParameter(var);
96
    }
97
}
98
99
const TFunction &sh::CloneFunction(TSymbolTable &symbolTable,
100
                                   IdGen &idGen,
101
                                   const TFunction &oldFunc)
102
{
103
    ASSERT(oldFunc.symbolType() == SymbolType::UserDefined);
104
105
    Name newName = idGen.createNewName(Name(oldFunc));
106
107
    auto &newFunc = *new TFunction(&symbolTable, newName.rawName(), newName.symbolType(),
108
                                   &oldFunc.getReturnType(), oldFunc.isKnownToNotHaveSideEffects());
109
110
    AcquireFunctionExtras(newFunc, oldFunc);
111
    AddParametersFrom(newFunc, oldFunc);
112
113
    return newFunc;
114
}
115
116
const TFunction &sh::CloneFunctionAndPrependParam(TSymbolTable &symbolTable,
117
                                                  IdGen *idGen,
118
                                                  const TFunction &oldFunc,
119
                                                  const TVariable &newParam)
120
{
121
    ASSERT(oldFunc.symbolType() == SymbolType::UserDefined ||
122
           oldFunc.symbolType() == SymbolType::AngleInternal);
123
124
    Name newName = idGen ? idGen->createNewName(Name(oldFunc)) : Name(oldFunc);
125
126
    auto &newFunc = *new TFunction(&symbolTable, newName.rawName(), newName.symbolType(),
127
                                   &oldFunc.getReturnType(), oldFunc.isKnownToNotHaveSideEffects());
128
129
    AcquireFunctionExtras(newFunc, oldFunc);
130
    newFunc.addParameter(&newParam);
131
    AddParametersFrom(newFunc, oldFunc);
132
133
    return newFunc;
134
}
135
136
const TFunction &sh::CloneFunctionAndAppendParams(TSymbolTable &symbolTable,
137
                                                  IdGen *idGen,
138
                                                  const TFunction &oldFunc,
139
                                                  const std::vector<const TVariable *> &newParams)
140
{
141
    ASSERT(oldFunc.symbolType() == SymbolType::UserDefined ||
142
           oldFunc.symbolType() == SymbolType::AngleInternal);
143
144
    Name newName = idGen ? idGen->createNewName(Name(oldFunc)) : Name(oldFunc);
145
146
    auto &newFunc = *new TFunction(&symbolTable, newName.rawName(), newName.symbolType(),
147
                                   &oldFunc.getReturnType(), oldFunc.isKnownToNotHaveSideEffects());
148
149
    AcquireFunctionExtras(newFunc, oldFunc);
150
    AddParametersFrom(newFunc, oldFunc);
151
    for (auto *param : newParams)
152
    {
153
        newFunc.addParameter(param);
154
    }
155
156
    return newFunc;
157
}
158
159
const TFunction &sh::CloneFunctionAndChangeReturnType(TSymbolTable &symbolTable,
160
                                                      IdGen *idGen,
161
                                                      const TFunction &oldFunc,
162
                                                      const TStructure &newReturn)
163
{
164
    ASSERT(oldFunc.symbolType() == SymbolType::UserDefined);
165
166
    Name newName = idGen ? idGen->createNewName(Name(oldFunc)) : Name(oldFunc);
167
168
    auto *newReturnType = new TType(&newReturn, true);
169
    auto &newFunc       = *new TFunction(&symbolTable, newName.rawName(), newName.symbolType(),
170
                                   newReturnType, oldFunc.isKnownToNotHaveSideEffects());
171
172
    AcquireFunctionExtras(newFunc, oldFunc);
173
    AddParametersFrom(newFunc, oldFunc);
174
175
    return newFunc;
176
}
177
178
TIntermTyped &sh::GetArg(const TIntermAggregate &call, size_t index)
179
{
180
    ASSERT(index < call.getChildCount());
181
    auto *arg = call.getChildNode(index);
182
    ASSERT(arg);
183
    auto *targ = arg->getAsTyped();
184
    ASSERT(targ);
185
    return *targ;
186
}
187
188
void sh::SetArg(TIntermAggregate &call, size_t index, TIntermTyped &arg)
189
{
190
    ASSERT(index < call.getChildCount());
191
    (*call.getSequence())[index] = &arg;
192
}
193
194
int sh::GetFieldIndex(const TStructure &structure, const ImmutableString &fieldName)
195
{
196
    const TFieldList &fieldList = structure.fields();
197
198
    int i = 0;
199
    for (TField *field : fieldList)
200
    {
201
        if (field->name() == fieldName)
202
        {
203
            return i;
204
        }
205
        ++i;
206
    }
207
208
    return -1;
209
}
210
211
TIntermBinary &sh::AccessField(const TVariable &structInstanceVar, const ImmutableString &fieldName)
212
{
213
    return AccessField(*new TIntermSymbol(&structInstanceVar), fieldName);
214
}
215
216
TIntermBinary &sh::AccessField(TIntermTyped &object, const ImmutableString &fieldName)
217
{
218
    const TStructure *structure = object.getType().getStruct();
219
    ASSERT(structure);
220
221
    const int index = GetFieldIndex(*structure, fieldName);
222
    ASSERT(index >= 0);
223
    return AccessFieldByIndex(object, index);
224
}
225
226
TIntermBinary &sh::AccessFieldByIndex(TIntermTyped &object, int index)
227
{
228
#if defined(ANGLE_ENABLE_ASSERTS)
229
    const TType &type = object.getType();
230
    ASSERT(!type.isArray());
231
    const TStructure *structure = type.getStruct();
232
    ASSERT(structure);
233
    ASSERT(0 <= index);
234
    ASSERT(static_cast<size_t>(index) < structure->fields().size());
235
#endif
236
237
    return *new TIntermBinary(
238
        TOperator::EOpIndexDirectStruct, &object,
239
        new TIntermConstantUnion(new TConstantUnion(index), *new TType(TBasicType::EbtInt)));
240
}
241
242
TIntermBinary &sh::AccessIndex(TIntermTyped &indexableNode, int index)
243
{
244
#if defined(ANGLE_ENABLE_ASSERTS)
245
    const TType &type = indexableNode.getType();
246
    ASSERT(type.isArray() || type.isVector() || type.isMatrix());
247
#endif
248
249
    auto *accessNode = new TIntermBinary(
250
        TOperator::EOpIndexDirect, &indexableNode,
251
        new TIntermConstantUnion(new TConstantUnion(index), *new TType(TBasicType::EbtInt)));
252
    return *accessNode;
253
}
254
255
TIntermTyped &sh::AccessIndex(TIntermTyped &node, const int *index)
256
{
257
    if (index)
258
    {
259
        return AccessIndex(node, *index);
260
    }
261
    return node;
262
}
263
264
TIntermTyped &sh::SubVector(TIntermTyped &vectorNode, int begin, int end)
265
{
266
    ASSERT(vectorNode.getType().isVector());
267
    ASSERT(0 <= begin);
268
    ASSERT(end <= 4);
269
    ASSERT(begin <= end);
270
    if (begin == 0 && end == vectorNode.getType().getNominalSize())
271
    {
272
        return vectorNode;
273
    }
274
    TVector<int> offsets(static_cast<size_t>(end - begin));
275
    std::iota(offsets.begin(), offsets.end(), begin);
276
    auto *swizzle = new TIntermSwizzle(&vectorNode, offsets);
277
    return *swizzle;
278
}
279
280
bool sh::IsScalarBasicType(const TType &type)
281
{
282
    if (!type.isScalar())
283
    {
284
        return false;
285
    }
286
    return HasScalarBasicType(type);
287
}
288
289
bool sh::IsVectorBasicType(const TType &type)
290
{
291
    if (!type.isVector())
292
    {
293
        return false;
294
    }
295
    return HasScalarBasicType(type);
296
}
297
298
bool sh::HasScalarBasicType(TBasicType type)
299
{
300
    switch (type)
301
    {
302
        case TBasicType::EbtFloat:
303
        case TBasicType::EbtDouble:
304
        case TBasicType::EbtInt:
305
        case TBasicType::EbtUInt:
306
        case TBasicType::EbtBool:
307
            return true;
308
309
        default:
310
            return false;
311
    }
312
}
313
314
bool sh::HasScalarBasicType(const TType &type)
315
{
316
    return HasScalarBasicType(type.getBasicType());
317
}
318
319
static void InitType(TType &type)
320
{
321
    if (type.isArray())
322
    {
323
        auto sizes = type.getArraySizes();
324
        type.toArrayBaseType();
325
        type.makeArrays(sizes);
326
    }
327
}
328
329
TType &sh::CloneType(const TType &type)
330
{
331
    auto &clone = *new TType(type);
332
    InitType(clone);
333
    return clone;
334
}
335
336
TType &sh::InnermostType(const TType &type)
337
{
338
    auto &inner = *new TType(type);
339
    inner.toArrayBaseType();
340
    InitType(inner);
341
    return inner;
342
}
343
344
TType &sh::DropColumns(const TType &matrixType)
345
{
346
    ASSERT(matrixType.isMatrix());
347
    ASSERT(HasScalarBasicType(matrixType));
348
    const char *mangledName = nullptr;
349
350
    auto &vectorType =
351
        *new TType(matrixType.getBasicType(), matrixType.getPrecision(), matrixType.getQualifier(),
352
                   matrixType.getRows(), 1, matrixType.getArraySizes(), mangledName);
353
    InitType(vectorType);
354
    return vectorType;
355
}
356
357
TType &sh::DropOuterDimension(const TType &arrayType)
358
{
359
    ASSERT(arrayType.isArray());
360
    const char *mangledName = nullptr;
361
    const auto &arraySizes  = arrayType.getArraySizes();
362
363
    auto &innerType =
364
        *new TType(arrayType.getBasicType(), arrayType.getPrecision(), arrayType.getQualifier(),
365
                   arrayType.getNominalSize(), arrayType.getSecondarySize(),
366
                   arraySizes.subspan(0, arraySizes.size() - 1), mangledName);
367
    InitType(innerType);
368
    return innerType;
369
}
370
371
static TType &SetTypeDimsImpl(const TType &type, int primary, int secondary)
372
{
373
    ASSERT(1 < primary && primary <= 4);
374
    ASSERT(1 <= secondary && secondary <= 4);
375
    ASSERT(HasScalarBasicType(type));
376
    const char *mangledName = nullptr;
377
378
    auto &newType = *new TType(type.getBasicType(), type.getPrecision(), type.getQualifier(),
379
                               primary, secondary, type.getArraySizes(), mangledName);
380
    InitType(newType);
381
    return newType;
382
}
383
384
TType &sh::SetVectorDim(const TType &type, int newDim)
385
{
386
    ASSERT(type.isRank0() || type.isVector());
387
    return SetTypeDimsImpl(type, newDim, 1);
388
}
389
390
TType &sh::SetMatrixRowDim(const TType &matrixType, int newDim)
391
{
392
    ASSERT(matrixType.isMatrix());
393
    ASSERT(1 < newDim && newDim <= 4);
394
    return SetTypeDimsImpl(matrixType, matrixType.getCols(), newDim);
395
}
396
397
bool sh::HasMatrixField(const TStructure &structure)
398
{
399
    for (const TField *field : structure.fields())
400
    {
401
        const TType &type = *field->type();
402
        if (type.isMatrix())
403
        {
404
            return true;
405
        }
406
    }
407
    return false;
408
}
409
410
bool sh::HasArrayField(const TStructure &structure)
411
{
412
    for (const TField *field : structure.fields())
413
    {
414
        const TType &type = *field->type();
415
        if (type.isArray())
416
        {
417
            return true;
418
        }
419
    }
420
    return false;
421
}
422
423
TIntermTyped &sh::CoerceSimple(TBasicType toType, TIntermTyped &fromNode)
424
{
425
    const TType &fromType = fromNode.getType();
426
427
    ASSERT(HasScalarBasicType(toType));
428
    ASSERT(HasScalarBasicType(fromType));
429
    ASSERT(!fromType.isArray());
430
431
    if (toType != fromType.getBasicType())
432
    {
433
        return *TIntermAggregate::CreateConstructor(
434
            *new TType(toType, fromType.getNominalSize(), fromType.getSecondarySize()),
435
            new TIntermSequence{&fromNode});
436
    }
437
    return fromNode;
438
}
439
440
TIntermTyped &sh::CoerceSimple(const TType &toType, TIntermTyped &fromNode)
441
{
442
    const TType &fromType = fromNode.getType();
443
444
    ASSERT(HasScalarBasicType(toType));
445
    ASSERT(HasScalarBasicType(fromType));
446
    ASSERT(toType.getNominalSize() == fromType.getNominalSize());
447
    ASSERT(toType.getSecondarySize() == fromType.getSecondarySize());
448
    ASSERT(!toType.isArray());
449
    ASSERT(!fromType.isArray());
450
451
    if (toType.getBasicType() != fromType.getBasicType())
452
    {
453
        return *TIntermAggregate::CreateConstructor(toType, new TIntermSequence{&fromNode});
454
    }
455
    return fromNode;
456
}
457
458
TIntermTyped &sh::AsType(SymbolEnv &symbolEnv, const TType &toType, TIntermTyped &fromNode)
459
{
460
    const TType &fromType = fromNode.getType();
461
462
    ASSERT(HasScalarBasicType(toType));
463
    ASSERT(HasScalarBasicType(fromType));
464
    ASSERT(!toType.isArray());
465
    ASSERT(!fromType.isArray());
466
467
    if (toType == fromType)
468
    {
469
        return fromNode;
470
    }
471
    TemplateArg targ(toType);
472
    return symbolEnv.callFunctionOverload(Name("as_type", SymbolType::BuiltIn), toType,
473
                                          *new TIntermSequence{&fromNode}, 1, &targ);
474
}
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/AstHelpers.h +157 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/AstHelpers.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_ASTHELPERS_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_ASTHELPERS_H_
9
10
#include <cstring>
11
#include <unordered_map>
12
#include <unordered_set>
13
14
#include "compiler/translator/TranslatorMetalDirect/IdGen.h"
15
#include "compiler/translator/TranslatorMetalDirect/Name.h"
16
#include "compiler/translator/TranslatorMetalDirect/SymbolEnv.h"
17
18
namespace sh
19
{
20
21
// A convenience view of a TIntermDeclaration node's children.
22
struct Declaration
23
{
24
    TIntermSymbol &symbol;
25
    TIntermTyped *initExpr;  // Non-null iff declaration is initialized.
26
};
27
28
// Returns a `Declaration` view of the given node.
29
Declaration ViewDeclaration(TIntermDeclaration &declNode);
30
31
// Creates a variable for a struct type.
32
const TVariable &CreateStructTypeVariable(TSymbolTable &symbolTable, const TStructure &structure);
33
34
// Creates a variable for a struct instance.
35
const TVariable &CreateInstanceVariable(TSymbolTable &symbolTable,
36
                                        const TStructure &structure,
37
                                        const Name &name,
38
                                        TQualifier qualifier = TQualifier::EvqTemporary,
39
                                        const TSpan<const unsigned int> *arraySizes = nullptr);
40
41
// The input sequence should be discarded from AST after this is called.
42
TIntermSequence &CloneSequenceAndPrepend(const TIntermSequence &seq, TIntermNode &node);
43
44
// Appends parameters from `src` function to `dest` function.
45
void AddParametersFrom(TFunction &dest, const TFunction &src);
46
47
// Clones a function.
48
const TFunction &CloneFunction(TSymbolTable &symbolTable, IdGen &idGen, const TFunction &oldFunc);
49
50
// Clones a function and prepends the provided extr parameter.
51
// If `idGen` is null, the original function must be discarded from the AST.
52
const TFunction &CloneFunctionAndPrependParam(TSymbolTable &symbolTable,
53
                                              IdGen *idGen,
54
                                              const TFunction &oldFunc,
55
                                              const TVariable &newParam);
56
57
// Clones a function and appends the provided extra parameters.
58
// If `idGen` is null, the original function must be discarded from the AST.
59
const TFunction &CloneFunctionAndAppendParams(TSymbolTable &symbolTable,
60
                                              IdGen *idGen,
61
                                              const TFunction &oldFunc,
62
                                              const std::vector<const TVariable *> &newParam);
63
64
// Clones a function and changes its return type.
65
// If `idGen` is null, the original function must be discarded from the AST.
66
const TFunction &CloneFunctionAndChangeReturnType(TSymbolTable &symbolTable,
67
                                                  IdGen *idGen,
68
                                                  const TFunction &oldFunc,
69
                                                  const TStructure &newReturn);
70
71
// Gets the argument of a function call at the given index.
72
TIntermTyped &GetArg(const TIntermAggregate &call, size_t index);
73
74
// Sets the argument of a function call at the given index.
75
void SetArg(TIntermAggregate &call, size_t index, TIntermTyped &arg);
76
77
// Returns the field index within the given struct for the given field name.
78
// Returns -1 if the struct has no field with the given name.
79
int GetFieldIndex(const TStructure &structure, const ImmutableString &fieldName);
80
81
// Accesses a field for the given variable with the given field name.
82
// The variable must be a struct instance.
83
TIntermBinary &AccessField(const TVariable &structInstanceVar, const ImmutableString &fieldName);
84
85
// Accesses a field for the given node with the given field name.
86
// The node must be a struct instance.
87
TIntermBinary &AccessField(TIntermTyped &object, const ImmutableString &fieldName);
88
89
// Accesses a field for the given node by its field index.
90
// The node must be a struct instance.
91
TIntermBinary &AccessFieldByIndex(TIntermTyped &object, int index);
92
93
// Accesses an element by index for the given node.
94
// The node must be an array, vector, or matrix.
95
TIntermBinary &AccessIndex(TIntermTyped &indexableNode, int index);
96
97
// Accesses an element by index for the given node if `index` is non-null.
98
// Returns the original node if `index` is null.
99
// The node must be an array, vector, or matrix if `index` is non-null.
100
TIntermTyped &AccessIndex(TIntermTyped &node, const int *index);
101
102
// Returns a subvector based on the input slice range.
103
// This returns the original node if the slice is an identity for the node.
104
TIntermTyped &SubVector(TIntermTyped &vectorNode, int begin, int end);
105
106
// Matches scalar bool, int, uint, float, double.
107
bool IsScalarBasicType(const TType &type);
108
109
// Matches vector bool, int, uint, float, double.
110
bool IsVectorBasicType(const TType &type);
111
112
// Matches bool, int, uint, float, double.
113
// Type does not need to be a scalar.
114
bool HasScalarBasicType(const TType &type);
115
116
// Matches bool, int, uint, float, double.
117
bool HasScalarBasicType(TBasicType type);
118
119
// Clones a type.
120
TType &CloneType(const TType &type);
121
122
// Clones a type and drops all array dimensions.
123
TType &InnermostType(const TType &type);
124
125
// Creates a vector type by dropping the columns off of a matrix type.
126
TType &DropColumns(const TType &matrixType);
127
128
// Creates a type by dropping the outer dimension off of an array type.
129
TType &DropOuterDimension(const TType &arrayType);
130
131
// Creates a scalar or vector type by changing the dimensions of a vector type.
132
TType &SetVectorDim(const TType &type, int newDim);
133
134
// Creates a matrix type by changing the row dimensions of a matrix type.
135
TType &SetMatrixRowDim(const TType &matrixType, int newDim);
136
137
// Returns true iff the structure directly contains a field with matrix type.
138
bool HasMatrixField(const TStructure &structure);
139
140
// Returns true iff the structure directly contains a field with array type.
141
bool HasArrayField(const TStructure &structure);
142
143
// Coerces `fromNode` to `toType` by a constructor call of `toType` if their types differ.
144
// Vector and matrix dimensions are retained.
145
// Array types are not allowed.
146
TIntermTyped &CoerceSimple(TBasicType toType, TIntermTyped &fromNode);
147
148
// Coerces `fromNode` to `toType` by a constructor call of `toType` if their types differ.
149
// Vector and matrix dimensions must coincide between to and from.
150
// Array types are not allowed.
151
TIntermTyped &CoerceSimple(const TType &toType, TIntermTyped &fromNode);
152
153
TIntermTyped &AsType(SymbolEnv &symbolEnv, const TType &toType, TIntermTyped &fromNode);
154
155
}  // namespace sh
156
157
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_ASTHELPERS_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/ConstantNames.h +26 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/ConstantNames.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_CONSTANT_NAMES_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_CONSTANT_NAMES_H_
9
10
#include "compiler/translator/TranslatorMetalDirect/Name.h"
11
12
namespace sh
13
{
14
15
namespace constant_names
16
{
17
18
constexpr Name kCoverageMaskEnabled("ANGLE_CoverageMaskEnabled", SymbolType::AngleInternal);
19
constexpr Name kRasterizationDiscardEnabled("ANGLE_RasterizationDiscard",
20
                                            SymbolType::AngleInternal);
21
22
}  // namespace constant_names
23
24
}  // namespace sh
25
26
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_CONSTANT_NAMES_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/Debug.h +16 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/Debug.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_DEBUG_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_DEBUG_H_
9
10
#include "common/debug.h"
11
12
#define TODO() ASSERT(false)
13
14
#define LOGIC_ERROR() ASSERT(false)
15
16
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_DEBUG_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/DebugSink.h +159 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/DebugSink.h_sec1
1
//
2
// Copyright 2020 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
7
#include <iostream>
8
9
#include "compiler/translator/InfoSink.h"
10
11
namespace sh
12
{
13
14
class StringObserver
15
{
16
  public:
17
    StringObserver(const std::string &needle) : needle(needle) { ASSERT(!needle.empty()); }
18
19
    bool observe(char c)
20
    {
21
        if (needle[currPos] == c)
22
        {
23
            ++currPos;
24
            if (currPos == needle.size())
25
            {
26
                reset();
27
                return true;
28
            }
29
        }
30
        else
31
        {
32
            reset();
33
        }
34
        return false;
35
    }
36
37
    const std::string &getNeedle() const { return needle; }
38
39
    void reset() { currPos = 0; }
40
41
  private:
42
    std::string needle;
43
    size_t currPos = 0;
44
};
45
46
class DebugSink : angle::NonCopyable
47
{
48
  public:
49
    friend class EscapedSink;
50
    class EscapedSink : angle::NonCopyable
51
    {
52
        friend class DebugSink;
53
54
      private:
55
        EscapedSink(DebugSink &owner) : mOwner(owner), mBegin(owner.size()) {}
56
57
      public:
58
        EscapedSink(EscapedSink &&other) : mOwner(other.mOwner), mBegin(other.mBegin) {}
59
60
        ~EscapedSink()
61
        {
62
            const char *p = mOwner.c_str();
63
            const int end = mOwner.size();
64
            mOwner.onWrite(p + mBegin, p + end);
65
        }
66
67
        TInfoSinkBase &get() { return mOwner.mParent; }
68
69
        operator TInfoSinkBase &() { return get(); }
70
71
      private:
72
        DebugSink &mOwner;
73
        const int mBegin;
74
    };
75
76
  public:
77
    DebugSink(TInfoSinkBase &parent, bool alsoLogToStdout)
78
        : mParent(parent), mAlsoLogToStdout(alsoLogToStdout)
79
    {}
80
81
    void watch(std::string const &needle)
82
    {
83
        if (!needle.empty())
84
        {
85
            mObservers.emplace_back(needle);
86
        }
87
    }
88
89
    void erase()
90
    {
91
        mParent.erase();
92
        for (StringObserver &observer : mObservers)
93
        {
94
            observer.reset();
95
        }
96
    }
97
98
    int size() { return mParent.size(); }
99
100
    const TPersistString &str() const { return mParent.str(); }
101
102
    const char *c_str() const { return mParent.c_str(); }
103
104
    EscapedSink escape() { return EscapedSink(*this); }
105
106
    template <typename T>
107
    DebugSink &operator<<(const T &value)
108
    {
109
        const size_t begin = mParent.size();
110
        mParent << value;
111
        const size_t end = mParent.size();
112
113
        const char *p = mParent.c_str();
114
        onWrite(p + begin, p + end);
115
116
        return *this;
117
    }
118
119
  private:
120
    void onWrite(const char *begin, char const *end)
121
    {
122
        const char *p = begin;
123
        while (p != end)
124
        {
125
            if (mAlsoLogToStdout)
126
            {
127
                std::cout << *p;
128
            }
129
130
            for (StringObserver &observer : mObservers)
131
            {
132
                if (observer.observe(*p))
133
                {
134
                    if (mAlsoLogToStdout)
135
                    {
136
                        std::cout.flush();
137
                    }
138
                    const std::string &needle = observer.getNeedle();
139
                    (void)needle;
140
                    ASSERT(true);  // place your breakpoint here
141
                }
142
            }
143
144
            ++p;
145
        }
146
147
        if (mAlsoLogToStdout)
148
        {
149
            std::cout.flush();
150
        }
151
    }
152
153
  private:
154
    TInfoSinkBase &mParent;
155
    std::vector<StringObserver> mObservers;
156
    bool mAlsoLogToStdout;
157
};
158
159
}  // namespace sh
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/DiscoverDependentFunctions.cpp +131 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/DiscoverDependentFunctions.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include <cstring>
8
#include <unordered_map>
9
#include <unordered_set>
10
11
#include "compiler/translator/TranslatorMetalDirect/DiscoverDependentFunctions.h"
12
#include "compiler/translator/TranslatorMetalDirect/DiscoverEnclosingFunctionTraverser.h"
13
#include "compiler/translator/TranslatorMetalDirect/MapFunctionsToDefinitions.h"
14
15
using namespace sh;
16
17
////////////////////////////////////////////////////////////////////////////////
18
19
namespace
20
{
21
22
class Discoverer : public DiscoverEnclosingFunctionTraverser
23
{
24
  private:
25
    const std::function<bool(const TVariable &)> &mVars;
26
    const FunctionToDefinition &mFuncToDef;
27
    std::unordered_set<const TFunction *> mNonDepFunctions;
28
29
  public:
30
    std::unordered_set<const TFunction *> mDepFunctions;
31
32
  public:
33
    Discoverer(const std::function<bool(const TVariable &)> &vars,
34
               const FunctionToDefinition &funcToDef)
35
        : DiscoverEnclosingFunctionTraverser(true, false, true), mVars(vars), mFuncToDef(funcToDef)
36
    {}
37
38
    void visitSymbol(TIntermSymbol *symbolNode) override
39
    {
40
        const TVariable &var = symbolNode->variable();
41
        if (!mVars(var))
42
        {
43
            return;
44
        }
45
        const TFunction *owner = discoverEnclosingFunction(symbolNode);
46
        ASSERT(owner);
47
        mDepFunctions.insert(owner);
48
    }
49
50
    bool visitAggregate(Visit visit, TIntermAggregate *aggregateNode) override
51
    {
52
        if (visit != Visit::PreVisit)
53
        {
54
            return true;
55
        }
56
57
        if (!aggregateNode->isConstructor())
58
        {
59
            const TFunction *func = aggregateNode->getFunction();
60
61
            if (mNonDepFunctions.find(func) != mNonDepFunctions.end())
62
            {
63
                return true;
64
            }
65
66
            if (mDepFunctions.find(func) == mDepFunctions.end())
67
            {
68
                auto it = mFuncToDef.find(func);
69
                if (it == mFuncToDef.end())
70
                {
71
                    return true;
72
                }
73
74
                // Recursion is banned in GLSL, so I believe AngleIR has this property too.
75
                // This implementation assumes (direct and mutual) recursion is prohibited.
76
                TIntermFunctionDefinition &funcDefNode = *it->second;
77
                funcDefNode.traverse(this);
78
                if (mNonDepFunctions.find(func) != mNonDepFunctions.end())
79
                {
80
                    return true;
81
                }
82
                ASSERT(mDepFunctions.find(func) != mDepFunctions.end());
83
            }
84
85
            const TFunction *owner = discoverEnclosingFunction(aggregateNode);
86
            ASSERT(owner);
87
            mDepFunctions.insert(owner);
88
        }
89
90
        return true;
91
    }
92
93
    bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *funcDefNode) override
94
    {
95
        const TFunction *func = funcDefNode->getFunction();
96
97
        if (visit != Visit::PostVisit)
98
        {
99
            if (mDepFunctions.find(func) != mDepFunctions.end())
100
            {
101
                return false;
102
            }
103
104
            if (mNonDepFunctions.find(func) != mNonDepFunctions.end())
105
            {
106
                return false;
107
            }
108
109
            return true;
110
        }
111
112
        if (mDepFunctions.find(func) == mDepFunctions.end())
113
        {
114
            mNonDepFunctions.insert(func);
115
        }
116
117
        return true;
118
    }
119
};
120
121
}  // namespace
122
123
std::unordered_set<const TFunction *> sh::DiscoverDependentFunctions(
124
    TIntermBlock &root,
125
    const std::function<bool(const TVariable &)> &vars)
126
{
127
    const FunctionToDefinition funcToDef = MapFunctionsToDefinitions(root);
128
    Discoverer discoverer(vars, funcToDef);
129
    root.traverse(&discoverer);
130
    return std::move(discoverer.mDepFunctions);
131
}
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/DiscoverDependentFunctions.h +25 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/DiscoverDependentFunctions.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_DISCOVERDEPENDENTFUNCTIONS_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_DISCOVERDEPENDENTFUNCTIONS_H_
9
10
#include <unordered_set>
11
12
#include "common/angleutils.h"
13
#include "compiler/translator/Compiler.h"
14
15
namespace sh
16
{
17
18
// Finds and returns all functions that contain the provided variables.
19
ANGLE_NO_DISCARD std::unordered_set<const TFunction *> DiscoverDependentFunctions(
20
    TIntermBlock &root,
21
    const std::function<bool(const TVariable &)> &vars);
22
23
}  // namespace sh
24
25
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_DISCOVERDEPENDENTFUNCTIONS_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/DiscoverEnclosingFunctionTraverser.cpp +33 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/DiscoverEnclosingFunctionTraverser.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include "compiler/translator/TranslatorMetalDirect/DiscoverEnclosingFunctionTraverser.h"
8
9
using namespace sh;
10
11
DiscoverEnclosingFunctionTraverser::DiscoverEnclosingFunctionTraverser(bool preVisit_,
12
                                                                       bool inVisit_,
13
                                                                       bool postVisit_,
14
                                                                       TSymbolTable *symbolTable)
15
    : TIntermTraverser(preVisit_, inVisit_, postVisit_, symbolTable)
16
{}
17
18
const TFunction *DiscoverEnclosingFunctionTraverser::discoverEnclosingFunction(TIntermNode *node)
19
{
20
    ASSERT(!node->getAsFunctionDefinition());
21
22
    unsigned height = 0;
23
    while (TIntermNode *ancestor = getAncestorNode(height))
24
    {
25
        if (TIntermFunctionDefinition *funcDefNode = ancestor->getAsFunctionDefinition())
26
        {
27
            return funcDefNode->getFunction();
28
        }
29
        ++height;
30
    }
31
32
    return nullptr;
33
}
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/DiscoverEnclosingFunctionTraverser.h +31 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/DiscoverEnclosingFunctionTraverser.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_DISCOVERENCLOSINGFUNCTIONTRAVERSER_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_DISCOVERENCLOSINGFUNCTIONTRAVERSER_H_
9
10
#include "compiler/translator/tree_util/IntermTraverse.h"
11
12
namespace sh
13
{
14
15
// A TIntermTraverser that supports discovery of the function a node belongs to.
16
class DiscoverEnclosingFunctionTraverser : public TIntermTraverser
17
{
18
  public:
19
    DiscoverEnclosingFunctionTraverser(bool preVisit,
20
                                       bool inVisit,
21
                                       bool postVisit,
22
                                       TSymbolTable *symbolTable = nullptr);
23
24
    // Returns the function a node belongs inside.
25
    // Returns null if the node does not belong inside a function.
26
    const TFunction *discoverEnclosingFunction(TIntermNode *node);
27
};
28
29
}  // namespace sh
30
31
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_DISCOVERENCLOSINGFUNCTIONTRAVERSER_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/EmitMetal.cpp +2455 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/EmitMetal.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include <cctype>
8
#include <map>
9
10
#include "compiler/translator/ImmutableStringBuilder.h"
11
#include "compiler/translator/SymbolTable.h"
12
#include "compiler/translator/TranslatorMetalDirect.h"
13
#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
14
#include "compiler/translator/TranslatorMetalDirect/Debug.h"
15
#include "compiler/translator/TranslatorMetalDirect/DebugSink.h"
16
#include "compiler/translator/TranslatorMetalDirect/EmitMetal.h"
17
#include "compiler/translator/TranslatorMetalDirect/EnvironmentVariable.h"
18
#include "compiler/translator/TranslatorMetalDirect/Layout.h"
19
#include "compiler/translator/TranslatorMetalDirect/Name.h"
20
#include "compiler/translator/TranslatorMetalDirect/ProgramPrelude.h"
21
#include "compiler/translator/TranslatorMetalDirect/RewritePipelines.h"
22
#include "compiler/translator/tree_util/IntermTraverse.h"
23
#include "libANGLE/renderer/metal/mtl_constants.h"
24
25
using namespace sh;
26
27
////////////////////////////////////////////////////////////////////////////////
28
29
#if defined(ANGLE_ENABLE_ASSERTS)
30
using Sink = DebugSink;
31
#else
32
using Sink = TInfoSinkBase;
33
#endif
34
35
////////////////////////////////////////////////////////////////////////////////
36
37
namespace
38
{
39
40
struct VarDecl
41
{
42
    explicit VarDecl(const TVariable &var) : mVariable(&var), mIsField(false) {}
43
    explicit VarDecl(const TField &field) : mField(&field), mIsField(true) {}
44
45
    ANGLE_INLINE const TVariable &variable() const
46
    {
47
        ASSERT(isVariable());
48
        return *mVariable;
49
    }
50
51
    ANGLE_INLINE const TField &field() const
52
    {
53
        ASSERT(isField());
54
        return *mField;
55
    }
56
57
    ANGLE_INLINE bool isVariable() const { return !mIsField; }
58
59
    ANGLE_INLINE bool isField() const { return mIsField; }
60
61
    const TType &type() const { return isField() ? *field().type() : variable().getType(); }
62
63
    SymbolType symbolType() const
64
    {
65
        return isField() ? field().symbolType() : variable().symbolType();
66
    }
67
68
  private:
69
    union
70
    {
71
        const TVariable *mVariable;
72
        const TField *mField;
73
    };
74
    bool mIsField;
75
};
76
77
class GenMetalTraverser : public TIntermTraverser
78
{
79
  public:
80
    ~GenMetalTraverser() override;
81
82
    GenMetalTraverser(const TCompiler &compiler,
83
                      Sink &out,
84
                      IdGen &idGen,
85
                      const PipelineStructs &pipelineStructs,
86
                      const Invariants &invariants,
87
                      SymbolEnv &symbolEnv);
88
89
    void visitSymbol(TIntermSymbol *) override;
90
    void visitConstantUnion(TIntermConstantUnion *) override;
91
    bool visitSwizzle(Visit, TIntermSwizzle *) override;
92
    bool visitBinary(Visit, TIntermBinary *) override;
93
    bool visitUnary(Visit, TIntermUnary *) override;
94
    bool visitTernary(Visit, TIntermTernary *) override;
95
    bool visitIfElse(Visit, TIntermIfElse *) override;
96
    bool visitSwitch(Visit, TIntermSwitch *) override;
97
    bool visitCase(Visit, TIntermCase *) override;
98
    void visitFunctionPrototype(TIntermFunctionPrototype *) override;
99
    bool visitFunctionDefinition(Visit, TIntermFunctionDefinition *) override;
100
    bool visitAggregate(Visit, TIntermAggregate *) override;
101
    bool visitBlock(Visit, TIntermBlock *) override;
102
    bool visitGlobalQualifierDeclaration(Visit, TIntermGlobalQualifierDeclaration *) override;
103
    bool visitDeclaration(Visit, TIntermDeclaration *) override;
104
    bool visitLoop(Visit, TIntermLoop *) override;
105
    bool visitForLoop(TIntermLoop *);
106
    bool visitWhileLoop(TIntermLoop *);
107
    bool visitDoWhileLoop(TIntermLoop *);
108
    bool visitBranch(Visit, TIntermBranch *) override;
109
110
  private:
111
    using FuncToName = std::map<ImmutableString, Name>;
112
    static FuncToName BuildFuncToName();
113
114
    struct EmitVariableDeclarationConfig
115
    {
116
        bool isParameter                = false;
117
        bool isMainParameter            = false;
118
        bool emitPostQualifier          = false;
119
        bool isPacked                   = false;
120
        bool disableStructSpecifier     = false;
121
        const AddressSpace *isPointer   = nullptr;
122
        const AddressSpace *isReference = nullptr;
123
    };
124
125
    struct EmitTypeConfig
126
    {
127
        const EmitVariableDeclarationConfig *evdConfig = nullptr;
128
    };
129
130
    void emitIndentation();
131
    void emitFunctionSignature(const TFunction &func);
132
    void emitFunctionReturn(const TFunction &func);
133
    void emitFunctionParameter(const TFunction &func, const TVariable &param);
134
135
    void emitNameOf(const TField &object);
136
    void emitNameOf(const TSymbol &object);
137
    void emitNameOf(const VarDecl &object);
138
139
    void emitBareTypeName(const TType &type, const EmitTypeConfig &etConfig);
140
    void emitType(const TType &type, const EmitTypeConfig &etConfig);
141
    void emitPostQualifier(const EmitVariableDeclarationConfig &evdConfig,
142
                           const VarDecl &decl,
143
                           const TQualifier qualifier);
144
145
    struct FieldAnnotationIndices
146
    {
147
        size_t attribute = 0;
148
        size_t color     = 0;
149
    };
150
151
    void emitFieldDeclaration(const TField &field,
152
                              const TStructure &parent,
153
                              FieldAnnotationIndices &annotationIndices);
154
    void emitAttributeDeclaration(const TField &field, FieldAnnotationIndices &annotationIndices);
155
    void emitStructDeclaration(const TType &type);
156
    void emitOrdinaryVariableDeclaration(const VarDecl &decl,
157
                                         const EmitVariableDeclarationConfig &evdConfig);
158
    void emitVariableDeclaration(const VarDecl &decl,
159
                                 const EmitVariableDeclarationConfig &evdConfig);
160
161
    void emitOpenBrace();
162
    void emitCloseBrace();
163
164
    void groupedTraverse(TIntermNode &node);
165
166
    const TField &getDirectField(const TFieldListCollection &fieldsNode,
167
                                 const TConstantUnion &index);
168
    const TField &getDirectField(const TIntermTyped &fieldsNode, TIntermTyped &indexNode);
169
170
    const TConstantUnion *emitConstantUnionArray(const TConstantUnion *const constUnion,
171
                                                 const size_t size);
172
173
    const TConstantUnion *emitConstantUnion(const TType &type, const TConstantUnion *constUnion);
174
175
    void emitSingleConstant(const TConstantUnion *const constUnion);
176
177
  private:
178
    Sink &mOut;
179
    const TCompiler &mCompiler;
180
    const PipelineStructs &mPipelineStructs;
181
    const Invariants &mInvariants;
182
    SymbolEnv &mSymbolEnv;
183
    IdGen &mIdGen;
184
    int mIndentLevel        = -1;
185
    int mLastIndentationPos = -1;
186
    bool mParentIsSwitch    = false;
187
    std::unordered_map<const TSymbol *, Name> mRenamedSymbols;
188
    const FuncToName mFuncToName   = BuildFuncToName();
189
    size_t mMainTextureIndex       = 0;
190
    size_t mMainSamplerIndex       = 0;
191
    size_t mMainUniformBufferIndex = rx::mtl::kDefaultUniformsBindingIndex;
192
};
193
194
}  // anonymous namespace
195
196
GenMetalTraverser::~GenMetalTraverser()
197
{
198
    ASSERT(mIndentLevel == -1);
199
    ASSERT(!mParentIsSwitch);
200
}
201
202
GenMetalTraverser::GenMetalTraverser(const TCompiler &compiler,
203
                                     Sink &out,
204
                                     IdGen &idGen,
205
                                     const PipelineStructs &pipelineStructs,
206
                                     const Invariants &invariants,
207
                                     SymbolEnv &symbolEnv)
208
    : TIntermTraverser(true, false, false),
209
      mOut(out),
210
      mCompiler(compiler),
211
      mPipelineStructs(pipelineStructs),
212
      mInvariants(invariants),
213
      mSymbolEnv(symbolEnv),
214
      mIdGen(idGen)
215
{}
216
217
void GenMetalTraverser::emitIndentation()
218
{
219
    ASSERT(mIndentLevel >= 0);
220
221
    if (mLastIndentationPos == mOut.size())
222
    {
223
        return;  // Line is already indented.
224
    }
225
226
    for (int i = 0; i < mIndentLevel; ++i)
227
    {
228
        mOut << "  ";
229
    }
230
231
    mLastIndentationPos = mOut.size();
232
}
233
234
static const char *GetOperatorString(TOperator op,
235
                                     const TType &resultType,
236
                                     const TType *argType0,
237
                                     const TType *argType1 = nullptr)
238
{
239
    switch (op)
240
    {
241
        case TOperator::EOpComma:
242
            return ",";
243
        case TOperator::EOpAssign:
244
            return "=";
245
        case TOperator::EOpInitialize:
246
            return "=";
247
        case TOperator::EOpAddAssign:
248
            return "+=";
249
        case TOperator::EOpSubAssign:
250
            return "-=";
251
        case TOperator::EOpMulAssign:
252
            return "*=";
253
        case TOperator::EOpDivAssign:
254
            return "/=";
255
        case TOperator::EOpIModAssign:
256
            return "%=";
257
        case TOperator::EOpBitShiftLeftAssign:
258
            return "<<=";  // TODO: Check logical vs arithmetic shifting.
259
        case TOperator::EOpBitShiftRightAssign:
260
            return ">>=";  // TODO: Check logical vs arithmetic shifting.
261
        case TOperator::EOpBitwiseAndAssign:
262
            return "&=";
263
        case TOperator::EOpBitwiseXorAssign:
264
            return "^=";
265
        case TOperator::EOpBitwiseOrAssign:
266
            return "|=";
267
        case TOperator::EOpAdd:
268
            return "+";
269
        case TOperator::EOpSub:
270
            return "-";
271
        case TOperator::EOpMul:
272
            return "*";
273
        case TOperator::EOpDiv:
274
            return "/";
275
        case TOperator::EOpIMod:
276
            return "%";
277
        case TOperator::EOpBitShiftLeft:
278
            return "<<";  // TODO: Check logical vs arithmetic shifting.
279
        case TOperator::EOpBitShiftRight:
280
            return ">>";  // TODO: Check logical vs arithmetic shifting.
281
        case TOperator::EOpBitwiseAnd:
282
            return "&";
283
        case TOperator::EOpBitwiseXor:
284
            return "^";
285
        case TOperator::EOpBitwiseOr:
286
            return "|";
287
        case TOperator::EOpLessThan:
288
            return "<";
289
        case TOperator::EOpGreaterThan:
290
            return ">";
291
        case TOperator::EOpLessThanEqual:
292
            return "<=";
293
        case TOperator::EOpGreaterThanEqual:
294
            return ">=";
295
        case TOperator::EOpLessThanComponentWise:
296
            return "<";
297
        case TOperator::EOpLessThanEqualComponentWise:
298
            return "<=";
299
        case TOperator::EOpGreaterThanEqualComponentWise:
300
            return ">=";
301
        case TOperator::EOpGreaterThanComponentWise:
302
            return ">";
303
        case TOperator::EOpLogicalOr:
304
            return "||";
305
        case TOperator::EOpLogicalXor:
306
            return "!=/*xor*/";  // XXX: This might need to be handled differently for some obtuse
307
                                 // use case.
308
        case TOperator::EOpLogicalAnd:
309
            return "&&";
310
        case TOperator::EOpNegative:
311
            return "-";
312
        case TOperator::EOpPositive:
313
            if (argType0->isMatrix())
314
            {
315
                return "";
316
            }
317
            return "+";
318
        case TOperator::EOpLogicalNot:
319
            return "!";
320
        case TOperator::EOpLogicalNotComponentWise:
321
            return "!";
322
        case TOperator::EOpBitwiseNot:
323
            return "~";
324
        case TOperator::EOpPostIncrement:
325
            return "++";
326
        case TOperator::EOpPostDecrement:
327
            return "--";
328
        case TOperator::EOpPreIncrement:
329
            return "++";
330
        case TOperator::EOpPreDecrement:
331
            return "--";
332
        case TOperator::EOpVectorTimesScalarAssign:
333
            return "*=";
334
        case TOperator::EOpVectorTimesMatrixAssign:
335
            return "*=";
336
        case TOperator::EOpMatrixTimesScalarAssign:
337
            return "*=";
338
        case TOperator::EOpMatrixTimesMatrixAssign:
339
            return "*=";
340
        case TOperator::EOpVectorTimesScalar:
341
            return "*";
342
        case TOperator::EOpVectorTimesMatrix:
343
            return "*";
344
        case TOperator::EOpMatrixTimesVector:
345
            return "*";
346
        case TOperator::EOpMatrixTimesScalar:
347
            return "*";
348
        case TOperator::EOpMatrixTimesMatrix:
349
            return "*";
350
        case TOperator::EOpEqualComponentWise:
351
            return "==";
352
        case TOperator::EOpNotEqualComponentWise:
353
            return "!=";
354
355
        case TOperator::EOpEqual:
356
            if ((argType0->isVector() && argType1->isVector()) ||
357
                (argType0->getStruct() && argType1->getStruct()) ||
358
                (argType0->isArray() && argType1->isArray()))
359
360
            {
361
                return "ANGLE_equal";
362
            }
363
364
            return "==";
365
366
        case TOperator::EOpNotEqual:
367
            if ((argType0->isVector() && argType1->isVector()) ||
368
                (argType0->isArray() && argType1->isArray()))
369
            {
370
                return "ANGLE_notEqual";
371
            }
372
            else if (argType0->getStruct() && argType1->getStruct())
373
            {
374
                return "ANGLE_notEqualStruct";
375
            }
376
            return "!=";
377
378
        case TOperator::EOpKill:
379
            TODO();
380
            return "kill";
381
        case TOperator::EOpReturn:
382
            return "return";
383
        case TOperator::EOpBreak:
384
            return "break";
385
        case TOperator::EOpContinue:
386
            return "continue";
387
388
        case TOperator::EOpRadians:
389
            return "ANGLE_radians";
390
        case TOperator::EOpDegrees:
391
            return "ANGLE_degrees";
392
        case TOperator::EOpAtan:
393
            return "ANGLE_atan";
394
        case TOperator::EOpMod:
395
            return "ANGLE_mod";  // differs from metal::mod
396
        case TOperator::EOpRefract:
397
            return "ANGLE_refract";
398
        case TOperator::EOpDistance:
399
            return "ANGLE_distance";
400
        case TOperator::EOpLength:
401
            return "ANGLE_length";
402
        case TOperator::EOpDot:
403
            return "ANGLE_dot";
404
        case TOperator::EOpNormalize:
405
            return "ANGLE_normalize";
406
        case TOperator::EOpFaceforward:
407
            return "ANGLE_faceforward";
408
        case TOperator::EOpReflect:
409
            return "ANGLE_reflect";
410
        case TOperator::EOpMulMatrixComponentWise:
411
            return "ANGLE_componentWiseMultiply";
412
        case TOperator::EOpOuterProduct:
413
            return "ANGLE_outerProduct";
414
        case TOperator::EOpSign:
415
            return "ANGLE_sign";
416
417
        case TOperator::EOpAbs:
418
            return "metal::abs";
419
        case TOperator::EOpAll:
420
            return "metal::all";
421
        case TOperator::EOpAny:
422
            return "metal::any";
423
        case TOperator::EOpSin:
424
            return "metal::sin";
425
        case TOperator::EOpCos:
426
            return "metal::cos";
427
        case TOperator::EOpTan:
428
            return "metal::tan";
429
        case TOperator::EOpAsin:
430
            return "metal::asin";
431
        case TOperator::EOpAcos:
432
            return "metal::acos";
433
        case TOperator::EOpSinh:
434
            return "metal::sinh";
435
        case TOperator::EOpCosh:
436
            return "metal::cosh";
437
        case TOperator::EOpTanh:
438
            return "metal::tanh";
439
        case TOperator::EOpAsinh:
440
            return "metal::asinh";
441
        case TOperator::EOpAcosh:
442
            return "metal::acosh";
443
        case TOperator::EOpAtanh:
444
            return "metal::atanh";
445
        case TOperator::EOpFma:
446
            return "metal::fma";
447
        case TOperator::EOpPow:
448
            return "metal::pow";
449
        case TOperator::EOpExp:
450
            return "metal::exp";
451
        case TOperator::EOpExp2:
452
            return "metal::exp2";
453
        case TOperator::EOpLog:
454
            return "metal::log";
455
        case TOperator::EOpLog2:
456
            return "metal::log2";
457
        case TOperator::EOpSqrt:
458
            return "metal::sqrt";
459
        case TOperator::EOpFloor:
460
            return "metal::floor";
461
        case TOperator::EOpTrunc:
462
            return "metal::trunc";
463
        case TOperator::EOpCeil:
464
            return "metal::ceil";
465
        case TOperator::EOpFract:
466
            return "metal::fract";
467
        case TOperator::EOpMin:
468
            return "metal::min";
469
        case TOperator::EOpMax:
470
            return "metal::max";
471
        case TOperator::EOpRound:
472
            return "metal::round";
473
        case TOperator::EOpRoundEven:
474
            return "metal::rint";
475
        case TOperator::EOpClamp:
476
            return "metal::clamp";  // TODO fast vs precise namespace
477
        case TOperator::EOpMix:
478
            return "metal::mix";
479
        case TOperator::EOpStep:
480
            return "metal::step";
481
        case TOperator::EOpSmoothstep:
482
            return "metal::smoothstep";
483
        case TOperator::EOpModf:
484
            return "metal::modf";
485
        case TOperator::EOpIsnan:
486
            return "metal::isnan";
487
        case TOperator::EOpIsinf:
488
            return "metal::isinf";
489
        case TOperator::EOpLdexp:
490
            return "metal::ldexp";
491
        case TOperator::EOpFrexp:
492
            return "metal::frexp";
493
        case TOperator::EOpInversesqrt:
494
            return "metal::rsqrt";
495
        case TOperator::EOpCross:
496
            return "metal::cross";
497
        case TOperator::EOpDFdx:
498
            return "metal::dfdx";
499
        case TOperator::EOpDFdy:
500
            return "metal::dfdy";
501
        case TOperator::EOpFwidth:
502
            return "metal::fwidth";
503
        case TOperator::EOpTranspose:
504
            return "metal::transpose";
505
        case TOperator::EOpDeterminant:
506
            return "metal::determinant";
507
508
        case TOperator::EOpInverse:
509
            return "ANGLE_inverse";
510
511
        case TOperator::EOpFloatBitsToInt:
512
        case TOperator::EOpFloatBitsToUint:
513
        case TOperator::EOpIntBitsToFloat:
514
        case TOperator::EOpUintBitsToFloat:
515
        {
516
#define RETURN_AS_TYPE(post)                     \
517
    do                                           \
518
        switch (resultType.getBasicType())       \
519
        {                                        \
520
            case TBasicType::EbtInt:             \
521
                return "as_type<int" post ">";   \
522
            case TBasicType::EbtUInt:            \
523
                return "as_type<uint" post ">";  \
524
            case TBasicType::EbtFloat:           \
525
                return "as_type<float" post ">"; \
526
            default:                             \
527
                TODO();                          \
528
                return "TOperator_TODO";         \
529
        }                                        \
530
    while (false)
531
532
            if (resultType.isScalar())
533
            {
534
                RETURN_AS_TYPE("");
535
            }
536
            else if (resultType.isVector())
537
            {
538
                switch (resultType.getNominalSize())
539
                {
540
                    case 2:
541
                        RETURN_AS_TYPE("2");
542
                    case 3:
543
                        RETURN_AS_TYPE("3");
544
                    case 4:
545
                        RETURN_AS_TYPE("4");
546
                    default:
547
                        LOGIC_ERROR();
548
                        return nullptr;
549
                }
550
            }
551
            else
552
            {
553
                TODO();
554
                return "TOperator_TODO";
555
            }
556
557
#undef RETURN_AS_TYPE
558
        }
559
560
        case TOperator::EOpPackUnorm2x16:
561
            return "metal::pack_float_to_unorm2x16";
562
        case TOperator::EOpPackSnorm2x16:
563
            return "metal::pack_float_to_snorm2x16";
564
565
        case TOperator::EOpPackUnorm4x8:
566
            return "metal::pack_float_to_unorm4x8";
567
        case TOperator::EOpPackSnorm4x8:
568
            return "metal::pack_float_to_snorm4x8";
569
570
        case TOperator::EOpUnpackUnorm2x16:
571
            return "metal::unpack_unorm2x16_to_float";
572
        case TOperator::EOpUnpackSnorm2x16:
573
            return "metal::unpack_snorm2x16_to_float";
574
575
        case TOperator::EOpUnpackUnorm4x8:
576
            return "metal::unpack_unorm4x8_to_float";
577
        case TOperator::EOpUnpackSnorm4x8:
578
            return "metal::unpack_snorm4x8_to_float";
579
580
        case TOperator::EOpPackHalf2x16:
581
            return "ANGLE_pack_half_2x16";
582
        case TOperator::EOpUnpackHalf2x16:
583
            return "ANGLE_unpack_half_2x16";
584
585
        case TOperator::EOpBitfieldExtract:
586
        case TOperator::EOpBitfieldInsert:
587
        case TOperator::EOpBitfieldReverse:
588
        case TOperator::EOpBitCount:
589
        case TOperator::EOpFindLSB:
590
        case TOperator::EOpFindMSB:
591
        case TOperator::EOpUaddCarry:
592
        case TOperator::EOpUsubBorrow:
593
        case TOperator::EOpUmulExtended:
594
        case TOperator::EOpImulExtended:
595
        case TOperator::EOpBarrier:
596
        case TOperator::EOpMemoryBarrier:
597
        case TOperator::EOpMemoryBarrierAtomicCounter:
598
        case TOperator::EOpMemoryBarrierBuffer:
599
        case TOperator::EOpMemoryBarrierImage:
600
        case TOperator::EOpMemoryBarrierShared:
601
        case TOperator::EOpGroupMemoryBarrier:
602
        case TOperator::EOpAtomicAdd:
603
        case TOperator::EOpAtomicMin:
604
        case TOperator::EOpAtomicMax:
605
        case TOperator::EOpAtomicAnd:
606
        case TOperator::EOpAtomicOr:
607
        case TOperator::EOpAtomicXor:
608
        case TOperator::EOpAtomicExchange:
609
        case TOperator::EOpAtomicCompSwap:
610
        case TOperator::EOpEmitVertex:
611
        case TOperator::EOpEndPrimitive:
612
        case TOperator::EOpFTransform:
613
        case TOperator::EOpPackDouble2x32:
614
        case TOperator::EOpUnpackDouble2x32:
615
        case TOperator::EOpArrayLength:
616
            TODO();
617
            return "TOperator_TODO";
618
619
        case TOperator::EOpNull:
620
        case TOperator::EOpConstruct:
621
        case TOperator::EOpCallFunctionInAST:
622
        case TOperator::EOpCallInternalRawFunction:
623
        case TOperator::EOpCallBuiltInFunction:
624
        case TOperator::EOpIndexDirect:
625
        case TOperator::EOpIndexIndirect:
626
        case TOperator::EOpIndexDirectStruct:
627
        case TOperator::EOpIndexDirectInterfaceBlock:
628
            LOGIC_ERROR();
629
            return nullptr;
630
    }
631
}
632
633
#if 0
634
static int GetOperatorPrecedence(TOperator op)
635
{
636
    switch (op)
637
    {
638
        case TOperator::EOpComma: {
639
            return 17;
640
        } break;
641
642
        case TOperator::EOpAssign:
643
        case TOperator::EOpInitialize:
644
        case TOperator::EOpAddAssign:
645
        case TOperator::EOpSubAssign:
646
        case TOperator::EOpMulAssign:
647
        case TOperator::EOpDivAssign:
648
        case TOperator::EOpIModAssign:
649
        case TOperator::EOpBitShiftLeftAssign:
650
        case TOperator::EOpBitShiftRightAssign:
651
        case TOperator::EOpBitwiseAndAssign:
652
        case TOperator::EOpBitwiseXorAssign:
653
        case TOperator::EOpBitwiseOrAssign: {
654
            return 16;
655
        } break;
656
657
        case TOperator::EOpLogicalOr: {
658
            return 15;
659
        } break;
660
661
        case TOperator::EOpLogicalAnd: {
662
            return 14;
663
        } break;
664
665
        case TOperator::EOpBitwiseOr: {
666
            return 13;
667
        } break;
668
669
        case TOperator::EOpBitwiseXor: {
670
            return 12;
671
        } break;
672
673
        case TOperator::EOpBitwiseAnd: {
674
            return 11;
675
        } break;
676
677
        case TOperator::EOpLogicalXor:
678
        case TOperator::EOpEqual:
679
        case TOperator::EOpNotEqual: {
680
            return 10;
681
        } break;
682
683
        case TOperator::EOpLessThan:
684
        case TOperator::EOpGreaterThan:
685
        case TOperator::EOpLessThanEqual:
686
        case TOperator::EOpGreaterThanEqual: {
687
            return 9;
688
        } break;
689
690
        case TOperator::EOpBitShiftLeft:
691
        case TOperator::EOpBitShiftRight: {
692
            return 7;
693
        } break;
694
695
        case TOperator::EOpAdd:
696
        case TOperator::EOpSub: {
697
            return 6;
698
        } break;
699
700
        case TOperator::EOpMul:
701
        case TOperator::EOpDiv:
702
        case TOperator::EOpIMod: {
703
            return 5;
704
        } break;
705
706
        case TOperator::EOpNegative:
707
        case TOperator::EOpPositive:
708
        case TOperator::EOpLogicalNot:
709
        case TOperator::EOpBitwiseNot:
710
        case TOperator::EOpPreIncrement:
711
        case TOperator::EOpPreDecrement: {
712
            return 3;
713
        } break;
714
715
        case TOperator::EOpPostIncrement:
716
        case TOperator::EOpPostDecrement: {
717
            return 2;
718
        } break;
719
720
        default: {
721
            TODO();
722
            return -1;
723
        }
724
    }
725
}
726
727
namespace
728
{
729
730
enum class Associativity
731
{
732
    None,
733
    Left,
734
    Right,
735
};
736
737
} // anonymous namespace
738
739
static Associativity GetAssociativity(TOperator op)
740
{
741
    switch (op)
742
    {
743
        case TOperator::EOpAdd:
744
        case TOperator::EOpSub:
745
        case TOperator::EOpMul:
746
        case TOperator::EOpDiv:
747
        case TOperator::EOpIMod:
748
        case TOperator::EOpBitShiftLeft:
749
        case TOperator::EOpBitShiftRight:
750
        case TOperator::EOpBitwiseAnd:
751
        case TOperator::EOpBitwiseXor:
752
        case TOperator::EOpBitwiseOr:
753
        case TOperator::EOpEqual:
754
        case TOperator::EOpNotEqual:
755
        case TOperator::EOpLessThan:
756
        case TOperator::EOpGreaterThan:
757
        case TOperator::EOpLessThanEqual:
758
        case TOperator::EOpGreaterThanEqual:
759
        case TOperator::EOpLogicalOr:
760
        case TOperator::EOpLogicalXor:
761
        case TOperator::EOpLogicalAnd:
762
        case TOperator::EOpComma: {
763
            return Associativity::Left;
764
        } break;
765
766
        case TOperator::EOpAssign:
767
        case TOperator::EOpInitialize:
768
        case TOperator::EOpAddAssign:
769
        case TOperator::EOpSubAssign:
770
        case TOperator::EOpMulAssign:
771
        case TOperator::EOpDivAssign:
772
        case TOperator::EOpIModAssign:
773
        case TOperator::EOpBitShiftLeftAssign:
774
        case TOperator::EOpBitShiftRightAssign:
775
        case TOperator::EOpBitwiseAndAssign:
776
        case TOperator::EOpBitwiseXorAssign:
777
        case TOperator::EOpBitwiseOrAssign: {
778
            return Associativity::Right;
779
        } break;
780
781
        case TOperator::EOpNegative:
782
        case TOperator::EOpPositive:
783
        case TOperator::EOpLogicalNot:
784
        case TOperator::EOpBitwiseNot:
785
        case TOperator::EOpPostIncrement:
786
        case TOperator::EOpPostDecrement:
787
        case TOperator::EOpPreIncrement:
788
        case TOperator::EOpPreDecrement: {
789
            return Associativity::None;
790
        } break;
791
792
        default: {
793
            TODO();
794
            return Associativity::None;
795
        }
796
    }
797
}
798
#endif
799
800
static bool IsSymbolicOperator(TOperator op,
801
                               const TType &resultType,
802
                               const TType *argType0,
803
                               const TType *argType1 = nullptr)
804
{
805
    if (op == TOperator::EOpCallBuiltInFunction)
806
    {
807
        return false;
808
    }
809
    return !std::isalnum(GetOperatorString(op, resultType, argType0, argType1)[0]);
810
}
811
812
static TIntermBinary *AsSpecificBinaryNode(TIntermNode &node, TOperator op)
813
{
814
    TIntermBinary *binaryNode = node.getAsBinaryNode();
815
    if (binaryNode)
816
    {
817
        return binaryNode->getOp() == op ? binaryNode : nullptr;
818
    }
819
    return nullptr;
820
}
821
822
static bool Parenthesize(TIntermNode &node)
823
{
824
    if (node.getAsSymbolNode())
825
    {
826
        return false;
827
    }
828
    if (node.getAsConstantUnion())
829
    {
830
        return false;
831
    }
832
    if (node.getAsAggregate())
833
    {
834
        return false;
835
    }
836
    if (node.getAsSwizzleNode())
837
    {
838
        return false;
839
    }
840
841
    if (TIntermUnary *unaryNode = node.getAsUnaryNode())
842
    {
843
        // TODO: Use a precedence and associativity rules instead of this ad-hoc impl.
844
        const TType &resultType = unaryNode->getType();
845
        const TType &argType    = unaryNode->getOperand()->getType();
846
        return IsSymbolicOperator(unaryNode->getOp(), resultType, &argType);
847
    }
848
849
    if (TIntermBinary *binaryNode = node.getAsBinaryNode())
850
    {
851
        // TODO: Use a precedence and associativity rules instead of this ad-hoc impl.
852
        const TOperator op = binaryNode->getOp();
853
        switch (op)
854
        {
855
            case TOperator::EOpIndexDirectStruct:
856
            case TOperator::EOpIndexDirectInterfaceBlock:
857
            case TOperator::EOpIndexDirect:
858
            case TOperator::EOpIndexIndirect:
859
                return Parenthesize(*binaryNode->getLeft());
860
861
            case TOperator::EOpAssign:
862
            case TOperator::EOpInitialize:
863
                return AsSpecificBinaryNode(*binaryNode->getRight(), TOperator::EOpComma);
864
865
            default:
866
            {
867
                const TType &resultType = binaryNode->getType();
868
                const TType &leftType   = binaryNode->getLeft()->getType();
869
                const TType &rightType  = binaryNode->getRight()->getType();
870
                return IsSymbolicOperator(binaryNode->getOp(), resultType, &leftType, &rightType);
871
            }
872
        }
873
    }
874
875
    return true;
876
}
877
878
void GenMetalTraverser::groupedTraverse(TIntermNode &node)
879
{
880
    const bool emitParens = Parenthesize(node);
881
882
    if (emitParens)
883
    {
884
        mOut << "(";
885
    }
886
887
    node.traverse(this);
888
889
    if (emitParens)
890
    {
891
        mOut << ")";
892
    }
893
}
894
895
void GenMetalTraverser::emitPostQualifier(const EmitVariableDeclarationConfig &evdConfig,
896
                                          const VarDecl &decl,
897
                                          const TQualifier qualifier)
898
{
899
    switch (qualifier)
900
    {
901
        case TQualifier::EvqPosition:
902
        case TQualifier::EvqFragCoord:
903
            mOut << " [[position]]";
904
            break;
905
906
        case TQualifier::EvqPointSize:
907
            mOut << " [[point_size]]";
908
            break;
909
910
        case TQualifier::EvqVertexID:
911
            if (evdConfig.isMainParameter)
912
            {
913
                mOut << " [[vertex_id]]";
914
            }
915
            break;
916
917
        case TQualifier::EvqPointCoord:
918
            if (evdConfig.isMainParameter)
919
            {
920
                mOut << " [[point_coord]]";
921
            }
922
            break;
923
924
        case TQualifier::EvqFrontFacing:
925
            if (evdConfig.isMainParameter)
926
            {
927
                mOut << " [[front_facing]]";
928
            }
929
            break;
930
931
        default:
932
            break;
933
    }
934
935
    const bool isInvariant =
936
        decl.isField() ? mInvariants.contains(decl.field()) : mInvariants.contains(decl.variable());
937
938
    if (isInvariant)
939
    {
940
        mOut << " [[invariant]]";
941
    }
942
}
943
944
static void EmitName(Sink &out, const Name &name)
945
{
946
#if defined(ANGLE_ENABLE_ASSERTS)
947
    DebugSink::EscapedSink escapedOut(out.escape());
948
#else
949
    TInfoSinkBase &escapedOut = out;
950
#endif
951
    name.emit(escapedOut);
952
}
953
954
void GenMetalTraverser::emitNameOf(const TField &object)
955
{
956
    EmitName(mOut, Name(object));
957
}
958
959
void GenMetalTraverser::emitNameOf(const TSymbol &object)
960
{
961
    auto it = mRenamedSymbols.find(&object);
962
    if (it == mRenamedSymbols.end())
963
    {
964
        EmitName(mOut, Name(object));
965
    }
966
    else
967
    {
968
        EmitName(mOut, it->second);
969
    }
970
}
971
972
void GenMetalTraverser::emitNameOf(const VarDecl &object)
973
{
974
    if (object.isField())
975
    {
976
        emitNameOf(object.field());
977
    }
978
    else
979
    {
980
        emitNameOf(object.variable());
981
    }
982
}
983
984
void GenMetalTraverser::emitBareTypeName(const TType &type, const EmitTypeConfig &etConfig)
985
{
986
    const TBasicType basicType = type.getBasicType();
987
988
    switch (basicType)
989
    {
990
        case TBasicType::EbtVoid:
991
        case TBasicType::EbtBool:
992
        case TBasicType::EbtFloat:
993
        case TBasicType::EbtInt:
994
        case TBasicType::EbtUInt:
995
        {
996
            mOut << type.getBasicString();
997
        }
998
        break;
999
1000
        case TBasicType::EbtStruct:
1001
        {
1002
            const TStructure &structure = *type.getStruct();
1003
            emitNameOf(structure);
1004
        }
1005
        break;
1006
1007
        case TBasicType::EbtInterfaceBlock:
1008
        {
1009
            const TInterfaceBlock &interfaceBlock = *type.getInterfaceBlock();
1010
            emitNameOf(interfaceBlock);
1011
        }
1012
        break;
1013
1014
        default:
1015
        {
1016
            if (IsSampler(basicType))
1017
            {
1018
                if (etConfig.evdConfig && etConfig.evdConfig->isMainParameter)
1019
                {
1020
                    EmitName(mOut, GetTextureTypeName(basicType));
1021
                }
1022
                else
1023
                {
1024
                    const TStructure &env = mSymbolEnv.getTextureEnv(basicType);
1025
                    emitNameOf(env);
1026
                }
1027
            }
1028
            else
1029
            {
1030
                TODO();
1031
            }
1032
        }
1033
    }
1034
}
1035
1036
void GenMetalTraverser::emitType(const TType &type, const EmitTypeConfig &etConfig)
1037
{
1038
    if (etConfig.evdConfig)
1039
    {
1040
        const auto &evdConfig = *etConfig.evdConfig;
1041
        if (evdConfig.isPointer)
1042
        {
1043
            mOut << toString(*evdConfig.isPointer);
1044
            mOut << " ";
1045
        }
1046
        else if (evdConfig.isReference)
1047
        {
1048
            mOut << toString(*evdConfig.isReference);
1049
            mOut << " ";
1050
        }
1051
    }
1052
1053
    if (type.isArray())
1054
    {
1055
        mOut << "ANGLE_tensor<";
1056
    }
1057
1058
    if (type.isVector() || type.isMatrix())
1059
    {
1060
        mOut << "metal::";
1061
    }
1062
1063
    if (etConfig.evdConfig && etConfig.evdConfig->isPacked)
1064
    {
1065
        mOut << "packed_";
1066
    }
1067
1068
    emitBareTypeName(type, etConfig);
1069
1070
    if (type.isVector())
1071
    {
1072
        mOut << type.getNominalSize();
1073
    }
1074
    else if (type.isMatrix())
1075
    {
1076
        mOut << type.getCols() << "x" << type.getRows();
1077
    }
1078
1079
    if (type.isArray())
1080
    {
1081
        for (auto size : type.getArraySizes())
1082
        {
1083
            mOut << ", " << size;
1084
        }
1085
        mOut << ">";
1086
    }
1087
1088
    if (etConfig.evdConfig)
1089
    {
1090
        const auto &evdConfig = *etConfig.evdConfig;
1091
        if (evdConfig.isPointer)
1092
        {
1093
            mOut << " *";
1094
        }
1095
        else if (evdConfig.isReference)
1096
        {
1097
            mOut << " &";
1098
        }
1099
    }
1100
}
1101
1102
void GenMetalTraverser::emitFieldDeclaration(const TField &field,
1103
                                             const TStructure &parent,
1104
                                             FieldAnnotationIndices &annotationIndices)
1105
{
1106
    const TType &type      = *field.type();
1107
    const TBasicType basic = type.getBasicType();
1108
1109
    EmitVariableDeclarationConfig evdConfig;
1110
    evdConfig.emitPostQualifier      = true;
1111
    evdConfig.disableStructSpecifier = true;
1112
    evdConfig.isPacked               = mSymbolEnv.isPacked(field);
1113
    evdConfig.isPointer              = mSymbolEnv.isPointer(field);
1114
    evdConfig.isReference            = mSymbolEnv.isReference(field);
1115
    emitVariableDeclaration(VarDecl(field), evdConfig);
1116
1117
    const TQualifier qual = type.getQualifier();
1118
    switch (qual)
1119
    {
1120
        case TQualifier::EvqFlatIn:
1121
            if (mPipelineStructs.fragmentIn.external == &parent)
1122
            {
1123
                mOut << " [[flat]]";
1124
            }
1125
            break;
1126
1127
        case TQualifier::EvqFragmentOut:
1128
        case TQualifier::EvqFragData:
1129
            if (mPipelineStructs.fragmentOut.external == &parent)
1130
            {
1131
                if ((type.isVector() &&
1132
                     (basic == TBasicType::EbtInt || basic == TBasicType::EbtUInt ||
1133
                      basic == TBasicType::EbtFloat)) ||
1134
                    type.getQualifier() == EvqFragData)
1135
                {
1136
                    // TODO:
1137
                    // This is not correct in general and needs a reimplementation.
1138
                    // In GLSL 3.0, We can't always assume this is going to be a safe index.
1139
                    // See 4.3.8.2
1140
                    // https://www.khronos.org/registry/OpenGL/specs/es/3.0/GLSL_ES_Specification_3.00.pdf
1141
                    size_t index = annotationIndices.color++;
1142
                    mOut << " [[color(" << index << ")]]";
1143
                }
1144
            }
1145
            break;
1146
1147
        case TQualifier::EvqFragDepth:
1148
            mOut << " [[depth(any)]]";
1149
            break;
1150
1151
        default:
1152
            break;
1153
    }
1154
}
1155
1156
static std::map<Name, size_t> BuildExternalAttributeIndexMap(
1157
    const TCompiler &compiler,
1158
    const PipelineScoped<TStructure> &structure)
1159
{
1160
    ASSERT(structure.isTotallyFull());
1161
1162
    const auto &shaderVars     = compiler.getAttributes();
1163
    const size_t shaderVarSize = shaderVars.size();
1164
    size_t shaderVarIndex      = 0;
1165
1166
    const auto &externalFields = structure.external->fields();
1167
    const size_t externalSize  = externalFields.size();
1168
    size_t externalIndex       = 0;
1169
1170
    const auto &internalFields = structure.internal->fields();
1171
    const size_t internalSize  = internalFields.size();
1172
    size_t internalIndex       = 0;
1173
1174
    // Internal fields are never split. External fields are sometimes split.
1175
    ASSERT(externalSize >= internalSize);
1176
1177
    // Structures do not contain any inactive fields.
1178
    ASSERT(shaderVarSize >= internalSize);
1179
1180
    std::map<Name, size_t> externalNameToAttributeIndex;
1181
    size_t attributeIndex = 0;
1182
1183
    while (internalIndex < internalSize)
1184
    {
1185
        const TField &internalField = *internalFields[internalIndex];
1186
        const Name internalName     = Name(internalField);
1187
        const TType &internalType   = *internalField.type();
1188
        while (internalName.rawName() != shaderVars[shaderVarIndex].name)
1189
        {
1190
            // This case represents an inactive field.
1191
1192
            ++shaderVarIndex;
1193
            ASSERT(shaderVarIndex < shaderVarSize);
1194
1195
            ++attributeIndex;  // TODO: Might need to increment more if shader var type is a matrix.
1196
        }
1197
1198
        const size_t cols = internalType.isMatrix() ? internalType.getCols() : 1;
1199
1200
        for (size_t c = 0; c < cols; ++c)
1201
        {
1202
            const TField &externalField = *externalFields[externalIndex];
1203
            const Name externalName     = Name(externalField);
1204
            ASSERT(!externalField.type()->isMatrix());
1205
1206
            externalNameToAttributeIndex[externalName] = attributeIndex;
1207
1208
            ++externalIndex;
1209
            ++attributeIndex;
1210
        }
1211
1212
        ++shaderVarIndex;
1213
        ++internalIndex;
1214
    }
1215
1216
    ASSERT(shaderVarIndex <= shaderVarSize);
1217
    ASSERT(externalIndex <= externalSize);  // less than if padding was introduced
1218
    ASSERT(internalIndex == internalSize);
1219
1220
    return externalNameToAttributeIndex;
1221
}
1222
1223
void GenMetalTraverser::emitAttributeDeclaration(const TField &field,
1224
                                                 FieldAnnotationIndices &annotationIndices)
1225
{
1226
    EmitVariableDeclarationConfig evdConfig;
1227
    evdConfig.disableStructSpecifier = true;
1228
    emitVariableDeclaration(VarDecl(field), evdConfig);
1229
    mOut << " [[attribute(" << annotationIndices.attribute++ << ")]]";
1230
}
1231
1232
void GenMetalTraverser::emitStructDeclaration(const TType &type)
1233
{
1234
    ASSERT(type.getBasicType() == TBasicType::EbtStruct);
1235
    ASSERT(type.isStructSpecifier());
1236
1237
    mOut << "struct ";
1238
    emitBareTypeName(type, {});
1239
1240
    mOut << "\n";
1241
    emitOpenBrace();
1242
1243
    const TStructure &structure = *type.getStruct();
1244
    std::map<Name, size_t> fieldToAttributeIndex;
1245
    const bool hasAttributeIndices           = mPipelineStructs.vertexIn.external == &structure;
1246
    const bool reclaimUnusedAttributeIndices = mCompiler.getShaderVersion() < 300;
1247
1248
    if (hasAttributeIndices)
1249
    {
1250
        fieldToAttributeIndex =
1251
            BuildExternalAttributeIndexMap(mCompiler, mPipelineStructs.vertexIn);
1252
    }
1253
1254
    FieldAnnotationIndices annotationIndices;
1255
1256
    for (const TField *field : structure.fields())
1257
    {
1258
        emitIndentation();
1259
        if (hasAttributeIndices)
1260
        {
1261
            const auto it = fieldToAttributeIndex.find(Name(*field));
1262
            if (it == fieldToAttributeIndex.end())
1263
            {
1264
                ASSERT(field->symbolType() == SymbolType::AngleInternal);
1265
                ASSERT(field->name().beginsWith("_"));
1266
                ASSERT(angle::EndsWith(field->name().data(), "_pad"));
1267
                emitFieldDeclaration(*field, structure, annotationIndices);
1268
            }
1269
            else
1270
            {
1271
                ASSERT(field->symbolType() != SymbolType::AngleInternal ||
1272
                       !field->name().beginsWith("_") ||
1273
                       !angle::EndsWith(field->name().data(), "_pad"));
1274
                if (!reclaimUnusedAttributeIndices)
1275
                {
1276
                    annotationIndices.attribute = it->second;
1277
                }
1278
                emitAttributeDeclaration(*field, annotationIndices);
1279
            }
1280
        }
1281
        else
1282
        {
1283
            emitFieldDeclaration(*field, structure, annotationIndices);
1284
        }
1285
        mOut << ";\n";
1286
    }
1287
1288
    if (!mPipelineStructs.matches(structure, true, true))
1289
    {
1290
        MetalLayoutOfConfig layoutConfig;
1291
        layoutConfig.treatSamplersAsTextureEnv = true;
1292
        Layout layout                          = MetalLayoutOf(type, layoutConfig);
1293
        size_t pad                             = layout.sizeOf % 16;
1294
        if (pad != 0)
1295
        {
1296
            emitIndentation();
1297
            mOut << "char ";
1298
            EmitName(mOut, mIdGen.createNewName("pad"));
1299
            mOut << "[" << pad << "];\n";
1300
        }
1301
    }
1302
1303
    emitCloseBrace();
1304
}
1305
1306
void GenMetalTraverser::emitOrdinaryVariableDeclaration(
1307
    const VarDecl &decl,
1308
    const EmitVariableDeclarationConfig &evdConfig)
1309
{
1310
    EmitTypeConfig etConfig;
1311
    etConfig.evdConfig = &evdConfig;
1312
1313
    const TType &type = decl.type();
1314
    emitType(type, etConfig);
1315
1316
    if (decl.symbolType() != SymbolType::Empty)
1317
    {
1318
        mOut << " ";
1319
        emitNameOf(decl);
1320
    }
1321
}
1322
1323
void GenMetalTraverser::emitVariableDeclaration(const VarDecl &decl,
1324
                                                const EmitVariableDeclarationConfig &evdConfig)
1325
{
1326
    const SymbolType symbolType = decl.symbolType();
1327
    const TType &type           = decl.type();
1328
    const TBasicType basicType  = type.getBasicType();
1329
1330
    switch (basicType)
1331
    {
1332
        case TBasicType::EbtStruct:
1333
        {
1334
            if (type.isStructSpecifier() && !evdConfig.disableStructSpecifier)
1335
            {
1336
                ASSERT(!evdConfig.isParameter);
1337
                emitStructDeclaration(type);
1338
                if (symbolType != SymbolType::Empty)
1339
                {
1340
                    mOut << " ";
1341
                    emitNameOf(decl);
1342
                }
1343
            }
1344
            else
1345
            {
1346
                emitOrdinaryVariableDeclaration(decl, evdConfig);
1347
            }
1348
        }
1349
        break;
1350
1351
        default:
1352
        {
1353
            ASSERT(symbolType != SymbolType::Empty || evdConfig.isParameter);
1354
            emitOrdinaryVariableDeclaration(decl, evdConfig);
1355
        }
1356
    }
1357
1358
    if (evdConfig.emitPostQualifier)
1359
    {
1360
        emitPostQualifier(evdConfig, decl, type.getQualifier());
1361
    }
1362
}
1363
1364
void GenMetalTraverser::visitSymbol(TIntermSymbol *symbolNode)
1365
{
1366
    const TVariable &var = symbolNode->variable();
1367
    const TType &type    = var.getType();
1368
1369
    ASSERT(var.symbolType() != SymbolType::Empty);
1370
1371
    if (type.getBasicType() == TBasicType::EbtVoid)
1372
    {
1373
        mOut << "/*";
1374
        emitNameOf(var);
1375
        mOut << "*/";
1376
    }
1377
    else
1378
    {
1379
        emitNameOf(var);
1380
    }
1381
}
1382
1383
void GenMetalTraverser::emitSingleConstant(const TConstantUnion *const constUnion)
1384
{
1385
    switch (constUnion->getType())
1386
    {
1387
        case TBasicType::EbtBool:
1388
        {
1389
            mOut << (constUnion->getBConst() ? "true" : "false");
1390
        }
1391
        break;
1392
1393
        case TBasicType::EbtFloat:
1394
        {
1395
            mOut << constUnion->getFConst() << "f";
1396
        }
1397
        break;
1398
1399
        case TBasicType::EbtInt:
1400
        {
1401
            mOut << constUnion->getIConst();
1402
        }
1403
        break;
1404
1405
        case TBasicType::EbtUInt:
1406
        {
1407
            mOut << constUnion->getUConst() << "u";
1408
        }
1409
        break;
1410
1411
        default:
1412
        {
1413
            TODO();
1414
        }
1415
    }
1416
}
1417
1418
const TConstantUnion *GenMetalTraverser::emitConstantUnionArray(
1419
    const TConstantUnion *const constUnion,
1420
    const size_t size)
1421
{
1422
    const TConstantUnion *constUnionIterated = constUnion;
1423
    for (size_t i = 0; i < size; i++, constUnionIterated++)
1424
    {
1425
        emitSingleConstant(constUnionIterated);
1426
1427
        if (i != size - 1)
1428
        {
1429
            mOut << ", ";
1430
        }
1431
    }
1432
    return constUnionIterated;
1433
}
1434
1435
const TConstantUnion *GenMetalTraverser::emitConstantUnion(const TType &type,
1436
                                                           const TConstantUnion *constUnionBegin)
1437
{
1438
    const TConstantUnion *constUnionCurr = constUnionBegin;
1439
    const TStructure *structure          = type.getStruct();
1440
    if (structure)
1441
    {
1442
        EmitTypeConfig config = EmitTypeConfig{nullptr};
1443
        emitType(type, config);
1444
        mOut << "{";
1445
        const TFieldList &fields = structure->fields();
1446
        for (size_t i = 0; i < fields.size(); ++i)
1447
        {
1448
            const TType *fieldType = fields[i]->type();
1449
            constUnionCurr         = emitConstantUnion(*fieldType, constUnionCurr);
1450
            if (i != fields.size() - 1)
1451
            {
1452
                mOut << ", ";
1453
            }
1454
        }
1455
        mOut << "}";
1456
    }
1457
    else
1458
    {
1459
        size_t size    = type.getObjectSize();
1460
        bool writeType = size > 1;
1461
        if (writeType)
1462
        {
1463
            EmitTypeConfig config = EmitTypeConfig{nullptr};
1464
            emitType(type, config);
1465
            mOut << "(";
1466
        }
1467
        constUnionCurr = emitConstantUnionArray(constUnionCurr, size);
1468
        if (writeType)
1469
        {
1470
            mOut << ")";
1471
        }
1472
    }
1473
    return constUnionCurr;
1474
}
1475
1476
void GenMetalTraverser::visitConstantUnion(TIntermConstantUnion *constValueNode)
1477
{
1478
    emitConstantUnion(constValueNode->getType(), constValueNode->getConstantValue());
1479
}
1480
1481
bool GenMetalTraverser::visitSwizzle(Visit, TIntermSwizzle *swizzleNode)
1482
{
1483
    groupedTraverse(*swizzleNode->getOperand());
1484
    mOut << ".";
1485
1486
    {
1487
#if defined(ANGLE_ENABLE_ASSERTS)
1488
        DebugSink::EscapedSink escapedOut(mOut.escape());
1489
        TInfoSinkBase &out = escapedOut.get();
1490
#else
1491
        TInfoSinkBase &out        = mOut;
1492
#endif
1493
        swizzleNode->writeOffsetsAsXYZW(&out);
1494
    }
1495
1496
    return false;
1497
}
1498
1499
const TField &GenMetalTraverser::getDirectField(const TFieldListCollection &fieldListCollection,
1500
                                                const TConstantUnion &index)
1501
{
1502
    ASSERT(index.getType() == TBasicType::EbtInt);
1503
1504
    const TFieldList &fieldList = fieldListCollection.fields();
1505
    const int indexVal          = index.getIConst();
1506
    const TField &field         = *fieldList[indexVal];
1507
1508
    return field;
1509
}
1510
1511
const TField &GenMetalTraverser::getDirectField(const TIntermTyped &fieldsNode,
1512
                                                TIntermTyped &indexNode)
1513
{
1514
    const TType &fieldsType = fieldsNode.getType();
1515
1516
    const TFieldListCollection *fieldListCollection = fieldsType.getStruct();
1517
    if (fieldListCollection == nullptr)
1518
    {
1519
        fieldListCollection = fieldsType.getInterfaceBlock();
1520
    }
1521
    ASSERT(fieldListCollection);
1522
1523
    const TIntermConstantUnion *indexNode_ = indexNode.getAsConstantUnion();
1524
    ASSERT(indexNode_);
1525
    const TConstantUnion &index = *indexNode_->getConstantValue();
1526
1527
    return getDirectField(*fieldListCollection, index);
1528
}
1529
1530
bool GenMetalTraverser::visitBinary(Visit, TIntermBinary *binaryNode)
1531
{
1532
    const TOperator op      = binaryNode->getOp();
1533
    TIntermTyped &leftNode  = *binaryNode->getLeft();
1534
    TIntermTyped &rightNode = *binaryNode->getRight();
1535
1536
    switch (op)
1537
    {
1538
        case TOperator::EOpIndexDirectStruct:
1539
        case TOperator::EOpIndexDirectInterfaceBlock:
1540
        {
1541
            groupedTraverse(leftNode);
1542
            mOut << ".";
1543
            emitNameOf(getDirectField(leftNode, rightNode));
1544
        }
1545
        break;
1546
1547
        case TOperator::EOpIndexDirect:
1548
        case TOperator::EOpIndexIndirect:
1549
        {
1550
            groupedTraverse(leftNode);
1551
            mOut << "[";
1552
            rightNode.traverse(this);
1553
            mOut << "]";
1554
        }
1555
        break;
1556
1557
        default:
1558
        {
1559
            const TType &resultType = binaryNode->getType();
1560
            const TType &leftType   = leftNode.getType();
1561
            const TType &rightType  = rightNode.getType();
1562
1563
            if (IsSymbolicOperator(op, resultType, &leftType, &rightType))
1564
            {
1565
                groupedTraverse(leftNode);
1566
                if (op != TOperator::EOpComma)
1567
                {
1568
                    mOut << " ";
1569
                }
1570
                mOut << GetOperatorString(op, resultType, &leftType, &rightType) << " ";
1571
                groupedTraverse(rightNode);
1572
            }
1573
            else
1574
            {
1575
                mOut << GetOperatorString(op, resultType, &leftType, &rightType) << "(";
1576
                leftNode.traverse(this);
1577
                mOut << ", ";
1578
                rightNode.traverse(this);
1579
                mOut << ")";
1580
            }
1581
        }
1582
    }
1583
1584
    return false;
1585
}
1586
1587
static bool IsPostfix(TOperator op)
1588
{
1589
    switch (op)
1590
    {
1591
        case TOperator::EOpPostIncrement:
1592
        case TOperator::EOpPostDecrement:
1593
            return true;
1594
1595
        default:
1596
            return false;
1597
    }
1598
}
1599
1600
bool GenMetalTraverser::visitUnary(Visit, TIntermUnary *unaryNode)
1601
{
1602
    const TOperator op      = unaryNode->getOp();
1603
    const TType &resultType = unaryNode->getType();
1604
1605
    TIntermTyped &arg    = *unaryNode->getOperand();
1606
    const TType &argType = arg.getType();
1607
1608
    const char *name = GetOperatorString(op, resultType, &argType);
1609
1610
    if (IsSymbolicOperator(op, resultType, &argType))
1611
    {
1612
        const bool postfix = IsPostfix(op);
1613
        if (!postfix)
1614
        {
1615
            mOut << name;
1616
        }
1617
        groupedTraverse(arg);
1618
        if (postfix)
1619
        {
1620
            mOut << name;
1621
        }
1622
    }
1623
    else
1624
    {
1625
        mOut << name << "(";
1626
        arg.traverse(this);
1627
        mOut << ")";
1628
    }
1629
1630
    return false;
1631
}
1632
1633
bool GenMetalTraverser::visitTernary(Visit, TIntermTernary *conditionalNode)
1634
{
1635
    groupedTraverse(*conditionalNode->getCondition());
1636
    mOut << " ? ";
1637
    groupedTraverse(*conditionalNode->getTrueExpression());
1638
    mOut << " : ";
1639
    groupedTraverse(*conditionalNode->getFalseExpression());
1640
1641
    return false;
1642
}
1643
1644
bool GenMetalTraverser::visitIfElse(Visit, TIntermIfElse *ifThenElseNode)
1645
{
1646
    TIntermTyped &condNode = *ifThenElseNode->getCondition();
1647
    TIntermBlock *thenNode = ifThenElseNode->getTrueBlock();
1648
    TIntermBlock *elseNode = ifThenElseNode->getFalseBlock();
1649
1650
    emitIndentation();
1651
    mOut << "if (";
1652
    condNode.traverse(this);
1653
    mOut << ")";
1654
1655
    if (thenNode)
1656
    {
1657
        mOut << "\n";
1658
        thenNode->traverse(this);
1659
    }
1660
    else
1661
    {
1662
        mOut << " {}";
1663
    }
1664
1665
    if (elseNode)
1666
    {
1667
        mOut << "\n";
1668
        emitIndentation();
1669
        mOut << "else\n";
1670
        elseNode->traverse(this);
1671
    }
1672
    else
1673
    {
1674
        // Always emit "else" even when empty block to avoid nested if-stmt issues.
1675
        mOut << " else {}";
1676
    }
1677
1678
    return false;
1679
}
1680
1681
bool GenMetalTraverser::visitSwitch(Visit, TIntermSwitch *switchNode)
1682
{
1683
    emitIndentation();
1684
    mOut << "switch (";
1685
    switchNode->getInit()->traverse(this);
1686
    mOut << ")\n";
1687
1688
    ASSERT(!mParentIsSwitch);
1689
    mParentIsSwitch = true;
1690
    switchNode->getStatementList()->traverse(this);
1691
    mParentIsSwitch = false;
1692
1693
    return false;
1694
}
1695
1696
bool GenMetalTraverser::visitCase(Visit, TIntermCase *caseNode)
1697
{
1698
    emitIndentation();
1699
1700
    if (caseNode->hasCondition())
1701
    {
1702
        TIntermTyped *condExpr = caseNode->getCondition();
1703
        mOut << "case ";
1704
        condExpr->traverse(this);
1705
        mOut << ":";
1706
    }
1707
    else
1708
    {
1709
        mOut << "default:\n";
1710
    }
1711
1712
    return false;
1713
}
1714
1715
void GenMetalTraverser::emitFunctionSignature(const TFunction &func)
1716
{
1717
    const bool isMain = func.isMain();
1718
1719
    emitFunctionReturn(func);
1720
1721
    mOut << " ";
1722
    emitNameOf(func);
1723
    if (isMain)
1724
    {
1725
        mOut << "0";
1726
    }
1727
    mOut << "(";
1728
1729
    bool emitComma          = false;
1730
    const size_t paramCount = func.getParamCount();
1731
    for (size_t i = 0; i < paramCount; ++i)
1732
    {
1733
        if (emitComma)
1734
        {
1735
            mOut << ", ";
1736
        }
1737
        emitComma = true;
1738
1739
        const TVariable &param = *func.getParam(i);
1740
        emitFunctionParameter(func, param);
1741
    }
1742
1743
    mOut << ")";
1744
}
1745
1746
void GenMetalTraverser::emitFunctionReturn(const TFunction &func)
1747
{
1748
    const bool isMain = func.isMain();
1749
1750
    const TType &returnType = func.getReturnType();
1751
    if (isMain)
1752
    {
1753
        const TStructure *structure = returnType.getStruct();
1754
        ASSERT(structure != nullptr);
1755
        if (mPipelineStructs.fragmentOut.matches(*structure))
1756
        {
1757
            mOut << "fragment ";
1758
        }
1759
        else if (mPipelineStructs.vertexOut.matches(*structure))
1760
        {
1761
            mOut << "vertex ";
1762
        }
1763
        else
1764
        {
1765
            TODO();
1766
        }
1767
    }
1768
    emitType(returnType, EmitTypeConfig());
1769
}
1770
1771
void GenMetalTraverser::emitFunctionParameter(const TFunction &func, const TVariable &param)
1772
{
1773
    const bool isMain = func.isMain();
1774
1775
    const TType &type           = param.getType();
1776
    const TStructure *structure = type.getStruct();
1777
1778
    EmitVariableDeclarationConfig evdConfig;
1779
    evdConfig.isParameter       = true;
1780
    evdConfig.isMainParameter   = isMain;
1781
    evdConfig.emitPostQualifier = isMain;
1782
    evdConfig.isPointer         = mSymbolEnv.isPointer(param);
1783
    evdConfig.isReference       = mSymbolEnv.isReference(param);
1784
    emitVariableDeclaration(VarDecl(param), evdConfig);
1785
1786
    if (isMain)
1787
    {
1788
        TranslatorMetalReflection *reflection =
1789
            ((sh::TranslatorMetalDirect *)&mCompiler)->getTranslatorMetalReflection();
1790
        if (structure)
1791
        {
1792
            if (mPipelineStructs.fragmentIn.matches(*structure) ||
1793
                mPipelineStructs.vertexIn.matches(*structure))
1794
            {
1795
                mOut << " [[stage_in]]";
1796
            }
1797
            else if (mPipelineStructs.angleUniforms.matches(*structure))
1798
            {
1799
                mOut << " [[buffer(" << rx::mtl::kDriverUniformsBindingIndex << ")]]";
1800
            }
1801
            else if (mPipelineStructs.userUniforms.matches(*structure))
1802
            {
1803
                mOut << " [[buffer(" << mMainUniformBufferIndex << ")]]";
1804
                reflection->addUniformBufferBinding(param.name().data(), mMainUniformBufferIndex);
1805
                mMainUniformBufferIndex += type.getArraySizeProduct();
1806
            }
1807
            else if (structure->name() == "metal::sampler")
1808
            {
1809
                mOut << " [[sampler(" << (mMainSamplerIndex) << ")]]";
1810
                const std::string originalName =
1811
                    reflection->getOriginalName(param.uniqueId().get());
1812
                reflection->addSamplerBinding(originalName, mMainSamplerIndex);
1813
                mMainSamplerIndex += type.getArraySizeProduct();
1814
            }
1815
        }
1816
        else if (IsSampler(type.getBasicType()))
1817
        {
1818
            mOut << " [[texture(" << (mMainTextureIndex) << ")]]";
1819
            const std::string originalName = reflection->getOriginalName(param.uniqueId().get());
1820
            reflection->addTextureBinding(originalName, mMainSamplerIndex);
1821
            mMainTextureIndex += type.getArraySizeProduct();
1822
        }
1823
        else if (Name(param) == Pipeline{Pipeline::Type::InstanceId, nullptr}.getStructInstanceName(
1824
                                    Pipeline::Variant::Modified))
1825
        {
1826
            mOut << " [[instance_id]]";
1827
        }
1828
    }
1829
}
1830
1831
void GenMetalTraverser::visitFunctionPrototype(TIntermFunctionPrototype *funcProtoNode)
1832
{
1833
    const TFunction &func = *funcProtoNode->getFunction();
1834
1835
    emitIndentation();
1836
    emitFunctionSignature(func);
1837
}
1838
1839
bool GenMetalTraverser::visitFunctionDefinition(Visit, TIntermFunctionDefinition *funcDefNode)
1840
{
1841
    const TFunction &func = *funcDefNode->getFunction();
1842
    TIntermBlock &body    = *funcDefNode->getBody();
1843
1844
    emitIndentation();
1845
    emitFunctionSignature(func);
1846
    mOut << "\n";
1847
    body.traverse(this);
1848
1849
    return false;
1850
}
1851
1852
GenMetalTraverser::FuncToName GenMetalTraverser::BuildFuncToName()
1853
{
1854
    FuncToName map;
1855
1856
    auto putAngle = [&](const char *nameStr) {
1857
        const ImmutableString name(nameStr);
1858
        ASSERT(map.find(name) == map.end());
1859
        map[name] = Name(nameStr, SymbolType::AngleInternal);
1860
    };
1861
1862
    putAngle("texelFetch");
1863
    putAngle("texelFetchOffset");
1864
    putAngle("texture");
1865
    putAngle("texture1D");
1866
    putAngle("texture1DLod");
1867
    putAngle("texture1DProjLod");
1868
    putAngle("texture2D");
1869
    putAngle("texture2DLod");
1870
    putAngle("texture2DProj");
1871
    putAngle("texture2DProjLod");
1872
    putAngle("texture3D");
1873
    putAngle("texture3DLod");
1874
    putAngle("texture3DProjLod");
1875
    putAngle("textureCube");
1876
    putAngle("textureCubeLod");
1877
    putAngle("textureCubeProjLod");
1878
    putAngle("textureGrad");
1879
    putAngle("textureGradOffset");
1880
    putAngle("textureLod");
1881
    putAngle("textureLodOffset");
1882
    putAngle("textureOffset");
1883
    putAngle("textureProj");
1884
    putAngle("textureProjGrad");
1885
    putAngle("textureProjGradOffset");
1886
    putAngle("textureProjLod");
1887
    putAngle("textureProjLodOffset");
1888
    putAngle("textureProjOffset");
1889
    putAngle("textureSize");
1890
1891
    return map;
1892
}
1893
1894
bool GenMetalTraverser::visitAggregate(Visit, TIntermAggregate *aggregateNode)
1895
{
1896
    const TIntermSequence &args = *aggregateNode->getSequence();
1897
1898
    auto emitArgList = [&](const char *open, const char *close) {
1899
        mOut << open;
1900
1901
        bool emitComma = false;
1902
        for (TIntermNode *arg : args)
1903
        {
1904
            if (emitComma)
1905
            {
1906
                mOut << ", ";
1907
            }
1908
            emitComma = true;
1909
            arg->traverse(this);
1910
        }
1911
1912
        mOut << close;
1913
    };
1914
1915
    const TType &retType = aggregateNode->getType();
1916
1917
    if (aggregateNode->isConstructor())
1918
    {
1919
        const bool isStandalone = getParentNode()->getAsBlock();
1920
        if (isStandalone)
1921
        {
1922
            // Prevent constructor from being interpreted as a declaration by wrapping in parens.
1923
            // This can happen if given something like:
1924
            //      int(symbol); // <- This will be treated like `int symbol;`... don't want that.
1925
            // So instead emit:
1926
            //      (int(symbol));
1927
            mOut << "(";
1928
        }
1929
1930
        const EmitTypeConfig etConfig;
1931
1932
        if (retType.isArray())
1933
        {
1934
            emitType(retType, etConfig);
1935
            emitArgList("{", "}");
1936
        }
1937
        else if (retType.getStruct())
1938
        {
1939
            emitType(retType, etConfig);
1940
            emitArgList("{", "}");
1941
        }
1942
        else
1943
        {
1944
            emitType(retType, etConfig);
1945
            emitArgList("(", ")");
1946
        }
1947
1948
        if (isStandalone)
1949
        {
1950
            mOut << ")";
1951
        }
1952
1953
        return false;
1954
    }
1955
    else
1956
    {
1957
        const TOperator op = aggregateNode->getOp();
1958
        switch (op)
1959
        {
1960
            case TOperator::EOpCallFunctionInAST:
1961
            case TOperator::EOpCallInternalRawFunction:
1962
            {
1963
                const TFunction &func = *aggregateNode->getFunction();
1964
                emitNameOf(func);
1965
                emitArgList("(", ")");
1966
                return false;
1967
            }
1968
1969
            case TOperator::EOpCallBuiltInFunction:
1970
            {
1971
                const TFunction &func = *aggregateNode->getFunction();
1972
                auto it               = mFuncToName.find(func.name());
1973
                ASSERT(it != mFuncToName.end());
1974
                EmitName(mOut, it->second);
1975
                emitArgList("(", ")");
1976
                return false;
1977
            }
1978
1979
            default:
1980
            {
1981
                auto getArgType = [&](size_t index) -> const TType * {
1982
                    if (index < args.size())
1983
                    {
1984
                        TIntermTyped *arg = args[index]->getAsTyped();
1985
                        ASSERT(arg);
1986
                        return &arg->getType();
1987
                    }
1988
                    return nullptr;
1989
                };
1990
1991
                ASSERT(!args.empty());
1992
                const TType *argType0 = getArgType(0);
1993
                const TType *argType1 = getArgType(1);
1994
                ASSERT(argType0);
1995
1996
                const char *opName = GetOperatorString(op, retType, argType0, argType1);
1997
1998
                if (IsSymbolicOperator(op, retType, argType0, argType1))
1999
                {
2000
                    switch (args.size())
2001
                    {
2002
                        case 1:
2003
                        {
2004
                            TIntermNode &operandNode = *aggregateNode->getChildNode(0);
2005
                            if (IsPostfix(op))
2006
                            {
2007
                                mOut << opName;
2008
                                groupedTraverse(operandNode);
2009
                                return false;
2010
                            }
2011
                            else
2012
                            {
2013
                                groupedTraverse(operandNode);
2014
                                mOut << opName;
2015
                                return false;
2016
                            }
2017
                        }
2018
                        break;
2019
2020
                        case 2:
2021
                        {
2022
                            TIntermNode &leftNode  = *aggregateNode->getChildNode(0);
2023
                            TIntermNode &rightNode = *aggregateNode->getChildNode(1);
2024
                            groupedTraverse(leftNode);
2025
                            mOut << " " << opName << " ";
2026
                            groupedTraverse(rightNode);
2027
                            return false;
2028
                        }
2029
                        break;
2030
2031
                        default:
2032
                            LOGIC_ERROR();
2033
                            return false;
2034
                    }
2035
                }
2036
                else
2037
                {
2038
                    mOut << opName;
2039
                    emitArgList("(", ")");
2040
                    return false;
2041
                }
2042
            }
2043
        }
2044
    }
2045
}
2046
2047
void GenMetalTraverser::emitOpenBrace()
2048
{
2049
    ASSERT(mIndentLevel >= 0);
2050
2051
    emitIndentation();
2052
    mOut << "{\n";
2053
    ++mIndentLevel;
2054
}
2055
2056
void GenMetalTraverser::emitCloseBrace()
2057
{
2058
    ASSERT(mIndentLevel >= 1);
2059
2060
    --mIndentLevel;
2061
    emitIndentation();
2062
    mOut << "}";
2063
}
2064
2065
static bool RequiresSemicolonTerminator(TIntermNode &node)
2066
{
2067
    if (node.getAsBlock())
2068
    {
2069
        return false;
2070
    }
2071
    if (node.getAsLoopNode())
2072
    {
2073
        return false;
2074
    }
2075
    if (node.getAsSwitchNode())
2076
    {
2077
        return false;
2078
    }
2079
    if (node.getAsIfElseNode())
2080
    {
2081
        return false;
2082
    }
2083
    if (node.getAsFunctionDefinition())
2084
    {
2085
        return false;
2086
    }
2087
    if (node.getAsCaseNode())
2088
    {
2089
        return false;
2090
    }
2091
    return true;
2092
}
2093
2094
static bool NewlinePad(TIntermNode &node)
2095
{
2096
    if (node.getAsFunctionDefinition())
2097
    {
2098
        return true;
2099
    }
2100
    if (TIntermDeclaration *declNode = node.getAsDeclarationNode())
2101
    {
2102
        ASSERT(declNode->getChildCount() == 1);
2103
        TIntermNode &childNode = *declNode->getChildNode(0);
2104
        if (TIntermSymbol *symbolNode = childNode.getAsSymbolNode())
2105
        {
2106
            const TVariable &var = symbolNode->variable();
2107
            return var.getType().isStructSpecifier();
2108
        }
2109
        return false;
2110
    }
2111
    return false;
2112
}
2113
2114
bool GenMetalTraverser::visitBlock(Visit, TIntermBlock *blockNode)
2115
{
2116
    ASSERT(mIndentLevel >= -1);
2117
    const bool isGlobalScope  = mIndentLevel == -1;
2118
    const bool parentIsSwitch = mParentIsSwitch;
2119
    mParentIsSwitch           = false;
2120
2121
    if (isGlobalScope)
2122
    {
2123
        ++mIndentLevel;
2124
    }
2125
    else
2126
    {
2127
        emitOpenBrace();
2128
        if (parentIsSwitch)
2129
        {
2130
            ++mIndentLevel;
2131
        }
2132
    }
2133
2134
    TIntermNode *prevStmtNode = nullptr;
2135
2136
    const size_t stmtCount = blockNode->getChildCount();
2137
    for (size_t i = 0; i < stmtCount; ++i)
2138
    {
2139
        TIntermNode &stmtNode = *blockNode->getChildNode(i);
2140
2141
        if (isGlobalScope && prevStmtNode && (NewlinePad(*prevStmtNode) || NewlinePad(stmtNode)))
2142
        {
2143
            mOut << "\n";
2144
        }
2145
        const bool isCase = stmtNode.getAsCaseNode();
2146
        mIndentLevel -= isCase;
2147
        emitIndentation();
2148
        mIndentLevel += isCase;
2149
        stmtNode.traverse(this);
2150
        if (RequiresSemicolonTerminator(stmtNode))
2151
        {
2152
            mOut << ";";
2153
        }
2154
        mOut << "\n";
2155
2156
        prevStmtNode = &stmtNode;
2157
    }
2158
2159
    if (isGlobalScope)
2160
    {
2161
        ASSERT(mIndentLevel == 0);
2162
        --mIndentLevel;
2163
    }
2164
    else
2165
    {
2166
        if (parentIsSwitch)
2167
        {
2168
            ASSERT(mIndentLevel >= 1);
2169
            --mIndentLevel;
2170
        }
2171
        emitCloseBrace();
2172
        mParentIsSwitch = parentIsSwitch;
2173
    }
2174
2175
    return false;
2176
}
2177
2178
bool GenMetalTraverser::visitGlobalQualifierDeclaration(Visit, TIntermGlobalQualifierDeclaration *)
2179
{
2180
    LOGIC_ERROR();  // RewriteGlobalQualifierDecls should have been called before this.
2181
    return false;
2182
}
2183
2184
bool GenMetalTraverser::visitDeclaration(Visit, TIntermDeclaration *declNode)
2185
{
2186
    ASSERT(declNode->getChildCount() == 1);
2187
    TIntermNode &node = *declNode->getChildNode(0);
2188
2189
    EmitVariableDeclarationConfig evdConfig;
2190
2191
    if (TIntermSymbol *symbolNode = node.getAsSymbolNode())
2192
    {
2193
        const TVariable &var = symbolNode->variable();
2194
        emitVariableDeclaration(VarDecl(var), evdConfig);
2195
    }
2196
    else if (TIntermBinary *initNode = node.getAsBinaryNode())
2197
    {
2198
        ASSERT(initNode->getOp() == TOperator::EOpInitialize);
2199
        TIntermSymbol *symbolNode = initNode->getLeft()->getAsSymbolNode();
2200
        TIntermTyped *valueNode   = initNode->getRight()->getAsTyped();
2201
        ASSERT(symbolNode && valueNode);
2202
2203
        if (getRootNode() == getParentBlock())
2204
        {
2205
            // DeferGlobalInitializers should have turned non-const global initializers into
2206
            // deferred initializers. Note that variables marked as EvqGlobal can be treated as
2207
            // EvqConst in some ANGLE code but not actually have their qualifier actually changed to
2208
            // EvqConst. Thus just assume all EvqGlobal are actually EvqConst for all code run after
2209
            // DeferGlobalInitializers.
2210
            mOut << "constant ";
2211
        }
2212
2213
        const TVariable &var = symbolNode->variable();
2214
        const Name varName(var);
2215
2216
        if (ExpressionContainsName(varName, *valueNode))
2217
        {
2218
            mRenamedSymbols[&var] = mIdGen.createNewName(varName);
2219
        }
2220
2221
        emitVariableDeclaration(VarDecl(var), evdConfig);
2222
        mOut << " = ";
2223
        groupedTraverse(*valueNode);
2224
    }
2225
    else
2226
    {
2227
        LOGIC_ERROR();
2228
    }
2229
2230
    return false;
2231
}
2232
2233
bool GenMetalTraverser::visitLoop(Visit, TIntermLoop *loopNode)
2234
{
2235
    const TLoopType loopType = loopNode->getType();
2236
2237
    switch (loopType)
2238
    {
2239
        case TLoopType::ELoopFor:
2240
            return visitForLoop(loopNode);
2241
        case TLoopType::ELoopWhile:
2242
            return visitWhileLoop(loopNode);
2243
        case TLoopType::ELoopDoWhile:
2244
            return visitDoWhileLoop(loopNode);
2245
    }
2246
}
2247
2248
bool GenMetalTraverser::visitForLoop(TIntermLoop *loopNode)
2249
{
2250
    ASSERT(loopNode->getType() == TLoopType::ELoopFor);
2251
2252
    TIntermNode *initNode  = loopNode->getInit();
2253
    TIntermTyped *condNode = loopNode->getCondition();
2254
    TIntermTyped *exprNode = loopNode->getExpression();
2255
    TIntermBlock *bodyNode = loopNode->getBody();
2256
    ASSERT(bodyNode);
2257
2258
    mOut << "for (";
2259
2260
    if (initNode)
2261
    {
2262
        initNode->traverse(this);
2263
    }
2264
    else
2265
    {
2266
        mOut << " ";
2267
    }
2268
2269
    mOut << "; ";
2270
2271
    if (condNode)
2272
    {
2273
        condNode->traverse(this);
2274
    }
2275
2276
    mOut << "; ";
2277
2278
    if (exprNode)
2279
    {
2280
        exprNode->traverse(this);
2281
    }
2282
2283
    mOut << ")\n";
2284
2285
    bodyNode->traverse(this);
2286
2287
    return false;
2288
}
2289
2290
bool GenMetalTraverser::visitWhileLoop(TIntermLoop *loopNode)
2291
{
2292
    ASSERT(loopNode->getType() == TLoopType::ELoopWhile);
2293
2294
    TIntermNode *initNode  = loopNode->getInit();
2295
    TIntermTyped *condNode = loopNode->getCondition();
2296
    TIntermTyped *exprNode = loopNode->getExpression();
2297
    TIntermBlock *bodyNode = loopNode->getBody();
2298
    ASSERT(condNode && bodyNode);
2299
    ASSERT(!initNode && !exprNode);
2300
2301
    emitIndentation();
2302
    mOut << "while (";
2303
    condNode->traverse(this);
2304
    mOut << ")\n";
2305
    bodyNode->traverse(this);
2306
2307
    return false;
2308
}
2309
2310
bool GenMetalTraverser::visitDoWhileLoop(TIntermLoop *loopNode)
2311
{
2312
    ASSERT(loopNode->getType() == TLoopType::ELoopDoWhile);
2313
2314
    TIntermNode *initNode  = loopNode->getInit();
2315
    TIntermTyped *condNode = loopNode->getCondition();
2316
    TIntermTyped *exprNode = loopNode->getExpression();
2317
    TIntermBlock *bodyNode = loopNode->getBody();
2318
    ASSERT(condNode && bodyNode);
2319
    ASSERT(!initNode && !exprNode);
2320
2321
    emitIndentation();
2322
    mOut << "do\n";
2323
    bodyNode->traverse(this);
2324
    mOut << "\n";
2325
    emitIndentation();
2326
    mOut << "while (";
2327
    condNode->traverse(this);
2328
    mOut << ");";
2329
2330
    return false;
2331
}
2332
2333
bool GenMetalTraverser::visitBranch(Visit, TIntermBranch *branchNode)
2334
{
2335
    const TOperator flowOp = branchNode->getFlowOp();
2336
    TIntermTyped *exprNode = branchNode->getExpression();
2337
2338
    emitIndentation();
2339
2340
    switch (flowOp)
2341
    {
2342
        case TOperator::EOpKill:
2343
        {
2344
            ASSERT(exprNode == nullptr);
2345
            mOut << "metal::discard_fragment()";
2346
        }
2347
        break;
2348
2349
        case TOperator::EOpReturn:
2350
        {
2351
            mOut << "return";
2352
            if (exprNode)
2353
            {
2354
                mOut << " ";
2355
                exprNode->traverse(this);
2356
            }
2357
        }
2358
        break;
2359
2360
        case TOperator::EOpBreak:
2361
        {
2362
            ASSERT(exprNode == nullptr);
2363
            mOut << "break";
2364
        }
2365
        break;
2366
2367
        case TOperator::EOpContinue:
2368
        {
2369
            ASSERT(exprNode == nullptr);
2370
            mOut << "continue";
2371
        }
2372
        break;
2373
2374
        default:
2375
        {
2376
            LOGIC_ERROR();
2377
        }
2378
    }
2379
2380
    return false;
2381
}
2382
2383
static size_t emitMetalCallCount = 0;
2384
2385
bool sh::EmitMetal(TCompiler &compiler,
2386
                   TIntermBlock &root,
2387
                   IdGen &idGen,
2388
                   const PipelineStructs &pipelineStructs,
2389
                   const Invariants &invariants,
2390
                   SymbolEnv &symbolEnv,
2391
                   const ProgramPreludeConfig &ppc)
2392
{
2393
    TInfoSinkBase &out = compiler.getInfoSink().obj;
2394
2395
    {
2396
        ++emitMetalCallCount;
2397
        auto filenameProto = readStringEnvVar("GMD_FIXED_EMIT");
2398
        if (!filenameProto.empty())
2399
        {
2400
            if (filenameProto != "/dev/null")
2401
            {
2402
                auto tryOpen = [&](char const *ext) {
2403
                    auto filename = filenameProto;
2404
                    filename += std::to_string(emitMetalCallCount);
2405
                    filename += ".";
2406
                    filename += ext;
2407
                    return fopen(filename.c_str(), "rb");
2408
                };
2409
                FILE *file = tryOpen("metal");
2410
                if (!file)
2411
                {
2412
                    file = tryOpen("cpp");
2413
                }
2414
                ASSERT(file);
2415
2416
                fseek(file, 0, SEEK_END);
2417
                size_t fileSize = ftell(file);
2418
                fseek(file, 0, SEEK_SET);
2419
2420
                std::vector<char> buff;
2421
                buff.resize(fileSize + 1);
2422
                fread(buff.data(), fileSize, 1, file);
2423
                buff.back() = '\0';
2424
2425
                fclose(file);
2426
2427
                out << buff.data();
2428
            }
2429
2430
            return true;
2431
        }
2432
    }
2433
2434
    out << "\n\n";
2435
2436
    if (!EmitProgramPrelude(root, out, ppc))
2437
    {
2438
        return false;
2439
    }
2440
2441
    {
2442
#if defined(ANGLE_ENABLE_ASSERTS)
2443
        DebugSink outWrapper(out, readBoolEnvVar("GMD_STDOUT"));
2444
        outWrapper.watch(readStringEnvVar("GMD_WATCH_STRING"));
2445
#else
2446
        TInfoSinkBase &outWrapper = out;
2447
#endif
2448
        GenMetalTraverser gen(compiler, outWrapper, idGen, pipelineStructs, invariants, symbolEnv);
2449
        root.traverse(&gen);
2450
    }
2451
2452
    out << "\n";
2453
2454
    return true;
2455
}
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/EmitMetal.h +32 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/EmitMetal.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_EMITMETAL_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_EMITMETAL_H_
9
10
#include "common/angleutils.h"
11
#include "compiler/translator/Compiler.h"
12
#include "compiler/translator/TranslatorMetalDirect/IdGen.h"
13
#include "compiler/translator/TranslatorMetalDirect/ProgramPrelude.h"
14
#include "compiler/translator/TranslatorMetalDirect/RewriteGlobalQualifierDecls.h"
15
#include "compiler/translator/TranslatorMetalDirect/RewritePipelines.h"
16
#include "compiler/translator/TranslatorMetalDirect/SymbolEnv.h"
17
18
namespace sh
19
{
20
21
// Walks the AST and emits Metal code.
22
ANGLE_NO_DISCARD bool EmitMetal(TCompiler &compiler,
23
                                TIntermBlock &root,
24
                                IdGen &idGen,
25
                                const PipelineStructs &pipelineStructs,
26
                                const Invariants &invariants,
27
                                SymbolEnv &symbolEnv,
28
                                const ProgramPreludeConfig &ppc);
29
30
}  // namespace sh
31
32
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_EMITMETAL_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/EnvironmentVariable.h +45 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/EnvironmentVariable.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_ENVIRONMENTVARIABLE_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_ENVIRONMENTVARIABLE_H_
9
10
#include <cstdlib>
11
#include <string>
12
13
#include "common/debug.h"
14
15
namespace sh
16
{
17
18
inline bool readBoolEnvVar(const char *var)
19
{
20
    const char *str = std::getenv(var);
21
    if (str == nullptr)
22
    {
23
        return false;
24
    }
25
    if (strcmp(str, "0") == 0)
26
    {
27
        return false;
28
    }
29
    ASSERT(strcmp(str, "1") == 0);
30
    return true;
31
}
32
33
inline std::string readStringEnvVar(const char *var)
34
{
35
    const char *str = std::getenv(var);
36
    if (str == nullptr)
37
    {
38
        return "";
39
    }
40
    return str;
41
}
42
43
}  // namespace sh
44
45
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_ENVIRONMENTVARIABLE_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/HoistConstants.cpp +96 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/HoistConstants.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include "compiler/translator/TranslatorMetalDirect/HoistConstants.h"
8
#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
9
#include "compiler/translator/TranslatorMetalDirect/Layout.h"
10
#include "compiler/translator/tree_util/FindFunction.h"
11
#include "compiler/translator/tree_util/IntermRebuild.h"
12
#include "compiler/translator/tree_util/ReplaceVariable.h"
13
14
using namespace sh;
15
16
////////////////////////////////////////////////////////////////////////////////
17
18
namespace
19
{
20
21
class Rewriter : private TIntermRebuild
22
{
23
  private:
24
    const size_t mMinRequiredSize;
25
    TIntermSequence mHoistedDeclNodes;
26
27
  public:
28
    Rewriter(TCompiler &compiler, size_t minRequiredSize)
29
        : TIntermRebuild(compiler, true, false), mMinRequiredSize(minRequiredSize)
30
    {}
31
32
    PreResult visitDeclarationPre(TIntermDeclaration &declNode) override
33
    {
34
        if (getParentFunction())
35
        {
36
            Declaration decl  = ViewDeclaration(declNode);
37
            const TType &type = decl.symbol.getType();
38
            if (type.getQualifier() == TQualifier::EvqConst)
39
            {
40
                if (decl.initExpr && decl.initExpr->hasConstantValue())
41
                {
42
                    const size_t size = MetalLayoutOf(type).sizeOf;
43
                    if (size >= mMinRequiredSize)
44
                    {
45
                        mHoistedDeclNodes.push_back(&declNode);
46
                        return nullptr;
47
                    }
48
                }
49
            }
50
        }
51
        return {declNode, VisitBits::Neither};
52
    }
53
54
    bool rewrite(TIntermBlock &root, IdGen &idGen)
55
    {
56
        if (!rebuildRoot(root))
57
        {
58
            return false;
59
        }
60
61
        if (mHoistedDeclNodes.empty())
62
        {
63
            return true;
64
        }
65
66
        root.insertChildNodes(FindFirstFunctionDefinitionIndex(&root), mHoistedDeclNodes);
67
68
        for (TIntermNode *opaqueDeclNode : mHoistedDeclNodes)
69
        {
70
            TIntermDeclaration *declNode = opaqueDeclNode->getAsDeclarationNode();
71
            ASSERT(declNode);
72
            const TVariable &oldVar = ViewDeclaration(*declNode).symbol.variable();
73
            const Name newName      = idGen.createNewName(oldVar.name());
74
            auto *newVar = new TVariable(&mSymbolTable, newName.rawName(), &oldVar.getType(),
75
                                         newName.symbolType());
76
            if (!ReplaceVariable(&mCompiler, &root, &oldVar, newVar))
77
            {
78
                return false;
79
            }
80
        }
81
82
        return true;
83
    }
84
};
85
86
}  // anonymous namespace
87
88
////////////////////////////////////////////////////////////////////////////////
89
90
bool sh::HoistConstants(TCompiler &compiler,
91
                        TIntermBlock &root,
92
                        IdGen &idGen,
93
                        size_t minRequiredSize)
94
{
95
    return Rewriter(compiler, minRequiredSize).rewrite(root, idGen);
96
}
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/HoistConstants.h +26 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/HoistConstants.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_HOISTCONSTANTS_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_HOISTCONSTANTS_H_
9
10
#include "common/angleutils.h"
11
#include "compiler/translator/Compiler.h"
12
#include "compiler/translator/TranslatorMetalDirect/IdGen.h"
13
14
namespace sh
15
{
16
17
// Hoists function-local constants to the global scope if their Metal sizeof meets
18
// `minRequiredSize`.
19
ANGLE_NO_DISCARD bool HoistConstants(TCompiler &compiler,
20
                                     TIntermBlock &root,
21
                                     IdGen &idGen,
22
                                     size_t minRequiredSize);
23
24
}  // namespace sh
25
26
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_HOISTCONSTANTS_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/IdGen.cpp +97 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/IdGen.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include <cctype>
8
#include <cstring>
9
#include <limits>
10
#include <unordered_map>
11
#include <unordered_set>
12
13
#include "compiler/translator/TranslatorMetalDirect/RewriteKeywords.h"
14
15
using namespace sh;
16
17
////////////////////////////////////////////////////////////////////////////////
18
19
IdGen::IdGen() {}
20
21
template <typename String, typename StringToImmutable>
22
Name IdGen::createNewName(size_t count,
23
                          const String *baseNames,
24
                          const StringToImmutable &toImmutable)
25
{
26
    const unsigned id = mNext++;
27
    char idBuffer[std::numeric_limits<unsigned>::digits10 + 1];
28
    sprintf(idBuffer, "%u", id);
29
30
    mNewNameBuffer.clear();
31
    mNewNameBuffer += '_';
32
    mNewNameBuffer += idBuffer;
33
34
    // Note:
35
    // Double underscores are only allowed in C++ (and thus Metal) vendor identifiers, so here we
36
    // take care not to introduce any.
37
38
    for (size_t i = 0; i < count; ++i)
39
    {
40
        const ImmutableString baseName = toImmutable(baseNames[i]);
41
        if (!baseName.empty())
42
        {
43
            const char *base = baseName.data();
44
            if (baseName.beginsWith(kAngleInternalPrefix))
45
            {
46
                base += sizeof(kAngleInternalPrefix) - 1;
47
            }
48
            if (*base == '_')
49
            {
50
                ++base;
51
            }
52
            ASSERT(*base != '_');
53
54
            if (mNewNameBuffer.back() != '_')
55
            {
56
                mNewNameBuffer += '_';
57
            }
58
59
            mNewNameBuffer += base;
60
        }
61
    }
62
63
    return Name(ImmutableString(mNewNameBuffer), SymbolType::AngleInternal);
64
}
65
66
Name IdGen::createNewName(const ImmutableString &baseName)
67
{
68
    return createNewName({baseName});
69
}
70
71
Name IdGen::createNewName(const Name &baseName)
72
{
73
    return createNewName(baseName.rawName());
74
}
75
76
Name IdGen::createNewName(const char *baseName)
77
{
78
    return createNewName(ImmutableString(baseName));
79
}
80
81
Name IdGen::createNewName(std::initializer_list<ImmutableString> baseNames)
82
{
83
    return createNewName(baseNames.size(), baseNames.begin(),
84
                         [](const ImmutableString &s) { return s; });
85
}
86
87
Name IdGen::createNewName(std::initializer_list<Name> baseNames)
88
{
89
    return createNewName(baseNames.size(), baseNames.begin(),
90
                         [](const Name &s) { return s.rawName(); });
91
}
92
93
Name IdGen::createNewName(std::initializer_list<const char *> baseNames)
94
{
95
    return createNewName(baseNames.size(), baseNames.begin(),
96
                         [](const char *s) { return ImmutableString(s); });
97
}
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/IdGen.h +41 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/IdGen.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_IDGEN_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_IDGEN_H_
9
10
#include "common/angleutils.h"
11
#include "compiler/translator/TranslatorMetalDirect/Name.h"
12
13
namespace sh
14
{
15
16
// For creating new fresh names.
17
// All names created are marked as SymbolType::AngleInternal.
18
class IdGen : angle::NonCopyable
19
{
20
  public:
21
    IdGen();
22
23
    Name createNewName(const ImmutableString &baseName);
24
    Name createNewName(const Name &baseName);
25
    Name createNewName(const char *baseName);
26
    Name createNewName(std::initializer_list<ImmutableString> baseNames);
27
    Name createNewName(std::initializer_list<Name> baseNames);
28
    Name createNewName(std::initializer_list<const char *> baseNames);
29
30
  private:
31
    template <typename String, typename StringToImmutable>
32
    Name createNewName(size_t count, const String *baseNames, const StringToImmutable &toImmutable);
33
34
  private:
35
    unsigned mNext = 0;          // `unsigned` because of "%u" use in sprintf
36
    std::string mNewNameBuffer;  // reusable buffer to avoid tons of reallocations
37
};
38
39
}  // namespace sh
40
41
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_IDGEN_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/Layout.cpp +401 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/Layout.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include <algorithm>
8
#include <cctype>
9
#include <cstring>
10
#include <limits>
11
#include <unordered_map>
12
#include <unordered_set>
13
14
#include "compiler/translator/Symbol.h"
15
#include "compiler/translator/TranslatorMetalDirect/Debug.h"
16
#include "compiler/translator/TranslatorMetalDirect/Layout.h"
17
18
using namespace sh;
19
20
////////////////////////////////////////////////////////////////////////////////
21
22
enum class Language
23
{
24
    Metal,
25
    GLSL,
26
};
27
28
static size_t RoundUpToMultipleOf(size_t x, size_t multiple)
29
{
30
    const size_t rem = x % multiple;
31
    return rem == 0 ? x : x + (multiple - rem);
32
}
33
34
void Layout::requireAlignment(size_t align, bool pad)
35
{
36
    alignOf = std::max(alignOf, align);
37
    if (pad)
38
    {
39
        sizeOf = RoundUpToMultipleOf(sizeOf, align);
40
    }
41
}
42
43
bool Layout::operator==(const Layout &other) const
44
{
45
    return sizeOf == other.sizeOf && alignOf == other.alignOf;
46
}
47
48
void Layout::operator+=(const Layout &other)
49
{
50
    requireAlignment(other.alignOf, true);
51
    sizeOf += other.sizeOf;
52
}
53
54
void Layout::operator*=(size_t scale)
55
{
56
    sizeOf *= scale;
57
}
58
59
Layout Layout::operator+(const Layout &other) const
60
{
61
    auto self = *this;
62
    self += other;
63
    return self;
64
}
65
66
Layout Layout::operator*(size_t scale) const
67
{
68
    auto self = *this;
69
    self *= scale;
70
    return self;
71
}
72
73
static Layout ScalarLayoutOf(const TType &type, Language language)
74
{
75
    const TBasicType basicType = type.getBasicType();
76
    switch (basicType)
77
    {
78
        case TBasicType::EbtBool:
79
            return {1, 1};
80
        case TBasicType::EbtInt:
81
        case TBasicType::EbtUInt:
82
        case TBasicType::EbtFloat:
83
            return {4, 4};
84
        default:
85
            if (IsSampler(basicType))
86
            {
87
                switch (language)
88
                {
89
                    case Language::Metal:
90
                        return {8, 8};
91
                    case Language::GLSL:
92
                        return {4, 4};
93
                }
94
            }
95
            TODO();
96
            return Layout::Invalid();
97
    }
98
}
99
100
static const size_t innerScalesPacked[]   = {0, 1, 2, 3, 4};
101
static const size_t innerScalesUnpacked[] = {0, 1, 2, 4, 4};
102
103
Layout sh::MetalLayoutOf(const TType &type, MetalLayoutOfConfig config)
104
{
105
    ASSERT(type.getNominalSize() <= 4);
106
    ASSERT(type.getSecondarySize() <= 4);
107
108
    const TLayoutBlockStorage storage = type.getLayoutQualifier().blockStorage;
109
110
    const bool isPacked = !config.disablePacking && (storage == TLayoutBlockStorage::EbsPacked ||
111
                                                     storage == TLayoutBlockStorage::EbsShared);
112
113
    if (type.isArray() && !config.maskArray)
114
    {
115
        config.maskArray    = true;
116
        const Layout layout = MetalLayoutOf(type, config);
117
        config.maskArray    = false;
118
        const size_t vol    = type.getArraySizeProduct();
119
        return layout * vol;
120
    }
121
122
    if (const TStructure *structure = type.getStruct())
123
    {
124
        ASSERT(type.getNominalSize() == 1);
125
        ASSERT(type.getSecondarySize() == 1);
126
        auto config2             = config;
127
        config2.maskArray        = false;
128
        auto layout              = Layout::Identity();
129
        const TFieldList &fields = structure->fields();
130
        for (const TField *field : fields)
131
        {
132
            layout += MetalLayoutOf(*field->type(), config2);
133
        }
134
        if (config.assumeStructsAreTailPadded)
135
        {
136
            size_t pad = layout.sizeOf % 16;
137
            layout.sizeOf += pad;
138
        }
139
        layout.sizeOf = RoundUpToMultipleOf(layout.sizeOf, layout.alignOf);
140
        return layout;
141
    }
142
143
    if (config.treatSamplersAsTextureEnv && IsSampler(type.getBasicType()))
144
    {
145
        return {16, 8};  // pointer{8,8} and metal::sampler{8,8}
146
    }
147
148
    const Layout scalarLayout = ScalarLayoutOf(type, Language::Metal);
149
150
    if (type.isRank0())
151
    {
152
        return scalarLayout;
153
    }
154
    else if (type.isVector())
155
    {
156
        if (isPacked)
157
        {
158
            const size_t innerScale = innerScalesPacked[type.getNominalSize()];
159
            auto layout = Layout{scalarLayout.sizeOf * innerScale, scalarLayout.alignOf};
160
            return layout;
161
        }
162
        else
163
        {
164
            const size_t innerScale = innerScalesUnpacked[type.getNominalSize()];
165
            auto layout             = Layout::Both(scalarLayout.sizeOf * innerScale);
166
            return layout;
167
        }
168
    }
169
    else
170
    {
171
        ASSERT(type.isMatrix());
172
        ASSERT(type.getBasicType() == TBasicType::EbtFloat);
173
        // typeCxR <=> typeR[C]
174
        const size_t innerScale = innerScalesUnpacked[type.getRows()];
175
        const size_t outerScale = static_cast<size_t>(type.getCols());
176
        const size_t n          = scalarLayout.sizeOf * innerScale;
177
        return {n * outerScale, n};
178
    }
179
}
180
181
TLayoutBlockStorage sh::Overlay(TLayoutBlockStorage oldStorage, const TType &type)
182
{
183
    const TLayoutBlockStorage newStorage = type.getLayoutQualifier().blockStorage;
184
    switch (newStorage)
185
    {
186
        case TLayoutBlockStorage::EbsUnspecified:
187
            return oldStorage == TLayoutBlockStorage::EbsUnspecified ? kDefaultLayoutBlockStorage
188
                                                                     : oldStorage;
189
        default:
190
            return newStorage;
191
    }
192
}
193
194
TLayoutMatrixPacking sh::Overlay(TLayoutMatrixPacking oldPacking, const TType &type)
195
{
196
    const TLayoutMatrixPacking newPacking = type.getLayoutQualifier().matrixPacking;
197
    switch (newPacking)
198
    {
199
        case TLayoutMatrixPacking::EmpUnspecified:
200
            return oldPacking == TLayoutMatrixPacking::EmpUnspecified ? kDefaultLayoutMatrixPacking
201
                                                                      : oldPacking;
202
        default:
203
            return newPacking;
204
    }
205
}
206
207
bool sh::CanBePacked(TLayoutBlockStorage storage)
208
{
209
    switch (storage)
210
    {
211
        case TLayoutBlockStorage::EbsPacked:
212
        case TLayoutBlockStorage::EbsShared:
213
            return true;
214
        case TLayoutBlockStorage::EbsStd140:
215
        case TLayoutBlockStorage::EbsStd430:
216
            return false;
217
        case TLayoutBlockStorage::EbsUnspecified:
218
            LOGIC_ERROR();
219
            return false;
220
    }
221
}
222
223
bool sh::CanBePacked(TLayoutQualifier layoutQualifier)
224
{
225
    return CanBePacked(layoutQualifier.blockStorage);
226
}
227
228
bool sh::CanBePacked(const TType &type)
229
{
230
    if (!type.isVector())
231
    {
232
        return false;
233
    }
234
    return CanBePacked(type.getLayoutQualifier());
235
}
236
237
void sh::SetBlockStorage(TType &type, TLayoutBlockStorage storage)
238
{
239
    auto qual         = type.getLayoutQualifier();
240
    qual.blockStorage = storage;
241
    type.setLayoutQualifier(qual);
242
}
243
244
static Layout CommonGlslStructLayoutOf(TField const *const *begin,
245
                                       TField const *const *end,
246
                                       const TLayoutBlockStorage storage,
247
                                       const TLayoutMatrixPacking matrixPacking,
248
                                       const bool maskArray,
249
                                       const size_t baseAlignment)
250
{
251
    const bool isPacked =
252
        storage == TLayoutBlockStorage::EbsPacked || storage == TLayoutBlockStorage::EbsShared;
253
254
    auto layout = Layout::Identity();
255
    for (auto iter = begin; iter != end; ++iter)
256
    {
257
        layout += GlslLayoutOf(*(*iter)->type(), storage, matrixPacking, false);
258
    }
259
    if (!isPacked)  // XXX: Correct?
260
    {
261
        layout.sizeOf = RoundUpToMultipleOf(layout.sizeOf, layout.alignOf);
262
    }
263
    layout.requireAlignment(baseAlignment, true);
264
    return layout;
265
}
266
267
static Layout CommonGlslLayoutOf(const TType &type,
268
                                 const TLayoutBlockStorage storage,
269
                                 const TLayoutMatrixPacking matrixPacking,
270
                                 const bool maskArray,
271
                                 const size_t baseAlignment)
272
{
273
    ASSERT(storage != TLayoutBlockStorage::EbsUnspecified);
274
275
    const bool isPacked =
276
        storage == TLayoutBlockStorage::EbsPacked || storage == TLayoutBlockStorage::EbsShared;
277
278
    if (type.isArray() && !type.isMatrix() && !maskArray)
279
    {
280
        auto layout = GlslLayoutOf(type, storage, matrixPacking, true);
281
        layout *= type.getArraySizeProduct();
282
        layout.requireAlignment(baseAlignment, true);
283
        return layout;
284
    }
285
286
    if (const TStructure *structure = type.getStruct())
287
    {
288
        ASSERT(type.getNominalSize() == 1);
289
        ASSERT(type.getSecondarySize() == 1);
290
        const TFieldList &fields = structure->fields();
291
        return CommonGlslStructLayoutOf(fields.data(), fields.data() + fields.size(), storage,
292
                                        matrixPacking, maskArray, baseAlignment);
293
    }
294
295
    const auto scalarLayout = ScalarLayoutOf(type, Language::GLSL);
296
297
    if (type.isRank0())
298
    {
299
        return scalarLayout;
300
    }
301
    else if (type.isVector())
302
    {
303
        if (isPacked)
304
        {
305
            const size_t sizeScale  = innerScalesPacked[type.getNominalSize()];
306
            const size_t alignScale = innerScalesUnpacked[type.getNominalSize()];
307
            auto layout =
308
                Layout{scalarLayout.sizeOf * sizeScale, scalarLayout.alignOf * alignScale};
309
            return layout;
310
        }
311
        else
312
        {
313
            const size_t innerScale = innerScalesUnpacked[type.getNominalSize()];
314
            auto layout             = Layout::Both(scalarLayout.sizeOf * innerScale);
315
            return layout;
316
        }
317
    }
318
    else
319
    {
320
        ASSERT(type.isMatrix());
321
322
        size_t innerDim;
323
        size_t outerDim;
324
325
        switch (matrixPacking)
326
        {
327
            case TLayoutMatrixPacking::EmpColumnMajor:
328
                innerDim = static_cast<size_t>(type.getRows());
329
                outerDim = static_cast<size_t>(type.getCols());
330
                break;
331
            case TLayoutMatrixPacking::EmpRowMajor:
332
                innerDim = static_cast<size_t>(type.getCols());
333
                outerDim = static_cast<size_t>(type.getRows());
334
                break;
335
            case TLayoutMatrixPacking::EmpUnspecified:
336
                LOGIC_ERROR();
337
                innerDim = 0;
338
                outerDim = 0;
339
        }
340
341
        outerDim *= type.getArraySizeProduct();
342
343
        const size_t innerScale = innerScalesUnpacked[innerDim];
344
        const size_t n          = innerScale * scalarLayout.sizeOf;
345
        Layout layout           = {outerDim * n, n};
346
        layout.requireAlignment(baseAlignment, true);
347
        return layout;
348
    }
349
}
350
351
Layout sh::GlslLayoutOf(const TType &type,
352
                        TLayoutBlockStorage storage,
353
                        TLayoutMatrixPacking matrixPacking,
354
                        bool maskArray)
355
{
356
    ASSERT(type.getNominalSize() <= 4);
357
    ASSERT(type.getSecondarySize() <= 4);
358
359
    storage       = Overlay(storage, type);
360
    matrixPacking = Overlay(matrixPacking, type);
361
362
    switch (storage)
363
    {
364
        case TLayoutBlockStorage::EbsPacked:
365
            return CommonGlslLayoutOf(type, storage, matrixPacking, maskArray, 1);
366
        case TLayoutBlockStorage::EbsShared:
367
            return CommonGlslLayoutOf(type, storage, matrixPacking, maskArray, 16);
368
        case TLayoutBlockStorage::EbsStd140:
369
            return CommonGlslLayoutOf(type, storage, matrixPacking, maskArray, 16);
370
        case TLayoutBlockStorage::EbsStd430:
371
            return CommonGlslLayoutOf(type, storage, matrixPacking, maskArray, 1);
372
        case TLayoutBlockStorage::EbsUnspecified:
373
            LOGIC_ERROR();
374
            return Layout::Invalid();
375
    }
376
}
377
378
ANGLE_NO_DISCARD Layout sh::GlslStructLayoutOf(TField const *const *begin,
379
                                               TField const *const *end,
380
                                               TLayoutBlockStorage storage,
381
                                               TLayoutMatrixPacking matrixPacking,
382
                                               bool maskArray)
383
{
384
    ASSERT(storage != TLayoutBlockStorage::EbsUnspecified);
385
    ASSERT(matrixPacking != TLayoutMatrixPacking::EmpUnspecified);
386
387
    switch (storage)
388
    {
389
        case TLayoutBlockStorage::EbsPacked:
390
            return CommonGlslStructLayoutOf(begin, end, storage, matrixPacking, maskArray, 1);
391
        case TLayoutBlockStorage::EbsShared:
392
            return CommonGlslStructLayoutOf(begin, end, storage, matrixPacking, maskArray, 16);
393
        case TLayoutBlockStorage::EbsStd140:
394
            return CommonGlslStructLayoutOf(begin, end, storage, matrixPacking, maskArray, 16);
395
        case TLayoutBlockStorage::EbsStd430:
396
            return CommonGlslStructLayoutOf(begin, end, storage, matrixPacking, maskArray, 1);
397
        case TLayoutBlockStorage::EbsUnspecified:
398
            LOGIC_ERROR();
399
            return Layout::Invalid();
400
    }
401
}
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/Layout.h +88 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/Layout.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_LAYOUT_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_LAYOUT_H_
9
10
#include "common/angleutils.h"
11
#include "compiler/translator/Types.h"
12
13
namespace sh
14
{
15
16
constexpr const auto kDefaultLayoutBlockStorage  = TLayoutBlockStorage::EbsShared;
17
constexpr const auto kDefaultLayoutMatrixPacking = TLayoutMatrixPacking::EmpColumnMajor;
18
19
// Returns `oldStorage` if `type` has unspecified block storage.
20
// Otherwise returns block storage of `type`.
21
TLayoutBlockStorage Overlay(TLayoutBlockStorage oldStorage, const TType &type);
22
23
// Returns `oldPacking` if `type` has unspecified matrix packing.
24
// Otherwise returns matrix packing of `type`.
25
TLayoutMatrixPacking Overlay(TLayoutMatrixPacking oldPacking, const TType &type);
26
27
// Returns whether or not it is permissable for the block storage to use a packed representation.
28
bool CanBePacked(TLayoutBlockStorage storage);
29
30
// Returns whether or not it is permissable for the layout qualifier to use a packed representation.
31
bool CanBePacked(TLayoutQualifier layoutQualifier);
32
33
// Returns whether or not it is permissable for the type to use a packed representation.
34
bool CanBePacked(const TType &type);
35
36
// Sets the block storage for a type.
37
void SetBlockStorage(TType &type, TLayoutBlockStorage storage);
38
39
// Contains `sizeof` and `alignof` information.
40
struct Layout
41
{
42
    size_t sizeOf;
43
    size_t alignOf;
44
45
    static Layout Identity() { return {0, 1}; }
46
    static Layout Invalid() { return {0, 0}; }
47
    static Layout Both(size_t n) { return {n, n}; }
48
49
    void requireAlignment(size_t align, bool pad);
50
51
    bool operator==(const Layout &other) const;
52
53
    void operator+=(const Layout &other);
54
    void operator*=(size_t scale);
55
56
    Layout operator+(const Layout &other) const;
57
    Layout operator*(size_t scale) const;
58
};
59
60
struct MetalLayoutOfConfig
61
{
62
    bool disablePacking             = false;
63
    bool maskArray                  = false;
64
    bool treatSamplersAsTextureEnv  = false;
65
    bool assumeStructsAreTailPadded = false;  // Pad to multiple of 16
66
};
67
68
// Returns the layout of a type if it were to be represented in a Metal program.
69
// This deliberately ignores the TLayoutBlockStorage and TLayoutMatrixPacking of any type.
70
ANGLE_NO_DISCARD Layout MetalLayoutOf(const TType &type, MetalLayoutOfConfig config = {});
71
72
// Returns the layout of a type if it were to be represented in a GLSL program.
73
ANGLE_NO_DISCARD Layout
74
GlslLayoutOf(const TType &type,
75
             TLayoutBlockStorage storage        = TLayoutBlockStorage::EbsUnspecified,
76
             TLayoutMatrixPacking matrixPacking = TLayoutMatrixPacking::EmpUnspecified,
77
             bool maskArray                     = false);
78
79
// Returns the layout of a structure if it were to be represented in a GLSL program.
80
ANGLE_NO_DISCARD Layout GlslStructLayoutOf(TField const *const *begin,
81
                                           TField const *const *end,
82
                                           TLayoutBlockStorage storage,
83
                                           TLayoutMatrixPacking matrixPacking,
84
                                           bool maskArray = false);
85
86
}  // namespace sh
87
88
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_LAYOUT_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/MapFunctionsToDefinitions.cpp +34 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/MapFunctionsToDefinitions.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include "compiler/translator/TranslatorMetalDirect/MapFunctionsToDefinitions.h"
8
#include "compiler/translator/Symbol.h"
9
10
using namespace sh;
11
12
class Mapper : public TIntermTraverser
13
{
14
  public:
15
    FunctionToDefinition mFuncToDef;
16
17
  public:
18
    Mapper() : TIntermTraverser(true, false, false) {}
19
20
    bool visitFunctionDefinition(Visit, TIntermFunctionDefinition *funcDefNode) override
21
    {
22
        const TFunction *func = funcDefNode->getFunction();
23
        ASSERT(func->getBuiltInOp() == TOperator::EOpNull);
24
        mFuncToDef[func] = funcDefNode;
25
        return false;
26
    }
27
};
28
29
FunctionToDefinition sh::MapFunctionsToDefinitions(TIntermBlock &root)
30
{
31
    Mapper mapper;
32
    root.traverse(&mapper);
33
    return std::move(mapper.mFuncToDef);
34
}
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/MapFunctionsToDefinitions.h +25 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/MapFunctionsToDefinitions.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_MAPFUNCTIONSTODEFINITIONS_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_MAPFUNCTIONSTODEFINITIONS_H_
9
10
#include <unordered_map>
11
12
#include "compiler/translator/tree_util/IntermTraverse.h"
13
14
namespace sh
15
{
16
17
// A map from functions to their corresponding definitions.
18
using FunctionToDefinition = std::unordered_map<const TFunction *, TIntermFunctionDefinition *>;
19
20
// Maps functions to their corresponding definitions.
21
ANGLE_NO_DISCARD FunctionToDefinition MapFunctionsToDefinitions(TIntermBlock &root);
22
23
}  // namespace sh
24
25
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_MAPFUNCTIONSTODEFINITIONS_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/MapSymbols.cpp +46 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/MapSymbols.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include "compiler/translator/TranslatorMetalDirect/MapSymbols.h"
8
#include "compiler/translator/tree_util/IntermRebuild.h"
9
10
using namespace sh;
11
12
////////////////////////////////////////////////////////////////////////////////
13
14
namespace
15
{
16
17
class Rewriter : public TIntermRebuild
18
{
19
  private:
20
    std::function<TIntermNode &(const TFunction *, TIntermSymbol &)> mMap;
21
22
  public:
23
    Rewriter(TCompiler &compiler,
24
             std::function<TIntermNode &(const TFunction *, TIntermSymbol &)> map)
25
        : TIntermRebuild(compiler, false, true), mMap(map)
26
    {}
27
28
    PostResult visitSymbolPost(TIntermSymbol &symbolNode) override
29
    {
30
        return mMap(getParentFunction(), symbolNode);
31
    }
32
};
33
34
}  // namespace
35
36
bool sh::MapSymbols(TCompiler &compiler,
37
                    TIntermBlock &root,
38
                    std::function<TIntermNode &(const TFunction *, TIntermSymbol &)> map)
39
{
40
    Rewriter rewriter(compiler, std::move(map));
41
    if (!rewriter.rebuildRoot(root))
42
    {
43
        return false;
44
    }
45
    return true;
46
}
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/MapSymbols.h +27 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/MapSymbols.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_MAPVARIABLESTOMEMBERACCESS_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_MAPVARIABLESTOMEMBERACCESS_H_
9
10
#include <functional>
11
12
#include "common/angleutils.h"
13
#include "compiler/translator/Compiler.h"
14
15
namespace sh
16
{
17
18
// Maps TIntermSymbol nodes to TIntermNode nodes.
19
// The parent function of a symbol is provided to the mapping when applicable.
20
ANGLE_NO_DISCARD bool MapSymbols(
21
    TCompiler &compiler,
22
    TIntermBlock &root,
23
    std::function<TIntermNode &(const TFunction *, TIntermSymbol &)> map);
24
25
}  // namespace sh
26
27
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_MAPVARIABLESTOMEMBERACCESS_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/ModifyStruct.cpp +1001 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/ModifyStruct.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include <algorithm>
8
#include <cstring>
9
#include <numeric>
10
#include <unordered_map>
11
#include <unordered_set>
12
13
#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
14
#include "compiler/translator/TranslatorMetalDirect/ModifyStruct.h"
15
16
using namespace sh;
17
18
////////////////////////////////////////////////////////////////////////////////
19
20
size_t ModifiedStructMachineries::size() const
21
{
22
    return ordering.size();
23
}
24
25
const ModifiedStructMachinery &ModifiedStructMachineries::at(size_t index) const
26
{
27
    ASSERT(index < size());
28
    const TStructure *s              = ordering[index];
29
    const ModifiedStructMachinery *m = find(*s);
30
    ASSERT(m);
31
    return *m;
32
}
33
34
const ModifiedStructMachinery *ModifiedStructMachineries::find(const TStructure &s) const
35
{
36
    auto iter = originalToMachinery.find(&s);
37
    if (iter == originalToMachinery.end())
38
    {
39
        return nullptr;
40
    }
41
    return &iter->second;
42
}
43
44
void ModifiedStructMachineries::insert(const TStructure &s,
45
                                       const ModifiedStructMachinery &machinery)
46
{
47
    ASSERT(!find(s));
48
    originalToMachinery[&s] = machinery;
49
    ordering.push_back(&s);
50
}
51
52
////////////////////////////////////////////////////////////////////////////////
53
54
namespace
55
{
56
57
TIntermTyped &Flatten(SymbolEnv &symbolEnv, TIntermTyped &node)
58
{
59
    auto &type = node.getType();
60
    ASSERT(type.isArray());
61
62
    auto &retType = InnermostType(type);
63
    retType.makeArray(1);
64
65
    return symbolEnv.callFunctionOverload(Name("flatten"), retType, *new TIntermSequence{&node});
66
}
67
68
struct FlattenArray
69
{};
70
71
struct PathItem
72
{
73
    enum class Type
74
    {
75
        Field,         // Struct field indexing.
76
        Index,         // Array, vector, or matrix indexing.
77
        FlattenArray,  // Array of any rank -> pointer of innermost type.
78
    };
79
80
    PathItem(const TField &field) : field(&field), type(Type::Field) {}
81
    PathItem(int index) : index(index), type(Type::Index) {}
82
    PathItem(unsigned index) : PathItem(static_cast<int>(index)) {}
83
    PathItem(FlattenArray flatten) : type(Type::FlattenArray) {}
84
85
    union
86
    {
87
        const TField *field;
88
        int index;
89
    };
90
    Type type;
91
};
92
93
TIntermTyped &BuildPathAccess(SymbolEnv &symbolEnv,
94
                              const TVariable &var,
95
                              const std::vector<PathItem> &path)
96
{
97
    TIntermTyped *curr = new TIntermSymbol(&var);
98
    for (const PathItem &item : path)
99
    {
100
        switch (item.type)
101
        {
102
            case PathItem::Type::Field:
103
                curr = &AccessField(*curr, item.field->name());
104
                break;
105
            case PathItem::Type::Index:
106
                curr = &AccessIndex(*curr, item.index);
107
                break;
108
            case PathItem::Type::FlattenArray:
109
            {
110
                curr = &Flatten(symbolEnv, *curr);
111
            }
112
            break;
113
        }
114
    }
115
    return *curr;
116
}
117
118
////////////////////////////////////////////////////////////////////////////////
119
120
using OriginalParam = const TVariable &;
121
using ModifiedParam = const TVariable &;
122
123
using OriginalAccess = TIntermTyped;
124
using ModifiedAccess = TIntermTyped;
125
126
struct Access
127
{
128
    OriginalAccess &original;
129
    ModifiedAccess &modified;
130
131
    struct Env
132
    {
133
        const ConvertType type;
134
    };
135
};
136
137
using ConversionFunc = std::function<Access(Access::Env &, OriginalAccess &, ModifiedAccess &)>;
138
139
class ConvertStructState : angle::NonCopyable
140
{
141
  private:
142
    struct ConversionInfo
143
    {
144
        ConversionFunc stdFunc;
145
        const TFunction *astFunc;
146
        std::vector<PathItem> pathItems;
147
        ImmutableString pathName;
148
    };
149
150
  public:
151
    ConvertStructState(SymbolEnv &symbolEnv,
152
                       IdGen &idGen,
153
                       const ModifyStructConfig &config,
154
                       ModifiedStructMachineries &outMachineries)
155
        : config(config),
156
          symbolEnv(symbolEnv),
157
          modifiedFields(*new TFieldList()),
158
          symbolTable(symbolEnv.symbolTable()),
159
          idGen(idGen),
160
          outMachineries(outMachineries)
161
    {}
162
163
    ~ConvertStructState()
164
    {
165
        ASSERT(namePath.empty());
166
        ASSERT(namePathSizes.empty());
167
    }
168
169
    void publish(const TStructure &originalStruct, const Name &modifiedStructName)
170
    {
171
        const bool isOriginalToModified = config.convertType == ConvertType::OriginalToModified;
172
173
        auto &modifiedStruct = *new TStructure(&symbolTable, modifiedStructName.rawName(),
174
                                               &modifiedFields, modifiedStructName.symbolType());
175
176
        auto &func = *new TFunction(
177
            &symbolTable,
178
            idGen.createNewName(isOriginalToModified ? "originalToModified" : "modifiedToOriginal")
179
                .rawName(),
180
            SymbolType::AngleInternal, new TType(TBasicType::EbtVoid), false);
181
182
        OriginalParam originalParam =
183
            CreateInstanceVariable(symbolTable, originalStruct, Name("original"));
184
        ModifiedParam modifiedParam =
185
            CreateInstanceVariable(symbolTable, modifiedStruct, Name("modified"));
186
        symbolEnv.markAsReference(originalParam, AddressSpace::Thread);
187
        symbolEnv.markAsReference(modifiedParam, config.externalAddressSpace);
188
        if (isOriginalToModified)
189
        {
190
            func.addParameter(&originalParam);
191
            func.addParameter(&modifiedParam);
192
        }
193
        else
194
        {
195
            func.addParameter(&modifiedParam);
196
            func.addParameter(&originalParam);
197
        }
198
199
        TIntermBlock &body = *new TIntermBlock();
200
201
        Access::Env env{config.convertType};
202
203
        for (ConversionInfo &info : conversionInfos)
204
        {
205
            auto convert = [&](OriginalAccess &original, ModifiedAccess &modified) {
206
                if (info.astFunc)
207
                {
208
                    ASSERT(!info.stdFunc);
209
                    TIntermTyped &src  = isOriginalToModified ? modified : original;
210
                    TIntermTyped &dest = isOriginalToModified ? original : modified;
211
                    body.appendStatement(TIntermAggregate::CreateFunctionCall(
212
                        *info.astFunc, new TIntermSequence{&dest, &src}));
213
                }
214
                else
215
                {
216
                    ASSERT(info.stdFunc);
217
                    Access access      = info.stdFunc(env, original, modified);
218
                    TIntermTyped &src  = isOriginalToModified ? access.original : access.modified;
219
                    TIntermTyped &dest = isOriginalToModified ? access.modified : access.original;
220
                    body.appendStatement(new TIntermBinary(TOperator::EOpAssign, &dest, &src));
221
                }
222
            };
223
224
            OriginalAccess *original = &BuildPathAccess(symbolEnv, originalParam, info.pathItems);
225
            ModifiedAccess *modified = &AccessField(modifiedParam, info.pathName);
226
227
            const TType ot = original->getType();
228
            const TType mt = modified->getType();
229
            ASSERT(ot.isArray() == mt.isArray());
230
231
            if (ot.isArray() && ot != mt)
232
            {
233
                ASSERT(ot.getArraySizes() == mt.getArraySizes());
234
                if (ot.isArrayOfArrays())
235
                {
236
                    original = &Flatten(symbolEnv, *original);
237
                    modified = &Flatten(symbolEnv, *modified);
238
                }
239
                const int volume = static_cast<int>(ot.getArraySizeProduct());
240
                for (int i = 0; i < volume; ++i)
241
                {
242
                    if (i != 0)
243
                    {
244
                        original = original->deepCopy();
245
                        modified = modified->deepCopy();
246
                    }
247
                    OriginalAccess &o = AccessIndex(*original, i);
248
                    OriginalAccess &m = AccessIndex(*modified, i);
249
                    convert(o, m);
250
                }
251
            }
252
            else
253
            {
254
                convert(*original, *modified);
255
            }
256
        }
257
258
        auto *funcProto = new TIntermFunctionPrototype(&func);
259
        auto *funcDef   = new TIntermFunctionDefinition(funcProto, &body);
260
261
        ModifiedStructMachinery machinery;
262
        machinery.modifiedStruct                   = &modifiedStruct;
263
        machinery.getConverter(config.convertType) = funcDef;
264
265
        outMachineries.insert(originalStruct, machinery);
266
    }
267
268
    void pushPath(PathItem const &item)
269
    {
270
        pathItems.push_back(item);
271
272
        switch (item.type)
273
        {
274
            case PathItem::Type::Field:
275
                pushNamePath(item.field->name().data());
276
                break;
277
278
            case PathItem::Type::Index:
279
                pushNamePath(item.index);
280
                break;
281
282
            case PathItem::Type::FlattenArray:
283
                namePathSizes.push_back(namePath.size());
284
                break;
285
        }
286
    }
287
288
    void popPath()
289
    {
290
        ASSERT(!namePath.empty());
291
        ASSERT(!namePathSizes.empty());
292
        namePath.resize(namePathSizes.back());
293
        namePathSizes.pop_back();
294
295
        ASSERT(!pathItems.empty());
296
        pathItems.pop_back();
297
    }
298
299
    void finalize()
300
    {
301
        ASSERT(!finalized);
302
        finalized = true;
303
        introducePacking();
304
        ASSERT(metalLayoutTotal == Layout::Identity());
305
        introducePadding();
306
    }
307
308
    void addModifiedField(const TField &field,
309
                          TType &newType,
310
                          TLayoutBlockStorage storage,
311
                          TLayoutMatrixPacking packing)
312
    {
313
        TLayoutQualifier layoutQualifier = newType.getLayoutQualifier();
314
        layoutQualifier.blockStorage     = storage;
315
        layoutQualifier.matrixPacking    = packing;
316
        newType.setLayoutQualifier(layoutQualifier);
317
318
        const ImmutableString pathName(namePath);
319
        modifiedFields.push_back(new TField(&newType, pathName, field.line(), field.symbolType()));
320
    }
321
322
    void addConversion(const ConversionFunc &func)
323
    {
324
        ASSERT(!modifiedFields.empty());
325
        conversionInfos.push_back({func, nullptr, pathItems, modifiedFields.back()->name()});
326
    }
327
328
    void addConversion(const TFunction &func)
329
    {
330
        ASSERT(!modifiedFields.empty());
331
        conversionInfos.push_back({{}, &func, pathItems, modifiedFields.back()->name()});
332
    }
333
334
    bool hasPacking() const { return containsPacked; }
335
336
    bool hasPadding() const { return padFieldCount > 0; }
337
338
    bool recurse(const TStructure &structure, ModifiedStructMachinery &outMachinery)
339
    {
340
        const ModifiedStructMachinery *m = outMachineries.find(structure);
341
        if (m == nullptr)
342
        {
343
            const Name name = idGen.createNewName(structure.name().data());
344
            if (!TryCreateModifiedStruct(symbolEnv, idGen, config, structure, name, outMachineries))
345
            {
346
                return false;
347
            }
348
            m = outMachineries.find(structure);
349
            ASSERT(m);
350
        }
351
        outMachinery = *m;
352
        return true;
353
    }
354
355
  private:
356
    void addPadding(size_t padAmount, bool updateLayout)
357
    {
358
        if (padAmount == 0)
359
        {
360
            return;
361
        }
362
363
        const size_t begin = modifiedFields.size();
364
365
        // Iteratively adding in scalar or vector padding because some struct types will not
366
        // allow matrix or array members.
367
        while (padAmount > 0)
368
        {
369
            TType *padType;
370
            if (padAmount >= 16)
371
            {
372
                padAmount -= 16;
373
                padType = new TType(TBasicType::EbtFloat, 4);
374
            }
375
            else if (padAmount >= 8)
376
            {
377
                padAmount -= 8;
378
                padType = new TType(TBasicType::EbtFloat, 2);
379
            }
380
            else if (padAmount >= 4)
381
            {
382
                padAmount -= 4;
383
                padType = new TType(TBasicType::EbtFloat);
384
            }
385
            else if (padAmount >= 2)
386
            {
387
                padAmount -= 2;
388
                padType = new TType(TBasicType::EbtBool, 2);
389
            }
390
            else
391
            {
392
                ASSERT(padAmount == 1);
393
                padAmount -= 1;
394
                padType = new TType(TBasicType::EbtBool);
395
            }
396
397
            if (updateLayout)
398
            {
399
                metalLayoutTotal += MetalLayoutOf(*padType);
400
            }
401
402
            const Name name = idGen.createNewName("pad");
403
            modifiedFields.push_back(
404
                new TField(padType, name.rawName(), kNoSourceLoc, name.symbolType()));
405
            ++padFieldCount;
406
        }
407
408
        std::reverse(modifiedFields.begin() + begin, modifiedFields.end());
409
    }
410
411
    void introducePacking()
412
    {
413
        if (!config.allowPacking)
414
        {
415
            return;
416
        }
417
418
        auto setUnpackedStorage = [](TType &type) {
419
            TLayoutBlockStorage storage = type.getLayoutQualifier().blockStorage;
420
            switch (storage)
421
            {
422
                case TLayoutBlockStorage::EbsShared:
423
                    storage = TLayoutBlockStorage::EbsStd140;
424
                    break;
425
                case TLayoutBlockStorage::EbsPacked:
426
                    storage = TLayoutBlockStorage::EbsStd430;
427
                    break;
428
                case TLayoutBlockStorage::EbsStd140:
429
                case TLayoutBlockStorage::EbsStd430:
430
                case TLayoutBlockStorage::EbsUnspecified:
431
                    break;
432
            }
433
            SetBlockStorage(type, storage);
434
        };
435
436
        Layout glslLayoutTotal = Layout::Identity();
437
        const size_t size      = modifiedFields.size();
438
439
        for (size_t i = 0; i < size; ++i)
440
        {
441
            TField &curr           = *modifiedFields[i];
442
            TType &currType        = *curr.type();
443
            const bool canBePacked = CanBePacked(currType);
444
445
            auto dontPack = [&]() {
446
                if (canBePacked)
447
                {
448
                    setUnpackedStorage(currType);
449
                }
450
                glslLayoutTotal += GlslLayoutOf(currType);
451
            };
452
453
            if (!CanBePacked(currType))
454
            {
455
                dontPack();
456
                continue;
457
            }
458
459
            const Layout packedGlslLayout           = GlslLayoutOf(currType);
460
            const TLayoutBlockStorage packedStorage = currType.getLayoutQualifier().blockStorage;
461
            setUnpackedStorage(currType);
462
            const Layout unpackedGlslLayout = GlslLayoutOf(currType);
463
            SetBlockStorage(currType, packedStorage);
464
465
            ASSERT(packedGlslLayout.sizeOf <= unpackedGlslLayout.sizeOf);
466
            if (packedGlslLayout.sizeOf == unpackedGlslLayout.sizeOf)
467
            {
468
                dontPack();
469
                continue;
470
            }
471
472
            const size_t j = i + 1;
473
            if (j == size)
474
            {
475
                dontPack();
476
                break;
477
            }
478
479
            const size_t pad            = unpackedGlslLayout.sizeOf - packedGlslLayout.sizeOf;
480
            const TField &next          = *modifiedFields[j];
481
            const Layout nextGlslLayout = GlslLayoutOf(*next.type());
482
483
            if (pad < nextGlslLayout.sizeOf)
484
            {
485
                dontPack();
486
                continue;
487
            }
488
489
            symbolEnv.markAsPacked(curr);
490
            glslLayoutTotal += packedGlslLayout;
491
            containsPacked = true;
492
        }
493
    }
494
495
    void introducePadding()
496
    {
497
        if (!config.allowPadding)
498
        {
499
            return;
500
        }
501
502
        MetalLayoutOfConfig layoutConfig;
503
        layoutConfig.disablePacking             = !config.allowPacking;
504
        layoutConfig.assumeStructsAreTailPadded = true;
505
506
        TFieldList fields = std::move(modifiedFields);
507
        ASSERT(!fields.empty());  // GLSL requires at least one member.
508
509
        const TField *const first = fields.front();
510
511
        for (TField *field : fields)
512
        {
513
            const TType &type = *field->type();
514
515
            const Layout glslLayout  = GlslLayoutOf(type);
516
            const Layout metalLayout = MetalLayoutOf(type, layoutConfig);
517
518
            size_t prePadAmount = 0;
519
            if (glslLayout.alignOf > metalLayout.alignOf && field != first)
520
            {
521
                const size_t prePaddedSize = metalLayoutTotal.sizeOf;
522
                metalLayoutTotal.requireAlignment(glslLayout.alignOf, true);
523
                const size_t paddedSize = metalLayoutTotal.sizeOf;
524
                prePadAmount            = paddedSize - prePaddedSize;
525
                metalLayoutTotal += metalLayout;
526
                addPadding(prePadAmount, false);  // Note: requireAlignment() already updated layout
527
            }
528
            else
529
            {
530
                metalLayoutTotal += metalLayout;
531
            }
532
533
            modifiedFields.push_back(field);
534
535
            if (glslLayout.sizeOf > metalLayout.sizeOf && field != fields.back())
536
            {
537
                const bool updateLayout = true;  // XXX: Correct?
538
                const size_t padAmount  = glslLayout.sizeOf - metalLayout.sizeOf;
539
                addPadding(padAmount, updateLayout);
540
            }
541
        }
542
    }
543
544
    void pushNamePath(const char *extra)
545
    {
546
        ASSERT(extra && *extra != '\0');
547
        namePathSizes.push_back(namePath.size());
548
        const char *p = extra;
549
        if (namePath.empty())
550
        {
551
            namePath = p;
552
            return;
553
        }
554
        while (*p == '_')
555
        {
556
            ++p;
557
        }
558
        if (*p == '\0')
559
        {
560
            p = "x";
561
        }
562
        if (namePath.back() != '_')
563
        {
564
            namePath += '_';
565
        }
566
        namePath += p;
567
    }
568
569
    void pushNamePath(unsigned extra)
570
    {
571
        char buffer[std::numeric_limits<unsigned>::digits10 + 1];
572
        sprintf(buffer, "%u", extra);
573
        pushNamePath(buffer);
574
    }
575
576
  public:
577
    const ModifyStructConfig &config;
578
    SymbolEnv &symbolEnv;
579
580
  private:
581
    TFieldList &modifiedFields;
582
    Layout metalLayoutTotal = Layout::Identity();
583
    size_t padFieldCount    = 0;
584
    bool containsPacked     = false;
585
    bool finalized          = false;
586
587
    std::vector<PathItem> pathItems;
588
589
    std::vector<size_t> namePathSizes;
590
    std::string namePath;
591
592
    std::vector<ConversionInfo> conversionInfos;
593
    TSymbolTable &symbolTable;
594
    IdGen &idGen;
595
    ModifiedStructMachineries &outMachineries;
596
};
597
598
////////////////////////////////////////////////////////////////////////////////
599
600
using ModifyFunc = bool (*)(ConvertStructState &state,
601
                            const TField &field,
602
                            const TLayoutBlockStorage storage,
603
                            const TLayoutMatrixPacking packing);
604
605
bool ModifyRecursive(ConvertStructState &state,
606
                     const TField &field,
607
                     const TLayoutBlockStorage storage,
608
                     const TLayoutMatrixPacking packing);
609
610
bool IdentityModify(ConvertStructState &state,
611
                    const TField &field,
612
                    const TLayoutBlockStorage storage,
613
                    const TLayoutMatrixPacking packing)
614
{
615
    const TType &type = *field.type();
616
    state.addModifiedField(field, CloneType(type), storage, packing);
617
    state.addConversion([=](Access::Env &, OriginalAccess &o, ModifiedAccess &m) {
618
        return Access{o, m};
619
    });
620
    return false;
621
}
622
623
bool InlineStruct(ConvertStructState &state,
624
                  const TField &field,
625
                  const TLayoutBlockStorage storage,
626
                  const TLayoutMatrixPacking packing)
627
{
628
    const TType &type              = *field.type();
629
    const TStructure *substructure = state.symbolEnv.remap(type.getStruct());
630
    if (!substructure)
631
    {
632
        return false;
633
    }
634
    if (type.isArray())
635
    {
636
        return false;
637
    }
638
    if (!state.config.inlineStruct(field))
639
    {
640
        return false;
641
    }
642
643
    const TFieldList &subfields = substructure->fields();
644
    for (const TField *subfield : subfields)
645
    {
646
        const TType &subtype                  = *subfield->type();
647
        const TLayoutBlockStorage substorage  = Overlay(storage, subtype);
648
        const TLayoutMatrixPacking subpacking = Overlay(packing, subtype);
649
        ModifyRecursive(state, *subfield, substorage, subpacking);
650
    }
651
652
    return true;
653
}
654
655
bool RecurseStruct(ConvertStructState &state,
656
                   const TField &field,
657
                   const TLayoutBlockStorage storage,
658
                   const TLayoutMatrixPacking packing)
659
{
660
    const TType &type              = *field.type();
661
    const TStructure *substructure = state.symbolEnv.remap(type.getStruct());
662
    if (!substructure)
663
    {
664
        return false;
665
    }
666
    if (!state.config.recurseStruct(field))
667
    {
668
        return false;
669
    }
670
671
    ModifiedStructMachinery machinery;
672
    if (!state.recurse(*substructure, machinery))
673
    {
674
        return false;
675
    }
676
677
    TType &newType = *new TType(machinery.modifiedStruct, false);
678
    if (type.isArray())
679
    {
680
        newType.makeArrays(type.getArraySizes());
681
    }
682
683
    TIntermFunctionDefinition *converter = machinery.getConverter(state.config.convertType);
684
    ASSERT(converter);
685
686
    state.addModifiedField(field, newType, storage, packing);
687
    state.addConversion(*converter->getFunction());
688
689
    return true;
690
}
691
692
bool SplitMatrixColumns(ConvertStructState &state,
693
                        const TField &field,
694
                        const TLayoutBlockStorage storage,
695
                        const TLayoutMatrixPacking packing)
696
{
697
    const TType &type = *field.type();
698
    if (!type.isMatrix())
699
    {
700
        return false;
701
    }
702
    if (!state.config.splitMatrixColumns(field))
703
    {
704
        return false;
705
    }
706
707
    const int cols = type.getCols();
708
    TType &rowType = DropColumns(type);
709
710
    for (int c = 0; c < cols; ++c)
711
    {
712
        state.pushPath(c);
713
714
        state.addModifiedField(field, rowType, storage, packing);
715
        state.addConversion([=](Access::Env &, OriginalAccess &o, ModifiedAccess &m) {
716
            return Access{o, m};
717
        });
718
719
        state.popPath();
720
    }
721
722
    return true;
723
}
724
725
bool SaturateMatrixRows(ConvertStructState &state,
726
                        const TField &field,
727
                        const TLayoutBlockStorage storage,
728
                        const TLayoutMatrixPacking packing)
729
{
730
    const TType &type = *field.type();
731
    if (!type.isMatrix())
732
    {
733
        return false;
734
    }
735
    const int rows       = type.getRows();
736
    const int saturation = state.config.saturateMatrixRows(field);
737
    if (saturation <= rows)
738
    {
739
        return false;
740
    }
741
742
    const int cols = type.getCols();
743
    TType &satType = SetMatrixRowDim(type, saturation);
744
    state.addModifiedField(field, satType, storage, packing);
745
746
    for (int c = 0; c < cols; ++c)
747
    {
748
        for (int r = 0; r < rows; ++r)
749
        {
750
            state.addConversion([=](Access::Env &, OriginalAccess &o, ModifiedAccess &m) {
751
                auto &o_ = AccessIndex(AccessIndex(o, c), r);
752
                auto &m_ = AccessIndex(AccessIndex(m, c), r);
753
                return Access{o_, m_};
754
            });
755
        }
756
    }
757
758
    return true;
759
}
760
761
bool TestBoolToUint(ConvertStructState &state, const TField &field)
762
{
763
    if (field.type()->getBasicType() != TBasicType::EbtBool)
764
    {
765
        return false;
766
    }
767
    if (!state.config.promoteBoolToUint(field))
768
    {
769
        return false;
770
    }
771
    return true;
772
}
773
774
Access ConvertBoolToUint(ConvertType convertType, OriginalAccess &o, ModifiedAccess &m)
775
{
776
    auto coerce = [](TIntermTyped &to, TIntermTyped &from) -> TIntermTyped & {
777
        return *TIntermAggregate::CreateConstructor(to.getType(), new TIntermSequence{&from});
778
    };
779
    switch (convertType)
780
    {
781
        case ConvertType::OriginalToModified:
782
            return Access{coerce(m, o), m};
783
        case ConvertType::ModifiedToOriginal:
784
            return Access{o, coerce(o, m)};
785
    }
786
}
787
788
bool SaturateScalarOrVectorCommon(ConvertStructState &state,
789
                                  const TField &field,
790
                                  const TLayoutBlockStorage storage,
791
                                  const TLayoutMatrixPacking packing,
792
                                  const bool array)
793
{
794
    const TType &type = *field.type();
795
    if (type.isArray() != array)
796
    {
797
        return false;
798
    }
799
    if (!((type.isRank0() && HasScalarBasicType(type)) || type.isVector()))
800
    {
801
        return false;
802
    }
803
    const auto saturator =
804
        array ? state.config.saturateScalarOrVectorArrays : state.config.saturateScalarOrVector;
805
    const int dim        = type.getNominalSize();
806
    const int saturation = saturator(field);
807
    if (saturation <= dim)
808
    {
809
        return false;
810
    }
811
812
    TType &satType        = SetVectorDim(type, saturation);
813
    const bool boolToUint = TestBoolToUint(state, field);
814
    if (boolToUint)
815
    {
816
        satType.setBasicType(TBasicType::EbtUInt);
817
    }
818
    state.addModifiedField(field, satType, storage, packing);
819
820
    for (int d = 0; d < dim; ++d)
821
    {
822
        state.addConversion([=](Access::Env &env, OriginalAccess &o, ModifiedAccess &m) {
823
            auto &o_ = dim > 1 ? AccessIndex(o, d) : o;
824
            auto &m_ = AccessIndex(m, d);
825
            if (boolToUint)
826
            {
827
                return ConvertBoolToUint(env.type, o_, m_);
828
            }
829
            else
830
            {
831
                return Access{o_, m_};
832
            }
833
        });
834
    }
835
836
    return true;
837
}
838
839
bool SaturateScalarOrVectorArrays(ConvertStructState &state,
840
                                  const TField &field,
841
                                  const TLayoutBlockStorage storage,
842
                                  const TLayoutMatrixPacking packing)
843
{
844
    return SaturateScalarOrVectorCommon(state, field, storage, packing, true);
845
}
846
847
bool SaturateScalarOrVector(ConvertStructState &state,
848
                            const TField &field,
849
                            const TLayoutBlockStorage storage,
850
                            const TLayoutMatrixPacking packing)
851
{
852
    return SaturateScalarOrVectorCommon(state, field, storage, packing, false);
853
}
854
855
bool PromoteBoolToUint(ConvertStructState &state,
856
                       const TField &field,
857
                       const TLayoutBlockStorage storage,
858
                       const TLayoutMatrixPacking packing)
859
{
860
    if (!TestBoolToUint(state, field))
861
    {
862
        return false;
863
    }
864
865
    auto &promotedType = CloneType(*field.type());
866
    promotedType.setBasicType(TBasicType::EbtUInt);
867
    state.addModifiedField(field, promotedType, storage, packing);
868
869
    state.addConversion([=](Access::Env &env, OriginalAccess &o, ModifiedAccess &m) {
870
        return ConvertBoolToUint(env.type, o, m);
871
    });
872
873
    return true;
874
}
875
876
bool ModifyCommon(ConvertStructState &state,
877
                  const TField &field,
878
                  const TLayoutBlockStorage storage,
879
                  const TLayoutMatrixPacking packing)
880
{
881
    ModifyFunc funcs[] = {
882
        InlineStruct,                  //
883
        RecurseStruct,                 //
884
        SplitMatrixColumns,            //
885
        SaturateMatrixRows,            //
886
        SaturateScalarOrVectorArrays,  //
887
        SaturateScalarOrVector,        //
888
        PromoteBoolToUint,             //
889
    };
890
891
    for (ModifyFunc func : funcs)
892
    {
893
        if (func(state, field, storage, packing))
894
        {
895
            return true;
896
        }
897
    }
898
899
    return IdentityModify(state, field, storage, packing);
900
}
901
902
bool InlineArray(ConvertStructState &state,
903
                 const TField &field,
904
                 const TLayoutBlockStorage storage,
905
                 const TLayoutMatrixPacking packing)
906
{
907
    const TType &type = *field.type();
908
    if (!type.isArray())
909
    {
910
        return false;
911
    }
912
    if (!state.config.inlineArray(field))
913
    {
914
        return false;
915
    }
916
917
    const unsigned volume = type.getArraySizeProduct();
918
    const bool isMultiDim = type.isArrayOfArrays();
919
920
    auto &innermostType = InnermostType(type);
921
    const TField innermostField(&innermostType, field.name(), field.line(), field.symbolType());
922
923
    if (isMultiDim)
924
    {
925
        state.pushPath(FlattenArray());
926
    }
927
928
    for (unsigned i = 0; i < volume; ++i)
929
    {
930
        state.pushPath(i);
931
        ModifyCommon(state, innermostField, storage, packing);
932
        state.popPath();
933
    }
934
935
    if (isMultiDim)
936
    {
937
        state.popPath();
938
    }
939
940
    return true;
941
}
942
943
bool ModifyRecursive(ConvertStructState &state,
944
                     const TField &field,
945
                     const TLayoutBlockStorage storage,
946
                     const TLayoutMatrixPacking packing)
947
{
948
    state.pushPath(field);
949
950
    bool modified;
951
    if (InlineArray(state, field, storage, packing))
952
    {
953
        modified = true;
954
    }
955
    else
956
    {
957
        modified = ModifyCommon(state, field, storage, packing);
958
    }
959
960
    state.popPath();
961
962
    return modified;
963
}
964
965
}  // anonymous namespace
966
967
////////////////////////////////////////////////////////////////////////////////
968
969
bool sh::TryCreateModifiedStruct(SymbolEnv &symbolEnv,
970
                                 IdGen &idGen,
971
                                 const ModifyStructConfig &config,
972
                                 const TStructure &originalStruct,
973
                                 const Name &modifiedStructName,
974
                                 ModifiedStructMachineries &outMachineries)
975
{
976
    ConvertStructState state(symbolEnv, idGen, config, outMachineries);
977
    size_t identicalFieldCount = 0;
978
979
    const TFieldList &originalFields = originalStruct.fields();
980
    for (TField *originalField : originalFields)
981
    {
982
        const TType &originalType          = *originalField->type();
983
        const TLayoutBlockStorage storage  = Overlay(config.initialBlockStorage, originalType);
984
        const TLayoutMatrixPacking packing = Overlay(config.initialMatrixPacking, originalType);
985
        if (!ModifyRecursive(state, *originalField, storage, packing))
986
        {
987
            ++identicalFieldCount;
988
        }
989
    }
990
991
    state.finalize();
992
993
    if (identicalFieldCount == originalFields.size() && !state.hasPacking() && !state.hasPadding())
994
    {
995
        return false;
996
    }
997
998
    state.publish(originalStruct, modifiedStructName);
999
1000
    return true;
1001
}
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/ModifyStruct.h +135 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/ModifyStruct.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_MODIFYSTRUCT_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_MODIFYSTRUCT_H_
9
10
#include <cstring>
11
#include <unordered_map>
12
#include <unordered_set>
13
14
#include "compiler/translator/TranslatorMetalDirect/IdGen.h"
15
#include "compiler/translator/TranslatorMetalDirect/Layout.h"
16
#include "compiler/translator/TranslatorMetalDirect/Name.h"
17
#include "compiler/translator/TranslatorMetalDirect/ProgramPrelude.h"
18
#include "compiler/translator/TranslatorMetalDirect/SymbolEnv.h"
19
20
namespace sh
21
{
22
23
enum class ConvertType
24
{
25
    OriginalToModified,
26
    ModifiedToOriginal,
27
};
28
29
// Configures how struct modification is performed.
30
class ModifyStructConfig
31
{
32
  public:
33
    struct Predicate
34
    {
35
        using Func = bool (*)(const TField &);
36
        static bool False(const TField &) { return false; }
37
        static bool True(const TField &) { return true; }
38
    };
39
40
    struct SaturateVector
41
    {
42
        // Valid return values are [0, 1, 2, 3, 4].
43
        // If original dim >= return value, the field remains untouched.
44
        using Func = int (*)(const TField &);
45
        static int DontSaturate(const TField &) { return 0; }
46
        static int FullySaturate(const TField &) { return 4; }
47
    };
48
49
  public:
50
    ModifyStructConfig(ConvertType convertType, bool allowPacking, bool allowPadding)
51
        : convertType(convertType), allowPacking(allowPacking), allowPadding(allowPadding)
52
    {}
53
54
    // Matrix field is split into multiple fields of row vectors.
55
    Predicate::Func splitMatrixColumns = Predicate::False;
56
57
    // Array fields are split into multiple fields of element type.
58
    Predicate::Func inlineArray = Predicate::False;
59
60
    // Struct fields have their subfields inlined directly.
61
    Predicate::Func inlineStruct = Predicate::False;
62
63
    // Struct fields are modified.
64
    Predicate::Func recurseStruct = Predicate::False;
65
66
    // Vector and scalar bool fields are promoted to uint fields.
67
    Predicate::Func promoteBoolToUint = Predicate::False;
68
69
    // Creates a new structure where scalar or vector fields are saturated vectors.
70
    // e.g. `float -> float4`.
71
    // e.g. `float2 -> float4`.
72
    SaturateVector::Func saturateScalarOrVector = SaturateVector::DontSaturate;
73
74
    // Creates a new structure where scalar or vector array fields are saturated.
75
    // e.g. `float[10] -> float4[10]`
76
    // e.g. `float2[10] -> float4[10]`
77
    SaturateVector::Func saturateScalarOrVectorArrays = SaturateVector::DontSaturate;
78
79
    // Creates a new structure where matrix fields are row-saturated.
80
    // e.g. `float2x2 -> float2x4`.
81
    SaturateVector::Func saturateMatrixRows = SaturateVector::DontSaturate;
82
83
    TLayoutBlockStorage initialBlockStorage   = kDefaultLayoutBlockStorage;
84
    TLayoutMatrixPacking initialMatrixPacking = kDefaultLayoutMatrixPacking;
85
    ConvertType convertType;
86
    bool allowPacking;
87
    bool allowPadding;
88
    AddressSpace externalAddressSpace;
89
};
90
91
struct ModifiedStructMachinery
92
{
93
    const TStructure *modifiedStruct                  = nullptr;
94
    TIntermFunctionDefinition *funcOriginalToModified = nullptr;
95
    TIntermFunctionDefinition *funcModifiedToOriginal = nullptr;
96
97
    TIntermFunctionDefinition *&getConverter(ConvertType convertType)
98
    {
99
        if (convertType == ConvertType::OriginalToModified)
100
        {
101
            return funcOriginalToModified;
102
        }
103
        else
104
        {
105
            return funcModifiedToOriginal;
106
        }
107
    }
108
};
109
110
// Indexed by topological order.
111
class ModifiedStructMachineries
112
{
113
  public:
114
    size_t size() const;
115
    const ModifiedStructMachinery &at(size_t index) const;
116
    const ModifiedStructMachinery *find(const TStructure &s) const;
117
    void insert(const TStructure &s, const ModifiedStructMachinery &machinery);
118
119
  private:
120
    std::unordered_map<const TStructure *, ModifiedStructMachinery> originalToMachinery;
121
    std::vector<const TStructure *> ordering;
122
};
123
124
// Returns true and `outMachinery` populated if modifications were performed.
125
// Returns false otherwise.
126
bool TryCreateModifiedStruct(SymbolEnv &symbolEnv,
127
                             IdGen &idGen,
128
                             const ModifyStructConfig &config,
129
                             const TStructure &originalStruct,
130
                             const Name &modifiedStructName,
131
                             ModifiedStructMachineries &outMachineries);
132
133
}  // namespace sh
134
135
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_MODIFYSTRUCT_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/Name.cpp +220 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/Name.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include "compiler/translator/TranslatorMetalDirect/Name.h"
8
#include "common/debug.h"
9
#include "compiler/translator/TranslatorMetalDirect/Debug.h"
10
#include "compiler/translator/tree_util/IntermTraverse.h"
11
12
using namespace sh;
13
14
////////////////////////////////////////////////////////////////////////////////
15
16
template <typename T>
17
static ImmutableString GetName(T const &object)
18
{
19
    if (object.symbolType() == SymbolType::Empty)
20
    {
21
        return kEmptyImmutableString;
22
    }
23
    return object.name();
24
}
25
26
Name::Name(const TField &field) : Name(GetName(field), field.symbolType()) {}
27
28
Name::Name(const TSymbol &symbol) : Name(GetName(symbol), symbol.symbolType()) {}
29
30
bool Name::operator==(const Name &other) const
31
{
32
    return mRawName == other.mRawName && mSymbolType == other.mSymbolType;
33
}
34
35
bool Name::operator!=(const Name &other) const
36
{
37
    return !(*this == other);
38
}
39
40
bool Name::operator<(const Name &other) const
41
{
42
    if (mRawName < other.mRawName)
43
    {
44
        return true;
45
    }
46
    if (other.mRawName < mRawName)
47
    {
48
        return false;
49
    }
50
    return mSymbolType < other.mSymbolType;
51
}
52
53
bool Name::empty() const
54
{
55
    return mSymbolType == SymbolType::Empty;
56
}
57
58
bool Name::beginsWith(const Name &prefix) const
59
{
60
    if (mSymbolType != prefix.mSymbolType)
61
    {
62
        return false;
63
    }
64
    return mRawName.beginsWith(prefix.mRawName);
65
}
66
67
void Name::emit(TInfoSinkBase &out) const
68
{
69
    switch (mSymbolType)
70
    {
71
        case SymbolType::BuiltIn:
72
        case SymbolType::UserDefined:
73
            ASSERT(!mRawName.empty());
74
            out << mRawName;
75
            break;
76
77
        case SymbolType::AngleInternal:
78
            ASSERT(!mRawName.empty());
79
            if (mRawName.beginsWith(kAngleInternalPrefix))
80
            {
81
                out << mRawName;
82
            }
83
            else if (mRawName[0] != '_')
84
            {
85
                out << kAngleInternalPrefix << '_' << mRawName;
86
            }
87
            else
88
            {
89
                out << kAngleInternalPrefix << mRawName;
90
            }
91
            break;
92
93
        case SymbolType::Empty:
94
            LOGIC_ERROR();
95
            break;
96
    }
97
}
98
99
////////////////////////////////////////////////////////////////////////////////
100
101
namespace
102
{
103
104
// NOTE: This matches more things than FindSymbolNode.
105
class ExpressionContainsNameVisitor : public TIntermTraverser
106
{
107
    Name mName;
108
    bool mFoundName = false;
109
110
  public:
111
    ExpressionContainsNameVisitor(const Name &name)
112
        : TIntermTraverser(true, false, false), mName(name)
113
    {}
114
115
    bool foundName() const { return mFoundName; }
116
117
    void visitSymbol(TIntermSymbol *node) override
118
    {
119
        if (Name(node->variable()) == mName)
120
        {
121
            mFoundName = true;
122
        }
123
    }
124
125
    bool visitSwizzle(Visit, TIntermSwizzle *) override { return !mFoundName; }
126
127
    bool visitBinary(Visit visit, TIntermBinary *node) override { return !mFoundName; }
128
129
    bool visitUnary(Visit visit, TIntermUnary *node) override  { return !mFoundName; }
130
131
    bool visitTernary(Visit visit, TIntermTernary *node) override { return !mFoundName; }
132
133
    bool visitAggregate(Visit visit, TIntermAggregate *node) override
134
    {
135
        if (node->isConstructor())
136
        {
137
            const TType &type           = node->getType();
138
            const TStructure *structure = type.getStruct();
139
            if (structure && Name(*structure) == mName)
140
            {
141
                mFoundName = true;
142
            }
143
        }
144
        else
145
        {
146
            const TFunction *func = node->getFunction();
147
            if (func && Name(*func) == mName)
148
            {
149
                mFoundName = true;
150
            }
151
        }
152
        return !mFoundName;
153
    }
154
155
    bool visitIfElse(Visit visit, TIntermIfElse *node) override
156
    {
157
        LOGIC_ERROR();
158
        return false;
159
    }
160
161
    bool visitSwitch(Visit, TIntermSwitch *) override
162
    {
163
        LOGIC_ERROR();
164
        return false;
165
    }
166
    bool visitCase(Visit, TIntermCase *) override
167
    {
168
        LOGIC_ERROR();
169
        return false;
170
    }
171
172
    void visitFunctionPrototype(TIntermFunctionPrototype *) override { LOGIC_ERROR(); }
173
174
    bool visitFunctionDefinition(Visit, TIntermFunctionDefinition *) override
175
    {
176
        LOGIC_ERROR();
177
        return false;
178
    }
179
180
    bool visitBlock(Visit, TIntermBlock *) override
181
    {
182
        LOGIC_ERROR();
183
        return false;
184
    }
185
186
    bool visitGlobalQualifierDeclaration(Visit, TIntermGlobalQualifierDeclaration *) override
187
    {
188
        LOGIC_ERROR();
189
        return false;
190
    }
191
192
    bool visitDeclaration(Visit, TIntermDeclaration *) override
193
    {
194
        LOGIC_ERROR();
195
        return false;
196
    }
197
198
    bool visitLoop(Visit, TIntermLoop *) override
199
    {
200
        LOGIC_ERROR();
201
        return false;
202
    }
203
204
    bool visitBranch(Visit, TIntermBranch *) override
205
    {
206
        LOGIC_ERROR();
207
        return false;
208
    }
209
210
    void visitPreprocessorDirective(TIntermPreprocessorDirective *) override { LOGIC_ERROR(); }
211
};
212
213
}  // anonymous namespace
214
215
bool sh::ExpressionContainsName(const Name &name, TIntermTyped &node)
216
{
217
    ExpressionContainsNameVisitor visitor(name);
218
    node.traverse(&visitor);
219
    return visitor.foundName();
220
}
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/Name.h +68 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/Name.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_NAME_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_NAME_H_
9
10
#include "compiler/translator/ImmutableString.h"
11
#include "compiler/translator/InfoSink.h"
12
#include "compiler/translator/IntermNode.h"
13
#include "compiler/translator/Symbol.h"
14
#include "compiler/translator/Types.h"
15
16
namespace sh
17
{
18
19
constexpr char kAngleInternalPrefix[] = "ANGLE";
20
21
// Represents the name of a symbol.
22
class Name
23
{
24
  public:
25
    constexpr Name(const Name &) = default;
26
27
    constexpr Name() : Name(kEmptyImmutableString, SymbolType::Empty) {}
28
29
    explicit constexpr Name(ImmutableString rawName, SymbolType symbolType)
30
        : mRawName(rawName), mSymbolType(symbolType)
31
    {
32
        ASSERT(rawName.empty() == (symbolType == SymbolType::Empty));
33
    }
34
35
    explicit constexpr Name(const char *rawName, SymbolType symbolType = SymbolType::AngleInternal)
36
        : Name(ImmutableString(rawName), symbolType)
37
    {}
38
39
    explicit Name(const std::string &rawName, SymbolType symbolType)
40
        : Name(ImmutableString(rawName), symbolType)
41
    {}
42
43
    explicit Name(const TField &field);
44
    explicit Name(const TSymbol &symbol);
45
46
    Name &operator=(const Name &) = default;
47
    bool operator==(const Name &other) const;
48
    bool operator!=(const Name &other) const;
49
    bool operator<(const Name &other) const;
50
51
    constexpr const ImmutableString &rawName() const { return mRawName; }
52
    constexpr SymbolType symbolType() const { return mSymbolType; }
53
54
    bool empty() const;
55
    bool beginsWith(const Name &prefix) const;
56
57
    void emit(TInfoSinkBase &out) const;
58
59
  private:
60
    ImmutableString mRawName;
61
    SymbolType mSymbolType;
62
};
63
64
ANGLE_NO_DISCARD bool ExpressionContainsName(const Name &name, TIntermTyped &node);
65
66
}  // namespace sh
67
68
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_NAME_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/Pipeline.cpp +476 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/Pipeline.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include "compiler/translator/TranslatorMetalDirect/Pipeline.h"
8
#include "compiler/translator/TranslatorMetalDirect/Debug.h"
9
#include "compiler/translator/tree_util/BuiltIn.h"
10
11
using namespace sh;
12
13
////////////////////////////////////////////////////////////////////////////////
14
15
#define VARIANT_NAME(variant, base) (variant == Variant::Modified ? base "Mod" : base)
16
17
bool Pipeline::uses(const TVariable &var) const
18
{
19
    if (var.symbolType() == SymbolType::Empty)
20
    {
21
        return false;
22
    }
23
24
    if (globalInstanceVar)
25
    {
26
        return &var == globalInstanceVar;
27
    }
28
29
    const TType &nodeType      = var.getType();
30
    const TQualifier qualifier = nodeType.getQualifier();
31
32
    switch (type)
33
    {
34
        case Type::VertexIn:
35
            switch (qualifier)
36
            {
37
                case TQualifier::EvqAttribute:
38
                case TQualifier::EvqVertexIn:
39
                    return true;
40
                default:
41
                    return false;
42
            }
43
44
        case Type::VertexOut:
45
            switch (qualifier)
46
            {
47
                case TQualifier::EvqVertexOut:
48
                case TQualifier::EvqPosition:
49
                case TQualifier::EvqFlatOut:
50
                case TQualifier::EvqPointSize:
51
                case TQualifier::EvqSmoothOut:
52
                case TQualifier::EvqCentroidOut:
53
                case TQualifier::EvqNoPerspectiveOut:
54
                case TQualifier::EvqVaryingOut:
55
                    return true;
56
                default:
57
                    return false;
58
            }
59
60
        case Type::FragmentIn:
61
            switch (qualifier)
62
            {
63
                case TQualifier::EvqFragmentIn:
64
                case TQualifier::EvqFlatIn:
65
                case TQualifier::EvqSmoothIn:
66
                case TQualifier::EvqCentroidIn:
67
                case TQualifier::EvqNoPerspectiveIn:
68
                case TQualifier::EvqVaryingIn:
69
                    return true;
70
                default:
71
                    return false;
72
            }
73
74
        case Type::FragmentOut:
75
            switch (qualifier)
76
            {
77
                case TQualifier::EvqFragmentOut:
78
                case TQualifier::EvqFragColor:
79
                case TQualifier::EvqFragData:
80
                case TQualifier::EvqFragDepth:
81
                    return true;
82
                default:
83
                    return false;
84
            }
85
86
        case Type::UserUniforms:
87
            switch (qualifier)
88
            {
89
                case TQualifier::EvqUniform:
90
                    return true;
91
                default:
92
                    return false;
93
            }
94
95
        case Type::NonConstantGlobals:
96
            switch (qualifier)
97
            {
98
                case TQualifier::EvqGlobal:
99
                    return true;
100
                default:
101
                    return false;
102
            }
103
104
        case Type::InvocationVertexGlobals:
105
            switch (qualifier)
106
            {
107
                case TQualifier::EvqVertexID:
108
                    return true;
109
                default:
110
                    return false;
111
            }
112
113
        case Type::InvocationFragmentGlobals:
114
            switch (qualifier)
115
            {
116
                case TQualifier::EvqFragCoord:
117
                case TQualifier::EvqPointCoord:
118
                case TQualifier::EvqFrontFacing:
119
                    return true;
120
                default:
121
                    return false;
122
            }
123
124
        case Type::AngleUniforms:
125
            LOGIC_ERROR();  // globalInstanceVar should be non-null and thus never reach here.
126
            return false;
127
128
        case Type::Texture:
129
            return IsSampler(nodeType.getBasicType());
130
131
        case Type::InstanceId:
132
            return Name(var) == Name(*BuiltInVariable::gl_InstanceID());
133
    }
134
}
135
136
Name Pipeline::getStructTypeName(Variant variant) const
137
{
138
    const char *name;
139
    switch (type)
140
    {
141
        case Type::VertexIn:
142
            name = VARIANT_NAME(variant, "VertexIn");
143
            break;
144
        case Type::VertexOut:
145
            name = VARIANT_NAME(variant, "VertexOut");
146
            break;
147
        case Type::FragmentIn:
148
            name = VARIANT_NAME(variant, "FragmentIn");
149
            break;
150
        case Type::FragmentOut:
151
            name = VARIANT_NAME(variant, "FragmentOut");
152
            break;
153
        case Type::UserUniforms:
154
            name = VARIANT_NAME(variant, "UserUniforms");
155
            break;
156
        case Type::AngleUniforms:
157
            name = VARIANT_NAME(variant, "AngleUniforms");
158
            break;
159
        case Type::NonConstantGlobals:
160
            name = VARIANT_NAME(variant, "NonConstGlobals");
161
            break;
162
        case Type::InvocationVertexGlobals:
163
            name = VARIANT_NAME(variant, "InvocationVertexGlobals");
164
            break;
165
        case Type::InvocationFragmentGlobals:
166
            name = VARIANT_NAME(variant, "InvocationFragmentGlobals");
167
            break;
168
        case Type::Texture:
169
            name = VARIANT_NAME(variant, "TextureEnvs");
170
            break;
171
        case Type::InstanceId:
172
            name = VARIANT_NAME(variant, "InstanceId");
173
            break;
174
    }
175
    return Name(name);
176
}
177
178
Name Pipeline::getStructInstanceName(Variant variant) const
179
{
180
    const char *name;
181
    switch (type)
182
    {
183
        case Type::VertexIn:
184
            name = VARIANT_NAME(variant, "vertexIn");
185
            break;
186
        case Type::VertexOut:
187
            name = VARIANT_NAME(variant, "vertexOut");
188
            break;
189
        case Type::FragmentIn:
190
            name = VARIANT_NAME(variant, "fragmentIn");
191
            break;
192
        case Type::FragmentOut:
193
            name = VARIANT_NAME(variant, "fragmentOut");
194
            break;
195
        case Type::UserUniforms:
196
            name = VARIANT_NAME(variant, "userUniforms");
197
            break;
198
        case Type::AngleUniforms:
199
            name = VARIANT_NAME(variant, "angleUniforms");
200
            break;
201
        case Type::NonConstantGlobals:
202
            name = VARIANT_NAME(variant, "nonConstGlobals");
203
            break;
204
        case Type::InvocationVertexGlobals:
205
            name = VARIANT_NAME(variant, "invocationVertexGlobals");
206
            break;
207
        case Type::InvocationFragmentGlobals:
208
            name = VARIANT_NAME(variant, "invocationFragmentGlobals");
209
            break;
210
        case Type::Texture:
211
            name = VARIANT_NAME(variant, "textureEnvs");
212
            break;
213
        case Type::InstanceId:
214
            name = VARIANT_NAME(variant, "instanceId");
215
            break;
216
    }
217
    return Name(name);
218
}
219
220
static bool AllowPacking(Pipeline::Type type)
221
{
222
    using Type = Pipeline::Type;
223
224
    switch (type)
225
    {
226
        case Type::UserUniforms:
227
            return true;
228
229
        case Type::VertexIn:
230
        case Type::VertexOut:
231
        case Type::FragmentIn:
232
        case Type::FragmentOut:
233
        case Type::AngleUniforms:
234
        case Type::NonConstantGlobals:
235
        case Type::InvocationVertexGlobals:
236
        case Type::InvocationFragmentGlobals:
237
        case Type::Texture:
238
        case Type::InstanceId:
239
            return false;
240
    }
241
}
242
243
static bool AllowPadding(Pipeline::Type type)
244
{
245
    using Type = Pipeline::Type;
246
247
    switch (type)
248
    {
249
        case Type::UserUniforms:
250
        case Type::VertexIn:
251
        case Type::VertexOut:
252
        case Type::FragmentIn:
253
        case Type::FragmentOut:
254
        case Type::AngleUniforms:
255
        case Type::NonConstantGlobals:
256
        case Type::InvocationVertexGlobals:
257
        case Type::InvocationFragmentGlobals:
258
            return true;
259
260
        case Type::Texture:
261
        case Type::InstanceId:
262
            return false;
263
    }
264
}
265
enum Compare
266
{
267
    LT,
268
    LTE,
269
    EQ,
270
    GTE,
271
    GT,
272
};
273
274
template <typename T>
275
static bool CompareBy(Compare op, const T &x, const T &y)
276
{
277
    switch (op)
278
    {
279
        case LT:
280
            return x < y;
281
        case LTE:
282
            return x <= y;
283
        case EQ:
284
            return x == y;
285
        case GTE:
286
            return x >= y;
287
        case GT:
288
            return x > y;
289
    }
290
}
291
292
template <TBasicType BT, Compare Cmp, int MatchDim, int NewDim>
293
static int SaturateVectorOf(const TField &field)
294
{
295
    static_assert(NewDim >= MatchDim, "");
296
297
    const TType &type = *field.type();
298
    ASSERT(type.isScalar() || type.isVector());
299
300
    const bool cond = type.getBasicType() == BT && !type.isArray() &&
301
                      CompareBy(Cmp, type.getNominalSize(), MatchDim);
302
303
    if (cond)
304
    {
305
        return NewDim;
306
    }
307
    return 0;
308
}
309
310
ModifyStructConfig Pipeline::externalStructModifyConfig() const
311
{
312
    using Pred   = ModifyStructConfig::Predicate;
313
    using SatVec = ModifyStructConfig::SaturateVector;
314
315
    ModifyStructConfig config(
316
        isPipelineOut() ? ConvertType::OriginalToModified : ConvertType::ModifiedToOriginal,
317
        AllowPacking(type), AllowPadding(type));
318
319
    config.externalAddressSpace = externalAddressSpace();
320
321
    switch (type)
322
    {
323
        case Type::VertexIn:
324
            config.inlineArray        = Pred::True;
325
            config.splitMatrixColumns = Pred::True;
326
            config.inlineStruct       = Pred::True;
327
            break;
328
329
        case Type::VertexOut:
330
            config.inlineArray        = Pred::True;
331
            config.splitMatrixColumns = Pred::True;
332
            config.inlineStruct       = Pred::True;
333
            break;
334
335
        case Type::FragmentIn:
336
            config.inlineArray        = Pred::True;
337
            config.splitMatrixColumns = Pred::True;
338
            config.inlineStruct       = Pred::True;
339
            break;
340
341
        case Type::FragmentOut:
342
            config.inlineArray            = Pred::True;
343
            config.splitMatrixColumns     = Pred::True;
344
            config.inlineStruct           = Pred::True;
345
            config.saturateScalarOrVector = [](const TField &field) {
346
                if (int s = SaturateVectorOf<TBasicType::EbtInt, LT, 4, 4>(field))
347
                {
348
                    return s;
349
                }
350
                if (int s = SaturateVectorOf<TBasicType::EbtUInt, LT, 4, 4>(field))
351
                {
352
                    return s;
353
                }
354
                if (int s = SaturateVectorOf<TBasicType::EbtFloat, LT, 4, 4>(field))
355
                {
356
                    return s;
357
                }
358
                return 0;
359
            };
360
            break;
361
362
        case Type::UserUniforms:
363
            config.promoteBoolToUint            = Pred::True;
364
            config.saturateMatrixRows           = SatVec::FullySaturate;
365
            config.saturateScalarOrVectorArrays = SatVec::FullySaturate;
366
            config.recurseStruct                = Pred::True;
367
            break;
368
369
        case Type::AngleUniforms:
370
            config.initialBlockStorage = TLayoutBlockStorage::EbsStd430;  // XXX: Correct?
371
            break;
372
373
        case Type::NonConstantGlobals:
374
            break;
375
376
        case Type::InvocationVertexGlobals:
377
        case Type::InvocationFragmentGlobals:
378
        case Type::Texture:
379
        case Type::InstanceId:
380
            break;
381
    }
382
383
    return config;
384
}
385
386
bool Pipeline::alwaysRequiresLocalVariableDeclarationInMain() const
387
{
388
    switch (type)
389
    {
390
        case Type::VertexIn:
391
        case Type::FragmentIn:
392
        case Type::UserUniforms:
393
        case Type::AngleUniforms:
394
            return false;
395
396
        case Type::VertexOut:
397
        case Type::FragmentOut:
398
        case Type::NonConstantGlobals:
399
        case Type::InvocationVertexGlobals:
400
        case Type::InvocationFragmentGlobals:
401
        case Type::Texture:
402
        case Type::InstanceId:
403
            return true;
404
    }
405
}
406
407
bool Pipeline::isPipelineOut() const
408
{
409
    switch (type)
410
    {
411
        case Type::VertexIn:
412
        case Type::FragmentIn:
413
        case Type::UserUniforms:
414
        case Type::AngleUniforms:
415
        case Type::NonConstantGlobals:
416
        case Type::InvocationVertexGlobals:
417
        case Type::InvocationFragmentGlobals:
418
        case Type::Texture:
419
        case Type::InstanceId:
420
            return false;
421
422
        case Type::VertexOut:
423
        case Type::FragmentOut:
424
            return true;
425
    }
426
}
427
428
AddressSpace Pipeline::externalAddressSpace() const
429
{
430
    switch (type)
431
    {
432
        case Type::VertexIn:
433
        case Type::FragmentIn:
434
        case Type::NonConstantGlobals:
435
        case Type::InvocationVertexGlobals:
436
        case Type::InvocationFragmentGlobals:
437
        case Type::Texture:
438
        case Type::InstanceId:
439
        case Type::FragmentOut:
440
        case Type::VertexOut:
441
            return AddressSpace::Thread;
442
443
        case Type::UserUniforms:
444
        case Type::AngleUniforms:
445
            return AddressSpace::Constant;
446
    }
447
}
448
449
bool PipelineStructs::matches(const TStructure &s, bool internal, bool external) const
450
{
451
    PipelineScoped<TStructure> ps[] = {
452
        fragmentIn,
453
        fragmentOut,
454
        vertexIn,
455
        vertexOut,
456
        userUniforms,
457
        angleUniforms,
458
        nonConstantGlobals,
459
        invocationVertexGlobals,
460
        invocationFragmentGlobals,
461
        texture,
462
        instanceId,
463
    };
464
    for (const auto &p : ps)
465
    {
466
        if (internal && p.internal == &s)
467
        {
468
            return true;
469
        }
470
        if (external && p.external == &s)
471
        {
472
            return true;
473
        }
474
    }
475
    return false;
476
}
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/Pipeline.h +123 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/Pipeline.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_PIPELINE_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_PIPELINE_H_
9
10
#include "compiler/translator/Symbol.h"
11
#include "compiler/translator/TranslatorMetalDirect/ModifyStruct.h"
12
#include "compiler/translator/TranslatorMetalDirect/Name.h"
13
#include "compiler/translator/TranslatorMetalDirect/SymbolEnv.h"
14
15
namespace sh
16
{
17
18
// Data that is scoped as `external` and `internal` for a given pipeline.
19
template <typename T>
20
struct PipelineScoped
21
{
22
    // Data that is configured to talk externally to the program.
23
    // May coincide with `internal`, but may also diverge from `internal`.
24
    const T *external = nullptr;
25
26
    // Data that is configured to talk internally within the program.
27
    // May coincide with `external`, but may also diverge from `external`.
28
    const T *internal = nullptr;
29
30
    // Returns true iff the input coincides with either `external` or `internal` data.
31
    bool matches(const T &object) const { return external == &object || internal == &object; }
32
33
    // Both `external` and `internal` representations are non-null.
34
    bool isTotallyFull() const { return external && internal; }
35
36
    // Both `external` and `internal` representations are null.
37
    bool isTotallyEmpty() const { return !external && !internal; }
38
39
    // Both `external` and `internal` representations are the same.
40
    bool isUniform() const { return external == internal; }
41
};
42
43
// Represents a high-level program pipeline.
44
class Pipeline
45
{
46
  public:
47
    enum class Type
48
    {
49
        VertexIn,
50
        VertexOut,
51
        FragmentIn,
52
        FragmentOut,
53
        UserUniforms,
54
        AngleUniforms,
55
        NonConstantGlobals,
56
        InvocationVertexGlobals,
57
        InvocationFragmentGlobals,
58
        Texture,
59
        InstanceId,
60
    };
61
62
    enum class Variant
63
    {
64
        // For all internal pipeline uses.
65
        // For external pipeline uses if pipeline does not require splitting or saturation.
66
        Original,
67
68
        // Only for external pipeline uses if the pipeline was split or saturated.
69
        Modified,
70
    };
71
72
  public:
73
    // The type of the pipeline.
74
    Type type;
75
76
    // Non-null if a global instance of the pipeline struct already exists.
77
    // If non-null struct splitting should not be needed.
78
    const TVariable *globalInstanceVar;
79
80
  public:
81
    // Returns true iff the variable belongs to the pipeline.
82
    bool uses(const TVariable &var) const;
83
84
    // Returns the name for the struct type that stores variables of this pipeline.
85
    Name getStructTypeName(Variant variant) const;
86
87
    // Returns the name for the struct instance that stores variables of this pipeline.
88
    Name getStructInstanceName(Variant variant) const;
89
90
    ModifyStructConfig externalStructModifyConfig() const;
91
92
    // Returns true if the pipeline always requires a non-parameter local instance declaration of
93
    // the pipeline structures.
94
    bool alwaysRequiresLocalVariableDeclarationInMain() const;
95
96
    // Returns true iff the pipeline is an output pipeline. The external pipeline structure should
97
    // be returned from `main`.
98
    bool isPipelineOut() const;
99
100
    AddressSpace externalAddressSpace() const;
101
};
102
103
// A collection of various pipeline structures.
104
struct PipelineStructs : angle::NonCopyable
105
{
106
    PipelineScoped<TStructure> fragmentIn;
107
    PipelineScoped<TStructure> fragmentOut;
108
    PipelineScoped<TStructure> vertexIn;
109
    PipelineScoped<TStructure> vertexOut;
110
    PipelineScoped<TStructure> userUniforms;
111
    PipelineScoped<TStructure> angleUniforms;
112
    PipelineScoped<TStructure> nonConstantGlobals;
113
    PipelineScoped<TStructure> invocationVertexGlobals;
114
    PipelineScoped<TStructure> invocationFragmentGlobals;
115
    PipelineScoped<TStructure> texture;
116
    PipelineScoped<TStructure> instanceId;
117
118
    bool matches(const TStructure &s, bool internal, bool external) const;
119
};
120
121
}  // namespace sh
122
123
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_PIPELINE_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/ProgramPrelude.cpp +3757 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/ProgramPrelude.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include <cctype>
8
9
#include "compiler/translator/InfoSink.h"
10
#include "compiler/translator/Symbol.h"
11
#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
12
#include "compiler/translator/TranslatorMetalDirect/ConstantNames.h"
13
#include "compiler/translator/TranslatorMetalDirect/Debug.h"
14
#include "compiler/translator/TranslatorMetalDirect/Name.h"
15
#include "compiler/translator/TranslatorMetalDirect/ProgramPrelude.h"
16
#include "compiler/translator/tree_util/IntermTraverse.h"
17
18
using namespace sh;
19
20
////////////////////////////////////////////////////////////////////////////////
21
22
namespace
23
{
24
25
class ProgramPrelude : public TIntermTraverser
26
{
27
    using LineTag       = unsigned;
28
    using FuncEmitter   = void (*)(ProgramPrelude &, const TFunction &);
29
    using FuncToEmitter = std::map<Name, FuncEmitter>;
30
31
  public:
32
    ProgramPrelude(TInfoSinkBase &out, const ProgramPreludeConfig &ppc)
33
        : TIntermTraverser(true, false, false), mOut(out)
34
    {
35
        ALWAYS_INLINE();
36
37
        if (ppc.hasStructEq)
38
        {
39
            equalVector();
40
            equalMatrix();
41
        }
42
43
#if 1
44
        mOut << "#define ANGLE_tensor metal::array\n";
45
#else
46
        tensor();
47
#endif
48
    }
49
50
  private:
51
    bool emitGuard(LineTag lineTag)
52
    {
53
        if (mEmitted.find(lineTag) != mEmitted.end())
54
        {
55
            return false;
56
        }
57
        mEmitted.insert(lineTag);
58
        return true;
59
    }
60
61
    static FuncToEmitter BuildFuncToEmitter();
62
63
    void visitOperator(TOperator op,
64
                       const TFunction *func,
65
                       const TType *argType0,
66
                       const TType *argType1 = nullptr);
67
    void visitVariable(const Name &name, const TType &type);
68
    void visitVariable(const TVariable &var);
69
    void visitStructure(const TStructure &s);
70
71
    bool visitBinary(Visit, TIntermBinary *node) override;
72
    bool visitUnary(Visit, TIntermUnary *node) override;
73
    bool visitAggregate(Visit, TIntermAggregate *node) override;
74
    bool visitDeclaration(Visit, TIntermDeclaration *node) override;
75
    void visitSymbol(TIntermSymbol *node) override;
76
77
  private:
78
    void ALWAYS_INLINE();
79
80
    void include_metal_atomic();
81
    void include_metal_common();
82
    void include_metal_geometric();
83
    void include_metal_graphics();
84
    void include_metal_math();
85
    void include_metal_matrix();
86
    void include_metal_pack();
87
    void include_metal_relational();
88
89
    void enable_if();
90
    void scalar_of();
91
    void is_scalar();
92
    void is_vector();
93
    void is_matrix();
94
    void addressof();
95
    void distance();
96
    void length();
97
    void dot();
98
    void normalize();
99
    void faceforward();
100
    void reflect();
101
    void refract();
102
    void degrees();
103
    void radians();
104
    void mod();
105
    void postIncrementMatrix();
106
    void preIncrementMatrix();
107
    void postDecrementMatrix();
108
    void preDecrementMatrix();
109
    void negateMatrix();
110
    void matmulAssign();
111
    void atan();
112
    void addMatrixScalarAssign();
113
    void subMatrixScalarAssign();
114
    void addMatrixScalar();
115
    void subMatrixScalar();
116
    void divMatrixScalar();
117
    void divMatrixScalarFast();
118
    void divMatrixScalarAssign();
119
    void divMatrixScalarAssignFast();
120
    void tensor();
121
    void componentWiseDivide();
122
    void componentWiseDivideAssign();
123
    void componentWiseMultiply();
124
    void outerProduct();
125
    void inverse2();
126
    void inverse3();
127
    void inverse4();
128
    void equalVector();
129
    void equalMatrix();
130
    void notEqualVector();
131
    void notEqualStruct();
132
    void equalArray();
133
    void notEqualArray();
134
    void sign();
135
    void pack_half_2x16();
136
    void unpack_half_2x16();
137
    void vectorElemRef();
138
    void swizzleRef();
139
    void out();
140
    void inout();
141
    void flattenArray();
142
    void castVector();
143
    void castMatrix();
144
    void functionConstants();
145
    void gradient();
146
    void textureEnv();
147
    void texelFetch();
148
    void texelFetchOffset();
149
    void texture();
150
    void texture_generic_float2();
151
    void texture_generic_float2_float();
152
    void texture_generic_float3();
153
    void texture_generic_float3_float();
154
    void texture_depth2d_float3();
155
    void texture_depth2d_float3_float();
156
    void texture_depth2darray_float4();
157
    void texture_depth2darray_float4_float();
158
    void texture_depthcube_float4();
159
    void texture_depthcube_float4_float();
160
    void texture_texture2darray_float3();
161
    void texture_texture2darray_float3_float();
162
    void texture_texture2darray_float4();
163
    void texture_texture2darray_float4_float();
164
    void texture1DLod();
165
    void texture1DProj();
166
    void texture1DProjLod();
167
    void texture2D();
168
    void texture2DLod();
169
    void texture2DProj();
170
    void texture2DProjLod();
171
    void texture3DLod();
172
    void texture3DProj();
173
    void texture3DProjLod();
174
    void textureCube();
175
    void textureCubeLod();
176
    void textureCubeProj();
177
    void textureCubeProjLod();
178
    void textureGrad();
179
    void textureGrad_generic_floatN_floatN_floatN();
180
    void textureGrad_generic_float3_float2_float2();
181
    void textureGrad_generic_float4_float2_float2();
182
    void textureGrad_depth2d_float3_float2_float2();
183
    void textureGrad_depth2darray_float4_float2_float2();
184
    void textureGrad_depthcube_float4_float3_float3();
185
    void textureGrad_texturecube_float3_float3_float3();
186
    void textureGradOffset();
187
    void textureGradOffset_generic_floatN_floatN_floatN_intN();
188
    void textureGradOffset_generic_float3_float2_float2_int2();
189
    void textureGradOffset_generic_float4_float2_float2_int2();
190
    void textureGradOffset_depth2d_float3_float2_float2_int2();
191
    void textureGradOffset_depth2darray_float4_float2_float2_int2();
192
    void textureGradOffset_depthcube_float4_float3_float3_int3();
193
    void textureGradOffset_texturecube_float3_float3_float3_int3();
194
    void textureLod();
195
    void textureLod_generic_float2();
196
    void textureLod_generic_float3();
197
    void textureLod_depth2d_float3();
198
    void textureLod_texture2darray_float3();
199
    void textureLod_texture2darray_float4();
200
    void textureLodOffset();
201
    void textureOffset();
202
    void textureProj();
203
    void textureProjGrad();
204
    void textureProjGrad_generic_float3_float2_float2();
205
    void textureProjGrad_generic_float4_float2_float2();
206
    void textureProjGrad_depth2d_float4_float2_float2();
207
    void textureProjGrad_texture3d_float4_float3_float3();
208
    void textureProjGradOffset();
209
    void textureProjGradOffset_generic_float3_float2_float2_int2();
210
    void textureProjGradOffset_generic_float4_float2_float2_int2();
211
    void textureProjGradOffset_depth2d_float4_float2_float2_int2();
212
    void textureProjGradOffset_texture3d_float4_float3_float3_int3();
213
    void textureProjLod();
214
    void textureProjLod_generic_float3();
215
    void textureProjLod_generic_float4();
216
    void textureProjLod_depth2d_float4();
217
    void textureProjLod_texture3d_float4();
218
    void textureProjLodOffset();
219
    void textureProjOffset();
220
    void textureSize();
221
222
  private:
223
    TInfoSinkBase &mOut;
224
    std::unordered_set<LineTag> mEmitted;
225
    std::unordered_set<const TSymbol *> mHandled;
226
    const FuncToEmitter mFuncToEmitter = BuildFuncToEmitter();
227
};
228
229
}  // anonymous namespace
230
231
////////////////////////////////////////////////////////////////////////////////
232
233
#define PROGRAM_PRELUDE_INCLUDE(header)             \
234
    void ProgramPrelude::include_##header()         \
235
    {                                               \
236
        if (emitGuard(__LINE__))                    \
237
        {                                           \
238
            mOut << ("#include <" #header ">\n\n"); \
239
        }                                           \
240
    }
241
242
#define PROGRAM_PRELUDE_DECLARE(name, code, ...)                \
243
    void ProgramPrelude::name()                                 \
244
    {                                                           \
245
        ASSERT(code[0] == '\n');                                \
246
        if (emitGuard(__LINE__))                                \
247
        {                                                       \
248
            __VA_ARGS__; /* dependencies */                     \
249
            mOut << (static_cast<const char *>(code "\n") + 1); \
250
        }                                                       \
251
    }
252
253
////////////////////////////////////////////////////////////////////////////////
254
255
PROGRAM_PRELUDE_INCLUDE(metal_atomic)
256
PROGRAM_PRELUDE_INCLUDE(metal_common)
257
PROGRAM_PRELUDE_INCLUDE(metal_geometric)
258
PROGRAM_PRELUDE_INCLUDE(metal_graphics)
259
PROGRAM_PRELUDE_INCLUDE(metal_math)
260
PROGRAM_PRELUDE_INCLUDE(metal_matrix)
261
PROGRAM_PRELUDE_INCLUDE(metal_pack)
262
PROGRAM_PRELUDE_INCLUDE(metal_relational)
263
264
////////////////////////////////////////////////////////////////////////////////
265
266
PROGRAM_PRELUDE_DECLARE(ALWAYS_INLINE, R"(
267
#define ANGLE_ALWAYS_INLINE __attribute__((always_inline))
268
)")
269
270
PROGRAM_PRELUDE_DECLARE(enable_if, R"(
271
template <bool B, typename T = void>
272
struct ANGLE_enable_if {};
273
template <typename T>
274
struct ANGLE_enable_if<true, T>
275
{
276
    using type = T;
277
};
278
template <bool B>
279
using ANGLE_enable_if_t = typename ANGLE_enable_if<B>::type;
280
)")
281
282
PROGRAM_PRELUDE_DECLARE(scalar_of, R"(
283
template <typename T>
284
struct ANGLE_scalar_of
285
{
286
    using type = T;
287
};
288
template <typename T>
289
using ANGLE_scalar_of_t = typename ANGLE_scalar_of<T>::type;
290
)")
291
292
PROGRAM_PRELUDE_DECLARE(is_scalar, R"(
293
template <typename T>
294
struct ANGLE_is_scalar {};
295
#define ANGLE_DEFINE_SCALAR(scalar) \
296
    template <> struct ANGLE_is_scalar<scalar> { enum { value = true }; }
297
ANGLE_DEFINE_SCALAR(bool);
298
ANGLE_DEFINE_SCALAR(char);
299
ANGLE_DEFINE_SCALAR(short);
300
ANGLE_DEFINE_SCALAR(int);
301
ANGLE_DEFINE_SCALAR(long);
302
ANGLE_DEFINE_SCALAR(uchar);
303
ANGLE_DEFINE_SCALAR(ushort);
304
ANGLE_DEFINE_SCALAR(uint);
305
ANGLE_DEFINE_SCALAR(ulong);
306
ANGLE_DEFINE_SCALAR(half);
307
ANGLE_DEFINE_SCALAR(float);
308
)")
309
310
PROGRAM_PRELUDE_DECLARE(is_vector,
311
                        R"(
312
template <typename T>
313
struct ANGLE_is_vector
314
{
315
    enum { value = false };
316
};
317
#define ANGLE_DEFINE_VECTOR(scalar) \
318
    template <> struct ANGLE_is_vector<metal::scalar ## 2> { enum { value = true }; }; \
319
    template <> struct ANGLE_is_vector<metal::scalar ## 3> { enum { value = true }; }; \
320
    template <> struct ANGLE_is_vector<metal::scalar ## 4> { enum { value = true }; }; \
321
    template <> struct ANGLE_scalar_of<metal::scalar ## 2> { using type = scalar; }; \
322
    template <> struct ANGLE_scalar_of<metal::scalar ## 3> { using type = scalar; }; \
323
    template <> struct ANGLE_scalar_of<metal::scalar ## 4> { using type = scalar; }
324
ANGLE_DEFINE_VECTOR(bool);
325
ANGLE_DEFINE_VECTOR(char);
326
ANGLE_DEFINE_VECTOR(short);
327
ANGLE_DEFINE_VECTOR(int);
328
ANGLE_DEFINE_VECTOR(long);
329
ANGLE_DEFINE_VECTOR(uchar);
330
ANGLE_DEFINE_VECTOR(ushort);
331
ANGLE_DEFINE_VECTOR(uint);
332
ANGLE_DEFINE_VECTOR(ulong);
333
ANGLE_DEFINE_VECTOR(half);
334
ANGLE_DEFINE_VECTOR(float);
335
)",
336
                        scalar_of())
337
338
PROGRAM_PRELUDE_DECLARE(is_matrix,
339
                        R"(
340
template <typename T>
341
struct ANGLE_is_matrix
342
{
343
    enum { value = false };
344
};
345
#define ANGLE_DEFINE_MATRIX(scalar) \
346
    template <> struct ANGLE_is_matrix<metal::scalar ## 2x2> { enum { value = true }; }; \
347
    template <> struct ANGLE_is_matrix<metal::scalar ## 2x3> { enum { value = true }; }; \
348
    template <> struct ANGLE_is_matrix<metal::scalar ## 2x4> { enum { value = true }; }; \
349
    template <> struct ANGLE_is_matrix<metal::scalar ## 3x2> { enum { value = true }; }; \
350
    template <> struct ANGLE_is_matrix<metal::scalar ## 3x3> { enum { value = true }; }; \
351
    template <> struct ANGLE_is_matrix<metal::scalar ## 3x4> { enum { value = true }; }; \
352
    template <> struct ANGLE_is_matrix<metal::scalar ## 4x2> { enum { value = true }; }; \
353
    template <> struct ANGLE_is_matrix<metal::scalar ## 4x3> { enum { value = true }; }; \
354
    template <> struct ANGLE_is_matrix<metal::scalar ## 4x4> { enum { value = true }; }; \
355
    template <> struct ANGLE_scalar_of<metal::scalar ## 2x2> { using type = scalar; }; \
356
    template <> struct ANGLE_scalar_of<metal::scalar ## 2x3> { using type = scalar; }; \
357
    template <> struct ANGLE_scalar_of<metal::scalar ## 2x4> { using type = scalar; }; \
358
    template <> struct ANGLE_scalar_of<metal::scalar ## 3x2> { using type = scalar; }; \
359
    template <> struct ANGLE_scalar_of<metal::scalar ## 3x3> { using type = scalar; }; \
360
    template <> struct ANGLE_scalar_of<metal::scalar ## 3x4> { using type = scalar; }; \
361
    template <> struct ANGLE_scalar_of<metal::scalar ## 4x2> { using type = scalar; }; \
362
    template <> struct ANGLE_scalar_of<metal::scalar ## 4x3> { using type = scalar; }; \
363
    template <> struct ANGLE_scalar_of<metal::scalar ## 4x4> { using type = scalar; }
364
ANGLE_DEFINE_MATRIX(half);
365
ANGLE_DEFINE_MATRIX(float);
366
)",
367
                        scalar_of())
368
369
PROGRAM_PRELUDE_DECLARE(addressof,
370
                        R"(
371
template <typename T>
372
ANGLE_ALWAYS_INLINE thread T * ANGLE_addressof(thread T &ref)
373
{
374
    return &ref;
375
}
376
)")
377
378
PROGRAM_PRELUDE_DECLARE(distance,
379
                        R"(
380
template <typename T, typename Enable = void>
381
struct ANGLE_distance_impl
382
{
383
    static ANGLE_ALWAYS_INLINE ANGLE_scalar_of_t<T> exec(T x, T y)
384
    {
385
        return metal::distance(x, y);
386
    }
387
};
388
template <typename T>
389
struct ANGLE_distance_impl<T, ANGLE_enable_if_t<ANGLE_is_scalar<T>::value>>
390
{
391
    static ANGLE_ALWAYS_INLINE T exec(T x, T y)
392
    {
393
        return metal::abs(x - y);
394
    }
395
};
396
template <typename T>
397
ANGLE_ALWAYS_INLINE ANGLE_scalar_of_t<T> ANGLE_distance(T x, T y)
398
{
399
    return ANGLE_distance_impl<T>::exec(x, y);
400
};
401
)",
402
                        include_metal_geometric(),
403
                        include_metal_math(),
404
                        enable_if(),
405
                        is_scalar(),
406
                        is_vector(),
407
                        is_matrix())
408
409
PROGRAM_PRELUDE_DECLARE(length,
410
                        R"(
411
template <typename T, typename Enable = void>
412
struct ANGLE_length_impl
413
{
414
    static ANGLE_ALWAYS_INLINE ANGLE_scalar_of_t<T> exec(T x)
415
    {
416
        return metal::length(x);
417
    }
418
};
419
template <typename T>
420
struct ANGLE_length_impl<T, ANGLE_enable_if_t<ANGLE_is_scalar<T>::value>>
421
{
422
    static ANGLE_ALWAYS_INLINE T exec(T x)
423
    {
424
        return metal::abs(x);
425
    }
426
};
427
template <typename T>
428
ANGLE_ALWAYS_INLINE ANGLE_scalar_of_t<T> ANGLE_length(T x)
429
{
430
    return ANGLE_length_impl<T>::exec(x);
431
};
432
)",
433
                        include_metal_geometric(),
434
                        include_metal_math(),
435
                        enable_if(),
436
                        is_scalar(),
437
                        is_vector(),
438
                        is_matrix())
439
440
PROGRAM_PRELUDE_DECLARE(dot,
441
                        R"(
442
template <typename T, typename Enable = void>
443
struct ANGLE_dot_impl
444
{
445
    static ANGLE_ALWAYS_INLINE ANGLE_scalar_of_t<T> exec(T x, T y)
446
    {
447
        return metal::dot(x, y);
448
    }
449
};
450
template <typename T>
451
struct ANGLE_dot_impl<T, ANGLE_enable_if_t<ANGLE_is_scalar<T>::value>>
452
{
453
    static ANGLE_ALWAYS_INLINE T exec(T x, T y)
454
    {
455
        return x * y;
456
    }
457
};
458
template <typename T>
459
ANGLE_ALWAYS_INLINE ANGLE_scalar_of_t<T> ANGLE_dot(T x, T y)
460
{
461
    return ANGLE_dot_impl<T>::exec(x, y);
462
};
463
)",
464
                        include_metal_geometric(),
465
                        enable_if(),
466
                        is_scalar(),
467
                        is_vector(),
468
                        is_matrix())
469
470
PROGRAM_PRELUDE_DECLARE(normalize,
471
                        R"(
472
template <typename T, typename Enable = void>
473
struct ANGLE_normalize_impl
474
{
475
    static ANGLE_ALWAYS_INLINE T exec(T x)
476
    {
477
        return metal::normalize(x);
478
    }
479
};
480
template <typename T>
481
struct ANGLE_normalize_impl<T, ANGLE_enable_if_t<ANGLE_is_scalar<T>::value>>
482
{
483
    static ANGLE_ALWAYS_INLINE T exec(T x)
484
    {
485
        return ANGLE_sign(x);
486
    }
487
};
488
template <typename T>
489
ANGLE_ALWAYS_INLINE T ANGLE_normalize(T x)
490
{
491
    return ANGLE_normalize_impl<T>::exec(x);
492
};
493
)",
494
                        include_metal_common(),
495
                        include_metal_geometric(),
496
                        enable_if(),
497
                        is_scalar(),
498
                        is_vector(),
499
                        is_matrix(),
500
                        sign())
501
502
PROGRAM_PRELUDE_DECLARE(faceforward,
503
                        R"(
504
template <typename T, typename Enable = void>
505
struct ANGLE_faceforward_impl
506
{
507
    static ANGLE_ALWAYS_INLINE T exec(T n, T i, T nref)
508
    {
509
        return metal::faceforward(n, i, nref);
510
    }
511
};
512
template <typename T>
513
struct ANGLE_faceforward_impl<T, ANGLE_enable_if_t<ANGLE_is_scalar<T>::value>>
514
{
515
    static ANGLE_ALWAYS_INLINE T exec(T n, T i, T nref)
516
    {
517
        return ANGLE_dot(nref, i) < T(0) ? n : -n;
518
    }
519
};
520
template <typename T>
521
ANGLE_ALWAYS_INLINE T ANGLE_faceforward(T n, T i, T nref)
522
{
523
    return ANGLE_faceforward_impl<T>::exec(n, i, nref);
524
};
525
)",
526
                        include_metal_geometric(),
527
                        enable_if(),
528
                        is_scalar(),
529
                        is_vector(),
530
                        is_matrix(),
531
                        dot())
532
533
PROGRAM_PRELUDE_DECLARE(reflect,
534
                        R"(
535
template <typename T, typename Enable = void>
536
struct ANGLE_reflect_impl
537
{
538
    static ANGLE_ALWAYS_INLINE T exec(T i, T n)
539
    {
540
        return metal::reflect(i, n);
541
    }
542
};
543
template <typename T>
544
struct ANGLE_reflect_impl<T, ANGLE_enable_if_t<ANGLE_is_scalar<T>::value>>
545
{
546
    static ANGLE_ALWAYS_INLINE T exec(T i, T n)
547
    {
548
        return i - T(2) * ANGLE_dot(n, i) * n;
549
    }
550
};
551
template <typename T>
552
ANGLE_ALWAYS_INLINE T ANGLE_reflect(T i, T n)
553
{
554
    return ANGLE_reflect_impl<T>::exec(i, n);
555
};
556
)",
557
                        include_metal_geometric(),
558
                        enable_if(),
559
                        is_scalar(),
560
                        is_vector(),
561
                        is_matrix(),
562
                        dot())
563
564
PROGRAM_PRELUDE_DECLARE(refract,
565
                        R"(
566
template <typename T, typename Enable = void>
567
struct ANGLE_refract_impl
568
{
569
    static ANGLE_ALWAYS_INLINE T exec(T i, T n, ANGLE_scalar_of_t<T> eta)
570
    {
571
        return metal::refract(i, n, eta);
572
    }
573
};
574
template <typename T>
575
struct ANGLE_refract_impl<T, ANGLE_enable_if_t<ANGLE_is_scalar<T>::value>>
576
{
577
    static ANGLE_ALWAYS_INLINE T exec(T i, T n, T eta)
578
    {
579
        auto dotNI = n * i;
580
        auto k = T(1) - eta * eta * (T(1) - dotNI * dotNI);
581
        if (k < T(0))
582
        {
583
            return T(0);
584
        }
585
        else
586
        {
587
            return eta * i - (eta * dotNI + metal::sqrt(k)) * n;
588
        }
589
    }
590
};
591
template <typename T>
592
ANGLE_ALWAYS_INLINE T ANGLE_refract(T i, T n, ANGLE_scalar_of_t<T> eta)
593
{
594
    return ANGLE_refract_impl<T>::exec(i, n, eta);
595
};
596
)",
597
                        include_metal_math(),
598
                        include_metal_geometric(),
599
                        enable_if(),
600
                        is_scalar(),
601
                        is_vector(),
602
                        is_matrix())
603
604
PROGRAM_PRELUDE_DECLARE(sign,
605
                        R"(
606
template <typename T, typename Enable = void>
607
struct ANGLE_sign_impl
608
{
609
    static ANGLE_ALWAYS_INLINE T exec(T x)
610
    {
611
        return metal::sign(x);
612
    }
613
};
614
template <>
615
struct ANGLE_sign_impl<int>
616
{
617
    static ANGLE_ALWAYS_INLINE int exec(int x)
618
    {
619
        return (0 < x) - (x < 0);
620
    }
621
};
622
template <int N>
623
struct ANGLE_sign_impl<metal::vec<int, N>>
624
{
625
    static ANGLE_ALWAYS_INLINE metal::vec<int, N> exec(metal::vec<int, N> x)
626
    {
627
        metal::vec<int, N> s;
628
        for (int i = 0; i < N; ++i)
629
        {
630
            s[i] = ANGLE_sign_impl<int>::exec(x[i]);
631
        }
632
        return s;
633
    }
634
};
635
template <typename T>
636
ANGLE_ALWAYS_INLINE T ANGLE_sign(T x)
637
{
638
    return ANGLE_sign_impl<T>::exec(x);
639
};
640
)",
641
                        include_metal_common())
642
643
PROGRAM_PRELUDE_DECLARE(atan,
644
                        R"(
645
template <typename T>
646
ANGLE_ALWAYS_INLINE T ANGLE_atan(T yOverX)
647
{
648
    return metal::atan(yOverX);
649
}
650
template <typename T>
651
ANGLE_ALWAYS_INLINE T ANGLE_atan(T y, T x)
652
{
653
    return metal::atan2(y, x);
654
}
655
)",
656
                        include_metal_math())
657
658
PROGRAM_PRELUDE_DECLARE(degrees, R"(
659
template <typename T>
660
ANGLE_ALWAYS_INLINE T ANGLE_degrees(T x)
661
{
662
    return static_cast<T>(57.29577951308232) * x;
663
}
664
)")
665
666
PROGRAM_PRELUDE_DECLARE(radians, R"(
667
template <typename T>
668
ANGLE_ALWAYS_INLINE T ANGLE_radians(T x)
669
{
670
    return static_cast<T>(1.7453292519943295e-2) * x;
671
}
672
)")
673
674
PROGRAM_PRELUDE_DECLARE(mod,
675
                        R"(
676
template <typename X, typename Y>
677
ANGLE_ALWAYS_INLINE X ANGLE_mod(X x, Y y)
678
{
679
    return x - y * metal::floor(x / y);
680
}
681
)",
682
                        include_metal_math())
683
684
PROGRAM_PRELUDE_DECLARE(pack_half_2x16,
685
                        R"(
686
ANGLE_ALWAYS_INLINE uint ANGLE_pack_half_2x16(float2 v)
687
{
688
    return as_type<uint>(half2(v));
689
}
690
)", )
691
692
PROGRAM_PRELUDE_DECLARE(unpack_half_2x16,
693
                        R"(
694
ANGLE_ALWAYS_INLINE float2 ANGLE_unpack_half_2x16(uint x)
695
{
696
    return float2(as_type<half2>(x));
697
}
698
)", )
699
700
PROGRAM_PRELUDE_DECLARE(matmulAssign, R"(
701
template <typename T, int N>
702
ANGLE_ALWAYS_INLINE thread metal::matrix<T, N, N> &operator*=(thread metal::matrix<T, N, N> &a, metal::matrix<T, N, N> b)
703
{
704
    a = a * b;
705
    return a;
706
}
707
)")
708
709
PROGRAM_PRELUDE_DECLARE(postIncrementMatrix,
710
                        R"(
711
template <typename T, int Cols, int Rows>
712
ANGLE_ALWAYS_INLINE metal::matrix<T, Cols, Rows> operator++(thread metal::matrix<T, Cols, Rows> &a, int)
713
{
714
    auto b = a;
715
    a += T(1);
716
    return b;
717
}
718
)",
719
                        addMatrixScalarAssign())
720
721
PROGRAM_PRELUDE_DECLARE(preIncrementMatrix,
722
                        R"(
723
template <typename T, int Cols, int Rows>
724
ANGLE_ALWAYS_INLINE thread metal::matrix<T, Cols, Rows> &operator++(thread metal::matrix<T, Cols, Rows> &a)
725
{
726
    a += T(1);
727
    return a;
728
}
729
)",
730
                        addMatrixScalarAssign())
731
732
PROGRAM_PRELUDE_DECLARE(postDecrementMatrix,
733
                        R"(
734
template <typename T, int Cols, int Rows>
735
ANGLE_ALWAYS_INLINE metal::matrix<T, Cols, Rows> operator--(thread metal::matrix<T, Cols, Rows> &a, int)
736
{
737
    auto b = a;
738
    a -= T(1);
739
    return b;
740
}
741
)",
742
                        subMatrixScalarAssign())
743
744
PROGRAM_PRELUDE_DECLARE(preDecrementMatrix,
745
                        R"(
746
template <typename T, int Cols, int Rows>
747
ANGLE_ALWAYS_INLINE thread metal::matrix<T, Cols, Rows> &operator--(thread metal::matrix<T, Cols, Rows> &a)
748
{
749
    a -= T(1);
750
    return a;
751
}
752
)",
753
                        subMatrixScalarAssign())
754
755
PROGRAM_PRELUDE_DECLARE(negateMatrix,
756
                        R"(
757
template <typename T, int Cols, int Rows>
758
ANGLE_ALWAYS_INLINE metal::matrix<T, Cols, Rows> operator-(metal::matrix<T, Cols, Rows> m)
759
{
760
    for (size_t col = 0; col < Cols; ++col)
761
    {
762
        thread auto &mCol = m[col];
763
        mCol = -mCol;
764
    }
765
    return m;
766
}
767
)", )
768
769
PROGRAM_PRELUDE_DECLARE(addMatrixScalarAssign, R"(
770
template <typename T, int Cols, int Rows>
771
ANGLE_ALWAYS_INLINE thread metal::matrix<T, Cols, Rows> &operator+=(thread metal::matrix<T, Cols, Rows> &m, T x)
772
{
773
    for (size_t col = 0; col < Cols; ++col)
774
    {
775
        m[col] += x;
776
    }
777
    return m;
778
}
779
)")
780
781
PROGRAM_PRELUDE_DECLARE(addMatrixScalar,
782
                        R"(
783
template <typename T, int Cols, int Rows>
784
ANGLE_ALWAYS_INLINE metal::matrix<T, Cols, Rows> operator+(metal::matrix<T, Cols, Rows> m, T x)
785
{
786
    m += x;
787
    return m;
788
}
789
)",
790
                        addMatrixScalarAssign())
791
792
PROGRAM_PRELUDE_DECLARE(subMatrixScalarAssign,
793
                        R"(
794
template <typename T, int Cols, int Rows>
795
ANGLE_ALWAYS_INLINE thread metal::matrix<T, Cols, Rows> &operator-=(thread metal::matrix<T, Cols, Rows> &m, T x)
796
{
797
    for (size_t col = 0; col < Cols; ++col)
798
    {
799
        m[col] -= x;
800
    }
801
    return m;
802
}
803
)", )
804
805
PROGRAM_PRELUDE_DECLARE(subMatrixScalar,
806
                        R"(
807
template <typename T, int Cols, int Rows>
808
ANGLE_ALWAYS_INLINE metal::matrix<T, Cols, Rows> operator-(metal::matrix<T, Cols, Rows> m, T x)
809
{
810
    m -= x;
811
    return m;
812
}
813
)",
814
                        subMatrixScalarAssign())
815
816
PROGRAM_PRELUDE_DECLARE(divMatrixScalarAssignFast,
817
                        R"(
818
template <typename T, int Cols, int Rows>
819
ANGLE_ALWAYS_INLINE thread metal::matrix<T, Cols, Rows> &operator/=(thread metal::matrix<T, Cols, Rows> &m, T x)
820
{
821
    x = T(1) / x;
822
    for (size_t col = 0; col < Cols; ++col)
823
    {
824
        m[col] *= x;
825
    }
826
    return m;
827
}
828
)", )
829
830
PROGRAM_PRELUDE_DECLARE(divMatrixScalarAssign,
831
                        R"(
832
template <typename T, int Cols, int Rows>
833
ANGLE_ALWAYS_INLINE thread metal::matrix<T, Cols, Rows> &operator/=(thread metal::matrix<T, Cols, Rows> &m, T x)
834
{
835
    for (size_t col = 0; col < Cols; ++col)
836
    {
837
        m[col] /= x;
838
    }
839
    return m;
840
}
841
)", )
842
843
PROGRAM_PRELUDE_DECLARE(divMatrixScalarFast,
844
                        R"(
845
#if __METAL_VERSION__ <= 220
846
template <typename T, int Cols, int Rows>
847
ANGLE_ALWAYS_INLINE metal::matrix<T, Cols, Rows> operator/(metal::matrix<T, Cols, Rows> m, T x)
848
{
849
    m /= x;
850
    return m;
851
}
852
#endif
853
)",
854
                        divMatrixScalarAssignFast())
855
856
PROGRAM_PRELUDE_DECLARE(divMatrixScalar,
857
                        R"(
858
#if __METAL_VERSION__ <= 220
859
template <typename T, int Cols, int Rows>
860
ANGLE_ALWAYS_INLINE metal::matrix<T, Cols, Rows> operator/(metal::matrix<T, Cols, Rows> m, T x)
861
{
862
    m /= x;
863
    return m;
864
}
865
#endif
866
)",
867
                        divMatrixScalarAssign())
868
869
PROGRAM_PRELUDE_DECLARE(componentWiseDivide, R"(
870
template <typename T, int Cols, int Rows>
871
ANGLE_ALWAYS_INLINE metal::matrix<T, Cols, Rows> operator/(metal::matrix<T, Cols, Rows> a, metal::matrix<T, Cols, Rows> b)
872
{
873
    for (size_t col = 0; col < Cols; ++col)
874
    {
875
        a[col] /= b[col];
876
    }
877
    return a;
878
}
879
)")
880
881
PROGRAM_PRELUDE_DECLARE(componentWiseDivideAssign,
882
                        R"(
883
template <typename T, int Cols, int Rows>
884
ANGLE_ALWAYS_INLINE thread metal::matrix<T, Cols, Rows> &operator/=(thread metal::matrix<T, Cols, Rows> &a, metal::matrix<T, Cols, Rows> b)
885
{
886
    a = a / b;
887
    return a;
888
}
889
)",
890
                        componentWiseDivide())
891
892
PROGRAM_PRELUDE_DECLARE(componentWiseMultiply, R"(
893
template <typename T, int Cols, int Rows>
894
ANGLE_ALWAYS_INLINE metal::matrix<T, Cols, Rows> ANGLE_componentWiseMultiply(metal::matrix<T, Cols, Rows> a, metal::matrix<T, Cols, Rows> b)
895
{
896
    for (size_t col = 0; col < Cols; ++col)
897
    {
898
        a[col] *= b[col];
899
    }
900
    return a;
901
}
902
)")
903
904
PROGRAM_PRELUDE_DECLARE(outerProduct, R"(
905
template <typename T, int M, int N>
906
ANGLE_ALWAYS_INLINE metal::matrix<T, N, M> ANGLE_outerProduct(metal::vec<T, M> u, metal::vec<T, N> v)
907
{
908
    metal::matrix<T, N, M> o;
909
    for (size_t n = 0; n < N; ++n)
910
    {
911
        o[n] = u * v[n];
912
    }
913
    return o;
914
}
915
)")
916
917
PROGRAM_PRELUDE_DECLARE(inverse2, R"(
918
template <typename T>
919
ANGLE_ALWAYS_INLINE metal::matrix<T, 2, 2> ANGLE_inverse(metal::matrix<T, 2, 2> m)
920
{
921
    metal::matrix<T, 2, 2> adj;
922
    adj[0][0] =  m[1][1];
923
    adj[0][1] = -m[0][1];
924
    adj[1][0] = -m[1][0];
925
    adj[1][1] =  m[0][0];
926
    T det = (adj[0][0] * m[0][0]) + (adj[0][1] * m[1][0]);
927
    return adj * (T(1) / det);
928
}
929
)")
930
931
PROGRAM_PRELUDE_DECLARE(inverse3, R"(
932
template <typename T>
933
ANGLE_ALWAYS_INLINE metal::matrix<T, 3, 3> ANGLE_inverse(metal::matrix<T, 3, 3> m)
934
{
935
    T a = m[1][1] * m[2][2] - m[2][1] * m[1][2];
936
    T b = m[1][0] * m[2][2];
937
    T c = m[1][2] * m[2][0];
938
    T d = m[1][0] * m[2][1];
939
    T det = m[0][0] * (a) -
940
            m[0][1] * (b - c) +
941
            m[0][2] * (d - m[1][1] * m[2][0]);
942
    det = T(1) / det;
943
    metal::matrix<T, 3, 3> minv;
944
    minv[0][0] = (a) * det;
945
    minv[0][1] = (m[0][2] * m[2][1] - m[0][1] * m[2][2]) * det;
946
    minv[0][2] = (m[0][1] * m[1][2] - m[0][2] * m[1][1]) * det;
947
    minv[1][0] = (c - b) * det;
948
    minv[1][1] = (m[0][0] * m[2][2] - m[0][2] * m[2][0]) * det;
949
    minv[1][2] = (m[1][0] * m[0][2] - m[0][0] * m[1][2]) * det;
950
    minv[2][0] = (d - m[2][0] * m[1][1]) * det;
951
    minv[2][1] = (m[2][0] * m[0][1] - m[0][0] * m[2][1]) * det;
952
    minv[2][2] = (m[0][0] * m[1][1] - m[1][0] * m[0][1]) * det;
953
    return minv;
954
}
955
)")
956
957
PROGRAM_PRELUDE_DECLARE(inverse4, R"(
958
template <typename T>
959
ANGLE_ALWAYS_INLINE metal::matrix<T, 4, 4> ANGLE_inverse(metal::matrix<T, 4, 4> m)
960
{
961
    T A2323 = m[2][2] * m[3][3] - m[2][3] * m[3][2];
962
    T A1323 = m[2][1] * m[3][3] - m[2][3] * m[3][1];
963
    T A1223 = m[2][1] * m[3][2] - m[2][2] * m[3][1];
964
    T A0323 = m[2][0] * m[3][3] - m[2][3] * m[3][0];
965
    T A0223 = m[2][0] * m[3][2] - m[2][2] * m[3][0];
966
    T A0123 = m[2][0] * m[3][1] - m[2][1] * m[3][0];
967
    T A2313 = m[1][2] * m[3][3] - m[1][3] * m[3][2];
968
    T A1313 = m[1][1] * m[3][3] - m[1][3] * m[3][1];
969
    T A1213 = m[1][1] * m[3][2] - m[1][2] * m[3][1];
970
    T A2312 = m[1][2] * m[2][3] - m[1][3] * m[2][2];
971
    T A1312 = m[1][1] * m[2][3] - m[1][3] * m[2][1];
972
    T A1212 = m[1][1] * m[2][2] - m[1][2] * m[2][1];
973
    T A0313 = m[1][0] * m[3][3] - m[1][3] * m[3][0];
974
    T A0213 = m[1][0] * m[3][2] - m[1][2] * m[3][0];
975
    T A0312 = m[1][0] * m[2][3] - m[1][3] * m[2][0];
976
    T A0212 = m[1][0] * m[2][2] - m[1][2] * m[2][0];
977
    T A0113 = m[1][0] * m[3][1] - m[1][1] * m[3][0];
978
    T A0112 = m[1][0] * m[2][1] - m[1][1] * m[2][0];
979
    T a = m[1][1] * A2323 - m[1][2] * A1323 + m[1][3] * A1223;
980
    T b = m[1][0] * A2323 - m[1][2] * A0323 + m[1][3] * A0223;
981
    T c = m[1][0] * A1323 - m[1][1] * A0323 + m[1][3] * A0123;
982
    T d = m[1][0] * A1223 - m[1][1] * A0223 + m[1][2] * A0123;
983
    T det = m[0][0] * ( a )
984
          - m[0][1] * ( b )
985
          + m[0][2] * ( c )
986
          - m[0][3] * ( d );
987
    det = T(1) / det;
988
    metal::matrix<T, 4, 4> im;
989
    im[0][0] = det *   ( a );
990
    im[0][1] = det * - ( m[0][1] * A2323 - m[0][2] * A1323 + m[0][3] * A1223 );
991
    im[0][2] = det *   ( m[0][1] * A2313 - m[0][2] * A1313 + m[0][3] * A1213 );
992
    im[0][3] = det * - ( m[0][1] * A2312 - m[0][2] * A1312 + m[0][3] * A1212 );
993
    im[1][0] = det * - ( b );
994
    im[1][1] = det *   ( m[0][0] * A2323 - m[0][2] * A0323 + m[0][3] * A0223 );
995
    im[1][2] = det * - ( m[0][0] * A2313 - m[0][2] * A0313 + m[0][3] * A0213 );
996
    im[1][3] = det *   ( m[0][0] * A2312 - m[0][2] * A0312 + m[0][3] * A0212 );
997
    im[2][0] = det *   ( c );
998
    im[2][1] = det * - ( m[0][0] * A1323 - m[0][1] * A0323 + m[0][3] * A0123 );
999
    im[2][2] = det *   ( m[0][0] * A1313 - m[0][1] * A0313 + m[0][3] * A0113 );
1000
    im[2][3] = det * - ( m[0][0] * A1312 - m[0][1] * A0312 + m[0][3] * A0112 );
1001
    im[3][0] = det * - ( d );
1002
    im[3][1] = det *   ( m[0][0] * A1223 - m[0][1] * A0223 + m[0][2] * A0123 );
1003
    im[3][2] = det * - ( m[0][0] * A1213 - m[0][1] * A0213 + m[0][2] * A0113 );
1004
    im[3][3] = det *   ( m[0][0] * A1212 - m[0][1] * A0212 + m[0][2] * A0112 );
1005
    return im;
1006
}
1007
)")
1008
1009
PROGRAM_PRELUDE_DECLARE(equalArray,
1010
                        R"(
1011
template <typename T, size_t N>
1012
ANGLE_ALWAYS_INLINE bool ANGLE_equal(metal::array<T, N> u, metal::array<T, N> v)
1013
{
1014
    for(size_t i = 0; i < N; i++)
1015
        if (u[i] != v[i]) return false;
1016
    return true;
1017
}
1018
)")
1019
1020
PROGRAM_PRELUDE_DECLARE(notEqualArray,
1021
                        R"(
1022
template <typename T, size_t N>
1023
ANGLE_ALWAYS_INLINE bool ANGLE_notEqual(metal::array<T, N> u, metal::array<T, N> v)
1024
{
1025
    return !ANGLE_equal(u,v);
1026
}
1027
)",
1028
                        equalArray())
1029
1030
PROGRAM_PRELUDE_DECLARE(equalVector,
1031
                        R"(
1032
template <typename T, int N>
1033
ANGLE_ALWAYS_INLINE bool ANGLE_equal(metal::vec<T, N> u, metal::vec<T, N> v)
1034
{
1035
    return metal::all(u == v);
1036
}
1037
)",
1038
                        include_metal_math())
1039
1040
PROGRAM_PRELUDE_DECLARE(equalMatrix,
1041
                        R"(
1042
template <typename T, int C, int R>
1043
ANGLE_ALWAYS_INLINE bool ANGLE_equal(metal::matrix<T, C, R> a, metal::matrix<T, C, R> b)
1044
{
1045
    for (int c = 0; c < C; ++c)
1046
    {
1047
        if (!ANGLE_equal(a[c], b[c]))
1048
        {
1049
            return false;
1050
        }
1051
    }
1052
    return true;
1053
}
1054
)",
1055
                        equalVector())
1056
1057
PROGRAM_PRELUDE_DECLARE(notEqualVector,
1058
                        R"(
1059
template <typename T, int N>
1060
ANGLE_ALWAYS_INLINE bool ANGLE_notEqual(metal::vec<T, N> u, metal::vec<T, N> v)
1061
{
1062
    return !ANGLE_equal(u, v);
1063
}
1064
)",
1065
                        equalVector())
1066
1067
PROGRAM_PRELUDE_DECLARE(notEqualStruct,
1068
                        R"(
1069
template <typename T>
1070
ANGLE_ALWAYS_INLINE bool ANGLE_notEqualStruct(thread const T &a, thread const T &b)
1071
{
1072
    return !ANGLE_equal(a, b);
1073
}
1074
)",
1075
                        equalVector(),
1076
                        equalMatrix())
1077
1078
PROGRAM_PRELUDE_DECLARE(vectorElemRef, R"(
1079
template <typename T, int N>
1080
struct ANGLE_VectorElemRef
1081
{
1082
    thread metal::vec<T, N> &mVec;
1083
    T mRef;
1084
    const int mIndex;
1085
    ~ANGLE_VectorElemRef() { mVec[mIndex] = mRef; }
1086
    ANGLE_VectorElemRef(thread metal::vec<T, N> &vec, int index)
1087
        : mVec(vec), mRef(vec[index]), mIndex(index)
1088
    {}
1089
    operator thread T &() { return mRef; }
1090
};
1091
template <typename T, int N>
1092
ANGLE_ALWAYS_INLINE ANGLE_VectorElemRef<T, N> ANGLE_elem_ref(thread metal::vec<T, N> &vec, int index)
1093
{
1094
    return ANGLE_VectorElemRef<T, N>(vec, index);
1095
}
1096
)")
1097
1098
PROGRAM_PRELUDE_DECLARE(swizzleRef,
1099
                        R"(
1100
template <typename T, int VN, int SN>
1101
struct ANGLE_SwizzleRef
1102
{
1103
    thread metal::vec<T, VN> &mVec;
1104
    metal::vec<T, SN> mRef;
1105
    int mIndices[SN];
1106
    ~ANGLE_SwizzleRef()
1107
    {
1108
        for (int i = 0; i < SN; ++i)
1109
        {
1110
            const int j = mIndices[i];
1111
            mVec[j] = mRef[i];
1112
        }
1113
    }
1114
    ANGLE_SwizzleRef(thread metal::vec<T, N> &vec, thread const int *indices)
1115
        : mVec(vec)
1116
    {
1117
        for (int i = 0; i < SN; ++i)
1118
        {
1119
            const int j = indices[i];
1120
            mIndices[i] = j;
1121
            mRef[i] = mVec[j];
1122
        }
1123
    }
1124
    operator thread metal::vec<T, SN> &() { return mRef; }
1125
};
1126
template <typename T, int N>
1127
ANGLE_ALWAYS_INLINE ANGLE_VectorElemRef<T, N> ANGLE_swizzle_ref(thread metal::vec<T, N> &vec, int i0)
1128
{
1129
    return ANGLE_VectorElemRef<T, N>(vec, index);
1130
}
1131
template <typename T, int N>
1132
ANGLE_ALWAYS_INLINE ANGLE_SwizzleRef<T, N, 2> ANGLE_swizzle_ref(thread metal::vec<T, N> &vec, int i0, int i1)
1133
{
1134
    const int is[] = { i0, i1 };
1135
    return ANGLE_SwizzleRef<T, N, 2>(vec, is);
1136
}
1137
template <typename T, int N>
1138
ANGLE_ALWAYS_INLINE ANGLE_SwizzleRef<T, N, 3> ANGLE_swizzle_ref(thread metal::vec<T, N> &vec, int i0, int i1, int i2)
1139
{
1140
    const int is[] = { i0, i1, i2 };
1141
    return ANGLE_SwizzleRef<T, N, 3>(vec, is);
1142
}
1143
template <typename T, int N>
1144
ANGLE_ALWAYS_INLINE ANGLE_SwizzleRef<T, N, 4> ANGLE_swizzle_ref(thread metal::vec<T, N> &vec, int i0, int i1, int i2, int i3)
1145
{
1146
    const int is[] = { i0, i1, i2, i3 };
1147
    return ANGLE_SwizzleRef<T, N, 4>(vec, is);
1148
}
1149
)",
1150
                        vectorElemRef())
1151
1152
PROGRAM_PRELUDE_DECLARE(out, R"(
1153
template <typename T>
1154
struct ANGLE_Out
1155
{
1156
    T mTemp;
1157
    thread T &mDest;
1158
    ~ANGLE_Out() { mDest = mTemp; }
1159
    ANGLE_Out(thread T &dest)
1160
        : mDest(dest)
1161
    {}
1162
    operator thread T &() { return mTemp; }
1163
};
1164
template <typename T>
1165
ANGLE_ALWAYS_INLINE ANGLE_Out<T> ANGLE_out(thread T &dest)
1166
{
1167
    return ANGLE_Out<T>(dest);
1168
}
1169
)")
1170
1171
PROGRAM_PRELUDE_DECLARE(inout, R"(
1172
template <typename T>
1173
struct ANGLE_InOut
1174
{
1175
    T mTemp;
1176
    thread T &mDest;
1177
    ~ANGLE_InOut() { mDest = mTemp; }
1178
    ANGLE_InOut(thread T &dest)
1179
        : mTemp(dest), mDest(dest)
1180
    {}
1181
    operator thread T &() { return mTemp; }
1182
};
1183
template <typename T>
1184
ANGLE_ALWAYS_INLINE ANGLE_InOut<T> ANGLE_inout(thread T &dest)
1185
{
1186
    return ANGLE_InOut<T>(dest);
1187
}
1188
)")
1189
1190
PROGRAM_PRELUDE_DECLARE(flattenArray, R"(
1191
template <typename T>
1192
struct ANGLE_flatten_impl
1193
{
1194
    static ANGLE_ALWAYS_INLINE thread T *exec(thread T &x)
1195
    {
1196
        return &x;
1197
    }
1198
};
1199
template <typename T, size_t N>
1200
struct ANGLE_flatten_impl<metal::array<T, N>>
1201
{
1202
    static ANGLE_ALWAYS_INLINE auto exec(thread metal::array<T, N> &arr) -> T
1203
    {
1204
        return ANGLE_flatten_impl<T>::exec(arr[0]);
1205
    }
1206
};
1207
template <typename T, size_t N>
1208
ANGLE_ALWAYS_INLINE auto ANGLE_flatten(thread metal::array<T, N> &arr) -> T
1209
{
1210
    return ANGLE_flatten_impl<T>::exec(arr[0]);
1211
}
1212
)")
1213
1214
PROGRAM_PRELUDE_DECLARE(castVector, R"(
1215
template <typename T, int N1, int N2>
1216
struct ANGLE_castVector {};
1217
template <typename T, int N>
1218
struct ANGLE_castVector<T, N, N>
1219
{
1220
    static ANGLE_ALWAYS_INLINE metal::vec<T, N> exec(thread metal::vec<T, N> const &v)
1221
    {
1222
        return v;
1223
    }
1224
};
1225
template <typename T>
1226
struct ANGLE_castVector<T, 2, 3>
1227
{
1228
    static ANGLE_ALWAYS_INLINE metal::vec<T, 2> exec(thread metal::vec<T, 3> const &v)
1229
    {
1230
        return v.xy;
1231
    }
1232
};
1233
template <typename T>
1234
struct ANGLE_castVector<T, 2, 4>
1235
{
1236
    static ANGLE_ALWAYS_INLINE metal::vec<T, 2> exec(thread metal::vec<T, 4> const &v)
1237
    {
1238
        return v.xy;
1239
    }
1240
};
1241
template <typename T>
1242
struct ANGLE_castVector<T, 3, 4>
1243
{
1244
    static ANGLE_ALWAYS_INLINE metal::vec<T, 3> exec(thread metal::vec<T, 4> const &v)
1245
    {
1246
        return as_type<metal::vec<T, 3>>(v);
1247
    }
1248
};
1249
template <int N1, int N2, typename T>
1250
ANGLE_ALWAYS_INLINE metal::vec<T, N1> ANGLE_cast(thread metal::vec<T, N2> const &v)
1251
{
1252
    return ANGLE_castVector<T, N1, N2>::exec(v);
1253
}
1254
)")
1255
1256
PROGRAM_PRELUDE_DECLARE(castMatrix,
1257
                        R"(
1258
template <typename T, int C1, int R1, int C2, int R2, typename Enable = void>
1259
struct ANGLE_castMatrix
1260
{
1261
    static ANGLE_ALWAYS_INLINE metal::matrix<T, C1, R1> exec(thread metal::matrix<T, C2, R2> const &m2)
1262
    {
1263
        metal::matrix<T, C1, R1> m1;
1264
        const int MinC = C1 <= C2 ? C1 : C2;
1265
        const int MinR = R1 <= R2 ? R1 : R2;
1266
        for (int c = 0; c < MinC; ++c)
1267
        {
1268
            for (int r = 0; r < MinR; ++r)
1269
            {
1270
                m1[c][r] = m2[c][r];
1271
            }
1272
            for (int r = R2; r < R1; ++r)
1273
            {
1274
                m1[c][r] = c == r ? T(1) : T(0);
1275
            }
1276
        }
1277
        for (int c = C2; c < C1; ++c)
1278
        {
1279
            for (int r = 0; r < R1; ++r)
1280
            {
1281
                m1[c][r] = c == r ? T(1) : T(0);
1282
            }
1283
        }
1284
        return m1;
1285
    }
1286
};
1287
template <typename T, int C1, int R1, int C2, int R2>
1288
struct ANGLE_castMatrix<T, C1, R1, C2, R2, ANGLE_enable_if_t<(C1 <= C2 && R1 <= R2)>>
1289
{
1290
    static ANGLE_ALWAYS_INLINE metal::matrix<T, C1, R1> exec(thread metal::matrix<T, C2, R2> const &m2)
1291
    {
1292
        metal::matrix<T, C1, R1> m1;
1293
        for (size_t c = 0; c < C1; ++c)
1294
        {
1295
            m1[c] = ANGLE_cast<R1>(m2[c]);
1296
        }
1297
        return m1;
1298
    }
1299
};
1300
template <int C1, int R1, int C2, int R2, typename T>
1301
ANGLE_ALWAYS_INLINE metal::matrix<T, C1, R1> ANGLE_cast(thread metal::matrix<T, C2, R2> const &m)
1302
{
1303
    return ANGLE_castMatrix<T, C1, R1, C2, R2>::exec(m);
1304
};
1305
)",
1306
                        enable_if(),
1307
                        castVector())
1308
1309
PROGRAM_PRELUDE_DECLARE(tensor, R"(
1310
template <typename T, size_t... DS>
1311
struct ANGLE_tensor_traits;
1312
template <typename T, size_t D>
1313
struct ANGLE_tensor_traits<T, D>
1314
{
1315
    enum : size_t { outer_dim = D };
1316
    using inner_type = T;
1317
    using outer_type = inner_type[D];
1318
};
1319
template <typename T, size_t D, size_t... DS>
1320
struct ANGLE_tensor_traits<T, D, DS...>
1321
{
1322
    enum : size_t { outer_dim = D };
1323
    using inner_type = typename ANGLE_tensor_traits<T, DS...>::outer_type;
1324
    using outer_type = inner_type[D];
1325
};
1326
template <size_t D, typename value_type_, typename inner_type_>
1327
struct ANGLE_tensor_impl
1328
{
1329
    enum : size_t { outer_dim = D };
1330
    using value_type = value_type_;
1331
    using inner_type = inner_type_;
1332
    using outer_type = inner_type[D];
1333
    outer_type _data;
1334
    ANGLE_ALWAYS_INLINE size_t size() const { return outer_dim; }
1335
    ANGLE_ALWAYS_INLINE inner_type &operator[](size_t i) { return _data[i]; }
1336
    ANGLE_ALWAYS_INLINE const inner_type &operator[](size_t i) const { return _data[i]; }
1337
};
1338
template <typename T, size_t... DS>
1339
using ANGLE_tensor = ANGLE_tensor_impl<
1340
    ANGLE_tensor_traits<T, DS...>::outer_dim,
1341
    T,
1342
    typename ANGLE_tensor_traits<T, DS...>::inner_type>;
1343
)")
1344
1345
PROGRAM_PRELUDE_DECLARE(gradient,
1346
                        R"(
1347
template <int N>
1348
struct ANGLE_gradient_traits;
1349
template <>
1350
struct ANGLE_gradient_traits<2> { using type = metal::gradient2d; };
1351
template <>
1352
struct ANGLE_gradient_traits<3> { using type = metal::gradient3d; };
1353
1354
template <int N>
1355
using ANGLE_gradient = typename ANGLE_gradient_traits<N>::type;
1356
)")
1357
1358
PROGRAM_PRELUDE_DECLARE(textureEnv,
1359
                        R"(
1360
template <typename T>
1361
struct ANGLE_TextureEnv
1362
{
1363
    thread T *texture;
1364
    thread metal::sampler *sampler;
1365
};
1366
)")
1367
1368
PROGRAM_PRELUDE_DECLARE(functionConstants,
1369
                        R"(
1370
#define ANGLE_SAMPLE_COMPARE_GRADIENT_INDEX 0
1371
#define ANGLE_SAMPLE_COMPARE_LOD_INDEX      1
1372
#define ANGLE_RASTERIZATION_DISCARD_INDEX   2
1373
1374
constant bool ANGLE_UseSampleCompareGradient [[function_constant(ANGLE_SAMPLE_COMPARE_GRADIENT_INDEX)]];
1375
constant bool ANGLE_UseSampleCompareLod      [[function_constant(ANGLE_SAMPLE_COMPARE_LOD_INDEX)]];
1376
constant bool ANGLE_RasterizationDiscard     [[function_constant(ANGLE_RASTERIZATION_DISCARD_INDEX)]];
1377
)")
1378
1379
PROGRAM_PRELUDE_DECLARE(texelFetch,
1380
                        R"(
1381
#define ANGLE_texelFetch(env, ...) ANGLE_texelFetch_impl(*env.texture, __VA_ARGS__)
1382
1383
template <typename Texture>
1384
ANGLE_ALWAYS_INLINE auto ANGLE_texelFetch_impl(
1385
    thread Texture &texture,
1386
    thread metal::int2 const &coord,
1387
    uint level)
1388
{
1389
    return texture.read(uint2(coord), level);
1390
}
1391
1392
template <typename Texture>
1393
ANGLE_ALWAYS_INLINE auto ANGLE_texelFetch_impl(
1394
    thread Texture &texture,
1395
    thread metal::int3 const &coord,
1396
    uint level)
1397
{
1398
    return texture.read(uint3(coord), level);
1399
}
1400
1401
template <typename T>
1402
ANGLE_ALWAYS_INLINE auto ANGLE_texelFetch_impl(
1403
    thread metal::texture2d_array<T> &texture,
1404
    thread metal::int3 const &coord,
1405
    uint level)
1406
{
1407
    return texture.read(uint2(coord.xy), uint(coord.z), level);
1408
}
1409
)",
1410
                        textureEnv())
1411
1412
PROGRAM_PRELUDE_DECLARE(texelFetchOffset,
1413
                        R"(
1414
#define ANGLE_texelFetchOffset(env, ...) ANGLE_texelFetchOffset_impl(*env.texture, __VA_ARGS__)
1415
1416
template <typename Texture>
1417
ANGLE_ALWAYS_INLINE auto ANGLE_texelFetchOffset_impl(
1418
    thread Texture &texture,
1419
    thread metal::int2 const &coord,
1420
    uint level,
1421
    thread metal::int2 const &offset)
1422
{
1423
    return texture.read(uint2(coord + offset), level);
1424
}
1425
1426
template <typename Texture>
1427
ANGLE_ALWAYS_INLINE auto ANGLE_texelFetchOffset_impl(
1428
    thread Texture &texture,
1429
    thread metal::int3 const &coord,
1430
    uint level,
1431
    thread metal::int3 const &offset)
1432
{
1433
    return texture.read(uint3(coord + offset), level);
1434
}
1435
1436
template <typename T>
1437
ANGLE_ALWAYS_INLINE auto ANGLE_texelFetchOffset_impl(
1438
    thread metal::texture2d_array<T> &texture,
1439
    thread metal::int3 const &coord,
1440
    uint level,
1441
    thread metal::int2 const &offset)
1442
{
1443
    return texture.read(uint2(coord.xy + offset), uint(coord.z), level);
1444
}
1445
)",
1446
                        textureEnv())
1447
1448
PROGRAM_PRELUDE_DECLARE(texture,
1449
                        R"(
1450
#define ANGLE_texture(env, ...) ANGLE_texture_impl(*env.texture, *env.sampler, __VA_ARGS__)
1451
)",
1452
                        textureEnv())
1453
1454
PROGRAM_PRELUDE_DECLARE(texture_generic_float2,
1455
                        R"(
1456
template <typename Texture>
1457
ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
1458
    thread Texture &texture,
1459
    thread metal::sampler const &sampler,
1460
    thread metal::float2 const &coord)
1461
{
1462
    return texture.sample(sampler, coord);
1463
}
1464
)",
1465
                        texture())
1466
1467
PROGRAM_PRELUDE_DECLARE(texture_generic_float2_float,
1468
                        R"(
1469
template <typename Texture>
1470
ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
1471
    thread Texture &texture,
1472
    thread metal::sampler const &sampler,
1473
    thread metal::float2 const &coord,
1474
    float bias)
1475
{
1476
    return texture.sample(sampler, coord, metal::bias(bias));
1477
}
1478
)",
1479
                        texture())
1480
1481
PROGRAM_PRELUDE_DECLARE(texture_generic_float3,
1482
                        R"(
1483
template <typename Texture>
1484
ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
1485
    thread Texture &texture,
1486
    thread metal::sampler const &sampler,
1487
    thread metal::float3 const &coord)
1488
{
1489
    return texture.sample(sampler, coord);
1490
}
1491
)",
1492
                        texture())
1493
1494
PROGRAM_PRELUDE_DECLARE(texture_generic_float3_float,
1495
                        R"(
1496
template <typename Texture>
1497
ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
1498
    thread Texture &texture,
1499
    thread metal::sampler const &sampler,
1500
    thread metal::float3 const &coord,
1501
    float bias)
1502
{
1503
    return texture.sample(sampler, coord, metal::bias(bias));
1504
}
1505
)",
1506
                        texture())
1507
1508
PROGRAM_PRELUDE_DECLARE(texture_depth2d_float3,
1509
                        R"(
1510
template <typename T>
1511
ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
1512
    thread metal::depth2d<T> &texture,
1513
    thread metal::sampler const &sampler,
1514
    thread metal::float3 const &coord)
1515
{
1516
    return texture.sample(sampler, coord.xy);
1517
}
1518
)",
1519
                        texture())
1520
1521
PROGRAM_PRELUDE_DECLARE(texture_depth2d_float3_float,
1522
                        R"(
1523
template <typename T>
1524
ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
1525
    thread metal::depth2d<T> &texture,
1526
    thread metal::sampler const &sampler,
1527
    thread metal::float3 const &coord,
1528
    float bias)
1529
{
1530
    return texture.sample(sampler, coord.xy, metal::bias(bias));
1531
}
1532
)",
1533
                        texture())
1534
1535
PROGRAM_PRELUDE_DECLARE(texture_depth2darray_float4,
1536
                        R"(
1537
template <typename T>
1538
ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
1539
    thread metal::depth2d_array<T> &texture,
1540
    thread metal::sampler const &sampler,
1541
    thread metal::float4 const &coord)
1542
{
1543
    return texture.sample_compare(sampler, coord.xy, uint(metal::round(coord.z)), coord.w);
1544
}
1545
)",
1546
                        texture())
1547
1548
PROGRAM_PRELUDE_DECLARE(texture_depth2darray_float4_float,
1549
                        R"(
1550
template <typename T>
1551
ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
1552
    thread metal::depth2d_array<T> &texture,
1553
    thread metal::sampler const &sampler,
1554
    thread metal::float4 const &coord,
1555
    float compare)
1556
{
1557
    return texture.sample_compare(sampler, coord.xyz, uint(metal::round(coord.w)), compare);
1558
}
1559
)",
1560
                        texture())
1561
1562
PROGRAM_PRELUDE_DECLARE(texture_depthcube_float4,
1563
                        R"(
1564
template <typename T>
1565
ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
1566
    thread metal::depthcube<T> &texture,
1567
    thread metal::sampler const &sampler,
1568
    thread metal::float4 const &coord)
1569
{
1570
    return texture.sample(sampler, coord.xyz);
1571
}
1572
)",
1573
                        texture())
1574
1575
PROGRAM_PRELUDE_DECLARE(texture_depthcube_float4_float,
1576
                        R"(
1577
template <typename T>
1578
ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
1579
    thread metal::depthcube<T> &texture,
1580
    thread metal::sampler const &sampler,
1581
    thread metal::float4 const &coord,
1582
    float bias)
1583
{
1584
    return texture.sample(sampler, coord.xyz, metal::bias(bias));
1585
}
1586
)",
1587
                        texture())
1588
1589
PROGRAM_PRELUDE_DECLARE(texture_texture2darray_float3,
1590
                        R"(
1591
template <typename T>
1592
ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
1593
    thread metal::texture2d_array<T> &texture,
1594
    thread metal::sampler const &sampler,
1595
    thread metal::float3 const &coord)
1596
{
1597
    return texture.sample(sampler, coord.xy, uint(metal::round(coord.z)));
1598
}
1599
)",
1600
                        texture())
1601
1602
PROGRAM_PRELUDE_DECLARE(texture_texture2darray_float3_float,
1603
                        R"(
1604
template <typename T>
1605
ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
1606
    thread metal::texture2d_array<T> &texture,
1607
    thread metal::sampler const &sampler,
1608
    thread metal::float3 const &coord,
1609
    float bias)
1610
{
1611
    return texture.sample(sampler, coord.xy, uint(metal::round(coord.z)), metal::bias(bias));
1612
}
1613
)",
1614
                        texture())
1615
1616
PROGRAM_PRELUDE_DECLARE(texture_texture2darray_float4,
1617
                        R"(
1618
template <typename T>
1619
ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
1620
    thread metal::texture2d_array<T> &texture,
1621
    thread metal::sampler const &sampler,
1622
    thread metal::float4 const &coord)
1623
{
1624
    return texture.sample(sampler, coord.xyz, uint(metal::round(coord.w)));
1625
}
1626
)",
1627
                        texture())
1628
1629
PROGRAM_PRELUDE_DECLARE(texture_texture2darray_float4_float,
1630
                        R"(
1631
template <typename T>
1632
ANGLE_ALWAYS_INLINE auto ANGLE_texture_impl(
1633
    thread metal::texture2d_array<T> &texture,
1634
    thread metal::sampler const &sampler,
1635
    thread metal::float4 const &coord,
1636
    float bias)
1637
{
1638
    return texture.sample(sampler, coord.xyz, uint(metal::round(coord.w)), metal::bias(bias));
1639
}
1640
)",
1641
                        texture())
1642
1643
PROGRAM_PRELUDE_DECLARE(texture1DLod,
1644
                        R"(
1645
#define ANGLE_texture1DLod(env, ...) ANGLE_texture1DLod_impl(*env.texture, *env.sampler, __VA_ARGS__)
1646
1647
template <typename Texture>
1648
ANGLE_ALWAYS_INLINE auto ANGLE_texture1DLod_impl(
1649
    thread Texture &texture,
1650
    thread metal::sampler const &sampler,
1651
    thread float const &coord,
1652
    float level)
1653
{
1654
    return texture.sample(sampler, coord, metal::level(level));
1655
}
1656
)",
1657
                        textureEnv())
1658
1659
PROGRAM_PRELUDE_DECLARE(texture1DProj,
1660
                        R"(
1661
#define ANGLE_texture1DProj(env, ...) ANGLE_texture1DProj_impl(*env.texture, *env.sampler, __VA_ARGS__)
1662
1663
template <typename Texture>
1664
ANGLE_ALWAYS_INLINE auto ANGLE_texture1DProj_impl(
1665
    thread Texture &texture,
1666
    thread metal::sampler const &sampler,
1667
    thread metal::float2 const &coord,
1668
    float bias = 0)
1669
{
1670
    return texture.sample(sampler, coord.x/coord.y, metal::bias(bias));
1671
}
1672
1673
template <typename Texture>
1674
ANGLE_ALWAYS_INLINE auto ANGLE_texture1DProj_impl(
1675
    thread Texture &texture,
1676
    thread metal::sampler const &sampler,
1677
    thread metal::float4 const &coord,
1678
    float bias = 0)
1679
{
1680
    return texture.sample(sampler, coord.x/coord.w, metal::bias(bias));
1681
}
1682
)",
1683
                        textureEnv())
1684
1685
PROGRAM_PRELUDE_DECLARE(texture1DProjLod,
1686
                        R"(
1687
#define ANGLE_texture1DProjLod(env, ...) ANGLE_texture1DProjLod_impl(*env.texture, *env.sampler, __VA_ARGS__)
1688
1689
template <typename Texture>
1690
ANGLE_ALWAYS_INLINE auto ANGLE_texture1DProjLod_impl(
1691
    thread Texture &texture,
1692
    thread metal::sampler const &sampler,
1693
    thread metal::float2 const &coord,
1694
    float level)
1695
{
1696
    return texture.sample(sampler, coord.x/coord.y, metal::level(level));
1697
}
1698
1699
template <typename Texture>
1700
ANGLE_ALWAYS_INLINE auto ANGLE_texture1DProjLod_impl(
1701
    thread Texture &texture,
1702
    thread metal::sampler const &sampler,
1703
    thread metal::float4 const &coord,
1704
    float level)
1705
{
1706
    return texture.sample(sampler, coord.x/coord.w, metal::level(level));
1707
}
1708
)",
1709
                        textureEnv())
1710
1711
PROGRAM_PRELUDE_DECLARE(texture2D,
1712
                        R"(
1713
#define ANGLE_texture2D(env, ...) ANGLE_texture2D_impl(*env.texture, *env.sampler, __VA_ARGS__)
1714
1715
template <typename Texture>
1716
ANGLE_ALWAYS_INLINE auto ANGLE_texture2D_impl(
1717
    thread Texture &texture,
1718
    thread metal::sampler const &sampler,
1719
    thread metal::float2 const &coord)
1720
{
1721
    return texture.sample(sampler, coord);
1722
}
1723
1724
template <typename Texture>
1725
ANGLE_ALWAYS_INLINE auto ANGLE_texture2D_impl(
1726
    thread Texture &texture,
1727
    thread metal::sampler const &sampler,
1728
    thread metal::float2 const &coord,
1729
    float bias)
1730
{
1731
    return texture.sample(sampler, coord, metal::bias(bias));
1732
}
1733
1734
template <typename Texture>
1735
ANGLE_ALWAYS_INLINE auto ANGLE_texture2D_impl(
1736
    thread Texture &texture,
1737
    thread metal::sampler const &sampler,
1738
    thread metal::float3 const &coord)
1739
{
1740
    return texture.sample(sampler, coord);
1741
}
1742
1743
template <typename Texture>
1744
ANGLE_ALWAYS_INLINE auto ANGLE_texture2D_impl(
1745
    thread Texture &texture,
1746
    thread metal::sampler const &sampler,
1747
    thread metal::float3 const &coord,
1748
    float bias)
1749
{
1750
    return texture.sample(sampler, coord, metal::bias(bias));
1751
}
1752
)",
1753
                        textureEnv())
1754
1755
PROGRAM_PRELUDE_DECLARE(texture2DLod,
1756
                        R"(
1757
#define ANGLE_texture2DLod(env, ...) ANGLE_texture2DLod_impl(*env.texture, *env.sampler, __VA_ARGS__)
1758
1759
template <typename Texture>
1760
ANGLE_ALWAYS_INLINE auto ANGLE_texture2DLod_impl(
1761
    thread Texture &texture,
1762
    thread metal::sampler const &sampler,
1763
    thread metal::float2 const &coord,
1764
    float level)
1765
{
1766
    return texture.sample(sampler, coord, metal::level(level));
1767
}
1768
)",
1769
                        textureEnv())
1770
1771
PROGRAM_PRELUDE_DECLARE(texture2DProj,
1772
                        R"(
1773
#define ANGLE_texture2DProj(env, ...) ANGLE_texture2DProj_impl(*env.texture, *env.sampler, __VA_ARGS__)
1774
1775
template <typename Texture>
1776
ANGLE_ALWAYS_INLINE auto ANGLE_texture2DProj_impl(
1777
    thread Texture &texture,
1778
    thread metal::sampler const &sampler,
1779
    thread metal::float3 const &coord,
1780
    float bias = 0)
1781
{
1782
    return texture.sample(sampler, coord.xy/coord.z, metal::bias(bias));
1783
}
1784
1785
template <typename Texture>
1786
ANGLE_ALWAYS_INLINE auto ANGLE_texture2DProj_impl(
1787
    thread Texture &texture,
1788
    thread metal::sampler const &sampler,
1789
    thread metal::float4 const &coord,
1790
    float bias = 0)
1791
{
1792
    return texture.sample(sampler, coord.xy/coord.w, metal::bias(bias));
1793
}
1794
)",
1795
                        textureEnv())
1796
1797
PROGRAM_PRELUDE_DECLARE(texture2DProjLod,
1798
                        R"(
1799
#define ANGLE_texture2DProjLod(env, ...) ANGLE_texture2DProjLod_impl(*env.texture, *env.sampler, __VA_ARGS__)
1800
1801
template <typename Texture>
1802
ANGLE_ALWAYS_INLINE auto ANGLE_texture2DProjLod_impl(
1803
    thread Texture &texture,
1804
    thread metal::sampler const &sampler,
1805
    thread metal::float3 const &coord,
1806
    float level)
1807
{
1808
    return texture.sample(sampler, coord.xy/coord.z, metal::level(level));
1809
}
1810
1811
template <typename Texture>
1812
ANGLE_ALWAYS_INLINE auto ANGLE_texture2DProjLod_impl(
1813
    thread Texture &texture,
1814
    thread metal::sampler const &sampler,
1815
    thread metal::float4 const &coord,
1816
    float level)
1817
{
1818
    return texture.sample(sampler, coord.xy/coord.w, metal::level(level));
1819
}
1820
)",
1821
                        textureEnv())
1822
1823
PROGRAM_PRELUDE_DECLARE(texture3DLod,
1824
                        R"(
1825
#define ANGLE_texture3DLod(env, ...) ANGLE_texture3DLod_impl(*env.texture, *env.sampler, __VA_ARGS__)
1826
1827
template <typename Texture>
1828
ANGLE_ALWAYS_INLINE auto ANGLE_texture3DLod_impl(
1829
    thread Texture &texture,
1830
    thread metal::sampler const &sampler,
1831
    thread metal::float3 const &coord,
1832
    float level)
1833
{
1834
    return texture.sample(sampler, coord, metal::level(level));
1835
}
1836
)",
1837
                        textureEnv())
1838
1839
PROGRAM_PRELUDE_DECLARE(texture3DProj,
1840
                        R"(
1841
#define ANGLE_texture3DProj(env, ...) ANGLE_texture3DProj_impl(*env.texture, *env.sampler, __VA_ARGS__)
1842
1843
template <typename Texture>
1844
ANGLE_ALWAYS_INLINE auto ANGLE_texture3DProj_impl(
1845
    thread Texture &texture,
1846
    thread metal::sampler const &sampler,
1847
    thread metal::float4 const &coord,
1848
    float bias = 0)
1849
{
1850
    return texture.sample(sampler, coord.xyz/coord.w, metal::bias(bias));
1851
}
1852
)",
1853
                        textureEnv())
1854
1855
PROGRAM_PRELUDE_DECLARE(texture3DProjLod,
1856
                        R"(
1857
#define ANGLE_texture3DProjLod(env, ...) ANGLE_texture3DProjLod_impl(*env.texture, *env.sampler, __VA_ARGS__)
1858
1859
template <typename Texture>
1860
ANGLE_ALWAYS_INLINE auto ANGLE_texture3DProjLod_impl(
1861
    thread Texture &texture,
1862
    thread metal::sampler const &sampler,
1863
    thread metal::float4 const &coord,
1864
    float level)
1865
{
1866
    return texture.sample(sampler, coord.xyz/coord.w, metal::level(level));
1867
}
1868
)",
1869
                        textureEnv())
1870
1871
PROGRAM_PRELUDE_DECLARE(textureCube,
1872
                        R"(
1873
#define ANGLE_textureCube(env, ...) ANGLE_textureCube_impl(*env.texture, *env.sampler, __VA_ARGS__)
1874
1875
template <typename Texture>
1876
ANGLE_ALWAYS_INLINE auto ANGLE_textureCube_impl(
1877
    thread Texture &texture,
1878
    thread metal::sampler const &sampler,
1879
    thread metal::float3 const &coord)
1880
{
1881
    return texture.sample(sampler, coord);
1882
}
1883
1884
template <typename Texture>
1885
ANGLE_ALWAYS_INLINE auto ANGLE_textureCube_impl(
1886
    thread Texture &texture,
1887
    thread metal::sampler const &sampler,
1888
    thread metal::float3 const &coord,
1889
    float bias)
1890
{
1891
    return texture.sample(sampler, coord, metal::bias(bias));
1892
}
1893
)",
1894
                        textureEnv())
1895
1896
PROGRAM_PRELUDE_DECLARE(textureCubeLod,
1897
                        R"(
1898
#define ANGLE_textureCubeLod(env, ...) ANGLE_textureCubeLod_impl(*env.texture, *env.sampler, __VA_ARGS__)
1899
1900
template <typename Texture>
1901
ANGLE_ALWAYS_INLINE auto ANGLE_textureCubeLod_impl(
1902
    thread Texture &texture,
1903
    thread metal::sampler const &sampler,
1904
    thread metal::float3 const &coord,
1905
    float level)
1906
{
1907
    return texture.sample(sampler, coord, metal::level(level));
1908
}
1909
)",
1910
                        textureEnv())
1911
1912
PROGRAM_PRELUDE_DECLARE(textureCubeProj,
1913
                        R"(
1914
#define ANGLE_textureCubeProj(env, ...) ANGLE_textureCubeProj_impl(*env.texture, *env.sampler, __VA_ARGS__)
1915
1916
template <typename Texture>
1917
ANGLE_ALWAYS_INLINE auto ANGLE_textureCubeProj_impl(
1918
    thread Texture &texture,
1919
    thread metal::sampler const &sampler,
1920
    thread metal::float4 const &coord,
1921
    float bias = 0)
1922
{
1923
    return texture.sample(sampler, coord.xyz/coord.w, metal::bias(bias));
1924
}
1925
)",
1926
                        textureEnv())
1927
1928
PROGRAM_PRELUDE_DECLARE(textureCubeProjLod,
1929
                        R"(
1930
#define ANGLE_textureCubeProjLod(env, ...) ANGLE_textureCubeProjLod_impl(*env.texture, *env.sampler, __VA_ARGS__)
1931
1932
template <typename Texture>
1933
ANGLE_ALWAYS_INLINE auto ANGLE_textureCubeProjLod_impl(
1934
    thread Texture &texture,
1935
    thread metal::sampler const &sampler,
1936
    thread metal::float4 const &coord,
1937
    float level)
1938
{
1939
    return texture.sample(sampler, coord.xyz/coord.w, metal::level(level));
1940
}
1941
)",
1942
                        textureEnv())
1943
1944
PROGRAM_PRELUDE_DECLARE(textureGrad,
1945
                        R"(
1946
#define ANGLE_textureGrad(env, ...) ANGLE_textureGrad_impl(*env.texture, *env.sampler, __VA_ARGS__)
1947
)",
1948
                        textureEnv())
1949
1950
PROGRAM_PRELUDE_DECLARE(textureGrad_generic_floatN_floatN_floatN,
1951
                        R"(
1952
template <typename Texture, int N>
1953
ANGLE_ALWAYS_INLINE auto ANGLE_textureGrad_impl(
1954
    thread Texture &texture,
1955
    thread metal::sampler const &sampler,
1956
    thread metal::vec<float, N> const &coord,
1957
    thread metal::vec<float, N> const &dPdx,
1958
    thread metal::vec<float, N> const &dPdy)
1959
{
1960
    return texture.sample(sampler, coord, ANGLE_gradient<N>(dPdx, dPdy));
1961
}
1962
)",
1963
                        gradient(),
1964
                        textureGrad())
1965
1966
PROGRAM_PRELUDE_DECLARE(textureGrad_generic_float3_float2_float2,
1967
                        R"(
1968
template <typename Texture>
1969
ANGLE_ALWAYS_INLINE auto ANGLE_textureGrad_impl(
1970
    thread Texture &texture,
1971
    thread metal::sampler const &sampler,
1972
    thread metal::float3 const &coord,
1973
    thread metal::float2 const &dPdx,
1974
    thread metal::float2 const &dPdy)
1975
{
1976
    return texture.sample(sampler, coord.xy, uint(metal::round(coord.z)), metal::gradient2d(dPdx, dPdy));
1977
}
1978
)",
1979
                        textureGrad())
1980
1981
PROGRAM_PRELUDE_DECLARE(textureGrad_generic_float4_float2_float2,
1982
                        R"(
1983
template <typename Texture>
1984
ANGLE_ALWAYS_INLINE auto ANGLE_textureGrad_impl(
1985
    thread Texture &texture,
1986
    thread metal::sampler const &sampler,
1987
    thread metal::float4 const &coord,
1988
    thread metal::float2 const &dPdx,
1989
    thread metal::float2 const &dPdy)
1990
{
1991
    return texture.sample(sampler, coord.xy, uint(metal::round(coord.z)), metal::gradient2d(dPdx, dPdy));
1992
}
1993
)",
1994
                        textureGrad())
1995
1996
PROGRAM_PRELUDE_DECLARE(textureGrad_depth2d_float3_float2_float2,
1997
                        R"(
1998
template <typename T>
1999
ANGLE_ALWAYS_INLINE auto ANGLE_textureGrad_impl(
2000
    thread metal::depth2d<T> &texture,
2001
    thread metal::sampler const &sampler,
2002
    thread metal::float3 const &coord,
2003
    thread metal::float2 const &dPdx,
2004
    thread metal::float2 const &dPdy)
2005
{
2006
    if (ANGLE_UseSampleCompareGradient)
2007
    {
2008
        return static_cast<T>(texture.sample_compare(sampler, coord.xy, coord.z, metal::gradient2d(dPdx, dPdy)));
2009
    }
2010
    else
2011
    {
2012
        return static_cast<T>(texture.sample(sampler, coord.xy, metal::gradient2d(dPdx, dPdy)) > coord.z);
2013
    }
2014
}
2015
)",
2016
                        functionConstants(),
2017
                        textureGrad())
2018
2019
PROGRAM_PRELUDE_DECLARE(textureGrad_depth2darray_float4_float2_float2,
2020
                        R"(
2021
template <typename T>
2022
ANGLE_ALWAYS_INLINE auto ANGLE_textureGrad_impl(
2023
    thread metal::depth2d_array<T> &texture,
2024
    thread metal::sampler const &sampler,
2025
    thread metal::float4 const &coord,
2026
    thread metal::float2 const &dPdx,
2027
    thread metal::float2 const &dPdy)
2028
{
2029
    if (ANGLE_UseSampleCompareGradient)
2030
    {
2031
        return static_cast<T>(texture.sample_compare(sampler, coord.xy, uint(metal::round(coord.z)), coord.w, metal::gradient2d(dPdx, dPdy)));
2032
    }
2033
    else
2034
    {
2035
        return static_cast<T>(texture.sample(sampler, coord.xy, uint(metal::round(coord.z)), metal::gradient2d(dPdx, dPdy)) > coord.w);
2036
    }
2037
}
2038
)",
2039
                        functionConstants(),
2040
                        textureGrad())
2041
2042
PROGRAM_PRELUDE_DECLARE(textureGrad_depthcube_float4_float3_float3,
2043
                        R"(
2044
template <typename T>
2045
ANGLE_ALWAYS_INLINE auto ANGLE_textureGrad_impl(
2046
    thread metal::depthcube<T> &texture,
2047
    thread metal::sampler const &sampler,
2048
    thread metal::float4 const &coord,
2049
    thread metal::float3 const &dPdx,
2050
    thread metal::float3 const &dPdy)
2051
{
2052
    if (ANGLE_UseSampleCompareGradient)
2053
    {
2054
        return static_cast<T>(texture.sample_compare(sampler, coord.xyz, coord.w, metal::gradientcube(dPdx, dPdy)));
2055
    }
2056
    else
2057
    {
2058
        return static_cast<T>(texture.sample(sampler, coord.xyz, metal::gradientcube(dPdx, dPdy)) > coord.w);
2059
    }
2060
}
2061
)",
2062
                        functionConstants(),
2063
                        textureGrad())
2064
2065
PROGRAM_PRELUDE_DECLARE(textureGrad_texturecube_float3_float3_float3,
2066
                        R"(
2067
template <typename T>
2068
ANGLE_ALWAYS_INLINE auto ANGLE_textureGrad_impl(
2069
    thread metal::texturecube<T> &texture,
2070
    thread metal::sampler const &sampler,
2071
    thread metal::float3 const &coord,
2072
    thread metal::float3 const &dPdx,
2073
    thread metal::float3 const &dPdy)
2074
{
2075
    return texture.sample(sampler, coord, metal::gradientcube(dPdx, dPdy));
2076
}
2077
)",
2078
                        textureGrad())
2079
2080
PROGRAM_PRELUDE_DECLARE(textureGradOffset,
2081
                        R"(
2082
#define ANGLE_textureGradOffset(env, ...) ANGLE_textureGradOffset_impl(*env.texture, *env.sampler, __VA_ARGS__)
2083
)",
2084
                        textureEnv())
2085
2086
PROGRAM_PRELUDE_DECLARE(textureGradOffset_generic_floatN_floatN_floatN_intN,
2087
                        R"(
2088
template <typename Texture, int N>
2089
ANGLE_ALWAYS_INLINE auto ANGLE_textureGradOffset_impl(
2090
    thread Texture &texture,
2091
    thread metal::sampler const &sampler,
2092
    thread metal::vec<float, N> const &coord,
2093
    thread metal::vec<float, N> const &dPdx,
2094
    thread metal::vec<float, N> const &dPdy,
2095
    thread metal::vec<int, N> const &offset)
2096
{
2097
    return texture.sample(sampler, coord, ANGLE_gradient<N>(dPdx, dPdy), offset);
2098
}
2099
)",
2100
                        gradient(),
2101
                        textureGradOffset())
2102
2103
PROGRAM_PRELUDE_DECLARE(textureGradOffset_generic_float3_float2_float2_int2,
2104
                        R"(
2105
template <typename Texture>
2106
ANGLE_ALWAYS_INLINE auto ANGLE_textureGradOffset_impl(
2107
    thread Texture &texture,
2108
    thread metal::sampler const &sampler,
2109
    thread metal::float3 const &coord,
2110
    thread metal::float2 const &dPdx,
2111
    thread metal::float2 const &dPdy,
2112
    thread metal::int2 const &offset)
2113
{
2114
    return texture.sample(sampler, coord.xy, uint(metal::round(coord.z)), metal::gradient2d(dPdx, dPdy), offset);
2115
}
2116
)",
2117
                        textureGradOffset())
2118
2119
PROGRAM_PRELUDE_DECLARE(textureGradOffset_generic_float4_float2_float2_int2,
2120
                        R"(
2121
template <typename Texture>
2122
ANGLE_ALWAYS_INLINE auto ANGLE_textureGradOffset_impl(
2123
    thread Texture &texture,
2124
    thread metal::sampler const &sampler,
2125
    thread metal::float4 const &coord,
2126
    thread metal::float2 const &dPdx,
2127
    thread metal::float2 const &dPdy,
2128
    thread metal::int2 const &offset)
2129
{
2130
    return texture.sample(sampler, coord.xy, uint(metal::round(coord.z)), metal::gradient2d(dPdx, dPdy), offset);
2131
}
2132
)",
2133
                        textureGradOffset())
2134
2135
PROGRAM_PRELUDE_DECLARE(textureGradOffset_depth2d_float3_float2_float2_int2,
2136
                        R"(
2137
template <typename T>
2138
ANGLE_ALWAYS_INLINE auto ANGLE_textureGradOffset_impl(
2139
    thread metal::depth2d<T> &texture,
2140
    thread metal::sampler const &sampler,
2141
    thread metal::float3 const &coord,
2142
    thread metal::float2 const &dPdx,
2143
    thread metal::float2 const &dPdy,
2144
    thread metal::int2 const &offset)
2145
{
2146
    if (ANGLE_UseSampleCompareGradient)
2147
    {
2148
        return static_cast<T>(texture.sample_compare(sampler, coord.xy, coord.z, metal::gradient2d(dPdx, dPdy), offset));
2149
    }
2150
    else
2151
    {
2152
        return static_cast<T>(texture.sample(sampler, coord.xy, metal::gradient2d(dPdx, dPdy), offset) > coord.z);
2153
    }
2154
}
2155
)",
2156
                        functionConstants(),
2157
                        textureGradOffset())
2158
2159
PROGRAM_PRELUDE_DECLARE(textureGradOffset_depth2darray_float4_float2_float2_int2,
2160
                        R"(
2161
template <typename T>
2162
ANGLE_ALWAYS_INLINE auto ANGLE_textureGradOffset_impl(
2163
    thread metal::depth2d_array<T> &texture,
2164
    thread metal::sampler const &sampler,
2165
    thread metal::float4 const &coord,
2166
    thread metal::float2 const &dPdx,
2167
    thread metal::float2 const &dPdy,
2168
    thread metal::int2 const &offset)
2169
{
2170
    if (ANGLE_UseSampleCompareGradient)
2171
    {
2172
        return static_cast<T>(texture.sample_compare(sampler, coord.xy, uint(metal::round(coord.z)), coord.w, metal::gradient2d(dPdx, dPdy), offset));
2173
    }
2174
    else
2175
    {
2176
        return static_cast<T>(texture.sample(sampler, coord.xy, uint(metal::round(coord.z)), metal::gradient2d(dPdx, dPdy), offset) > coord.w);
2177
    }
2178
}
2179
)",
2180
                        functionConstants(),
2181
                        textureGradOffset())
2182
2183
PROGRAM_PRELUDE_DECLARE(textureGradOffset_depthcube_float4_float3_float3_int3,
2184
                        R"(
2185
template <typename T>
2186
ANGLE_ALWAYS_INLINE auto ANGLE_textureGradOffset_impl(
2187
    thread metal::depthcube<T> &texture,
2188
    thread metal::sampler const &sampler,
2189
    thread metal::float4 const &coord,
2190
    thread metal::float3 const &dPdx,
2191
    thread metal::float3 const &dPdy,
2192
    thread metal::int3 const &offset)
2193
{
2194
    return texture.sample(sampler, coord.xyz, metal::gradientcube(dPdx, dPdy), offset);
2195
}
2196
)",
2197
                        textureGradOffset())
2198
2199
PROGRAM_PRELUDE_DECLARE(textureGradOffset_texturecube_float3_float3_float3_int3,
2200
                        R"(
2201
template <typename T>
2202
ANGLE_ALWAYS_INLINE auto ANGLE_textureGradOffset_impl(
2203
    thread metal::texturecube<T> &texture,
2204
    thread metal::sampler const &sampler,
2205
    thread metal::float3 const &coord,
2206
    thread metal::float3 const &dPdx,
2207
    thread metal::float3 const &dPdy,
2208
    thread metal::int3 const &offset)
2209
{
2210
    return texture.sample(sampler, coord, metal::gradientcube(dPdx, dPdy), offset);
2211
}
2212
)",
2213
                        textureGradOffset())
2214
2215
PROGRAM_PRELUDE_DECLARE(textureLod,
2216
                        R"(
2217
#define ANGLE_textureLod(env, ...) ANGLE_textureLod_impl(*env.texture, *env.sampler, __VA_ARGS__)
2218
)",
2219
                        textureEnv())
2220
2221
PROGRAM_PRELUDE_DECLARE(textureLod_generic_float2,
2222
                        R"(
2223
template <typename Texture>
2224
ANGLE_ALWAYS_INLINE auto ANGLE_textureLod_impl(
2225
    thread Texture &texture,
2226
    thread metal::sampler const &sampler,
2227
    thread metal::float2 const &coord,
2228
    float level)
2229
{
2230
    return texture.sample(sampler, coord, metal::level(level));
2231
}
2232
)",
2233
                        textureLod())
2234
2235
PROGRAM_PRELUDE_DECLARE(textureLod_generic_float3,
2236
                        R"(
2237
template <typename Texture>
2238
ANGLE_ALWAYS_INLINE auto ANGLE_textureLod_impl(
2239
    thread Texture &texture,
2240
    thread metal::sampler const &sampler,
2241
    thread metal::float3 const &coord,
2242
    float level)
2243
{
2244
    return texture.sample(sampler, coord, metal::level(level));
2245
}
2246
)",
2247
                        textureLod())
2248
2249
PROGRAM_PRELUDE_DECLARE(textureLod_depth2d_float3,
2250
                        R"(
2251
template <typename T>
2252
ANGLE_ALWAYS_INLINE auto ANGLE_textureLod_impl(
2253
    thread metal::depth2d<T> &texture,
2254
    thread metal::sampler const &sampler,
2255
    thread metal::float3 const &coord,
2256
    float level)
2257
{
2258
    if (ANGLE_UseSampleCompareLod)
2259
    {
2260
        return static_cast<T>(texture.sample_compare(sampler, coord.xy, coord.z, metal::level(level)));
2261
    }
2262
    else
2263
    {
2264
        return static_cast<T>(texture.sample(sampler, coord.xy, metal::level(level)) > coord.z);
2265
    }
2266
}
2267
)",
2268
                        functionConstants(),
2269
                        textureLod())
2270
2271
PROGRAM_PRELUDE_DECLARE(textureLod_texture2darray_float3,
2272
                        R"(
2273
template <typename T>
2274
ANGLE_ALWAYS_INLINE auto ANGLE_textureLod_impl(
2275
    thread metal::texture2d_array<T> &texture,
2276
    thread metal::sampler const &sampler,
2277
    thread metal::float3 const &coord,
2278
    float level)
2279
{
2280
    return texture.sample(sampler, coord.xy, uint(metal::round(coord.z)), metal::level(level));
2281
}
2282
)",
2283
                        textureLod())
2284
2285
PROGRAM_PRELUDE_DECLARE(textureLod_texture2darray_float4,
2286
                        R"(
2287
template <typename T>
2288
ANGLE_ALWAYS_INLINE auto ANGLE_textureLod_impl(
2289
    thread metal::texture2d_array<T> &texture,
2290
    thread metal::sampler const &sampler,
2291
    thread metal::float4 const &coord,
2292
    float level)
2293
{
2294
    return texture.sample(sampler, coord.xyz, uint(metal::round(coord.w)), metal::level(level));
2295
}
2296
)",
2297
                        textureLod())
2298
2299
PROGRAM_PRELUDE_DECLARE(textureLodOffset,
2300
                        R"(
2301
#define ANGLE_textureLodOffset(env, ...) ANGLE_textureLodOffset_impl(*env.texture, *env.sampler, __VA_ARGS__)
2302
2303
template <typename Texture>
2304
ANGLE_ALWAYS_INLINE auto ANGLE_textureLodOffset_impl(
2305
    thread Texture &texture,
2306
    thread metal::sampler const &sampler,
2307
    thread metal::float2 const &coord,
2308
    float level,
2309
    thread int2 const &offset)
2310
{
2311
    return texture.sample(sampler, coord, metal::level(level), offset);
2312
}
2313
2314
template <typename Texture>
2315
ANGLE_ALWAYS_INLINE auto ANGLE_textureLodOffset_impl(
2316
    thread Texture &texture,
2317
    thread metal::sampler const &sampler,
2318
    thread metal::float3 const &coord,
2319
    float level,
2320
    thread int3 const &offset)
2321
{
2322
    return texture.sample(sampler, coord, metal::level(level), offset);
2323
}
2324
2325
template <typename T>
2326
ANGLE_ALWAYS_INLINE auto ANGLE_textureLodOffset_impl(
2327
    thread metal::depth2d<T> &texture,
2328
    thread metal::sampler const &sampler,
2329
    thread metal::float3 const &coord,
2330
    float level,
2331
    thread int2 const &offset)
2332
{
2333
    if (ANGLE_UseSampleCompareLod)
2334
    {
2335
        return static_cast<T>(texture.sample_compare(sampler, coord.xy, coord.z, metal::level(level), offset));
2336
    }
2337
    else
2338
    {
2339
        return static_cast<T>(texture.sample(sampler, coord.xy, metal::level(level), offset) > coord.z);
2340
    }
2341
}
2342
2343
template <typename T>
2344
ANGLE_ALWAYS_INLINE auto ANGLE_textureLodOffset_impl(
2345
    thread metal::texture2d_array<T> &texture,
2346
    thread metal::sampler const &sampler,
2347
    thread metal::float3 const &coord,
2348
    float level,
2349
    thread int2 const &offset)
2350
{
2351
    return texture.sample(sampler, coord.xy, uint(metal::round(coord.z)), metal::level(level), offset);
2352
}
2353
2354
template <typename T>
2355
ANGLE_ALWAYS_INLINE auto ANGLE_textureLodOffset_impl(
2356
    thread metal::texture2d_array<T> &texture,
2357
    thread metal::sampler const &sampler,
2358
    thread metal::float4 const &coord,
2359
    float level,
2360
    thread int3 const &offset)
2361
{
2362
    return texture.sample(sampler, coord.xyz, uint(metal::round(coord.w)), metal::level(level), offset);
2363
}
2364
)",
2365
                        functionConstants(),
2366
                        textureEnv())
2367
2368
PROGRAM_PRELUDE_DECLARE(textureOffset,
2369
                        R"(
2370
#define ANGLE_textureOffset(env, ...) ANGLE_textureOffset_impl(*env.texture, *env.sampler, __VA_ARGS__)
2371
2372
template <typename Texture>
2373
ANGLE_ALWAYS_INLINE auto ANGLE_textureOffset_impl(
2374
    thread Texture &texture,
2375
    thread metal::sampler const &sampler,
2376
    thread float2 const &coord,
2377
    thread int2 const &offset)
2378
{
2379
    return texture.sample(sampler, coord, offset);
2380
}
2381
2382
template <typename Texture>
2383
ANGLE_ALWAYS_INLINE auto ANGLE_textureOffset_impl(
2384
    thread Texture &texture,
2385
    thread metal::sampler const &sampler,
2386
    thread float2 const &coord,
2387
    thread int2 const &offset,
2388
    float bias)
2389
{
2390
    return texture.sample(sampler, coord, metal::bias(bias), offset);
2391
}
2392
2393
template <typename Texture>
2394
ANGLE_ALWAYS_INLINE auto ANGLE_textureOffset_impl(
2395
    thread Texture &texture,
2396
    thread metal::sampler const &sampler,
2397
    thread float3 const &coord,
2398
    thread int2 const &offset)
2399
{
2400
    return texture.sample(sampler, coord.xy, uint(metal::round(coord.z)), offset);
2401
}
2402
2403
template <typename Texture>
2404
ANGLE_ALWAYS_INLINE auto ANGLE_textureOffset_impl(
2405
    thread Texture &texture,
2406
    thread metal::sampler const &sampler,
2407
    thread float3 const &coord,
2408
    thread int2 const &offset,
2409
    float bias)
2410
{
2411
    return texture.sample(sampler, coord.xy, uint(metal::round(coord.z)), metal::bias(bias), offset);
2412
}
2413
2414
template <typename Texture>
2415
ANGLE_ALWAYS_INLINE auto ANGLE_textureOffset_impl(
2416
    thread Texture &texture,
2417
    thread metal::sampler const &sampler,
2418
    thread float3 const &coord,
2419
    thread int3 const &offset)
2420
{
2421
    return texture.sample(sampler, coord, offset);
2422
}
2423
2424
template <typename Texture>
2425
ANGLE_ALWAYS_INLINE auto ANGLE_textureOffset_impl(
2426
    thread Texture &texture,
2427
    thread metal::sampler const &sampler,
2428
    thread float3 const &coord,
2429
    thread int3 const &offset,
2430
    float bias)
2431
{
2432
    return texture.sample(sampler, coord, metal::bias(bias), offset);
2433
}
2434
2435
template <typename T>
2436
ANGLE_ALWAYS_INLINE auto ANGLE_textureOffset_impl(
2437
    thread metal::depth2d<T> &texture,
2438
    thread metal::sampler const &sampler,
2439
    thread float3 const &coord,
2440
    thread int2 const &offset)
2441
{
2442
    return texture.sample(sampler, coord.xy, offset);
2443
}
2444
2445
template <typename T>
2446
ANGLE_ALWAYS_INLINE auto ANGLE_textureOffset_impl(
2447
    thread metal::depth2d<T> &texture,
2448
    thread metal::sampler const &sampler,
2449
    thread float3 const &coord,
2450
    thread int2 const &offset,
2451
    float bias)
2452
{
2453
    return texture.sample(sampler, coord.xy, metal::bias(bias), offset);
2454
}
2455
)",
2456
                        textureEnv())
2457
2458
PROGRAM_PRELUDE_DECLARE(textureProj,
2459
                        R"(
2460
#define ANGLE_textureProj(env, ...) ANGLE_textureProj_impl(*env.texture, *env.sampler, __VA_ARGS__)
2461
2462
template <typename Texture>
2463
ANGLE_ALWAYS_INLINE auto ANGLE_textureProj_impl(
2464
    thread Texture &texture,
2465
    thread metal::sampler const &sampler,
2466
    thread metal::float3 const &coord,
2467
    float bias = 0)
2468
{
2469
    return texture.sample(sampler, coord.xy/coord.z, metal::bias(bias));
2470
}
2471
2472
template <typename Texture>
2473
ANGLE_ALWAYS_INLINE auto ANGLE_textureProj_impl(
2474
    thread Texture &texture,
2475
    thread metal::sampler const &sampler,
2476
    thread metal::float4 const &coord,
2477
    float bias = 0)
2478
{
2479
    return texture.sample(sampler, coord.xy/coord.w, metal::bias(bias));
2480
}
2481
2482
template <typename T>
2483
ANGLE_ALWAYS_INLINE auto ANGLE_textureProj_impl(
2484
    thread metal::texture3d<T> &texture,
2485
    thread metal::sampler const &sampler,
2486
    thread metal::float4 const &coord,
2487
    float bias = 0)
2488
{
2489
    return texture.sample(sampler, coord.xyz/coord.w, metal::bias(bias));
2490
}
2491
)",
2492
                        textureEnv())
2493
2494
PROGRAM_PRELUDE_DECLARE(textureProjGrad,
2495
                        R"(
2496
#define ANGLE_textureProjGrad(env, ...) ANGLE_textureProjGrad_impl(*env.texture, *env.sampler, __VA_ARGS__)
2497
)",
2498
                        textureEnv())
2499
2500
PROGRAM_PRELUDE_DECLARE(textureProjGrad_generic_float3_float2_float2,
2501
                        R"(
2502
template <typename Texture>
2503
ANGLE_ALWAYS_INLINE auto ANGLE_textureProjGrad_impl(
2504
    thread Texture &texture,
2505
    thread metal::sampler const &sampler,
2506
    thread metal::float3 const &coord,
2507
    thread metal::float2 const &dPdx,
2508
    thread metal::float2 const &dPdy)
2509
{
2510
    return texture.sample(sampler, coord.xy/coord.z, metal::gradient2d(dPdx, dPdy));
2511
}
2512
)",
2513
                        textureProjGrad())
2514
2515
PROGRAM_PRELUDE_DECLARE(textureProjGrad_generic_float4_float2_float2,
2516
                        R"(
2517
template <typename Texture>
2518
ANGLE_ALWAYS_INLINE auto ANGLE_textureProjGrad_impl(
2519
    thread Texture &texture,
2520
    thread metal::sampler const &sampler,
2521
    thread metal::float4 const &coord,
2522
    thread metal::float2 const &dPdx,
2523
    thread metal::float2 const &dPdy)
2524
{
2525
    return texture.sample(sampler, coord.xy/coord.w, metal::gradient2d(dPdx, dPdy));
2526
}
2527
)",
2528
                        textureProjGrad())
2529
2530
PROGRAM_PRELUDE_DECLARE(textureProjGrad_depth2d_float4_float2_float2,
2531
                        R"(
2532
template <typename T>
2533
ANGLE_ALWAYS_INLINE auto ANGLE_textureProjGrad_impl(
2534
    thread metal::depth2d<T> &texture,
2535
    thread metal::sampler const &sampler,
2536
    thread metal::float4 const &coord,
2537
    thread metal::float2 const &dPdx,
2538
    thread metal::float2 const &dPdy)
2539
{
2540
    if (ANGLE_UseSampleCompareGradient)
2541
    {
2542
        return static_cast<T>(texture.sample_compare(sampler, coord.xy/coord.w, coord.z/coord.w, metal::gradient2d(dPdx, dPdy)));
2543
    }
2544
    else
2545
    {
2546
        return static_cast<T>(texture.sample(sampler, coord.xy/coord.w, metal::gradient2d(dPdx, dPdy)) > coord.z/coord.w);
2547
    }
2548
}
2549
)",
2550
                        functionConstants(),
2551
                        textureProjGrad())
2552
2553
PROGRAM_PRELUDE_DECLARE(textureProjGrad_texture3d_float4_float3_float3,
2554
                        R"(
2555
template <typename T>
2556
ANGLE_ALWAYS_INLINE auto ANGLE_textureProjGrad_impl(
2557
    thread metal::texture3d<T> &texture,
2558
    thread metal::sampler const &sampler,
2559
    thread metal::float4 const &coord,
2560
    thread metal::float3 const &dPdx,
2561
    thread metal::float3 const &dPdy)
2562
{
2563
    return texture.sample(sampler, coord.xyz/coord.w, metal::gradient3d(dPdx, dPdy));
2564
}
2565
)",
2566
                        textureProjGrad())
2567
2568
PROGRAM_PRELUDE_DECLARE(textureProjGradOffset,
2569
                        R"(
2570
#define ANGLE_textureProjGradOffset(env, ...) ANGLE_textureProjGradOffset_impl(*env.texture, *env.sampler, __VA_ARGS__)
2571
)",
2572
                        textureEnv())
2573
2574
PROGRAM_PRELUDE_DECLARE(textureProjGradOffset_generic_float3_float2_float2_int2,
2575
                        R"(
2576
template <typename Texture>
2577
ANGLE_ALWAYS_INLINE auto ANGLE_textureProjGradOffset_impl(
2578
    thread Texture &texture,
2579
    thread metal::sampler const &sampler,
2580
    thread metal::float3 const &coord,
2581
    thread metal::float2 const &dPdx,
2582
    thread metal::float2 const &dPdy,
2583
    thread int2 const &offset)
2584
{
2585
    return texture.sample(sampler, coord.xy/coord.z, metal::gradient2d(dPdx, dPdy), offset);
2586
}
2587
)",
2588
                        textureProjGradOffset())
2589
2590
PROGRAM_PRELUDE_DECLARE(textureProjGradOffset_generic_float4_float2_float2_int2,
2591
                        R"(
2592
template <typename Texture>
2593
ANGLE_ALWAYS_INLINE auto ANGLE_textureProjGradOffset_impl(
2594
    thread Texture &texture,
2595
    thread metal::sampler const &sampler,
2596
    thread metal::float4 const &coord,
2597
    thread metal::float2 const &dPdx,
2598
    thread metal::float2 const &dPdy,
2599
    thread int2 const &offset)
2600
{
2601
    return texture.sample(sampler, coord.xy/coord.w, metal::gradient2d(dPdx, dPdy), offset);
2602
}
2603
)",
2604
                        textureProjGradOffset())
2605
2606
PROGRAM_PRELUDE_DECLARE(textureProjGradOffset_depth2d_float4_float2_float2_int2,
2607
                        R"(
2608
template <typename T>
2609
ANGLE_ALWAYS_INLINE auto ANGLE_textureProjGradOffset_impl(
2610
    thread metal::depth2d<T> &texture,
2611
    thread metal::sampler const &sampler,
2612
    thread metal::float4 const &coord,
2613
    thread metal::float2 const &dPdx,
2614
    thread metal::float2 const &dPdy,
2615
    thread int2 const &offset)
2616
{
2617
    if (ANGLE_UseSampleCompareGradient)
2618
    {
2619
        return static_cast<T>(texture.sample_compare(sampler, coord.xy/coord.w, coord.z/coord.w, metal::gradient2d(dPdx, dPdy), offset));
2620
    }
2621
    else
2622
    {
2623
        return static_cast<T>(texture.sample(sampler, coord.xy/coord.w, metal::gradient2d(dPdx, dPdy), offset) > coord.z/coord.w);
2624
    }
2625
}
2626
)",
2627
                        functionConstants(),
2628
                        textureProjGradOffset())
2629
2630
PROGRAM_PRELUDE_DECLARE(textureProjGradOffset_texture3d_float4_float3_float3_int3,
2631
                        R"(
2632
template <typename T>
2633
ANGLE_ALWAYS_INLINE auto ANGLE_textureProjGradOffset_impl(
2634
    thread metal::texture3d<T> &texture,
2635
    thread metal::sampler const &sampler,
2636
    thread metal::float4 const &coord,
2637
    thread metal::float3 const &dPdx,
2638
    thread metal::float3 const &dPdy,
2639
    thread int3 const &offset)
2640
{
2641
    return texture.sample(sampler, coord.xyz/coord.w, metal::gradient3d(dPdx, dPdy), offset);
2642
}
2643
)",
2644
                        textureProjGradOffset())
2645
2646
PROGRAM_PRELUDE_DECLARE(textureProjLod,
2647
                        R"(
2648
#define ANGLE_textureProjLod(env, ...) ANGLE_textureProjLod_impl(*env.texture, *env.sampler, __VA_ARGS__)
2649
)",
2650
                        textureEnv())
2651
2652
PROGRAM_PRELUDE_DECLARE(textureProjLod_generic_float3,
2653
                        R"(
2654
template <typename Texture>
2655
ANGLE_ALWAYS_INLINE auto ANGLE_textureProjLod_impl(
2656
    thread Texture &texture,
2657
    thread metal::sampler const &sampler,
2658
    thread metal::float3 const &coord,
2659
    float level)
2660
{
2661
    return texture.sample(sampler, coord.xy/coord.z, metal::level(level));
2662
}
2663
)",
2664
                        textureProjLod())
2665
2666
PROGRAM_PRELUDE_DECLARE(textureProjLod_generic_float4,
2667
                        R"(
2668
template <typename Texture>
2669
ANGLE_ALWAYS_INLINE auto ANGLE_textureProjLod_impl(
2670
    thread Texture &texture,
2671
    thread metal::sampler const &sampler,
2672
    thread metal::float4 const &coord,
2673
    float level)
2674
{
2675
    return texture.sample(sampler, coord.xy/coord.w, metal::level(level));
2676
}
2677
)",
2678
                        textureProjLod())
2679
2680
PROGRAM_PRELUDE_DECLARE(textureProjLod_depth2d_float4,
2681
                        R"(
2682
template <typename T>
2683
ANGLE_ALWAYS_INLINE auto ANGLE_textureProjLod_impl(
2684
    thread metal::depth2d<T> &texture,
2685
    thread metal::sampler const &sampler,
2686
    thread metal::float4 const &coord,
2687
    float level)
2688
{
2689
    if (ANGLE_UseSampleCompareLod)
2690
    {
2691
        return static_cast<T>(texture.sample_compare(sampler, coord.xy/coord.w, coord.z/coord.w, metal::level(level)));
2692
    }
2693
    else
2694
    {
2695
        return static_cast<T>(texture.sample(sampler, coord.xy/coord.w, metal::level(level)) > coord.z/coord.w);
2696
    }
2697
}
2698
)",
2699
                        functionConstants(),
2700
                        textureProjLod())
2701
2702
PROGRAM_PRELUDE_DECLARE(textureProjLod_texture3d_float4,
2703
                        R"(
2704
template <typename T>
2705
ANGLE_ALWAYS_INLINE auto ANGLE_textureProjLod_impl(
2706
    thread metal::texture3d<T> &texture,
2707
    thread metal::sampler const &sampler,
2708
    thread metal::float4 const &coord,
2709
    float level)
2710
{
2711
    return texture.sample(sampler, coord.xyz/coord.w, metal::level(level));
2712
}
2713
)",
2714
                        textureProjLod())
2715
2716
PROGRAM_PRELUDE_DECLARE(textureProjLodOffset,
2717
                        R"(
2718
#define ANGLE_textureProjLodOffset(env, ...) ANGLE_textureProjLodOffset_impl(*env.texture, *env.sampler, __VA_ARGS__)
2719
2720
template <typename Texture>
2721
ANGLE_ALWAYS_INLINE auto ANGLE_textureProjLodOffset_impl(
2722
    thread Texture &texture,
2723
    thread metal::sampler const &sampler,
2724
    thread metal::float3 const &coord,
2725
    float level,
2726
    thread int2 const &offset)
2727
{
2728
    return texture.sample(sampler, coord.xy/coord.z, metal::level(level), offset);
2729
}
2730
2731
template <typename Texture>
2732
ANGLE_ALWAYS_INLINE auto ANGLE_textureProjLodOffset_impl(
2733
    thread Texture &texture,
2734
    thread metal::sampler const &sampler,
2735
    thread metal::float4 const &coord,
2736
    float level,
2737
    thread int2 const &offset)
2738
{
2739
    return texture.sample(sampler, coord.xy/coord.w, metal::level(level), offset);
2740
}
2741
2742
template <typename T>
2743
ANGLE_ALWAYS_INLINE auto ANGLE_textureProjLodOffset_impl(
2744
    thread metal::depth2d<T> &texture,
2745
    thread metal::sampler const &sampler,
2746
    thread metal::float4 const &coord,
2747
    float level,
2748
    thread int2 const &offset)
2749
{
2750
    if (ANGLE_UseSampleCompareLod)
2751
    {
2752
        return static_cast<T>(texture.sample_compare(sampler, coord.xy/coord.w, coord.z/coord.w, metal::level(level), offset));
2753
    }
2754
    else
2755
    {
2756
        return static_cast<T>(texture.sample(sampler, coord.xy/coord.w, metal::level(level), offset) > coord.z/coord.w);
2757
    }
2758
}
2759
2760
template <typename T>
2761
ANGLE_ALWAYS_INLINE auto ANGLE_textureProjLodOffset_impl(
2762
    thread metal::texture3d<T> &texture,
2763
    thread metal::sampler const &sampler,
2764
    thread metal::float4 const &coord,
2765
    float level,
2766
    thread int3 const &offset)
2767
{
2768
    return texture.sample(sampler, coord.xyz/coord.w, metal::level(level), offset);
2769
}
2770
)",
2771
                        functionConstants(),
2772
                        textureEnv())
2773
2774
PROGRAM_PRELUDE_DECLARE(textureProjOffset,
2775
                        R"(
2776
#define ANGLE_textureProjOffset(env, ...) ANGLE_textureProjOffset_impl(*env.texture, *env.sampler, __VA_ARGS__)
2777
2778
template <typename Texture>
2779
ANGLE_ALWAYS_INLINE auto ANGLE_textureProjOffset_impl(
2780
    thread Texture &texture,
2781
    thread metal::sampler const &sampler,
2782
    thread metal::float3 const &coord,
2783
    thread int2 const &offset,
2784
    float bias = 0)
2785
{
2786
    return texture.sample(sampler, coord.xy/coord.z, metal::bias(bias), offset);
2787
}
2788
2789
template <typename Texture>
2790
ANGLE_ALWAYS_INLINE auto ANGLE_textureProjOffset_impl(
2791
    thread Texture &texture,
2792
    thread metal::sampler const &sampler,
2793
    thread metal::float4 const &coord,
2794
    thread int2 const &offset,
2795
    float bias = 0)
2796
{
2797
    return texture.sample(sampler, coord.xy/coord.w, metal::bias(bias), offset);
2798
}
2799
2800
template <typename T>
2801
ANGLE_ALWAYS_INLINE auto ANGLE_textureProjOffset_impl(
2802
    thread metal::texture3d<T> &texture,
2803
    thread metal::sampler const &sampler,
2804
    thread metal::float4 const &coord,
2805
    thread int3 const &offset,
2806
    float bias = 0)
2807
{
2808
    return texture.sample(sampler, coord.xyz/coord.w, metal::bias(bias), offset);
2809
}
2810
)",
2811
                        textureEnv())
2812
2813
PROGRAM_PRELUDE_DECLARE(textureSize,
2814
                        R"(
2815
#define ANGLE_textureSize(env, ...) ANGLE_textureSize_impl(*env.texture, __VA_ARGS__)
2816
2817
template <typename Texture>
2818
ANGLE_ALWAYS_INLINE auto ANGLE_textureSize_impl(
2819
    thread Texture &texture,
2820
    int level)
2821
{
2822
    return int2(texture.get_width(uint(level)), texture.get_height(uint(level)));
2823
}
2824
2825
template <typename T>
2826
ANGLE_ALWAYS_INLINE auto ANGLE_textureSize_impl(
2827
    thread metal::texture3d<T> &texture,
2828
    int level)
2829
{
2830
    return int3(texture.get_width(uint(level)), texture.get_height(uint(level)), texture.get_depth(uint(level)));
2831
}
2832
2833
template <typename T>
2834
ANGLE_ALWAYS_INLINE auto ANGLE_textureSize_impl(
2835
    thread metal::depth2d_array<T> &texture,
2836
    int level)
2837
{
2838
    return int3(texture.get_width(uint(level)), texture.get_height(uint(level)), texture.get_array_size());
2839
}
2840
2841
template <typename T>
2842
ANGLE_ALWAYS_INLINE auto ANGLE_textureSize_impl(
2843
    thread metal::texture2d_array<T> &texture,
2844
    int level)
2845
{
2846
    return int3(texture.get_width(uint(level)), texture.get_height(uint(level)), texture.get_array_size());
2847
}
2848
)",
2849
                        textureEnv())
2850
2851
////////////////////////////////////////////////////////////////////////////////
2852
2853
// Returned Name is valid for as long as `buffer` is still alive.
2854
// Returns false if no template args exist.
2855
// Returns false if buffer is not large enough.
2856
//
2857
// Example:
2858
//  "foo<1,2>" --> "foo<>"
2859
static std::pair<Name, bool> MaskTemplateArgs(const Name &name, size_t bufferSize, char *buffer)
2860
{
2861
    const char *begin = name.rawName().data();
2862
    const char *end   = strchr(begin, '<');
2863
    if (!end)
2864
    {
2865
        return {{}, false};
2866
    }
2867
    size_t n = end - begin;
2868
    if (n + 3 > bufferSize)
2869
    {
2870
        return {{}, false};
2871
    }
2872
    for (size_t i = 0; i < n; ++i)
2873
    {
2874
        buffer[i] = begin[i];
2875
    }
2876
    buffer[n + 0] = '<';
2877
    buffer[n + 1] = '>';
2878
    buffer[n + 2] = '\0';
2879
    return {Name(buffer, name.symbolType()), true};
2880
}
2881
2882
ProgramPrelude::FuncToEmitter ProgramPrelude::BuildFuncToEmitter()
2883
{
2884
#define EMIT_METHOD(method) \
2885
    [](ProgramPrelude &pp, const TFunction &) -> void { return pp.method(); }
2886
    FuncToEmitter map;
2887
2888
    auto put = [&](Name name, FuncEmitter emitter) {
2889
        FuncEmitter &dest = map[name];
2890
        ASSERT(!dest);
2891
        dest = emitter;
2892
    };
2893
2894
    auto putAngle = [&](const char *nameStr, FuncEmitter emitter) {
2895
        Name name(nameStr, SymbolType::AngleInternal);
2896
        put(name, emitter);
2897
    };
2898
2899
    auto putBuiltIn = [&](const char *nameStr, FuncEmitter emitter) {
2900
        Name name(nameStr, SymbolType::BuiltIn);
2901
        put(name, emitter);
2902
    };
2903
2904
    putAngle("addressof", EMIT_METHOD(addressof));
2905
    putAngle("cast<>", EMIT_METHOD(castMatrix));
2906
    putAngle("elem_ref", EMIT_METHOD(vectorElemRef));
2907
    putAngle("flatten", EMIT_METHOD(flattenArray));
2908
    putAngle("inout", EMIT_METHOD(inout));
2909
    putAngle("out", EMIT_METHOD(out));
2910
    putAngle("swizzle_ref", EMIT_METHOD(swizzleRef));
2911
2912
    putBuiltIn("texelFetch", EMIT_METHOD(texelFetch));
2913
    putBuiltIn("texelFetchOffset", EMIT_METHOD(texelFetchOffset));
2914
    putBuiltIn("texture", [](ProgramPrelude &pp, const TFunction &func) {
2915
        const ImmutableString textureName =
2916
            GetTextureTypeName(func.getParam(0)->getType().getBasicType()).rawName();
2917
        const TType &coord          = func.getParam(1)->getType();
2918
        const TBasicType coordBasic = coord.getBasicType();
2919
        const int coordN            = coord.getNominalSize();
2920
        const bool bias             = func.getParamCount() >= 3;
2921
        if (textureName.beginsWith("metal::depth2d<"))
2922
        {
2923
            if (coordBasic == TBasicType::EbtFloat && coordN == 3)
2924
            {
2925
                if (bias)
2926
                {
2927
                    return pp.texture_depth2d_float3_float();
2928
                }
2929
                return pp.texture_depth2d_float3();
2930
            }
2931
        }
2932
        if (textureName.beginsWith("metal::depthcube<"))
2933
        {
2934
            if (coordBasic == TBasicType::EbtFloat && coordN == 4)
2935
            {
2936
                if (bias)
2937
                {
2938
                    return pp.texture_depthcube_float4_float();
2939
                }
2940
                return pp.texture_depthcube_float4();
2941
            }
2942
        }
2943
        if (textureName.beginsWith("metal::depth2d_array<"))
2944
        {
2945
            if (coordBasic == TBasicType::EbtFloat && coordN == 4)
2946
            {
2947
                if (bias)
2948
                {
2949
                    return pp.texture_depth2darray_float4_float();
2950
                }
2951
                return pp.texture_depth2darray_float4();
2952
            }
2953
        }
2954
        if (textureName.beginsWith("metal::texture2d_array<"))
2955
        {
2956
            if (coordBasic == TBasicType::EbtFloat && coordN == 3)
2957
            {
2958
                if (bias)
2959
                {
2960
                    return pp.texture_texture2darray_float3_float();
2961
                }
2962
                return pp.texture_texture2darray_float3();
2963
            }
2964
            if (coordBasic == TBasicType::EbtFloat && coordN == 4)
2965
            {
2966
                if (bias)
2967
                {
2968
                    return pp.texture_texture2darray_float4_float();
2969
                }
2970
                return pp.texture_texture2darray_float4();
2971
            }
2972
        }
2973
        if (coordBasic == TBasicType::EbtFloat && coordN == 2)
2974
        {
2975
            if (bias)
2976
            {
2977
                return pp.texture_generic_float2_float();
2978
            }
2979
            return pp.texture_generic_float2();
2980
        }
2981
        if (coordBasic == TBasicType::EbtFloat && coordN == 3)
2982
        {
2983
            if (bias)
2984
            {
2985
                return pp.texture_generic_float3_float();
2986
            }
2987
            return pp.texture_generic_float3();
2988
        }
2989
        TODO();
2990
    });
2991
    putBuiltIn("texture1DLod", EMIT_METHOD(texture1DLod));
2992
    putBuiltIn("texture1DProj", EMIT_METHOD(texture1DProj));
2993
    putBuiltIn("texture1DProjLod", EMIT_METHOD(texture1DProjLod));
2994
    putBuiltIn("texture2D", EMIT_METHOD(texture2D));
2995
    putBuiltIn("texture2DLod", EMIT_METHOD(texture2DLod));
2996
    putBuiltIn("texture2DProj", EMIT_METHOD(texture2DProj));
2997
    putBuiltIn("texture3DLod", EMIT_METHOD(texture3DLod));
2998
    putBuiltIn("texture3DProj", EMIT_METHOD(texture3DProj));
2999
    putBuiltIn("texture3DProjLod", EMIT_METHOD(texture3DProjLod));
3000
    putBuiltIn("textureCube", EMIT_METHOD(textureCube));
3001
    putBuiltIn("textureCubeLod", EMIT_METHOD(textureCubeLod));
3002
    putBuiltIn("textureCubeProj", EMIT_METHOD(textureCubeProj));
3003
    putBuiltIn("textureCubeProjLod", EMIT_METHOD(textureCubeProjLod));
3004
    putBuiltIn("texture2DProjLod", EMIT_METHOD(texture2DProjLod));
3005
    putBuiltIn("textureGrad", [](ProgramPrelude &pp, const TFunction &func) {
3006
        const ImmutableString textureName =
3007
            GetTextureTypeName(func.getParam(0)->getType().getBasicType()).rawName();
3008
        const TType &coord          = func.getParam(1)->getType();
3009
        const TBasicType coordBasic = coord.getBasicType();
3010
        const int coordN            = coord.getNominalSize();
3011
        const TType &dPdx           = func.getParam(2)->getType();
3012
        const int dPdxN             = dPdx.getNominalSize();
3013
        if (textureName.beginsWith("metal::depth2d<"))
3014
        {
3015
            if (coordBasic == TBasicType::EbtFloat && coordN == 3 && dPdxN == 2)
3016
            {
3017
                return pp.textureGrad_depth2d_float3_float2_float2();
3018
            }
3019
        }
3020
        if (textureName.beginsWith("metal::depth2d_array<"))
3021
        {
3022
            if (coordBasic == TBasicType::EbtFloat && coordN == 4 && dPdxN == 2)
3023
            {
3024
                return pp.textureGrad_depth2darray_float4_float2_float2();
3025
            }
3026
        }
3027
        if (textureName.beginsWith("metal::depthcube<"))
3028
        {
3029
            if (coordBasic == TBasicType::EbtFloat && coordN == 4 && dPdxN == 3)
3030
            {
3031
                return pp.textureGrad_depthcube_float4_float3_float3();
3032
            }
3033
        }
3034
        if (textureName.beginsWith("metal::texturecube<"))
3035
        {
3036
            if (coordBasic == TBasicType::EbtFloat && coordN == 3 && dPdxN == 3)
3037
            {
3038
                return pp.textureGrad_texturecube_float3_float3_float3();
3039
            }
3040
        }
3041
        if (coordBasic == TBasicType::EbtFloat && coordN == 3 && dPdxN == 2)
3042
        {
3043
            return pp.textureGrad_generic_float3_float2_float2();
3044
        }
3045
        if (coordBasic == TBasicType::EbtFloat && coordN == 4 && dPdxN == 2)
3046
        {
3047
            return pp.textureGrad_generic_float4_float2_float2();
3048
        }
3049
        if (coordBasic == TBasicType::EbtFloat && coordN == dPdxN)
3050
        {
3051
            return pp.textureGrad_generic_floatN_floatN_floatN();
3052
        }
3053
        TODO();
3054
    });
3055
    putBuiltIn("textureGradOffset", [](ProgramPrelude &pp, const TFunction &func) {
3056
        const ImmutableString textureName =
3057
            GetTextureTypeName(func.getParam(0)->getType().getBasicType()).rawName();
3058
        const TType &coord          = func.getParam(1)->getType();
3059
        const TBasicType coordBasic = coord.getBasicType();
3060
        const int coordN            = coord.getNominalSize();
3061
        const TType &dPdx           = func.getParam(2)->getType();
3062
        const int dPdxN             = dPdx.getNominalSize();
3063
        if (textureName.beginsWith("metal::depth2d<"))
3064
        {
3065
            if (coordBasic == TBasicType::EbtFloat && coordN == 3 && dPdxN == 2)
3066
            {
3067
                return pp.textureGradOffset_depth2d_float3_float2_float2_int2();
3068
            }
3069
        }
3070
        if (textureName.beginsWith("metal::depth2d_array<"))
3071
        {
3072
            if (coordBasic == TBasicType::EbtFloat && coordN == 4 && dPdxN == 2)
3073
            {
3074
                return pp.textureGradOffset_depth2darray_float4_float2_float2_int2();
3075
            }
3076
        }
3077
        if (textureName.beginsWith("metal::depthcube<"))
3078
        {
3079
            if (coordBasic == TBasicType::EbtFloat && coordN == 4 && dPdxN == 3)
3080
            {
3081
                return pp.textureGradOffset_depthcube_float4_float3_float3_int3();
3082
            }
3083
        }
3084
        if (textureName.beginsWith("metal::texturecube<"))
3085
        {
3086
            if (coordBasic == TBasicType::EbtFloat && coordN == 3 && dPdxN == 3)
3087
            {
3088
                return pp.textureGradOffset_texturecube_float3_float3_float3_int3();
3089
            }
3090
        }
3091
        if (coordBasic == TBasicType::EbtFloat && coordN == 3 && dPdxN == 2)
3092
        {
3093
            return pp.textureGradOffset_generic_float3_float2_float2_int2();
3094
        }
3095
        if (coordBasic == TBasicType::EbtFloat && coordN == 4 && dPdxN == 2)
3096
        {
3097
            return pp.textureGradOffset_generic_float4_float2_float2_int2();
3098
        }
3099
        if (coordBasic == TBasicType::EbtFloat && coordN == dPdxN)
3100
        {
3101
            return pp.textureGradOffset_generic_floatN_floatN_floatN_intN();
3102
        }
3103
        TODO();
3104
    });
3105
    putBuiltIn("textureLod", [](ProgramPrelude &pp, const TFunction &func) {
3106
        const ImmutableString textureName =
3107
            GetTextureTypeName(func.getParam(0)->getType().getBasicType()).rawName();
3108
        const TType &coord          = func.getParam(1)->getType();
3109
        const TBasicType coordBasic = coord.getBasicType();
3110
        const int coordN            = coord.getNominalSize();
3111
        if (textureName.beginsWith("metal::depth2d<"))
3112
        {
3113
            if (coordBasic == TBasicType::EbtFloat && coordN == 3)
3114
            {
3115
                return pp.textureLod_depth2d_float3();
3116
            }
3117
        }
3118
        if (textureName.beginsWith("metal::texture2d_array<"))
3119
        {
3120
            if (coordBasic == TBasicType::EbtFloat && coordN == 3)
3121
            {
3122
                return pp.textureLod_texture2darray_float3();
3123
            }
3124
            if (coordBasic == TBasicType::EbtFloat && coordN == 4)
3125
            {
3126
                return pp.textureLod_texture2darray_float4();
3127
            }
3128
        }
3129
        if (coordBasic == TBasicType::EbtFloat && coordN == 2)
3130
        {
3131
            return pp.textureLod_generic_float2();
3132
        }
3133
        if (coordBasic == TBasicType::EbtFloat && coordN == 3)
3134
        {
3135
            return pp.textureLod_generic_float3();
3136
        }
3137
        TODO();
3138
    });
3139
    putBuiltIn("textureLodOffset", EMIT_METHOD(textureLodOffset));
3140
    putBuiltIn("textureOffset", EMIT_METHOD(textureOffset));
3141
    putBuiltIn("textureProj", EMIT_METHOD(textureProj));
3142
    putBuiltIn("textureProjGrad", [](ProgramPrelude &pp, const TFunction &func) {
3143
        const ImmutableString textureName =
3144
            GetTextureTypeName(func.getParam(0)->getType().getBasicType()).rawName();
3145
        const TType &coord          = func.getParam(1)->getType();
3146
        const TBasicType coordBasic = coord.getBasicType();
3147
        const int coordN            = coord.getNominalSize();
3148
        const TType &dPdx           = func.getParam(2)->getType();
3149
        const int dPdxN             = dPdx.getNominalSize();
3150
        if (textureName.beginsWith("metal::depth2d<"))
3151
        {
3152
            if (coordBasic == TBasicType::EbtFloat && coordN == 4 && dPdxN == 2)
3153
            {
3154
                return pp.textureProjGrad_depth2d_float4_float2_float2();
3155
            }
3156
        }
3157
        if (textureName.beginsWith("metal::texture3d<"))
3158
        {
3159
            if (coordBasic == TBasicType::EbtFloat && coordN == 4 && dPdxN == 3)
3160
            {
3161
                return pp.textureProjGrad_texture3d_float4_float3_float3();
3162
            }
3163
        }
3164
        if (coordBasic == TBasicType::EbtFloat && coordN == 3 && dPdxN == 2)
3165
        {
3166
            return pp.textureProjGrad_generic_float3_float2_float2();
3167
        }
3168
        if (coordBasic == TBasicType::EbtFloat && coordN == 4 && dPdxN == 2)
3169
        {
3170
            return pp.textureProjGrad_generic_float4_float2_float2();
3171
        }
3172
        TODO();
3173
    });
3174
    putBuiltIn("textureProjGradOffset", [](ProgramPrelude &pp, const TFunction &func) {
3175
        const ImmutableString textureName =
3176
            GetTextureTypeName(func.getParam(0)->getType().getBasicType()).rawName();
3177
        const TType &coord          = func.getParam(1)->getType();
3178
        const TBasicType coordBasic = coord.getBasicType();
3179
        const int coordN            = coord.getNominalSize();
3180
        const TType &dPdx           = func.getParam(2)->getType();
3181
        const int dPdxN             = dPdx.getNominalSize();
3182
        if (textureName.beginsWith("metal::depth2d<"))
3183
        {
3184
            if (coordBasic == TBasicType::EbtFloat && coordN == 4 && dPdxN == 2)
3185
            {
3186
                return pp.textureProjGradOffset_depth2d_float4_float2_float2_int2();
3187
            }
3188
        }
3189
        if (textureName.beginsWith("metal::texture3d<"))
3190
        {
3191
            if (coordBasic == TBasicType::EbtFloat && coordN == 4 && dPdxN == 3)
3192
            {
3193
                return pp.textureProjGradOffset_texture3d_float4_float3_float3_int3();
3194
            }
3195
        }
3196
        if (coordBasic == TBasicType::EbtFloat && coordN == 3 && dPdxN == 2)
3197
        {
3198
            return pp.textureProjGradOffset_generic_float3_float2_float2_int2();
3199
        }
3200
        if (coordBasic == TBasicType::EbtFloat && coordN == 4 && dPdxN == 2)
3201
        {
3202
            return pp.textureProjGradOffset_generic_float4_float2_float2_int2();
3203
        }
3204
        TODO();
3205
    });
3206
    putBuiltIn("textureProjLod", [](ProgramPrelude &pp, const TFunction &func) {
3207
        const ImmutableString textureName =
3208
            GetTextureTypeName(func.getParam(0)->getType().getBasicType()).rawName();
3209
        const TType &coord          = func.getParam(1)->getType();
3210
        const TBasicType coordBasic = coord.getBasicType();
3211
        const int coordN            = coord.getNominalSize();
3212
        if (textureName.beginsWith("metal::depth2d<"))
3213
        {
3214
            if (coordBasic == TBasicType::EbtFloat && coordN == 4)
3215
            {
3216
                return pp.textureProjLod_depth2d_float4();
3217
            }
3218
        }
3219
        if (textureName.beginsWith("metal::texture3d<"))
3220
        {
3221
            if (coordBasic == TBasicType::EbtFloat && coordN == 4)
3222
            {
3223
                return pp.textureProjLod_texture3d_float4();
3224
            }
3225
        }
3226
        if (coordBasic == TBasicType::EbtFloat && coordN == 3)
3227
        {
3228
            return pp.textureProjLod_generic_float3();
3229
        }
3230
        if (coordBasic == TBasicType::EbtFloat && coordN == 4)
3231
        {
3232
            return pp.textureProjLod_generic_float4();
3233
        }
3234
        TODO();
3235
    });
3236
    putBuiltIn("textureProjLodOffset", EMIT_METHOD(textureProjLodOffset));
3237
    putBuiltIn("textureProjOffset", EMIT_METHOD(textureProjOffset));
3238
    putBuiltIn("textureSize", EMIT_METHOD(textureSize));
3239
3240
    return map;
3241
3242
#undef EMIT_METHOD
3243
}
3244
3245
void ProgramPrelude::visitOperator(TOperator op,
3246
                                   const TFunction *func,
3247
                                   const TType *argType0,
3248
                                   const TType *argType1)
3249
{
3250
    switch (op)
3251
    {
3252
        case TOperator::EOpRadians:
3253
            radians();
3254
            break;
3255
        case TOperator::EOpDegrees:
3256
            degrees();
3257
            break;
3258
        case TOperator::EOpAtan:
3259
            atan();
3260
            break;
3261
        case TOperator::EOpMod:
3262
            mod();
3263
            break;
3264
        case TOperator::EOpRefract:
3265
            refract();
3266
            break;
3267
        case TOperator::EOpDistance:
3268
            distance();
3269
            break;
3270
        case TOperator::EOpLength:
3271
            length();
3272
            break;
3273
        case TOperator::EOpDot:
3274
            dot();
3275
            break;
3276
        case TOperator::EOpNormalize:
3277
            normalize();
3278
            break;
3279
        case TOperator::EOpFaceforward:
3280
            faceforward();
3281
            break;
3282
        case TOperator::EOpReflect:
3283
            reflect();
3284
            break;
3285
3286
        case TOperator::EOpSin:
3287
        case TOperator::EOpCos:
3288
        case TOperator::EOpTan:
3289
        case TOperator::EOpAsin:
3290
        case TOperator::EOpAcos:
3291
        case TOperator::EOpSinh:
3292
        case TOperator::EOpCosh:
3293
        case TOperator::EOpTanh:
3294
        case TOperator::EOpAsinh:
3295
        case TOperator::EOpAcosh:
3296
        case TOperator::EOpAtanh:
3297
        case TOperator::EOpAbs:
3298
        case TOperator::EOpFma:
3299
        case TOperator::EOpPow:
3300
        case TOperator::EOpExp:
3301
        case TOperator::EOpExp2:
3302
        case TOperator::EOpLog:
3303
        case TOperator::EOpLog2:
3304
        case TOperator::EOpSqrt:
3305
        case TOperator::EOpFloor:
3306
        case TOperator::EOpTrunc:
3307
        case TOperator::EOpCeil:
3308
        case TOperator::EOpFract:
3309
        case TOperator::EOpRound:
3310
        case TOperator::EOpRoundEven:
3311
        case TOperator::EOpModf:
3312
        case TOperator::EOpLdexp:
3313
        case TOperator::EOpFrexp:
3314
        case TOperator::EOpInversesqrt:
3315
            include_metal_math();
3316
            break;
3317
3318
        case TOperator::EOpEqual:
3319
            if (argType0->isVector() && argType1->isVector())
3320
            {
3321
                equalVector();
3322
            }
3323
            // Even if Arg0 is a vector or matrix, it could also be an array.
3324
            if (argType0->isArray() && argType1->isArray())
3325
            {
3326
                equalArray();
3327
            }
3328
            break;
3329
3330
        case TOperator::EOpNotEqual:
3331
            if (argType0->isVector() && argType1->isVector())
3332
            {
3333
                notEqualVector();
3334
            }
3335
            else if (argType0->getStruct() && argType1->getStruct())
3336
            {
3337
                notEqualStruct();
3338
            }
3339
            // Same as above.
3340
            if (argType0->isArray() && argType1->isArray())
3341
            {
3342
                notEqualArray();
3343
            }
3344
            break;
3345
3346
        case TOperator::EOpCross:
3347
            include_metal_geometric();
3348
            break;
3349
3350
        case TOperator::EOpSign:
3351
            sign();
3352
            break;
3353
3354
        case TOperator::EOpClamp:
3355
        case TOperator::EOpMin:
3356
        case TOperator::EOpMax:
3357
        case TOperator::EOpMix:
3358
        case TOperator::EOpStep:
3359
        case TOperator::EOpSmoothstep:
3360
            include_metal_common();
3361
            break;
3362
3363
        case TOperator::EOpAll:
3364
        case TOperator::EOpAny:
3365
        case TOperator::EOpIsnan:
3366
        case TOperator::EOpIsinf:
3367
            include_metal_relational();
3368
            break;
3369
3370
        case TOperator::EOpDFdx:
3371
        case TOperator::EOpDFdy:
3372
        case TOperator::EOpFwidth:
3373
            include_metal_graphics();
3374
            break;
3375
3376
        case TOperator::EOpTranspose:
3377
        case TOperator::EOpDeterminant:
3378
            include_metal_matrix();
3379
            break;
3380
3381
        case TOperator::EOpAdd:
3382
            if (argType0->isMatrix() && argType1->isScalar())
3383
            {
3384
                addMatrixScalar();
3385
            }
3386
            break;
3387
3388
        case TOperator::EOpSub:
3389
            if (argType0->isMatrix() && argType1->isScalar())
3390
            {
3391
                subMatrixScalar();
3392
            }
3393
            break;
3394
3395
        case TOperator::EOpDiv:
3396
            if (argType0->isMatrix())
3397
            {
3398
                if (argType1->isMatrix())
3399
                {
3400
                    componentWiseDivide();
3401
                }
3402
                else if (argType1->isScalar())
3403
                {
3404
                    divMatrixScalar();
3405
                }
3406
            }
3407
            break;
3408
3409
        case TOperator::EOpDivAssign:
3410
            if (argType0->isMatrix() && argType1->isMatrix())
3411
            {
3412
                componentWiseDivideAssign();
3413
            }
3414
            break;
3415
3416
        case TOperator::EOpMulMatrixComponentWise:
3417
            if (argType0->isMatrix() && argType1->isMatrix())
3418
            {
3419
                componentWiseMultiply();
3420
            }
3421
            break;
3422
3423
        case TOperator::EOpOuterProduct:
3424
            outerProduct();
3425
            break;
3426
3427
        case TOperator::EOpInverse:
3428
            switch (argType0->getCols())
3429
            {
3430
                case 2:
3431
                    inverse2();
3432
                    break;
3433
                case 3:
3434
                    inverse3();
3435
                    break;
3436
                case 4:
3437
                    inverse4();
3438
                    break;
3439
                default:
3440
                    LOGIC_ERROR();
3441
            }
3442
            break;
3443
3444
        case TOperator::EOpMatrixTimesMatrixAssign:
3445
            matmulAssign();
3446
            break;
3447
3448
        case TOperator::EOpPreIncrement:
3449
            if (argType0->isMatrix())
3450
            {
3451
                preIncrementMatrix();
3452
            }
3453
            break;
3454
3455
        case TOperator::EOpPostIncrement:
3456
            if (argType0->isMatrix())
3457
            {
3458
                postIncrementMatrix();
3459
            }
3460
            break;
3461
3462
        case TOperator::EOpPreDecrement:
3463
            if (argType0->isMatrix())
3464
            {
3465
                preDecrementMatrix();
3466
            }
3467
            break;
3468
3469
        case TOperator::EOpPostDecrement:
3470
            if (argType0->isMatrix())
3471
            {
3472
                postDecrementMatrix();
3473
            }
3474
            break;
3475
3476
            break;
3477
3478
        case TOperator::EOpNegative:
3479
            if (argType0->isMatrix())
3480
            {
3481
                negateMatrix();
3482
            }
3483
            break;
3484
3485
        case TOperator::EOpComma:
3486
        case TOperator::EOpAssign:
3487
        case TOperator::EOpInitialize:
3488
        case TOperator::EOpAddAssign:
3489
        case TOperator::EOpSubAssign:
3490
        case TOperator::EOpMulAssign:
3491
        case TOperator::EOpIModAssign:
3492
        case TOperator::EOpBitShiftLeftAssign:
3493
        case TOperator::EOpBitShiftRightAssign:
3494
        case TOperator::EOpBitwiseAndAssign:
3495
        case TOperator::EOpBitwiseXorAssign:
3496
        case TOperator::EOpBitwiseOrAssign:
3497
        case TOperator::EOpMul:
3498
        case TOperator::EOpIMod:
3499
        case TOperator::EOpBitShiftLeft:
3500
        case TOperator::EOpBitShiftRight:
3501
        case TOperator::EOpBitwiseAnd:
3502
        case TOperator::EOpBitwiseXor:
3503
        case TOperator::EOpBitwiseOr:
3504
        case TOperator::EOpLessThan:
3505
        case TOperator::EOpGreaterThan:
3506
        case TOperator::EOpLessThanEqual:
3507
        case TOperator::EOpGreaterThanEqual:
3508
        case TOperator::EOpLessThanComponentWise:
3509
        case TOperator::EOpLessThanEqualComponentWise:
3510
        case TOperator::EOpGreaterThanEqualComponentWise:
3511
        case TOperator::EOpGreaterThanComponentWise:
3512
        case TOperator::EOpLogicalOr:
3513
        case TOperator::EOpLogicalXor:
3514
        case TOperator::EOpLogicalAnd:
3515
        case TOperator::EOpPositive:
3516
        case TOperator::EOpLogicalNot:
3517
        case TOperator::EOpLogicalNotComponentWise:
3518
        case TOperator::EOpBitwiseNot:
3519
        case TOperator::EOpVectorTimesScalarAssign:
3520
        case TOperator::EOpVectorTimesMatrixAssign:
3521
        case TOperator::EOpMatrixTimesScalarAssign:
3522
        case TOperator::EOpVectorTimesScalar:
3523
        case TOperator::EOpVectorTimesMatrix:
3524
        case TOperator::EOpMatrixTimesVector:
3525
        case TOperator::EOpMatrixTimesScalar:
3526
        case TOperator::EOpMatrixTimesMatrix:
3527
        case TOperator::EOpReturn:
3528
        case TOperator::EOpBreak:
3529
        case TOperator::EOpContinue:
3530
        case TOperator::EOpEqualComponentWise:
3531
        case TOperator::EOpNotEqualComponentWise:
3532
        case TOperator::EOpIndexDirect:
3533
        case TOperator::EOpIndexIndirect:
3534
        case TOperator::EOpIndexDirectStruct:
3535
        case TOperator::EOpIndexDirectInterfaceBlock:
3536
        case TOperator::EOpFloatBitsToInt:
3537
        case TOperator::EOpIntBitsToFloat:
3538
        case TOperator::EOpUintBitsToFloat:
3539
        case TOperator::EOpFloatBitsToUint:
3540
        case TOperator::EOpNull:
3541
            // do nothing
3542
            break;
3543
3544
        case TOperator::EOpKill:
3545
            include_metal_graphics();
3546
            break;
3547
3548
        case TOperator::EOpPackUnorm2x16:
3549
        case TOperator::EOpPackSnorm2x16:
3550
        case TOperator::EOpPackUnorm4x8:
3551
        case TOperator::EOpPackSnorm4x8:
3552
        case TOperator::EOpUnpackSnorm2x16:
3553
        case TOperator::EOpUnpackUnorm2x16:
3554
        case TOperator::EOpUnpackUnorm4x8:
3555
        case TOperator::EOpUnpackSnorm4x8:
3556
            include_metal_pack();
3557
            break;
3558
3559
        case TOperator::EOpPackHalf2x16:
3560
            pack_half_2x16();
3561
            break;
3562
        case TOperator::EOpUnpackHalf2x16:
3563
            unpack_half_2x16();
3564
            break;
3565
3566
        case TOperator::EOpBitfieldExtract:
3567
        case TOperator::EOpBitfieldInsert:
3568
        case TOperator::EOpBitfieldReverse:
3569
        case TOperator::EOpBitCount:
3570
        case TOperator::EOpFindLSB:
3571
        case TOperator::EOpFindMSB:
3572
        case TOperator::EOpUaddCarry:
3573
        case TOperator::EOpUsubBorrow:
3574
        case TOperator::EOpUmulExtended:
3575
        case TOperator::EOpImulExtended:
3576
        case TOperator::EOpBarrier:
3577
        case TOperator::EOpMemoryBarrier:
3578
        case TOperator::EOpMemoryBarrierAtomicCounter:
3579
        case TOperator::EOpMemoryBarrierBuffer:
3580
        case TOperator::EOpMemoryBarrierImage:
3581
        case TOperator::EOpMemoryBarrierShared:
3582
        case TOperator::EOpGroupMemoryBarrier:
3583
        case TOperator::EOpAtomicAdd:
3584
        case TOperator::EOpAtomicMin:
3585
        case TOperator::EOpAtomicMax:
3586
        case TOperator::EOpAtomicAnd:
3587
        case TOperator::EOpAtomicOr:
3588
        case TOperator::EOpAtomicXor:
3589
        case TOperator::EOpAtomicExchange:
3590
        case TOperator::EOpAtomicCompSwap:
3591
        case TOperator::EOpEmitVertex:
3592
        case TOperator::EOpEndPrimitive:
3593
        case TOperator::EOpFTransform:
3594
        case TOperator::EOpPackDouble2x32:
3595
        case TOperator::EOpUnpackDouble2x32:
3596
        case TOperator::EOpArrayLength:
3597
            TODO();
3598
            break;
3599
3600
        case TOperator::EOpConstruct:
3601
            ASSERT(!func);
3602
            break;
3603
3604
        case TOperator::EOpCallFunctionInAST:
3605
        case TOperator::EOpCallInternalRawFunction:
3606
        case TOperator::EOpCallBuiltInFunction:
3607
            ASSERT(func);
3608
            if (mHandled.insert(func).second)
3609
            {
3610
                const Name name(*func);
3611
                const auto end = mFuncToEmitter.end();
3612
                auto iter      = mFuncToEmitter.find(name);
3613
                if (iter == end)
3614
                {
3615
                    char buffer[32];
3616
                    auto mask = MaskTemplateArgs(name, sizeof(buffer), buffer);
3617
                    if (mask.second)
3618
                    {
3619
                        iter = mFuncToEmitter.find(mask.first);
3620
                    }
3621
                }
3622
                if (iter != end)
3623
                {
3624
                    const auto &emitter = iter->second;
3625
                    emitter(*this, *func);
3626
                }
3627
            }
3628
            break;
3629
    }
3630
}
3631
3632
void ProgramPrelude::visitVariable(const Name &name, const TType &type)
3633
{
3634
    if (const TStructure *s = type.getStruct())
3635
    {
3636
        const Name typeName(*s);
3637
        if (typeName.beginsWith(Name("TextureEnv<")))
3638
        {
3639
            textureEnv();
3640
        }
3641
    }
3642
    else
3643
    {
3644
        if (name == constant_names::kRasterizationDiscardEnabled)
3645
        {
3646
            functionConstants();
3647
        }
3648
    }
3649
}
3650
3651
void ProgramPrelude::visitVariable(const TVariable &var)
3652
{
3653
    if (mHandled.insert(&var).second)
3654
    {
3655
        visitVariable(Name(var), var.getType());
3656
    }
3657
}
3658
3659
void ProgramPrelude::visitStructure(const TStructure &s)
3660
{
3661
    if (mHandled.insert(&s).second)
3662
    {
3663
        for (const TField *field : s.fields())
3664
        {
3665
            const TType &type = *field->type();
3666
            visitVariable(Name(*field), type);
3667
        }
3668
    }
3669
}
3670
3671
bool ProgramPrelude::visitBinary(Visit visit, TIntermBinary *node)
3672
{
3673
    const TType &leftType  = node->getLeft()->getType();
3674
    const TType &rightType = node->getRight()->getType();
3675
    visitOperator(node->getOp(), nullptr, &leftType, &rightType);
3676
    return true;
3677
}
3678
3679
bool ProgramPrelude::visitUnary(Visit visit, TIntermUnary *node)
3680
{
3681
    const TType &argType = node->getOperand()->getType();
3682
    visitOperator(node->getOp(), nullptr, &argType);
3683
    return true;
3684
}
3685
3686
bool ProgramPrelude::visitAggregate(Visit visit, TIntermAggregate *node)
3687
{
3688
    const size_t argCount = node->getChildCount();
3689
3690
    auto getArgType = [node, argCount](size_t index) -> const TType & {
3691
        ASSERT(index < argCount);
3692
        TIntermTyped *arg = node->getChildNode(index)->getAsTyped();
3693
        ASSERT(arg);
3694
        return arg->getType();
3695
    };
3696
3697
    const TFunction *func = node->getFunction();
3698
3699
    switch (node->getChildCount())
3700
    {
3701
        case 0:
3702
        {
3703
            visitOperator(node->getOp(), func, nullptr);
3704
        }
3705
        break;
3706
3707
        case 1:
3708
        {
3709
            const TType &argType0 = getArgType(0);
3710
            visitOperator(node->getOp(), func, &argType0);
3711
        }
3712
        break;
3713
3714
        case 2:
3715
        {
3716
            const TType &argType0 = getArgType(0);
3717
            const TType &argType1 = getArgType(1);
3718
            visitOperator(node->getOp(), func, &argType0, &argType1);
3719
        }
3720
        break;
3721
3722
        default:
3723
        {
3724
            const TType &argType0 = getArgType(0);
3725
            const TType &argType1 = getArgType(1);
3726
            visitOperator(node->getOp(), func, &argType0, &argType1);
3727
        }
3728
        break;
3729
    }
3730
3731
    return true;
3732
}
3733
3734
bool ProgramPrelude::visitDeclaration(Visit, TIntermDeclaration *node)
3735
{
3736
    Declaration decl  = ViewDeclaration(*node);
3737
    const TType &type = decl.symbol.getType();
3738
    if (type.isStructSpecifier())
3739
    {
3740
        const TStructure *s = type.getStruct();
3741
        ASSERT(s);
3742
        visitStructure(*s);
3743
    }
3744
    return true;
3745
}
3746
3747
void ProgramPrelude::visitSymbol(TIntermSymbol *node)
3748
{
3749
    visitVariable(node->variable());
3750
}
3751
3752
bool sh::EmitProgramPrelude(TIntermBlock &root, TInfoSinkBase &out, const ProgramPreludeConfig &ppc)
3753
{
3754
    ProgramPrelude programPrelude(out, ppc);
3755
    root.traverse(&programPrelude);
3756
    return true;
3757
}
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/ProgramPrelude.h +35 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/ProgramPrelude.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_PROGRAMPRELUDE_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_PROGRAMPRELUDE_H_
9
10
#include <unordered_set>
11
12
#include "common/angleutils.h"
13
14
namespace sh
15
{
16
17
class TInfoSinkBase;
18
class TIntermBlock;
19
20
struct ProgramPreludeConfig
21
{
22
    bool hasStructEq = false;
23
};
24
25
// This emits fixed helper Metal code directly without adding code to the AST. This walks the AST to
26
// figure out the required what prelude MSL code is needed for various things in the AST. You can
27
// think of this as effectively inlining various portions of a helper library into the emitted
28
// Metal program.
29
ANGLE_NO_DISCARD bool EmitProgramPrelude(TIntermBlock &root,
30
                                         TInfoSinkBase &out,
31
                                         const ProgramPreludeConfig &ppc);
32
33
}  // namespace sh
34
35
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_PROGRAMPRELUDE_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/ReduceInterfaceBlocks.cpp +130 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/ReduceInterfaceBlocks.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include <algorithm>
8
#include <unordered_map>
9
10
#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
11
#include "compiler/translator/TranslatorMetalDirect/ReduceInterfaceBlocks.h"
12
#include "compiler/translator/tree_ops/SeparateDeclarations.h"
13
#include "compiler/translator/tree_util/IntermRebuild.h"
14
15
using namespace sh;
16
17
////////////////////////////////////////////////////////////////////////////////
18
19
namespace
20
{
21
22
class Reducer : public TIntermRebuild
23
{
24
    std::unordered_map<const TInterfaceBlock *, std::map<ImmutableString, const TVariable *>>
25
        mLiftedMap;
26
    std::unordered_map<const TVariable *, const TVariable *> mInstanceMap;
27
28
  public:
29
    Reducer(TCompiler &compiler) : TIntermRebuild(compiler, true, false) {}
30
31
    PreResult visitDeclarationPre(TIntermDeclaration &declNode) override
32
    {
33
        ASSERT(declNode.getChildCount() == 1);
34
        TIntermNode &node = *declNode.getChildNode(0);
35
36
        if (TIntermSymbol *symbolNode = node.getAsSymbolNode())
37
        {
38
            const TVariable &var        = symbolNode->variable();
39
            const TType &type           = var.getType();
40
            const SymbolType symbolType = var.symbolType();
41
            if (const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock())
42
            {
43
                if (symbolType == SymbolType::Empty)
44
                {
45
                    auto &nameToVar = mLiftedMap[interfaceBlock];
46
                    std::vector<TIntermNode *> replacements;
47
                    for (TField *field : interfaceBlock->fields())
48
                    {
49
                        auto &liftedType = CloneType(*field->type());
50
                        ASSERT(liftedType.getQualifier() == TQualifier::EvqUniform ||
51
                               liftedType.getQualifier() == TQualifier::EvqGlobal);
52
                        liftedType.setQualifier(TQualifier::EvqUniform);
53
                        auto *liftedVar = new TVariable(&mSymbolTable, field->name(), &liftedType,
54
                                                        field->symbolType());
55
56
                        nameToVar[field->name()] = liftedVar;
57
58
                        replacements.push_back(
59
                            new TIntermDeclaration{new TIntermSymbol(liftedVar)});
60
                    }
61
                    return PreResult::Multi(std::move(replacements));
62
                }
63
                else
64
                {
65
                    ASSERT(type.getQualifier() == TQualifier::EvqUniform);
66
67
                    auto &structure =
68
                        *new TStructure(&mSymbolTable, interfaceBlock->name(),
69
                                        &interfaceBlock->fields(), interfaceBlock->symbolType());
70
                    auto &structVar = CreateStructTypeVariable(mSymbolTable, structure);
71
                    auto &instanceVar =
72
                        CreateInstanceVariable(mSymbolTable, structure, Name(var),
73
                                               TQualifier::EvqUniform, &type.getArraySizes());
74
75
                    mInstanceMap[&var] = &instanceVar;
76
77
                    TIntermNode *replacements[] = {
78
                        new TIntermDeclaration{new TIntermSymbol(&structVar)},
79
                        new TIntermDeclaration{new TIntermSymbol(&instanceVar)}};
80
                    return PreResult::Multi(std::begin(replacements), std::end(replacements));
81
                }
82
            }
83
        }
84
85
        return {declNode, VisitBits::Neither};
86
    }
87
88
    PreResult visitSymbolPre(TIntermSymbol &symbolNode) override
89
    {
90
        const TVariable &var = symbolNode.variable();
91
        {
92
            auto it = mInstanceMap.find(&var);
93
            if (it != mInstanceMap.end())
94
            {
95
                return *new TIntermSymbol(it->second);
96
            }
97
        }
98
        if (const TInterfaceBlock *ib = var.getType().getInterfaceBlock())
99
        {
100
            auto it = mLiftedMap.find(ib);
101
            if (it != mLiftedMap.end())
102
            {
103
                auto *liftedVar = it->second[var.name()];
104
                ASSERT(liftedVar);
105
                return *new TIntermSymbol(liftedVar);
106
            }
107
        }
108
        return symbolNode;
109
    }
110
};
111
112
}  // anonymous namespace
113
114
////////////////////////////////////////////////////////////////////////////////
115
116
bool sh::ReduceInterfaceBlocks(TCompiler &compiler, TIntermBlock &root)
117
{
118
    Reducer reducer(compiler);
119
    if (!reducer.rebuildRoot(root))
120
    {
121
        return false;
122
    }
123
124
    if (!SeparateDeclarations(&compiler, &root))
125
    {
126
        return false;
127
    }
128
129
    return true;
130
}
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/ReduceInterfaceBlocks.h +35 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/ReduceInterfaceBlocks.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REDUCEINTERFACEBLOCKS_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REDUCEINTERFACEBLOCKS_H_
9
10
#include "common/angleutils.h"
11
#include "compiler/translator/Compiler.h"
12
13
namespace sh
14
{
15
16
// This rewrites interface block declarations only.
17
//
18
// Access of interface blocks is not rewritten (e.g. TOperator::EOpIndexDirectInterfaceBlock). //
19
// XXX: ^ Still true?
20
//
21
// Example:
22
//  uniform Foo { int x; };
23
// Becomes:
24
//  uniform int x;
25
//
26
// Example:
27
//  uniform Foo { int x; } foo;
28
// Becomes:
29
//  struct Foo { int x; }; uniform Foo x;
30
//
31
ANGLE_NO_DISCARD bool ReduceInterfaceBlocks(TCompiler &compiler, TIntermBlock &root);
32
33
}  // namespace sh
34
35
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REDUCEINTERFACEBLOCKS_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/Reference.h +50 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/Reference.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REFERENCE_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REFERENCE_H_
9
10
namespace sh
11
{
12
13
// Similar to std::reference_wrapper, but also lifts comparison operators.
14
template <typename T>
15
class Ref
16
{
17
  public:
18
    Ref(const Ref &) = default;
19
    Ref(Ref &&)      = default;
20
    Ref(T &ref) : mPtr(&ref) {}
21
22
    Ref &operator=(const Ref &) = default;
23
    Ref &operator=(Ref &&) = default;
24
25
    bool operator==(const Ref &other) const { return *mPtr == *other.mPtr; }
26
    bool operator!=(const Ref &other) const { return *mPtr != *other.mPtr; }
27
    bool operator<=(const Ref &other) const { return *mPtr <= *other.mPtr; }
28
    bool operator>=(const Ref &other) const { return *mPtr >= *other.mPtr; }
29
    bool operator<(const Ref &other) const { return *mPtr < *other.mPtr; }
30
    bool operator>(const Ref &other) const { return *mPtr > *other.mPtr; }
31
32
    T &get() { return *mPtr; }
33
    T const &get() const { return *mPtr; }
34
35
    operator T &() { return *mPtr; }
36
    operator T const &() const { return *mPtr; }
37
38
    operator T *() { return *mPtr; }
39
    operator T const *() const { return *mPtr; }
40
41
  private:
42
    T *mPtr;
43
};
44
45
template <typename T>
46
using CRef = Ref<T const>;
47
48
}  // namespace sh
49
50
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REFERENCE_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/RewriteCaseDeclarations.cpp +91 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/RewriteCaseDeclarations.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include "compiler/translator/TranslatorMetalDirect/RewriteCaseDeclarations.h"
8
#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
9
#include "compiler/translator/tree_util/IntermRebuild.h"
10
11
using namespace sh;
12
13
////////////////////////////////////////////////////////////////////////////////
14
15
namespace
16
{
17
18
class Rewriter : public TIntermRebuild
19
{
20
    std::vector<std::vector<const TVariable *>> mDeclaredVarStack;
21
22
  public:
23
    Rewriter(TCompiler &compiler) : TIntermRebuild(compiler, true, true) {}
24
25
    ~Rewriter() override { ASSERT(mDeclaredVarStack.empty()); }
26
27
  private:
28
    PreResult visitSwitchPre(TIntermSwitch &node) override
29
    {
30
        mDeclaredVarStack.emplace_back();
31
        return node;
32
    }
33
34
    PostResult visitSwitchPost(TIntermSwitch &node) override
35
    {
36
        ASSERT(!mDeclaredVarStack.empty());
37
        const auto vars = std::move(mDeclaredVarStack.back());
38
        mDeclaredVarStack.pop_back();
39
        if (!vars.empty())
40
        {
41
            auto &block = *new TIntermBlock();
42
            for (const TVariable *var : vars)
43
            {
44
                block.appendStatement(new TIntermDeclaration{var});
45
            }
46
            block.appendStatement(&node);
47
            return block;
48
        }
49
        return node;
50
    }
51
52
    PreResult visitDeclarationPre(TIntermDeclaration &node) override
53
    {
54
        if (!mDeclaredVarStack.empty())
55
        {
56
            TIntermNode *parent = getParentNode();
57
            if (parent->getAsBlock())
58
            {
59
                TIntermNode *grandparent = getParentNode(1);
60
                if (grandparent && grandparent->getAsSwitchNode())
61
                {
62
                    Declaration decl = ViewDeclaration(node);
63
                    mDeclaredVarStack.back().push_back(&decl.symbol.variable());
64
                    if (decl.initExpr)
65
                    {
66
                        return *new TIntermBinary(TOperator::EOpAssign, &decl.symbol,
67
                                                  decl.initExpr);
68
                    }
69
                    else
70
                    {
71
                        return nullptr;
72
                    }
73
                }
74
            }
75
        }
76
        return node;
77
    }
78
};
79
80
}  // anonymous namespace
81
82
////////////////////////////////////////////////////////////////////////////////
83
84
bool sh::RewriteCaseDeclarations(TCompiler &compiler, TIntermBlock &root)
85
{
86
    if (!Rewriter(compiler).rebuildRoot(root))
87
    {
88
        return false;
89
    }
90
    return true;
91
}
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/RewriteCaseDeclarations.h +50 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/RewriteCaseDeclarations.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITECASEDECLARATIONS_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITECASEDECLARATIONS_H_
9
10
#include "common/angleutils.h"
11
#include "compiler/translator/Compiler.h"
12
13
namespace sh
14
{
15
16
// EXAMPLE
17
//    switch (expr)
18
//    {
19
//      case 0:
20
//        int x = 0;
21
//        break;
22
//      case 1:
23
//        int y = 0;
24
//        {
25
//          int z = 0;
26
//        }
27
//        break;
28
//    }
29
// Becomes
30
//    {
31
//      int x;
32
//      int y;
33
//      switch (expr)
34
//      {
35
//        case 0:
36
//          x = 0;
37
//          break;
38
//        case 1:
39
//          y = 0;
40
//          {
41
//            int z = 0;
42
//          }
43
//          break;
44
//      }
45
//    }
46
ANGLE_NO_DISCARD bool RewriteCaseDeclarations(TCompiler &compiler, TIntermBlock &root);
47
48
}  // namespace sh
49
50
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITECASEDECLARATIONS_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/RewriteGlobalQualifierDecls.cpp +114 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/RewriteGlobalQualifierDecls.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include "compiler/translator/TranslatorMetalDirect/RewriteGlobalQualifierDecls.h"
8
#include "compiler/translator/TranslatorMetalDirect/Debug.h"
9
#include "compiler/translator/tree_util/IntermRebuild.h"
10
11
using namespace sh;
12
13
namespace
14
{
15
16
class FindDeclaredGlobals : public TIntermRebuild
17
{
18
  public:
19
    std::unordered_set<const TVariable *> mDeclaredGlobals;
20
21
    FindDeclaredGlobals(TCompiler &compiler) : TIntermRebuild(compiler, true, false) {}
22
23
    PreResult visitDeclarationPre(TIntermDeclaration &declNode) override
24
    {
25
        TIntermNode *declaratorNode = declNode.getChildNode(0);
26
        TIntermSymbol *symbolNode   = nullptr;
27
28
        if (TIntermBinary *initNode = declaratorNode->getAsBinaryNode())
29
        {
30
            symbolNode = initNode->getLeft()->getAsSymbolNode();
31
        }
32
        else
33
        {
34
            symbolNode = declaratorNode->getAsSymbolNode();
35
        }
36
37
        ASSERT(symbolNode);
38
        const TVariable &var = symbolNode->variable();
39
40
        mDeclaredGlobals.insert(&var);
41
42
        return {declNode, VisitBits::Neither};
43
    }
44
45
    PreResult visitFunctionDefinitionPre(TIntermFunctionDefinition &node) override
46
    {
47
        return {node, VisitBits::Neither};
48
    }
49
};
50
51
class Rewriter : public TIntermRebuild
52
{
53
    const std::unordered_set<const TVariable *> &mDeclaredGlobals;
54
    Invariants &mOutInvariants;
55
56
  public:
57
    Rewriter(TCompiler &compiler,
58
             const std::unordered_set<const TVariable *> &declaredGlobals,
59
             Invariants &outInvariants)
60
        : TIntermRebuild(compiler, true, false),
61
          mDeclaredGlobals(declaredGlobals),
62
          mOutInvariants(outInvariants)
63
    {}
64
65
    PreResult visitGlobalQualifierDeclarationPre(
66
        TIntermGlobalQualifierDeclaration &gqDeclNode) override
67
    {
68
        TIntermSymbol &symbolNode = *gqDeclNode.getSymbol();
69
        const TVariable &var      = symbolNode.variable();
70
71
        if (gqDeclNode.isInvariant())
72
        {
73
            mOutInvariants.insert(var);
74
        }
75
76
        if (mDeclaredGlobals.find(&var) == mDeclaredGlobals.end())
77
        {
78
            return *new TIntermDeclaration{&symbolNode};
79
        }
80
        return nullptr;
81
    }
82
83
    PreResult visitDeclarationPre(TIntermDeclaration &node) override
84
    {
85
        return {node, VisitBits::Neither};
86
    }
87
88
    PreResult visitFunctionDefinitionPre(TIntermFunctionDefinition &node) override
89
    {
90
        return {node, VisitBits::Neither};
91
    }
92
};
93
94
}  // anonymous namespace
95
96
bool sh::RewriteGlobalQualifierDecls(TCompiler &compiler,
97
                                     TIntermBlock &root,
98
                                     Invariants &outInvariants)
99
{
100
    FindDeclaredGlobals fdg(compiler);
101
    if (!fdg.rebuildRoot(root))
102
    {
103
        LOGIC_ERROR();
104
        return false;
105
    }
106
107
    Rewriter rewriter(compiler, fdg.mDeclaredGlobals, outInvariants);
108
    if (!rewriter.rebuildRoot(root))
109
    {
110
        return false;
111
    }
112
113
    return true;
114
}
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/RewriteGlobalQualifierDecls.h +48 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/RewriteGlobalQualifierDecls.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEGLOBALQUALIFIERDECLS_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEGLOBALQUALIFIERDECLS_H_
9
10
#include <unordered_set>
11
12
#include "compiler/translator/Compiler.h"
13
14
namespace sh
15
{
16
17
// Tracks TVariables and TFields that are marked as "invariant".
18
class Invariants
19
{
20
  public:
21
    void insert(const TVariable &var) { mInvariants.insert(&var); }
22
23
    void insert(const TField &field) { mInvariants.insert(&field); }
24
25
    bool contains(const TVariable &var) const
26
    {
27
        return mInvariants.find(&var) != mInvariants.end();
28
    }
29
30
    bool contains(const TField &field) const
31
    {
32
        return mInvariants.find(&field) != mInvariants.end();
33
    }
34
35
  private:
36
    std::unordered_set<const void *> mInvariants;
37
};
38
39
// This rewrites TIntermGlobalQualifierDeclarations as TIntermDeclarations.
40
// `outInvariants` is populated with the information that would otherwise be lost by such a
41
// transform.
42
ANGLE_NO_DISCARD bool RewriteGlobalQualifierDecls(TCompiler &compiler,
43
                                                  TIntermBlock &root,
44
                                                  Invariants &outInvariants);
45
46
}  // namespace sh
47
48
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEGLOBALQUALIFIERDECLS_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/RewriteKeywords.cpp +434 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/RewriteKeywords.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include <cctype>
8
#include <cstring>
9
#include <limits>
10
#include <unordered_map>
11
#include <unordered_set>
12
13
#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
14
#include "compiler/translator/TranslatorMetalDirect/Debug.h"
15
#include "compiler/translator/TranslatorMetalDirect/RewriteKeywords.h"
16
#include "compiler/translator/tree_util/IntermRebuild.h"
17
18
using namespace sh;
19
20
////////////////////////////////////////////////////////////////////////////////
21
22
namespace
23
{
24
25
template <typename T>
26
using Remapping = std::unordered_map<const T *, const T *>;
27
28
class Rewriter : public TIntermRebuild
29
{
30
  private:
31
    const std::set<ImmutableString> &mKeywords;
32
    IdGen &mIdGen;
33
    Remapping<TField> modifiedFields;
34
    Remapping<TFieldList> mFieldLists;
35
    Remapping<TFunction> mFunctions;
36
    Remapping<TInterfaceBlock> mInterfaceBlocks;
37
    Remapping<TStructure> mStructures;
38
    Remapping<TVariable> mVariables;
39
    std::string mNewNameBuffer;
40
41
  private:
42
    template <typename T>
43
    ImmutableString maybeCreateNewName(T const &object)
44
    {
45
        if (needsRenaming(object, false))
46
        {
47
            return mIdGen.createNewName(Name(object)).rawName();
48
        }
49
        return Name(object).rawName();
50
    }
51
52
    const TField *createRenamed(const TField &field)
53
    {
54
        auto *renamed =
55
            new TField(const_cast<TType *>(&getRenamedOrOriginal(*field.type())),
56
                       maybeCreateNewName(field), field.line(), SymbolType::AngleInternal);
57
58
        return renamed;
59
    }
60
61
    const TFieldList *createRenamed(const TFieldList &fieldList)
62
    {
63
        auto *renamed = new TFieldList();
64
        for (const TField *field : fieldList)
65
        {
66
            renamed->push_back(const_cast<TField *>(&getRenamedOrOriginal(*field)));
67
        }
68
        return renamed;
69
    }
70
71
    const TFunction *createRenamed(const TFunction &function)
72
    {
73
        auto *renamed =
74
            new TFunction(&mSymbolTable, maybeCreateNewName(function), SymbolType::AngleInternal,
75
                          &getRenamedOrOriginal(function.getReturnType()),
76
                          function.isKnownToNotHaveSideEffects());
77
78
        const size_t paramCount = function.getParamCount();
79
        for (size_t i = 0; i < paramCount; ++i)
80
        {
81
            const TVariable &param = *function.getParam(i);
82
            renamed->addParameter(&getRenamedOrOriginal(param));
83
        }
84
85
        if (function.isDefined())
86
        {
87
            renamed->setDefined();
88
        }
89
90
        if (function.hasPrototypeDeclaration())
91
        {
92
            renamed->setHasPrototypeDeclaration();
93
        }
94
95
        return renamed;
96
    }
97
98
    const TInterfaceBlock *createRenamed(const TInterfaceBlock &interfaceBlock)
99
    {
100
        TLayoutQualifier layoutQualifier = TLayoutQualifier::Create();
101
        layoutQualifier.blockStorage     = interfaceBlock.blockStorage();
102
        layoutQualifier.binding          = interfaceBlock.blockBinding();
103
104
        auto *renamed =
105
            new TInterfaceBlock(&mSymbolTable, maybeCreateNewName(interfaceBlock),
106
                                &getRenamedOrOriginal(interfaceBlock.fields()), layoutQualifier,
107
                                SymbolType::AngleInternal, interfaceBlock.extension());
108
109
        return renamed;
110
    }
111
112
    const TStructure *createRenamed(const TStructure &structure)
113
    {
114
        auto *renamed =
115
            new TStructure(&mSymbolTable, maybeCreateNewName(structure),
116
                           &getRenamedOrOriginal(structure.fields()), SymbolType::AngleInternal);
117
118
        renamed->setAtGlobalScope(structure.atGlobalScope());
119
120
        return renamed;
121
    }
122
123
    const TType *createRenamed(const TType &type)
124
    {
125
        TType *renamed;
126
127
        if (const TStructure *structure = type.getStruct())
128
        {
129
            renamed = new TType(&getRenamedOrOriginal(*structure), type.isStructSpecifier());
130
        }
131
        else if (const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock())
132
        {
133
            renamed = new TType(&getRenamedOrOriginal(*interfaceBlock), type.getQualifier(),
134
                                type.getLayoutQualifier());
135
        }
136
        else
137
        {
138
            LOGIC_ERROR();  // Can't rename built-in types.
139
            renamed = nullptr;
140
        }
141
142
        if (type.isArray())
143
        {
144
            renamed->makeArrays(type.getArraySizes());
145
        }
146
        renamed->setPrecise(type.isPrecise());
147
        renamed->setInvariant(type.isInvariant());
148
        renamed->setMemoryQualifier(type.getMemoryQualifier());
149
        renamed->setLayoutQualifier(type.getLayoutQualifier());
150
151
        return renamed;
152
    }
153
154
    const TVariable *createRenamed(const TVariable &variable)
155
    {
156
        auto *renamed = new TVariable(&mSymbolTable, maybeCreateNewName(variable),
157
                                      &getRenamedOrOriginal(variable.getType()),
158
                                      SymbolType::AngleInternal, variable.extension());
159
160
        return renamed;
161
    }
162
163
    template <typename T>
164
    const T *tryGetRenamedImpl(const T &object, Remapping<T> *remapping)
165
    {
166
        if (!needsRenaming(object, true))
167
        {
168
            return nullptr;
169
        }
170
171
        if (remapping)
172
        {
173
            auto it = remapping->find(&object);
174
            if (it != remapping->end())
175
            {
176
                return it->second;
177
            }
178
        }
179
180
        const T *renamedObject = createRenamed(object);
181
182
        if (remapping)
183
        {
184
            (*remapping)[&object] = renamedObject;
185
        }
186
187
        return renamedObject;
188
    }
189
190
    const TField *tryGetRenamed(const TField &field)
191
    {
192
        return tryGetRenamedImpl(field, &modifiedFields);
193
    }
194
195
    const TFieldList *tryGetRenamed(const TFieldList &fieldList)
196
    {
197
        return tryGetRenamedImpl(fieldList, &mFieldLists);
198
    }
199
200
    const TFunction *tryGetRenamed(const TFunction &func)
201
    {
202
        return tryGetRenamedImpl(func, &mFunctions);
203
    }
204
205
    const TInterfaceBlock *tryGetRenamed(const TInterfaceBlock &interfaceBlock)
206
    {
207
        return tryGetRenamedImpl(interfaceBlock, &mInterfaceBlocks);
208
    }
209
210
    const TStructure *tryGetRenamed(const TStructure &structure)
211
    {
212
        return tryGetRenamedImpl(structure, &mStructures);
213
    }
214
215
    const TType *tryGetRenamed(const TType &type)
216
    {
217
        return tryGetRenamedImpl(type, static_cast<Remapping<TType> *>(nullptr));
218
    }
219
220
    const TVariable *tryGetRenamed(const TVariable &variable)
221
    {
222
        return tryGetRenamedImpl(variable, &mVariables);
223
    }
224
225
    template <typename T>
226
    const T &getRenamedOrOriginal(const T &object)
227
    {
228
        const T *renamed = tryGetRenamed(object);
229
        if (renamed)
230
        {
231
            return *renamed;
232
        }
233
        return object;
234
    }
235
236
    template <typename T>
237
    bool needsRenamingImpl(const T &object) const
238
    {
239
        const SymbolType symbolType = object.symbolType();
240
        switch (symbolType)
241
        {
242
            case SymbolType::BuiltIn:
243
            case SymbolType::AngleInternal:
244
            case SymbolType::Empty:
245
                return false;
246
247
            case SymbolType::UserDefined:
248
                break;
249
        }
250
251
        const ImmutableString name = Name(object).rawName();
252
        if (mKeywords.find(name) != mKeywords.end())
253
        {
254
            return true;
255
        }
256
257
        if (name.beginsWith(kAngleInternalPrefix))
258
        {
259
            return true;
260
        }
261
262
        return false;
263
    }
264
265
    bool needsRenaming(const TField &field, bool recursive) const
266
    {
267
        return needsRenamingImpl(field) || (recursive && needsRenaming(*field.type(), true));
268
    }
269
270
    bool needsRenaming(const TFieldList &fieldList, bool recursive) const
271
    {
272
        ASSERT(recursive);
273
        for (const TField *field : fieldList)
274
        {
275
            if (needsRenaming(*field, true))
276
            {
277
                return true;
278
            }
279
        }
280
        return false;
281
    }
282
283
    bool needsRenaming(const TFunction &function, bool recursive) const
284
    {
285
        if (needsRenamingImpl(function))
286
        {
287
            return true;
288
        }
289
290
        if (!recursive)
291
        {
292
            return false;
293
        }
294
295
        const size_t paramCount = function.getParamCount();
296
        for (size_t i = 0; i < paramCount; ++i)
297
        {
298
            const TVariable &param = *function.getParam(i);
299
            if (needsRenaming(param, true))
300
            {
301
                return true;
302
            }
303
        }
304
305
        return false;
306
    }
307
308
    bool needsRenaming(const TInterfaceBlock &interfaceBlock, bool recursive) const
309
    {
310
        return needsRenamingImpl(interfaceBlock) ||
311
               (recursive && needsRenaming(interfaceBlock.fields(), true));
312
    }
313
314
    bool needsRenaming(const TStructure &structure, bool recursive) const
315
    {
316
        return needsRenamingImpl(structure) ||
317
               (recursive && needsRenaming(structure.fields(), true));
318
    }
319
320
    bool needsRenaming(const TType &type, bool recursive) const
321
    {
322
        if (const TStructure *structure = type.getStruct())
323
        {
324
            return needsRenaming(*structure, recursive);
325
        }
326
        else if (const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock())
327
        {
328
            return needsRenaming(*interfaceBlock, recursive);
329
        }
330
        else
331
        {
332
            return false;
333
        }
334
    }
335
336
    bool needsRenaming(const TVariable &variable, bool recursive) const
337
    {
338
        return needsRenamingImpl(variable) ||
339
               (recursive && needsRenaming(variable.getType(), true));
340
    }
341
342
  public:
343
    Rewriter(TCompiler &compiler, IdGen &idGen, const std::set<ImmutableString> &keywords)
344
        : TIntermRebuild(compiler, false, true), mKeywords(keywords), mIdGen(idGen)
345
    {}
346
347
    PostResult visitSymbol(TIntermSymbol &symbolNode)
348
    {
349
        const TVariable &var = symbolNode.variable();
350
        if (needsRenaming(var, true))
351
        {
352
            const TVariable &rVar = getRenamedOrOriginal(var);
353
            return *new TIntermSymbol(&rVar);
354
        }
355
        return symbolNode;
356
    }
357
358
    PostResult visitFunctionPrototype(TIntermFunctionPrototype &funcProtoNode)
359
    {
360
        const TFunction &func = *funcProtoNode.getFunction();
361
        if (needsRenaming(func, true))
362
        {
363
            const TFunction &rFunc = getRenamedOrOriginal(func);
364
            return *new TIntermFunctionPrototype(&rFunc);
365
        }
366
        return funcProtoNode;
367
    }
368
369
    PostResult visitFunctionDefinitionPost(TIntermFunctionDefinition &funcDefNode) override
370
    {
371
        TIntermFunctionPrototype &funcProtoNode = *funcDefNode.getFunctionPrototype();
372
        const TFunction &func                   = *funcProtoNode.getFunction();
373
        if (needsRenaming(func, true))
374
        {
375
            const TFunction &rFunc = getRenamedOrOriginal(func);
376
            auto *rFuncProtoNode   = new TIntermFunctionPrototype(&rFunc);
377
            return *new TIntermFunctionDefinition(rFuncProtoNode, funcDefNode.getBody());
378
        }
379
        return funcDefNode;
380
    }
381
382
    PostResult visitAggregatePost(TIntermAggregate &aggregateNode) override
383
    {
384
        if (aggregateNode.isConstructor())
385
        {
386
            const TType &type = aggregateNode.getType();
387
            if (needsRenaming(type, true))
388
            {
389
                const TType &rType = getRenamedOrOriginal(type);
390
                return TIntermAggregate::CreateConstructor(rType, aggregateNode.getSequence());
391
            }
392
        }
393
        else
394
        {
395
            const TFunction &func = *aggregateNode.getFunction();
396
            if (needsRenaming(func, true))
397
            {
398
                const TFunction &rFunc = getRenamedOrOriginal(func);
399
                switch (aggregateNode.getOp())
400
                {
401
                    case TOperator::EOpCallFunctionInAST:
402
                        return TIntermAggregate::CreateFunctionCall(rFunc,
403
                                                                    aggregateNode.getSequence());
404
405
                    case TOperator::EOpCallInternalRawFunction:
406
                        return TIntermAggregate::CreateRawFunctionCall(rFunc,
407
                                                                       aggregateNode.getSequence());
408
409
                    default:
410
                        return TIntermAggregate::CreateBuiltInFunctionCall(
411
                            rFunc, aggregateNode.getSequence());
412
                }
413
            }
414
        }
415
        return aggregateNode;
416
    }
417
};
418
419
}  // anonymous namespace
420
421
////////////////////////////////////////////////////////////////////////////////
422
423
bool sh::RewriteKeywords(TCompiler &compiler,
424
                         TIntermBlock &root,
425
                         IdGen &idGen,
426
                         const std::set<ImmutableString> &keywords)
427
{
428
    Rewriter rewriter(compiler, idGen, keywords);
429
    if (!rewriter.rebuildRoot(root))
430
    {
431
        return false;
432
    }
433
    return true;
434
}
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/RewriteKeywords.h +27 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/RewriteKeywords.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEKEYWORDS_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEKEYWORDS_H_
9
10
#include <set>
11
12
#include "common/angleutils.h"
13
#include "compiler/translator/Compiler.h"
14
#include "compiler/translator/TranslatorMetalDirect/IdGen.h"
15
16
namespace sh
17
{
18
19
// This walks the tree and renames all names that conflict with the input `keywords`.
20
ANGLE_NO_DISCARD bool RewriteKeywords(TCompiler &compiler,
21
                                      TIntermBlock &root,
22
                                      IdGen &idGen,
23
                                      const std::set<ImmutableString> &keywords);
24
25
}  // namespace sh
26
27
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEKEYWORDS_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/RewriteOutArgs.cpp +204 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/RewriteOutArgs.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include "compiler/translator/TranslatorMetalDirect/RewriteOutArgs.h"
8
#include "compiler/translator/tree_util/IntermRebuild.h"
9
10
using namespace sh;
11
12
namespace
13
{
14
15
template <typename T>
16
class SmallMultiSet
17
{
18
  public:
19
    struct Entry
20
    {
21
        T elem;
22
        size_t count;
23
    };
24
25
    const Entry *find(const T &x) const
26
    {
27
        for (auto &entry : mEntries)
28
        {
29
            if (x == entry.elem)
30
            {
31
                return &entry;
32
            }
33
        }
34
        return nullptr;
35
    }
36
37
    size_t multiplicity(const T &x) const
38
    {
39
        const Entry *entry = find(x);
40
        return entry ? entry->count : 0;
41
    }
42
43
    const Entry &insert(const T &x)
44
    {
45
        Entry *entry = findMutable(x);
46
        if (entry)
47
        {
48
            ++entry->count;
49
            return *entry;
50
        }
51
        else
52
        {
53
            mEntries.push_back({x, 1});
54
            return mEntries.back();
55
        }
56
    }
57
58
    void clear() { mEntries.clear(); }
59
60
    bool empty() const { return mEntries.empty(); }
61
62
    size_t uniqueSize() const { return mEntries.size(); }
63
64
  private:
65
    ANGLE_INLINE Entry *findMutable(const T &x) { return const_cast<Entry *>(find(x)); }
66
67
  private:
68
    std::vector<Entry> mEntries;
69
};
70
71
const TVariable *GetVariable(TIntermNode &node)
72
{
73
    TIntermTyped *tyNode = node.getAsTyped();
74
    ASSERT(tyNode);
75
    if (TIntermSymbol *symbol = tyNode->getAsSymbolNode())
76
    {
77
        return &symbol->variable();
78
    }
79
    return nullptr;
80
}
81
82
class Rewriter : public TIntermRebuild
83
{
84
    SmallMultiSet<const TVariable *> mVarBuffer;  // reusable buffer
85
    SymbolEnv &mSymbolEnv;
86
87
  public:
88
    ~Rewriter() override { ASSERT(mVarBuffer.empty()); }
89
90
    Rewriter(TCompiler &compiler, SymbolEnv &symbolEnv)
91
        : TIntermRebuild(compiler, false, true), mSymbolEnv(symbolEnv)
92
    {}
93
94
    PostResult visitAggregatePost(TIntermAggregate &aggregateNode) override
95
    {
96
        ASSERT(mVarBuffer.empty());
97
98
        const TFunction *func = aggregateNode.getFunction();
99
        if (!func)
100
        {
101
            return aggregateNode;
102
        }
103
104
        TIntermSequence &args = *aggregateNode.getSequence();
105
        size_t argCount       = args.size();
106
107
        auto getParamQualifier = [&](size_t i) {
108
            const TVariable &param     = *func->getParam(i);
109
            const TType &paramType     = param.getType();
110
            const TQualifier paramQual = paramType.getQualifier();
111
            switch (paramQual)
112
            {
113
                case TQualifier::EvqOut:
114
                case TQualifier::EvqInOut:
115
                    if (!mSymbolEnv.isReference(param))
116
                    {
117
                        mSymbolEnv.markAsReference(param, AddressSpace::Thread);
118
                    }
119
                    break;
120
                default:
121
                    break;
122
            }
123
            return paramQual;
124
        };
125
126
        bool mightAlias = false;
127
128
        for (size_t i = 0; i < argCount; ++i)
129
        {
130
            const TQualifier paramQual = getParamQualifier(i);
131
132
            switch (paramQual)
133
            {
134
                case TQualifier::EvqOut:
135
                case TQualifier::EvqInOut:
136
                {
137
                    const TVariable *var = GetVariable(*args[i]);
138
                    if (mVarBuffer.insert(var).count > 1)
139
                    {
140
                        mightAlias = true;
141
                        i          = argCount;
142
                    }
143
                }
144
                break;
145
146
                default:
147
                    break;
148
            }
149
        }
150
151
        const bool hasIndeterminateVar = mVarBuffer.find(nullptr);
152
153
        if (!mightAlias)
154
        {
155
            mightAlias = hasIndeterminateVar && mVarBuffer.uniqueSize() > 1;
156
        }
157
158
        if (mightAlias)
159
        {
160
            for (size_t i = 0; i < argCount; ++i)
161
            {
162
                TIntermTyped *arg = args[i]->getAsTyped();
163
                ASSERT(arg);
164
                const TVariable *var       = GetVariable(*arg);
165
                const TQualifier paramQual = getParamQualifier(i);
166
167
                if (hasIndeterminateVar || mVarBuffer.multiplicity(var) > 1)
168
                {
169
                    switch (paramQual)
170
                    {
171
                        case TQualifier::EvqOut:
172
                            args[i] = &mSymbolEnv.callFunctionOverload(Name("out"), arg->getType(),
173
                                                                       *new TIntermSequence{arg});
174
                            break;
175
176
                        case TQualifier::EvqInOut:
177
                            args[i] = &mSymbolEnv.callFunctionOverload(
178
                                Name("inout"), arg->getType(), *new TIntermSequence{arg});
179
                            break;
180
181
                        default:
182
                            break;
183
                    }
184
                }
185
            }
186
        }
187
188
        mVarBuffer.clear();
189
190
        return aggregateNode;
191
    }
192
};
193
194
}  // anonymous namespace
195
196
bool sh::RewriteOutArgs(TCompiler &compiler, TIntermBlock &root, SymbolEnv &symbolEnv)
197
{
198
    Rewriter rewriter(compiler, symbolEnv);
199
    if (!rewriter.rebuildRoot(root))
200
    {
201
        return false;
202
    }
203
    return true;
204
}
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/RewriteOutArgs.h +33 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/RewriteOutArgs.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEOUTARGS_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEOUTARGS_H_
9
10
#include "compiler/translator/Compiler.h"
11
#include "compiler/translator/TranslatorMetalDirect/ProgramPrelude.h"
12
#include "compiler/translator/TranslatorMetalDirect/SymbolEnv.h"
13
14
namespace sh
15
{
16
17
// e.g.:
18
//    /*void foo(out int x, inout int y)*/
19
//    foo(z, w);
20
// becomes
21
//    foo(Out(z), InOut(w));
22
// unless `z` and `w` are detected to never alias.
23
// The translated example effectively behaves the same as:
24
//    int _1;
25
//    int _2 = w;
26
//    foo(_1, _2);
27
//    z = _1;
28
//    w = _2;
29
ANGLE_NO_DISCARD bool RewriteOutArgs(TCompiler &compiler, TIntermBlock &root, SymbolEnv &symbolEnv);
30
31
}  // namespace sh
32
33
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEOUTARGS_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/RewritePipelines.cpp +938 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/RewritePipelines.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include <cstring>
8
#include <unordered_map>
9
#include <unordered_set>
10
11
#include "compiler/translator/TranslatorMetalDirect.h"
12
#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
13
#include "compiler/translator/TranslatorMetalDirect/DiscoverDependentFunctions.h"
14
#include "compiler/translator/TranslatorMetalDirect/IdGen.h"
15
#include "compiler/translator/TranslatorMetalDirect/MapSymbols.h"
16
#include "compiler/translator/TranslatorMetalDirect/Pipeline.h"
17
#include "compiler/translator/TranslatorMetalDirect/RewritePipelines.h"
18
#include "compiler/translator/tree_ops/PruneNoOps.h"
19
#include "compiler/translator/tree_util/FindMain.h"
20
#include "compiler/translator/tree_util/IntermRebuild.h"
21
#include "compiler/translator/tree_util/IntermTraverse.h"
22
23
using namespace sh;
24
25
////////////////////////////////////////////////////////////////////////////////
26
27
namespace
28
{
29
30
using VariableSet  = std::unordered_set<const TVariable *>;
31
using VariableList = std::vector<const TVariable *>;
32
33
////////////////////////////////////////////////////////////////////////////////
34
35
struct PipelineStructInfo
36
{
37
    VariableSet pipelineVariables;
38
    PipelineScoped<TStructure> pipelineStruct;
39
    const TFunction *funcOriginalToModified = nullptr;
40
    const TFunction *funcModifiedToOriginal = nullptr;
41
42
    bool isEmpty() const
43
    {
44
        if (pipelineStruct.isTotallyEmpty())
45
        {
46
            ASSERT(pipelineVariables.empty());
47
            return true;
48
        }
49
        else
50
        {
51
            ASSERT(pipelineStruct.isTotallyFull());
52
            ASSERT(!pipelineVariables.empty());
53
            return false;
54
        }
55
    }
56
};
57
58
class GeneratePipelineStruct : private TIntermRebuild
59
{
60
  private:
61
    const Pipeline &mPipeline;
62
    SymbolEnv &mSymbolEnv;
63
    Invariants &mInvariants;
64
    VariableList mPipelineVariableList;
65
    IdGen &mIdGen;
66
    PipelineStructInfo mInfo;
67
68
  public:
69
    static bool Exec(PipelineStructInfo &out,
70
                     TCompiler &compiler,
71
                     TIntermBlock &root,
72
                     IdGen &idGen,
73
                     const Pipeline &pipeline,
74
                     SymbolEnv &symbolEnv,
75
                     Invariants &invariants)
76
    {
77
        GeneratePipelineStruct self(compiler, idGen, pipeline, symbolEnv, invariants);
78
        if (!self.exec(root))
79
        {
80
            return false;
81
        }
82
        out = self.mInfo;
83
        return true;
84
    }
85
86
  private:
87
    GeneratePipelineStruct(TCompiler &compiler,
88
                           IdGen &idGen,
89
                           const Pipeline &pipeline,
90
                           SymbolEnv &symbolEnv,
91
                           Invariants &invariants)
92
        : TIntermRebuild(compiler, true, true),
93
          mPipeline(pipeline),
94
          mSymbolEnv(symbolEnv),
95
          mInvariants(invariants),
96
          mIdGen(idGen)
97
    {}
98
99
    bool exec(TIntermBlock &root)
100
    {
101
        if (!rebuildRoot(root))
102
        {
103
            return false;
104
        }
105
106
        if (mInfo.pipelineVariables.empty())
107
        {
108
            return true;
109
        }
110
111
        TIntermSequence seq;
112
113
        const TStructure &pipelineStruct = [&]() -> const TStructure & {
114
            if (mPipeline.globalInstanceVar)
115
            {
116
                return *mPipeline.globalInstanceVar->getType().getStruct();
117
            }
118
            else
119
            {
120
                return createInternalPipelineStruct(root, seq);
121
            }
122
        }();
123
124
        ModifiedStructMachineries modifiedMachineries;
125
        const bool modified = TryCreateModifiedStruct(
126
            mSymbolEnv, mIdGen, mPipeline.externalStructModifyConfig(), pipelineStruct,
127
            mPipeline.getStructTypeName(Pipeline::Variant::Modified), modifiedMachineries);
128
129
        if (modified)
130
        {
131
            ASSERT(mPipeline.type != Pipeline::Type::Texture);
132
            ASSERT(!mPipeline.globalInstanceVar);  // This shouldn't happen by construction.
133
134
            auto getFunction = [](sh::TIntermFunctionDefinition *funcDecl) {
135
                return funcDecl ? funcDecl->getFunction() : nullptr;
136
            };
137
138
            const size_t size = modifiedMachineries.size();
139
            ASSERT(size > 0);
140
            for (size_t i = 0; i < size; ++i)
141
            {
142
                const ModifiedStructMachinery &machinery = modifiedMachineries.at(i);
143
                ASSERT(machinery.modifiedStruct);
144
145
                seq.push_back(new TIntermDeclaration{
146
                    &CreateStructTypeVariable(mSymbolTable, *machinery.modifiedStruct)});
147
148
                if (mPipeline.isPipelineOut())
149
                {
150
                    ASSERT(machinery.funcOriginalToModified);
151
                    ASSERT(!machinery.funcModifiedToOriginal);
152
                    seq.push_back(machinery.funcOriginalToModified);
153
                }
154
                else
155
                {
156
                    ASSERT(machinery.funcModifiedToOriginal);
157
                    ASSERT(!machinery.funcOriginalToModified);
158
                    seq.push_back(machinery.funcModifiedToOriginal);
159
                }
160
161
                if (i == size - 1)
162
                {
163
                    mInfo.funcOriginalToModified = getFunction(machinery.funcOriginalToModified);
164
                    mInfo.funcModifiedToOriginal = getFunction(machinery.funcModifiedToOriginal);
165
166
                    mInfo.pipelineStruct.internal = &pipelineStruct;
167
                    mInfo.pipelineStruct.external =
168
                        modified ? machinery.modifiedStruct : &pipelineStruct;
169
                }
170
            }
171
        }
172
        else
173
        {
174
            mInfo.pipelineStruct.internal = &pipelineStruct;
175
            mInfo.pipelineStruct.external = &pipelineStruct;
176
        }
177
178
        root.insertChildNodes(FindMainIndex(&root), seq);
179
180
        return true;
181
    }
182
183
  private:
184
    PreResult visitFunctionDefinitionPre(TIntermFunctionDefinition &node) override
185
    {
186
        return {node, VisitBits::Neither};
187
    }
188
189
    PostResult visitDeclarationPost(TIntermDeclaration &declNode) override
190
    {
191
        Declaration decl     = ViewDeclaration(declNode);
192
        const TVariable &var = decl.symbol.variable();
193
194
        if (mPipeline.uses(var))
195
        {
196
            ASSERT(mInfo.pipelineVariables.find(&var) == mInfo.pipelineVariables.end());
197
            mInfo.pipelineVariables.insert(&var);
198
            mPipelineVariableList.push_back(&var);
199
            return nullptr;
200
        }
201
202
        return declNode;
203
    }
204
205
    const TStructure &createInternalPipelineStruct(TIntermBlock &root, TIntermSequence &outDeclSeq)
206
    {
207
        auto &fields = *new TFieldList();
208
209
        switch (mPipeline.type)
210
        {
211
            case Pipeline::Type::Texture:
212
            {
213
                for (const TVariable *var : mPipelineVariableList)
214
                {
215
                    ASSERT(!mInvariants.contains(*var));
216
                    const TType &varType         = var->getType();
217
                    const TBasicType samplerType = varType.getBasicType();
218
219
                    const TStructure &textureEnv = mSymbolEnv.getTextureEnv(samplerType);
220
                    auto *textureEnvType         = new TType(&textureEnv, false);
221
                    if (varType.isArray())
222
                    {
223
                        textureEnvType->makeArrays(varType.getArraySizes());
224
                    }
225
226
                    fields.push_back(
227
                        new TField(textureEnvType, var->name(), kNoSourceLoc, var->symbolType()));
228
                }
229
            }
230
            break;
231
232
            default:
233
            {
234
                for (const TVariable *var : mPipelineVariableList)
235
                {
236
                    auto &type  = CloneType(var->getType());
237
                    auto *field = new TField(&type, var->name(), kNoSourceLoc, var->symbolType());
238
                    fields.push_back(field);
239
240
                    if (mInvariants.contains(*var))
241
                    {
242
                        mInvariants.insert(*field);
243
                    }
244
                }
245
            }
246
            break;
247
        }
248
249
        Name pipelineStructName = mPipeline.getStructTypeName(Pipeline::Variant::Original);
250
        auto &s = *new TStructure(&mSymbolTable, pipelineStructName.rawName(), &fields,
251
                                  pipelineStructName.symbolType());
252
253
        outDeclSeq.push_back(new TIntermDeclaration{&CreateStructTypeVariable(mSymbolTable, s)});
254
255
        return s;
256
    }
257
};
258
259
////////////////////////////////////////////////////////////////////////////////
260
261
PipelineScoped<TVariable> CreatePipelineMainLocalVar(TSymbolTable &symbolTable,
262
                                                     const Pipeline &pipeline,
263
                                                     PipelineScoped<TStructure> pipelineStruct)
264
{
265
    ASSERT(pipelineStruct.isTotallyFull());
266
267
    PipelineScoped<TVariable> pipelineMainLocalVar;
268
269
    auto populateExternalMainLocalVar = [&]() {
270
        ASSERT(!pipelineMainLocalVar.external);
271
        pipelineMainLocalVar.external = &CreateInstanceVariable(
272
            symbolTable, *pipelineStruct.external,
273
            pipeline.getStructInstanceName(pipelineStruct.isUniform()
274
                                               ? Pipeline::Variant::Original
275
                                               : Pipeline::Variant::Modified));
276
    };
277
278
    auto populateDistinctInternalMainLocalVar = [&]() {
279
        ASSERT(!pipelineMainLocalVar.internal);
280
        pipelineMainLocalVar.internal =
281
            &CreateInstanceVariable(symbolTable, *pipelineStruct.internal,
282
                                    pipeline.getStructInstanceName(Pipeline::Variant::Original));
283
    };
284
285
    if (pipeline.type == Pipeline::Type::InstanceId)
286
    {
287
        populateDistinctInternalMainLocalVar();
288
    }
289
    else if (pipeline.alwaysRequiresLocalVariableDeclarationInMain())
290
    {
291
        populateExternalMainLocalVar();
292
293
        if (pipelineStruct.isUniform())
294
        {
295
            pipelineMainLocalVar.internal = pipelineMainLocalVar.external;
296
        }
297
        else
298
        {
299
            populateDistinctInternalMainLocalVar();
300
        }
301
    }
302
    else if (!pipelineStruct.isUniform())
303
    {
304
        populateDistinctInternalMainLocalVar();
305
    }
306
307
    return pipelineMainLocalVar;
308
}
309
310
class PipelineFunctionEnv
311
{
312
  private:
313
    TCompiler &mCompiler;
314
    SymbolEnv &mSymbolEnv;
315
    TSymbolTable &mSymbolTable;
316
    IdGen &mIdGen;
317
    const Pipeline &mPipeline;
318
    const std::unordered_set<const TFunction *> &mPipelineFunctions;
319
    const PipelineScoped<TStructure> mPipelineStruct;
320
    PipelineScoped<TVariable> &mPipelineMainLocalVar;
321
322
    std::unordered_map<const TFunction *, const TFunction *> mFuncMap;
323
324
  public:
325
    PipelineFunctionEnv(TCompiler &compiler,
326
                        SymbolEnv &symbolEnv,
327
                        IdGen &idGen,
328
                        const Pipeline &pipeline,
329
                        const std::unordered_set<const TFunction *> &pipelineFunctions,
330
                        PipelineScoped<TStructure> pipelineStruct,
331
                        PipelineScoped<TVariable> &pipelineMainLocalVar)
332
        : mCompiler(compiler),
333
          mSymbolEnv(symbolEnv),
334
          mSymbolTable(symbolEnv.symbolTable()),
335
          mIdGen(idGen),
336
          mPipeline(pipeline),
337
          mPipelineFunctions(pipelineFunctions),
338
          mPipelineStruct(pipelineStruct),
339
          mPipelineMainLocalVar(pipelineMainLocalVar)
340
    {}
341
342
    bool isOriginalPipelineFunction(const TFunction &func) const
343
    {
344
        return mPipelineFunctions.find(&func) != mPipelineFunctions.end();
345
    }
346
347
    bool isUpdatedPipelineFunction(const TFunction &func) const
348
    {
349
        auto it = mFuncMap.find(&func);
350
        if (it == mFuncMap.end())
351
        {
352
            return false;
353
        }
354
        return &func == it->second;
355
    }
356
357
    const TFunction &getUpdatedFunction(const TFunction &func)
358
    {
359
        ASSERT(isOriginalPipelineFunction(func) || isUpdatedPipelineFunction(func));
360
361
        const TFunction *newFunc;
362
363
        auto it = mFuncMap.find(&func);
364
        if (it == mFuncMap.end())
365
        {
366
            const bool isMain = func.isMain();
367
368
            if (isMain && mPipeline.isPipelineOut())
369
            {
370
                ASSERT(func.getReturnType().getBasicType() == TBasicType::EbtVoid);
371
                newFunc = &CloneFunctionAndChangeReturnType(mSymbolTable, nullptr, func,
372
                                                            *mPipelineStruct.external);
373
            }
374
            else if (isMain && (mPipeline.type == Pipeline::Type::InvocationVertexGlobals ||
375
                                mPipeline.type == Pipeline::Type::InvocationFragmentGlobals))
376
            {
377
                std::vector<const TVariable *> variables;
378
                for (const TField *field : mPipelineStruct.external->fields())
379
                {
380
                    variables.push_back(new TVariable(&mSymbolTable, field->name(), field->type(),
381
                                                      field->symbolType()));
382
                }
383
                newFunc = &CloneFunctionAndAppendParams(mSymbolTable, nullptr, func, variables);
384
            }
385
            else if (isMain && mPipeline.type == Pipeline::Type::Texture)
386
            {
387
                std::vector<const TVariable *> variables;
388
                TranslatorMetalReflection *reflection =
389
                    ((sh::TranslatorMetalDirect *)&mCompiler)->getTranslatorMetalReflection();
390
                for (const TField *field : mPipelineStruct.external->fields())
391
                {
392
                    const TStructure *textureEnv = field->type()->getStruct();
393
                    ASSERT(textureEnv && textureEnv->fields().size() == 2);
394
                    for (const TField *subfield : textureEnv->fields())
395
                    {
396
                        const Name name = mIdGen.createNewName({field->name(), subfield->name()});
397
                        TType &type     = *new TType(*subfield->type());
398
                        ASSERT(!type.isArray());
399
                        type.makeArrays(field->type()->getArraySizes());
400
                        auto *var =
401
                            new TVariable(&mSymbolTable, name.rawName(), &type, name.symbolType());
402
                        variables.push_back(var);
403
                        reflection->addOriginalName(var->uniqueId().get(), field->name().data());
404
                    }
405
                }
406
                newFunc = &CloneFunctionAndAppendParams(mSymbolTable, nullptr, func, variables);
407
            }
408
            else if (isMain && mPipeline.type == Pipeline::Type::InstanceId)
409
            {
410
                Name name = mPipeline.getStructInstanceName(Pipeline::Variant::Modified);
411
                auto *var = new TVariable(&mSymbolTable, name.rawName(),
412
                                          new TType(TBasicType::EbtUInt), name.symbolType());
413
                newFunc   = &CloneFunctionAndPrependParam(mSymbolTable, nullptr, func, *var);
414
                mSymbolEnv.markAsReference(*var, mPipeline.externalAddressSpace());
415
                mPipelineMainLocalVar.external = var;
416
            }
417
            else if (isMain && mPipeline.alwaysRequiresLocalVariableDeclarationInMain())
418
            {
419
                ASSERT(mPipelineMainLocalVar.isTotallyFull());
420
                newFunc = &func;
421
            }
422
            else
423
            {
424
                const TVariable *var;
425
                AddressSpace addressSpace;
426
427
                if (isMain && !mPipelineMainLocalVar.isUniform())
428
                {
429
                    var = &CreateInstanceVariable(
430
                        mSymbolTable, *mPipelineStruct.external,
431
                        mPipeline.getStructInstanceName(Pipeline::Variant::Modified));
432
                    addressSpace = mPipeline.externalAddressSpace();
433
                }
434
                else
435
                {
436
                    var = &CreateInstanceVariable(
437
                        mSymbolTable, *mPipelineStruct.internal,
438
                        mPipeline.getStructInstanceName(Pipeline::Variant::Original));
439
                    addressSpace = mPipelineMainLocalVar.isUniform()
440
                                       ? mPipeline.externalAddressSpace()
441
                                       : AddressSpace::Thread;
442
                }
443
444
                bool markAsReference = true;
445
                if (isMain)
446
                {
447
                    switch (mPipeline.type)
448
                    {
449
                        case Pipeline::Type::VertexIn:
450
                        case Pipeline::Type::FragmentIn:
451
                            markAsReference = false;
452
                            break;
453
454
                        default:
455
                            break;
456
                    }
457
                }
458
459
                if (markAsReference)
460
                {
461
                    mSymbolEnv.markAsReference(*var, addressSpace);
462
                }
463
464
                newFunc = &CloneFunctionAndPrependParam(mSymbolTable, nullptr, func, *var);
465
            }
466
467
            mFuncMap[&func]   = newFunc;
468
            mFuncMap[newFunc] = newFunc;
469
        }
470
        else
471
        {
472
            newFunc = it->second;
473
        }
474
475
        return *newFunc;
476
    }
477
478
    TIntermFunctionPrototype *createUpdatedFunctionPrototype(
479
        TIntermFunctionPrototype &funcProtoNode)
480
    {
481
        const TFunction &func = *funcProtoNode.getFunction();
482
        if (!isOriginalPipelineFunction(func) && !isUpdatedPipelineFunction(func))
483
        {
484
            return nullptr;
485
        }
486
        const TFunction &newFunc = getUpdatedFunction(func);
487
        return new TIntermFunctionPrototype(&newFunc);
488
    }
489
};
490
491
class UpdatePipelineFunctions : private TIntermRebuild
492
{
493
  private:
494
    const Pipeline &mPipeline;
495
    const PipelineScoped<TStructure> mPipelineStruct;
496
    PipelineScoped<TVariable> &mPipelineMainLocalVar;
497
    SymbolEnv &mSymbolEnv;
498
    PipelineFunctionEnv mEnv;
499
    const TFunction *mFuncOriginalToModified;
500
    const TFunction *mFuncModifiedToOriginal;
501
502
  public:
503
    static bool ThreadPipeline(TCompiler &compiler,
504
                               TIntermBlock &root,
505
                               const Pipeline &pipeline,
506
                               const std::unordered_set<const TFunction *> &pipelineFunctions,
507
                               PipelineScoped<TStructure> pipelineStruct,
508
                               PipelineScoped<TVariable> &pipelineMainLocalVar,
509
                               IdGen &idGen,
510
                               SymbolEnv &symbolEnv,
511
                               const TFunction *funcOriginalToModified,
512
                               const TFunction *funcModifiedToOriginal)
513
    {
514
        UpdatePipelineFunctions self(compiler, pipeline, pipelineFunctions, pipelineStruct,
515
                                     pipelineMainLocalVar, idGen, symbolEnv, funcOriginalToModified,
516
                                     funcModifiedToOriginal);
517
        if (!self.rebuildRoot(root))
518
        {
519
            return false;
520
        }
521
        return true;
522
    }
523
524
  private:
525
    UpdatePipelineFunctions(TCompiler &compiler,
526
                            const Pipeline &pipeline,
527
                            const std::unordered_set<const TFunction *> &pipelineFunctions,
528
                            PipelineScoped<TStructure> pipelineStruct,
529
                            PipelineScoped<TVariable> &pipelineMainLocalVar,
530
                            IdGen &idGen,
531
                            SymbolEnv &symbolEnv,
532
                            const TFunction *funcOriginalToModified,
533
                            const TFunction *funcModifiedToOriginal)
534
        : TIntermRebuild(compiler, false, true),
535
          mPipeline(pipeline),
536
          mPipelineStruct(pipelineStruct),
537
          mPipelineMainLocalVar(pipelineMainLocalVar),
538
          mSymbolEnv(symbolEnv),
539
          mEnv(compiler,
540
               symbolEnv,
541
               idGen,
542
               pipeline,
543
               pipelineFunctions,
544
               pipelineStruct,
545
               mPipelineMainLocalVar),
546
          mFuncOriginalToModified(funcOriginalToModified),
547
          mFuncModifiedToOriginal(funcModifiedToOriginal)
548
    {
549
        ASSERT(mPipelineStruct.isTotallyFull());
550
    }
551
552
    const TVariable &getInternalPipelineVariable(const TFunction &pipelineFunc)
553
    {
554
        if (pipelineFunc.isMain() && (mPipeline.alwaysRequiresLocalVariableDeclarationInMain() ||
555
                                      !mPipelineMainLocalVar.isUniform()))
556
        {
557
            ASSERT(mPipelineMainLocalVar.internal);
558
            return *mPipelineMainLocalVar.internal;
559
        }
560
        else
561
        {
562
            ASSERT(pipelineFunc.getParamCount() > 0);
563
            return *pipelineFunc.getParam(0);
564
        }
565
    }
566
567
    const TVariable &getExternalPipelineVariable(const TFunction &mainFunc)
568
    {
569
        ASSERT(mainFunc.isMain());
570
        if (mPipelineMainLocalVar.external)
571
        {
572
            return *mPipelineMainLocalVar.external;
573
        }
574
        else
575
        {
576
            ASSERT(mainFunc.getParamCount() > 0);
577
            return *mainFunc.getParam(0);
578
        }
579
    }
580
581
    PostResult visitAggregatePost(TIntermAggregate &callNode) override
582
    {
583
        if (callNode.isConstructor())
584
        {
585
            return callNode;
586
        }
587
        else
588
        {
589
            const TFunction &oldCalledFunc = *callNode.getFunction();
590
            if (!mEnv.isOriginalPipelineFunction(oldCalledFunc))
591
            {
592
                return callNode;
593
            }
594
            const TFunction &newCalledFunc = mEnv.getUpdatedFunction(oldCalledFunc);
595
596
            const TFunction *oldOwnerFunc = getParentFunction();
597
            ASSERT(oldOwnerFunc);
598
            const TFunction &newOwnerFunc = mEnv.getUpdatedFunction(*oldOwnerFunc);
599
600
            return *TIntermAggregate::CreateFunctionCall(
601
                newCalledFunc, &CloneSequenceAndPrepend(
602
                                   *callNode.getSequence(),
603
                                   *new TIntermSymbol(&getInternalPipelineVariable(newOwnerFunc))));
604
        }
605
    }
606
607
    PostResult visitFunctionPrototypePost(TIntermFunctionPrototype &funcProtoNode) override
608
    {
609
        TIntermFunctionPrototype *newFuncProtoNode =
610
            mEnv.createUpdatedFunctionPrototype(funcProtoNode);
611
        if (newFuncProtoNode == nullptr)
612
        {
613
            return funcProtoNode;
614
        }
615
        return *newFuncProtoNode;
616
    }
617
618
    PostResult visitFunctionDefinitionPost(TIntermFunctionDefinition &funcDefNode) override
619
    {
620
        if (funcDefNode.getFunction()->isMain())
621
        {
622
            return visitMain(funcDefNode);
623
        }
624
        else
625
        {
626
            return visitNonMain(funcDefNode);
627
        }
628
    }
629
630
    TIntermNode &visitNonMain(TIntermFunctionDefinition &funcDefNode)
631
    {
632
        TIntermFunctionPrototype &funcProtoNode = *funcDefNode.getFunctionPrototype();
633
        ASSERT(!funcProtoNode.getFunction()->isMain());
634
635
        TIntermFunctionPrototype *newFuncProtoNode =
636
            mEnv.createUpdatedFunctionPrototype(funcProtoNode);
637
        if (newFuncProtoNode == nullptr)
638
        {
639
            return funcDefNode;
640
        }
641
642
        const TFunction &func = *newFuncProtoNode->getFunction();
643
        ASSERT(!func.isMain());
644
645
        TIntermBlock *body = funcDefNode.getBody();
646
647
        return *new TIntermFunctionDefinition(newFuncProtoNode, body);
648
    }
649
650
    TIntermNode &visitMain(TIntermFunctionDefinition &funcDefNode)
651
    {
652
        TIntermFunctionPrototype &funcProtoNode = *funcDefNode.getFunctionPrototype();
653
        ASSERT(funcProtoNode.getFunction()->isMain());
654
655
        TIntermFunctionPrototype *newFuncProtoNode =
656
            mEnv.createUpdatedFunctionPrototype(funcProtoNode);
657
        if (newFuncProtoNode == nullptr)
658
        {
659
            return funcDefNode;
660
        }
661
662
        const TFunction &func = *newFuncProtoNode->getFunction();
663
        ASSERT(func.isMain());
664
665
        auto callModifiedToOriginal = [&](TIntermBlock &body) {
666
            ASSERT(mPipelineMainLocalVar.internal);
667
            if (!mPipeline.isPipelineOut())
668
            {
669
                ASSERT(mFuncModifiedToOriginal);
670
                auto *m = new TIntermSymbol(&getExternalPipelineVariable(func));
671
                auto *o = new TIntermSymbol(mPipelineMainLocalVar.internal);
672
                body.appendStatement(TIntermAggregate::CreateFunctionCall(
673
                    *mFuncModifiedToOriginal, new TIntermSequence{m, o}));
674
            }
675
        };
676
677
        auto callOriginalToModified = [&](TIntermBlock &body) {
678
            ASSERT(mPipelineMainLocalVar.internal);
679
            if (mPipeline.isPipelineOut())
680
            {
681
                ASSERT(mFuncOriginalToModified);
682
                auto *o = new TIntermSymbol(mPipelineMainLocalVar.internal);
683
                auto *m = new TIntermSymbol(&getExternalPipelineVariable(func));
684
                body.appendStatement(TIntermAggregate::CreateFunctionCall(
685
                    *mFuncOriginalToModified, new TIntermSequence{o, m}));
686
            }
687
        };
688
689
        TIntermBlock *body = funcDefNode.getBody();
690
691
        if (mPipeline.alwaysRequiresLocalVariableDeclarationInMain())
692
        {
693
            ASSERT(mPipelineMainLocalVar.isTotallyFull());
694
695
            auto *newBody = new TIntermBlock();
696
            newBody->appendStatement(new TIntermDeclaration{mPipelineMainLocalVar.internal});
697
698
            if (mPipeline.type == Pipeline::Type::InvocationVertexGlobals ||
699
                mPipeline.type == Pipeline::Type::InvocationFragmentGlobals)
700
            {
701
                // Populate struct instance with references to global pipeline variables.
702
                for (const TField *field : mPipelineStruct.external->fields())
703
                {
704
                    auto *var        = new TVariable(&mSymbolTable, field->name(), field->type(),
705
                                              field->symbolType());
706
                    auto *symbol     = new TIntermSymbol(var);
707
                    auto &accessNode = AccessField(*mPipelineMainLocalVar.internal, var->name());
708
                    auto *assignNode = new TIntermBinary(TOperator::EOpAssign, &accessNode, symbol);
709
                    newBody->appendStatement(assignNode);
710
                }
711
            }
712
            else if (mPipeline.type == Pipeline::Type::Texture)
713
            {
714
                const TFieldList &fields = mPipelineStruct.external->fields();
715
716
                ASSERT(func.getParamCount() >= 2 * fields.size());
717
                size_t paramIndex = func.getParamCount() - 2 * fields.size();
718
719
                for (const TField *field : fields)
720
                {
721
                    const TVariable &textureParam = *func.getParam(paramIndex++);
722
                    const TVariable &samplerParam = *func.getParam(paramIndex++);
723
724
                    auto go = [&](TIntermTyped &env, const int *index) {
725
                        TIntermTyped &textureField = AccessField(
726
                            AccessIndex(*env.deepCopy(), index), ImmutableString("texture"));
727
                        TIntermTyped &samplerField = AccessField(
728
                            AccessIndex(*env.deepCopy(), index), ImmutableString("sampler"));
729
730
                        auto mkAssign = [&](TIntermTyped &field, const TVariable &param) {
731
                            return new TIntermBinary(TOperator::EOpAssign, &field,
732
                                                     &mSymbolEnv.callFunctionOverload(
733
                                                         Name("addressof"), field.getType(),
734
                                                         *new TIntermSequence{&AccessIndex(
735
                                                             *new TIntermSymbol(&param), index)}));
736
                        };
737
738
                        newBody->appendStatement(mkAssign(textureField, textureParam));
739
                        newBody->appendStatement(mkAssign(samplerField, samplerParam));
740
                    };
741
742
                    TIntermTyped &env = AccessField(*mPipelineMainLocalVar.internal, field->name());
743
                    const TType &envType = env.getType();
744
745
                    if (envType.isArray())
746
                    {
747
                        ASSERT(!envType.isArrayOfArrays());
748
                        const auto n = static_cast<int>(envType.getArraySizeProduct());
749
                        for (int i = 0; i < n; ++i)
750
                        {
751
                            go(env, &i);
752
                        }
753
                    }
754
                    else
755
                    {
756
                        go(env, nullptr);
757
                    }
758
                }
759
            }
760
            else if (mPipeline.type == Pipeline::Type::InstanceId)
761
            {
762
                newBody->appendStatement(new TIntermBinary(
763
                    TOperator::EOpAssign,
764
                    &AccessFieldByIndex(*new TIntermSymbol(&getInternalPipelineVariable(func)), 0),
765
                    &AsType(mSymbolEnv, *new TType(TBasicType::EbtInt),
766
                            *new TIntermSymbol(&getExternalPipelineVariable(func)))));
767
            }
768
            else if (!mPipelineMainLocalVar.isUniform())
769
            {
770
                newBody->appendStatement(new TIntermDeclaration{mPipelineMainLocalVar.external});
771
                callModifiedToOriginal(*newBody);
772
            }
773
774
            newBody->appendStatement(body);
775
776
            if (!mPipelineMainLocalVar.isUniform())
777
            {
778
                callOriginalToModified(*newBody);
779
            }
780
781
            if (mPipeline.isPipelineOut())
782
            {
783
                newBody->appendStatement(new TIntermBranch(
784
                    TOperator::EOpReturn, new TIntermSymbol(mPipelineMainLocalVar.external)));
785
            }
786
787
            body = newBody;
788
        }
789
        else if (!mPipelineMainLocalVar.isUniform())
790
        {
791
            ASSERT(!mPipelineMainLocalVar.external);
792
            ASSERT(mPipelineMainLocalVar.internal);
793
794
            auto *newBody = new TIntermBlock();
795
            newBody->appendStatement(new TIntermDeclaration{mPipelineMainLocalVar.internal});
796
            callModifiedToOriginal(*newBody);
797
            newBody->appendStatement(body);
798
            callOriginalToModified(*newBody);
799
            body = newBody;
800
        }
801
802
        return *new TIntermFunctionDefinition(newFuncProtoNode, body);
803
    }
804
};
805
806
////////////////////////////////////////////////////////////////////////////////
807
808
bool UpdatePipelineSymbols(Pipeline::Type pipelineType,
809
                           TCompiler &compiler,
810
                           TIntermBlock &root,
811
                           SymbolEnv &symbolEnv,
812
                           const VariableSet &pipelineVariables,
813
                           PipelineScoped<TVariable> pipelineMainLocalVar)
814
{
815
    auto map = [&](const TFunction *owner, TIntermSymbol &symbol) -> TIntermNode & {
816
        const TVariable &var = symbol.variable();
817
        if (pipelineVariables.find(&var) == pipelineVariables.end())
818
        {
819
            return symbol;
820
        }
821
        ASSERT(owner);
822
        const TVariable *structInstanceVar;
823
        if (owner->isMain())
824
        {
825
            ASSERT(pipelineMainLocalVar.internal);
826
            structInstanceVar = pipelineMainLocalVar.internal;
827
        }
828
        else
829
        {
830
            ASSERT(owner->getParamCount() > 0);
831
            structInstanceVar = owner->getParam(0);
832
        }
833
        ASSERT(structInstanceVar);
834
        return AccessField(*structInstanceVar, var.name());
835
    };
836
    return MapSymbols(compiler, root, map);
837
}
838
839
////////////////////////////////////////////////////////////////////////////////
840
841
bool RewritePipeline(TCompiler &compiler,
842
                     TIntermBlock &root,
843
                     IdGen &idGen,
844
                     const Pipeline &pipeline,
845
                     SymbolEnv &symbolEnv,
846
                     Invariants &invariants,
847
                     PipelineScoped<TStructure> &outStruct)
848
{
849
    ASSERT(outStruct.isTotallyEmpty());
850
851
    TSymbolTable &symbolTable = compiler.getSymbolTable();
852
853
    PipelineStructInfo psi;
854
    if (!GeneratePipelineStruct::Exec(psi, compiler, root, idGen, pipeline, symbolEnv, invariants))
855
    {
856
        return false;
857
    }
858
859
    if (psi.isEmpty())
860
    {
861
        return true;
862
    }
863
864
    const auto pipelineFunctions = DiscoverDependentFunctions(root, [&](const TVariable &var) {
865
        return psi.pipelineVariables.find(&var) != psi.pipelineVariables.end();
866
    });
867
868
    auto pipelineMainLocalVar =
869
        CreatePipelineMainLocalVar(symbolTable, pipeline, psi.pipelineStruct);
870
871
    if (!UpdatePipelineFunctions::ThreadPipeline(
872
            compiler, root, pipeline, pipelineFunctions, psi.pipelineStruct, pipelineMainLocalVar,
873
            idGen, symbolEnv, psi.funcOriginalToModified, psi.funcModifiedToOriginal))
874
    {
875
        return false;
876
    }
877
878
    if (!pipeline.globalInstanceVar)
879
    {
880
        if (!UpdatePipelineSymbols(pipeline.type, compiler, root, symbolEnv, psi.pipelineVariables,
881
                                   pipelineMainLocalVar))
882
        {
883
            return false;
884
        }
885
    }
886
887
    if (!PruneNoOps(&compiler, &root, &compiler.getSymbolTable()))
888
    {
889
        return false;
890
    }
891
892
    outStruct = psi.pipelineStruct;
893
    return true;
894
}
895
896
}  // anonymous namespace
897
898
bool sh::RewritePipelines(TCompiler &compiler,
899
                          TIntermBlock &root,
900
                          IdGen &idGen,
901
                          const TVariable &angleUniformsGlobalInstanceVar,
902
                          SymbolEnv &symbolEnv,
903
                          Invariants &invariants,
904
                          PipelineStructs &outStructs)
905
{
906
    struct Info
907
    {
908
        Pipeline::Type pipelineType;
909
        PipelineScoped<TStructure> &outStruct;
910
        const TVariable *globalInstanceVar;
911
    };
912
913
    Info infos[] = {
914
        {Pipeline::Type::InstanceId, outStructs.instanceId, nullptr},
915
        {Pipeline::Type::Texture, outStructs.texture, nullptr},
916
        {Pipeline::Type::NonConstantGlobals, outStructs.nonConstantGlobals, nullptr},
917
        {Pipeline::Type::AngleUniforms, outStructs.angleUniforms, &angleUniformsGlobalInstanceVar},
918
        {Pipeline::Type::UserUniforms, outStructs.userUniforms, nullptr},
919
        {Pipeline::Type::VertexIn, outStructs.vertexIn, nullptr},
920
        {Pipeline::Type::VertexOut, outStructs.vertexOut, nullptr},
921
        {Pipeline::Type::FragmentIn, outStructs.fragmentIn, nullptr},
922
        {Pipeline::Type::FragmentOut, outStructs.fragmentOut, nullptr},
923
        {Pipeline::Type::InvocationVertexGlobals, outStructs.invocationVertexGlobals, nullptr},
924
        {Pipeline::Type::InvocationFragmentGlobals, outStructs.invocationFragmentGlobals, nullptr},
925
    };
926
927
    for (Info &info : infos)
928
    {
929
        Pipeline pipeline{info.pipelineType, info.globalInstanceVar};
930
        if (!RewritePipeline(compiler, root, idGen, pipeline, symbolEnv, invariants,
931
                             info.outStruct))
932
        {
933
            return false;
934
        }
935
    }
936
937
    return true;
938
}
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/RewritePipelines.h +45 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/RewritePipelines.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEPIPELINES_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEPIPELINES_H_
9
10
#include "common/angleutils.h"
11
#include "compiler/translator/Compiler.h"
12
#include "compiler/translator/TranslatorMetalDirect/IdGen.h"
13
#include "compiler/translator/TranslatorMetalDirect/Pipeline.h"
14
#include "compiler/translator/TranslatorMetalDirect/RewriteGlobalQualifierDecls.h"
15
#include "compiler/translator/TranslatorMetalDirect/SymbolEnv.h"
16
17
namespace sh
18
{
19
20
// This rewrites all pipelines.
21
//
22
// For each pipeline:
23
//    - Discover all variables that are used by the pipeline
24
//    - Move the variables into an internal pipeline struct instance and update old variables to be
25
//      member access instead.
26
//    - Dependency inject the internal pipeline struct to all functions that access variables from
27
//      the struct.
28
//    - A new external pipeline struct is created if needed for impedance reasons. Otherwise the
29
//      external and internal pipeline structs are the same.
30
//    - Add `main` parameter or return value for the external pipeline struct as needed.
31
//    - Inside `main`, map the external struct to the internal struct if they differ and is provided
32
//      as a parameter to `main`.
33
//    - Inside `main`, map the internal struct to the external struct if they differ and is returned
34
//      from `main`.
35
ANGLE_NO_DISCARD bool RewritePipelines(TCompiler &compiler,
36
                                       TIntermBlock &root,
37
                                       IdGen &idGen,
38
                                       const TVariable &angleUniformsGlobalInstanceVar,
39
                                       SymbolEnv &symbolEnv,
40
                                       Invariants &invariants,
41
                                       PipelineStructs &outStructs);
42
43
}  // namespace sh
44
45
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEPIPELINES_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/RewriteUnaddressableReferences.cpp +376 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/RewriteUnaddressableReferences.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include "compiler/translator/TranslatorMetalDirect/RewriteUnaddressableReferences.h"
8
#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
9
#include "compiler/translator/TranslatorMetalDirect/Debug.h"
10
#include "compiler/translator/tree_util/AsNode.h"
11
#include "compiler/translator/tree_util/IntermRebuild.h"
12
13
using namespace sh;
14
15
namespace
16
{
17
18
bool IsOutParam(const TType &paramType)
19
{
20
    const TQualifier qual = paramType.getQualifier();
21
    switch (qual)
22
    {
23
        case TQualifier::EvqInOut:
24
        case TQualifier::EvqOut:
25
            return true;
26
27
        default:
28
            return false;
29
    }
30
}
31
32
bool IsVectorAccess(TIntermBinary &binary)
33
{
34
    TOperator op = binary.getOp();
35
    switch (op)
36
    {
37
        case TOperator::EOpIndexDirect:
38
        case TOperator::EOpIndexIndirect:
39
            break;
40
41
        default:
42
            return false;
43
    }
44
45
    const TType &leftType = binary.getLeft()->getType();
46
    if (!leftType.isVector() || leftType.isArray())
47
    {
48
        return false;
49
    }
50
51
    ASSERT(IsScalarBasicType(binary.getType()));
52
53
    return true;
54
}
55
56
bool IsVectorAccess(TIntermNode &node)
57
{
58
    if (auto *bin = node.getAsBinaryNode())
59
    {
60
        return IsVectorAccess(*bin);
61
    }
62
    return false;
63
}
64
65
// Differs from IsAssignment in that it does not include (++) or (--).
66
bool IsAssignEqualsSign(TOperator op)
67
{
68
    switch (op)
69
    {
70
        case TOperator::EOpAssign:
71
        case TOperator::EOpInitialize:
72
        case TOperator::EOpAddAssign:
73
        case TOperator::EOpSubAssign:
74
        case TOperator::EOpMulAssign:
75
        case TOperator::EOpVectorTimesMatrixAssign:
76
        case TOperator::EOpVectorTimesScalarAssign:
77
        case TOperator::EOpMatrixTimesScalarAssign:
78
        case TOperator::EOpMatrixTimesMatrixAssign:
79
        case TOperator::EOpDivAssign:
80
        case TOperator::EOpIModAssign:
81
        case TOperator::EOpBitShiftLeftAssign:
82
        case TOperator::EOpBitShiftRightAssign:
83
        case TOperator::EOpBitwiseAndAssign:
84
        case TOperator::EOpBitwiseXorAssign:
85
        case TOperator::EOpBitwiseOrAssign:
86
            return true;
87
88
        default:
89
            return false;
90
    }
91
}
92
93
// Only includes ($=) style assigns, where ($) is a binary op.
94
bool IsCompoundAssign(TOperator op)
95
{
96
    switch (op)
97
    {
98
        case TOperator::EOpAddAssign:
99
        case TOperator::EOpSubAssign:
100
        case TOperator::EOpMulAssign:
101
        case TOperator::EOpVectorTimesMatrixAssign:
102
        case TOperator::EOpVectorTimesScalarAssign:
103
        case TOperator::EOpMatrixTimesScalarAssign:
104
        case TOperator::EOpMatrixTimesMatrixAssign:
105
        case TOperator::EOpDivAssign:
106
        case TOperator::EOpIModAssign:
107
        case TOperator::EOpBitShiftLeftAssign:
108
        case TOperator::EOpBitShiftRightAssign:
109
        case TOperator::EOpBitwiseAndAssign:
110
        case TOperator::EOpBitwiseXorAssign:
111
        case TOperator::EOpBitwiseOrAssign:
112
            return true;
113
114
        default:
115
            return false;
116
    }
117
}
118
119
bool ReturnsReference(TOperator op)
120
{
121
    switch (op)
122
    {
123
        case TOperator::EOpAssign:
124
        case TOperator::EOpInitialize:
125
        case TOperator::EOpAddAssign:
126
        case TOperator::EOpSubAssign:
127
        case TOperator::EOpMulAssign:
128
        case TOperator::EOpVectorTimesMatrixAssign:
129
        case TOperator::EOpVectorTimesScalarAssign:
130
        case TOperator::EOpMatrixTimesScalarAssign:
131
        case TOperator::EOpMatrixTimesMatrixAssign:
132
        case TOperator::EOpDivAssign:
133
        case TOperator::EOpIModAssign:
134
        case TOperator::EOpBitShiftLeftAssign:
135
        case TOperator::EOpBitShiftRightAssign:
136
        case TOperator::EOpBitwiseAndAssign:
137
        case TOperator::EOpBitwiseXorAssign:
138
        case TOperator::EOpBitwiseOrAssign:
139
140
        case TOperator::EOpPostIncrement:
141
        case TOperator::EOpPostDecrement:
142
        case TOperator::EOpPreIncrement:
143
        case TOperator::EOpPreDecrement:
144
145
        case TOperator::EOpIndexDirect:
146
        case TOperator::EOpIndexIndirect:
147
        case TOperator::EOpIndexDirectStruct:
148
        case TOperator::EOpIndexDirectInterfaceBlock:
149
150
            return true;
151
152
        default:
153
            return false;
154
    }
155
}
156
157
TIntermTyped &DecomposeCompoundAssignment(TIntermBinary &node)
158
{
159
    TOperator op = node.getOp();
160
    switch (op)
161
    {
162
        case TOperator::EOpAddAssign:
163
            op = TOperator::EOpAdd;
164
            break;
165
        case TOperator::EOpSubAssign:
166
            op = TOperator::EOpSub;
167
            break;
168
        case TOperator::EOpMulAssign:
169
            op = TOperator::EOpMul;
170
            break;
171
        case TOperator::EOpVectorTimesMatrixAssign:
172
            op = TOperator::EOpVectorTimesMatrix;
173
            break;
174
        case TOperator::EOpVectorTimesScalarAssign:
175
            op = TOperator::EOpVectorTimesScalar;
176
            break;
177
        case TOperator::EOpMatrixTimesScalarAssign:
178
            op = TOperator::EOpMatrixTimesScalar;
179
            break;
180
        case TOperator::EOpMatrixTimesMatrixAssign:
181
            op = TOperator::EOpMatrixTimesMatrix;
182
            break;
183
        case TOperator::EOpDivAssign:
184
            op = TOperator::EOpDiv;
185
            break;
186
        case TOperator::EOpIModAssign:
187
            op = TOperator::EOpIMod;
188
            break;
189
        case TOperator::EOpBitShiftLeftAssign:
190
            op = TOperator::EOpBitShiftLeft;
191
            break;
192
        case TOperator::EOpBitShiftRightAssign:
193
            op = TOperator::EOpBitShiftRight;
194
            break;
195
        case TOperator::EOpBitwiseAndAssign:
196
            op = TOperator::EOpBitwiseAnd;
197
            break;
198
        case TOperator::EOpBitwiseXorAssign:
199
            op = TOperator::EOpBitwiseXor;
200
            break;
201
        case TOperator::EOpBitwiseOrAssign:
202
            op = TOperator::EOpBitwiseOr;
203
            break;
204
        default:
205
            LOGIC_ERROR();
206
    }
207
208
    // This assumes SeparateCompoundExpressions has already been called.
209
    // This assumption allows this code to not need to introduce temporaries.
210
    //
211
    // e.g. dont have to worry about:
212
    //      vec[hasSideEffect()] *= 4
213
    // becoming
214
    //      vec[hasSideEffect()] = vec[hasSideEffect()] * 4
215
216
    TIntermTyped *left  = node.getLeft();
217
    TIntermTyped *right = node.getRight();
218
    return *new TIntermBinary(TOperator::EOpAssign, left->deepCopy(),
219
                              new TIntermBinary(op, left, right));
220
}
221
222
class Rewriter1 : public TIntermRebuild
223
{
224
  public:
225
    Rewriter1(TCompiler &compiler) : TIntermRebuild(compiler, false, true) {}
226
227
    PostResult visitBinaryPost(TIntermBinary &binaryNode) override
228
    {
229
        const TOperator op = binaryNode.getOp();
230
        if (IsCompoundAssign(op))
231
        {
232
            TIntermTyped &left = *binaryNode.getLeft();
233
            if (left.getAsSwizzleNode() || IsVectorAccess(left))
234
            {
235
                return DecomposeCompoundAssignment(binaryNode);
236
            }
237
        }
238
        return binaryNode;
239
    }
240
};
241
242
class Rewriter2 : public TIntermRebuild
243
{
244
    std::vector<bool> mRequiresAddressingStack;
245
    SymbolEnv &mSymbolEnv;
246
247
  private:
248
    bool requiresAddressing() const
249
    {
250
        if (mRequiresAddressingStack.empty())
251
        {
252
            return false;
253
        }
254
        return mRequiresAddressingStack.back();
255
    }
256
257
  public:
258
    ~Rewriter2() override { ASSERT(mRequiresAddressingStack.empty()); }
259
260
    Rewriter2(TCompiler &compiler, SymbolEnv &symbolEnv)
261
        : TIntermRebuild(compiler, true, true), mSymbolEnv(symbolEnv)
262
    {}
263
264
    PreResult visitAggregatePre(TIntermAggregate &aggregateNode) override
265
    {
266
        const TFunction *func = aggregateNode.getFunction();
267
        if (!func)
268
        {
269
            return aggregateNode;
270
        }
271
272
        TIntermSequence &args = *aggregateNode.getSequence();
273
        size_t argCount       = args.size();
274
275
        for (size_t i = 0; i < argCount; ++i)
276
        {
277
            const TVariable &param = *func->getParam(i);
278
            const TType &paramType = param.getType();
279
            TIntermNode *arg       = args[i];
280
            ASSERT(arg);
281
282
            mRequiresAddressingStack.push_back(IsOutParam(paramType));
283
            args[i] = rebuild(*arg).single();
284
            ASSERT(args[i]);
285
            ASSERT(!mRequiresAddressingStack.empty());
286
            mRequiresAddressingStack.pop_back();
287
        }
288
289
        return {aggregateNode, VisitBits::Neither};
290
    }
291
292
    PostResult visitSwizzlePost(TIntermSwizzle &swizzleNode) override
293
    {
294
        if (!requiresAddressing())
295
        {
296
            return swizzleNode;
297
        }
298
299
        TIntermTyped &vecNode         = *swizzleNode.getOperand();
300
        const TQualifierList &offsets = swizzleNode.getSwizzleOffsets();
301
        ASSERT(!offsets.empty());
302
        ASSERT(offsets.size() <= 4);
303
304
        auto &args = *new TIntermSequence();
305
        args.reserve(offsets.size() + 1);
306
        args.push_back(&vecNode);
307
        for (int offset : offsets)
308
        {
309
            args.push_back(new TIntermConstantUnion(new TConstantUnion(offset),
310
                                                    *new TType(TBasicType::EbtInt)));
311
        }
312
313
        return mSymbolEnv.callFunctionOverload(Name("swizzle_ref"), swizzleNode.getType(), args);
314
    }
315
316
    PreResult visitBinaryPre(TIntermBinary &binaryNode) override
317
    {
318
        const TOperator op = binaryNode.getOp();
319
320
        const bool isAccess = IsVectorAccess(binaryNode);
321
322
        const bool disableTop   = !ReturnsReference(op) || !requiresAddressing();
323
        const bool disableLeft  = disableTop;
324
        const bool disableRight = disableTop || isAccess || IsAssignEqualsSign(op);
325
326
        auto traverse = [&](TIntermTyped &node, const bool disable) -> TIntermTyped & {
327
            if (disable)
328
            {
329
                mRequiresAddressingStack.push_back(false);
330
            }
331
            auto *newNode = asNode<TIntermTyped>(rebuild(node).single());
332
            ASSERT(newNode);
333
            if (disable)
334
            {
335
                mRequiresAddressingStack.pop_back();
336
            }
337
            return *newNode;
338
        };
339
340
        TIntermTyped &leftNode  = *binaryNode.getLeft();
341
        TIntermTyped &rightNode = *binaryNode.getRight();
342
343
        TIntermTyped &newLeft  = traverse(leftNode, disableLeft);
344
        TIntermTyped &newRight = traverse(rightNode, disableRight);
345
346
        if (!isAccess || disableTop)
347
        {
348
            if (&leftNode == &newLeft && &rightNode == &newRight)
349
            {
350
                return {&binaryNode, VisitBits::Neither};
351
            }
352
            return {*new TIntermBinary(op, &newLeft, &newRight), VisitBits::Neither};
353
        }
354
355
        return {mSymbolEnv.callFunctionOverload(Name("elem_ref"), binaryNode.getType(),
356
                                                *new TIntermSequence{&newLeft, &newRight}),
357
                VisitBits::Neither};
358
    }
359
};
360
361
}  // anonymous namespace
362
363
bool sh::RewriteUnaddressableReferences(TCompiler &compiler,
364
                                        TIntermBlock &root,
365
                                        SymbolEnv &symbolEnv)
366
{
367
    if (!Rewriter1(compiler).rebuildRoot(root))
368
    {
369
        return false;
370
    }
371
    if (!Rewriter2(compiler, symbolEnv).rebuildRoot(root))
372
    {
373
        return false;
374
    }
375
    return true;
376
}
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/RewriteUnaddressableReferences.h +31 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/RewriteUnaddressableReferences.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEUNADDRESSABLEREFERENCES_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEUNADDRESSABLEREFERENCES_H_
9
10
#include "compiler/translator/Compiler.h"
11
#include "compiler/translator/TranslatorMetalDirect/ProgramPrelude.h"
12
#include "compiler/translator/TranslatorMetalDirect/SymbolEnv.h"
13
14
namespace sh
15
{
16
17
// Given:
18
//   void foo(out x);
19
// It is possible for the following to be legal in GLSL but not in Metal:
20
//   foo(expression);
21
// This can happen in cases where `expression` is a vector swizzle or vector element access.
22
// This rewrite functionality introduces temporaries that serve as proxies to be passed to the
23
// out/inout parameters as needed. The corresponding expressions get populated with their
24
// proxies after the function call.
25
ANGLE_NO_DISCARD bool RewriteUnaddressableReferences(TCompiler &compiler,
26
                                                     TIntermBlock &root,
27
                                                     SymbolEnv &symbolEnv);
28
29
}  // namespace sh
30
31
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_REWRITEUNADDRESSABLEREFERENCES_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/SeparateCompoundExpressions.cpp +655 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/SeparateCompoundExpressions.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include <unordered_map>
8
9
#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
10
#include "compiler/translator/TranslatorMetalDirect/Debug.h"
11
#include "compiler/translator/TranslatorMetalDirect/EnvironmentVariable.h"
12
#include "compiler/translator/TranslatorMetalDirect/SeparateCompoundExpressions.h"
13
#include "compiler/translator/tree_ops/SimplifyLoopConditions.h"
14
#include "compiler/translator/tree_util/IntermRebuild.h"
15
16
using namespace sh;
17
18
////////////////////////////////////////////////////////////////////////////////
19
20
namespace
21
{
22
23
bool IsIndex(TOperator op)
24
{
25
    switch (op)
26
    {
27
        case TOperator::EOpIndexDirect:
28
        case TOperator::EOpIndexDirectInterfaceBlock:
29
        case TOperator::EOpIndexDirectStruct:
30
        case TOperator::EOpIndexIndirect:
31
            return true;
32
        default:
33
            return false;
34
    }
35
}
36
37
bool IsIndex(TIntermTyped &expr)
38
{
39
    if (auto *binary = expr.getAsBinaryNode())
40
    {
41
        return IsIndex(binary->getOp());
42
    }
43
    return expr.getAsSwizzleNode();
44
}
45
46
bool ViewBinaryChain(TOperator op, TIntermTyped &node, std::vector<TIntermTyped *> &out)
47
{
48
    TIntermBinary *binary = node.getAsBinaryNode();
49
    if (!binary || binary->getOp() != op)
50
    {
51
        return false;
52
    }
53
54
    TIntermTyped *left  = binary->getLeft();
55
    TIntermTyped *right = binary->getRight();
56
57
    if (!ViewBinaryChain(op, *left, out))
58
    {
59
        out.push_back(left);
60
    }
61
62
    if (!ViewBinaryChain(op, *right, out))
63
    {
64
        out.push_back(right);
65
    }
66
67
    return true;
68
}
69
70
std::vector<TIntermTyped *> ViewBinaryChain(TIntermBinary &node)
71
{
72
    std::vector<TIntermTyped *> chain;
73
    ViewBinaryChain(node.getOp(), node, chain);
74
    ASSERT(chain.size() >= 2);
75
    return chain;
76
}
77
78
class PrePass : public TIntermRebuild
79
{
80
  public:
81
    PrePass(TCompiler &compiler) : TIntermRebuild(compiler, true, true) {}
82
83
  private:
84
    // Change chains of
85
    //      x OP y OP z
86
    // to
87
    //      x OP (y OP z)
88
    // regardless of original parenthesization.
89
    TIntermTyped &reassociateRight(TIntermBinary &node)
90
    {
91
        const TOperator op                = node.getOp();
92
        std::vector<TIntermTyped *> chain = ViewBinaryChain(node);
93
94
        TIntermTyped *result = chain.back();
95
        chain.pop_back();
96
        ASSERT(result);
97
98
        const auto begin = chain.rbegin();
99
        const auto end   = chain.rend();
100
101
        for (auto iter = begin; iter != end; ++iter)
102
        {
103
            TIntermTyped *part = *iter;
104
            ASSERT(part);
105
            TIntermNode *temp = rebuild(*part).single();
106
            ASSERT(temp);
107
            part = temp->getAsTyped();
108
            ASSERT(part);
109
            result = new TIntermBinary(op, part, result);
110
        }
111
        return *result;
112
    }
113
114
  private:
115
    PreResult visitBinaryPre(TIntermBinary &node) override
116
    {
117
        const TOperator op = node.getOp();
118
        if (op == TOperator::EOpLogicalAnd || op == TOperator::EOpLogicalOr)
119
        {
120
            return {reassociateRight(node), VisitBits::Neither};
121
        }
122
        return node;
123
    }
124
};
125
126
class Separator : public TIntermRebuild
127
{
128
    IdGen &mIdGen;
129
    std::vector<std::vector<TIntermNode *>> mStmtsStack;
130
    std::vector<std::unordered_map<const TVariable *, TIntermDeclaration *>> mBindingMapStack;
131
    std::unordered_map<TIntermTyped *, TIntermTyped *> mExprMap;
132
    std::unordered_set<TIntermDeclaration *> mMaskedDecls;
133
134
  public:
135
    Separator(TCompiler &compiler, SymbolEnv &symbolEnv, IdGen &idGen)
136
        : TIntermRebuild(compiler, true, true), mIdGen(idGen)
137
    {}
138
139
    ~Separator() override
140
    {
141
        ASSERT(mStmtsStack.empty());
142
        ASSERT(mExprMap.empty());
143
        ASSERT(mBindingMapStack.empty());
144
    }
145
146
  private:
147
    std::vector<TIntermNode *> &getCurrStmts()
148
    {
149
        ASSERT(!mStmtsStack.empty());
150
        return mStmtsStack.back();
151
    }
152
153
    std::unordered_map<const TVariable *, TIntermDeclaration *> &getCurrBindingMap()
154
    {
155
        ASSERT(!mBindingMapStack.empty());
156
        return mBindingMapStack.back();
157
    }
158
159
    void pushStmt(TIntermNode &node) { getCurrStmts().push_back(&node); }
160
161
    bool isTerminalExpr(TIntermNode &node)
162
    {
163
        NodeType nodeType = getNodeType(node);
164
        switch (nodeType)
165
        {
166
            case NodeType::Symbol:
167
            case NodeType::ConstantUnion:
168
                return true;
169
            default:
170
                return false;
171
        }
172
    }
173
174
    TIntermTyped *pullMappedExpr(TIntermTyped *node, bool allowBacktrack)
175
    {
176
        TIntermTyped *expr;
177
178
        {
179
            auto iter = mExprMap.find(node);
180
            if (iter == mExprMap.end())
181
            {
182
                return node;
183
            }
184
            ASSERT(node);
185
            expr = iter->second;
186
            ASSERT(expr);
187
            mExprMap.erase(iter);
188
        }
189
190
        if (allowBacktrack)
191
        {
192
            auto &bindingMap = getCurrBindingMap();
193
            while (TIntermSymbol *symbol = expr->getAsSymbolNode())
194
            {
195
                const TVariable &var = symbol->variable();
196
                auto iter            = bindingMap.find(&var);
197
                if (iter == bindingMap.end())
198
                {
199
                    return expr;
200
                }
201
                ASSERT(var.symbolType() == SymbolType::AngleInternal);
202
                TIntermDeclaration *decl = iter->second;
203
                ASSERT(decl);
204
                expr = ViewDeclaration(*decl).initExpr;
205
                ASSERT(expr);
206
                bindingMap.erase(iter);
207
                mMaskedDecls.insert(decl);
208
            }
209
        }
210
211
        return expr;
212
    }
213
214
    bool isStandaloneExpr(TIntermTyped &expr)
215
    {
216
        if (getParentNode()->getAsBlock())
217
        {
218
            return true;
219
        }
220
        ASSERT(expr.getType().getBasicType() != TBasicType::EbtVoid);
221
        return false;
222
    }
223
224
    void pushBinding(TIntermTyped &oldExpr, TIntermTyped &newExpr)
225
    {
226
        if (isStandaloneExpr(newExpr))
227
        {
228
            pushStmt(newExpr);
229
            return;
230
        }
231
        if (IsIndex(newExpr))
232
        {
233
            mExprMap[&oldExpr] = &newExpr;
234
            return;
235
        }
236
        auto &bindingMap = getCurrBindingMap();
237
        const Name name  = mIdGen.createNewName("");
238
        auto *var =
239
            new TVariable(&mSymbolTable, name.rawName(), &newExpr.getType(), name.symbolType());
240
        auto *decl = new TIntermDeclaration(var, &newExpr);
241
        pushStmt(*decl);
242
        mExprMap[&oldExpr] = new TIntermSymbol(var);
243
        bindingMap[var]    = decl;
244
    }
245
246
    void pushStacks()
247
    {
248
        mStmtsStack.emplace_back();
249
        mBindingMapStack.emplace_back();
250
    }
251
252
    void popStacks()
253
    {
254
        ASSERT(!mBindingMapStack.empty());
255
        ASSERT(!mStmtsStack.empty());
256
        ASSERT(mStmtsStack.back().empty());
257
        mBindingMapStack.pop_back();
258
        mStmtsStack.pop_back();
259
    }
260
261
    void pushStmtsIntoBlock(TIntermBlock &block, std::vector<TIntermNode *> &stmts)
262
    {
263
        TIntermSequence &seq = *block.getSequence();
264
        for (TIntermNode *stmt : stmts)
265
        {
266
            if (TIntermDeclaration *decl = stmt->getAsDeclarationNode())
267
            {
268
                auto iter = mMaskedDecls.find(decl);
269
                if (iter != mMaskedDecls.end())
270
                {
271
                    mMaskedDecls.erase(iter);
272
                    continue;
273
                }
274
            }
275
            seq.push_back(stmt);
276
        }
277
    }
278
279
    TIntermBlock &buildBlockWithTailAssign(const TVariable &var, TIntermTyped &newExpr)
280
    {
281
        std::vector<TIntermNode *> stmts = std::move(getCurrStmts());
282
        popStacks();
283
284
        auto &block = *new TIntermBlock();
285
        auto &seq   = *block.getSequence();
286
        seq.reserve(1 + stmts.size());
287
        pushStmtsIntoBlock(block, stmts);
288
        seq.push_back(new TIntermBinary(TOperator::EOpAssign, new TIntermSymbol(&var), &newExpr));
289
290
        return block;
291
    }
292
293
  private:
294
    PreResult visitBlockPre(TIntermBlock &node) override
295
    {
296
        pushStacks();
297
        return node;
298
    }
299
300
    PostResult visitBlockPost(TIntermBlock &node) override
301
    {
302
        std::vector<TIntermNode *> stmts = std::move(getCurrStmts());
303
        popStacks();
304
305
        TIntermSequence &seq = *node.getSequence();
306
        seq.clear();
307
        seq.reserve(stmts.size());
308
        pushStmtsIntoBlock(node, stmts);
309
310
        TIntermNode *parent = getParentNode();
311
        if (parent && parent->getAsBlock())
312
        {
313
            pushStmt(node);
314
        }
315
316
        return node;
317
    }
318
319
    PreResult visitDeclarationPre(TIntermDeclaration &node) override
320
    {
321
        Declaration decl = ViewDeclaration(node);
322
        if (!decl.initExpr || isTerminalExpr(*decl.initExpr))
323
        {
324
            pushStmt(node);
325
            return {node, VisitBits::Neither};
326
        }
327
        return node;
328
    }
329
330
    PostResult visitDeclarationPost(TIntermDeclaration &node) override
331
    {
332
        Declaration decl = ViewDeclaration(node);
333
        ASSERT(decl.symbol.variable().symbolType() != SymbolType::Empty);
334
        ASSERT(!decl.symbol.variable().getType().isStructSpecifier());
335
336
        TIntermTyped *newInitExpr = pullMappedExpr(decl.initExpr, true);
337
        if (decl.initExpr == newInitExpr)
338
        {
339
            pushStmt(node);
340
        }
341
        else
342
        {
343
            auto &newNode = *new TIntermDeclaration();
344
            newNode.appendDeclarator(
345
                new TIntermBinary(TOperator::EOpInitialize, &decl.symbol, newInitExpr));
346
            pushStmt(newNode);
347
        }
348
        return node;
349
    }
350
351
    PostResult visitUnaryPost(TIntermUnary &node) override
352
    {
353
        TIntermTyped *expr    = node.getOperand();
354
        TIntermTyped *newExpr = pullMappedExpr(expr, false);
355
        if (expr == newExpr)
356
        {
357
            pushBinding(node, node);
358
        }
359
        else
360
        {
361
            pushBinding(node, *new TIntermUnary(node.getOp(), newExpr, node.getFunction()));
362
        }
363
        return node;
364
    }
365
366
    PreResult visitBinaryPre(TIntermBinary &node) override
367
    {
368
        const TOperator op = node.getOp();
369
        if (op == TOperator::EOpLogicalAnd || op == TOperator::EOpLogicalOr)
370
        {
371
            TIntermTyped *left  = node.getLeft();
372
            TIntermTyped *right = node.getRight();
373
374
            PostResult leftResult = rebuild(*left);
375
            ASSERT(leftResult.single());
376
377
            pushStacks();
378
            PostResult rightResult = rebuild(*right);
379
            ASSERT(rightResult.single());
380
381
            return {node, VisitBits::Post};
382
        }
383
384
        return node;
385
    }
386
387
    PostResult visitBinaryPost(TIntermBinary &node) override
388
    {
389
        const TOperator op = node.getOp();
390
        if (op == TOperator::EOpInitialize && getParentNode()->getAsDeclarationNode())
391
        {
392
            // Special case is handled by visitDeclarationPost
393
            return node;
394
        }
395
396
        TIntermTyped *left  = node.getLeft();
397
        TIntermTyped *right = node.getRight();
398
399
        if (op == TOperator::EOpLogicalAnd || op == TOperator::EOpLogicalOr)
400
        {
401
            const Name name = mIdGen.createNewName("");
402
            auto *var = new TVariable(&mSymbolTable, name.rawName(), new TType(TBasicType::EbtBool),
403
                                      name.symbolType());
404
405
            TIntermTyped *newRight   = pullMappedExpr(right, true);
406
            TIntermBlock *rightBlock = &buildBlockWithTailAssign(*var, *newRight);
407
            TIntermTyped *newLeft    = pullMappedExpr(left, true);
408
409
            TIntermTyped *cond = new TIntermSymbol(var);
410
            if (op == TOperator::EOpLogicalOr)
411
            {
412
                cond = new TIntermUnary(TOperator::EOpLogicalNot, cond, nullptr);
413
            }
414
415
            pushStmt(*new TIntermDeclaration(var, newLeft));
416
            pushStmt(*new TIntermIfElse(cond, rightBlock, nullptr));
417
            if (!isStandaloneExpr(node))
418
            {
419
                mExprMap[&node] = new TIntermSymbol(var);
420
            }
421
422
            return node;
423
        }
424
425
        const bool isAssign    = IsAssignment(op);
426
        TIntermTyped *newLeft  = pullMappedExpr(left, false);
427
        TIntermTyped *newRight = pullMappedExpr(right, isAssign);
428
429
        if (op == TOperator::EOpComma)
430
        {
431
            pushBinding(node, *newRight);
432
            return node;
433
        }
434
        else
435
        {
436
            TIntermBinary *newNode;
437
            if (left == newLeft && right == newRight)
438
            {
439
                newNode = &node;
440
            }
441
            else
442
            {
443
                newNode = new TIntermBinary(op, newLeft, newRight);
444
            }
445
            pushBinding(node, *newNode);
446
            return node;
447
        }
448
    }
449
450
    PreResult visitTernaryPre(TIntermTernary &node) override
451
    {
452
        PostResult condResult = rebuild(*node.getCondition());
453
        ASSERT(condResult.single());
454
455
        pushStacks();
456
        PostResult thenResult = rebuild(*node.getTrueExpression());
457
        ASSERT(thenResult.single());
458
459
        pushStacks();
460
        PostResult elseResult = rebuild(*node.getFalseExpression());
461
        ASSERT(elseResult.single());
462
463
        return {node, VisitBits::Post};
464
    }
465
466
    PostResult visitTernaryPost(TIntermTernary &node) override
467
    {
468
        TIntermTyped *cond  = node.getCondition();
469
        TIntermTyped *then  = node.getTrueExpression();
470
        TIntermTyped *else_ = node.getFalseExpression();
471
472
        const Name name = mIdGen.createNewName("");
473
        auto *var =
474
            new TVariable(&mSymbolTable, name.rawName(), &node.getType(), name.symbolType());
475
476
        TIntermTyped *newElse   = pullMappedExpr(else_, false);
477
        TIntermBlock *elseBlock = &buildBlockWithTailAssign(*var, *newElse);
478
        TIntermTyped *newThen   = pullMappedExpr(then, true);
479
        TIntermBlock *thenBlock = &buildBlockWithTailAssign(*var, *newThen);
480
        TIntermTyped *newCond   = pullMappedExpr(cond, true);
481
482
        pushStmt(*new TIntermDeclaration{var});
483
        pushStmt(*new TIntermIfElse(newCond, thenBlock, elseBlock));
484
        if (!isStandaloneExpr(node))
485
        {
486
            mExprMap[&node] = new TIntermSymbol(var);
487
        }
488
489
        return node;
490
    }
491
492
    PostResult visitSwizzlePost(TIntermSwizzle &node) override
493
    {
494
        TIntermTyped *expr    = node.getOperand();
495
        TIntermTyped *newExpr = pullMappedExpr(expr, false);
496
        if (expr == newExpr)
497
        {
498
            pushBinding(node, node);
499
        }
500
        else
501
        {
502
            pushBinding(node, *new TIntermSwizzle(newExpr, node.getSwizzleOffsets()));
503
        }
504
        return node;
505
    }
506
507
    PostResult visitAggregatePost(TIntermAggregate &node) override
508
    {
509
        TIntermSequence &args = *node.getSequence();
510
        for (TIntermNode *&arg : args)
511
        {
512
            TIntermTyped *targ = arg->getAsTyped();
513
            ASSERT(targ);
514
            arg = pullMappedExpr(targ, false);
515
        }
516
        pushBinding(node, node);
517
        return node;
518
    }
519
520
    PostResult visitPreprocessorDirectivePost(TIntermPreprocessorDirective &node) override
521
    {
522
        pushStmt(node);
523
        return node;
524
    }
525
526
    PostResult visitFunctionPrototypePost(TIntermFunctionPrototype &node) override
527
    {
528
        if (!getParentFunction())
529
        {
530
            pushStmt(node);
531
        }
532
        return node;
533
    }
534
535
    PreResult visitCasePre(TIntermCase &node) override
536
    {
537
        if (TIntermTyped *cond = node.getCondition())
538
        {
539
            ASSERT(isTerminalExpr(*cond));
540
        }
541
        pushStmt(node);
542
        return {node, VisitBits::Neither};
543
    }
544
545
    PostResult visitSwitchPost(TIntermSwitch &node) override
546
    {
547
        TIntermTyped *init    = node.getInit();
548
        TIntermTyped *newInit = pullMappedExpr(init, false);
549
        if (init == newInit)
550
        {
551
            pushStmt(node);
552
        }
553
        else
554
        {
555
            pushStmt(*new TIntermSwitch(newInit, node.getStatementList()));
556
        }
557
558
        return node;
559
    }
560
561
    PostResult visitFunctionDefinitionPost(TIntermFunctionDefinition &node) override
562
    {
563
        pushStmt(node);
564
        return node;
565
    }
566
567
    PostResult visitIfElsePost(TIntermIfElse &node) override
568
    {
569
        TIntermTyped *cond    = node.getCondition();
570
        TIntermTyped *newCond = pullMappedExpr(cond, false);
571
        if (cond == newCond)
572
        {
573
            pushStmt(node);
574
        }
575
        else
576
        {
577
            pushStmt(*new TIntermIfElse(newCond, node.getTrueBlock(), node.getFalseBlock()));
578
        }
579
        return node;
580
    }
581
582
    PostResult visitBranchPost(TIntermBranch &node) override
583
    {
584
        TIntermTyped *expr    = node.getExpression();
585
        TIntermTyped *newExpr = pullMappedExpr(expr, false);
586
        if (expr == newExpr)
587
        {
588
            pushStmt(node);
589
        }
590
        else
591
        {
592
            pushStmt(*new TIntermBranch(node.getFlowOp(), newExpr));
593
        }
594
        return node;
595
    }
596
597
    PreResult visitLoopPre(TIntermLoop &node) override
598
    {
599
        if (!rebuildInPlace(*node.getBody()))
600
        {
601
            LOGIC_ERROR();
602
        }
603
        pushStmt(node);
604
        return {node, VisitBits::Neither};
605
    }
606
607
    PostResult visitConstantUnionPost(TIntermConstantUnion &node) override
608
    {
609
        const TType &type = node.getType();
610
        if (!type.isScalar())
611
        {
612
            pushBinding(node, node);
613
        }
614
        return node;
615
    }
616
617
    PostResult visitGlobalQualifierDeclarationPost(TIntermGlobalQualifierDeclaration &node) override
618
    {
619
        ASSERT(false);  // These should be scrubbed from AST before rewriter is called.
620
        pushStmt(node);
621
        return node;
622
    }
623
};
624
625
}  // anonymous namespace
626
627
////////////////////////////////////////////////////////////////////////////////
628
629
bool sh::SeparateCompoundExpressions(TCompiler &compiler,
630
                                     SymbolEnv &symbolEnv,
631
                                     IdGen &idGen,
632
                                     TIntermBlock &root)
633
{
634
    if (readBoolEnvVar("GMT_DISABLE_SEPARATE_COMPOUND_EXPRESSIONS"))
635
    {
636
        return true;
637
    }
638
639
    if (!SimplifyLoopConditions(&compiler, &root, &compiler.getSymbolTable()))
640
    {
641
        return false;
642
    }
643
644
    if (!PrePass(compiler).rebuildRoot(root))
645
    {
646
        return false;
647
    }
648
649
    if (!Separator(compiler, symbolEnv, idGen).rebuildRoot(root))
650
    {
651
        return false;
652
    }
653
654
    return true;
655
}
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/SeparateCompoundExpressions.h +47 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/SeparateCompoundExpressions.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_SEPARATECOMPOUNDEXPRESSIONS_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_SEPARATECOMPOUNDEXPRESSIONS_H_
9
10
#include "common/angleutils.h"
11
#include "compiler/translator/Compiler.h"
12
#include "compiler/translator/TranslatorMetalDirect/IdGen.h"
13
#include "compiler/translator/TranslatorMetalDirect/SymbolEnv.h"
14
15
namespace sh
16
{
17
18
// Transforms code to (usually) have most one non-terminal expression per statement.
19
// This also rewrites (&&), (||), and (?:) into raw if/if-not/if-else statements, respectively.
20
//
21
// e.g.
22
//    int x = 6 + foo(y, bar());
23
// becomes
24
//    auto _1 = bar();
25
//    auto _2 = foo(y, _1);
26
//    auto _3 = 6 + _2;
27
//    int x = _3;
28
//
29
// WARNING:
30
//    - This does not rewrite object indexing operators as a whole (e.g. foo.x, foo[x]), but will
31
//      rewrite the arguments to the operator (when applicable).
32
//      e.g.
33
//        foo(getVec()[i + 2] + 1);
34
//      becomes
35
//        auto _1 = getVec();
36
//        auto _2 = i + 2;
37
//        auto _3 = _1[_2] + 1; // Index operator remains in (+) expr here.
38
//        foo(_3);
39
//
40
ANGLE_NO_DISCARD bool SeparateCompoundExpressions(TCompiler &compiler,
41
                                                  SymbolEnv &symbolEnv,
42
                                                  IdGen &idGen,
43
                                                  TIntermBlock &root);
44
45
}  // namespace sh
46
47
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_SEPARATECOMPOUNDEXPRESSIONS_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/SeparateCompoundStructDeclarations.cpp +77 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/SeparateCompoundStructDeclarations.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include <algorithm>
8
9
#include "compiler/translator/TranslatorMetalDirect/SeparateCompoundStructDeclarations.h"
10
#include "compiler/translator/tree_ops/SeparateDeclarations.h"
11
#include "compiler/translator/tree_util/IntermTraverse.h"
12
13
using namespace sh;
14
15
////////////////////////////////////////////////////////////////////////////////
16
17
namespace
18
{
19
20
class Separator : public TIntermTraverser
21
{
22
  public:
23
    Separator(TSymbolTable &symbolTable) : TIntermTraverser(false, false, true, &symbolTable) {}
24
25
    bool visitDeclaration(Visit, TIntermDeclaration *declNode) override
26
    {
27
        ASSERT(declNode->getChildCount() == 1);
28
        TIntermNode &node = *declNode->getChildNode(0);
29
30
        if (TIntermSymbol *symbolNode = node.getAsSymbolNode())
31
        {
32
            const TVariable &var        = symbolNode->variable();
33
            const TType &type           = var.getType();
34
            const SymbolType symbolType = var.symbolType();
35
            if (type.isStructSpecifier() && symbolType != SymbolType::Empty)
36
            {
37
                const TStructure *structure = type.getStruct();
38
                auto *structVar             = new TVariable(mSymbolTable, ImmutableString(""),
39
                                                new TType(structure, true), SymbolType::Empty);
40
41
                auto *instanceType = new TType(structure, false);
42
                instanceType->setQualifier(type.getQualifier());
43
                auto *instanceVar = new TVariable(mSymbolTable, var.name(), instanceType,
44
                                                  symbolType, var.extension());
45
46
                TIntermSequence replacements;
47
                replacements.push_back(new TIntermSymbol(structVar));
48
                replacements.push_back(new TIntermSymbol(instanceVar));
49
                mMultiReplacements.push_back(
50
                    NodeReplaceWithMultipleEntry(declNode, symbolNode, std::move(replacements)));
51
            }
52
        }
53
54
        return false;
55
    }
56
};
57
58
}  // anonymous namespace
59
60
////////////////////////////////////////////////////////////////////////////////
61
62
bool sh::SeparateCompoundStructDeclarations(TCompiler &compiler, TIntermBlock &root)
63
{
64
    Separator separator(compiler.getSymbolTable());
65
    root.traverse(&separator);
66
    if (!separator.updateTree(&compiler, &root))
67
    {
68
        return false;
69
    }
70
71
    if (!SeparateDeclarations(&compiler, &root))
72
    {
73
        return false;
74
    }
75
76
    return true;
77
}
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/SeparateCompoundStructDeclarations.h +24 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/SeparateCompoundStructDeclarations.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_SEPARATECOMPOUNDSTRUCTDECLARATIONS_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_SEPARATECOMPOUNDSTRUCTDECLARATIONS_H_
9
10
#include "common/angleutils.h"
11
#include "compiler/translator/Compiler.h"
12
13
namespace sh
14
{
15
16
// Example:
17
//  struct Foo { int x; } foo;
18
// Becomes:
19
//  struct Foo {int x; }; Foo foo;
20
ANGLE_NO_DISCARD bool SeparateCompoundStructDeclarations(TCompiler &compiler, TIntermBlock &root);
21
22
}  // namespace sh
23
24
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_SEPARATECOMPOUNDSTRUCTDECLARATIONS_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/SkippingTraverser.h +47 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/SkippingTraverser.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_SKIPPINGTRAVERSER_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_SKIPPINGTRAVERSER_H_
9
10
#include "compiler/translator/tree_util/IntermTraverse.h"
11
12
namespace sh
13
{
14
15
// A TIntermTraverser that skips traversing childen by default.
16
class SkippingTraverser : public TIntermTraverser
17
{
18
  public:
19
    SkippingTraverser(bool preVisit_,
20
                      bool inVisit_,
21
                      bool postVisit_,
22
                      TSymbolTable *symbolTable = nullptr)
23
        : TIntermTraverser(preVisit_, inVisit_, postVisit_, symbolTable)
24
    {}
25
26
    bool visitSwizzle(Visit, TIntermSwizzle *) { return false; }
27
    bool visitUnary(Visit, TIntermUnary *) { return false; }
28
    bool visitBinary(Visit, TIntermBinary *) { return false; }
29
    bool visitTernary(Visit, TIntermTernary *) { return false; }
30
    bool visitIfElse(Visit, TIntermIfElse *) { return false; }
31
    bool visitSwitch(Visit, TIntermSwitch *) { return false; }
32
    bool visitCase(Visit, TIntermCase *) { return false; }
33
    bool visitFunctionDefinition(Visit, TIntermFunctionDefinition *) { return false; }
34
    bool visitAggregate(Visit, TIntermAggregate *) { return false; }
35
    bool visitBlock(Visit, TIntermBlock *) { return false; }
36
    bool visitDeclaration(Visit, TIntermDeclaration *) { return false; }
37
    bool visitLoop(Visit, TIntermLoop *) { return false; }
38
    bool visitBranch(Visit, TIntermBranch *) { return false; }
39
    bool visitGlobalQualifierDeclaration(Visit, TIntermGlobalQualifierDeclaration *)
40
    {
41
        return false;
42
    }
43
};
44
45
}  // namespace sh
46
47
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_SKIPPINGTRAVERSER_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/SymbolEnv.cpp +681 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/SymbolEnv.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include <algorithm>
8
#include <limits>
9
10
#include "compiler/translator/ImmutableStringBuilder.h"
11
#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
12
#include "compiler/translator/TranslatorMetalDirect/Debug.h"
13
#include "compiler/translator/TranslatorMetalDirect/SymbolEnv.h"
14
#include "compiler/translator/tree_util/IntermRebuild.h"
15
16
using namespace sh;
17
18
////////////////////////////////////////////////////////////////////////////////
19
20
constexpr AddressSpace kAddressSpaces[] = {
21
    AddressSpace::Constant,
22
    AddressSpace::Device,
23
    AddressSpace::Thread,
24
};
25
26
char const *sh::toString(AddressSpace space)
27
{
28
    switch (space)
29
    {
30
        case AddressSpace::Constant:
31
            return "constant";
32
        case AddressSpace::Device:
33
            return "device";
34
        case AddressSpace::Thread:
35
            return "thread";
36
    }
37
}
38
39
////////////////////////////////////////////////////////////////////////////////
40
41
using NameToStruct = std::map<Name, const TStructure *>;
42
43
class StructFinder : TIntermRebuild
44
{
45
    NameToStruct nameToStruct;
46
47
    StructFinder(TCompiler &compiler) : TIntermRebuild(compiler, true, false) {}
48
49
    PreResult visitDeclarationPre(TIntermDeclaration &node) override
50
    {
51
        Declaration decl     = ViewDeclaration(node);
52
        const TVariable &var = decl.symbol.variable();
53
        const TType &type    = var.getType();
54
55
        if (var.symbolType() == SymbolType::Empty && type.isStructSpecifier())
56
        {
57
            const TStructure *s = type.getStruct();
58
            ASSERT(s);
59
            const Name name(*s);
60
            const TStructure *&z = nameToStruct[name];
61
            ASSERT(!z);
62
            z = s;
63
        }
64
65
        return node;
66
    }
67
68
    PreResult visitFunctionDefinitionPre(TIntermFunctionDefinition &node) override
69
    {
70
        return {node, VisitBits::Neither};
71
    }
72
73
  public:
74
    static NameToStruct FindStructs(TCompiler &compiler, TIntermBlock &root)
75
    {
76
        StructFinder finder(compiler);
77
        if (!finder.rebuildRoot(root))
78
        {
79
            LOGIC_ERROR();
80
        }
81
        return std::move(finder.nameToStruct);
82
    }
83
};
84
85
////////////////////////////////////////////////////////////////////////////////
86
87
TemplateArg::TemplateArg(bool value) : mKind(Kind::Bool), mValue(value) {}
88
89
TemplateArg::TemplateArg(int value) : mKind(Kind::Int), mValue(value) {}
90
91
TemplateArg::TemplateArg(unsigned value) : mKind(Kind::UInt), mValue(value) {}
92
93
TemplateArg::TemplateArg(const TType &value) : mKind(Kind::Type), mValue(value) {}
94
95
bool TemplateArg::operator==(const TemplateArg &other) const
96
{
97
    if (mKind != other.mKind)
98
    {
99
        return false;
100
    }
101
102
    switch (mKind)
103
    {
104
        case Kind::Bool:
105
            return mValue.b == other.mValue.b;
106
        case Kind::Int:
107
            return mValue.i == other.mValue.i;
108
        case Kind::UInt:
109
            return mValue.u == other.mValue.u;
110
        case Kind::Type:
111
            return *mValue.t == *other.mValue.t;
112
    }
113
}
114
115
bool TemplateArg::operator<(const TemplateArg &other) const
116
{
117
    if (mKind < other.mKind)
118
    {
119
        return true;
120
    }
121
122
    if (mKind > other.mKind)
123
    {
124
        return false;
125
    }
126
127
    switch (mKind)
128
    {
129
        case Kind::Bool:
130
            return mValue.b < other.mValue.b;
131
        case Kind::Int:
132
            return mValue.i < other.mValue.i;
133
        case Kind::UInt:
134
            return mValue.u < other.mValue.u;
135
        case Kind::Type:
136
            return *mValue.t < *other.mValue.t;
137
    }
138
}
139
140
////////////////////////////////////////////////////////////////////////////////
141
142
bool SymbolEnv::TemplateName::operator==(const TemplateName &other) const
143
{
144
    return baseName == other.baseName && templateArgs == other.templateArgs;
145
}
146
147
bool SymbolEnv::TemplateName::operator<(const TemplateName &other) const
148
{
149
    if (baseName < other.baseName)
150
    {
151
        return true;
152
    }
153
    if (other.baseName < baseName)
154
    {
155
        return false;
156
    }
157
    return templateArgs < other.templateArgs;
158
}
159
160
bool SymbolEnv::TemplateName::empty() const
161
{
162
    return baseName.empty() && templateArgs.empty();
163
}
164
165
void SymbolEnv::TemplateName::clear()
166
{
167
    baseName = Name();
168
    templateArgs.clear();
169
}
170
171
Name SymbolEnv::TemplateName::fullName(std::string &buffer) const
172
{
173
    ASSERT(buffer.empty());
174
175
    if (templateArgs.empty())
176
    {
177
        return baseName;
178
    }
179
180
    static constexpr size_t n = std::max({
181
        std::numeric_limits<unsigned>::digits10,  //
182
        std::numeric_limits<int>::digits10,       //
183
        5,                                        // max_length("true", "false")
184
    });
185
186
    buffer.reserve(baseName.rawName().length() + (n + 2) * templateArgs.size() + 1);
187
    buffer += baseName.rawName().data();
188
189
    if (!templateArgs.empty())
190
    {
191
        buffer += "<";
192
193
        bool first = true;
194
        char argBuffer[n + 1];
195
        for (const TemplateArg &arg : templateArgs)
196
        {
197
            if (first)
198
            {
199
                first = false;
200
            }
201
            else
202
            {
203
                buffer += ", ";
204
            }
205
206
            const TemplateArg::Value value = arg.value();
207
            const TemplateArg::Kind kind   = arg.kind();
208
            switch (kind)
209
            {
210
                case TemplateArg::Kind::Bool:
211
                    if (value.b)
212
                    {
213
                        buffer += "true";
214
                    }
215
                    else
216
                    {
217
                        buffer += "false";
218
                    }
219
                    break;
220
221
                case TemplateArg::Kind::Int:
222
                    sprintf(argBuffer, "%i", value.i);
223
                    buffer += argBuffer;
224
                    break;
225
226
                case TemplateArg::Kind::UInt:
227
                    sprintf(argBuffer, "%u", value.u);
228
                    buffer += argBuffer;
229
                    break;
230
231
                case TemplateArg::Kind::Type:
232
                {
233
                    const TType &type = *value.t;
234
                    if (const TStructure *s = type.getStruct())
235
                    {
236
                        buffer += s->name().data();
237
                    }
238
                    else if (HasScalarBasicType(type))
239
                    {
240
                        ASSERT(!type.isArray());  // TODO
241
                        buffer += type.getBasicString();
242
                        if (type.isVector())
243
                        {
244
                            sprintf(argBuffer, "%i", type.getNominalSize());
245
                            buffer += argBuffer;
246
                        }
247
                        else if (type.isMatrix())
248
                        {
249
                            sprintf(argBuffer, "%i", type.getCols());
250
                            buffer += argBuffer;
251
                            buffer += "x";
252
                            sprintf(argBuffer, "%i", type.getRows());
253
                            buffer += argBuffer;
254
                        }
255
                    }
256
                }
257
                break;
258
            }
259
        }
260
261
        buffer += ">";
262
    }
263
264
    const ImmutableString name(buffer);
265
    buffer.clear();
266
267
    return Name(name, baseName.symbolType());
268
}
269
270
void SymbolEnv::TemplateName::assign(const Name &name, size_t argCount, const TemplateArg *args)
271
{
272
    baseName = name;
273
    templateArgs.clear();
274
    for (size_t i = 0; i < argCount; ++i)
275
    {
276
        templateArgs.push_back(args[i]);
277
    }
278
}
279
280
////////////////////////////////////////////////////////////////////////////////
281
282
SymbolEnv::SymbolEnv(TCompiler &compiler, TIntermBlock &root)
283
    : mSymbolTable(compiler.getSymbolTable()),
284
      mNameToStruct(StructFinder::FindStructs(compiler, root))
285
{}
286
287
const TStructure &SymbolEnv::remap(const TStructure &s) const
288
{
289
    const Name name(s);
290
    auto iter = mNameToStruct.find(name);
291
    if (iter == mNameToStruct.end())
292
    {
293
        return s;
294
    }
295
    const TStructure &z = *iter->second;
296
    return z;
297
}
298
299
const TStructure *SymbolEnv::remap(const TStructure *s) const
300
{
301
    if (s)
302
    {
303
        return &remap(*s);
304
    }
305
    return nullptr;
306
}
307
308
const TFunction &SymbolEnv::getFunctionOverloadImpl()
309
{
310
    ASSERT(!mReusableSigBuffer.empty());
311
312
    SigToFunc &sigToFunc = mOverloads[mReusableTemplateNameBuffer];
313
    TFunction *&func     = sigToFunc[mReusableSigBuffer];
314
315
    if (!func)
316
    {
317
        const TType &returnType = mReusableSigBuffer.back();
318
        mReusableSigBuffer.pop_back();
319
320
        const Name name = mReusableTemplateNameBuffer.fullName(mReusableStringBuffer);
321
322
        func = new TFunction(&mSymbolTable, name.rawName(), name.symbolType(), &returnType, false);
323
        for (const TType &paramType : mReusableSigBuffer)
324
        {
325
            func->addParameter(
326
                new TVariable(&mSymbolTable, kEmptyImmutableString, &paramType, SymbolType::Empty));
327
        }
328
    }
329
330
    mReusableSigBuffer.clear();
331
    mReusableTemplateNameBuffer.clear();
332
333
    return *func;
334
}
335
336
const TFunction &SymbolEnv::getFunctionOverload(const Name &name,
337
                                                const TType &returnType,
338
                                                size_t paramCount,
339
                                                const TType **paramTypes,
340
                                                size_t templateArgCount,
341
                                                const TemplateArg *templateArgs)
342
{
343
    ASSERT(mReusableSigBuffer.empty());
344
    ASSERT(mReusableTemplateNameBuffer.empty());
345
346
    for (size_t i = 0; i < paramCount; ++i)
347
    {
348
        mReusableSigBuffer.push_back(*paramTypes[i]);
349
    }
350
    mReusableSigBuffer.push_back(returnType);
351
    mReusableTemplateNameBuffer.assign(name, templateArgCount, templateArgs);
352
    return getFunctionOverloadImpl();
353
}
354
355
TIntermAggregate &SymbolEnv::callFunctionOverload(const Name &name,
356
                                                  const TType &returnType,
357
                                                  TIntermSequence &args,
358
                                                  size_t templateArgCount,
359
                                                  const TemplateArg *templateArgs)
360
{
361
    ASSERT(mReusableSigBuffer.empty());
362
    ASSERT(mReusableTemplateNameBuffer.empty());
363
364
    for (TIntermNode *arg : args)
365
    {
366
        TIntermTyped *targ = arg->getAsTyped();
367
        ASSERT(targ);
368
        mReusableSigBuffer.push_back(targ->getType());
369
    }
370
    mReusableSigBuffer.push_back(returnType);
371
    mReusableTemplateNameBuffer.assign(name, templateArgCount, templateArgs);
372
    const TFunction &func = getFunctionOverloadImpl();
373
    return *TIntermAggregate::CreateRawFunctionCall(func, &args);
374
}
375
376
const TStructure &SymbolEnv::newStructure(const Name &name, TFieldList &fields)
377
{
378
    ASSERT(name.symbolType() == SymbolType::AngleInternal);
379
380
    TStructure *&s = mAngleStructs[name.rawName()];
381
    ASSERT(!s);
382
    s = new TStructure(&mSymbolTable, name.rawName(), &fields, name.symbolType());
383
    return *s;
384
}
385
386
const TStructure &SymbolEnv::getTextureEnv(TBasicType samplerType)
387
{
388
    ASSERT(IsSampler(samplerType));
389
    const TStructure *&env = mTextureEnvs[samplerType];
390
    if (env == nullptr)
391
    {
392
        auto *textureType = new TType(samplerType);
393
        auto *texture     = new TField(textureType, ImmutableString("texture"), kNoSourceLoc,
394
                                   SymbolType::UserDefined);
395
        markAsPointer(*texture, AddressSpace::Thread);
396
397
        auto *sampler =
398
            new TField(new TType(&getSamplerStruct(), false), ImmutableString("sampler"),
399
                       kNoSourceLoc, SymbolType::UserDefined);
400
        markAsPointer(*sampler, AddressSpace::Thread);
401
402
        std::string envName;
403
        envName += "TextureEnv<";
404
        envName += GetTextureTypeName(samplerType).rawName().data();
405
        envName += ">";
406
407
        env = &newStructure(Name(envName, SymbolType::AngleInternal),
408
                            *new TFieldList{texture, sampler});
409
    }
410
    return *env;
411
}
412
413
const TStructure &SymbolEnv::getSamplerStruct()
414
{
415
    if (!mSampler)
416
    {
417
        mSampler = new TStructure(&mSymbolTable, ImmutableString("metal::sampler"),
418
                                  new TFieldList(), SymbolType::UserDefined);
419
    }
420
    return *mSampler;
421
}
422
423
void SymbolEnv::markSpace(VarField x,
424
                          AddressSpace space,
425
                          std::unordered_map<VarField, AddressSpace> &map)
426
{
427
    // It is in principle permissible to have references to pointers or multiple pointers, but this
428
    // is not required for now and would require code changes to get right.
429
    ASSERT(!isPointer(x));
430
    ASSERT(!isReference(x));
431
432
    map[x] = space;
433
}
434
435
const AddressSpace *SymbolEnv::isSpace(VarField x,
436
                                       const std::unordered_map<VarField, AddressSpace> &map) const
437
{
438
    const auto iter = map.find(x);
439
    if (iter == map.end())
440
    {
441
        return nullptr;
442
    }
443
    const AddressSpace space = iter->second;
444
    const auto index         = static_cast<std::underlying_type_t<AddressSpace>>(space);
445
    return &kAddressSpaces[index];
446
}
447
448
void SymbolEnv::markAsPointer(VarField x, AddressSpace space)
449
{
450
    return markSpace(x, space, mPointers);
451
}
452
453
void SymbolEnv::markAsReference(VarField x, AddressSpace space)
454
{
455
    return markSpace(x, space, mReferences);
456
}
457
458
const AddressSpace *SymbolEnv::isPointer(VarField x) const
459
{
460
    return isSpace(x, mPointers);
461
}
462
463
const AddressSpace *SymbolEnv::isReference(VarField x) const
464
{
465
    return isSpace(x, mReferences);
466
}
467
468
void SymbolEnv::markAsPacked(const TField &field)
469
{
470
    mPackedFields.insert(&field);
471
}
472
473
bool SymbolEnv::isPacked(const TField &field) const
474
{
475
    return mPackedFields.find(&field) != mPackedFields.end();
476
}
477
478
static TBasicType GetTextureBasicType(TBasicType basicType)
479
{
480
    ASSERT(IsSampler(basicType));
481
482
    switch (basicType)
483
    {
484
        case EbtSampler2D:
485
        case EbtSampler3D:
486
        case EbtSamplerCube:
487
        case EbtSampler2DArray:
488
        case EbtSamplerExternalOES:
489
        case EbtSamplerExternal2DY2YEXT:
490
        case EbtSampler2DRect:
491
        case EbtSampler2DMS:
492
        case EbtSampler2DMSArray:
493
        case EbtSamplerVideoWEBGL:
494
        case EbtSampler2DShadow:
495
        case EbtSamplerCubeShadow:
496
        case EbtSampler2DArrayShadow:
497
        case EbtSampler1D:
498
        case EbtSampler1DArray:
499
        case EbtSampler1DArrayShadow:
500
        case EbtSamplerBuffer:
501
        case EbtSamplerCubeArray:
502
        case EbtSamplerCubeArrayShadow:
503
        case EbtSampler1DShadow:
504
        case EbtSampler2DRectShadow:
505
            return TBasicType::EbtFloat;
506
507
        case EbtISampler2D:
508
        case EbtISampler3D:
509
        case EbtISamplerCube:
510
        case EbtISampler2DArray:
511
        case EbtISampler2DMS:
512
        case EbtISampler2DMSArray:
513
        case EbtISampler1D:
514
        case EbtISampler1DArray:
515
        case EbtISampler2DRect:
516
        case EbtISamplerBuffer:
517
        case EbtISamplerCubeArray:
518
            return TBasicType::EbtInt;
519
520
        case EbtUSampler2D:
521
        case EbtUSampler3D:
522
        case EbtUSamplerCube:
523
        case EbtUSampler2DArray:
524
        case EbtUSampler2DMS:
525
        case EbtUSampler2DMSArray:
526
        case EbtUSampler1D:
527
        case EbtUSampler1DArray:
528
        case EbtUSampler2DRect:
529
        case EbtUSamplerBuffer:
530
        case EbtUSamplerCubeArray:
531
            return TBasicType::EbtUInt;
532
533
        default:
534
            LOGIC_ERROR();
535
            return TBasicType::EbtVoid;
536
    }
537
}
538
539
Name sh::GetTextureTypeName(TBasicType samplerType)
540
{
541
    ASSERT(IsSampler(samplerType));
542
543
    const TBasicType textureType = GetTextureBasicType(samplerType);
544
    const char *name;
545
546
#define HANDLE_TEXTURE_NAME(baseName)                \
547
    do                                               \
548
    {                                                \
549
        switch (textureType)                         \
550
        {                                            \
551
            case TBasicType::EbtFloat:               \
552
                name = "metal::" baseName "<float>"; \
553
                break;                               \
554
            case TBasicType::EbtInt:                 \
555
                name = "metal::" baseName "<int>";   \
556
                break;                               \
557
            case TBasicType::EbtUInt:                \
558
                name = "metal::" baseName "<uint>";  \
559
                break;                               \
560
            default:                                 \
561
                LOGIC_ERROR();                       \
562
                name = nullptr;                      \
563
                break;                               \
564
        }                                            \
565
    } while (false)
566
567
    switch (samplerType)
568
    {
569
        // 1d
570
        case EbtSampler1D:  // Desktop GLSL sampler type:
571
        case EbtISampler1D:
572
        case EbtUSampler1D:
573
            HANDLE_TEXTURE_NAME("texture1d");
574
            break;
575
576
        // 1d array
577
        case EbtSampler1DArray:
578
        case EbtISampler1DArray:
579
        case EbtUSampler1DArray:
580
            HANDLE_TEXTURE_NAME("texture1d_array");
581
            break;
582
583
        // Buffer textures
584
        case EbtSamplerBuffer:
585
        case EbtISamplerBuffer:
586
        case EbtUSamplerBuffer:
587
            HANDLE_TEXTURE_NAME("texture_buffer");
588
            break;
589
590
        // 2d textures
591
        case EbtSampler2D:
592
        case EbtISampler2D:
593
        case EbtUSampler2D:
594
        case EbtSampler2DRect:
595
        case EbtUSampler2DRect:
596
        case EbtISampler2DRect:
597
            HANDLE_TEXTURE_NAME("texture2d");
598
            break;
599
600
        // 3d textures
601
        case EbtSampler3D:
602
        case EbtISampler3D:
603
        case EbtUSampler3D:
604
            HANDLE_TEXTURE_NAME("texture3d");
605
            break;
606
607
        // Cube textures
608
        case EbtSamplerCube:
609
        case EbtISamplerCube:
610
        case EbtUSamplerCube:
611
            HANDLE_TEXTURE_NAME("texturecube");
612
            break;
613
614
        // 2d array textures
615
        case EbtSampler2DArray:
616
        case EbtUSampler2DArray:
617
        case EbtISampler2DArray:
618
            HANDLE_TEXTURE_NAME("texture2d_array");
619
            break;
620
621
        case EbtSampler2DMS:
622
        case EbtISampler2DMS:
623
        case EbtUSampler2DMS:
624
            HANDLE_TEXTURE_NAME("texture2d_ms");
625
            break;
626
627
        case EbtSampler2DMSArray:
628
        case EbtISampler2DMSArray:
629
        case EbtUSampler2DMSArray:
630
            HANDLE_TEXTURE_NAME("texture2d_ms_array");
631
            break;
632
633
        // cube array
634
        case EbtSamplerCubeArray:
635
        case EbtISamplerCubeArray:
636
        case EbtUSamplerCubeArray:
637
            HANDLE_TEXTURE_NAME("texturecube_array");
638
            break;
639
640
        // Shadow
641
        case EbtSampler1DShadow:
642
        case EbtSampler1DArrayShadow:
643
            TODO();
644
            HANDLE_TEXTURE_NAME("TODO");
645
            break;
646
647
        case EbtSampler2DRectShadow:
648
        case EbtSampler2DShadow:
649
            HANDLE_TEXTURE_NAME("depth2d");
650
            break;
651
652
        case EbtSamplerCubeShadow:
653
            HANDLE_TEXTURE_NAME("depthcube");
654
            break;
655
656
        case EbtSampler2DArrayShadow:
657
            HANDLE_TEXTURE_NAME("depth2d_array");
658
            break;
659
660
        case EbtSamplerCubeArrayShadow:
661
            HANDLE_TEXTURE_NAME("depthcube_array");
662
            break;
663
664
        // Extentions
665
        case EbtSamplerExternalOES:       // Only valid if OES_EGL_image_external exists:
666
        case EbtSamplerExternal2DY2YEXT:  // Only valid if GL_EXT_YUV_target exists:
667
        case EbtSamplerVideoWEBGL:
668
            TODO();
669
            HANDLE_TEXTURE_NAME("TODO");
670
            break;
671
672
        default:
673
            LOGIC_ERROR();
674
            name = nullptr;
675
            break;
676
    }
677
678
#undef HANDLE_TEXTURE_NAME
679
680
    return Name(name, SymbolType::UserDefined);
681
}
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/SymbolEnv.h +218 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/SymbolEnv.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_SYMBOLENV_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_SYMBOLENV_H_
9
10
#include <unordered_set>
11
12
#include "compiler/translator/Compiler.h"
13
#include "compiler/translator/TranslatorMetalDirect/Name.h"
14
#include "compiler/translator/TranslatorMetalDirect/Reference.h"
15
#include "compiler/translator/Types.h"
16
17
namespace sh
18
{
19
20
enum class AddressSpace
21
{
22
    Constant,
23
    Device,
24
    Thread,
25
};
26
27
char const *toString(AddressSpace space);
28
29
class VarField
30
{
31
  public:
32
    VarField(const TVariable &var) : mVariable(&var) {}
33
    VarField(const TField &field) : mField(&field) {}
34
35
    ANGLE_INLINE const TVariable *variable() const { return mVariable; }
36
37
    ANGLE_INLINE const TField *field() const { return mField; }
38
39
    ANGLE_INLINE bool operator==(const VarField &other) const
40
    {
41
        return mVariable == other.mVariable && mField == other.mField;
42
    }
43
44
  private:
45
    const TVariable *mVariable = nullptr;
46
    const TField *mField       = nullptr;
47
};
48
49
}  // namespace sh
50
51
namespace std
52
{
53
54
template <>
55
struct hash<sh::VarField>
56
{
57
    size_t operator()(const sh::VarField &x) const
58
    {
59
        const sh::TVariable *var = x.variable();
60
        if (var)
61
        {
62
            return std::hash<const sh::TVariable *>()(var);
63
        }
64
        const sh::TField *field = x.field();
65
        return std::hash<const sh::TField *>()(field);
66
    }
67
};
68
69
}  // namespace std
70
71
namespace sh
72
{
73
74
class TemplateArg
75
{
76
  public:
77
    enum class Kind
78
    {
79
        Bool,
80
        Int,
81
        UInt,
82
        Type,
83
    };
84
85
    union Value
86
    {
87
        Value(bool value) : b(value) {}
88
        Value(int value) : i(value) {}
89
        Value(unsigned value) : u(value) {}
90
        Value(const TType &value) : t(&value) {}
91
92
        bool b;
93
        int i;
94
        unsigned u;
95
        const TType *t;
96
    };
97
98
    TemplateArg(bool value);
99
    TemplateArg(int value);
100
    TemplateArg(unsigned value);
101
    TemplateArg(const TType &value);
102
103
    bool operator==(const TemplateArg &other) const;
104
    bool operator<(const TemplateArg &other) const;
105
106
    Kind kind() const { return mKind; }
107
    Value value() const { return mValue; }
108
109
  public:
110
    Kind mKind;
111
    Value mValue;
112
};
113
114
// An environment for creating and uniquely sharing TSymbol objects.
115
class SymbolEnv
116
{
117
    class TemplateName
118
    {
119
        Name baseName;
120
        std::vector<TemplateArg> templateArgs;
121
122
      public:
123
        bool operator==(const TemplateName &other) const;
124
        bool operator<(const TemplateName &other) const;
125
126
        bool empty() const;
127
        void clear();
128
129
        Name fullName(std::string &buffer) const;
130
131
        void assign(const Name &name, size_t argCount, const TemplateArg *args);
132
    };
133
134
    using TypeRef        = CRef<TType>;
135
    using Sig            = std::vector<TypeRef>;  // Param0, Param1, ... ParamN, Return
136
    using SigToFunc      = std::map<Sig, TFunction *>;
137
    using Overloads      = std::map<TemplateName, SigToFunc>;
138
    using AngleStructs   = std::map<ImmutableString, TStructure *>;
139
    using TextureStructs = std::map<TBasicType, TStructure *>;
140
141
  public:
142
    SymbolEnv(TCompiler &compiler, TIntermBlock &root);
143
144
    TSymbolTable &symbolTable() { return mSymbolTable; }
145
146
    // There exist Angle rewrites that can lead to incoherent structs
147
    //
148
    // Example
149
    //    struct A { ... }
150
    //    struct B { A' a; } // A' has same name as A but is not identical.
151
    // becomes
152
    //    struct A { ... }
153
    //    struct B { A a; }
154
    //
155
    // This notably happens when A contains a sampler in the original GLSL code but is rewritten to
156
    // not have a sampler, yet the A' struct field still contains the sampler field.
157
    const TStructure &remap(const TStructure &s) const;
158
159
    // Like `TStructure &remap(const TStructure &s)` but additionally maps null to null.
160
    const TStructure *remap(const TStructure *s) const;
161
162
    const TFunction &getFunctionOverload(const Name &name,
163
                                         const TType &returnType,
164
                                         size_t paramCount,
165
                                         const TType **paramTypes,
166
                                         size_t templateArgCount         = 0,
167
                                         const TemplateArg *templateArgs = nullptr);
168
169
    TIntermAggregate &callFunctionOverload(const Name &name,
170
                                           const TType &returnType,
171
                                           TIntermSequence &args,
172
                                           size_t templateArgCount         = 0,
173
                                           const TemplateArg *templateArgs = nullptr);
174
175
    const TStructure &newStructure(const Name &name, TFieldList &fields);
176
177
    const TStructure &getTextureEnv(TBasicType samplerType);
178
    const TStructure &getSamplerStruct();
179
180
    void markAsPointer(VarField x, AddressSpace space);
181
    const AddressSpace *isPointer(VarField x) const;
182
183
    void markAsReference(VarField x, AddressSpace space);
184
    const AddressSpace *isReference(VarField x) const;
185
186
    void markAsPacked(const TField &field);
187
    bool isPacked(const TField &field) const;
188
189
  private:
190
    const TFunction &getFunctionOverloadImpl();
191
192
    void markSpace(VarField x, AddressSpace space, std::unordered_map<VarField, AddressSpace> &map);
193
    const AddressSpace *isSpace(VarField x,
194
                                const std::unordered_map<VarField, AddressSpace> &map) const;
195
196
  private:
197
    TSymbolTable &mSymbolTable;
198
199
    std::map<Name, const TStructure *> mNameToStruct;
200
    Overloads mOverloads;
201
    Sig mReusableSigBuffer;
202
    TemplateName mReusableTemplateNameBuffer;
203
    std::string mReusableStringBuffer;
204
205
    AngleStructs mAngleStructs;
206
    std::unordered_map<TBasicType, const TStructure *> mTextureEnvs;
207
    const TStructure *mSampler = nullptr;
208
209
    std::unordered_map<VarField, AddressSpace> mPointers;
210
    std::unordered_map<VarField, AddressSpace> mReferences;
211
    std::unordered_set<const TField *> mPackedFields;
212
};
213
214
Name GetTextureTypeName(TBasicType samplerType);
215
216
}  // namespace sh
217
218
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_SYMBOLENV_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/ToposortStructs.cpp +383 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/ToposortStructs.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include <functional>
8
#include <unordered_map>
9
#include <unordered_set>
10
#include <vector>
11
12
#include "compiler/translator/ImmutableStringBuilder.h"
13
#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
14
#include "compiler/translator/TranslatorMetalDirect/Debug.h"
15
#include "compiler/translator/TranslatorMetalDirect/ToposortStructs.h"
16
#include "compiler/translator/tree_util/IntermNode_util.h"
17
#include "compiler/translator/tree_util/IntermTraverse.h"
18
19
using namespace sh;
20
21
////////////////////////////////////////////////////////////////////////////////
22
23
namespace
24
{
25
26
template <typename T>
27
using Edges = std::unordered_set<T>;
28
29
template <typename T>
30
using Graph = std::unordered_map<T, Edges<T>>;
31
32
void BuildGraphImpl(SymbolEnv &symbolEnv, Graph<const TStructure *> &g, const TStructure *s)
33
{
34
    if (g.find(s) != g.end())
35
    {
36
        return;
37
    }
38
39
    Edges<const TStructure *> &es = g[s];
40
41
    const TFieldList &fs = s->fields();
42
    for (const TField *f : fs)
43
    {
44
        if (const TStructure *z = symbolEnv.remap(f->type()->getStruct()))
45
        {
46
            es.insert(z);
47
            BuildGraphImpl(symbolEnv, g, z);
48
            Edges<const TStructure *> &ez = g[z];
49
            es.insert(ez.begin(), ez.end());
50
        }
51
    }
52
}
53
54
Graph<const TStructure *> BuildGraph(SymbolEnv &symbolEnv,
55
                                     const std::vector<const TStructure *> &structs)
56
{
57
    Graph<const TStructure *> g;
58
    for (const TStructure *s : structs)
59
    {
60
        BuildGraphImpl(symbolEnv, g, s);
61
    }
62
    return g;
63
}
64
65
// Algorthm: https://en.wikipedia.org/wiki/Topological_sorting#Depth-first_search
66
template <typename T>
67
std::vector<T> Toposort(const Graph<T> &g)
68
{
69
    // nodes with temporary mark
70
    std::unordered_set<T> temps;
71
72
    // nodes without permanent mark
73
    std::unordered_set<T> invPerms;
74
    for (const auto &entry : g)
75
    {
76
        invPerms.insert(entry.first);
77
    }
78
79
    // L ← Empty list that will contain the sorted elements
80
    std::vector<T> L;
81
82
    // function visit(node n)
83
    std::function<void(T)> visit = [&](T n) -> void {
84
        // if n has a permanent mark then
85
        if (invPerms.find(n) == invPerms.end())
86
        {
87
            // return
88
            return;
89
        }
90
        // if n has a temporary mark then
91
        if (temps.find(n) != temps.end())
92
        {
93
            // stop   (not a DAG)
94
            LOGIC_ERROR();
95
        }
96
97
        // mark n with a temporary mark
98
        temps.insert(n);
99
100
        // for each node m with an edge from n to m do
101
        auto enIter = g.find(n);
102
        ASSERT(enIter != g.end());
103
        const Edges<T> &en = enIter->second;
104
        for (T m : en)
105
        {
106
            // visit(m)
107
            visit(m);
108
        }
109
110
        // remove temporary mark from n
111
        temps.erase(n);
112
        // mark n with a permanent mark
113
        invPerms.erase(n);
114
        // add n to head of L
115
        L.push_back(n);
116
    };
117
118
    // while exists nodes without a permanent mark do
119
    while (!invPerms.empty())
120
    {
121
        // select an unmarked node n
122
        T n = *invPerms.begin();
123
        // visit(n)
124
        visit(n);
125
    }
126
127
    return L;
128
}
129
130
TIntermFunctionDefinition *CreateStructEqualityFunction(TSymbolTable &symbolTable,
131
                                                        const TStructure &aStructType)
132
{
133
    ////////////////////
134
135
    auto &funcEquality =
136
        *new TFunction(&symbolTable, ImmutableString("equal"), SymbolType::AngleInternal,
137
                       new TType(TBasicType::EbtBool), true);
138
    auto &aStruct = CreateInstanceVariable(symbolTable, aStructType, Name("a"));
139
    auto &bStruct = CreateInstanceVariable(symbolTable, aStructType, Name("b"));
140
    funcEquality.addParameter(&aStruct);
141
    funcEquality.addParameter(&bStruct);
142
143
    auto &bodyEquality = *new TIntermBlock();
144
    std::vector<TIntermTyped *> andNodes;
145
    ////////////////////
146
147
    const TFieldList &aFields = aStructType.fields();
148
    const size_t size         = aFields.size();
149
150
    auto testEquality = [&](TIntermTyped &a, TIntermTyped &b) -> TIntermTyped * {
151
        ASSERT(a.getType() == b.getType());
152
        const TType &type = a.getType();
153
        if (type.isVector() || type.isMatrix() || type.getStruct())
154
        {
155
            auto *func =
156
                new TFunction(&symbolTable, ImmutableString("equal"), SymbolType::AngleInternal,
157
                              new TType(TBasicType::EbtBool), true);
158
            return TIntermAggregate::CreateFunctionCall(*func, new TIntermSequence{&a, &b});
159
        }
160
        else
161
        {
162
            return new TIntermBinary(TOperator::EOpEqual, &a, &b);
163
        }
164
    };
165
166
    for (size_t idx = 0; idx < size; ++idx)
167
    {
168
        const TField &aField    = *aFields[idx];
169
        const TType &aFieldType = *aField.type();
170
        auto &aFieldName        = aField.name();
171
172
        if (aFieldType.isArray())
173
        {
174
            ASSERT(!aFieldType.isArrayOfArrays());  // TODO
175
            int dim = aFieldType.getOutermostArraySize();
176
            for (int d = 0; d < dim; ++d)
177
            {
178
                auto &aAccess = AccessIndex(AccessField(aStruct, aFieldName), d);
179
                auto &bAccess = AccessIndex(AccessField(bStruct, aFieldName), d);
180
                auto *eqNode  = testEquality(bAccess, aAccess);
181
                andNodes.push_back(eqNode);
182
            }
183
        }
184
        else
185
        {
186
            auto &aAccess = AccessField(aStruct, aFieldName);
187
            auto &bAccess = AccessField(bStruct, aFieldName);
188
            auto *eqNode  = testEquality(bAccess, aAccess);
189
            andNodes.push_back(eqNode);
190
        }
191
    }
192
193
    ASSERT(andNodes.size() > 0);  // Empty structs are not allowed in GLSL
194
    TIntermTyped *outNode = andNodes.back();
195
    andNodes.pop_back();
196
    for (TIntermTyped *andNode : andNodes)
197
    {
198
        outNode = new TIntermBinary(TOperator::EOpLogicalAnd, andNode, outNode);
199
    }
200
    bodyEquality.appendStatement(new TIntermBranch(TOperator::EOpReturn, outNode));
201
    auto *funcProtoEquality = new TIntermFunctionPrototype(&funcEquality);
202
    return new TIntermFunctionDefinition(funcProtoEquality, &bodyEquality);
203
}
204
205
struct DeclaredStructure
206
{
207
    TIntermDeclaration *declNode;
208
    TIntermFunctionDefinition *equalityFunctionDefinition;
209
    const TStructure *structure;
210
};
211
212
bool GetAsDeclaredStructure(SymbolEnv &symbolEnv,
213
                            TIntermNode &node,
214
                            DeclaredStructure &out,
215
                            TSymbolTable &symbolTable,
216
                            const std::unordered_set<const TStructure *> &usedStructs)
217
{
218
    if (TIntermDeclaration *declNode = node.getAsDeclarationNode())
219
    {
220
        ASSERT(declNode->getChildCount() == 1);
221
        TIntermNode &node = *declNode->getChildNode(0);
222
223
        if (TIntermSymbol *symbolNode = node.getAsSymbolNode())
224
        {
225
            const TVariable &var = symbolNode->variable();
226
            const TType &type    = var.getType();
227
            if (const TStructure *structure = symbolEnv.remap(type.getStruct()))
228
            {
229
                if (type.isStructSpecifier())
230
                {
231
                    out.declNode  = declNode;
232
                    out.structure = structure;
233
                    out.equalityFunctionDefinition =
234
                        usedStructs.find(structure) == usedStructs.end()
235
                            ? nullptr
236
                            : CreateStructEqualityFunction(symbolTable, *structure);
237
                    return true;
238
                }
239
            }
240
        }
241
    }
242
    return false;
243
}
244
245
class FindStructEqualityUse : public TIntermTraverser
246
{
247
  public:
248
    SymbolEnv &mSymbolEnv;
249
    std::unordered_set<const TStructure *> mUsedStructs;
250
251
    FindStructEqualityUse(SymbolEnv &symbolEnv)
252
        : TIntermTraverser(false, false, true), mSymbolEnv(symbolEnv)
253
    {}
254
255
    bool visitBinary(Visit, TIntermBinary *binary) override
256
    {
257
        const TOperator op = binary->getOp();
258
259
        switch (op)
260
        {
261
            case TOperator::EOpEqual:
262
            case TOperator::EOpNotEqual:
263
            {
264
                const TType &leftType  = binary->getLeft()->getType();
265
                const TType &rightType = binary->getRight()->getType();
266
                ASSERT(leftType.getStruct() == rightType.getStruct());
267
                if (const TStructure *structure = mSymbolEnv.remap(leftType.getStruct()))
268
                {
269
                    useStruct(*structure);
270
                }
271
            }
272
            break;
273
274
            default:
275
                break;
276
        }
277
278
        return true;
279
    }
280
281
  private:
282
    void useStruct(const TStructure &structure)
283
    {
284
        if (mUsedStructs.insert(&structure).second)
285
        {
286
            for (const TField *field : structure.fields())
287
            {
288
                if (const TStructure *subStruct = mSymbolEnv.remap(field->type()->getStruct()))
289
                {
290
                    useStruct(*subStruct);
291
                }
292
            }
293
        }
294
    }
295
};
296
297
}  // anonymous namespace
298
299
////////////////////////////////////////////////////////////////////////////////
300
301
bool sh::ToposortStructs(TCompiler &compiler,
302
                         SymbolEnv &symbolEnv,
303
                         TIntermBlock &root,
304
                         ProgramPreludeConfig &ppc)
305
{
306
    FindStructEqualityUse finder(symbolEnv);
307
    root.traverse(&finder);
308
    ppc.hasStructEq = !finder.mUsedStructs.empty();
309
310
    DeclaredStructure declaredStruct;
311
    std::vector<DeclaredStructure> declaredStructs;
312
    std::vector<TIntermNode *> nonStructStmtNodes;
313
314
    {
315
        const size_t stmtCount = root.getChildCount();
316
        for (size_t i = 0; i < stmtCount; ++i)
317
        {
318
            TIntermNode &stmtNode = *root.getChildNode(i);
319
            if (GetAsDeclaredStructure(symbolEnv, stmtNode, declaredStruct,
320
                                       compiler.getSymbolTable(), finder.mUsedStructs))
321
            {
322
                declaredStructs.push_back(declaredStruct);
323
            }
324
            else
325
            {
326
                nonStructStmtNodes.push_back(&stmtNode);
327
            }
328
        }
329
    }
330
331
    {
332
        std::vector<const TStructure *> structs;
333
        std::unordered_map<const TStructure *, DeclaredStructure> rawToDeclared;
334
335
        for (const DeclaredStructure &d : declaredStructs)
336
        {
337
            structs.push_back(d.structure);
338
            ASSERT(rawToDeclared.find(d.structure) == rawToDeclared.end());
339
            rawToDeclared[d.structure] = d;
340
        }
341
342
        // Note: Graph may contain more than only explicitly declared structures.
343
        Graph<const TStructure *> g                   = BuildGraph(symbolEnv, structs);
344
        std::vector<const TStructure *> sortedStructs = Toposort(g);
345
        ASSERT(declaredStructs.size() <= sortedStructs.size());
346
347
        declaredStructs.clear();
348
        for (const TStructure *s : sortedStructs)
349
        {
350
            auto it = rawToDeclared.find(s);
351
            if (it != rawToDeclared.end())
352
            {
353
                auto &d = it->second;
354
                ASSERT(d.declNode);
355
                declaredStructs.push_back(d);
356
            }
357
        }
358
    }
359
360
    {
361
        TIntermSequence newStmtNodes;
362
363
        for (DeclaredStructure &declaredStruct : declaredStructs)
364
        {
365
            ASSERT(declaredStruct.declNode);
366
            newStmtNodes.push_back(declaredStruct.declNode);
367
            if (declaredStruct.equalityFunctionDefinition)
368
            {
369
                newStmtNodes.push_back(declaredStruct.equalityFunctionDefinition);
370
            }
371
        }
372
373
        for (TIntermNode *stmtNode : nonStructStmtNodes)
374
        {
375
            ASSERT(stmtNode);
376
            newStmtNodes.push_back(stmtNode);
377
        }
378
379
        *root.getSequence() = newStmtNodes;
380
    }
381
382
    return compiler.validateAST(&root);
383
}
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/ToposortStructs.h +27 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/ToposortStructs.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_TOPOSORTSTRUCTS_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_TOPOSORTSTRUCTS_H_
9
10
#include "common/angleutils.h"
11
#include "compiler/translator/Compiler.h"
12
#include "compiler/translator/TranslatorMetalDirect/ProgramPrelude.h"
13
#include "compiler/translator/TranslatorMetalDirect/SymbolEnv.h"
14
15
namespace sh
16
{
17
18
// Does a toposort on structs based on type dependencies.
19
// Struct type declarations are moved to the top of the root block.
20
ANGLE_NO_DISCARD bool ToposortStructs(TCompiler &compiler,
21
                                      SymbolEnv &symbolEnv,
22
                                      TIntermBlock &root,
23
                                      ProgramPreludeConfig &ppc);
24
25
}  // namespace sh
26
27
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_TOPOSORTSTRUCTS_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/WrapMain.cpp +94 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/WrapMain.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include "compiler/translator/TranslatorMetalDirect/WrapMain.h"
8
#include "compiler/translator/Compiler.h"
9
#include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
10
11
using namespace sh;
12
13
////////////////////////////////////////////////////////////////////////////////
14
15
namespace
16
{
17
18
class Wrapper : public TIntermTraverser
19
{
20
  private:
21
    IdGen &mIdGen;
22
23
  public:
24
    Wrapper(TSymbolTable &symbolTable, IdGen &idGen)
25
        : TIntermTraverser(false, false, true, &symbolTable), mIdGen(idGen)
26
    {}
27
28
    bool visitBlock(Visit, TIntermBlock *blockNode) override
29
    {
30
        if (blockNode != getRootNode())
31
        {
32
            return true;
33
        }
34
35
        for (TIntermNode *node : *blockNode->getSequence())
36
        {
37
            if (TIntermFunctionDefinition *funcDefNode = node->getAsFunctionDefinition())
38
            {
39
                const TFunction &func = *funcDefNode->getFunction();
40
                if (func.isMain())
41
                {
42
                    visitMain(*blockNode, funcDefNode);
43
                    break;
44
                }
45
            }
46
        }
47
48
        return true;
49
    }
50
51
  private:
52
    void visitMain(TIntermBlock &root, TIntermFunctionDefinition *funcDefNode)
53
    {
54
        const TFunction &func = *funcDefNode->getFunction();
55
        ASSERT(func.isMain());
56
        ASSERT(func.getReturnType().getBasicType() == TBasicType::EbtVoid);
57
        ASSERT(func.getParamCount() == 0);
58
59
        const TFunction &externalMainFunc = *funcDefNode->getFunction();
60
        const TFunction &internalMainFunc = CloneFunction(*mSymbolTable, mIdGen, externalMainFunc);
61
62
        TIntermFunctionPrototype *externalMainProto = funcDefNode->getFunctionPrototype();
63
        TIntermFunctionPrototype *internalMainProto =
64
            new TIntermFunctionPrototype(&internalMainFunc);
65
66
        TIntermBlock *externalMainBody = new TIntermBlock();
67
        externalMainBody->appendStatement(
68
            TIntermAggregate::CreateFunctionCall(internalMainFunc, new TIntermSequence()));
69
70
        TIntermBlock *internalMainBody = funcDefNode->getBody();
71
72
        TIntermFunctionDefinition *externalMainDef =
73
            new TIntermFunctionDefinition(externalMainProto, externalMainBody);
74
        TIntermFunctionDefinition *internalMainDef =
75
            new TIntermFunctionDefinition(internalMainProto, internalMainBody);
76
77
        mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(
78
            &root, funcDefNode, TIntermSequence{internalMainDef, externalMainDef}));
79
    }
80
};
81
82
}  // namespace
83
84
bool sh::WrapMain(TCompiler &compiler, IdGen &idGen, TIntermBlock &root)
85
{
86
    TSymbolTable &symbolTable = compiler.getSymbolTable();
87
    Wrapper wrapper(symbolTable, idGen);
88
    root.traverse(&wrapper);
89
    if (!wrapper.updateTree(&compiler, &root))
90
    {
91
        return false;
92
    }
93
    return true;
94
}
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/WrapMain.h +28 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalDirect/WrapMain.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_WRAPMAIN_H_
8
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_WRAPMAIN_H_
9
10
#include "compiler/translator/TranslatorMetalDirect/IdGen.h"
11
#include "compiler/translator/tree_util/IntermTraverse.h"
12
13
namespace sh
14
{
15
16
// Changes
17
//    void main(args) { main-body }
18
// To
19
//    void FRESH_NAME(args) { main-body }
20
//    void main(args) { FRESH_NAME(args); }
21
//
22
// This transformation is useful if the original `main` has multiple return paths because this
23
// reduces down to a single path in the new `main`. Nice for inserting cleanup code in `main`.
24
ANGLE_NO_DISCARD bool WrapMain(TCompiler &compiler, IdGen &idGen, TIntermBlock &root);
25
26
}  // namespace sh
27
28
#endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_WRAPMAIN_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalUtils.cpp +305 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalUtils.cpp_sec1
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
7
#if defined(_MSC_VER)
8
#    pragma warning(disable : 4718)
9
#endif
10
#include "compiler/translator/TranslatorMetalUtils.h"
11
#include <algorithm>
12
#include <climits>
13
#include "compiler/translator/HashNames.h"
14
#include "compiler/translator/ImmutableString.h"
15
#include "compiler/translator/InfoSink.h"
16
#include "compiler/translator/IntermNode.h"
17
#include "compiler/translator/SymbolTable.h"
18
#include "compiler/translator/Types.h"
19
20
namespace sh
21
{
22
23
const char *getBasicMetalString(const TType *t)
24
{
25
    switch (t->getBasicType())
26
    {
27
        case EbtVoid:
28
            return "void";
29
        case EbtFloat:
30
            return "float";
31
        case EbtInt:
32
            return "int";
33
        case EbtUInt:
34
            return "uint";
35
        case EbtBool:
36
            return "bool";
37
        case EbtYuvCscStandardEXT:
38
            return "yuvCscStandardEXT";
39
        case EbtSampler2D:
40
            return "sampler2D";
41
        case EbtSampler3D:
42
            return "sampler3D";
43
        case EbtSamplerCube:
44
            return "samplerCube";
45
        case EbtSamplerExternalOES:
46
            return "samplerExternalOES";
47
        case EbtSamplerExternal2DY2YEXT:
48
            return "__samplerExternal2DY2YEXT";
49
        case EbtSampler2DRect:
50
            return "sampler2DRect";
51
        case EbtSampler2DArray:
52
            return "sampler2DArray";
53
        case EbtSampler2DMS:
54
            return "sampler2DMS";
55
        case EbtSampler2DMSArray:
56
            return "sampler2DMSArray";
57
        case EbtSamplerCubeArray:
58
            return "samplerCubeArray";
59
        case EbtISampler2D:
60
            return "isampler2D";
61
        case EbtISampler3D:
62
            return "isampler3D";
63
        case EbtISamplerCube:
64
            return "isamplerCube";
65
        case EbtISampler2DArray:
66
            return "isampler2DArray";
67
        case EbtISampler2DMS:
68
            return "isampler2DMS";
69
        case EbtISampler2DMSArray:
70
            return "isampler2DMSArray";
71
        case EbtISamplerCubeArray:
72
            return "isamplerCubeArray";
73
        case EbtUSampler2D:
74
            return "usampler2D";
75
        case EbtUSampler3D:
76
            return "usampler3D";
77
        case EbtUSamplerCube:
78
            return "usamplerCube";
79
        case EbtUSampler2DArray:
80
            return "usampler2DArray";
81
        case EbtUSampler2DMS:
82
            return "usampler2DMS";
83
        case EbtUSampler2DMSArray:
84
            return "usampler2DMSArray";
85
        case EbtUSamplerCubeArray:
86
            return "usamplerCubeArray";
87
        case EbtSampler2DShadow:
88
            return "sampler2DShadow";
89
        case EbtSamplerCubeShadow:
90
            return "samplerCubeShadow";
91
        case EbtSampler2DArrayShadow:
92
            return "sampler2DArrayShadow";
93
        case EbtSamplerCubeArrayShadow:
94
            return "samplerCubeArrayShadow";
95
        case EbtStruct:
96
            return "structure";
97
        case EbtInterfaceBlock:
98
            return "interface block";
99
        case EbtImage2D:
100
            return "texture2d";
101
        case EbtIImage2D:
102
            return "texture2d<int>";
103
        case EbtUImage2D:
104
            return "texture2d<uint>";
105
        case EbtImage3D:
106
            return "texture3d";
107
        case EbtIImage3D:
108
            return "texture3d<int>";
109
        case EbtUImage3D:
110
            return "texture3d<uint>";
111
        case EbtImage2DArray:
112
            if (t->isUnsizedArray())
113
            {
114
                return "array_ref<texture2d>";
115
            }
116
            else
117
            {
118
                return "NOT_IMPLEMENTED";
119
            }
120
        case EbtIImage2DArray:
121
            if (t->isUnsizedArray())
122
            {
123
                return "array_ref<texture2d<int>>";
124
            }
125
            else
126
            {
127
                return "NOT_IMPLEMENTED";
128
            }
129
        case EbtUImage2DArray:
130
            if (t->isUnsizedArray())
131
            {
132
                return "array_ref<texture2d<uint>>";
133
            }
134
            else
135
            {
136
                return "NOT_IMPLEMENTED";
137
            }
138
        case EbtImageCube:
139
            return "texturecube";
140
        case EbtIImageCube:
141
            return "texturecube<int>";
142
        case EbtUImageCube:
143
            return "texturecube<uint>";
144
        case EbtImageCubeArray:
145
            if (t->isUnsizedArray())
146
            {
147
                return "array_ref<texturecube>";
148
            }
149
            else
150
            {
151
                return "NOT_IMPLEMENTED";
152
            }
153
        case EbtIImageCubeArray:
154
            if (t->isUnsizedArray())
155
            {
156
                return "array_ref<texturecube<int>>";
157
            }
158
            else
159
            {
160
                return "NOT_IMPLEMENTED";
161
            }
162
        case EbtUImageCubeArray:
163
            if (t->isUnsizedArray())
164
            {
165
                return "array_ref<texturecube<uint>>";
166
            }
167
            else
168
            {
169
                return "NOT_IMPLEMENTED";
170
            }
171
        case EbtAtomicCounter:
172
            return "atomic_uint";
173
        case EbtSamplerVideoWEBGL:
174
            return "$samplerVideoWEBGL";
175
        default:
176
            UNREACHABLE();
177
            return "unknown type";
178
    }
179
}
180
181
const char *getBuiltInMetalTypeNameString(const TType *t)
182
{
183
    if (t->isMatrix())
184
    {
185
        switch (t->getCols())
186
        {
187
            case 2:
188
                switch (t->getRows())
189
                {
190
                    case 2:
191
                        return "float2";
192
                    case 3:
193
                        return "float2x3";
194
                    case 4:
195
                        return "float2x4";
196
                    default:
197
                        UNREACHABLE();
198
                        return nullptr;
199
                }
200
            case 3:
201
                switch (t->getRows())
202
                {
203
                    case 2:
204
                        return "float3x2";
205
                    case 3:
206
                        return "float3";
207
                    case 4:
208
                        return "float3x4";
209
                    default:
210
                        UNREACHABLE();
211
                        return nullptr;
212
                }
213
            case 4:
214
                switch (t->getRows())
215
                {
216
                    case 2:
217
                        return "float4x2";
218
                    case 3:
219
                        return "float4x3";
220
                    case 4:
221
                        return "float4";
222
                    default:
223
                        UNREACHABLE();
224
                        return nullptr;
225
                }
226
            default:
227
                UNREACHABLE();
228
                return nullptr;
229
        }
230
    }
231
    if (t->isVector())
232
    {
233
        switch (t->getBasicType())
234
        {
235
            case EbtFloat:
236
                switch (t->getNominalSize())
237
                {
238
                    case 2:
239
                        return "float2";
240
                    case 3:
241
                        return "float3";
242
                    case 4:
243
                        return "float4";
244
                    default:
245
                        UNREACHABLE();
246
                        return nullptr;
247
                }
248
            case EbtInt:
249
                switch (t->getNominalSize())
250
                {
251
                    case 2:
252
                        return "int2";
253
                    case 3:
254
                        return "int3";
255
                    case 4:
256
                        return "int4";
257
                    default:
258
                        UNREACHABLE();
259
                        return nullptr;
260
                }
261
            case EbtBool:
262
                switch (t->getNominalSize())
263
                {
264
                    case 2:
265
                        return "bool2";
266
                    case 3:
267
                        return "bool3";
268
                    case 4:
269
                        return "bool4";
270
                    default:
271
                        UNREACHABLE();
272
                        return nullptr;
273
                }
274
            case EbtUInt:
275
                switch (t->getNominalSize())
276
                {
277
                    case 2:
278
                        return "uint2";
279
                    case 3:
280
                        return "uint3";
281
                    case 4:
282
                        return "uint4";
283
                    default:
284
                        UNREACHABLE();
285
                        return nullptr;
286
                }
287
            default:
288
                UNREACHABLE();
289
                return nullptr;
290
        }
291
    }
292
    ASSERT(t->getBasicType() != EbtStruct);
293
    ASSERT(t->getBasicType() != EbtInterfaceBlock);
294
    return getBasicMetalString(t);
295
}
296
297
ImmutableString GetMetalTypeName(const TType &type, ShHashFunction64 hashFunction, NameMap *nameMap)
298
{
299
    if (type.getBasicType() == EbtStruct)
300
        return HashName(type.getStruct(), hashFunction, nameMap);
301
    else
302
        return ImmutableString(getBuiltInMetalTypeNameString(&type));
303
}
304
305
}  // namespace sh
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalUtils.h +31 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorMetalUtils.h_sec1
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
7
#ifndef TRANSLATOR_METAL_UTILS_H_
8
#define TRANSLATOR_METAL_UTILS_H_
9
10
#include "common/angleutils.h"
11
#include "common/debug.h"
12
#include "compiler/translator/BaseTypes.h"
13
#include "compiler/translator/Common.h"
14
#include "compiler/translator/HashNames.h"
15
#include "compiler/translator/ImmutableString.h"
16
#include "compiler/translator/SymbolUniqueId.h"
17
#include "compiler/translator/Types.h"
18
namespace sh
19
{
20
21
const char *getBasicMetalString(const TType *t);
22
23
const char *getBuiltInMetalTypeNameString(const TType *t);
24
25
ImmutableString GetMetalTypeName(const TType &type,
26
                                 ShHashFunction64 hashFunction,
27
                                 NameMap *nameMap);
28
29
}  // namespace sh
30
31
#endif  // TRANSLATOR_METAL_UTILS_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorVulkan.cpp -3 / +5 lines
Lines 163-168 class DeclareDefaultUniformsTraverser : public TIntermTraverser a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorVulkan.cpp_sec1
163
constexpr ImmutableString kFlippedPointCoordName    = ImmutableString("flippedPointCoord");
163
constexpr ImmutableString kFlippedPointCoordName    = ImmutableString("flippedPointCoord");
164
constexpr ImmutableString kFlippedFragCoordName     = ImmutableString("flippedFragCoord");
164
constexpr ImmutableString kFlippedFragCoordName     = ImmutableString("flippedFragCoord");
165
constexpr ImmutableString kEmulatedDepthRangeParams = ImmutableString("ANGLEDepthRangeParams");
165
constexpr ImmutableString kEmulatedDepthRangeParams = ImmutableString("ANGLEDepthRangeParams");
166
constexpr ImmutableString kUniformsBlockName        = ImmutableString("ANGLEUniformBlock");
167
constexpr ImmutableString kUniformsVarName          = ImmutableString("ANGLEUniforms");
166
168
167
constexpr gl::ShaderMap<const char *> kDefaultUniformNames = {
169
constexpr gl::ShaderMap<const char *> kDefaultUniformNames = {
168
    {gl::ShaderType::Vertex, vk::kDefaultUniformsNameVS},
170
    {gl::ShaderType::Vertex, vk::kDefaultUniformsNameVS},
Lines 450-458 const TVariable *AddGraphicsDriverUniformsToShader(TIntermBlock *root, a/Source/ThirdParty/ANGLE/src/compiler/translator/TranslatorVulkan.cpp_sec2
450
                            additionalFields.end());
452
                            additionalFields.end());
451
453
452
    // Define a driver uniform block "ANGLEUniformBlock" with instance name "ANGLEUniforms".
454
    // Define a driver uniform block "ANGLEUniformBlock" with instance name "ANGLEUniforms".
453
    return DeclareInterfaceBlock(
455
    return DeclareInterfaceBlock(root, symbolTable, driverFieldList, EvqUniform,
454
        root, symbolTable, driverFieldList, EvqUniform, TMemoryQualifier::Create(), 0,
456
                                 TMemoryQualifier::Create(), 0, kUniformsBlockName,
455
        ImmutableString(vk::kDriverUniformsBlockName), ImmutableString(vk::kDriverUniformsVarName));
457
                                 kUniformsVarName);
456
}
458
}
457
459
458
const TVariable *AddComputeDriverUniformsToShader(TIntermBlock *root, TSymbolTable *symbolTable)
460
const TVariable *AddComputeDriverUniformsToShader(TIntermBlock *root, TSymbolTable *symbolTable)
- a/Source/ThirdParty/ANGLE/src/compiler/translator/Types.h +1 lines
Lines 232-237 class TType a/Source/ThirdParty/ANGLE/src/compiler/translator/Types.h_sec1
232
232
233
    bool isVector() const { return primarySize > 1 && secondarySize == 1; }
233
    bool isVector() const { return primarySize > 1 && secondarySize == 1; }
234
    bool isVectorArray() const { return primarySize > 1 && secondarySize == 1 && isArray(); }
234
    bool isVectorArray() const { return primarySize > 1 && secondarySize == 1 && isArray(); }
235
    bool isRank0() const { return primarySize == 1 && secondarySize == 1; }
235
    bool isScalar() const
236
    bool isScalar() const
236
    {
237
    {
237
        return primarySize == 1 && secondarySize == 1 && !mStructure && !isArray();
238
        return primarySize == 1 && secondarySize == 1 && !mStructure && !isArray();
- a/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateAST.cpp -12 / +8 lines
Lines 76-87 ValidateAST::ValidateAST(TIntermNode *root, a/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateAST.cpp_sec1
76
                         TDiagnostics *diagnostics,
76
                         TDiagnostics *diagnostics,
77
                         const ValidateASTOptions &options)
77
                         const ValidateASTOptions &options)
78
    : TIntermTraverser(true, false, true, nullptr), mOptions(options), mDiagnostics(diagnostics)
78
    : TIntermTraverser(true, false, true, nullptr), mOptions(options), mDiagnostics(diagnostics)
79
{
79
{}
80
    if (mOptions.validateSingleParent)
81
    {
82
        mParent[root] = nullptr;
83
    }
84
}
85
80
86
void ValidateAST::visitNode(Visit visit, TIntermNode *node)
81
void ValidateAST::visitNode(Visit visit, TIntermNode *node)
87
{
82
{
Lines 90-101 void ValidateAST::visitNode(Visit visit, TIntermNode *node) a/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateAST.cpp_sec2
90
        size_t childCount = node->getChildCount();
85
        size_t childCount = node->getChildCount();
91
        for (size_t i = 0; i < childCount; ++i)
86
        for (size_t i = 0; i < childCount; ++i)
92
        {
87
        {
93
            TIntermNode *child = node->getChildNode(i);
88
            TIntermNode *child   = node->getChildNode(i);
94
            if (mParent.find(child) != mParent.end())
89
            TIntermNode *&parent = mParent[child];
90
            if (parent)
95
            {
91
            {
96
                // If child is visited twice but through the same parent, the problem is in one of
92
                // If child is visited twice but through the same parent, the problem is in one of
97
                // the ancestors.
93
                // the ancestors.
98
                if (mParent[child] != node)
94
                if (parent != node)
99
                {
95
                {
100
                    mDiagnostics->error(node->getLine(), "Found child with two parents",
96
                    mDiagnostics->error(node->getLine(), "Found child with two parents",
101
                                        "<validateSingleParent>");
97
                                        "<validateSingleParent>");
Lines 103-119 void ValidateAST::visitNode(Visit visit, TIntermNode *node) a/Source/ThirdParty/ANGLE/src/compiler/translator/ValidateAST.cpp_sec3
103
                }
99
                }
104
            }
100
            }
105
101
106
            mParent[child] = node;
102
            parent = node;
107
        }
103
        }
108
    }
104
    }
109
}
105
}
110
106
111
void ValidateAST::expectNonNullChildren(Visit visit, TIntermNode *node, size_t least_count)
107
void ValidateAST::expectNonNullChildren(Visit visit, TIntermNode *node, size_t leastCount)
112
{
108
{
113
    if (visit == PreVisit && mOptions.validateNullNodes)
109
    if (visit == PreVisit && mOptions.validateNullNodes)
114
    {
110
    {
115
        size_t childCount = node->getChildCount();
111
        size_t childCount = node->getChildCount();
116
        if (childCount < least_count)
112
        if (childCount < leastCount)
117
        {
113
        {
118
            mDiagnostics->error(node->getLine(), "Too few children", "<validateNullNodes>");
114
            mDiagnostics->error(node->getLine(), "Too few children", "<validateNullNodes>");
119
            mNullNodesFailed = true;
115
            mNullNodesFailed = true;
- a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp -1 / +2 lines
Lines 53-59 void GetDeferredInitializers(TIntermDeclaration *declaration, a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp_sec1
53
        ASSERT(symbolNode);
53
        ASSERT(symbolNode);
54
        TIntermTyped *expression = init->getRight();
54
        TIntermTyped *expression = init->getRight();
55
55
56
        if (expression->getQualifier() != EvqConst || !expression->hasConstantValue())
56
        if (expression->getQualifier() != EvqConst || !expression->hasConstantValue() ||
57
            symbolNode->getQualifier() == EvqGlobal)
57
        {
58
        {
58
            // For variables which are not constant, defer their real initialization until
59
            // For variables which are not constant, defer their real initialization until
59
            // after we initialize uniforms.
60
            // after we initialize uniforms.
- a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_ops/PruneEmptyCases.cpp -2 / +2 lines
Lines 17-23 namespace sh a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_ops/PruneEmptyCases.cpp_sec1
17
namespace
17
namespace
18
{
18
{
19
19
20
bool AreEmptyBlocks(TIntermSequence *statements);
20
bool AreEmptyBlocks(const TIntermSequence *statements);
21
21
22
bool IsEmptyBlock(TIntermNode *node)
22
bool IsEmptyBlock(TIntermNode *node)
23
{
23
{
Lines 37-43 bool IsEmptyBlock(TIntermNode *node) a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_ops/PruneEmptyCases.cpp_sec2
37
37
38
// Return true if all statements in "statements" consist only of empty blocks and no-op statements.
38
// Return true if all statements in "statements" consist only of empty blocks and no-op statements.
39
// Returns true also if there are no statements.
39
// Returns true also if there are no statements.
40
bool AreEmptyBlocks(TIntermSequence *statements)
40
bool AreEmptyBlocks(const TIntermSequence *statements)
41
{
41
{
42
    for (size_t i = 0u; i < statements->size(); ++i)
42
    for (size_t i = 0u; i < statements->size(); ++i)
43
    {
43
    {
- a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_ops/RemoveSwitchFallThrough.cpp -3 / +5 lines
Lines 44-50 class RemoveSwitchFallThroughTraverser : public TIntermTraverser a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_ops/RemoveSwitchFallThrough.cpp_sec1
44
    bool visitLoop(Visit, TIntermLoop *node) override;
44
    bool visitLoop(Visit, TIntermLoop *node) override;
45
    bool visitBranch(Visit, TIntermBranch *node) override;
45
    bool visitBranch(Visit, TIntermBranch *node) override;
46
46
47
    void outputSequence(TIntermSequence *sequence, size_t startIndex);
47
    void outputSequence(const TIntermSequence *sequence, size_t startIndex);
48
    void handlePreviousCase();
48
    void handlePreviousCase();
49
49
50
    TIntermBlock *mStatementList;
50
    TIntermBlock *mStatementList;
Lines 153-163 bool RemoveSwitchFallThroughTraverser::visitSwitch(Visit, TIntermSwitch *node) a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_ops/RemoveSwitchFallThrough.cpp_sec2
153
    return false;
153
    return false;
154
}
154
}
155
155
156
void RemoveSwitchFallThroughTraverser::outputSequence(TIntermSequence *sequence, size_t startIndex)
156
void RemoveSwitchFallThroughTraverser::outputSequence(const TIntermSequence *sequence,
157
                                                      size_t startIndex)
157
{
158
{
159
    auto &outSeq = *mStatementListOut->getSequence();
158
    for (size_t i = startIndex; i < sequence->size(); ++i)
160
    for (size_t i = startIndex; i < sequence->size(); ++i)
159
    {
161
    {
160
        mStatementListOut->getSequence()->push_back(sequence->at(i));
162
        outSeq.push_back(sequence->at(i));
161
    }
163
    }
162
}
164
}
163
165
- a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_ops/SimplifyLoopConditions.cpp -101 / +292 lines
Lines 21-30 namespace sh a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_ops/SimplifyLoopConditions.cpp_sec1
21
namespace
21
namespace
22
{
22
{
23
23
24
struct LoopInfo
25
{
26
    const TVariable *conditionVariable = nullptr;
27
    TIntermTyped *condition            = nullptr;
28
    TIntermTyped *expression           = nullptr;
29
};
30
24
class SimplifyLoopConditionsTraverser : public TLValueTrackingTraverser
31
class SimplifyLoopConditionsTraverser : public TLValueTrackingTraverser
25
{
32
{
26
  public:
33
  public:
27
    SimplifyLoopConditionsTraverser(unsigned int conditionsToSimplifyMask,
34
    SimplifyLoopConditionsTraverser(const IntermNodePatternMatcher *conditionsToSimplify,
28
                                    TSymbolTable *symbolTable);
35
                                    TSymbolTable *symbolTable);
29
36
30
    void traverseLoop(TIntermLoop *node) override;
37
    void traverseLoop(TIntermLoop *node) override;
Lines 34-39 class SimplifyLoopConditionsTraverser : public TLValueTrackingTraverser a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_ops/SimplifyLoopConditions.cpp_sec2
34
    bool visitAggregate(Visit visit, TIntermAggregate *node) override;
41
    bool visitAggregate(Visit visit, TIntermAggregate *node) override;
35
    bool visitTernary(Visit visit, TIntermTernary *node) override;
42
    bool visitTernary(Visit visit, TIntermTernary *node) override;
36
    bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
43
    bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
44
    bool visitBranch(Visit visit, TIntermBranch *node) override;
37
45
38
    bool foundLoopToChange() const { return mFoundLoopToChange; }
46
    bool foundLoopToChange() const { return mFoundLoopToChange; }
39
47
Lines 42-57 class SimplifyLoopConditionsTraverser : public TLValueTrackingTraverser a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_ops/SimplifyLoopConditions.cpp_sec3
42
    // found.
50
    // found.
43
    bool mFoundLoopToChange;
51
    bool mFoundLoopToChange;
44
    bool mInsideLoopInitConditionOrExpression;
52
    bool mInsideLoopInitConditionOrExpression;
45
    IntermNodePatternMatcher mConditionsToSimplify;
53
    const IntermNodePatternMatcher *mConditionsToSimplify;
54
55
  private:
56
    LoopInfo mLoop;
46
};
57
};
47
58
48
SimplifyLoopConditionsTraverser::SimplifyLoopConditionsTraverser(
59
SimplifyLoopConditionsTraverser::SimplifyLoopConditionsTraverser(
49
    unsigned int conditionsToSimplifyMask,
60
    const IntermNodePatternMatcher *conditionsToSimplify,
50
    TSymbolTable *symbolTable)
61
    TSymbolTable *symbolTable)
51
    : TLValueTrackingTraverser(true, false, false, symbolTable),
62
    : TLValueTrackingTraverser(true, false, false, symbolTable),
52
      mFoundLoopToChange(false),
63
      mFoundLoopToChange(false),
53
      mInsideLoopInitConditionOrExpression(false),
64
      mInsideLoopInitConditionOrExpression(false),
54
      mConditionsToSimplify(conditionsToSimplifyMask)
65
      mConditionsToSimplify(conditionsToSimplify)
55
{}
66
{}
56
67
57
// If we're inside a loop initialization, condition, or expression, we check for expressions that
68
// If we're inside a loop initialization, condition, or expression, we check for expressions that
Lines 68-74 bool SimplifyLoopConditionsTraverser::visitUnary(Visit visit, TIntermUnary *node a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_ops/SimplifyLoopConditions.cpp_sec4
68
    if (mFoundLoopToChange)
79
    if (mFoundLoopToChange)
69
        return false;  // Already decided to change this loop.
80
        return false;  // Already decided to change this loop.
70
81
71
    mFoundLoopToChange = mConditionsToSimplify.match(node);
82
    ASSERT(mConditionsToSimplify);
83
    mFoundLoopToChange = mConditionsToSimplify->match(node);
72
    return !mFoundLoopToChange;
84
    return !mFoundLoopToChange;
73
}
85
}
74
86
Lines 80-86 bool SimplifyLoopConditionsTraverser::visitBinary(Visit visit, TIntermBinary *no a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_ops/SimplifyLoopConditions.cpp_sec5
80
    if (mFoundLoopToChange)
92
    if (mFoundLoopToChange)
81
        return false;  // Already decided to change this loop.
93
        return false;  // Already decided to change this loop.
82
94
83
    mFoundLoopToChange = mConditionsToSimplify.match(node, getParentNode(), isLValueRequiredHere());
95
    ASSERT(mConditionsToSimplify);
96
    mFoundLoopToChange =
97
        mConditionsToSimplify->match(node, getParentNode(), isLValueRequiredHere());
84
    return !mFoundLoopToChange;
98
    return !mFoundLoopToChange;
85
}
99
}
86
100
Lines 92-98 bool SimplifyLoopConditionsTraverser::visitAggregate(Visit visit, TIntermAggrega a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_ops/SimplifyLoopConditions.cpp_sec6
92
    if (mFoundLoopToChange)
106
    if (mFoundLoopToChange)
93
        return false;  // Already decided to change this loop.
107
        return false;  // Already decided to change this loop.
94
108
95
    mFoundLoopToChange = mConditionsToSimplify.match(node, getParentNode());
109
    ASSERT(mConditionsToSimplify);
110
    mFoundLoopToChange = mConditionsToSimplify->match(node, getParentNode());
96
    return !mFoundLoopToChange;
111
    return !mFoundLoopToChange;
97
}
112
}
98
113
Lines 104-110 bool SimplifyLoopConditionsTraverser::visitTernary(Visit visit, TIntermTernary * a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_ops/SimplifyLoopConditions.cpp_sec7
104
    if (mFoundLoopToChange)
119
    if (mFoundLoopToChange)
105
        return false;  // Already decided to change this loop.
120
        return false;  // Already decided to change this loop.
106
121
107
    mFoundLoopToChange = mConditionsToSimplify.match(node);
122
    ASSERT(mConditionsToSimplify);
123
    mFoundLoopToChange = mConditionsToSimplify->match(node);
108
    return !mFoundLoopToChange;
124
    return !mFoundLoopToChange;
109
}
125
}
110
126
Lines 116-125 bool SimplifyLoopConditionsTraverser::visitDeclaration(Visit visit, TIntermDecla a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_ops/SimplifyLoopConditions.cpp_sec8
116
    if (mFoundLoopToChange)
132
    if (mFoundLoopToChange)
117
        return false;  // Already decided to change this loop.
133
        return false;  // Already decided to change this loop.
118
134
119
    mFoundLoopToChange = mConditionsToSimplify.match(node);
135
    ASSERT(mConditionsToSimplify);
136
    mFoundLoopToChange = mConditionsToSimplify->match(node);
120
    return !mFoundLoopToChange;
137
    return !mFoundLoopToChange;
121
}
138
}
122
139
140
bool SimplifyLoopConditionsTraverser::visitBranch(Visit visit, TIntermBranch *node)
141
{
142
    if (node->getFlowOp() == EOpContinue && (mLoop.condition || mLoop.expression))
143
    {
144
        TIntermBlock *parent = getParentNode()->getAsBlock();
145
        ASSERT(parent);
146
        TIntermSequence seq;
147
        if (mLoop.expression)
148
        {
149
            seq.push_back(mLoop.expression->deepCopy());
150
        }
151
        if (mLoop.condition)
152
        {
153
            ASSERT(mLoop.conditionVariable);
154
            seq.push_back(
155
                CreateTempAssignmentNode(mLoop.conditionVariable, mLoop.condition->deepCopy()));
156
        }
157
        seq.push_back(node);
158
        mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(parent, node, std::move(seq)));
159
    }
160
161
    return true;
162
}
163
123
void SimplifyLoopConditionsTraverser::traverseLoop(TIntermLoop *node)
164
void SimplifyLoopConditionsTraverser::traverseLoop(TIntermLoop *node)
124
{
165
{
125
    // Mark that we're inside a loop condition or expression, and determine if the loop needs to be
166
    // Mark that we're inside a loop condition or expression, and determine if the loop needs to be
Lines 128-134 void SimplifyLoopConditionsTraverser::traverseLoop(TIntermLoop *node) a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_ops/SimplifyLoopConditions.cpp_sec9
128
    ScopedNodeInTraversalPath addToPath(this, node);
169
    ScopedNodeInTraversalPath addToPath(this, node);
129
170
130
    mInsideLoopInitConditionOrExpression = true;
171
    mInsideLoopInitConditionOrExpression = true;
131
    mFoundLoopToChange                   = false;
172
    mFoundLoopToChange                   = !mConditionsToSimplify;
132
173
133
    if (!mFoundLoopToChange && node->getInit())
174
    if (!mFoundLoopToChange && node->getInit())
134
    {
175
    {
Lines 147-229 void SimplifyLoopConditionsTraverser::traverseLoop(TIntermLoop *node) a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_ops/SimplifyLoopConditions.cpp_sec10
147
188
148
    mInsideLoopInitConditionOrExpression = false;
189
    mInsideLoopInitConditionOrExpression = false;
149
190
191
    const LoopInfo prevLoop = mLoop;
192
150
    if (mFoundLoopToChange)
193
    if (mFoundLoopToChange)
151
    {
194
    {
152
        const TType *boolType        = StaticType::Get<EbtBool, EbpUndefined, EvqTemporary, 1, 1>();
195
        const TType *boolType   = StaticType::Get<EbtBool, EbpUndefined, EvqTemporary, 1, 1>();
153
        TVariable *conditionVariable = CreateTempVariable(mSymbolTable, boolType);
196
        mLoop.conditionVariable = CreateTempVariable(mSymbolTable, boolType);
197
        mLoop.condition         = node->getCondition();
198
        mLoop.expression        = node->getExpression();
154
199
155
        // Replace the loop condition with a boolean variable that's updated on each iteration.
200
        // Replace the loop condition with a boolean variable that's updated on each iteration.
156
        TLoopType loopType = node->getType();
201
        TLoopType loopType = node->getType();
157
        if (loopType == ELoopWhile)
202
        if (loopType == ELoopWhile)
158
        {
203
        {
159
            // Transform:
204
            ASSERT(!mLoop.expression);
160
            //   while (expr) { body; }
205
161
            // into
206
            if (mLoop.condition->getAsSymbolNode())
162
            //   bool s0 = expr;
163
            //   while (s0) { { body; } s0 = expr; }
164
            TIntermDeclaration *tempInitDeclaration =
165
                CreateTempInitDeclarationNode(conditionVariable, node->getCondition()->deepCopy());
166
            insertStatementInParentBlock(tempInitDeclaration);
167
168
            TIntermBlock *newBody = new TIntermBlock();
169
            if (node->getBody())
170
            {
207
            {
171
                newBody->getSequence()->push_back(node->getBody());
208
                // Mask continue statement condition variable update.
209
                mLoop.condition = nullptr;
210
            }
211
            else if (mLoop.condition->getAsConstantUnion())
212
            {
213
                // Transform:
214
                //   while (expr) { body; }
215
                // into
216
                //   bool s0 = expr;
217
                //   while (s0) { body; }
218
                TIntermDeclaration *tempInitDeclaration =
219
                    CreateTempInitDeclarationNode(mLoop.conditionVariable, mLoop.condition);
220
                insertStatementInParentBlock(tempInitDeclaration);
221
222
                node->setCondition(CreateTempSymbolNode(mLoop.conditionVariable));
223
224
                // Mask continue statement condition variable update.
225
                mLoop.condition = nullptr;
226
            }
227
            else
228
            {
229
                // Transform:
230
                //   while (expr) { body; }
231
                // into
232
                //   bool s0 = expr;
233
                //   while (s0) { { body; } s0 = expr; }
234
                //
235
                // Local case statements are transformed into:
236
                //   s0 = expr; continue;
237
                TIntermDeclaration *tempInitDeclaration =
238
                    CreateTempInitDeclarationNode(mLoop.conditionVariable, mLoop.condition);
239
                insertStatementInParentBlock(tempInitDeclaration);
240
241
                TIntermBlock *newBody = new TIntermBlock();
242
                if (node->getBody())
243
                {
244
                    newBody->getSequence()->push_back(node->getBody());
245
                }
246
                newBody->getSequence()->push_back(
247
                    CreateTempAssignmentNode(mLoop.conditionVariable, mLoop.condition->deepCopy()));
248
249
                // Can't use queueReplacement to replace old body, since it may have been nullptr.
250
                // It's safe to do the replacements in place here - the new body will still be
251
                // traversed, but that won't create any problems.
252
                node->setBody(newBody);
253
                node->setCondition(CreateTempSymbolNode(mLoop.conditionVariable));
172
            }
254
            }
173
            newBody->getSequence()->push_back(
174
                CreateTempAssignmentNode(conditionVariable, node->getCondition()->deepCopy()));
175
176
            // Can't use queueReplacement to replace old body, since it may have been nullptr.
177
            // It's safe to do the replacements in place here - the new body will still be
178
            // traversed, but that won't create any problems.
179
            node->setBody(newBody);
180
            node->setCondition(CreateTempSymbolNode(conditionVariable));
181
        }
255
        }
182
        else if (loopType == ELoopDoWhile)
256
        else if (loopType == ELoopDoWhile)
183
        {
257
        {
184
            // Transform:
258
            ASSERT(!mLoop.expression);
185
            //   do {
259
186
            //     body;
260
            if (mLoop.condition->getAsSymbolNode())
187
            //   } while (expr);
188
            // into
189
            //   bool s0 = true;
190
            //   do {
191
            //     { body; }
192
            //     s0 = expr;
193
            //   } while (s0);
194
            TIntermDeclaration *tempInitDeclaration =
195
                CreateTempInitDeclarationNode(conditionVariable, CreateBoolNode(true));
196
            insertStatementInParentBlock(tempInitDeclaration);
197
198
            TIntermBlock *newBody = new TIntermBlock();
199
            if (node->getBody())
200
            {
261
            {
201
                newBody->getSequence()->push_back(node->getBody());
262
                // Mask continue statement condition variable update.
263
                mLoop.condition = nullptr;
264
            }
265
            else if (mLoop.condition->getAsConstantUnion())
266
            {
267
                // Transform:
268
                //   do {
269
                //     body;
270
                //   } while (expr);
271
                // into
272
                //   bool s0 = expr;
273
                //   do {
274
                //     body;
275
                //   } while (s0);
276
                TIntermDeclaration *tempInitDeclaration =
277
                    CreateTempInitDeclarationNode(mLoop.conditionVariable, mLoop.condition);
278
                insertStatementInParentBlock(tempInitDeclaration);
279
280
                node->setCondition(CreateTempSymbolNode(mLoop.conditionVariable));
281
282
                // Mask continue statement condition variable update.
283
                mLoop.condition = nullptr;
284
            }
285
            else
286
            {
287
                // Transform:
288
                //   do {
289
                //     body;
290
                //   } while (expr);
291
                // into
292
                //   bool s0;
293
                //   do {
294
                //     { body; }
295
                //     s0 = expr;
296
                //   } while (s0);
297
                // Local case statements are transformed into:
298
                //   s0 = expr; continue;
299
                TIntermDeclaration *tempInitDeclaration =
300
                    CreateTempDeclarationNode(mLoop.conditionVariable);
301
                insertStatementInParentBlock(tempInitDeclaration);
302
303
                TIntermBlock *newBody = new TIntermBlock();
304
                if (node->getBody())
305
                {
306
                    newBody->getSequence()->push_back(node->getBody());
307
                }
308
                newBody->getSequence()->push_back(
309
                    CreateTempAssignmentNode(mLoop.conditionVariable, mLoop.condition));
310
311
                // Can't use queueReplacement to replace old body, since it may have been nullptr.
312
                // It's safe to do the replacements in place here - the new body will still be
313
                // traversed, but that won't create any problems.
314
                node->setBody(newBody);
315
                node->setCondition(CreateTempSymbolNode(mLoop.conditionVariable));
202
            }
316
            }
203
            newBody->getSequence()->push_back(
204
                CreateTempAssignmentNode(conditionVariable, node->getCondition()->deepCopy()));
205
206
            // Can't use queueReplacement to replace old body, since it may have been nullptr.
207
            // It's safe to do the replacements in place here - the new body will still be
208
            // traversed, but that won't create any problems.
209
            node->setBody(newBody);
210
            node->setCondition(CreateTempSymbolNode(conditionVariable));
211
        }
317
        }
212
        else if (loopType == ELoopFor)
318
        else if (loopType == ELoopFor)
213
        {
319
        {
214
            // Move the loop condition inside the loop.
320
            if (!mLoop.condition)
215
            // Transform:
321
            {
216
            //   for (init; expr; exprB) { body; }
322
                mLoop.condition = CreateBoolNode(true);
217
            // into
323
            }
218
            //   {
324
219
            //     init;
325
            TIntermLoop *whileLoop;
220
            //     bool s0 = expr;
221
            //     while (s0) {
222
            //       { body; }
223
            //       exprB;
224
            //       s0 = expr;
225
            //     }
226
            //   }
227
            TIntermBlock *loopScope            = new TIntermBlock();
326
            TIntermBlock *loopScope            = new TIntermBlock();
228
            TIntermSequence *loopScopeSequence = loopScope->getSequence();
327
            TIntermSequence *loopScopeSequence = loopScope->getSequence();
229
328
Lines 233-280 void SimplifyLoopConditionsTraverser::traverseLoop(TIntermLoop *node) a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_ops/SimplifyLoopConditions.cpp_sec11
233
                loopScopeSequence->push_back(node->getInit());
332
                loopScopeSequence->push_back(node->getInit());
234
            }
333
            }
235
334
236
            // Insert "bool s0 = expr;" if applicable, "bool s0 = true;" otherwise
335
            if (mLoop.condition->getAsSymbolNode())
237
            TIntermTyped *conditionInitializer = nullptr;
238
            if (node->getCondition())
239
            {
336
            {
240
                conditionInitializer = node->getCondition()->deepCopy();
337
                // Move the loop condition inside the loop.
338
                // Transform:
339
                //   for (init; expr; exprB) { body; }
340
                // into
341
                //   {
342
                //     init;
343
                //     while (expr) {
344
                //       { body; }
345
                //       exprB;
346
                //     }
347
                //   }
348
                //
349
                // Local case statements are transformed into:
350
                //   exprB; continue;
351
352
                // Insert "{ body; }" in the while loop
353
                TIntermBlock *whileLoopBody = new TIntermBlock();
354
                if (node->getBody())
355
                {
356
                    whileLoopBody->getSequence()->push_back(node->getBody());
357
                }
358
                // Insert "exprB;" in the while loop
359
                if (node->getExpression())
360
                {
361
                    whileLoopBody->getSequence()->push_back(node->getExpression());
362
                }
363
                // Create "while(expr) { whileLoopBody }"
364
                whileLoop =
365
                    new TIntermLoop(ELoopWhile, nullptr, mLoop.condition, nullptr, whileLoopBody);
366
367
                // Mask continue statement condition variable update.
368
                mLoop.condition = nullptr;
241
            }
369
            }
242
            else
370
            else if (mLoop.condition->getAsConstantUnion())
243
            {
371
            {
244
                conditionInitializer = CreateBoolNode(true);
372
                // Move the loop condition inside the loop.
373
                // Transform:
374
                //   for (init; expr; exprB) { body; }
375
                // into
376
                //   {
377
                //     init;
378
                //     bool s0 = expr;
379
                //     while (s0) {
380
                //       { body; }
381
                //       exprB;
382
                //     }
383
                //   }
384
                //
385
                // Local case statements are transformed into:
386
                //   exprB; continue;
387
388
                // Insert "bool s0 = expr;"
389
                loopScopeSequence->push_back(
390
                    CreateTempInitDeclarationNode(mLoop.conditionVariable, mLoop.condition));
391
                // Insert "{ body; }" in the while loop
392
                TIntermBlock *whileLoopBody = new TIntermBlock();
393
                if (node->getBody())
394
                {
395
                    whileLoopBody->getSequence()->push_back(node->getBody());
396
                }
397
                // Insert "exprB;" in the while loop
398
                if (node->getExpression())
399
                {
400
                    whileLoopBody->getSequence()->push_back(node->getExpression());
401
                }
402
                // Create "while(s0) { whileLoopBody }"
403
                whileLoop = new TIntermLoop(ELoopWhile, nullptr,
404
                                            CreateTempSymbolNode(mLoop.conditionVariable), nullptr,
405
                                            whileLoopBody);
406
407
                // Mask continue statement condition variable update.
408
                mLoop.condition = nullptr;
245
            }
409
            }
246
            loopScopeSequence->push_back(
410
            else
247
                CreateTempInitDeclarationNode(conditionVariable, conditionInitializer));
248
249
            // Insert "{ body; }" in the while loop
250
            TIntermBlock *whileLoopBody = new TIntermBlock();
251
            if (node->getBody())
252
            {
253
                whileLoopBody->getSequence()->push_back(node->getBody());
254
            }
255
            // Insert "exprB;" in the while loop
256
            if (node->getExpression())
257
            {
258
                whileLoopBody->getSequence()->push_back(node->getExpression());
259
            }
260
            // Insert "s0 = expr;" in the while loop
261
            if (node->getCondition())
262
            {
411
            {
412
                // Move the loop condition inside the loop.
413
                // Transform:
414
                //   for (init; expr; exprB) { body; }
415
                // into
416
                //   {
417
                //     init;
418
                //     bool s0 = expr;
419
                //     while (s0) {
420
                //       { body; }
421
                //       exprB;
422
                //       s0 = expr;
423
                //     }
424
                //   }
425
                //
426
                // Local case statements are transformed into:
427
                //   exprB; s0 = expr; continue;
428
429
                // Insert "bool s0 = expr;"
430
                loopScopeSequence->push_back(
431
                    CreateTempInitDeclarationNode(mLoop.conditionVariable, mLoop.condition));
432
                // Insert "{ body; }" in the while loop
433
                TIntermBlock *whileLoopBody = new TIntermBlock();
434
                if (node->getBody())
435
                {
436
                    whileLoopBody->getSequence()->push_back(node->getBody());
437
                }
438
                // Insert "exprB;" in the while loop
439
                if (node->getExpression())
440
                {
441
                    whileLoopBody->getSequence()->push_back(node->getExpression());
442
                }
443
                // Insert "s0 = expr;" in the while loop
263
                whileLoopBody->getSequence()->push_back(
444
                whileLoopBody->getSequence()->push_back(
264
                    CreateTempAssignmentNode(conditionVariable, node->getCondition()->deepCopy()));
445
                    CreateTempAssignmentNode(mLoop.conditionVariable, mLoop.condition->deepCopy()));
446
                // Create "while(s0) { whileLoopBody }"
447
                whileLoop = new TIntermLoop(ELoopWhile, nullptr,
448
                                            CreateTempSymbolNode(mLoop.conditionVariable), nullptr,
449
                                            whileLoopBody);
265
            }
450
            }
266
451
267
            // Create "while(s0) { whileLoopBody }"
268
            TIntermLoop *whileLoop =
269
                new TIntermLoop(ELoopWhile, nullptr, CreateTempSymbolNode(conditionVariable),
270
                                nullptr, whileLoopBody);
271
            loopScope->getSequence()->push_back(whileLoop);
452
            loopScope->getSequence()->push_back(whileLoop);
272
            queueReplacement(loopScope, OriginalNode::IS_DROPPED);
453
            queueReplacement(loopScope, OriginalNode::IS_DROPPED);
273
454
274
            // After this the old body node will be traversed and loops inside it may be
455
            // After this the old body node will be traversed and loops inside it may be
275
            // transformed. This is fine, since the old body node will still be in the AST after the
456
            // transformed. This is fine, since the old body node will still be in the AST after
276
            // transformation that's queued here, and transforming loops inside it doesn't need to
457
            // the transformation that's queued here, and transforming loops inside it doesn't
277
            // know the exact post-transform path to it.
458
            // need to know the exact post-transform path to it.
278
        }
459
        }
279
    }
460
    }
280
461
Lines 283-298 void SimplifyLoopConditionsTraverser::traverseLoop(TIntermLoop *node) a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_ops/SimplifyLoopConditions.cpp_sec12
283
    // We traverse the body of the loop even if the loop is transformed.
464
    // We traverse the body of the loop even if the loop is transformed.
284
    if (node->getBody())
465
    if (node->getBody())
285
        node->getBody()->traverse(this);
466
        node->getBody()->traverse(this);
467
468
    mLoop = prevLoop;
286
}
469
}
287
470
288
}  // namespace
471
}  // namespace
289
472
473
bool SimplifyLoopConditions(TCompiler *compiler, TIntermNode *root, TSymbolTable *symbolTable)
474
{
475
    SimplifyLoopConditionsTraverser traverser(nullptr, symbolTable);
476
    root->traverse(&traverser);
477
    return traverser.updateTree(compiler, root);
478
}
479
290
bool SimplifyLoopConditions(TCompiler *compiler,
480
bool SimplifyLoopConditions(TCompiler *compiler,
291
                            TIntermNode *root,
481
                            TIntermNode *root,
292
                            unsigned int conditionsToSimplifyMask,
482
                            unsigned int conditionsToSimplifyMask,
293
                            TSymbolTable *symbolTable)
483
                            TSymbolTable *symbolTable)
294
{
484
{
295
    SimplifyLoopConditionsTraverser traverser(conditionsToSimplifyMask, symbolTable);
485
    IntermNodePatternMatcher conditionsToSimplify(conditionsToSimplifyMask);
486
    SimplifyLoopConditionsTraverser traverser(&conditionsToSimplify, symbolTable);
296
    root->traverse(&traverser);
487
    root->traverse(&traverser);
297
    return traverser.updateTree(compiler, root);
488
    return traverser.updateTree(compiler, root);
298
}
489
}
- a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_ops/SimplifyLoopConditions.h +4 lines
Lines 19-24 class TCompiler; a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_ops/SimplifyLoopConditions.h_sec1
19
class TIntermNode;
19
class TIntermNode;
20
class TSymbolTable;
20
class TSymbolTable;
21
21
22
ANGLE_NO_DISCARD bool SimplifyLoopConditions(TCompiler *compiler,
23
                                             TIntermNode *root,
24
                                             TSymbolTable *symbolTable);
25
22
ANGLE_NO_DISCARD bool SimplifyLoopConditions(TCompiler *compiler,
26
ANGLE_NO_DISCARD bool SimplifyLoopConditions(TCompiler *compiler,
23
                                             TIntermNode *root,
27
                                             TIntermNode *root,
24
                                             unsigned int conditionsToSimplify,
28
                                             unsigned int conditionsToSimplify,
- a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_util/AsNode.h +212 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_util/AsNode.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TREEUTIL_INTERMASNODE_H_
8
#define COMPILER_TRANSLATOR_TREEUTIL_INTERMASNODE_H_
9
10
#include "common/angleutils.h"
11
#include "compiler/translator/IntermNode.h"
12
13
#include <utility>
14
15
namespace sh
16
{
17
18
namespace priv
19
{
20
21
template <typename T>
22
struct AsNode
23
{};
24
25
template <>
26
struct AsNode<TIntermNode>
27
{
28
    static ANGLE_INLINE TIntermNode *exec(TIntermNode *node) { return node; }
29
};
30
31
template <>
32
struct AsNode<TIntermTyped>
33
{
34
    static ANGLE_INLINE TIntermTyped *exec(TIntermNode *node)
35
    {
36
        return node ? node->getAsTyped() : nullptr;
37
    }
38
};
39
40
template <>
41
struct AsNode<TIntermSymbol>
42
{
43
    static ANGLE_INLINE TIntermSymbol *exec(TIntermNode *node)
44
    {
45
        return node ? node->getAsSymbolNode() : nullptr;
46
    }
47
};
48
49
template <>
50
struct AsNode<TIntermConstantUnion>
51
{
52
    static ANGLE_INLINE TIntermConstantUnion *exec(TIntermNode *node)
53
    {
54
        return node ? node->getAsConstantUnion() : nullptr;
55
    }
56
};
57
58
template <>
59
struct AsNode<TIntermFunctionPrototype>
60
{
61
    static ANGLE_INLINE TIntermFunctionPrototype *exec(TIntermNode *node)
62
    {
63
        return node ? node->getAsFunctionPrototypeNode() : nullptr;
64
    }
65
};
66
67
template <>
68
struct AsNode<TIntermPreprocessorDirective>
69
{
70
    static ANGLE_INLINE TIntermPreprocessorDirective *exec(TIntermNode *node)
71
    {
72
        return node ? node->getAsPreprocessorDirective() : nullptr;
73
    }
74
};
75
76
template <>
77
struct AsNode<TIntermSwizzle>
78
{
79
    static ANGLE_INLINE TIntermSwizzle *exec(TIntermNode *node)
80
    {
81
        return node ? node->getAsSwizzleNode() : nullptr;
82
    }
83
};
84
85
template <>
86
struct AsNode<TIntermBinary>
87
{
88
    static ANGLE_INLINE TIntermBinary *exec(TIntermNode *node)
89
    {
90
        return node ? node->getAsBinaryNode() : nullptr;
91
    }
92
};
93
94
template <>
95
struct AsNode<TIntermUnary>
96
{
97
    static ANGLE_INLINE TIntermUnary *exec(TIntermNode *node)
98
    {
99
        return node ? node->getAsUnaryNode() : nullptr;
100
    }
101
};
102
103
template <>
104
struct AsNode<TIntermTernary>
105
{
106
    static ANGLE_INLINE TIntermTernary *exec(TIntermNode *node)
107
    {
108
        return node ? node->getAsTernaryNode() : nullptr;
109
    }
110
};
111
112
template <>
113
struct AsNode<TIntermIfElse>
114
{
115
    static ANGLE_INLINE TIntermIfElse *exec(TIntermNode *node)
116
    {
117
        return node ? node->getAsIfElseNode() : nullptr;
118
    }
119
};
120
121
template <>
122
struct AsNode<TIntermSwitch>
123
{
124
    static ANGLE_INLINE TIntermSwitch *exec(TIntermNode *node)
125
    {
126
        return node ? node->getAsSwitchNode() : nullptr;
127
    }
128
};
129
130
template <>
131
struct AsNode<TIntermCase>
132
{
133
    static ANGLE_INLINE TIntermCase *exec(TIntermNode *node)
134
    {
135
        return node ? node->getAsCaseNode() : nullptr;
136
    }
137
};
138
139
template <>
140
struct AsNode<TIntermFunctionDefinition>
141
{
142
    static ANGLE_INLINE TIntermFunctionDefinition *exec(TIntermNode *node)
143
    {
144
        return node ? node->getAsFunctionDefinition() : nullptr;
145
    }
146
};
147
148
template <>
149
struct AsNode<TIntermAggregate>
150
{
151
    static ANGLE_INLINE TIntermAggregate *exec(TIntermNode *node)
152
    {
153
        return node ? node->getAsAggregate() : nullptr;
154
    }
155
};
156
157
template <>
158
struct AsNode<TIntermBlock>
159
{
160
    static ANGLE_INLINE TIntermBlock *exec(TIntermNode *node)
161
    {
162
        return node ? node->getAsBlock() : nullptr;
163
    }
164
};
165
166
template <>
167
struct AsNode<TIntermGlobalQualifierDeclaration>
168
{
169
    static ANGLE_INLINE TIntermGlobalQualifierDeclaration *exec(TIntermNode *node)
170
    {
171
        return node ? node->getAsGlobalQualifierDeclarationNode() : nullptr;
172
    }
173
};
174
175
template <>
176
struct AsNode<TIntermDeclaration>
177
{
178
    static ANGLE_INLINE TIntermDeclaration *exec(TIntermNode *node)
179
    {
180
        return node ? node->getAsDeclarationNode() : nullptr;
181
    }
182
};
183
184
template <>
185
struct AsNode<TIntermLoop>
186
{
187
    static ANGLE_INLINE TIntermLoop *exec(TIntermNode *node)
188
    {
189
        return node ? node->getAsLoopNode() : nullptr;
190
    }
191
};
192
193
template <>
194
struct AsNode<TIntermBranch>
195
{
196
    static ANGLE_INLINE TIntermBranch *exec(TIntermNode *node)
197
    {
198
        return node ? node->getAsBranchNode() : nullptr;
199
    }
200
};
201
202
}  // namespace priv
203
204
template <typename T>
205
ANGLE_INLINE T *asNode(TIntermNode *node)
206
{
207
    return priv::AsNode<T>::exec(node);
208
}
209
210
}  // namespace sh
211
212
#endif  // COMPILER_TRANSLATOR_TREEUTIL_INTERMASNODE_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp -7 / +7 lines
Lines 65-71 bool IntermNodePatternMatcher::IsDynamicIndexingOfSwizzledVector(TIntermBinary * a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp_sec1
65
    return IsDynamicIndexingOfVectorOrMatrix(node) && node->getLeft()->getAsSwizzleNode();
65
    return IsDynamicIndexingOfVectorOrMatrix(node) && node->getLeft()->getAsSwizzleNode();
66
}
66
}
67
67
68
bool IntermNodePatternMatcher::matchInternal(TIntermBinary *node, TIntermNode *parentNode)
68
bool IntermNodePatternMatcher::matchInternal(TIntermBinary *node, TIntermNode *parentNode) const
69
{
69
{
70
    if ((mMask & kExpressionReturningArray) != 0)
70
    if ((mMask & kExpressionReturningArray) != 0)
71
    {
71
    {
Lines 87-93 bool IntermNodePatternMatcher::matchInternal(TIntermBinary *node, TIntermNode *p a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp_sec2
87
    return false;
87
    return false;
88
}
88
}
89
89
90
bool IntermNodePatternMatcher::match(TIntermUnary *node)
90
bool IntermNodePatternMatcher::match(TIntermUnary *node) const
91
{
91
{
92
    if ((mMask & kArrayLengthMethod) != 0)
92
    if ((mMask & kArrayLengthMethod) != 0)
93
    {
93
    {
Lines 99-105 bool IntermNodePatternMatcher::match(TIntermUnary *node) a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp_sec3
99
    return false;
99
    return false;
100
}
100
}
101
101
102
bool IntermNodePatternMatcher::match(TIntermBinary *node, TIntermNode *parentNode)
102
bool IntermNodePatternMatcher::match(TIntermBinary *node, TIntermNode *parentNode) const
103
{
103
{
104
    // L-value tracking information is needed to check for dynamic indexing in L-value.
104
    // L-value tracking information is needed to check for dynamic indexing in L-value.
105
    // Traversers that don't track l-values can still use this class and match binary nodes with
105
    // Traversers that don't track l-values can still use this class and match binary nodes with
Lines 110-116 bool IntermNodePatternMatcher::match(TIntermBinary *node, TIntermNode *parentNod a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp_sec4
110
110
111
bool IntermNodePatternMatcher::match(TIntermBinary *node,
111
bool IntermNodePatternMatcher::match(TIntermBinary *node,
112
                                     TIntermNode *parentNode,
112
                                     TIntermNode *parentNode,
113
                                     bool isLValueRequiredHere)
113
                                     bool isLValueRequiredHere) const
114
{
114
{
115
    if (matchInternal(node, parentNode))
115
    if (matchInternal(node, parentNode))
116
    {
116
    {
Lines 126-132 bool IntermNodePatternMatcher::match(TIntermBinary *node, a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp_sec5
126
    return false;
126
    return false;
127
}
127
}
128
128
129
bool IntermNodePatternMatcher::match(TIntermAggregate *node, TIntermNode *parentNode)
129
bool IntermNodePatternMatcher::match(TIntermAggregate *node, TIntermNode *parentNode) const
130
{
130
{
131
    if ((mMask & kExpressionReturningArray) != 0)
131
    if ((mMask & kExpressionReturningArray) != 0)
132
    {
132
    {
Lines 161-167 bool IntermNodePatternMatcher::match(TIntermAggregate *node, TIntermNode *parent a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp_sec6
161
    return false;
161
    return false;
162
}
162
}
163
163
164
bool IntermNodePatternMatcher::match(TIntermTernary *node)
164
bool IntermNodePatternMatcher::match(TIntermTernary *node) const
165
{
165
{
166
    if ((mMask & kUnfoldedShortCircuitExpression) != 0)
166
    if ((mMask & kUnfoldedShortCircuitExpression) != 0)
167
    {
167
    {
Lines 170-176 bool IntermNodePatternMatcher::match(TIntermTernary *node) a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp_sec7
170
    return false;
170
    return false;
171
}
171
}
172
172
173
bool IntermNodePatternMatcher::match(TIntermDeclaration *node)
173
bool IntermNodePatternMatcher::match(TIntermDeclaration *node) const
174
{
174
{
175
    if ((mMask & kMultiDeclaration) != 0)
175
    if ((mMask & kMultiDeclaration) != 0)
176
    {
176
    {
- a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_util/IntermNodePatternMatcher.h -16 / +16 lines
Lines 28-79 class IntermNodePatternMatcher a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_util/IntermNodePatternMatcher.h_sec1
28
    static bool IsDynamicIndexingOfVectorOrMatrix(TIntermBinary *node);
28
    static bool IsDynamicIndexingOfVectorOrMatrix(TIntermBinary *node);
29
    static bool IsDynamicIndexingOfSwizzledVector(TIntermBinary *node);
29
    static bool IsDynamicIndexingOfSwizzledVector(TIntermBinary *node);
30
30
31
    enum PatternType
31
    enum PatternType : unsigned int
32
    {
32
    {
33
        // Matches expressions that are unfolded to if statements by UnfoldShortCircuitToIf
33
        // Matches expressions that are unfolded to if statements by UnfoldShortCircuitToIf
34
        kUnfoldedShortCircuitExpression = 0x0001,
34
        kUnfoldedShortCircuitExpression = 1u << 0u,
35
35
36
        // Matches expressions that return arrays with the exception of simple statements where a
36
        // Matches expressions that return arrays with the exception of simple statements where a
37
        // constructor or function call result is assigned.
37
        // constructor or function call result is assigned.
38
        kExpressionReturningArray = 0x0001 << 1,
38
        kExpressionReturningArray = 1u << 1u,
39
39
40
        // Matches dynamic indexing of vectors or matrices in l-values.
40
        // Matches dynamic indexing of vectors or matrices in l-values.
41
        kDynamicIndexingOfVectorOrMatrixInLValue = 0x0001 << 2,
41
        kDynamicIndexingOfVectorOrMatrixInLValue = 1u << 2u,
42
42
43
        // Matches declarations with more than one declared variables.
43
        // Matches declarations with more than one declared variables.
44
        kMultiDeclaration = 0x0001 << 3,
44
        kMultiDeclaration = 1u << 3u,
45
45
46
        // Matches declarations of arrays.
46
        // Matches declarations of arrays.
47
        kArrayDeclaration = 0x0001 << 4,
47
        kArrayDeclaration = 1u << 4u,
48
48
49
        // Matches declarations of structs where the struct type does not have a name.
49
        // Matches declarations of structs where the struct type does not have a name.
50
        kNamelessStructDeclaration = 0x0001 << 5,
50
        kNamelessStructDeclaration = 1u << 5u,
51
51
52
        // Matches array length() method.
52
        // Matches array length() method.
53
        kArrayLengthMethod = 0x0001 << 6,
53
        kArrayLengthMethod = 1u << 6u,
54
54
55
        // Matches a vector or matrix constructor whose arguments are scalarized by the
55
        // Matches a vector or matrix constructor whose arguments are scalarized by the
56
        // SH_SCALARIZE_VEC_OR_MAT_CONSTRUCTOR_ARGUMENTS workaround.
56
        // SH_SCALARIZE_VEC_OR_MAT_CONSTRUCTOR_ARGUMENTS workaround.
57
        kScalarizedVecOrMatConstructor = 0x0001 << 7
57
        kScalarizedVecOrMatConstructor = 1u << 7u,
58
    };
58
    };
59
    IntermNodePatternMatcher(const unsigned int mask);
59
    IntermNodePatternMatcher(const unsigned int mask);
60
60
61
    bool match(TIntermUnary *node);
61
    bool match(TIntermUnary *node) const;
62
62
63
    bool match(TIntermBinary *node, TIntermNode *parentNode);
63
    bool match(TIntermBinary *node, TIntermNode *parentNode) const;
64
64
65
    // Use this version for checking binary node matches in case you're using flag
65
    // Use this version for checking binary node matches in case you're using flag
66
    // kDynamicIndexingOfVectorOrMatrixInLValue.
66
    // kDynamicIndexingOfVectorOrMatrixInLValue.
67
    bool match(TIntermBinary *node, TIntermNode *parentNode, bool isLValueRequiredHere);
67
    bool match(TIntermBinary *node, TIntermNode *parentNode, bool isLValueRequiredHere) const;
68
68
69
    bool match(TIntermAggregate *node, TIntermNode *parentNode);
69
    bool match(TIntermAggregate *node, TIntermNode *parentNode) const;
70
    bool match(TIntermTernary *node);
70
    bool match(TIntermTernary *node) const;
71
    bool match(TIntermDeclaration *node);
71
    bool match(TIntermDeclaration *node) const;
72
72
73
  private:
73
  private:
74
    const unsigned int mMask;
74
    const unsigned int mMask;
75
75
76
    bool matchInternal(TIntermBinary *node, TIntermNode *parentNode);
76
    bool matchInternal(TIntermBinary *node, TIntermNode *parentNode) const;
77
};
77
};
78
78
79
}  // namespace sh
79
}  // namespace sh
- a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_util/IntermNode_util.cpp +44 lines
Lines 224-229 TVariable *DeclareTempVariable(TSymbolTable *symbolTable, a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_util/IntermNode_util.cpp_sec1
224
    return variable;
224
    return variable;
225
}
225
}
226
226
227
std::pair<const TVariable *, const TVariable *> DeclareStructure(
228
    TIntermBlock *root,
229
    TSymbolTable *symbolTable,
230
    TFieldList *fieldList,
231
    TQualifier qualifier,
232
    const TMemoryQualifier &memoryQualifier,
233
    uint32_t arraySize,
234
    const ImmutableString &structTypeName,
235
    const ImmutableString *structInstanceName)
236
{
237
    TStructure *structure =
238
        new TStructure(symbolTable, structTypeName, fieldList, SymbolType::AngleInternal);
239
240
    auto makeStructureType = [&](bool isStructSpecifier) {
241
        TType *structureType = new TType(structure, isStructSpecifier);
242
        structureType->setQualifier(qualifier);
243
        structureType->setMemoryQualifier(memoryQualifier);
244
        if (arraySize > 0)
245
        {
246
            structureType->makeArray(arraySize);
247
        }
248
        return structureType;
249
    };
250
251
    TIntermSequence insertSequence;
252
253
    TVariable *typeVar = new TVariable(symbolTable, kEmptyImmutableString, makeStructureType(true),
254
                                       SymbolType::Empty);
255
    insertSequence.push_back(new TIntermDeclaration{typeVar});
256
257
    TVariable *instanceVar = nullptr;
258
    if (structInstanceName)
259
    {
260
        instanceVar = new TVariable(symbolTable, *structInstanceName, makeStructureType(false),
261
                                    SymbolType::AngleInternal);
262
        insertSequence.push_back(new TIntermDeclaration{instanceVar});
263
    }
264
265
    size_t firstFunctionIndex = FindFirstFunctionDefinitionIndex(root);
266
    root->insertChildNodes(firstFunctionIndex, insertSequence);
267
268
    return {typeVar, instanceVar};
269
}
270
227
const TVariable *DeclareInterfaceBlock(TIntermBlock *root,
271
const TVariable *DeclareInterfaceBlock(TIntermBlock *root,
228
                                       TSymbolTable *symbolTable,
272
                                       TSymbolTable *symbolTable,
229
                                       TFieldList *fieldList,
273
                                       TFieldList *fieldList,
- a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_util/IntermNode_util.h +9 lines
Lines 45-50 TVariable *DeclareTempVariable(TSymbolTable *symbolTable, a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_util/IntermNode_util.h_sec1
45
                               TIntermTyped *initializer,
45
                               TIntermTyped *initializer,
46
                               TQualifier qualifier,
46
                               TQualifier qualifier,
47
                               TIntermDeclaration **declarationOut);
47
                               TIntermDeclaration **declarationOut);
48
std::pair<const TVariable *, const TVariable *> DeclareStructure(
49
    TIntermBlock *root,
50
    TSymbolTable *symbolTable,
51
    TFieldList *fieldList,
52
    TQualifier qualifier,
53
    const TMemoryQualifier &memoryQualifier,
54
    uint32_t arraySize,
55
    const ImmutableString &structTypeName,
56
    const ImmutableString *structInstanceName);
48
const TVariable *DeclareInterfaceBlock(TIntermBlock *root,
57
const TVariable *DeclareInterfaceBlock(TIntermBlock *root,
49
                                       TSymbolTable *symbolTable,
58
                                       TSymbolTable *symbolTable,
50
                                       TFieldList *fieldList,
59
                                       TFieldList *fieldList,
- a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_util/IntermRebuild.cpp +1028 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_util/IntermRebuild.cpp_sec1
1
//
2
// Copyright 2020 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
7
#include <algorithm>
8
9
#include "compiler/translator/Compiler.h"
10
#include "compiler/translator/SymbolTable.h"
11
#include "compiler/translator/tree_util/AsNode.h"
12
#include "compiler/translator/tree_util/IntermRebuild.h"
13
14
#define GUARD2(cond, failVal) \
15
    do                        \
16
    {                         \
17
        if (!(cond))          \
18
        {                     \
19
            return failVal;   \
20
        }                     \
21
    } while (false)
22
23
#define GUARD(cond) GUARD2(cond, nullptr)
24
25
namespace sh
26
{
27
28
template <typename T, typename U>
29
ANGLE_INLINE bool AllBits(T haystack, U needle)
30
{
31
    return (haystack & needle) == needle;
32
}
33
34
template <typename T, typename U>
35
ANGLE_INLINE bool AnyBits(T haystack, U needle)
36
{
37
    return (haystack & needle) != 0;
38
}
39
40
////////////////////////////////////////////////////////////////////////////////
41
42
TIntermRebuild::BaseResult::BaseResult(BaseResult &other)
43
    : mAction(other.mAction),
44
      mVisit(other.mVisit),
45
      mSingle(other.mSingle),
46
      mMulti(std::move(other.mMulti))
47
{}
48
49
TIntermRebuild::BaseResult::BaseResult(TIntermNode &node, VisitBits visit)
50
    : mAction(Action::ReplaceSingle), mVisit(visit), mSingle(&node)
51
{}
52
53
TIntermRebuild::BaseResult::BaseResult(TIntermNode *node, VisitBits visit)
54
    : mAction(node ? Action::ReplaceSingle : Action::Drop),
55
      mVisit(node ? visit : VisitBits::Neither),
56
      mSingle(node)
57
{}
58
59
TIntermRebuild::BaseResult::BaseResult(nullptr_t)
60
    : mAction(Action::Drop), mVisit(VisitBits::Neither), mSingle(nullptr)
61
{}
62
63
TIntermRebuild::BaseResult::BaseResult(Fail)
64
    : mAction(Action::Fail), mVisit(VisitBits::Neither), mSingle(nullptr)
65
{}
66
67
TIntermRebuild::BaseResult::BaseResult(std::vector<TIntermNode *> &&nodes)
68
    : mAction(Action::ReplaceMulti),
69
      mVisit(VisitBits::Neither),
70
      mSingle(nullptr),
71
      mMulti(std::move(nodes))
72
{}
73
74
void TIntermRebuild::BaseResult::moveAssignImpl(BaseResult &other)
75
{
76
    mAction = other.mAction;
77
    mVisit  = other.mVisit;
78
    mSingle = other.mSingle;
79
    mMulti  = std::move(other.mMulti);
80
}
81
82
TIntermRebuild::BaseResult TIntermRebuild::BaseResult::Multi(std::vector<TIntermNode *> &&nodes)
83
{
84
    auto it = std::remove(nodes.begin(), nodes.end(), nullptr);
85
    nodes.erase(it, nodes.end());
86
    return std::move(nodes);
87
}
88
89
bool TIntermRebuild::BaseResult::isFail() const
90
{
91
    return mAction == Action::Fail;
92
}
93
94
bool TIntermRebuild::BaseResult::isDrop() const
95
{
96
    return mAction == Action::Drop;
97
}
98
99
TIntermNode *TIntermRebuild::BaseResult::single() const
100
{
101
    return mSingle;
102
}
103
104
const std::vector<TIntermNode *> *TIntermRebuild::BaseResult::multi() const
105
{
106
    if (mAction == Action::ReplaceMulti)
107
    {
108
        return &mMulti;
109
    }
110
    return nullptr;
111
}
112
113
////////////////////////////////////////////////////////////////////////////////
114
115
using PreResult = TIntermRebuild::PreResult;
116
117
PreResult::PreResult(TIntermNode &node, VisitBits visit) : BaseResult(node, visit) {}
118
PreResult::PreResult(TIntermNode *node, VisitBits visit) : BaseResult(node, visit) {}
119
PreResult::PreResult(nullptr_t) : BaseResult(nullptr) {}
120
PreResult::PreResult(Fail) : BaseResult(Fail()) {}
121
122
PreResult::PreResult(BaseResult &&other) : BaseResult(other) {}
123
PreResult::PreResult(PreResult &&other) : BaseResult(other) {}
124
125
void PreResult::operator=(PreResult &&other)
126
{
127
    moveAssignImpl(other);
128
}
129
130
////////////////////////////////////////////////////////////////////////////////
131
132
using PostResult = TIntermRebuild::PostResult;
133
134
PostResult::PostResult(TIntermNode &node) : BaseResult(node, VisitBits::Neither) {}
135
PostResult::PostResult(TIntermNode *node) : BaseResult(node, VisitBits::Neither) {}
136
PostResult::PostResult(nullptr_t) : BaseResult(nullptr) {}
137
PostResult::PostResult(Fail) : BaseResult(Fail()) {}
138
139
PostResult::PostResult(PostResult &&other) : BaseResult(other) {}
140
PostResult::PostResult(BaseResult &&other) : BaseResult(other) {}
141
142
void PostResult::operator=(PostResult &&other)
143
{
144
    moveAssignImpl(other);
145
}
146
147
////////////////////////////////////////////////////////////////////////////////
148
149
TIntermRebuild::TIntermRebuild(TCompiler &compiler, bool preVisit, bool postVisit)
150
    : mCompiler(compiler),
151
      mSymbolTable(compiler.getSymbolTable()),
152
      mPreVisit(preVisit),
153
      mPostVisit(postVisit)
154
{
155
    ASSERT(preVisit || postVisit);
156
}
157
158
TIntermRebuild::~TIntermRebuild()
159
{
160
    ASSERT(!mNodeStack.value);
161
    ASSERT(!mNodeStack.tail);
162
}
163
164
const TFunction *TIntermRebuild::getParentFunction() const
165
{
166
    return mParentFunc;
167
}
168
169
TIntermNode *TIntermRebuild::getParentNode(size_t offset) const
170
{
171
    ASSERT(mNodeStack.tail);
172
    auto parent = *mNodeStack.tail;
173
    while (offset > 0)
174
    {
175
        --offset;
176
        ASSERT(parent.tail);
177
        parent = *parent.tail;
178
    }
179
    return parent.value;
180
}
181
182
bool TIntermRebuild::rebuildRoot(TIntermBlock &root)
183
{
184
    if (!rebuildInPlace(root))
185
    {
186
        return false;
187
    }
188
    return mCompiler.validateAST(&root);
189
}
190
191
bool TIntermRebuild::rebuildInPlace(TIntermAggregate &node)
192
{
193
    return rebuildInPlaceImpl(node);
194
}
195
196
bool TIntermRebuild::rebuildInPlace(TIntermBlock &node)
197
{
198
    return rebuildInPlaceImpl(node);
199
}
200
201
bool TIntermRebuild::rebuildInPlace(TIntermDeclaration &node)
202
{
203
    return rebuildInPlaceImpl(node);
204
}
205
206
template <typename Node>
207
bool TIntermRebuild::rebuildInPlaceImpl(Node &node)
208
{
209
    auto *newNode = traverseAnyAs<Node>(node);
210
    if (!newNode)
211
    {
212
        return false;
213
    }
214
215
    if (newNode != &node)
216
    {
217
        *node.getSequence() = std::move(*newNode->getSequence());
218
    }
219
220
    return true;
221
}
222
223
PostResult TIntermRebuild::rebuild(TIntermNode &node)
224
{
225
    return traverseAny(node);
226
}
227
228
////////////////////////////////////////////////////////////////////////////////
229
230
template <typename Node>
231
Node *TIntermRebuild::traverseAnyAs(TIntermNode &node)
232
{
233
    PostResult result(traverseAny(node));
234
    if (result.mAction == Action::Fail || !result.mSingle)
235
    {
236
        return nullptr;
237
    }
238
    return asNode<Node>(result.mSingle);
239
}
240
241
template <typename Node>
242
bool TIntermRebuild::traverseAnyAs(TIntermNode &node, Node *&out)
243
{
244
    PostResult result(traverseAny(node));
245
    if (result.mAction == Action::Fail || result.mAction == Action::ReplaceMulti)
246
    {
247
        return false;
248
    }
249
    if (!result.mSingle)
250
    {
251
        return true;
252
    }
253
    out = asNode<Node>(result.mSingle);
254
    return out;
255
}
256
257
bool TIntermRebuild::traverseAggregateBaseChildren(TIntermAggregateBase &node)
258
{
259
    auto *const children = node.getSequence();
260
    ASSERT(children);
261
    TIntermSequence newChildren;
262
263
    for (TIntermNode *child : *children)
264
    {
265
        ASSERT(child);
266
        PostResult result(traverseAny(*child));
267
268
        switch (result.mAction)
269
        {
270
            case Action::ReplaceSingle:
271
                newChildren.push_back(result.mSingle);
272
                break;
273
274
            case Action::ReplaceMulti:
275
                for (TIntermNode *newNode : result.mMulti)
276
                {
277
                    if (newNode)
278
                    {
279
                        newChildren.push_back(newNode);
280
                    }
281
                }
282
                break;
283
284
            case Action::Drop:
285
                break;
286
287
            case Action::Fail:
288
                return false;
289
        }
290
    }
291
292
    *children = std::move(newChildren);
293
294
    return true;
295
}
296
297
////////////////////////////////////////////////////////////////////////////////
298
299
struct TIntermRebuild::NodeStackGuard
300
{
301
    ConsList<TIntermNode *> oldNodeStack;
302
    ConsList<TIntermNode *> &nodeStack;
303
    NodeStackGuard(ConsList<TIntermNode *> &nodeStack)
304
        : oldNodeStack(nodeStack), nodeStack(nodeStack)
305
    {}
306
    ~NodeStackGuard() { nodeStack = oldNodeStack; }
307
};
308
309
PostResult TIntermRebuild::traverseAny(TIntermNode &originalNode)
310
{
311
    PreResult preResult = traversePre(originalNode);
312
    if (!preResult.mSingle)
313
    {
314
        ASSERT(preResult.mVisit == VisitBits::Neither);
315
        return std::move(preResult);
316
    }
317
318
    TIntermNode *currNode       = preResult.mSingle;
319
    const VisitBits visit       = preResult.mVisit;
320
    const NodeType currNodeType = getNodeType(*currNode);
321
322
    currNode = traverseChildren(currNodeType, originalNode, *currNode, visit);
323
    if (!currNode)
324
    {
325
        return Fail();
326
    }
327
328
    return traversePost(currNodeType, originalNode, *currNode, visit);
329
}
330
331
PreResult TIntermRebuild::traversePre(TIntermNode &originalNode)
332
{
333
    if (!mPreVisit)
334
    {
335
        return {originalNode, VisitBits::Both};
336
    }
337
338
    NodeStackGuard guard(mNodeStack);
339
    mNodeStack = {&originalNode, &guard.oldNodeStack};
340
341
    const NodeType originalNodeType = getNodeType(originalNode);
342
343
    switch (originalNodeType)
344
    {
345
        case NodeType::Unknown:
346
            ASSERT(false);
347
            return Fail();
348
        case NodeType::Symbol:
349
            return visitSymbolPre(*originalNode.getAsSymbolNode());
350
        case NodeType::ConstantUnion:
351
            return visitConstantUnionPre(*originalNode.getAsConstantUnion());
352
        case NodeType::FunctionPrototype:
353
            return visitFunctionPrototypePre(*originalNode.getAsFunctionPrototypeNode());
354
        case NodeType::PreprocessorDirective:
355
            return visitPreprocessorDirectivePre(*originalNode.getAsPreprocessorDirective());
356
        case NodeType::Unary:
357
            return visitUnaryPre(*originalNode.getAsUnaryNode());
358
        case NodeType::Binary:
359
            return visitBinaryPre(*originalNode.getAsBinaryNode());
360
        case NodeType::Ternary:
361
            return visitTernaryPre(*originalNode.getAsTernaryNode());
362
        case NodeType::Swizzle:
363
            return visitSwizzlePre(*originalNode.getAsSwizzleNode());
364
        case NodeType::IfElse:
365
            return visitIfElsePre(*originalNode.getAsIfElseNode());
366
        case NodeType::Switch:
367
            return visitSwitchPre(*originalNode.getAsSwitchNode());
368
        case NodeType::Case:
369
            return visitCasePre(*originalNode.getAsCaseNode());
370
        case NodeType::FunctionDefinition:
371
            return visitFunctionDefinitionPre(*originalNode.getAsFunctionDefinition());
372
        case NodeType::Aggregate:
373
            return visitAggregatePre(*originalNode.getAsAggregate());
374
        case NodeType::Block:
375
            return visitBlockPre(*originalNode.getAsBlock());
376
        case NodeType::GlobalQualifierDeclaration:
377
            return visitGlobalQualifierDeclarationPre(
378
                *originalNode.getAsGlobalQualifierDeclarationNode());
379
        case NodeType::Declaration:
380
            return visitDeclarationPre(*originalNode.getAsDeclarationNode());
381
        case NodeType::Loop:
382
            return visitLoopPre(*originalNode.getAsLoopNode());
383
        case NodeType::Branch:
384
            return visitBranchPre(*originalNode.getAsBranchNode());
385
    }
386
}
387
388
TIntermNode *TIntermRebuild::traverseChildren(NodeType currNodeType,
389
                                              const TIntermNode &originalNode,
390
                                              TIntermNode &currNode,
391
                                              VisitBits visit)
392
{
393
    if (!AnyBits(visit, VisitBits::Children))
394
    {
395
        return &currNode;
396
    }
397
398
    if (AnyBits(visit, VisitBits::ChildrenRequiresSame) && &originalNode != &currNode)
399
    {
400
        return &currNode;
401
    }
402
403
    NodeStackGuard guard(mNodeStack);
404
    mNodeStack = {&currNode, &guard.oldNodeStack};
405
406
    switch (currNodeType)
407
    {
408
        case NodeType::Unknown:
409
            ASSERT(false);
410
            return nullptr;
411
        case NodeType::Symbol:
412
            return &currNode;
413
        case NodeType::ConstantUnion:
414
            return &currNode;
415
        case NodeType::FunctionPrototype:
416
            return &currNode;
417
        case NodeType::PreprocessorDirective:
418
            return &currNode;
419
        case NodeType::Unary:
420
            return traverseUnaryChildren(*currNode.getAsUnaryNode());
421
        case NodeType::Binary:
422
            return traverseBinaryChildren(*currNode.getAsBinaryNode());
423
        case NodeType::Ternary:
424
            return traverseTernaryChildren(*currNode.getAsTernaryNode());
425
        case NodeType::Swizzle:
426
            return traverseSwizzleChildren(*currNode.getAsSwizzleNode());
427
        case NodeType::IfElse:
428
            return traverseIfElseChildren(*currNode.getAsIfElseNode());
429
        case NodeType::Switch:
430
            return traverseSwitchChildren(*currNode.getAsSwitchNode());
431
        case NodeType::Case:
432
            return traverseCaseChildren(*currNode.getAsCaseNode());
433
        case NodeType::FunctionDefinition:
434
            return traverseFunctionDefinitionChildren(*currNode.getAsFunctionDefinition());
435
        case NodeType::Aggregate:
436
            return traverseAggregateChildren(*currNode.getAsAggregate());
437
        case NodeType::Block:
438
            return traverseBlockChildren(*currNode.getAsBlock());
439
        case NodeType::GlobalQualifierDeclaration:
440
            return traverseGlobalQualifierDeclarationChildren(
441
                *currNode.getAsGlobalQualifierDeclarationNode());
442
        case NodeType::Declaration:
443
            return traverseDeclarationChildren(*currNode.getAsDeclarationNode());
444
        case NodeType::Loop:
445
            return traverseLoopChildren(*currNode.getAsLoopNode());
446
        case NodeType::Branch:
447
            return traverseBranchChildren(*currNode.getAsBranchNode());
448
    }
449
}
450
451
PostResult TIntermRebuild::traversePost(NodeType currNodeType,
452
                                        const TIntermNode &originalNode,
453
                                        TIntermNode &currNode,
454
                                        VisitBits visit)
455
{
456
    if (!mPostVisit)
457
    {
458
        return currNode;
459
    }
460
461
    if (!AnyBits(visit, VisitBits::Post))
462
    {
463
        return currNode;
464
    }
465
466
    if (AnyBits(visit, VisitBits::PostRequiresSame) && &originalNode != &currNode)
467
    {
468
        return currNode;
469
    }
470
471
    NodeStackGuard guard(mNodeStack);
472
    mNodeStack = {&currNode, &guard.oldNodeStack};
473
474
    switch (currNodeType)
475
    {
476
        case NodeType::Unknown:
477
            ASSERT(false);
478
            return Fail();
479
        case NodeType::Symbol:
480
            return visitSymbolPost(*currNode.getAsSymbolNode());
481
        case NodeType::ConstantUnion:
482
            return visitConstantUnionPost(*currNode.getAsConstantUnion());
483
        case NodeType::FunctionPrototype:
484
            return visitFunctionPrototypePost(*currNode.getAsFunctionPrototypeNode());
485
        case NodeType::PreprocessorDirective:
486
            return visitPreprocessorDirectivePost(*currNode.getAsPreprocessorDirective());
487
        case NodeType::Unary:
488
            return visitUnaryPost(*currNode.getAsUnaryNode());
489
        case NodeType::Binary:
490
            return visitBinaryPost(*currNode.getAsBinaryNode());
491
        case NodeType::Ternary:
492
            return visitTernaryPost(*currNode.getAsTernaryNode());
493
        case NodeType::Swizzle:
494
            return visitSwizzlePost(*currNode.getAsSwizzleNode());
495
        case NodeType::IfElse:
496
            return visitIfElsePost(*currNode.getAsIfElseNode());
497
        case NodeType::Switch:
498
            return visitSwitchPost(*currNode.getAsSwitchNode());
499
        case NodeType::Case:
500
            return visitCasePost(*currNode.getAsCaseNode());
501
        case NodeType::FunctionDefinition:
502
            return visitFunctionDefinitionPost(*currNode.getAsFunctionDefinition());
503
        case NodeType::Aggregate:
504
            return visitAggregatePost(*currNode.getAsAggregate());
505
        case NodeType::Block:
506
            return visitBlockPost(*currNode.getAsBlock());
507
        case NodeType::GlobalQualifierDeclaration:
508
            return visitGlobalQualifierDeclarationPost(
509
                *currNode.getAsGlobalQualifierDeclarationNode());
510
        case NodeType::Declaration:
511
            return visitDeclarationPost(*currNode.getAsDeclarationNode());
512
        case NodeType::Loop:
513
            return visitLoopPost(*currNode.getAsLoopNode());
514
        case NodeType::Branch:
515
            return visitBranchPost(*currNode.getAsBranchNode());
516
    }
517
}
518
519
////////////////////////////////////////////////////////////////////////////////
520
521
TIntermNode *TIntermRebuild::traverseAggregateChildren(TIntermAggregate &node)
522
{
523
    if (traverseAggregateBaseChildren(node))
524
    {
525
        return &node;
526
    }
527
    return nullptr;
528
}
529
530
TIntermNode *TIntermRebuild::traverseBlockChildren(TIntermBlock &node)
531
{
532
    if (traverseAggregateBaseChildren(node))
533
    {
534
        return &node;
535
    }
536
    return nullptr;
537
}
538
539
TIntermNode *TIntermRebuild::traverseDeclarationChildren(TIntermDeclaration &node)
540
{
541
    if (traverseAggregateBaseChildren(node))
542
    {
543
        return &node;
544
    }
545
    return nullptr;
546
}
547
548
TIntermNode *TIntermRebuild::traverseSwizzleChildren(TIntermSwizzle &node)
549
{
550
    auto *const operand = node.getOperand();
551
    ASSERT(operand);
552
553
    auto *newOperand = traverseAnyAs<TIntermTyped>(*operand);
554
    GUARD(newOperand);
555
556
    if (newOperand != operand)
557
    {
558
        return new TIntermSwizzle(newOperand, node.getSwizzleOffsets());
559
    }
560
561
    return &node;
562
}
563
564
TIntermNode *TIntermRebuild::traverseBinaryChildren(TIntermBinary &node)
565
{
566
    auto *const left = node.getLeft();
567
    ASSERT(left);
568
    auto *const right = node.getRight();
569
    ASSERT(right);
570
571
    auto *const newLeft = traverseAnyAs<TIntermTyped>(*left);
572
    GUARD(newLeft);
573
    auto *const newRight = traverseAnyAs<TIntermTyped>(*right);
574
    GUARD(newRight);
575
576
    if (newLeft != left || newRight != right)
577
    {
578
        TOperator op = node.getOp();
579
        switch (op)
580
        {
581
            case TOperator::EOpIndexDirectStruct:
582
            {
583
                if (newLeft->getType().getInterfaceBlock())
584
                {
585
                    op = TOperator::EOpIndexDirectInterfaceBlock;
586
                }
587
            }
588
            break;
589
590
            case TOperator::EOpIndexDirectInterfaceBlock:
591
            {
592
                if (newLeft->getType().getStruct())
593
                {
594
                    op = TOperator::EOpIndexDirectStruct;
595
                }
596
            }
597
            break;
598
599
            case TOperator::EOpComma:
600
                return TIntermBinary::CreateComma(newLeft, newRight, mCompiler.getShaderVersion());
601
602
            default:
603
                break;
604
        }
605
606
        return new TIntermBinary(op, newLeft, newRight);
607
    }
608
609
    return &node;
610
}
611
612
TIntermNode *TIntermRebuild::traverseUnaryChildren(TIntermUnary &node)
613
{
614
    auto *const operand = node.getOperand();
615
    ASSERT(operand);
616
617
    auto *const newOperand = traverseAnyAs<TIntermTyped>(*operand);
618
    GUARD(newOperand);
619
620
    if (newOperand != operand)
621
    {
622
        return new TIntermUnary(node.getOp(), newOperand, node.getFunction());
623
    }
624
625
    return &node;
626
}
627
628
TIntermNode *TIntermRebuild::traverseTernaryChildren(TIntermTernary &node)
629
{
630
    auto *const cond = node.getCondition();
631
    ASSERT(cond);
632
    auto *const true_ = node.getTrueExpression();
633
    ASSERT(true_);
634
    auto *const false_ = node.getFalseExpression();
635
    ASSERT(false_);
636
637
    auto *const newCond = traverseAnyAs<TIntermTyped>(*cond);
638
    GUARD(newCond);
639
    auto *const newTrue = traverseAnyAs<TIntermTyped>(*true_);
640
    GUARD(newTrue);
641
    auto *const newFalse = traverseAnyAs<TIntermTyped>(*false_);
642
    GUARD(newFalse);
643
644
    if (newCond != cond || newTrue != true_ || newFalse != false_)
645
    {
646
        return new TIntermTernary(newCond, newTrue, newFalse);
647
    }
648
649
    return &node;
650
}
651
652
TIntermNode *TIntermRebuild::traverseIfElseChildren(TIntermIfElse &node)
653
{
654
    auto *const cond = node.getCondition();
655
    ASSERT(cond);
656
    auto *const true_  = node.getTrueBlock();
657
    auto *const false_ = node.getFalseBlock();
658
659
    auto *const newCond = traverseAnyAs<TIntermTyped>(*cond);
660
    GUARD(newCond);
661
    TIntermBlock *newTrue = nullptr;
662
    if (true_)
663
    {
664
        GUARD(traverseAnyAs(*true_, newTrue));
665
    }
666
    TIntermBlock *newFalse = nullptr;
667
    if (false_)
668
    {
669
        GUARD(traverseAnyAs(*false_, newFalse));
670
    }
671
672
    if (newCond != cond || newTrue != true_ || newFalse != false_)
673
    {
674
        return new TIntermIfElse(newCond, newTrue, newFalse);
675
    }
676
677
    return &node;
678
}
679
680
TIntermNode *TIntermRebuild::traverseSwitchChildren(TIntermSwitch &node)
681
{
682
    auto *const init = node.getInit();
683
    ASSERT(init);
684
    auto *const stmts = node.getStatementList();
685
    ASSERT(stmts);
686
687
    auto *const newInit = traverseAnyAs<TIntermTyped>(*init);
688
    GUARD(newInit);
689
    auto *const newStmts = traverseAnyAs<TIntermBlock>(*stmts);
690
    GUARD(newStmts);
691
692
    if (newInit != init || newStmts != stmts)
693
    {
694
        return new TIntermSwitch(newInit, newStmts);
695
    }
696
697
    return &node;
698
}
699
700
TIntermNode *TIntermRebuild::traverseCaseChildren(TIntermCase &node)
701
{
702
    auto *const cond = node.getCondition();
703
704
    TIntermTyped *newCond = nullptr;
705
    if (cond)
706
    {
707
        GUARD(traverseAnyAs(*cond, newCond));
708
    }
709
710
    if (newCond != cond)
711
    {
712
        return new TIntermCase(newCond);
713
    }
714
715
    return &node;
716
}
717
718
TIntermNode *TIntermRebuild::traverseFunctionDefinitionChildren(TIntermFunctionDefinition &node)
719
{
720
    GUARD(!mParentFunc);  // Function definitions cannot be nested.
721
    mParentFunc = node.getFunction();
722
    struct OnExit
723
    {
724
        const TFunction *&parentFunc;
725
        OnExit(const TFunction *&parentFunc) : parentFunc(parentFunc) {}
726
        ~OnExit() { parentFunc = nullptr; }
727
    } onExit(mParentFunc);
728
729
    auto *const proto = node.getFunctionPrototype();
730
    ASSERT(proto);
731
    auto *const body = node.getBody();
732
    ASSERT(body);
733
734
    auto *const newProto = traverseAnyAs<TIntermFunctionPrototype>(*proto);
735
    GUARD(newProto);
736
    auto *const newBody = traverseAnyAs<TIntermBlock>(*body);
737
    GUARD(newBody);
738
739
    if (newProto != proto || newBody != body)
740
    {
741
        return new TIntermFunctionDefinition(newProto, newBody);
742
    }
743
744
    return &node;
745
}
746
747
TIntermNode *TIntermRebuild::traverseGlobalQualifierDeclarationChildren(
748
    TIntermGlobalQualifierDeclaration &node)
749
{
750
    auto *const symbol = node.getSymbol();
751
    ASSERT(symbol);
752
753
    auto *const newSymbol = traverseAnyAs<TIntermSymbol>(*symbol);
754
    GUARD(newSymbol);
755
756
    if (newSymbol != symbol)
757
    {
758
        return new TIntermGlobalQualifierDeclaration(newSymbol, node.isPrecise(), node.getLine());
759
    }
760
761
    return &node;
762
}
763
764
TIntermNode *TIntermRebuild::traverseLoopChildren(TIntermLoop &node)
765
{
766
    const TLoopType loopType = node.getType();
767
768
    auto *const init = node.getInit();
769
    auto *const cond = node.getCondition();
770
    auto *const expr = node.getExpression();
771
    auto *const body = node.getBody();
772
    ASSERT(body);
773
774
#if defined(ANGLE_ENABLE_ASSERTS)
775
    switch (loopType)
776
    {
777
        case TLoopType::ELoopFor:
778
            break;
779
        case TLoopType::ELoopWhile:
780
        case TLoopType::ELoopDoWhile:
781
            ASSERT(cond);
782
            ASSERT(!init && !expr);
783
            break;
784
    }
785
#endif
786
787
    auto *const newBody = traverseAnyAs<TIntermBlock>(*body);
788
    GUARD(newBody);
789
    TIntermNode *newInit = nullptr;
790
    if (init)
791
    {
792
        GUARD(traverseAnyAs(*init, newInit));
793
    }
794
    TIntermTyped *newCond = nullptr;
795
    if (cond)
796
    {
797
        GUARD(traverseAnyAs(*cond, newCond));
798
    }
799
    TIntermTyped *newExpr = nullptr;
800
    if (expr)
801
    {
802
        GUARD(traverseAnyAs(*expr, newExpr));
803
    }
804
805
    if (newInit != init || newCond != cond || newExpr != expr || newBody != body)
806
    {
807
        switch (loopType)
808
        {
809
            case TLoopType::ELoopFor:
810
                GUARD(newBody);
811
                break;
812
            case TLoopType::ELoopWhile:
813
            case TLoopType::ELoopDoWhile:
814
                GUARD(newCond && newBody);
815
                GUARD(!newInit && !newExpr);
816
                break;
817
        }
818
        return new TIntermLoop(loopType, newInit, newCond, newExpr, newBody);
819
    }
820
821
    return &node;
822
}
823
824
TIntermNode *TIntermRebuild::traverseBranchChildren(TIntermBranch &node)
825
{
826
    auto *const expr = node.getExpression();
827
828
    TIntermTyped *newExpr = nullptr;
829
    if (expr)
830
    {
831
        GUARD(traverseAnyAs<TIntermTyped>(*expr, newExpr));
832
    }
833
834
    if (newExpr != expr)
835
    {
836
        return new TIntermBranch(node.getFlowOp(), newExpr);
837
    }
838
839
    return &node;
840
}
841
842
////////////////////////////////////////////////////////////////////////////////
843
844
PreResult TIntermRebuild::visitSymbolPre(TIntermSymbol &node)
845
{
846
    return {node, VisitBits::Both};
847
}
848
849
PreResult TIntermRebuild::visitConstantUnionPre(TIntermConstantUnion &node)
850
{
851
    return {node, VisitBits::Both};
852
}
853
854
PreResult TIntermRebuild::visitFunctionPrototypePre(TIntermFunctionPrototype &node)
855
{
856
    return {node, VisitBits::Both};
857
}
858
859
PreResult TIntermRebuild::visitPreprocessorDirectivePre(TIntermPreprocessorDirective &node)
860
{
861
    return {node, VisitBits::Both};
862
}
863
864
PreResult TIntermRebuild::visitUnaryPre(TIntermUnary &node)
865
{
866
    return {node, VisitBits::Both};
867
}
868
869
PreResult TIntermRebuild::visitBinaryPre(TIntermBinary &node)
870
{
871
    return {node, VisitBits::Both};
872
}
873
874
PreResult TIntermRebuild::visitTernaryPre(TIntermTernary &node)
875
{
876
    return {node, VisitBits::Both};
877
}
878
879
PreResult TIntermRebuild::visitSwizzlePre(TIntermSwizzle &node)
880
{
881
    return {node, VisitBits::Both};
882
}
883
884
PreResult TIntermRebuild::visitIfElsePre(TIntermIfElse &node)
885
{
886
    return {node, VisitBits::Both};
887
}
888
889
PreResult TIntermRebuild::visitSwitchPre(TIntermSwitch &node)
890
{
891
    return {node, VisitBits::Both};
892
}
893
894
PreResult TIntermRebuild::visitCasePre(TIntermCase &node)
895
{
896
    return {node, VisitBits::Both};
897
}
898
899
PreResult TIntermRebuild::visitLoopPre(TIntermLoop &node)
900
{
901
    return {node, VisitBits::Both};
902
}
903
904
PreResult TIntermRebuild::visitBranchPre(TIntermBranch &node)
905
{
906
    return {node, VisitBits::Both};
907
}
908
909
PreResult TIntermRebuild::visitDeclarationPre(TIntermDeclaration &node)
910
{
911
    return {node, VisitBits::Both};
912
}
913
914
PreResult TIntermRebuild::visitBlockPre(TIntermBlock &node)
915
{
916
    return {node, VisitBits::Both};
917
}
918
919
PreResult TIntermRebuild::visitAggregatePre(TIntermAggregate &node)
920
{
921
    return {node, VisitBits::Both};
922
}
923
924
PreResult TIntermRebuild::visitFunctionDefinitionPre(TIntermFunctionDefinition &node)
925
{
926
    return {node, VisitBits::Both};
927
}
928
929
PreResult TIntermRebuild::visitGlobalQualifierDeclarationPre(
930
    TIntermGlobalQualifierDeclaration &node)
931
{
932
    return {node, VisitBits::Both};
933
}
934
935
////////////////////////////////////////////////////////////////////////////////
936
937
PostResult TIntermRebuild::visitSymbolPost(TIntermSymbol &node)
938
{
939
    return node;
940
}
941
942
PostResult TIntermRebuild::visitConstantUnionPost(TIntermConstantUnion &node)
943
{
944
    return node;
945
}
946
947
PostResult TIntermRebuild::visitFunctionPrototypePost(TIntermFunctionPrototype &node)
948
{
949
    return node;
950
}
951
952
PostResult TIntermRebuild::visitPreprocessorDirectivePost(TIntermPreprocessorDirective &node)
953
{
954
    return node;
955
}
956
957
PostResult TIntermRebuild::visitUnaryPost(TIntermUnary &node)
958
{
959
    return node;
960
}
961
962
PostResult TIntermRebuild::visitBinaryPost(TIntermBinary &node)
963
{
964
    return node;
965
}
966
967
PostResult TIntermRebuild::visitTernaryPost(TIntermTernary &node)
968
{
969
    return node;
970
}
971
972
PostResult TIntermRebuild::visitSwizzlePost(TIntermSwizzle &node)
973
{
974
    return node;
975
}
976
977
PostResult TIntermRebuild::visitIfElsePost(TIntermIfElse &node)
978
{
979
    return node;
980
}
981
982
PostResult TIntermRebuild::visitSwitchPost(TIntermSwitch &node)
983
{
984
    return node;
985
}
986
987
PostResult TIntermRebuild::visitCasePost(TIntermCase &node)
988
{
989
    return node;
990
}
991
992
PostResult TIntermRebuild::visitLoopPost(TIntermLoop &node)
993
{
994
    return node;
995
}
996
997
PostResult TIntermRebuild::visitBranchPost(TIntermBranch &node)
998
{
999
    return node;
1000
}
1001
1002
PostResult TIntermRebuild::visitDeclarationPost(TIntermDeclaration &node)
1003
{
1004
    return node;
1005
}
1006
1007
PostResult TIntermRebuild::visitBlockPost(TIntermBlock &node)
1008
{
1009
    return node;
1010
}
1011
1012
PostResult TIntermRebuild::visitAggregatePost(TIntermAggregate &node)
1013
{
1014
    return node;
1015
}
1016
1017
PostResult TIntermRebuild::visitFunctionDefinitionPost(TIntermFunctionDefinition &node)
1018
{
1019
    return node;
1020
}
1021
1022
PostResult TIntermRebuild::visitGlobalQualifierDeclarationPost(
1023
    TIntermGlobalQualifierDeclaration &node)
1024
{
1025
    return node;
1026
}
1027
1028
}  // namespace sh
- a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_util/IntermRebuild.h +328 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_util/IntermRebuild.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TREEUTIL_INTERMREBUILD_H_
8
#define COMPILER_TRANSLATOR_TREEUTIL_INTERMREBUILD_H_
9
10
#include "compiler/translator/tree_util/IntermTraverse.h"
11
#include "compiler/translator/tree_util/NodeType.h"
12
13
namespace sh
14
{
15
16
// Walks the tree to rebuild nodes.
17
// This class is intended to be derived with overridden visitXXX functions.
18
//
19
// Each visitXXX function that does not have a Visit parameter simply has the visitor called
20
// exactly once, regardless of (preVisit) or (postVisit) values.
21
22
// Each visitXXX function that has a Visit parameter behaves as follows:
23
//    * If (preVisit):
24
//      - The node is visited before children are traversed.
25
//      - The returned value is used to replace the visited node. The returned value may be the same
26
//        as the original node.
27
//      - If multiple nodes are returned, children and post visits of the returned nodes are not
28
//        preformed, even if it is a singleton collection.
29
//    * If (childVisit)
30
//      - If any new children are returned, the node is automatically rebuilt with the new children
31
//        before post visit.
32
//      - Depending on the type of the node, null children may be discarded.
33
//      - Ill-typed children cause rebuild errors. Ill-typed means the node to automatically rebuild
34
//        cannot accept a child of a certain type as input to its constructor.
35
//      - Only instances of TIntermAggregateBase can accept Multi results for any of its children.
36
//        If supplied, the nodes are spliced children at the spot of the original child.
37
//    * If (postVisit)
38
//      - The node is visited after any children are traversed.
39
//      - Only after such a rebuild (or lack thereof), the post-visit is performed.
40
//
41
// Nodes in visit functions are allowed to be modified in place, including TIntermAggregateBase
42
// child sequences.
43
//
44
// The default implementations of all the visitXXX functions support full pre and post traversal
45
// without modifying the visited nodes.
46
//
47
class TIntermRebuild : angle::NonCopyable
48
{
49
50
    enum class Action
51
    {
52
        ReplaceSingle,
53
        ReplaceMulti,
54
        Drop,
55
        Fail,
56
    };
57
58
  public:
59
    struct Fail
60
    {};
61
62
    enum VisitBits : size_t
63
    {
64
        // No bits are set.
65
        Empty = 0u,
66
67
        // Allow visit of returned node's children.
68
        Children = 1u << 0u,
69
70
        // Allow post visit of returned node.
71
        Post = 1u << 1u,
72
73
        // If (Children) bit, only visit if the returned node is the same as the original node.
74
        ChildrenRequiresSame = 1u << 2u,
75
76
        // If (Post) bit, only visit if the returned node is the same as the original node.
77
        PostRequiresSame = 1u << 3u,
78
79
        RequireSame  = ChildrenRequiresSame | PostRequiresSame,
80
        Neither      = Empty,
81
        Both         = Children | Post,
82
        BothWhenSame = Both | RequireSame,
83
    };
84
85
  private:
86
    struct NodeStackGuard;
87
88
    template <typename T>
89
    struct ConsList
90
    {
91
        T value;
92
        ConsList<T> *tail;
93
    };
94
95
    class BaseResult
96
    {
97
        BaseResult(const BaseResult &) = delete;
98
        BaseResult &operator=(const BaseResult &) = delete;
99
100
      public:
101
        BaseResult(BaseResult &&other) = default;
102
        BaseResult(BaseResult &other);  // For subclass move constructor impls
103
        BaseResult(TIntermNode &node, VisitBits visit);
104
        BaseResult(TIntermNode *node, VisitBits visit);
105
        BaseResult(nullptr_t);
106
        BaseResult(Fail);
107
        BaseResult(std::vector<TIntermNode *> &&nodes);
108
109
        void moveAssignImpl(BaseResult &other);  // For subclass move assign impls
110
111
        static BaseResult Multi(std::vector<TIntermNode *> &&nodes);
112
113
        template <typename Iter>
114
        static BaseResult Multi(Iter nodesBegin, Iter nodesEnd)
115
        {
116
            std::vector<TIntermNode *> nodes;
117
            for (Iter nodesCurr = nodesBegin; nodesCurr != nodesEnd; ++nodesCurr)
118
            {
119
                nodes.push_back(*nodesCurr);
120
            }
121
            return std::move(nodes);
122
        }
123
124
        bool isFail() const;
125
        bool isDrop() const;
126
        TIntermNode *single() const;
127
        const std::vector<TIntermNode *> *multi() const;
128
129
      public:
130
        Action mAction;
131
        VisitBits mVisit;
132
        TIntermNode *mSingle;
133
        std::vector<TIntermNode *> mMulti;
134
    };
135
136
  public:
137
    class PreResult : private BaseResult
138
    {
139
        friend class TIntermRebuild;
140
141
      public:
142
        PreResult(PreResult &&other);
143
        PreResult(TIntermNode &node, VisitBits visit = VisitBits::BothWhenSame);
144
        PreResult(TIntermNode *node, VisitBits visit = VisitBits::BothWhenSame);
145
        PreResult(nullptr_t);  // Used to drop a node.
146
        PreResult(Fail);       // Used to signal failure.
147
148
        void operator=(PreResult &&other);
149
150
        static PreResult Multi(std::vector<TIntermNode *> &&nodes)
151
        {
152
            return BaseResult::Multi(std::move(nodes));
153
        }
154
155
        template <typename Iter>
156
        static PreResult Multi(Iter nodesBegin, Iter nodesEnd)
157
        {
158
            return BaseResult::Multi(nodesBegin, nodesEnd);
159
        }
160
161
        using BaseResult::isDrop;
162
        using BaseResult::isFail;
163
        using BaseResult::multi;
164
        using BaseResult::single;
165
166
      private:
167
        PreResult(BaseResult &&other);
168
    };
169
170
    class PostResult : private BaseResult
171
    {
172
        friend class TIntermRebuild;
173
174
      public:
175
        PostResult(PostResult &&other);
176
        PostResult(TIntermNode &node);
177
        PostResult(TIntermNode *node);
178
        PostResult(nullptr_t);  // Used to drop a node
179
        PostResult(Fail);       // Used to signal failure.
180
181
        void operator=(PostResult &&other);
182
183
        static PostResult Multi(std::vector<TIntermNode *> &&nodes)
184
        {
185
            return BaseResult::Multi(std::move(nodes));
186
        }
187
188
        template <typename Iter>
189
        static PostResult Multi(Iter nodesBegin, Iter nodesEnd)
190
        {
191
            return BaseResult::Multi(nodesBegin, nodesEnd);
192
        }
193
194
        using BaseResult::isDrop;
195
        using BaseResult::isFail;
196
        using BaseResult::multi;
197
        using BaseResult::single;
198
199
      private:
200
        PostResult(BaseResult &&other);
201
    };
202
203
  public:
204
    TIntermRebuild(TCompiler &compiler, bool preVisit, bool postVisit);
205
206
    virtual ~TIntermRebuild();
207
208
    // Rebuilds the tree starting at the provided root. If a new node would be returned for the
209
    // root, the root node's children become that of the new node instead. Returns false if failure
210
    // occurred.
211
    ANGLE_NO_DISCARD bool rebuildRoot(TIntermBlock &root);
212
213
  protected:
214
    virtual PreResult visitSymbolPre(TIntermSymbol &node);
215
    virtual PreResult visitConstantUnionPre(TIntermConstantUnion &node);
216
    virtual PreResult visitFunctionPrototypePre(TIntermFunctionPrototype &node);
217
    virtual PreResult visitPreprocessorDirectivePre(TIntermPreprocessorDirective &node);
218
    virtual PreResult visitUnaryPre(TIntermUnary &node);
219
    virtual PreResult visitBinaryPre(TIntermBinary &node);
220
    virtual PreResult visitTernaryPre(TIntermTernary &node);
221
    virtual PreResult visitSwizzlePre(TIntermSwizzle &node);
222
    virtual PreResult visitIfElsePre(TIntermIfElse &node);
223
    virtual PreResult visitSwitchPre(TIntermSwitch &node);
224
    virtual PreResult visitCasePre(TIntermCase &node);
225
    virtual PreResult visitLoopPre(TIntermLoop &node);
226
    virtual PreResult visitBranchPre(TIntermBranch &node);
227
    virtual PreResult visitDeclarationPre(TIntermDeclaration &node);
228
    virtual PreResult visitBlockPre(TIntermBlock &node);
229
    virtual PreResult visitAggregatePre(TIntermAggregate &node);
230
    virtual PreResult visitFunctionDefinitionPre(TIntermFunctionDefinition &node);
231
    virtual PreResult visitGlobalQualifierDeclarationPre(TIntermGlobalQualifierDeclaration &node);
232
233
    virtual PostResult visitSymbolPost(TIntermSymbol &node);
234
    virtual PostResult visitConstantUnionPost(TIntermConstantUnion &node);
235
    virtual PostResult visitFunctionPrototypePost(TIntermFunctionPrototype &node);
236
    virtual PostResult visitPreprocessorDirectivePost(TIntermPreprocessorDirective &node);
237
    virtual PostResult visitUnaryPost(TIntermUnary &node);
238
    virtual PostResult visitBinaryPost(TIntermBinary &node);
239
    virtual PostResult visitTernaryPost(TIntermTernary &node);
240
    virtual PostResult visitSwizzlePost(TIntermSwizzle &node);
241
    virtual PostResult visitIfElsePost(TIntermIfElse &node);
242
    virtual PostResult visitSwitchPost(TIntermSwitch &node);
243
    virtual PostResult visitCasePost(TIntermCase &node);
244
    virtual PostResult visitLoopPost(TIntermLoop &node);
245
    virtual PostResult visitBranchPost(TIntermBranch &node);
246
    virtual PostResult visitDeclarationPost(TIntermDeclaration &node);
247
    virtual PostResult visitBlockPost(TIntermBlock &node);
248
    virtual PostResult visitAggregatePost(TIntermAggregate &node);
249
    virtual PostResult visitFunctionDefinitionPost(TIntermFunctionDefinition &node);
250
    virtual PostResult visitGlobalQualifierDeclarationPost(TIntermGlobalQualifierDeclaration &node);
251
252
    // Can be used to rebuild a specific node during a traversal. Useful for fine control of
253
    // rebuilding a node's children.
254
    ANGLE_NO_DISCARD PostResult rebuild(TIntermNode &node);
255
256
    // Rebuilds the provided node in place. If a new node would be returned, the old node's children
257
    // become that of the new node instead. Returns false if failure occurred.
258
    ANGLE_NO_DISCARD bool rebuildInPlace(TIntermAggregate &node);
259
260
    // Rebuilds the provided node in place. If a new node would be returned, the old node's children
261
    // become that of the new node instead. Returns false if failure occurred.
262
    ANGLE_NO_DISCARD bool rebuildInPlace(TIntermBlock &node);
263
264
    // Rebuilds the provided node in place. If a new node would be returned, the old node's children
265
    // become that of the new node instead. Returns false if failure occurred.
266
    ANGLE_NO_DISCARD bool rebuildInPlace(TIntermDeclaration &node);
267
268
    // If currently at or below a function declaration body, this returns the function that encloses
269
    // the currently visited node. (This returns null if at a function declaration node.)
270
    const TFunction *getParentFunction() const;
271
272
    TIntermNode *getParentNode(size_t offset = 0) const;
273
274
  private:
275
    template <typename Node>
276
    ANGLE_NO_DISCARD bool rebuildInPlaceImpl(Node &node);
277
278
    PostResult traverseAny(TIntermNode &node);
279
280
    template <typename Node>
281
    Node *traverseAnyAs(TIntermNode &node);
282
283
    template <typename Node>
284
    bool traverseAnyAs(TIntermNode &node, Node *&out);
285
286
    PreResult traversePre(TIntermNode &originalNode);
287
    TIntermNode *traverseChildren(NodeType currNodeType,
288
                                  const TIntermNode &originalNode,
289
                                  TIntermNode &currNode,
290
                                  VisitBits visit);
291
    PostResult traversePost(NodeType nodeType,
292
                            const TIntermNode &originalNode,
293
                            TIntermNode &currNode,
294
                            VisitBits visit);
295
296
    bool traverseAggregateBaseChildren(TIntermAggregateBase &node);
297
298
    TIntermNode *traverseUnaryChildren(TIntermUnary &node);
299
    TIntermNode *traverseBinaryChildren(TIntermBinary &node);
300
    TIntermNode *traverseTernaryChildren(TIntermTernary &node);
301
    TIntermNode *traverseSwizzleChildren(TIntermSwizzle &node);
302
    TIntermNode *traverseIfElseChildren(TIntermIfElse &node);
303
    TIntermNode *traverseSwitchChildren(TIntermSwitch &node);
304
    TIntermNode *traverseCaseChildren(TIntermCase &node);
305
    TIntermNode *traverseLoopChildren(TIntermLoop &node);
306
    TIntermNode *traverseBranchChildren(TIntermBranch &node);
307
    TIntermNode *traverseDeclarationChildren(TIntermDeclaration &node);
308
    TIntermNode *traverseBlockChildren(TIntermBlock &node);
309
    TIntermNode *traverseAggregateChildren(TIntermAggregate &node);
310
    TIntermNode *traverseFunctionDefinitionChildren(TIntermFunctionDefinition &node);
311
    TIntermNode *traverseGlobalQualifierDeclarationChildren(
312
        TIntermGlobalQualifierDeclaration &node);
313
314
  protected:
315
    TCompiler &mCompiler;
316
    TSymbolTable &mSymbolTable;
317
    const TFunction *mParentFunc = nullptr;
318
    GetNodeType getNodeType;
319
320
  private:
321
    ConsList<TIntermNode *> mNodeStack{nullptr, nullptr};
322
    bool mPreVisit;
323
    bool mPostVisit;
324
};
325
326
}  // namespace sh
327
328
#endif  // COMPILER_TRANSLATOR_TREEUTIL_INTERMREBUILD_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_util/NodeType.h +155 lines
Line 0 a/Source/ThirdParty/ANGLE/src/compiler/translator/tree_util/NodeType.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef COMPILER_TRANSLATOR_TREEUTIL_NODETYPE_H_
8
#define COMPILER_TRANSLATOR_TREEUTIL_NODETYPE_H_
9
10
#include "compiler/translator/tree_util/IntermTraverse.h"
11
12
namespace sh
13
{
14
15
enum class NodeType
16
{
17
    Unknown,
18
    Symbol,
19
    ConstantUnion,
20
    FunctionPrototype,
21
    PreprocessorDirective,
22
    Unary,
23
    Binary,
24
    Ternary,
25
    Swizzle,
26
    IfElse,
27
    Switch,
28
    Case,
29
    FunctionDefinition,
30
    Aggregate,
31
    Block,
32
    GlobalQualifierDeclaration,
33
    Declaration,
34
    Loop,
35
    Branch,
36
};
37
38
// This is a function like object instead of a function that stack allocates this because
39
// TIntermTraverser is a heavy object to construct.
40
class GetNodeType : private TIntermTraverser
41
{
42
    NodeType nodeType;
43
44
  public:
45
    GetNodeType() : TIntermTraverser(true, false, false) {}
46
47
    NodeType operator()(TIntermNode &node)
48
    {
49
        node.visit(Visit::PreVisit, this);
50
        return nodeType;
51
    }
52
53
  private:
54
    void visitSymbol(TIntermSymbol *) override { nodeType = NodeType::Symbol; }
55
56
    void visitConstantUnion(TIntermConstantUnion *) override { nodeType = NodeType::ConstantUnion; }
57
58
    void visitFunctionPrototype(TIntermFunctionPrototype *) override
59
    {
60
        nodeType = NodeType::FunctionPrototype;
61
    }
62
63
    void visitPreprocessorDirective(TIntermPreprocessorDirective *) override
64
    {
65
        nodeType = NodeType::PreprocessorDirective;
66
    }
67
68
    bool visitSwizzle(Visit, TIntermSwizzle *) override
69
    {
70
        nodeType = NodeType::Swizzle;
71
        return false;
72
    }
73
74
    bool visitBinary(Visit, TIntermBinary *) override
75
    {
76
        nodeType = NodeType::Binary;
77
        return false;
78
    }
79
80
    bool visitUnary(Visit, TIntermUnary *) override
81
    {
82
        nodeType = NodeType::Unary;
83
        return false;
84
    }
85
86
    bool visitTernary(Visit, TIntermTernary *) override
87
    {
88
        nodeType = NodeType::Ternary;
89
        return false;
90
    }
91
92
    bool visitIfElse(Visit, TIntermIfElse *) override
93
    {
94
        nodeType = NodeType::IfElse;
95
        return false;
96
    }
97
98
    bool visitSwitch(Visit, TIntermSwitch *) override
99
    {
100
        nodeType = NodeType::Switch;
101
        return false;
102
    }
103
104
    bool visitCase(Visit, TIntermCase *) override
105
    {
106
        nodeType = NodeType::Case;
107
        return false;
108
    }
109
110
    bool visitFunctionDefinition(Visit, TIntermFunctionDefinition *) override
111
    {
112
        nodeType = NodeType::FunctionDefinition;
113
        return false;
114
    }
115
116
    bool visitAggregate(Visit, TIntermAggregate *) override
117
    {
118
        nodeType = NodeType::Aggregate;
119
        return false;
120
    }
121
122
    bool visitBlock(Visit, TIntermBlock *) override
123
    {
124
        nodeType = NodeType::Block;
125
        return false;
126
    }
127
128
    bool visitGlobalQualifierDeclaration(Visit, TIntermGlobalQualifierDeclaration *) override
129
    {
130
        nodeType = NodeType::GlobalQualifierDeclaration;
131
        return false;
132
    }
133
134
    bool visitDeclaration(Visit, TIntermDeclaration *) override
135
    {
136
        nodeType = NodeType::Declaration;
137
        return false;
138
    }
139
140
    bool visitLoop(Visit, TIntermLoop *) override
141
    {
142
        nodeType = NodeType::Loop;
143
        return false;
144
    }
145
146
    bool visitBranch(Visit, TIntermBranch *) override
147
    {
148
        nodeType = NodeType::Branch;
149
        return false;
150
    }
151
};
152
153
}  // namespace sh
154
155
#endif  // COMPILER_TRANSLATOR_TREEUTIL_NODETYPE_H_
- a/Source/ThirdParty/ANGLE/src/compiler/translator/util.cpp +4 lines
Lines 804-809 bool IsOutputMetal(ShShaderOutput output) a/Source/ThirdParty/ANGLE/src/compiler/translator/util.cpp_sec1
804
{
804
{
805
    return output == SH_GLSL_METAL_OUTPUT;
805
    return output == SH_GLSL_METAL_OUTPUT;
806
}
806
}
807
bool IsOutputMetalDirect(ShShaderOutput output)
808
{
809
    return output == SH_MSL_METAL_OUTPUT;
810
}
807
811
808
bool IsInShaderStorageBlock(TIntermTyped *node)
812
bool IsInShaderStorageBlock(TIntermTyped *node)
809
{
813
{
- a/Source/ThirdParty/ANGLE/src/compiler/translator/util.h +1 lines
Lines 77-82 bool IsOutputGLSL(ShShaderOutput output); a/Source/ThirdParty/ANGLE/src/compiler/translator/util.h_sec1
77
bool IsOutputHLSL(ShShaderOutput output);
77
bool IsOutputHLSL(ShShaderOutput output);
78
bool IsOutputVulkan(ShShaderOutput output);
78
bool IsOutputVulkan(ShShaderOutput output);
79
bool IsOutputMetal(ShShaderOutput output);
79
bool IsOutputMetal(ShShaderOutput output);
80
bool IsOutputMetalDirect(ShShaderOutput output);
80
81
81
bool IsInShaderStorageBlock(TIntermTyped *node);
82
bool IsInShaderStorageBlock(TIntermTyped *node);
82
83
- a/Source/ThirdParty/ANGLE/src/gpu_info_util/SystemInfo_apple.mm -2 / +20 lines
Lines 1-5 a/Source/ThirdParty/ANGLE/src/gpu_info_util/SystemInfo_apple.mm_sec1
1
//
1
//
2
// Copyright 2020 The ANGLE Project Authors. All rights reserved.
2
// Copyright 2020 Apple, Inc. All rights reserved.
3
// Use of this source code is governed by a BSD-style license that can be
3
// Use of this source code is governed by a BSD-style license that can be
4
// found in the LICENSE file.
4
// found in the LICENSE file.
5
//
5
//
Lines 19-25 namespace angle a/Source/ThirdParty/ANGLE/src/gpu_info_util/SystemInfo_apple.mm_sec2
19
19
20
bool GetSystemInfo(SystemInfo *info)
20
bool GetSystemInfo(SystemInfo *info)
21
{
21
{
22
#if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
22
#    if defined(ANGLE_PLATFORM_MACCATALYST) && defined(ANGLE_CPU_ARM64)
23
    static bool isiOSAppOnMac = false;
24
    static dispatch_once_t once;
25
    dispatch_once(&once, ^{
26
      isiOSAppOnMac = [[NSProcessInfo processInfo] isiOSAppOnMac];
27
    });
28
29
    if (isiOSAppOnMac)
30
    {
31
        GetSystemInfo_ios(info);
32
        if (info)
33
        {
34
            info->isiOSAppOnMac = true;
35
        }
36
        return info;
37
    }
38
39
    return GetSystemInfo_mac(info);
40
#    elif defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
23
    return GetSystemInfo_mac(info);
41
    return GetSystemInfo_mac(info);
24
#    else
42
#    else
25
    return GetSystemInfo_ios(info);
43
    return GetSystemInfo_ios(info);
- a/Source/ThirdParty/ANGLE/src/gpu_info_util/SystemInfo_ios.cpp -2 / +9 lines
Lines 18-26 namespace angle a/Source/ThirdParty/ANGLE/src/gpu_info_util/SystemInfo_ios.cpp_sec1
18
bool GetSystemInfo_ios(SystemInfo *info)
18
bool GetSystemInfo_ios(SystemInfo *info)
19
{
19
{
20
    {
20
    {
21
        // TODO(anglebug.com/4275): Get the actual system version and GPU info.
21
        //        GPUDeviceInfo deviceInfo;
22
        //        deviceInfo.vendorId      = kVendorID_Apple;
23
        //        deviceInfo.deviceId      = 0;
24
        //        deviceInfo.driverVendor  = "Apple";
25
        //        deviceInfo.driverVersion = "0.0";
26
        //        deviceInfo.driverDate    = "1/1/1970";
27
28
        // TODO(anglebug.com/4275): Get the actual system version.
22
        info->machineModelVersion = "0.0";
29
        info->machineModelVersion = "0.0";
23
        info->gpus.emplace_back().vendorId = kVendorID_Apple;
30
        // info->gpus.push_back(deviceInfo);
24
    }
31
    }
25
32
26
    return true;
33
    return true;
- a/Source/ThirdParty/ANGLE/src/libANGLE/Caps.cpp -12 / +1 lines
Lines 170-177 static bool GetFormatSupportBase(const TextureCapsMap &textureCaps, a/Source/ThirdParty/ANGLE/src/libANGLE/Caps.cpp_sec1
170
{
170
{
171
    for (size_t i = 0; i < requiredFormatsSize; i++)
171
    for (size_t i = 0; i < requiredFormatsSize; i++)
172
    {
172
    {
173
        const TextureCaps &cap = textureCaps.get(requiredFormats[i]);
174
173
174
        const TextureCaps &cap = textureCaps.get(requiredFormats[i]);
175
        if (requiresTexturing && !cap.texturable)
175
        if (requiresTexturing && !cap.texturable)
176
        {
176
        {
177
            return false;
177
            return false;
Lines 462-468 static bool DetermineASTCLDRTextureSupport(const TextureCapsMap &textureCaps) a/Source/ThirdParty/ANGLE/src/libANGLE/Caps.cpp_sec2
462
        GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR,  GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR,
462
        GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR,  GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR,
463
        GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR,
463
        GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR,
464
    };
464
    };
465
466
    return GetFormatSupport(textureCaps, requiredFormats, true, true, false, false, false);
465
    return GetFormatSupport(textureCaps, requiredFormats, true, true, false, false, false);
467
}
466
}
468
467
Lines 630-641 static bool DetermineDepthTextureANGLESupport(const TextureCapsMap &textureCaps) a/Source/ThirdParty/ANGLE/src/libANGLE/Caps.cpp_sec3
630
{
629
{
631
    constexpr GLenum requiredFormats[] = {
630
    constexpr GLenum requiredFormats[] = {
632
        GL_DEPTH_COMPONENT16,
631
        GL_DEPTH_COMPONENT16,
633
#if !defined(ANGLE_PLATFORM_IOS) && (!defined(ANGLE_PLATFORM_MACCATALYST) || !defined(ANGLE_CPU_ARM64))
634
        // TODO(dino): Temporarily Removing the need for GL_DEPTH_COMPONENT32_OES
635
        // because it is not supported on iOS.
636
        // TODO(dino): I think this needs to be a runtime check when running an iOS app on Mac.
637
        GL_DEPTH_COMPONENT32_OES,
632
        GL_DEPTH_COMPONENT32_OES,
638
#endif
639
        GL_DEPTH24_STENCIL8_OES,
633
        GL_DEPTH24_STENCIL8_OES,
640
    };
634
    };
641
635
Lines 647-658 static bool DetermineDepthTextureOESSupport(const TextureCapsMap &textureCaps) a/Source/ThirdParty/ANGLE/src/libANGLE/Caps.cpp_sec4
647
{
641
{
648
    constexpr GLenum requiredFormats[] = {
642
    constexpr GLenum requiredFormats[] = {
649
        GL_DEPTH_COMPONENT16,
643
        GL_DEPTH_COMPONENT16,
650
#if !defined(ANGLE_PLATFORM_IOS) && (!defined(ANGLE_PLATFORM_MACCATALYST) || !defined(ANGLE_CPU_ARM64))
651
        // TODO(dino): Temporarily Removing the need for GL_DEPTH_COMPONENT32_OES
652
        // because it is not supported on iOS.
653
        // TODO(dino): I think this needs to be a runtime check when running an iOS app on Mac.
654
        GL_DEPTH_COMPONENT32_OES,
644
        GL_DEPTH_COMPONENT32_OES,
655
#endif
656
    };
645
    };
657
646
658
    return GetFormatSupport(textureCaps, requiredFormats, true, true, true, true, false);
647
    return GetFormatSupport(textureCaps, requiredFormats, true, true, true, true, false);
- a/Source/ThirdParty/ANGLE/src/libANGLE/Display.cpp +47 lines
Lines 181-187 EGLAttrib GetDisplayTypeFromEnvironment() a/Source/ThirdParty/ANGLE/src/libANGLE/Display.cpp_sec1
181
        return EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE;
181
        return EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE;
182
    }
182
    }
183
#endif
183
#endif
184
#if defined(ANGLE_ENABLE_METAL)
185
    if (angleDefaultEnv == "metal")
186
    {
187
        return EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE;
188
    }
184
189
190
#endif
185
#if defined(ANGLE_ENABLE_D3D11)
191
#if defined(ANGLE_ENABLE_D3D11)
186
    return EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE;
192
    return EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE;
187
#elif defined(ANGLE_ENABLE_D3D9)
193
#elif defined(ANGLE_ENABLE_D3D9)
Lines 1325-1330 Error Display::makeCurrent(gl::Context *previousContext, a/Source/ThirdParty/ANGLE/src/libANGLE/Display.cpp_sec2
1325
    return NoError();
1331
    return NoError();
1326
}
1332
}
1327
1333
1334
Error Display::makeCurrent(const Thread *thread,
1335
                           egl::Surface *drawSurface,
1336
                           egl::Surface *readSurface,
1337
                           gl::Context *context)
1338
{
1339
    if (!mInitialized)
1340
    {
1341
        return NoError();
1342
    }
1343
1344
    gl::Context *previousContext = thread->getContext();
1345
    if (previousContext)
1346
    {
1347
        ANGLE_TRY(previousContext->unMakeCurrent(this));
1348
    }
1349
1350
    ANGLE_TRY(mImplementation->makeCurrent(this, drawSurface, readSurface, context));
1351
1352
    if (context != nullptr)
1353
    {
1354
        ANGLE_TRY(context->makeCurrent(this, drawSurface, readSurface));
1355
    }
1356
1357
    // Tick all the scratch buffers to make sure they get cleaned up eventually if they stop being
1358
    // used.
1359
    {
1360
        std::lock_guard<std::mutex> lock(mScratchBufferMutex);
1361
1362
        for (angle::ScratchBuffer &scatchBuffer : mScratchBuffers)
1363
        {
1364
            scatchBuffer.tick();
1365
        }
1366
        for (angle::ScratchBuffer &zeroFilledBuffer : mZeroFilledBuffers)
1367
        {
1368
            zeroFilledBuffer.tick();
1369
        }
1370
    }
1371
1372
    return NoError();
1373
}
1374
1328
Error Display::restoreLostDevice()
1375
Error Display::restoreLostDevice()
1329
{
1376
{
1330
    for (ContextSet::iterator ctx = mContextSet.begin(); ctx != mContextSet.end(); ctx++)
1377
    for (ContextSet::iterator ctx = mContextSet.begin(); ctx != mContextSet.end(); ctx++)
- a/Source/ThirdParty/ANGLE/src/libANGLE/Display.h +5 lines
Lines 166-171 class Display final : public LabeledObject, a/Source/ThirdParty/ANGLE/src/libANGLE/Display.h_sec1
166
                        const AttributeMap &attribs,
166
                        const AttributeMap &attribs,
167
                        gl::Context **outContext);
167
                        gl::Context **outContext);
168
168
169
    Error makeCurrent(const Thread *thread,
170
                      Surface *drawSurface,
171
                      Surface *readSurface,
172
                      gl::Context *context);
173
169
    Error createSync(const gl::Context *currentContext,
174
    Error createSync(const gl::Context *currentContext,
170
                     EGLenum type,
175
                     EGLenum type,
171
                     const AttributeMap &attribs,
176
                     const AttributeMap &attribs,
- a/Source/ThirdParty/ANGLE/src/libANGLE/Program.h +5 lines
Lines 276-281 class ProgramState final : angle::NonCopyable a/Source/ThirdParty/ANGLE/src/libANGLE/Program.h_sec1
276
    {
276
    {
277
        return mExecutable->getLinkedTransformFeedbackVaryings();
277
        return mExecutable->getLinkedTransformFeedbackVaryings();
278
    }
278
    }
279
    void setLinkedTransformFeedbackVaryings(
280
        const std::vector<TransformFeedbackVarying> _mLinkedTransformFeedbackVaryings) const
281
    {
282
        return mExecutable->setLinkedTransformFeedbackVaryings(_mLinkedTransformFeedbackVaryings);
283
    }
279
    const std::vector<GLsizei> &getTransformFeedbackStrides() const
284
    const std::vector<GLsizei> &getTransformFeedbackStrides() const
280
    {
285
    {
281
        return mExecutable->getTransformFeedbackStrides();
286
        return mExecutable->getTransformFeedbackStrides();
- a/Source/ThirdParty/ANGLE/src/libANGLE/ProgramExecutable.h +5 lines
Lines 229-234 class ProgramExecutable final : public angle::Subject a/Source/ThirdParty/ANGLE/src/libANGLE/ProgramExecutable.h_sec1
229
    {
229
    {
230
        return mLinkedTransformFeedbackVaryings;
230
        return mLinkedTransformFeedbackVaryings;
231
    }
231
    }
232
    void setLinkedTransformFeedbackVaryings(
233
        const std::vector<TransformFeedbackVarying> _mLinkedTransformFeedbackVaryings)
234
    {
235
        mLinkedTransformFeedbackVaryings = _mLinkedTransformFeedbackVaryings;
236
    }
232
    GLint getTransformFeedbackBufferMode() const { return mTransformFeedbackBufferMode; }
237
    GLint getTransformFeedbackBufferMode() const { return mTransformFeedbackBufferMode; }
233
    GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const
238
    GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const
234
    {
239
    {
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/driver_utils.cpp -1 / +9 lines
Lines 205-211 bool operator>=(const OSVersion &a, const OSVersion &b) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/driver_utils.cpp_sec1
205
           std::tie(b.majorVersion, b.minorVersion, b.patchVersion);
205
           std::tie(b.majorVersion, b.minorVersion, b.patchVersion);
206
}
206
}
207
207
208
#if !defined(ANGLE_PLATFORM_APPLE)
208
#if !defined(ANGLE_PLATFORM_MACOS)
209
OSVersion GetMacOSVersion()
209
OSVersion GetMacOSVersion()
210
{
210
{
211
    // Return a default version
211
    // Return a default version
Lines 213-218 OSVersion GetMacOSVersion() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/driver_utils.cpp_sec2
213
}
213
}
214
#endif
214
#endif
215
215
216
#if !defined(ANGLE_PLATFORM_IOS)
217
OSVersion GetiOSVersion()
218
{
219
    // Return a default version
220
    return OSVersion(0, 0, 0);
221
}
222
#endif
223
216
#if defined(ANGLE_PLATFORM_LINUX)
224
#if defined(ANGLE_PLATFORM_LINUX)
217
bool ParseLinuxOSVersion(const char *version, int *major, int *minor, int *patch)
225
bool ParseLinuxOSVersion(const char *version, int *major, int *minor, int *patch)
218
{
226
{
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/driver_utils.h +11 lines
Lines 167-172 inline bool IsApple() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/driver_utils.h_sec1
167
#endif
167
#endif
168
}
168
}
169
169
170
inline bool IsMac()
171
{
172
#if defined(ANGLE_PLATFORM_APPLE) && defined(ANGLE_PLATFORM_MACOS)
173
    return true;
174
#else
175
    return false;
176
#endif
177
}
178
170
inline bool IsFuchsia()
179
inline bool IsFuchsia()
171
{
180
{
172
#if defined(ANGLE_PLATFORM_FUCHSIA)
181
#if defined(ANGLE_PLATFORM_FUCHSIA)
Lines 204-209 bool operator>=(const OSVersion &a, const OSVersion &b); a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/driver_utils.h_sec2
204
213
205
OSVersion GetMacOSVersion();
214
OSVersion GetMacOSVersion();
206
215
216
OSVersion GetiOSVersion();
217
207
OSVersion GetLinuxOSVersion();
218
OSVersion GetLinuxOSVersion();
208
219
209
inline bool IsAndroid()
220
inline bool IsAndroid()
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/driver_utils_ios.mm +28 lines
Line 0 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/driver_utils_ios.mm_sec1
1
//
2
// Copyright 2019 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
7
// driver_utils_ios.mm : provides ios-specific information about current driver.
8
9
#include "libANGLE/renderer/driver_utils.h"
10
11
#import <Foundation/Foundation.h>
12
13
namespace rx
14
{
15
16
OSVersion GetiOSVersion()
17
{
18
    OSVersion result;
19
20
    NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion];
21
    result.majorVersion              = static_cast<int>(version.majorVersion);
22
    result.minorVersion              = static_cast<int>(version.minorVersion);
23
    result.patchVersion              = static_cast<int>(version.patchVersion);
24
25
    return result;
26
}
27
28
}
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/driver_utils_mac.mm -1 / +2 lines
Lines 13-18 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/driver_utils_mac.mm_sec1
13
namespace rx
13
namespace rx
14
{
14
{
15
15
16
#if defined(ANGLE_PLATFORM_MACOS)
16
OSVersion GetMacOSVersion()
17
OSVersion GetMacOSVersion()
17
{
18
{
18
    OSVersion result;
19
    OSVersion result;
Lines 24-28 OSVersion GetMacOSVersion() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/driver_utils_mac.mm_sec2
24
25
25
    return result;
26
    return result;
26
}
27
}
27
28
#endif
28
}
29
}
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/SoftLinking_apple.h +112 lines
Line 0 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/SoftLinking_apple.h_sec1
1
//
2
// Copyright 2020 Apple, Inc. 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
7
// SoftLinking_apple.cpp: Macros for soft-linking Frameworks and Functions.
8
9
#ifndef SOFT_LINKING_APPLE_H_
10
#define SOFT_LINKING_APPLE_H_
11
12
#include "common/platform.h"
13
14
#if defined(ANGLE_PLATFORM_APPLE)
15
16
#    include "common/debug.h"
17
18
#    import <dispatch/dispatch.h>
19
#    import <dlfcn.h>
20
#    import <objc/runtime.h>
21
22
#    define RELEASE_ASSERT(expression, message)                                               \
23
        (expression                                                                           \
24
             ? static_cast<void>(0)                                                           \
25
             : (FATAL() << "\t! Assert failed in " << __FUNCTION__ << " (" << __FILE__ << ":" \
26
                        << __LINE__ << "): " << #expression << "\n\t! Message: " << message))
27
28
#    ifdef __cplusplus
29
#        define EXTERN_C_BEGIN extern "C" {
30
#        define EXTERN_C_END }
31
#    else
32
#        define EXTERN_C_BEGIN
33
#        define EXTERN_C_END
34
#    endif
35
36
#    define SOFT_LINK_FRAMEWORK_HEADER(framework) extern void *framework##Library();
37
38
#    define SOFT_LINK_FRAMEWORK_SOURCE(framework)                                               \
39
        void *framework##Library()                                                              \
40
        {                                                                                       \
41
            static dispatch_once_t once   = 0;                                                  \
42
            static void *frameworkLibrary = NULL;                                               \
43
            dispatch_once(&once, ^{                                                             \
44
              frameworkLibrary = dlopen(                                                        \
45
                  "/System/Library/Frameworks/" #framework ".framework/" #framework, RTLD_NOW); \
46
              RELEASE_ASSERT(frameworkLibrary, "Unable to load " #framework ".framework");      \
47
            });                                                                                 \
48
            return frameworkLibrary;                                                            \
49
        }
50
51
#    define SOFT_LINK_FUNCTION_HEADER(framework, functionName, resultType, parameterDeclarations, \
52
                                      parameterNames)                                             \
53
        EXTERN_C_BEGIN                                                                            \
54
        resultType functionName parameterDeclarations;                                            \
55
        EXTERN_C_END                                                                              \
56
        extern resultType init##framework##functionName parameterDeclarations;                    \
57
        extern resultType(*softLink##framework##functionName) parameterDeclarations;              \
58
        inline __attribute__((__always_inline__)) resultType functionName parameterDeclarations   \
59
        {                                                                                         \
60
            return softLink##framework##functionName parameterNames;                              \
61
        }
62
63
#    define SOFT_LINK_FUNCTION_SOURCE(framework, functionName, resultType, parameterDeclarations,  \
64
                                      parameterNames)                                              \
65
        resultType(*softLink##framework##functionName) parameterDeclarations =                     \
66
            init##framework##functionName;                                                         \
67
        resultType init##framework##functionName parameterDeclarations                             \
68
        {                                                                                          \
69
            static dispatch_once_t once;                                                           \
70
            dispatch_once(&once, ^{                                                                \
71
              softLink##framework##functionName =                                                  \
72
                  (resultType(*) parameterDeclarations)dlsym(framework##Library(), #functionName); \
73
            });                                                                                    \
74
            return softLink##framework##functionName parameterNames;                               \
75
        }
76
77
#    define SOFT_LINK_CLASS_HEADER(className)    \
78
        @class className;                        \
79
        extern Class (*get##className##Class)(); \
80
        className *alloc##className##Instance(); \
81
        inline className *alloc##className##Instance() { return [get##className##Class() alloc]; }
82
83
#    define SOFT_LINK_CLASS(framework, className)                                       \
84
        @class className;                                                               \
85
        static Class init##className();                                                 \
86
        Class (*get##className##Class)() = init##className;                             \
87
        static Class class##className;                                                  \
88
                                                                                        \
89
        static Class className##Function() { return class##className; }                 \
90
                                                                                        \
91
        static Class init##className()                                                  \
92
        {                                                                               \
93
            static dispatch_once_t once;                                                \
94
            dispatch_once(&once, ^{                                                     \
95
              framework##Library();                                                     \
96
              class##className = objc_getClass(#className);                             \
97
              RELEASE_ASSERT(class##className, "objc_getClass failed for " #className); \
98
              get##className##Class = className##Function;                              \
99
            });                                                                         \
100
            return class##className;                                                    \
101
        }                                                                               \
102
        _Pragma("clang diagnostic push")                                                \
103
            _Pragma("clang diagnostic ignored \"-Wunused-function\"") static className  \
104
                *alloc##className##Instance()                                           \
105
        {                                                                               \
106
            return [get##className##Class() alloc];                                     \
107
        }                                                                               \
108
        _Pragma("clang diagnostic pop")
109
110
#endif  // defined(ANGLE_PLATFORM_APPLE)
111
112
#endif  // SOFT_LINKING_APPLE_H_
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/cgl/CGLFunctions.cpp +77 lines
Line 0 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/cgl/CGLFunctions.cpp_sec1
1
//
2
// Copyright 2020 Apple, Inc. 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
7
// CGLFunctions.cpp: Exposing the soft-linked CGL interface.
8
9
#include "libANGLE/renderer/gl/cgl/CGLFunctions.h"
10
#include "common/platform.h"
11
12
#if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
13
14
SOFT_LINK_FRAMEWORK_SOURCE(OpenGL)
15
16
SOFT_LINK_FUNCTION_SOURCE(OpenGL,
17
                          CGLChoosePixelFormat,
18
                          CGLError,
19
                          (const CGLPixelFormatAttribute *attribs,
20
                           CGLPixelFormatObj *pix,
21
                           GLint *npix),
22
                          (attribs, pix, npix))
23
SOFT_LINK_FUNCTION_SOURCE(OpenGL,
24
                          CGLCreateContext,
25
                          CGLError,
26
                          (CGLPixelFormatObj pix, CGLContextObj share, CGLContextObj *ctx),
27
                          (pix, share, ctx))
28
SOFT_LINK_FUNCTION_SOURCE(
29
    OpenGL,
30
    CGLDescribePixelFormat,
31
    CGLError,
32
    (CGLPixelFormatObj pix, GLint pix_num, CGLPixelFormatAttribute attrib, GLint *value),
33
    (pix, pix_num, attrib, value))
34
SOFT_LINK_FUNCTION_SOURCE(OpenGL, CGLDestroyContext, CGLError, (CGLContextObj ctx), (ctx))
35
SOFT_LINK_FUNCTION_SOURCE(OpenGL, CGLDestroyPixelFormat, CGLError, (CGLPixelFormatObj pix), (pix))
36
SOFT_LINK_FUNCTION_SOURCE(OpenGL, CGLErrorString, const char *, (CGLError error), (error))
37
SOFT_LINK_FUNCTION_SOURCE(OpenGL, CGLReleaseContext, void, (CGLContextObj ctx), (ctx))
38
SOFT_LINK_FUNCTION_SOURCE(OpenGL, CGLSetCurrentContext, CGLError, (CGLContextObj ctx), (ctx))
39
SOFT_LINK_FUNCTION_SOURCE(OpenGL,
40
                          CGLSetVirtualScreen,
41
                          CGLError,
42
                          (CGLContextObj ctx, GLint screen),
43
                          (ctx, screen))
44
SOFT_LINK_FUNCTION_SOURCE(
45
    OpenGL,
46
    CGLTexImageIOSurface2D,
47
    CGLError,
48
    (CGLContextObj ctx,
49
     GLenum target,
50
     GLenum internal_format,
51
     GLsizei width,
52
     GLsizei height,
53
     GLenum format,
54
     GLenum type,
55
     IOSurfaceRef ioSurface,
56
     GLuint plane),
57
    (ctx, target, internal_format, width, height, format, type, ioSurface, plane))
58
SOFT_LINK_FUNCTION_SOURCE(OpenGL, CGLUpdateContext, CGLError, (CGLContextObj ctx), (ctx))
59
60
SOFT_LINK_FUNCTION_SOURCE(
61
    OpenGL,
62
    CGLDescribeRenderer,
63
    CGLError,
64
    (CGLRendererInfoObj rend, GLint rend_num, CGLRendererProperty prop, GLint *value),
65
    (rend, rend_num, prop, value))
66
SOFT_LINK_FUNCTION_SOURCE(OpenGL,
67
                          CGLDestroyRendererInfo,
68
                          CGLError,
69
                          (CGLRendererInfoObj rend),
70
                          (rend))
71
SOFT_LINK_FUNCTION_SOURCE(OpenGL,
72
                          CGLQueryRendererInfo,
73
                          CGLError,
74
                          (GLuint display_mask, CGLRendererInfoObj *rend, GLint *nrend),
75
                          (display_mask, rend, nrend))
76
77
#endif  // defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/cgl/CGLFunctions.h +84 lines
Line 0 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/cgl/CGLFunctions.h_sec1
1
//
2
// Copyright 2020 Apple, Inc. 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
7
// CGLFunctions.h: Exposing the soft-linked CGL interface.
8
9
#ifndef CGL_FUNCTIONS_H_
10
#define CGL_FUNCTIONS_H_
11
12
#include "common/platform.h"
13
14
#if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
15
16
#    include <OpenGL/OpenGL.h>
17
18
#    include "libANGLE/renderer/gl/SoftLinking_apple.h"
19
20
SOFT_LINK_FRAMEWORK_HEADER(OpenGL)
21
22
SOFT_LINK_FUNCTION_HEADER(OpenGL,
23
                          CGLChoosePixelFormat,
24
                          CGLError,
25
                          (const CGLPixelFormatAttribute *attribs,
26
                           CGLPixelFormatObj *pix,
27
                           GLint *npix),
28
                          (attribs, pix, npix))
29
SOFT_LINK_FUNCTION_HEADER(OpenGL,
30
                          CGLCreateContext,
31
                          CGLError,
32
                          (CGLPixelFormatObj pix, CGLContextObj share, CGLContextObj *ctx),
33
                          (pix, share, ctx))
34
SOFT_LINK_FUNCTION_HEADER(
35
    OpenGL,
36
    CGLDescribePixelFormat,
37
    CGLError,
38
    (CGLPixelFormatObj pix, GLint pix_num, CGLPixelFormatAttribute attrib, GLint *value),
39
    (pix, pix_num, attrib, value))
40
SOFT_LINK_FUNCTION_HEADER(
41
    OpenGL,
42
    CGLDescribeRenderer,
43
    CGLError,
44
    (CGLRendererInfoObj rend, GLint rend_num, CGLRendererProperty prop, GLint *value),
45
    (rend, rend_num, prop, value))
46
SOFT_LINK_FUNCTION_HEADER(OpenGL, CGLDestroyContext, CGLError, (CGLContextObj ctx), (ctx))
47
SOFT_LINK_FUNCTION_HEADER(OpenGL, CGLDestroyPixelFormat, CGLError, (CGLPixelFormatObj pix), (pix))
48
SOFT_LINK_FUNCTION_HEADER(OpenGL,
49
                          CGLDestroyRendererInfo,
50
                          CGLError,
51
                          (CGLRendererInfoObj rend),
52
                          (rend))
53
SOFT_LINK_FUNCTION_HEADER(OpenGL, CGLErrorString, const char *, (CGLError error), (error))
54
SOFT_LINK_FUNCTION_HEADER(OpenGL,
55
                          CGLQueryRendererInfo,
56
                          CGLError,
57
                          (GLuint display_mask, CGLRendererInfoObj *rend, GLint *nrend),
58
                          (display_mask, rend, nrend))
59
SOFT_LINK_FUNCTION_HEADER(OpenGL, CGLReleaseContext, void, (CGLContextObj ctx), (ctx))
60
SOFT_LINK_FUNCTION_HEADER(OpenGL, CGLSetCurrentContext, CGLError, (CGLContextObj ctx), (ctx))
61
SOFT_LINK_FUNCTION_HEADER(OpenGL,
62
                          CGLSetVirtualScreen,
63
                          CGLError,
64
                          (CGLContextObj ctx, GLint screen),
65
                          (ctx, screen))
66
SOFT_LINK_FUNCTION_HEADER(
67
    OpenGL,
68
    CGLTexImageIOSurface2D,
69
    CGLError,
70
    (CGLContextObj ctx,
71
     GLenum target,
72
     GLenum internal_format,
73
     GLsizei width,
74
     GLsizei height,
75
     GLenum format,
76
     GLenum type,
77
     IOSurfaceRef ioSurface,
78
     GLuint plane),
79
    (ctx, target, internal_format, width, height, format, type, ioSurface, plane))
80
SOFT_LINK_FUNCTION_HEADER(OpenGL, CGLUpdateContext, CGLError, (CGLContextObj ctx), (ctx))
81
82
#endif  // defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
83
84
#endif  // CGL_FUNCTIONS_H_
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/cgl/DisplayCGL.mm -4 / +7 lines
Lines 29-34 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/cgl/DisplayCGL.mm_sec1
29
#    include "libANGLE/renderer/gl/cgl/WindowSurfaceCGL.h"
29
#    include "libANGLE/renderer/gl/cgl/WindowSurfaceCGL.h"
30
#    include "platform/PlatformMethods.h"
30
#    include "platform/PlatformMethods.h"
31
31
32
#    include "libANGLE/renderer/gl/cgl/CGLFunctions.h"
33
32
namespace
34
namespace
33
{
35
{
34
36
Lines 163-171 egl::Error DisplayCGL::initialize(egl::Display *display) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/cgl/DisplayCGL.mm_sec2
163
    mEGLDisplay = display;
165
    mEGLDisplay = display;
164
166
165
    angle::SystemInfo info;
167
    angle::SystemInfo info;
166
    // It's legal for GetSystemInfo to return false and thereby
168
    if (!angle::GetSystemInfo(&info))
167
    // contain incomplete information.
169
    {
168
    (void)angle::GetSystemInfo(&info);
170
        return egl::EglNotInitialized() << "Unable to query ANGLE's SystemInfo.";
171
    }
169
172
170
    // This code implements the effect of the
173
    // This code implements the effect of the
171
    // disableGPUSwitchingSupport workaround in FeaturesGL.
174
    // disableGPUSwitchingSupport workaround in FeaturesGL.
Lines 440-446 egl::Error DisplayCGL::restoreLostDevice(const egl::Display *display) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/cgl/DisplayCGL.mm_sec3
440
443
441
bool DisplayCGL::isValidNativeWindow(EGLNativeWindowType window) const
444
bool DisplayCGL::isValidNativeWindow(EGLNativeWindowType window) const
442
{
445
{
443
    NSObject *layer = (__bridge NSObject *)window;
446
    NSObject *layer = reinterpret_cast<NSObject *>(window);
444
    return [layer isKindOfClass:[CALayer class]];
447
    return [layer isKindOfClass:[CALayer class]];
445
}
448
}
446
449
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/eagl/DisplayEAGL.mm -7 / +10 lines
Lines 27-32 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/eagl/DisplayEAGL.mm_sec1
27
#    import <QuartzCore/QuartzCore.h>
27
#    import <QuartzCore/QuartzCore.h>
28
#    import <dlfcn.h>
28
#    import <dlfcn.h>
29
29
30
#    import "libANGLE/renderer/gl/eagl/EAGLFunctions.h"
31
30
namespace
32
namespace
31
{
33
{
32
34
Lines 64-72 egl::Error DisplayEAGL::initialize(egl::Display *display) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/eagl/DisplayEAGL.mm_sec2
64
    mEGLDisplay = display;
66
    mEGLDisplay = display;
65
67
66
    angle::SystemInfo info;
68
    angle::SystemInfo info;
67
    // It's legal for GetSystemInfo to return false and thereby
69
    if (!angle::GetSystemInfo(&info))
68
    // contain incomplete information.
70
    {
69
    (void)angle::GetSystemInfo(&info);
71
        return egl::EglNotInitialized() << "Unable to query ANGLE's SystemInfo.";
72
    }
70
73
71
    mContext = [allocEAGLContextInstance() initWithAPI:kEAGLRenderingAPIOpenGLES3];
74
    mContext = [allocEAGLContextInstance() initWithAPI:kEAGLRenderingAPIOpenGLES3];
72
    if (mContext == nullptr)
75
    if (mContext == nullptr)
Lines 113-118 void DisplayEAGL::terminate() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/eagl/DisplayEAGL.mm_sec3
113
    if (mContext != nullptr)
116
    if (mContext != nullptr)
114
    {
117
    {
115
        [getEAGLContextClass() setCurrentContext:nil];
118
        [getEAGLContextClass() setCurrentContext:nil];
119
        [mContext release];
116
        mContext = nullptr;
120
        mContext = nullptr;
117
        mThreadsWithContextCurrent.clear();
121
        mThreadsWithContextCurrent.clear();
118
    }
122
    }
Lines 275-281 egl::Error DisplayEAGL::restoreLostDevice(const egl::Display *display) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/eagl/DisplayEAGL.mm_sec4
275
279
276
bool DisplayEAGL::isValidNativeWindow(EGLNativeWindowType window) const
280
bool DisplayEAGL::isValidNativeWindow(EGLNativeWindowType window) const
277
{
281
{
278
    NSObject *layer = (__bridge NSObject *)window;
282
    NSObject *layer = reinterpret_cast<NSObject *>(window);
279
    return [layer isKindOfClass:[CALayer class]];
283
    return [layer isKindOfClass:[CALayer class]];
280
}
284
}
281
285
Lines 311-319 void DisplayEAGL::generateExtensions(egl::DisplayExtensions *outExtensions) cons a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/eagl/DisplayEAGL.mm_sec5
311
    outExtensions->surfacelessContext    = true;
315
    outExtensions->surfacelessContext    = true;
312
    outExtensions->deviceQuery           = true;
316
    outExtensions->deviceQuery           = true;
313
317
314
    // Contexts are virtualized so textures ans semaphores can be shared globally
318
    // Contexts are virtualized so textures can be shared globally
315
    outExtensions->displayTextureShareGroup   = true;
319
    outExtensions->displayTextureShareGroup = true;
316
    outExtensions->displaySemaphoreShareGroup = true;
317
320
318
    outExtensions->powerPreference = false;
321
    outExtensions->powerPreference = false;
319
322
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/eagl/EAGLFunctions.h +30 lines
Line 0 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/eagl/EAGLFunctions.h_sec1
1
//
2
// Copyright 2020 Apple, Inc. 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
7
// EAGLFunctions.h: Exposing the soft-linked EAGL interface.
8
9
#ifndef EAGL_FUNCTIONS_H_
10
#define EAGL_FUNCTIONS_H_
11
12
#include "common/platform.h"
13
14
#if (defined(ANGLE_PLATFORM_IOS) && !defined(ANGLE_PLATFORM_MACCATALYST)) || \
15
    (defined(ANGLE_PLATFORM_MACCATALYST) && defined(ANGLE_CPU_ARM64))
16
17
#    import <OpenGLES/EAGL.h>
18
#    import <OpenGLES/EAGLDrawable.h>
19
#    import <OpenGLES/EAGLIOSurface.h>
20
21
#    include "libANGLE/renderer/gl/SoftLinking_apple.h"
22
23
SOFT_LINK_FRAMEWORK_HEADER(OpenGLES)
24
25
SOFT_LINK_CLASS_HEADER(EAGLContext)
26
27
#endif  // (defined(ANGLE_PLATFORM_IOS) && !defined(ANGLE_PLATFORM_MACCATALYST)) ||
28
        // (defined(ANGLE_PLATFORM_MACCATALYST) && defined(ANGLE_CPU_ARM64))
29
30
#endif  // CGL_FUNCTIONS_H_
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/eagl/EAGLFunctions.mm +25 lines
Line 0 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/eagl/EAGLFunctions.mm_sec1
1
//
2
// Copyright 2020 Apple, Inc. 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
7
// EAGLFunctions.cpp: Exposing the soft-linked EAGL interface.
8
9
#include "common/platform.h"
10
11
#if (defined(ANGLE_PLATFORM_IOS) && !defined(ANGLE_PLATFORM_MACCATALYST)) || \
12
    (defined(ANGLE_PLATFORM_MACCATALYST) && defined(ANGLE_CPU_ARM64))
13
14
#    import <OpenGLES/EAGL.h>
15
#    import <OpenGLES/EAGLDrawable.h>
16
#    import <OpenGLES/EAGLIOSurface.h>
17
18
#    include "libANGLE/renderer/gl/SoftLinking_apple.h"
19
20
SOFT_LINK_FRAMEWORK_SOURCE(OpenGLES)
21
22
SOFT_LINK_CLASS(OpenGLES, EAGLContext)
23
24
#endif  // (defined(ANGLE_PLATFORM_IOS) && !defined(ANGLE_PLATFORM_MACCATALYST)) ||
25
        // (defined(ANGLE_PLATFORM_MACCATALYST) && defined(ANGLE_CPU_ARM64))
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/glslang_wrapper_utils.cpp -10 / +64 lines
Lines 281-290 std::string SubstituteTransformFeedbackMarkers(const std::string &originalSource a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/glslang_wrapper_utils.cpp_sec1
281
                                               const std::string &xfbOut)
281
                                               const std::string &xfbOut)
282
{
282
{
283
    const size_t xfbDeclMarkerStart = originalSource.find(kXfbDeclMarker);
283
    const size_t xfbDeclMarkerStart = originalSource.find(kXfbDeclMarker);
284
    const size_t xfbDeclMarkerEnd   = xfbDeclMarkerStart + ConstStrLen(kXfbDeclMarker);
284
    ASSERT(xfbDeclMarkerStart != std::string::npos);
285
    const size_t xfbDeclMarkerEnd = xfbDeclMarkerStart + ConstStrLen(kXfbDeclMarker);
285
286
286
    const size_t xfbOutMarkerStart = originalSource.find(kXfbOutMarker, xfbDeclMarkerStart);
287
    const size_t xfbOutMarkerStart = originalSource.find(kXfbOutMarker, xfbDeclMarkerStart);
287
    const size_t xfbOutMarkerEnd   = xfbOutMarkerStart + ConstStrLen(kXfbOutMarker);
288
    ASSERT(xfbOutMarkerStart != std::string::npos);
289
    const size_t xfbOutMarkerEnd = xfbOutMarkerStart + ConstStrLen(kXfbOutMarker);
288
290
289
    // The shader is the following form:
291
    // The shader is the following form:
290
    //
292
    //
Lines 362-368 void GenerateTransformFeedbackEmulationOutputs(const GlslangSourceOptions &optio a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/glslang_wrapper_utils.cpp_sec2
362
                                               const gl::ProgramState &programState,
364
                                               const gl::ProgramState &programState,
363
                                               GlslangProgramInterfaceInfo *programInterfaceInfo,
365
                                               GlslangProgramInterfaceInfo *programInterfaceInfo,
364
                                               std::string *vertexShader,
366
                                               std::string *vertexShader,
365
                                               ShaderInterfaceVariableInfoMap *variableInfoMapOut)
367
                                               ShaderInterfaceVariableInfoMap *variableInfoMapOut,
368
                                               bool earlyReturn)
366
{
369
{
367
    const std::vector<gl::TransformFeedbackVarying> &varyings =
370
    const std::vector<gl::TransformFeedbackVarying> &varyings =
368
        programState.getLinkedTransformFeedbackVaryings();
371
        programState.getLinkedTransformFeedbackVaryings();
Lines 413-418 void GenerateTransformFeedbackEmulationOutputs(const GlslangSourceOptions &optio a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/glslang_wrapper_utils.cpp_sec3
413
            outputOffset += info.columnCount * info.rowCount * varying.size();
416
            outputOffset += info.columnCount * info.rowCount * varying.size();
414
        }
417
        }
415
    }
418
    }
419
    if (earlyReturn)
420
    {
421
        xfbOut += "return;";
422
    }
416
    xfbOut += "}\n";
423
    xfbOut += "}\n";
417
424
418
    *vertexShader = SubstituteTransformFeedbackMarkers(*vertexShader, xfbDecl, xfbOut);
425
    *vertexShader = SubstituteTransformFeedbackMarkers(*vertexShader, xfbDecl, xfbOut);
Lines 3368-3378 std::string GlslangGetMappedSamplerName(const std::string &originalName) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/glslang_wrapper_utils.cpp_sec4
3368
    return samplerName;
3375
    return samplerName;
3369
}
3376
}
3370
3377
3371
std::string GetXfbBufferName(const uint32_t bufferIndex)
3372
{
3373
    return "xfbBuffer" + Str(bufferIndex);
3374
}
3375
3376
void GlslangGenTransformFeedbackEmulationOutputs(const GlslangSourceOptions &options,
3378
void GlslangGenTransformFeedbackEmulationOutputs(const GlslangSourceOptions &options,
3377
                                                 const gl::ProgramState &programState,
3379
                                                 const gl::ProgramState &programState,
3378
                                                 GlslangProgramInterfaceInfo *programInterfaceInfo,
3380
                                                 GlslangProgramInterfaceInfo *programInterfaceInfo,
Lines 3380-3386 void GlslangGenTransformFeedbackEmulationOutputs(const GlslangSourceOptions &opt a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/glslang_wrapper_utils.cpp_sec5
3380
                                                 ShaderInterfaceVariableInfoMap *variableInfoMapOut)
3382
                                                 ShaderInterfaceVariableInfoMap *variableInfoMapOut)
3381
{
3383
{
3382
    GenerateTransformFeedbackEmulationOutputs(options, programState, programInterfaceInfo,
3384
    GenerateTransformFeedbackEmulationOutputs(options, programState, programInterfaceInfo,
3383
                                              vertexShader, variableInfoMapOut);
3385
                                              vertexShader, variableInfoMapOut, false);
3384
}
3386
}
3385
3387
3386
void GlslangAssignLocations(const GlslangSourceOptions &options,
3388
void GlslangAssignLocations(const GlslangSourceOptions &options,
Lines 3428-3433 void GlslangAssignLocations(const GlslangSourceOptions &options, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/glslang_wrapper_utils.cpp_sec6
3428
                             variableInfoMapOut);
3430
                             variableInfoMapOut);
3429
}
3431
}
3430
3432
3433
std::string GetXfbBufferName(const uint32_t bufferIndex)
3434
{
3435
    return "xfbBuffer" + Str(bufferIndex);
3436
}
3437
3438
3439
void GlslangAssignLocations(GlslangSourceOptions &options,
3440
                            const gl::ProgramExecutable &programExecutable,
3441
                            const gl::ShaderType shaderType,
3442
                            GlslangProgramInterfaceInfo *programInterfaceInfo,
3443
                            ShaderMapInterfaceVariableInfoMap *variableInfoMapOut)
3444
{
3445
    // Assign outputs to the fragment shader, if any.
3446
    if ((shaderType == gl::ShaderType::Fragment) &&
3447
        programExecutable.hasLinkedShaderStage(gl::ShaderType::Fragment))
3448
    {
3449
        AssignOutputLocations(programExecutable, gl::ShaderType::Fragment,
3450
                              &(*variableInfoMapOut)[gl::ShaderType::Fragment]);
3451
    }
3452
3453
    // Assign attributes to the vertex shader, if any.
3454
    if ((shaderType == gl::ShaderType::Vertex) &&
3455
        programExecutable.hasLinkedShaderStage(gl::ShaderType::Vertex))
3456
    {
3457
        AssignAttributeLocations(programExecutable, gl::ShaderType::Vertex,
3458
                                 &(*variableInfoMapOut)[gl::ShaderType::Vertex]);
3459
    }
3460
3461
    if (!programExecutable.hasLinkedShaderStage(gl::ShaderType::Compute))
3462
    {
3463
        // Assign varying locations.
3464
        AssignVaryingLocations(options, programExecutable, shaderType, programInterfaceInfo,
3465
                               variableInfoMapOut);
3466
3467
        if (!programExecutable.getLinkedTransformFeedbackVaryings().empty() &&
3468
            options.supportsTransformFeedbackExtension && (shaderType == gl::ShaderType::Vertex))
3469
        {
3470
            AssignTransformFeedbackExtensionQualifiers(
3471
                programExecutable, programInterfaceInfo->locationsUsedForXfbExtension,
3472
                gl::ShaderType::Vertex, &(*variableInfoMapOut)[gl::ShaderType::Vertex]);
3473
        }
3474
    }
3475
3476
    AssignUniformBindings(options, programExecutable, shaderType, programInterfaceInfo,
3477
                          variableInfoMapOut);
3478
    AssignTextureBindings(options, programExecutable, shaderType, programInterfaceInfo,
3479
                          variableInfoMapOut);
3480
    AssignNonTextureBindings(options, programExecutable, shaderType, programInterfaceInfo,
3481
                             variableInfoMapOut);
3482
}
3483
3431
void GlslangGetShaderSource(const GlslangSourceOptions &options,
3484
void GlslangGetShaderSource(const GlslangSourceOptions &options,
3432
                            const gl::ProgramState &programState,
3485
                            const gl::ProgramState &programState,
3433
                            const gl::ProgramLinkedResources &resources,
3486
                            const gl::ProgramLinkedResources &resources,
Lines 3462-3468 void GlslangGetShaderSource(const GlslangSourceOptions &options, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/glslang_wrapper_utils.cpp_sec7
3462
            {
3515
            {
3463
                GenerateTransformFeedbackEmulationOutputs(
3516
                GenerateTransformFeedbackEmulationOutputs(
3464
                    options, programState, programInterfaceInfo, vertexSource,
3517
                    options, programState, programInterfaceInfo, vertexSource,
3465
                    &(*variableInfoMapOut)[gl::ShaderType::Vertex]);
3518
                    &(*variableInfoMapOut)[gl::ShaderType::Vertex],
3519
                    options.transformFeedbackEarlyReturn);
3466
            }
3520
            }
3467
            else
3521
            else
3468
            {
3522
            {
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/glslang_wrapper_utils.h +1 lines
Lines 51-56 struct GlslangSourceOptions a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/glslang_wrapper_utils.h_sec1
51
    bool supportsTransformFeedbackExtension = false;
51
    bool supportsTransformFeedbackExtension = false;
52
    bool emulateTransformFeedback           = false;
52
    bool emulateTransformFeedback           = false;
53
    bool emulateBresenhamLines              = false;
53
    bool emulateBresenhamLines              = false;
54
    bool transformFeedbackEarlyReturn       = false;
54
};
55
};
55
56
56
using SpirvBlob = std::vector<uint32_t>;
57
using SpirvBlob = std::vector<uint32_t>;
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/load_functions_data.json +3 lines
Lines 672-677 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/load_functions_data.json_sec1
672
    "D32_FLOAT_S8X24_UINT": {
672
    "D32_FLOAT_S8X24_UINT": {
673
      "GL_UNSIGNED_INT_24_8": "LoadD24S8ToD32FS8X24",
673
      "GL_UNSIGNED_INT_24_8": "LoadD24S8ToD32FS8X24",
674
      "GL_UNSIGNED_INT": "LoadD32ToD32FX32"
674
      "GL_UNSIGNED_INT": "LoadD32ToD32FX32"
675
    },
676
    "D32_FLOAT": {
677
      "GL_UNSIGNED_INT": "LoadD24S8ToD32F"
675
    }
678
    }
676
  },
679
  },
677
  "GL_R32I": {
680
  "GL_R32I": {
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/load_functions_table_autogen.cpp -11 / +19 lines
Lines 446-453 LoadImageFunctionInfo COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGB_UNORM_B a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/load_functions_table_autogen.cpp_sec1
446
    }
446
    }
447
}
447
}
448
448
449
LoadImageFunctionInfo COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2_to_ETC2_R8G8B8A1_UNORM_BLOCK(
449
LoadImageFunctionInfo COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2_to_ETC2_R8G8B8A1_UNORM_BLOCK(GLenum type)
450
    GLenum type)
451
{
450
{
452
    switch (type)
451
    switch (type)
453
    {
452
    {
Lines 471-478 LoadImageFunctionInfo COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2_to_R8G8B8A8_UNORM a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/load_functions_table_autogen.cpp_sec2
471
    }
470
    }
472
}
471
}
473
472
474
LoadImageFunctionInfo
473
LoadImageFunctionInfo COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGBA_UNORM_BLOCK(GLenum type)
475
COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGBA_UNORM_BLOCK(GLenum type)
476
{
474
{
477
    switch (type)
475
    switch (type)
478
    {
476
    {
Lines 1312-1319 LoadImageFunctionInfo COMPRESSED_SRGB8_ETC2_to_R8G8B8A8_UNORM_SRGB(GLenum type) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/load_functions_table_autogen.cpp_sec3
1312
    }
1310
    }
1313
}
1311
}
1314
1312
1315
LoadImageFunctionInfo COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGB_UNORM_SRGB_BLOCK(
1313
LoadImageFunctionInfo COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGB_UNORM_SRGB_BLOCK(GLenum type)
1316
    GLenum type)
1317
{
1314
{
1318
    switch (type)
1315
    switch (type)
1319
    {
1316
    {
Lines 1325-1332 LoadImageFunctionInfo COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGB_UNORM_ a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/load_functions_table_autogen.cpp_sec4
1325
    }
1322
    }
1326
}
1323
}
1327
1324
1328
LoadImageFunctionInfo COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2_to_ETC2_R8G8B8A1_SRGB_BLOCK(
1325
LoadImageFunctionInfo COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2_to_ETC2_R8G8B8A1_SRGB_BLOCK(GLenum type)
1329
    GLenum type)
1330
{
1326
{
1331
    switch (type)
1327
    switch (type)
1332
    {
1328
    {
Lines 1350-1358 LoadImageFunctionInfo COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2_to_R8G8B8A8_UNOR a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/load_functions_table_autogen.cpp_sec5
1350
    }
1346
    }
1351
}
1347
}
1352
1348
1353
LoadImageFunctionInfo
1349
LoadImageFunctionInfo COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGBA_UNORM_SRGB_BLOCK(GLenum type)
1354
COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGBA_UNORM_SRGB_BLOCK(
1355
    GLenum type)
1356
{
1350
{
1357
    switch (type)
1351
    switch (type)
1358
    {
1352
    {
Lines 1510-1515 LoadImageFunctionInfo DEPTH_COMPONENT24_to_D24_UNORM_X8_UINT(GLenum type) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/load_functions_table_autogen.cpp_sec6
1510
    }
1504
    }
1511
}
1505
}
1512
1506
1507
LoadImageFunctionInfo DEPTH_COMPONENT24_to_D32_FLOAT(GLenum type)
1508
{
1509
    switch (type)
1510
    {
1511
        case GL_UNSIGNED_INT:
1512
            return LoadImageFunctionInfo(LoadD24S8ToD32F, true);
1513
        default:
1514
            UNREACHABLE();
1515
            return LoadImageFunctionInfo(UnreachableLoadFunction, true);
1516
    }
1517
}
1518
1513
LoadImageFunctionInfo DEPTH_COMPONENT24_to_D32_FLOAT_S8X24_UINT(GLenum type)
1519
LoadImageFunctionInfo DEPTH_COMPONENT24_to_D32_FLOAT_S8X24_UINT(GLenum type)
1514
{
1520
{
1515
    switch (type)
1521
    switch (type)
Lines 3624-3629 LoadFunctionMap GetLoadFunctionsMap(GLenum internalFormat, FormatID angleFormat) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/load_functions_table_autogen.cpp_sec7
3624
                    return DEPTH_COMPONENT24_to_D24_UNORM_S8_UINT;
3630
                    return DEPTH_COMPONENT24_to_D24_UNORM_S8_UINT;
3625
                case FormatID::D24_UNORM_X8_UINT:
3631
                case FormatID::D24_UNORM_X8_UINT:
3626
                    return DEPTH_COMPONENT24_to_D24_UNORM_X8_UINT;
3632
                    return DEPTH_COMPONENT24_to_D24_UNORM_X8_UINT;
3633
                case FormatID::D32_FLOAT:
3634
                    return DEPTH_COMPONENT24_to_D32_FLOAT;
3627
                case FormatID::D32_FLOAT_S8X24_UINT:
3635
                case FormatID::D32_FLOAT_S8X24_UINT:
3628
                    return DEPTH_COMPONENT24_to_D32_FLOAT_S8X24_UINT;
3636
                    return DEPTH_COMPONENT24_to_D32_FLOAT_S8X24_UINT;
3629
                default:
3637
                default:
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/BUILD.gn -5 / +12 lines
Lines 6-12 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/BUILD.gn_sec1
6
6
7
import("../../../../gni/angle.gni")
7
import("../../../../gni/angle.gni")
8
8
9
assert(is_mac)
9
assert(is_mac || is_ios)
10
assert(angle_enable_metal)
10
assert(angle_enable_metal)
11
11
12
_metal_backend_sources = [
12
_metal_backend_sources = [
Lines 21-26 _metal_backend_sources = [ a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/BUILD.gn_sec2
21
  "DisplayMtl_api.h",
21
  "DisplayMtl_api.h",
22
  "FrameBufferMtl.h",
22
  "FrameBufferMtl.h",
23
  "FrameBufferMtl.mm",
23
  "FrameBufferMtl.mm",
24
  "IOSurfaceSurfaceMtl.h",
25
  "IOSurfaceSurfaceMtl.mm",
24
  "ProgramMtl.h",
26
  "ProgramMtl.h",
25
  "ProgramMtl.mm",
27
  "ProgramMtl.mm",
26
  "QueryMtl.h",
28
  "QueryMtl.h",
Lines 52-57 _metal_backend_sources = [ a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/BUILD.gn_sec3
52
  "mtl_format_table_autogen.mm",
54
  "mtl_format_table_autogen.mm",
53
  "mtl_format_utils.h",
55
  "mtl_format_utils.h",
54
  "mtl_format_utils.mm",
56
  "mtl_format_utils.mm",
57
  "mtl_glslang_mtl_utils.h",
58
  "mtl_glslang_mtl_utils.mm",
55
  "mtl_glslang_utils.h",
59
  "mtl_glslang_utils.h",
56
  "mtl_glslang_utils.mm",
60
  "mtl_glslang_utils.mm",
57
  "mtl_occlusion_query_pool.h",
61
  "mtl_occlusion_query_pool.h",
Lines 65-76 _metal_backend_sources = [ a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/BUILD.gn_sec4
65
  "mtl_utils.h",
69
  "mtl_utils.h",
66
  "mtl_utils.mm",
70
  "mtl_utils.mm",
67
  "shaders/constants.h",
71
  "shaders/constants.h",
68
  "shaders/format_autogen.h",
72
  "shaders/mtl_default_shaders_src_autogen.inc"
69
  "shaders/mtl_default_shaders_src_autogen.inc",
70
]
73
]
71
74
72
config("angle_metal_backend_config") {
75
config("angle_metal_backend_config") {
73
  defines = [ "ANGLE_ENABLE_METAL" ]
76
  defines = [ "ANGLE_ENABLE_METAL", "ANGLE_ENABLE_METAL_SPIRV" ]
74
  ldflags = [
77
  ldflags = [
75
    "-weak_framework",
78
    "-weak_framework",
76
    "Metal",
79
    "Metal",
Lines 96-107 angle_source_set("angle_metal_backend") { a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/BUILD.gn_sec5
96
    "${angle_root}:libANGLE_headers",
99
    "${angle_root}:libANGLE_headers",
97
  ]
100
  ]
98
101
99
  deps = [ "${angle_spirv_cross_dir}/gn:spirv_cross_sources" ]
102
  deps = [
103
    "$angle_spirv_tools_dir:spvtools_val",
104
    "${angle_spirv_cross_dir}/gn:spirv_cross_sources",
105
  ]
100
106
101
  objc_flags = [
107
  objc_flags = [
102
    "-Wno-nullability-completeness",
108
    "-Wno-nullability-completeness",
103
    "-Wno-unguarded-availability",
109
    "-Wno-unguarded-availability",
104
    "-fno-objc-arc",
110
    "-fno-objc-arc",
111
    "-Wno-extra-semi-stmt",
105
  ]
112
  ]
106
  cflags_objc += objc_flags
113
  cflags_objc += objc_flags
107
  cflags_objcc += objc_flags
114
  cflags_objcc += objc_flags
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/BufferMtl.h -3 / +12 lines
Lines 152-161 class BufferMtl : public BufferImpl, public BufferHolderMtl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/BufferMtl.h_sec1
152
152
153
    ConversionBufferMtl *getUniformConversionBuffer(ContextMtl *context, size_t offset);
153
    ConversionBufferMtl *getUniformConversionBuffer(ContextMtl *context, size_t offset);
154
154
155
    // NOTE(hqle): If the buffer is modifed by GPU, this function must be explicitly
156
    // called.
157
    void markConversionBuffersDirty();
158
155
    size_t size() const { return static_cast<size_t>(mState.getSize()); }
159
    size_t size() const { return static_cast<size_t>(mState.getSize()); }
156
160
157
  private:
161
  private:
158
    angle::Result setDataImpl(const gl::Context *context,
162
    angle::Result setDataImpl(const gl::Context *context,
163
                              gl::BufferBinding target,
159
                              const void *data,
164
                              const void *data,
160
                              size_t size,
165
                              size_t size,
161
                              gl::BufferUsage usage);
166
                              gl::BufferUsage usage);
Lines 167-186 class BufferMtl : public BufferImpl, public BufferHolderMtl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/BufferMtl.h_sec2
167
    angle::Result commitShadowCopy(const gl::Context *context);
172
    angle::Result commitShadowCopy(const gl::Context *context);
168
    angle::Result commitShadowCopy(const gl::Context *context, size_t size);
173
    angle::Result commitShadowCopy(const gl::Context *context, size_t size);
169
174
170
    void markConversionBuffersDirty();
171
172
    void clearConversionBuffers();
175
    void clearConversionBuffers();
176
173
    bool clientShadowCopyDataNeedSync(ContextMtl *contextMtl);
177
    bool clientShadowCopyDataNeedSync(ContextMtl *contextMtl);
174
    void ensureShadowCopySyncedFromGPU(ContextMtl *contextMtl);
178
    void ensureShadowCopySyncedFromGPU(ContextMtl *contextMtl);
175
    uint8_t *syncAndObtainShadowCopy(ContextMtl *contextMtl);
179
    uint8_t *syncAndObtainShadowCopy(ContextMtl *contextMtl);
176
180
181
    // Convenient method
182
    const uint8_t *getClientShadowCopyData(const gl::Context *context)
183
    {
184
        return getClientShadowCopyData(mtl::GetImpl(context));
185
    }
177
    // Client side shadow buffer
186
    // Client side shadow buffer
178
    angle::MemoryBuffer mShadowCopy;
187
    angle::MemoryBuffer mShadowCopy;
179
188
180
    // GPU side buffers pool
189
    // GPU side buffers pool
181
    mtl::BufferPool mBufferPool;
190
    mtl::BufferPool mBufferPool;
182
191
183
    // A cache of converted buffer data.
192
    // A cache of converted vertex data.
184
    std::vector<VertexConversionBufferMtl> mVertexConversionBuffers;
193
    std::vector<VertexConversionBufferMtl> mVertexConversionBuffers;
185
194
186
    std::vector<IndexConversionBufferMtl> mIndexConversionBuffers;
195
    std::vector<IndexConversionBufferMtl> mIndexConversionBuffers;
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/BufferMtl.mm -4 / +17 lines
Lines 23-28 namespace a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/BufferMtl.mm_sec1
23
// Start with a fairly small buffer size. We can increase this dynamically as we convert more data.
23
// Start with a fairly small buffer size. We can increase this dynamically as we convert more data.
24
constexpr size_t kConvertedElementArrayBufferInitialSize = 1024 * 8;
24
constexpr size_t kConvertedElementArrayBufferInitialSize = 1024 * 8;
25
25
26
// The max size that we will use buffer pool for dynamic update.
27
// If the buffer size exceeds this limit, we will use only one buffer instead of using the pool.
28
constexpr size_t kDynamicBufferPoolMaxBufSize = 128 * 1024;
29
26
template <typename IndexType>
30
template <typename IndexType>
27
angle::Result GetFirstLastIndices(const IndexType *indices,
31
angle::Result GetFirstLastIndices(const IndexType *indices,
28
                                  size_t count,
32
                                  size_t count,
Lines 105-111 angle::Result BufferMtl::setData(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/BufferMtl.mm_sec2
105
                                 size_t intendedSize,
109
                                 size_t intendedSize,
106
                                 gl::BufferUsage usage)
110
                                 gl::BufferUsage usage)
107
{
111
{
108
    return setDataImpl(context, data, intendedSize, usage);
112
    return setDataImpl(context, target, data, intendedSize, usage);
109
}
113
}
110
114
111
angle::Result BufferMtl::setSubData(const gl::Context *context,
115
angle::Result BufferMtl::setSubData(const gl::Context *context,
Lines 164-170 angle::Result BufferMtl::mapRange(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/BufferMtl.mm_sec3
164
{
168
{
165
    if (access & GL_MAP_INVALIDATE_BUFFER_BIT)
169
    if (access & GL_MAP_INVALIDATE_BUFFER_BIT)
166
    {
170
    {
167
        ANGLE_TRY(setDataImpl(context, nullptr, size(), mState.getUsage()));
171
        ANGLE_TRY(setDataImpl(context, gl::BufferBinding::InvalidEnum, nullptr, size(),
172
                              mState.getUsage()));
168
    }
173
    }
169
174
170
    if (mapPtr)
175
    if (mapPtr)
Lines 173-179 angle::Result BufferMtl::mapRange(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/BufferMtl.mm_sec4
173
        if (mBufferPool.getMaxBuffers() == 1)
178
        if (mBufferPool.getMaxBuffers() == 1)
174
        {
179
        {
175
            *mapPtr = mBuffer->mapWithOpt(contextMtl, (access & GL_MAP_WRITE_BIT) == 0,
180
            *mapPtr = mBuffer->mapWithOpt(contextMtl, (access & GL_MAP_WRITE_BIT) == 0,
176
                                          access & GL_MAP_UNSYNCHRONIZED_BIT) +
181
                                   access & GL_MAP_UNSYNCHRONIZED_BIT) +
177
                      offset;
182
                      offset;
178
        }
183
        }
179
        else
184
        else
Lines 395-400 void BufferMtl::clearConversionBuffers() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/BufferMtl.mm_sec5
395
}
400
}
396
401
397
angle::Result BufferMtl::setDataImpl(const gl::Context *context,
402
angle::Result BufferMtl::setDataImpl(const gl::Context *context,
403
                                     gl::BufferBinding target,
398
                                     const void *data,
404
                                     const void *data,
399
                                     size_t intendedSize,
405
                                     size_t intendedSize,
400
                                     gl::BufferUsage usage)
406
                                     gl::BufferUsage usage)
Lines 413-418 angle::Result BufferMtl::setDataImpl(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/BufferMtl.mm_sec6
413
419
414
    size_t adjustedSize = std::max<size_t>(1, intendedSize);
420
    size_t adjustedSize = std::max<size_t>(1, intendedSize);
415
421
422
    // Ensures no validation layer issues in std140 with data types like vec3 being 12 bytes vs 16
423
    // in MSL.
424
    if (target == gl::BufferBinding::Uniform)
425
    {
426
        adjustedSize = roundUpPow2(adjustedSize, (size_t)16);
427
    }
428
416
    size_t maxBuffers;
429
    size_t maxBuffers;
417
    switch (usage)
430
    switch (usage)
418
    {
431
    {
Lines 427-433 angle::Result BufferMtl::setDataImpl(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/BufferMtl.mm_sec7
427
        default:
440
        default:
428
            // dynamic buffer, allow up to 10 update per frame/encoding without
441
            // dynamic buffer, allow up to 10 update per frame/encoding without
429
            // waiting for GPU.
442
            // waiting for GPU.
430
            if (adjustedSize <= mtl::kSharedMemBufferMaxBufSizeHint)
443
            if (adjustedSize <= kDynamicBufferPoolMaxBufSize)
431
            {
444
            {
432
                maxBuffers = 10;
445
                maxBuffers = 10;
433
                mBufferPool.setAlwaysUseSharedMem();
446
                mBufferPool.setAlwaysUseSharedMem();
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/CompilerMtl.mm -1 / +11 lines
Lines 10-15 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/CompilerMtl.mm_sec1
10
#include "libANGLE/renderer/metal/CompilerMtl.h"
10
#include "libANGLE/renderer/metal/CompilerMtl.h"
11
11
12
#include "common/debug.h"
12
#include "common/debug.h"
13
#include "compiler/translator/TranslatorMetalDirect/EnvironmentVariable.h"
13
14
14
namespace rx
15
namespace rx
15
{
16
{
Lines 20-26 CompilerMtl::~CompilerMtl() {} a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/CompilerMtl.mm_sec2
20
21
21
ShShaderOutput CompilerMtl::getTranslatorOutputType() const
22
ShShaderOutput CompilerMtl::getTranslatorOutputType() const
22
{
23
{
23
    return SH_GLSL_METAL_OUTPUT;
24
    if (sh::readBoolEnvVar("ANGLE_GEN_MTL_WITH_SPIRV"))
25
    {
26
        // We want to return GL output first, we can't actually
27
        // get MSL code until link time. Translation time is too early
28
        return SH_GLSL_METAL_OUTPUT;
29
    }
30
    else
31
    {
32
        return SH_MSL_METAL_OUTPUT;
33
    }
24
}
34
}
25
35
26
}  // namespace rx
36
}  // namespace rx
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.h -12 / +61 lines
Lines 29-36 class FramebufferMtl; a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.h_sec1
29
class VertexArrayMtl;
29
class VertexArrayMtl;
30
class ProgramMtl;
30
class ProgramMtl;
31
class RenderTargetMtl;
31
class RenderTargetMtl;
32
class WindowSurfaceMtl;
32
class SurfaceMtlProtocol;
33
class TransformFeedbackMtl;
33
class BufferMtl;
34
34
35
class ContextMtl : public ContextImpl, public mtl::Context
35
class ContextMtl : public ContextImpl, public mtl::Context
36
{
36
{
Lines 85-91 class ContextMtl : public ContextImpl, public mtl::Context a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.h_sec2
85
                                                  GLsizei count,
85
                                                  GLsizei count,
86
                                                  gl::DrawElementsType type,
86
                                                  gl::DrawElementsType type,
87
                                                  const void *indices,
87
                                                  const void *indices,
88
                                                  GLsizei instanceCount,
88
                                                  GLsizei instances,
89
                                                  GLint baseVertex) override;
89
                                                  GLint baseVertex) override;
90
    angle::Result drawElementsInstancedBaseVertexBaseInstance(const gl::Context *context,
90
    angle::Result drawElementsInstancedBaseVertexBaseInstance(const gl::Context *context,
91
                                                              gl::PrimitiveMode mode,
91
                                                              gl::PrimitiveMode mode,
Lines 157-162 class ContextMtl : public ContextImpl, public mtl::Context a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.h_sec3
157
                                                                   const GLint *baseVertices,
157
                                                                   const GLint *baseVertices,
158
                                                                   const GLuint *baseInstances,
158
                                                                   const GLuint *baseInstances,
159
                                                                   GLsizei drawcount) override;
159
                                                                   GLsizei drawcount) override;
160
    angle::Result drawElementsSimpleTypesPrimitiveRestart(const gl::Context *context,
161
                                                          gl::PrimitiveMode mode,
162
                                                          GLsizei count,
163
                                                          gl::DrawElementsType type,
164
                                                          const void *indices,
165
                                                          GLsizei instances);
160
166
161
    // Device loss
167
    // Device loss
162
    gl::GraphicsResetStatus getResetStatus() override;
168
    gl::GraphicsResetStatus getResetStatus() override;
Lines 196-201 class ContextMtl : public ContextImpl, public mtl::Context a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.h_sec4
196
    const gl::Extensions &getNativeExtensions() const override;
202
    const gl::Extensions &getNativeExtensions() const override;
197
    const gl::Limitations &getNativeLimitations() const override;
203
    const gl::Limitations &getNativeLimitations() const override;
198
204
205
    const ProgramMtl *getProgram() const { return mProgram; }
206
199
    // Shader creation
207
    // Shader creation
200
    CompilerImpl *createCompiler() override;
208
    CompilerImpl *createCompiler() override;
201
    ShaderImpl *createShader(const gl::ShaderState &state) override;
209
    ShaderImpl *createShader(const gl::ShaderState &state) override;
Lines 249-260 class ContextMtl : public ContextImpl, public mtl::Context a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.h_sec5
249
    angle::Result memoryBarrier(const gl::Context *context, GLbitfield barriers) override;
257
    angle::Result memoryBarrier(const gl::Context *context, GLbitfield barriers) override;
250
    angle::Result memoryBarrierByRegion(const gl::Context *context, GLbitfield barriers) override;
258
    angle::Result memoryBarrierByRegion(const gl::Context *context, GLbitfield barriers) override;
251
259
260
    void invalidateCurrentTransformFeedbackBuffers();
261
    void onTransformFeedbackStateChanged();
262
    angle::Result onBeginTransformFeedback(
263
        size_t bufferCount,
264
        const gl::TransformFeedbackBuffersArray<BufferMtl *> &buffers);
265
266
    void onEndTransformFeedback();
267
    angle::Result onPauseTransformFeedback();
268
269
    void populateTransformFeedbackBufferSet(
270
        size_t bufferCount,
271
        const gl::TransformFeedbackBuffersArray<BufferMtl *> &buffers);
252
    // override mtl::ErrorHandler
272
    // override mtl::ErrorHandler
253
    void handleError(GLenum error,
273
    void handleError(GLenum error,
254
                     const char *file,
274
                     const char *file,
255
                     const char *function,
275
                     const char *function,
256
                     unsigned int line) override;
276
                     unsigned int line) override;
257
    void handleError(NSError *_Nullable error,
277
    void handleError(NSError *error,
258
                     const char *file,
278
                     const char *file,
259
                     const char *function,
279
                     const char *function,
260
                     unsigned int line) override;
280
                     unsigned int line) override;
Lines 272-283 class ContextMtl : public ContextImpl, public mtl::Context a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.h_sec6
272
    void onDrawFrameBufferChangedState(const gl::Context *context,
292
    void onDrawFrameBufferChangedState(const gl::Context *context,
273
                                       FramebufferMtl *framebuffer,
293
                                       FramebufferMtl *framebuffer,
274
                                       bool renderPassChanged);
294
                                       bool renderPassChanged);
275
    void onBackbufferResized(const gl::Context *context, WindowSurfaceMtl *backbuffer);
295
    void onBackbufferResized(const gl::Context *context, SurfaceMtlProtocol *backbuffer);
276
296
277
    // Invoke by QueryMtl
297
    // Invoke by QueryMtl
278
    angle::Result onOcclusionQueryBegin(const gl::Context *context, QueryMtl *query);
298
    angle::Result onOcclusionQueryBegan(const gl::Context *context, QueryMtl *query);
279
    void onOcclusionQueryEnd(const gl::Context *context, QueryMtl *query);
299
    void onOcclusionQueryEnded(const gl::Context *context, QueryMtl *query);
280
    void onOcclusionQueryDestroy(const gl::Context *context, QueryMtl *query);
300
    void onOcclusionQueryDestroyed(const gl::Context *context, QueryMtl *query);
281
301
282
    // Useful for temporarily pause then restart occlusion query during clear/blit with draw.
302
    // Useful for temporarily pause then restart occlusion query during clear/blit with draw.
283
    bool hasActiveOcclusionQuery() const { return mOcclusionQuery; }
303
    bool hasActiveOcclusionQuery() const { return mOcclusionQuery; }
Lines 367-373 class ContextMtl : public ContextImpl, public mtl::Context a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.h_sec7
367
                            GLsizei instanceCount,
387
                            GLsizei instanceCount,
368
                            gl::DrawElementsType indexTypeOrNone,
388
                            gl::DrawElementsType indexTypeOrNone,
369
                            const void *indices,
389
                            const void *indices,
370
                            bool xfbPass);
390
                            bool transformFeedbackDraw);
371
391
372
    angle::Result drawTriFanArrays(const gl::Context *context,
392
    angle::Result drawTriFanArrays(const gl::Context *context,
373
                                   GLint first,
393
                                   GLint first,
Lines 417-422 class ContextMtl : public ContextImpl, public mtl::Context a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.h_sec8
417
                                   const void *indices,
437
                                   const void *indices,
418
                                   GLsizei instanceCount);
438
                                   GLsizei instanceCount);
419
439
440
    void execDrawInstanced(MTLPrimitiveType primitiveType,
441
                           uint32_t vertexStart,
442
                           uint32_t vertexCount,
443
                           uint32_t instances);
444
445
    void execDrawIndexedInstanced(MTLPrimitiveType primitiveType,
446
                                  uint32_t indexCount,
447
                                  MTLIndexType indexType,
448
                                  const mtl::BufferRef &indexBuffer,
449
                                  size_t bufferOffset,
450
                                  uint32_t instances);
451
420
    void updateExtendedState(const gl::State &glState);
452
    void updateExtendedState(const gl::State &glState);
421
453
422
    void updateViewport(FramebufferMtl *framebufferMtl,
454
    void updateViewport(FramebufferMtl *framebufferMtl,
Lines 442-447 class ContextMtl : public ContextImpl, public mtl::Context a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.h_sec9
442
    angle::Result fillDriverXFBUniforms(GLint drawCallFirstVertex,
474
    angle::Result fillDriverXFBUniforms(GLint drawCallFirstVertex,
443
                                        uint32_t verticesPerInstance,
475
                                        uint32_t verticesPerInstance,
444
                                        uint32_t skippedInstances);
476
                                        uint32_t skippedInstances);
477
    angle::Result handleDirtyGraphicsTransformFeedbackBuffersEmulation(const gl::Context *context);
445
    angle::Result handleDirtyDepthStencilState(const gl::Context *context);
478
    angle::Result handleDirtyDepthStencilState(const gl::Context *context);
446
    angle::Result handleDirtyDepthBias(const gl::Context *context);
479
    angle::Result handleDirtyDepthBias(const gl::Context *context);
447
    angle::Result handleDirtyRenderPass(const gl::Context *context);
480
    angle::Result handleDirtyRenderPass(const gl::Context *context);
Lines 470-475 class ContextMtl : public ContextImpl, public mtl::Context a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.h_sec10
470
        DIRTY_BIT_RENDER_PIPELINE,
503
        DIRTY_BIT_RENDER_PIPELINE,
471
        DIRTY_BIT_UNIFORM_BUFFERS_BINDING,
504
        DIRTY_BIT_UNIFORM_BUFFERS_BINDING,
472
        DIRTY_BIT_RASTERIZER_DISCARD,
505
        DIRTY_BIT_RASTERIZER_DISCARD,
506
        DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS,
473
        DIRTY_BIT_MAX,
507
        DIRTY_BIT_MAX,
474
    };
508
    };
475
509
Lines 488-494 class ContextMtl : public ContextImpl, public mtl::Context a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.h_sec11
488
        uint32_t xfbActiveUnpaused;
522
        uint32_t xfbActiveUnpaused;
489
        uint32_t xfbVerticesPerDraw;
523
        uint32_t xfbVerticesPerDraw;
490
        // NOTE: Explicit padding. Fill in with useful data when needed in the future.
524
        // NOTE: Explicit padding. Fill in with useful data when needed in the future.
491
        int32_t padding[3];
525
        int32_t padding_0[3];
492
526
493
        int32_t xfbBufferOffsets[4];
527
        int32_t xfbBufferOffsets[4];
494
        uint32_t acbBufferOffsets[4];
528
        uint32_t acbBufferOffsets[4];
Lines 508-519 class ContextMtl : public ContextImpl, public mtl::Context a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.h_sec12
508
542
509
        uint32_t coverageMask;
543
        uint32_t coverageMask;
510
544
511
        float padding2[3];
545
        int32_t emulatedInstanceID;
546
547
        // NOTE: Explicit padding. Fill in with useful data when needed in the future.
548
        int32_t padding_1[2];
512
    };
549
    };
513
550
514
    struct DefaultAttribute
551
    struct DefaultAttribute
515
    {
552
    {
516
        uint8_t values[sizeof(float) * 4];
553
        float values[4];
517
    };
554
    };
518
555
519
    mtl::OcclusionQueryPool mOcclusionQueryPool;
556
    mtl::OcclusionQueryPool mOcclusionQueryPool;
Lines 522-527 class ContextMtl : public ContextImpl, public mtl::Context a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.h_sec13
522
    mtl::RenderCommandEncoder mRenderEncoder;
559
    mtl::RenderCommandEncoder mRenderEncoder;
523
    mtl::BlitCommandEncoder mBlitEncoder;
560
    mtl::BlitCommandEncoder mBlitEncoder;
524
    mtl::ComputeCommandEncoder mComputeEncoder;
561
    mtl::ComputeCommandEncoder mComputeEncoder;
562
    // TODO(jcunningham):
563
    // Cache the current draw call's firstVertex to be passed to
564
    // TransformFeedbackMtl::getBufferOffsets.  We should switch
565
    // to using gl_BaseVertex -> base_vertex in MSL
566
    GLint mXfbBaseVertex;
567
    // Cache the current draw call's vertex count as well to support instanced draw calls
568
    GLuint mXfbVertexCountPerInstance;
525
569
526
    // Cached back-end objects
570
    // Cached back-end objects
527
    FramebufferMtl *mDrawFramebuffer = nullptr;
571
    FramebufferMtl *mDrawFramebuffer = nullptr;
Lines 554-559 class ContextMtl : public ContextImpl, public mtl::Context a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.h_sec14
554
    mtl::BufferPool mTriFanIndexBuffer;
598
    mtl::BufferPool mTriFanIndexBuffer;
555
    // one buffer can be reused for any starting vertex in DrawArrays()
599
    // one buffer can be reused for any starting vertex in DrawArrays()
556
    mtl::BufferRef mTriFanArraysIndexBuffer;
600
    mtl::BufferRef mTriFanArraysIndexBuffer;
601
    //
602
    mtl::BufferPool mPrimitiveRestartBuffer;
557
603
558
    // Dummy texture to be used for transform feedback only pass.
604
    // Dummy texture to be used for transform feedback only pass.
559
    mtl::TextureRef mDummyXFBRenderTexture;
605
    mtl::TextureRef mDummyXFBRenderTexture;
Lines 562-567 class ContextMtl : public ContextImpl, public mtl::Context a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.h_sec15
562
608
563
    DefaultAttribute mDefaultAttributes[mtl::kMaxVertexAttribs];
609
    DefaultAttribute mDefaultAttributes[mtl::kMaxVertexAttribs];
564
610
611
    // Transform feedback buffers.
612
    std::unordered_set<const BufferMtl *> mCurrentTransformFeedbackBuffers;
613
565
    IncompleteTextureSet mIncompleteTextures;
614
    IncompleteTextureSet mIncompleteTextures;
566
    bool mIncompleteTexturesInitialized = false;
615
    bool mIncompleteTexturesInitialized = false;
567
};
616
};
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm -255 / +437 lines
Lines 44-68 constexpr uint32_t kMaxTriFanLineLoopBuffersPerFrame = 0; a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec1
44
constexpr uint32_t kMaxTriFanLineLoopBuffersPerFrame = 10;
44
constexpr uint32_t kMaxTriFanLineLoopBuffersPerFrame = 10;
45
#endif
45
#endif
46
46
47
#define ANGLE_MTL_XFB_DRAW(DRAW_PROC)                                                       \
48
    if (!mState.isTransformFeedbackActiveUnpaused())                                        \
49
    {                                                                                       \
50
        /* Normal draw call */                                                              \
51
        DRAW_PROC(false);                                                                   \
52
    }                                                                                       \
53
    else                                                                                    \
54
    {                                                                                       \
55
        /* First pass: write to XFB buffers in vertex shader, fragment shader inactive */   \
56
        DRAW_PROC(true);                                                                    \
57
        if (!mState.isRasterizerDiscardEnabled())                                           \
58
        {                                                                                   \
59
            /* Second pass: full rasterization: vertex shader + fragment shader are active. \
60
               Vertex shader writes to stage output but won't write to XFB buffers */       \
61
            invalidateRenderPipeline();                                                     \
62
            DRAW_PROC(false);                                                               \
63
        }                                                                                   \
64
    }
65
66
angle::Result AllocateTriangleFanBufferFromPool(ContextMtl *context,
47
angle::Result AllocateTriangleFanBufferFromPool(ContextMtl *context,
67
                                                GLsizei vertexCount,
48
                                                GLsizei vertexCount,
68
                                                mtl::BufferPool *pool,
49
                                                mtl::BufferPool *pool,
Lines 84-94 angle::Result AllocateTriangleFanBufferFromPool(ContextMtl *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec2
84
    return angle::Result::Continue;
65
    return angle::Result::Continue;
85
}
66
}
86
67
87
angle::Result AllocateLineLoopBufferFromPool(ContextMtl *context,
68
angle::Result AllocateBufferFromPool(ContextMtl *context,
88
                                             GLsizei indicesToReserve,
69
                                     GLsizei indicesToReserve,
89
                                             mtl::BufferPool *pool,
70
                                     mtl::BufferPool *pool,
90
                                             mtl::BufferRef *bufferOut,
71
                                     mtl::BufferRef *bufferOut,
91
                                             uint32_t *offsetOut)
72
                                     uint32_t *offsetOut)
92
{
73
{
93
    size_t offset;
74
    size_t offset;
94
    pool->releaseInFlightBuffers(context);
75
    pool->releaseInFlightBuffers(context);
Lines 105-116 bool NeedToInvertDepthRange(float near, float far) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec3
105
    return near > far;
86
    return near > far;
106
}
87
}
107
88
108
bool IsTransformFeedbackOnly(const gl::State &glState)
89
std::string ConvertMarkerToCpp(GLsizei length, const char *marker)
109
{
110
    return glState.isTransformFeedbackActiveUnpaused() && glState.isRasterizerDiscardEnabled();
111
}
112
113
std::string ConvertMarkerToString(GLsizei length, const char *marker)
114
{
90
{
115
    std::string cppString;
91
    std::string cppString;
116
    if (length == 0)
92
    if (length == 0)
Lines 173-179 class LineLoopLastSegmentHelper a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec4
173
                    {indexTypeOrNone, vertexOrIndexCount, indices, mLineLoopIndexBuffer, 0}));
149
                    {indexTypeOrNone, vertexOrIndexCount, indices, mLineLoopIndexBuffer, 0}));
174
        }
150
        }
175
151
176
        ANGLE_TRY(indexBufferPool->commit(mContextMtl));
152
        ANGLE_TRY(indexBufferPool->commit(mContextMtl, false));
177
153
178
        return angle::Result::Continue;
154
        return angle::Result::Continue;
179
    }
155
    }
Lines 191-197 ContextMtl::ContextMtl(const gl::State &state, gl::ErrorSet *errorSet, DisplayMt a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec5
191
      mCmdBuffer(&display->cmdQueue()),
167
      mCmdBuffer(&display->cmdQueue()),
192
      mRenderEncoder(&mCmdBuffer, mOcclusionQueryPool),
168
      mRenderEncoder(&mCmdBuffer, mOcclusionQueryPool),
193
      mBlitEncoder(&mCmdBuffer),
169
      mBlitEncoder(&mCmdBuffer),
194
      mComputeEncoder(&mCmdBuffer)
170
      mComputeEncoder(&mCmdBuffer),
171
      mXfbVertexCountPerInstance(0)
195
{}
172
{}
196
173
197
ContextMtl::~ContextMtl() {}
174
ContextMtl::~ContextMtl() {}
Lines 208-213 angle::Result ContextMtl::initialize() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec6
208
    mLineLoopLastSegmentIndexBuffer.initialize(this, 2 * sizeof(uint32_t),
185
    mLineLoopLastSegmentIndexBuffer.initialize(this, 2 * sizeof(uint32_t),
209
                                               mtl::kIndexBufferOffsetAlignment,
186
                                               mtl::kIndexBufferOffsetAlignment,
210
                                               kMaxTriFanLineLoopBuffersPerFrame);
187
                                               kMaxTriFanLineLoopBuffersPerFrame);
188
    mPrimitiveRestartBuffer.initialize(this, 0, mtl::kIndexBufferOffsetAlignment,
189
                                       kMaxTriFanLineLoopBuffersPerFrame);
211
190
212
    return angle::Result::Continue;
191
    return angle::Result::Continue;
213
}
192
}
Lines 227-249 void ContextMtl::onDestroy(const gl::Context *context) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec7
227
206
228
angle::Result ContextMtl::ensureIncompleteTexturesCreated(const gl::Context *context)
207
angle::Result ContextMtl::ensureIncompleteTexturesCreated(const gl::Context *context)
229
{
208
{
230
    if (ANGLE_LIKELY(mIncompleteTexturesInitialized))
209
    if (ANGLE_UNLIKELY(!mIncompleteTexturesInitialized))
231
    {
232
        return angle::Result::Continue;
233
    }
234
    constexpr gl::TextureType supportedTextureTypes[] = {gl::TextureType::_2D, gl::TextureType::_3D,
235
                                                         gl::TextureType::_2DArray,
236
                                                         gl::TextureType::CubeMap};
237
    for (gl::TextureType texType : supportedTextureTypes)
238
    {
210
    {
239
        gl::Texture *texture;
211
        constexpr gl::TextureType supportedTextureTypes[] = {
240
        ANGLE_TRY(mIncompleteTextures.getIncompleteTexture(context, texType, nullptr, &texture));
212
            gl::TextureType::_2D, gl::TextureType::_2DArray, gl::TextureType::_3D,
241
213
            gl::TextureType::CubeMap};
242
        TextureMtl *textureMtl                      = mtl::GetImpl(texture);
214
        for (auto texType : supportedTextureTypes)
243
        textureMtl->getNativeTexture()->get().label = @"IncompleteTexture";
215
        {
216
            gl::Texture *texture;
217
            ANGLE_UNUSED_VARIABLE(texture);
218
            ANGLE_TRY(
219
                mIncompleteTextures.getIncompleteTexture(context, texType, nullptr, &texture));
220
        }
221
        mIncompleteTexturesInitialized = true;
244
    }
222
    }
245
    mIncompleteTexturesInitialized = true;
246
247
    return angle::Result::Continue;
223
    return angle::Result::Continue;
248
}
224
}
249
225
Lines 282-288 angle::Result ContextMtl::drawTriFanArraysWithBaseVertex(const gl::Context *cont a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec8
282
            this, {0, static_cast<uint32_t>(count), mTriFanArraysIndexBuffer, 0}));
258
            this, {0, static_cast<uint32_t>(count), mTriFanArraysIndexBuffer, 0}));
283
    }
259
    }
284
260
285
    ASSERT(!getState().isTransformFeedbackActiveUnpaused());
261
    if (mState.isTransformFeedbackActiveUnpaused())
262
    {
263
        ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, first, count, instances,
264
                            gl::DrawElementsType::InvalidEnum, reinterpret_cast<const void *>(0),
265
                            true));
266
        // Draw with the zero starting index buffer, shift the vertex index using baseVertex
267
        // instanced draw:
268
        mRenderEncoder.drawIndexedInstancedBaseVertex(MTLPrimitiveTypeTriangle, genIndicesCount,
269
                                                      MTLIndexTypeUInt32, mTriFanArraysIndexBuffer,
270
                                                      0, instances, first);
271
    }
286
272
287
    ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, first, count, instances,
273
    ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, first, count, instances,
288
                        gl::DrawElementsType::InvalidEnum, reinterpret_cast<const void *>(0),
274
                        gl::DrawElementsType::InvalidEnum, reinterpret_cast<const void *>(0),
Lines 311-326 angle::Result ContextMtl::drawTriFanArraysLegacy(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec9
311
        this, {static_cast<uint32_t>(first), static_cast<uint32_t>(count), genIdxBuffer,
297
        this, {static_cast<uint32_t>(first), static_cast<uint32_t>(count), genIdxBuffer,
312
               genIdxBufferOffset}));
298
               genIdxBufferOffset}));
313
299
314
    ANGLE_TRY(mTriFanIndexBuffer.commit(this));
300
    ANGLE_TRY(mTriFanIndexBuffer.commit(this, false));
315
301
316
    ASSERT(!getState().isTransformFeedbackActiveUnpaused());
302
    if (mState.isTransformFeedbackActiveUnpaused())
303
    {
304
        ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, first, count, instances,
305
                            gl::DrawElementsType::InvalidEnum, reinterpret_cast<const void *>(0),
306
                            true));
317
307
308
        execDrawIndexedInstanced(MTLPrimitiveTypeTriangle, genIndicesCount, MTLIndexTypeUInt32,
309
                                 genIdxBuffer, genIdxBufferOffset, instances);
310
    }
318
    ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, first, count, instances,
311
    ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, first, count, instances,
319
                        gl::DrawElementsType::InvalidEnum, reinterpret_cast<const void *>(0),
312
                        gl::DrawElementsType::InvalidEnum, reinterpret_cast<const void *>(0),
320
                        false));
313
                        false));
321
314
322
    mRenderEncoder.drawIndexed(MTLPrimitiveTypeTriangle, genIndicesCount, MTLIndexTypeUInt32,
315
    execDrawIndexedInstanced(MTLPrimitiveTypeTriangle, genIndicesCount, MTLIndexTypeUInt32,
323
                               genIdxBuffer, genIdxBufferOffset);
316
                             genIdxBuffer, genIdxBufferOffset, instances);
324
317
325
    return angle::Result::Continue;
318
    return angle::Result::Continue;
326
}
319
}
Lines 368-389 angle::Result ContextMtl::drawLineLoopArrays(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec10
368
    uint32_t genIdxBufferOffset;
361
    uint32_t genIdxBufferOffset;
369
    uint32_t genIndicesCount = count + 1;
362
    uint32_t genIndicesCount = count + 1;
370
363
371
    ANGLE_TRY(AllocateLineLoopBufferFromPool(this, genIndicesCount, &mLineLoopIndexBuffer,
364
    ANGLE_TRY(AllocateBufferFromPool(this, genIndicesCount, &mLineLoopIndexBuffer, &genIdxBuffer,
372
                                             &genIdxBuffer, &genIdxBufferOffset));
365
                                     &genIdxBufferOffset));
373
    ANGLE_TRY(getDisplay()->getUtils().generateLineLoopBufferFromArrays(
366
    ANGLE_TRY(getDisplay()->getUtils().generateLineLoopBufferFromArrays(
374
        this, {static_cast<uint32_t>(first), static_cast<uint32_t>(count), genIdxBuffer,
367
        this, {static_cast<uint32_t>(first), static_cast<uint32_t>(count), genIdxBuffer,
375
               genIdxBufferOffset}));
368
               genIdxBufferOffset}));
376
369
377
    ANGLE_TRY(mLineLoopIndexBuffer.commit(this));
370
    ANGLE_TRY(mLineLoopIndexBuffer.commit(this, false));
378
371
379
    ASSERT(!getState().isTransformFeedbackActiveUnpaused());
372
    if (mState.isTransformFeedbackActiveUnpaused())
373
    {
374
        ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::LineLoop, first, count, instances,
375
                            gl::DrawElementsType::InvalidEnum, nullptr, true));
380
376
377
        execDrawIndexedInstanced(MTLPrimitiveTypeLineStrip, genIndicesCount, MTLIndexTypeUInt32,
378
                                 genIdxBuffer, genIdxBufferOffset, instances);
379
    }
381
    ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::LineLoop, first, count, instances,
380
    ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::LineLoop, first, count, instances,
382
                        gl::DrawElementsType::InvalidEnum, nullptr, false));
381
                        gl::DrawElementsType::InvalidEnum, nullptr, false));
383
382
384
    mRenderEncoder.drawIndexedInstanced(MTLPrimitiveTypeLineStrip, genIndicesCount,
383
    execDrawIndexedInstanced(MTLPrimitiveTypeLineStrip, genIndicesCount, MTLIndexTypeUInt32,
385
                                        MTLIndexTypeUInt32, genIdxBuffer, genIdxBufferOffset,
384
                             genIdxBuffer, genIdxBufferOffset, instances);
386
                                        instances);
387
385
388
    return angle::Result::Continue;
386
    return angle::Result::Continue;
389
}
387
}
Lines 413-433 angle::Result ContextMtl::drawArraysImpl(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec11
413
411
414
    MTLPrimitiveType mtlType = mtl::GetPrimitiveType(mode);
412
    MTLPrimitiveType mtlType = mtl::GetPrimitiveType(mode);
415
413
416
#define DRAW_GENERIC_ARRAY(xfbPass)                                                                \
414
    if (mState.isTransformFeedbackActiveUnpaused())
417
    ANGLE_TRY(setupDraw(context, mode, first, count, instances, gl::DrawElementsType::InvalidEnum, \
415
    {
418
                        nullptr, xfbPass));                                                        \
416
        ANGLE_TRY(setupDraw(context, mode, first, count, instances,
419
                                                                                                   \
417
                            gl::DrawElementsType::InvalidEnum, nullptr, true));
420
    if (instances == 0)                                                                            \
418
421
    {                                                                                              \
419
        if (instances == 0)
422
        /* This method is called from normal drawArrays() */                                       \
420
        {
423
        mRenderEncoder.draw(mtlType, first, count);                                                \
421
            // This method is called from normal drawArrays()
424
    }                                                                                              \
422
            mRenderEncoder.draw(mtlType, first, count);
425
    else                                                                                           \
423
        }
426
    {                                                                                              \
424
        else
427
        mRenderEncoder.drawInstanced(mtlType, first, count, instanceCount);                        \
425
        {
426
            execDrawInstanced(mtlType, first, count, instanceCount);
427
        }
428
    }
428
    }
429
    ANGLE_TRY(setupDraw(context, mode, first, count, instances, gl::DrawElementsType::InvalidEnum,
430
                        nullptr, false));
429
431
430
    ANGLE_MTL_XFB_DRAW(DRAW_GENERIC_ARRAY)
432
    if (instances == 0)
433
    {
434
        // This method is called from normal drawArrays()
435
        mRenderEncoder.draw(mtlType, first, count);
436
    }
437
    else
438
    {
439
        execDrawInstanced(mtlType, first, count, instanceCount);
440
    }
431
441
432
    return angle::Result::Continue;
442
    return angle::Result::Continue;
433
}
443
}
Lines 480-495 angle::Result ContextMtl::drawTriFanElements(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec12
480
                                                    &genIdxBufferOffset, &genIndicesCount));
490
                                                    &genIdxBufferOffset, &genIndicesCount));
481
491
482
        ANGLE_TRY(getDisplay()->getUtils().generateTriFanBufferFromElementsArray(
492
        ANGLE_TRY(getDisplay()->getUtils().generateTriFanBufferFromElementsArray(
483
            this, {type, count, indices, genIdxBuffer, genIdxBufferOffset, primitiveRestart}));
493
            this, {type, count, indices, genIdxBuffer, genIdxBufferOffset, primitiveRestart},
494
            &genIndicesCount));
495
496
        ANGLE_TRY(mTriFanIndexBuffer.commit(this, false));
497
498
        if (mState.isTransformFeedbackActiveUnpaused())
499
        {
500
            ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, 0, count, instances, type,
501
                                indices, true));
484
502
485
        ANGLE_TRY(mTriFanIndexBuffer.commit(this));
503
            execDrawIndexedInstanced(MTLPrimitiveTypeTriangle, genIndicesCount, MTLIndexTypeUInt32,
504
                                     genIdxBuffer, genIdxBufferOffset, instances);
505
        }
486
506
487
        ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, 0, count, instances, type,
507
        ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, 0, count, instances, type,
488
                            indices, false));
508
                            indices, false));
489
509
490
        mRenderEncoder.drawIndexedInstanced(MTLPrimitiveTypeTriangle, genIndicesCount,
510
        execDrawIndexedInstanced(MTLPrimitiveTypeTriangle, genIndicesCount, MTLIndexTypeUInt32,
491
                                            MTLIndexTypeUInt32, genIdxBuffer, genIdxBufferOffset,
511
                                 genIdxBuffer, genIdxBufferOffset, instances);
492
                                            instances);
493
512
494
        return angle::Result::Continue;
513
        return angle::Result::Continue;
495
    }  // if (count > 3)
514
    }  // if (count > 3)
Lines 532-558 angle::Result ContextMtl::drawLineLoopElements(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec13
532
        uint32_t genIdxBufferOffset;
551
        uint32_t genIdxBufferOffset;
533
        uint32_t reservedIndices = count * 2;
552
        uint32_t reservedIndices = count * 2;
534
        uint32_t genIndicesCount;
553
        uint32_t genIndicesCount;
535
        ANGLE_TRY(AllocateLineLoopBufferFromPool(this, reservedIndices, &mLineLoopIndexBuffer,
554
        ANGLE_TRY(AllocateBufferFromPool(this, reservedIndices, &mLineLoopIndexBuffer,
536
                                                 &genIdxBuffer, &genIdxBufferOffset));
555
                                         &genIdxBuffer, &genIdxBufferOffset));
537
556
538
        ANGLE_TRY(getDisplay()->getUtils().generateLineLoopBufferFromElementsArray(
557
        ANGLE_TRY(getDisplay()->getUtils().generateLineLoopBufferFromElementsArray(
539
            this, {type, count, indices, genIdxBuffer, genIdxBufferOffset, primitiveRestart},
558
            this, {type, count, indices, genIdxBuffer, genIdxBufferOffset, primitiveRestart},
540
            &genIndicesCount));
559
            &genIndicesCount));
541
560
542
        ANGLE_TRY(mLineLoopIndexBuffer.commit(this));
561
        ANGLE_TRY(mLineLoopIndexBuffer.commit(this, false));
562
563
        if (mState.isTransformFeedbackActiveUnpaused())
564
        {
565
            ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::LineLoop, 0, count, instances, type,
566
                                indices, true));
567
568
            execDrawIndexedInstanced(MTLPrimitiveTypeLineStrip, genIndicesCount, MTLIndexTypeUInt32,
569
                                     genIdxBuffer, genIdxBufferOffset, instances);
570
        }
543
571
544
        ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::LineLoop, 0, count, instances, type,
572
        ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::LineLoop, 0, count, instances, type,
545
                            indices, false));
573
                            indices, false));
546
574
547
        mRenderEncoder.drawIndexedInstanced(MTLPrimitiveTypeLineStrip, genIndicesCount,
575
        execDrawIndexedInstanced(MTLPrimitiveTypeLineStrip, genIndicesCount, MTLIndexTypeUInt32,
548
                                            MTLIndexTypeUInt32, genIdxBuffer, genIdxBufferOffset,
576
                                 genIdxBuffer, genIdxBufferOffset, instances);
549
                                            instances);
550
577
551
        return angle::Result::Continue;
578
        return angle::Result::Continue;
552
    }  // if (count >= 2)
579
    }  // if (count >= 2)
553
    return drawElementsInstanced(context, gl::PrimitiveMode::Lines, count, type, indices,
580
    return drawElementsInstanced(context, gl::PrimitiveMode::Lines, count, type, indices,
554
                                 instances);
581
                                 instances);
555
}
582
}
583
angle::Result ContextMtl::drawElementsSimpleTypesPrimitiveRestart(const gl::Context *context,
584
                                                                  gl::PrimitiveMode mode,
585
                                                                  GLsizei count,
586
                                                                  gl::DrawElementsType type,
587
                                                                  const void *indices,
588
                                                                  GLsizei instances)
589
{
590
591
    mtl::BufferRef genIdxBuffer;
592
    uint32_t genIdxBufferOffset;
593
    uint32_t reservedIndices = count;
594
    size_t genIndicesCount;
595
    ANGLE_TRY(AllocateBufferFromPool(this, reservedIndices, &mPrimitiveRestartBuffer, &genIdxBuffer,
596
                                     &genIdxBufferOffset));
597
    switch (mode)
598
    {
599
        case gl::PrimitiveMode::Points:
600
            ANGLE_TRY(getDisplay()->getUtils().generatePrimitiveRestartPointsBuffer(
601
                this, {type, count, indices, genIdxBuffer, genIdxBufferOffset, true},
602
                &genIndicesCount));
603
            break;
604
        case gl::PrimitiveMode::Lines:
605
            ANGLE_TRY(getDisplay()->getUtils().generatePrimitiveRestartLinesBuffer(
606
                this, {type, count, indices, genIdxBuffer, genIdxBufferOffset, true},
607
                &genIndicesCount));
608
            break;
609
        case gl::PrimitiveMode::Triangles:
610
            ANGLE_TRY(getDisplay()->getUtils().generatePrimitiveRestartTrianglesBuffer(
611
                this, {type, count, indices, genIdxBuffer, genIdxBufferOffset, true},
612
                &genIndicesCount));
613
            break;
614
        default:
615
            UNREACHABLE();
616
            return angle::Result::Stop;
617
    }
618
    ANGLE_TRY(mPrimitiveRestartBuffer.commit(this));
619
    MTLPrimitiveType mtlType = mtl::GetPrimitiveType(mode);
620
    if (mState.isTransformFeedbackActiveUnpaused())
621
    {
622
        ANGLE_TRY(setupDraw(context, mode, 0, count, instances, type,
623
                            reinterpret_cast<const void *>(0), true));
624
625
        execDrawIndexedInstanced(mtlType, (uint32_t)genIndicesCount, MTLIndexTypeUInt32,
626
                                 genIdxBuffer, genIdxBufferOffset, instances);
627
    }
628
    ANGLE_TRY(setupDraw(context, mode, 0, count, instances, type, indices, false));
629
630
    execDrawIndexedInstanced(mtlType, (uint32_t)genIndicesCount, MTLIndexTypeUInt32, genIdxBuffer,
631
                             genIdxBufferOffset, instances);
632
633
    return angle::Result::Continue;
634
}
556
635
557
angle::Result ContextMtl::drawElementsImpl(const gl::Context *context,
636
angle::Result ContextMtl::drawElementsImpl(const gl::Context *context,
558
                                           gl::PrimitiveMode mode,
637
                                           gl::PrimitiveMode mode,
Lines 563-569 angle::Result ContextMtl::drawElementsImpl(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec14
563
{
642
{
564
    // Real instances count. Zero means this is not instanced draw.
643
    // Real instances count. Zero means this is not instanced draw.
565
    GLsizei instanceCount = instances ? instances : 1;
644
    GLsizei instanceCount = instances ? instances : 1;
566
567
    if (mCullAllPolygons && gl::IsPolygonMode(mode))
645
    if (mCullAllPolygons && gl::IsPolygonMode(mode))
568
    {
646
    {
569
        return angle::Result::Continue;
647
        return angle::Result::Continue;
Lines 577-594 angle::Result ContextMtl::drawElementsImpl(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec15
577
    {
655
    {
578
        return drawLineLoopElements(context, count, type, indices, instanceCount);
656
        return drawLineLoopElements(context, count, type, indices, instanceCount);
579
    }
657
    }
580
581
    mtl::BufferRef idxBuffer;
658
    mtl::BufferRef idxBuffer;
582
    size_t convertedOffset             = 0;
659
    size_t convertedOffset             = 0;
583
    gl::DrawElementsType convertedType = type;
660
    gl::DrawElementsType convertedType = type;
661
    size_t convertedCount              = (size_t)count;
584
662
585
    ANGLE_TRY(mVertexArray->getIndexBuffer(context, type, count, indices, &idxBuffer,
663
    ANGLE_TRY(mVertexArray->getIndexBuffer(context, type, mode, count, indices, &idxBuffer,
586
                                           &convertedOffset, &convertedType));
664
                                           &convertedOffset, &convertedType, &convertedCount));
587
665
588
    ASSERT(idxBuffer);
666
    ASSERT(idxBuffer);
589
    ASSERT((convertedOffset % mtl::kIndexBufferOffsetAlignment) == 0);
667
    ASSERT((convertedOffset % mtl::kIndexBufferOffsetAlignment) == 0);
668
    uint32_t convertedCounti32 = (uint32_t)convertedCount;
669
    if (mState.isTransformFeedbackActiveUnpaused())
670
    {
671
        ANGLE_TRY(setupDraw(context, mode, 0, convertedCounti32, instances, type, indices, true));
672
        MTLPrimitiveType mtlType = mtl::GetPrimitiveType(mode);
590
673
591
    ANGLE_TRY(setupDraw(context, mode, 0, count, instances, type, indices, false));
674
        MTLIndexType mtlIdxType = mtl::GetIndexType(convertedType);
675
676
        if (instances == 0)
677
        {
678
            // Normal draw
679
            mRenderEncoder.drawIndexed(mtlType, convertedCounti32, mtlIdxType, idxBuffer,
680
                                       convertedOffset);
681
        }
682
        else
683
        {
684
            // Instanced draw
685
            execDrawIndexedInstanced(mtlType, convertedCounti32, mtlIdxType, idxBuffer,
686
                                     convertedOffset, instanceCount);
687
        }
688
    }
689
690
    ANGLE_TRY(setupDraw(context, mode, 0, convertedCounti32, instances, type, indices, false));
592
691
593
    MTLPrimitiveType mtlType = mtl::GetPrimitiveType(mode);
692
    MTLPrimitiveType mtlType = mtl::GetPrimitiveType(mode);
594
693
Lines 597-609 angle::Result ContextMtl::drawElementsImpl(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec16
597
    if (instances == 0)
696
    if (instances == 0)
598
    {
697
    {
599
        // Normal draw
698
        // Normal draw
600
        mRenderEncoder.drawIndexed(mtlType, count, mtlIdxType, idxBuffer, convertedOffset);
699
        mRenderEncoder.drawIndexed(mtlType, convertedCounti32, mtlIdxType, idxBuffer,
700
                                   convertedOffset);
601
    }
701
    }
602
    else
702
    else
603
    {
703
    {
604
        // Instanced draw
704
        // Instanced draw
605
        mRenderEncoder.drawIndexedInstanced(mtlType, count, mtlIdxType, idxBuffer, convertedOffset,
705
        execDrawIndexedInstanced(mtlType, convertedCounti32, mtlIdxType, idxBuffer, convertedOffset,
606
                                            instanceCount);
706
                                 instanceCount);
607
    }
707
    }
608
708
609
    return angle::Result::Continue;
709
    return angle::Result::Continue;
Lines 625-631 angle::Result ContextMtl::drawElementsBaseVertex(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec17
625
                                                 const void *indices,
725
                                                 const void *indices,
626
                                                 GLint baseVertex)
726
                                                 GLint baseVertex)
627
{
727
{
628
    // NOTE(hqle): ES 3.2
629
    UNIMPLEMENTED();
728
    UNIMPLEMENTED();
630
    return angle::Result::Stop;
729
    return angle::Result::Stop;
631
}
730
}
Lines 649-658 angle::Result ContextMtl::drawElementsInstancedBaseVertex(const gl::Context *con a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec18
649
                                                          GLsizei count,
748
                                                          GLsizei count,
650
                                                          gl::DrawElementsType type,
749
                                                          gl::DrawElementsType type,
651
                                                          const void *indices,
750
                                                          const void *indices,
652
                                                          GLsizei instanceCount,
751
                                                          GLsizei instances,
653
                                                          GLint baseVertex)
752
                                                          GLint baseVertex)
654
{
753
{
655
    // NOTE(hqle): ES 3.2
656
    UNIMPLEMENTED();
754
    UNIMPLEMENTED();
657
    return angle::Result::Stop;
755
    return angle::Result::Stop;
658
}
756
}
Lines 669-675 angle::Result ContextMtl::drawElementsInstancedBaseVertexBaseInstance(const gl:: a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec19
669
    UNIMPLEMENTED();
767
    UNIMPLEMENTED();
670
    return angle::Result::Stop;
768
    return angle::Result::Stop;
671
}
769
}
672
673
angle::Result ContextMtl::drawRangeElements(const gl::Context *context,
770
angle::Result ContextMtl::drawRangeElements(const gl::Context *context,
674
                                            gl::PrimitiveMode mode,
771
                                            gl::PrimitiveMode mode,
675
                                            GLuint start,
772
                                            GLuint start,
Lines 690-696 angle::Result ContextMtl::drawRangeElementsBaseVertex(const gl::Context *context a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec20
690
                                                      const void *indices,
787
                                                      const void *indices,
691
                                                      GLint baseVertex)
788
                                                      GLint baseVertex)
692
{
789
{
693
    // NOTE(hqle): ES 3.2
694
    UNIMPLEMENTED();
790
    UNIMPLEMENTED();
695
    return angle::Result::Stop;
791
    return angle::Result::Stop;
696
}
792
}
Lines 713-718 angle::Result ContextMtl::drawElementsIndirect(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec21
713
    return angle::Result::Stop;
809
    return angle::Result::Stop;
714
}
810
}
715
811
812
void ContextMtl::execDrawInstanced(MTLPrimitiveType primitiveType,
813
                                   uint32_t vertexStart,
814
                                   uint32_t vertexCount,
815
                                   uint32_t instances)
816
{
817
    if (getDisplay()->getFeatures().hasBaseVertexInstancedDraw.enabled)
818
    {
819
        mRenderEncoder.drawInstanced(primitiveType, vertexStart, vertexCount, instances);
820
    }
821
    else
822
    {
823
        mRenderEncoder.draw(primitiveType, vertexStart, vertexCount);
824
        for (uint32_t inst = 1; inst < instances; ++inst)
825
        {
826
            mDriverUniforms.emulatedInstanceID = inst;
827
828
            mRenderEncoder.setVertexData(mDriverUniforms, mtl::kDriverUniformsBindingIndex);
829
830
            mVertexArray->emulateInstanceDrawStep(&mRenderEncoder, inst);
831
832
            mRenderEncoder.draw(primitiveType, vertexStart, vertexCount);
833
        }
834
        // Reset instance ID to zero
835
        mVertexArray->emulateInstanceDrawStep(&mRenderEncoder, 0);
836
    }
837
}
838
839
void ContextMtl::execDrawIndexedInstanced(MTLPrimitiveType primitiveType,
840
                                          uint32_t indexCount,
841
                                          MTLIndexType indexType,
842
                                          const mtl::BufferRef &indexBuffer,
843
                                          size_t bufferOffset,
844
                                          uint32_t instances)
845
{
846
    if (getDisplay()->getFeatures().hasBaseVertexInstancedDraw.enabled)
847
    {
848
        mRenderEncoder.drawIndexedInstanced(primitiveType, indexCount, indexType, indexBuffer,
849
                                            bufferOffset, instances);
850
    }
851
    else
852
    {
853
        mRenderEncoder.drawIndexed(primitiveType, indexCount, indexType, indexBuffer, bufferOffset);
854
        for (uint32_t inst = 1; inst < instances; ++inst)
855
        {
856
            mDriverUniforms.emulatedInstanceID = inst;
857
858
            mRenderEncoder.setVertexData(mDriverUniforms, mtl::kDriverUniformsBindingIndex);
859
860
            mVertexArray->emulateInstanceDrawStep(&mRenderEncoder, inst);
861
862
            mRenderEncoder.drawIndexed(primitiveType, indexCount, indexType, indexBuffer,
863
                                       bufferOffset);
864
        }
865
        // Reset instance ID to zero
866
        mVertexArray->emulateInstanceDrawStep(&mRenderEncoder, 0);
867
    }
868
}
869
716
angle::Result ContextMtl::multiDrawArrays(const gl::Context *context,
870
angle::Result ContextMtl::multiDrawArrays(const gl::Context *context,
717
                                          gl::PrimitiveMode mode,
871
                                          gl::PrimitiveMode mode,
718
                                          const GLint *firsts,
872
                                          const GLint *firsts,
Lines 802-816 std::string ContextMtl::getRendererDescription() const a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec22
802
// EXT_debug_marker
956
// EXT_debug_marker
803
angle::Result ContextMtl::insertEventMarker(GLsizei length, const char *marker)
957
angle::Result ContextMtl::insertEventMarker(GLsizei length, const char *marker)
804
{
958
{
959
    mCmdBuffer.insertDebugSign(ConvertMarkerToCpp(length, marker));
805
    return angle::Result::Continue;
960
    return angle::Result::Continue;
806
}
961
}
807
962
808
angle::Result ContextMtl::pushGroupMarker(GLsizei length, const char *marker)
963
angle::Result ContextMtl::pushGroupMarker(GLsizei length, const char *marker)
809
{
964
{
810
    mCmdBuffer.pushDebugGroup(ConvertMarkerToString(length, marker));
965
    mCmdBuffer.pushDebugGroup(ConvertMarkerToCpp(length, marker));
811
    return angle::Result::Continue;
966
    return angle::Result::Continue;
812
}
967
}
813
814
angle::Result ContextMtl::popGroupMarker()
968
angle::Result ContextMtl::popGroupMarker()
815
{
969
{
816
    mCmdBuffer.popDebugGroup();
970
    mCmdBuffer.popDebugGroup();
Lines 1155-1164 QueryImpl *ContextMtl::createQuery(gl::QueryType type) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec23
1155
{
1309
{
1156
    return new QueryMtl(type);
1310
    return new QueryMtl(type);
1157
}
1311
}
1312
1158
FenceNVImpl *ContextMtl::createFenceNV()
1313
FenceNVImpl *ContextMtl::createFenceNV()
1159
{
1314
{
1160
    return new FenceNVMtl();
1315
    return new FenceNVMtl();
1161
}
1316
}
1317
1162
SyncImpl *ContextMtl::createSync()
1318
SyncImpl *ContextMtl::createSync()
1163
{
1319
{
1164
    return new SyncMtl();
1320
    return new SyncMtl();
Lines 1205-1210 OverlayImpl *ContextMtl::createOverlay(const gl::OverlayState &state) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec24
1205
    return nullptr;
1361
    return nullptr;
1206
}
1362
}
1207
1363
1364
void ContextMtl::invalidateCurrentTransformFeedbackBuffers()
1365
{
1366
    if (getDisplay()->getFeatures().emulateTransformFeedback.enabled)
1367
    {
1368
        mDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
1369
    }
1370
}
1371
1372
void ContextMtl::onTransformFeedbackStateChanged()
1373
{
1374
    if (getDisplay()->getFeatures().emulateTransformFeedback.enabled)
1375
    {
1376
        invalidateDriverUniforms();
1377
    }
1378
}
1379
1380
angle::Result ContextMtl::onBeginTransformFeedback(
1381
    size_t bufferCount,
1382
    const gl::TransformFeedbackBuffersArray<BufferMtl *> &buffers)
1383
{
1384
    onTransformFeedbackStateChanged();
1385
1386
    for (size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
1387
    {
1388
        if (mCurrentTransformFeedbackBuffers.count(buffers[bufferIndex]) != 0)
1389
        {
1390
            endEncoding(mRenderEncoder);
1391
            break;
1392
        }
1393
    }
1394
1395
    populateTransformFeedbackBufferSet(bufferCount, buffers);
1396
1397
    return angle::Result::Continue;
1398
}
1399
1400
void ContextMtl::populateTransformFeedbackBufferSet(
1401
    size_t bufferCount,
1402
    const gl::TransformFeedbackBuffersArray<BufferMtl *> &buffers)
1403
{
1404
    for (size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
1405
    {
1406
        mCurrentTransformFeedbackBuffers.insert(buffers[bufferIndex]);
1407
    }
1408
}
1409
1410
void ContextMtl::onEndTransformFeedback()
1411
{
1412
    if (getDisplay()->getFeatures().emulateTransformFeedback.enabled)
1413
    {
1414
        onTransformFeedbackStateChanged();
1415
    }
1416
}
1417
1418
angle::Result ContextMtl::onPauseTransformFeedback()
1419
{
1420
    if (getDisplay()->getFeatures().emulateTransformFeedback.enabled)
1421
    {
1422
        onTransformFeedbackStateChanged();
1423
    }
1424
    return angle::Result::Continue;
1425
}
1426
1208
angle::Result ContextMtl::dispatchCompute(const gl::Context *context,
1427
angle::Result ContextMtl::dispatchCompute(const gl::Context *context,
1209
                                          GLuint numGroupsX,
1428
                                          GLuint numGroupsX,
1210
                                          GLuint numGroupsY,
1429
                                          GLuint numGroupsY,
Lines 1331-1336 const mtl::Format &ContextMtl::getPixelFormat(angle::FormatID angleFormatId) con a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec25
1331
    return getDisplay()->getPixelFormat(angleFormatId);
1550
    return getDisplay()->getPixelFormat(angleFormatId);
1332
}
1551
}
1333
1552
1553
const mtl::FormatCaps &ContextMtl::getNativeFormatCaps(MTLPixelFormat mtlFormat) const
1554
{
1555
    return getDisplay()->getNativeFormatCaps(mtlFormat);
1556
}
1557
1334
// See mtl::FormatTable::getVertexFormat()
1558
// See mtl::FormatTable::getVertexFormat()
1335
const mtl::VertexFormat &ContextMtl::getVertexFormat(angle::FormatID angleFormatId,
1559
const mtl::VertexFormat &ContextMtl::getVertexFormat(angle::FormatID angleFormatId,
1336
                                                     bool tightlyPacked) const
1560
                                                     bool tightlyPacked) const
Lines 1338-1348 const mtl::VertexFormat &ContextMtl::getVertexFormat(angle::FormatID angleFormat a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec26
1338
    return getDisplay()->getVertexFormat(angleFormatId, tightlyPacked);
1562
    return getDisplay()->getVertexFormat(angleFormatId, tightlyPacked);
1339
}
1563
}
1340
1564
1341
const mtl::FormatCaps &ContextMtl::getNativeFormatCaps(MTLPixelFormat mtlFormat) const
1342
{
1343
    return getDisplay()->getNativeFormatCaps(mtlFormat);
1344
}
1345
1346
angle::Result ContextMtl::getIncompleteTexture(const gl::Context *context,
1565
angle::Result ContextMtl::getIncompleteTexture(const gl::Context *context,
1347
                                               gl::TextureType type,
1566
                                               gl::TextureType type,
1348
                                               gl::Texture **textureOut)
1567
                                               gl::Texture **textureOut)
Lines 1362-1367 void ContextMtl::endRenderEncoding(mtl::RenderCommandEncoder *encoder) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec27
1362
1581
1363
    // Resolve visibility results
1582
    // Resolve visibility results
1364
    mOcclusionQueryPool.resolveVisibilityResults(this);
1583
    mOcclusionQueryPool.resolveVisibilityResults(this);
1584
1585
    mCurrentTransformFeedbackBuffers.clear();
1586
1587
    // Reset serials for XFB if active.
1588
    if (mState.isTransformFeedbackActiveUnpaused())
1589
    {
1590
        const gl::ProgramExecutable *executable = mState.getProgramExecutable();
1591
        ASSERT(executable);
1592
        size_t xfbBufferCount = executable->getTransformFeedbackBufferCount();
1593
1594
        TransformFeedbackMtl *transformFeedbackMtl =
1595
            mtl::GetImpl(mState.getCurrentTransformFeedback());
1596
1597
        populateTransformFeedbackBufferSet(xfbBufferCount,
1598
                                           transformFeedbackMtl->getBufferHandles());
1599
    }
1365
}
1600
}
1366
1601
1367
void ContextMtl::endEncoding(bool forceSaveRenderPassContent)
1602
void ContextMtl::endEncoding(bool forceSaveRenderPassContent)
Lines 1390-1396 void ContextMtl::endEncoding(bool forceSaveRenderPassContent) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec28
1390
1625
1391
void ContextMtl::flushCommandBufer()
1626
void ContextMtl::flushCommandBufer()
1392
{
1627
{
1393
    if (!mCmdBuffer.ready())
1628
    if (!mCmdBuffer.valid())
1394
    {
1629
    {
1395
        return;
1630
        return;
1396
    }
1631
    }
Lines 1454-1459 mtl::RenderCommandEncoder *ContextMtl::getRenderPassCommandEncoder(const mtl::Re a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec29
1454
    // Need to re-apply everything on next draw call.
1689
    // Need to re-apply everything on next draw call.
1455
    mDirtyBits.set();
1690
    mDirtyBits.set();
1456
1691
1692
    id<MTLDevice> metalDevice = getDisplay()->getMetalDevice();
1693
    if (mtl::DeviceHasMaximumRenderTargetSize(metalDevice))
1694
    {
1695
        MTLRenderPassDescriptor *objCDesc = [MTLRenderPassDescriptor renderPassDescriptor];
1696
        desc.convertToMetalDesc(objCDesc);
1697
        NSUInteger maxSize = mtl::GetMaxRenderTargetSizeForDeviceInBytes(metalDevice);
1698
        NSUInteger renderTargetSize =
1699
            ComputeTotalSizeUsedForMTLRenderPassDescriptor(objCDesc, this, metalDevice);
1700
        if (renderTargetSize > maxSize)
1701
        {
1702
            NSString *errorString =
1703
                [NSString stringWithFormat:@"This set of render targets requires %lu bytes of "
1704
                                           @"pixel storage. This device supports %lu bytes.",
1705
                                           (unsigned long)renderTargetSize, (unsigned long)maxSize];
1706
            NSError *err = [NSError errorWithDomain:@"MTLValidationError"
1707
                                               code:-1
1708
                                           userInfo:@{NSLocalizedDescriptionKey : errorString}];
1709
            this->handleError(err, __FILE__, ANGLE_FUNCTION, __LINE__);
1710
            return nil;
1711
        }
1712
    }
1457
    return &mRenderEncoder.restart(desc);
1713
    return &mRenderEncoder.restart(desc);
1458
}
1714
}
1459
1715
Lines 1467-1477 mtl::RenderCommandEncoder *ContextMtl::getTextureRenderCommandEncoder( a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec30
1467
1723
1468
    mtl::RenderPassDesc rpDesc;
1724
    mtl::RenderPassDesc rpDesc;
1469
1725
1470
    rpDesc.colorAttachments[0].texture      = textureTarget;
1726
    rpDesc.colorAttachments[0].renderTarget->texture = textureTarget;
1471
    rpDesc.colorAttachments[0].level        = index.getNativeLevel();
1727
    rpDesc.colorAttachments[0].renderTarget->level   = index.getNativeLevel();
1472
    rpDesc.colorAttachments[0].sliceOrDepth = index.hasLayer() ? index.getLayerIndex() : 0;
1728
    rpDesc.colorAttachments[0].renderTarget->sliceOrDepth =
1473
    rpDesc.numColorAttachments              = 1;
1729
        index.hasLayer() ? index.getLayerIndex() : 0;
1474
    rpDesc.sampleCount                      = textureTarget->samples();
1730
    rpDesc.numColorAttachments = 1;
1731
    rpDesc.sampleCount         = textureTarget->samples();
1475
1732
1476
    return getRenderPassCommandEncoder(rpDesc);
1733
    return getRenderPassCommandEncoder(rpDesc);
1477
}
1734
}
Lines 1536-1547 mtl::ComputeCommandEncoder *ContextMtl::getComputeCommandEncoder() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec31
1536
1793
1537
void ContextMtl::ensureCommandBufferReady()
1794
void ContextMtl::ensureCommandBufferReady()
1538
{
1795
{
1539
    if (!mCmdBuffer.ready())
1796
    if (!mCmdBuffer.valid())
1540
    {
1797
    {
1541
        mCmdBuffer.restart();
1798
        mCmdBuffer.restart();
1542
    }
1799
    }
1543
1800
1544
    ASSERT(mCmdBuffer.ready());
1801
    ASSERT(mCmdBuffer.valid());
1545
}
1802
}
1546
1803
1547
void ContextMtl::updateViewport(FramebufferMtl *framebufferMtl,
1804
void ContextMtl::updateViewport(FramebufferMtl *framebufferMtl,
Lines 1677-1683 void ContextMtl::onDrawFrameBufferChangedState(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec32
1677
    }
1934
    }
1678
}
1935
}
1679
1936
1680
void ContextMtl::onBackbufferResized(const gl::Context *context, WindowSurfaceMtl *backbuffer)
1937
void ContextMtl::onBackbufferResized(const gl::Context *context, SurfaceMtlProtocol *backbuffer)
1681
{
1938
{
1682
    const gl::State &glState    = getState();
1939
    const gl::State &glState    = getState();
1683
    FramebufferMtl *framebuffer = mtl::GetImpl(glState.getDrawFramebuffer());
1940
    FramebufferMtl *framebuffer = mtl::GetImpl(glState.getDrawFramebuffer());
Lines 1686-1695 void ContextMtl::onBackbufferResized(const gl::Context *context, WindowSurfaceMt a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec33
1686
        return;
1943
        return;
1687
    }
1944
    }
1688
1945
1946
    updateViewport(framebuffer, glState.getViewport(), glState.getNearPlane(),
1947
                   glState.getFarPlane());
1948
    updateScissor(glState);
1689
    onDrawFrameBufferChangedState(context, framebuffer, true);
1949
    onDrawFrameBufferChangedState(context, framebuffer, true);
1690
}
1950
}
1691
1951
1692
angle::Result ContextMtl::onOcclusionQueryBegin(const gl::Context *context, QueryMtl *query)
1952
angle::Result ContextMtl::onOcclusionQueryBegan(const gl::Context *context, QueryMtl *query)
1693
{
1953
{
1694
    ASSERT(mOcclusionQuery == nullptr);
1954
    ASSERT(mOcclusionQuery == nullptr);
1695
    mOcclusionQuery = query;
1955
    mOcclusionQuery = query;
Lines 1706-1712 angle::Result ContextMtl::onOcclusionQueryBegin(const gl::Context *context, Quer a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec34
1706
1966
1707
    return angle::Result::Continue;
1967
    return angle::Result::Continue;
1708
}
1968
}
1709
void ContextMtl::onOcclusionQueryEnd(const gl::Context *context, QueryMtl *query)
1969
void ContextMtl::onOcclusionQueryEnded(const gl::Context *context, QueryMtl *query)
1710
{
1970
{
1711
    ASSERT(mOcclusionQuery == query);
1971
    ASSERT(mOcclusionQuery == query);
1712
1972
Lines 1718-1724 void ContextMtl::onOcclusionQueryEnd(const gl::Context *context, QueryMtl *query a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec35
1718
1978
1719
    mOcclusionQuery = nullptr;
1979
    mOcclusionQuery = nullptr;
1720
}
1980
}
1721
void ContextMtl::onOcclusionQueryDestroy(const gl::Context *context, QueryMtl *query)
1981
void ContextMtl::onOcclusionQueryDestroyed(const gl::Context *context, QueryMtl *query)
1722
{
1982
{
1723
    if (query->getAllocatedVisibilityOffsets().empty())
1983
    if (query->getAllocatedVisibilityOffsets().empty())
1724
    {
1984
    {
Lines 1726-1732 void ContextMtl::onOcclusionQueryDestroy(const gl::Context *context, QueryMtl *q a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec36
1726
    }
1986
    }
1727
    if (mOcclusionQuery == query)
1987
    if (mOcclusionQuery == query)
1728
    {
1988
    {
1729
        onOcclusionQueryEnd(context, query);
1989
        onOcclusionQueryEnded(context, query);
1730
    }
1990
    }
1731
    mOcclusionQueryPool.deallocateQueryOffset(this, query);
1991
    mOcclusionQueryPool.deallocateQueryOffset(this, query);
1732
}
1992
}
Lines 1770-1789 angle::Result ContextMtl::startOcclusionQueryInRenderPass(QueryMtl *query, bool a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec37
1770
    return angle::Result::Continue;
2030
    return angle::Result::Continue;
1771
}
2031
}
1772
2032
1773
void ContextMtl::onTransformFeedbackActive(const gl::Context *context, TransformFeedbackMtl *xfb)
1774
{
1775
    // NOTE(hqle): We have to end current render pass to enable synchronization before XFB
1776
    // buffers could be used as vertex input. Consider a better approach.
1777
    endEncoding(true);
1778
}
1779
1780
void ContextMtl::onTransformFeedbackInactive(const gl::Context *context, TransformFeedbackMtl *xfb)
1781
{
1782
    // NOTE(hqle): We have to end current render pass to enable synchronization before XFB
1783
    // buffers could be used as vertex input. Consider a better approach.
1784
    endEncoding(true);
1785
}
1786
1787
void ContextMtl::queueEventSignal(const mtl::SharedEventRef &event, uint64_t value)
2033
void ContextMtl::queueEventSignal(const mtl::SharedEventRef &event, uint64_t value)
1788
{
2034
{
1789
    ensureCommandBufferReady();
2035
    ensureCommandBufferReady();
Lines 1842-1851 angle::Result ContextMtl::setupDraw(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec38
1842
                                    GLsizei instances,
2088
                                    GLsizei instances,
1843
                                    gl::DrawElementsType indexTypeOrNone,
2089
                                    gl::DrawElementsType indexTypeOrNone,
1844
                                    const void *indices,
2090
                                    const void *indices,
1845
                                    bool xfbPass)
2091
                                    bool transformFeedbackDraw)
1846
{
2092
{
1847
    ASSERT(mProgram);
2093
    ASSERT(mProgram);
1848
2094
2095
    // Update transform feedback offsets on every draw call.
2096
    if (mState.isTransformFeedbackActiveUnpaused())
2097
    {
2098
        ASSERT(firstVertex != -1);
2099
        mXfbBaseVertex             = firstVertex;
2100
        mXfbVertexCountPerInstance = vertexOrIndexCount;
2101
        invalidateDriverUniforms();
2102
    }
2103
1849
    // instances=0 means no instanced draw.
2104
    // instances=0 means no instanced draw.
1850
    GLsizei instanceCount = instances ? instances : 1;
2105
    GLsizei instanceCount = instances ? instances : 1;
1851
2106
Lines 1862-1881 angle::Result ContextMtl::setupDraw(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec39
1862
        ANGLE_TRY(handleDirtyActiveTextures(context));
2117
        ANGLE_TRY(handleDirtyActiveTextures(context));
1863
    }
2118
    }
1864
2119
1865
    if (mDirtyBits.test(DIRTY_BIT_RASTERIZER_DISCARD))
1866
    {
1867
        if (getState().isTransformFeedbackActiveUnpaused())
1868
        {
1869
            // If XFB is active we need to reset render pass since we could use a dummy render
1870
            // target if only XFB is needed.
1871
            invalidateState(context);
1872
        }
1873
        else
1874
        {
1875
            invalidateRenderPipeline();
1876
        }
1877
    }
1878
1879
    if (!mRenderEncoder.valid())
2120
    if (!mRenderEncoder.valid())
1880
    {
2121
    {
1881
        // re-apply everything
2122
        // re-apply everything
Lines 1884-1890 angle::Result ContextMtl::setupDraw(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec40
1884
2125
1885
    if (mDirtyBits.test(DIRTY_BIT_DRAW_FRAMEBUFFER))
2126
    if (mDirtyBits.test(DIRTY_BIT_DRAW_FRAMEBUFFER))
1886
    {
2127
    {
1887
        ANGLE_TRY(handleDirtyRenderPass(context));
2128
        // Start new render command encoder
2129
        ANGLE_MTL_TRY(this, mDrawFramebuffer->ensureRenderPassStarted(context));
2130
2131
        // re-apply everything
2132
        invalidateState(context);
1888
    }
2133
    }
1889
2134
1890
    if (mOcclusionQuery && mOcclusionQueryPool.getNumRenderPassAllocatedQueries() == 0)
2135
    if (mOcclusionQuery && mOcclusionQueryPool.getNumRenderPassAllocatedQueries() == 0)
Lines 1894-1910 angle::Result ContextMtl::setupDraw(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec41
1894
        ANGLE_TRY(startOcclusionQueryInRenderPass(mOcclusionQuery, false));
2139
        ANGLE_TRY(startOcclusionQueryInRenderPass(mOcclusionQuery, false));
1895
    }
2140
    }
1896
2141
1897
    bool isPipelineDescChanged;
2142
    bool changedPipeline;
1898
    ANGLE_TRY(checkIfPipelineChanged(context, mode, xfbPass, &isPipelineDescChanged));
2143
    ANGLE_TRY(checkIfPipelineChanged(context, mode, mState.isTransformFeedbackActive(),
2144
                                     &changedPipeline));
1899
2145
1900
    bool uniformBuffersDirty = false;
2146
    bool uniformBuffersDirty = false;
1901
1902
    if (IsTransformFeedbackOnly(getState()))
1903
    {
1904
        // Filter out unneeded dirty bits
1905
        filterOutXFBOnlyDirtyBits(context);
1906
    }
1907
1908
    for (size_t bit : mDirtyBits)
2147
    for (size_t bit : mDirtyBits)
1909
    {
2148
    {
1910
        switch (bit)
2149
        switch (bit)
Lines 1953-1960 angle::Result ContextMtl::setupDraw(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec42
1953
            case DIRTY_BIT_UNIFORM_BUFFERS_BINDING:
2192
            case DIRTY_BIT_UNIFORM_BUFFERS_BINDING:
1954
                uniformBuffersDirty = true;
2193
                uniformBuffersDirty = true;
1955
                break;
2194
                break;
2195
            case DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS:
2196
                ANGLE_TRY(handleDirtyGraphicsTransformFeedbackBuffersEmulation(context));
2197
                break;
1956
            case DIRTY_BIT_RASTERIZER_DISCARD:
2198
            case DIRTY_BIT_RASTERIZER_DISCARD:
1957
                // Already handled.
1958
                break;
2199
                break;
1959
            default:
2200
            default:
1960
                UNREACHABLE();
2201
                UNREACHABLE();
Lines 1962-2043 angle::Result ContextMtl::setupDraw(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec43
1962
        }
2203
        }
1963
    }
2204
    }
1964
2205
1965
    if (xfbPass && !mDirtyBits.test(DIRTY_BIT_DRIVER_UNIFORMS))
1966
    {
1967
        // If handleDirtyDriverUniforms() was not called and this is XFB pass, we still need to
1968
        // update XFB related uniforms
1969
        ANGLE_TRY(
1970
            fillDriverXFBUniforms(firstVertex, vertexOrIndexCount, /** skippedInstances */ 0));
1971
        mRenderEncoder.setVertexData(mDriverUniforms, mtl::kDriverUniformsBindingIndex);
1972
    }
1973
1974
    mDirtyBits.reset();
2206
    mDirtyBits.reset();
1975
2207
1976
    ANGLE_TRY(mProgram->setupDraw(context, &mRenderEncoder, mRenderPipelineDesc,
2208
    if (transformFeedbackDraw)
1977
                                  isPipelineDescChanged, textureChanged, uniformBuffersDirty));
1978
1979
    return angle::Result::Continue;
1980
}
1981
1982
void ContextMtl::filterOutXFBOnlyDirtyBits(const gl::Context *context)
1983
{
1984
    ASSERT(IsTransformFeedbackOnly(getState()));
1985
1986
    ASSERT(mRenderEncoder.renderPassDesc().colorAttachments[0].texture == mDummyXFBRenderTexture);
1987
1988
    // In transform feedback only pass, only vertex shader's related states are needed.
1989
    constexpr size_t kUnneededBits =
1990
        angle::Bit<size_t>(DIRTY_BIT_DEPTH_STENCIL_DESC) |
1991
        angle::Bit<size_t>(DIRTY_BIT_DEPTH_BIAS) | angle::Bit<size_t>(DIRTY_BIT_STENCIL_REF) |
1992
        angle::Bit<size_t>(DIRTY_BIT_BLEND_COLOR) | angle::Bit<size_t>(DIRTY_BIT_VIEWPORT) |
1993
        angle::Bit<size_t>(DIRTY_BIT_SCISSOR) | angle::Bit<size_t>(DIRTY_BIT_CULL_MODE) |
1994
        angle::Bit<size_t>(DIRTY_BIT_WINDING);
1995
1996
    mDirtyBits &= ~kUnneededBits;
1997
}
1998
1999
angle::Result ContextMtl::handleDirtyRenderPass(const gl::Context *context)
2000
{
2001
    if (!IsTransformFeedbackOnly(mState))
2002
    {
2209
    {
2003
        // Start new render command encoder
2210
        mtl::RenderUtils &utils = getDisplay()->getUtils();
2004
        ANGLE_MTL_TRY(this, mDrawFramebuffer->ensureRenderPassStarted(context));
2211
        angle::Result result =
2005
    }
2212
            utils.createTransformFeedbackPSO(context, &mRenderEncoder, mRenderPipelineDesc);
2006
    else
2213
        ANGLE_UNUSED_VARIABLE(result);
2007
    {
2214
        assert(result == angle::Result::Continue);
2008
        // XFB is active and rasterization is disabled. Use dummy render target.
2215
        changedPipeline = true;
2009
        // We currently need to end the render pass when XFB is activated/deactivated so using
2010
        // a small dummy render target would make the render pass ending very cheap.
2011
        if (!mDummyXFBRenderTexture)
2012
        {
2013
            ANGLE_TRY(mtl::Texture::Make2DTexture(this,
2014
                                                  getPixelFormat(angle::FormatID::R8G8B8A8_UNORM),
2015
                                                  1, 1, 1, true, false, &mDummyXFBRenderTexture));
2016
        }
2017
        mtl::RenderCommandEncoder *encoder = getTextureRenderCommandEncoder(
2018
            mDummyXFBRenderTexture,
2019
            mtl::ImageNativeIndex::FromBaseZeroGLIndex(gl::ImageIndex::Make2D(0)));
2020
        encoder->setColorLoadAction(MTLLoadActionDontCare, MTLClearColor(), 0);
2021
        encoder->setColorStoreAction(MTLStoreActionDontCare);
2022
2023
#ifndef NDEBUG
2024
        encoder->setLabel(@"TransformFeedbackOnlyPass");
2025
#endif
2026
    }
2216
    }
2027
2217
2028
    // re-apply everything
2218
    ANGLE_TRY(mProgram->setupDraw(context, &mRenderEncoder, mRenderPipelineDesc, changedPipeline,
2029
    invalidateState(context);
2219
                                  textureChanged, uniformBuffersDirty, transformFeedbackDraw));
2030
2220
2031
    return angle::Result::Continue;
2221
    return angle::Result::Continue;
2032
}
2222
}
2033
2223
2034
angle::Result ContextMtl::handleDirtyActiveTextures(const gl::Context *context)
2224
angle::Result ContextMtl::handleDirtyActiveTextures(const gl::Context *context)
2035
{
2225
{
2036
    const gl::State &glState   = mState;
2226
    const gl::State &glState                = mState;
2037
    const gl::Program *program = glState.getProgram();
2227
    const gl::ProgramExecutable *executable = context->getState().getProgramExecutable();
2038
2228
2039
    const gl::ActiveTexturesCache &textures     = glState.getActiveTexturesCache();
2229
    const gl::ActiveTexturesCache &textures     = glState.getActiveTexturesCache();
2040
    const gl::ActiveTextureMask &activeTextures = program->getExecutable().getActiveSamplersMask();
2230
    const gl::ActiveTextureMask &activeTextures = executable->getActiveSamplersMask();
2041
2231
2042
    for (size_t textureUnit : activeTextures)
2232
    for (size_t textureUnit : activeTextures)
2043
    {
2233
    {
Lines 2067-2072 angle::Result ContextMtl::handleDirtyDefaultAttribs(const gl::Context *context) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec44
2067
    }
2257
    }
2068
2258
2069
    ASSERT(mRenderEncoder.valid());
2259
    ASSERT(mRenderEncoder.valid());
2260
    mRenderEncoder.setFragmentData(mDefaultAttributes, mtl::kDefaultAttribsBindingIndex);
2070
    mRenderEncoder.setVertexData(mDefaultAttributes, mtl::kDefaultAttribsBindingIndex);
2261
    mRenderEncoder.setVertexData(mDefaultAttributes, mtl::kDefaultAttribsBindingIndex);
2071
2262
2072
    mDirtyDefaultAttribsMask.reset();
2263
    mDirtyDefaultAttribsMask.reset();
Lines 2120-2128 angle::Result ContextMtl::handleDirtyDriverUniforms(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec45
2120
    }
2311
    }
2121
    mDriverUniforms.coverageMask = coverageMask;
2312
    mDriverUniforms.coverageMask = coverageMask;
2122
2313
2123
    ANGLE_TRY(
2124
        fillDriverXFBUniforms(drawCallFirstVertex, verticesPerInstance, /** skippedInstances */ 0));
2125
2126
    ASSERT(mRenderEncoder.valid());
2314
    ASSERT(mRenderEncoder.valid());
2127
    mRenderEncoder.setFragmentData(mDriverUniforms, mtl::kDriverUniformsBindingIndex);
2315
    mRenderEncoder.setFragmentData(mDriverUniforms, mtl::kDriverUniformsBindingIndex);
2128
    mRenderEncoder.setVertexData(mDriverUniforms, mtl::kDriverUniformsBindingIndex);
2316
    mRenderEncoder.setVertexData(mDriverUniforms, mtl::kDriverUniformsBindingIndex);
Lines 2130-2154 angle::Result ContextMtl::handleDirtyDriverUniforms(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec46
2130
    return angle::Result::Continue;
2318
    return angle::Result::Continue;
2131
}
2319
}
2132
2320
2133
angle::Result ContextMtl::fillDriverXFBUniforms(GLint drawCallFirstVertex,
2321
angle::Result ContextMtl::handleDirtyGraphicsTransformFeedbackBuffersEmulation(
2134
                                                uint32_t verticesPerInstance,
2322
    const gl::Context *context)
2135
                                                uint32_t skippedInstances)
2136
{
2323
{
2137
    gl::TransformFeedback *transformFeedback = getState().getCurrentTransformFeedback();
2324
    const gl::ProgramExecutable *executable = mState.getProgramExecutable();
2325
    ASSERT(executable);
2138
2326
2139
    mDriverUniforms.xfbActiveUnpaused = getState().isTransformFeedbackActiveUnpaused();
2327
    if (!executable->hasTransformFeedbackOutput() || !mState.isTransformFeedbackActive())
2140
    if (!transformFeedback || !mDriverUniforms.xfbActiveUnpaused)
2141
    {
2328
    {
2142
        return angle::Result::Continue;
2329
        return angle::Result::Continue;
2143
    }
2330
    }
2144
2331
2145
    mDriverUniforms.xfbVerticesPerDraw = verticesPerInstance;
2332
    TransformFeedbackMtl *transformFeedbackMtl = mtl::GetImpl(mState.getCurrentTransformFeedback());
2333
    size_t bufferCount                         = executable->getTransformFeedbackBufferCount();
2334
    const gl::TransformFeedbackBuffersArray<BufferMtl *> &bufferHandles =
2335
        transformFeedbackMtl->getBufferHandles();
2146
2336
2147
    TransformFeedbackMtl *transformFeedbackMtl = mtl::GetImpl(transformFeedback);
2337
    for (size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
2338
    {
2339
        BufferMtl *bufferHandle = bufferHandles[bufferIndex];
2340
        ASSERT(bufferHandle);
2341
        ASSERT(mRenderEncoder.valid());
2342
        mRenderEncoder.setBufferForWrite(
2343
            gl::ShaderType::Vertex, bufferHandle->getCurrentBuffer(), 0,
2344
            mtl::kTransformFeedbackBindingIndex + (uint32_t)bufferIndex);
2345
    }
2148
2346
2149
    return transformFeedbackMtl->getBufferOffsets(this, drawCallFirstVertex,
2347
    return angle::Result::Continue;
2150
                                                  verticesPerInstance * skippedInstances,
2151
                                                  mDriverUniforms.xfbBufferOffsets);
2152
}
2348
}
2153
2349
2154
angle::Result ContextMtl::handleDirtyDepthStencilState(const gl::Context *context)
2350
angle::Result ContextMtl::handleDirtyDepthStencilState(const gl::Context *context)
Lines 2159-2171 angle::Result ContextMtl::handleDirtyDepthStencilState(const gl::Context *contex a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec47
2159
    mtl::DepthStencilDesc dsDesc              = mDepthStencilDesc;
2355
    mtl::DepthStencilDesc dsDesc              = mDepthStencilDesc;
2160
    const mtl::RenderPassDesc &renderPassDesc = mRenderEncoder.renderPassDesc();
2356
    const mtl::RenderPassDesc &renderPassDesc = mRenderEncoder.renderPassDesc();
2161
2357
2162
    if (!renderPassDesc.depthAttachment.texture)
2358
    if (!renderPassDesc.depthAttachment.texture())
2163
    {
2359
    {
2164
        dsDesc.depthWriteEnabled    = false;
2360
        dsDesc.depthWriteEnabled    = false;
2165
        dsDesc.depthCompareFunction = MTLCompareFunctionAlways;
2361
        dsDesc.depthCompareFunction = MTLCompareFunctionAlways;
2166
    }
2362
    }
2167
2363
2168
    if (!renderPassDesc.stencilAttachment.texture)
2364
    if (!renderPassDesc.stencilAttachment.texture())
2169
    {
2365
    {
2170
        dsDesc.frontFaceStencil.reset();
2366
        dsDesc.frontFaceStencil.reset();
2171
        dsDesc.backFaceStencil.reset();
2367
        dsDesc.backFaceStencil.reset();
Lines 2196-2203 angle::Result ContextMtl::handleDirtyDepthBias(const gl::Context *context) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec48
2196
2392
2197
angle::Result ContextMtl::checkIfPipelineChanged(const gl::Context *context,
2393
angle::Result ContextMtl::checkIfPipelineChanged(const gl::Context *context,
2198
                                                 gl::PrimitiveMode primitiveMode,
2394
                                                 gl::PrimitiveMode primitiveMode,
2199
                                                 bool xfbPass,
2395
                                                 bool xbfPass,
2200
                                                 bool *isPipelineDescChanged)
2396
                                                 bool *pipelineDescChanged)
2201
{
2397
{
2202
    ASSERT(mRenderEncoder.valid());
2398
    ASSERT(mRenderEncoder.valid());
2203
    mtl::PrimitiveTopologyClass topologyClass = mtl::GetPrimitiveTopologyClass(primitiveMode);
2399
    mtl::PrimitiveTopologyClass topologyClass = mtl::GetPrimitiveTopologyClass(primitiveMode);
Lines 2216-2239 angle::Result ContextMtl::checkIfPipelineChanged(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec49
2216
        renderPassDesc.populateRenderPipelineOutputDesc(mBlendDesc,
2412
        renderPassDesc.populateRenderPipelineOutputDesc(mBlendDesc,
2217
                                                        &mRenderPipelineDesc.outputDescriptor);
2413
                                                        &mRenderPipelineDesc.outputDescriptor);
2218
2414
2219
        if (xfbPass)
2220
        {
2221
            // In XFB pass, we disable fragment shader.
2222
            mRenderPipelineDesc.rasterizationType = mtl::RenderPipelineRasterization::Disabled;
2223
        }
2224
        else if (mState.isRasterizerDiscardEnabled())
2225
        {
2226
            // If XFB is not active and rasterizer discard is enabled, we need to emulate the
2227
            // discard. Because in this case, vertex shader might write to stage output values and
2228
            // Metal doesn't allow rasterization to be disabled.
2229
            mRenderPipelineDesc.rasterizationType =
2230
                mtl::RenderPipelineRasterization::EmulatedDiscard;
2231
        }
2232
        else
2233
        {
2234
            mRenderPipelineDesc.rasterizationType = mtl::RenderPipelineRasterization::Enabled;
2235
        }
2236
        mRenderPipelineDesc.inputPrimitiveTopology = topologyClass;
2415
        mRenderPipelineDesc.inputPrimitiveTopology = topologyClass;
2416
        mRenderPipelineDesc.rasterizationType =
2417
            (mState.isRasterizerDiscardEnabled() ? mtl::RenderPipelineRasterization::EmulatedDiscard
2418
                                                 : mtl::RenderPipelineRasterization::Enabled);
2237
        mRenderPipelineDesc.alphaToCoverageEnabled = mState.isSampleAlphaToCoverageEnabled();
2419
        mRenderPipelineDesc.alphaToCoverageEnabled = mState.isSampleAlphaToCoverageEnabled();
2238
        mRenderPipelineDesc.emulateCoverageMask    = mState.isSampleCoverageEnabled();
2420
        mRenderPipelineDesc.emulateCoverageMask    = mState.isSampleCoverageEnabled();
2239
2421
Lines 2241-2247 angle::Result ContextMtl::checkIfPipelineChanged(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm_sec50
2241
            mDrawFramebuffer->getState().getEnabledDrawBuffers());
2423
            mDrawFramebuffer->getState().getEnabledDrawBuffers());
2242
    }
2424
    }
2243
2425
2244
    *isPipelineDescChanged = rppChange;
2426
    *pipelineDescChanged = rppChange;
2245
2427
2246
    return angle::Result::Continue;
2428
    return angle::Result::Continue;
2247
}
2429
}
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.h -5 / +6 lines
Lines 52-57 class DisplayMtl : public DisplayImpl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.h_sec1
52
52
53
    egl::Error waitClient(const gl::Context *context) override;
53
    egl::Error waitClient(const gl::Context *context) override;
54
    egl::Error waitNative(const gl::Context *context, EGLint engine) override;
54
    egl::Error waitNative(const gl::Context *context, EGLint engine) override;
55
    egl::Error validateClientBuffer(const egl::Config *configuration,
56
                                    EGLenum buftype,
57
                                    EGLClientBuffer clientBuffer,
58
                                    const egl::AttributeMap &attribs) const override;
55
59
56
    SurfaceImpl *createWindowSurface(const egl::SurfaceState &state,
60
    SurfaceImpl *createWindowSurface(const egl::SurfaceState &state,
57
                                     EGLNativeWindowType window,
61
                                     EGLNativeWindowType window,
Lines 96-106 class DisplayMtl : public DisplayImpl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.h_sec2
96
100
97
    bool isValidNativeWindow(EGLNativeWindowType window) const override;
101
    bool isValidNativeWindow(EGLNativeWindowType window) const override;
98
102
99
    egl::Error validateClientBuffer(const egl::Config *configuration,
100
                                    EGLenum buftype,
101
                                    EGLClientBuffer clientBuffer,
102
                                    const egl::AttributeMap &attribs) const override;
103
104
    egl::ConfigSet generateConfigs() override;
103
    egl::ConfigSet generateConfigs() override;
105
104
106
    std::string getRendererDescription() const;
105
    std::string getRendererDescription() const;
Lines 165-170 class DisplayMtl : public DisplayImpl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.h_sec3
165
    void initializeExtensions() const;
164
    void initializeExtensions() const;
166
    void initializeTextureCaps() const;
165
    void initializeTextureCaps() const;
167
    void initializeFeatures();
166
    void initializeFeatures();
167
    void initializeLimitations();
168
168
    angle::Result initializeShaderLibrary();
169
    angle::Result initializeShaderLibrary();
169
170
170
    mtl::AutoObjCPtr<id<MTLDevice>> mMetalDevice = nil;
171
    mtl::AutoObjCPtr<id<MTLDevice>> mMetalDevice = nil;
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.mm -218 / +170 lines
Lines 8-19 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.mm_sec1
8
8
9
#include "libANGLE/renderer/metal/DisplayMtl.h"
9
#include "libANGLE/renderer/metal/DisplayMtl.h"
10
10
11
#include "common/system_utils.h"
11
#include "gpu_info_util/SystemInfo.h"
12
#include "gpu_info_util/SystemInfo.h"
12
#include "libANGLE/Context.h"
13
#include "libANGLE/Context.h"
13
#include "libANGLE/Display.h"
14
#include "libANGLE/Display.h"
14
#include "libANGLE/Surface.h"
15
#include "libANGLE/Surface.h"
15
#include "libANGLE/renderer/glslang_wrapper_utils.h"
16
#include "libANGLE/renderer/glslang_wrapper_utils.h"
16
#include "libANGLE/renderer/metal/ContextMtl.h"
17
#include "libANGLE/renderer/metal/ContextMtl.h"
18
#include "libANGLE/renderer/metal/IOSurfaceSurfaceMtl.h"
17
#include "libANGLE/renderer/metal/SurfaceMtl.h"
19
#include "libANGLE/renderer/metal/SurfaceMtl.h"
18
#include "libANGLE/renderer/metal/SyncMtl.h"
20
#include "libANGLE/renderer/metal/SyncMtl.h"
19
#include "libANGLE/renderer/metal/mtl_common.h"
21
#include "libANGLE/renderer/metal/mtl_common.h"
Lines 22-30 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.mm_sec2
22
24
23
#include "EGL/eglext.h"
25
#include "EGL/eglext.h"
24
26
27
#if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
28
constexpr char kANGLEPreferredDeviceEnv[] = "ANGLE_PREFERRED_DEVICE";
29
#endif
30
constexpr char kANGLETransformFeedbackEnv[] = "ANGLE_METAL_XFB_ENABLE";
31
25
namespace rx
32
namespace rx
26
{
33
{
27
34
35
static EGLint GetDepthSize(GLint internalformat)
36
{
37
    switch (internalformat)
38
    {
39
        case GL_STENCIL_INDEX8:
40
            return 0;
41
        case GL_DEPTH_COMPONENT16:
42
            return 16;
43
        case GL_DEPTH_COMPONENT24:
44
            return 24;
45
        case GL_DEPTH_COMPONENT32_OES:
46
            return 32;
47
        case GL_DEPTH_COMPONENT32F:
48
            return 32;
49
        case GL_DEPTH24_STENCIL8:
50
            return 24;
51
        case GL_DEPTH32F_STENCIL8:
52
            return 32;
53
        default:
54
            //    UNREACHABLE(internalformat);
55
            return 0;
56
    }
57
}
58
59
static EGLint GetStencilSize(GLint internalformat)
60
{
61
    switch (internalformat)
62
    {
63
        case GL_STENCIL_INDEX8:
64
            return 8;
65
        case GL_DEPTH_COMPONENT16:
66
            return 0;
67
        case GL_DEPTH_COMPONENT24:
68
            return 0;
69
        case GL_DEPTH_COMPONENT32_OES:
70
            return 0;
71
        case GL_DEPTH_COMPONENT32F:
72
            return 0;
73
        case GL_DEPTH24_STENCIL8:
74
            return 8;
75
        case GL_DEPTH32F_STENCIL8:
76
            return 8;
77
        default:
78
            //    UNREACHABLE(internalformat);
79
            return 0;
80
    }
81
}
82
28
bool IsMetalDisplayAvailable()
83
bool IsMetalDisplayAvailable()
29
{
84
{
30
    // We only support macos 10.13+ and 11 for now. Since they are requirements for Metal 2.0.
85
    // We only support macos 10.13+ and 11 for now. Since they are requirements for Metal 2.0.
Lines 57-63 struct DefaultShaderAsyncInfoMtl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.mm_sec3
57
};
112
};
58
113
59
DisplayMtl::DisplayMtl(const egl::DisplayState &state)
114
DisplayMtl::DisplayMtl(const egl::DisplayState &state)
60
    : DisplayImpl(state), mUtils(this), mGlslangInitialized(false)
115
    : DisplayImpl(state), mStateCache(mFeatures), mUtils(this)
61
{}
116
{}
62
117
63
DisplayMtl::~DisplayMtl() {}
118
DisplayMtl::~DisplayMtl() {}
Lines 78-87 angle::Result DisplayMtl::initializeImpl(egl::Display *display) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.mm_sec4
78
{
133
{
79
    ANGLE_MTL_OBJC_SCOPE
134
    ANGLE_MTL_OBJC_SCOPE
80
    {
135
    {
81
        mMetalDevice = [MTLCreateSystemDefaultDevice() ANGLE_MTL_AUTORELEASE];
136
#if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
137
        const std::string anglePreferredDevice = angle::GetEnvironmentVar(kANGLEPreferredDeviceEnv);
138
        if (anglePreferredDevice != "")
139
        {
140
            NSArray<id<MTLDevice>> *devices = [MTLCopyAllDevices() ANGLE_MTL_AUTORELEASE];
141
            for (id<MTLDevice> device in devices)
142
            {
143
                if ([device.name.lowercaseString
144
                        containsString:[NSString stringWithUTF8String:anglePreferredDevice.c_str()]
145
                                           .lowercaseString])
146
                {
147
                    NSLog(@"Using Metal Device: %@", [device name]);
148
                    mMetalDevice = [device ANGLE_MTL_AUTORELEASE];
149
                    break;
150
                }
151
            }
152
        }
153
#endif
82
        if (!mMetalDevice)
154
        if (!mMetalDevice)
83
        {
155
        {
84
            return angle::Result::Stop;
156
            mMetalDevice = [MTLCreateSystemDefaultDevice() ANGLE_MTL_AUTORELEASE];
85
        }
157
        }
86
158
87
        mMetalDeviceVendorId = mtl::GetDeviceVendorId(mMetalDevice);
159
        mMetalDeviceVendorId = mtl::GetDeviceVendorId(mMetalDevice);
Lines 89-100 angle::Result DisplayMtl::initializeImpl(egl::Display *display) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.mm_sec5
89
        mCmdQueue.set([[mMetalDevice.get() newCommandQueue] ANGLE_MTL_AUTORELEASE]);
161
        mCmdQueue.set([[mMetalDevice.get() newCommandQueue] ANGLE_MTL_AUTORELEASE]);
90
162
91
        mCapsInitialized = false;
163
        mCapsInitialized = false;
92
164
#if ANGLE_ENABLE_METAL_SPIRV
93
        if (!mGlslangInitialized)
165
        if (!mGlslangInitialized)
94
        {
166
        {
95
            GlslangInitialize();
167
            GlslangInitialize();
96
            mGlslangInitialized = true;
168
            mGlslangInitialized = true;
97
        }
169
        }
170
#endif
98
171
99
        if (!mState.featuresAllDisabled)
172
        if (!mState.featuresAllDisabled)
100
        {
173
        {
Lines 120-131 void DisplayMtl::terminate() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.mm_sec6
120
    mCapsInitialized = false;
193
    mCapsInitialized = false;
121
194
122
    mMetalDeviceVendorId = 0;
195
    mMetalDeviceVendorId = 0;
123
196
#if ANGLE_ENABLE_METAL_SPIRV
124
    if (mGlslangInitialized)
197
    if (mGlslangInitialized)
125
    {
198
    {
126
        GlslangRelease();
199
        GlslangRelease();
127
        mGlslangInitialized = false;
200
        mGlslangInitialized = false;
128
    }
201
    }
202
#endif
129
}
203
}
130
204
131
bool DisplayMtl::testDeviceLost()
205
bool DisplayMtl::testDeviceLost()
Lines 171-176 egl::Error DisplayMtl::waitClient(const gl::Context *context) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.mm_sec7
171
    return egl::NoError();
245
    return egl::NoError();
172
}
246
}
173
247
248
egl::Error DisplayMtl::validateClientBuffer(const egl::Config *configuration,
249
                                            EGLenum buftype,
250
                                            EGLClientBuffer clientBuffer,
251
                                            const egl::AttributeMap &attribs) const
252
{
253
    // TODO: Fill out properly
254
    return egl::NoError();
255
}
256
174
egl::Error DisplayMtl::waitNative(const gl::Context *context, EGLint engine)
257
egl::Error DisplayMtl::waitNative(const gl::Context *context, EGLint engine)
175
{
258
{
176
    UNIMPLEMENTED();
259
    UNIMPLEMENTED();
Lines 187-193 SurfaceImpl *DisplayMtl::createWindowSurface(const egl::SurfaceState &state, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.mm_sec8
187
SurfaceImpl *DisplayMtl::createPbufferSurface(const egl::SurfaceState &state,
270
SurfaceImpl *DisplayMtl::createPbufferSurface(const egl::SurfaceState &state,
188
                                              const egl::AttributeMap &attribs)
271
                                              const egl::AttributeMap &attribs)
189
{
272
{
190
    return new PBufferSurfaceMtl(this, state, attribs);
273
    UNIMPLEMENTED();
274
    return static_cast<SurfaceImpl *>(0);
191
}
275
}
192
276
193
SurfaceImpl *DisplayMtl::createPbufferFromClientBuffer(const egl::SurfaceState &state,
277
SurfaceImpl *DisplayMtl::createPbufferFromClientBuffer(const egl::SurfaceState &state,
Lines 195-209 SurfaceImpl *DisplayMtl::createPbufferFromClientBuffer(const egl::SurfaceState & a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.mm_sec9
195
                                                       EGLClientBuffer clientBuffer,
279
                                                       EGLClientBuffer clientBuffer,
196
                                                       const egl::AttributeMap &attribs)
280
                                                       const egl::AttributeMap &attribs)
197
{
281
{
198
    switch (buftype)
282
    return new IOSurfaceSurfaceMtl(this, state, clientBuffer, attribs);
199
    {
200
        case EGL_IOSURFACE_ANGLE:
201
            return new IOSurfaceSurfaceMtl(this, state, clientBuffer, attribs);
202
            break;
203
        default:
204
            UNREACHABLE();
205
    }
206
    return nullptr;
207
}
283
}
208
284
209
SurfaceImpl *DisplayMtl::createPixmapSurface(const egl::SurfaceState &state,
285
SurfaceImpl *DisplayMtl::createPixmapSurface(const egl::SurfaceState &state,
Lines 240-256 StreamProducerImpl *DisplayMtl::createStreamProducerD3DTexture( a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.mm_sec10
240
    return nullptr;
316
    return nullptr;
241
}
317
}
242
318
243
ShareGroupImpl *DisplayMtl::createShareGroup()
244
{
245
    return new ShareGroupMtl();
246
}
247
248
gl::Version DisplayMtl::getMaxSupportedESVersion() const
319
gl::Version DisplayMtl::getMaxSupportedESVersion() const
249
{
320
{
250
    // NOTE(hqle): Supports GLES 3.0 on iOS GPU family 4+ for now.
321
    // NOTE(hqle): Supports GLES 3.0 on iOS GPU family 4+ for now.
251
    if (supportsEitherGPUFamily(4, 1))
322
    if (supportsEitherGPUFamily(4, 1))
252
    {
323
    {
253
        return mtl::kMaxSupportedGLVersion;
324
        return gl::Version(3, 0);
254
    }
325
    }
255
    return gl::Version(2, 0);
326
    return gl::Version(2, 0);
256
}
327
}
Lines 265-270 EGLSyncImpl *DisplayMtl::createSync(const egl::AttributeMap &attribs) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.mm_sec11
265
    return new EGLSyncMtl(attribs);
336
    return new EGLSyncMtl(attribs);
266
}
337
}
267
338
339
ShareGroupImpl *DisplayMtl::createShareGroup()
340
{
341
    return new ShareGroupImpl();
342
}
343
268
egl::Error DisplayMtl::makeCurrent(egl::Display *display,
344
egl::Error DisplayMtl::makeCurrent(egl::Display *display,
269
                                   egl::Surface *drawSurface,
345
                                   egl::Surface *drawSurface,
270
                                   egl::Surface *readSurface,
346
                                   egl::Surface *readSurface,
Lines 326-332 egl::ConfigSet DisplayMtl::generateConfigs() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.mm_sec12
326
    config.transparentType = EGL_NONE;
402
    config.transparentType = EGL_NONE;
327
403
328
    // Pbuffer
404
    // Pbuffer
329
    config.bindToTextureTarget = EGL_TEXTURE_2D;
405
    config.bindToTextureTarget = EGL_TEXTURE_RECTANGLE_ANGLE;
330
    config.maxPBufferWidth     = 4096;
406
    config.maxPBufferWidth     = 4096;
331
    config.maxPBufferHeight    = 4096;
407
    config.maxPBufferHeight    = 4096;
332
    config.maxPBufferPixels    = 4096 * 4096;
408
    config.maxPBufferPixels    = 4096 * 4096;
Lines 361-401 egl::ConfigSet DisplayMtl::generateConfigs() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.mm_sec13
361
437
362
    config.colorComponentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
438
    config.colorComponentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
363
439
364
    constexpr int samplesSupported[] = {0, 4};
440
    // Buffer sizes
441
    config.redSize    = 8;
442
    config.greenSize  = 8;
443
    config.blueSize   = 8;
444
    config.alphaSize  = 8;
445
    config.bufferSize = config.redSize + config.greenSize + config.blueSize + config.alphaSize;
365
446
366
    for (int samples : samplesSupported)
447
    // Tests like dEQP-GLES2.functional.depth_range.* assume EGL_DEPTH_SIZE is properly set even if
367
    {
448
    // renderConfig attributes are set to glu::RenderConfig::DONT_CARE
368
        config.samples       = samples;
449
    config.depthSize   = GetDepthSize(config.depthStencilFormat);
369
        config.sampleBuffers = (samples == 0) ? 0 : 1;
450
    config.stencilSize = GetStencilSize(config.depthStencilFormat);
370
451
    configs.add(config);
371
        // Buffer sizes
372
        config.redSize    = 8;
373
        config.greenSize  = 8;
374
        config.blueSize   = 8;
375
        config.alphaSize  = 8;
376
        config.bufferSize = config.redSize + config.greenSize + config.blueSize + config.alphaSize;
377
378
        // With DS
379
        config.depthSize   = 24;
380
        config.stencilSize = 8;
381
382
        configs.add(config);
383
384
        // With D
385
        config.depthSize   = 24;
386
        config.stencilSize = 0;
387
        configs.add(config);
388
389
        // With S
390
        config.depthSize   = 0;
391
        config.stencilSize = 8;
392
        configs.add(config);
393
394
        // No DS
395
        config.depthSize   = 0;
396
        config.stencilSize = 0;
397
        configs.add(config);
398
    }
399
452
400
    return configs;
453
    return configs;
401
}
454
}
Lines 409-434 bool DisplayMtl::isValidNativeWindow(EGLNativeWindowType window) const a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.mm_sec14
409
    }
462
    }
410
}
463
}
411
464
412
egl::Error DisplayMtl::validateClientBuffer(const egl::Config *configuration,
413
                                            EGLenum buftype,
414
                                            EGLClientBuffer clientBuffer,
415
                                            const egl::AttributeMap &attribs) const
416
{
417
    switch (buftype)
418
    {
419
        case EGL_IOSURFACE_ANGLE:
420
            if (!IOSurfaceSurfaceMtl::ValidateAttributes(clientBuffer, attribs))
421
            {
422
                return egl::EglBadAttribute();
423
            }
424
            break;
425
        default:
426
            UNREACHABLE();
427
            return egl::EglBadAttribute();
428
    }
429
    return egl::NoError();
430
}
431
432
std::string DisplayMtl::getRendererDescription() const
465
std::string DisplayMtl::getRendererDescription() const
433
{
466
{
434
    ANGLE_MTL_OBJC_SCOPE
467
    ANGLE_MTL_OBJC_SCOPE
Lines 512-521 void DisplayMtl::ensureCapsInitialized() const a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.mm_sec15
512
    mNativeCaps.maxRenderbufferSize   = mNativeCaps.max2DTextureSize;
545
    mNativeCaps.maxRenderbufferSize   = mNativeCaps.max2DTextureSize;
513
    mNativeCaps.minAliasedPointSize   = 1;
546
    mNativeCaps.minAliasedPointSize   = 1;
514
    // NOTE(hqle): Metal has some problems drawing big point size even though
547
    // NOTE(hqle): Metal has some problems drawing big point size even though
515
    // Metal-Feature-Set-Tables.pdf says that max supported point size is 511. We limit it to 64 for
548
    // Metal-Feature-Set-Tables.pdf says that max supported point size is 511. We limit it to 255
516
    // now.
549
    // on Intel and 64 on AMD for now.
517
    // http://anglebug.com/4816
550
    if ([mMetalDevice.get().name rangeOfString:@"Intel"].location != NSNotFound)
518
    mNativeCaps.maxAliasedPointSize = 64;
551
    {
552
        mNativeCaps.maxAliasedPointSize = 255;
553
    }
554
    else
555
    {
556
        mNativeCaps.maxAliasedPointSize = 64;
557
    }
519
558
520
    mNativeCaps.minAliasedLineWidth = 1.0f;
559
    mNativeCaps.minAliasedLineWidth = 1.0f;
521
    mNativeCaps.maxAliasedLineWidth = 1.0f;
560
    mNativeCaps.maxAliasedLineWidth = 1.0f;
Lines 615-620 void DisplayMtl::ensureCapsInitialized() const a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.mm_sec16
615
    mNativeCaps.maxTransformFeedbackSeparateComponents =
654
    mNativeCaps.maxTransformFeedbackSeparateComponents =
616
        gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS;
655
        gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS;
617
656
657
    // GL_OES_get_program_binary
658
    mNativeCaps.programBinaryFormats.push_back(GL_PROGRAM_BINARY_ANGLE);
659
618
    // GL_APPLE_clip_distance
660
    // GL_APPLE_clip_distance
619
    mNativeCaps.maxClipDistances = 8;
661
    mNativeCaps.maxClipDistances = 8;
620
662
Lines 647-652 void DisplayMtl::initializeExtensions() const a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.mm_sec17
647
    mNativeExtensions.textureBorderClampOES  = false;  // not implemented yet
689
    mNativeExtensions.textureBorderClampOES  = false;  // not implemented yet
648
    mNativeExtensions.translatedShaderSource = true;
690
    mNativeExtensions.translatedShaderSource = true;
649
    mNativeExtensions.discardFramebuffer     = true;
691
    mNativeExtensions.discardFramebuffer     = true;
692
    // Not implemented but expose
693
    mNativeExtensions.textureRectangle = true;
694
695
    // EXT_multisampled_render_to_texture
696
    if (mFeatures.allowMultisampleStoreAndResolve.enabled &&
697
        mFeatures.hasDepthAutoResolve.enabled && mFeatures.hasStencilAutoResolve.enabled)
698
    {
699
        mNativeExtensions.multisampledRenderToTexture = true;
700
    }
650
701
651
    // Enable EXT_blend_minmax
702
    // Enable EXT_blend_minmax
652
    mNativeExtensions.blendMinMax = true;
703
    mNativeExtensions.blendMinMax = true;
Lines 662-669 void DisplayMtl::initializeExtensions() const a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.mm_sec18
662
    mNativeExtensions.semaphore   = false;
713
    mNativeExtensions.semaphore   = false;
663
    mNativeExtensions.semaphoreFd = false;
714
    mNativeExtensions.semaphoreFd = false;
664
715
665
    mNativeExtensions.instancedArraysANGLE = mFeatures.hasBaseVertexInstancedDraw.enabled;
716
    mNativeExtensions.instancedArraysANGLE = true;
666
    mNativeExtensions.instancedArraysEXT   = mNativeExtensions.instancedArraysANGLE;
717
    mNativeExtensions.instancedArraysEXT   = true;
667
718
668
    mNativeExtensions.robustBufferAccessBehavior = false;
719
    mNativeExtensions.robustBufferAccessBehavior = false;
669
720
Lines 686-691 void DisplayMtl::initializeExtensions() const a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.mm_sec19
686
737
687
    mNativeExtensions.elementIndexUintOES = true;
738
    mNativeExtensions.elementIndexUintOES = true;
688
739
740
    // GL_OES_get_program_binary
741
    mNativeExtensions.getProgramBinaryOES = true;
742
689
    // GL_APPLE_clip_distance
743
    // GL_APPLE_clip_distance
690
    mNativeExtensions.clipDistanceAPPLE = true;
744
    mNativeExtensions.clipDistanceAPPLE = true;
691
745
Lines 713-723 void DisplayMtl::initializeTextureCaps() const a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.mm_sec20
713
767
714
    // Re-verify texture extensions.
768
    // Re-verify texture extensions.
715
    mNativeExtensions.setTextureExtensionSupport(mNativeTextureCaps);
769
    mNativeExtensions.setTextureExtensionSupport(mNativeTextureCaps);
716
770
    // Modify extensions based off of support
717
    // Disable all depth buffer and stencil buffer readback extensions until we need them
771
    // Disable all depth buffer and stencil buffer readback extensions until we need them
718
    mNativeExtensions.readDepthNV         = false;
772
    mNativeExtensions.readDepthNV         = false;
719
    mNativeExtensions.readStencilNV       = false;
773
    mNativeExtensions.readStencilNV       = false;
720
    mNativeExtensions.depthBufferFloat2NV = false;
774
    mNativeExtensions.depthBufferFloat2NV = false;
775
    mNativeExtensions.textureCompressionASTCLDRKHR &= supportsIOSGPUFamily(2);
776
}
777
778
void DisplayMtl::initializeLimitations()
779
{
780
    mNativeLimitations.noVertexAttributeAliasing = true;
721
}
781
}
722
782
723
void DisplayMtl::initializeFeatures()
783
void DisplayMtl::initializeFeatures()
Lines 779-784 void DisplayMtl::initializeFeatures() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.mm_sec21
779
    ANGLE_FEATURE_CONDITION((&mFeatures), allowSeparatedDepthStencilBuffers,
839
    ANGLE_FEATURE_CONDITION((&mFeatures), allowSeparatedDepthStencilBuffers,
780
                            !isOSX && !isCatalyst && !isSimulator);
840
                            !isOSX && !isCatalyst && !isSimulator);
781
841
842
    mFeatures.emulateTransformFeedback.enabled =
843
        angle::GetEnvironmentVar(kANGLETransformFeedbackEnv)[0] == '1';
844
782
    angle::PlatformMethods *platform = ANGLEPlatformCurrent();
845
    angle::PlatformMethods *platform = ANGLEPlatformCurrent();
783
    platform->overrideFeaturesMtl(platform, &mFeatures);
846
    platform->overrideFeaturesMtl(platform, &mFeatures);
784
847
Lines 787-792 void DisplayMtl::initializeFeatures() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.mm_sec22
787
850
788
angle::Result DisplayMtl::initializeShaderLibrary()
851
angle::Result DisplayMtl::initializeShaderLibrary()
789
{
852
{
853
    #ifdef ANGLE_METAL_XCODE_BUILDS_SHADERS
854
        mDefaultShadersAsyncInfo.reset(new DefaultShaderAsyncInfoMtl);
855
        
856
    
857
        NSString *path = [NSBundle bundleWithIdentifier:@"com.apple.WebKit"].bundlePath;
858
        NSError * error = nullptr;
859
        mDefaultShadersAsyncInfo->defaultShaders = [getMetalDevice() newDefaultLibraryWithBundle:[NSBundle bundleWithPath:path] error:&error];
860
861
        if (error && !mDefaultShadersAsyncInfo->defaultShaders)
862
        {
863
            ANGLE_MTL_OBJC_SCOPE
864
            {
865
                ERR() << "Internal error: newDefaultLibraryWithBundle failed. " << error.localizedDescription.UTF8String;
866
            }
867
            mDefaultShadersAsyncInfo->defaultShadersCompileError = std::move(error);
868
            return angle::Result::Stop;
869
                 
870
        }
871
        mDefaultShadersAsyncInfo->compiled = true;
872
        
873
    #else
790
    mDefaultShadersAsyncInfo.reset(new DefaultShaderAsyncInfoMtl);
874
    mDefaultShadersAsyncInfo.reset(new DefaultShaderAsyncInfoMtl);
791
875
792
    // Create references to async info struct since it might be released in terminate(), but the
876
    // Create references to async info struct since it might be released in terminate(), but the
Lines 815-821 angle::Result DisplayMtl::initializeShaderLibrary() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.mm_sec23
815
899
816
        [nsSource ANGLE_MTL_AUTORELEASE];
900
        [nsSource ANGLE_MTL_AUTORELEASE];
817
    }
901
    }
818
902
    #endif
819
    return angle::Result::Continue;
903
    return angle::Result::Continue;
820
}
904
}
821
905
Lines 847-990 id<MTLLibrary> DisplayMtl::getDefaultShadersLib() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/DisplayMtl.mm_sec24
847
931
848
bool DisplayMtl::supportsIOSGPUFamily(uint8_t iOSFamily) const
932
bool DisplayMtl::supportsIOSGPUFamily(uint8_t iOSFamily) const
849
{
933
{
850
#if (!TARGET_OS_IOS && !TARGET_OS_TV) || TARGET_OS_MACCATALYST
934
    return mtl::SupportsIOSGPUFamily(getMetalDevice(), iOSFamily);
851
    return false;
852
#else
853
#    if (__IPHONE_OS_VERSION_MAX_ALLOWED >= 130000) || (__TV_OS_VERSION_MAX_ALLOWED >= 130000)
854
    // If device supports [MTLDevice supportsFamily:], then use it.
855
    if (ANGLE_APPLE_AVAILABLE_I(13.0))
856
    {
857
        MTLGPUFamily family;
858
        switch (iOSFamily)
859
        {
860
            case 1:
861
                family = MTLGPUFamilyApple1;
862
                break;
863
            case 2:
864
                family = MTLGPUFamilyApple2;
865
                break;
866
            case 3:
867
                family = MTLGPUFamilyApple3;
868
                break;
869
            case 4:
870
                family = MTLGPUFamilyApple4;
871
                break;
872
            case 5:
873
                family = MTLGPUFamilyApple5;
874
                break;
875
#        if TARGET_OS_IOS
876
            case 6:
877
                family = MTLGPUFamilyApple6;
878
                break;
879
#        endif
880
            default:
881
                return false;
882
        }
883
        return [getMetalDevice() supportsFamily:family];
884
    }  // Metal 2.2
885
#    endif  // __IPHONE_OS_VERSION_MAX_ALLOWED
886
887
    // If device doesn't support [MTLDevice supportsFamily:], then use
888
    // [MTLDevice supportsFeatureSet:].
889
    MTLFeatureSet featureSet;
890
    switch (iOSFamily)
891
    {
892
#    if TARGET_OS_IOS
893
        case 1:
894
            featureSet = MTLFeatureSet_iOS_GPUFamily1_v1;
895
            break;
896
        case 2:
897
            featureSet = MTLFeatureSet_iOS_GPUFamily2_v1;
898
            break;
899
        case 3:
900
            featureSet = MTLFeatureSet_iOS_GPUFamily3_v1;
901
            break;
902
        case 4:
903
            featureSet = MTLFeatureSet_iOS_GPUFamily4_v1;
904
            break;
905
#        if __IPHONE_OS_VERSION_MAX_ALLOWED >= 120000
906
        case 5:
907
            featureSet = MTLFeatureSet_iOS_GPUFamily5_v1;
908
            break;
909
#        endif  // __IPHONE_OS_VERSION_MAX_ALLOWED
910
#    elif TARGET_OS_TV
911
        case 1:
912
        case 2:
913
            featureSet = MTLFeatureSet_tvOS_GPUFamily1_v1;
914
            break;
915
        case 3:
916
            featureSet = MTLFeatureSet_tvOS_GPUFamily2_v1;
917
            break;
918
#    endif  // TARGET_OS_IOS
919
        default:
920
            return false;
921
    }
922
923
    return [getMetalDevice() supportsFeatureSet:featureSet];
924
#endif      // TARGET_OS_IOS || TARGET_OS_TV
925
}
935
}
926
936
927
bool DisplayMtl::supportsMacGPUFamily(uint8_t macFamily) const
937
bool DisplayMtl::supportsMacGPUFamily(uint8_t macFamily) const
928
{
938
{
929
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
939
    return mtl::SupportsMacGPUFamily(getMetalDevice(), macFamily);
930
#    if defined(__MAC_10_15)
931
    // If device supports [MTLDevice supportsFamily:], then use it.
932
    if (ANGLE_APPLE_AVAILABLE_XC(10.15, 13.0))
933
    {
934
        MTLGPUFamily family;
935
936
        switch (macFamily)
937
        {
938
#        if TARGET_OS_MACCATALYST
939
            case 1:
940
                family = MTLGPUFamilyMacCatalyst1;
941
                break;
942
            case 2:
943
                family = MTLGPUFamilyMacCatalyst2;
944
                break;
945
#        else   // TARGET_OS_MACCATALYST
946
            case 1:
947
                family = MTLGPUFamilyMac1;
948
                break;
949
            case 2:
950
                family = MTLGPUFamilyMac2;
951
                break;
952
#        endif  // TARGET_OS_MACCATALYST
953
            default:
954
                return false;
955
        }
956
957
        return [getMetalDevice() supportsFamily:family];
958
    }  // Metal 2.2
959
#    endif
960
961
    // If device doesn't support [MTLDevice supportsFamily:], then use
962
    // [MTLDevice supportsFeatureSet:].
963
#    if TARGET_OS_MACCATALYST
964
    UNREACHABLE();
965
    return false;
966
#    else
967
    MTLFeatureSet featureSet;
968
    switch (macFamily)
969
    {
970
        case 1:
971
            featureSet = MTLFeatureSet_macOS_GPUFamily1_v1;
972
            break;
973
#        if defined(__MAC_10_14)
974
        case 2:
975
            featureSet = MTLFeatureSet_macOS_GPUFamily2_v1;
976
            break;
977
#        endif
978
        default:
979
            return false;
980
    }
981
    return [getMetalDevice() supportsFeatureSet:featureSet];
982
#    endif  // TARGET_OS_MACCATALYST
983
#else       // #if TARGET_OS_OSX || TARGET_OS_MACCATALYST
984
985
    return false;
986
987
#endif
988
}
940
}
989
941
990
bool DisplayMtl::supportsEitherGPUFamily(uint8_t iOSFamily, uint8_t macFamily) const
942
bool DisplayMtl::supportsEitherGPUFamily(uint8_t iOSFamily, uint8_t macFamily) const
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.h -5 / +39 lines
Lines 23-34 namespace mtl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.h_sec1
23
class RenderCommandEncoder;
23
class RenderCommandEncoder;
24
}  // namespace mtl
24
}  // namespace mtl
25
class ContextMtl;
25
class ContextMtl;
26
class WindowSurfaceMtl;
26
class SurfaceMtl;
27
27
28
class FramebufferMtl : public FramebufferImpl
28
class FramebufferMtl : public FramebufferImpl
29
{
29
{
30
  public:
30
  public:
31
    FramebufferMtl(const gl::FramebufferState &state, bool flipY, WindowSurfaceMtl *backbuffer);
31
    explicit FramebufferMtl(const gl::FramebufferState &state,
32
                            bool flipY,
33
                            SurfaceMtlProtocol *backbuffer);
32
    ~FramebufferMtl() override;
34
    ~FramebufferMtl() override;
33
    void destroy(const gl::Context *context) override;
35
    void destroy(const gl::Context *context) override;
34
36
Lines 97-103 class FramebufferMtl : public FramebufferImpl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.h_sec2
97
99
98
    gl::Rectangle getCompleteRenderArea() const;
100
    gl::Rectangle getCompleteRenderArea() const;
99
    int getSamples() const;
101
    int getSamples() const;
100
    WindowSurfaceMtl *getAttachedBackbuffer() const { return mBackbuffer; }
102
    SurfaceMtlProtocol *getAttachedBackbuffer() const { return mBackbuffer; }
101
103
102
    bool renderPassHasStarted(ContextMtl *contextMtl) const;
104
    bool renderPassHasStarted(ContextMtl *contextMtl) const;
103
    mtl::RenderCommandEncoder *ensureRenderPassStarted(const gl::Context *context);
105
    mtl::RenderCommandEncoder *ensureRenderPassStarted(const gl::Context *context);
Lines 162-167 class FramebufferMtl : public FramebufferImpl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.h_sec3
162
    mtl::RenderCommandEncoder *ensureRenderPassStarted(const gl::Context *context,
164
    mtl::RenderCommandEncoder *ensureRenderPassStarted(const gl::Context *context,
163
                                                       const mtl::RenderPassDesc &desc);
165
                                                       const mtl::RenderPassDesc &desc);
164
166
167
    void overrideClearColor(const mtl::TextureRef &texture,
168
                            MTLClearColor clearColor,
169
                            MTLClearColor *colorOut);
170
165
    angle::Result updateColorRenderTarget(const gl::Context *context, size_t colorIndexGL);
171
    angle::Result updateColorRenderTarget(const gl::Context *context, size_t colorIndexGL);
166
    angle::Result updateDepthRenderTarget(const gl::Context *context);
172
    angle::Result updateDepthRenderTarget(const gl::Context *context);
167
    angle::Result updateStencilRenderTarget(const gl::Context *context);
173
    angle::Result updateStencilRenderTarget(const gl::Context *context);
Lines 169-179 class FramebufferMtl : public FramebufferImpl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.h_sec4
169
                                           const gl::FramebufferAttachment *attachment,
175
                                           const gl::FramebufferAttachment *attachment,
170
                                           RenderTargetMtl **cachedRenderTarget);
176
                                           RenderTargetMtl **cachedRenderTarget);
171
177
178
    // This function either returns the render target's texture itself if the texture is readable
179
    // or create a copy of that texture that is readable if not. This function is typically used
180
    // for packed depth stencil where reading stencil requires a stencil view. However if a texture
181
    // has both render target, pixel format view & shader readable usage flags, there will be
182
    // some glitches happen in Metal framework.
183
    // So the solution is creating a depth stencil texture without pixel format view flag but has
184
    // render target flag, then during blitting process, this texture is copied to another
185
    // intermidiate texture having pixel format view flag, but not render target flag.
186
    angle::Result getReadableViewForRenderTarget(const gl::Context *context,
187
                                                 const RenderTargetMtl &rtt,
188
                                                 const gl::Rectangle &readArea,
189
                                                 mtl::TextureRef *readableDepthView,
190
                                                 mtl::TextureRef *readableStencilView,
191
                                                 uint32_t *readableViewLevel,
192
                                                 uint32_t *readableViewLayer,
193
                                                 gl::Rectangle *readableViewArea);
194
172
    angle::Result readPixelsToPBO(const gl::Context *context,
195
    angle::Result readPixelsToPBO(const gl::Context *context,
173
                                  const gl::Rectangle &area,
196
                                  const gl::Rectangle &area,
174
                                  const PackPixelsParams &packPixelsParams,
197
                                  const PackPixelsParams &packPixelsParams,
175
                                  const RenderTargetMtl *renderTarget) const;
198
                                  const RenderTargetMtl *renderTarget) const;
176
199
200
    angle::Result readPixelsToBuffer(const gl::Context *context,
201
                                     const gl::Rectangle &area,
202
                                     const RenderTargetMtl *renderTarget,
203
                                     bool reverseRowOrder,
204
                                     const angle::Format &dstAngleFormat,
205
                                     uint32_t dstBufferOffset,
206
                                     uint32_t dstBufferRowPitch,
207
                                     const mtl::BufferRef *dstBuffer) const;
208
177
    // NOTE: we cannot use RenderTargetCache here because it doesn't support separate
209
    // NOTE: we cannot use RenderTargetCache here because it doesn't support separate
178
    // depth & stencil attachments as of now. Separate depth & stencil could be useful to
210
    // depth & stencil attachments as of now. Separate depth & stencil could be useful to
179
    // save spaces on iOS devices. See doc/PackedDepthStencilSupport.md.
211
    // save spaces on iOS devices. See doc/PackedDepthStencilSupport.md.
Lines 189-196 class FramebufferMtl : public FramebufferImpl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.h_sec5
189
    // as by a compute pass.
221
    // as by a compute pass.
190
    bool mRenderPassCleanStart = false;
222
    bool mRenderPassCleanStart = false;
191
223
192
    WindowSurfaceMtl *mBackbuffer = nullptr;
224
    SurfaceMtlProtocol *mBackbuffer = nullptr;
193
    const bool mFlipY             = false;
225
    const bool mFlipY               = false;
226
227
    mtl::BufferRef mReadPixelBuffer;
194
};
228
};
195
}  // namespace rx
229
}  // namespace rx
196
230
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.mm -35 / +159 lines
Lines 33-44 void OverrideMTLClearColor(const mtl::TextureRef &texture, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.mm_sec1
33
    *colorOut =
33
    *colorOut =
34
        mtl::EmulatedAlphaClearColor(clearColor.toMTLClearColor(), texture->getColorWritableMask());
34
        mtl::EmulatedAlphaClearColor(clearColor.toMTLClearColor(), texture->getColorWritableMask());
35
}
35
}
36
37
const gl::InternalFormat &GetReadAttachmentInfo(const gl::Context *context,
38
                                                RenderTargetMtl *renderTarget)
39
{
40
    GLenum implFormat;
41
42
    if (renderTarget && renderTarget->getFormat())
43
    {
44
        implFormat = renderTarget->getFormat()->actualAngleFormat().fboImplementationInternalFormat;
45
    }
46
    else
47
    {
48
        implFormat = GL_NONE;
49
    }
50
51
    return gl::GetSizedInternalFormatInfo(implFormat);
52
}
53
36
}
54
}
37
55
38
// FramebufferMtl implementation
56
// FramebufferMtl implementation
39
FramebufferMtl::FramebufferMtl(const gl::FramebufferState &state,
57
FramebufferMtl::FramebufferMtl(const gl::FramebufferState &state,
40
                               bool flipY,
58
                               bool flipY,
41
                               WindowSurfaceMtl *backbuffer)
59
                               SurfaceMtlProtocol *backbuffer)
42
    : FramebufferImpl(state), mBackbuffer(backbuffer), mFlipY(flipY)
60
    : FramebufferImpl(state), mBackbuffer(backbuffer), mFlipY(flipY)
43
{
61
{
44
    reset();
62
    reset();
Lines 55-60 void FramebufferMtl::reset() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.mm_sec2
55
    mDepthRenderTarget = mStencilRenderTarget = nullptr;
73
    mDepthRenderTarget = mStencilRenderTarget = nullptr;
56
74
57
    mRenderPassFirstColorAttachmentFormat = nullptr;
75
    mRenderPassFirstColorAttachmentFormat = nullptr;
76
77
    mReadPixelBuffer = nullptr;
58
}
78
}
59
79
60
void FramebufferMtl::destroy(const gl::Context *context)
80
void FramebufferMtl::destroy(const gl::Context *context)
Lines 122-128 angle::Result FramebufferMtl::clearBufferfv(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.mm_sec3
122
                                            const GLfloat *values)
142
                                            const GLfloat *values)
123
{
143
{
124
    mtl::ClearRectParams clearOpts;
144
    mtl::ClearRectParams clearOpts;
125
126
    gl::DrawBufferMask clearColorBuffers;
145
    gl::DrawBufferMask clearColorBuffers;
127
    if (buffer == GL_DEPTH)
146
    if (buffer == GL_DEPTH)
128
    {
147
    {
Lines 133-139 angle::Result FramebufferMtl::clearBufferfv(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.mm_sec4
133
        clearColorBuffers.set(drawbuffer);
152
        clearColorBuffers.set(drawbuffer);
134
        clearOpts.clearColor = mtl::ClearColorValue(values[0], values[1], values[2], values[3]);
153
        clearOpts.clearColor = mtl::ClearColorValue(values[0], values[1], values[2], values[3]);
135
    }
154
    }
136
137
    return clearImpl(context, clearColorBuffers, &clearOpts);
155
    return clearImpl(context, clearColorBuffers, &clearOpts);
138
}
156
}
139
angle::Result FramebufferMtl::clearBufferuiv(const gl::Context *context,
157
angle::Result FramebufferMtl::clearBufferuiv(const gl::Context *context,
Lines 145-152 angle::Result FramebufferMtl::clearBufferuiv(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.mm_sec5
145
    clearColorBuffers.set(drawbuffer);
163
    clearColorBuffers.set(drawbuffer);
146
164
147
    mtl::ClearRectParams clearOpts;
165
    mtl::ClearRectParams clearOpts;
148
    clearOpts.clearColor = mtl::ClearColorValue(values[0], values[1], values[2], values[3]);
166
    clearOpts.clearColor =  mtl::ClearColorValue(values[0], values[1], values[2], values[3]);
149
150
    return clearImpl(context, clearColorBuffers, &clearOpts);
167
    return clearImpl(context, clearColorBuffers, &clearOpts);
151
}
168
}
152
angle::Result FramebufferMtl::clearBufferiv(const gl::Context *context,
169
angle::Result FramebufferMtl::clearBufferiv(const gl::Context *context,
Lines 159-165 angle::Result FramebufferMtl::clearBufferiv(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.mm_sec6
159
    gl::DrawBufferMask clearColorBuffers;
176
    gl::DrawBufferMask clearColorBuffers;
160
    if (buffer == GL_STENCIL)
177
    if (buffer == GL_STENCIL)
161
    {
178
    {
162
        clearOpts.clearStencil = values[0] & mtl::kStencilMaskAll;
179
        clearOpts.clearStencil = gl::clamp(values[0], 0, static_cast<GLint>(mtl::kStencilMaskAll));
163
    }
180
    }
164
    else
181
    else
165
    {
182
    {
Lines 177-183 angle::Result FramebufferMtl::clearBufferfi(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.mm_sec7
177
{
194
{
178
    mtl::ClearRectParams clearOpts;
195
    mtl::ClearRectParams clearOpts;
179
    clearOpts.clearDepth   = depth;
196
    clearOpts.clearDepth   = depth;
180
    clearOpts.clearStencil = stencil & mtl::kStencilMaskAll;
197
    clearOpts.clearStencil = gl::clamp(stencil, 0, static_cast<GLint>(mtl::kStencilMaskAll));
181
198
182
    return clearImpl(context, gl::DrawBufferMask(), &clearOpts);
199
    return clearImpl(context, gl::DrawBufferMask(), &clearOpts);
183
}
200
}
Lines 185-196 angle::Result FramebufferMtl::clearBufferfi(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.mm_sec8
185
const gl::InternalFormat &FramebufferMtl::getImplementationColorReadFormat(
202
const gl::InternalFormat &FramebufferMtl::getImplementationColorReadFormat(
186
    const gl::Context *context) const
203
    const gl::Context *context) const
187
{
204
{
188
    ContextMtl *contextMtl   = mtl::GetImpl(context);
205
    return GetReadAttachmentInfo(context, getColorReadRenderTarget(context));
189
    GLenum sizedFormat       = mState.getReadAttachment()->getFormat().info->sizedInternalFormat;
190
    angle::FormatID formatID = angle::Format::InternalFormatToID(sizedFormat);
191
    const mtl::Format &mtlFormat = contextMtl->getDisplay()->getPixelFormat(formatID);
192
    GLenum implFormat            = mtlFormat.actualAngleFormat().fboImplementationInternalFormat;
193
    return gl::GetSizedInternalFormatInfo(implFormat);
194
}
206
}
195
207
196
angle::Result FramebufferMtl::readPixels(const gl::Context *context,
208
angle::Result FramebufferMtl::readPixels(const gl::Context *context,
Lines 590-595 angle::Result FramebufferMtl::syncState(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.mm_sec9
590
        {
602
        {
591
            contextMtl->onDrawFrameBufferChangedState(context, this, renderPassChanged);
603
            contextMtl->onDrawFrameBufferChangedState(context, this, renderPassChanged);
592
        }
604
        }
605
606
        // Recreate pixel reading buffer if needed in future.
607
        mReadPixelBuffer = nullptr;
593
    }
608
    }
594
609
595
    return angle::Result::Continue;
610
    return angle::Result::Continue;
Lines 748-754 void FramebufferMtl::onStartedDrawingToFrameBuffer(const gl::Context *context) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.mm_sec10
748
763
749
void FramebufferMtl::onFrameEnd(const gl::Context *context)
764
void FramebufferMtl::onFrameEnd(const gl::Context *context)
750
{
765
{
751
    if (!mBackbuffer)
766
    if (!mBackbuffer || mBackbuffer->preserveBuffer())
752
    {
767
    {
753
        return;
768
        return;
754
    }
769
    }
Lines 812-817 angle::Result FramebufferMtl::updateCachedRenderTarget(const gl::Context *contex a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.mm_sec11
812
    return angle::Result::Continue;
827
    return angle::Result::Continue;
813
}
828
}
814
829
830
angle::Result FramebufferMtl::getReadableViewForRenderTarget(
831
    const gl::Context *context,
832
    const RenderTargetMtl &rtt,
833
    const gl::Rectangle &readArea,
834
    mtl::TextureRef *readableDepthViewOut,
835
    mtl::TextureRef *readableStencilViewOut,
836
    uint32_t *readableViewLevel,
837
    uint32_t *readableViewLayer,
838
    gl::Rectangle *readableViewArea)
839
{
840
    ContextMtl *contextMtl     = mtl::GetImpl(context);
841
    mtl::TextureRef srcTexture = rtt.getTexture();
842
    uint32_t level             = rtt.getLevelIndex().get();
843
    uint32_t slice             = rtt.getLayerIndex();
844
845
    // NOTE(hqle): slice is not used atm.
846
    ASSERT(slice == 0);
847
848
    bool readStencil = readableStencilViewOut;
849
850
    if (!srcTexture)
851
    {
852
        if (readableDepthViewOut)
853
        {
854
            *readableDepthViewOut = nullptr;
855
        }
856
        if (readableStencilViewOut)
857
        {
858
            *readableStencilViewOut = nullptr;
859
        }
860
        *readableViewArea = readArea;
861
        return angle::Result::Continue;
862
    }
863
864
    bool skipCopy = srcTexture->isShaderReadable();
865
    if (rtt.getFormat()->hasDepthAndStencilBits() && readStencil)
866
    {
867
        // If the texture is packed depth stencil, and we need stencil view,
868
        // then it must support creating different format view.
869
        skipCopy = skipCopy && srcTexture->supportFormatView();
870
    }
871
872
    if (skipCopy)
873
    {
874
        // Texture supports stencil view, just use it directly
875
        if (readableDepthViewOut)
876
        {
877
            *readableDepthViewOut = srcTexture;
878
        }
879
        if (readableStencilViewOut)
880
        {
881
            *readableStencilViewOut = srcTexture;
882
        }
883
        *readableViewLevel = level;
884
        *readableViewLayer = slice;
885
        *readableViewArea  = readArea;
886
    }
887
    else
888
    {
889
        ASSERT(srcTexture->textureType() != MTLTextureType3D);
890
891
        // Texture doesn't support stencil view or not shader readable, copy to an interminate
892
        // texture that supports stencil view and shader read.
893
        mtl::TextureRef formatableView = srcTexture->getReadableCopy(
894
            contextMtl, contextMtl->getBlitCommandEncoder(), level, slice,
895
            MTLRegionMake2D(readArea.x, readArea.y, readArea.width, readArea.height));
896
897
        ANGLE_CHECK_GL_ALLOC(contextMtl, formatableView);
898
899
        if (readableDepthViewOut)
900
        {
901
            *readableDepthViewOut = formatableView;
902
        }
903
        if (readableStencilViewOut)
904
        {
905
            *readableStencilViewOut = formatableView->getStencilView();
906
        }
907
908
        *readableViewLevel = 0;
909
        *readableViewLayer = 0;
910
        *readableViewArea  = gl::Rectangle(0, 0, readArea.width, readArea.height);
911
    }
912
913
    return angle::Result::Continue;
914
}
915
815
angle::Result FramebufferMtl::prepareRenderPass(const gl::Context *context,
916
angle::Result FramebufferMtl::prepareRenderPass(const gl::Context *context,
816
                                                mtl::RenderPassDesc *pDescOut)
917
                                                mtl::RenderPassDesc *pDescOut)
817
{
918
{
Lines 832-840 angle::Result FramebufferMtl::prepareRenderPass(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.mm_sec12
832
        if (colorRenderTarget)
933
        if (colorRenderTarget)
833
        {
934
        {
834
            colorRenderTarget->toRenderPassAttachmentDesc(&colorAttachment);
935
            colorRenderTarget->toRenderPassAttachmentDesc(&colorAttachment);
936
            desc.sampleCount = std::max(desc.sampleCount, colorRenderTarget->getRenderSamples());
835
937
836
            desc.numColorAttachments = std::max(desc.numColorAttachments, colorIndexGL + 1);
938
            desc.numColorAttachments = std::max(desc.numColorAttachments, colorIndexGL + 1);
837
            desc.sampleCount = std::max(desc.sampleCount, colorRenderTarget->getRenderSamples());
838
939
839
            if (!mRenderPassFirstColorAttachmentFormat)
940
            if (!mRenderPassFirstColorAttachmentFormat)
840
            {
941
            {
Lines 862-883 angle::Result FramebufferMtl::prepareRenderPass(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.mm_sec13
862
        mDepthRenderTarget->toRenderPassAttachmentDesc(&desc.depthAttachment);
963
        mDepthRenderTarget->toRenderPassAttachmentDesc(&desc.depthAttachment);
863
        desc.sampleCount = std::max(desc.sampleCount, mDepthRenderTarget->getRenderSamples());
964
        desc.sampleCount = std::max(desc.sampleCount, mDepthRenderTarget->getRenderSamples());
864
    }
965
    }
865
    else
866
    {
867
        desc.depthAttachment.reset();
868
    }
869
966
870
    if (mStencilRenderTarget)
967
    if (mStencilRenderTarget)
871
    {
968
    {
872
        mStencilRenderTarget->toRenderPassAttachmentDesc(&desc.stencilAttachment);
969
        mStencilRenderTarget->toRenderPassAttachmentDesc(&desc.stencilAttachment);
873
        desc.sampleCount = std::max(desc.sampleCount, mStencilRenderTarget->getRenderSamples());
970
        desc.sampleCount = std::max(desc.sampleCount, mStencilRenderTarget->getRenderSamples());
874
    }
971
    }
972
973
    return angle::Result::Continue;
974
}
975
976
// Override clear color based on texture's write mask
977
void FramebufferMtl::overrideClearColor(const mtl::TextureRef &texture,
978
                                        MTLClearColor clearColor,
979
                                        MTLClearColor *colorOut)
980
{
981
    if (texture)
982
    {
983
        *colorOut = mtl::EmulatedAlphaClearColor(clearColor, texture->getColorWritableMask());
984
    }
875
    else
985
    else
876
    {
986
    {
877
        desc.stencilAttachment.reset();
987
        *colorOut = clearColor;
878
    }
988
    }
879
880
    return angle::Result::Continue;
881
}
989
}
882
990
883
angle::Result FramebufferMtl::clearWithLoadOp(const gl::Context *context,
991
angle::Result FramebufferMtl::clearWithLoadOp(const gl::Context *context,
Lines 923-929 angle::Result FramebufferMtl::clearWithLoadOpRenderPassNotStarted( a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.mm_sec14
923
1031
924
        mtl::RenderPassColorAttachmentDesc &colorAttachment =
1032
        mtl::RenderPassColorAttachmentDesc &colorAttachment =
925
            tempDesc.colorAttachments[colorIndexGL];
1033
            tempDesc.colorAttachments[colorIndexGL];
926
        const mtl::TextureRef &texture = colorAttachment.texture;
1034
        const mtl::TextureRef &texture = colorAttachment.texture();
927
1035
928
        if (clearColorBuffers.test(colorIndexGL))
1036
        if (clearColorBuffers.test(colorIndexGL))
929
        {
1037
        {
Lines 966-972 angle::Result FramebufferMtl::clearWithLoadOpRenderPassStarted( a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.mm_sec15
966
1074
967
        mtl::RenderPassColorAttachmentDesc &colorAttachment =
1075
        mtl::RenderPassColorAttachmentDesc &colorAttachment =
968
            mRenderPassDesc.colorAttachments[colorIndexGL];
1076
            mRenderPassDesc.colorAttachments[colorIndexGL];
969
        const mtl::TextureRef &texture = colorAttachment.texture;
1077
        const mtl::TextureRef &texture = colorAttachment.texture();
970
1078
971
        if (clearColorBuffers.test(colorIndexGL))
1079
        if (clearColorBuffers.test(colorIndexGL))
972
        {
1080
        {
Lines 1193-1200 gl::Rectangle FramebufferMtl::getCorrectFlippedReadArea(const gl::Context *conte a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.mm_sec16
1193
    gl::Rectangle flippedArea = glArea;
1301
    gl::Rectangle flippedArea = glArea;
1194
    if (mFlipY)
1302
    if (mFlipY)
1195
    {
1303
    {
1196
        flippedArea.y = readRT->getTexture()->height(readRT->getLevelIndex()) - flippedArea.y -
1304
        flippedArea.y =
1197
                        flippedArea.height;
1305
            readRT->getTexture()->height(readRT->getLevelIndex()) -
1306
            flippedArea.y - flippedArea.height;
1198
    }
1307
    }
1199
1308
1200
    return flippedArea;
1309
    return flippedArea;
Lines 1211-1217 angle::Result FramebufferMtl::readPixelsImpl(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.mm_sec17
1211
    {
1320
    {
1212
        return angle::Result::Continue;
1321
        return angle::Result::Continue;
1213
    }
1322
    }
1214
1215
    if (packPixelsParams.packBuffer)
1323
    if (packPixelsParams.packBuffer)
1216
    {
1324
    {
1217
        return readPixelsToPBO(context, area, packPixelsParams, renderTarget);
1325
        return readPixelsToPBO(context, area, packPixelsParams, renderTarget);
Lines 1261-1267 angle::Result FramebufferMtl::readPixelsImpl(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.mm_sec18
1261
1369
1262
        // Convert to destination format
1370
        // Convert to destination format
1263
        PackPixels(packPixelsRowParams, readAngleFormat, bufferRowPitch, readPixelRowBuffer.data(),
1371
        PackPixels(packPixelsRowParams, readAngleFormat, bufferRowPitch, readPixelRowBuffer.data(),
1264
                   pixels);
1372
           pixels);
1265
    }
1373
    }
1266
1374
1267
    return angle::Result::Continue;
1375
    return angle::Result::Continue;
Lines 1279-1297 angle::Result FramebufferMtl::readPixelsToPBO(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.mm_sec19
1279
1387
1280
    ANGLE_MTL_CHECK(contextMtl, packPixelsParams.offset <= std::numeric_limits<uint32_t>::max(),
1388
    ANGLE_MTL_CHECK(contextMtl, packPixelsParams.offset <= std::numeric_limits<uint32_t>::max(),
1281
                    GL_INVALID_OPERATION);
1389
                    GL_INVALID_OPERATION);
1282
    const uint32_t dstBufferOffset      = static_cast<uint32_t>(packPixelsParams.offset);
1390
    uint32_t offset = static_cast<uint32_t>(packPixelsParams.offset);
1283
    const uint32_t dstBufferRowPitch    = packPixelsParams.outputPitch;
1284
    const angle::Format &dstAngleFormat = *packPixelsParams.destFormat;
1285
    const bool reverseRowOrder          = packPixelsParams.reverseRowOrder;
1286
1391
1287
    BufferMtl *packBufferMtl = mtl::GetImpl(packPixelsParams.packBuffer);
1392
    BufferMtl *packBufferMtl = mtl::GetImpl(packPixelsParams.packBuffer);
1288
    mtl::BufferRef dstBuffer = packBufferMtl->getCurrentBuffer();
1393
    mtl::BufferRef dstBuffer = packBufferMtl->getCurrentBuffer();
1289
1394
1395
    return readPixelsToBuffer(context, area, renderTarget, packPixelsParams.reverseRowOrder,
1396
                              *packPixelsParams.destFormat, offset, packPixelsParams.outputPitch,
1397
                              &dstBuffer);
1398
}
1399
1400
angle::Result FramebufferMtl::readPixelsToBuffer(const gl::Context *context,
1401
                                                 const gl::Rectangle &area,
1402
                                                 const RenderTargetMtl *renderTarget,
1403
                                                 bool reverseRowOrder,
1404
                                                 const angle::Format &dstAngleFormat,
1405
                                                 uint32_t dstBufferOffset,
1406
                                                 uint32_t dstBufferRowPitch,
1407
                                                 const mtl::BufferRef *pDstBuffer) const
1408
{
1409
    ASSERT(renderTarget);
1410
1411
    ContextMtl *contextMtl = mtl::GetImpl(context);
1412
1290
    const mtl::Format &readFormat        = *renderTarget->getFormat();
1413
    const mtl::Format &readFormat        = *renderTarget->getFormat();
1291
    const angle::Format &readAngleFormat = readFormat.actualAngleFormat();
1414
    const angle::Format &readAngleFormat = readFormat.actualAngleFormat();
1292
1415
1293
    mtl::TextureRef texture = renderTarget->getTexture();
1416
    mtl::TextureRef texture = renderTarget->getTexture();
1294
1417
1418
    const mtl::BufferRef &dstBuffer = *pDstBuffer;
1419
1295
    if (dstAngleFormat.id != readAngleFormat.id || texture->samples() > 1 ||
1420
    if (dstAngleFormat.id != readAngleFormat.id || texture->samples() > 1 ||
1296
        (dstBufferOffset % dstAngleFormat.pixelBytes) ||
1421
        (dstBufferOffset % dstAngleFormat.pixelBytes) ||
1297
        (dstBufferOffset % mtl::kTextureToBufferBlittingAlignment))
1422
        (dstBufferOffset % mtl::kTextureToBufferBlittingAlignment))
Lines 1359-1366 angle::Result FramebufferMtl::readPixelsToPBO(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.mm_sec20
1359
1484
1360
            uint32_t bufferRowOffset = dstBufferOffset;
1485
            uint32_t bufferRowOffset = dstBufferOffset;
1361
            // Copy pixels row by row
1486
            // Copy pixels row by row
1362
            for (int r = startRow, copiedRows = 0; copiedRows < area.height;
1487
            for (int r = startRow, i = 0; i < area.height;
1363
                 ++copiedRows, --r, bufferRowOffset += dstBufferRowPitch)
1488
                 ++i, --r, bufferRowOffset += dstBufferRowPitch)
1364
            {
1489
            {
1365
                srcRowRegion.y = r;
1490
                srcRowRegion.y = r;
1366
1491
Lines 1375-1379 angle::Result FramebufferMtl::readPixelsToPBO(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/FrameBufferMtl.mm_sec21
1375
1500
1376
    return angle::Result::Continue;
1501
    return angle::Result::Continue;
1377
}
1502
}
1378
1379
}
1503
}
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/IOSurfaceSurfaceMtl.h +126 lines
Line 0 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/IOSurfaceSurfaceMtl.h_sec1
1
//
2
// Copyright 2020 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
7
#ifndef LIBANGLE_RENDERER_METAL_IOSURFACESURFACEMTL_H_
8
#define LIBANGLE_RENDERER_METAL_IOSURFACESURFACEMTL_H_
9
10
#include <IOSurface/IOSurfaceRef.h>
11
#include "libANGLE/renderer/SurfaceImpl.h"
12
#include "libANGLE/renderer/metal/DisplayMtl.h"
13
#include "libANGLE/renderer/metal/SurfaceMtl.h"
14
15
namespace metal
16
{
17
class AttributeMap;
18
}  // namespace metal
19
20
namespace rx
21
{
22
23
class DisplayMTL;
24
25
class IOSurfaceSurfaceMtl : public SurfaceMtlProtocol
26
{
27
  public:
28
    IOSurfaceSurfaceMtl(DisplayMtl *display,
29
                        const egl::SurfaceState &state,
30
                        EGLClientBuffer buffer,
31
                        const egl::AttributeMap &attribs);
32
    ~IOSurfaceSurfaceMtl() override;
33
34
    void destroy(const egl::Display *display) override;
35
36
    egl::Error initialize(const egl::Display *display) override;
37
    FramebufferImpl *createDefaultFramebuffer(const gl::Context *context,
38
                                              const gl::FramebufferState &state) override;
39
40
    egl::Error makeCurrent(const gl::Context *context) override;
41
    egl::Error unMakeCurrent(const gl::Context *context) override;
42
    egl::Error swap(const gl::Context *context) override;
43
    egl::Error postSubBuffer(const gl::Context *context,
44
                             EGLint x,
45
                             EGLint y,
46
                             EGLint width,
47
                             EGLint height) override;
48
49
    egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) override;
50
    egl::Error bindTexImage(const gl::Context *context,
51
                            gl::Texture *texture,
52
                            EGLint buffer) override;
53
    egl::Error releaseTexImage(const gl::Context *context, EGLint buffer) override;
54
    egl::Error getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) override;
55
    egl::Error getMscRate(EGLint *numerator, EGLint *denominator) override;
56
    void setSwapInterval(EGLint interval) override;
57
    void setFixedWidth(EGLint width) override;
58
    void setFixedHeight(EGLint height) override;
59
60
    // Width can change when the client window resizes.
61
    EGLint getWidth() const override;
62
    // Height can change when the client window resizes.
63
    EGLint getHeight() const override;
64
65
    EGLint isPostSubBufferSupported() const override;
66
    EGLint getSwapBehavior() const override;
67
68
    angle::Result getAttachmentRenderTarget(const gl::Context *context,
69
                                            GLenum binding,
70
                                            const gl::ImageIndex &imageIndex,
71
                                            GLsizei samples,
72
                                            FramebufferAttachmentRenderTarget **rtOut) override;
73
74
    angle::Result ensureCurrentDrawableObtained(const gl::Context *context) override;
75
    angle::Result ensureCurrentDrawableObtained(const gl::Context *context,
76
                                                bool *newDrawableOut) override;
77
    int getSamples() const override { return 1; }
78
    bool preserveBuffer() const override { return false; }
79
    mtl::TextureRef getTexture(const gl::Context *context);
80
    bool hasRobustResourceInit() const override { return false; }
81
    angle::Result ensureColorTextureReadyForReadPixels(const gl::Context *context) override
82
    {
83
        return angle::Result::Continue;
84
    }
85
    const mtl::TextureRef &getColorTexture() override { return mIOSurfaceTexture; }
86
87
  private:
88
    angle::Result ensureTextureCreated(const gl::Context *context);
89
    angle::Result createBackingTexture(const gl::Context *context);
90
    angle::Result createTexture(const gl::Context *context,
91
                                const mtl::Format &format,
92
                                uint32_t width,
93
                                uint32_t height,
94
                                bool renderTargetOnly,
95
                                mtl::TextureRef *textureOut);
96
97
    angle::Result initializeAlphaChannel(const gl::Context *context, GLuint texture);
98
99
#if defined(ANGLE_PLATFORM_IOS_SIMULATOR)
100
    IOSurfaceLockOptions getIOSurfaceLockOptions() const;
101
#endif
102
103
    ContextMtl *contextMTL;
104
    IOSurfaceRef mIOSurface;
105
    mtl::TextureRef mIOSurfaceTexture;
106
    mtl::TextureRef mIOSurfaceTextureView;
107
    mtl::Format mFormat;
108
    mtl::Format mInternalFormat;
109
    RenderTargetMtl mRenderTarget;
110
    bool mIOSurfaceTextureCreated;
111
    int mWidth;
112
    int mHeight;
113
    int mPlane;
114
    int mFormatIndex;
115
    int mRowStrideInPixels;
116
117
#if defined(ANGLE_PLATFORM_IOS_SIMULATOR)
118
    GLuint mBoundTextureID;
119
    bool mUploadFromIOSurface;
120
    bool mReadbackToIOSurface;
121
#endif
122
};
123
124
}  // namespace rx
125
126
#endif  // LIBANGLE_RENDERER_GL_EAGL_IOSURFACESURFACEEAGL_H_
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/IOSurfaceSurfaceMtl.mm +467 lines
Line 0 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/IOSurfaceSurfaceMtl.mm_sec1
1
//
2
// Copyright 2019 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
// IOSurfaceSurfaceMtl.mm:
7
//    Implements the class methods for IOSurfaceSurfaceMtl.
8
//
9
10
#include "libANGLE/renderer/metal/IOSurfaceSurfaceMtl.h"
11
12
#include <TargetConditionals.h>
13
14
#include "libANGLE/Display.h"
15
#include "libANGLE/Surface.h"
16
#include "libANGLE/renderer/metal/ContextMtl.h"
17
#include "libANGLE/renderer/metal/DisplayMtl.h"
18
#include "libANGLE/renderer/metal/FrameBufferMtl.h"
19
#include "libANGLE/renderer/metal/mtl_format_utils.h"
20
21
// Compiler can turn on programmatical frame capture in release build by defining
22
// ANGLE_METAL_FRAME_CAPTURE flag.
23
#if defined(NDEBUG) && !defined(ANGLE_METAL_FRAME_CAPTURE)
24
#    define ANGLE_METAL_FRAME_CAPTURE_ENABLED 0
25
#else
26
#    define ANGLE_METAL_FRAME_CAPTURE_ENABLED ANGLE_WITH_MODERN_METAL_API
27
#endif
28
namespace rx
29
{
30
31
namespace
32
{
33
34
struct IOSurfaceFormatInfo
35
{
36
    GLenum internalFormat;
37
    GLenum type;
38
    angle::FormatID pixelFormat;
39
    angle::FormatID internalPixelFormat;
40
};
41
42
static const IOSurfaceFormatInfo kIOSurfaceFormats[] = {
43
    {GL_RED, GL_UNSIGNED_BYTE, angle::FormatID::R8_UNORM, angle::FormatID::R8_UNORM},
44
    {GL_R16UI, GL_UNSIGNED_SHORT, angle::FormatID::R16G16_UINT, angle::FormatID::R16G16_UINT},
45
    {GL_RG, GL_UNSIGNED_BYTE, angle::FormatID::R8G8_UNORM, angle::FormatID::R8G8_UNORM},
46
    {GL_RGB, GL_UNSIGNED_BYTE, angle::FormatID::R8G8B8A8_UNORM, angle::FormatID::B8G8R8A8_UNORM},
47
    {GL_BGRA_EXT, GL_UNSIGNED_BYTE, angle::FormatID::B8G8R8A8_UNORM,
48
     angle::FormatID::B8G8R8A8_UNORM},
49
    {GL_RGB10_A2, GL_UNSIGNED_INT_2_10_10_10_REV, angle::FormatID::R10G10B10A2_UNORM,
50
     angle::FormatID::R10G10B10A2_UNORM},
51
    {GL_RGBA, GL_HALF_FLOAT, angle::FormatID::R16G16B16A16_FLOAT,
52
     angle::FormatID::R16G16B16A16_FLOAT},
53
};
54
55
int FindIOSurfaceFormatIndex(GLenum internalFormat, GLenum type)
56
{
57
    for (size_t i = 0; i < static_cast<size_t>(ArraySize(kIOSurfaceFormats)); ++i)
58
    {
59
        const auto &formatInfo = kIOSurfaceFormats[i];
60
        if (formatInfo.internalFormat == internalFormat && formatInfo.type == type)
61
        {
62
            return static_cast<int>(i);
63
        }
64
    }
65
    return -1;
66
}
67
68
// TODO(jcunningham) : refactor this and surfacemtl to reduce copy+pasted code
69
70
ANGLE_MTL_UNUSED
71
bool IsFrameCaptureEnabled()
72
{
73
#if !ANGLE_METAL_FRAME_CAPTURE_ENABLED
74
    return false;
75
#else
76
    // We only support frame capture programmatically if the ANGLE_METAL_FRAME_CAPTURE
77
    // environment flag is set. Otherwise, it will slow down the rendering. This allows user to
78
    // finely control whether they want to capture the frame for particular application or not.
79
    auto var                  = std::getenv("ANGLE_METAL_FRAME_CAPTURE");
80
    static const bool enabled = var ? (strcmp(var, "1") == 0) : false;
81
82
    return enabled;
83
#endif
84
}
85
86
ANGLE_MTL_UNUSED
87
std::string GetMetalCaptureFile()
88
{
89
#if !ANGLE_METAL_FRAME_CAPTURE_ENABLED
90
    return "";
91
#else
92
    auto var                   = std::getenv("ANGLE_METAL_FRAME_CAPTURE_FILE");
93
    const std::string filePath = var ? var : "";
94
95
    return filePath;
96
#endif
97
}
98
99
ANGLE_MTL_UNUSED
100
size_t MaxAllowedFrameCapture()
101
{
102
#if !ANGLE_METAL_FRAME_CAPTURE_ENABLED
103
    return 0;
104
#else
105
    auto var                      = std::getenv("ANGLE_METAL_FRAME_CAPTURE_MAX");
106
    static const size_t maxFrames = var ? std::atoi(var) : 100;
107
108
    return maxFrames;
109
#endif
110
}
111
112
ANGLE_MTL_UNUSED
113
size_t MinAllowedFrameCapture()
114
{
115
#if !ANGLE_METAL_FRAME_CAPTURE_ENABLED
116
    return 0;
117
#else
118
    auto var                     = std::getenv("ANGLE_METAL_FRAME_CAPTURE_MIN");
119
    static const size_t minFrame = var ? std::atoi(var) : 0;
120
121
    return minFrame;
122
#endif
123
}
124
125
ANGLE_MTL_UNUSED
126
bool FrameCaptureDeviceScope()
127
{
128
#if !ANGLE_METAL_FRAME_CAPTURE_ENABLED
129
    return false;
130
#else
131
    auto var                      = std::getenv("ANGLE_METAL_FRAME_CAPTURE_SCOPE");
132
    static const bool scopeDevice = var ? (strcmp(var, "device") == 0) : false;
133
134
    return scopeDevice;
135
#endif
136
}
137
138
ANGLE_MTL_UNUSED
139
std::atomic<size_t> gFrameCaptured(0);
140
141
ANGLE_MTL_UNUSED
142
void StartFrameCapture(id<MTLDevice> metalDevice, id<MTLCommandQueue> metalCmdQueue)
143
{
144
#if ANGLE_METAL_FRAME_CAPTURE_ENABLED
145
    if (!IsFrameCaptureEnabled())
146
    {
147
        return;
148
    }
149
150
    if (gFrameCaptured >= MaxAllowedFrameCapture())
151
    {
152
        return;
153
    }
154
155
    MTLCaptureManager *captureManager = [MTLCaptureManager sharedCaptureManager];
156
    if (captureManager.isCapturing)
157
    {
158
        return;
159
    }
160
161
    gFrameCaptured++;
162
163
    if (gFrameCaptured < MinAllowedFrameCapture())
164
    {
165
        return;
166
    }
167
168
#    ifdef __MAC_10_15
169
    if (ANGLE_APPLE_AVAILABLE_XCI(10.15, 13.0, 13))
170
    {
171
        MTLCaptureDescriptor *captureDescriptor = [[MTLCaptureDescriptor alloc] init];
172
        captureDescriptor.captureObject         = metalDevice;
173
        const std::string filePath              = GetMetalCaptureFile();
174
        if (filePath != "")
175
        {
176
            const std::string numberedPath =
177
                filePath + std::to_string(gFrameCaptured - 1) + ".gputrace";
178
            captureDescriptor.destination = MTLCaptureDestinationGPUTraceDocument;
179
            captureDescriptor.outputURL =
180
                [NSURL fileURLWithPath:[NSString stringWithUTF8String:numberedPath.c_str()]
181
                           isDirectory:false];
182
        }
183
        else
184
        {
185
            // This will pause execution only if application is being debugged inside Xcode
186
            captureDescriptor.destination = MTLCaptureDestinationDeveloperTools;
187
        }
188
189
        NSError *error;
190
        if (![captureManager startCaptureWithDescriptor:captureDescriptor error:&error])
191
        {
192
            NSLog(@"Failed to start capture, error %@", error);
193
        }
194
    }
195
    else
196
#    endif  // __MAC_10_15
197
        if (ANGLE_APPLE_AVAILABLE_XCI(10.15, 13.0, 13))
198
    {
199
        MTLCaptureDescriptor *captureDescriptor = [[MTLCaptureDescriptor alloc] init];
200
        captureDescriptor.captureObject         = metalDevice;
201
202
        NSError *error;
203
        if (![captureManager startCaptureWithDescriptor:captureDescriptor error:&error])
204
        {
205
            NSLog(@"Failed to start capture, error %@", error);
206
        }
207
    }
208
#endif  // ANGLE_METAL_FRAME_CAPTURE_ENABLED
209
}
210
211
void StartFrameCapture(ContextMtl *context)
212
{
213
    StartFrameCapture(context->getMetalDevice(), context->cmdQueue().get());
214
}
215
216
void StopFrameCapture()
217
{
218
#if ANGLE_METAL_FRAME_CAPTURE_ENABLED
219
    if (!IsFrameCaptureEnabled())
220
    {
221
        return;
222
    }
223
    MTLCaptureManager *captureManager = [MTLCaptureManager sharedCaptureManager];
224
    if (captureManager.isCapturing)
225
    {
226
        [captureManager stopCapture];
227
    }
228
#endif
229
}
230
231
}  // anonymous namespace
232
233
IOSurfaceSurfaceMtl::IOSurfaceSurfaceMtl(DisplayMtl *display,
234
                                         const egl::SurfaceState &state,
235
                                         EGLClientBuffer buffer,
236
                                         const egl::AttributeMap &attribs)
237
    : SurfaceMtlProtocol(state)
238
{
239
    // Keep reference to the IOSurface so it doesn't get deleted while the pbuffer exists.
240
    mIOSurface = reinterpret_cast<IOSurfaceRef>(buffer);
241
    CFRetain(mIOSurface);
242
243
    // Extract attribs useful for the call to EAGLTexImageIOSurface2D
244
    mWidth  = static_cast<int>(attribs.get(EGL_WIDTH));
245
    mHeight = static_cast<int>(attribs.get(EGL_HEIGHT));
246
    mPlane  = static_cast<int>(attribs.get(EGL_IOSURFACE_PLANE_ANGLE));
247
    // Hopefully the number of bytes per row is always an integer number of pixels. We use
248
    // glReadPixels to fill the IOSurface in the simulator and it can only support strides that are
249
    // an integer number of pixels.
250
    ASSERT(IOSurfaceGetBytesPerRowOfPlane(mIOSurface, mPlane) %
251
               IOSurfaceGetBytesPerElementOfPlane(mIOSurface, mPlane) ==
252
           0);
253
    mRowStrideInPixels = static_cast<int>(IOSurfaceGetBytesPerRowOfPlane(mIOSurface, mPlane) /
254
                                          IOSurfaceGetBytesPerElementOfPlane(mIOSurface, mPlane));
255
256
    EGLAttrib internalFormat = attribs.get(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE);
257
    EGLAttrib type           = attribs.get(EGL_TEXTURE_TYPE_ANGLE);
258
    mFormatIndex =
259
        FindIOSurfaceFormatIndex(static_cast<GLenum>(internalFormat), static_cast<GLenum>(type));
260
    ASSERT(mFormatIndex >= 0);
261
    mFormat         = display->getPixelFormat(kIOSurfaceFormats[mFormatIndex].pixelFormat);
262
    mInternalFormat = display->getPixelFormat(kIOSurfaceFormats[mFormatIndex].internalPixelFormat);
263
}
264
265
IOSurfaceSurfaceMtl::~IOSurfaceSurfaceMtl()
266
{
267
    StopFrameCapture();
268
    if (mIOSurface != nullptr)
269
    {
270
        CFRelease(mIOSurface);
271
        mIOSurface = nullptr;
272
    }
273
}
274
275
void IOSurfaceSurfaceMtl::destroy(const egl::Display *display) {}
276
277
egl::Error IOSurfaceSurfaceMtl::initialize(const egl::Display *display)
278
{
279
    DisplayMtl *displayMtl    = mtl::GetImpl(display);
280
    id<MTLDevice> metalDevice = displayMtl->getMetalDevice();
281
282
    StartFrameCapture(metalDevice, displayMtl->cmdQueue().get());
283
    return egl::NoError();
284
}
285
286
FramebufferImpl *IOSurfaceSurfaceMtl::createDefaultFramebuffer(const gl::Context *context,
287
                                                               const gl::FramebufferState &state)
288
{
289
    auto fbo = new FramebufferMtl(state, /* flipY */ true, /* backbuffer */ this);
290
    return fbo;
291
}
292
293
egl::Error IOSurfaceSurfaceMtl::makeCurrent(const gl::Context *context)
294
{
295
    ContextMtl *contextMtl = mtl::GetImpl(context);
296
    StartFrameCapture(contextMtl);
297
    return egl::NoError();
298
}
299
300
egl::Error IOSurfaceSurfaceMtl::unMakeCurrent(const gl::Context *context)
301
{
302
    StopFrameCapture();
303
    return egl::NoError();
304
}
305
306
egl::Error IOSurfaceSurfaceMtl::swap(const gl::Context *context)
307
{
308
    StopFrameCapture();
309
    ContextMtl *contextMtl = mtl::GetImpl(context);
310
    StartFrameCapture(contextMtl);
311
    return egl::NoError();
312
}
313
314
egl::Error IOSurfaceSurfaceMtl::postSubBuffer(const gl::Context *context,
315
                                              EGLint x,
316
                                              EGLint y,
317
                                              EGLint width,
318
                                              EGLint height)
319
{
320
    UNIMPLEMENTED();
321
    return egl::EglBadAccess();
322
}
323
324
egl::Error IOSurfaceSurfaceMtl::querySurfacePointerANGLE(EGLint attribute, void **value)
325
{
326
    UNIMPLEMENTED();
327
    return egl::EglBadAccess();
328
}
329
330
egl::Error IOSurfaceSurfaceMtl::bindTexImage(const gl::Context *context,
331
                                             gl::Texture *texture,
332
                                             EGLint buffer)
333
{
334
335
    angle::Result res = createBackingTexture(context);
336
    if (res == angle::Result::Continue)
337
        return egl::NoError();
338
    else
339
        return egl::EglBadAccess();
340
}
341
342
egl::Error IOSurfaceSurfaceMtl::releaseTexImage(const gl::Context *context, EGLint buffer)
343
{
344
    // This will need implementation
345
    ContextMtl *contextMtl = mtl::GetImpl(context);
346
    if (contextMtl->flush(context) == angle::Result::Continue)
347
    {
348
        mIOSurfaceTextureCreated = false;
349
        return egl::NoError();
350
    }
351
    return egl::EglBadAccess();
352
}
353
354
egl::Error IOSurfaceSurfaceMtl::getSyncValues(EGLuint64KHR *ust,
355
                                              EGLuint64KHR *msc,
356
                                              EGLuint64KHR *sbc)
357
{
358
    UNIMPLEMENTED();
359
    return egl::EglBadAccess();
360
}
361
362
egl::Error IOSurfaceSurfaceMtl::getMscRate(EGLint *numerator, EGLint *denominator)
363
{
364
    UNIMPLEMENTED();
365
    return egl::EglBadAccess();
366
}
367
368
void IOSurfaceSurfaceMtl::setSwapInterval(EGLint interval)
369
{
370
    UNIMPLEMENTED();
371
}
372
373
void IOSurfaceSurfaceMtl::setFixedWidth(EGLint width)
374
{
375
    UNIMPLEMENTED();
376
}
377
378
void IOSurfaceSurfaceMtl::setFixedHeight(EGLint height)
379
{
380
    UNIMPLEMENTED();
381
}
382
383
// width and height can change with client window resizing
384
EGLint IOSurfaceSurfaceMtl::getWidth() const
385
{
386
    return static_cast<EGLint>(mWidth);
387
}
388
389
EGLint IOSurfaceSurfaceMtl::getHeight() const
390
{
391
    return static_cast<EGLint>(mHeight);
392
}
393
394
EGLint IOSurfaceSurfaceMtl::isPostSubBufferSupported() const
395
{
396
    return EGL_FALSE;
397
}
398
399
EGLint IOSurfaceSurfaceMtl::getSwapBehavior() const
400
{
401
    return EGL_BUFFER_DESTROYED;
402
}
403
404
angle::Result IOSurfaceSurfaceMtl::getAttachmentRenderTarget(
405
    const gl::Context *context,
406
    GLenum binding,
407
    const gl::ImageIndex &imageIndex,
408
    GLsizei samples,
409
    FramebufferAttachmentRenderTarget **rtOut)
410
{
411
    ANGLE_TRY(ensureTextureCreated(context));
412
    *rtOut = &mRenderTarget;
413
    return angle::Result::Continue;
414
}
415
416
angle::Result IOSurfaceSurfaceMtl::ensureCurrentDrawableObtained(const gl::Context *context, bool *newDrawableOut)
417
{
418
    return angle::Result::Continue;
419
}
420
angle::Result IOSurfaceSurfaceMtl::ensureCurrentDrawableObtained(const gl::Context *context)
421
{
422
    return angle::Result::Continue;
423
}
424
425
angle::Result IOSurfaceSurfaceMtl::createBackingTexture(const gl::Context *context)
426
{
427
    mtl::TextureRef mTemporarySurfaceRef;
428
    ANGLE_TRY(createTexture(context, mFormat, mWidth, mHeight, false, &mTemporarySurfaceRef));
429
    // Create texture view around the base format of the texture.
430
    mIOSurfaceTexture =
431
        mTemporarySurfaceRef->createViewWithDifferentFormat(MTLPixelFormatBGRA8Unorm);
432
    mRenderTarget.set(mIOSurfaceTexture, mtl::kZeroNativeMipLevel, 0, mInternalFormat);
433
    mIOSurfaceTextureCreated = true;
434
    return angle::Result::Continue;
435
}
436
437
angle::Result IOSurfaceSurfaceMtl::ensureTextureCreated(const gl::Context *context)
438
{
439
    if (!mIOSurfaceTextureCreated)
440
    {
441
        return createBackingTexture(context);
442
    }
443
    return angle::Result::Continue;
444
}
445
446
mtl::TextureRef IOSurfaceSurfaceMtl::getTexture(const gl::Context *context)
447
{
448
    if (ensureCurrentDrawableObtained(context) == angle::Result::Continue)
449
    {
450
        return mIOSurfaceTexture;
451
    }
452
    return nullptr;
453
}
454
455
angle::Result IOSurfaceSurfaceMtl::createTexture(const gl::Context *context,
456
                                                 const mtl::Format &format,
457
                                                 uint32_t width,
458
                                                 uint32_t height,
459
                                                 bool renderTargetOnly,
460
                                                 mtl::TextureRef *textureOut)
461
{
462
    ContextMtl *contextMtl = mtl::GetImpl(context);
463
    ANGLE_TRY(mtl::Texture::MakeIOSurfaceTexture(contextMtl, format, width, height, mIOSurface,
464
                                                 mPlane, textureOut));
465
    return angle::Result::Continue;
466
}
467
}
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.h -10 / +41 lines
Lines 20-31 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.h_sec1
20
#include "libANGLE/renderer/glslang_wrapper_utils.h"
20
#include "libANGLE/renderer/glslang_wrapper_utils.h"
21
#include "libANGLE/renderer/metal/mtl_buffer_pool.h"
21
#include "libANGLE/renderer/metal/mtl_buffer_pool.h"
22
#include "libANGLE/renderer/metal/mtl_command_buffer.h"
22
#include "libANGLE/renderer/metal/mtl_command_buffer.h"
23
#include "libANGLE/renderer/metal/mtl_glslang_utils.h"
23
#include "libANGLE/renderer/metal/mtl_glslang_mtl_utils.h"
24
#include "libANGLE/renderer/metal/mtl_resources.h"
24
#include "libANGLE/renderer/metal/mtl_resources.h"
25
#include "libANGLE/renderer/metal/mtl_state_cache.h"
25
#include "libANGLE/renderer/metal/mtl_state_cache.h"
26
26
27
namespace rx
27
namespace rx
28
{
28
{
29
#define SHADER_ENTRY_NAME @"main0"
29
class ContextMtl;
30
class ContextMtl;
30
31
31
struct ProgramArgumentBufferEncoderMtl
32
struct ProgramArgumentBufferEncoderMtl
Lines 134-139 class ProgramMtl : public ProgramImpl, public mtl::RenderPipelineCacheSpecialize a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.h_sec2
134
    bool hasSpecializedShader(gl::ShaderType shaderType,
135
    bool hasSpecializedShader(gl::ShaderType shaderType,
135
                              const mtl::RenderPipelineDesc &renderPipelineDesc) override;
136
                              const mtl::RenderPipelineDesc &renderPipelineDesc) override;
136
137
138
    angle::Result createMslShaderLib(mtl::Context *context,
139
                                     gl::ShaderType shaderType,
140
                                     gl::InfoLog &infoLog,
141
                                     mtl::TranslatedShaderInfo *translatedMslInfo);
137
    // Calls this before drawing, changedPipelineDesc is passed when vertex attributes desc and/or
142
    // Calls this before drawing, changedPipelineDesc is passed when vertex attributes desc and/or
138
    // shader program changed.
143
    // shader program changed.
139
    angle::Result setupDraw(const gl::Context *glContext,
144
    angle::Result setupDraw(const gl::Context *glContext,
Lines 141-147 class ProgramMtl : public ProgramImpl, public mtl::RenderPipelineCacheSpecialize a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.h_sec3
141
                            const mtl::RenderPipelineDesc &pipelineDesc,
146
                            const mtl::RenderPipelineDesc &pipelineDesc,
142
                            bool pipelineDescChanged,
147
                            bool pipelineDescChanged,
143
                            bool forceTexturesSetting,
148
                            bool forceTexturesSetting,
144
                            bool uniformBuffersDirty);
149
                            bool uniformBuffersDirty,
150
                            bool transformFeedbackDraw);
151
152
    std::string getXfbMslSource() const { return mXfbMslSource; }
153
154
    mtl::RenderPipelineCache *mMetalXfbRenderPipelineCache;
145
155
146
  private:
156
  private:
147
    template <int cols, int rows>
157
    template <int cols, int rows>
Lines 156-161 class ProgramMtl : public ProgramImpl, public mtl::RenderPipelineCacheSpecialize a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.h_sec4
156
    void setUniformImpl(GLint location, GLsizei count, const T *v, GLenum entryPointType);
166
    void setUniformImpl(GLint location, GLsizei count, const T *v, GLenum entryPointType);
157
167
158
    angle::Result initDefaultUniformBlocks(const gl::Context *glContext);
168
    angle::Result initDefaultUniformBlocks(const gl::Context *glContext);
169
    angle::Result resizeDefaultUniformBlocksMemory(const gl::Context *glContext,
170
                                                   const gl::ShaderMap<size_t> &requiredBufferSize);
171
    void saveDefaultUniformBlocksInfo(gl::BinaryOutputStream *stream);
172
    angle::Result loadDefaultUniformBlocksInfo(const gl::Context *glContext,
173
                                               gl::BinaryInputStream *stream);
159
174
160
    angle::Result commitUniforms(ContextMtl *context, mtl::RenderCommandEncoder *cmdEncoder);
175
    angle::Result commitUniforms(ContextMtl *context, mtl::RenderCommandEncoder *cmdEncoder);
161
    angle::Result updateTextures(const gl::Context *glContext,
176
    angle::Result updateTextures(const gl::Context *glContext,
Lines 177-197 class ProgramMtl : public ProgramImpl, public mtl::RenderPipelineCacheSpecialize a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.h_sec5
177
        const std::vector<gl::InterfaceBlock> &blocks,
192
        const std::vector<gl::InterfaceBlock> &blocks,
178
        gl::ShaderType shaderType);
193
        gl::ShaderType shaderType);
179
194
180
    angle::Result updateXfbBuffers(ContextMtl *context,
181
                                   mtl::RenderCommandEncoder *cmdEncoder,
182
                                   const mtl::RenderPipelineDesc &pipelineDesc);
183
184
    void reset(ContextMtl *context);
195
    void reset(ContextMtl *context);
185
196
197
    void saveTranslatedShaders(gl::BinaryOutputStream *stream);
198
    void loadTranslatedShaders(gl::BinaryInputStream *stream);
199
200
    void saveShaderInternalInfo(gl::BinaryOutputStream *stream);
201
    void loadShaderInternalInfo(gl::BinaryInputStream *stream);
202
203
#if ANGLE_ENABLE_METAL_SPIRV
204
205
    angle::Result linkImplSpirv(const gl::Context *glContext,
206
                                const gl::ProgramLinkedResources &resources,
207
                                gl::InfoLog &infoLog);
208
#endif
209
210
    angle::Result linkImplDirect(const gl::Context *glContext,
211
                                 const gl::ProgramLinkedResources &resources,
212
                                 gl::InfoLog &infoLog);
213
186
    void linkResources(const gl::ProgramLinkedResources &resources);
214
    void linkResources(const gl::ProgramLinkedResources &resources);
187
    angle::Result linkImpl(const gl::Context *glContext,
215
    angle::Result linkImpl(const gl::Context *glContext,
188
                           const gl::ProgramLinkedResources &resources,
216
                           const gl::ProgramLinkedResources &resources,
189
                           gl::InfoLog &infoLog);
217
                           gl::InfoLog &infoLog);
190
218
191
    angle::Result createMslShaderLib(mtl::Context *context,
219
    angle::Result linkTranslatedShaders(const gl::Context *glContext,
192
                                     gl::ShaderType shaderType,
220
                                        gl::BinaryInputStream *stream,
193
                                     gl::InfoLog &infoLog,
221
                                        gl::InfoLog &infoLog);
194
                                     mtl::TranslatedShaderInfo *translatedMslInfo);
195
222
196
    // State for the default uniform blocks.
223
    // State for the default uniform blocks.
197
    struct DefaultUniformBlock final : private angle::NonCopyable
224
    struct DefaultUniformBlock final : private angle::NonCopyable
Lines 230-235 class ProgramMtl : public ProgramImpl, public mtl::RenderPipelineCacheSpecialize a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.h_sec6
230
    // Cached references of current shader variants.
257
    // Cached references of current shader variants.
231
    gl::ShaderMap<ProgramShaderObjVariantMtl *> mCurrentShaderVariants;
258
    gl::ShaderMap<ProgramShaderObjVariantMtl *> mCurrentShaderVariants;
232
259
260
    ShaderMapInterfaceVariableInfoMap mVariableInfoMap;
233
    // Scratch data:
261
    // Scratch data:
234
    // Legalized buffers and their offsets. For example, uniform buffer's offset=1 is not a valid
262
    // Legalized buffers and their offsets. For example, uniform buffer's offset=1 is not a valid
235
    // offset, it will be converted to legal offset and the result is stored in this array.
263
    // offset, it will be converted to legal offset and the result is stored in this array.
Lines 238-244 class ProgramMtl : public ProgramImpl, public mtl::RenderPipelineCacheSpecialize a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.h_sec7
238
    // into an argument buffer.
266
    // into an argument buffer.
239
    std::vector<uint32_t> mArgumentBufferRenderStageUsages;
267
    std::vector<uint32_t> mArgumentBufferRenderStageUsages;
240
268
269
    uint32_t mShadowCompareModes[mtl::kMaxShaderSamplers] = {0};
270
241
    mtl::RenderPipelineCache mMetalRenderPipelineCache;
271
    mtl::RenderPipelineCache mMetalRenderPipelineCache;
272
    std::string mXfbMslSource;
242
};
273
};
243
274
244
}  // namespace rx
275
}  // namespace rx
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.mm -112 / +295 lines
Lines 14-38 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.mm_sec1
14
#include <sstream>
14
#include <sstream>
15
15
16
#include "common/debug.h"
16
#include "common/debug.h"
17
#include "compiler/translator/TranslatorMetal.h"
18
#include "compiler/translator/TranslatorMetalDirect.h"
19
#include "compiler/translator/TranslatorMetalDirect/EnvironmentVariable.h"
17
#include "libANGLE/Context.h"
20
#include "libANGLE/Context.h"
18
#include "libANGLE/ProgramLinkedResources.h"
21
#include "libANGLE/ProgramLinkedResources.h"
19
#include "libANGLE/renderer/metal/BufferMtl.h"
22
#include "libANGLE/renderer/metal/BufferMtl.h"
20
#include "libANGLE/renderer/metal/ContextMtl.h"
23
#include "libANGLE/renderer/metal/ContextMtl.h"
21
#include "libANGLE/renderer/metal/DisplayMtl.h"
24
#include "libANGLE/renderer/metal/DisplayMtl.h"
22
#include "libANGLE/renderer/metal/TextureMtl.h"
25
#include "libANGLE/renderer/metal/TextureMtl.h"
23
#include "libANGLE/renderer/metal/mtl_glslang_utils.h"
26
#include "libANGLE/renderer/metal/mtl_glslang_mtl_utils.h"
24
#include "libANGLE/renderer/metal/mtl_utils.h"
27
#include "libANGLE/renderer/metal/mtl_utils.h"
25
#include "libANGLE/renderer/renderer_utils.h"
28
#include "libANGLE/renderer/renderer_utils.h"
26
29
30
#if ANGLE_ENABLE_METAL_SPIRV
31
#    include "libANGLE/renderer/metal/mtl_glslang_utils.h"
32
#endif
33
27
namespace rx
34
namespace rx
28
{
35
{
29
36
30
namespace
37
namespace
31
{
38
{
32
39
#if ANGLE_ENABLE_METAL_SPIRV
33
#define SHADER_ENTRY_NAME @"main0"
34
constexpr char kSpirvCrossSpecConstSuffix[] = "_tmp";
40
constexpr char kSpirvCrossSpecConstSuffix[] = "_tmp";
35
41
#endif
36
template <typename T>
42
template <typename T>
37
class ScopedAutoClearVector
43
class ScopedAutoClearVector
38
{
44
{
Lines 78-83 void InitDefaultUniformBlock(const std::vector<sh::Uniform> &uniforms, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.mm_sec2
78
84
79
    size_t blockSize = blockEncoder.getCurrentOffset();
85
    size_t blockSize = blockEncoder.getCurrentOffset();
80
86
87
    // TODO(jmadill): I think we still need a valid block for the pipeline even if zero sized.
81
    if (blockSize == 0)
88
    if (blockSize == 0)
82
    {
89
    {
83
        *blockSizeOut = 0;
90
        *blockSizeOut = 0;
Lines 228-238 ProgramMtl::DefaultUniformBlock::DefaultUniformBlock() {} a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.mm_sec3
228
235
229
ProgramMtl::DefaultUniformBlock::~DefaultUniformBlock() = default;
236
ProgramMtl::DefaultUniformBlock::~DefaultUniformBlock() = default;
230
237
231
ProgramMtl::ProgramMtl(const gl::ProgramState &state)
238
ProgramMtl::ProgramMtl(const gl::ProgramState &state) : ProgramImpl(state),
232
    : ProgramImpl(state), mMetalRenderPipelineCache(this)
239
    mMetalRenderPipelineCache(this)
233
{}
240
{
241
    mMetalXfbRenderPipelineCache = new mtl::RenderPipelineCache();
242
}
234
243
235
ProgramMtl::~ProgramMtl() {}
244
ProgramMtl::~ProgramMtl()
245
{
246
    delete mMetalXfbRenderPipelineCache;
247
}
236
248
237
void ProgramMtl::destroy(const gl::Context *context)
249
void ProgramMtl::destroy(const gl::Context *context)
238
{
250
{
Lines 262-286 void ProgramMtl::reset(ContextMtl *context) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.mm_sec4
262
    {
274
    {
263
        var.reset(context);
275
        var.reset(context);
264
    }
276
    }
265
266
    mMetalRenderPipelineCache.clear();
277
    mMetalRenderPipelineCache.clear();
278
    mMetalXfbRenderPipelineCache->clear();
279
}
280
281
void ProgramMtl::saveTranslatedShaders(gl::BinaryOutputStream *stream)
282
{
283
    // Write out shader sources for all shader types
284
    for (const gl::ShaderType shaderType : gl::AllShaderTypes())
285
    {
286
        stream->writeString(mMslShaderTranslateInfo[shaderType].metalShaderSource);
287
    }
288
    stream->writeString(mXfbMslSource);
289
}
290
291
void ProgramMtl::loadTranslatedShaders(gl::BinaryInputStream *stream)
292
{
293
    // Read in shader sources for all shader types
294
    for (const gl::ShaderType shaderType : gl::AllShaderTypes())
295
    {
296
        mMslShaderTranslateInfo[shaderType].metalShaderSource = stream->readString();
297
    }
298
    mXfbMslSource = stream->readString();
267
}
299
}
268
300
269
std::unique_ptr<rx::LinkEvent> ProgramMtl::load(const gl::Context *context,
301
std::unique_ptr<rx::LinkEvent> ProgramMtl::load(const gl::Context *context,
270
                                                gl::BinaryInputStream *stream,
302
                                                gl::BinaryInputStream *stream,
271
                                                gl::InfoLog &infoLog)
303
                                                gl::InfoLog &infoLog)
272
{
304
{
273
    // NOTE(hqle): support binary shader
305
274
    UNIMPLEMENTED();
306
    return std::make_unique<LinkEventDone>(linkTranslatedShaders(context, stream, infoLog));
275
    return std::make_unique<LinkEventDone>(angle::Result::Stop);
276
}
307
}
277
308
278
void ProgramMtl::save(const gl::Context *context, gl::BinaryOutputStream *stream)
309
void ProgramMtl::save(const gl::Context *context, gl::BinaryOutputStream *stream)
279
{
310
{
280
    // NOTE(hqle): support binary shader
311
    saveTranslatedShaders(stream);
281
    UNIMPLEMENTED();
312
    saveShaderInternalInfo(stream);
313
    saveDefaultUniformBlocksInfo(stream);
282
}
314
}
283
315
316
284
void ProgramMtl::setBinaryRetrievableHint(bool retrievable)
317
void ProgramMtl::setBinaryRetrievableHint(bool retrievable)
285
{
318
{
286
    UNIMPLEMENTED();
319
    UNIMPLEMENTED();
Lines 294-300 void ProgramMtl::setSeparable(bool separable) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.mm_sec5
294
std::unique_ptr<LinkEvent> ProgramMtl::link(const gl::Context *context,
327
std::unique_ptr<LinkEvent> ProgramMtl::link(const gl::Context *context,
295
                                            const gl::ProgramLinkedResources &resources,
328
                                            const gl::ProgramLinkedResources &resources,
296
                                            gl::InfoLog &infoLog,
329
                                            gl::InfoLog &infoLog,
297
                                            const gl::ProgramMergedVaryings & /* mergedVaryings */)
330
                                            const gl::ProgramMergedVaryings &mergedVaryings)
298
{
331
{
299
    // Link resources before calling GetShaderSource to make sure they are ready for the set/binding
332
    // Link resources before calling GetShaderSource to make sure they are ready for the set/binding
300
    // assignment done in that function.
333
    // assignment done in that function.
Lines 304-310 std::unique_ptr<LinkEvent> ProgramMtl::link(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.mm_sec6
304
    return std::make_unique<LinkEventDone>(linkImpl(context, resources, infoLog));
337
    return std::make_unique<LinkEventDone>(linkImpl(context, resources, infoLog));
305
}
338
}
306
339
307
angle::Result ProgramMtl::linkImpl(const gl::Context *glContext,
340
#if ANGLE_ENABLE_METAL_SPIRV
341
angle::Result ProgramMtl::linkImplSpirv(const gl::Context *glContext,
308
                                   const gl::ProgramLinkedResources &resources,
342
                                   const gl::ProgramLinkedResources &resources,
309
                                   gl::InfoLog &infoLog)
343
                                   gl::InfoLog &infoLog)
310
{
344
{
Lines 355-360 angle::Result ProgramMtl::linkImpl(const gl::Context *glContext, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.mm_sec7
355
389
356
    return angle::Result::Continue;
390
    return angle::Result::Continue;
357
}
391
}
392
#endif
393
394
angle::Result ProgramMtl::linkImplDirect(const gl::Context *glContext,
395
                                   const gl::ProgramLinkedResources &resources,
396
                                   gl::InfoLog &infoLog)
397
{
398
    ContextMtl *contextMtl = mtl::GetImpl(glContext);
399
400
    reset(contextMtl);
401
    ANGLE_TRY(initDefaultUniformBlocks(glContext));
402
    ShaderMapInterfaceVariableInfoMap variableInfoMap;
403
404
    gl::ShaderMap<std::string> shaderSources;
405
    gl::ShaderMap<std::string> translatedMslShaders;
406
    mtl::MSLGetShaderSource(mState, resources, &shaderSources, &variableInfoMap);
407
408
    ANGLE_TRY(mtl::GlslangGetMSL(glContext, mState, contextMtl->getCaps(), shaderSources,
409
                                 variableInfoMap, &mMslShaderTranslateInfo,
410
                                 &translatedMslShaders,
411
                                 mState.getExecutable().getTransformFeedbackBufferCount()));
412
413
414
    for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
415
    {
416
        // Create actual Metal shader
417
        ANGLE_TRY(
418
            createMslShaderLib(contextMtl, shaderType, infoLog, &mMslShaderTranslateInfo[shaderType]));
419
    }
420
    return angle::Result::Continue;
421
}
422
423
angle::Result ProgramMtl::linkImpl(const gl::Context *glContext,
424
                                   const gl::ProgramLinkedResources &resources,
425
                                   gl::InfoLog &infoLog)
426
{
427
    // TODO: We need some way of toggling this.
428
#if ANGLE_ENABLE_METAL_SPIRV
429
    if (sh::readBoolEnvVar("ANGLE_GEN_MTL_WITH_SPIRV"))
430
    {
431
       return linkImplSpirv(glContext, resources, infoLog);
432
    }
433
    else
434
#endif
435
    {
436
       return linkImplDirect(glContext, resources, infoLog);
437
    }
438
}
439
440
441
angle::Result ProgramMtl::linkTranslatedShaders(const gl::Context *glContext,
442
                                                gl::BinaryInputStream *stream,
443
                                                gl::InfoLog &infoLog)
444
{
445
    ContextMtl *contextMtl = mtl::GetImpl(glContext);
446
    // NOTE(hqle): No transform feedbacks for now, since we only support ES 2.0 atm
447
448
    reset(contextMtl);
449
450
    loadTranslatedShaders(stream);
451
    loadShaderInternalInfo(stream);
452
    ANGLE_TRY(loadDefaultUniformBlocksInfo(glContext, stream));
453
454
    ANGLE_TRY(createMslShaderLib(contextMtl, gl::ShaderType::Vertex, infoLog,
455
                              &mMslShaderTranslateInfo[gl::ShaderType::Vertex]));
456
    ANGLE_TRY(createMslShaderLib(contextMtl, gl::ShaderType::Fragment, infoLog,
457
                              &mMslShaderTranslateInfo[gl::ShaderType::Fragment]));
458
459
    return angle::Result::Continue;
460
}
358
461
359
void ProgramMtl::linkResources(const gl::ProgramLinkedResources &resources)
462
void ProgramMtl::linkResources(const gl::ProgramLinkedResources &resources)
360
{
463
{
Lines 366-373 void ProgramMtl::linkResources(const gl::ProgramLinkedResources &resources) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.mm_sec8
366
469
367
angle::Result ProgramMtl::initDefaultUniformBlocks(const gl::Context *glContext)
470
angle::Result ProgramMtl::initDefaultUniformBlocks(const gl::Context *glContext)
368
{
471
{
369
    ContextMtl *contextMtl = mtl::GetImpl(glContext);
370
371
    // Process vertex and fragment uniforms into std140 packing.
472
    // Process vertex and fragment uniforms into std140 packing.
372
    gl::ShaderMap<sh::BlockLayoutMap> layoutMap;
473
    gl::ShaderMap<sh::BlockLayoutMap> layoutMap;
373
    gl::ShaderMap<size_t> requiredBufferSize;
474
    gl::ShaderMap<size_t> requiredBufferSize;
Lines 426-431 angle::Result ProgramMtl::initDefaultUniformBlocks(const gl::Context *glContext) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.mm_sec9
426
        }
527
        }
427
    }
528
    }
428
529
530
    return resizeDefaultUniformBlocksMemory(glContext, requiredBufferSize);
531
}
532
533
angle::Result ProgramMtl::resizeDefaultUniformBlocksMemory(
534
    const gl::Context *glContext,
535
    const gl::ShaderMap<size_t> &requiredBufferSize)
536
{
537
    ContextMtl *contextMtl = mtl::GetImpl(glContext);
538
429
    for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
539
    for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
430
    {
540
    {
431
        if (requiredBufferSize[shaderType] > 0)
541
        if (requiredBufferSize[shaderType] > 0)
Lines 453-458 angle::Result ProgramMtl::getSpecializedShader(mtl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.mm_sec10
453
                                               id<MTLFunction> *shaderOut)
563
                                               id<MTLFunction> *shaderOut)
454
{
564
{
455
    static_assert(YES == 1, "YES should have value of 1");
565
    static_assert(YES == 1, "YES should have value of 1");
566
    #if ANGLE_ENABLE_METAL_SPIRV
567
        static const bool useSpirv = sh::readBoolEnvVar("ANGLE_GEN_MTL_WITH_SPIRV");
568
    #endif
456
569
457
    mtl::TranslatedShaderInfo *translatedMslInfo = &mMslShaderTranslateInfo[shaderType];
570
    mtl::TranslatedShaderInfo *translatedMslInfo = &mMslShaderTranslateInfo[shaderType];
458
    ProgramShaderObjVariantMtl *shaderVariant;
571
    ProgramShaderObjVariantMtl *shaderVariant;
Lines 490-498 angle::Result ProgramMtl::getSpecializedShader(mtl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.mm_sec11
490
            BOOL emulateDiscard = renderPipelineDesc.rasterizationType ==
603
            BOOL emulateDiscard = renderPipelineDesc.rasterizationType ==
491
                                  mtl::RenderPipelineRasterization::EmulatedDiscard;
604
                                  mtl::RenderPipelineRasterization::EmulatedDiscard;
492
605
493
            NSString *discardEnabledStr =
606
            NSString *discardEnabledStr;
494
                [NSString stringWithFormat:@"%s%s", sh::mtl::kRasterizerDiscardEnabledConstName,
607
#if ANGLE_ENABLE_METAL_SPIRV
495
                                           kSpirvCrossSpecConstSuffix];
608
            if (useSpirv)
609
            {
610
                discardEnabledStr = [NSString
611
                    stringWithFormat:@"%s%s",
612
                                     sh::TranslatorMetal::GetRasterizationDiscardEnabledConstName(),
613
                                     kSpirvCrossSpecConstSuffix];
614
            }
615
            else
616
#endif
617
            {
618
                discardEnabledStr =
619
                    [NSString stringWithUTF8String:sh::TranslatorMetalDirect::
620
                                                       GetRasterizationDiscardEnabledConstName()];
621
            }
496
622
497
            funcConstants = [[MTLFunctionConstantValues alloc] init];
623
            funcConstants = [[MTLFunctionConstantValues alloc] init];
498
            [funcConstants setConstantValue:&emulateDiscard
624
            [funcConstants setConstantValue:&emulateDiscard
Lines 515-523 angle::Result ProgramMtl::getSpecializedShader(mtl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.mm_sec12
515
641
516
        ANGLE_MTL_OBJC_SCOPE
642
        ANGLE_MTL_OBJC_SCOPE
517
        {
643
        {
518
            NSString *coverageMaskEnabledStr =
644
            NSString *coverageMaskEnabledStr;
519
                [NSString stringWithFormat:@"%s%s", sh::mtl::kCoverageMaskEnabledConstName,
645
#if ANGLE_ENABLE_METAL_SPIRV
520
                                           kSpirvCrossSpecConstSuffix];
646
            if (useSpirv)
647
            {
648
                coverageMaskEnabledStr = [NSString
649
                    stringWithFormat:@"%s%s",
650
                                     sh::TranslatorMetal::GetCoverageMaskEnabledConstName(),
651
                                     kSpirvCrossSpecConstSuffix];
652
            }
653
            else
654
#endif
655
            {
656
                coverageMaskEnabledStr =
657
                    [NSString stringWithUTF8String:sh::TranslatorMetalDirect::
658
                                                       GetCoverageMaskEnabledConstName()];
659
            }
521
660
522
            funcConstants = [[MTLFunctionConstantValues alloc] init];
661
            funcConstants = [[MTLFunctionConstantValues alloc] init];
523
            [funcConstants setConstantValue:&emulateCoverageMask
662
            [funcConstants setConstantValue:&emulateCoverageMask
Lines 555-560 angle::Result ProgramMtl::getSpecializedShader(mtl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.mm_sec13
555
694
556
    return angle::Result::Continue;
695
    return angle::Result::Continue;
557
}
696
}
697
558
bool ProgramMtl::hasSpecializedShader(gl::ShaderType shaderType,
698
bool ProgramMtl::hasSpecializedShader(gl::ShaderType shaderType,
559
                                      const mtl::RenderPipelineDesc &renderPipelineDesc)
699
                                      const mtl::RenderPipelineDesc &renderPipelineDesc)
560
{
700
{
Lines 592-597 angle::Result ProgramMtl::createMslShaderLib(mtl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.mm_sec14
592
    }
732
    }
593
}
733
}
594
734
735
void ProgramMtl::saveDefaultUniformBlocksInfo(gl::BinaryOutputStream *stream)
736
{
737
    // Serializes the uniformLayout data of mDefaultUniformBlocks
738
    for (gl::ShaderType shaderType : gl::AllShaderTypes())
739
    {
740
        const size_t uniformCount = mDefaultUniformBlocks[shaderType].uniformLayout.size();
741
        stream->writeInt<size_t>(uniformCount);
742
        for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
743
        {
744
            sh::BlockMemberInfo &blockInfo =
745
                mDefaultUniformBlocks[shaderType].uniformLayout[uniformIndex];
746
            gl::WriteBlockMemberInfo(stream, blockInfo);
747
        }
748
    }
749
750
    // Serializes required uniform block memory sizes
751
    for (gl::ShaderType shaderType : gl::AllShaderTypes())
752
    {
753
        stream->writeInt(mDefaultUniformBlocks[shaderType].uniformData.size());
754
    }
755
}
756
757
angle::Result ProgramMtl::loadDefaultUniformBlocksInfo(const gl::Context *glContext,
758
                                                       gl::BinaryInputStream *stream)
759
{
760
    gl::ShaderMap<size_t> requiredBufferSize;
761
    requiredBufferSize.fill(0);
762
763
    // Deserializes the uniformLayout data of mDefaultUniformBlocks
764
    for (gl::ShaderType shaderType : gl::AllShaderTypes())
765
    {
766
        const size_t uniformCount = stream->readInt<size_t>();
767
        for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
768
        {
769
            sh::BlockMemberInfo blockInfo;
770
            gl::LoadBlockMemberInfo(stream, &blockInfo);
771
            mDefaultUniformBlocks[shaderType].uniformLayout.push_back(blockInfo);
772
        }
773
    }
774
775
    // Deserializes required uniform block memory sizes
776
    for (gl::ShaderType shaderType : gl::AllShaderTypes())
777
    {
778
        requiredBufferSize[shaderType] = stream->readInt<size_t>();
779
    }
780
781
    return resizeDefaultUniformBlocksMemory(glContext, requiredBufferSize);
782
}
783
784
void ProgramMtl::saveShaderInternalInfo(gl::BinaryOutputStream *stream)
785
{
786
    for (gl::ShaderType shaderType : gl::AllShaderTypes())
787
    {
788
        stream->writeInt<int>(mMslShaderTranslateInfo[shaderType].hasUBOArgumentBuffer);
789
        for (const mtl::SamplerBinding &binding :
790
             mMslShaderTranslateInfo[shaderType].actualSamplerBindings)
791
        {
792
            stream->writeInt<uint32_t>(binding.textureBinding);
793
            stream->writeInt<uint32_t>(binding.samplerBinding);
794
        }
795
796
        for (uint32_t uboBinding : mMslShaderTranslateInfo[shaderType].actualUBOBindings)
797
        {
798
            stream->writeInt<uint32_t>(uboBinding);
799
        }
800
    }
801
}
802
803
void ProgramMtl::loadShaderInternalInfo(gl::BinaryInputStream *stream)
804
{
805
    for (gl::ShaderType shaderType : gl::AllShaderTypes())
806
    {
807
        mMslShaderTranslateInfo[shaderType].hasUBOArgumentBuffer = stream->readInt<int>() != 0;
808
        for (mtl::SamplerBinding &binding :
809
             mMslShaderTranslateInfo[shaderType].actualSamplerBindings)
810
        {
811
            binding.textureBinding = stream->readInt<uint32_t>();
812
            binding.samplerBinding = stream->readInt<uint32_t>();
813
        }
814
815
        for (uint32_t &uboBinding : mMslShaderTranslateInfo[shaderType].actualUBOBindings)
816
        {
817
            uboBinding = stream->readInt<uint32_t>();
818
        }
819
    }
820
}
821
595
GLboolean ProgramMtl::validate(const gl::Caps &caps, gl::InfoLog *infoLog)
822
GLboolean ProgramMtl::validate(const gl::Caps &caps, gl::InfoLog *infoLog)
596
{
823
{
597
    // No-op. The spec is very vague about the behavior of validation.
824
    // No-op. The spec is very vague about the behavior of validation.
Lines 877-890 angle::Result ProgramMtl::setupDraw(const gl::Context *glContext, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.mm_sec15
877
                                    const mtl::RenderPipelineDesc &pipelineDesc,
1104
                                    const mtl::RenderPipelineDesc &pipelineDesc,
878
                                    bool pipelineDescChanged,
1105
                                    bool pipelineDescChanged,
879
                                    bool forceTexturesSetting,
1106
                                    bool forceTexturesSetting,
880
                                    bool uniformBuffersDirty)
1107
                                    bool uniformBuffersDirty,
1108
                                    bool transformFeedbackDraw)
881
{
1109
{
882
    ContextMtl *context = mtl::GetImpl(glContext);
1110
    ContextMtl *context = mtl::GetImpl(glContext);
883
    if (pipelineDescChanged)
1111
    if (pipelineDescChanged)
884
    {
1112
    {
885
        // Render pipeline state needs to be changed
1113
        // Render pipeline state needs to be changed
886
        id<MTLRenderPipelineState> pipelineState =
1114
        id<MTLRenderPipelineState> pipelineState = nil;
887
            mMetalRenderPipelineCache.getRenderPipelineState(context, pipelineDesc);
1115
        if (transformFeedbackDraw)
1116
        {
1117
            mtl::RenderPipelineDesc xfbPipelineDesc = mtl::RenderPipelineDesc(pipelineDesc);
1118
            xfbPipelineDesc.rasterizationType    = mtl::RenderPipelineRasterization::Disabled;
1119
            pipelineState =
1120
                mMetalXfbRenderPipelineCache->getRenderPipelineState(context, xfbPipelineDesc);
1121
        }
1122
        else
1123
        {
1124
            pipelineState = mMetalRenderPipelineCache.getRenderPipelineState(context, pipelineDesc);
1125
        }
888
        if (!pipelineState)
1126
        if (!pipelineState)
889
        {
1127
        {
890
            // Error already logged inside getRenderPipelineState()
1128
            // Error already logged inside getRenderPipelineState()
Lines 913-923 angle::Result ProgramMtl::setupDraw(const gl::Context *glContext, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.mm_sec16
913
        ANGLE_TRY(updateUniformBuffers(context, cmdEncoder, pipelineDesc));
1151
        ANGLE_TRY(updateUniformBuffers(context, cmdEncoder, pipelineDesc));
914
    }
1152
    }
915
1153
916
    if (pipelineDescChanged)
917
    {
918
        ANGLE_TRY(updateXfbBuffers(context, cmdEncoder, pipelineDesc));
919
    }
920
921
    return angle::Result::Continue;
1154
    return angle::Result::Continue;
922
}
1155
}
923
1156
Lines 948-957 angle::Result ProgramMtl::updateTextures(const gl::Context *glContext, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.mm_sec17
948
                                         mtl::RenderCommandEncoder *cmdEncoder,
1181
                                         mtl::RenderCommandEncoder *cmdEncoder,
949
                                         bool forceUpdate)
1182
                                         bool forceUpdate)
950
{
1183
{
951
    ContextMtl *contextMtl = mtl::GetImpl(glContext);
1184
    ContextMtl *contextMtl                  = mtl::GetImpl(glContext);
952
    const auto &glState    = glContext->getState();
1185
    const auto &glState                     = glContext->getState();
1186
    const gl::ProgramExecutable *executable = glContext->getState().getProgramExecutable();
953
1187
954
    const gl::ActiveTexturesCache &completeTextures = glState.getActiveTexturesCache();
1188
    const gl::ActiveTexturesCache &completeTextures = glState.getActiveTexturesCache();
1189
    const gl::ActiveTextureTypeArray &textureTypes  = executable->getActiveSamplerTypes();
955
1190
956
    for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
1191
    for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
957
    {
1192
    {
Lines 964-969 angle::Result ProgramMtl::updateTextures(const gl::Context *glContext, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.mm_sec18
964
        const mtl::TranslatedShaderInfo &shaderInfo =
1199
        const mtl::TranslatedShaderInfo &shaderInfo =
965
            *mCurrentShaderVariants[shaderType]->translatedSrcInfo;
1200
            *mCurrentShaderVariants[shaderType]->translatedSrcInfo;
966
1201
1202
        bool hasDepthSampler = false;
1203
967
        for (uint32_t textureIndex = 0; textureIndex < mState.getSamplerBindings().size();
1204
        for (uint32_t textureIndex = 0; textureIndex < mState.getSamplerBindings().size();
968
             ++textureIndex)
1205
             ++textureIndex)
969
        {
1206
        {
Lines 975-990 angle::Result ProgramMtl::updateTextures(const gl::Context *glContext, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.mm_sec19
975
                continue;
1212
                continue;
976
            }
1213
            }
977
1214
978
            gl::TextureType textureType = samplerBinding.textureType;
979
1215
980
            for (uint32_t arrayElement = 0; arrayElement < samplerBinding.boundTextureUnits.size();
1216
            for (uint32_t arrayElement = 0; arrayElement < samplerBinding.boundTextureUnits.size();
981
                 ++arrayElement)
1217
                 ++arrayElement)
982
            {
1218
            {
983
                GLuint textureUnit   = samplerBinding.boundTextureUnits[arrayElement];
1219
                GLuint textureUnit          = samplerBinding.boundTextureUnits[arrayElement];
984
                gl::Texture *texture = completeTextures[textureUnit];
1220
                gl::Texture *texture        = completeTextures[textureUnit];
985
                gl::Sampler *sampler = contextMtl->getState().getSampler(textureUnit);
1221
                gl::Sampler *sampler        = contextMtl->getState().getSampler(textureUnit);
986
                uint32_t textureSlot = mslBinding.textureBinding + arrayElement;
1222
                gl::TextureType textureType = textureTypes[textureUnit];
987
                uint32_t samplerSlot = mslBinding.samplerBinding + arrayElement;
1223
                uint32_t textureSlot        = mslBinding.textureBinding + arrayElement;
1224
                uint32_t samplerSlot        = mslBinding.samplerBinding + arrayElement;
988
                if (!texture)
1225
                if (!texture)
989
                {
1226
                {
990
                    ANGLE_TRY(contextMtl->getIncompleteTexture(glContext, textureType, &texture));
1227
                    ANGLE_TRY(contextMtl->getIncompleteTexture(glContext, textureType, &texture));
Lines 994-1018 angle::Result ProgramMtl::updateTextures(const gl::Context *glContext, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.mm_sec20
994
                TextureMtl *textureMtl = mtl::GetImpl(texture);
1231
                TextureMtl *textureMtl = mtl::GetImpl(texture);
995
                if (samplerBinding.format == gl::SamplerFormat::Shadow)
1232
                if (samplerBinding.format == gl::SamplerFormat::Shadow)
996
                {
1233
                {
997
                    // http://anglebug.com/5107
1234
                    hasDepthSampler                  = true;
998
                    // Metal doesn't support a compare mode where sampling a shadow sampler could
1235
                    mShadowCompareModes[textureSlot] = mtl::MslGetShaderShadowCompareMode(
999
                    // return a same value as if sampling from a normal sampler.
1236
                        samplerState->getCompareMode(), samplerState->getCompareFunc());
1000
                    // Supporting this could require hacking spirv-cross to change sample_compare()
1001
                    // to sample().
1002
                    if (ANGLE_UNLIKELY(samplerState->getCompareMode() != GL_COMPARE_REF_TO_TEXTURE))
1003
                    {
1004
                        ERR() << "GL_TEXTURE_COMPARE_MODE != GL_COMPARE_REF_TO_TEXTURE is not "
1005
                                 "supported";
1006
                        ANGLE_MTL_TRY(contextMtl,
1007
                                      samplerState->getCompareMode() == GL_COMPARE_REF_TO_TEXTURE);
1008
                    }
1009
                }
1237
                }
1010
1238
1011
                ANGLE_TRY(textureMtl->bindToShader(glContext, cmdEncoder, shaderType, sampler,
1239
                ANGLE_TRY(textureMtl->bindToShader(glContext, cmdEncoder, shaderType, sampler,
1012
                                                   textureSlot, samplerSlot));
1240
                                                   textureSlot, samplerSlot));
1013
            }  // for array elements
1241
            }  // for array elements
1014
        }      // for sampler bindings
1242
        }      // for sampler bindings
1015
    }          // for shader types
1243
1244
        if (hasDepthSampler)
1245
        {
1246
            cmdEncoder->setData(shaderType, mShadowCompareModes,
1247
                                mtl::kShadowSamplerCompareModesBindingIndex);
1248
        }
1249
    }  // for shader types
1016
1250
1017
    return angle::Result::Continue;
1251
    return angle::Result::Continue;
1018
}
1252
}
Lines 1040-1050 angle::Result ProgramMtl::updateUniformBuffers(ContextMtl *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.mm_sec21
1040
1274
1041
    for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
1275
    for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
1042
    {
1276
    {
1043
        if (!mCurrentShaderVariants[shaderType])
1044
        {
1045
            continue;
1046
        }
1047
1048
        if (mCurrentShaderVariants[shaderType]->translatedSrcInfo->hasUBOArgumentBuffer)
1277
        if (mCurrentShaderVariants[shaderType]->translatedSrcInfo->hasUBOArgumentBuffer)
1049
        {
1278
        {
1050
            ANGLE_TRY(
1279
            ANGLE_TRY(
Lines 1149-1156 angle::Result ProgramMtl::bindUniformBuffersToDiscreteSlots( a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.mm_sec22
1149
    gl::ShaderType shaderType)
1378
    gl::ShaderType shaderType)
1150
{
1379
{
1151
    const gl::State &glState = context->getState();
1380
    const gl::State &glState = context->getState();
1152
    const mtl::TranslatedShaderInfo &shaderInfo =
1153
        *mCurrentShaderVariants[shaderType]->translatedSrcInfo;
1154
    for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex)
1381
    for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex)
1155
    {
1382
    {
1156
        const gl::InterfaceBlock &block = blocks[bufferIndex];
1383
        const gl::InterfaceBlock &block = blocks[bufferIndex];
Lines 1162-1168 angle::Result ProgramMtl::bindUniformBuffersToDiscreteSlots( a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.mm_sec23
1162
            continue;
1389
            continue;
1163
        }
1390
        }
1164
1391
1165
        uint32_t actualBufferIdx = shaderInfo.actualUBOBindings[bufferIndex];
1392
        uint32_t actualBufferIdx =
1393
            mMslShaderTranslateInfo[shaderType].actualUBOBindings[bufferIndex];
1166
1394
1167
        if (actualBufferIdx >= mtl::kMaxShaderBuffers)
1395
        if (actualBufferIdx >= mtl::kMaxShaderBuffers)
1168
        {
1396
        {
Lines 1199-1210 angle::Result ProgramMtl::encodeUniformBuffersInfoArgumentBuffer( a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.mm_sec24
1199
    [bufferEncoder.metalArgBufferEncoder setArgumentBuffer:argumentBuffer->get()
1427
    [bufferEncoder.metalArgBufferEncoder setArgumentBuffer:argumentBuffer->get()
1200
                                                    offset:argumentBufferOffset];
1428
                                                    offset:argumentBufferOffset];
1201
1429
1202
    static_assert(MTLRenderStageVertex == (0x1 << static_cast<uint32_t>(gl::ShaderType::Vertex)),
1430
    constexpr gl::ShaderMap<MTLRenderStages> kShaderStageMap = {
1203
                  "Expected gl ShaderType enum and Metal enum to relative to each other");
1431
        {gl::ShaderType::Vertex, mtl::kRenderStageVertex},
1204
    static_assert(
1432
        {gl::ShaderType::Fragment, mtl::kRenderStageFragment},
1205
        MTLRenderStageFragment == (0x1 << static_cast<uint32_t>(gl::ShaderType::Fragment)),
1433
    };
1206
        "Expected gl ShaderType enum and Metal enum to relative to each other");
1434
1207
    auto mtlRenderStage = static_cast<MTLRenderStages>(0x1 << static_cast<uint32_t>(shaderType));
1435
    auto mtlRenderStage = kShaderStageMap[shaderType];
1208
1436
1209
    for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex)
1437
    for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex)
1210
    {
1438
    {
Lines 1239-1287 angle::Result ProgramMtl::encodeUniformBuffersInfoArgumentBuffer( a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ProgramMtl.mm_sec25
1239
    return angle::Result::Continue;
1467
    return angle::Result::Continue;
1240
}
1468
}
1241
1469
1242
angle::Result ProgramMtl::updateXfbBuffers(ContextMtl *context,
1243
                                           mtl::RenderCommandEncoder *cmdEncoder,
1244
                                           const mtl::RenderPipelineDesc &pipelineDesc)
1245
{
1246
    const gl::State &glState                 = context->getState();
1247
    gl::TransformFeedback *transformFeedback = glState.getCurrentTransformFeedback();
1248
1249
    if (pipelineDesc.rasterizationEnabled() || !glState.isTransformFeedbackActiveUnpaused() ||
1250
        ANGLE_UNLIKELY(!transformFeedback))
1251
    {
1252
        // XFB output can only be used with rasterization disabled.
1253
        return angle::Result::Continue;
1254
    }
1255
1256
    size_t xfbBufferCount = glState.getProgramExecutable()->getTransformFeedbackBufferCount();
1257
1258
    ASSERT(xfbBufferCount > 0);
1259
    ASSERT(mState.getTransformFeedbackBufferMode() != GL_INTERLEAVED_ATTRIBS ||
1260
           xfbBufferCount == 1);
1261
1262
    for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
1263
    {
1264
        uint32_t actualBufferIdx = mMslXfbOnlyVertexShaderInfo.actualXFBBindings[bufferIndex];
1265
1266
        if (actualBufferIdx >= mtl::kMaxShaderBuffers)
1267
        {
1268
            continue;
1269
        }
1270
1271
        const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
1272
            transformFeedback->getIndexedBuffer(bufferIndex);
1273
        gl::Buffer *buffer = bufferBinding.get();
1274
        ASSERT((bufferBinding.getOffset() % 4) == 0);
1275
        ASSERT(buffer != nullptr);
1276
1277
        BufferMtl *bufferMtl = mtl::GetImpl(buffer);
1278
1279
        // Use offset=0, actual offset will be set in Driver Uniform inside ContextMtl.
1280
        cmdEncoder->setBufferForWrite(gl::ShaderType::Vertex, bufferMtl->getCurrentBuffer(), 0,
1281
                                      actualBufferIdx);
1282
    }
1283
1284
    return angle::Result::Continue;
1285
}
1286
1287
}  // namespace rx
1470
}  // namespace rx
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/QueryMtl.h -4 / +8 lines
Lines 1-5 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/QueryMtl.h_sec1
1
//
1
//
2
// Copyright 2020 The ANGLE Project Authors. All rights reserved.
2
// Copyright (c) 2020 The ANGLE Project Authors. All rights reserved.
3
// Use of this source code is governed by a BSD-style license that can be
3
// Use of this source code is governed by a BSD-style license that can be
4
// found in the LICENSE file.
4
// found in the LICENSE file.
5
//
5
//
Lines 98-105 class QueryMtl : public QueryImpl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/QueryMtl.h_sec2
98
    const mtl::BufferRef &getVisibilityResultBuffer() const { return mVisibilityResultBuffer; }
98
    const mtl::BufferRef &getVisibilityResultBuffer() const { return mVisibilityResultBuffer; }
99
    // Reset the occlusion query result stored in buffer to zero
99
    // Reset the occlusion query result stored in buffer to zero
100
    void resetVisibilityResult(ContextMtl *contextMtl);
100
    void resetVisibilityResult(ContextMtl *contextMtl);
101
101
    void onTransformFeedbackEnd(GLsizeiptr primitivesDrawn);
102
    void onTransformFeedbackEnd(const gl::Context *context);
103
102
104
  private:
103
  private:
105
    template <typename T>
104
    template <typename T>
Lines 108-115 class QueryMtl : public QueryImpl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/QueryMtl.h_sec3
108
    // List of offsets in the render pass's occlusion query pool buffer allocated for this query
107
    // List of offsets in the render pass's occlusion query pool buffer allocated for this query
109
    VisibilityBufferOffsetsMtl mVisibilityBufferOffsets;
108
    VisibilityBufferOffsetsMtl mVisibilityBufferOffsets;
110
    mtl::BufferRef mVisibilityResultBuffer;
109
    mtl::BufferRef mVisibilityResultBuffer;
110
    // Used with TransformFeedbackPrimitivesWritten when transform feedback is emulated.
111
    size_t mTransformFeedbackPrimitivesDrawn;
111
112
112
    size_t mTransformFeedbackPrimitivesDrawn = 0;
113
    // TODO(jcunningham): currently only used for mTransformFeedbackPrimitivesDrawn
114
    // but can be used for rest of results
115
    uint64_t mCachedResult;
116
    bool mCachedResultValid;
113
};
117
};
114
118
115
}  // namespace rx
119
}  // namespace rx
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/QueryMtl.mm -15 / +27 lines
Lines 1-5 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/QueryMtl.mm_sec1
1
//
1
//
2
// Copyright 2020 The ANGLE Project Authors. All rights reserved.
2
// Copyright (c) 2020 The ANGLE Project Authors. All rights reserved.
3
// Use of this source code is governed by a BSD-style license that can be
3
// Use of this source code is governed by a BSD-style license that can be
4
// found in the LICENSE file.
4
// found in the LICENSE file.
5
//
5
//
Lines 13-19 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/QueryMtl.mm_sec2
13
13
14
namespace rx
14
namespace rx
15
{
15
{
16
QueryMtl::QueryMtl(gl::QueryType type) : QueryImpl(type) {}
16
QueryMtl::QueryMtl(gl::QueryType type)
17
    : QueryImpl(type),
18
      mTransformFeedbackPrimitivesDrawn(0),
19
      mCachedResult(0),
20
      mCachedResultValid(false)
21
{}
17
22
18
QueryMtl::~QueryMtl() {}
23
QueryMtl::~QueryMtl() {}
19
24
Lines 22-34 void QueryMtl::onDestroy(const gl::Context *context) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/QueryMtl.mm_sec3
22
    ContextMtl *contextMtl = mtl::GetImpl(context);
27
    ContextMtl *contextMtl = mtl::GetImpl(context);
23
    if (!getAllocatedVisibilityOffsets().empty())
28
    if (!getAllocatedVisibilityOffsets().empty())
24
    {
29
    {
25
        contextMtl->onOcclusionQueryDestroy(context, this);
30
        contextMtl->onOcclusionQueryDestroyed(context, this);
26
    }
31
    }
27
    mVisibilityResultBuffer = nullptr;
32
    mVisibilityResultBuffer = nullptr;
28
}
33
}
29
34
30
angle::Result QueryMtl::begin(const gl::Context *context)
35
angle::Result QueryMtl::begin(const gl::Context *context)
31
{
36
{
37
    mCachedResultValid     = false;
32
    ContextMtl *contextMtl = mtl::GetImpl(context);
38
    ContextMtl *contextMtl = mtl::GetImpl(context);
33
    switch (getType())
39
    switch (getType())
34
    {
40
    {
Lines 47-53 angle::Result QueryMtl::begin(const gl::Context *context) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/QueryMtl.mm_sec4
47
                }
53
                }
48
            }
54
            }
49
55
50
            ANGLE_TRY(contextMtl->onOcclusionQueryBegin(context, this));
56
            ANGLE_TRY(contextMtl->onOcclusionQueryBegan(context, this));
51
            break;
57
            break;
52
        case gl::QueryType::TransformFeedbackPrimitivesWritten:
58
        case gl::QueryType::TransformFeedbackPrimitivesWritten:
53
            mTransformFeedbackPrimitivesDrawn = 0;
59
            mTransformFeedbackPrimitivesDrawn = 0;
Lines 66-78 angle::Result QueryMtl::end(const gl::Context *context) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/QueryMtl.mm_sec5
66
    {
72
    {
67
        case gl::QueryType::AnySamples:
73
        case gl::QueryType::AnySamples:
68
        case gl::QueryType::AnySamplesConservative:
74
        case gl::QueryType::AnySamplesConservative:
69
            contextMtl->onOcclusionQueryEnd(context, this);
75
            contextMtl->onOcclusionQueryEnded(context, this);
70
            break;
76
            break;
71
        case gl::QueryType::TransformFeedbackPrimitivesWritten:
77
        case gl::QueryType::TransformFeedbackPrimitivesWritten:
78
        {
79
            mCachedResult = mTransformFeedbackPrimitivesDrawn;
80
72
            // There could be transform feedback in progress, so add the primitives drawn so far
81
            // There could be transform feedback in progress, so add the primitives drawn so far
73
            // from the current transform feedback object.
82
            // from the current transform feedback object.
74
            onTransformFeedbackEnd(context);
83
            gl::TransformFeedback *transformFeedback =
75
            break;
84
                context->getState().getCurrentTransformFeedback();
85
            if (transformFeedback)
86
            {
87
                mCachedResult += transformFeedback->getPrimitivesDrawn();
88
            }
89
            mCachedResultValid = true;
90
        }
91
        break;
76
        default:
92
        default:
77
            UNIMPLEMENTED();
93
            UNIMPLEMENTED();
78
            break;
94
            break;
Lines 110-116 angle::Result QueryMtl::waitAndGetResult(const gl::Context *context, T *params) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/QueryMtl.mm_sec6
110
        }
126
        }
111
        break;
127
        break;
112
        case gl::QueryType::TransformFeedbackPrimitivesWritten:
128
        case gl::QueryType::TransformFeedbackPrimitivesWritten:
113
            *params = static_cast<T>(mTransformFeedbackPrimitivesDrawn);
129
            *params = static_cast<T>(mCachedResult);
114
            break;
130
            break;
115
        default:
131
        default:
116
            UNIMPLEMENTED();
132
            UNIMPLEMENTED();
Lines 137-143 angle::Result QueryMtl::isResultAvailable(const gl::Context *context, bool *avai a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/QueryMtl.mm_sec7
137
            *available = !mVisibilityResultBuffer->isBeingUsedByGPU(contextMtl);
153
            *available = !mVisibilityResultBuffer->isBeingUsedByGPU(contextMtl);
138
            break;
154
            break;
139
        case gl::QueryType::TransformFeedbackPrimitivesWritten:
155
        case gl::QueryType::TransformFeedbackPrimitivesWritten:
140
            *available = true;
156
            *available = mCachedResultValid;
141
            break;
157
            break;
142
        default:
158
        default:
143
            UNIMPLEMENTED();
159
            UNIMPLEMENTED();
Lines 175-187 void QueryMtl::resetVisibilityResult(ContextMtl *contextMtl) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/QueryMtl.mm_sec8
175
    mVisibilityResultBuffer->syncContent(contextMtl, blitEncoder);
191
    mVisibilityResultBuffer->syncContent(contextMtl, blitEncoder);
176
}
192
}
177
193
178
void QueryMtl::onTransformFeedbackEnd(const gl::Context *context)
194
void QueryMtl::onTransformFeedbackEnd(GLsizeiptr primitivesDrawn)
179
{
195
{
180
    gl::TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback();
196
    mTransformFeedbackPrimitivesDrawn += primitivesDrawn;
181
    if (transformFeedback)
182
    {
183
        mTransformFeedbackPrimitivesDrawn += transformFeedback->getPrimitivesDrawn();
184
    }
185
}
197
}
186
198
187
}
199
}
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/RenderBufferMtl.h +1 lines
Lines 57-62 class RenderbufferMtl : public RenderbufferImpl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/RenderBufferMtl.h_sec1
57
57
58
    mtl::Format mFormat;
58
    mtl::Format mFormat;
59
    mtl::TextureRef mTexture;
59
    mtl::TextureRef mTexture;
60
    mtl::TextureRef mImplicitMSTexture;
60
    RenderTargetMtl mRenderTarget;
61
    RenderTargetMtl mRenderTarget;
61
};
62
};
62
63
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/RenderBufferMtl.mm -16 / +49 lines
Lines 27-33 void RenderbufferMtl::onDestroy(const gl::Context *context) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/RenderBufferMtl.mm_sec1
27
27
28
void RenderbufferMtl::releaseTexture()
28
void RenderbufferMtl::releaseTexture()
29
{
29
{
30
    mTexture = nullptr;
30
    mTexture           = nullptr;
31
    mImplicitMSTexture = nullptr;
31
}
32
}
32
33
33
angle::Result RenderbufferMtl::setStorageImpl(const gl::Context *context,
34
angle::Result RenderbufferMtl::setStorageImpl(const gl::Context *context,
Lines 42-49 angle::Result RenderbufferMtl::setStorageImpl(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/RenderBufferMtl.mm_sec2
42
    {
43
    {
43
        // Check against the state if we need to recreate the storage.
44
        // Check against the state if we need to recreate the storage.
44
        if (internalformat != mState.getFormat().info->internalFormat ||
45
        if (internalformat != mState.getFormat().info->internalFormat ||
45
            width != mState.getWidth() || height != mState.getHeight() ||
46
            static_cast<GLsizei>(width) != mState.getWidth() ||
46
            samples != mState.getSamples())
47
            static_cast<GLsizei>(height) != mState.getHeight() ||
48
            static_cast<GLsizei>(samples) != mState.getSamples())
47
        {
49
        {
48
            releaseTexture();
50
            releaseTexture();
49
        }
51
        }
Lines 72-101 angle::Result RenderbufferMtl::setStorageImpl(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/RenderBufferMtl.mm_sec3
72
74
73
    if ((mTexture == nullptr || !mTexture->valid()) && (width != 0 && height != 0))
75
    if ((mTexture == nullptr || !mTexture->valid()) && (width != 0 && height != 0))
74
    {
76
    {
75
        if (actualSamples == 1)
77
        if (actualSamples == 1 || (mFormat.hasDepthAndStencilBits() && mFormat.getCaps().resolve))
76
        {
78
        {
77
            ANGLE_TRY(mtl::Texture::Make2DTexture(contextMtl, mFormat, width, height, 1, false,
79
            ANGLE_TRY(mtl::Texture::Make2DTexture(contextMtl, mFormat, static_cast<uint32_t>(width),
78
                                                  mFormat.hasDepthAndStencilBits(), &mTexture));
80
                                                  static_cast<uint32_t>(height), 1,
81
                                                  /* renderTargetOnly */ false,
82
                                                  /* allowFormatView */ false, &mTexture));
83
84
            // Use implicit resolve for depth stencil texture whenever possible. This is because
85
            // for depth stencil texture, if stencil needs to be blitted, a formatted clone has
86
            // to be created. And it is expensive to clone a multisample texture.
87
            if (actualSamples > 1)
88
            {
89
                // This format must supports implicit resolve
90
                ASSERT(mFormat.getCaps().resolve);
91
92
                ANGLE_TRY(mtl::Texture::Make2DMSTexture(
93
                    contextMtl, mFormat, static_cast<uint32_t>(width),
94
                    static_cast<uint32_t>(height), actualSamples,
95
                    /* renderTargetOnly */ true,
96
                    /* allowFormatView */ false, &mImplicitMSTexture));
97
            }
79
        }
98
        }
80
        else
99
        else
81
        {
100
        {
82
            ANGLE_TRY(mtl::Texture::Make2DMSTexture(
101
            ANGLE_TRY(mtl::Texture::Make2DMSTexture(contextMtl, mFormat,
83
                contextMtl, mFormat, width, height, actualSamples,
102
                                                    static_cast<uint32_t>(width),
84
                /* renderTargetOnly */ false,
103
                                                    static_cast<uint32_t>(height), actualSamples,
85
                /* allowFormatView */ mFormat.hasDepthAndStencilBits(), &mTexture));
104
                                                    /* renderTargetOnly */ false,
105
                                                    /* allowFormatView */ false, &mTexture));
86
        }
106
        }
87
107
88
        mRenderTarget.set(mTexture, mtl::kZeroNativeMipLevel, 0, mFormat);
108
        mRenderTarget.setWithImplicitMSTexture(mTexture, mImplicitMSTexture, mtl::kZeroNativeMipLevel, 0, mFormat);
89
109
90
        // For emulated channels that GL texture intends to not have,
110
        // For emulated channels that GL texture intends to not have,
91
        // we need to initialize their content.
111
        // we need to initialize their content.
92
        bool emulatedChannels = mtl::IsFormatEmulated(mFormat);
112
        bool emulatedChannels = mtl::IsFormatEmulated(mFormat);
93
        if (emulatedChannels)
113
        if (emulatedChannels)
94
        {
114
        {
95
            auto index = mtl::ImageNativeIndex::FromBaseZeroGLIndex(gl::ImageIndex::Make2D(0));
115
            gl::ImageIndex index;
96
116
97
            ANGLE_TRY(mtl::InitializeTextureContents(context, mTexture, mFormat, index));
117
            if (actualSamples > 1)
98
        }
118
            {
119
                index = gl::ImageIndex::Make2DMultisample();
120
            }
121
            else
122
            {
123
                index = gl::ImageIndex::Make2D(0);
124
            }
125
126
            ANGLE_TRY(mtl::InitializeTextureContents(context, mTexture, mFormat, mtl::ImageNativeIndex(index, 0)));
127
            if (mImplicitMSTexture)
128
            {
129
                ANGLE_TRY(mtl::InitializeTextureContents(context, mImplicitMSTexture, mFormat,
130
                                                         mtl::ImageNativeIndex(gl::ImageIndex::Make2DMultisample(), 0)));
131
            }
132
        }  // if (emulatedChannels)
99
    }
133
    }
100
134
101
    return angle::Result::Continue;
135
    return angle::Result::Continue;
Lines 133-139 angle::Result RenderbufferMtl::getAttachmentRenderTarget(const gl::Context *cont a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/RenderBufferMtl.mm_sec4
133
                                                         GLsizei samples,
167
                                                         GLsizei samples,
134
                                                         FramebufferAttachmentRenderTarget **rtOut)
168
                                                         FramebufferAttachmentRenderTarget **rtOut)
135
{
169
{
136
    // NOTE(hqle): Support MSAA.
137
    ASSERT(mTexture && mTexture->valid());
170
    ASSERT(mTexture && mTexture->valid());
138
    *rtOut = &mRenderTarget;
171
    *rtOut = &mRenderTarget;
139
    return angle::Result::Continue;
172
    return angle::Result::Continue;
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/RenderTargetMtl.h -9 / +7 lines
Lines 46-66 class RenderTargetMtl final : public FramebufferAttachmentRenderTarget a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/RenderTargetMtl.h_sec1
46
    void duplicateFrom(const RenderTargetMtl &src);
46
    void duplicateFrom(const RenderTargetMtl &src);
47
    void reset();
47
    void reset();
48
48
49
    mtl::TextureRef getTexture() const { return mTexture.lock(); }
49
    mtl::TextureRef getTexture() const { return mTextureRenderTargetInfo->getTextureRef(); }
50
    mtl::TextureRef getImplicitMSTexture() const { return mImplicitMSTexture.lock(); }
50
    mtl::TextureRef getImplicitMSTexture() const { return mTextureRenderTargetInfo->getImplicitMSTextureRef(); }
51
    const mtl::MipmapNativeLevel &getLevelIndex() const { return mLevelIndex; }
51
    const mtl::MipmapNativeLevel &getLevelIndex() const { return mTextureRenderTargetInfo->level; }
52
    uint32_t getLayerIndex() const { return mLayerIndex; }
52
    uint32_t getLayerIndex() const { return mTextureRenderTargetInfo->sliceOrDepth; }
53
    uint32_t getRenderSamples() const;
53
    uint32_t getRenderSamples() const;
54
    const mtl::Format *getFormat() const { return mFormat; }
54
    const mtl::Format *getFormat() const { return mFormat; }
55
55
56
    void toRenderPassAttachmentDesc(mtl::RenderPassAttachmentDesc *rpaDescOut) const;
56
    void toRenderPassAttachmentDesc(mtl::RenderPassAttachmentDesc *rpaDescOut) const;
57
57
58
  private:
58
  private:
59
    mtl::TextureWeakRef mTexture;
59
// This is shared pointer to avoid crashing when texture deleted after bound to a frame buffer.
60
    mtl::TextureWeakRef mImplicitMSTexture;
60
    std::shared_ptr<mtl::RenderPassAttachmentTextureTargetDesc> mTextureRenderTargetInfo;
61
    mtl::MipmapNativeLevel mLevelIndex = mtl::kZeroNativeMipLevel;
61
    const mtl::Format *mFormat = nullptr;
62
    uint32_t mLayerIndex               = 0;
63
    const mtl::Format *mFormat         = nullptr;
64
};
62
};
65
}  // namespace rx
63
}  // namespace rx
66
64
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/RenderTargetMtl.mm -24 / +18 lines
Lines 11-17 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/RenderTargetMtl.mm_sec1
11
11
12
namespace rx
12
namespace rx
13
{
13
{
14
RenderTargetMtl::RenderTargetMtl() {}
14
RenderTargetMtl::RenderTargetMtl() :
15
  mTextureRenderTargetInfo(std::make_shared<mtl::RenderPassAttachmentTextureTargetDesc>()),
16
  mFormat(nullptr)
17
{}
15
18
16
RenderTargetMtl::~RenderTargetMtl()
19
RenderTargetMtl::~RenderTargetMtl()
17
{
20
{
Lines 19-28 RenderTargetMtl::~RenderTargetMtl() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/RenderTargetMtl.mm_sec2
19
}
22
}
20
23
21
RenderTargetMtl::RenderTargetMtl(RenderTargetMtl &&other)
24
RenderTargetMtl::RenderTargetMtl(RenderTargetMtl &&other)
22
    : mTexture(std::move(other.mTexture)),
25
    : mTextureRenderTargetInfo(std::move(other.mTextureRenderTargetInfo))
23
      mImplicitMSTexture(std::move(other.mImplicitMSTexture)),
24
      mLevelIndex(other.mLevelIndex),
25
      mLayerIndex(other.mLayerIndex)
26
{}
26
{}
27
27
28
void RenderTargetMtl::set(const mtl::TextureRef &texture,
28
void RenderTargetMtl::set(const mtl::TextureRef &texture,
Lines 39-59 void RenderTargetMtl::setWithImplicitMSTexture(const mtl::TextureRef &texture, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/RenderTargetMtl.mm_sec3
39
                                               uint32_t layer,
39
                                               uint32_t layer,
40
                                               const mtl::Format &format)
40
                                               const mtl::Format &format)
41
{
41
{
42
    mTexture           = texture;
42
    mTextureRenderTargetInfo->texture           = texture;
43
    mImplicitMSTexture = implicitMSTexture;
43
    mTextureRenderTargetInfo->implicitMSTexture = implicitMSTexture;
44
    mLevelIndex        = level;
44
    mTextureRenderTargetInfo->level        = level;
45
    mLayerIndex        = layer;
45
    mTextureRenderTargetInfo->sliceOrDepth        = layer;
46
    mFormat            = &format;
46
    mFormat            = &format;
47
}
47
}
48
48
49
void RenderTargetMtl::setTexture(const mtl::TextureRef &texture)
49
void RenderTargetMtl::setTexture(const mtl::TextureRef &texture)
50
{
50
{
51
    mTexture = texture;
51
    mTextureRenderTargetInfo->texture = texture;
52
}
52
}
53
53
54
void RenderTargetMtl::setImplicitMSTexture(const mtl::TextureRef &implicitMSTexture)
54
void RenderTargetMtl::setImplicitMSTexture(const mtl::TextureRef &implicitMSTexture)
55
{
55
{
56
    mImplicitMSTexture = implicitMSTexture;
56
    mTextureRenderTargetInfo->implicitMSTexture = implicitMSTexture;
57
}
57
}
58
58
59
void RenderTargetMtl::duplicateFrom(const RenderTargetMtl &src)
59
void RenderTargetMtl::duplicateFrom(const RenderTargetMtl &src)
Lines 64-88 void RenderTargetMtl::duplicateFrom(const RenderTargetMtl &src) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/RenderTargetMtl.mm_sec4
64
64
65
void RenderTargetMtl::reset()
65
void RenderTargetMtl::reset()
66
{
66
{
67
    mTexture.reset();
67
    mTextureRenderTargetInfo->texture.reset();
68
    mImplicitMSTexture.reset();
68
    mTextureRenderTargetInfo->implicitMSTexture.reset();
69
    mLevelIndex = mtl::kZeroNativeMipLevel;
69
    mTextureRenderTargetInfo->level        = mtl::kZeroNativeMipLevel;
70
    mLayerIndex = 0;
70
    mTextureRenderTargetInfo->sliceOrDepth = 0;
71
    mFormat     = nullptr;
71
    mFormat                                = nullptr;
72
}
72
}
73
73
74
uint32_t RenderTargetMtl::getRenderSamples() const
74
uint32_t RenderTargetMtl::getRenderSamples() const
75
{
75
{
76
    mtl::TextureRef implicitMSTex = getImplicitMSTexture();
76
    return mTextureRenderTargetInfo->getRenderSamples();
77
    mtl::TextureRef tex           = getTexture();
78
    return implicitMSTex ? implicitMSTex->samples() : (tex ? tex->samples() : 1);
79
}
77
}
80
void RenderTargetMtl::toRenderPassAttachmentDesc(mtl::RenderPassAttachmentDesc *rpaDescOut) const
78
void RenderTargetMtl::toRenderPassAttachmentDesc(mtl::RenderPassAttachmentDesc *rpaDescOut) const
81
{
79
{
82
    rpaDescOut->texture           = mTexture.lock();
80
    rpaDescOut->renderTarget = mTextureRenderTargetInfo;
83
    rpaDescOut->implicitMSTexture = mImplicitMSTexture.lock();
84
    rpaDescOut->level             = mLevelIndex;
85
    rpaDescOut->sliceOrDepth      = mLayerIndex;
86
    rpaDescOut->blendable         = mFormat ? mFormat->getCaps().blendable : false;
87
}
81
}
88
}
82
}
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ShaderMtl.h -1 / +13 lines
Lines 11-18 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ShaderMtl.h_sec1
11
11
12
#include <map>
12
#include <map>
13
13
14
#include "compiler/translator/TranslatorMetalDirect.h"
14
#include "libANGLE/renderer/ShaderImpl.h"
15
#include "libANGLE/renderer/ShaderImpl.h"
15
16
namespace rx
16
namespace rx
17
{
17
{
18
18
Lines 26-32 class ShaderMtl : public ShaderImpl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ShaderMtl.h_sec2
26
                                                  gl::ShCompilerInstance *compilerInstance,
26
                                                  gl::ShCompilerInstance *compilerInstance,
27
                                                  ShCompileOptions options) override;
27
                                                  ShCompileOptions options) override;
28
28
29
    sh::TranslatorMetalReflection *getTranslatorMetalReflection()
30
    {
31
        return &translatorMetalReflection;
32
    }
29
    std::string getDebugInfo() const override;
33
    std::string getDebugInfo() const override;
34
35
    sh::TranslatorMetalReflection translatorMetalReflection = {};
36
37
  private:
38
    std::shared_ptr<WaitableCompileEvent> compileImplMtl(const gl::Context *context,
39
                                                         gl::ShCompilerInstance *compilerInstance,
40
                                                         const std::string &source,
41
                                                         ShCompileOptions compileOptions);
30
};
42
};
31
43
32
}  // namespace rx
44
}  // namespace rx
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ShaderMtl.mm -1 / +99 lines
Lines 10-17 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ShaderMtl.mm_sec1
10
#include "libANGLE/renderer/metal/ShaderMtl.h"
10
#include "libANGLE/renderer/metal/ShaderMtl.h"
11
11
12
#include "common/debug.h"
12
#include "common/debug.h"
13
#include "compiler/translator/TranslatorMetal.h"
14
#include "compiler/translator/TranslatorMetalDirect.h"
13
#include "libANGLE/Context.h"
15
#include "libANGLE/Context.h"
16
#include "libANGLE/Shader.h"
17
#include "libANGLE/WorkerThread.h"
14
#include "libANGLE/renderer/metal/ContextMtl.h"
18
#include "libANGLE/renderer/metal/ContextMtl.h"
19
#include "libANGLE/renderer/metal/DisplayMtl.h"
15
20
16
namespace rx
21
namespace rx
17
{
22
{
Lines 20-29 ShaderMtl::ShaderMtl(const gl::ShaderState &state) : ShaderImpl(state) {} a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ShaderMtl.mm_sec2
20
25
21
ShaderMtl::~ShaderMtl() {}
26
ShaderMtl::~ShaderMtl() {}
22
27
28
class TranslateTask : public angle::Closure
29
{
30
  public:
31
    TranslateTask(ShHandle handle, ShCompileOptions options, const std::string &source)
32
        : mHandle(handle), mOptions(options), mSource(source), mResult(false)
33
    {}
34
35
    void operator()() override
36
    {
37
        const char *source = mSource.c_str();
38
        mResult            = sh::Compile(mHandle, &source, 1, mOptions);
39
    }
40
41
    bool getResult() { return mResult; }
42
43
    ShHandle getHandle() { return mHandle; }
44
45
  private:
46
    ShHandle mHandle;
47
    ShCompileOptions mOptions;
48
    std::string mSource;
49
    bool mResult;
50
};
51
52
class MTLWaitableCompileEventImpl final : public WaitableCompileEvent
53
{
54
  public:
55
    MTLWaitableCompileEventImpl(ShaderMtl *shader,
56
                                std::shared_ptr<angle::WaitableEvent> waitableEvent,
57
                                std::shared_ptr<TranslateTask> translateTask)
58
        : WaitableCompileEvent(waitableEvent), mTranslateTask(translateTask), mShader(shader)
59
    {}
60
61
    bool getResult() override { return mTranslateTask->getResult(); }
62
63
    bool postTranslate(std::string *infoLog) override
64
    {
65
        sh::TShHandleBase *base    = static_cast<sh::TShHandleBase *>(mTranslateTask->getHandle());
66
        auto translatorMetalDirect = base->getAsTranslatorMetalDirect();
67
        if (translatorMetalDirect != nullptr)
68
        {
69
            // Copy reflection from translation.
70
            mShader->translatorMetalReflection =
71
                *(translatorMetalDirect->getTranslatorMetalReflection());
72
            translatorMetalDirect->getTranslatorMetalReflection()->reset();
73
        }
74
        return true;
75
    }
76
77
  private:
78
    std::shared_ptr<TranslateTask> mTranslateTask;
79
    ShaderMtl *mShader;
80
};
81
82
std::shared_ptr<WaitableCompileEvent> ShaderMtl::compileImplMtl(
83
    const gl::Context *context,
84
    gl::ShCompilerInstance *compilerInstance,
85
    const std::string &source,
86
    ShCompileOptions compileOptions)
87
{
88
#if defined(ANGLE_ENABLE_ASSERTS)
89
    compileOptions |= SH_VALIDATE_AST;
90
#endif
91
92
    auto workerThreadPool = context->getWorkerThreadPool();
93
    auto translateTask =
94
        std::make_shared<TranslateTask>(compilerInstance->getHandle(), compileOptions, source);
95
96
    return std::make_shared<MTLWaitableCompileEventImpl>(
97
        this, angle::WorkerThreadPool::PostWorkerTask(workerThreadPool, translateTask),
98
        translateTask);
99
}
100
23
std::shared_ptr<WaitableCompileEvent> ShaderMtl::compile(const gl::Context *context,
101
std::shared_ptr<WaitableCompileEvent> ShaderMtl::compile(const gl::Context *context,
24
                                                         gl::ShCompilerInstance *compilerInstance,
102
                                                         gl::ShCompilerInstance *compilerInstance,
25
                                                         ShCompileOptions options)
103
                                                         ShCompileOptions options)
26
{
104
{
105
    ContextMtl *contextMtl = mtl::GetImpl(context);
106
    if (getState().getShaderType() == gl::ShaderType::Vertex &&
107
        !contextMtl->getDisplay()->getFeatures().hasBaseVertexInstancedDraw.enabled)
108
    {
109
        // Emulate gl_InstanceID
110
        sh::TShHandleBase *base = static_cast<sh::TShHandleBase *>(compilerInstance->getHandle());
111
        auto translatorMetalDirect = base->getAsTranslatorMetalDirect();
112
        if (translatorMetalDirect == nullptr)
113
        {
114
            auto translatorMetal = static_cast<sh::TranslatorMetal *>(base->getAsCompiler());
115
            translatorMetal->enableEmulatedInstanceID(true);
116
        }
117
        else
118
        {
119
            translatorMetalDirect->enableEmulatedInstanceID(true);
120
        }
121
    }
27
    ShCompileOptions compileOptions = SH_INITIALIZE_UNINITIALIZED_LOCALS;
122
    ShCompileOptions compileOptions = SH_INITIALIZE_UNINITIALIZED_LOCALS;
28
123
29
    bool isWebGL = context->getExtensions().webglCompatibility;
124
    bool isWebGL = context->getExtensions().webglCompatibility;
Lines 33-40 std::shared_ptr<WaitableCompileEvent> ShaderMtl::compile(const gl::Context *cont a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ShaderMtl.mm_sec3
33
    }
128
    }
34
129
35
    compileOptions |= SH_CLAMP_POINT_SIZE;
130
    compileOptions |= SH_CLAMP_POINT_SIZE;
131
#if defined(ANGLE_PLATFORM_IOS) && !defined(ANGLE_PLATFORM_MACCATALYST)
132
    compileOptions |= SH_CLAMP_FRAG_DEPTH;
133
#endif
36
134
37
    return compileImpl(context, compilerInstance, mState.getSource(), compileOptions | options);
135
    return compileImplMtl(context, compilerInstance, getState().getSource(), compileOptions | options);
38
}
136
}
39
137
40
std::string ShaderMtl::getDebugInfo() const
138
std::string ShaderMtl::getDebugInfo() const
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SurfaceMtl.h -39 / +30 lines
Lines 24-30 namespace rx a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SurfaceMtl.h_sec1
24
24
25
class DisplayMtl;
25
class DisplayMtl;
26
26
27
class SurfaceMtl : public SurfaceImpl
27
class SurfaceMtlProtocol : public SurfaceImpl
28
{
29
  public:
30
    SurfaceMtlProtocol(const egl::SurfaceState &state) : SurfaceImpl(state) {}
31
    virtual int getSamples() const      = 0;
32
    virtual bool preserveBuffer() const = 0;
33
34
    virtual angle::Result getAttachmentRenderTarget(const gl::Context *context,
35
                                                    GLenum binding,
36
                                                    const gl::ImageIndex &imageIndex,
37
                                                    GLsizei samples,
38
                                                    FramebufferAttachmentRenderTarget **rtOut) override = 0;
39
40
    virtual bool hasRobustResourceInit() const = 0;
41
    virtual angle::Result ensureCurrentDrawableObtained(const gl::Context *context) = 0;
42
    virtual angle::Result ensureCurrentDrawableObtained(const gl::Context *context, bool *newDrawableOut) = 0;
43
    virtual angle::Result ensureColorTextureReadyForReadPixels(const gl::Context *context) = 0;
44
    virtual const mtl::TextureRef & getColorTexture() = 0;
45
};
46
47
class SurfaceMtl : public SurfaceMtlProtocol
28
{
48
{
29
  public:
49
  public:
30
    SurfaceMtl(DisplayMtl *display,
50
    SurfaceMtl(DisplayMtl *display,
Lines 67-77 class SurfaceMtl : public SurfaceImpl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SurfaceMtl.h_sec2
67
    angle::Result initializeContents(const gl::Context *context,
87
    angle::Result initializeContents(const gl::Context *context,
68
                                     const gl::ImageIndex &imageIndex) override;
88
                                     const gl::ImageIndex &imageIndex) override;
69
89
70
    const mtl::TextureRef &getColorTexture() { return mColorTexture; }
90
    const mtl::TextureRef &getColorTexture() override { return mColorTexture; }
71
    const mtl::Format &getColorFormat() const { return mColorFormat; }
91
    const mtl::Format &getColorFormat() const { return mColorFormat; }
72
    int getSamples() const { return mSamples; }
92
    int getSamples() const override { return mSamples; }
73
93
74
    bool hasRobustResourceInit() const { return mRobustResourceInit; }
94
    bool hasRobustResourceInit() const override { return mRobustResourceInit; }
75
95
76
    angle::Result getAttachmentRenderTarget(const gl::Context *context,
96
    angle::Result getAttachmentRenderTarget(const gl::Context *context,
77
                                            GLenum binding,
97
                                            GLenum binding,
Lines 144-156 class WindowSurfaceMtl : public SurfaceMtl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SurfaceMtl.h_sec3
144
                                            GLsizei samples,
164
                                            GLsizei samples,
145
                                            FramebufferAttachmentRenderTarget **rtOut) override;
165
                                            FramebufferAttachmentRenderTarget **rtOut) override;
146
166
167
    angle::Result ensureCurrentDrawableObtained(const gl::Context *context) override;
147
    angle::Result ensureCurrentDrawableObtained(const gl::Context *context,
168
    angle::Result ensureCurrentDrawableObtained(const gl::Context *context,
148
                                                bool *newDrawableOut /** nullable */);
169
                                                bool *newDrawableOut /** nullable */) override;
149
170
150
    // Ensure the the texture returned from getColorTexture() is ready for glReadPixels(). This
171
    // Ensure the the texture returned from getColorTexture() is ready for glReadPixels(). This
151
    // implicitly calls ensureCurrentDrawableObtained().
172
    // implicitly calls ensureCurrentDrawableObtained().
152
    angle::Result ensureColorTextureReadyForReadPixels(const gl::Context *context);
173
    angle::Result ensureColorTextureReadyForReadPixels(const gl::Context *context) override;
153
174
    bool preserveBuffer() const override { return mRetainBuffer; }
154
  private:
175
  private:
155
    angle::Result swapImpl(const gl::Context *context);
176
    angle::Result swapImpl(const gl::Context *context);
156
    angle::Result obtainNextDrawable(const gl::Context *context);
177
    angle::Result obtainNextDrawable(const gl::Context *context);
Lines 168-173 class WindowSurfaceMtl : public SurfaceMtl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SurfaceMtl.h_sec4
168
    // event. We don't use mMetalLayer.drawableSize directly since it might be changed internally by
189
    // event. We don't use mMetalLayer.drawableSize directly since it might be changed internally by
169
    // metal runtime.
190
    // metal runtime.
170
    CGSize mCurrentKnownDrawableSize;
191
    CGSize mCurrentKnownDrawableSize;
192
193
    bool mRetainBuffer = false;
171
};
194
};
172
195
173
// Offscreen surface, base class of PBuffer, IOSurface.
196
// Offscreen surface, base class of PBuffer, IOSurface.
Lines 212-248 class PBufferSurfaceMtl : public OffscreenSurfaceMtl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SurfaceMtl.h_sec5
212
    void setFixedHeight(EGLint height) override;
235
    void setFixedHeight(EGLint height) override;
213
};
236
};
214
237
215
// Offscreen created from IOSurface
216
class IOSurfaceSurfaceMtl : public OffscreenSurfaceMtl
217
{
218
  public:
219
    IOSurfaceSurfaceMtl(DisplayMtl *display,
220
                        const egl::SurfaceState &state,
221
                        EGLClientBuffer buffer,
222
                        const egl::AttributeMap &attribs);
223
    ~IOSurfaceSurfaceMtl() override;
224
225
    egl::Error bindTexImage(const gl::Context *context,
226
                            gl::Texture *texture,
227
                            EGLint buffer) override;
228
    egl::Error releaseTexImage(const gl::Context *context, EGLint buffer) override;
229
230
    angle::Result getAttachmentRenderTarget(const gl::Context *context,
231
                                            GLenum binding,
232
                                            const gl::ImageIndex &imageIndex,
233
                                            GLsizei samples,
234
                                            FramebufferAttachmentRenderTarget **rtOut) override;
235
236
    static bool ValidateAttributes(EGLClientBuffer buffer, const egl::AttributeMap &attribs);
237
238
  private:
239
    angle::Result ensureColorTextureCreated(const gl::Context *context);
240
241
    IOSurfaceRef mIOSurface;
242
    NSUInteger mIOSurfacePlane;
243
    int mIOSurfaceFormatIdx;
244
};
245
246
}  // namespace rx
238
}  // namespace rx
247
248
#endif /* LIBANGLE_RENDERER_METAL_SURFACEMTL_H_ */
239
#endif /* LIBANGLE_RENDERER_METAL_SURFACEMTL_H_ */
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SurfaceMtl.mm -204 / +48 lines
Lines 23-29 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SurfaceMtl.mm_sec1
23
#if defined(NDEBUG) && !defined(ANGLE_METAL_FRAME_CAPTURE)
23
#if defined(NDEBUG) && !defined(ANGLE_METAL_FRAME_CAPTURE)
24
#    define ANGLE_METAL_FRAME_CAPTURE_ENABLED 0
24
#    define ANGLE_METAL_FRAME_CAPTURE_ENABLED 0
25
#else
25
#else
26
#    define ANGLE_METAL_FRAME_CAPTURE_ENABLED 1
26
#    define ANGLE_METAL_FRAME_CAPTURE_ENABLED ANGLE_WITH_MODERN_METAL_API
27
#endif
27
#endif
28
28
29
namespace rx
29
namespace rx
Lines 33-87 namespace a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SurfaceMtl.mm_sec2
33
{
33
{
34
34
35
#define ANGLE_TO_EGL_TRY(EXPR)                                 \
35
#define ANGLE_TO_EGL_TRY(EXPR)                                 \
36
    do                                                         \
36
do                                                         \
37
    {                                                          \
37
{                                                          \
38
        if (ANGLE_UNLIKELY((EXPR) != angle::Result::Continue)) \
38
    if (ANGLE_UNLIKELY((EXPR) != angle::Result::Continue)) \
39
        {                                                      \
39
    {                                                      \
40
            return egl::EglBadSurface();                       \
40
        return egl::EglBadSurface();                       \
41
        }                                                      \
41
    }                                                      \
42
    } while (0)
42
} while (0)
43
43
44
constexpr angle::FormatID kDefaultFrameBufferDepthFormatId   = angle::FormatID::D32_FLOAT;
44
constexpr angle::FormatID kDefaultFrameBufferDepthFormatId   = angle::FormatID::D32_FLOAT;
45
constexpr angle::FormatID kDefaultFrameBufferStencilFormatId = angle::FormatID::S8_UINT;
45
constexpr angle::FormatID kDefaultFrameBufferStencilFormatId = angle::FormatID::S8_UINT;
46
constexpr angle::FormatID kDefaultFrameBufferDepthStencilFormatId =
46
constexpr angle::FormatID kDefaultFrameBufferDepthStencilFormatId =
47
    angle::FormatID::D24_UNORM_S8_UINT;
47
    angle::FormatID::D24_UNORM_S8_UINT;
48
48
49
struct IOSurfaceFormatInfo
50
{
51
    GLenum internalFormat;
52
    GLenum type;
53
    size_t componentBytes;
54
55
    angle::FormatID nativeAngleFormatId;
56
};
57
58
// clang-format off
59
// NOTE(hqle): Support R16_UINT once GLES3 is complete.
60
constexpr std::array<IOSurfaceFormatInfo, 8> kIOSurfaceFormats = {{
61
    {GL_RED,      GL_UNSIGNED_BYTE,               1, angle::FormatID::R8_UNORM},
62
    {GL_RED,      GL_UNSIGNED_SHORT,              2, angle::FormatID::R16_UNORM},
63
    {GL_RG,       GL_UNSIGNED_BYTE,               2, angle::FormatID::R8G8_UNORM},
64
    {GL_RG,       GL_UNSIGNED_SHORT,              4, angle::FormatID::R16G16_UNORM},
65
    {GL_RGB,      GL_UNSIGNED_BYTE,               4, angle::FormatID::B8G8R8A8_UNORM},
66
    {GL_BGRA_EXT, GL_UNSIGNED_BYTE,               4, angle::FormatID::B8G8R8A8_UNORM},
67
    {GL_RGBA,     GL_HALF_FLOAT,                  8, angle::FormatID::R16G16B16A16_FLOAT},
68
    {GL_RGB10_A2, GL_UNSIGNED_INT_2_10_10_10_REV, 4, angle::FormatID::B10G10R10A2_UNORM},
69
}};
70
// clang-format on
71
72
int FindIOSurfaceFormatIndex(GLenum internalFormat, GLenum type)
73
{
74
    for (int i = 0; i < static_cast<int>(kIOSurfaceFormats.size()); ++i)
75
    {
76
        const auto &formatInfo = kIOSurfaceFormats[i];
77
        if (formatInfo.internalFormat == internalFormat && formatInfo.type == type)
78
        {
79
            return i;
80
        }
81
    }
82
    return -1;
83
}
84
85
angle::Result CreateOrResizeTexture(const gl::Context *context,
49
angle::Result CreateOrResizeTexture(const gl::Context *context,
86
                                    const mtl::Format &format,
50
                                    const mtl::Format &format,
87
                                    uint32_t width,
51
                                    uint32_t width,
Lines 128-133 bool IsFrameCaptureEnabled() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SurfaceMtl.mm_sec3
128
#endif
92
#endif
129
}
93
}
130
94
95
ANGLE_MTL_UNUSED
96
std::string GetMetalCaptureFile()
97
{
98
#if !ANGLE_METAL_FRAME_CAPTURE_ENABLED
99
    return "";
100
#else
101
    auto var                   = std::getenv("ANGLE_METAL_FRAME_CAPTURE_FILE");
102
    const std::string filePath = var ? var : "";
103
104
    return filePath;
105
#endif
106
}
107
131
ANGLE_MTL_UNUSED
108
ANGLE_MTL_UNUSED
132
size_t MaxAllowedFrameCapture()
109
size_t MaxAllowedFrameCapture()
133
{
110
{
Lines 202-207 void StartFrameCapture(id<MTLDevice> metalDevice, id<MTLCommandQueue> metalCmdQu a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SurfaceMtl.mm_sec4
202
    {
179
    {
203
        MTLCaptureDescriptor *captureDescriptor = [[MTLCaptureDescriptor alloc] init];
180
        MTLCaptureDescriptor *captureDescriptor = [[MTLCaptureDescriptor alloc] init];
204
        captureDescriptor.captureObject         = metalDevice;
181
        captureDescriptor.captureObject         = metalDevice;
182
        const std::string filePath              = GetMetalCaptureFile();
183
        if (filePath != "")
184
        {
185
            const std::string numberedPath =
186
                filePath + std::to_string(gFrameCaptured - 1) + ".gputrace";
187
            captureDescriptor.destination = MTLCaptureDestinationGPUTraceDocument;
188
            captureDescriptor.outputURL =
189
                [NSURL fileURLWithPath:[NSString stringWithUTF8String:numberedPath.c_str()]
190
                           isDirectory:false];
191
        }
192
        else
193
        {
194
            // This will pause execution only if application is being debugged inside Xcode
195
            captureDescriptor.destination = MTLCaptureDestinationDeveloperTools;
196
        }
205
197
206
        NSError *error;
198
        NSError *error;
207
        if (![captureManager startCaptureWithDescriptor:captureDescriptor error:&error])
199
        if (![captureManager startCaptureWithDescriptor:captureDescriptor error:&error])
Lines 211-224 void StartFrameCapture(id<MTLDevice> metalDevice, id<MTLCommandQueue> metalCmdQu a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SurfaceMtl.mm_sec5
211
    }
203
    }
212
    else
204
    else
213
#    endif  // __MAC_10_15
205
#    endif  // __MAC_10_15
206
        if (ANGLE_APPLE_AVAILABLE_XCI(10.15, 13.0, 13))
214
    {
207
    {
215
        if (FrameCaptureDeviceScope())
208
        MTLCaptureDescriptor *captureDescriptor = [[MTLCaptureDescriptor alloc] init];
216
        {
209
        captureDescriptor.captureObject         = metalDevice;
217
            [captureManager startCaptureWithDevice:metalDevice];
210
218
        }
211
        NSError *error;
219
        else
212
        if (![captureManager startCaptureWithDescriptor:captureDescriptor error:&error])
220
        {
213
        {
221
            [captureManager startCaptureWithCommandQueue:metalCmdQueue];
214
            NSLog(@"Failed to start capture, error %@", error);
222
        }
215
        }
223
    }
216
    }
224
#endif  // ANGLE_METAL_FRAME_CAPTURE_ENABLED
217
#endif  // ANGLE_METAL_FRAME_CAPTURE_ENABLED
Lines 245-255 void StopFrameCapture() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SurfaceMtl.mm_sec6
245
}
238
}
246
}
239
}
247
240
248
// SurfaceMtl implementation
249
SurfaceMtl::SurfaceMtl(DisplayMtl *display,
241
SurfaceMtl::SurfaceMtl(DisplayMtl *display,
250
                       const egl::SurfaceState &state,
242
                       const egl::SurfaceState &state,
251
                       const egl::AttributeMap &attribs)
243
                       const egl::AttributeMap &attribs)
252
    : SurfaceImpl(state)
244
    : SurfaceMtlProtocol(state)
253
{
245
{
254
    mRobustResourceInit =
246
    mRobustResourceInit =
255
        attribs.get(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE, EGL_FALSE) == EGL_TRUE;
247
        attribs.get(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE, EGL_FALSE) == EGL_TRUE;
Lines 693-698 angle::Result WindowSurfaceMtl::getAttachmentRenderTarget(const gl::Context *con a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SurfaceMtl.mm_sec7
693
    return SurfaceMtl::getAttachmentRenderTarget(context, binding, imageIndex, samples, rtOut);
685
    return SurfaceMtl::getAttachmentRenderTarget(context, binding, imageIndex, samples, rtOut);
694
}
686
}
695
687
688
angle::Result WindowSurfaceMtl::ensureCurrentDrawableObtained(const gl::Context *context)
689
{
690
    return ensureCurrentDrawableObtained(context, nullptr);
691
}
696
angle::Result WindowSurfaceMtl::ensureCurrentDrawableObtained(const gl::Context *context,
692
angle::Result WindowSurfaceMtl::ensureCurrentDrawableObtained(const gl::Context *context,
697
                                                              bool *newDrawableOut)
693
                                                              bool *newDrawableOut)
698
{
694
{
Lines 943-1099 void PBufferSurfaceMtl::setFixedHeight(EGLint height) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SurfaceMtl.mm_sec8
943
    mSize.height = height;
939
    mSize.height = height;
944
}
940
}
945
941
946
// IOSurfaceSurfaceMtl implementation.
947
IOSurfaceSurfaceMtl::IOSurfaceSurfaceMtl(DisplayMtl *display,
948
                                         const egl::SurfaceState &state,
949
                                         EGLClientBuffer buffer,
950
                                         const egl::AttributeMap &attribs)
951
    : OffscreenSurfaceMtl(display, state, attribs), mIOSurface((__bridge IOSurfaceRef)(buffer))
952
{
953
    CFRetain(mIOSurface);
954
955
    mIOSurfacePlane = static_cast<int>(attribs.get(EGL_IOSURFACE_PLANE_ANGLE));
956
957
    EGLAttrib internalFormat = attribs.get(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE);
958
    EGLAttrib type           = attribs.get(EGL_TEXTURE_TYPE_ANGLE);
959
    mIOSurfaceFormatIdx =
960
        FindIOSurfaceFormatIndex(static_cast<GLenum>(internalFormat), static_cast<GLenum>(type));
961
    ASSERT(mIOSurfaceFormatIdx >= 0);
962
963
    mColorFormat =
964
        display->getPixelFormat(kIOSurfaceFormats[mIOSurfaceFormatIdx].nativeAngleFormatId);
965
}
966
IOSurfaceSurfaceMtl::~IOSurfaceSurfaceMtl()
967
{
968
    if (mIOSurface != nullptr)
969
    {
970
        CFRelease(mIOSurface);
971
        mIOSurface = nullptr;
972
    }
973
}
974
975
egl::Error IOSurfaceSurfaceMtl::bindTexImage(const gl::Context *context,
976
                                             gl::Texture *texture,
977
                                             EGLint buffer)
978
{
979
    ContextMtl *contextMtl = mtl::GetImpl(context);
980
    StartFrameCapture(contextMtl);
981
982
    // Initialize offscreen texture if needed:
983
    ANGLE_TO_EGL_TRY(ensureColorTextureCreated(context));
984
985
    return OffscreenSurfaceMtl::bindTexImage(context, texture, buffer);
986
}
987
988
egl::Error IOSurfaceSurfaceMtl::releaseTexImage(const gl::Context *context, EGLint buffer)
989
{
990
    egl::Error re = OffscreenSurfaceMtl::releaseTexImage(context, buffer);
991
    StopFrameCapture();
992
    return re;
993
}
994
995
angle::Result IOSurfaceSurfaceMtl::getAttachmentRenderTarget(
996
    const gl::Context *context,
997
    GLenum binding,
998
    const gl::ImageIndex &imageIndex,
999
    GLsizei samples,
1000
    FramebufferAttachmentRenderTarget **rtOut)
1001
{
1002
    // Initialize offscreen texture if needed:
1003
    ANGLE_TRY(ensureColorTextureCreated(context));
1004
1005
    return OffscreenSurfaceMtl::getAttachmentRenderTarget(context, binding, imageIndex, samples,
1006
                                                          rtOut);
1007
}
1008
1009
angle::Result IOSurfaceSurfaceMtl::ensureColorTextureCreated(const gl::Context *context)
1010
{
1011
    if (mColorTexture)
1012
    {
1013
        return angle::Result::Continue;
1014
    }
1015
    ContextMtl *contextMtl = mtl::GetImpl(context);
1016
    ANGLE_MTL_OBJC_SCOPE
1017
    {
1018
        auto texDesc =
1019
            [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:mColorFormat.metalFormat
1020
                                                               width:mSize.width
1021
                                                              height:mSize.height
1022
                                                           mipmapped:NO];
1023
1024
        texDesc.usage = MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget;
1025
1026
        id<MTLTexture> texture =
1027
            [contextMtl->getMetalDevice() newTextureWithDescriptor:texDesc
1028
                                                         iosurface:mIOSurface
1029
                                                             plane:mIOSurfacePlane];
1030
1031
        mColorTexture = mtl::Texture::MakeFromMetal([texture ANGLE_MTL_AUTORELEASE]);
1032
    }
1033
1034
    mColorRenderTarget.set(mColorTexture, mtl::kZeroNativeMipLevel, 0, mColorFormat);
1035
1036
    if (kIOSurfaceFormats[mIOSurfaceFormatIdx].internalFormat == GL_RGB)
1037
    {
1038
        // This format has emulated alpha channel. Initialize texture's alpha channel to 1.0.
1039
        const mtl::Format &rgbClearFormat =
1040
            contextMtl->getPixelFormat(angle::FormatID::R8G8B8_UNORM);
1041
        ANGLE_TRY(mtl::InitializeTextureContentsGPU(
1042
            context, mColorTexture, rgbClearFormat,
1043
            mtl::ImageNativeIndex::FromBaseZeroGLIndex(gl::ImageIndex::Make2D(0)),
1044
            MTLColorWriteMaskAlpha));
1045
1046
        // Disable subsequent rendering to alpha channel.
1047
        mColorTexture->setColorWritableMask(MTLColorWriteMaskAll & (~MTLColorWriteMaskAlpha));
1048
    }
1049
1050
    return angle::Result::Continue;
1051
}
1052
1053
// static
1054
bool IOSurfaceSurfaceMtl::ValidateAttributes(EGLClientBuffer buffer,
1055
                                             const egl::AttributeMap &attribs)
1056
{
1057
    IOSurfaceRef ioSurface = (__bridge IOSurfaceRef)(buffer);
1058
1059
    // The plane must exist for this IOSurface. IOSurfaceGetPlaneCount can return 0 for non-planar
1060
    // ioSurfaces but we will treat non-planar like it is a single plane.
1061
    size_t surfacePlaneCount = std::max(size_t(1), IOSurfaceGetPlaneCount(ioSurface));
1062
    EGLAttrib plane          = attribs.get(EGL_IOSURFACE_PLANE_ANGLE);
1063
    if (plane < 0 || static_cast<size_t>(plane) >= surfacePlaneCount)
1064
    {
1065
        return false;
1066
    }
1067
1068
    // The width height specified must be at least (1, 1) and at most the plane size
1069
    EGLAttrib width  = attribs.get(EGL_WIDTH);
1070
    EGLAttrib height = attribs.get(EGL_HEIGHT);
1071
    if (width <= 0 || static_cast<size_t>(width) > IOSurfaceGetWidthOfPlane(ioSurface, plane) ||
1072
        height <= 0 || static_cast<size_t>(height) > IOSurfaceGetHeightOfPlane(ioSurface, plane))
1073
    {
1074
        return false;
1075
    }
1076
1077
    // Find this IOSurface format
1078
    EGLAttrib internalFormat = attribs.get(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE);
1079
    EGLAttrib type           = attribs.get(EGL_TEXTURE_TYPE_ANGLE);
1080
1081
    int formatIndex =
1082
        FindIOSurfaceFormatIndex(static_cast<GLenum>(internalFormat), static_cast<GLenum>(type));
1083
1084
    if (formatIndex < 0)
1085
    {
1086
        return false;
1087
    }
1088
1089
    // Check that the format matches this IOSurface plane
1090
    if (IOSurfaceGetBytesPerElementOfPlane(ioSurface, plane) !=
1091
        kIOSurfaceFormats[formatIndex].componentBytes)
1092
    {
1093
        return false;
1094
    }
1095
1096
    return true;
1097
}
1098
942
1099
}
943
}
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SyncMtl.h -6 / +6 lines
Lines 1-5 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SyncMtl.h_sec1
1
//
1
//
2
// Copyright 2020 The ANGLE Project Authors. All rights reserved.
2
// Copyright (c) 2020 The ANGLE Project Authors. All rights reserved.
3
// Use of this source code is governed by a BSD-style license that can be
3
// Use of this source code is governed by a BSD-style license that can be
4
// found in the LICENSE file.
4
// found in the LICENSE file.
5
//
5
//
Lines 33-39 namespace mtl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SyncMtl.h_sec2
33
33
34
// Common class to be used by both SyncImpl and EGLSyncImpl.
34
// Common class to be used by both SyncImpl and EGLSyncImpl.
35
// NOTE: SharedEvent is only declared on iOS 12.0+ or mac 10.14+
35
// NOTE: SharedEvent is only declared on iOS 12.0+ or mac 10.14+
36
#if ANGLE_MTL_EVENT_AVAILABLE
36
#if defined(__IPHONE_12_0) || defined(__MAC_10_14)
37
class Sync
37
class Sync
38
{
38
{
39
  public:
39
  public:
Lines 59-65 class Sync a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SyncMtl.h_sec3
59
    std::shared_ptr<std::condition_variable> mCv;
59
    std::shared_ptr<std::condition_variable> mCv;
60
    std::shared_ptr<std::mutex> mLock;
60
    std::shared_ptr<std::mutex> mLock;
61
};
61
};
62
#else   // #if ANGLE_MTL_EVENT_AVAILABLE
62
#else   // #if defined(__IPHONE_12_0) || defined(__MAC_10_14)
63
class Sync
63
class Sync
64
{
64
{
65
  public:
65
  public:
Lines 90-96 class Sync a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SyncMtl.h_sec4
90
        return angle::Result::Stop;
90
        return angle::Result::Stop;
91
    }
91
    }
92
};
92
};
93
#endif  // #if ANGLE_MTL_EVENT_AVAILABLE
93
#endif  // #if defined(__IPHONE_12_0) || defined(__MAC_10_14)
94
}  // namespace mtl
94
}  // namespace mtl
95
95
96
class FenceNVMtl : public FenceNVImpl
96
class FenceNVMtl : public FenceNVImpl
Lines 98-106 class FenceNVMtl : public FenceNVImpl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SyncMtl.h_sec5
98
  public:
98
  public:
99
    FenceNVMtl();
99
    FenceNVMtl();
100
    ~FenceNVMtl() override;
100
    ~FenceNVMtl() override;
101
102
    void onDestroy(const gl::Context *context) override;
101
    void onDestroy(const gl::Context *context) override;
103
104
    angle::Result set(const gl::Context *context, GLenum condition) override;
102
    angle::Result set(const gl::Context *context, GLenum condition) override;
105
    angle::Result test(const gl::Context *context, GLboolean *outFinished) override;
103
    angle::Result test(const gl::Context *context, GLboolean *outFinished) override;
106
    angle::Result finish(const gl::Context *context) override;
104
    angle::Result finish(const gl::Context *context) override;
Lines 152-157 class EGLSyncMtl final : public EGLSyncImpl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SyncMtl.h_sec6
152
                          EGLint flags) override;
150
                          EGLint flags) override;
153
    egl::Error getStatus(const egl::Display *display, EGLint *outStatus) override;
151
    egl::Error getStatus(const egl::Display *display, EGLint *outStatus) override;
154
152
153
    egl::Error dupNativeFenceFD(const egl::Display *display, EGLint *result) const override;
154
155
  private:
155
  private:
156
    mtl::Sync mSync;
156
    mtl::Sync mSync;
157
};
157
};
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SyncMtl.mm -5 / +13 lines
Lines 1-5 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SyncMtl.mm_sec1
1
//
1
//
2
// Copyright 2020 The ANGLE Project Authors. All rights reserved.
2
// Copyright (c) 2020 The ANGLE Project Authors. All rights reserved.
3
// Use of this source code is governed by a BSD-style license that can be
3
// Use of this source code is governed by a BSD-style license that can be
4
// found in the LICENSE file.
4
// found in the LICENSE file.
5
//
5
//
Lines 22-28 namespace rx a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SyncMtl.mm_sec2
22
namespace mtl
22
namespace mtl
23
{
23
{
24
// SharedEvent is only available on iOS 12.0+ or mac 10.14+
24
// SharedEvent is only available on iOS 12.0+ or mac 10.14+
25
#if ANGLE_MTL_EVENT_AVAILABLE
25
#if defined(__IPHONE_12_0) || defined(__MAC_10_14)
26
Sync::Sync() {}
26
Sync::Sync() {}
27
Sync::~Sync() {}
27
Sync::~Sync() {}
28
28
Lines 87-93 angle::Result Sync::clientWait(ContextMtl *contextMtl, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SyncMtl.mm_sec3
87
    // onDestroy(), but the callback might still not be fired yet.
87
    // onDestroy(), but the callback might still not be fired yet.
88
    std::shared_ptr<std::condition_variable> cvRef = mCv;
88
    std::shared_ptr<std::condition_variable> cvRef = mCv;
89
    std::shared_ptr<std::mutex> lockRef            = mLock;
89
    std::shared_ptr<std::mutex> lockRef            = mLock;
90
90
#if ANGLE_MTL_EVENT_AVAILABLE
91
    AutoObjCObj<MTLSharedEventListener> eventListener =
91
    AutoObjCObj<MTLSharedEventListener> eventListener =
92
        contextMtl->getDisplay()->getOrCreateSharedEventListener();
92
        contextMtl->getDisplay()->getOrCreateSharedEventListener();
93
    [mMetalSharedEvent.get() notifyListener:eventListener
93
    [mMetalSharedEvent.get() notifyListener:eventListener
Lines 106-111 angle::Result Sync::clientWait(ContextMtl *contextMtl, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SyncMtl.mm_sec4
106
106
107
    ASSERT(mMetalSharedEvent.get().signaledValue >= mSetCounter);
107
    ASSERT(mMetalSharedEvent.get().signaledValue >= mSetCounter);
108
    *outResult = GL_CONDITION_SATISFIED;
108
    *outResult = GL_CONDITION_SATISFIED;
109
#endif
109
110
110
    return angle::Result::Continue;
111
    return angle::Result::Continue;
111
}
112
}
Lines 118-124 angle::Result Sync::getStatus(bool *signaled) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SyncMtl.mm_sec5
118
    *signaled = mMetalSharedEvent.get().signaledValue >= mSetCounter;
119
    *signaled = mMetalSharedEvent.get().signaledValue >= mSetCounter;
119
    return angle::Result::Continue;
120
    return angle::Result::Continue;
120
}
121
}
121
#endif  // #if ANGLE_MTL_EVENT_AVAILABLE
122
#endif  // #if defined(__IPHONE_12_0) || defined(__MAC_10_14)
122
}  // namespace mtl
123
}  // namespace mtl
123
124
124
// FenceNVMtl implementation
125
// FenceNVMtl implementation
Lines 128-134 FenceNVMtl::~FenceNVMtl() {} a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SyncMtl.mm_sec6
128
129
129
void FenceNVMtl::onDestroy(const gl::Context *context)
130
void FenceNVMtl::onDestroy(const gl::Context *context)
130
{
131
{
131
    mSync.onDestroy();
132
    UNIMPLEMENTED();
133
    return;
132
}
134
}
133
135
134
angle::Result FenceNVMtl::set(const gl::Context *context, GLenum condition)
136
angle::Result FenceNVMtl::set(const gl::Context *context, GLenum condition)
Lines 307-310 egl::Error EGLSyncMtl::getStatus(const egl::Display *display, EGLint *outStatus) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/SyncMtl.mm_sec7
307
    return egl::NoError();
309
    return egl::NoError();
308
}
310
}
309
311
312
egl::Error EGLSyncMtl::dupNativeFenceFD(const egl::Display *display, EGLint *result) const
313
{
314
    UNREACHABLE();
315
    return egl::EglBadDisplay();
316
}
317
310
}
318
}
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/TextureMtl.h -10 / +10 lines
Lines 15-23 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/TextureMtl.h_sec1
15
#include "common/PackedEnums.h"
15
#include "common/PackedEnums.h"
16
#include "libANGLE/renderer/TextureImpl.h"
16
#include "libANGLE/renderer/TextureImpl.h"
17
#include "libANGLE/renderer/metal/RenderTargetMtl.h"
17
#include "libANGLE/renderer/metal/RenderTargetMtl.h"
18
#include "libANGLE/renderer/metal/SurfaceMtl.h"
18
#include "libANGLE/renderer/metal/mtl_command_buffer.h"
19
#include "libANGLE/renderer/metal/mtl_command_buffer.h"
19
#include "libANGLE/renderer/metal/mtl_resources.h"
20
#include "libANGLE/renderer/metal/mtl_resources.h"
20
21
namespace rx
21
namespace rx
22
{
22
{
23
23
Lines 32-37 class TextureMtl : public TextureImpl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/TextureMtl.h_sec2
32
{
32
{
33
  public:
33
  public:
34
    TextureMtl(const gl::TextureState &state);
34
    TextureMtl(const gl::TextureState &state);
35
    // Texture  view
36
    TextureMtl(const TextureMtl &mtl, GLenum format);
35
    ~TextureMtl() override;
37
    ~TextureMtl() override;
36
    void onDestroy(const gl::Context *context) override;
38
    void onDestroy(const gl::Context *context) override;
37
39
Lines 193-198 class TextureMtl : public TextureImpl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/TextureMtl.h_sec3
193
    ImageDefinitionMtl &getImageDefinition(const gl::ImageIndex &imageIndex);
195
    ImageDefinitionMtl &getImageDefinition(const gl::ImageIndex &imageIndex);
194
    RenderTargetMtl &getRenderTarget(const gl::ImageIndex &imageIndex);
196
    RenderTargetMtl &getRenderTarget(const gl::ImageIndex &imageIndex);
195
    bool isIndexWithinMinMaxLevels(const gl::ImageIndex &imageIndex) const;
197
    bool isIndexWithinMinMaxLevels(const gl::ImageIndex &imageIndex) const;
198
    mtl::TextureRef &getImplicitMSTexture(const gl::ImageIndex &imageIndex);
196
199
197
    // If levels = 0, this function will create full mipmaps texture.
200
    // If levels = 0, this function will create full mipmaps texture.
198
    angle::Result setStorageImpl(const gl::Context *context,
201
    angle::Result setStorageImpl(const gl::Context *context,
Lines 312-319 class TextureMtl : public TextureImpl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/TextureMtl.h_sec4
312
    angle::Result generateMipmapCPU(const gl::Context *context);
315
    angle::Result generateMipmapCPU(const gl::Context *context);
313
316
314
    mtl::Format mFormat;
317
    mtl::Format mFormat;
318
    SurfaceMtlProtocol *mBoundSurface = nil;
315
    // The real texture used by Metal draw calls.
319
    // The real texture used by Metal draw calls.
316
    mtl::TextureRef mNativeTexture;
320
    mtl::TextureRef mNativeTexture         = nil;
317
    id<MTLSamplerState> mMetalSamplerState = nil;
321
    id<MTLSamplerState> mMetalSamplerState = nil;
318
322
319
    // Number of slices
323
    // Number of slices
Lines 323-340 class TextureMtl : public TextureImpl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/TextureMtl.h_sec5
323
    // Once the images array is complete, they will be transferred to real texture object.
327
    // Once the images array is complete, they will be transferred to real texture object.
324
    // NOTE:
328
    // NOTE:
325
    //  - The second dimension is indexed by configured base level + actual native level
329
    //  - The second dimension is indexed by configured base level + actual native level
326
    //  - For Cube map, there will be at most 6 entries in the mTexImageDefs table, one for each
330
    //  - For Cube map, there will be at most 6 entries in the map table, one for each face. This is
327
    //  face. This is because the Cube map's image is defined per face & per level.
331
    //  because the Cube map's image is defined per face & per level.
328
    //  - For other texture types, there will be only one entry in the map table. All other textures
332
    //  - For other texture types, there will be only one entry in the map table. All other textures
329
    //  except Cube map has texture image defined per level (all slices included).
333
    //  except Cube map has texture image defined per level (all slices included).
334
    //  - These three variables' second dimension are indexed by image index (base level included).
330
    std::map<int, gl::TexLevelArray<ImageDefinitionMtl>> mTexImageDefs;
335
    std::map<int, gl::TexLevelArray<ImageDefinitionMtl>> mTexImageDefs;
331
332
    // Render Target per slice/depth/cube face.
333
    // - For 2D texture: There will be one key entry in the map.
334
    // - For Cube map: There will be at most 6 key entries.
335
    // - For array/3D texture: There will be at most slices/depths number of key entries.
336
    // - The second dimension is indexed by configured base level + actual native level
337
    std::map<int, gl::TexLevelArray<RenderTargetMtl>> mPerLayerRenderTargets;
336
    std::map<int, gl::TexLevelArray<RenderTargetMtl>> mPerLayerRenderTargets;
337
    std::map<int, gl::TexLevelArray<mtl::TextureRef>> mImplicitMSTextures;
338
338
339
    // Mipmap views are indexed by native level (ignored base level):
339
    // Mipmap views are indexed by native level (ignored base level):
340
    mtl::NativeTexLevelArray mNativeLevelViews;
340
    mtl::NativeTexLevelArray mNativeLevelViews;
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/TextureMtl.mm -15 / +15 lines
Lines 20-27 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/TextureMtl.mm_sec1
20
#include "libANGLE/renderer/metal/ContextMtl.h"
20
#include "libANGLE/renderer/metal/ContextMtl.h"
21
#include "libANGLE/renderer/metal/DisplayMtl.h"
21
#include "libANGLE/renderer/metal/DisplayMtl.h"
22
#include "libANGLE/renderer/metal/FrameBufferMtl.h"
22
#include "libANGLE/renderer/metal/FrameBufferMtl.h"
23
#include "libANGLE/renderer/metal/IOSurfaceSurfaceMtl.h"
23
#include "libANGLE/renderer/metal/SamplerMtl.h"
24
#include "libANGLE/renderer/metal/SamplerMtl.h"
24
#include "libANGLE/renderer/metal/SurfaceMtl.h"
25
#include "libANGLE/renderer/metal/mtl_common.h"
25
#include "libANGLE/renderer/metal/mtl_common.h"
26
#include "libANGLE/renderer/metal/mtl_format_utils.h"
26
#include "libANGLE/renderer/metal/mtl_format_utils.h"
27
#include "libANGLE/renderer/metal/mtl_utils.h"
27
#include "libANGLE/renderer/metal/mtl_utils.h"
Lines 534-539 void TextureMtl::releaseTexture(bool releaseImages, bool releaseTextureObjectsOn a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/TextureMtl.mm_sec2
534
534
535
angle::Result TextureMtl::ensureTextureCreated(const gl::Context *context)
535
angle::Result TextureMtl::ensureTextureCreated(const gl::Context *context)
536
{
536
{
537
    if (mBoundSurface)
538
    {
539
        return angle::Result::Continue;
540
    }
537
    if (mNativeTexture)
541
    if (mNativeTexture)
538
    {
542
    {
539
        return angle::Result::Continue;
543
        return angle::Result::Continue;
Lines 1207-1231 angle::Result TextureMtl::setBaseLevel(const gl::Context *context, GLuint baseLe a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/TextureMtl.mm_sec3
1207
1211
1208
angle::Result TextureMtl::bindTexImage(const gl::Context *context, egl::Surface *surface)
1212
angle::Result TextureMtl::bindTexImage(const gl::Context *context, egl::Surface *surface)
1209
{
1213
{
1210
    releaseTexture(true);
1214
    IOSurfaceSurfaceMtl *surfaceMtl = (IOSurfaceSurfaceMtl *)mtl::GetImpl(surface);
1211
1215
    mBoundSurface                   = surfaceMtl;
1212
    auto pBuffer     = GetImplAs<OffscreenSurfaceMtl>(surface);
1213
    mNativeTexture   = pBuffer->getColorTexture();
1214
    mFormat          = pBuffer->getColorFormat();
1215
    gl::Extents size = mNativeTexture->sizeAt0();
1216
    mIsPow2          = gl::isPow2(size.width) && gl::isPow2(size.height) && gl::isPow2(size.depth);
1217
    ANGLE_TRY(ensureSamplerStateCreated(context));
1218
1219
    // Tell context to rebind textures
1220
    ContextMtl *contextMtl = mtl::GetImpl(context);
1221
    contextMtl->invalidateCurrentTextures();
1222
1223
    return angle::Result::Continue;
1216
    return angle::Result::Continue;
1224
}
1217
}
1225
1218
1226
angle::Result TextureMtl::releaseTexImage(const gl::Context *context)
1219
angle::Result TextureMtl::releaseTexImage(const gl::Context *context)
1227
{
1220
{
1228
    releaseTexture(true);
1221
    mBoundSurface = nil;
1222
1229
    return angle::Result::Continue;
1223
    return angle::Result::Continue;
1230
}
1224
}
1231
1225
Lines 1235-1240 angle::Result TextureMtl::getAttachmentRenderTarget(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/TextureMtl.mm_sec4
1235
                                                    GLsizei samples,
1229
                                                    GLsizei samples,
1236
                                                    FramebufferAttachmentRenderTarget **rtOut)
1230
                                                    FramebufferAttachmentRenderTarget **rtOut)
1237
{
1231
{
1232
    if (mBoundSurface)
1233
    {
1234
        ANGLE_TRY(
1235
            mBoundSurface->getAttachmentRenderTarget(context, binding, imageIndex, samples, rtOut));
1236
        return angle::Result::Continue;
1237
    }
1238
    ANGLE_TRY(ensureTextureCreated(context));
1238
    ANGLE_TRY(ensureTextureCreated(context));
1239
1239
1240
    ContextMtl *contextMtl = mtl::GetImpl(context);
1240
    ContextMtl *contextMtl = mtl::GetImpl(context);
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/TransformFeedbackMtl.h -11 / +25 lines
Lines 10-21 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/TransformFeedbackMtl.h_sec1
10
#ifndef LIBANGLE_RENDERER_METAL_TRANSFORMFEEDBACKMTL_H_
10
#ifndef LIBANGLE_RENDERER_METAL_TRANSFORMFEEDBACKMTL_H_
11
#define LIBANGLE_RENDERER_METAL_TRANSFORMFEEDBACKMTL_H_
11
#define LIBANGLE_RENDERER_METAL_TRANSFORMFEEDBACKMTL_H_
12
12
13
#include <Metal/Metal.h>
13
#include "libANGLE/renderer/TransformFeedbackImpl.h"
14
#include "libANGLE/renderer/TransformFeedbackImpl.h"
15
#include "libANGLE/renderer/metal/BufferMtl.h"
16
#include "libANGLE/renderer/metal/mtl_resources.h"
14
17
15
namespace rx
18
typedef uint64_t MtlDeviceSize;
19
20
namespace gl
16
{
21
{
22
class ProgramState;
23
}  // namespace gl
17
24
18
class ContextMtl;
25
namespace rx
26
{
19
27
20
class TransformFeedbackMtl : public TransformFeedbackImpl
28
class TransformFeedbackMtl : public TransformFeedbackImpl
21
{
29
{
Lines 32-48 class TransformFeedbackMtl : public TransformFeedbackImpl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/TransformFeedbackMtl.h_sec2
32
                                    size_t index,
40
                                    size_t index,
33
                                    const gl::OffsetBindingPointer<gl::Buffer> &binding) override;
41
                                    const gl::OffsetBindingPointer<gl::Buffer> &binding) override;
34
42
35
    // Params:
43
    void getBufferOffsets(ContextMtl *contextMtl,
36
    // - drawCallFirstVertex is first vertex used by glDrawArrays*. This is important because
44
                          GLint drawCallFirstVertex,
37
    // gl_VertexIndex is starting from this.
45
                          int32_t *offsetsOut,
38
    // - skippedVertices is number of skipped vertices (useful for multiple metal draws per GL draw
46
                          size_t offsetsSize) const;
39
    // call).
47
40
    angle::Result getBufferOffsets(ContextMtl *contextMtl,
48
    const gl::TransformFeedbackBuffersArray<BufferMtl *> &getBufferHandles() const
41
                                   GLint drawCallFirstVertex,
49
    {
42
                                   uint32_t skippedVertices,
50
        return mBufferHandles;
43
                                   int32_t *offsetsOut);
51
    }
44
52
45
  private:
53
  private:
54
    gl::TransformFeedbackBuffersArray<BufferMtl *> mBufferHandles;
55
    gl::TransformFeedbackBuffersArray<MtlDeviceSize> mBufferOffsets;
56
    gl::TransformFeedbackBuffersArray<MtlDeviceSize> mBufferSizes;
57
58
    // Aligned offset for emulation. Could be smaller than offset.
59
    gl::TransformFeedbackBuffersArray<MtlDeviceSize> mAlignedBufferOffsets;
46
};
60
};
47
61
48
}  // namespace rx
62
}  // namespace rx
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/TransformFeedbackMtl.mm -35 / +84 lines
Lines 8-25 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/TransformFeedbackMtl.mm_sec1
8
//
8
//
9
9
10
#include "libANGLE/renderer/metal/TransformFeedbackMtl.h"
10
#include "libANGLE/renderer/metal/TransformFeedbackMtl.h"
11
#include "libANGLE/renderer/metal/BufferMtl.h"
12
#include "libANGLE/renderer/metal/ContextMtl.h"
13
#include "libANGLE/renderer/metal/DisplayMtl.h"
14
#include "libANGLE/renderer/metal/ProgramMtl.h"
15
#include "libANGLE/renderer/metal/QueryMtl.h"
16
#include "libANGLE/renderer/metal/mtl_common.h"
11
17
12
#include "common/debug.h"
13
#include "libANGLE/Context.h"
18
#include "libANGLE/Context.h"
14
#include "libANGLE/Query.h"
19
#include "libANGLE/Query.h"
15
#include "libANGLE/renderer/metal/ContextMtl.h"
20
16
#include "libANGLE/renderer/metal/QueryMtl.h"
21
#include "common/debug.h"
17
22
18
namespace rx
23
namespace rx
19
{
24
{
20
25
21
TransformFeedbackMtl::TransformFeedbackMtl(const gl::TransformFeedbackState &state)
26
TransformFeedbackMtl::TransformFeedbackMtl(const gl::TransformFeedbackState &state)
22
    : TransformFeedbackImpl(state)
27
    : TransformFeedbackImpl(state),
28
      mBufferHandles{},
29
      mBufferOffsets{},
30
      mBufferSizes{},
31
      mAlignedBufferOffsets{}
23
{}
32
{}
24
33
25
TransformFeedbackMtl::~TransformFeedbackMtl() {}
34
TransformFeedbackMtl::~TransformFeedbackMtl() {}
Lines 27-66 TransformFeedbackMtl::~TransformFeedbackMtl() {} a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/TransformFeedbackMtl.mm_sec2
27
angle::Result TransformFeedbackMtl::begin(const gl::Context *context,
36
angle::Result TransformFeedbackMtl::begin(const gl::Context *context,
28
                                          gl::PrimitiveMode primitiveMode)
37
                                          gl::PrimitiveMode primitiveMode)
29
{
38
{
30
    mtl::GetImpl(context)->onTransformFeedbackActive(context, this);
39
    ContextMtl *contextMtl = mtl::GetImpl(context);
40
    // Not currently supported with msl compiler
41
    if (!contextMtl->getDisplay()->getFeatures().emulateTransformFeedback.enabled)
42
    {
43
        return angle::Result::Stop;
44
    }
31
45
32
    return angle::Result::Continue;
46
    const gl::ProgramExecutable *executable = contextMtl->getState().getProgramExecutable();
47
    ASSERT(executable);
48
    size_t xfbBufferCount = executable->getTransformFeedbackBufferCount();
49
50
    for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
51
    {
52
        const gl::OffsetBindingPointer<gl::Buffer> &binding = mState.getIndexedBuffer(bufferIndex);
53
        ASSERT(binding.get());
54
55
        BufferMtl *bufferMtl = mtl::GetImpl(binding.get());
56
57
        assert(bufferMtl);
58
        mBufferOffsets[bufferIndex] = binding.getOffset();
59
        mBufferSizes[bufferIndex]   = gl::GetBoundBufferAvailableSize(binding);
60
        mBufferHandles[bufferIndex] = bufferMtl;
61
62
        ASSERT(contextMtl->getDisplay()->getFeatures().emulateTransformFeedback.enabled);
63
        const MtlDeviceSize offsetAlignment = mtl::kUniformBufferSettingOffsetMinAlignment;
64
65
        // Make sure there's no possible under/overflow with binding size.
66
        static_assert(sizeof(MtlDeviceSize) >= sizeof(binding.getSize()),
67
                      "MtlDeviceSize too small");
68
69
        // Set the offset as close as possible to the requested offset while remaining aligned.
70
        mAlignedBufferOffsets[bufferIndex] =
71
            (mBufferOffsets[bufferIndex] / offsetAlignment) * offsetAlignment;
72
    }
73
74
    return contextMtl->onBeginTransformFeedback(xfbBufferCount, mBufferHandles);
33
}
75
}
34
76
35
angle::Result TransformFeedbackMtl::end(const gl::Context *context)
77
angle::Result TransformFeedbackMtl::end(const gl::Context *context)
36
{
78
{
79
    ContextMtl *contextMtl = mtl::GetImpl(context);
80
    // Not currently supported with msl compiler
81
    if (!contextMtl->getDisplay()->getFeatures().emulateTransformFeedback.enabled)
82
    {
83
        return angle::Result::Stop;
84
    }
85
86
    // If there's an active transform feedback query, accumulate the primitives drawn.
37
    const gl::State &glState = context->getState();
87
    const gl::State &glState = context->getState();
38
    gl::Query *transformFeedbackQuery =
88
    gl::Query *transformFeedbackQuery =
39
        glState.getActiveQuery(gl::QueryType::TransformFeedbackPrimitivesWritten);
89
        glState.getActiveQuery(gl::QueryType::TransformFeedbackPrimitivesWritten);
90
40
    if (transformFeedbackQuery)
91
    if (transformFeedbackQuery)
41
    {
92
    {
42
        mtl::GetImpl(transformFeedbackQuery)->onTransformFeedbackEnd(context);
93
        mtl::GetImpl(transformFeedbackQuery)->onTransformFeedbackEnd(mState.getPrimitivesDrawn());
43
    }
94
    }
44
95
    contextMtl->onEndTransformFeedback();
45
    mtl::GetImpl(context)->onTransformFeedbackInactive(context, this);
46
47
    return angle::Result::Continue;
96
    return angle::Result::Continue;
48
}
97
}
49
98
50
angle::Result TransformFeedbackMtl::pause(const gl::Context *context)
99
angle::Result TransformFeedbackMtl::pause(const gl::Context *context)
51
{
100
{
52
    // When XFB is paused, OpenGL allows XFB buffers to be bound for other purposes. We need to call
101
    ContextMtl *contextMtl = mtl::GetImpl(context);
53
    // onTransformFeedbackInactive() to issue a sync.
102
    return contextMtl->onPauseTransformFeedback();
54
    mtl::GetImpl(context)->onTransformFeedbackInactive(context, this);
55
56
    return angle::Result::Continue;
57
}
103
}
58
104
59
angle::Result TransformFeedbackMtl::resume(const gl::Context *context)
105
angle::Result TransformFeedbackMtl::resume(const gl::Context *context)
60
{
106
{
61
    mtl::GetImpl(context)->onTransformFeedbackActive(context, this);
107
    ContextMtl *contextMtl                  = mtl::GetImpl(context);
62
108
    const gl::ProgramExecutable *executable = contextMtl->getState().getProgramExecutable();
63
    return angle::Result::Continue;
109
    ASSERT(executable);
110
    size_t xfbBufferCount = executable->getTransformFeedbackBufferCount();
111
    return contextMtl->onBeginTransformFeedback(xfbBufferCount, mBufferHandles);
64
}
112
}
65
113
66
angle::Result TransformFeedbackMtl::bindIndexedBuffer(
114
angle::Result TransformFeedbackMtl::bindIndexedBuffer(
Lines 68-84 angle::Result TransformFeedbackMtl::bindIndexedBuffer( a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/TransformFeedbackMtl.mm_sec3
68
    size_t index,
116
    size_t index,
69
    const gl::OffsetBindingPointer<gl::Buffer> &binding)
117
    const gl::OffsetBindingPointer<gl::Buffer> &binding)
70
{
118
{
71
    // Do nothing for now
119
    UNIMPLEMENTED();
72
120
73
    return angle::Result::Continue;
121
    return angle::Result::Continue;
74
}
122
}
75
123
76
angle::Result TransformFeedbackMtl::getBufferOffsets(ContextMtl *contextMtl,
124
void TransformFeedbackMtl::getBufferOffsets(ContextMtl *contextMtl,
77
                                                     GLint drawCallFirstVertex,
125
                                            GLint drawCallFirstVertex,
78
                                                     uint32_t skippedVertices,
126
                                            int32_t *offsetsOut,
79
                                                     int32_t *offsetsOut)
127
                                            size_t offsetsSize) const
80
{
128
{
81
    int64_t verticesDrawn = static_cast<int64_t>(mState.getVerticesDrawn()) + skippedVertices;
129
    if (!contextMtl->getDisplay()->getFeatures().emulateTransformFeedback.enabled)
130
        return;
131
132
    GLsizeiptr verticesDrawn = mState.getVerticesDrawn();
82
    const std::vector<GLsizei> &bufferStrides =
133
    const std::vector<GLsizei> &bufferStrides =
83
        mState.getBoundProgram()->getTransformFeedbackStrides();
134
        mState.getBoundProgram()->getTransformFeedbackStrides();
84
    const gl::ProgramExecutable *executable = contextMtl->getState().getProgramExecutable();
135
    const gl::ProgramExecutable *executable = contextMtl->getState().getProgramExecutable();
Lines 87-113 angle::Result TransformFeedbackMtl::getBufferOffsets(ContextMtl *contextMtl, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/TransformFeedbackMtl.mm_sec4
87
138
88
    ASSERT(xfbBufferCount > 0);
139
    ASSERT(xfbBufferCount > 0);
89
140
141
    // The caller should make sure the offsets array has enough space.  The maximum possible
142
    // number of outputs is gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS.
143
    ASSERT(offsetsSize >= xfbBufferCount);
144
90
    for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
145
    for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
91
    {
146
    {
92
        const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
147
        int64_t offsetFromDescriptor =
93
            mState.getIndexedBuffer(bufferIndex);
148
            static_cast<int64_t>(mBufferOffsets[bufferIndex] - mAlignedBufferOffsets[bufferIndex]);
94
95
        ASSERT((bufferBinding.getOffset() % 4) == 0);
96
97
        // Offset the gl_VertexIndex by drawCallFirstVertex
98
        int64_t drawCallVertexOffset = static_cast<int64_t>(verticesDrawn) - drawCallFirstVertex;
149
        int64_t drawCallVertexOffset = static_cast<int64_t>(verticesDrawn) - drawCallFirstVertex;
99
150
100
        int64_t writeOffset =
151
        int64_t writeOffset =
101
            (bufferBinding.getOffset() + drawCallVertexOffset * bufferStrides[bufferIndex]) /
152
            (offsetFromDescriptor + drawCallVertexOffset * bufferStrides[bufferIndex]) /
102
            static_cast<int64_t>(sizeof(uint32_t));
153
            static_cast<int64_t>(sizeof(uint32_t));
103
154
104
        offsetsOut[bufferIndex] = static_cast<int32_t>(writeOffset);
155
        offsetsOut[bufferIndex] = static_cast<int32_t>(writeOffset);
105
156
106
        // Check for overflow.
157
        // Assert on overflow.  For now, support transform feedback up to 2GB.
107
        ANGLE_CHECK_GL_ALLOC(contextMtl, offsetsOut[bufferIndex] == writeOffset);
158
        ASSERT(offsetsOut[bufferIndex] == writeOffset);
108
    }
159
    }
109
110
    return angle::Result::Continue;
111
}
160
}
112
161
113
}  // namespace rx
162
}  // namespace rx
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.h -5 / +38 lines
Lines 43-50 class VertexArrayMtl : public VertexArrayImpl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.h_sec1
43
                                      const void *indices);
43
                                      const void *indices);
44
44
45
    // vertexDescChanged is both input and output, the input value if is true, will force new
45
    // vertexDescChanged is both input and output, the input value if is true, will force new
46
    // mtl::VertexDesc to be returned via vertexDescOut. Otherwise, it is only returned when the
46
    // mtl::VertexDesc to be returned via vertexDescOut. This typically happens when active shader
47
    // vertex array is dirty
47
    // program is changed.
48
    // Otherwise, it is only returned when the vertex array is dirty.
48
    angle::Result setupDraw(const gl::Context *glContext,
49
    angle::Result setupDraw(const gl::Context *glContext,
49
                            mtl::RenderCommandEncoder *cmdEncoder,
50
                            mtl::RenderCommandEncoder *cmdEncoder,
50
                            bool *vertexDescChanged,
51
                            bool *vertexDescChanged,
Lines 52-62 class VertexArrayMtl : public VertexArrayImpl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.h_sec2
52
53
53
    angle::Result getIndexBuffer(const gl::Context *glContext,
54
    angle::Result getIndexBuffer(const gl::Context *glContext,
54
                                 gl::DrawElementsType indexType,
55
                                 gl::DrawElementsType indexType,
56
                                 gl::PrimitiveMode primitiveMode,
55
                                 size_t indexCount,
57
                                 size_t indexCount,
56
                                 const void *sourcePointer,
58
                                 const void *sourcePointer,
57
                                 mtl::BufferRef *idxBufferOut,
59
                                 mtl::BufferRef *idxBufferOut,
58
                                 size_t *idxBufferOffsetOut,
60
                                 size_t *idxBufferOffsetOut,
59
                                 gl::DrawElementsType *indexTypeOut);
61
                                 gl::DrawElementsType *indexTypeOut,
62
                                 size_t *indexBufferCountOut);
63
64
    // Use to emulate instanced draw for instance <instanceId>.
65
    // The typical call sequence for emulated instance draw is:
66
    // - setupDraw()
67
    // - draw.
68
    // - emulateInstanceDrawStep(1)
69
    // - draw.
70
    // - emulateInstanceDrawStep(n)
71
    // - draw.
72
    // - emulateInstanceDrawStep(0)
73
    void emulateInstanceDrawStep(mtl::RenderCommandEncoder *cmdEncoder, uint32_t instanceId);
60
74
61
  private:
75
  private:
62
    void reset(ContextMtl *context);
76
    void reset(ContextMtl *context);
Lines 72-86 class VertexArrayMtl : public VertexArrayImpl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.h_sec3
72
86
73
    angle::Result convertIndexBuffer(const gl::Context *glContext,
87
    angle::Result convertIndexBuffer(const gl::Context *glContext,
74
                                     gl::DrawElementsType indexType,
88
                                     gl::DrawElementsType indexType,
89
                                     gl::PrimitiveMode mode,
75
                                     size_t offset,
90
                                     size_t offset,
76
                                     mtl::BufferRef *idxBufferOut,
91
                                     mtl::BufferRef *idxBufferOut,
77
                                     size_t *idxBufferOffsetOut);
92
                                     size_t *idxBufferOffsetOut,
93
                                     size_t *indexBufferCountOut);
78
    angle::Result streamIndexBufferFromClient(const gl::Context *glContext,
94
    angle::Result streamIndexBufferFromClient(const gl::Context *glContext,
79
                                              gl::DrawElementsType indexType,
95
                                              gl::DrawElementsType indexType,
96
                                              gl::PrimitiveMode primitiveType,
80
                                              size_t indexCount,
97
                                              size_t indexCount,
81
                                              const void *sourcePointer,
98
                                              const void *sourcePointer,
82
                                              mtl::BufferRef *idxBufferOut,
99
                                              mtl::BufferRef *idxBufferOut,
83
                                              size_t *idxBufferOffsetOut);
100
                                              size_t *idxBufferOffsetOut,
101
                                              size_t *idxBufferCountOut);
84
102
85
    angle::Result convertIndexBufferGPU(const gl::Context *glContext,
103
    angle::Result convertIndexBufferGPU(const gl::Context *glContext,
86
                                        gl::DrawElementsType indexType,
104
                                        gl::DrawElementsType indexType,
Lines 117-123 class VertexArrayMtl : public VertexArrayImpl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.h_sec4
117
    gl::AttribArray<BufferHolderMtl *> mCurrentArrayBuffers;
135
    gl::AttribArray<BufferHolderMtl *> mCurrentArrayBuffers;
118
    gl::AttribArray<SimpleWeakBufferHolderMtl> mConvertedArrayBufferHolders;
136
    gl::AttribArray<SimpleWeakBufferHolderMtl> mConvertedArrayBufferHolders;
119
    gl::AttribArray<size_t> mCurrentArrayBufferOffsets;
137
    gl::AttribArray<size_t> mCurrentArrayBufferOffsets;
138
139
    // Size to be uploaded as inline constant data. Used for client vertex attribute's data that
140
    // is small enough that we can send directly as inline constant data instead of streaming
141
    // through a buffer.
142
    gl::AttribArray<size_t> mCurrentArrayInlineDataSizes;
143
    // Array of host buffers storing converted data for client attributes that are small enough.
144
    gl::AttribArray<angle::MemoryBuffer> mConvertedClientSmallArrays;
145
    gl::AttribArray<const uint8_t *> mCurrentArrayInlineDataPointers;
146
    // Max size of inline constant data that can be used for client vertex attribute.
147
    size_t mInlineDataMaxSize;
148
149
    // Stride per vertex attribute
120
    gl::AttribArray<GLuint> mCurrentArrayBufferStrides;
150
    gl::AttribArray<GLuint> mCurrentArrayBufferStrides;
151
    // Format per vertex attribute
121
    gl::AttribArray<const mtl::VertexFormat *> mCurrentArrayBufferFormats;
152
    gl::AttribArray<const mtl::VertexFormat *> mCurrentArrayBufferFormats;
122
153
123
    const mtl::VertexFormat &mDefaultFloatVertexFormat;
154
    const mtl::VertexFormat &mDefaultFloatVertexFormat;
Lines 127-132 class VertexArrayMtl : public VertexArrayImpl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.h_sec5
127
    mtl::BufferPool mDynamicVertexData;
158
    mtl::BufferPool mDynamicVertexData;
128
    mtl::BufferPool mDynamicIndexData;
159
    mtl::BufferPool mDynamicIndexData;
129
160
161
    std::vector<uint32_t> mEmulatedInstanceAttribs;
162
130
    bool mVertexArrayDirty = true;
163
    bool mVertexArrayDirty = true;
131
};
164
};
132
}  // namespace rx
165
}  // namespace rx
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.mm -70 / +211 lines
Lines 8-13 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.mm_sec1
8
//
8
//
9
9
10
#include "libANGLE/renderer/metal/VertexArrayMtl.h"
10
#include "libANGLE/renderer/metal/VertexArrayMtl.h"
11
12
#include <TargetConditionals.h>
13
11
#include "libANGLE/renderer/metal/BufferMtl.h"
14
#include "libANGLE/renderer/metal/BufferMtl.h"
12
#include "libANGLE/renderer/metal/ContextMtl.h"
15
#include "libANGLE/renderer/metal/ContextMtl.h"
13
#include "libANGLE/renderer/metal/DisplayMtl.h"
16
#include "libANGLE/renderer/metal/DisplayMtl.h"
Lines 76-90 angle::Result StreamIndexData(ContextMtl *contextMtl, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.mm_sec2
76
                              const uint8_t *sourcePointer,
79
                              const uint8_t *sourcePointer,
77
                              gl::DrawElementsType indexType,
80
                              gl::DrawElementsType indexType,
78
                              size_t indexCount,
81
                              size_t indexCount,
82
                              gl::PrimitiveMode mode,
79
                              bool primitiveRestartEnabled,
83
                              bool primitiveRestartEnabled,
80
                              mtl::BufferRef *bufferOut,
84
                              mtl::BufferRef *bufferOut,
81
                              size_t *bufferOffsetOut)
85
                              size_t *bufferOffsetOut,
86
                              size_t *indexCountOut)
82
{
87
{
83
    dynamicBuffer->releaseInFlightBuffers(contextMtl);
88
    dynamicBuffer->releaseInFlightBuffers(contextMtl);
84
85
    const size_t amount = GetIndexConvertedBufferSize(indexType, indexCount);
89
    const size_t amount = GetIndexConvertedBufferSize(indexType, indexCount);
86
    GLubyte *dst        = nullptr;
90
    GLubyte *dst        = nullptr;
87
88
    ANGLE_TRY(
91
    ANGLE_TRY(
89
        dynamicBuffer->allocate(contextMtl, amount, &dst, bufferOut, bufferOffsetOut, nullptr));
92
        dynamicBuffer->allocate(contextMtl, amount, &dst, bufferOut, bufferOffsetOut, nullptr));
90
93
Lines 121-126 angle::Result StreamIndexData(ContextMtl *contextMtl, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.mm_sec3
121
    {
124
    {
122
        memcpy(dst, sourcePointer, amount);
125
        memcpy(dst, sourcePointer, amount);
123
    }
126
    }
127
    *indexCountOut = indexCount;
124
    ANGLE_TRY(dynamicBuffer->commit(contextMtl));
128
    ANGLE_TRY(dynamicBuffer->commit(contextMtl));
125
129
126
    return angle::Result::Continue;
130
    return angle::Result::Continue;
Lines 208-213 void VertexArrayMtl::reset(ContextMtl *context) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.mm_sec4
208
        format = &mDefaultFloatVertexFormat;
212
        format = &mDefaultFloatVertexFormat;
209
    }
213
    }
210
214
215
    for (size_t &inlineDataSize : mCurrentArrayInlineDataSizes)
216
    {
217
        inlineDataSize = 0;
218
    }
219
220
    for (angle::MemoryBuffer &convertedClientArray : mConvertedClientSmallArrays)
221
    {
222
        convertedClientArray.clear();
223
    }
224
225
    for (const uint8_t *&clientPointer : mCurrentArrayInlineDataPointers)
226
    {
227
        clientPointer = nullptr;
228
    }
229
230
    if (context->getDisplay()->getFeatures().allowInlineConstVertexData.enabled)
231
    {
232
        mInlineDataMaxSize = mtl::kInlineConstDataMaxSize;
233
    }
234
    else
235
    {
236
        mInlineDataMaxSize = 0;
237
    }
238
211
    mVertexArrayDirty = true;
239
    mVertexArrayDirty = true;
212
}
240
}
213
241
Lines 315-336 ANGLE_INLINE void VertexArrayMtl::getVertexAttribFormatAndArraySize(const sh::Sh a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.mm_sec5
315
}
343
}
316
344
317
// vertexDescChanged is both input and output, the input value if is true, will force new
345
// vertexDescChanged is both input and output, the input value if is true, will force new
318
// mtl::VertexDesc to be returned via vertexDescOut. Otherwise, it is only returned when the
346
// mtl::VertexDesc to be returned via vertexDescOut. This typically happens when active shader
319
// vertex array is dirty
347
// program is changed.
348
// Otherwise, it is only returned when the vertex array is dirty.
320
angle::Result VertexArrayMtl::setupDraw(const gl::Context *glContext,
349
angle::Result VertexArrayMtl::setupDraw(const gl::Context *glContext,
321
                                        mtl::RenderCommandEncoder *cmdEncoder,
350
                                        mtl::RenderCommandEncoder *cmdEncoder,
322
                                        bool *vertexDescChanged,
351
                                        bool *vertexDescChanged,
323
                                        mtl::VertexDesc *vertexDescOut)
352
                                        mtl::VertexDesc *vertexDescOut)
324
{
353
{
354
    // NOTE(hqle): consider only updating dirty attributes
325
    bool dirty = mVertexArrayDirty || *vertexDescChanged;
355
    bool dirty = mVertexArrayDirty || *vertexDescChanged;
326
356
327
    if (dirty)
357
    if (dirty)
328
    {
358
    {
359
        ContextMtl *contextMtl = mtl::GetImpl(glContext);
360
329
        mVertexArrayDirty = false;
361
        mVertexArrayDirty = false;
362
        mEmulatedInstanceAttribs.clear();
330
363
331
        const gl::ProgramState &programState = glContext->getState().getProgram()->getState();
364
        const gl::ProgramExecutable *executable = glContext->getState().getProgramExecutable();
332
        const gl::AttributesMask &programActiveAttribsMask =
365
        const gl::AttributesMask &programActiveAttribsMask =
333
            glContext->getState().getProgram()->getExecutable().getActiveAttribLocationsMask();
366
            executable->getActiveAttribLocationsMask();
367
        const gl::ProgramState &programState = glContext->getState().getProgram()->getState();
334
368
335
        const std::vector<gl::VertexAttribute> &attribs = mState.getVertexAttributes();
369
        const std::vector<gl::VertexAttribute> &attribs = mState.getVertexAttributes();
336
        const std::vector<gl::VertexBinding> &bindings  = mState.getVertexBindings();
370
        const std::vector<gl::VertexBinding> &bindings  = mState.getVertexBindings();
Lines 360-367 angle::Result VertexArrayMtl::setupDraw(const gl::Context *glContext, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.mm_sec6
360
            const gl::VertexBinding &binding = bindings[attrib.bindingIndex];
394
            const gl::VertexBinding &binding = bindings[attrib.bindingIndex];
361
395
362
            bool attribEnabled = attrib.enabled;
396
            bool attribEnabled = attrib.enabled;
363
            if (attribEnabled &&
397
            if (attribEnabled && !mCurrentArrayBuffers[v] && !mCurrentArrayInlineDataPointers[v])
364
                (!mCurrentArrayBuffers[v] || !mCurrentArrayBuffers[v]->getCurrentBuffer()))
365
            {
398
            {
366
                // Disable it to avoid crash.
399
                // Disable it to avoid crash.
367
                attribEnabled = false;
400
                attribEnabled = false;
Lines 369-401 angle::Result VertexArrayMtl::setupDraw(const gl::Context *glContext, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.mm_sec7
369
402
370
            if (!attribEnabled)
403
            if (!attribEnabled)
371
            {
404
            {
372
                // Use default attribute
405
                desc.attributes[v].bufferIndex = mtl::kDefaultAttribsBindingIndex;
406
                desc.attributes[v].offset      = v * mtl::kDefaultAttributeSize;
373
                // Need to find the attribute having the exact binding location = v in the program
407
                // Need to find the attribute having the exact binding location = v in the program
374
                // inputs list to retrieve its coresponding data type:
408
                // inputs list to retrieve its coresponding data type:
375
                const std::vector<sh::ShaderVariable> &programInputs =
409
                const std::vector<sh::ShaderVariable> &programInputs =
376
                    programState.getProgramInputs();
410
                    programState.getProgramInputs();
377
                std::vector<sh::ShaderVariable>::const_iterator attribInfoIte = std::find_if(
411
                std::vector<sh::ShaderVariable>::const_iterator attribInfoIte = std::find_if(
378
                    begin(programInputs), end(programInputs), [v](const sh::ShaderVariable &sv) {
412
                    begin(programInputs), end(programInputs), [v](const sh::ShaderVariable &sv) {
379
                        return static_cast<uint32_t>(sv.location) == v;
413
                        return static_cast<uint32_t>(sv.location) <= v &&
414
                               v < static_cast<uint32_t>(sv.location) +
415
                                       gl::VariableAttributeCount(sv.type);
380
                    });
416
                    });
381
417
382
                if (attribInfoIte == end(programInputs))
418
                ASSERT(attribInfoIte != end(programInputs));
383
                {
419
                switch (gl::VariableComponentType(attribInfoIte->type))
384
                    // Most likely this is array element with index > 0.
385
                    // Already handled when encounter first element.
386
                    continue;
387
                }
388
389
                uint32_t arraySize;
390
                MTLVertexFormat format;
391
392
                getVertexAttribFormatAndArraySize(*attribInfoIte, &format, &arraySize);
393
394
                for (uint32_t vaIdx = v; vaIdx < v + arraySize; ++vaIdx)
395
                {
420
                {
396
                    desc.attributes[vaIdx].bufferIndex = mtl::kDefaultAttribsBindingIndex;
421
                    case GL_INT:
397
                    desc.attributes[vaIdx].offset      = vaIdx * mtl::kDefaultAttributeSize;
422
                        desc.attributes[v].format = mDefaultIntVertexFormat.metalFormat;
398
                    desc.attributes[vaIdx].format      = format;
423
                        break;
424
                    case GL_UNSIGNED_INT:
425
                        desc.attributes[v].format = mDefaultUIntVertexFormat.metalFormat;
426
                        break;
427
                    default:
428
                        desc.attributes[v].format = mDefaultFloatVertexFormat.metalFormat;
399
                }
429
                }
400
            }
430
            }
401
            else
431
            else
Lines 417-433 angle::Result VertexArrayMtl::setupDraw(const gl::Context *glContext, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.mm_sec8
417
                    desc.layouts[bufferIdx].stepFunction = MTLVertexStepFunctionPerVertex;
447
                    desc.layouts[bufferIdx].stepFunction = MTLVertexStepFunctionPerVertex;
418
                    desc.layouts[bufferIdx].stepRate     = 1;
448
                    desc.layouts[bufferIdx].stepRate     = 1;
419
                }
449
                }
420
                else
450
                else if (contextMtl->getDisplay()->getFeatures().hasBaseVertexInstancedDraw.enabled)
421
                {
451
                {
422
                    desc.layouts[bufferIdx].stepFunction = MTLVertexStepFunctionPerInstance;
452
                    desc.layouts[bufferIdx].stepFunction = MTLVertexStepFunctionPerInstance;
423
                    desc.layouts[bufferIdx].stepRate     = binding.getDivisor();
453
                    desc.layouts[bufferIdx].stepRate     = binding.getDivisor();
424
                }
454
                }
455
                else
456
                {
457
                    // Emulate instance attribute
458
                    mEmulatedInstanceAttribs.push_back(v);
459
                    desc.layouts[bufferIdx].stepFunction = MTLVertexStepFunctionConstant;
460
                    desc.layouts[bufferIdx].stepRate     = 0;
461
                }
462
425
                desc.layouts[bufferIdx].stride = mCurrentArrayBufferStrides[v];
463
                desc.layouts[bufferIdx].stride = mCurrentArrayBufferStrides[v];
426
464
427
                cmdEncoder->setVertexBuffer(mCurrentArrayBuffers[v]->getCurrentBuffer(),
465
                if (mCurrentArrayBuffers[v])
428
                                            bufferOffset, bufferIdx);
466
                {
467
                    cmdEncoder->setVertexBuffer(mCurrentArrayBuffers[v]->getCurrentBuffer(),
468
                                                bufferOffset, bufferIdx);
469
                }
470
                else
471
                {
472
                    // No buffer specified, use the client memory directly as inline constant data
473
                    ASSERT(mCurrentArrayInlineDataSizes[v] <= mInlineDataMaxSize);
474
                    cmdEncoder->setVertexBytes(mCurrentArrayInlineDataPointers[v],
475
                                               mCurrentArrayInlineDataSizes[v], bufferIdx);
476
                }
429
            }
477
            }
430
        }
478
        }  // for (v)
431
    }
479
    }
432
480
433
    *vertexDescChanged = dirty;
481
    *vertexDescChanged = dirty;
Lines 435-440 angle::Result VertexArrayMtl::setupDraw(const gl::Context *glContext, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.mm_sec9
435
    return angle::Result::Continue;
483
    return angle::Result::Continue;
436
}
484
}
437
485
486
void VertexArrayMtl::emulateInstanceDrawStep(mtl::RenderCommandEncoder *cmdEncoder,
487
                                             uint32_t instanceId)
488
{
489
490
    const std::vector<gl::VertexAttribute> &attribs = mState.getVertexAttributes();
491
    const std::vector<gl::VertexBinding> &bindings  = mState.getVertexBindings();
492
493
    for (uint32_t instanceAttribIdx : mEmulatedInstanceAttribs)
494
    {
495
        uint32_t bufferIdx               = mtl::kVboBindingIndexStart + instanceAttribIdx;
496
        const auto &attrib               = attribs[instanceAttribIdx];
497
        const gl::VertexBinding &binding = bindings[attrib.bindingIndex];
498
        uint32_t offset =
499
            instanceId / binding.getDivisor() * mCurrentArrayBufferStrides[instanceAttribIdx];
500
        if (mCurrentArrayBuffers[instanceAttribIdx])
501
        {
502
            offset += static_cast<uint32_t>(mCurrentArrayBufferOffsets[instanceAttribIdx]);
503
504
            cmdEncoder->setVertexBuffer(mCurrentArrayBuffers[instanceAttribIdx]->getCurrentBuffer(),
505
                                        offset, bufferIdx);
506
        }
507
        else
508
        {
509
            // No buffer specified, use the client memory directly as inline constant data
510
            ASSERT(mCurrentArrayInlineDataSizes[instanceAttribIdx] <= mInlineDataMaxSize);
511
            if (offset > mCurrentArrayInlineDataSizes[instanceAttribIdx])
512
            {
513
                offset = static_cast<uint32_t>(mCurrentArrayInlineDataSizes[instanceAttribIdx]);
514
            }
515
            cmdEncoder->setVertexBytes(mCurrentArrayInlineDataPointers[instanceAttribIdx] + offset,
516
                                       mCurrentArrayInlineDataSizes[instanceAttribIdx] - offset,
517
                                       bufferIdx);
518
        }
519
    }
520
}
521
438
angle::Result VertexArrayMtl::updateClientAttribs(const gl::Context *context,
522
angle::Result VertexArrayMtl::updateClientAttribs(const gl::Context *context,
439
                                                  GLint firstVertex,
523
                                                  GLint firstVertex,
440
                                                  GLsizei vertexOrIndexCount,
524
                                                  GLsizei vertexOrIndexCount,
Lines 463-472 angle::Result VertexArrayMtl::updateClientAttribs(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.mm_sec10
463
        const gl::VertexBinding &binding  = bindings[attrib.bindingIndex];
547
        const gl::VertexBinding &binding  = bindings[attrib.bindingIndex];
464
        ASSERT(attrib.enabled && binding.getBuffer().get() == nullptr);
548
        ASSERT(attrib.enabled && binding.getBuffer().get() == nullptr);
465
549
466
        GLuint stride;
550
        // Source client memory pointer
467
        const mtl::VertexFormat &vertexFormat =
468
            GetVertexConversionFormat(contextMtl, attrib.format->id, &stride);
469
470
        const uint8_t *src = static_cast<const uint8_t *>(attrib.pointer);
551
        const uint8_t *src = static_cast<const uint8_t *>(attrib.pointer);
471
        ASSERT(src);
552
        ASSERT(src);
472
553
Lines 484-505 angle::Result VertexArrayMtl::updateClientAttribs(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.mm_sec11
484
            startElement = 0;
565
            startElement = 0;
485
            elementCount = UnsignedCeilDivide(instanceCount, binding.getDivisor());
566
            elementCount = UnsignedCeilDivide(instanceCount, binding.getDivisor());
486
        }
567
        }
487
        // Allocate space for startElement + elementCount so indexing will work.  If we don't
568
        size_t bytesIntendedToUse = (startElement + elementCount) * binding.getStride();
488
        // start at zero all the indices will be off.
489
        // Only elementCount vertices will be used by the upcoming draw so that is all we copy.
490
        size_t bytesToAllocate = (startElement + elementCount) * stride;
491
        src += startElement * binding.getStride();
492
        size_t destOffset = startElement * stride;
493
494
        mDynamicVertexData.updateAlignment(contextMtl, vertexFormat.actualAngleFormat().pixelBytes);
495
        ANGLE_TRY(StreamVertexData(
496
            contextMtl, &mDynamicVertexData, src, bytesToAllocate, destOffset, elementCount,
497
            binding.getStride(), vertexFormat.vertexLoadFunction,
498
            &mConvertedArrayBufferHolders[attribIndex], &mCurrentArrayBufferOffsets[attribIndex]));
499
569
500
        mCurrentArrayBuffers[attribIndex]       = &mConvertedArrayBufferHolders[attribIndex];
570
        const mtl::VertexFormat &format = contextMtl->getVertexFormat(attrib.format->id, false);
501
        mCurrentArrayBufferFormats[attribIndex] = &vertexFormat;
571
        bool needStreaming              = format.actualFormatId != format.intendedFormatId ||
502
        mCurrentArrayBufferStrides[attribIndex] = stride;
572
                             (binding.getStride() % mtl::kVertexAttribBufferStrideAlignment) != 0 ||
573
                             (binding.getStride() < format.actualAngleFormat().pixelBytes) ||
574
                             bytesIntendedToUse > mInlineDataMaxSize;
575
576
        if (!needStreaming)
577
        {
578
            // Data will be uploaded directly as inline constant data
579
            mCurrentArrayBuffers[attribIndex]            = nullptr;
580
            mCurrentArrayInlineDataPointers[attribIndex] = src;
581
            mCurrentArrayInlineDataSizes[attribIndex]    = bytesIntendedToUse;
582
            mCurrentArrayBufferOffsets[attribIndex]      = 0;
583
            mCurrentArrayBufferFormats[attribIndex]      = &format;
584
            mCurrentArrayBufferStrides[attribIndex]      = binding.getStride();
585
        }
586
        else
587
        {
588
            GLuint convertedStride;
589
            // Need to stream the client vertex data to a buffer.
590
            const mtl::VertexFormat &streamFormat =
591
                GetVertexConversionFormat(contextMtl, attrib.format->id, &convertedStride);
592
593
            // Allocate space for startElement + elementCount so indexing will work.  If we don't
594
            // start at zero all the indices will be off.
595
            // Only elementCount vertices will be used by the upcoming draw so that is all we copy.
596
            size_t bytesToAllocate = (startElement + elementCount) * convertedStride;
597
            src += startElement * binding.getStride();
598
            size_t destOffset = startElement * convertedStride;
599
600
            mCurrentArrayBufferFormats[attribIndex] = &streamFormat;
601
            mCurrentArrayBufferStrides[attribIndex] = convertedStride;
602
603
            if (bytesToAllocate <= mInlineDataMaxSize)
604
            {
605
                // If the data is small enough, use host memory instead of creating GPU buffer. To
606
                // avoid synchronizing access to GPU buffer that is still in use.
607
                angle::MemoryBuffer &convertedClientArray =
608
                    mConvertedClientSmallArrays[attribIndex];
609
                if (bytesToAllocate > convertedClientArray.size())
610
                {
611
                    ANGLE_CHECK_GL_ALLOC(contextMtl, convertedClientArray.resize(bytesToAllocate));
612
                }
613
614
                ASSERT(streamFormat.vertexLoadFunction);
615
                streamFormat.vertexLoadFunction(src, binding.getStride(), elementCount,
616
                                                convertedClientArray.data() + destOffset);
617
618
                mCurrentArrayBuffers[attribIndex]            = nullptr;
619
                mCurrentArrayInlineDataPointers[attribIndex] = convertedClientArray.data();
620
                mCurrentArrayInlineDataSizes[attribIndex]    = bytesToAllocate;
621
                mCurrentArrayBufferOffsets[attribIndex]      = 0;
622
            }
623
            else
624
            {
625
                // Stream the client data to a GPU buffer. Synchronization might happen if buffer is
626
                // in use.
627
                mDynamicVertexData.updateAlignment(contextMtl,
628
                                                   streamFormat.actualAngleFormat().pixelBytes);
629
                ANGLE_TRY(StreamVertexData(contextMtl, &mDynamicVertexData, src, bytesToAllocate,
630
                                           destOffset, elementCount, binding.getStride(),
631
                                           streamFormat.vertexLoadFunction,
632
                                           &mConvertedArrayBufferHolders[attribIndex],
633
                                           &mCurrentArrayBufferOffsets[attribIndex]));
634
635
                mCurrentArrayBuffers[attribIndex] = &mConvertedArrayBufferHolders[attribIndex];
636
            }
637
        }  // if (needStreaming)
503
    }
638
    }
504
639
505
    mVertexArrayDirty = true;
640
    mVertexArrayDirty = true;
Lines 526-532 angle::Result VertexArrayMtl::syncDirtyAttrib(const gl::Context *glContext, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.mm_sec12
526
            bool needConversion =
661
            bool needConversion =
527
                format.actualFormatId != format.intendedFormatId ||
662
                format.actualFormatId != format.intendedFormatId ||
528
                (binding.getOffset() % format.actualAngleFormat().pixelBytes) != 0 ||
663
                (binding.getOffset() % format.actualAngleFormat().pixelBytes) != 0 ||
529
                (binding.getOffset() % mtl::kVertexAttribBufferStrideAlignment) != 0 ||
664
                (binding.getOffset() % 4) != 0 ||
530
                (binding.getStride() < format.actualAngleFormat().pixelBytes) ||
665
                (binding.getStride() < format.actualAngleFormat().pixelBytes) ||
531
                (binding.getStride() % mtl::kVertexAttribBufferStrideAlignment) != 0;
666
                (binding.getStride() % mtl::kVertexAttribBufferStrideAlignment) != 0;
532
667
Lines 563-581 angle::Result VertexArrayMtl::syncDirtyAttrib(const gl::Context *glContext, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.mm_sec13
563
698
564
angle::Result VertexArrayMtl::getIndexBuffer(const gl::Context *context,
699
angle::Result VertexArrayMtl::getIndexBuffer(const gl::Context *context,
565
                                             gl::DrawElementsType type,
700
                                             gl::DrawElementsType type,
701
                                             gl::PrimitiveMode mode,
566
                                             size_t count,
702
                                             size_t count,
567
                                             const void *indices,
703
                                             const void *indices,
568
                                             mtl::BufferRef *idxBufferOut,
704
                                             mtl::BufferRef *idxBufferOut,
569
                                             size_t *idxBufferOffsetOut,
705
                                             size_t *idxBufferOffsetOut,
570
                                             gl::DrawElementsType *indexTypeOut)
706
                                             gl::DrawElementsType *indexTypeOut,
707
                                             size_t *indexBufferCountOut)
571
{
708
{
572
    const gl::Buffer *glElementArrayBuffer = getState().getElementArrayBuffer();
709
    const gl::Buffer *glElementArrayBuffer = getState().getElementArrayBuffer();
573
710
574
    size_t convertedOffset = reinterpret_cast<size_t>(indices);
711
    size_t convertedOffset = reinterpret_cast<size_t>(indices);
575
    if (!glElementArrayBuffer)
712
    if (!glElementArrayBuffer)
576
    {
713
    {
577
        ANGLE_TRY(streamIndexBufferFromClient(context, type, count, indices, idxBufferOut,
714
        ANGLE_TRY(streamIndexBufferFromClient(context, type, mode, count, indices, idxBufferOut,
578
                                              idxBufferOffsetOut));
715
                                              idxBufferOffsetOut, indexBufferCountOut));
579
    }
716
    }
580
    else
717
    else
581
    {
718
    {
Lines 583-590 angle::Result VertexArrayMtl::getIndexBuffer(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.mm_sec14
583
                              (convertedOffset % mtl::kIndexBufferOffsetAlignment) != 0;
720
                              (convertedOffset % mtl::kIndexBufferOffsetAlignment) != 0;
584
        if (needConversion)
721
        if (needConversion)
585
        {
722
        {
586
            ANGLE_TRY(convertIndexBuffer(context, type, convertedOffset, idxBufferOut,
723
            ANGLE_TRY(convertIndexBuffer(context, type, mode, convertedOffset, idxBufferOut,
587
                                         idxBufferOffsetOut));
724
                                         idxBufferOffsetOut, indexBufferCountOut));
588
        }
725
        }
589
        else
726
        else
590
        {
727
        {
Lines 592-597 angle::Result VertexArrayMtl::getIndexBuffer(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.mm_sec15
592
            BufferMtl *bufferMtl = mtl::GetImpl(glElementArrayBuffer);
729
            BufferMtl *bufferMtl = mtl::GetImpl(glElementArrayBuffer);
593
            *idxBufferOut        = bufferMtl->getCurrentBuffer();
730
            *idxBufferOut        = bufferMtl->getCurrentBuffer();
594
            *idxBufferOffsetOut  = convertedOffset;
731
            *idxBufferOffsetOut  = convertedOffset;
732
            *indexBufferCountOut = count;
595
        }
733
        }
596
    }
734
    }
597
735
Lines 607-615 angle::Result VertexArrayMtl::getIndexBuffer(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.mm_sec16
607
745
608
angle::Result VertexArrayMtl::convertIndexBuffer(const gl::Context *glContext,
746
angle::Result VertexArrayMtl::convertIndexBuffer(const gl::Context *glContext,
609
                                                 gl::DrawElementsType indexType,
747
                                                 gl::DrawElementsType indexType,
748
                                                 gl::PrimitiveMode mode,
610
                                                 size_t offset,
749
                                                 size_t offset,
611
                                                 mtl::BufferRef *idxBufferOut,
750
                                                 mtl::BufferRef *idxBufferOut,
612
                                                 size_t *idxBufferOffsetOut)
751
                                                 size_t *idxBufferOffsetOut,
752
                                                 size_t *indexBufferCountOut)
613
{
753
{
614
    size_t offsetModulo = offset % mtl::kIndexBufferOffsetAlignment;
754
    size_t offsetModulo = offset % mtl::kIndexBufferOffsetAlignment;
615
    ASSERT(offsetModulo != 0 || indexType == gl::DrawElementsType::UnsignedByte);
755
    ASSERT(offsetModulo != 0 || indexType == gl::DrawElementsType::UnsignedByte);
Lines 638-652 angle::Result VertexArrayMtl::convertIndexBuffer(const gl::Context *glContext, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.mm_sec17
638
    }
778
    }
639
779
640
    size_t indexCount = GetIndexCount(idxBuffer, offsetModulo, indexType);
780
    size_t indexCount = GetIndexCount(idxBuffer, offsetModulo, indexType);
641
781
    if ((!contextMtl->getDisplay()->getFeatures().breakRenderPassIsCheap.enabled &&
642
    if (!contextMtl->getDisplay()->getFeatures().hasCheapRenderPass.enabled &&
782
         contextMtl->getRenderCommandEncoder()))
643
        contextMtl->getRenderCommandEncoder())
644
    {
783
    {
645
        // We shouldn't use GPU to convert when we are in a middle of a render pass.
784
        // We shouldn't use GPU to convert when we are in a middle of a render pass.
646
        ANGLE_TRY(StreamIndexData(contextMtl, &conversion->data,
785
        ANGLE_TRY(StreamIndexData(contextMtl, &conversion->data,
647
                                  idxBuffer->getClientShadowCopyData(contextMtl) + offsetModulo,
786
                                  idxBuffer->getClientShadowCopyData(contextMtl) + offsetModulo,
648
                                  indexType, indexCount, glState.isPrimitiveRestartEnabled(),
787
                                  indexType, indexCount, mode, glState.isPrimitiveRestartEnabled(),
649
                                  &conversion->convertedBuffer, &conversion->convertedOffset));
788
                                  &conversion->convertedBuffer, &conversion->convertedOffset,
789
                                  indexBufferCountOut));
650
    }
790
    }
651
    else
791
    else
652
    {
792
    {
Lines 695-712 angle::Result VertexArrayMtl::convertIndexBufferGPU(const gl::Context *glContext a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.mm_sec18
695
835
696
angle::Result VertexArrayMtl::streamIndexBufferFromClient(const gl::Context *context,
836
angle::Result VertexArrayMtl::streamIndexBufferFromClient(const gl::Context *context,
697
                                                          gl::DrawElementsType indexType,
837
                                                          gl::DrawElementsType indexType,
838
                                                          gl::PrimitiveMode mode,
698
                                                          size_t indexCount,
839
                                                          size_t indexCount,
699
                                                          const void *sourcePointer,
840
                                                          const void *sourcePointer,
700
                                                          mtl::BufferRef *idxBufferOut,
841
                                                          mtl::BufferRef *idxBufferOut,
701
                                                          size_t *idxBufferOffsetOut)
842
                                                          size_t *idxBufferOffsetOut,
843
                                                          size_t *idxBufferCountOut)
702
{
844
{
703
    ASSERT(getState().getElementArrayBuffer() == nullptr);
845
    ASSERT(getState().getElementArrayBuffer() == nullptr);
704
    ContextMtl *contextMtl = mtl::GetImpl(context);
846
    ContextMtl *contextMtl = mtl::GetImpl(context);
705
847
706
    auto srcData = static_cast<const uint8_t *>(sourcePointer);
848
    auto srcData = static_cast<const uint8_t *>(sourcePointer);
707
    ANGLE_TRY(StreamIndexData(contextMtl, &mDynamicIndexData, srcData, indexType, indexCount,
849
    ANGLE_TRY(StreamIndexData(contextMtl, &mDynamicIndexData, srcData, indexType, indexCount, mode,
708
                              context->getState().isPrimitiveRestartEnabled(), idxBufferOut,
850
                              context->getState().isPrimitiveRestartEnabled(), idxBufferOut,
709
                              idxBufferOffsetOut));
851
                              idxBufferOffsetOut, idxBufferCountOut));
710
852
711
    return angle::Result::Continue;
853
    return angle::Result::Continue;
712
}
854
}
Lines 744-750 angle::Result VertexArrayMtl::convertVertexBuffer(const gl::Context *glContext, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.mm_sec19
744
    // Has the content of the buffer has changed since last conversion?
886
    // Has the content of the buffer has changed since last conversion?
745
    if (!conversion->dirty)
887
    if (!conversion->dirty)
746
    {
888
    {
747
        // Buffer's data hasn't been changed. Re-use last converted results
748
        mConvertedArrayBufferHolders[attribIndex].set(conversion->convertedBuffer);
889
        mConvertedArrayBufferHolders[attribIndex].set(conversion->convertedBuffer);
749
        mCurrentArrayBufferOffsets[attribIndex] = conversion->convertedOffset;
890
        mCurrentArrayBufferOffsets[attribIndex] = conversion->convertedOffset;
750
891
Lines 761-767 angle::Result VertexArrayMtl::convertVertexBuffer(const gl::Context *glContext, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.mm_sec20
761
    bool canExpandComponentsOnGPU = convertedFormat.actualSameGLType;
902
    bool canExpandComponentsOnGPU = convertedFormat.actualSameGLType;
762
903
763
    if (contextMtl->getRenderCommandEncoder() &&
904
    if (contextMtl->getRenderCommandEncoder() &&
764
        !contextMtl->getDisplay()->getFeatures().hasCheapRenderPass.enabled &&
905
        !contextMtl->getDisplay()->getFeatures().breakRenderPassIsCheap.enabled &&
765
        !contextMtl->getDisplay()->getFeatures().hasExplicitMemBarrier.enabled)
906
        !contextMtl->getDisplay()->getFeatures().hasExplicitMemBarrier.enabled)
766
    {
907
    {
767
        // Cannot use GPU to convert when we are in a middle of a render pass.
908
        // Cannot use GPU to convert when we are in a middle of a render pass.
Lines 792-797 angle::Result VertexArrayMtl::convertVertexBuffer(const gl::Context *glContext, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.mm_sec21
792
    conversion->convertedBuffer = mConvertedArrayBufferHolders[attribIndex].getCurrentBuffer();
933
    conversion->convertedBuffer = mConvertedArrayBufferHolders[attribIndex].getCurrentBuffer();
793
    conversion->convertedOffset = mCurrentArrayBufferOffsets[attribIndex];
934
    conversion->convertedOffset = mCurrentArrayBufferOffsets[attribIndex];
794
935
936
    ASSERT(conversion->dirty);
937
    conversion->dirty = false;
938
795
#ifndef NDEBUG
939
#ifndef NDEBUG
796
    ANGLE_MTL_OBJC_SCOPE
940
    ANGLE_MTL_OBJC_SCOPE
797
    {
941
    {
Lines 801-809 angle::Result VertexArrayMtl::convertVertexBuffer(const gl::Context *glContext, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.mm_sec22
801
    }
945
    }
802
#endif
946
#endif
803
947
804
    ASSERT(conversion->dirty);
805
    conversion->dirty = false;
806
807
    return angle::Result::Continue;
948
    return angle::Result::Continue;
808
}
949
}
809
950
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/doc/APPLE_clip_distance.md -3 / +28 lines
Lines 6-11 level side. Writing to `gl_ClipDistance[i]` in shader will be ignored if it is d a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/doc/APPLE_clip_distance.md_sec1
6
doesn't have any equivalent API to disable/enable the writing, though writing to a `clip_distance`
6
doesn't have any equivalent API to disable/enable the writing, though writing to a `clip_distance`
7
variable automatically enables it.
7
variable automatically enables it.
8
8
9
To emulate this enabling/disabling API, the Metal back-end uses a similar implementation as what
9
To implement this enabling/disabling API in Metal back-end:
10
[Vulkan back-end does](../../vulkan/doc/APPLE_clip_distance.md). Please refer to that document for
10
11
more details.
11
- The shader compiler will translate each `gl_ClipDistance[i]` assignment to an assignment to
12
  `ANGLEClipDistance[i]` variable.
13
- A special driver uniform variable `clipDistancesEnabled` will contain one bit flag for each
14
  enabled `gl_ClipDistance[i]`. This variable supports up to 32 `gl_ClipDistance` indices.
15
- At the end of vertex shader, the enabled `gl_ClipDistance[i]` will be assigned the respective
16
  value from `ANGLEClipDistance[i]`. On the other hand, those disabled elements will be assigned
17
  zero value. This step is described in the following code:
18
    ```
19
    for (int index : arraylength(gl_ClipDistance))
20
    {
21
        if (ANGLEUniforms.clipDistancesEnabled & (0x1 << index))
22
            gl_ClipDistance[index] = ANGLEClipDistance[index];
23
        else
24
            gl_ClipDistance[index] = 0;
25
    }
26
    ```
27
- Some minor optimizations:
28
    - Only those indices that are referenced in the original code will be used in if else block
29
      above.
30
    - Those elements whose index not referenced in the original code will be zeroised instead.
31
    - If the original code only uses up to an index < `gl_MaxClipDistances`, then
32
      the loop will have at most `index+1` iterations. If there is at least one index not being
33
      integral constant value known at compile time then declared size of `gl_ClipDistance`
34
      will be the loop size.
35
    - Finally, if the original code doesn't use `gl_ClipDistance`, then all the steps above will be
36
      omitted.
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/gen_mtl_format_table.py -4 / +59 lines
Lines 37-42 template_autogen_inl = """// GENERATED FILE - DO NOT EDIT. a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/gen_mtl_format_table.py_sec1
37
#include "libANGLE/renderer/Format.h"
37
#include "libANGLE/renderer/Format.h"
38
#include "libANGLE/renderer/metal/DisplayMtl.h"
38
#include "libANGLE/renderer/metal/DisplayMtl.h"
39
#include "libANGLE/renderer/metal/mtl_format_utils.h"
39
#include "libANGLE/renderer/metal/mtl_format_utils.h"
40
#include "libANGLE/renderer/metal/mtl_utils.h"
40
41
41
using namespace angle;
42
using namespace angle;
42
43
Lines 48-54 namespace mtl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/gen_mtl_format_table.py_sec2
48
void Format::init(const DisplayMtl *display, angle::FormatID intendedFormatId_)
49
void Format::init(const DisplayMtl *display, angle::FormatID intendedFormatId_)
49
{{
50
{{
50
    this->intendedFormatId = intendedFormatId_;
51
    this->intendedFormatId = intendedFormatId_;
51
52
    id<MTLDevice> metalDevice = display->getMetalDevice();
52
    id<MTLDevice> metalDevice = display->getMetalDevice();
53
53
54
    // Actual conversion
54
    // Actual conversion
Lines 109-114 image_format_assign_template2 = """ a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/gen_mtl_format_table.py_sec3
109
                this->initFunction = {init_function_fallback};
109
                this->initFunction = {init_function_fallback};
110
            }}
110
            }}
111
"""
111
"""
112
#D16 is fully supported on  Apple3+. However, on
113
#previous  versions of Apple hardware, some operations can cause
114
#undefined behavior.
115
image_format_assign_template3 = """
116
            if (mtl::SupportsIOSGPUFamily(metalDevice, 3))
117
            {{
118
                this->metalFormat = {mtl_format};
119
                this->actualFormatId = angle::FormatID::{actual_angle_format};
120
                this->initFunction = {init_function};
121
            }}
122
            else
123
            {{
124
                this->metalFormat = {mtl_format_fallback};
125
                this->actualFormatId = angle::FormatID::{actual_angle_format_fallback};
126
                this->initFunction = {init_function_fallback};
127
            }}
128
"""
112
129
113
case_image_format_template1 = """        case angle::FormatID::{angle_format}:
130
case_image_format_template1 = """        case angle::FormatID::{angle_format}:
114
            {image_format_assign}
131
            {image_format_assign}
Lines 213-218 def get_vertex_copy_function_and_default_alpha(src_format, dst_format): a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/gen_mtl_format_table.py_sec4
213
230
214
231
215
# Generate format conversion switch case (generic case)
232
# Generate format conversion switch case (generic case)
233
234
216
def gen_image_map_switch_case(angle_format, actual_angle_format_info, angle_to_mtl_map,
235
def gen_image_map_switch_case(angle_format, actual_angle_format_info, angle_to_mtl_map,
217
                              assign_gen_func):
236
                              assign_gen_func):
218
    if isinstance(actual_angle_format_info, dict):
237
    if isinstance(actual_angle_format_info, dict):
Lines 255-260 def gen_image_map_switch_case(angle_format, actual_angle_format_info, angle_to_m a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/gen_mtl_format_table.py_sec5
255
274
256
275
257
# Generate format conversion switch case (simple case)
276
# Generate format conversion switch case (simple case)
277
278
258
def gen_image_map_switch_simple_case(angle_format, actual_angle_format_info, angle_to_gl,
279
def gen_image_map_switch_simple_case(angle_format, actual_angle_format_info, angle_to_gl,
259
                                     angle_to_mtl_map):
280
                                     angle_to_mtl_map):
260
281
Lines 270-275 def gen_image_map_switch_simple_case(angle_format, actual_angle_format_info, ang a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/gen_mtl_format_table.py_sec6
270
291
271
292
272
# Generate format conversion switch case (Mac case)
293
# Generate format conversion switch case (Mac case)
294
295
273
def gen_image_map_switch_mac_case(angle_format, actual_angle_format_info, angle_to_gl,
296
def gen_image_map_switch_mac_case(angle_format, actual_angle_format_info, angle_to_gl,
274
                                  angle_to_mtl_map, mac_fallbacks):
297
                                  angle_to_mtl_map, mac_fallbacks):
275
    gl_format = angle_to_gl[angle_format]
298
    gl_format = angle_to_gl[angle_format]
Lines 301-311 def gen_image_map_switch_mac_case(angle_format, actual_angle_format_info, angle_ a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/gen_mtl_format_table.py_sec7
301
                                     gen_format_assign_code)
324
                                     gen_format_assign_code)
302
325
303
326
327
def gen_image_map_switch_ios_case(angle_format, actual_angle_format_info, angle_to_gl,
328
                                  angle_to_mtl_map, ios_fallbacks):
329
    gl_format = angle_to_gl[angle_format]
330
331
    def gen_format_assign_code(actual_angle_format, angle_to_mtl_map):
332
        if actual_angle_format in ios_fallbacks:
333
            # This format (Depth16Uniform) requires fallback when iOS hardware does not fully support depth16.
334
            # Fallback format:
335
            actual_angle_format_fallback = ios_fallbacks[actual_angle_format]
336
            # return if else block:
337
            return image_format_assign_template3.format(
338
                actual_angle_format=actual_angle_format,
339
                mtl_format=angle_to_mtl_map[actual_angle_format],
340
                init_function=angle_format_utils.get_internal_format_initializer(
341
                    gl_format, actual_angle_format),
342
                actual_angle_format_fallback=actual_angle_format_fallback,
343
                mtl_format_fallback=angle_to_mtl_map[actual_angle_format_fallback],
344
                init_function_fallback=angle_format_utils.get_internal_format_initializer(
345
                    gl_format, actual_angle_format_fallback))
346
        else:
347
            # return ordinary block:
348
            return image_format_assign_template1.format(
349
                actual_angle_format=actual_angle_format,
350
                mtl_format=angle_to_mtl_map[actual_angle_format],
351
                init_function=angle_format_utils.get_internal_format_initializer(
352
                    gl_format, actual_angle_format))
353
354
    return gen_image_map_switch_case(angle_format, actual_angle_format_info, angle_to_mtl_map,
355
                                     gen_format_assign_code)
356
357
304
def gen_image_map_switch_string(image_table, angle_to_gl):
358
def gen_image_map_switch_string(image_table, angle_to_gl):
305
    angle_override = image_table["override"]
359
    angle_override = image_table["override"]
306
    mac_override = image_table["override_mac"]
360
    mac_override = image_table["override_mac"]
307
    ios_override = image_table["override_ios"]
361
    ios_override = image_table["override_ios"]
308
    mac_fallbacks = image_table["d24s8_fallbacks_mac"]
362
    mac_fallbacks = image_table["fallbacks_mac"]
363
    ios_fallbacks = image_table["fallbacks_ios"]
309
    angle_to_mtl = image_table["map"]
364
    angle_to_mtl = image_table["map"]
310
    mac_specific_map = image_table["map_mac"]
365
    mac_specific_map = image_table["map_mac"]
311
    ios_specific_map = image_table["map_ios"]
366
    ios_specific_map = image_table["map_ios"]
Lines 322-329 def gen_image_map_switch_string(image_table, angle_to_gl): a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/gen_mtl_format_table.py_sec8
322
    def gen_image_map_switch_common_case(angle_format, actual_angle_format):
377
    def gen_image_map_switch_common_case(angle_format, actual_angle_format):
323
        mac_case = gen_image_map_switch_mac_case(angle_format, actual_angle_format, angle_to_gl,
378
        mac_case = gen_image_map_switch_mac_case(angle_format, actual_angle_format, angle_to_gl,
324
                                                 mac_angle_to_mtl, mac_fallbacks)
379
                                                 mac_angle_to_mtl, mac_fallbacks)
325
        non_mac_case = gen_image_map_switch_simple_case(angle_format, actual_angle_format,
380
        non_mac_case = gen_image_map_switch_ios_case(angle_format, actual_angle_format,
326
                                                        angle_to_gl, angle_to_mtl)
381
                                                     angle_to_gl, angle_to_mtl, ios_fallbacks)
327
        if mac_case == non_mac_case:
382
        if mac_case == non_mac_case:
328
            return mac_case
383
            return mac_case
329
384
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_buffer_pool.h -3 / +2 lines
Lines 81-87 class BufferPool a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_buffer_pool.h_sec1
81
                           bool *newBufferAllocatedOut = nullptr);
81
                           bool *newBufferAllocatedOut = nullptr);
82
82
83
    // After a sequence of CPU writes, call commit to ensure the data is visible to the device.
83
    // After a sequence of CPU writes, call commit to ensure the data is visible to the device.
84
    angle::Result commit(ContextMtl *contextMtl);
84
    angle::Result commit(ContextMtl *contextMtl, bool flushEntireBuffer = false);
85
85
86
    // This releases all the buffers that have been allocated since this was last called.
86
    // This releases all the buffers that have been allocated since this was last called.
87
    void releaseInFlightBuffers(ContextMtl *contextMtl);
87
    void releaseInFlightBuffers(ContextMtl *contextMtl);
Lines 114-120 class BufferPool a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_buffer_pool.h_sec2
114
    angle::Result allocateNewBuffer(ContextMtl *contextMtl);
114
    angle::Result allocateNewBuffer(ContextMtl *contextMtl);
115
    void destroyBufferList(ContextMtl *contextMtl, std::deque<BufferRef> *buffers);
115
    void destroyBufferList(ContextMtl *contextMtl, std::deque<BufferRef> *buffers);
116
    angle::Result finalizePendingBuffer(ContextMtl *contextMtl);
116
    angle::Result finalizePendingBuffer(ContextMtl *contextMtl);
117
118
    size_t mInitialSize;
117
    size_t mInitialSize;
119
    BufferRef mBuffer;
118
    BufferRef mBuffer;
120
    uint32_t mNextAllocationOffset;
119
    uint32_t mNextAllocationOffset;
Lines 127-133 class BufferPool a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_buffer_pool.h_sec3
127
126
128
    size_t mBuffersAllocated;
127
    size_t mBuffersAllocated;
129
    size_t mMaxBuffers;
128
    size_t mMaxBuffers;
130
    BufferPoolMemPolicy mMemPolicy;
129
    BufferPoolMemPolicy mMemPolicy = BufferPoolMemPolicy::Auto;
131
    bool mAlwaysAllocateNewBuffer;
130
    bool mAlwaysAllocateNewBuffer;
132
};
131
};
133
132
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_buffer_pool.mm -2 / +9 lines
Lines 250-260 angle::Result BufferPool::allocate(ContextMtl *contextMtl, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_buffer_pool.mm_sec1
250
    return angle::Result::Continue;
250
    return angle::Result::Continue;
251
}
251
}
252
252
253
angle::Result BufferPool::commit(ContextMtl *contextMtl)
253
angle::Result BufferPool::commit(ContextMtl *contextMtl, bool flushEntireBuffer)
254
{
254
{
255
    if (mBuffer && mNextAllocationOffset > mLastFlushOffset)
255
    if (mBuffer && mNextAllocationOffset > mLastFlushOffset)
256
    {
256
    {
257
        mBuffer->flush(contextMtl, mLastFlushOffset, mNextAllocationOffset - mLastFlushOffset);
257
        if (flushEntireBuffer)
258
        {
259
            mBuffer->flush(contextMtl, 0, mLastFlushOffset);
260
        }
261
        else
262
        {
263
            mBuffer->flush(contextMtl, mLastFlushOffset, mNextAllocationOffset - mLastFlushOffset);
264
        }
258
        mLastFlushOffset = mNextAllocationOffset;
265
        mLastFlushOffset = mNextAllocationOffset;
259
    }
266
    }
260
    return angle::Result::Continue;
267
    return angle::Result::Continue;
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.h -8 / +28 lines
Lines 102-108 class CommandBuffer final : public WrappedObject<id<MTLCommandBuffer>>, angle::N a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.h_sec1
102
102
103
    // Return true if command buffer can be encoded into. Return false if it has been committed
103
    // Return true if command buffer can be encoded into. Return false if it has been committed
104
    // and hasn't been restarted.
104
    // and hasn't been restarted.
105
    bool ready() const;
105
    bool valid() const;
106
    void commit();
106
    void commit();
107
    // wait for committed command buffer to finish.
107
    // wait for committed command buffer to finish.
108
    void finish();
108
    void finish();
Lines 115-120 class CommandBuffer final : public WrappedObject<id<MTLCommandBuffer>>, angle::N a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.h_sec2
115
115
116
    void queueEventSignal(const mtl::SharedEventRef &event, uint64_t value);
116
    void queueEventSignal(const mtl::SharedEventRef &event, uint64_t value);
117
    void serverWaitEvent(const mtl::SharedEventRef &event, uint64_t value);
117
    void serverWaitEvent(const mtl::SharedEventRef &event, uint64_t value);
118
119
    void insertDebugSign(const std::string &marker);
118
    void pushDebugGroup(const std::string &marker);
120
    void pushDebugGroup(const std::string &marker);
119
    void popDebugGroup();
121
    void popDebugGroup();
120
122
Lines 128-134 class CommandBuffer final : public WrappedObject<id<MTLCommandBuffer>>, angle::N a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.h_sec3
128
    void set(id<MTLCommandBuffer> metalBuffer);
130
    void set(id<MTLCommandBuffer> metalBuffer);
129
    void cleanup();
131
    void cleanup();
130
132
131
    bool readyImpl() const;
133
    bool validImpl() const;
132
    void commitImpl();
134
    void commitImpl();
133
    void forceEndingCurrentEncoder();
135
    void forceEndingCurrentEncoder();
134
136
Lines 149-154 class CommandBuffer final : public WrappedObject<id<MTLCommandBuffer>>, angle::N a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.h_sec4
149
151
150
    mutable std::mutex mLock;
152
    mutable std::mutex mLock;
151
153
154
    std::vector<std::string> mPendingDebugSigns;
152
    std::vector<std::pair<mtl::SharedEventRef, uint64_t>> mPendingSignalEvents;
155
    std::vector<std::pair<mtl::SharedEventRef, uint64_t>> mPendingSignalEvents;
153
156
154
    std::vector<std::string> mDebugGroups;
157
    std::vector<std::string> mDebugGroups;
Lines 176-181 class CommandEncoder : public WrappedObject<id<MTLCommandEncoder>>, angle::NonCo a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.h_sec5
176
    CommandEncoder &markResourceBeingWrittenByGPU(const BufferRef &buffer);
179
    CommandEncoder &markResourceBeingWrittenByGPU(const BufferRef &buffer);
177
    CommandEncoder &markResourceBeingWrittenByGPU(const TextureRef &texture);
180
    CommandEncoder &markResourceBeingWrittenByGPU(const TextureRef &texture);
178
181
182
    void insertDebugSign(NSString *label);
183
179
    virtual void pushDebugGroup(NSString *label);
184
    virtual void pushDebugGroup(NSString *label);
180
    virtual void popDebugGroup();
185
    virtual void popDebugGroup();
181
186
Lines 189-194 class CommandEncoder : public WrappedObject<id<MTLCommandEncoder>>, angle::NonCo a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.h_sec6
189
194
190
    void set(id<MTLCommandEncoder> metalCmdEncoder);
195
    void set(id<MTLCommandEncoder> metalCmdEncoder);
191
196
197
    virtual void insertDebugSignImpl(NSString *marker);
198
192
  private:
199
  private:
193
    const Type mType;
200
    const Type mType;
194
    CommandBuffer &mCmdBuffer;
201
    CommandBuffer &mCmdBuffer;
Lines 201-207 class IntermediateCommandStream a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.h_sec7
201
    template <typename T>
208
    template <typename T>
202
    inline IntermediateCommandStream &push(const T &val)
209
    inline IntermediateCommandStream &push(const T &val)
203
    {
210
    {
204
        const uint8_t *ptr = reinterpret_cast<const uint8_t *>(&val);
211
        auto ptr = reinterpret_cast<const uint8_t *>(&val);
205
        mBuffer.insert(mBuffer.end(), ptr, ptr + sizeof(T));
212
        mBuffer.insert(mBuffer.end(), ptr, ptr + sizeof(T));
206
        return *this;
213
        return *this;
207
    }
214
    }
Lines 217-223 class IntermediateCommandStream a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.h_sec8
217
    {
224
    {
218
        ASSERT(mReadPtr <= mBuffer.size() - sizeof(T));
225
        ASSERT(mReadPtr <= mBuffer.size() - sizeof(T));
219
        T re;
226
        T re;
220
        uint8_t *ptr = reinterpret_cast<uint8_t *>(&re);
227
        auto ptr = reinterpret_cast<uint8_t *>(&re);
221
        std::copy(mBuffer.data() + mReadPtr, mBuffer.data() + mReadPtr + sizeof(T), ptr);
228
        std::copy(mBuffer.data() + mReadPtr, mBuffer.data() + mReadPtr + sizeof(T), ptr);
222
        return re;
229
        return re;
223
    }
230
    }
Lines 225-231 class IntermediateCommandStream a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.h_sec9
225
    template <typename T>
232
    template <typename T>
226
    inline T fetch()
233
    inline T fetch()
227
    {
234
    {
228
        T re = peek<T>();
235
        auto re = peek<T>();
229
        mReadPtr += sizeof(T);
236
        mReadPtr += sizeof(T);
230
        return re;
237
        return re;
231
    }
238
    }
Lines 233-239 class IntermediateCommandStream a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.h_sec10
233
    inline const uint8_t *fetch(size_t bytes)
240
    inline const uint8_t *fetch(size_t bytes)
234
    {
241
    {
235
        ASSERT(mReadPtr <= mBuffer.size() - bytes);
242
        ASSERT(mReadPtr <= mBuffer.size() - bytes);
236
        size_t cur = mReadPtr;
243
        auto cur = mReadPtr;
237
        mReadPtr += bytes;
244
        mReadPtr += bytes;
238
        return mBuffer.data() + cur;
245
        return mBuffer.data() + cur;
239
    }
246
    }
Lines 479-490 class RenderCommandEncoder final : public CommandEncoder a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.h_sec11
479
    {
486
    {
480
        return static_cast<id<MTLRenderCommandEncoder>>(CommandEncoder::get());
487
        return static_cast<id<MTLRenderCommandEncoder>>(CommandEncoder::get());
481
    }
488
    }
489
    void insertDebugSignImpl(NSString *label) override;
482
490
483
    void initAttachmentWriteDependencyAndScissorRect(const RenderPassAttachmentDesc &attachment);
491
    void initAttachmentWriteDependencyAndScissorRect(const RenderPassAttachmentDesc &attachment);
492
    void initWriteDependency(const TextureRef &texture);
484
493
485
    void finalizeLoadStoreAction(MTLRenderPassAttachmentDescriptor *objCRenderPassAttachment);
494
    void finalizeLoadStoreAction(MTLRenderPassAttachmentDescriptor *objCRenderPassAttachment);
486
495
487
    void encodeMetalEncoder();
496
    void encodeMetalEncoder();
497
    void simulateDiscardFramebuffer();
498
    void endEncodingImpl(bool considerDiscardSimulation);
488
499
489
    RenderCommandEncoder &commonSetBuffer(gl::ShaderType shaderType,
500
    RenderCommandEncoder &commonSetBuffer(gl::ShaderType shaderType,
490
                                          id<MTLBuffer> mtlBuffer,
501
                                          id<MTLBuffer> mtlBuffer,
Lines 560-570 class BlitCommandEncoder final : public CommandEncoder a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.h_sec12
560
                                    uint32_t sliceCount,
571
                                    uint32_t sliceCount,
561
                                    uint32_t levelCount);
572
                                    uint32_t levelCount);
562
573
574
    BlitCommandEncoder &copyTexture(const TextureRef &src,
575
                                    uint32_t srcSlice,
576
                                    uint32_t srcLevel,
577
                                    const TextureRef &dst,
578
                                    uint32_t dstSlice,
579
                                    uint32_t dstLevel,
580
                                    uint32_t sliceCount,
581
                                    uint32_t levelCount);
582
563
    BlitCommandEncoder &fillBuffer(const BufferRef &buffer, NSRange range, uint8_t value);
583
    BlitCommandEncoder &fillBuffer(const BufferRef &buffer, NSRange range, uint8_t value);
564
584
565
    BlitCommandEncoder &generateMipmapsForTexture(const TextureRef &texture);
585
    BlitCommandEncoder &generateMipmapsForTexture(const TextureRef &texture);
566
    BlitCommandEncoder &synchronizeResource(Buffer *bufferPtr);
586
    BlitCommandEncoder &synchronizeResource(const BufferRef &buffer);
567
    BlitCommandEncoder &synchronizeResource(Texture *texturePtr);
587
    BlitCommandEncoder &synchronizeResource(const TextureRef &texture);
568
588
569
  private:
589
  private:
570
    id<MTLBlitCommandEncoder> get()
590
    id<MTLBlitCommandEncoder> get()
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm -194 / +308 lines
Lines 11-16 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec1
11
#include "libANGLE/renderer/metal/mtl_command_buffer.h"
11
#include "libANGLE/renderer/metal/mtl_command_buffer.h"
12
12
13
#include <cassert>
13
#include <cassert>
14
#if ANGLE_MTL_SIMULATE_DISCARD_FRAMEBUFFER
15
#    include <random>
16
#endif
14
17
15
#include "common/debug.h"
18
#include "common/debug.h"
16
#include "libANGLE/renderer/metal/mtl_occlusion_query_pool.h"
19
#include "libANGLE/renderer/metal/mtl_occlusion_query_pool.h"
Lines 65-70 namespace a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec2
65
    PROC(SetVisibilityResultMode)        \
68
    PROC(SetVisibilityResultMode)        \
66
    PROC(UseResource)                    \
69
    PROC(UseResource)                    \
67
    PROC(MemoryBarrierWithResource)      \
70
    PROC(MemoryBarrierWithResource)      \
71
    PROC(InsertDebugsign)                \
68
    PROC(PushDebugGroup)                 \
72
    PROC(PushDebugGroup)                 \
69
    PROC(PopDebugGroup)
73
    PROC(PopDebugGroup)
70
74
Lines 85-126 void InvalidCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream * a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec3
85
void SetRenderPipelineStateCmd(id<MTLRenderCommandEncoder> encoder,
89
void SetRenderPipelineStateCmd(id<MTLRenderCommandEncoder> encoder,
86
                               IntermediateCommandStream *stream)
90
                               IntermediateCommandStream *stream)
87
{
91
{
88
    id<MTLRenderPipelineState> state = stream->fetch<id<MTLRenderPipelineState>>();
92
    auto state = stream->fetch<id<MTLRenderPipelineState>>();
89
    [encoder setRenderPipelineState:state];
93
    [encoder setRenderPipelineState:state];
90
    [state ANGLE_MTL_RELEASE];
94
    [state ANGLE_MTL_RELEASE];
91
}
95
}
92
96
93
void SetTriangleFillModeCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
97
void SetTriangleFillModeCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
94
{
98
{
95
    MTLTriangleFillMode mode = stream->fetch<MTLTriangleFillMode>();
99
    auto mode = stream->fetch<MTLTriangleFillMode>();
96
    [encoder setTriangleFillMode:mode];
100
    [encoder setTriangleFillMode:mode];
97
}
101
}
98
102
99
void SetFrontFacingWindingCmd(id<MTLRenderCommandEncoder> encoder,
103
void SetFrontFacingWindingCmd(id<MTLRenderCommandEncoder> encoder,
100
                              IntermediateCommandStream *stream)
104
                              IntermediateCommandStream *stream)
101
{
105
{
102
    MTLWinding winding = stream->fetch<MTLWinding>();
106
    auto winding = stream->fetch<MTLWinding>();
103
    [encoder setFrontFacingWinding:winding];
107
    [encoder setFrontFacingWinding:winding];
104
}
108
}
105
109
106
void SetCullModeCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
110
void SetCullModeCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
107
{
111
{
108
    MTLCullMode mode = stream->fetch<MTLCullMode>();
112
    auto mode = stream->fetch<MTLCullMode>();
109
    [encoder setCullMode:mode];
113
    [encoder setCullMode:mode];
110
}
114
}
111
115
112
void SetDepthStencilStateCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
116
void SetDepthStencilStateCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
113
{
117
{
114
    id<MTLDepthStencilState> state = stream->fetch<id<MTLDepthStencilState>>();
118
    auto state = stream->fetch<id<MTLDepthStencilState>>();
115
    [encoder setDepthStencilState:state];
119
    [encoder setDepthStencilState:state];
116
    [state ANGLE_MTL_RELEASE];
120
    [state ANGLE_MTL_RELEASE];
117
}
121
}
118
122
119
void SetDepthBiasCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
123
void SetDepthBiasCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
120
{
124
{
121
    float depthBias  = stream->fetch<float>();
125
    auto depthBias  = stream->fetch<float>();
122
    float slopeScale = stream->fetch<float>();
126
    auto slopeScale = stream->fetch<float>();
123
    float clamp      = stream->fetch<float>();
127
    auto clamp      = stream->fetch<float>();
124
    [encoder setDepthBias:depthBias slopeScale:slopeScale clamp:clamp];
128
    [encoder setDepthBias:depthBias slopeScale:slopeScale clamp:clamp];
125
}
129
}
126
130
Lines 134-146 void SetStencilRefValsCmd(id<MTLRenderCommandEncoder> encoder, IntermediateComma a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec4
134
138
135
void SetViewportCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
139
void SetViewportCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
136
{
140
{
137
    MTLViewport viewport = stream->fetch<MTLViewport>();
141
    auto viewport = stream->fetch<MTLViewport>();
138
    [encoder setViewport:viewport];
142
    [encoder setViewport:viewport];
139
}
143
}
140
144
141
void SetScissorRectCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
145
void SetScissorRectCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
142
{
146
{
143
    MTLScissorRect rect = stream->fetch<MTLScissorRect>();
147
    auto rect = stream->fetch<MTLScissorRect>();
144
    [encoder setScissorRect:rect];
148
    [encoder setScissorRect:rect];
145
}
149
}
146
150
Lines 155-163 void SetBlendColorCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec5
155
159
156
void SetVertexBufferCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
160
void SetVertexBufferCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
157
{
161
{
158
    id<MTLBuffer> buffer = stream->fetch<id<MTLBuffer>>();
162
    auto buffer = stream->fetch<id<MTLBuffer>>();
159
    uint32_t offset      = stream->fetch<uint32_t>();
163
    auto offset = stream->fetch<uint32_t>();
160
    uint32_t index       = stream->fetch<uint32_t>();
164
    auto index  = stream->fetch<uint32_t>();
161
    [encoder setVertexBuffer:buffer offset:offset atIndex:index];
165
    [encoder setVertexBuffer:buffer offset:offset atIndex:index];
162
    [buffer ANGLE_MTL_RELEASE];
166
    [buffer ANGLE_MTL_RELEASE];
163
}
167
}
Lines 165-190 void SetVertexBufferCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommand a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec6
165
void SetVertexBufferOffsetCmd(id<MTLRenderCommandEncoder> encoder,
169
void SetVertexBufferOffsetCmd(id<MTLRenderCommandEncoder> encoder,
166
                              IntermediateCommandStream *stream)
170
                              IntermediateCommandStream *stream)
167
{
171
{
168
    uint32_t offset = stream->fetch<uint32_t>();
172
    auto offset = stream->fetch<uint32_t>();
169
    uint32_t index  = stream->fetch<uint32_t>();
173
    auto index  = stream->fetch<uint32_t>();
170
    [encoder setVertexBufferOffset:offset atIndex:index];
174
    [encoder setVertexBufferOffset:offset atIndex:index];
171
}
175
}
172
176
173
void SetVertexBytesCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
177
void SetVertexBytesCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
174
{
178
{
175
    size_t size          = stream->fetch<size_t>();
179
    auto size  = stream->fetch<size_t>();
176
    const uint8_t *bytes = stream->fetch(size);
180
    auto bytes = stream->fetch(size);
177
    uint32_t index       = stream->fetch<uint32_t>();
181
    auto index = stream->fetch<uint32_t>();
178
    [encoder setVertexBytes:bytes length:size atIndex:index];
182
    [encoder setVertexBytes:bytes length:size atIndex:index];
179
}
183
}
180
184
181
void SetVertexSamplerStateCmd(id<MTLRenderCommandEncoder> encoder,
185
void SetVertexSamplerStateCmd(id<MTLRenderCommandEncoder> encoder,
182
                              IntermediateCommandStream *stream)
186
                              IntermediateCommandStream *stream)
183
{
187
{
184
    id<MTLSamplerState> state = stream->fetch<id<MTLSamplerState>>();
188
    auto state        = stream->fetch<id<MTLSamplerState>>();
185
    float lodMinClamp         = stream->fetch<float>();
189
    float lodMinClamp = stream->fetch<float>();
186
    float lodMaxClamp         = stream->fetch<float>();
190
    float lodMaxClamp = stream->fetch<float>();
187
    uint32_t index            = stream->fetch<uint32_t>();
191
    auto index        = stream->fetch<uint32_t>();
188
    [encoder setVertexSamplerState:state
192
    [encoder setVertexSamplerState:state
189
                       lodMinClamp:lodMinClamp
193
                       lodMinClamp:lodMinClamp
190
                       lodMaxClamp:lodMaxClamp
194
                       lodMaxClamp:lodMaxClamp
Lines 195-211 void SetVertexSamplerStateCmd(id<MTLRenderCommandEncoder> encoder, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec7
195
199
196
void SetVertexTextureCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
200
void SetVertexTextureCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
197
{
201
{
198
    id<MTLTexture> texture = stream->fetch<id<MTLTexture>>();
202
    auto texture = stream->fetch<id<MTLTexture>>();
199
    uint32_t index         = stream->fetch<uint32_t>();
203
    auto index   = stream->fetch<uint32_t>();
200
    [encoder setVertexTexture:texture atIndex:index];
204
    [encoder setVertexTexture:texture atIndex:index];
201
    [texture ANGLE_MTL_RELEASE];
205
    [texture ANGLE_MTL_RELEASE];
202
}
206
}
203
207
204
void SetFragmentBufferCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
208
void SetFragmentBufferCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
205
{
209
{
206
    id<MTLBuffer> buffer = stream->fetch<id<MTLBuffer>>();
210
    auto buffer = stream->fetch<id<MTLBuffer>>();
207
    uint32_t offset      = stream->fetch<uint32_t>();
211
    auto offset = stream->fetch<uint32_t>();
208
    uint32_t index       = stream->fetch<uint32_t>();
212
    auto index  = stream->fetch<uint32_t>();
209
    [encoder setFragmentBuffer:buffer offset:offset atIndex:index];
213
    [encoder setFragmentBuffer:buffer offset:offset atIndex:index];
210
    [buffer ANGLE_MTL_RELEASE];
214
    [buffer ANGLE_MTL_RELEASE];
211
}
215
}
Lines 213-238 void SetFragmentBufferCmd(id<MTLRenderCommandEncoder> encoder, IntermediateComma a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec8
213
void SetFragmentBufferOffsetCmd(id<MTLRenderCommandEncoder> encoder,
217
void SetFragmentBufferOffsetCmd(id<MTLRenderCommandEncoder> encoder,
214
                                IntermediateCommandStream *stream)
218
                                IntermediateCommandStream *stream)
215
{
219
{
216
    uint32_t offset = stream->fetch<uint32_t>();
220
    auto offset = stream->fetch<uint32_t>();
217
    uint32_t index  = stream->fetch<uint32_t>();
221
    auto index  = stream->fetch<uint32_t>();
218
    [encoder setFragmentBufferOffset:offset atIndex:index];
222
    [encoder setFragmentBufferOffset:offset atIndex:index];
219
}
223
}
220
224
221
void SetFragmentBytesCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
225
void SetFragmentBytesCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
222
{
226
{
223
    size_t size          = stream->fetch<size_t>();
227
    auto size  = stream->fetch<size_t>();
224
    const uint8_t *bytes = stream->fetch(size);
228
    auto bytes = stream->fetch(size);
225
    uint32_t index       = stream->fetch<uint32_t>();
229
    auto index = stream->fetch<uint32_t>();
226
    [encoder setFragmentBytes:bytes length:size atIndex:index];
230
    [encoder setFragmentBytes:bytes length:size atIndex:index];
227
}
231
}
228
232
229
void SetFragmentSamplerStateCmd(id<MTLRenderCommandEncoder> encoder,
233
void SetFragmentSamplerStateCmd(id<MTLRenderCommandEncoder> encoder,
230
                                IntermediateCommandStream *stream)
234
                                IntermediateCommandStream *stream)
231
{
235
{
232
    id<MTLSamplerState> state = stream->fetch<id<MTLSamplerState>>();
236
    auto state        = stream->fetch<id<MTLSamplerState>>();
233
    float lodMinClamp         = stream->fetch<float>();
237
    float lodMinClamp = stream->fetch<float>();
234
    float lodMaxClamp         = stream->fetch<float>();
238
    float lodMaxClamp = stream->fetch<float>();
235
    uint32_t index            = stream->fetch<uint32_t>();
239
    auto index        = stream->fetch<uint32_t>();
236
    [encoder setFragmentSamplerState:state
240
    [encoder setFragmentSamplerState:state
237
                         lodMinClamp:lodMinClamp
241
                         lodMinClamp:lodMinClamp
238
                         lodMaxClamp:lodMaxClamp
242
                         lodMaxClamp:lodMaxClamp
Lines 242-267 void SetFragmentSamplerStateCmd(id<MTLRenderCommandEncoder> encoder, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec9
242
246
243
void SetFragmentTextureCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
247
void SetFragmentTextureCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
244
{
248
{
245
    id<MTLTexture> texture = stream->fetch<id<MTLTexture>>();
249
    auto texture = stream->fetch<id<MTLTexture>>();
246
    uint32_t index         = stream->fetch<uint32_t>();
250
    auto index   = stream->fetch<uint32_t>();
247
    [encoder setFragmentTexture:texture atIndex:index];
251
    [encoder setFragmentTexture:texture atIndex:index];
248
    [texture ANGLE_MTL_RELEASE];
252
    [texture ANGLE_MTL_RELEASE];
249
}
253
}
250
254
251
void DrawCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
255
void DrawCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
252
{
256
{
253
    MTLPrimitiveType primitiveType = stream->fetch<MTLPrimitiveType>();
257
    auto primitiveType = stream->fetch<MTLPrimitiveType>();
254
    uint32_t vertexStart           = stream->fetch<uint32_t>();
258
    auto vertexStart   = stream->fetch<uint32_t>();
255
    uint32_t vertexCount           = stream->fetch<uint32_t>();
259
    auto vertexCount   = stream->fetch<uint32_t>();
256
    [encoder drawPrimitives:primitiveType vertexStart:vertexStart vertexCount:vertexCount];
260
    [encoder drawPrimitives:primitiveType vertexStart:vertexStart vertexCount:vertexCount];
257
}
261
}
258
262
259
void DrawInstancedCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
263
void DrawInstancedCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
260
{
264
{
261
    MTLPrimitiveType primitiveType = stream->fetch<MTLPrimitiveType>();
265
    auto primitiveType = stream->fetch<MTLPrimitiveType>();
262
    uint32_t vertexStart           = stream->fetch<uint32_t>();
266
    auto vertexStart   = stream->fetch<uint32_t>();
263
    uint32_t vertexCount           = stream->fetch<uint32_t>();
267
    auto vertexCount   = stream->fetch<uint32_t>();
264
    uint32_t instances             = stream->fetch<uint32_t>();
268
    auto instances     = stream->fetch<uint32_t>();
265
    [encoder drawPrimitives:primitiveType
269
    [encoder drawPrimitives:primitiveType
266
                vertexStart:vertexStart
270
                vertexStart:vertexStart
267
                vertexCount:vertexCount
271
                vertexCount:vertexCount
Lines 270-280 void DrawInstancedCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandSt a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec10
270
274
271
void DrawIndexedCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
275
void DrawIndexedCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
272
{
276
{
273
    MTLPrimitiveType primitiveType = stream->fetch<MTLPrimitiveType>();
277
    auto primitiveType = stream->fetch<MTLPrimitiveType>();
274
    uint32_t indexCount            = stream->fetch<uint32_t>();
278
    auto indexCount    = stream->fetch<uint32_t>();
275
    MTLIndexType indexType         = stream->fetch<MTLIndexType>();
279
    auto indexType     = stream->fetch<MTLIndexType>();
276
    id<MTLBuffer> indexBuffer      = stream->fetch<id<MTLBuffer>>();
280
    auto indexBuffer   = stream->fetch<id<MTLBuffer>>();
277
    size_t bufferOffset            = stream->fetch<size_t>();
281
    auto bufferOffset  = stream->fetch<size_t>();
278
    [encoder drawIndexedPrimitives:primitiveType
282
    [encoder drawIndexedPrimitives:primitiveType
279
                        indexCount:indexCount
283
                        indexCount:indexCount
280
                         indexType:indexType
284
                         indexType:indexType
Lines 285-296 void DrawIndexedCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStre a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec11
285
289
286
void DrawIndexedInstancedCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
290
void DrawIndexedInstancedCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
287
{
291
{
288
    MTLPrimitiveType primitiveType = stream->fetch<MTLPrimitiveType>();
292
    auto primitiveType = stream->fetch<MTLPrimitiveType>();
289
    uint32_t indexCount            = stream->fetch<uint32_t>();
293
    auto indexCount    = stream->fetch<uint32_t>();
290
    MTLIndexType indexType         = stream->fetch<MTLIndexType>();
294
    auto indexType     = stream->fetch<MTLIndexType>();
291
    id<MTLBuffer> indexBuffer      = stream->fetch<id<MTLBuffer>>();
295
    auto indexBuffer   = stream->fetch<id<MTLBuffer>>();
292
    size_t bufferOffset            = stream->fetch<size_t>();
296
    auto bufferOffset  = stream->fetch<size_t>();
293
    uint32_t instances             = stream->fetch<uint32_t>();
297
    auto instances     = stream->fetch<uint32_t>();
294
    [encoder drawIndexedPrimitives:primitiveType
298
    [encoder drawIndexedPrimitives:primitiveType
295
                        indexCount:indexCount
299
                        indexCount:indexCount
296
                         indexType:indexType
300
                         indexType:indexType
Lines 303-315 void DrawIndexedInstancedCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCo a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec12
303
void DrawIndexedInstancedBaseVertexCmd(id<MTLRenderCommandEncoder> encoder,
307
void DrawIndexedInstancedBaseVertexCmd(id<MTLRenderCommandEncoder> encoder,
304
                                       IntermediateCommandStream *stream)
308
                                       IntermediateCommandStream *stream)
305
{
309
{
306
    MTLPrimitiveType primitiveType = stream->fetch<MTLPrimitiveType>();
310
    auto primitiveType = stream->fetch<MTLPrimitiveType>();
307
    uint32_t indexCount            = stream->fetch<uint32_t>();
311
    auto indexCount    = stream->fetch<uint32_t>();
308
    MTLIndexType indexType         = stream->fetch<MTLIndexType>();
312
    auto indexType     = stream->fetch<MTLIndexType>();
309
    id<MTLBuffer> indexBuffer      = stream->fetch<id<MTLBuffer>>();
313
    auto indexBuffer   = stream->fetch<id<MTLBuffer>>();
310
    size_t bufferOffset            = stream->fetch<size_t>();
314
    auto bufferOffset  = stream->fetch<size_t>();
311
    uint32_t instances             = stream->fetch<uint32_t>();
315
    auto instances     = stream->fetch<uint32_t>();
312
    uint32_t baseVertex            = stream->fetch<uint32_t>();
316
    auto baseVertex    = stream->fetch<uint32_t>();
313
    [encoder drawIndexedPrimitives:primitiveType
317
    [encoder drawIndexedPrimitives:primitiveType
314
                        indexCount:indexCount
318
                        indexCount:indexCount
315
                         indexType:indexType
319
                         indexType:indexType
Lines 324-339 void DrawIndexedInstancedBaseVertexCmd(id<MTLRenderCommandEncoder> encoder, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec13
324
void SetVisibilityResultModeCmd(id<MTLRenderCommandEncoder> encoder,
328
void SetVisibilityResultModeCmd(id<MTLRenderCommandEncoder> encoder,
325
                                IntermediateCommandStream *stream)
329
                                IntermediateCommandStream *stream)
326
{
330
{
327
    MTLVisibilityResultMode mode = stream->fetch<MTLVisibilityResultMode>();
331
    auto mode   = stream->fetch<MTLVisibilityResultMode>();
328
    size_t offset                = stream->fetch<size_t>();
332
    auto offset = stream->fetch<size_t>();
329
    [encoder setVisibilityResultMode:mode offset:offset];
333
    [encoder setVisibilityResultMode:mode offset:offset];
330
}
334
}
331
335
332
void UseResourceCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
336
void UseResourceCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
333
{
337
{
334
    id<MTLResource> resource = stream->fetch<id<MTLResource>>();
338
    auto resource = stream->fetch<id<MTLResource>>();
335
    MTLResourceUsage usage   = stream->fetch<MTLResourceUsage>();
339
    auto usage    = stream->fetch<MTLResourceUsage>();
336
    mtl::RenderStages stages = stream->fetch<mtl::RenderStages>();
340
    auto stages   = stream->fetch<mtl::RenderStages>();
337
    ANGLE_UNUSED_VARIABLE(stages);
341
    ANGLE_UNUSED_VARIABLE(stages);
338
#if defined(__IPHONE_13_0) || defined(__MAC_10_15)
342
#if defined(__IPHONE_13_0) || defined(__MAC_10_15)
339
    if (ANGLE_APPLE_AVAILABLE_XCI(10.15, 13.0, 13.0))
343
    if (ANGLE_APPLE_AVAILABLE_XCI(10.15, 13.0, 13.0))
Lines 351-359 void UseResourceCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStre a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec14
351
void MemoryBarrierWithResourceCmd(id<MTLRenderCommandEncoder> encoder,
355
void MemoryBarrierWithResourceCmd(id<MTLRenderCommandEncoder> encoder,
352
                                  IntermediateCommandStream *stream)
356
                                  IntermediateCommandStream *stream)
353
{
357
{
354
    id<MTLResource> resource = stream->fetch<id<MTLResource>>();
358
    auto resource = stream->fetch<id<MTLResource>>();
355
    mtl::RenderStages after  = stream->fetch<mtl::RenderStages>();
359
    auto after    = stream->fetch<mtl::RenderStages>();
356
    mtl::RenderStages before = stream->fetch<mtl::RenderStages>();
360
    auto before   = stream->fetch<mtl::RenderStages>();
357
    ANGLE_UNUSED_VARIABLE(after);
361
    ANGLE_UNUSED_VARIABLE(after);
358
    ANGLE_UNUSED_VARIABLE(before);
362
    ANGLE_UNUSED_VARIABLE(before);
359
#if defined(__MAC_10_14) && (TARGET_OS_OSX || TARGET_OS_MACCATALYST)
363
#if defined(__MAC_10_14) && (TARGET_OS_OSX || TARGET_OS_MACCATALYST)
Lines 368-376 void MemoryBarrierWithResourceCmd(id<MTLRenderCommandEncoder> encoder, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec15
368
    [resource ANGLE_MTL_RELEASE];
372
    [resource ANGLE_MTL_RELEASE];
369
}
373
}
370
374
375
void InsertDebugsignCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
376
{
377
    auto label = stream->fetch<NSString *>();
378
    [encoder insertDebugSignpost:label];
379
    [label ANGLE_MTL_RELEASE];
380
}
381
371
void PushDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
382
void PushDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
372
{
383
{
373
    NSString *label = stream->fetch<NSString *>();
384
    auto label = stream->fetch<NSString *>();
374
    [encoder pushDebugGroup:label];
385
    [encoder pushDebugGroup:label];
375
    [label ANGLE_MTL_RELEASE];
386
    [label ANGLE_MTL_RELEASE];
376
}
387
}
Lines 388-394 constexpr CommandEncoderFunc gCommandEncoders[] = {ANGLE_MTL_CMD_X(ANGLE_MTL_CMD a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec16
388
399
389
NSString *cppLabelToObjC(const std::string &marker)
400
NSString *cppLabelToObjC(const std::string &marker)
390
{
401
{
391
    NSString *label = [NSString stringWithUTF8String:marker.c_str()];
402
    auto label = [NSString stringWithUTF8String:marker.c_str()];
392
    if (!label)
403
    if (!label)
393
    {
404
    {
394
        // This can happen if the string is not a valid ascii string.
405
        // This can happen if the string is not a valid ascii string.
Lines 396-402 NSString *cppLabelToObjC(const std::string &marker) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec17
396
    }
407
    }
397
    return label;
408
    return label;
398
}
409
}
399
400
}
410
}
401
411
402
// CommandQueue implementation
412
// CommandQueue implementation
Lines 565-575 CommandBuffer::~CommandBuffer() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec18
565
    cleanup();
575
    cleanup();
566
}
576
}
567
577
568
bool CommandBuffer::ready() const
578
bool CommandBuffer::valid() const
569
{
579
{
570
    std::lock_guard<std::mutex> lg(mLock);
580
    std::lock_guard<std::mutex> lg(mLock);
571
581
572
    return readyImpl();
582
    return validImpl();
573
}
583
}
574
584
575
void CommandBuffer::commit()
585
void CommandBuffer::commit()
Lines 598-604 void CommandBuffer::setWriteDependency(const ResourceRef &resource) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec19
598
608
599
    std::lock_guard<std::mutex> lg(mLock);
609
    std::lock_guard<std::mutex> lg(mLock);
600
610
601
    if (!readyImpl())
611
    if (!validImpl())
602
    {
612
    {
603
        return;
613
        return;
604
    }
614
    }
Lines 620-626 void CommandBuffer::setReadDependency(Resource *resource) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec20
620
630
621
    std::lock_guard<std::mutex> lg(mLock);
631
    std::lock_guard<std::mutex> lg(mLock);
622
632
623
    if (!readyImpl())
633
    if (!validImpl())
624
    {
634
    {
625
        return;
635
        return;
626
    }
636
    }
Lines 647-703 void CommandBuffer::restart() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec21
647
    ASSERT(metalCmdBuffer);
657
    ASSERT(metalCmdBuffer);
648
}
658
}
649
659
650
void CommandBuffer::queueEventSignal(const mtl::SharedEventRef &event, uint64_t value)
660
void CommandBuffer::insertDebugSign(const std::string &marker)
651
{
661
{
652
    std::lock_guard<std::mutex> lg(mLock);
662
    mtl::CommandEncoder *currentEncoder = mActiveCommandEncoder;
653
663
    if (currentEncoder)
654
    ASSERT(readyImpl());
655
656
    if (mActiveCommandEncoder && mActiveCommandEncoder->getType() == CommandEncoder::RENDER)
657
    {
664
    {
658
        // We cannot set event when there is an active render pass, defer the setting until the
665
        ANGLE_MTL_OBJC_SCOPE
659
        // pass end.
666
        {
660
        mPendingSignalEvents.push_back({event, value});
667
            auto label = cppLabelToObjC(marker);
668
            currentEncoder->insertDebugSign(label);
669
        }
661
    }
670
    }
662
    else
671
    else
663
    {
672
    {
664
        setEventImpl(event, value);
673
        mPendingDebugSigns.push_back(marker);
665
    }
674
    }
666
}
675
}
667
676
668
void CommandBuffer::serverWaitEvent(const mtl::SharedEventRef &event, uint64_t value)
677
void CommandBuffer::pushDebugGroup(const std::string &marker)
669
{
678
{
670
    std::lock_guard<std::mutex> lg(mLock);
679
    // NOTE(hqle): to implement this
671
    ASSERT(readyImpl());
672
673
    waitEventImpl(event, value);
674
}
680
}
675
681
676
void CommandBuffer::pushDebugGroup(const std::string &marker)
682
void CommandBuffer::popDebugGroup()
677
{
683
{
678
    mDebugGroups.push_back(marker);
684
    // NOTE(hqle): to implement this
685
}
679
686
687
void CommandBuffer::queueEventSignal(const mtl::SharedEventRef &event, uint64_t value)
688
{
680
    std::lock_guard<std::mutex> lg(mLock);
689
    std::lock_guard<std::mutex> lg(mLock);
681
690
682
    if (readyImpl())
691
    ASSERT(validImpl());
692
693
    if (mActiveCommandEncoder && mActiveCommandEncoder->getType() == CommandEncoder::RENDER)
683
    {
694
    {
684
        pushDebugGroupImpl(marker);
695
        // We cannot set event when there is an active render pass, defer the setting until the
696
        // pass end.
697
        mPendingSignalEvents.push_back({event, value});
685
    }
698
    }
686
}
699
    else
687
688
void CommandBuffer::popDebugGroup()
689
{
690
    if (!mDebugGroups.empty())
691
    {
700
    {
692
        mDebugGroups.pop_back();
701
        setEventImpl(event, value);
693
    }
702
    }
703
}
694
704
705
void CommandBuffer::serverWaitEvent(const mtl::SharedEventRef &event, uint64_t value)
706
{
695
    std::lock_guard<std::mutex> lg(mLock);
707
    std::lock_guard<std::mutex> lg(mLock);
708
    ASSERT(validImpl());
696
709
697
    if (readyImpl())
710
    waitEventImpl(event, value);
698
    {
699
        return;
700
    }
701
}
711
}
702
712
703
/** private use only */
713
/** private use only */
Lines 709-714 void CommandBuffer::set(id<MTLCommandBuffer> metalBuffer) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec22
709
void CommandBuffer::setActiveCommandEncoder(CommandEncoder *encoder)
719
void CommandBuffer::setActiveCommandEncoder(CommandEncoder *encoder)
710
{
720
{
711
    mActiveCommandEncoder = encoder;
721
    mActiveCommandEncoder = encoder;
722
    for (auto &marker : mPendingDebugSigns)
723
    {
724
        ANGLE_MTL_OBJC_SCOPE
725
        {
726
            auto label = cppLabelToObjC(marker);
727
            encoder->insertDebugSign(label);
728
        }
729
    }
730
    mPendingDebugSigns.clear();
712
}
731
}
713
732
714
void CommandBuffer::invalidateActiveCommandEncoder(CommandEncoder *encoder)
733
void CommandBuffer::invalidateActiveCommandEncoder(CommandEncoder *encoder)
Lines 729-735 void CommandBuffer::cleanup() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec23
729
    ParentClass::set(nil);
748
    ParentClass::set(nil);
730
}
749
}
731
750
732
bool CommandBuffer::readyImpl() const
751
bool CommandBuffer::validImpl() const
733
{
752
{
734
    if (!ParentClass::valid())
753
    if (!ParentClass::valid())
735
    {
754
    {
Lines 741-747 bool CommandBuffer::readyImpl() const a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec24
741
760
742
void CommandBuffer::commitImpl()
761
void CommandBuffer::commitImpl()
743
{
762
{
744
    if (!readyImpl())
763
    if (!validImpl())
745
    {
764
    {
746
        return;
765
        return;
747
    }
766
    }
Lines 889-894 void CommandEncoder::popDebugGroup() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec25
889
    [get() popDebugGroup];
908
    [get() popDebugGroup];
890
}
909
}
891
910
911
void CommandEncoder::insertDebugSign(NSString *label)
912
{
913
    insertDebugSignImpl(label);
914
}
915
916
void CommandEncoder::insertDebugSignImpl(NSString *label)
917
{
918
    // Default implementation
919
    [get() insertDebugSignpost:label];
920
}
921
892
// RenderCommandEncoderShaderStates implementation
922
// RenderCommandEncoderShaderStates implementation
893
RenderCommandEncoderShaderStates::RenderCommandEncoderShaderStates()
923
RenderCommandEncoderShaderStates::RenderCommandEncoderShaderStates()
894
{
924
{
Lines 951-956 void RenderCommandEncoderStates::reset() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec26
951
    {
981
    {
952
        shaderStates.reset();
982
        shaderStates.reset();
953
    }
983
    }
984
985
    visibilityResultMode         = MTLVisibilityResultModeDisabled;
986
    visibilityResultBufferOffset = 0;
954
}
987
}
955
988
956
// RenderCommandEncoder implemtation
989
// RenderCommandEncoder implemtation
Lines 1014-1024 void RenderCommandEncoder::finalizeLoadStoreAction( a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec27
1014
    {
1047
    {
1015
        if (objCRenderPassAttachment.storeAction == MTLStoreActionStore)
1048
        if (objCRenderPassAttachment.storeAction == MTLStoreActionStore)
1016
        {
1049
        {
1017
            // NOTE(hqle): Currently if the store action with implicit MS texture is
1050
            // NOTE(hqle): Currently if the store action with implicit MS texture is MTLStoreAction,
1018
            // MTLStoreActionStore, it is automatically convert to store and resolve action. It
1051
            // it is automatically convert to store and resolve action. It might introduce
1019
            // might introduce unnecessary overhead. Consider an improvement such as only store the
1052
            // unnecessary overhead.
1020
            // MS texture, and resolve only at the end of real render pass (not render pass the is
1053
            // Consider an improvement such as only store the MS texture, and resolve only at
1021
            // interrupted by compute pass) or before glBlitFramebuffer operation starts.
1054
            // the end of real render pass (not render pass the was interrupted by compute pass)
1055
            // or before glBlitFramebuffer operation starts.
1022
            objCRenderPassAttachment.storeAction = MTLStoreActionStoreAndMultisampleResolve;
1056
            objCRenderPassAttachment.storeAction = MTLStoreActionStoreAndMultisampleResolve;
1023
        }
1057
        }
1024
        else if (objCRenderPassAttachment.storeAction == MTLStoreActionDontCare)
1058
        else if (objCRenderPassAttachment.storeAction == MTLStoreActionDontCare)
Lines 1036-1041 void RenderCommandEncoder::finalizeLoadStoreAction( a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec28
1036
}
1070
}
1037
1071
1038
void RenderCommandEncoder::endEncoding()
1072
void RenderCommandEncoder::endEncoding()
1073
{
1074
    endEncodingImpl(true);
1075
}
1076
1077
void RenderCommandEncoder::endEncodingImpl(bool considerDiscardSimulation)
1039
{
1078
{
1040
    if (!valid())
1079
    if (!valid())
1041
        return;
1080
        return;
Lines 1050-1060 void RenderCommandEncoder::endEncoding() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec29
1050
        finalizeLoadStoreAction(objCRenderPassDesc.colorAttachments[i]);
1089
        finalizeLoadStoreAction(objCRenderPassDesc.colorAttachments[i]);
1051
    }
1090
    }
1052
1091
1053
    // Update depth store action set between restart() and endEncoding()
1092
    // Update store action set between restart() and endEncoding()
1054
    objCRenderPassDesc.depthAttachment.storeAction = mRenderPassDesc.depthAttachment.storeAction;
1093
    objCRenderPassDesc.depthAttachment.storeAction = mRenderPassDesc.depthAttachment.storeAction;
1055
    finalizeLoadStoreAction(objCRenderPassDesc.depthAttachment);
1094
    finalizeLoadStoreAction(objCRenderPassDesc.depthAttachment);
1056
1095
1057
    // Update stencil store action set between restart() and endEncoding()
1096
    // Update store action set between restart() and endEncoding()
1058
    objCRenderPassDesc.stencilAttachment.storeAction =
1097
    objCRenderPassDesc.stencilAttachment.storeAction =
1059
        mRenderPassDesc.stencilAttachment.storeAction;
1098
        mRenderPassDesc.stencilAttachment.storeAction;
1060
    finalizeLoadStoreAction(objCRenderPassDesc.stencilAttachment);
1099
    finalizeLoadStoreAction(objCRenderPassDesc.stencilAttachment);
Lines 1075-1100 void RenderCommandEncoder::endEncoding() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec30
1075
1114
1076
    CommandEncoder::endEncoding();
1115
    CommandEncoder::endEncoding();
1077
1116
1117
#if ANGLE_MTL_SIMULATE_DISCARD_FRAMEBUFFER
1118
    if (considerDiscardSimulation)
1119
    {
1120
        simulateDiscardFramebuffer();
1121
    }
1122
#endif
1123
1078
    // reset state
1124
    // reset state
1079
    mRenderPassDesc = RenderPassDesc();
1125
    mRenderPassDesc = RenderPassDesc();
1080
    mStateCache.reset();
1126
    mStateCache.reset();
1081
}
1127
}
1082
1128
1083
inline void RenderCommandEncoder::initAttachmentWriteDependencyAndScissorRect(
1129
inline void RenderCommandEncoder::initWriteDependency(const TextureRef &texture)
1084
    const RenderPassAttachmentDesc &attachment)
1085
{
1130
{
1086
    TextureRef texture = attachment.texture;
1087
    if (texture)
1131
    if (texture)
1088
    {
1132
    {
1089
        cmdBuffer().setWriteDependency(texture);
1133
        cmdBuffer().setWriteDependency(texture);
1134
    }
1135
}
1090
1136
1091
        const MipmapNativeLevel &mipLevel = attachment.level;
1137
void RenderCommandEncoder::simulateDiscardFramebuffer()
1138
{
1139
    // Simulate true framebuffer discard operation by clearing the framebuffer
1140
#if ANGLE_MTL_SIMULATE_DISCARD_FRAMEBUFFER
1141
    std::random_device rd;   // Will be used to obtain a seed for the random number engine
1142
    std::mt19937 gen(rd());  // Standard mersenne_twister_engine seeded with rd()
1143
    std::uniform_real_distribution<float> dis(0.0, 1.0f);
1144
    bool hasDiscard = false;
1145
    for (uint32_t i = 0; i < mRenderPassDesc.numColorAttachments; ++i)
1146
    {
1147
        if (mRenderPassDesc.colorAttachments[i].storeAction == MTLStoreActionDontCare)
1148
        {
1149
            hasDiscard                                     = true;
1150
            mRenderPassDesc.colorAttachments[i].loadAction = MTLLoadActionClear;
1151
            mRenderPassDesc.colorAttachments[i].clearColor =
1152
                MTLClearColorMake(dis(gen), dis(gen), dis(gen), dis(gen));
1153
        }
1154
        else
1155
        {
1156
            mRenderPassDesc.colorAttachments[i].loadAction = MTLLoadActionLoad;
1157
        }
1158
    }
1092
1159
1093
        mRenderPassMaxScissorRect.width =
1160
    if (mRenderPassDesc.depthAttachment.storeAction == MTLStoreActionDontCare)
1094
            std::min<NSUInteger>(mRenderPassMaxScissorRect.width, texture->width(mipLevel));
1161
    {
1095
        mRenderPassMaxScissorRect.height =
1162
        hasDiscard                                 = true;
1096
            std::min<NSUInteger>(mRenderPassMaxScissorRect.height, texture->height(mipLevel));
1163
        mRenderPassDesc.depthAttachment.loadAction = MTLLoadActionClear;
1164
        mRenderPassDesc.depthAttachment.clearDepth = dis(gen);
1165
    }
1166
    else
1167
    {
1168
        mRenderPassDesc.depthAttachment.loadAction = MTLLoadActionLoad;
1169
    }
1170
1171
    if (mRenderPassDesc.stencilAttachment.storeAction == MTLStoreActionDontCare)
1172
    {
1173
        hasDiscard                                     = true;
1174
        mRenderPassDesc.stencilAttachment.loadAction   = MTLLoadActionClear;
1175
        mRenderPassDesc.stencilAttachment.clearStencil = rand();
1176
    }
1177
    else
1178
    {
1179
        mRenderPassDesc.stencilAttachment.loadAction = MTLLoadActionLoad;
1097
    }
1180
    }
1181
1182
    if (hasDiscard)
1183
    {
1184
        auto tmpDesc = mRenderPassDesc;
1185
        restart(tmpDesc);
1186
        endEncodingImpl(false);
1187
    }
1188
#endif  // ANGLE_MTL_SIMULATE_DISCARD_FRAMEBUFFER
1098
}
1189
}
1099
1190
1100
void RenderCommandEncoder::encodeMetalEncoder()
1191
void RenderCommandEncoder::encodeMetalEncoder()
Lines 1102-1108 void RenderCommandEncoder::encodeMetalEncoder() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec31
1102
    ANGLE_MTL_OBJC_SCOPE
1193
    ANGLE_MTL_OBJC_SCOPE
1103
    {
1194
    {
1104
        ANGLE_MTL_LOG("Creating new render command encoder with desc: %@",
1195
        ANGLE_MTL_LOG("Creating new render command encoder with desc: %@",
1105
                      mCachedRenderPassDescObjC.get());
1196
                      [mCachedRenderPassDescObjC description]);
1106
1197
1107
        id<MTLRenderCommandEncoder> metalCmdEncoder =
1198
        id<MTLRenderCommandEncoder> metalCmdEncoder =
1108
            [cmdBuffer().get() renderCommandEncoderWithDescriptor:mCachedRenderPassDescObjC];
1199
            [cmdBuffer().get() renderCommandEncoderWithDescriptor:mCachedRenderPassDescObjC];
Lines 1110-1116 void RenderCommandEncoder::encodeMetalEncoder() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec32
1110
        set(metalCmdEncoder);
1201
        set(metalCmdEncoder);
1111
1202
1112
        // Verify that it was created successfully
1203
        // Verify that it was created successfully
1113
        ASSERT(metalCmdEncoder);
1204
        ASSERT(get());
1205
1206
        // Work-around driver bug on iOS devices: stencil must be explicitly set to zero
1207
        // even if the doc says the default value is already zero.
1208
        [metalCmdEncoder setStencilReferenceValue:0];
1114
1209
1115
        if (mLabel)
1210
        if (mLabel)
1116
        {
1211
        {
Lines 1119-1125 void RenderCommandEncoder::encodeMetalEncoder() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec33
1119
1214
1120
        while (mCommands.good())
1215
        while (mCommands.good())
1121
        {
1216
        {
1122
            CmdType cmdType            = mCommands.fetch<CmdType>();
1217
            auto cmdType               = mCommands.fetch<CmdType>();
1123
            CommandEncoderFunc encoder = gCommandEncoders[static_cast<int>(cmdType)];
1218
            CommandEncoderFunc encoder = gCommandEncoders[static_cast<int>(cmdType)];
1124
            encoder(metalCmdEncoder, &mCommands);
1219
            encoder(metalCmdEncoder, &mCommands);
1125
        }
1220
        }
Lines 1142-1182 RenderCommandEncoder &RenderCommandEncoder::restart(const RenderPassDesc &desc) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec34
1142
        endEncoding();
1237
        endEncoding();
1143
    }
1238
    }
1144
1239
1145
    if (!cmdBuffer().ready())
1240
    if (!cmdBuffer().valid())
1146
    {
1241
    {
1147
        reset();
1242
        reset();
1148
        return *this;
1243
        return *this;
1149
    }
1244
    }
1150
1245
1151
    mLabel.reset();
1246
    mRenderPassDesc = desc;
1247
    mRecording      = true;
1248
    mHasDrawCalls   = false;
1152
1249
1153
    mRenderPassDesc           = desc;
1250
    // mask writing dependency & set appropriate store options
1154
    mRecording                = true;
1155
    mHasDrawCalls             = false;
1156
    mRenderPassMaxScissorRect = {.x      = 0,
1157
                                 .y      = 0,
1158
                                 .width  = std::numeric_limits<NSUInteger>::max(),
1159
                                 .height = std::numeric_limits<NSUInteger>::max()};
1160
1161
    // Set writing dependency & constrain the scissor rect
1162
    for (uint32_t i = 0; i < mRenderPassDesc.numColorAttachments; ++i)
1251
    for (uint32_t i = 0; i < mRenderPassDesc.numColorAttachments; ++i)
1163
    {
1252
    {
1164
        initAttachmentWriteDependencyAndScissorRect(mRenderPassDesc.colorAttachments[i]);
1253
        initWriteDependency(mRenderPassDesc.colorAttachments[i].texture());
1165
    }
1254
    }
1166
1255
1167
    initAttachmentWriteDependencyAndScissorRect(mRenderPassDesc.depthAttachment);
1256
    initWriteDependency(mRenderPassDesc.depthAttachment.texture());
1168
1257
1169
    initAttachmentWriteDependencyAndScissorRect(mRenderPassDesc.stencilAttachment);
1258
    initWriteDependency(mRenderPassDesc.stencilAttachment.texture());
1170
1259
1171
    // Convert to Objective-C descriptor
1260
    // Convert to Objective-C descriptor
1172
    mRenderPassDesc.convertToMetalDesc(mCachedRenderPassDescObjC);
1261
    mRenderPassDesc.convertToMetalDesc(mCachedRenderPassDescObjC);
1173
1262
1174
    // The actual Objective-C encoder will be created later in endEncoding(), we do so in
1263
    // The actual Objective-C encoder will be created later in endEncoding(), we do so in order
1175
    // order to be able to sort the commands or do the preprocessing before the actual
1264
    // to be able to sort the commands or do the preprocessing before the actual encoding.
1176
    // encoding.
1177
1265
1178
    // Since we defer the native encoder creation, we need to explicitly tell command buffer
1266
    // Since we defer the native encoder creation, we need to explicitly tell command buffer that
1179
    // that this object is the active encoder:
1267
    // this object is the active encoder:
1180
    cmdBuffer().setActiveCommandEncoder(this);
1268
    cmdBuffer().setActiveCommandEncoder(this);
1181
1269
1182
    return *this;
1270
    return *this;
Lines 1302-1317 RenderCommandEncoder &RenderCommandEncoder::setScissorRect(const MTLScissorRect a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec35
1302
    {
1390
    {
1303
        return *this;
1391
        return *this;
1304
    }
1392
    }
1305
1306
    if (ANGLE_UNLIKELY(rect.x + rect.width > mRenderPassMaxScissorRect.width ||
1307
                       rect.y + rect.height > mRenderPassMaxScissorRect.height))
1308
    {
1309
        WARN() << "Out of bound scissor rect detected " << rect.x << " " << rect.y << " "
1310
               << rect.width << " " << rect.height;
1311
        // Out of bound rect will crash the metal runtime, ignore it.
1312
        return *this;
1313
    }
1314
1315
    mStateCache.scissorRect = rect;
1393
    mStateCache.scissorRect = rect;
1316
1394
1317
    mCommands.push(CmdType::SetScissorRect).push(rect);
1395
    mCommands.push(CmdType::SetScissorRect).push(rect);
Lines 1383-1389 RenderCommandEncoder &RenderCommandEncoder::commonSetBuffer(gl::ShaderType shade a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec36
1383
            return *this;
1461
            return *this;
1384
        }
1462
        }
1385
1463
1386
        // If buffer already bound but with different offset, then update the offset only.
1464
        // If buffer already bound but with different offset, then update the offer only.
1387
        shaderStates.bufferOffsets[index] = offset;
1465
        shaderStates.bufferOffsets[index] = offset;
1388
1466
1389
        mCommands.push(static_cast<CmdType>(mSetBufferOffsetCmds[shaderType]))
1467
        mCommands.push(static_cast<CmdType>(mSetBufferOffsetCmds[shaderType]))
Lines 1490-1501 RenderCommandEncoder &RenderCommandEncoder::draw(MTLPrimitiveType primitiveType, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec37
1490
                                                 uint32_t vertexStart,
1568
                                                 uint32_t vertexStart,
1491
                                                 uint32_t vertexCount)
1569
                                                 uint32_t vertexCount)
1492
{
1570
{
1493
    if (ANGLE_UNLIKELY(!mStateCache.renderPipeline))
1494
    {
1495
        // Ignore draw call if there is no render pipeline state set prior to this.
1496
        return *this;
1497
    }
1498
1499
    mHasDrawCalls = true;
1571
    mHasDrawCalls = true;
1500
    mCommands.push(CmdType::Draw).push(primitiveType).push(vertexStart).push(vertexCount);
1572
    mCommands.push(CmdType::Draw).push(primitiveType).push(vertexStart).push(vertexCount);
1501
1573
Lines 1507-1518 RenderCommandEncoder &RenderCommandEncoder::drawInstanced(MTLPrimitiveType primi a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec38
1507
                                                          uint32_t vertexCount,
1579
                                                          uint32_t vertexCount,
1508
                                                          uint32_t instances)
1580
                                                          uint32_t instances)
1509
{
1581
{
1510
    if (ANGLE_UNLIKELY(!mStateCache.renderPipeline))
1511
    {
1512
        // Ignore draw call if there is no render pipeline state set prior to this.
1513
        return *this;
1514
    }
1515
1516
    mHasDrawCalls = true;
1582
    mHasDrawCalls = true;
1517
    mCommands.push(CmdType::DrawInstanced)
1583
    mCommands.push(CmdType::DrawInstanced)
1518
        .push(primitiveType)
1584
        .push(primitiveType)
Lines 1529-1541 RenderCommandEncoder &RenderCommandEncoder::drawIndexed(MTLPrimitiveType primiti a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec39
1529
                                                        const BufferRef &indexBuffer,
1595
                                                        const BufferRef &indexBuffer,
1530
                                                        size_t bufferOffset)
1596
                                                        size_t bufferOffset)
1531
{
1597
{
1532
    if (ANGLE_UNLIKELY(!mStateCache.renderPipeline))
1598
    if (!indexBuffer)
1533
    {
1534
        // Ignore draw call if there is no render pipeline state set prior to this.
1535
        return *this;
1536
    }
1537
1538
    if (ANGLE_UNLIKELY(!indexBuffer))
1539
    {
1599
    {
1540
        return *this;
1600
        return *this;
1541
    }
1601
    }
Lines 1560-1572 RenderCommandEncoder &RenderCommandEncoder::drawIndexedInstanced(MTLPrimitiveTyp a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec40
1560
                                                                 size_t bufferOffset,
1620
                                                                 size_t bufferOffset,
1561
                                                                 uint32_t instances)
1621
                                                                 uint32_t instances)
1562
{
1622
{
1563
    if (ANGLE_UNLIKELY(!mStateCache.renderPipeline))
1623
    if (!indexBuffer)
1564
    {
1565
        // Ignore draw call if there is no render pipeline state set prior to this.
1566
        return *this;
1567
    }
1568
1569
    if (ANGLE_UNLIKELY(!indexBuffer))
1570
    {
1624
    {
1571
        return *this;
1625
        return *this;
1572
    }
1626
    }
Lines 1594-1606 RenderCommandEncoder &RenderCommandEncoder::drawIndexedInstancedBaseVertex( a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec41
1594
    uint32_t instances,
1648
    uint32_t instances,
1595
    uint32_t baseVertex)
1649
    uint32_t baseVertex)
1596
{
1650
{
1597
    if (ANGLE_UNLIKELY(!mStateCache.renderPipeline))
1651
    if (!indexBuffer)
1598
    {
1599
        // Ignore draw call if there is no render pipeline state set prior to this.
1600
        return *this;
1601
    }
1602
1603
    if (ANGLE_UNLIKELY(!indexBuffer))
1604
    {
1652
    {
1605
        return *this;
1653
        return *this;
1606
    }
1654
    }
Lines 1673-1678 RenderCommandEncoder &RenderCommandEncoder::memoryBarrierWithResource(const Buff a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec42
1673
    return *this;
1721
    return *this;
1674
}
1722
}
1675
1723
1724
void RenderCommandEncoder::insertDebugSignImpl(NSString *label)
1725
{
1726
    // Defer the insertion until endEncoding()
1727
    mCommands.push(CmdType::InsertDebugsign).push([label ANGLE_MTL_RETAIN]);
1728
}
1729
1676
void RenderCommandEncoder::pushDebugGroup(NSString *label)
1730
void RenderCommandEncoder::pushDebugGroup(NSString *label)
1677
{
1731
{
1678
    // Defer the insertion until endEncoding()
1732
    // Defer the insertion until endEncoding()
Lines 1799-1805 BlitCommandEncoder &BlitCommandEncoder::restart() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec43
1799
            return *this;
1853
            return *this;
1800
        }
1854
        }
1801
1855
1802
        if (!cmdBuffer().ready())
1856
        if (!cmdBuffer().valid())
1803
        {
1857
        {
1804
            reset();
1858
            reset();
1805
            return *this;
1859
            return *this;
Lines 1962-1967 BlitCommandEncoder &BlitCommandEncoder::fillBuffer(const BufferRef &buffer, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec44
1962
    return *this;
2016
    return *this;
1963
}
2017
}
1964
2018
2019
BlitCommandEncoder &BlitCommandEncoder::copyTexture(const TextureRef &src,
2020
                                                    uint32_t srcStartSlice,
2021
                                                    uint32_t srcStartLevel,
2022
                                                    const TextureRef &dst,
2023
                                                    uint32_t dstStartSlice,
2024
                                                    uint32_t dstStartLevel,
2025
                                                    uint32_t sliceCount,
2026
                                                    uint32_t levelCount)
2027
{
2028
    if (!src || !dst)
2029
    {
2030
        return *this;
2031
    }
2032
2033
    cmdBuffer().setReadDependency(src);
2034
    cmdBuffer().setWriteDependency(dst);
2035
2036
#if defined(__IPHONE_13_0) || defined(__MAC_10_15)
2037
    if (ANGLE_APPLE_AVAILABLE_XCI(10.15, 13.0, 13.0))
2038
    {
2039
        [get() copyFromTexture:src->get()
2040
                   sourceSlice:srcStartSlice
2041
                   sourceLevel:srcStartLevel
2042
                     toTexture:dst->get()
2043
              destinationSlice:dstStartSlice
2044
              destinationLevel:dstStartLevel
2045
                    sliceCount:sliceCount
2046
                    levelCount:levelCount];
2047
    }
2048
    else
2049
#endif
2050
    {
2051
        MTLOrigin origin = MTLOriginMake(0, 0, 0);
2052
        for (uint32_t slice = 0; slice < sliceCount; ++slice)
2053
        {
2054
            uint32_t srcSlice = srcStartSlice + slice;
2055
            uint32_t dstSlice = dstStartSlice + slice;
2056
            for (uint32_t level = 0; level < levelCount; ++level)
2057
            {
2058
                mtl::MipmapNativeLevel srcLevel = mtl::MipmapNativeLevel(srcStartLevel + level);
2059
                uint32_t dstLevel = dstStartLevel + level;
2060
                MTLSize srcSize =
2061
                    MTLSizeMake(src->width(srcLevel), src->height(srcLevel), src->depth(srcLevel));
2062
2063
                [get() copyFromTexture:src->get()
2064
                           sourceSlice:srcSlice
2065
                           sourceLevel:srcLevel.get()
2066
                          sourceOrigin:origin
2067
                            sourceSize:srcSize
2068
                             toTexture:dst->get()
2069
                      destinationSlice:dstSlice
2070
                      destinationLevel:dstLevel
2071
                     destinationOrigin:origin];
2072
            }
2073
        }
2074
    }
2075
2076
    return *this;
2077
}
2078
1965
BlitCommandEncoder &BlitCommandEncoder::generateMipmapsForTexture(const TextureRef &texture)
2079
BlitCommandEncoder &BlitCommandEncoder::generateMipmapsForTexture(const TextureRef &texture)
1966
{
2080
{
1967
    if (!texture)
2081
    if (!texture)
Lines 1974-1980 BlitCommandEncoder &BlitCommandEncoder::generateMipmapsForTexture(const TextureR a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec45
1974
2088
1975
    return *this;
2089
    return *this;
1976
}
2090
}
1977
BlitCommandEncoder &BlitCommandEncoder::synchronizeResource(Buffer *buffer)
2091
BlitCommandEncoder &BlitCommandEncoder::synchronizeResource(const BufferRef &buffer)
1978
{
2092
{
1979
    if (!buffer)
2093
    if (!buffer)
1980
    {
2094
    {
Lines 1989-1995 BlitCommandEncoder &BlitCommandEncoder::synchronizeResource(Buffer *buffer) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec46
1989
#endif
2103
#endif
1990
    return *this;
2104
    return *this;
1991
}
2105
}
1992
BlitCommandEncoder &BlitCommandEncoder::synchronizeResource(Texture *texture)
2106
BlitCommandEncoder &BlitCommandEncoder::synchronizeResource(const TextureRef &texture)
1993
{
2107
{
1994
    if (!texture)
2108
    if (!texture)
1995
    {
2109
    {
Lines 2028-2034 ComputeCommandEncoder &ComputeCommandEncoder::restart() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_command_buffer.mm_sec47
2028
            return *this;
2142
            return *this;
2029
        }
2143
        }
2030
2144
2031
        if (!cmdBuffer().ready())
2145
        if (!cmdBuffer().valid())
2032
        {
2146
        {
2033
            reset();
2147
            reset();
2034
            return *this;
2148
            return *this;
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_common.h -41 / +31 lines
Lines 27-35 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_common.h_sec1
27
#include "libANGLE/angletypes.h"
27
#include "libANGLE/angletypes.h"
28
28
29
#if TARGET_OS_IPHONE
29
#if TARGET_OS_IPHONE
30
#    if !defined(__IPHONE_11_0)
31
#        define __IPHONE_11_0 110000
32
#    endif
30
#    if !defined(ANGLE_IOS_DEPLOY_TARGET)
33
#    if !defined(ANGLE_IOS_DEPLOY_TARGET)
31
#        define ANGLE_IOS_DEPLOY_TARGET __IPHONE_11_0
34
#        define ANGLE_IOS_DEPLOY_TARGET __IPHONE_11_0
32
#    endif
35
#    endif
36
#    if !defined(__IPHONE_OS_VERSION_MAX_ALLOWED)
37
#        define __IPHONE_OS_VERSION_MAX_ALLOWED __IPHONE_11_0
38
#    endif
39
#    if !defined(__TV_OS_VERSION_MAX_ALLOWED)
40
#        define __TV_OS_VERSION_MAX_ALLOWED __IPHONE_11_0
41
#    endif
33
#endif
42
#endif
34
43
35
#if !defined(TARGET_OS_MACCATALYST)
44
#if !defined(TARGET_OS_MACCATALYST)
Lines 66-71 namespace egl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_common.h_sec2
66
{
75
{
67
class Display;
76
class Display;
68
class Image;
77
class Image;
78
class Surface;
69
}  // namespace egl
79
}  // namespace egl
70
80
71
#define ANGLE_GL_OBJECTS_X(PROC) \
81
#define ANGLE_GL_OBJECTS_X(PROC) \
Lines 102-107 class TextureMtl; a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_common.h_sec3
102
class ProgramMtl;
112
class ProgramMtl;
103
class SamplerMtl;
113
class SamplerMtl;
104
class TransformFeedbackMtl;
114
class TransformFeedbackMtl;
115
class SurfaceMtlProtocol;
105
116
106
ANGLE_GL_OBJECTS_X(ANGLE_PRE_DECLARE_MTL_OBJECT)
117
ANGLE_GL_OBJECTS_X(ANGLE_PRE_DECLARE_MTL_OBJECT)
107
118
Lines 128-134 constexpr size_t kDefaultAttributeSize = 4 * sizeof(float); a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_common.h_sec4
128
// Metal limits
139
// Metal limits
129
constexpr uint32_t kMaxShaderBuffers     = 31;
140
constexpr uint32_t kMaxShaderBuffers     = 31;
130
constexpr uint32_t kMaxShaderSamplers    = 16;
141
constexpr uint32_t kMaxShaderSamplers    = 16;
131
constexpr size_t kDefaultUniformsMaxSize = 4 * 1024;
142
constexpr size_t kInlineConstDataMaxSize = 4 * 1024;
143
constexpr size_t kDefaultUniformsMaxSize = kInlineConstDataMaxSize;
132
constexpr uint32_t kMaxViewports         = 1;
144
constexpr uint32_t kMaxViewports         = 1;
133
145
134
constexpr uint32_t kVertexAttribBufferStrideAlignment = 4;
146
constexpr uint32_t kVertexAttribBufferStrideAlignment = 4;
Lines 142-148 constexpr uint32_t kIndexBufferOffsetAlignment = 4; a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_common.h_sec5
142
constexpr uint32_t kArgumentBufferOffsetAlignment    = kUniformBufferSettingOffsetMinAlignment;
154
constexpr uint32_t kArgumentBufferOffsetAlignment    = kUniformBufferSettingOffsetMinAlignment;
143
constexpr uint32_t kTextureToBufferBlittingAlignment = 256;
155
constexpr uint32_t kTextureToBufferBlittingAlignment = 256;
144
156
145
// Front end binding limits
157
// Font end binding limits
146
constexpr uint32_t kMaxGLSamplerBindings = 2 * kMaxShaderSamplers;
158
constexpr uint32_t kMaxGLSamplerBindings = 2 * kMaxShaderSamplers;
147
constexpr uint32_t kMaxGLUBOBindings     = 2 * kMaxShaderUBOs;
159
constexpr uint32_t kMaxGLUBOBindings     = 2 * kMaxShaderUBOs;
148
160
Lines 155-175 constexpr uint32_t kDefaultAttribsBindingIndex = kVboBindingIndexStart + kMaxVer a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_common.h_sec6
155
constexpr uint32_t kDriverUniformsBindingIndex = kDefaultAttribsBindingIndex + 1;
167
constexpr uint32_t kDriverUniformsBindingIndex = kDefaultAttribsBindingIndex + 1;
156
// Binding index for default uniforms:
168
// Binding index for default uniforms:
157
constexpr uint32_t kDefaultUniformsBindingIndex = kDefaultAttribsBindingIndex + 3;
169
constexpr uint32_t kDefaultUniformsBindingIndex = kDefaultAttribsBindingIndex + 3;
158
// Binding index for UBO's argument buffer or starting discrete slot
170
// Binding index for Transform Feedback Buffers (4)
159
constexpr uint32_t kUBOArgumentBufferBindingIndex = kDefaultUniformsBindingIndex + 1;
171
constexpr uint32_t kTransformFeedbackBindingIndex = kDefaultUniformsBindingIndex + 1;
172
// Binding index for shadow samplers' compare modes
173
constexpr uint32_t kShadowSamplerCompareModesBindingIndex = kTransformFeedbackBindingIndex + 4;
174
// Binding index for UBO's argument buffer
175
constexpr uint32_t kUBOArgumentBufferBindingIndex = kShadowSamplerCompareModesBindingIndex + 1;
160
176
161
constexpr uint32_t kStencilMaskAll = 0xff;  // Only 8 bits stencil is supported
177
constexpr uint32_t kStencilMaskAll = 0xff;  // Only 8 bit stencil is supported
162
178
163
// This special constant is used to indicate that a particular vertex descriptor's buffer layout
179
// This special constant is used to indicate that a particular vertex descriptor's buffer layout
164
// index is unused.
180
// index is unused.
165
constexpr MTLVertexStepFunction kVertexStepFunctionInvalid =
181
constexpr MTLVertexStepFunction kVertexStepFunctionInvalid =
166
    static_cast<MTLVertexStepFunction>(0xff);
182
    static_cast<MTLVertexStepFunction>(0xff);
167
183
168
constexpr int kEmulatedAlphaValue = 1;
184
constexpr float kEmulatedAlphaValue = 1.0f;
169
170
constexpr size_t kOcclusionQueryResultSize = sizeof(uint64_t);
171
185
172
constexpr gl::Version kMaxSupportedGLVersion = gl::Version(3, 0);
186
constexpr uint32_t kOcclusionQueryResultSize = sizeof(uint64_t);
173
187
174
// Work-around the enum is not available on macOS
188
// Work-around the enum is not available on macOS
175
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
189
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
Lines 179-191 constexpr MTLBlitOption kBlitOptionRowLinearPVRTC = MTLBlitOptionRowLin a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_common.h_sec7
179
#endif
193
#endif
180
194
181
#if defined(__IPHONE_13_0) || defined(__MAC_10_15)
195
#if defined(__IPHONE_13_0) || defined(__MAC_10_15)
182
#    define ANGLE_MTL_SWIZZLE_AVAILABLE 1
183
using TextureSwizzleChannels                   = MTLTextureSwizzleChannels;
196
using TextureSwizzleChannels                   = MTLTextureSwizzleChannels;
184
using RenderStages                             = MTLRenderStages;
197
using RenderStages                             = MTLRenderStages;
185
constexpr MTLRenderStages kRenderStageVertex   = MTLRenderStageVertex;
198
constexpr MTLRenderStages kRenderStageVertex   = MTLRenderStageVertex;
186
constexpr MTLRenderStages kRenderStageFragment = MTLRenderStageFragment;
199
constexpr MTLRenderStages kRenderStageFragment = MTLRenderStageFragment;
187
#else
200
#else
188
#    define ANGLE_MTL_SWIZZLE_AVAILABLE 0
189
using TextureSwizzleChannels                               = int;
201
using TextureSwizzleChannels                               = int;
190
using RenderStages                                         = int;
202
using RenderStages                                         = int;
191
constexpr RenderStages kRenderStageVertex                  = 1;
203
constexpr RenderStages kRenderStageVertex                  = 1;
Lines 219-230 struct ImplTypeHelper<egl::Display> a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_common.h_sec8
219
{
231
{
220
    using ImplType = DisplayMtl;
232
    using ImplType = DisplayMtl;
221
};
233
};
222
234
template <>
235
struct ImplTypeHelper<egl::Surface>
236
{
237
    using ImplType = SurfaceMtlProtocol;
238
};
223
template <typename T>
239
template <typename T>
224
using GetImplType = typename ImplTypeHelper<T>::ImplType;
240
using GetImplType = typename ImplTypeHelper<T>::ImplType;
225
241
226
template <typename T>
242
template <typename T>
227
GetImplType<T> *GetImpl(const T *_Nonnull glObject)
243
GetImplType<T> *GetImpl(const T *glObject)
228
{
244
{
229
    return GetImplAs<GetImplType<T>>(glObject);
245
    return GetImplAs<GetImplType<T>>(glObject);
230
}
246
}
Lines 346-366 using AutoObjCObj = AutoObjCPtr<T *>; a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_common.h_sec9
346
362
347
// NOTE: SharedEvent is only declared on iOS 12.0+ or mac 10.14+
363
// NOTE: SharedEvent is only declared on iOS 12.0+ or mac 10.14+
348
#if defined(__IPHONE_12_0) || defined(__MAC_10_14)
364
#if defined(__IPHONE_12_0) || defined(__MAC_10_14)
349
#    define ANGLE_MTL_EVENT_AVAILABLE 1
350
using SharedEventRef = AutoObjCPtr<id<MTLSharedEvent>>;
365
using SharedEventRef = AutoObjCPtr<id<MTLSharedEvent>>;
351
#else
366
#else
352
#    define ANGLE_MTL_EVENT_AVAILABLE 0
353
using SharedEventRef                                       = AutoObjCObj<NSObject>;
367
using SharedEventRef                                       = AutoObjCObj<NSObject>;
354
#endif
368
#endif
355
369
356
// The native image index used by Metal back-end,  the image index uses native mipmap level instead
370
// The native image index used by Metal back-end,  the image index uses native mipmap level instead
357
// of "virtual" level modified by OpenGL's base level.
371
// of "virtual" level modified by OpenGL's base level.
358
using MipmapNativeLevel = gl::LevelIndexWrapper<uint32_t>;
372
using MipmapNativeLevel = gl::LevelIndexWrapper<uint32_t>;
359
360
constexpr MipmapNativeLevel kZeroNativeMipLevel(0);
373
constexpr MipmapNativeLevel kZeroNativeMipLevel(0);
361
362
class ImageNativeIndexIterator;
374
class ImageNativeIndexIterator;
363
364
class ImageNativeIndex final
375
class ImageNativeIndex final
365
{
376
{
366
  public:
377
  public:
Lines 370-424 class ImageNativeIndex final a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_common.h_sec10
370
        mNativeIndex = gl::ImageIndex::MakeFromType(src.getType(), src.getLevelIndex() - baseLevel,
381
        mNativeIndex = gl::ImageIndex::MakeFromType(src.getType(), src.getLevelIndex() - baseLevel,
371
                                                    src.getLayerIndex(), src.getLayerCount());
382
                                                    src.getLayerIndex(), src.getLayerCount());
372
    }
383
    }
373
374
    static ImageNativeIndex FromBaseZeroGLIndex(const gl::ImageIndex &src)
384
    static ImageNativeIndex FromBaseZeroGLIndex(const gl::ImageIndex &src)
375
    {
385
    {
376
        return ImageNativeIndex(src, 0);
386
        return ImageNativeIndex(src, 0);
377
    }
387
    }
378
379
    MipmapNativeLevel getNativeLevel() const
388
    MipmapNativeLevel getNativeLevel() const
380
    {
389
    {
381
        return MipmapNativeLevel(mNativeIndex.getLevelIndex());
390
        return MipmapNativeLevel(mNativeIndex.getLevelIndex());
382
    }
391
    }
383
384
    gl::TextureType getType() const { return mNativeIndex.getType(); }
392
    gl::TextureType getType() const { return mNativeIndex.getType(); }
385
    GLint getLayerIndex() const { return mNativeIndex.getLayerIndex(); }
393
    GLint getLayerIndex() const { return mNativeIndex.getLayerIndex(); }
386
    GLint getLayerCount() const { return mNativeIndex.getLayerCount(); }
394
    GLint getLayerCount() const { return mNativeIndex.getLayerCount(); }
387
    GLint cubeMapFaceIndex() const { return mNativeIndex.cubeMapFaceIndex(); }
395
    GLint cubeMapFaceIndex() const { return mNativeIndex.cubeMapFaceIndex(); }
388
389
    bool isLayered() const { return mNativeIndex.isLayered(); }
396
    bool isLayered() const { return mNativeIndex.isLayered(); }
390
    bool hasLayer() const { return mNativeIndex.hasLayer(); }
397
    bool hasLayer() const { return mNativeIndex.hasLayer(); }
391
    bool has3DLayer() const { return mNativeIndex.has3DLayer(); }
398
    bool has3DLayer() const { return mNativeIndex.has3DLayer(); }
392
    bool usesTex3D() const { return mNativeIndex.usesTex3D(); }
399
    bool usesTex3D() const { return mNativeIndex.usesTex3D(); }
393
394
    bool valid() const { return mNativeIndex.valid(); }
400
    bool valid() const { return mNativeIndex.valid(); }
395
396
    ImageNativeIndexIterator getLayerIterator(GLint layerCount) const;
401
    ImageNativeIndexIterator getLayerIterator(GLint layerCount) const;
397
398
  private:
402
  private:
399
    gl::ImageIndex mNativeIndex;
403
    gl::ImageIndex mNativeIndex;
400
};
404
};
401
402
class ImageNativeIndexIterator final
405
class ImageNativeIndexIterator final
403
{
406
{
404
  public:
407
  public:
405
    ImageNativeIndex next() { return ImageNativeIndex(mNativeIndexIte.next(), 0); }
408
    ImageNativeIndex next() { return ImageNativeIndex(mNativeIndexIte.next(), 0); }
406
    ImageNativeIndex current() const { return ImageNativeIndex(mNativeIndexIte.current(), 0); }
409
    ImageNativeIndex current() const { return ImageNativeIndex(mNativeIndexIte.current(), 0); }
407
    bool hasNext() const { return mNativeIndexIte.hasNext(); }
410
    bool hasNext() const { return mNativeIndexIte.hasNext(); }
408
409
  private:
411
  private:
410
    // This class is only constructable from ImageNativeIndex
412
    // This class is only constructable from ImageNativeIndex
411
    friend class ImageNativeIndex;
413
    friend class ImageNativeIndex;
412
413
    explicit ImageNativeIndexIterator(const gl::ImageIndexIterator &baseZeroSrc)
414
    explicit ImageNativeIndexIterator(const gl::ImageIndexIterator &baseZeroSrc)
414
        : mNativeIndexIte(baseZeroSrc)
415
        : mNativeIndexIte(baseZeroSrc)
415
    {}
416
    {}
416
417
    gl::ImageIndexIterator mNativeIndexIte;
417
    gl::ImageIndexIterator mNativeIndexIte;
418
};
418
};
419
420
using ClearColorValueBytes = std::array<uint8_t, 4 * sizeof(float)>;
419
using ClearColorValueBytes = std::array<uint8_t, 4 * sizeof(float)>;
421
422
class ClearColorValue
420
class ClearColorValue
423
{
421
{
424
  public:
422
  public:
Lines 437-458 class ClearColorValue a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_common.h_sec11
437
    constexpr ClearColorValue(const ClearColorValue &src)
435
    constexpr ClearColorValue(const ClearColorValue &src)
438
        : mType(src.mType), mValueBytes(src.mValueBytes)
436
        : mType(src.mType), mValueBytes(src.mValueBytes)
439
    {}
437
    {}
440
441
    MTLClearColor toMTLClearColor() const;
438
    MTLClearColor toMTLClearColor() const;
442
443
    PixelType getType() const { return mType; }
439
    PixelType getType() const { return mType; }
444
445
    const ClearColorValueBytes &getValueBytes() const { return mValueBytes; }
440
    const ClearColorValueBytes &getValueBytes() const { return mValueBytes; }
446
447
    ClearColorValue &operator=(const ClearColorValue &src);
441
    ClearColorValue &operator=(const ClearColorValue &src);
448
449
    void setAsFloat(float r, float g, float b, float a);
442
    void setAsFloat(float r, float g, float b, float a);
450
    void setAsInt(int32_t r, int32_t g, int32_t b, int32_t a);
443
    void setAsInt(int32_t r, int32_t g, int32_t b, int32_t a);
451
    void setAsUInt(uint32_t r, uint32_t g, uint32_t b, uint32_t a);
444
    void setAsUInt(uint32_t r, uint32_t g, uint32_t b, uint32_t a);
452
453
  private:
445
  private:
454
    PixelType mType;
446
    PixelType mType;
455
456
    union
447
    union
457
    {
448
    {
458
        struct
449
        struct
Lines 467-473 class ClearColorValue a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_common.h_sec12
467
        {
458
        {
468
            uint32_t mRedU, mGreenU, mBlueU, mAlphaU;
459
            uint32_t mRedU, mGreenU, mBlueU, mAlphaU;
469
        };
460
        };
470
471
        ClearColorValueBytes mValueBytes;
461
        ClearColorValueBytes mValueBytes;
472
    };
462
    };
473
};
463
};
Lines 483-489 class ErrorHandler a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_common.h_sec13
483
                             const char *function,
473
                             const char *function,
484
                             unsigned int line) = 0;
474
                             unsigned int line) = 0;
485
475
486
    virtual void handleError(NSError *_Nullable error,
476
    virtual void handleError(NSError *error,
487
                             const char *file,
477
                             const char *file,
488
                             const char *function,
478
                             const char *function,
489
                             unsigned int line) = 0;
479
                             unsigned int line) = 0;
Lines 493-499 class Context : public ErrorHandler a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_common.h_sec14
493
{
483
{
494
  public:
484
  public:
495
    Context(DisplayMtl *displayMtl);
485
    Context(DisplayMtl *displayMtl);
496
    _Nullable id<MTLDevice> getMetalDevice() const;
486
    id<MTLDevice> getMetalDevice() const;
497
    mtl::CommandQueue &cmdQueue();
487
    mtl::CommandQueue &cmdQueue();
498
488
499
    DisplayMtl *getDisplay() const { return mDisplay; }
489
    DisplayMtl *getDisplay() const { return mDisplay; }
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_constants.h +73 lines
Line 0 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_constants.h_sec1
1
//
2
// Copyright 2020 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
// mtl_common.h:
7
//      Declares numerical constants used in Metal.
8
//      error handler base class.
9
//
10
11
#ifndef LIBANGLE_RENDERER_METAL_MTL_CONSTANTS_H
12
#define LIBANGLE_RENDERER_METAL_MTL_CONSTANTS_H
13
#include "libANGLE/Constants.h"
14
#include "libANGLE/Version.h"
15
#include "libANGLE/angletypes.h"
16
17
namespace rx
18
{
19
namespace mtl
20
{
21
22
// NOTE(hqle): support variable max number of vertex attributes
23
constexpr uint32_t kMaxVertexAttribs = gl::MAX_VERTEX_ATTRIBS;
24
// NOTE(hqle): support variable max number of render targets
25
constexpr uint32_t kMaxRenderTargets = 4;
26
27
constexpr uint32_t kMaxShaderUBOs = 12;
28
constexpr uint32_t kMaxUBOSize    = 16384;
29
30
constexpr size_t kDefaultAttributeSize = 4 * sizeof(float);
31
32
// Metal limits
33
constexpr uint32_t kMaxShaderBuffers     = 31;
34
constexpr uint32_t kMaxShaderSamplers    = 16;
35
constexpr size_t kInlineConstDataMaxSize = 4 * 1024;
36
constexpr size_t kDefaultUniformsMaxSize = kInlineConstDataMaxSize;
37
constexpr uint32_t kMaxViewports         = 1;
38
39
constexpr uint32_t kVertexAttribBufferStrideAlignment = 4;
40
// Alignment requirement for offset passed to setVertex|FragmentBuffer
41
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
42
constexpr uint32_t kUniformBufferSettingOffsetMinAlignment = 256;
43
#else
44
constexpr uint32_t kUniformBufferSettingOffsetMinAlignment = 4;
45
#endif
46
constexpr uint32_t kIndexBufferOffsetAlignment       = 4;
47
constexpr uint32_t kTextureToBufferBlittingAlignment = 256;
48
49
// Font end binding limits
50
constexpr uint32_t kMaxGLSamplerBindings = 2 * kMaxShaderSamplers;
51
constexpr uint32_t kMaxGLUBOBindings     = 2 * kMaxShaderUBOs;
52
53
// Binding index start for vertex data buffers:
54
constexpr uint32_t kVboBindingIndexStart = 0;
55
56
// Binding index for default attribute buffer:
57
constexpr uint32_t kDefaultAttribsBindingIndex = kVboBindingIndexStart + kMaxVertexAttribs;
58
// Binding index for driver uniforms:
59
constexpr uint32_t kDriverUniformsBindingIndex = kDefaultAttribsBindingIndex + 1;
60
// Binding index for default uniforms:
61
constexpr uint32_t kDefaultUniformsBindingIndex = kDefaultAttribsBindingIndex + 3;
62
// Binding index for Transform Feedback Buffers (4)
63
constexpr uint32_t kTransformFeedbackBindingIndex = kDefaultUniformsBindingIndex + 1;
64
// Binding index for shadow samplers' compare modes
65
constexpr uint32_t kShadowSamplerCompareModesBindingIndex = kTransformFeedbackBindingIndex + 4;
66
// Binding index for UBO's argument buffer
67
constexpr uint32_t kUBOArgumentBufferBindingIndex = kShadowSamplerCompareModesBindingIndex + 1;
68
69
constexpr uint32_t kStencilMaskAll = 0xff;  // Only 8 bits stencil is supported
70
71
}  // namespace mtl
72
}  // namespace rx
73
#endif
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_map.json -36 / +35 lines
Lines 74-84 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_map.json_sec1
74
            "D32_FLOAT": "MTLPixelFormatDepth32Float",
74
            "D32_FLOAT": "MTLPixelFormatDepth32Float",
75
            "S8_UINT": "MTLPixelFormatStencil8",
75
            "S8_UINT": "MTLPixelFormatStencil8",
76
            "D32_FLOAT_S8X24_UINT": "MTLPixelFormatDepth32Float_Stencil8",
76
            "D32_FLOAT_S8X24_UINT": "MTLPixelFormatDepth32Float_Stencil8",
77
            "B10G10R10A2_UNORM": "MTLPixelFormatBGR10A2Unorm",
78
            "R10G10B10A2_UINT": "MTLPixelFormatRGB10A2Uint",
77
            "R10G10B10A2_UINT": "MTLPixelFormatRGB10A2Uint",
79
            "R10G10B10A2_UNORM": "MTLPixelFormatRGB10A2Unorm",
78
            "R10G10B10A2_UNORM": "MTLPixelFormatRGB10A2Unorm",
80
            "R11G11B10_FLOAT": "MTLPixelFormatRG11B10Float",
79
            "R11G11B10_FLOAT": "MTLPixelFormatRG11B10Float",
81
            "R9G9B9E5_SHAREDEXP": "MTLPixelFormatRGB9E5Float"
80
            "R9G9B9E5_SHAREDEXP": "MTLPixelFormatRGB9E5Float",
81
            "D16_UNORM": "MTLPixelFormatDepth16Unorm"
82
        },
82
        },
83
        "map_ios": {
83
        "map_ios": {
84
            "R5G6B5_UNORM": "MTLPixelFormatB5G6R5Unorm",
84
            "R5G6B5_UNORM": "MTLPixelFormatB5G6R5Unorm",
Lines 92-97 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_map.json_sec2
92
            "PVRTC1_RGB_4BPP_UNORM_SRGB_BLOCK": "MTLPixelFormatPVRTC_RGB_4BPP_sRGB",
92
            "PVRTC1_RGB_4BPP_UNORM_SRGB_BLOCK": "MTLPixelFormatPVRTC_RGB_4BPP_sRGB",
93
            "PVRTC1_RGBA_2BPP_UNORM_SRGB_BLOCK": "MTLPixelFormatPVRTC_RGBA_2BPP_sRGB",
93
            "PVRTC1_RGBA_2BPP_UNORM_SRGB_BLOCK": "MTLPixelFormatPVRTC_RGBA_2BPP_sRGB",
94
            "PVRTC1_RGBA_4BPP_UNORM_SRGB_BLOCK": "MTLPixelFormatPVRTC_RGBA_4BPP_sRGB",
94
            "PVRTC1_RGBA_4BPP_UNORM_SRGB_BLOCK": "MTLPixelFormatPVRTC_RGBA_4BPP_sRGB",
95
            "ETC1_R8G8B8_UNORM_BLOCK": "MTLPixelFormatETC2_RGB8",
95
            "ETC2_R8G8B8_UNORM_BLOCK": "MTLPixelFormatETC2_RGB8",
96
            "ETC2_R8G8B8_UNORM_BLOCK": "MTLPixelFormatETC2_RGB8",
96
            "ETC2_R8G8B8_SRGB_BLOCK": "MTLPixelFormatETC2_RGB8_sRGB",
97
            "ETC2_R8G8B8_SRGB_BLOCK": "MTLPixelFormatETC2_RGB8_sRGB",
97
            "ETC2_R8G8B8A1_UNORM_BLOCK": "MTLPixelFormatETC2_RGB8A1",
98
            "ETC2_R8G8B8A1_UNORM_BLOCK": "MTLPixelFormatETC2_RGB8A1",
Lines 100-138 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_map.json_sec3
100
            "ETC2_R8G8B8A8_SRGB_BLOCK": "MTLPixelFormatEAC_RGBA8_sRGB",
101
            "ETC2_R8G8B8A8_SRGB_BLOCK": "MTLPixelFormatEAC_RGBA8_sRGB",
101
            "EAC_R11_UNORM_BLOCK": "MTLPixelFormatEAC_R11Unorm",
102
            "EAC_R11_UNORM_BLOCK": "MTLPixelFormatEAC_R11Unorm",
102
            "EAC_R11_SNORM_BLOCK": "MTLPixelFormatEAC_R11Snorm",
103
            "EAC_R11_SNORM_BLOCK": "MTLPixelFormatEAC_R11Snorm",
103
            "EAC_R11G11_UNORM_BLOCK": "MTLPixelFormatEAC_RG11Unorm",
104
            "EAC_R11G11_UNORM_BLOCK": "MTLPixelFormatEAC_R11Unorm",
104
            "EAC_R11G11_SNORM_BLOCK": "MTLPixelFormatEAC_RG11Snorm",
105
            "EAC_R11G11_SNORM_BLOCK": "MTLPixelFormatEAC_RG11Snorm",
105
            "ASTC_4x4_UNORM_BLOCK": "MTLPixelFormatASTC_4x4_LDR",
106
            "ASTC_4x4_SRGB_BLOCK" : "MTLPixelFormatASTC_4x4_sRGB",
106
            "ASTC_4x4_SRGB_BLOCK": "MTLPixelFormatASTC_4x4_sRGB",
107
            "ASTC_5x4_SRGB_BLOCK" : "MTLPixelFormatASTC_5x4_sRGB",
107
            "ASTC_5x4_UNORM_BLOCK": "MTLPixelFormatASTC_5x4_LDR",
108
            "ASTC_5x5_SRGB_BLOCK" : "MTLPixelFormatASTC_5x5_sRGB",
108
            "ASTC_5x4_SRGB_BLOCK": "MTLPixelFormatASTC_5x4_sRGB",
109
            "ASTC_6x5_SRGB_BLOCK" : "MTLPixelFormatASTC_6x5_sRGB",
109
            "ASTC_5x5_UNORM_BLOCK": "MTLPixelFormatASTC_5x5_LDR",
110
            "ASTC_6x6_SRGB_BLOCK" : "MTLPixelFormatASTC_6x6_sRGB",
110
            "ASTC_5x5_SRGB_BLOCK": "MTLPixelFormatASTC_5x5_sRGB",
111
            "ASTC_8x5_SRGB_BLOCK" : "MTLPixelFormatASTC_8x5_sRGB",
111
            "ASTC_6x5_UNORM_BLOCK": "MTLPixelFormatASTC_6x5_LDR",
112
            "ASTC_8x6_SRGB_BLOCK" : "MTLPixelFormatASTC_8x6_sRGB",
112
            "ASTC_6x5_SRGB_BLOCK": "MTLPixelFormatASTC_6x5_sRGB",
113
            "ASTC_8x8_SRGB_BLOCK" : "MTLPixelFormatASTC_8x8_sRGB",
113
            "ASTC_6x6_UNORM_BLOCK": "MTLPixelFormatASTC_6x6_LDR",
114
            "ASTC_10x5_SRGB_BLOCK" : "MTLPixelFormatASTC_10x5_sRGB",
114
            "ASTC_6x6_SRGB_BLOCK": "MTLPixelFormatASTC_6x6_sRGB",
115
            "ASTC_10x6_SRGB_BLOCK" : "MTLPixelFormatASTC_10x6_sRGB",
115
            "ASTC_8x5_UNORM_BLOCK": "MTLPixelFormatASTC_8x5_LDR",
116
            "ASTC_10x8_SRGB_BLOCK" : "MTLPixelFormatASTC_10x8_sRGB",
116
            "ASTC_8x5_SRGB_BLOCK": "MTLPixelFormatASTC_8x5_sRGB",
117
            "ASTC_10x10_SRGB_BLOCK" : "MTLPixelFormatASTC_10x10_sRGB",
117
            "ASTC_8x6_UNORM_BLOCK": "MTLPixelFormatASTC_8x6_LDR",
118
            "ASTC_12x10_SRGB_BLOCK" : "MTLPixelFormatASTC_12x10_sRGB",
118
            "ASTC_8x6_SRGB_BLOCK": "MTLPixelFormatASTC_8x6_sRGB",
119
            "ASTC_12x12_SRGB_BLOCK" : "MTLPixelFormatASTC_12x12_sRGB",
119
            "ASTC_8x8_UNORM_BLOCK": "MTLPixelFormatASTC_8x8_LDR",
120
            "ASTC_4x4_UNORM_BLOCK" : "MTLPixelFormatASTC_4x4_LDR",
120
            "ASTC_8x8_SRGB_BLOCK": "MTLPixelFormatASTC_8x8_sRGB",
121
            "ASTC_5x4_UNORM_BLOCK" : "MTLPixelFormatASTC_5x4_LDR",
121
            "ASTC_10x5_UNORM_BLOCK": "MTLPixelFormatASTC_10x5_LDR",
122
            "ASTC_5x5_UNORM_BLOCK" : "MTLPixelFormatASTC_5x5_LDR",
122
            "ASTC_10x5_SRGB_BLOCK": "MTLPixelFormatASTC_10x5_sRGB",
123
            "ASTC_6x5_UNORM_BLOCK" : "MTLPixelFormatASTC_6x5_LDR",
123
            "ASTC_10x6_UNORM_BLOCK": "MTLPixelFormatASTC_10x6_LDR",
124
            "ASTC_6x6_UNORM_BLOCK" : "MTLPixelFormatASTC_6x6_LDR",
124
            "ASTC_10x6_SRGB_BLOCK": "MTLPixelFormatASTC_10x6_sRGB",
125
            "ASTC_8x5_UNORM_BLOCK" : "MTLPixelFormatASTC_8x5_LDR",
125
            "ASTC_10x8_UNORM_BLOCK": "MTLPixelFormatASTC_10x8_LDR",
126
            "ASTC_8x6_UNORM_BLOCK" : "MTLPixelFormatASTC_8x6_LDR",
126
            "ASTC_10x8_SRGB_BLOCK": "MTLPixelFormatASTC_10x8_sRGB",
127
            "ASTC_8x8_UNORM_BLOCK" : "MTLPixelFormatASTC_8x8_LDR",
127
            "ASTC_10x10_UNORM_BLOCK": "MTLPixelFormatASTC_10x10_LDR",
128
            "ASTC_10x5_UNORM_BLOCK" : "MTLPixelFormatASTC_10x5_LDR",
128
            "ASTC_10x10_SRGB_BLOCK": "MTLPixelFormatASTC_10x10_sRGB",
129
            "ASTC_10x6_UNORM_BLOCK" : "MTLPixelFormatASTC_10x6_LDR",
129
            "ASTC_12x10_UNORM_BLOCK": "MTLPixelFormatASTC_12x10_LDR",
130
            "ASTC_10x8_UNORM_BLOCK" : "MTLPixelFormatASTC_10x8_LDR",
130
            "ASTC_12x10_SRGB_BLOCK": "MTLPixelFormatASTC_12x10_sRGB",
131
            "ASTC_10x10_UNORM_BLOCK" : "MTLPixelFormatASTC_10x10_LDR",
131
            "ASTC_12x12_UNORM_BLOCK": "MTLPixelFormatASTC_12x12_LDR",
132
            "ASTC_12x10_UNORM_BLOCK" : "MTLPixelFormatASTC_12x10_LDR",
132
            "ASTC_12x12_SRGB_BLOCK": "MTLPixelFormatASTC_12x12_sRGB"
133
            "ASTC_12x12_UNORM_BLOCK" : "MTLPixelFormatASTC_12x12_LDR"
133
        },
134
        },
134
        "map_mac": {
135
        "map_mac": {
135
            "D16_UNORM": "MTLPixelFormatDepth16Unorm",
136
            "D24_UNORM_S8_UINT": "MTLPixelFormatDepth24Unorm_Stencil8",
136
            "D24_UNORM_S8_UINT": "MTLPixelFormatDepth24Unorm_Stencil8",
137
            "BC1_RGBA_UNORM_BLOCK": "MTLPixelFormatBC1_RGBA",
137
            "BC1_RGBA_UNORM_BLOCK": "MTLPixelFormatBC1_RGBA",
138
            "BC1_RGBA_UNORM_SRGB_BLOCK": "MTLPixelFormatBC1_RGBA_sRGB",
138
            "BC1_RGBA_UNORM_SRGB_BLOCK": "MTLPixelFormatBC1_RGBA_sRGB",
Lines 175-183 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_map.json_sec4
175
            "D32_UNORM": "D32_FLOAT"
175
            "D32_UNORM": "D32_FLOAT"
176
        },
176
        },
177
        "override_ios": {
177
        "override_ios": {
178
            "D24_UNORM_S8_UINT": "D32_FLOAT_S8X24_UINT",
178
            "D24_UNORM_S8_UINT": "D32_FLOAT_S8X24_UINT"
179
            "D16_UNORM": "D32_FLOAT",
180
            "ETC1_R8G8B8_UNORM_BLOCK": "ETC2_R8G8B8_UNORM_BLOCK"
181
        },
179
        },
182
        "override_mac": {
180
        "override_mac": {
183
            "R5G6B5_UNORM": "R8G8B8A8_UNORM",
181
            "R5G6B5_UNORM": "R8G8B8A8_UNORM",
Lines 203-209 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_map.json_sec5
203
            "EAC_R11G11_UNORM_BLOCK": "R16G16_UNORM",
201
            "EAC_R11G11_UNORM_BLOCK": "R16G16_UNORM",
204
            "EAC_R11G11_SNORM_BLOCK": "R16G16_SNORM"
202
            "EAC_R11G11_SNORM_BLOCK": "R16G16_SNORM"
205
        },
203
        },
206
        "d24s8_fallbacks_mac": {
204
        "fallbacks_mac": {
205
            "B8G8R8A8_UNORM": "R8G8B8A8_UNORM",
207
            "D24_UNORM_S8_UINT": "D32_FLOAT_S8X24_UINT"
206
            "D24_UNORM_S8_UINT": "D32_FLOAT_S8X24_UINT"
208
        },
207
        },
209
        "caps": {
208
        "caps": {
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_table_autogen.mm -35 / +58 lines
Lines 17-23 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_table_autogen.mm_sec1
17
#include "libANGLE/renderer/Format.h"
17
#include "libANGLE/renderer/Format.h"
18
#include "libANGLE/renderer/metal/DisplayMtl.h"
18
#include "libANGLE/renderer/metal/DisplayMtl.h"
19
#include "libANGLE/renderer/metal/mtl_format_utils.h"
19
#include "libANGLE/renderer/metal/mtl_format_utils.h"
20
20
#include "libANGLE/renderer/metal/mtl_utils.h"
21
using namespace angle;
21
using namespace angle;
22
22
23
namespace rx
23
namespace rx
Lines 27-34 namespace mtl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_table_autogen.mm_sec2
27
27
28
void Format::init(const DisplayMtl *display, angle::FormatID intendedFormatId_)
28
void Format::init(const DisplayMtl *display, angle::FormatID intendedFormatId_)
29
{
29
{
30
    this->intendedFormatId = intendedFormatId_;
30
    this->intendedFormatId    = intendedFormatId_;
31
32
    id<MTLDevice> metalDevice = display->getMetalDevice();
31
    id<MTLDevice> metalDevice = display->getMetalDevice();
33
32
34
    // Actual conversion
33
    // Actual conversion
Lines 43-57 void Format::init(const DisplayMtl *display, angle::FormatID intendedFormatId_) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_table_autogen.mm_sec3
43
            this->swizzled = false;
42
            this->swizzled = false;
44
            break;
43
            break;
45
44
46
        case angle::FormatID::B10G10R10A2_UNORM:
45
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
46
        case angle::FormatID::B8G8R8A8_UNORM:
47
47
48
            this->metalFormat    = MTLPixelFormatBGR10A2Unorm;
48
            if (metalDevice.depth24Stencil8PixelFormatSupported)
49
            this->actualFormatId = angle::FormatID::B10G10R10A2_UNORM;
49
            {
50
            this->initFunction   = nullptr;
50
                this->metalFormat    = MTLPixelFormatBGRA8Unorm;
51
                this->actualFormatId = angle::FormatID::B8G8R8A8_UNORM;
52
                this->initFunction   = nullptr;
53
            }
54
            else
55
            {
56
                this->metalFormat    = MTLPixelFormatRGBA8Unorm;
57
                this->actualFormatId = angle::FormatID::R8G8B8A8_UNORM;
58
                this->initFunction   = nullptr;
59
            }
51
60
52
            this->swizzled = false;
61
            this->swizzled = false;
53
            break;
62
            break;
54
63
64
#else  // TARGET_OS_OSX || TARGET_OS_MACCATALYST
55
        case angle::FormatID::B8G8R8A8_UNORM:
65
        case angle::FormatID::B8G8R8A8_UNORM:
56
66
57
            this->metalFormat    = MTLPixelFormatBGRA8Unorm;
67
            this->metalFormat    = MTLPixelFormatBGRA8Unorm;
Lines 61-66 void Format::init(const DisplayMtl *display, angle::FormatID intendedFormatId_) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_table_autogen.mm_sec4
61
            this->swizzled = false;
71
            this->swizzled = false;
62
            break;
72
            break;
63
73
74
#endif  // TARGET_OS_OSX || TARGET_OS_MACCATALYST
64
        case angle::FormatID::B8G8R8A8_UNORM_SRGB:
75
        case angle::FormatID::B8G8R8A8_UNORM_SRGB:
65
76
66
            this->metalFormat    = MTLPixelFormatBGRA8Unorm_sRGB;
77
            this->metalFormat    = MTLPixelFormatBGRA8Unorm_sRGB;
Lines 70-75 void Format::init(const DisplayMtl *display, angle::FormatID intendedFormatId_) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_table_autogen.mm_sec5
70
            this->swizzled = false;
81
            this->swizzled = false;
71
            break;
82
            break;
72
83
84
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
85
        case angle::FormatID::D16_UNORM:
86
87
            this->metalFormat    = MTLPixelFormatDepth16Unorm;
88
            this->actualFormatId = angle::FormatID::D16_UNORM;
89
            this->initFunction   = nullptr;
90
91
            this->swizzled = false;
92
            break;
93
94
#else  // TARGET_OS_OSX || TARGET_OS_MACCATALYST
95
        case angle::FormatID::D16_UNORM:
96
97
            if (SupportsIOSGPUFamily(metalDevice, 3))
98
            {
99
                this->metalFormat    = MTLPixelFormatDepth16Unorm;
100
                this->actualFormatId = angle::FormatID::D16_UNORM;
101
                this->initFunction   = nullptr;
102
            }
103
            else
104
            {
105
                this->metalFormat    = MTLPixelFormatDepth32Float;
106
                this->actualFormatId = angle::FormatID::D32_FLOAT;
107
                this->initFunction   = nullptr;
108
            }
109
110
            this->swizzled = false;
111
            break;
112
113
#endif  // TARGET_OS_OSX || TARGET_OS_MACCATALYST
73
        case angle::FormatID::D32_FLOAT:
114
        case angle::FormatID::D32_FLOAT:
74
115
75
            this->metalFormat    = MTLPixelFormatDepth32Float;
116
            this->metalFormat    = MTLPixelFormatDepth32Float;
Lines 815-829 void Format::init(const DisplayMtl *display, angle::FormatID intendedFormatId_) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_table_autogen.mm_sec6
815
            this->swizzled = false;
856
            this->swizzled = false;
816
            break;
857
            break;
817
858
818
        case angle::FormatID::D16_UNORM:
819
820
            this->metalFormat    = MTLPixelFormatDepth16Unorm;
821
            this->actualFormatId = angle::FormatID::D16_UNORM;
822
            this->initFunction   = nullptr;
823
824
            this->swizzled = false;
825
            break;
826
827
        case angle::FormatID::D24_UNORM_S8_UINT:
859
        case angle::FormatID::D24_UNORM_S8_UINT:
828
860
829
            if (metalDevice.depth24Stencil8PixelFormatSupported &&
861
            if (metalDevice.depth24Stencil8PixelFormatSupported &&
Lines 1281-1287 void Format::init(const DisplayMtl *display, angle::FormatID intendedFormatId_) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_table_autogen.mm_sec7
1281
1313
1282
        case angle::FormatID::EAC_R11G11_UNORM_BLOCK:
1314
        case angle::FormatID::EAC_R11G11_UNORM_BLOCK:
1283
1315
1284
            this->metalFormat    = MTLPixelFormatEAC_RG11Unorm;
1316
            this->metalFormat    = MTLPixelFormatEAC_R11Unorm;
1285
            this->actualFormatId = angle::FormatID::EAC_R11G11_UNORM_BLOCK;
1317
            this->actualFormatId = angle::FormatID::EAC_R11G11_UNORM_BLOCK;
1286
            this->initFunction   = nullptr;
1318
            this->initFunction   = nullptr;
1287
1319
Lines 1306-1311 void Format::init(const DisplayMtl *display, angle::FormatID intendedFormatId_) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_table_autogen.mm_sec8
1306
            this->swizzled = false;
1338
            this->swizzled = false;
1307
            break;
1339
            break;
1308
1340
1341
        case angle::FormatID::ETC1_R8G8B8_UNORM_BLOCK:
1342
1343
            this->metalFormat    = MTLPixelFormatETC2_RGB8;
1344
            this->actualFormatId = angle::FormatID::ETC1_R8G8B8_UNORM_BLOCK;
1345
            this->initFunction   = nullptr;
1346
1347
            this->swizzled = false;
1348
            break;
1349
1309
        case angle::FormatID::ETC2_R8G8B8A1_SRGB_BLOCK:
1350
        case angle::FormatID::ETC2_R8G8B8A1_SRGB_BLOCK:
1310
1351
1311
            this->metalFormat    = MTLPixelFormatETC2_RGB8A1_sRGB;
1352
            this->metalFormat    = MTLPixelFormatETC2_RGB8A1_sRGB;
Lines 1459-1473 void Format::init(const DisplayMtl *display, angle::FormatID intendedFormatId_) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_table_autogen.mm_sec9
1459
            this->swizzled = false;
1500
            this->swizzled = false;
1460
            break;
1501
            break;
1461
1502
1462
        case angle::FormatID::D16_UNORM:
1463
1464
            this->metalFormat    = MTLPixelFormatDepth32Float;
1465
            this->actualFormatId = angle::FormatID::D32_FLOAT;
1466
            this->initFunction   = nullptr;
1467
1468
            this->swizzled = false;
1469
            break;
1470
1471
        case angle::FormatID::D24_UNORM_S8_UINT:
1503
        case angle::FormatID::D24_UNORM_S8_UINT:
1472
1504
1473
            this->metalFormat    = MTLPixelFormatDepth32Float_Stencil8;
1505
            this->metalFormat    = MTLPixelFormatDepth32Float_Stencil8;
Lines 1477-1491 void Format::init(const DisplayMtl *display, angle::FormatID intendedFormatId_) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_table_autogen.mm_sec10
1477
            this->swizzled = false;
1509
            this->swizzled = false;
1478
            break;
1510
            break;
1479
1511
1480
        case angle::FormatID::ETC1_R8G8B8_UNORM_BLOCK:
1481
1482
            this->metalFormat    = MTLPixelFormatETC2_RGB8;
1483
            this->actualFormatId = angle::FormatID::ETC2_R8G8B8_UNORM_BLOCK;
1484
            this->initFunction   = nullptr;
1485
1486
            this->swizzled = false;
1487
            break;
1488
1489
#endif  // TARGET_OS_OSX || TARGET_OS_MACCATALYST
1512
#endif  // TARGET_OS_OSX || TARGET_OS_MACCATALYST
1490
        default:
1513
        default:
1491
            this->metalFormat    = MTLPixelFormatInvalid;
1514
            this->metalFormat    = MTLPixelFormatInvalid;
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_utils.h -7 / +40 lines
Lines 48-60 struct FormatCaps a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_utils.h_sec1
48
{
48
{
49
    bool isRenderable() const { return colorRenderable || depthRenderable; }
49
    bool isRenderable() const { return colorRenderable || depthRenderable; }
50
50
51
    bool filterable      = false;
51
    bool filterable           = false;
52
    bool writable        = false;
52
    bool writable             = false;
53
    bool colorRenderable = false;
53
    bool colorRenderable      = false;
54
    bool depthRenderable = false;
54
    bool depthRenderable      = false;
55
    bool blendable       = false;
55
    bool blendable            = false;
56
    bool multisample     = false;  // can be used as MSAA target
56
    bool multisample          = false;  // can be used as MSAA target
57
    bool resolve         = false;  // Can be used as resolve target
57
    bool resolve              = false;  // Can be used as resolve target
58
    bool compressed           = false;
59
    NSUInteger pixelBytes     = 0;
60
    NSUInteger pixelBytesMSAA = 0;
61
    NSUInteger channels       = 0;
62
    uint8_t alignment         = 0;
58
};
63
};
59
64
60
// Pixel format
65
// Pixel format
Lines 143-148 class FormatTable final : angle::NonCopyable a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_utils.h_sec2
143
  private:
148
  private:
144
    void initNativeFormatCapsAutogen(const DisplayMtl *display);
149
    void initNativeFormatCapsAutogen(const DisplayMtl *display);
145
    void initNativeFormatCaps(const DisplayMtl *display);
150
    void initNativeFormatCaps(const DisplayMtl *display);
151
146
    void setFormatCaps(MTLPixelFormat formatId,
152
    void setFormatCaps(MTLPixelFormat formatId,
147
                       bool filterable,
153
                       bool filterable,
148
                       bool writable,
154
                       bool writable,
Lines 150-155 class FormatTable final : angle::NonCopyable a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_utils.h_sec3
150
                       bool multisample,
156
                       bool multisample,
151
                       bool resolve,
157
                       bool resolve,
152
                       bool colorRenderable);
158
                       bool colorRenderable);
159
160
    void setFormatCaps(MTLPixelFormat formatId,
161
                       bool filterable,
162
                       bool writable,
163
                       bool blendable,
164
                       bool multisample,
165
                       bool resolve,
166
                       bool colorRenderable,
167
                       NSUInteger bytesPerChannel,
168
                       NSUInteger channels);
169
153
    void setFormatCaps(MTLPixelFormat formatId,
170
    void setFormatCaps(MTLPixelFormat formatId,
154
                       bool filterable,
171
                       bool filterable,
155
                       bool writable,
172
                       bool writable,
Lines 159-166 class FormatTable final : angle::NonCopyable a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_utils.h_sec4
159
                       bool colorRenderable,
176
                       bool colorRenderable,
160
                       bool depthRenderable);
177
                       bool depthRenderable);
161
178
179
    void setFormatCaps(MTLPixelFormat formatId,
180
                       bool filterable,
181
                       bool writable,
182
                       bool blendable,
183
                       bool multisample,
184
                       bool resolve,
185
                       bool colorRenderable,
186
                       bool depthRenderable,
187
                       NSUInteger bytesPerChannel,
188
                       NSUInteger channels);
189
162
    void setCompressedFormatCaps(MTLPixelFormat formatId, bool filterable);
190
    void setCompressedFormatCaps(MTLPixelFormat formatId, bool filterable);
163
191
192
    void adjustFormatCapsForDevice(id<MTLDevice> device,
193
                                   MTLPixelFormat id,
194
                                   bool supportsiOS2,
195
                                   bool supportsiOS4);
196
164
    std::array<Format, angle::kNumANGLEFormats> mPixelFormatTable;
197
    std::array<Format, angle::kNumANGLEFormats> mPixelFormatTable;
165
    std::unordered_map<MTLPixelFormat, FormatCaps> mNativePixelFormatCapsTable;
198
    std::unordered_map<MTLPixelFormat, FormatCaps> mNativePixelFormatCapsTable;
166
    // One for tightly packed buffers, one for general cases.
199
    // One for tightly packed buffers, one for general cases.
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_utils.mm -12 / +315 lines
Lines 77-84 void GenerateTextureCapsMap(const FormatTable &formatTable, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_utils.mm_sec1
77
            textureCaps.renderbuffer =
77
            textureCaps.renderbuffer =
78
                mtlFormat.getCaps().colorRenderable || mtlFormat.getCaps().depthRenderable;
78
                mtlFormat.getCaps().colorRenderable || mtlFormat.getCaps().depthRenderable;
79
            textureCaps.texturable        = true;
79
            textureCaps.texturable        = true;
80
            textureCaps.blendable         = mtlFormat.getCaps().blendable;
81
            textureCaps.textureAttachment = textureCaps.renderbuffer;
80
            textureCaps.textureAttachment = textureCaps.renderbuffer;
81
            textureCaps.blendable         = mtlFormat.getCaps().blendable;
82
        }
82
        }
83
83
84
        if (formatCaps.multisample)
84
        if (formatCaps.multisample)
Lines 148-159 bool Format::needConversion(angle::FormatID srcFormatId) const a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_utils.mm_sec2
148
        // WebGL allows unswizzled mapping when swizzling is not available. No need to convert.
148
        // WebGL allows unswizzled mapping when swizzling is not available. No need to convert.
149
        return false;
149
        return false;
150
    }
150
    }
151
    if (srcFormatId == angle::FormatID::ETC1_R8G8B8_UNORM_BLOCK &&
152
        actualFormatId == angle::FormatID::ETC2_R8G8B8_UNORM_BLOCK)
153
    {
154
        // ETC1 RGB & ETC2 RGB are technically the same.
155
        return false;
156
    }
157
    return srcFormatId != actualFormatId;
151
    return srcFormatId != actualFormatId;
158
}
152
}
159
153
Lines 192-199 angle::Result FormatTable::initialize(const DisplayMtl *display) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_utils.mm_sec3
192
        mPixelFormatTable[i].init(display, formatId);
186
        mPixelFormatTable[i].init(display, formatId);
193
        mPixelFormatTable[i].caps = &mNativePixelFormatCapsTable[mPixelFormatTable[i].metalFormat];
187
        mPixelFormatTable[i].caps = &mNativePixelFormatCapsTable[mPixelFormatTable[i].metalFormat];
194
188
195
        if (!mPixelFormatTable[i].caps->depthRenderable &&
189
        if (mPixelFormatTable[i].actualFormatId != mPixelFormatTable[i].intendedFormatId)
196
            mPixelFormatTable[i].actualFormatId != mPixelFormatTable[i].intendedFormatId)
197
        {
190
        {
198
            mPixelFormatTable[i].textureLoadFunctions = angle::GetLoadFunctionsMap(
191
            mPixelFormatTable[i].textureLoadFunctions = angle::GetLoadFunctionsMap(
199
                mPixelFormatTable[i].intendedAngleFormat().glInternalFormat,
192
                mPixelFormatTable[i].intendedAngleFormat().glInternalFormat,
Lines 204-209 angle::Result FormatTable::initialize(const DisplayMtl *display) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_utils.mm_sec4
204
        mVertexFormatTables[1][i].init(formatId, true);
197
        mVertexFormatTables[1][i].init(formatId, true);
205
    }
198
    }
206
199
200
    // NOTE(hqle): Work-around AMD's issue that D24S8 format sometimes returns zero during sampling:
201
    if (display->getRendererDescription().find("AMD") != std::string::npos)
202
    {
203
        // Fallback to D32_FLOAT_S8X24_UINT.
204
        Format &format =
205
            mPixelFormatTable[static_cast<uint32_t>(angle::FormatID::D24_UNORM_S8_UINT)];
206
        format.actualFormatId       = angle::FormatID::D32_FLOAT_S8X24_UINT;
207
        format.metalFormat          = MTLPixelFormatDepth32Float_Stencil8;
208
        format.initFunction         = nullptr;
209
        format.textureLoadFunctions = nullptr;
210
        format.caps = &mNativePixelFormatCapsTable[MTLPixelFormatDepth32Float_Stencil8];
211
    }
212
207
    return angle::Result::Continue;
213
    return angle::Result::Continue;
208
}
214
}
209
215
Lines 239-248 void FormatTable::setFormatCaps(MTLPixelFormat formatId, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_utils.mm_sec5
239
                                bool colorRenderable)
245
                                bool colorRenderable)
240
{
246
{
241
    setFormatCaps(formatId, filterable, writable, blendable, multisample, resolve, colorRenderable,
247
    setFormatCaps(formatId, filterable, writable, blendable, multisample, resolve, colorRenderable,
242
                  false);
248
                  false, 0);
249
}
250
void FormatTable::setFormatCaps(MTLPixelFormat formatId,
251
                                bool filterable,
252
                                bool writable,
253
                                bool blendable,
254
                                bool multisample,
255
                                bool resolve,
256
                                bool colorRenderable,
257
                                NSUInteger pixelBytes,
258
                                NSUInteger channels)
259
{
260
    setFormatCaps(formatId, filterable, writable, blendable, multisample, resolve, colorRenderable,
261
                  false, pixelBytes, channels);
243
}
262
}
244
263
245
void FormatTable::setFormatCaps(MTLPixelFormat id,
264
void FormatTable::setFormatCaps(MTLPixelFormat formatId,
246
                                bool filterable,
265
                                bool filterable,
247
                                bool writable,
266
                                bool writable,
248
                                bool blendable,
267
                                bool blendable,
Lines 250-255 void FormatTable::setFormatCaps(MTLPixelFormat id, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_utils.mm_sec6
250
                                bool resolve,
269
                                bool resolve,
251
                                bool colorRenderable,
270
                                bool colorRenderable,
252
                                bool depthRenderable)
271
                                bool depthRenderable)
272
{
273
    setFormatCaps(formatId, filterable, writable, blendable, multisample, resolve, colorRenderable,
274
                  depthRenderable, 0, 0);
275
}
276
void FormatTable::setFormatCaps(MTLPixelFormat id,
277
                                bool filterable,
278
                                bool writable,
279
                                bool blendable,
280
                                bool multisample,
281
                                bool resolve,
282
                                bool colorRenderable,
283
                                bool depthRenderable,
284
                                NSUInteger pixelBytes,
285
                                NSUInteger channels)
253
{
286
{
254
    mNativePixelFormatCapsTable[id].filterable      = filterable;
287
    mNativePixelFormatCapsTable[id].filterable      = filterable;
255
    mNativePixelFormatCapsTable[id].writable        = writable;
288
    mNativePixelFormatCapsTable[id].writable        = writable;
Lines 258-263 void FormatTable::setFormatCaps(MTLPixelFormat id, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_utils.mm_sec7
258
    mNativePixelFormatCapsTable[id].blendable       = blendable;
291
    mNativePixelFormatCapsTable[id].blendable       = blendable;
259
    mNativePixelFormatCapsTable[id].multisample     = multisample;
292
    mNativePixelFormatCapsTable[id].multisample     = multisample;
260
    mNativePixelFormatCapsTable[id].resolve         = resolve;
293
    mNativePixelFormatCapsTable[id].resolve         = resolve;
294
    mNativePixelFormatCapsTable[id].pixelBytes      = pixelBytes;
295
    mNativePixelFormatCapsTable[id].pixelBytesMSAA  = pixelBytes;
296
    mNativePixelFormatCapsTable[id].channels        = channels;
297
    if (channels != 0)
298
        mNativePixelFormatCapsTable[id].alignment = MAX(pixelBytes / channels, 1U);
261
}
299
}
262
300
263
void FormatTable::setCompressedFormatCaps(MTLPixelFormat formatId, bool filterable)
301
void FormatTable::setCompressedFormatCaps(MTLPixelFormat formatId, bool filterable)
Lines 265-273 void FormatTable::setCompressedFormatCaps(MTLPixelFormat formatId, bool filterab a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_format_utils.mm_sec8
265
    setFormatCaps(formatId, filterable, false, false, false, false, false, false);
303
    setFormatCaps(formatId, filterable, false, false, false, false, false, false);
266
}
304
}
267
305
306
void FormatTable::adjustFormatCapsForDevice(id<MTLDevice> device,
307
                                            MTLPixelFormat id,
308
                                            bool supportsiOS2,
309
                                            bool supportsiOS4)
310
{
311
#if !(TARGET_OS_OSX || TARGET_OS_MACCATALYST)
312
313
    NSUInteger pixelBytesRender     = mNativePixelFormatCapsTable[id].pixelBytes;
314
    NSUInteger pixelBytesRenderMSAA = mNativePixelFormatCapsTable[id].pixelBytesMSAA;
315
    NSUInteger alignment            = mNativePixelFormatCapsTable[id].alignment;
316
317
// Override the current pixelBytesRender
318
#    define SPECIFIC(_pixelFormat, _pixelBytesRender)                                            \
319
        case _pixelFormat:                                                                       \
320
            pixelBytesRender     = _pixelBytesRender;                                            \
321
            pixelBytesRenderMSAA = _pixelBytesRender;                                            \
322
            alignment =                                                                          \
323
                supportsiOS4 ? _pixelBytesRender / mNativePixelFormatCapsTable[id].channels : 4; \
324
            break
325
// Override the current pixel bytes render, and MSAA
326
#    define SPECIFIC_MSAA(_pixelFormat, _pixelBytesRender, _pixelBytesRenderMSAA)                \
327
        case _pixelFormat:                                                                       \
328
            pixelBytesRender     = _pixelBytesRender;                                            \
329
            pixelBytesRenderMSAA = _pixelBytesRenderMSAA;                                        \
330
            alignment =                                                                          \
331
                supportsiOS4 ? _pixelBytesRender / mNativePixelFormatCapsTable[id].channels : 4; \
332
            break
333
// Override the current pixelBytesRender, and alignment
334
#    define SPECIFIC_ALIGN(_pixelFormat, _pixelBytesRender, _alignment) \
335
        case _pixelFormat:                                              \
336
            pixelBytesRender     = _pixelBytesRender;                   \
337
            pixelBytesRenderMSAA = _pixelBytesRender;                   \
338
            alignment            = _alignment;                          \
339
            break
340
341
    if (!mNativePixelFormatCapsTable[id].compressed)
342
    {
343
        // On AppleGPUFamily4+, there is no 4byte minimum requirement for render targets
344
        uint32_t minSize     = supportsiOS4 ? 1U : 4U;
345
        pixelBytesRender     = MAX(mNativePixelFormatCapsTable[id].pixelBytes, minSize);
346
        pixelBytesRenderMSAA = pixelBytesRender;
347
        alignment =
348
            supportsiOS4 ? MAX(pixelBytesRender / mNativePixelFormatCapsTable[id].channels, 1U) : 4;
349
    }
350
351
    // This list of tables starts from a general multi-platform table,
352
    // to specific platforms (i.e. ios2, ios4) inheriting from the previous tables
353
354
    // Start off with the general case
355
    switch ((NSUInteger)id)
356
    {
357
        SPECIFIC(MTLPixelFormatB5G6R5Unorm, 4U);
358
        SPECIFIC(MTLPixelFormatA1BGR5Unorm, 4U);
359
        SPECIFIC(MTLPixelFormatABGR4Unorm, 4U);
360
        SPECIFIC(MTLPixelFormatBGR5A1Unorm, 4U);
361
362
        SPECIFIC(MTLPixelFormatRGBA8Unorm, 4U);
363
        SPECIFIC(MTLPixelFormatBGRA8Unorm, 4U);
364
365
        SPECIFIC_MSAA(MTLPixelFormatRGBA8Unorm_sRGB, 4U, 8U);
366
        SPECIFIC_MSAA(MTLPixelFormatBGRA8Unorm_sRGB, 4U, 8U);
367
        SPECIFIC_MSAA(MTLPixelFormatRGBA8Snorm, 4U, 8U);
368
        SPECIFIC_MSAA(MTLPixelFormatRGB10A2Uint, 4U, 8U);
369
370
        SPECIFIC(MTLPixelFormatRGB10A2Unorm, 8U);
371
        SPECIFIC(MTLPixelFormatBGR10A2Unorm, 8U);
372
373
        SPECIFIC(MTLPixelFormatRG11B10Float, 8U);
374
375
        SPECIFIC(MTLPixelFormatRGB9E5Float, 8U);
376
377
        SPECIFIC(MTLPixelFormatStencil8, 1U);
378
    }
379
380
    // Override based ios2
381
    if (supportsiOS2)
382
    {
383
        switch ((NSUInteger)id)
384
        {
385
            SPECIFIC(MTLPixelFormatB5G6R5Unorm, 8U);
386
            SPECIFIC(MTLPixelFormatA1BGR5Unorm, 8U);
387
            SPECIFIC(MTLPixelFormatABGR4Unorm, 8U);
388
            SPECIFIC(MTLPixelFormatBGR5A1Unorm, 8U);
389
            SPECIFIC_MSAA(MTLPixelFormatRGBA8Unorm, 4U, 8U);
390
            SPECIFIC_MSAA(MTLPixelFormatBGRA8Unorm, 4U, 8U);
391
        }
392
    }
393
394
    // Override based on ios4
395
    if (supportsiOS4)
396
    {
397
        switch ((NSUInteger)id)
398
        {
399
            SPECIFIC_ALIGN(MTLPixelFormatB5G6R5Unorm, 6U, 2U);
400
            SPECIFIC(MTLPixelFormatRGBA8Unorm, 4U);
401
            SPECIFIC(MTLPixelFormatBGRA8Unorm, 4U);
402
403
            SPECIFIC(MTLPixelFormatRGBA8Unorm_sRGB, 4U);
404
            SPECIFIC(MTLPixelFormatBGRA8Unorm_sRGB, 4U);
405
406
            SPECIFIC(MTLPixelFormatRGBA8Snorm, 4U);
407
408
            SPECIFIC_ALIGN(MTLPixelFormatRGB10A2Unorm, 4U, 4U);
409
            SPECIFIC_ALIGN(MTLPixelFormatBGR10A2Unorm, 4U, 4U);
410
            SPECIFIC(MTLPixelFormatRGB10A2Uint, 8U);
411
412
            SPECIFIC_ALIGN(MTLPixelFormatRG11B10Float, 4U, 4U);
413
414
            SPECIFIC_ALIGN(MTLPixelFormatRGB9E5Float, 4U, 4U);
415
        }
416
    }
417
    mNativePixelFormatCapsTable[id].pixelBytes     = pixelBytesRender;
418
    mNativePixelFormatCapsTable[id].pixelBytesMSAA = pixelBytesRenderMSAA;
419
    mNativePixelFormatCapsTable[id].alignment      = alignment;
420
421
#    undef SPECIFIC
422
#    undef SPECIFIC_ALIGN
423
#    undef SPECIFIC_MSAA
424
#endif
425
    // macOS does not need to perform any additoinal adjustment. These values are only used to check
426
    // valid MRT sizes on iOS.
427
}
428
268
void FormatTable::initNativeFormatCaps(const DisplayMtl *display)
429
void FormatTable::initNativeFormatCaps(const DisplayMtl *display)
269
{
430
{
270
    initNativeFormatCapsAutogen(display);
431
    const angle::FeaturesMtl &featuresMtl = display->getFeatures();
432
    // Skip auto resolve if either hasDepth/StencilAutoResolve or allowMultisampleStoreAndResolve
433
    // feature are disabled.
434
    bool supportDepthAutoResolve = featuresMtl.hasDepthAutoResolve.enabled &&
435
                                   featuresMtl.allowMultisampleStoreAndResolve.enabled;
436
    bool supportStencilAutoResolve = featuresMtl.hasStencilAutoResolve.enabled &&
437
                                     featuresMtl.allowMultisampleStoreAndResolve.enabled;
438
    bool supportDepthStencilAutoResolve = supportDepthAutoResolve && supportStencilAutoResolve;
439
440
    // Source: https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
441
    // clang-format off
442
443
    //            |  formatId                  | filterable    |  writable  |  blendable |  multisample |  resolve                              | colorRenderable | bytesPerChannel | channel
444
    setFormatCaps(MTLPixelFormatA8Unorm,        true,            false,       false,          false,       false,                                false, 1U, 1U);
445
    setFormatCaps(MTLPixelFormatR8Unorm,        true,            true,        true,           true,        true,                                 true,  1U, 1U);
446
    setFormatCaps(MTLPixelFormatR8Snorm,        true,            true,        true,           true,      display->supportsEitherGPUFamily(2, 1),  true,  1U, 1U);
447
    setFormatCaps(MTLPixelFormatR16Unorm,       true,            true,        true,           true,      display->supportsEitherGPUFamily(1, 1),        true,  2U, 1U);
448
    setFormatCaps(MTLPixelFormatR16Snorm,       true,            true,        true,           true,      display->supportsEitherGPUFamily(1, 1),        true,  2U, 1U);
449
    setFormatCaps(MTLPixelFormatRG8Unorm,       true,            true,        true,           true,        true,                                 true,  1U, 1U);
450
    setFormatCaps(MTLPixelFormatRG8Snorm,       true,            true,        true,           true,      display->supportsEitherGPUFamily(2, 1),  true,  2U, 2U);
451
    setFormatCaps(MTLPixelFormatRG16Unorm,      true,            true,        true,           true,      display->supportsEitherGPUFamily(1, 1),        true,  4U, 2U);
452
    setFormatCaps(MTLPixelFormatRG16Snorm,      true,            true,        true,           true,      display->supportsEitherGPUFamily(1, 1),        true,  4U, 2U);
453
    setFormatCaps(MTLPixelFormatRGBA16Unorm,    true,            true,        true,           true,      display->supportsEitherGPUFamily(1, 1),        true,  8U, 4U);
454
    setFormatCaps(MTLPixelFormatRGBA16Snorm,    true,            true,        true,           true,      display->supportsEitherGPUFamily(1, 1),        true,  8U, 4U);
455
    setFormatCaps(MTLPixelFormatRGBA16Float,    true,            true,        true,           true,        true,                                 true,  8U, 4U);
456
457
    //            |  formatId                      | filterable    |  writable                         |  blendable |  multisample |  resolve                              | colorRenderable |
458
    setFormatCaps(MTLPixelFormatRGBA8Unorm,          true,            true,                               true,           true,        true,                                    true,   4U, 4U);
459
    setFormatCaps(MTLPixelFormatRGBA8Unorm_sRGB,     true,          display->supportsIOSGPUFamily(2),      true,           true,        true,                                    true,   4U, 4U);
460
    setFormatCaps(MTLPixelFormatRGBA8Snorm,          true,            true,                               true,           true,     display->supportsEitherGPUFamily(2, 1),      true,   4U, 4U);
461
    setFormatCaps(MTLPixelFormatBGRA8Unorm,          true,            true,                               true,           true,        true,                                    true,   4U, 4U);
462
    setFormatCaps(MTLPixelFormatBGRA8Unorm_sRGB,     true,          display->supportsIOSGPUFamily(2),      true,           true,        true,                                    true,   4U, 4U);
463
464
    //            |  formatId              | filterable                    |  writable  |  blendable |  multisample |  resolve                              | colorRenderable |
465
    setFormatCaps(MTLPixelFormatR16Float,       true,                          true,        true,           true,        true,                                 true,    2U, 1U);
466
    setFormatCaps(MTLPixelFormatRG16Float,      true,                          true,        true,           true,        true,                                 true,    4U, 2U);
467
    setFormatCaps(MTLPixelFormatR32Float,    display->supportsEitherGPUFamily(1,1),  true,        true,           true,      display->supportsEitherGPUFamily(1,1),        true,    4U, 1U);
468
469
#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST
470
    //            |  formatId                  | filterable    |  writable  |  blendable |  multisample |  resolve   | colorRenderable |
471
    setFormatCaps(MTLPixelFormatB5G6R5Unorm,      true,            false,        true,           true,        true,      true,  2U, 3U);
472
    setFormatCaps(MTLPixelFormatABGR4Unorm,       true,            false,        true,           true,        true,      true,  2U, 4U);
473
    setFormatCaps(MTLPixelFormatBGR5A1Unorm,      true,            false,        true,           true,        true,      true,  2U, 4U);
474
    setFormatCaps(MTLPixelFormatA1BGR5Unorm,      true,            false,        true,           true,        true,      true,  2U, 4U);
475
#endif
476
477
    //            |  formatId                  | filterable    |  writable                                 |  blendable |  multisample |  resolve   | colorRenderable |
478
    setFormatCaps(MTLPixelFormatBGR10A2Unorm,     true,         display->supportsEitherGPUFamily(3, 1),       true,           true,        true,      true,  4U, 4U);
479
    setFormatCaps(MTLPixelFormatRGB10A2Unorm,     true,         display->supportsEitherGPUFamily(3, 1),       true,           true,        true,      true,  4U, 4U);
480
    setFormatCaps(MTLPixelFormatRGB10A2Uint,      false,        display->supportsEitherGPUFamily(3, 1),       false,          true,        false,     true,  4U, 4U);
481
    setFormatCaps(MTLPixelFormatRG11B10Float,     true,         display->supportsEitherGPUFamily(3, 1),       true,           true,        true,      true,  4U, 3U);
482
483
    //            |  formatId                  | filterable    |  writable                         |  blendable                     |  multisample                    |  resolve                       | colorRenderable                 |
484
    setFormatCaps(MTLPixelFormatRGB9E5Float,       true,          display->supportsIOSGPUFamily(3),  display->supportsIOSGPUFamily(1),  display->supportsIOSGPUFamily(1), display->supportsIOSGPUFamily(1), display->supportsIOSGPUFamily(1), 4U, 3U);
485
486
    //            |  formatId               | filterable    |  writable  |  blendable  |  multisample                        |  resolve      | colorRenderable |
487
    setFormatCaps(MTLPixelFormatR8Uint,        false,           true,        false,          true,                             false,         true, 1U, 1U);
488
    setFormatCaps(MTLPixelFormatR8Sint,        false,           true,        false,          true,                             false,         true, 1U, 1U);
489
    setFormatCaps(MTLPixelFormatR16Uint,       false,           true,        false,          true,                             false,         true, 2U, 1U);
490
    setFormatCaps(MTLPixelFormatR16Sint,       false,           true,        false,          true,                             false,         true, 4U, 1U);
491
    setFormatCaps(MTLPixelFormatRG8Uint,       false,           true,        false,          true,                             false,         true, 2U, 2U);
492
    setFormatCaps(MTLPixelFormatRG8Sint,       false,           true,        false,          true,                             false,         true, 2U, 2U);
493
    setFormatCaps(MTLPixelFormatR32Uint,       false,           true,        false,          display->supportsEitherGPUFamily(1,1),  false,         true, 4U, 1U);
494
    setFormatCaps(MTLPixelFormatR32Sint,       false,           true,        false,          display->supportsEitherGPUFamily(1,1),  false,         true, 4U, 1U);
495
    setFormatCaps(MTLPixelFormatRG16Uint,      false,           true,        false,          true,                             false,         true, 4U, 2U);
496
    setFormatCaps(MTLPixelFormatRG16Sint,      false,           true,        false,          true,                             false,         true, 4U, 2U);
497
    setFormatCaps(MTLPixelFormatRGBA8Uint,     false,           true,        false,          true,                             false,         true, 4U, 1U);
498
    setFormatCaps(MTLPixelFormatRGBA8Sint,     false,           true,        false,          true,                             false,         true, 4U, 1U);
499
    setFormatCaps(MTLPixelFormatRG32Uint,      false,           true,        false,          display->supportsEitherGPUFamily(1,1),  false,         true, 8U, 2U);
500
    setFormatCaps(MTLPixelFormatRG32Sint,      false,           true,        false,          display->supportsEitherGPUFamily(1,1),  false,         true, 8U, 2U);
501
    setFormatCaps(MTLPixelFormatRGBA16Uint,    false,           true,        false,          true,                             false,         true, 8U, 4U);
502
    setFormatCaps(MTLPixelFormatRGBA16Sint,    false,           true,        false,          true,                             false,         true, 8U, 4U);
503
    setFormatCaps(MTLPixelFormatRGBA32Uint,    false,           true,        false,          display->supportsEitherGPUFamily(1,1),  false,         true, 16U, 4U);
504
    setFormatCaps(MTLPixelFormatRGBA32Sint,    false,           true,        false,          display->supportsEitherGPUFamily(1,1),  false,         true, 16U, 4U);
505
506
    //            |  formatId                   | filterable                      |  writable  |  blendable                     |  multisample                     |  resolve                         | colorRenderable |
507
    setFormatCaps(MTLPixelFormatRG32Float,       display->supportsEitherGPUFamily(1,1),   true,        true,                            display->supportsEitherGPUFamily(1,1),  display->supportsEitherGPUFamily(1,1),         true,  8U, 2U);
508
    setFormatCaps(MTLPixelFormatRGBA32Float,     display->supportsEitherGPUFamily(1,1),   true,        display->supportsEitherGPUFamily(1,1), display->supportsEitherGPUFamily(1,1),  display->supportsEitherGPUFamily(1,1),         true,  16U, 4U);
509
510
    //            |  formatId                           | filterable                       |  writable  |  blendable |  multisample |  resolve                                | colorRenderable | depthRenderable                    |
511
    setFormatCaps(MTLPixelFormatDepth32Float,               display->supportsEitherGPUFamily(1,1),   false,        false,           true,    supportDepthAutoResolve,                    false,            true,  4U, 1U);
512
    setFormatCaps(MTLPixelFormatStencil8,                   false,                             false,        false,           true,    false,                                      false,            true,  1U, 1U);
513
    setFormatCaps(MTLPixelFormatDepth32Float_Stencil8,      display->supportsEitherGPUFamily(1,1),   false,        false,           true,    supportDepthStencilAutoResolve,             false,            true,  8U, 2U);
514
//ToDo: @available on 13.0
515
    setFormatCaps(MTLPixelFormatDepth16Unorm,               true,                              false,        false,           true,    supportDepthAutoResolve,                    false,            true,  2U, 1U);
516
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
517
    setFormatCaps(MTLPixelFormatDepth24Unorm_Stencil8,      display->supportsEitherGPUFamily(1,1),   false,        false,           true,    supportDepthStencilAutoResolve,             false,            display->supportsEitherGPUFamily(1,1), 4U, 2U);
518
519
    setCompressedFormatCaps(MTLPixelFormatBC1_RGBA, true);
520
    setCompressedFormatCaps(MTLPixelFormatBC1_RGBA_sRGB, true);
521
    setCompressedFormatCaps(MTLPixelFormatBC2_RGBA, true);
522
    setCompressedFormatCaps(MTLPixelFormatBC2_RGBA_sRGB, true);
523
    setCompressedFormatCaps(MTLPixelFormatBC3_RGBA, true);
524
    setCompressedFormatCaps(MTLPixelFormatBC3_RGBA_sRGB, true);
525
#else
526
    setCompressedFormatCaps(MTLPixelFormatPVRTC_RGB_2BPP, true);
527
    setCompressedFormatCaps(MTLPixelFormatPVRTC_RGB_2BPP_sRGB, true);
528
    setCompressedFormatCaps(MTLPixelFormatPVRTC_RGB_4BPP, true);
529
    setCompressedFormatCaps(MTLPixelFormatPVRTC_RGB_4BPP_sRGB, true);
530
    setCompressedFormatCaps(MTLPixelFormatPVRTC_RGBA_2BPP, true);
531
    setCompressedFormatCaps(MTLPixelFormatPVRTC_RGBA_2BPP_sRGB, true);
532
    setCompressedFormatCaps(MTLPixelFormatPVRTC_RGBA_4BPP, true);
533
    setCompressedFormatCaps(MTLPixelFormatPVRTC_RGBA_4BPP_sRGB, true);
534
    setCompressedFormatCaps(MTLPixelFormatEAC_R11Unorm, true);
535
    setCompressedFormatCaps(MTLPixelFormatEAC_R11Snorm, true);
536
    setCompressedFormatCaps(MTLPixelFormatEAC_RG11Unorm, true);
537
    setCompressedFormatCaps(MTLPixelFormatEAC_RG11Snorm, true);
538
    setCompressedFormatCaps(MTLPixelFormatEAC_RGBA8, true);
539
    setCompressedFormatCaps(MTLPixelFormatEAC_RGBA8_sRGB, true);
540
    setCompressedFormatCaps(MTLPixelFormatETC2_RGB8, true);
541
    setCompressedFormatCaps(MTLPixelFormatETC2_RGB8_sRGB, true);
542
    setCompressedFormatCaps(MTLPixelFormatETC2_RGB8A1, true);
543
    setCompressedFormatCaps(MTLPixelFormatETC2_RGB8A1_sRGB, true);
544
    setCompressedFormatCaps(MTLPixelFormatASTC_4x4_sRGB, true);
545
    setCompressedFormatCaps(MTLPixelFormatASTC_5x4_sRGB, true);
546
    setCompressedFormatCaps(MTLPixelFormatASTC_5x5_sRGB, true);
547
    setCompressedFormatCaps(MTLPixelFormatASTC_6x5_sRGB, true);
548
    setCompressedFormatCaps(MTLPixelFormatASTC_6x6_sRGB, true);
549
    setCompressedFormatCaps(MTLPixelFormatASTC_8x5_sRGB, true);
550
    setCompressedFormatCaps(MTLPixelFormatASTC_8x6_sRGB, true);
551
    setCompressedFormatCaps(MTLPixelFormatASTC_8x8_sRGB, true);
552
    setCompressedFormatCaps(MTLPixelFormatASTC_10x5_sRGB, true);
553
    setCompressedFormatCaps(MTLPixelFormatASTC_10x6_sRGB, true);
554
    setCompressedFormatCaps(MTLPixelFormatASTC_10x8_sRGB, true);
555
    setCompressedFormatCaps(MTLPixelFormatASTC_10x10_sRGB, true);
556
    setCompressedFormatCaps(MTLPixelFormatASTC_12x10_sRGB, true);
557
    setCompressedFormatCaps(MTLPixelFormatASTC_12x12_sRGB, true);
558
    setCompressedFormatCaps(MTLPixelFormatASTC_4x4_LDR, true);
559
    setCompressedFormatCaps(MTLPixelFormatASTC_5x4_LDR, true);
560
    setCompressedFormatCaps(MTLPixelFormatASTC_5x5_LDR, true);
561
    setCompressedFormatCaps(MTLPixelFormatASTC_6x5_LDR, true);
562
    setCompressedFormatCaps(MTLPixelFormatASTC_6x6_LDR, true);
563
    setCompressedFormatCaps(MTLPixelFormatASTC_8x5_LDR, true);
564
    setCompressedFormatCaps(MTLPixelFormatASTC_8x6_LDR, true);
565
    setCompressedFormatCaps(MTLPixelFormatASTC_8x8_LDR, true);
566
    setCompressedFormatCaps(MTLPixelFormatASTC_10x5_LDR, true);
567
    setCompressedFormatCaps(MTLPixelFormatASTC_10x6_LDR, true);
568
    setCompressedFormatCaps(MTLPixelFormatASTC_10x8_LDR, true);
569
    setCompressedFormatCaps(MTLPixelFormatASTC_10x10_LDR, true);
570
    setCompressedFormatCaps(MTLPixelFormatASTC_12x10_LDR, true);
571
    setCompressedFormatCaps(MTLPixelFormatASTC_12x12_LDR, true);
572
#endif
573
    // clang-format on
271
}
574
}
272
575
273
}  // namespace mtl
576
}  // namespace mtl
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_glslang_mtl_utils.h +57 lines
Line 0 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_glslang_mtl_utils.h_sec1
1
//
2
//  mtl_glslang_mtl_utils.h
3
//  ANGLE
4
//
5
//  Created by Kyle Piddington on 11/10/20.
6
//
7
8
#ifndef mtl_glslang_mtl_utils_h
9
#define mtl_glslang_mtl_utils_h
10
#include "libANGLE/Context.h"
11
#include "libANGLE/renderer/ProgramImpl.h"
12
#include "libANGLE/renderer/glslang_wrapper_utils.h"
13
#include "libANGLE/renderer/metal/mtl_common.h"
14
15
namespace rx
16
{
17
namespace mtl
18
{
19
struct SamplerBinding
20
{
21
    uint32_t textureBinding = 0;
22
    uint32_t samplerBinding = 0;
23
};
24
25
struct TranslatedShaderInfo
26
{
27
    void reset();
28
    // Translated Metal source code
29
    std::string metalShaderSource;
30
    // Metal library compiled from source code above. Used by ProgramMtl.
31
    AutoObjCPtr<id<MTLLibrary>> metalLibrary;
32
    std::array<SamplerBinding, kMaxGLSamplerBindings> actualSamplerBindings;
33
    std::array<uint32_t, kMaxGLUBOBindings> actualUBOBindings;
34
    std::array<uint32_t, kMaxShaderXFBs> actualXFBBindings;
35
    bool hasUBOArgumentBuffer;
36
};
37
void MSLGetShaderSource(const gl::ProgramState &programState,
38
                        const gl::ProgramLinkedResources &resources,
39
                        gl::ShaderMap<std::string> *shaderSourcesOut,
40
                        ShaderMapInterfaceVariableInfoMap *variableInfoMapOut);
41
42
angle::Result GlslangGetMSL(const gl::Context *glContext,
43
                            const gl::ProgramState &programState,
44
                            const gl::Caps &glCaps,
45
                            const gl::ShaderMap<std::string> &shaderSources,
46
                            const ShaderMapInterfaceVariableInfoMap &variableInfoMap,
47
                            gl::ShaderMap<TranslatedShaderInfo> *mslShaderInfoOut,
48
                            gl::ShaderMap<std::string> *mslCodeOut,
49
                            size_t xfbBufferCount);
50
51
// Get equivalent shadow compare mode that is used in translated msl shader.
52
uint MslGetShaderShadowCompareMode(GLenum mode, GLenum func);
53
54
}  // namespace mtl
55
}  // namespace rx
56
57
#endif /* mtl_glslang_mtl_utils_h */
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_glslang_mtl_utils.mm +241 lines
Line 0 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_glslang_mtl_utils.mm_sec1
1
//
2
//  mgl_glslang_mtl_utils.m
3
//  ANGLE (static)
4
//
5
//  Created by Kyle Piddington on 11/10/20.
6
//
7
8
#import <Foundation/Foundation.h>
9
10
#include "compiler/translator/TranslatorMetalDirect.h"
11
#include "libANGLE/renderer/metal/ShaderMtl.h"
12
#include "libANGLE/renderer/metal/mtl_glslang_mtl_utils.h"
13
14
namespace rx
15
{
16
namespace mtl
17
{
18
19
void TranslatedShaderInfo::reset()
20
{
21
    metalShaderSource.clear();
22
    metalLibrary         = nil;
23
    hasUBOArgumentBuffer = false;
24
    for (mtl::SamplerBinding &binding : actualSamplerBindings)
25
    {
26
        binding.textureBinding = mtl::kMaxShaderSamplers;
27
    }
28
29
    for (uint32_t &binding : actualUBOBindings)
30
    {
31
        binding = mtl::kMaxShaderBuffers;
32
    }
33
34
    for (uint32_t &binding : actualXFBBindings)
35
    {
36
        binding = mtl::kMaxShaderBuffers;
37
    }
38
}
39
40
// Original mapping of front end from sampler name to multiple sampler slots (in form of
41
// slot:count pair)
42
using OriginalSamplerBindingMap =
43
    std::unordered_map<std::string, std::vector<std::pair<uint32_t, uint32_t>>>;
44
45
bool MappedSamplerNameNeedsUserDefinedPrefix(const std::string &originalName)
46
{
47
    return originalName.find('.') == std::string::npos;
48
}
49
50
static std::string MSLGetMappedSamplerName(const std::string &originalName)
51
{
52
    std::string samplerName = originalName;
53
54
    // Samplers in structs are extracted.
55
    std::replace(samplerName.begin(), samplerName.end(), '.', '_');
56
57
    // Remove array elements
58
    auto out = samplerName.begin();
59
    for (auto in = samplerName.begin(); in != samplerName.end(); in++)
60
    {
61
        if (*in == '[')
62
        {
63
            while (*in != ']')
64
            {
65
                in++;
66
                ASSERT(in != samplerName.end());
67
            }
68
        }
69
        else
70
        {
71
            *out++ = *in;
72
        }
73
    }
74
75
    samplerName.erase(out, samplerName.end());
76
77
    if (MappedSamplerNameNeedsUserDefinedPrefix(originalName))
78
    {
79
        samplerName = sh::kUserDefinedNamePrefix + samplerName;
80
    }
81
82
    return samplerName;
83
}
84
85
void MSLGetShaderSource(const gl::ProgramState &programState,
86
                        const gl::ProgramLinkedResources &resources,
87
                        gl::ShaderMap<std::string> *shaderSourcesOut,
88
                        ShaderMapInterfaceVariableInfoMap *variableInfoMapOut)
89
{
90
    for (const gl::ShaderType shaderType : gl::AllShaderTypes())
91
    {
92
        gl::Shader *glShader            = programState.getAttachedShader(shaderType);
93
        (*shaderSourcesOut)[shaderType] = glShader ? glShader->getTranslatedSource() : "";
94
    }
95
}
96
97
void GetAssignedSamplerBindings(const sh::TranslatorMetalReflection *reflection,
98
                                const OriginalSamplerBindingMap &originalBindings,
99
                                std::unordered_set<std::string> &structSamplers,
100
                                std::array<SamplerBinding, mtl::kMaxGLSamplerBindings> *bindings)
101
{
102
    for (auto &sampler : reflection->getSamplerBindings())
103
    {
104
        const std::string &name          = sampler.first;
105
        const uint32_t actualSamplerSlot = (uint32_t)reflection->getSamplerBinding(name);
106
        const uint32_t actualTextureSlot = (uint32_t)reflection->getTextureBinding(name);
107
108
        // Assign sequential index for subsequent array elements
109
        const bool structSampler = structSamplers.find(name) != structSamplers.end();
110
        const std::string mappedName =
111
            structSampler ? name : MSLGetMappedSamplerName(sh::kUserDefinedNamePrefix + name);
112
        auto original = originalBindings.find(mappedName);
113
        if (original != originalBindings.end())
114
        {
115
            const std::vector<std::pair<uint32_t, uint32_t>> &resOrignalBindings =
116
                originalBindings.at(mappedName);
117
            uint32_t currentTextureSlot = actualTextureSlot;
118
            uint32_t currentSamplerSlot = actualSamplerSlot;
119
            for (const std::pair<uint32_t, uint32_t> &originalBindingRange : resOrignalBindings)
120
            {
121
                SamplerBinding &actualBinding = bindings->at(originalBindingRange.first);
122
                actualBinding.textureBinding  = currentTextureSlot;
123
                actualBinding.samplerBinding  = currentSamplerSlot;
124
125
                currentTextureSlot += originalBindingRange.second;
126
                currentSamplerSlot += originalBindingRange.second;
127
            }
128
        }
129
    }
130
}
131
132
sh::TranslatorMetalReflection *getReflectionFromShader(gl::Shader *shader)
133
{
134
    ShaderMtl *shaderInstance = static_cast<ShaderMtl *>(shader->getImplementation());
135
    return shaderInstance->getTranslatorMetalReflection();
136
}
137
138
sh::TranslatorMetalReflection *getReflectionFromCompiler(gl::Compiler *compiler,
139
                                                         gl::ShaderType type)
140
{
141
    auto compilerInstance      = compiler->getInstance(type);
142
    sh::TShHandleBase *base    = static_cast<sh::TShHandleBase *>(compilerInstance.getHandle());
143
    auto translatorMetalDirect = base->getAsTranslatorMetalDirect();
144
    compiler->putInstance(std::move(compilerInstance));
145
    return translatorMetalDirect->getTranslatorMetalReflection();
146
}
147
148
angle::Result GlslangGetMSL(const gl::Context *glContext,
149
                            const gl::ProgramState &programState,
150
                            const gl::Caps &glCaps,
151
                            const gl::ShaderMap<std::string> &shaderSources,
152
                            const ShaderMapInterfaceVariableInfoMap &variableInfoMap,
153
                            gl::ShaderMap<TranslatedShaderInfo> *mslShaderInfoOut,
154
                            gl::ShaderMap<std::string> *mslCodeOut,
155
                            size_t xfbBufferCount)
156
{
157
    // Retrieve original uniform buffer bindings generated by front end. We will need to do a remap.
158
    std::unordered_map<std::string, uint32_t> uboOriginalBindings;
159
    const std::vector<gl::InterfaceBlock> &blocks = programState.getUniformBlocks();
160
    for (uint32_t bufferIdx = 0; bufferIdx < blocks.size(); ++bufferIdx)
161
    {
162
        const gl::InterfaceBlock &block = blocks[bufferIdx];
163
        if (!uboOriginalBindings.count(block.mappedName))
164
        {
165
            uboOriginalBindings[block.mappedName] = bufferIdx;
166
        }
167
    }
168
    // Retrieve original sampler bindings produced by front end.
169
    OriginalSamplerBindingMap originalSamplerBindings;
170
    const std::vector<gl::SamplerBinding> &samplerBindings = programState.getSamplerBindings();
171
    const std::vector<gl::LinkedUniform> &uniforms         = programState.getUniforms();
172
173
    std::unordered_set<std::string> structSamplers = {};
174
175
    for (uint32_t textureIndex = 0; textureIndex < samplerBindings.size(); ++textureIndex)
176
    {
177
        const gl::SamplerBinding &samplerBinding = samplerBindings[textureIndex];
178
        uint32_t uniformIndex = programState.getUniformIndexFromSamplerIndex(textureIndex);
179
        const gl::LinkedUniform &samplerUniform = uniforms[uniformIndex];
180
        bool isSamplerInStruct        = samplerUniform.name.find('.') != std::string::npos;
181
        std::string mappedSamplerName = isSamplerInStruct
182
                                            ? MSLGetMappedSamplerName(samplerUniform.name)
183
                                            : MSLGetMappedSamplerName(samplerUniform.mappedName);
184
        // These need to be prefixed later seperately
185
        if (isSamplerInStruct)
186
            structSamplers.insert(mappedSamplerName);
187
        originalSamplerBindings[mappedSamplerName].push_back(
188
            {textureIndex, static_cast<uint32_t>(samplerBinding.boundTextureUnits.size())});
189
    }
190
    for (gl::ShaderType type : {gl::ShaderType::Vertex, gl::ShaderType::Fragment})
191
    {
192
        (*mslCodeOut)[type]                         = shaderSources[type];
193
        (*mslShaderInfoOut)[type].metalShaderSource = shaderSources[type];
194
        gl::Shader *shader                        = programState.getAttachedShader(type);
195
        sh::TranslatorMetalReflection *reflection = getReflectionFromShader(shader);
196
        // Retrieve automatic texture slot assignments
197
        if (originalSamplerBindings.size() > 0)
198
        {
199
            GetAssignedSamplerBindings(reflection, originalSamplerBindings, structSamplers,
200
                                       &mslShaderInfoOut->at(type).actualSamplerBindings);
201
        }
202
        reflection->reset();
203
    }
204
    return angle::Result::Continue;
205
}
206
207
uint MslGetShaderShadowCompareMode(GLenum mode, GLenum func)
208
{
209
    // See SpirvToMslCompiler::emit_header()
210
    if (mode == GL_NONE)
211
    {
212
        return 0;
213
    }
214
    else
215
    {
216
        switch (func)
217
        {
218
            case GL_LESS:
219
                return 1;
220
            case GL_LEQUAL:
221
                return 2;
222
            case GL_GREATER:
223
                return 3;
224
            case GL_GEQUAL:
225
                return 4;
226
            case GL_NEVER:
227
                return 5;
228
            case GL_ALWAYS:
229
                return 6;
230
            case GL_EQUAL:
231
                return 7;
232
            case GL_NOTEQUAL:
233
                return 8;
234
            default:
235
                UNREACHABLE();
236
                return 1;
237
        }
238
    }
239
}
240
}  // namespace mtl
241
}  // namespace rx
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_glslang_utils.h -23 / +25 lines
Lines 14-46 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_glslang_utils.h_sec1
14
#include "libANGLE/renderer/ProgramImpl.h"
14
#include "libANGLE/renderer/ProgramImpl.h"
15
#include "libANGLE/renderer/glslang_wrapper_utils.h"
15
#include "libANGLE/renderer/glslang_wrapper_utils.h"
16
#include "libANGLE/renderer/metal/mtl_common.h"
16
#include "libANGLE/renderer/metal/mtl_common.h"
17
17
#include "libANGLE/renderer/metal/mtl_glslang_mtl_utils.h"
18
namespace rx
18
namespace rx
19
{
19
{
20
namespace mtl
20
namespace mtl
21
{
21
{
22
23
struct SamplerBinding
24
{
25
    uint32_t textureBinding = 0;
26
    uint32_t samplerBinding = 0;
27
};
28
29
struct TranslatedShaderInfo
30
{
31
    void reset();
32
33
    // Translated Metal source code
34
    std::string metalShaderSource;
35
    // Metal library compiled from source code above. Used by ProgramMtl.
36
    AutoObjCPtr<id<MTLLibrary>> metalLibrary;
37
38
    std::array<SamplerBinding, kMaxGLSamplerBindings> actualSamplerBindings;
39
    std::array<uint32_t, kMaxGLUBOBindings> actualUBOBindings;
40
    std::array<uint32_t, kMaxShaderXFBs> actualXFBBindings;
41
    bool hasUBOArgumentBuffer;
42
};
43
44
// - shaderSourcesOut is result GLSL code per shader stage when XFB emulation is turned off.
22
// - shaderSourcesOut is result GLSL code per shader stage when XFB emulation is turned off.
45
// - xfbOnlyShaderSourceOut will contain vertex shader's GLSL code when XFB emulation is turned on.
23
// - xfbOnlyShaderSourceOut will contain vertex shader's GLSL code when XFB emulation is turned on.
46
void GlslangGetShaderSource(const gl::ProgramState &programState,
24
void GlslangGetShaderSource(const gl::ProgramState &programState,
Lines 57-62 angle::Result GlslangGetShaderSpirvCode(ErrorHandler *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_glslang_utils.h_sec2
57
                                        const ShaderMapInterfaceVariableInfoMap &variableInfoMap,
35
                                        const ShaderMapInterfaceVariableInfoMap &variableInfoMap,
58
                                        gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut);
36
                                        gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut);
59
37
38
angle::Result MSLGetShaderSpirvCode(ErrorHandler *context,
39
                                    const gl::ShaderBitSet &linkedShaderStages,
40
                                    const gl::Caps &glCaps,
41
                                    const gl::ShaderMap<std::string> &shaderSources,
42
                                    const ShaderMapInterfaceVariableInfoMap &variableInfoMap,
43
                                    gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut);
44
60
// Translate from SPIR-V code to Metal shader source code.
45
// Translate from SPIR-V code to Metal shader source code.
61
// - spirvShaderCode is SPIRV code per shader stage when XFB emulation is turned off.
46
// - spirvShaderCode is SPIRV code per shader stage when XFB emulation is turned off.
62
// - xfbOnlySpirvCode is  vertex shader's SPIRV code when XFB emulation is turned on.
47
// - xfbOnlySpirvCode is  vertex shader's SPIRV code when XFB emulation is turned on.
Lines 70-75 angle::Result SpirvCodeToMsl(Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_glslang_utils.h_sec3
70
                             gl::ShaderMap<TranslatedShaderInfo> *mslShaderInfoOut,
55
                             gl::ShaderMap<TranslatedShaderInfo> *mslShaderInfoOut,
71
                             TranslatedShaderInfo *mslXfbOnlyShaderInfoOut /** nullable */);
56
                             TranslatedShaderInfo *mslXfbOnlyShaderInfoOut /** nullable */);
72
57
58
void MSLGetShaderSource(const gl::ProgramState &programState,
59
                        const gl::ProgramLinkedResources &resources,
60
                        gl::ShaderMap<std::string> *shaderSourcesOut,
61
                        ShaderMapInterfaceVariableInfoMap *variableInfoMapOut);
62
63
angle::Result GlslangGetMSL(Context *context,
64
                            const gl::ShaderBitSet &linkedShaderStages,
65
                            const gl::Caps &glCaps,
66
                            const gl::ShaderMap<std::string> &shaderSources,
67
                            const ShaderMapInterfaceVariableInfoMap &variableInfoMap,
68
                            gl::ShaderMap<TranslatedShaderInfo> *mslShaderInfoOut,
69
                            gl::ShaderMap<std::string> *mslCodeOut,
70
                            size_t xfbBufferCount);
71
72
// Get equivalent shadow compare mode that is used in translated msl shader.
73
uint MslGetShaderShadowCompareMode(GLenum mode, GLenum func);
74
73
}  // namespace mtl
75
}  // namespace mtl
74
}  // namespace rx
76
}  // namespace rx
75
77
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_glslang_utils.mm -26 / +762 lines
Lines 13-18 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_glslang_utils.mm_sec1
13
#include <spirv_msl.hpp>
13
#include <spirv_msl.hpp>
14
14
15
#include "common/apple_platform_utils.h"
15
#include "common/apple_platform_utils.h"
16
#include "compiler/translator/TranslatorMetal.h"
16
#include "libANGLE/renderer/glslang_wrapper_utils.h"
17
#include "libANGLE/renderer/glslang_wrapper_utils.h"
17
#include "libANGLE/renderer/metal/DisplayMtl.h"
18
#include "libANGLE/renderer/metal/DisplayMtl.h"
18
19
Lines 22-33 namespace mtl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_glslang_utils.mm_sec2
22
{
23
{
23
namespace
24
namespace
24
{
25
{
25
26
constexpr uint32_t kGlslangTextureDescSet              = 0;
26
constexpr uint32_t kGlslangTextureDescSet              = 0;
27
constexpr uint32_t kGlslangDefaultUniformAndXfbDescSet = 1;
27
constexpr uint32_t kGlslangDefaultUniformAndXfbDescSet = 1;
28
constexpr uint32_t kGlslangDriverUniformsDescSet       = 2;
28
constexpr uint32_t kGlslangDriverUniformsDescSet       = 2;
29
constexpr uint32_t kGlslangShaderResourceDescSet       = 3;
29
constexpr uint32_t kGlslangShaderResourceDescSet       = 3;
30
30
31
constexpr char kShadowSamplerCompareModesVarName[] = "ANGLEShadowCompareModes";
32
31
// Original mapping of front end from sampler name to multiple sampler slots (in form of
33
// Original mapping of front end from sampler name to multiple sampler slots (in form of
32
// slot:count pair)
34
// slot:count pair)
33
using OriginalSamplerBindingMap =
35
using OriginalSamplerBindingMap =
Lines 56-64 void ResetGlslangProgramInterfaceInfo(GlslangProgramInterfaceInfo *programInterf a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_glslang_utils.mm_sec3
56
    static_assert(kDriverUniformsBindingIndex != 0, "kDriverUniformsBindingIndex must not be 0");
58
    static_assert(kDriverUniformsBindingIndex != 0, "kDriverUniformsBindingIndex must not be 0");
57
}
59
}
58
60
61
59
GlslangSourceOptions CreateSourceOptions()
62
GlslangSourceOptions CreateSourceOptions()
60
{
63
{
61
    GlslangSourceOptions options;
64
    GlslangSourceOptions options;
65
    options.emulateTransformFeedback = true;
66
    // We can early out in the MSL once transform feedback is written
67
    options.transformFeedbackEarlyReturn = true;
62
    return options;
68
    return options;
63
}
69
}
64
70
Lines 79-86 spv::ExecutionModel ShaderTypeToSpvExecutionModel(gl::ShaderType shaderType) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_glslang_utils.mm_sec4
79
void BindBuffers(spirv_cross::CompilerMSL *compiler,
85
void BindBuffers(spirv_cross::CompilerMSL *compiler,
80
                 const spirv_cross::SmallVector<spirv_cross::Resource> &resources,
86
                 const spirv_cross::SmallVector<spirv_cross::Resource> &resources,
81
                 gl::ShaderType shaderType,
87
                 gl::ShaderType shaderType,
82
                 const std::unordered_map<std::string, uint32_t> &uboOriginalBindings,
88
                 const angle::HashMap<std::string, uint32_t> &uboOriginalBindings,
83
                 const std::unordered_map<uint32_t, uint32_t> &xfbOriginalBindings,
89
                 const angle::HashMap<uint32_t, uint32_t> &xfbOriginalBindings,
84
                 std::array<uint32_t, kMaxGLUBOBindings> *uboBindingsRemapOut,
90
                 std::array<uint32_t, kMaxGLUBOBindings> *uboBindingsRemapOut,
85
                 std::array<uint32_t, kMaxShaderXFBs> *xfbBindingRemapOut,
91
                 std::array<uint32_t, kMaxShaderXFBs> *xfbBindingRemapOut,
86
                 bool *uboArgumentBufferUsed)
92
                 bool *uboArgumentBufferUsed)
Lines 253-282 void GetAssignedSamplerBindings(const spirv_cross::CompilerMSL &compilerMsl, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_glslang_utils.mm_sec5
253
    }
259
    }
254
}
260
}
255
261
256
std::string PostProcessTranslatedMsl(const std::string &translatedSource)
262
std::string PostProcessTranslatedMsl(bool hasDepthSampler, const std::string &translatedSource)
257
{
263
{
264
    std::string source;
265
    if (hasDepthSampler)
266
    {
267
        // Add ANGLEShadowCompareModes variable to main(), We need to add here because it is the
268
        // only way without modifying spirv-cross.
269
        std::regex mainDeclareRegex(
270
            R"(((vertex|fragment|kernel)\s+[_a-zA-Z0-9<>]+\s+main[^\(]*\())");
271
        std::string mainDeclareReplaceStr = std::string("$1constant uniform<uint> *") +
272
                                            kShadowSamplerCompareModesVarName + "[[buffer(" +
273
                                            Str(kShadowSamplerCompareModesBindingIndex) + ")]], ";
274
        source = std::regex_replace(translatedSource, mainDeclareRegex, mainDeclareReplaceStr);
275
    }
276
    else
277
    {
278
        source = translatedSource;
279
    }
280
258
    // Add function_constant attribute to gl_SampleMask.
281
    // Add function_constant attribute to gl_SampleMask.
259
    // Even though this varying is only used when ANGLECoverageMaskEnabled is true,
282
    // Even though this varying is only used when ANGLECoverageMaskEnabled is true,
260
    // the spirv-cross doesn't assign function_constant attribute to it. Thus it won't be dead-code
283
    // the spirv-cross doesn't assign function_constant attribute to it. Thus it won't be dead-code
261
    // removed when ANGLECoverageMaskEnabled=false.
284
    // removed when ANGLECoverageMaskEnabled=false.
262
    std::string sampleMaskReplaceStr = std::string("[[sample_mask, function_constant(") +
285
    std::string sampleMaskReplaceStr = std::string("[[sample_mask, function_constant(") +
263
                                       sh::mtl::kCoverageMaskEnabledConstName + ")]]";
286
                                       sh::TranslatorMetal::GetCoverageMaskEnabledConstName() +
287
                                       ")]]";
264
288
265
    // This replaces "gl_SampleMask [[sample_mask]]"
289
    // This replaces "gl_SampleMask [[sample_mask]]"
266
    //          with "gl_SampleMask [[sample_mask, function_constant(ANGLECoverageMaskEnabled)]]"
290
    //          with "gl_SampleMask [[sample_mask, function_constant(ANGLECoverageMaskEnabled)]]"
267
    std::regex sampleMaskDeclareRegex(R"(\[\s*\[\s*sample_mask\s*\]\s*\])");
291
    std::regex sampleMaskDeclareRegex(R"(\[\s*\[\s*sample_mask\s*\]\s*\])");
268
    return std::regex_replace(translatedSource, sampleMaskDeclareRegex, sampleMaskReplaceStr);
292
    return std::regex_replace(source, sampleMaskDeclareRegex, sampleMaskReplaceStr);
269
}
293
}
270
294
271
// Customized spirv-cross compiler
295
// Customized spirv-cross compiler
272
class SpirvToMslCompiler : public spirv_cross::CompilerMSL
296
class SpirvToMslCompiler : public spirv_cross::CompilerMSL
273
{
297
{
274
  public:
298
  public:
275
    SpirvToMslCompiler(std::vector<uint32_t> &&spriv) : spirv_cross::CompilerMSL(spriv) {}
299
    SpirvToMslCompiler(Context *context, std::vector<uint32_t> &&spriv)
300
        : spirv_cross::CompilerMSL(spriv), mContext(context)
301
    {}
276
302
277
    void compileEx(gl::ShaderType shaderType,
303
    void compileEx(gl::ShaderType shaderType,
278
                   const std::unordered_map<std::string, uint32_t> &uboOriginalBindings,
304
                   const angle::HashMap<std::string, uint32_t> &uboOriginalBindings,
279
                   const std::unordered_map<uint32_t, uint32_t> &xfbOriginalBindings,
305
                   const angle::HashMap<uint32_t, uint32_t> &xfbOriginalBindings,
280
                   const OriginalSamplerBindingMap &originalSamplerBindings,
306
                   const OriginalSamplerBindingMap &originalSamplerBindings,
281
                   TranslatedShaderInfo *mslShaderInfoOut)
307
                   TranslatedShaderInfo *mslShaderInfoOut)
282
    {
308
    {
Lines 328-335 class SpirvToMslCompiler : public spirv_cross::CompilerMSL a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_glslang_utils.mm_sec6
328
            // Force discrete slot bindings for textures, default uniforms & driver uniforms
354
            // Force discrete slot bindings for textures, default uniforms & driver uniforms
329
            // instead of using argument buffer.
355
            // instead of using argument buffer.
330
            spirv_cross::CompilerMSL::add_discrete_descriptor_set(kGlslangTextureDescSet);
356
            spirv_cross::CompilerMSL::add_discrete_descriptor_set(kGlslangTextureDescSet);
331
            spirv_cross::CompilerMSL::add_discrete_descriptor_set(
357
            spirv_cross::CompilerMSL::add_discrete_descriptor_set(kGlslangDefaultUniformAndXfbDescSet);
332
                kGlslangDefaultUniformAndXfbDescSet);
333
            spirv_cross::CompilerMSL::add_discrete_descriptor_set(kGlslangDriverUniformsDescSet);
358
            spirv_cross::CompilerMSL::add_discrete_descriptor_set(kGlslangDriverUniformsDescSet);
334
        }
359
        }
335
        else
360
        else
Lines 340-370 class SpirvToMslCompiler : public spirv_cross::CompilerMSL a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_glslang_utils.mm_sec7
340
365
341
        spirv_cross::CompilerMSL::set_msl_options(compOpt);
366
        spirv_cross::CompilerMSL::set_msl_options(compOpt);
342
367
368
        addBuiltInResources();
369
        analyzeShaderVariables();
370
343
        // Actual compilation
371
        // Actual compilation
344
        mslShaderInfoOut->metalShaderSource =
372
        mslShaderInfoOut->metalShaderSource =
345
            PostProcessTranslatedMsl(spirv_cross::CompilerMSL::compile());
373
            PostProcessTranslatedMsl(mHasDepthSampler, spirv_cross::CompilerMSL::compile());
346
374
347
        // Retrieve automatic texture slot assignments
375
        // Retrieve automatic texture slot assignments
348
        GetAssignedSamplerBindings(*this, originalSamplerBindings,
376
        GetAssignedSamplerBindings(*this, originalSamplerBindings,
349
                                   &mslShaderInfoOut->actualSamplerBindings);
377
                                   &mslShaderInfoOut->actualSamplerBindings);
350
    }
378
    }
379
380
  private:
381
    // Override CompilerMSL
382
    void emit_header() override
383
    {
384
        spirv_cross::CompilerMSL::emit_header();
385
        if (!mHasDepthSampler)
386
        {
387
            return;
388
        }
389
        // Work around code for these issues:
390
        // - spriv_cross always translates shadow texture's sampling to sample_compare() and doesn't
391
        // take into account GL_TEXTURE_COMPARE_MODE=GL_NONE.
392
        // - on macOS, explicit level of detail parameter is not supported in sample_compare().
393
        // - on devices prior to iOS GPU family 3, changing sampler's compare mode outside shader is
394
        // not supported.
395
        if (!mContext->getDisplay()->getFeatures().allowRuntimeSamplerCompareMode.enabled)
396
        {
397
            statement("#define ANGLE_MTL_NO_SAMPLER_RUNTIME_COMPARE_MODE");
398
        }
399
400
        statement("enum class ANGLECompareMode : uint");
401
        statement("{");
402
        statement("    None = 0,");
403
        statement("    Less,");
404
        statement("    LessEqual,");
405
        statement("    Greater,");
406
        statement("    GreaterEqual,");
407
        statement("    Never,");
408
        statement("    Always,");
409
        statement("    Equal,");
410
        statement("    NotEqual,");
411
        statement("};");
412
        statement("");
413
414
        statement("template <typename T, typename UniformOrUInt>");
415
        statement("inline T ANGLEcompare(T depth, T dref, UniformOrUInt compareMode)");
416
        statement("{");
417
        statement("   ANGLECompareMode mode = static_cast<ANGLECompareMode>(compareMode);");
418
        statement("   switch (mode)");
419
        statement("   {");
420
        statement("        case ANGLECompareMode::Less:");
421
        statement("            return dref < depth;");
422
        statement("        case ANGLECompareMode::LessEqual:");
423
        statement("            return dref <= depth;");
424
        statement("        case ANGLECompareMode::Greater:");
425
        statement("            return dref > depth;");
426
        statement("        case ANGLECompareMode::GreaterEqual:");
427
        statement("            return dref >= depth;");
428
        statement("        case ANGLECompareMode::Never:");
429
        statement("            return 0;");
430
        statement("        case ANGLECompareMode::Always:");
431
        statement("            return 1;");
432
        statement("        case ANGLECompareMode::Equal:");
433
        statement("            return dref == depth;");
434
        statement("        case ANGLECompareMode::NotEqual:");
435
        statement("            return dref != depth;");
436
        statement("        default:");
437
        statement("            return 1;");
438
        statement("   }");
439
        statement("}");
440
        statement("");
441
442
        statement("// Wrapper functions for shadow texture functions");
443
        // 2D PCF sampling
444
        statement("template <typename T, typename Opt, typename UniformOrUInt>");
445
        statement("inline T ANGLEtexturePCF(depth2d<T> texture, sampler s, float2 coord, float "
446
                  "compare_value, Opt options, int2 offset, UniformOrUInt shadowCompareMode)");
447
        statement("{");
448
        statement("#if defined(__METAL_MACOS__)");
449
        statement("    float2 dims = float2(texture.get_width(), texture.get_height());");
450
        statement("    float2 imgCoord = coord * dims;");
451
        statement("    float2 texelSize = 1.0 / dims;");
452
        statement("    float2 weight = fract(imgCoord);");
453
        statement("    float tl = ANGLEcompare(texture.sample(s, coord, options, offset), "
454
                  "compare_value, shadowCompareMode);");
455
        statement("    float tr = ANGLEcompare(texture.sample(s, coord + float2(texelSize.x, 0.0), "
456
                  "options, offset), compare_value, shadowCompareMode);");
457
        statement("    float bl = ANGLEcompare(texture.sample(s, coord + float2(0.0, texelSize.y), "
458
                  "options, offset), compare_value, shadowCompareMode);");
459
        statement("    float br = ANGLEcompare(texture.sample(s, coord + texelSize, options, "
460
                  "offset), compare_value, shadowCompareMode);");
461
        statement("    float top = mix(tl, tr, weight.x);");
462
        statement("    float bottom = mix(bl, br, weight.x);");
463
        statement("    return mix(top, bottom, weight.y);");
464
        statement("#else  // if defined(__METAL_MACOS__)");
465
        statement("    return ANGLEcompare(texture.sample(s, coord, options, offset), "
466
                  "compare_value, shadowCompareMode);");
467
        statement("#endif  // if defined(__METAL_MACOS__)");
468
        statement("}");
469
        statement("");
470
471
        // Cube PCF sampling
472
        statement("template <typename T, typename Opt, typename UniformOrUInt>");
473
        statement("inline T ANGLEtexturePCF(depthcube<T> texture, sampler s, float3 coord, float "
474
                  "compare_value, Opt options, UniformOrUInt shadowCompareMode)");
475
        statement("{");
476
        statement("    // NOTE(hqle): to implement");
477
        statement("    return ANGLEcompare(texture.sample(s, coord, options), compare_value, "
478
                  "shadowCompareMode);");
479
        statement("}");
480
        statement("");
481
482
        // 2D array PCF sampling
483
        statement("template <typename T, typename Opt, typename UniformOrUInt>");
484
        statement(
485
            "inline T ANGLEtexturePCF(depth2d_array<T> texture, sampler s, float2 coord, uint "
486
            "array, float compare_value, Opt options, int2 offset, UniformOrUInt "
487
            "shadowCompareMode)");
488
        statement("{");
489
        statement("#if defined(__METAL_MACOS__)");
490
        statement("    float2 dims = float2(texture.get_width(), texture.get_height());");
491
        statement("    float2 imgCoord = coord * dims;");
492
        statement("    float2 texelSize = 1.0 / dims;");
493
        statement("    float2 weight = fract(imgCoord);");
494
        statement("    float tl = ANGLEcompare(texture.sample(s, coord, array, options, offset), "
495
                  "compare_value, shadowCompareMode);");
496
        statement("    float tr = ANGLEcompare(texture.sample(s, coord + float2(texelSize.x, 0.0), "
497
                  "array, options, offset), compare_value, shadowCompareMode);");
498
        statement("    float bl = ANGLEcompare(texture.sample(s, coord + float2(0.0, texelSize.y), "
499
                  "array, options, offset), compare_value, shadowCompareMode);");
500
        statement("    float br = ANGLEcompare(texture.sample(s, coord + texelSize, array, "
501
                  "options, offset), compare_value, shadowCompareMode);");
502
        statement("    float top = mix(tl, tr, weight.x);");
503
        statement("    float bottom = mix(bl, br, weight.x);");
504
        statement("    return mix(top, bottom, weight.y);");
505
        statement("#else  // if defined(__METAL_MACOS__)");
506
        statement("    return ANGLEcompare(texture.sample(s, coord, array, options, offset), "
507
                  "compare_value, shadowCompareMode);");
508
        statement("#endif  // if defined(__METAL_MACOS__)");
509
        statement("}");
510
        statement("");
511
512
        // 2D texture's sample_compare() wrapper
513
        statement("template <typename T, typename Opt, typename UniformOrUInt>");
514
        statement("inline T ANGLEtextureCompare(depth2d<T> texture, sampler s, float2 coord, float "
515
                  "compare_value, Opt options, int2 offset, UniformOrUInt shadowCompareMode)");
516
        statement("{");
517
        statement(
518
            "#if defined(__METAL_MACOS__) || defined(ANGLE_MTL_NO_SAMPLER_RUNTIME_COMPARE_MODE)");
519
        statement("    return ANGLEtexturePCF(texture, s, coord, compare_value, options, offset, "
520
                  "shadowCompareMode);");
521
        statement("#else");
522
        statement("    return texture.sample_compare(s, coord, compare_value, options, offset);");
523
        statement("#endif");
524
        statement("}");
525
        statement("");
526
527
        statement("template <typename T, typename Opt, typename UniformOrUInt>");
528
        statement("inline T ANGLEtextureCompare(depth2d<T> texture, sampler s, float2 coord, float "
529
                  "compare_value, Opt options, UniformOrUInt shadowCompareMode)");
530
        statement("{");
531
        statement("    return ANGLEtextureCompare(texture, s, coord, compare_value, options, "
532
                  "int2(0), shadowCompareMode);");
533
        statement("}");
534
        statement("");
535
536
        statement("template <typename T, typename UniformOrUInt>");
537
        statement("inline T ANGLEtextureCompare(depth2d<T> texture, sampler s, float2 coord, float "
538
                  "compare_value, int2 offset, UniformOrUInt shadowCompareMode)");
539
        statement("{");
540
        statement("#if defined(ANGLE_MTL_NO_SAMPLER_RUNTIME_COMPARE_MODE)");
541
        statement("    return ANGLEtexturePCF(texture, s, coord, compare_value, level(0), offset, "
542
                  "shadowCompareMode);");
543
        statement("#else");
544
        statement("    return texture.sample_compare(s, coord, compare_value, offset);");
545
        statement("#endif");
546
        statement("}");
547
        statement("");
548
549
        // Cube texture's sample_compare() wrapper
550
        statement("template <typename T, typename Opt, typename UniformOrUInt>");
551
        statement(
552
            "inline T ANGLEtextureCompare(depthcube<T> texture, sampler s, float3 coord, float "
553
            "compare_value, Opt options, UniformOrUInt shadowCompareMode)");
554
        statement("{");
555
        statement(
556
            "#if defined(__METAL_MACOS__) || defined(ANGLE_MTL_NO_SAMPLER_RUNTIME_COMPARE_MODE)");
557
        statement("    return ANGLEtexturePCF(texture, s, coord, compare_value, options, "
558
                  "shadowCompareMode);");
559
        statement("#else");
560
        statement("    return texture.sample_compare(s, coord, compare_value, options);");
561
        statement("#endif");
562
        statement("}");
563
        statement("");
564
565
        statement("template <typename T, typename UniformOrUInt>");
566
        statement(
567
            "inline T ANGLEtextureCompare(depthcube<T> texture, sampler s, float3 coord, float "
568
            "compare_value, UniformOrUInt shadowCompareMode)");
569
        statement("{");
570
        statement("#if defined(ANGLE_MTL_NO_SAMPLER_RUNTIME_COMPARE_MODE)");
571
        statement("    return ANGLEtexturePCF(texture, s, coord, compare_value, level(0), "
572
                  "shadowCompareMode);");
573
        statement("#else");
574
        statement("    return texture.sample_compare(s, coord, compare_value);");
575
        statement("#endif");
576
        statement("}");
577
        statement("");
578
579
        // 2D array texture's sample_compare() wrapper
580
        statement("template <typename T, typename Opt, typename UniformOrUInt>");
581
        statement("inline T ANGLEtextureCompare(depth2d_array<T> texture, sampler s, float2 coord, "
582
                  "uint array, float compare_value, Opt options, int2 offset, UniformOrUInt "
583
                  "shadowCompareMode)");
584
        statement("{");
585
        statement(
586
            "#if defined(__METAL_MACOS__) || defined(ANGLE_MTL_NO_SAMPLER_RUNTIME_COMPARE_MODE)");
587
        statement("    return ANGLEtexturePCF(texture, s, coord, array, compare_value, options, "
588
                  "offset, shadowCompareMode);");
589
        statement("#else");
590
        statement(
591
            "    return texture.sample_compare(s, coord, array, compare_value, options, offset);");
592
        statement("#endif");
593
        statement("}");
594
        statement("");
595
596
        statement("template <typename T, typename Opt, typename UniformOrUInt>");
597
        statement("inline T ANGLEtextureCompare(depth2d_array<T> texture, sampler s, float2 coord, "
598
                  "uint array, float compare_value, Opt options, UniformOrUInt shadowCompareMode)");
599
        statement("{");
600
        statement("    return ANGLEtextureCompare(texture, s, coord, array, compare_value, "
601
                  "options, int2(0), shadowCompareMode);");
602
        statement("}");
603
        statement("");
604
605
        statement("template <typename T, typename UniformOrUInt>");
606
        statement("inline T ANGLEtextureCompare(depth2d_array<T> texture, sampler s, float2 coord, "
607
                  "uint array, float compare_value, int2 offset, UniformOrUInt "
608
                  "shadowCompareMode)");
609
        statement("{");
610
        statement("#if defined(ANGLE_MTL_NO_SAMPLER_RUNTIME_COMPARE_MODE)");
611
        statement("    return ANGLEtexturePCF(texture, s, coord, array, compare_value, level(0), "
612
                  "offset, shadowCompareMode);");
613
        statement("#else");
614
        statement("    return texture.sample_compare(s, coord, array, compare_value, offset);");
615
        statement("#endif");
616
        statement("}");
617
        statement("");
618
619
        // 2D texture's generic sampling function
620
        statement("// Wrapper functions for shadow texture functions");
621
        statement("template <typename T, typename UniformOrUInt>");
622
        statement("inline T ANGLEtexture(depth2d<T> texture, sampler s, float2 coord, int2 offset, "
623
                  "float compare_value, UniformOrUInt shadowCompareMode)");
624
        statement("{");
625
        statement("    if (shadowCompareMode)");
626
        statement("    {");
627
        statement("        return ANGLEtextureCompare(texture, s, coord, compare_value, offset, "
628
                  "shadowCompareMode);");
629
        statement("    }");
630
        statement("    else");
631
        statement("    {");
632
        statement("        return texture.sample(s, coord, offset);");
633
        statement("    }");
634
        statement("}");
635
        statement("");
636
637
        statement("template <typename T, typename UniformOrUInt>");
638
        statement("inline T ANGLEtexture(depth2d<T> texture, sampler s, float2 coord, float "
639
                  "compare_value, UniformOrUInt shadowCompareMode)");
640
        statement("{");
641
        statement("    return ANGLEtexture(texture, s, coord, int2(0), compare_value, "
642
                  "shadowCompareMode);");
643
        statement("}");
644
        statement("");
645
646
        statement("template <typename T, typename Opt, typename UniformOrUInt>");
647
        statement("inline T ANGLEtexture(depth2d<T> texture, sampler s, float2 coord, Opt options, "
648
                  "int2 offset, float compare_value, UniformOrUInt shadowCompareMode)");
649
        statement("{");
650
        statement("    if (shadowCompareMode)");
651
        statement("    {");
652
        statement("        return ANGLEtextureCompare(texture, s, coord, compare_value, options, "
653
                  "offset, shadowCompareMode);");
654
        statement("    }");
655
        statement("    else");
656
        statement("    {");
657
        statement("        return texture.sample(s, coord, options, offset);");
658
        statement("    }");
659
        statement("}");
660
        statement("");
661
662
        statement("template <typename T, typename Opt, typename UniformOrUInt>");
663
        statement("inline T ANGLEtexture(depth2d<T> texture, sampler s, float2 coord, Opt options, "
664
                  "float compare_value, UniformOrUInt shadowCompareMode)");
665
        statement("{");
666
        statement("    return ANGLEtexture(texture, s, coord, options, int2(0), compare_value, "
667
                  "shadowCompareMode);");
668
        statement("}");
669
        statement("");
670
671
        // Cube texture's generic sampling function
672
        statement("template <typename T, typename UniformOrUInt>");
673
        statement("inline T ANGLEtexture(depthcube<T> texture, sampler s, float3 coord, float "
674
                  "compare_value, UniformOrUInt shadowCompareMode)");
675
        statement("{");
676
        statement("    if (shadowCompareMode)");
677
        statement("    {");
678
        statement("        return ANGLEtextureCompare(texture, s, coord, compare_value, "
679
                  "shadowCompareMode);");
680
        statement("    }");
681
        statement("    else");
682
        statement("    {");
683
        statement("        return texture.sample(s, coord);");
684
        statement("    }");
685
        statement("}");
686
        statement("");
687
688
        statement("template <typename T, typename Opt, typename UniformOrUInt>");
689
        statement("inline T ANGLEtexture(depthcube<T> texture, sampler s, float2 coord, Opt "
690
                  "options, float compare_value, UniformOrUInt shadowCompareMode)");
691
        statement("{");
692
        statement("    if (shadowCompareMode)");
693
        statement("    {");
694
        statement("        return ANGLEtextureCompare(texture, s, coord, compare_value, options, "
695
                  "shadowCompareMode);");
696
        statement("    }");
697
        statement("    else");
698
        statement("    {");
699
        statement("        return texture.sample(s, coord, options);");
700
        statement("    }");
701
        statement("}");
702
        statement("");
703
704
        // 2D array texture's generic sampling function
705
        statement("template <typename T, typename UniformOrUInt>");
706
        statement("inline T ANGLEtexture(depth2d_array<T> texture, sampler s, float2 coord, uint "
707
                  "array, int2 offset, "
708
                  "float compare_value, UniformOrUInt shadowCompareMode)");
709
        statement("{");
710
        statement("    if (shadowCompareMode)");
711
        statement("    {");
712
        statement("        return ANGLEtextureCompare(texture, s, coord, array, compare_value, "
713
                  "offset, shadowCompareMode);");
714
        statement("    }");
715
        statement("    else");
716
        statement("    {");
717
        statement("        return texture.sample(s, coord, array, offset);");
718
        statement("    }");
719
        statement("}");
720
        statement("");
721
722
        statement("template <typename T, typename UniformOrUInt>");
723
        statement("inline T ANGLEtexture(depth2d_array<T> texture, sampler s, float2 coord, uint "
724
                  "array, float compare_value, UniformOrUInt shadowCompareMode)");
725
        statement("{");
726
        statement("    return ANGLEtexture(texture, s, coord, array, int2(0), compare_value, "
727
                  "shadowCompareMode);");
728
        statement("}");
729
        statement("");
730
731
        statement("template <typename T, typename Opt, typename UniformOrUInt>");
732
        statement("inline T ANGLEtexture(depth2d_array<T> texture, sampler s, float2 coord, uint "
733
                  "array, Opt options, int2 offset, "
734
                  "float compare_value, UniformOrUInt shadowCompareMode)");
735
        statement("{");
736
        statement("    if (shadowCompareMode)");
737
        statement("    {");
738
        statement("        return ANGLEtextureCompare(texture, s, coord, array, compare_value, "
739
                  "options, offset, shadowCompareMode);");
740
        statement("    }");
741
        statement("    else");
742
        statement("    {");
743
        statement("        return texture.sample(s, coord, array, options, offset);");
744
        statement("    }");
745
        statement("}");
746
        statement("");
747
748
        statement("template <typename T, typename Opt, typename UniformOrUInt>");
749
        statement("inline T ANGLEtexture(depth2d_array<T> texture, sampler s, float2 coord, uint "
750
                  "array, Opt options, float compare_value, UniformOrUInt shadowCompareMode)");
751
        statement("{");
752
        statement("    return ANGLEtexture(texture, s, coord, array, options, int2(0), "
753
                  "compare_value, shadowCompareMode);");
754
        statement("}");
755
        statement("");
756
    }
757
758
    std::string to_function_name(spirv_cross::VariableID img,
759
                                 const spirv_cross::SPIRType &imgType,
760
                                 bool isFetch,
761
                                 bool isGather,
762
                                 bool isProj,
763
                                 bool hasArrayOffsets,
764
                                 bool hasOffset,
765
                                 bool hasGrad,
766
                                 bool hasDref,
767
                                 uint32_t lod,
768
                                 uint32_t minLod) override
769
    {
770
        if (!hasDref)
771
        {
772
            return spirv_cross::CompilerMSL::to_function_name(img, imgType, isFetch, isGather,
773
                                                              isProj, hasArrayOffsets, hasOffset,
774
                                                              hasGrad, hasDref, lod, minLod);
775
        }
776
777
        // Use custom ANGLEtexture function instead of using built-in sample_compare()
778
        return "ANGLEtexture";
779
    }
780
781
    std::string to_function_args(spirv_cross::VariableID img,
782
                                 const spirv_cross::SPIRType &imgType,
783
                                 bool isFetch,
784
                                 bool isGather,
785
                                 bool isProj,
786
                                 uint32_t coord,
787
                                 uint32_t coordComponents,
788
                                 uint32_t dref,
789
                                 uint32_t gradX,
790
                                 uint32_t gradY,
791
                                 uint32_t lod,
792
                                 uint32_t coffset,
793
                                 uint32_t offset,
794
                                 uint32_t bias,
795
                                 uint32_t comp,
796
                                 uint32_t sample,
797
                                 uint32_t minlod,
798
                                 bool *pForward) override
799
    {
800
        bool forward;
801
        std::string argsWithoutDref = spirv_cross::CompilerMSL::to_function_args(
802
            img, imgType, isFetch, isGather, isProj, coord, coordComponents, 0, gradX, gradY, lod,
803
            coffset, offset, bias, comp, sample, minlod, &forward);
804
805
        if (!dref)
806
        {
807
            if (pForward)
808
            {
809
                *pForward = forward;
810
            }
811
            return argsWithoutDref;
812
        }
813
        // Convert to arguments to ANGLEtexture.
814
        std::string args = to_expression(img);
815
        args += ", ";
816
        args += argsWithoutDref;
817
        args += ", ";
818
819
        forward                               = forward && should_forward(dref);
820
        const spirv_cross::SPIRType &drefType = expression_type(dref);
821
        std::string drefExpr;
822
        uint32_t altCoordComponent = 0;
823
        switch (imgType.image.dim)
824
        {
825
            case spv::Dim2D:
826
                altCoordComponent = 2;
827
                break;
828
            case spv::Dim3D:
829
            case spv::DimCube:
830
                altCoordComponent = 3;
831
                break;
832
            default:
833
                UNREACHABLE();
834
                break;
835
        }
836
        if (isProj)
837
            drefExpr = spirv_cross::join(to_enclosed_expression(dref), " / ",
838
                                         to_extract_component_expression(coord, altCoordComponent));
839
        else
840
            drefExpr = to_expression(dref);
841
842
        if (drefType.basetype == spirv_cross::SPIRType::Half)
843
            drefExpr = convert_to_f32(drefExpr, 1);
844
845
        args += drefExpr;
846
        args += ", ";
847
        args += toShadowCompareModeExpression(img);
848
849
        if (pForward)
850
        {
851
            *pForward = forward;
852
        }
853
854
        return args;
855
    }
856
857
    // Override function prototype emitter to insert shadow compare mode flag to come
858
    // together with the shadow sampler. NOTE(hqle): This is just 90% copy of spirv_msl's code.
859
    // The better way is modifying and creating a PR on spirv-cross repo directly. But this should
860
    // be a work around solution for now.
861
    void emit_function_prototype(spirv_cross::SPIRFunction &func,
862
                                 const spirv_cross::Bitset &) override
863
    {
864
        // Turn off clang-format to easier compare with original code
865
        // clang-format off
866
        using namespace spirv_cross;
867
        using namespace spv;
868
        using namespace std;
869
870
        if (func.self != ir.default_entry_point)
871
            add_function_overload(func);
872
873
        local_variable_names = resource_names;
874
        string decl;
875
876
        processing_entry_point = func.self == ir.default_entry_point;
877
878
        // Metal helper functions must be static force-inline otherwise they will cause problems when linked together in a single Metallib.
879
        if (!processing_entry_point)
880
            statement("static inline __attribute__((always_inline))");
881
882
        auto &type = get<SPIRType>(func.return_type);
883
884
        if (!type.array.empty() && msl_options.force_native_arrays)
885
        {
886
            // We cannot return native arrays in MSL, so "return" through an out variable.
887
            decl += "void";
888
        }
889
        else
890
        {
891
            decl += func_type_decl(type);
892
        }
893
894
        decl += " ";
895
        decl += to_name(func.self);
896
        decl += "(";
897
898
        if (!type.array.empty() && msl_options.force_native_arrays)
899
        {
900
            // Fake arrays returns by writing to an out array instead.
901
            decl += "thread ";
902
            decl += type_to_glsl(type);
903
            decl += " (&SPIRV_Cross_return_value)";
904
            decl += type_to_array_glsl(type);
905
            if (!func.arguments.empty())
906
                decl += ", ";
907
        }
908
909
        if (processing_entry_point)
910
        {
911
            if (msl_options.argument_buffers)
912
                decl += entry_point_args_argument_buffer(!func.arguments.empty());
913
            else
914
                decl += entry_point_args_classic(!func.arguments.empty());
915
916
            // If entry point function has variables that require early declaration,
917
            // ensure they each have an empty initializer, creating one if needed.
918
            // This is done at this late stage because the initialization expression
919
            // is cleared after each compilation pass.
920
            for (auto var_id : vars_needing_early_declaration)
921
            {
922
                auto &ed_var = get<SPIRVariable>(var_id);
923
                ID &initializer = ed_var.initializer;
924
                if (!initializer)
925
                    initializer = ir.increase_bound_by(1);
926
927
                // Do not override proper initializers.
928
                if (ir.ids[initializer].get_type() == TypeNone || ir.ids[initializer].get_type() == TypeExpression)
929
                    set<SPIRExpression>(ed_var.initializer, "{}", ed_var.basetype, true);
930
            }
931
        }
932
933
        for (auto &arg : func.arguments)
934
        {
935
            uint32_t name_id = arg.id;
936
937
            auto *var = maybe_get<SPIRVariable>(arg.id);
938
            if (var)
939
            {
940
                // If we need to modify the name of the variable, make sure we modify the original variable.
941
                // Our alias is just a shadow variable.
942
                if (arg.alias_global_variable && var->basevariable)
943
                    name_id = var->basevariable;
944
945
                var->parameter = &arg; // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
946
            }
947
948
            add_local_variable_name(name_id);
949
950
            decl += argument_decl(arg);
951
952
            bool is_dynamic_img_sampler = has_extended_decoration(arg.id, SPIRVCrossDecorationDynamicImageSampler);
953
954
            auto &arg_type = get<SPIRType>(arg.type);
955
            if (arg_type.basetype == SPIRType::SampledImage && !is_dynamic_img_sampler)
956
            {
957
                // Manufacture automatic plane args for multiplanar texture
958
                uint32_t planes = 1;
959
                if (auto *constexpr_sampler = find_constexpr_sampler(name_id))
960
                    if (constexpr_sampler->ycbcr_conversion_enable)
961
                        planes = constexpr_sampler->planes;
962
                for (uint32_t i = 1; i < planes; i++)
963
                    decl += join(", ", argument_decl(arg), plane_name_suffix, i);
964
965
                // Manufacture automatic sampler arg for SampledImage texture
966
                if (arg_type.image.dim != DimBuffer)
967
                    decl += join(", thread const ", sampler_type(arg_type), " ", to_sampler_expression(arg.id));
968
            }
969
970
            // Manufacture automatic swizzle arg.
971
            if (msl_options.swizzle_texture_samples && has_sampled_images && is_sampled_image_type(arg_type) &&
972
                !is_dynamic_img_sampler)
973
            {
974
                bool arg_is_array = !arg_type.array.empty();
975
                decl += join(", constant uint", arg_is_array ? "* " : "& ", to_swizzle_expression(arg.id));
976
            }
977
978
            if (buffers_requiring_array_length.count(name_id))
979
            {
980
                bool arg_is_array = !arg_type.array.empty();
981
                decl += join(", constant uint", arg_is_array ? "* " : "& ", to_buffer_size_expression(name_id));
982
            }
983
984
            if (is_sampled_image_type(arg_type) && arg_type.image.depth)
985
            {
986
                bool arg_is_array = !arg_type.array.empty();
987
                // Insert shadow compare mode flag to the argument sequence:
988
                decl += join(", constant uniform<uint>", arg_is_array ? "* " : "& ",
989
                             toShadowCompareModeExpression(arg.id));
990
            }
991
992
            if (&arg != &func.arguments.back())
993
                decl += ", ";
994
        }
995
996
        decl += ")";
997
        statement(decl);
998
999
        // clang-format on
1000
    }
1001
1002
    // Override function call arguments passing generator to insert shadow compare mode flag to come
1003
    // together with the shadow sampler
1004
    std::string to_func_call_arg(const spirv_cross::SPIRFunction::Parameter &arg,
1005
                                 uint32_t id) override
1006
    {
1007
        std::string arg_str = spirv_cross::CompilerMSL::to_func_call_arg(arg, id);
1008
1009
        const spirv_cross::SPIRType &type = expression_type(id);
1010
1011
        if (is_sampled_image_type(type) && type.image.depth)
1012
        {
1013
            // Insert shadow compare mode flag to the argument sequence:
1014
            // Need to check the base variable in case we need to apply a qualified alias.
1015
            uint32_t var_id = 0;
1016
            auto *var       = maybe_get<spirv_cross::SPIRVariable>(id);
1017
            if (var)
1018
                var_id = var->basevariable;
1019
1020
            arg_str += ", " + toShadowCompareModeExpression(var_id ? var_id : id);
1021
        }
1022
        return arg_str;
1023
    }
1024
1025
    // Additional functions
1026
    void addBuiltInResources()
1027
    {
1028
        uint32_t varId = build_constant_uint_array_pointer();
1029
        set_name(varId, kShadowSamplerCompareModesVarName);
1030
        // This should never match anything.
1031
        set_decoration(varId, spv::DecorationDescriptorSet, kShadowSamplerCompareModesBindingIndex);
1032
        set_decoration(varId, spv::DecorationBinding, 0);
1033
        set_extended_decoration(varId, spirv_cross::SPIRVCrossDecorationResourceIndexPrimary, 0);
1034
        mANGLEShadowCompareModesVarId = varId;
1035
    }
1036
1037
    void analyzeShaderVariables()
1038
    {
1039
        ir.for_each_typed_id<spirv_cross::SPIRVariable>([this](uint32_t,
1040
                                                               spirv_cross::SPIRVariable &var) {
1041
            const spirv_cross::SPIRType &type = get_variable_data_type(var);
1042
            uint32_t varId                    = var.self;
1043
1044
            if (var.storage == spv::StorageClassUniformConstant && !is_hidden_variable(var))
1045
            {
1046
                if (is_sampled_image_type(type) && type.image.depth)
1047
                {
1048
                    mHasDepthSampler = true;
1049
1050
                    auto &entry_func = this->get<spirv_cross::SPIRFunction>(ir.default_entry_point);
1051
                    entry_func.fixup_hooks_in.push_back([this, &type, &var, varId]() {
1052
                        bool isArrayType = !type.array.empty();
1053
1054
                        statement("constant uniform<uint>", isArrayType ? "* " : "& ",
1055
                                  toShadowCompareModeExpression(varId),
1056
                                  isArrayType ? " = &" : " = ",
1057
                                  to_name(mANGLEShadowCompareModesVarId), "[",
1058
                                  spirv_cross::convert_to_string(
1059
                                      get_metal_resource_index(var, spirv_cross::SPIRType::Image)),
1060
                                  "];");
1061
                    });
1062
                }
1063
            }
1064
        });
1065
    }
1066
1067
    std::string toShadowCompareModeExpression(uint32_t id)
1068
    {
1069
        constexpr char kCompareModeSuffix[] = "_CompMode";
1070
        auto *combined                      = maybe_get<spirv_cross::SPIRCombinedImageSampler>(id);
1071
1072
        std::string expr = to_expression(combined ? combined->image : spirv_cross::VariableID(id));
1073
        auto index       = expr.find_first_of('[');
1074
1075
        if (index == std::string::npos)
1076
            return expr + kCompareModeSuffix;
1077
        else
1078
        {
1079
            auto imageExpr = expr.substr(0, index);
1080
            auto arrayExpr = expr.substr(index);
1081
            return imageExpr + kCompareModeSuffix + arrayExpr;
1082
        }
1083
    }
1084
1085
    Context *mContext;
1086
    uint32_t mANGLEShadowCompareModesVarId = 0;
1087
    bool mHasDepthSampler                  = false;
351
};
1088
};
352
1089
353
angle::Result ConvertSpirvToMsl(
1090
angle::Result ConvertSpirvToMsl(Context *context,
354
    Context *context,
1091
                                gl::ShaderType shaderType,
355
    gl::ShaderType shaderType,
1092
                                const angle::HashMap<std::string, uint32_t> &uboOriginalBindings,
356
    const std::unordered_map<std::string, uint32_t> &uboOriginalBindings,
1093
                                const angle::HashMap<uint32_t, uint32_t> &xfbOriginalBindings,
357
    const std::unordered_map<uint32_t, uint32_t> &xfbOriginalBindings,
1094
                                const OriginalSamplerBindingMap &originalSamplerBindings,
358
    const OriginalSamplerBindingMap &originalSamplerBindings,
1095
                                std::vector<uint32_t> *sprivCode,
359
    std::vector<uint32_t> *sprivCode,
1096
                                TranslatedShaderInfo *translatedShaderInfoOut)
360
    TranslatedShaderInfo *translatedShaderInfoOut)
361
{
1097
{
362
    if (!sprivCode || sprivCode->empty())
1098
    if (!sprivCode || sprivCode->empty())
363
    {
1099
    {
364
        return angle::Result::Continue;
1100
        return angle::Result::Continue;
365
    }
1101
    }
366
1102
367
    SpirvToMslCompiler compilerMsl(std::move(*sprivCode));
1103
    SpirvToMslCompiler compilerMsl(context, std::move(*sprivCode));
368
1104
369
    // NOTE(hqle): spirv-cross uses exceptions to report error, what should we do here
1105
    // NOTE(hqle): spirv-cross uses exceptions to report error, what should we do here
370
    // in case of error?
1106
    // in case of error?
Lines 431-442 void GlslangGetShaderSource(const gl::ProgramState &programState, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_glslang_utils.mm_sec8
431
            options, programState, &xfbOnlyInterfaceInfo, xfbOnlyShaderSourceOut,
1167
            options, programState, &xfbOnlyInterfaceInfo, xfbOnlyShaderSourceOut,
432
            &xfbOnlyVariableMaps[gl::ShaderType::Vertex]);
1168
            &xfbOnlyVariableMaps[gl::ShaderType::Vertex]);
433
1169
434
        GlslangAssignLocations(options, programState.getExecutable(), gl::ShaderType::Vertex,
1170
        GlslangAssignLocations(options, programState.getExecutable(), gl::ShaderType::Vertex, &xfbOnlyInterfaceInfo,
435
                               &xfbOnlyInterfaceInfo, &xfbOnlyVariableMaps);
1171
                               &xfbOnlyVariableMaps);
436
        *xfbOnlyVSVariableInfoMapOut = std::move(xfbOnlyVariableMaps[gl::ShaderType::Vertex]);
1172
        *xfbOnlyVSVariableInfoMapOut = std::move(xfbOnlyVariableMaps[gl::ShaderType::Vertex]);
437
    }
1173
    }
438
}
1174
}
439
1175
1176
440
angle::Result GlslangGetShaderSpirvCode(ErrorHandler *context,
1177
angle::Result GlslangGetShaderSpirvCode(ErrorHandler *context,
441
                                        const gl::ShaderBitSet &linkedShaderStages,
1178
                                        const gl::ShaderBitSet &linkedShaderStages,
442
                                        const gl::Caps &glCaps,
1179
                                        const gl::Caps &glCaps,
Lines 478-484 angle::Result SpirvCodeToMsl(Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_glslang_utils.mm_sec9
478
                             TranslatedShaderInfo *mslXfbOnlyShaderInfoOut /** nullable */)
1215
                             TranslatedShaderInfo *mslXfbOnlyShaderInfoOut /** nullable */)
479
{
1216
{
480
    // Retrieve original uniform buffer bindings generated by front end. We will need to do a remap.
1217
    // Retrieve original uniform buffer bindings generated by front end. We will need to do a remap.
481
    std::unordered_map<std::string, uint32_t> uboOriginalBindings;
1218
    angle::HashMap<std::string, uint32_t> uboOriginalBindings;
482
    const std::vector<gl::InterfaceBlock> &blocks = programState.getUniformBlocks();
1219
    const std::vector<gl::InterfaceBlock> &blocks = programState.getUniformBlocks();
483
    for (uint32_t bufferIdx = 0; bufferIdx < blocks.size(); ++bufferIdx)
1220
    for (uint32_t bufferIdx = 0; bufferIdx < blocks.size(); ++bufferIdx)
484
    {
1221
    {
Lines 489-495 angle::Result SpirvCodeToMsl(Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_glslang_utils.mm_sec10
489
        }
1226
        }
490
    }
1227
    }
491
    // Retrieve original XFB buffers bindings produced by front end.
1228
    // Retrieve original XFB buffers bindings produced by front end.
492
    std::unordered_map<uint32_t, uint32_t> xfbOriginalBindings;
1229
    angle::HashMap<uint32_t, uint32_t> xfbOriginalBindings;
493
    for (uint32_t bufferIdx = 0; bufferIdx < kMaxShaderXFBs; ++bufferIdx)
1230
    for (uint32_t bufferIdx = 0; bufferIdx < kMaxShaderXFBs; ++bufferIdx)
494
    {
1231
    {
495
        std::string bufferName = rx::GetXfbBufferName(bufferIdx);
1232
        std::string bufferName = rx::GetXfbBufferName(bufferIdx);
Lines 533-538 angle::Result SpirvCodeToMsl(Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_glslang_utils.mm_sec11
533
1270
534
    return angle::Result::Continue;
1271
    return angle::Result::Continue;
535
}
1272
}
536
537
}  // namespace mtl
1273
}  // namespace mtl
538
}  // namespace rx
1274
}  // namespace rx
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_occlusion_query_pool.h -1 / +1 lines
Lines 1-5 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_occlusion_query_pool.h_sec1
1
//
1
//
2
// Copyright 2020 The ANGLE Project Authors. All rights reserved.
2
// Copyright (c) 2020 The ANGLE Project Authors. All rights reserved.
3
// Use of this source code is governed by a BSD-style license that can be
3
// Use of this source code is governed by a BSD-style license that can be
4
// found in the LICENSE file.
4
// found in the LICENSE file.
5
//
5
//
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_occlusion_query_pool.mm -10 / +39 lines
Lines 1-5 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_occlusion_query_pool.mm_sec1
1
//
1
//
2
// Copyright 2020 The ANGLE Project Authors. All rights reserved.
2
// Copyright (c) 2020 The ANGLE Project Authors. All rights reserved.
3
// Use of this source code is governed by a BSD-style license that can be
3
// Use of this source code is governed by a BSD-style license that can be
4
// found in the LICENSE file.
4
// found in the LICENSE file.
5
//
5
//
Lines 52-67 angle::Result OcclusionQueryPool::allocateQueryOffset(ContextMtl *contextMtl, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_occlusion_query_pool.mm_sec2
52
    {
52
    {
53
        // First allocation
53
        // First allocation
54
        ANGLE_TRY(Buffer::MakeBufferWithResOpt(contextMtl, MTLResourceStorageModePrivate,
54
        ANGLE_TRY(Buffer::MakeBufferWithResOpt(contextMtl, MTLResourceStorageModePrivate,
55
                                               kOcclusionQueryResultSize, nullptr,
55
                                     kOcclusionQueryResultSize, nullptr, &mRenderPassResultsPool));
56
                                               &mRenderPassResultsPool));
57
        mRenderPassResultsPool->get().label = @"OcclusionQueryPool";
56
        mRenderPassResultsPool->get().label = @"OcclusionQueryPool";
58
    }
57
    }
59
    else if (currentOffset + kOcclusionQueryResultSize > mRenderPassResultsPool->size())
58
    else if (currentOffset + kOcclusionQueryResultSize > mRenderPassResultsPool->size())
60
    {
59
    {
61
        // Double the capacity
60
        // Double the capacity
62
        ANGLE_TRY(Buffer::MakeBufferWithResOpt(contextMtl, MTLResourceStorageModePrivate,
61
        ANGLE_TRY(Buffer::MakeBufferWithResOpt(contextMtl, MTLResourceStorageModePrivate,
63
                                               mRenderPassResultsPool->size() * 2, nullptr,
62
                                     mRenderPassResultsPool->size() * 2, nullptr,
64
                                               &mRenderPassResultsPool));
63
                                     &mRenderPassResultsPool));
65
        mRenderPassResultsPool->get().label = @"OcclusionQueryPool";
64
        mRenderPassResultsPool->get().label = @"OcclusionQueryPool";
66
    }
65
    }
67
66
Lines 88-93 angle::Result OcclusionQueryPool::allocateQueryOffset(ContextMtl *contextMtl, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_occlusion_query_pool.mm_sec3
88
    if (currentOffset == 0)
87
    if (currentOffset == 0)
89
    {
88
    {
90
        mResetFirstQuery = clearOldValue;
89
        mResetFirstQuery = clearOldValue;
90
        if (!clearOldValue && !contextMtl->getDisplay()->getFeatures().allowBufferReadWrite.enabled)
91
        {
92
            // If old value of first query needs to be retained and device doesn't support buffer
93
            // read-write, we need an additional offset to store the old value of the query.
94
            return allocateQueryOffset(contextMtl, query, false);
95
        }
91
    }
96
    }
92
97
93
    return angle::Result::Continue;
98
    return angle::Result::Continue;
Lines 112-121 void OcclusionQueryPool::resolveVisibilityResults(ContextMtl *contextMtl) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_occlusion_query_pool.mm_sec4
112
        return;
117
        return;
113
    }
118
    }
114
119
115
    RenderUtils &utils = contextMtl->getDisplay()->getUtils();
120
    RenderUtils &utils              = contextMtl->getDisplay()->getUtils();
121
    BlitCommandEncoder *blitEncoder = nullptr;
122
    // Combine the values stored in the offsets allocated for first query
123
    if (mAllocatedQueries[0])
124
    {
125
        const BufferRef &dstBuf = mAllocatedQueries[0]->getVisibilityResultBuffer();
126
        const VisibilityBufferOffsetsMtl &allocatedOffsets =
127
            mAllocatedQueries[0]->getAllocatedVisibilityOffsets();
128
        if (!mResetFirstQuery &&
129
            !contextMtl->getDisplay()->getFeatures().allowBufferReadWrite.enabled)
130
        {
131
            // If we cannot read and write to the same buffer in shader. We need to copy the old
132
            // value of first query to first offset allocated for it.
133
            blitEncoder = contextMtl->getBlitCommandEncoder();
134
            blitEncoder->copyBuffer(dstBuf, 0, mRenderPassResultsPool, allocatedOffsets.front(),
135
                                    kOcclusionQueryResultSize);
136
            utils.combineVisibilityResult(contextMtl, false, allocatedOffsets,
137
                                          mRenderPassResultsPool, dstBuf);
138
        }
139
        else
140
        {
141
            utils.combineVisibilityResult(contextMtl, !mResetFirstQuery, allocatedOffsets,
142
                                          mRenderPassResultsPool, dstBuf);
143
        }
144
    }
116
145
117
    // Combine the values stored in the offsets allocated for each of the remaining queries
146
    // Combine the values stored in the offsets allocated for each of the remaining queries
118
    for (size_t i = 0; i < mAllocatedQueries.size(); ++i)
147
    for (size_t i = 1; i < mAllocatedQueries.size(); ++i)
119
    {
148
    {
120
        QueryMtl *query = mAllocatedQueries[i];
149
        QueryMtl *query = mAllocatedQueries[i];
121
        if (!query)
150
        if (!query)
Lines 126-137 void OcclusionQueryPool::resolveVisibilityResults(ContextMtl *contextMtl) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_occlusion_query_pool.mm_sec5
126
        const BufferRef &dstBuf = mAllocatedQueries[i]->getVisibilityResultBuffer();
155
        const BufferRef &dstBuf = mAllocatedQueries[i]->getVisibilityResultBuffer();
127
        const VisibilityBufferOffsetsMtl &allocatedOffsets =
156
        const VisibilityBufferOffsetsMtl &allocatedOffsets =
128
            mAllocatedQueries[i]->getAllocatedVisibilityOffsets();
157
            mAllocatedQueries[i]->getAllocatedVisibilityOffsets();
129
        utils.combineVisibilityResult(contextMtl, /** keepOldValue */ i == 0 && !mResetFirstQuery,
158
        utils.combineVisibilityResult(contextMtl, false, allocatedOffsets, mRenderPassResultsPool,
130
                                      allocatedOffsets, mRenderPassResultsPool, dstBuf);
159
                                      dstBuf);
131
    }
160
    }
132
161
133
    // Request synchronization and cleanup
162
    // Request synchronization and cleanup
134
    BlitCommandEncoder *blitEncoder = contextMtl->getBlitCommandEncoder();
163
    blitEncoder = contextMtl->getBlitCommandEncoder();
135
    for (size_t i = 0; i < mAllocatedQueries.size(); ++i)
164
    for (size_t i = 0; i < mAllocatedQueries.size(); ++i)
136
    {
165
    {
137
        QueryMtl *query = mAllocatedQueries[i];
166
        QueryMtl *query = mAllocatedQueries[i];
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.h -11 / +64 lines
Lines 6-11 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.h_sec1
6
// mtl_render_utils.h:
6
// mtl_render_utils.h:
7
//    Defines the class interface for RenderUtils, which contains many utility functions and shaders
7
//    Defines the class interface for RenderUtils, which contains many utility functions and shaders
8
//    for converting, blitting, copying as well as generating data, and many more.
8
//    for converting, blitting, copying as well as generating data, and many more.
9
// NOTE(hqle): Consider splitting this class into multiple classes each doing different utilities.
10
// This class has become too big.
9
//
11
//
10
12
11
#ifndef LIBANGLE_RENDERER_METAL_MTL_RENDER_UTILS_H_
13
#ifndef LIBANGLE_RENDERER_METAL_MTL_RENDER_UTILS_H_
Lines 89-94 struct ColorBlitParams : public BlitParams a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.h_sec2
89
struct DepthStencilBlitParams : public BlitParams
91
struct DepthStencilBlitParams : public BlitParams
90
{
92
{
91
    TextureRef srcStencil;
93
    TextureRef srcStencil;
94
    uint32_t srcStencilLevel = 0;
95
    uint32_t srcStencilLayer = 0;
92
};
96
};
93
97
94
// Stencil blit via an intermediate buffer. NOTE: source depth texture parameter is ignored.
98
// Stencil blit via an intermediate buffer. NOTE: source depth texture parameter is ignored.
Lines 309-329 class IndexGeneratorUtils final : angle::NonCopyable a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.h_sec3
309
  public:
313
  public:
310
    void onDestroy();
314
    void onDestroy();
311
315
312
    // Convert index buffer.
313
    angle::Result convertIndexBufferGPU(ContextMtl *contextMtl,
316
    angle::Result convertIndexBufferGPU(ContextMtl *contextMtl,
314
                                        const IndexConversionParams &params);
317
                                        const IndexConversionParams &params);
315
    // Generate triangle fan index buffer for glDrawArrays().
316
    angle::Result generateTriFanBufferFromArrays(ContextMtl *contextMtl,
318
    angle::Result generateTriFanBufferFromArrays(ContextMtl *contextMtl,
317
                                                 const TriFanOrLineLoopFromArrayParams &params);
319
                                                 const TriFanOrLineLoopFromArrayParams &params);
318
    // Generate triangle fan index buffer for glDrawElements().
320
    // Generate triangle fan index buffer for glDrawElements().
319
    angle::Result generateTriFanBufferFromElementsArray(ContextMtl *contextMtl,
321
    angle::Result generateTriFanBufferFromElementsArray(ContextMtl *contextMtl,
320
                                                        const IndexGenerationParams &params);
322
                                                        const IndexGenerationParams &params,
323
                                                        uint32_t *indicesGenerated);
321
324
322
    // Generate line loop index buffer for glDrawArrays().
323
    angle::Result generateLineLoopBufferFromArrays(ContextMtl *contextMtl,
325
    angle::Result generateLineLoopBufferFromArrays(ContextMtl *contextMtl,
324
                                                   const TriFanOrLineLoopFromArrayParams &params);
326
                                                   const TriFanOrLineLoopFromArrayParams &params);
325
    // Generate line loop's last segment index buffer for glDrawArrays().
326
    // This is used when primitive restart is not enabled.
327
    angle::Result generateLineLoopLastSegment(ContextMtl *contextMtl,
327
    angle::Result generateLineLoopLastSegment(ContextMtl *contextMtl,
328
                                              uint32_t firstVertex,
328
                                              uint32_t firstVertex,
329
                                              uint32_t lastVertex,
329
                                              uint32_t lastVertex,
Lines 340-345 class IndexGeneratorUtils final : angle::NonCopyable a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.h_sec4
340
    angle::Result generateLineLoopLastSegmentFromElementsArray(ContextMtl *contextMtl,
340
    angle::Result generateLineLoopLastSegmentFromElementsArray(ContextMtl *contextMtl,
341
                                                               const IndexGenerationParams &params);
341
                                                               const IndexGenerationParams &params);
342
342
343
    angle::Result generatePrimitiveRestartPointsBuffer(ContextMtl *contextMtl,
344
                                                       const IndexGenerationParams &params,
345
                                                       size_t *indicesGenerated);
346
347
    angle::Result generatePrimitiveRestartLinesBuffer(ContextMtl *contextMtl,
348
                                                      const IndexGenerationParams &params,
349
                                                      size_t *indicesGenerated);
350
351
    angle::Result generatePrimitiveRestartTrianglesBuffer(ContextMtl *contextMtl,
352
                                                          const IndexGenerationParams &params,
353
                                                          size_t *indicesGenerated);
354
343
  private:
355
  private:
344
    // Index generator compute pipelines:
356
    // Index generator compute pipelines:
345
    //  - First dimension: index type.
357
    //  - First dimension: index type.
Lines 348-354 class IndexGeneratorUtils final : angle::NonCopyable a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.h_sec5
348
        std::array<std::array<AutoObjCPtr<id<MTLComputePipelineState>>, 2>,
360
        std::array<std::array<AutoObjCPtr<id<MTLComputePipelineState>>, 2>,
349
                   angle::EnumSize<gl::DrawElementsType>()>;
361
                   angle::EnumSize<gl::DrawElementsType>()>;
350
362
351
    // Get compute pipeline to convert index between buffers.
352
    AutoObjCPtr<id<MTLComputePipelineState>> getIndexConversionPipeline(
363
    AutoObjCPtr<id<MTLComputePipelineState>> getIndexConversionPipeline(
353
        ContextMtl *contextMtl,
364
        ContextMtl *contextMtl,
354
        gl::DrawElementsType srcType,
365
        gl::DrawElementsType srcType,
Lines 375-381 class IndexGeneratorUtils final : angle::NonCopyable a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.h_sec6
375
        // Must be multiples of kIndexBufferOffsetAlignment
386
        // Must be multiples of kIndexBufferOffsetAlignment
376
        uint32_t dstOffset);
387
        uint32_t dstOffset);
377
    angle::Result generateTriFanBufferFromElementsArrayCPU(ContextMtl *contextMtl,
388
    angle::Result generateTriFanBufferFromElementsArrayCPU(ContextMtl *contextMtl,
378
                                                           const IndexGenerationParams &params);
389
                                                           const IndexGenerationParams &params,
390
                                                           uint32_t *indicesGenerated);
379
391
380
    angle::Result generateLineLoopBufferFromElementsArrayGPU(
392
    angle::Result generateLineLoopBufferFromElementsArrayGPU(
381
        ContextMtl *contextMtl,
393
        ContextMtl *contextMtl,
Lines 393-398 class IndexGeneratorUtils final : angle::NonCopyable a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.h_sec7
393
        ContextMtl *contextMtl,
405
        ContextMtl *contextMtl,
394
        const IndexGenerationParams &params);
406
        const IndexGenerationParams &params);
395
407
408
    angle::Result generatePrimitiveRestartBuffer(ContextMtl *contextMtl,
409
                                                 unsigned numVerticesPerPrimitive,
410
                                                 const IndexGenerationParams &params,
411
                                                 size_t *indicesGenerated);
412
396
    IndexConversionPipelineArray mIndexConversionPipelineCaches;
413
    IndexConversionPipelineArray mIndexConversionPipelineCaches;
397
414
398
    IndexConversionPipelineArray mTriFanFromElemArrayGeneratorPipelineCaches;
415
    IndexConversionPipelineArray mTriFanFromElemArrayGeneratorPipelineCaches;
Lines 429-435 class MipmapUtils final : angle::NonCopyable a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.h_sec8
429
  public:
446
  public:
430
    void onDestroy();
447
    void onDestroy();
431
448
432
    // Compute based mipmap generation. Only possible for 3D texture for now.
449
    // Compute based mipmap generation.
433
    angle::Result generateMipmapCS(ContextMtl *contextMtl,
450
    angle::Result generateMipmapCS(ContextMtl *contextMtl,
434
                                   const TextureRef &srcTexture,
451
                                   const TextureRef &srcTexture,
435
                                   bool sRGBMipmap,
452
                                   bool sRGBMipmap,
Lines 437-445 class MipmapUtils final : angle::NonCopyable a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.h_sec9
437
454
438
  private:
455
  private:
439
    void ensure3DMipGeneratorPipelineInitialized(ContextMtl *contextMtl);
456
    void ensure3DMipGeneratorPipelineInitialized(ContextMtl *contextMtl);
457
    void ensure2DMipGeneratorPipelineInitialized(ContextMtl *contextMtl);
458
    void ensure2DArrayMipGeneratorPipelineInitialized(ContextMtl *contextMtl);
459
    void ensureCubeMipGeneratorPipelineInitialized(ContextMtl *contextMtl);
440
460
441
    // Mipmaps generating compute pipeline:
461
    // Mipmaps generating compute pipeline:
442
    AutoObjCPtr<id<MTLComputePipelineState>> m3DMipGeneratorPipeline;
462
    AutoObjCPtr<id<MTLComputePipelineState>> m3DMipGeneratorPipeline;
463
    AutoObjCPtr<id<MTLComputePipelineState>> m2DMipGeneratorPipeline;
464
    AutoObjCPtr<id<MTLComputePipelineState>> m2DArrayMipGeneratorPipeline;
465
    AutoObjCPtr<id<MTLComputePipelineState>> mCubeMipGeneratorPipeline;
443
};
466
};
444
467
445
// Util class for handling pixels copy between buffers and textures
468
// Util class for handling pixels copy between buffers and textures
Lines 543-548 class VertexFormatConversionUtils final : angle::NonCopyable a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.h_sec10
543
    RenderPipelineCache mComponentsExpandRenderPipelineCache;
566
    RenderPipelineCache mComponentsExpandRenderPipelineCache;
544
};
567
};
545
568
569
// Util class for handling transform feedback
570
    class TransformFeedbackUtils
571
{
572
  public:
573
    void onDestroy();
574
    AutoObjCPtr<id<MTLRenderPipelineState>> getTransformFeedbackRenderPipeline(
575
        ContextMtl *contextMtl,
576
        RenderCommandEncoder *cmdEncoder,
577
        mtl::RenderPipelineDesc &pipelineDesc);
578
579
  private:
580
    AutoObjCPtr<id<MTLLibrary>> createMslXfbLibrary(ContextMtl *contextMtl,
581
                                                    const std::string &translatedMsl);
582
};
583
546
// RenderUtils: container class of various util classes above
584
// RenderUtils: container class of various util classes above
547
class RenderUtils : public Context, angle::NonCopyable
585
class RenderUtils : public Context, angle::NonCopyable
548
{
586
{
Lines 587-593 class RenderUtils : public Context, angle::NonCopyable a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.h_sec11
587
    angle::Result generateTriFanBufferFromArrays(ContextMtl *contextMtl,
625
    angle::Result generateTriFanBufferFromArrays(ContextMtl *contextMtl,
588
                                                 const TriFanOrLineLoopFromArrayParams &params);
626
                                                 const TriFanOrLineLoopFromArrayParams &params);
589
    angle::Result generateTriFanBufferFromElementsArray(ContextMtl *contextMtl,
627
    angle::Result generateTriFanBufferFromElementsArray(ContextMtl *contextMtl,
590
                                                        const IndexGenerationParams &params);
628
                                                        const IndexGenerationParams &params,
629
                                                        uint32_t *indicesGenerated);
591
630
592
    angle::Result generateLineLoopBufferFromArrays(ContextMtl *contextMtl,
631
    angle::Result generateLineLoopBufferFromArrays(ContextMtl *contextMtl,
593
                                                   const TriFanOrLineLoopFromArrayParams &params);
632
                                                   const TriFanOrLineLoopFromArrayParams &params);
Lines 639-644 class RenderUtils : public Context, angle::NonCopyable a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.h_sec12
639
                                                 RenderCommandEncoder *renderEncoder,
678
                                                 RenderCommandEncoder *renderEncoder,
640
                                                 const angle::Format &srcAngleFormat,
679
                                                 const angle::Format &srcAngleFormat,
641
                                                 const VertexFormatConvertParams &params);
680
                                                 const VertexFormatConvertParams &params);
681
    angle::Result createTransformFeedbackPSO(const gl::Context *context,
682
                                             RenderCommandEncoder *renderEncoder,
683
                                             mtl::RenderPipelineDesc &pipelineDesc);
684
685
    angle::Result generatePrimitiveRestartPointsBuffer(ContextMtl *contextMtl,
686
                                                       const IndexGenerationParams &params,
687
                                                       size_t *indicesGenerated);
688
    angle::Result generatePrimitiveRestartLinesBuffer(ContextMtl *contextMtl,
689
                                                      const IndexGenerationParams &params,
690
                                                      size_t *indicesGenerated);
691
    angle::Result generatePrimitiveRestartTrianglesBuffer(ContextMtl *contextMtl,
692
                                                          const IndexGenerationParams &params,
693
                                                          size_t *indicesGenerated);
642
694
643
  private:
695
  private:
644
    // override ErrorHandler
696
    // override ErrorHandler
Lines 646-652 class RenderUtils : public Context, angle::NonCopyable a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.h_sec13
646
                     const char *file,
698
                     const char *file,
647
                     const char *function,
699
                     const char *function,
648
                     unsigned int line) override;
700
                     unsigned int line) override;
649
    void handleError(NSError *_Nullable error,
701
    void handleError(NSError *error,
650
                     const char *file,
702
                     const char *file,
651
                     const char *function,
703
                     const char *function,
652
                     unsigned int line) override;
704
                     unsigned int line) override;
Lines 662-667 class RenderUtils : public Context, angle::NonCopyable a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.h_sec14
662
    MipmapUtils mMipmapUtils;
714
    MipmapUtils mMipmapUtils;
663
    std::array<CopyPixelsUtils, angle::EnumSize<PixelType>()> mCopyPixelsUtils;
715
    std::array<CopyPixelsUtils, angle::EnumSize<PixelType>()> mCopyPixelsUtils;
664
    VertexFormatConversionUtils mVertexFormatUtils;
716
    VertexFormatConversionUtils mVertexFormatUtils;
717
    TransformFeedbackUtils mTransformFeedbackUtils;
665
};
718
};
666
719
667
}  // namespace mtl
720
}  // namespace mtl
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm -157 / +379 lines
Lines 15-20 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec1
15
#include "libANGLE/renderer/metal/BufferMtl.h"
15
#include "libANGLE/renderer/metal/BufferMtl.h"
16
#include "libANGLE/renderer/metal/ContextMtl.h"
16
#include "libANGLE/renderer/metal/ContextMtl.h"
17
#include "libANGLE/renderer/metal/DisplayMtl.h"
17
#include "libANGLE/renderer/metal/DisplayMtl.h"
18
#include "libANGLE/renderer/metal/ProgramMtl.h"
18
#include "libANGLE/renderer/metal/QueryMtl.h"
19
#include "libANGLE/renderer/metal/QueryMtl.h"
19
#include "libANGLE/renderer/metal/mtl_common.h"
20
#include "libANGLE/renderer/metal/mtl_common.h"
20
#include "libANGLE/renderer/metal/mtl_utils.h"
21
#include "libANGLE/renderer/metal/mtl_utils.h"
Lines 54-63 struct BlitParamsUniform a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec2
54
    float srcTexCoords[3][2];
55
    float srcTexCoords[3][2];
55
    int srcLevel         = 0;
56
    int srcLevel         = 0;
56
    int srcLayer         = 0;
57
    int srcLayer         = 0;
58
    int srcLevel2        = 0;
59
    int srcLayer2        = 0;
57
    uint8_t dstFlipX     = 0;
60
    uint8_t dstFlipX     = 0;
58
    uint8_t dstFlipY     = 0;
61
    uint8_t dstFlipY     = 0;
59
    uint8_t dstLuminance = 0;  // dest texture is luminace
62
    uint8_t dstLuminance = 0;  // dest texture is luminace
60
    uint8_t padding[13];
63
    uint8_t padding[9];
61
};
64
};
62
65
63
struct BlitStencilToBufferParamsUniform
66
struct BlitStencilToBufferParamsUniform
Lines 90-96 struct IndexConversionUniform a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec3
90
    uint8_t padding[7];
93
    uint8_t padding[7];
91
};
94
};
92
95
93
// See libANGLE/renderer/metal/shaders/visibility.metal
96
// See libANGLE/renderer/metal/shaders/misc.metal
94
struct CombineVisibilityResultUniform
97
struct CombineVisibilityResultUniform
95
{
98
{
96
    uint32_t startOffset;
99
    uint32_t startOffset;
Lines 99-110 struct CombineVisibilityResultUniform a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec4
99
};
102
};
100
103
101
// See libANGLE/renderer/metal/shaders/gen_mipmap.metal
104
// See libANGLE/renderer/metal/shaders/gen_mipmap.metal
102
struct GenerateMipmapUniform
105
struct Generate3DMipmapUniform
103
{
106
{
104
    uint32_t srcLevel;
107
    uint32_t srcLevel;
105
    uint32_t numMipmapsToGenerate;
108
    uint32_t numMipmapsToGenerate;
106
    uint8_t sRGB;
109
    uint32_t padding[2];
107
    uint8_t padding[7];
108
};
110
};
109
111
110
// See libANGLE/renderer/metal/shaders/copy_buffer.metal
112
// See libANGLE/renderer/metal/shaders/copy_buffer.metal
Lines 156-174 struct CopyVertexUniforms a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec5
156
// exiting block.
158
// exiting block.
157
struct ScopedDisableOcclusionQuery
159
struct ScopedDisableOcclusionQuery
158
{
160
{
159
    ScopedDisableOcclusionQuery(ContextMtl *contextMtl, angle::Result *resultOut)
161
    ScopedDisableOcclusionQuery(ContextMtl *contextMtl,
160
        : mContextMtl(contextMtl), mResultOut(resultOut)
162
                                RenderCommandEncoder *encoder,
163
                                angle::Result *resultOut)
164
        : mContextMtl(contextMtl), mEncoder(encoder), mResultOut(resultOut)
161
    {
165
    {
166
#ifndef NDEBUG
167
        if (contextMtl->hasActiveOcclusionQuery())
168
        {
169
            encoder->pushDebugGroup(@"Disabled OcclusionQuery");
170
        }
171
#endif
162
        // temporarily disable occlusion query
172
        // temporarily disable occlusion query
163
        contextMtl->disableActiveOcclusionQueryInRenderPass();
173
        contextMtl->disableActiveOcclusionQueryInRenderPass();
164
    }
174
    }
165
    ~ScopedDisableOcclusionQuery()
175
    ~ScopedDisableOcclusionQuery()
166
    {
176
    {
167
        *mResultOut = mContextMtl->restartActiveOcclusionQueryInRenderPass();
177
        *mResultOut = mContextMtl->restartActiveOcclusionQueryInRenderPass();
178
#ifndef NDEBUG
179
        if (mContextMtl->hasActiveOcclusionQuery())
180
        {
181
            mEncoder->popDebugGroup();
182
        }
183
#else
184
        ANGLE_UNUSED_VARIABLE(mEncoder);
185
#endif
168
    }
186
    }
169
187
170
  private:
188
  private:
171
    ContextMtl *mContextMtl;
189
    ContextMtl *mContextMtl;
190
    RenderCommandEncoder *mEncoder;
172
191
173
    angle::Result *mResultOut;
192
    angle::Result *mResultOut;
174
};
193
};
Lines 219-284 angle::Result GenTriFanFromClientElements(ContextMtl *contextMtl, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec6
219
                                          bool primitiveRestartEnabled,
238
                                          bool primitiveRestartEnabled,
220
                                          const T *indices,
239
                                          const T *indices,
221
                                          const BufferRef &dstBuffer,
240
                                          const BufferRef &dstBuffer,
222
                                          uint32_t dstOffset)
241
                                          uint32_t dstOffset,
242
                                          uint32_t *indicesGenerated)
223
{
243
{
224
    ASSERT(count > 2);
244
    ASSERT(count > 2);
225
245
    constexpr T kSrcPrimitiveRestartIndex = std::numeric_limits<T>::max();
226
    uint32_t genIndicesCount;
246
    GLsizei dstTriangle                   = 0;
227
    ANGLE_TRY(mtl::GetTriangleFanIndicesCount(contextMtl, count, &genIndicesCount));
228
229
    constexpr T kSrcPrimitiveRestartIndex    = std::numeric_limits<T>::max();
230
    const uint32_t kDstPrimitiveRestartIndex = std::numeric_limits<uint32_t>::max();
231
232
    uint32_t *dstPtr = reinterpret_cast<uint32_t *>(dstBuffer->map(contextMtl) + dstOffset);
247
    uint32_t *dstPtr = reinterpret_cast<uint32_t *>(dstBuffer->map(contextMtl) + dstOffset);
233
    T triFirstIdx    = 0;  // Vertex index of trianlge's 1st vertex
248
    T triFirstIdx, srcPrevIdx;
234
    T srcPrevIdx     = 0;  // Vertex index of trianlge's 2nd vertex
235
    memcpy(&triFirstIdx, indices, sizeof(triFirstIdx));
249
    memcpy(&triFirstIdx, indices, sizeof(triFirstIdx));
250
    memcpy(&srcPrevIdx, indices + 1, sizeof(srcPrevIdx));
236
251
237
    if (primitiveRestartEnabled)
252
    if (primitiveRestartEnabled)
238
    {
253
    {
239
        // triFirstIdxLoc: Location of current triangle's fist vertex in source buffer.
240
        GLsizei triFirstIdxLoc = 0;
254
        GLsizei triFirstIdxLoc = 0;
241
        while (triFirstIdx == kSrcPrimitiveRestartIndex)
255
        while (triFirstIdx == kSrcPrimitiveRestartIndex)
242
        {
256
        {
243
            memcpy(&dstPtr[triFirstIdxLoc++], &kDstPrimitiveRestartIndex,
257
            ++triFirstIdxLoc;
244
                   sizeof(kDstPrimitiveRestartIndex));
245
            memcpy(&triFirstIdx, indices + triFirstIdxLoc, sizeof(triFirstIdx));
258
            memcpy(&triFirstIdx, indices + triFirstIdxLoc, sizeof(triFirstIdx));
246
        }
259
        }
247
260
248
        if (triFirstIdxLoc + 2 >= count)
249
        {
250
            // Not enough indices.
251
            for (GLsizei i = triFirstIdxLoc; i < count; ++i)
252
            {
253
                memcpy(&dstPtr[i], &kDstPrimitiveRestartIndex, sizeof(kDstPrimitiveRestartIndex));
254
            }
255
        }
256
        else if (triFirstIdxLoc + 1 < count)
257
        {
258
            memcpy(&srcPrevIdx, indices + triFirstIdxLoc + 1, sizeof(srcPrevIdx));
259
        }
260
261
        for (GLsizei i = triFirstIdxLoc + 2; i < count; ++i)
261
        for (GLsizei i = triFirstIdxLoc + 2; i < count; ++i)
262
        {
262
        {
263
            uint32_t triIndices[3];
263
            uint32_t triIndices[3];
264
265
            T srcIdx;
264
            T srcIdx;
266
            memcpy(&srcIdx, indices + i, sizeof(srcIdx));
265
            memcpy(&srcIdx, indices + i, sizeof(srcIdx));
266
            bool completeTriangle = true;
267
            if (srcPrevIdx == kSrcPrimitiveRestartIndex || srcIdx == kSrcPrimitiveRestartIndex)
267
            if (srcPrevIdx == kSrcPrimitiveRestartIndex || srcIdx == kSrcPrimitiveRestartIndex)
268
            {
268
            {
269
                // Incomplete triangle.
269
                // Incomplete triangle. Move to next triangle and set triFirstIndex
270
                triIndices[0]  = kDstPrimitiveRestartIndex;
270
                triFirstIdx      = srcIdx;
271
                triIndices[1]  = kDstPrimitiveRestartIndex;
271
                triFirstIdxLoc   = i;
272
                triIndices[2]  = kDstPrimitiveRestartIndex;
272
                completeTriangle = false;
273
                triFirstIdx    = srcIdx;
274
                triFirstIdxLoc = i;
275
            }
273
            }
276
            else if (i < triFirstIdxLoc + 2)
274
            else if (i < triFirstIdxLoc + 2)
277
            {
275
            {
278
                // Incomplete triangle
276
                // Incomplete triangle, move to next triangle
279
                triIndices[0] = kDstPrimitiveRestartIndex;
277
                completeTriangle = false;
280
                triIndices[1] = kDstPrimitiveRestartIndex;
281
                triIndices[2] = kDstPrimitiveRestartIndex;
282
            }
278
            }
283
            else
279
            else
284
            {
280
            {
Lines 286-300 angle::Result GenTriFanFromClientElements(ContextMtl *contextMtl, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec7
286
                triIndices[1] = srcPrevIdx;
282
                triIndices[1] = srcPrevIdx;
287
                triIndices[2] = srcIdx;
283
                triIndices[2] = srcIdx;
288
            }
284
            }
285
            if (completeTriangle)
286
            {
287
                memcpy(dstPtr + 3 * dstTriangle, triIndices, sizeof(triIndices));
288
                ++dstTriangle;
289
            }
289
            srcPrevIdx = srcIdx;
290
            srcPrevIdx = srcIdx;
290
291
            memcpy(dstPtr + 3 * (i - 2), triIndices, sizeof(triIndices));
292
        }
291
        }
293
    }
292
    }
294
    else
293
    else
295
    {
294
    {
296
        memcpy(&srcPrevIdx, indices + 1, sizeof(srcPrevIdx));
297
298
        for (GLsizei i = 2; i < count; ++i)
295
        for (GLsizei i = 2; i < count; ++i)
299
        {
296
        {
300
            T srcIdx;
297
            T srcIdx;
Lines 306-316 angle::Result GenTriFanFromClientElements(ContextMtl *contextMtl, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec8
306
            triIndices[2] = srcIdx;
303
            triIndices[2] = srcIdx;
307
            srcPrevIdx    = srcIdx;
304
            srcPrevIdx    = srcIdx;
308
305
309
            memcpy(dstPtr + 3 * (i - 2), triIndices, sizeof(triIndices));
306
            memcpy(dstPtr + 3 * dstTriangle, triIndices, sizeof(triIndices));
307
            ++dstTriangle;
310
        }
308
        }
311
    }
309
    }
312
    dstBuffer->unmapAndFlushSubset(contextMtl, dstOffset, genIndicesCount * sizeof(uint32_t));
310
    if (indicesGenerated)
311
        *indicesGenerated = dstTriangle * 3;
312
    dstBuffer->unmap(contextMtl);
313
314
    return angle::Result::Continue;
315
}
313
316
317
template <typename T>
318
angle::Result GenPrimitiveRestartBuffer(ContextMtl *contextMtl,
319
                                        GLsizei count,
320
                                        GLsizei indicesPerPrimitive,
321
                                        const T *indices,
322
                                        const BufferRef &dstBuffer,
323
                                        uint32_t dstOffset,
324
                                        size_t *indicesGenerated)
325
{
326
    constexpr T kSrcPrimitiveRestartIndex = std::numeric_limits<T>::max();
327
    uint32_t *dstPtr     = reinterpret_cast<uint32_t *>(dstBuffer->map(contextMtl) + dstOffset);
328
    GLsizei readValueLoc = 0;
329
    T readValue          = 0;
330
    uint32_t dstIdx      = 0;
331
    memcpy(&readValue, indices, sizeof(readValue));
332
    while (readValue == kSrcPrimitiveRestartIndex)
333
    {
334
335
        ++readValueLoc;
336
        memcpy(&readValue, indices + readValueLoc, sizeof(readValue));
337
    }
338
    while (readValueLoc + indicesPerPrimitive <= count)
339
    {
340
341
        uint32_t primIndicies[3];
342
        bool foundPrimitive = true;
343
        for (int k = 0; k < indicesPerPrimitive; ++k)
344
        {
345
            memcpy(&readValue, indices + readValueLoc, sizeof(readValue));
346
            ++readValueLoc;
347
            if (readValue == kSrcPrimitiveRestartIndex)
348
            {
349
                foundPrimitive = false;
350
                break;
351
            }
352
            else
353
            {
354
                primIndicies[k] = (uint32_t)readValue;
355
            }
356
        }
357
        if (foundPrimitive)
358
        {
359
            memcpy(&dstPtr[dstIdx], primIndicies, (indicesPerPrimitive) * sizeof(uint32_t));
360
            dstIdx += indicesPerPrimitive;
361
        }
362
    }
363
    if (indicesGenerated)
364
        *indicesGenerated = dstIdx;
314
    return angle::Result::Continue;
365
    return angle::Result::Continue;
315
}
366
}
316
367
Lines 328-341 angle::Result GenLineLoopFromClientElements(ContextMtl *contextMtl, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec9
328
    const uint32_t kDstPrimitiveRestartIndex = std::numeric_limits<uint32_t>::max();
379
    const uint32_t kDstPrimitiveRestartIndex = std::numeric_limits<uint32_t>::max();
329
380
330
    uint32_t *dstPtr = reinterpret_cast<uint32_t *>(dstBuffer->map(contextMtl) + dstOffset);
381
    uint32_t *dstPtr = reinterpret_cast<uint32_t *>(dstBuffer->map(contextMtl) + dstOffset);
331
    // lineLoopFirstIdx: value of of current line loop's first vertex index. Can change when
332
    // encounter a primitive restart index.
333
    T lineLoopFirstIdx;
382
    T lineLoopFirstIdx;
334
    memcpy(&lineLoopFirstIdx, indices, sizeof(lineLoopFirstIdx));
383
    memcpy(&lineLoopFirstIdx, indices, sizeof(lineLoopFirstIdx));
335
384
336
    if (primitiveRestartEnabled)
385
    if (primitiveRestartEnabled)
337
    {
386
    {
338
        // lineLoopFirstIdxLoc: location of current line loop's first vertex in the source buffer.
339
        GLsizei lineLoopFirstIdxLoc = 0;
387
        GLsizei lineLoopFirstIdxLoc = 0;
340
        while (lineLoopFirstIdx == kSrcPrimitiveRestartIndex)
388
        while (lineLoopFirstIdx == kSrcPrimitiveRestartIndex)
341
        {
389
        {
Lines 344-358 angle::Result GenLineLoopFromClientElements(ContextMtl *contextMtl, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec10
344
            memcpy(&lineLoopFirstIdx, indices + lineLoopFirstIdxLoc, sizeof(lineLoopFirstIdx));
392
            memcpy(&lineLoopFirstIdx, indices + lineLoopFirstIdxLoc, sizeof(lineLoopFirstIdx));
345
        }
393
        }
346
394
347
        // dstIdx : value of index to be written to dest buffer
348
        uint32_t dstIdx = lineLoopFirstIdx;
395
        uint32_t dstIdx = lineLoopFirstIdx;
349
        memcpy(&dstPtr[lineLoopFirstIdxLoc], &dstIdx, sizeof(dstIdx));
396
        memcpy(&dstPtr[lineLoopFirstIdxLoc], &dstIdx, sizeof(dstIdx));
350
        // dstWritten: number of indices written to dest buffer
351
        uint32_t dstWritten = lineLoopFirstIdxLoc + 1;
397
        uint32_t dstWritten = lineLoopFirstIdxLoc + 1;
352
398
353
        for (GLsizei i = lineLoopFirstIdxLoc + 1; i < count; ++i)
399
        for (GLsizei i = lineLoopFirstIdxLoc + 1; i < count; ++i)
354
        {
400
        {
355
            // srcIdx : value of index from source buffer
356
            T srcIdx;
401
            T srcIdx;
357
            memcpy(&srcIdx, indices + i, sizeof(srcIdx));
402
            memcpy(&srcIdx, indices + i, sizeof(srcIdx));
358
            if (srcIdx == kSrcPrimitiveRestartIndex)
403
            if (srcIdx == kSrcPrimitiveRestartIndex)
Lines 400-406 angle::Result GenLineLoopFromClientElements(ContextMtl *contextMtl, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec11
400
445
401
        *indicesGenerated = count + 1;
446
        *indicesGenerated = count + 1;
402
    }
447
    }
403
    dstBuffer->unmapAndFlushSubset(contextMtl, dstOffset, (*indicesGenerated) * sizeof(uint32_t));
448
    dstBuffer->unmap(contextMtl);
404
449
405
    return angle::Result::Continue;
450
    return angle::Result::Continue;
406
}
451
}
Lines 472-478 void EnsureComputePipelineInitialized(DisplayMtl *display, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec12
472
    ANGLE_MTL_OBJC_SCOPE
517
    ANGLE_MTL_OBJC_SCOPE
473
    {
518
    {
474
        id<MTLDevice> metalDevice = display->getMetalDevice();
519
        id<MTLDevice> metalDevice = display->getMetalDevice();
475
        id<MTLLibrary> shaderLib  = display->getDefaultShadersLib();
520
        auto shaderLib            = display->getDefaultShadersLib();
476
        NSError *err              = nil;
521
        NSError *err              = nil;
477
        id<MTLFunction> shader    = [shaderLib newFunctionWithName:functionName];
522
        id<MTLFunction> shader    = [shaderLib newFunctionWithName:functionName];
478
523
Lines 512-518 void EnsureSpecializedComputePipelineInitialized( a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec13
512
    ANGLE_MTL_OBJC_SCOPE
557
    ANGLE_MTL_OBJC_SCOPE
513
    {
558
    {
514
        id<MTLDevice> metalDevice = display->getMetalDevice();
559
        id<MTLDevice> metalDevice = display->getMetalDevice();
515
        id<MTLLibrary> shaderLib  = display->getDefaultShadersLib();
560
        auto shaderLib            = display->getDefaultShadersLib();
516
        NSError *err              = nil;
561
        NSError *err              = nil;
517
562
518
        id<MTLFunction> shader = [shaderLib newFunctionWithName:functionName
563
        id<MTLFunction> shader = [shaderLib newFunctionWithName:functionName
Lines 538-543 void EnsureSpecializedComputePipelineInitialized( a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec14
538
ANGLE_INLINE
583
ANGLE_INLINE
539
void EnsureVertexShaderOnlyPipelineCacheInitialized(Context *context,
584
void EnsureVertexShaderOnlyPipelineCacheInitialized(Context *context,
540
                                                    NSString *vertexFunctionName,
585
                                                    NSString *vertexFunctionName,
586
                                                    id<MTLLibrary> shaderLib,
541
                                                    RenderPipelineCache *pipelineCacheOut)
587
                                                    RenderPipelineCache *pipelineCacheOut)
542
{
588
{
543
    RenderPipelineCache &pipelineCache = *pipelineCacheOut;
589
    RenderPipelineCache &pipelineCache = *pipelineCacheOut;
Lines 549-557 void EnsureVertexShaderOnlyPipelineCacheInitialized(Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec15
549
595
550
    ANGLE_MTL_OBJC_SCOPE
596
    ANGLE_MTL_OBJC_SCOPE
551
    {
597
    {
552
        DisplayMtl *display      = context->getDisplay();
598
        id<MTLFunction> shader = [shaderLib newFunctionWithName:vertexFunctionName];
553
        id<MTLLibrary> shaderLib = display->getDefaultShadersLib();
554
        id<MTLFunction> shader   = [shaderLib newFunctionWithName:vertexFunctionName];
555
599
556
        ASSERT([shader ANGLE_MTL_AUTORELEASE]);
600
        ASSERT([shader ANGLE_MTL_AUTORELEASE]);
557
601
Lines 570-576 void EnsureSpecializedVertexShaderOnlyPipelineCacheInitialized( a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec16
570
    if (!funcConstants)
614
    if (!funcConstants)
571
    {
615
    {
572
        // Non specialized constants provided, use default creation function.
616
        // Non specialized constants provided, use default creation function.
573
        EnsureVertexShaderOnlyPipelineCacheInitialized(context, vertexFunctionName,
617
        DisplayMtl *display = context->getDisplay();
618
        auto shaderLib      = display->getDefaultShadersLib();
619
        EnsureVertexShaderOnlyPipelineCacheInitialized(context, vertexFunctionName, shaderLib,
574
                                                       pipelineCacheOut);
620
                                                       pipelineCacheOut);
575
        return;
621
        return;
576
    }
622
    }
Lines 584-592 void EnsureSpecializedVertexShaderOnlyPipelineCacheInitialized( a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec17
584
630
585
    ANGLE_MTL_OBJC_SCOPE
631
    ANGLE_MTL_OBJC_SCOPE
586
    {
632
    {
587
        DisplayMtl *display      = context->getDisplay();
633
        DisplayMtl *display = context->getDisplay();
588
        id<MTLLibrary> shaderLib = display->getDefaultShadersLib();
634
        auto shaderLib      = display->getDefaultShadersLib();
589
        NSError *err             = nil;
635
        NSError *err        = nil;
590
636
591
        id<MTLFunction> shader = [shaderLib newFunctionWithName:vertexFunctionName
637
        id<MTLFunction> shader = [shaderLib newFunctionWithName:vertexFunctionName
592
                                                 constantValues:funcConstants
638
                                                 constantValues:funcConstants
Lines 609-620 RenderPipelineDesc GetComputingVertexShaderOnlyRenderPipelineDesc(RenderCommandE a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec18
609
    const RenderPassDesc &renderPassDesc = cmdEncoder->renderPassDesc();
655
    const RenderPassDesc &renderPassDesc = cmdEncoder->renderPassDesc();
610
656
611
    renderPassDesc.populateRenderPipelineOutputDesc(&pipelineDesc.outputDescriptor);
657
    renderPassDesc.populateRenderPipelineOutputDesc(&pipelineDesc.outputDescriptor);
612
    pipelineDesc.rasterizationType      = RenderPipelineRasterization::Disabled;
658
    pipelineDesc.rasterizationType   = RenderPipelineRasterization::Disabled;
613
    pipelineDesc.inputPrimitiveTopology = kPrimitiveTopologyClassPoint;
659
    pipelineDesc.inputPrimitiveTopology = kPrimitiveTopologyClassPoint;
614
660
615
    return pipelineDesc;
661
    return pipelineDesc;
616
}
662
}
617
663
664
// Get pipeline descriptor for render pipeline that contains vertex shader acting as transform
665
// feedback.
666
ANGLE_INLINE
667
RenderPipelineDesc GetTransformFeedbackRenderPipelineDesc(RenderCommandEncoder *cmdEncoder,
668
                                                          mtl::RenderPipelineDesc &pipelineDesc)
669
{
670
    RenderPipelineDesc xfbPipelineDesc   = RenderPipelineDesc(pipelineDesc);
671
    const RenderPassDesc &renderPassDesc = cmdEncoder->renderPassDesc();
672
673
    renderPassDesc.populateRenderPipelineOutputDesc(&pipelineDesc.outputDescriptor);
674
    xfbPipelineDesc.rasterizationType   = RenderPipelineRasterization::Disabled;
675
    xfbPipelineDesc.inputPrimitiveTopology = kPrimitiveTopologyClassPoint;
676
677
    return xfbPipelineDesc;
678
}
679
618
template <typename T>
680
template <typename T>
619
void ClearRenderPipelineCacheArray(T *pipelineCacheArray)
681
void ClearRenderPipelineCacheArray(T *pipelineCacheArray)
620
{
682
{
Lines 712-719 void SetupBlitWithDrawUniformData(RenderCommandEncoder *cmdEncoder, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec19
712
    uniformParams.srcLayer = params.srcLayer;
774
    uniformParams.srcLayer = params.srcLayer;
713
    if (isColorBlit)
775
    if (isColorBlit)
714
    {
776
    {
715
        const ColorBlitParams *colorParams = static_cast<const ColorBlitParams *>(&params);
777
        const auto colorParams     = static_cast<const ColorBlitParams *>(&params);
716
        uniformParams.dstLuminance         = colorParams->dstLuminance ? 1 : 0;
778
        uniformParams.dstLuminance = colorParams->dstLuminance ? 1 : 0;
779
    }
780
    else
781
    {
782
        const auto dsParams     = static_cast<const DepthStencilBlitParams *>(&params);
783
        uniformParams.srcLevel2 = dsParams->srcStencilLevel;
784
        uniformParams.srcLayer2 = dsParams->srcStencilLayer;
717
    }
785
    }
718
786
719
    // Compute source texCoords
787
    // Compute source texCoords
Lines 727-734 void SetupBlitWithDrawUniformData(RenderCommandEncoder *cmdEncoder, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec20
727
    {
795
    {
728
        const DepthStencilBlitParams *dsParams =
796
        const DepthStencilBlitParams *dsParams =
729
            static_cast<const DepthStencilBlitParams *>(&params);
797
            static_cast<const DepthStencilBlitParams *>(&params);
730
        srcWidth  = dsParams->srcStencil->width(dsParams->srcLevel);
798
        srcWidth  = dsParams->srcStencil->width(mtl::MipmapNativeLevel(dsParams->srcStencilLevel));
731
        srcHeight = dsParams->srcStencil->height(dsParams->srcLevel);
799
        srcHeight = dsParams->srcStencil->height(mtl::MipmapNativeLevel(dsParams->srcStencilLevel));
732
    }
800
    }
733
    else
801
    else
734
    {
802
    {
Lines 739-746 void SetupBlitWithDrawUniformData(RenderCommandEncoder *cmdEncoder, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec21
739
    GetBlitTexCoords(srcWidth, srcHeight, params.srcRect, params.srcYFlipped, params.unpackFlipX,
807
    GetBlitTexCoords(srcWidth, srcHeight, params.srcRect, params.srcYFlipped, params.unpackFlipX,
740
                     params.unpackFlipY, &u0, &v0, &u1, &v1);
808
                     params.unpackFlipY, &u0, &v0, &u1, &v1);
741
809
742
    float du = u1 - u0;
810
    auto du = u1 - u0;
743
    float dv = v1 - v0;
811
    auto dv = v1 - v0;
744
812
745
    // lower left
813
    // lower left
746
    uniformParams.srcTexCoords[0][0] = u0;
814
    uniformParams.srcTexCoords[0][0] = u0;
Lines 844-862 ANGLE_INLINE void SetPipelineState(ComputeCommandEncoder *encoder, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec22
844
// StencilBlitViaBufferParams implementation
912
// StencilBlitViaBufferParams implementation
845
StencilBlitViaBufferParams::StencilBlitViaBufferParams() {}
913
StencilBlitViaBufferParams::StencilBlitViaBufferParams() {}
846
914
847
StencilBlitViaBufferParams::StencilBlitViaBufferParams(const DepthStencilBlitParams &srcIn)
915
StencilBlitViaBufferParams::StencilBlitViaBufferParams(const DepthStencilBlitParams &srcParams)
848
{
916
{
849
    dstTextureSize = srcIn.dstTextureSize;
917
    dstTextureSize = srcParams.dstTextureSize;
850
    dstRect        = srcIn.dstRect;
918
    dstRect        = srcParams.dstRect;
851
    dstScissorRect = srcIn.dstScissorRect;
919
    dstScissorRect = srcParams.dstScissorRect;
852
    dstFlipY       = srcIn.dstFlipY;
920
    dstFlipY       = srcParams.dstFlipY;
853
    dstFlipX       = srcIn.dstFlipX;
921
    dstFlipX       = srcParams.dstFlipX;
854
    srcRect        = srcIn.srcRect;
922
    srcRect        = srcParams.srcRect;
855
    srcYFlipped    = srcIn.srcYFlipped;
923
    srcYFlipped    = srcParams.srcYFlipped;
856
    unpackFlipX    = srcIn.unpackFlipX;
924
    unpackFlipX    = srcParams.unpackFlipX;
857
    unpackFlipY    = srcIn.unpackFlipY;
925
    unpackFlipY    = srcParams.unpackFlipY;
858
926
859
    srcStencil = srcIn.srcStencil;
927
    srcStencil      = srcParams.srcStencil;
928
    srcStencilLevel = srcParams.srcStencilLevel;
929
    srcStencilLayer = srcParams.srcStencilLayer;
860
}
930
}
861
931
862
// RenderUtils implementation
932
// RenderUtils implementation
Lines 903-908 void RenderUtils::onDestroy() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec23
903
    }
973
    }
904
}
974
}
905
975
976
906
// override ErrorHandler
977
// override ErrorHandler
907
void RenderUtils::handleError(GLenum glErrorCode,
978
void RenderUtils::handleError(GLenum glErrorCode,
908
                              const char *file,
979
                              const char *file,
Lines 1016-1024 angle::Result RenderUtils::generateTriFanBufferFromArrays( a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec24
1016
}
1087
}
1017
angle::Result RenderUtils::generateTriFanBufferFromElementsArray(
1088
angle::Result RenderUtils::generateTriFanBufferFromElementsArray(
1018
    ContextMtl *contextMtl,
1089
    ContextMtl *contextMtl,
1019
    const IndexGenerationParams &params)
1090
    const IndexGenerationParams &params,
1091
    uint32_t *indicesGenerated)
1020
{
1092
{
1021
    return mIndexUtils.generateTriFanBufferFromElementsArray(contextMtl, params);
1093
    return mIndexUtils.generateTriFanBufferFromElementsArray(contextMtl, params, indicesGenerated);
1022
}
1094
}
1023
1095
1024
angle::Result RenderUtils::generateLineLoopBufferFromArrays(
1096
angle::Result RenderUtils::generateLineLoopBufferFromArrays(
Lines 1050-1055 angle::Result RenderUtils::generateLineLoopLastSegmentFromElementsArray( a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec25
1050
{
1122
{
1051
    return mIndexUtils.generateLineLoopLastSegmentFromElementsArray(contextMtl, params);
1123
    return mIndexUtils.generateLineLoopLastSegmentFromElementsArray(contextMtl, params);
1052
}
1124
}
1125
angle::Result RenderUtils::generatePrimitiveRestartPointsBuffer(ContextMtl *contextMtl,
1126
                                                                const IndexGenerationParams &params,
1127
                                                                size_t *indicesGenerated)
1128
{
1129
    return mIndexUtils.generatePrimitiveRestartPointsBuffer(contextMtl, params, indicesGenerated);
1130
}
1131
angle::Result RenderUtils::generatePrimitiveRestartLinesBuffer(ContextMtl *contextMtl,
1132
                                                               const IndexGenerationParams &params,
1133
                                                               size_t *indicesGenerated)
1134
{
1135
    return mIndexUtils.generatePrimitiveRestartLinesBuffer(contextMtl, params, indicesGenerated);
1136
}
1137
angle::Result RenderUtils::generatePrimitiveRestartTrianglesBuffer(
1138
    ContextMtl *contextMtl,
1139
    const IndexGenerationParams &params,
1140
    size_t *indicesGenerated)
1141
{
1142
    return mIndexUtils.generatePrimitiveRestartTrianglesBuffer(contextMtl, params,
1143
                                                               indicesGenerated);
1144
}
1053
1145
1054
void RenderUtils::combineVisibilityResult(
1146
void RenderUtils::combineVisibilityResult(
1055
    ContextMtl *contextMtl,
1147
    ContextMtl *contextMtl,
Lines 1121-1126 angle::Result RenderUtils::expandVertexFormatComponentsVS(const gl::Context *con a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec26
1121
                                                             params);
1213
                                                             params);
1122
}
1214
}
1123
1215
1216
angle::Result RenderUtils::createTransformFeedbackPSO(const gl::Context *context,
1217
                                                      RenderCommandEncoder *renderEncoder,
1218
                                                      mtl::RenderPipelineDesc &pipelineDesc)
1219
{
1220
    ContextMtl *contextMtl = mtl::GetImpl(context);
1221
    // Create and cache the PSO
1222
    auto pso = mTransformFeedbackUtils.getTransformFeedbackRenderPipeline(contextMtl, renderEncoder,
1223
                                                                          pipelineDesc);
1224
    if (pso)
1225
    {
1226
        return angle::Result::Continue;
1227
    }
1228
    return angle::Result::Stop;
1229
}
1230
1124
// ClearUtils implementation
1231
// ClearUtils implementation
1125
ClearUtils::ClearUtils(const std::string &fragmentShaderName)
1232
ClearUtils::ClearUtils(const std::string &fragmentShaderName)
1126
    : mFragmentShaderName(fragmentShaderName)
1233
    : mFragmentShaderName(fragmentShaderName)
Lines 1287-1297 angle::Result ClearUtils::clearWithDraw(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec27
1287
    {
1394
    {
1288
        overridedParams.clearColor.reset();
1395
        overridedParams.clearColor.reset();
1289
    }
1396
    }
1290
    if (!renderPassDesc.depthAttachment.texture)
1397
    if (!renderPassDesc.depthAttachment.texture())
1291
    {
1398
    {
1292
        overridedParams.clearDepth.reset();
1399
        overridedParams.clearDepth.reset();
1293
    }
1400
    }
1294
    if (!renderPassDesc.stencilAttachment.texture)
1401
    if (!renderPassDesc.stencilAttachment.texture())
1295
    {
1402
    {
1296
        overridedParams.clearStencil.reset();
1403
        overridedParams.clearStencil.reset();
1297
    }
1404
    }
Lines 1307-1313 angle::Result ClearUtils::clearWithDraw(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec28
1307
    angle::Result result;
1414
    angle::Result result;
1308
    {
1415
    {
1309
        // Need to disable occlusion query, otherwise clearing will affect the occlusion counting
1416
        // Need to disable occlusion query, otherwise clearing will affect the occlusion counting
1310
        ScopedDisableOcclusionQuery disableOcclusionQuery(contextMtl, &result);
1417
        ScopedDisableOcclusionQuery disableOcclusionQuery(contextMtl, cmdEncoder, &result);
1311
        // Draw the screen aligned triangle
1418
        // Draw the screen aligned triangle
1312
        cmdEncoder->draw(MTLPrimitiveTypeTriangle, 0, 3);
1419
        cmdEncoder->draw(MTLPrimitiveTypeTriangle, 0, 3);
1313
    }
1420
    }
Lines 1481-1487 angle::Result ColorBlitUtils::blitColorWithDraw(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec29
1481
    angle::Result result;
1588
    angle::Result result;
1482
    {
1589
    {
1483
        // Need to disable occlusion query, otherwise blitting will affect the occlusion counting
1590
        // Need to disable occlusion query, otherwise blitting will affect the occlusion counting
1484
        ScopedDisableOcclusionQuery disableOcclusionQuery(contextMtl, &result);
1591
        ScopedDisableOcclusionQuery disableOcclusionQuery(contextMtl, cmdEncoder, &result);
1485
        // Draw the screen aligned triangle
1592
        // Draw the screen aligned triangle
1486
        cmdEncoder->draw(MTLPrimitiveTypeTriangle, 0, 3);
1593
        cmdEncoder->draw(MTLPrimitiveTypeTriangle, 0, 3);
1487
    }
1594
    }
Lines 1703-1709 angle::Result DepthStencilBlitUtils::blitDepthStencilWithDraw(const gl::Context a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec30
1703
    angle::Result result;
1810
    angle::Result result;
1704
    {
1811
    {
1705
        // Need to disable occlusion query, otherwise blitting will affect the occlusion counting
1812
        // Need to disable occlusion query, otherwise blitting will affect the occlusion counting
1706
        ScopedDisableOcclusionQuery disableOcclusionQuery(contextMtl, &result);
1813
        ScopedDisableOcclusionQuery disableOcclusionQuery(contextMtl, cmdEncoder, &result);
1707
        // Draw the screen aligned triangle
1814
        // Draw the screen aligned triangle
1708
        cmdEncoder->draw(MTLPrimitiveTypeTriangle, 0, 3);
1815
        cmdEncoder->draw(MTLPrimitiveTypeTriangle, 0, 3);
1709
    }
1816
    }
Lines 2002-2008 angle::Result IndexGeneratorUtils::generateTriFanBufferFromArrays( a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec31
2002
2109
2003
angle::Result IndexGeneratorUtils::generateTriFanBufferFromElementsArray(
2110
angle::Result IndexGeneratorUtils::generateTriFanBufferFromElementsArray(
2004
    ContextMtl *contextMtl,
2111
    ContextMtl *contextMtl,
2005
    const IndexGenerationParams &params)
2112
    const IndexGenerationParams &params,
2113
    uint32_t *indicesGenerated)
2006
{
2114
{
2007
    const gl::VertexArray *vertexArray = contextMtl->getState().getVertexArray();
2115
    const gl::VertexArray *vertexArray = contextMtl->getState().getVertexArray();
2008
    const gl::Buffer *elementBuffer    = vertexArray->getElementArrayBuffer();
2116
    const gl::Buffer *elementBuffer    = vertexArray->getElementArrayBuffer();
Lines 2013-2025 angle::Result IndexGeneratorUtils::generateTriFanBufferFromElementsArray( a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec32
2013
        ANGLE_CHECK(contextMtl, srcOffset <= std::numeric_limits<uint32_t>::max(),
2121
        ANGLE_CHECK(contextMtl, srcOffset <= std::numeric_limits<uint32_t>::max(),
2014
                    "Index offset is too large", GL_INVALID_VALUE);
2122
                    "Index offset is too large", GL_INVALID_VALUE);
2015
        if (params.primitiveRestartEnabled ||
2123
        if (params.primitiveRestartEnabled ||
2016
            (!contextMtl->getDisplay()->getFeatures().hasCheapRenderPass.enabled &&
2124
            (!contextMtl->getDisplay()->getFeatures().breakRenderPassIsCheap.enabled &&
2017
             contextMtl->getRenderCommandEncoder()))
2125
             contextMtl->getRenderCommandEncoder()))
2018
        {
2126
        {
2019
            IndexGenerationParams cpuPathParams = params;
2127
            IndexGenerationParams cpuPathParams = params;
2020
            cpuPathParams.indices =
2128
            cpuPathParams.indices =
2021
                elementBufferMtl->getClientShadowCopyData(contextMtl) + srcOffset;
2129
                elementBufferMtl->getClientShadowCopyData(contextMtl) + srcOffset;
2022
            return generateTriFanBufferFromElementsArrayCPU(contextMtl, cpuPathParams);
2130
            return generateTriFanBufferFromElementsArrayCPU(contextMtl, cpuPathParams,
2131
                                                            indicesGenerated);
2023
        }
2132
        }
2024
        else
2133
        else
2025
        {
2134
        {
Lines 2030-2036 angle::Result IndexGeneratorUtils::generateTriFanBufferFromElementsArray( a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec33
2030
    }
2139
    }
2031
    else
2140
    else
2032
    {
2141
    {
2033
        return generateTriFanBufferFromElementsArrayCPU(contextMtl, params);
2142
        return generateTriFanBufferFromElementsArrayCPU(contextMtl, params, indicesGenerated);
2034
    }
2143
    }
2035
}
2144
}
2036
2145
Lines 2074-2095 angle::Result IndexGeneratorUtils::generateTriFanBufferFromElementsArrayGPU( a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec34
2074
2183
2075
angle::Result IndexGeneratorUtils::generateTriFanBufferFromElementsArrayCPU(
2184
angle::Result IndexGeneratorUtils::generateTriFanBufferFromElementsArrayCPU(
2076
    ContextMtl *contextMtl,
2185
    ContextMtl *contextMtl,
2077
    const IndexGenerationParams &params)
2186
    const IndexGenerationParams &params,
2187
    uint32_t *genIndices)
2078
{
2188
{
2079
    switch (params.srcType)
2189
    switch (params.srcType)
2080
    {
2190
    {
2081
        case gl::DrawElementsType::UnsignedByte:
2191
        case gl::DrawElementsType::UnsignedByte:
2082
            return GenTriFanFromClientElements(
2192
            return GenTriFanFromClientElements(
2083
                contextMtl, params.indexCount, params.primitiveRestartEnabled,
2193
                contextMtl, params.indexCount, params.primitiveRestartEnabled,
2084
                static_cast<const uint8_t *>(params.indices), params.dstBuffer, params.dstOffset);
2194
                static_cast<const uint8_t *>(params.indices), params.dstBuffer, params.dstOffset, genIndices);
2085
        case gl::DrawElementsType::UnsignedShort:
2195
        case gl::DrawElementsType::UnsignedShort:
2086
            return GenTriFanFromClientElements(
2196
            return GenTriFanFromClientElements(
2087
                contextMtl, params.indexCount, params.primitiveRestartEnabled,
2197
                contextMtl, params.indexCount, params.primitiveRestartEnabled,
2088
                static_cast<const uint16_t *>(params.indices), params.dstBuffer, params.dstOffset);
2198
                static_cast<const uint16_t *>(params.indices), params.dstBuffer, params.dstOffset, genIndices);
2089
        case gl::DrawElementsType::UnsignedInt:
2199
        case gl::DrawElementsType::UnsignedInt:
2090
            return GenTriFanFromClientElements(
2200
            return GenTriFanFromClientElements(
2091
                contextMtl, params.indexCount, params.primitiveRestartEnabled,
2201
                contextMtl, params.indexCount, params.primitiveRestartEnabled,
2092
                static_cast<const uint32_t *>(params.indices), params.dstBuffer, params.dstOffset);
2202
                static_cast<const uint32_t *>(params.indices), params.dstBuffer, params.dstOffset, genIndices);
2093
        default:
2203
        default:
2094
            UNREACHABLE();
2204
            UNREACHABLE();
2095
    }
2205
    }
Lines 2301-2306 angle::Result IndexGeneratorUtils::generateLineLoopLastSegmentFromElementsArrayC a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec35
2301
    return generateLineLoopLastSegment(contextMtl, first, last, params.dstBuffer, params.dstOffset);
2411
    return generateLineLoopLastSegment(contextMtl, first, last, params.dstBuffer, params.dstOffset);
2302
}
2412
}
2303
2413
2414
angle::Result IndexGeneratorUtils::generatePrimitiveRestartBuffer(
2415
    ContextMtl *contextMtl,
2416
    unsigned numVerticesPerPrimitive,
2417
    const IndexGenerationParams &params,
2418
    size_t *indicesGenerated)
2419
{
2420
    switch (params.srcType)
2421
    {
2422
        case gl::DrawElementsType::UnsignedByte:
2423
            return GenPrimitiveRestartBuffer(contextMtl, params.indexCount, numVerticesPerPrimitive,
2424
                                             static_cast<const uint8_t *>(params.indices),
2425
                                             params.dstBuffer, params.dstOffset, indicesGenerated);
2426
        case gl::DrawElementsType::UnsignedShort:
2427
            return GenPrimitiveRestartBuffer(contextMtl, params.indexCount, numVerticesPerPrimitive,
2428
                                             static_cast<const uint16_t *>(params.indices),
2429
                                             params.dstBuffer, params.dstOffset, indicesGenerated);
2430
        case gl::DrawElementsType::UnsignedInt:
2431
            return GenPrimitiveRestartBuffer(contextMtl, params.indexCount, numVerticesPerPrimitive,
2432
                                             static_cast<const uint32_t *>(params.indices),
2433
                                             params.dstBuffer, params.dstOffset, indicesGenerated);
2434
        default:
2435
            UNREACHABLE();
2436
            return angle::Result::Stop;
2437
    }
2438
}
2439
2440
angle::Result IndexGeneratorUtils::generatePrimitiveRestartTrianglesBuffer(
2441
    ContextMtl *contextMtl,
2442
    const IndexGenerationParams &params,
2443
    size_t *indicesGenerated)
2444
{
2445
    return generatePrimitiveRestartBuffer(contextMtl, 3, params, indicesGenerated);
2446
}
2447
2448
angle::Result IndexGeneratorUtils::generatePrimitiveRestartLinesBuffer(
2449
    ContextMtl *contextMtl,
2450
    const IndexGenerationParams &params,
2451
    size_t *indicesGenerated)
2452
{
2453
    return generatePrimitiveRestartBuffer(contextMtl, 2, params, indicesGenerated);
2454
}
2455
2456
angle::Result IndexGeneratorUtils::generatePrimitiveRestartPointsBuffer(
2457
    ContextMtl *contextMtl,
2458
    const IndexGenerationParams &params,
2459
    size_t *indicesGenerated)
2460
{
2461
    return generatePrimitiveRestartBuffer(contextMtl, 1, params, indicesGenerated);
2462
}
2463
2304
// VisibilityResultUtils implementation
2464
// VisibilityResultUtils implementation
2305
void VisibilityResultUtils::onDestroy()
2465
void VisibilityResultUtils::onDestroy()
2306
{
2466
{
Lines 2375-2381 void VisibilityResultUtils::combineVisibilityResult( a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec36
2375
// MipmapUtils implementation
2535
// MipmapUtils implementation
2376
void MipmapUtils::onDestroy()
2536
void MipmapUtils::onDestroy()
2377
{
2537
{
2378
    m3DMipGeneratorPipeline = nil;
2538
    m3DMipGeneratorPipeline      = nil;
2539
    m2DMipGeneratorPipeline      = nil;
2540
    m2DArrayMipGeneratorPipeline = nil;
2541
    mCubeMipGeneratorPipeline    = nil;
2379
}
2542
}
2380
2543
2381
void MipmapUtils::ensure3DMipGeneratorPipelineInitialized(ContextMtl *contextMtl)
2544
void MipmapUtils::ensure3DMipGeneratorPipelineInitialized(ContextMtl *contextMtl)
Lines 2384-2449 void MipmapUtils::ensure3DMipGeneratorPipelineInitialized(ContextMtl *contextMtl a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec37
2384
                                     &m3DMipGeneratorPipeline);
2547
                                     &m3DMipGeneratorPipeline);
2385
}
2548
}
2386
2549
2550
void MipmapUtils::ensure2DMipGeneratorPipelineInitialized(ContextMtl *contextMtl)
2551
{
2552
    EnsureComputePipelineInitialized(contextMtl->getDisplay(), @"generate2DMipmaps",
2553
                                     &m2DMipGeneratorPipeline);
2554
}
2555
2556
void MipmapUtils::ensure2DArrayMipGeneratorPipelineInitialized(ContextMtl *contextMtl)
2557
{
2558
    EnsureComputePipelineInitialized(contextMtl->getDisplay(), @"generate2DArrayMipmaps",
2559
                                     &m2DArrayMipGeneratorPipeline);
2560
}
2561
2562
void MipmapUtils::ensureCubeMipGeneratorPipelineInitialized(ContextMtl *contextMtl)
2563
{
2564
    EnsureComputePipelineInitialized(contextMtl->getDisplay(), @"generateCubeMipmaps",
2565
                                     &mCubeMipGeneratorPipeline);
2566
}
2567
2387
angle::Result MipmapUtils::generateMipmapCS(ContextMtl *contextMtl,
2568
angle::Result MipmapUtils::generateMipmapCS(ContextMtl *contextMtl,
2388
                                            const TextureRef &srcTexture,
2569
                                            const TextureRef &srcTexture,
2389
                                            bool sRGBMipmap,
2570
                                            bool sRGBMipmap,
2390
                                            NativeTexLevelArray *mipmapOutputViews)
2571
                                            NativeTexLevelArray * mipmapOutputViews)
2391
{
2572
{
2392
    // Only support 3D texture for now.
2573
    ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder();
2393
    ASSERT(srcTexture->textureType() == MTLTextureType3D);
2574
    ASSERT(cmdEncoder);
2394
2575
2395
    MTLSize threadGroupSize;
2576
    MTLSize threadGroupSize;
2396
    uint32_t slices                             = 1;
2577
    uint32_t slices = 1;
2397
    id<MTLComputePipelineState> computePipeline = nil;
2578
    switch (srcTexture->textureType())
2398
2399
    ensure3DMipGeneratorPipelineInitialized(contextMtl);
2400
    computePipeline = m3DMipGeneratorPipeline;
2401
    threadGroupSize =
2402
        MTLSizeMake(kGenerateMipThreadGroupSizePerDim, kGenerateMipThreadGroupSizePerDim,
2403
                    kGenerateMipThreadGroupSizePerDim);
2404
2405
    // The compute shader supports up to 4 mipmaps generated per pass.
2406
    // See shaders/gen_mipmap.metal
2407
    uint32_t maxMipsPerBatch = 4;
2408
2409
    if (threadGroupSize.width * threadGroupSize.height * threadGroupSize.depth >
2410
            computePipeline.maxTotalThreadsPerThreadgroup ||
2411
        ANGLE_UNLIKELY(
2412
            !contextMtl->getDisplay()->getFeatures().allowGenMultipleMipsPerPass.enabled))
2413
    {
2579
    {
2414
        // Multiple mipmaps generation is not supported due to hardware's thread group size limits.
2580
        case MTLTextureType2D:
2415
        // Fallback to generate one mip per pass and reduce thread group size.
2581
            ensure2DMipGeneratorPipelineInitialized(contextMtl);
2416
        if (ANGLE_UNLIKELY(threadGroupSize.width * threadGroupSize.height >
2582
            cmdEncoder->setComputePipelineState(m2DMipGeneratorPipeline);
2417
                           computePipeline.maxTotalThreadsPerThreadgroup))
2583
            threadGroupSize = MTLSizeMake(kGenerateMipThreadGroupSizePerDim,
2418
        {
2584
                                          kGenerateMipThreadGroupSizePerDim, 1);
2419
            // Even with reduced thread group size, we cannot proceed.
2585
            break;
2420
            // HACK: use blit command encoder to generate mipmaps if it is not possible
2586
        case MTLTextureType2DArray:
2421
            // to use compute shader due to hardware limits.
2587
            ensure2DArrayMipGeneratorPipelineInitialized(contextMtl);
2422
            BlitCommandEncoder *blitEncoder = contextMtl->getBlitCommandEncoder();
2588
            cmdEncoder->setComputePipelineState(m2DArrayMipGeneratorPipeline);
2423
            blitEncoder->generateMipmapsForTexture(srcTexture);
2589
            slices          = srcTexture->arrayLength();
2424
            return angle::Result::Continue;
2590
            threadGroupSize = MTLSizeMake(kGenerateMipThreadGroupSizePerDim,
2425
        }
2591
                                          kGenerateMipThreadGroupSizePerDim, 1);
2426
2592
            break;
2427
        threadGroupSize.depth = 1;
2593
        case MTLTextureTypeCube:
2428
        maxMipsPerBatch       = 1;
2594
            ensureCubeMipGeneratorPipelineInitialized(contextMtl);
2595
            cmdEncoder->setComputePipelineState(mCubeMipGeneratorPipeline);
2596
            slices          = 6;
2597
            threadGroupSize = MTLSizeMake(kGenerateMipThreadGroupSizePerDim,
2598
                                          kGenerateMipThreadGroupSizePerDim, 1);
2599
            break;
2600
        case MTLTextureType3D:
2601
            ensure3DMipGeneratorPipelineInitialized(contextMtl);
2602
            cmdEncoder->setComputePipelineState(m3DMipGeneratorPipeline);
2603
            threadGroupSize =
2604
                MTLSizeMake(kGenerateMipThreadGroupSizePerDim, kGenerateMipThreadGroupSizePerDim,
2605
                            kGenerateMipThreadGroupSizePerDim);
2606
            break;
2607
        default:
2608
            UNREACHABLE();
2429
    }
2609
    }
2430
2610
2431
    ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder();
2611
    Generate3DMipmapUniform options;
2432
    ASSERT(cmdEncoder);
2612
    uint32_t maxMipsPerBatch = 4;
2433
    cmdEncoder->setComputePipelineState(computePipeline);
2434
2435
    GenerateMipmapUniform options;
2436
2613
2437
    uint32_t remainMips             = srcTexture->mipmapLevels() - 1;
2614
    uint32_t remainMips = srcTexture->mipmapLevels() - 1;
2438
    MipmapNativeLevel batchSrcLevel = kZeroNativeMipLevel;
2615
    options.srcLevel    = 0;
2439
    options.srcLevel                = batchSrcLevel.get();
2440
    options.sRGB                    = sRGBMipmap;
2441
2616
2442
    cmdEncoder->setTexture(srcTexture, 0);
2617
    cmdEncoder->setTexture(srcTexture, 0);
2443
    cmdEncoder->markResourceBeingWrittenByGPU(srcTexture);
2618
    cmdEncoder->markResourceBeingWrittenByGPU(srcTexture);
2444
    while (remainMips)
2619
    while (remainMips)
2445
    {
2620
    {
2446
        const TextureRef &firstMipView = mipmapOutputViews->at(batchSrcLevel + 1);
2621
        const TextureRef &firstMipView = mipmapOutputViews->at(mtl::MipmapNativeLevel(options.srcLevel + 1));
2447
        gl::Extents size               = firstMipView->sizeAt0();
2622
        gl::Extents size               = firstMipView->sizeAt0();
2448
        bool isPow2 = gl::isPow2(size.width) && gl::isPow2(size.height) && gl::isPow2(size.depth);
2623
        bool isPow2 = gl::isPow2(size.width) && gl::isPow2(size.height) && gl::isPow2(size.depth);
2449
2624
Lines 2461-2480 angle::Result MipmapUtils::generateMipmapCS(ContextMtl *contextMtl, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec38
2461
2636
2462
        for (uint32_t i = 1; i <= options.numMipmapsToGenerate; ++i)
2637
        for (uint32_t i = 1; i <= options.numMipmapsToGenerate; ++i)
2463
        {
2638
        {
2464
            cmdEncoder->setTexture(mipmapOutputViews->at(batchSrcLevel + i), i);
2639
            cmdEncoder->setTexture(mipmapOutputViews->at(mtl::MipmapNativeLevel(options.srcLevel + i)), i);
2465
        }
2640
        }
2466
2641
2467
        uint32_t threadsPerZ = std::max(slices, firstMipView->depthAt0());
2642
        uint32_t threadsPerZ = std::max(slices, firstMipView->depthAt0());
2468
2643
2469
        DispatchCompute(
2644
        DispatchCompute(contextMtl, cmdEncoder,
2470
            contextMtl, cmdEncoder,
2645
                        /** allowNonUniform */ false,
2471
            /** allowNonUniform */ false,
2646
                        MTLSizeMake(firstMipView->widthAt0(), firstMipView->heightAt0(), threadsPerZ),
2472
            MTLSizeMake(firstMipView->widthAt0(), firstMipView->heightAt0(), threadsPerZ),
2647
                        threadGroupSize);
2473
            threadGroupSize);
2474
2648
2475
        remainMips -= options.numMipmapsToGenerate;
2649
        remainMips -= options.numMipmapsToGenerate;
2476
        batchSrcLevel    = batchSrcLevel + options.numMipmapsToGenerate;
2650
        options.srcLevel += options.numMipmapsToGenerate;
2477
        options.srcLevel = batchSrcLevel.get();
2478
    }
2651
    }
2479
2652
2480
    return angle::Result::Continue;
2653
    return angle::Result::Continue;
Lines 2504-2511 AutoObjCPtr<id<MTLComputePipelineState>> CopyPixelsUtils::getPixelsCopyPipeline( a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec39
2504
    int shaderTextureType = GetShaderTextureType(texture);
2677
    int shaderTextureType = GetShaderTextureType(texture);
2505
    int index2 = mtl_shader::kTextureTypeCount * (bufferWrite ? 1 : 0) + shaderTextureType;
2678
    int index2 = mtl_shader::kTextureTypeCount * (bufferWrite ? 1 : 0) + shaderTextureType;
2506
2679
2507
    AutoObjCPtr<id<MTLComputePipelineState>> &cache =
2680
    auto &cache = mPixelsCopyPipelineCaches[formatIDValue][index2];
2508
        mPixelsCopyPipelineCaches[formatIDValue][index2];
2509
2681
2510
    if (!cache)
2682
    if (!cache)
2511
    {
2683
    {
Lines 2783-2789 AutoObjCPtr<id<MTLRenderPipelineState>> a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec40
2783
VertexFormatConversionUtils::getComponentsExpandRenderPipeline(ContextMtl *contextMtl,
2955
VertexFormatConversionUtils::getComponentsExpandRenderPipeline(ContextMtl *contextMtl,
2784
                                                               RenderCommandEncoder *cmdEncoder)
2956
                                                               RenderCommandEncoder *cmdEncoder)
2785
{
2957
{
2958
    DisplayMtl *display = contextMtl->getDisplay();
2959
    auto shaderLib      = display->getDefaultShadersLib();
2786
    EnsureVertexShaderOnlyPipelineCacheInitialized(contextMtl, @"expandVertexFormatComponentsVS",
2960
    EnsureVertexShaderOnlyPipelineCacheInitialized(contextMtl, @"expandVertexFormatComponentsVS",
2961
                                                   shaderLib,
2787
                                                   &mComponentsExpandRenderPipelineCache);
2962
                                                   &mComponentsExpandRenderPipelineCache);
2788
2963
2789
    RenderPipelineDesc pipelineDesc = GetComputingVertexShaderOnlyRenderPipelineDesc(cmdEncoder);
2964
    RenderPipelineDesc pipelineDesc = GetComputingVertexShaderOnlyRenderPipelineDesc(cmdEncoder);
Lines 2797-2804 VertexFormatConversionUtils::getFloatConverstionComputePipeline(ContextMtl *cont a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec41
2797
{
2972
{
2798
    int formatIDValue = static_cast<int>(srcAngleFormat.id);
2973
    int formatIDValue = static_cast<int>(srcAngleFormat.id);
2799
2974
2800
    AutoObjCPtr<id<MTLComputePipelineState>> &cache =
2975
    auto &cache = mConvertToFloatCompPipelineCaches[formatIDValue];
2801
        mConvertToFloatCompPipelineCaches[formatIDValue];
2802
2976
2803
    if (!cache)
2977
    if (!cache)
2804
    {
2978
    {
Lines 2849-2853 VertexFormatConversionUtils::getFloatConverstionRenderPipeline(ContextMtl *conte a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_render_utils.mm_sec42
2849
    return cache.getRenderPipelineState(contextMtl, pipelineDesc);
3023
    return cache.getRenderPipelineState(contextMtl, pipelineDesc);
2850
}
3024
}
2851
3025
3026
AutoObjCPtr<id<MTLLibrary>> TransformFeedbackUtils::createMslXfbLibrary(
3027
    ContextMtl *contextMtl,
3028
    const std::string &translatedMsl)
3029
{
3030
    ANGLE_MTL_OBJC_SCOPE
3031
    {
3032
        DisplayMtl *display     = contextMtl->getDisplay();
3033
        id<MTLDevice> mtlDevice = display->getMetalDevice();
3034
3035
        // Convert to actual binary shader
3036
        mtl::AutoObjCPtr<NSError *> err = nil;
3037
        mtl::AutoObjCPtr<id<MTLLibrary>> mtlShaderLib =
3038
            mtl::CreateShaderLibrary(mtlDevice, translatedMsl, &err);
3039
        if (err && !mtlShaderLib)
3040
        {
3041
            NSLog(@"%@", err.get());
3042
            assert(0);
3043
        }
3044
        return mtlShaderLib;
3045
    }
3046
}
3047
3048
AutoObjCPtr<id<MTLRenderPipelineState>> TransformFeedbackUtils::getTransformFeedbackRenderPipeline(
3049
    ContextMtl *contextMtl,
3050
    RenderCommandEncoder *cmdEncoder,
3051
    mtl::RenderPipelineDesc &pipelineDesc)
3052
{
3053
    const ProgramMtl *programMtl = mtl::GetImpl(contextMtl->getState().getProgram());
3054
    RenderPipelineCache &cache   = *programMtl->mMetalXfbRenderPipelineCache;
3055
3056
    if (!cache.getVertexShader())
3057
    {
3058
        // Pipeline cache not intialized, do it now:
3059
        ANGLE_MTL_OBJC_SCOPE
3060
        {
3061
            auto shaderLib = createMslXfbLibrary(contextMtl, programMtl->getXfbMslSource());
3062
            // Non specialized constants provided, use default creation function.
3063
            EnsureVertexShaderOnlyPipelineCacheInitialized(contextMtl, SHADER_ENTRY_NAME, shaderLib,
3064
                                                           &cache);
3065
        }
3066
    }
3067
3068
    RenderPipelineDesc xfbPipelineDesc =
3069
        GetTransformFeedbackRenderPipelineDesc(cmdEncoder, pipelineDesc);
3070
3071
    return cache.getRenderPipelineState(contextMtl, xfbPipelineDesc);
3072
}
3073
2852
}  // namespace mtl
3074
}  // namespace mtl
2853
}  // namespace rx
3075
}  // namespace rx
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_resources.h -6 / +70 lines
Lines 63-69 class Resource : angle::NonCopyable a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_resources.h_sec1
63
    bool isCPUReadMemNeedSync() const { return mUsageRef->cpuReadMemNeedSync; }
63
    bool isCPUReadMemNeedSync() const { return mUsageRef->cpuReadMemNeedSync; }
64
    void resetCPUReadMemNeedSync() { mUsageRef->cpuReadMemNeedSync = false; }
64
    void resetCPUReadMemNeedSync() { mUsageRef->cpuReadMemNeedSync = false; }
65
65
66
    // These functions are useful for BufferMtl to know whether it should update the shadow copy
67
    bool isCPUReadMemDirty() const { return mUsageRef->cpuReadMemDirty; }
66
    bool isCPUReadMemDirty() const { return mUsageRef->cpuReadMemDirty; }
68
    void resetCPUReadMemDirty() { mUsageRef->cpuReadMemDirty = false; }
67
    void resetCPUReadMemDirty() { mUsageRef->cpuReadMemDirty = false; }
69
68
Lines 81-87 class Resource : angle::NonCopyable a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_resources.h_sec2
81
        uint64_t cmdBufferQueueSerial = 0;
80
        uint64_t cmdBufferQueueSerial = 0;
82
81
83
        // This flag means the resource was issued to be modified by GPU, if CPU wants to read
82
        // This flag means the resource was issued to be modified by GPU, if CPU wants to read
84
        // its content, explicit synchronization call must be invoked.
83
        // its content, explicit synchornization call must be invoked.
85
        bool cpuReadMemNeedSync = false;
84
        bool cpuReadMemNeedSync = false;
86
85
87
        // This flag is useful for BufferMtl to know whether it should update the shadow copy
86
        // This flag is useful for BufferMtl to know whether it should update the shadow copy
Lines 110-115 class Texture final : public Resource, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_resources.h_sec3
110
                                       bool allowFormatView,
109
                                       bool allowFormatView,
111
                                       TextureRef *refOut);
110
                                       TextureRef *refOut);
112
111
112
    // On macOS, memory will still be allocated for this texture.
113
    static angle::Result MakeMemoryLess2DTexture(ContextMtl *context,
114
                                                 const Format &format,
115
                                                 uint32_t width,
116
                                                 uint32_t height,
117
                                                 TextureRef *refOut);
118
113
    static angle::Result MakeCubeTexture(ContextMtl *context,
119
    static angle::Result MakeCubeTexture(ContextMtl *context,
114
                                         const Format &format,
120
                                         const Format &format,
115
                                         uint32_t size,
121
                                         uint32_t size,
Lines 147-156 class Texture final : public Resource, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_resources.h_sec4
147
                                       bool allowFormatView,
153
                                       bool allowFormatView,
148
                                       TextureRef *refOut);
154
                                       TextureRef *refOut);
149
155
156
    static angle::Result MakeIOSurfaceTexture(ContextMtl *context,
157
                                              const Format &format,
158
                                              uint32_t width,
159
                                              uint32_t height,
160
                                              IOSurfaceRef ref,
161
                                              uint32_t plane,
162
                                              TextureRef *refOut);
163
150
    static TextureRef MakeFromMetal(id<MTLTexture> metalTexture);
164
    static TextureRef MakeFromMetal(id<MTLTexture> metalTexture);
151
165
152
    // Allow CPU to read & write data directly to this texture?
166
    // Allow CPU to read & write data directly to this texture?
153
    bool isCPUAccessible() const;
167
    bool isCPUAccessible() const;
168
    // Allow shaders to read/sample this texture?
169
    // Texture created with renderTargetOnly flag won't be readable
170
    bool isShaderReadable() const;
154
171
155
    bool supportFormatView() const;
172
    bool supportFormatView() const;
156
173
Lines 218-233 class Texture final : public Resource, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_resources.h_sec5
218
    MTLColorWriteMask getColorWritableMask() const { return *mColorWritableMask; }
235
    MTLColorWriteMask getColorWritableMask() const { return *mColorWritableMask; }
219
    void setColorWritableMask(MTLColorWriteMask mask) { *mColorWritableMask = mask; }
236
    void setColorWritableMask(MTLColorWriteMask mask) { *mColorWritableMask = mask; }
220
237
221
    // Get linear color space view. Only usable for sRGB textures.
238
    // Get reading copy. Used for reading non-readable texture or reading stencil value from
222
    TextureRef getLinearColorView();
239
    // packed depth & stencil texture.
240
    // NOTE: this only copies 1 depth slice of the 3D texture.
241
    // The texels will be copied to region(0, 0, 0, areaToCopy.size) of the returned texture.
242
    // The returned pointer will be retained by the original texture object.
243
    // Calling getReadableCopy() will overwrite previously returned texture.
244
    TextureRef getReadableCopy(ContextMtl *context,
245
                               mtl::BlitCommandEncoder *encoder,
246
                               const uint32_t levelToCopy,
247
                               const uint32_t sliceToCopy,
248
                               const MTLRegion &areaToCopy);
249
250
    void releaseReadableCopy();
223
251
224
    // Get stencil view
252
    // Get stencil view
225
    TextureRef getStencilView();
253
    TextureRef getStencilView();
254
    //Get linear color
255
    TextureRef getLinearColorView();
226
256
227
    // Change the wrapped metal object. Special case for swapchain image
257
    // Change the wrapped metal object. Special case for swapchain image
228
    void set(id<MTLTexture> metalTexture);
258
    void set(id<MTLTexture> metalTexture);
229
259
230
    // sync content between CPU and GPU
260
    // Explicitly sync content between CPU and GPU
231
    void syncContent(ContextMtl *context, mtl::BlitCommandEncoder *encoder);
261
    void syncContent(ContextMtl *context, mtl::BlitCommandEncoder *encoder);
232
262
233
  private:
263
  private:
Lines 241-252 class Texture final : public Resource, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_resources.h_sec6
241
                                     bool allowFormatView,
271
                                     bool allowFormatView,
242
                                     TextureRef *refOut);
272
                                     TextureRef *refOut);
243
273
274
    static angle::Result MakeTexture(ContextMtl *context,
275
                                     const Format &mtlFormat,
276
                                     MTLTextureDescriptor *desc,
277
                                     uint32_t mips,
278
                                     bool renderTargetOnly,
279
                                     bool allowFormatView,
280
                                     bool memoryLess,
281
                                     TextureRef *refOut);
282
283
    static angle::Result MakeTexture(ContextMtl *context,
284
                                     const Format &mtlFormat,
285
                                     MTLTextureDescriptor *desc,
286
                                     IOSurfaceRef surfaceRef,
287
                                     NSUInteger slice,
288
                                     bool renderTargetOnly,
289
                                     TextureRef *refOut);
290
244
    Texture(id<MTLTexture> metalTexture);
291
    Texture(id<MTLTexture> metalTexture);
245
    Texture(ContextMtl *context,
292
    Texture(ContextMtl *context,
246
            MTLTextureDescriptor *desc,
293
            MTLTextureDescriptor *desc,
247
            uint32_t mips,
294
            uint32_t mips,
248
            bool renderTargetOnly,
295
            bool renderTargetOnly,
249
            bool allowFormatView);
296
            bool allowFormatView);
297
    Texture(ContextMtl *context,
298
            MTLTextureDescriptor *desc,
299
            uint32_t mips,
300
            bool renderTargetOnly,
301
            bool allowFormatView,
302
            bool memoryLess);
303
304
    Texture(ContextMtl *context,
305
            MTLTextureDescriptor *desc,
306
            IOSurfaceRef iosurface,
307
            NSUInteger plane,
308
            bool renderTargetOnly);
250
309
251
    // Create a texture view
310
    // Create a texture view
252
    Texture(Texture *original, MTLPixelFormat format);
311
    Texture(Texture *original, MTLPixelFormat format);
Lines 264-272 class Texture final : public Resource, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_resources.h_sec7
264
    TextureRef mLinearColorView;
323
    TextureRef mLinearColorView;
265
324
266
    TextureRef mStencilView;
325
    TextureRef mStencilView;
326
    //Readable copy of texture
327
    TextureRef mReadCopy;
328
267
};
329
};
268
330
269
class Buffer final : public Resource, public WrappedObject<id<MTLBuffer>>
331
class Buffer final : public Resource,
332
                     public WrappedObject<id<MTLBuffer>>,
333
                     public std::enable_shared_from_this<Buffer>
270
{
334
{
271
  public:
335
  public:
272
    static angle::Result MakeBuffer(ContextMtl *context,
336
    static angle::Result MakeBuffer(ContextMtl *context,
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_resources.mm -14 / +192 lines
Lines 34-53 inline NSUInteger GetMipSize(NSUInteger baseSize, const MipmapNativeLevel level) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_resources.mm_sec1
34
// Asynchronously synchronize the content of a resource between GPU memory and its CPU cache.
34
// Asynchronously synchronize the content of a resource between GPU memory and its CPU cache.
35
// NOTE: This operation doesn't finish immediately upon function's return.
35
// NOTE: This operation doesn't finish immediately upon function's return.
36
template <class T>
36
template <class T>
37
void InvokeCPUMemSync(ContextMtl *context, mtl::BlitCommandEncoder *blitEncoder, T *resource)
37
void SyncContent(ContextMtl *context,
38
                 mtl::BlitCommandEncoder *blitEncoder,
39
                 const std::shared_ptr<T> &resource)
38
{
40
{
39
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
41
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
40
    if (blitEncoder)
42
    if (blitEncoder)
41
    {
43
    {
42
        blitEncoder->synchronizeResource(resource);
44
        blitEncoder->synchronizeResource(resource);
45
43
        resource->resetCPUReadMemNeedSync();
46
        resource->resetCPUReadMemNeedSync();
44
    }
47
    }
45
#endif
48
#endif
46
}
49
}
47
// Ensure that a resource's CPU cache will be synchronized after GPU finishes its modifications on
50
48
// the resource.
49
template <class T>
51
template <class T>
50
void EnsureCPUMemWillBeSynced(ContextMtl *context, T *resource)
52
void EnsureContentSynced(ContextMtl *context, const std::shared_ptr<T> &resource)
51
{
53
{
52
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
54
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
53
    // Make sure GPU & CPU contents are synchronized.
55
    // Make sure GPU & CPU contents are synchronized.
Lines 56-62 void EnsureCPUMemWillBeSynced(ContextMtl *context, T *resource) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_resources.mm_sec2
56
    if (resource->get().storageMode == MTLStorageModeManaged && resource->isCPUReadMemNeedSync())
58
    if (resource->get().storageMode == MTLStorageModeManaged && resource->isCPUReadMemNeedSync())
57
    {
59
    {
58
        mtl::BlitCommandEncoder *blitEncoder = context->getBlitCommandEncoder();
60
        mtl::BlitCommandEncoder *blitEncoder = context->getBlitCommandEncoder();
59
        InvokeCPUMemSync(context, blitEncoder, resource);
61
        SyncContent(context, blitEncoder, resource);
60
    }
62
    }
61
#endif
63
#endif
62
}
64
}
Lines 122-127 angle::Result Texture::Make2DTexture(ContextMtl *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_resources.mm_sec3
122
    }  // ANGLE_MTL_OBJC_SCOPE
124
    }  // ANGLE_MTL_OBJC_SCOPE
123
}
125
}
124
126
127
/** static */
128
angle::Result Texture::MakeMemoryLess2DTexture(ContextMtl *context,
129
                                               const Format &format,
130
                                               uint32_t width,
131
                                               uint32_t height,
132
                                               TextureRef *refOut)
133
{
134
    ANGLE_MTL_OBJC_SCOPE
135
    {
136
        MTLTextureDescriptor *desc =
137
            [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:format.metalFormat
138
                                                               width:width
139
                                                              height:height
140
                                                           mipmapped:NO];
141
142
        return MakeTexture(context, format, desc, 1, true, false, true, refOut);
143
    }  // ANGLE_MTL_OBJC_SCOPE
144
}
125
/** static */
145
/** static */
126
angle::Result Texture::MakeCubeTexture(ContextMtl *context,
146
angle::Result Texture::MakeCubeTexture(ContextMtl *context,
127
                                       const Format &format,
147
                                       const Format &format,
Lines 223-228 angle::Result Texture::Make3DTexture(ContextMtl *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_resources.mm_sec4
223
        return MakeTexture(context, format, desc, mips, renderTargetOnly, allowFormatView, refOut);
243
        return MakeTexture(context, format, desc, mips, renderTargetOnly, allowFormatView, refOut);
224
    }  // ANGLE_MTL_OBJC_SCOPE
244
    }  // ANGLE_MTL_OBJC_SCOPE
225
}
245
}
246
angle::Result Texture::MakeIOSurfaceTexture(ContextMtl *context,
247
                                            const Format &format,
248
                                            uint32_t width,
249
                                            uint32_t height,
250
                                            IOSurfaceRef ref,
251
                                            uint32_t plane,
252
                                            TextureRef *refOut)
253
{
254
    MTLTextureDescriptor *desc = [[MTLTextureDescriptor new] ANGLE_MTL_AUTORELEASE];
255
    desc.textureType           = MTLTextureType2D;
256
    desc.pixelFormat           = format.metalFormat;
257
    desc.width                 = width;
258
    desc.height                = height;
259
    desc.mipmapLevelCount      = 1;
260
    desc.sampleCount           = 1;
261
    return MakeTexture(context, format, desc, ref, plane, NO, refOut);
262
}
226
263
227
/** static */
264
/** static */
228
angle::Result Texture::MakeTexture(ContextMtl *context,
265
angle::Result Texture::MakeTexture(ContextMtl *context,
Lines 233-239 angle::Result Texture::MakeTexture(ContextMtl *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_resources.mm_sec5
233
                                   bool allowFormatView,
270
                                   bool allowFormatView,
234
                                   TextureRef *refOut)
271
                                   TextureRef *refOut)
235
{
272
{
236
    refOut->reset(new Texture(context, desc, mips, renderTargetOnly, allowFormatView));
273
    return MakeTexture(context, mtlFormat, desc, mips, renderTargetOnly, allowFormatView, false,
274
                       refOut);
275
}
276
277
angle::Result Texture::MakeTexture(ContextMtl *context,
278
                                   const Format &mtlFormat,
279
                                   MTLTextureDescriptor *desc,
280
                                   uint32_t mips,
281
                                   bool renderTargetOnly,
282
                                   bool allowFormatView,
283
                                   bool memoryLess,
284
                                   TextureRef *refOut)
285
{
286
    refOut->reset(new Texture(context, desc, mips, renderTargetOnly, allowFormatView, memoryLess));
287
288
    if (!refOut || !refOut->get())
289
    {
290
        ANGLE_MTL_CHECK(context, false, GL_OUT_OF_MEMORY);
291
    }
292
    if (!mtlFormat.hasDepthAndStencilBits())
293
    {
294
        refOut->get()->setColorWritableMask(GetEmulatedColorWriteMask(mtlFormat));
295
    }
296
297
    return angle::Result::Continue;
298
}
299
300
angle::Result Texture::MakeTexture(ContextMtl *context,
301
                                   const Format &mtlFormat,
302
                                   MTLTextureDescriptor *desc,
303
                                   IOSurfaceRef surfaceRef,
304
                                   NSUInteger slice,
305
                                   bool renderTargetOnly,
306
                                   TextureRef *refOut)
307
{
308
    refOut->reset(new Texture(context, desc, surfaceRef, slice, renderTargetOnly));
237
309
238
    if (!(*refOut) || !(*refOut)->get())
310
    if (!(*refOut) || !(*refOut)->get())
239
    {
311
    {
Lines 264-269 Texture::Texture(ContextMtl *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_resources.mm_sec6
264
                 uint32_t mips,
336
                 uint32_t mips,
265
                 bool renderTargetOnly,
337
                 bool renderTargetOnly,
266
                 bool allowFormatView)
338
                 bool allowFormatView)
339
    : Texture(context, desc, mips, renderTargetOnly, allowFormatView, false)
340
{}
341
342
Texture::Texture(ContextMtl *context,
343
                 MTLTextureDescriptor *desc,
344
                 uint32_t mips,
345
                 bool renderTargetOnly,
346
                 bool allowFormatView,
347
                 bool memoryLess)
267
    : mColorWritableMask(std::make_shared<MTLColorWriteMask>(MTLColorWriteMaskAll))
348
    : mColorWritableMask(std::make_shared<MTLColorWriteMask>(MTLColorWriteMaskAll))
268
{
349
{
269
    ANGLE_MTL_OBJC_SCOPE
350
    ANGLE_MTL_OBJC_SCOPE
Lines 283-290 Texture::Texture(ContextMtl *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_resources.mm_sec7
283
            desc.usage |= MTLTextureUsageRenderTarget;
364
            desc.usage |= MTLTextureUsageRenderTarget;
284
        }
365
        }
285
366
286
        if (context->getNativeFormatCaps(desc.pixelFormat).depthRenderable ||
367
        if (memoryLess)
287
            desc.textureType == MTLTextureType2DMultisample)
368
        {
369
#if (TARGET_OS_IOS || TARGET_OS_TV) && !TARGET_OS_MACCATALYST
370
            desc.resourceOptions = MTLResourceStorageModeMemoryless;
371
#else
372
            desc.resourceOptions = MTLResourceStorageModePrivate;
373
#endif
374
        }
375
        else if (context->getNativeFormatCaps(desc.pixelFormat).depthRenderable ||
376
                 desc.textureType == MTLTextureType2DMultisample)
288
        {
377
        {
289
            // Metal doesn't support host access to depth stencil texture's data
378
            // Metal doesn't support host access to depth stencil texture's data
290
            desc.resourceOptions = MTLResourceStorageModePrivate;
379
            desc.resourceOptions = MTLResourceStorageModePrivate;
Lines 310-315 Texture::Texture(ContextMtl *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_resources.mm_sec8
310
    }
399
    }
311
}
400
}
312
401
402
Texture::Texture(ContextMtl *context,
403
                 MTLTextureDescriptor *desc,
404
                 IOSurfaceRef iosurface,
405
                 NSUInteger plane,
406
                 bool renderTargetOnly)
407
    : mColorWritableMask(std::make_shared<MTLColorWriteMask>(MTLColorWriteMaskAll))
408
{
409
    ANGLE_MTL_OBJC_SCOPE
410
    {
411
        id<MTLDevice> metalDevice = context->getMetalDevice();
412
413
        // Every texture will support being rendered for now
414
        desc.usage = MTLTextureUsagePixelFormatView;
415
416
        if (context->getNativeFormatCaps(desc.pixelFormat).isRenderable())
417
        {
418
            desc.usage |= MTLTextureUsageRenderTarget;
419
        }
420
421
#if (TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH) && !TARGET_OS_MACCATALYST
422
        desc.resourceOptions = MTLResourceStorageModeShared;
423
#else
424
        desc.resourceOptions = MTLResourceStorageModeManaged;
425
#endif
426
427
        if (!renderTargetOnly)
428
        {
429
            desc.usage = desc.usage | MTLTextureUsageShaderRead;
430
            if (context->getNativeFormatCaps(desc.pixelFormat).writable)
431
            {
432
                desc.usage = desc.usage | MTLTextureUsageShaderWrite;
433
            }
434
        }
435
        id<MTLTexture> iosurfTexture = [metalDevice newTextureWithDescriptor:desc
436
                                                                   iosurface:iosurface
437
                                                                       plane:plane];
438
        set([iosurfTexture ANGLE_MTL_AUTORELEASE]);
439
    }
440
}
441
313
Texture::Texture(Texture *original, MTLPixelFormat format)
442
Texture::Texture(Texture *original, MTLPixelFormat format)
314
    : Resource(original),
443
    : Resource(original),
315
      mColorWritableMask(original->mColorWritableMask)  // Share color write mask property
444
      mColorWritableMask(original->mColorWritableMask)  // Share color write mask property
Lines 341-347 Texture::Texture(Texture *original, const TextureSwizzleChannels &swizzle) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_resources.mm_sec9
341
    : Resource(original),
470
    : Resource(original),
342
      mColorWritableMask(original->mColorWritableMask)  // Share color write mask property
471
      mColorWritableMask(original->mColorWritableMask)  // Share color write mask property
343
{
472
{
344
#if ANGLE_MTL_SWIZZLE_AVAILABLE
473
#if defined(__IPHONE_13_0) || defined(__MAC_10_15)
345
    ANGLE_MTL_OBJC_SCOPE
474
    ANGLE_MTL_OBJC_SCOPE
346
    {
475
    {
347
        auto view = [original->get()
476
        auto view = [original->get()
Lines 360-371 Texture::Texture(Texture *original, const TextureSwizzleChannels &swizzle) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_resources.mm_sec10
360
489
361
void Texture::syncContent(ContextMtl *context, mtl::BlitCommandEncoder *blitEncoder)
490
void Texture::syncContent(ContextMtl *context, mtl::BlitCommandEncoder *blitEncoder)
362
{
491
{
363
    InvokeCPUMemSync(context, blitEncoder, this);
492
    SyncContent(context, blitEncoder, shared_from_this());
364
}
493
}
365
494
366
void Texture::syncContentIfNeeded(ContextMtl *context)
495
void Texture::syncContentIfNeeded(ContextMtl *context)
367
{
496
{
368
    EnsureCPUMemWillBeSynced(context, this);
497
    EnsureContentSynced(context, shared_from_this());
369
}
498
}
370
499
371
bool Texture::isCPUAccessible() const
500
bool Texture::isCPUAccessible() const
Lines 379-384 bool Texture::isCPUAccessible() const a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_resources.mm_sec11
379
    return get().storageMode == MTLStorageModeShared;
508
    return get().storageMode == MTLStorageModeShared;
380
}
509
}
381
510
511
bool Texture::isShaderReadable() const
512
{
513
    return get().usage & MTLTextureUsageShaderRead;
514
}
515
382
bool Texture::supportFormatView() const
516
bool Texture::supportFormatView() const
383
{
517
{
384
    return get().usage & MTLTextureUsagePixelFormatView;
518
    return get().usage & MTLTextureUsagePixelFormatView;
Lines 514-525 TextureRef Texture::createViewWithDifferentFormat(MTLPixelFormat format) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_resources.mm_sec12
514
    ASSERT(supportFormatView());
648
    ASSERT(supportFormatView());
515
    return TextureRef(new Texture(this, format));
649
    return TextureRef(new Texture(this, format));
516
}
650
}
651
517
TextureRef Texture::createViewWithCompatibleFormat(MTLPixelFormat format)
652
TextureRef Texture::createViewWithCompatibleFormat(MTLPixelFormat format)
518
{
653
{
519
    // No need for ASSERT(supportFormatView());
520
    return TextureRef(new Texture(this, format));
654
    return TextureRef(new Texture(this, format));
521
}
655
}
522
656
657
658
523
TextureRef Texture::createSwizzleView(const TextureSwizzleChannels &swizzle)
659
TextureRef Texture::createSwizzleView(const TextureSwizzleChannels &swizzle)
524
{
660
{
525
#if ANGLE_MTL_SWIZZLE_AVAILABLE
661
#if ANGLE_MTL_SWIZZLE_AVAILABLE
Lines 652-657 TextureRef Texture::getLinearColorView() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_resources.mm_sec13
652
    return mLinearColorView;
788
    return mLinearColorView;
653
}
789
}
654
790
791
TextureRef Texture::getReadableCopy(ContextMtl *context,
792
                                    mtl::BlitCommandEncoder *encoder,
793
                                    const uint32_t levelToCopy,
794
                                    const uint32_t sliceToCopy,
795
                                    const MTLRegion &areaToCopy)
796
{
797
    gl::Extents firstLevelSize = size(kZeroNativeMipLevel);
798
    if (!mReadCopy || mReadCopy->get().width < static_cast<size_t>(firstLevelSize.width) ||
799
        mReadCopy->get().height < static_cast<size_t>(firstLevelSize.height))
800
    {
801
        // Create a texture that big enough to store the first level data and any smaller level
802
        ANGLE_MTL_OBJC_SCOPE
803
        {
804
            auto desc            = [[MTLTextureDescriptor new] ANGLE_MTL_AUTORELEASE];
805
            desc.textureType     = get().textureType;
806
            desc.pixelFormat     = get().pixelFormat;
807
            desc.width           = firstLevelSize.width;
808
            desc.height          = firstLevelSize.height;
809
            desc.depth           = 1;
810
            desc.arrayLength     = 1;
811
            desc.resourceOptions = MTLResourceStorageModePrivate;
812
            desc.sampleCount     = get().sampleCount;
813
            desc.usage           = MTLTextureUsageShaderRead | MTLTextureUsagePixelFormatView;
814
815
            id<MTLTexture> mtlTexture = [context->getMetalDevice() newTextureWithDescriptor:desc];
816
            mReadCopy.reset(new Texture(mtlTexture));
817
        }  // ANGLE_MTL_OBJC_SCOPE
818
    }
819
820
    ASSERT(encoder);
821
822
    encoder->copyTexture(shared_from_this(), sliceToCopy, levelToCopy, mReadCopy, 0,
823
                         0, 1, 1);
824
825
    return mReadCopy;
826
}
827
828
void Texture::releaseReadableCopy()
829
{
830
    mReadCopy = nullptr;
831
}
832
655
TextureRef Texture::getStencilView()
833
TextureRef Texture::getStencilView()
656
{
834
{
657
    if (mStencilView)
835
    if (mStencilView)
Lines 799-805 angle::Result Buffer::resetWithResOpt(ContextMtl *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_resources.mm_sec14
799
977
800
void Buffer::syncContent(ContextMtl *context, mtl::BlitCommandEncoder *blitEncoder)
978
void Buffer::syncContent(ContextMtl *context, mtl::BlitCommandEncoder *blitEncoder)
801
{
979
{
802
    InvokeCPUMemSync(context, blitEncoder, this);
980
    SyncContent(context, blitEncoder, shared_from_this());
803
}
981
}
804
982
805
const uint8_t *Buffer::mapReadOnly(ContextMtl *context)
983
const uint8_t *Buffer::mapReadOnly(ContextMtl *context)
Lines 820-826 uint8_t *Buffer::mapWithOpt(ContextMtl *context, bool readonly, bool noSync) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_resources.mm_sec15
820
    {
998
    {
821
        CommandQueue &cmdQueue = context->cmdQueue();
999
        CommandQueue &cmdQueue = context->cmdQueue();
822
1000
823
        EnsureCPUMemWillBeSynced(context, this);
1001
        EnsureContentSynced(context, shared_from_this());
824
1002
825
        if (this->isBeingUsedByGPU(context))
1003
        if (this->isBeingUsedByGPU(context))
826
        {
1004
        {
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.h -18 / +65 lines
Lines 22-27 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.h_sec1
22
22
23
static inline bool operator==(const MTLClearColor &lhs, const MTLClearColor &rhs);
23
static inline bool operator==(const MTLClearColor &lhs, const MTLClearColor &rhs);
24
24
25
namespace angle
26
{
27
struct FeaturesMtl;
28
}
29
25
namespace rx
30
namespace rx
26
{
31
{
27
class ContextMtl;
32
class ContextMtl;
Lines 223-229 struct RenderPipelineOutputDesc a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.h_sec2
223
};
228
};
224
229
225
// Some SDK levels don't declare MTLPrimitiveTopologyClass. Needs to do compile time check here:
230
// Some SDK levels don't declare MTLPrimitiveTopologyClass. Needs to do compile time check here:
226
#if !(TARGET_OS_OSX || TARGET_OS_MACCATALYST) && ANGLE_IOS_DEPLOY_TARGET < __IPHONE_12_0
231
#if !(TARGET_OS_OSX || TARGET_OS_MACCATALYST) && \
232
    (!defined(__IPHONE_12_0) || ANGLE_IOS_DEPLOY_TARGET < __IPHONE_12_0)
227
#    define ANGLE_MTL_PRIMITIVE_TOPOLOGY_CLASS_AVAILABLE 0
233
#    define ANGLE_MTL_PRIMITIVE_TOPOLOGY_CLASS_AVAILABLE 0
228
using PrimitiveTopologyClass                                     = uint32_t;
234
using PrimitiveTopologyClass                                     = uint32_t;
229
constexpr PrimitiveTopologyClass kPrimitiveTopologyClassTriangle = 0;
235
constexpr PrimitiveTopologyClass kPrimitiveTopologyClassTriangle = 0;
Lines 267-275 struct alignas(4) RenderPipelineDesc a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.h_sec3
267
    RenderPipelineDesc &operator=(const RenderPipelineDesc &src);
273
    RenderPipelineDesc &operator=(const RenderPipelineDesc &src);
268
274
269
    bool operator==(const RenderPipelineDesc &rhs) const;
275
    bool operator==(const RenderPipelineDesc &rhs) const;
270
271
    size_t hash() const;
276
    size_t hash() const;
272
273
    bool rasterizationEnabled() const;
277
    bool rasterizationEnabled() const;
274
278
275
    VertexDesc vertexDescriptor;
279
    VertexDesc vertexDescriptor;
Lines 288-293 struct alignas(4) RenderPipelineDesc a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.h_sec4
288
    bool emulateCoverageMask : 1;
292
    bool emulateCoverageMask : 1;
289
};
293
};
290
294
295
struct RenderPassAttachmentTextureTargetDesc
296
{
297
    TextureRef getTextureRef() const { return texture.lock(); }
298
    TextureRef getImplicitMSTextureRef() const { return implicitMSTexture.lock(); }
299
    bool hasImplicitMSTexture() const { return !implicitMSTexture.expired(); }
300
    uint32_t getRenderSamples() const
301
    {
302
        TextureRef tex   = getTextureRef();
303
        TextureRef msTex = getImplicitMSTextureRef();
304
        return msTex ? msTex->samples() : (tex ? tex->samples() : 1);
305
    }
306
307
    TextureWeakRef texture;
308
    // Implicit multisample texture that will be rendered into and discarded at the end of
309
    // a render pass. Its result will be resolved into normal texture above.
310
    TextureWeakRef implicitMSTexture;
311
    MipmapNativeLevel level = kZeroNativeMipLevel;
312
    uint32_t sliceOrDepth   = 0;
313
    bool blendable          = true;
314
};
315
291
struct RenderPassAttachmentDesc
316
struct RenderPassAttachmentDesc
292
{
317
{
293
    RenderPassAttachmentDesc();
318
    RenderPassAttachmentDesc();
Lines 297-314 struct RenderPassAttachmentDesc a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.h_sec5
297
    bool equalIgnoreLoadStoreOptions(const RenderPassAttachmentDesc &other) const;
322
    bool equalIgnoreLoadStoreOptions(const RenderPassAttachmentDesc &other) const;
298
    bool operator==(const RenderPassAttachmentDesc &other) const;
323
    bool operator==(const RenderPassAttachmentDesc &other) const;
299
324
300
    ANGLE_INLINE bool hasImplicitMSTexture() const { return implicitMSTexture.get(); }
325
    ANGLE_INLINE TextureRef texture() const
301
326
    {
302
    TextureRef texture;
327
        return renderTarget ? renderTarget->getTextureRef() : nullptr;
303
    // Implicit multisample texture that will be rendered into and discarded at the end of
328
    }
304
    // a render pass. Its result will be resolved into normal texture above.
329
    ANGLE_INLINE TextureRef implicitMSTexture() const
305
    TextureRef implicitMSTexture;
330
    {
306
    MipmapNativeLevel level;
331
        return renderTarget ? renderTarget->getImplicitMSTextureRef() : nullptr;
307
    uint32_t sliceOrDepth;
332
    }
308
333
    ANGLE_INLINE bool hasImplicitMSTexture() const
309
    // This attachment is blendable or not.
334
    {
310
    bool blendable;
335
        return renderTarget ? renderTarget->hasImplicitMSTexture() : false;
336
    }
337
    ANGLE_INLINE uint32_t renderSamples() const
338
    {
339
        return renderTarget ? renderTarget->getRenderSamples() : 1;
340
    }
341
    ANGLE_INLINE MipmapNativeLevel level() const
342
    {
343
        return renderTarget ? renderTarget->level : kZeroNativeMipLevel;
344
    }
345
    ANGLE_INLINE uint32_t sliceOrDepth() const
346
    {
347
        return renderTarget ? renderTarget->sliceOrDepth : 0;
348
    }
349
    ANGLE_INLINE bool blendable() const { return renderTarget ? renderTarget->blendable : false; }
311
350
351
    // This is shared pointer to avoid crashing when texture deleted after bound to a frame buffer.
352
    std::shared_ptr<RenderPassAttachmentTextureTargetDesc> renderTarget;
312
    MTLLoadAction loadAction;
353
    MTLLoadAction loadAction;
313
    MTLStoreAction storeAction;
354
    MTLStoreAction storeAction;
314
    MTLStoreActionOptions storeActionOptions;
355
    MTLStoreActionOptions storeActionOptions;
Lines 354-359 struct RenderPassStencilAttachmentDesc : public RenderPassAttachmentDesc a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.h_sec6
354
    uint32_t clearStencil = 0;
395
    uint32_t clearStencil = 0;
355
};
396
};
356
397
398
//
399
// This is C++ equivalent of Objective-C MTLRenderPassDescriptor.
400
// We could use MTLRenderPassDescriptor directly, however, using C++ struct has benefits of fast
401
// copy, stack allocation, inlined comparing function, etc.
402
//
357
struct RenderPassDesc
403
struct RenderPassDesc
358
{
404
{
359
    RenderPassColorAttachmentDesc colorAttachments[kMaxRenderTargets];
405
    RenderPassColorAttachmentDesc colorAttachments[kMaxRenderTargets];
Lines 417-423 class RenderPipelineCacheSpecializeShaderFactory a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.h_sec7
417
{
463
{
418
  public:
464
  public:
419
    virtual ~RenderPipelineCacheSpecializeShaderFactory() = default;
465
    virtual ~RenderPipelineCacheSpecializeShaderFactory() = default;
420
421
    // Get specialized shader for the render pipeline cache.
466
    // Get specialized shader for the render pipeline cache.
422
    virtual angle::Result getSpecializedShader(Context *context,
467
    virtual angle::Result getSpecializedShader(Context *context,
423
                                               gl::ShaderType shaderType,
468
                                               gl::ShaderType shaderType,
Lines 429-435 class RenderPipelineCacheSpecializeShaderFactory a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.h_sec8
429
                                      const RenderPipelineDesc &renderPipelineDesc) = 0;
474
                                      const RenderPipelineDesc &renderPipelineDesc) = 0;
430
};
475
};
431
476
432
// Render pipeline state cache per shader program.
477
// render pipeline state cache per shader program
433
class RenderPipelineCache final : angle::NonCopyable
478
class RenderPipelineCache final : angle::NonCopyable
434
{
479
{
435
  public:
480
  public:
Lines 459-464 class RenderPipelineCache final : angle::NonCopyable a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.h_sec9
459
    AutoObjCPtr<id<MTLFunction>> mVertexShader;
504
    AutoObjCPtr<id<MTLFunction>> mVertexShader;
460
    // Non-specialized fragment shader
505
    // Non-specialized fragment shader
461
    AutoObjCPtr<id<MTLFunction>> mFragmentShader;
506
    AutoObjCPtr<id<MTLFunction>> mFragmentShader;
507
    // On shader with emulated rasterization discard, one without
462
508
463
  private:
509
  private:
464
    void clearPipelineStates();
510
    void clearPipelineStates();
Lines 477-490 class RenderPipelineCache final : angle::NonCopyable a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.h_sec10
477
    // One table with default attrib and one table without.
523
    // One table with default attrib and one table without.
478
    std::unordered_map<RenderPipelineDesc, AutoObjCPtr<id<MTLRenderPipelineState>>>
524
    std::unordered_map<RenderPipelineDesc, AutoObjCPtr<id<MTLRenderPipelineState>>>
479
        mRenderPipelineStates[2];
525
        mRenderPipelineStates[2];
480
481
    RenderPipelineCacheSpecializeShaderFactory *mSpecializedShaderFactory;
526
    RenderPipelineCacheSpecializeShaderFactory *mSpecializedShaderFactory;
482
};
527
};
483
528
484
class StateCache final : angle::NonCopyable
529
class StateCache final : angle::NonCopyable
485
{
530
{
486
  public:
531
  public:
487
    StateCache();
532
    StateCache(const angle::FeaturesMtl &features);
488
    ~StateCache();
533
    ~StateCache();
489
534
490
    // Null depth stencil state has depth/stecil read & write disabled.
535
    // Null depth stencil state has depth/stecil read & write disabled.
Lines 502-507 class StateCache final : angle::NonCopyable a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.h_sec11
502
    void clear();
547
    void clear();
503
548
504
  private:
549
  private:
550
    const angle::FeaturesMtl &mFeatures;
551
505
    AutoObjCPtr<id<MTLDepthStencilState>> mNullDepthStencilState = nil;
552
    AutoObjCPtr<id<MTLDepthStencilState>> mNullDepthStencilState = nil;
506
    std::unordered_map<DepthStencilDesc, AutoObjCPtr<id<MTLDepthStencilState>>> mDepthStencilStates;
553
    std::unordered_map<DepthStencilDesc, AutoObjCPtr<id<MTLDepthStencilState>>> mDepthStencilStates;
507
    std::unordered_map<SamplerDesc, AutoObjCPtr<id<MTLSamplerState>>> mSamplerStates;
554
    std::unordered_map<SamplerDesc, AutoObjCPtr<id<MTLSamplerState>>> mSamplerStates;
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.mm -70 / +92 lines
Lines 17-22 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.mm_sec1
17
#include "libANGLE/renderer/metal/ContextMtl.h"
17
#include "libANGLE/renderer/metal/ContextMtl.h"
18
#include "libANGLE/renderer/metal/mtl_resources.h"
18
#include "libANGLE/renderer/metal/mtl_resources.h"
19
#include "libANGLE/renderer/metal/mtl_utils.h"
19
#include "libANGLE/renderer/metal/mtl_utils.h"
20
#include "platform/FeaturesMtl.h"
20
21
21
#define ANGLE_OBJC_CP_PROPERTY(DST, SRC, PROPERTY) \
22
#define ANGLE_OBJC_CP_PROPERTY(DST, SRC, PROPERTY) \
22
    (DST).PROPERTY = static_cast<__typeof__((DST).PROPERTY)>(ToObjC((SRC).PROPERTY))
23
    (DST).PROPERTY = static_cast<__typeof__((DST).PROPERTY)>(ToObjC((SRC).PROPERTY))
Lines 182-191 id<MTLTexture> ToObjC(const TextureRef &texture) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.mm_sec2
182
    return textureRef ? textureRef->get() : nil;
183
    return textureRef ? textureRef->get() : nil;
183
}
184
}
184
185
185
void BaseRenderPassAttachmentDescToObjC(const RenderPassAttachmentDesc &src,
186
void BaseRenderPassAttachmentDescToObjC(MTLRenderPassAttachmentDescriptor *dst,
186
                                        MTLRenderPassAttachmentDescriptor *dst)
187
                                        const RenderPassAttachmentDesc &src)
187
{
188
{
188
    const TextureRef &implicitMsTexture = src.implicitMSTexture;
189
    auto implicitMsTexture = src.implicitMSTexture();
189
190
190
    if (implicitMsTexture)
191
    if (implicitMsTexture)
191
    {
192
    {
Lines 193-223 void BaseRenderPassAttachmentDescToObjC(const RenderPassAttachmentDesc &src, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.mm_sec3
193
        dst.level          = 0;
194
        dst.level          = 0;
194
        dst.slice          = 0;
195
        dst.slice          = 0;
195
        dst.depthPlane     = 0;
196
        dst.depthPlane     = 0;
196
        dst.resolveTexture = ToObjC(src.texture);
197
        dst.resolveTexture = ToObjC(src.texture());
197
        dst.resolveLevel   = src.level.get();
198
        dst.resolveLevel   = src.level().get();
198
        if (dst.resolveTexture.textureType == MTLTextureType3D)
199
        if (dst.resolveTexture.textureType == MTLTextureType3D)
199
        {
200
        {
200
            dst.resolveDepthPlane = src.sliceOrDepth;
201
            dst.resolveDepthPlane = src.sliceOrDepth();
201
            dst.resolveSlice      = 0;
202
            dst.resolveSlice      = 0;
202
        }
203
        }
203
        else
204
        else
204
        {
205
        {
205
            dst.resolveSlice      = src.sliceOrDepth;
206
            dst.resolveSlice      = src.sliceOrDepth();
206
            dst.resolveDepthPlane = 0;
207
            dst.resolveDepthPlane = 0;
207
        }
208
        }
208
    }
209
    }
209
    else
210
    else
210
    {
211
    {
211
        dst.texture = ToObjC(src.texture);
212
        dst.texture = ToObjC(src.texture());
212
        dst.level   = src.level.get();
213
        dst.level   = src.level().get();
213
        if (dst.texture.textureType == MTLTextureType3D)
214
        if (dst.texture.textureType == MTLTextureType3D)
214
        {
215
        {
215
            dst.depthPlane = src.sliceOrDepth;
216
            dst.depthPlane = src.sliceOrDepth();
216
            dst.slice      = 0;
217
            dst.slice      = 0;
217
        }
218
        }
218
        else
219
        else
219
        {
220
        {
220
            dst.slice      = src.sliceOrDepth;
221
            dst.slice      = src.sliceOrDepth();
221
            dst.depthPlane = 0;
222
            dst.depthPlane = 0;
222
        }
223
        }
223
        dst.resolveTexture    = nil;
224
        dst.resolveTexture    = nil;
Lines 231-256 void BaseRenderPassAttachmentDescToObjC(const RenderPassAttachmentDesc &src, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.mm_sec4
231
    ANGLE_OBJC_CP_PROPERTY(dst, src, storeActionOptions);
232
    ANGLE_OBJC_CP_PROPERTY(dst, src, storeActionOptions);
232
}
233
}
233
234
234
void ToObjC(const RenderPassColorAttachmentDesc &desc,
235
void ToObjC(MTLRenderPassColorAttachmentDescriptor *objCDesc,
235
            MTLRenderPassColorAttachmentDescriptor *objCDesc)
236
            const RenderPassColorAttachmentDesc &desc)
236
{
237
{
237
    BaseRenderPassAttachmentDescToObjC(desc, objCDesc);
238
    BaseRenderPassAttachmentDescToObjC(objCDesc, desc);
238
239
239
    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, clearColor);
240
    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, clearColor);
240
}
241
}
241
242
242
void ToObjC(const RenderPassDepthAttachmentDesc &desc,
243
void ToObjC(MTLRenderPassDepthAttachmentDescriptor *objCDesc,
243
            MTLRenderPassDepthAttachmentDescriptor *objCDesc)
244
            const RenderPassDepthAttachmentDesc &desc)
244
{
245
{
245
    BaseRenderPassAttachmentDescToObjC(desc, objCDesc);
246
    BaseRenderPassAttachmentDescToObjC(objCDesc, desc);
246
247
247
    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, clearDepth);
248
    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, clearDepth);
248
}
249
}
249
250
250
void ToObjC(const RenderPassStencilAttachmentDesc &desc,
251
void ToObjC(MTLRenderPassStencilAttachmentDescriptor *objCDesc,
251
            MTLRenderPassStencilAttachmentDescriptor *objCDesc)
252
            const RenderPassStencilAttachmentDesc &desc)
252
{
253
{
253
    BaseRenderPassAttachmentDescToObjC(desc, objCDesc);
254
    BaseRenderPassAttachmentDescToObjC(objCDesc, desc);
254
255
255
    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, clearStencil);
256
    ANGLE_OBJC_CP_PROPERTY(objCDesc, desc, clearStencil);
256
}
257
}
Lines 696-706 RenderPassAttachmentDesc::RenderPassAttachmentDesc() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.mm_sec5
696
697
697
void RenderPassAttachmentDesc::reset()
698
void RenderPassAttachmentDesc::reset()
698
{
699
{
699
    texture.reset();
700
    renderTarget       = nullptr;
700
    implicitMSTexture.reset();
701
    level              = mtl::kZeroNativeMipLevel;
702
    sliceOrDepth       = 0;
703
    blendable          = false;
704
    loadAction         = MTLLoadActionLoad;
701
    loadAction         = MTLLoadActionLoad;
705
    storeAction        = MTLStoreActionStore;
702
    storeAction        = MTLStoreActionStore;
706
    storeActionOptions = MTLStoreActionOptionNone;
703
    storeActionOptions = MTLStoreActionOptionNone;
Lines 709-716 void RenderPassAttachmentDesc::reset() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.mm_sec6
709
bool RenderPassAttachmentDesc::equalIgnoreLoadStoreOptions(
706
bool RenderPassAttachmentDesc::equalIgnoreLoadStoreOptions(
710
    const RenderPassAttachmentDesc &other) const
707
    const RenderPassAttachmentDesc &other) const
711
{
708
{
712
    return texture == other.texture && implicitMSTexture == other.implicitMSTexture &&
709
    return renderTarget == other.renderTarget ||
713
           level == other.level && sliceOrDepth == other.sliceOrDepth;
710
           (texture() == other.texture() && level() == other.level() &&
711
            sliceOrDepth() == other.sliceOrDepth());
714
}
712
}
715
713
716
bool RenderPassAttachmentDesc::operator==(const RenderPassAttachmentDesc &other) const
714
bool RenderPassAttachmentDesc::operator==(const RenderPassAttachmentDesc &other) const
Lines 723-728 bool RenderPassAttachmentDesc::operator==(const RenderPassAttachmentDesc &other) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.mm_sec7
723
    return loadAction == other.loadAction && storeAction == other.storeAction &&
721
    return loadAction == other.loadAction && storeAction == other.storeAction &&
724
           storeActionOptions == other.storeActionOptions;
722
           storeActionOptions == other.storeActionOptions;
725
}
723
}
724
// Convert to Metal object
725
void RenderPassDesc::convertToMetalDesc(MTLRenderPassDescriptor *objCDesc) const
726
{
727
    ANGLE_MTL_OBJC_SCOPE
728
    {
729
        for (uint32_t i = 0; i < numColorAttachments; ++i)
730
        {
731
            ToObjC(objCDesc.colorAttachments[i], colorAttachments[i]);
732
        }
733
        for (uint32_t i = numColorAttachments; i < kMaxRenderTargets; ++i)
734
        {
735
            // Inactive render target
736
            objCDesc.colorAttachments[i].texture     = nil;
737
            objCDesc.colorAttachments[i].level       = 0;
738
            objCDesc.colorAttachments[i].slice       = 0;
739
            objCDesc.colorAttachments[i].depthPlane  = 0;
740
            objCDesc.colorAttachments[i].loadAction  = MTLLoadActionDontCare;
741
            objCDesc.colorAttachments[i].storeAction = MTLStoreActionDontCare;
742
        }
743
744
        ToObjC(objCDesc.depthAttachment, depthAttachment);
745
        ToObjC(objCDesc.stencilAttachment, stencilAttachment);
746
    }
747
}
726
748
727
void RenderPassDesc::populateRenderPipelineOutputDesc(RenderPipelineOutputDesc *outDesc) const
749
void RenderPassDesc::populateRenderPipelineOutputDesc(RenderPipelineOutputDesc *outDesc) const
728
{
750
{
Lines 742-760 void RenderPassDesc::populateRenderPipelineOutputDesc(MTLColorWriteMask colorWri a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.mm_sec8
742
void RenderPassDesc::populateRenderPipelineOutputDesc(const BlendDesc &blendState,
764
void RenderPassDesc::populateRenderPipelineOutputDesc(const BlendDesc &blendState,
743
                                                      RenderPipelineOutputDesc *outDesc) const
765
                                                      RenderPipelineOutputDesc *outDesc) const
744
{
766
{
745
    RenderPipelineOutputDesc &outputDescriptor = *outDesc;
767
    auto &outputDescriptor               = *outDesc;
746
    outputDescriptor.numColorAttachments       = this->numColorAttachments;
768
    outputDescriptor.numColorAttachments = this->numColorAttachments;
747
    outputDescriptor.sampleCount               = this->sampleCount;
769
    outputDescriptor.sampleCount         = this->sampleCount;
748
    for (uint32_t i = 0; i < this->numColorAttachments; ++i)
770
    for (uint32_t i = 0; i < this->numColorAttachments; ++i)
749
    {
771
    {
750
        auto &renderPassColorAttachment = this->colorAttachments[i];
772
        auto &renderPassColorAttachment = this->colorAttachments[i];
751
        auto texture                    = renderPassColorAttachment.texture;
773
        auto texture                    = renderPassColorAttachment.texture();
752
774
753
        if (texture)
775
        if (texture)
754
        {
776
        {
755
            // Copy parameters from blend state
777
            // Copy parameters from blend state
756
            outputDescriptor.colorAttachments[i].update(blendState);
778
            outputDescriptor.colorAttachments[i].update(blendState);
757
            if (!renderPassColorAttachment.blendable)
779
            if (!renderPassColorAttachment.blendable())
758
            {
780
            {
759
                // Disable blending if the attachment's render target doesn't support blending.
781
                // Disable blending if the attachment's render target doesn't support blending.
760
                outputDescriptor.colorAttachments[i].blendingEnabled = false;
782
                outputDescriptor.colorAttachments[i].blendingEnabled = false;
Lines 781-791 void RenderPassDesc::populateRenderPipelineOutputDesc(const BlendDesc &blendStat a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.mm_sec9
781
        outputDescriptor.colorAttachments[i].reset();
803
        outputDescriptor.colorAttachments[i].reset();
782
    }
804
    }
783
805
784
    auto depthTexture = this->depthAttachment.texture;
806
    auto depthTexture = this->depthAttachment.texture();
785
    outputDescriptor.depthAttachmentPixelFormat =
807
    outputDescriptor.depthAttachmentPixelFormat =
786
        depthTexture ? depthTexture->pixelFormat() : MTLPixelFormatInvalid;
808
        depthTexture ? depthTexture->pixelFormat() : MTLPixelFormatInvalid;
787
809
788
    auto stencilTexture = this->stencilAttachment.texture;
810
    auto stencilTexture = this->stencilAttachment.texture();
789
    outputDescriptor.stencilAttachmentPixelFormat =
811
    outputDescriptor.stencilAttachmentPixelFormat =
790
        stencilTexture ? stencilTexture->pixelFormat() : MTLPixelFormatInvalid;
812
        stencilTexture ? stencilTexture->pixelFormat() : MTLPixelFormatInvalid;
791
}
813
}
Lines 831-872 bool RenderPassDesc::operator==(const RenderPassDesc &other) const a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.mm_sec10
831
    return depthAttachment == other.depthAttachment && stencilAttachment == other.stencilAttachment;
853
    return depthAttachment == other.depthAttachment && stencilAttachment == other.stencilAttachment;
832
}
854
}
833
855
834
// Convert to Metal object
835
void RenderPassDesc::convertToMetalDesc(MTLRenderPassDescriptor *objCDesc) const
836
{
837
    ANGLE_MTL_OBJC_SCOPE
838
    {
839
        for (uint32_t i = 0; i < numColorAttachments; ++i)
840
        {
841
            ToObjC(colorAttachments[i], objCDesc.colorAttachments[i]);
842
        }
843
        for (uint32_t i = numColorAttachments; i < kMaxRenderTargets; ++i)
844
        {
845
            // Inactive render target
846
            objCDesc.colorAttachments[i].texture     = nil;
847
            objCDesc.colorAttachments[i].level       = 0;
848
            objCDesc.colorAttachments[i].slice       = 0;
849
            objCDesc.colorAttachments[i].depthPlane  = 0;
850
            objCDesc.colorAttachments[i].loadAction  = MTLLoadActionDontCare;
851
            objCDesc.colorAttachments[i].storeAction = MTLStoreActionDontCare;
852
        }
853
854
        ToObjC(depthAttachment, objCDesc.depthAttachment);
855
        ToObjC(stencilAttachment, objCDesc.stencilAttachment);
856
    }
857
}
858
859
// RenderPipelineCache implementation
856
// RenderPipelineCache implementation
860
RenderPipelineCache::RenderPipelineCache() : RenderPipelineCache(nullptr) {}
857
RenderPipelineCache::RenderPipelineCache() : RenderPipelineCache(nullptr) {
858
}
861
859
862
RenderPipelineCache::RenderPipelineCache(
860
RenderPipelineCache::RenderPipelineCache(
863
    RenderPipelineCacheSpecializeShaderFactory *specializedShaderFactory)
861
    RenderPipelineCacheSpecializeShaderFactory *specializedShaderFactory)
864
    : mSpecializedShaderFactory(specializedShaderFactory)
862
    : mSpecializedShaderFactory(specializedShaderFactory)
865
{}
863
{
864
865
}
866
866
867
RenderPipelineCache::~RenderPipelineCache() {}
867
RenderPipelineCache::~RenderPipelineCache() {}
868
868
869
void RenderPipelineCache::setVertexShader(Context *context, id<MTLFunction> shader)
869
void RenderPipelineCache::setVertexShader(Context *context,
870
                                          id<MTLFunction> shader)
870
{
871
{
871
    mVertexShader.retainAssign(shader);
872
    mVertexShader.retainAssign(shader);
872
873
Lines 879-885 void RenderPipelineCache::setVertexShader(Context *context, id<MTLFunction> shad a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.mm_sec11
879
    recreatePipelineStates(context);
880
    recreatePipelineStates(context);
880
}
881
}
881
882
882
void RenderPipelineCache::setFragmentShader(Context *context, id<MTLFunction> shader)
883
void RenderPipelineCache::setFragmentShader(Context *context,
884
                                            id<MTLFunction> shader)
883
{
885
{
884
    mFragmentShader.retainAssign(shader);
886
    mFragmentShader.retainAssign(shader);
885
887
Lines 929-938 AutoObjCPtr<id<MTLRenderPipelineState>> RenderPipelineCache::insertRenderPipelin a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.mm_sec12
929
{
931
{
930
    AutoObjCPtr<id<MTLRenderPipelineState>> newState =
932
    AutoObjCPtr<id<MTLRenderPipelineState>> newState =
931
        createRenderPipelineState(context, desc, insertDefaultAttribLayout);
933
        createRenderPipelineState(context, desc, insertDefaultAttribLayout);
932
    if (!newState)
933
    {
934
        return nil;
935
    }
936
934
937
    int tableIdx = insertDefaultAttribLayout ? 1 : 0;
935
    int tableIdx = insertDefaultAttribLayout ? 1 : 0;
938
    auto re      = mRenderPipelineStates[tableIdx].insert(std::make_pair(desc, newState));
936
    auto re      = mRenderPipelineStates[tableIdx].insert(std::make_pair(desc, newState));
Lines 944-949 AutoObjCPtr<id<MTLRenderPipelineState>> RenderPipelineCache::insertRenderPipelin a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.mm_sec13
944
    return re.first->second;
942
    return re.first->second;
945
}
943
}
946
944
945
947
AutoObjCPtr<id<MTLRenderPipelineState>> RenderPipelineCache::createRenderPipelineState(
946
AutoObjCPtr<id<MTLRenderPipelineState>> RenderPipelineCache::createRenderPipelineState(
948
    Context *context,
947
    Context *context,
949
    const RenderPipelineDesc &originalDesc,
948
    const RenderPipelineDesc &originalDesc,
Lines 959-965 AutoObjCPtr<id<MTLRenderPipelineState>> RenderPipelineCache::createRenderPipelin a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.mm_sec14
959
            desc.emulateCoverageMask    = false;
958
            desc.emulateCoverageMask    = false;
960
            desc.alphaToCoverageEnabled = false;
959
            desc.alphaToCoverageEnabled = false;
961
        }
960
        }
962
963
        // Choose shader variant
961
        // Choose shader variant
964
        id<MTLFunction> vertShader = nil;
962
        id<MTLFunction> vertShader = nil;
965
        id<MTLFunction> fragShader = nil;
963
        id<MTLFunction> fragShader = nil;
Lines 1004-1010 AutoObjCPtr<id<MTLRenderPipelineState>> RenderPipelineCache::createRenderPipelin a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.mm_sec15
1004
1002
1005
        // Convert to Objective-C desc:
1003
        // Convert to Objective-C desc:
1006
        AutoObjCObj<MTLRenderPipelineDescriptor> objCDesc = ToObjC(vertShader, fragShader, desc);
1004
        AutoObjCObj<MTLRenderPipelineDescriptor> objCDesc = ToObjC(vertShader, fragShader, desc);
1007
1005
        // Validate Render Pipeline State:
1006
        if (DeviceHasMaximumRenderTargetSize(metalDevice))
1007
        {
1008
            NSUInteger maxSize = GetMaxRenderTargetSizeForDeviceInBytes(metalDevice);
1009
            NSUInteger renderTargetSize =
1010
                ComputeTotalSizeUsedForMTLRenderPipelineDescriptor(objCDesc, context, metalDevice);
1011
            if (renderTargetSize > maxSize)
1012
            {
1013
                NSString *errorString =
1014
                    [NSString stringWithFormat:@"This set of render targets requires %lu bytes of "
1015
                                               @"pixel storage. This device supports %lu bytes.",
1016
                                               (unsigned long)renderTargetSize, (unsigned long)maxSize];
1017
                NSError *err = [NSError errorWithDomain:@"MTLValidationError"
1018
                                                   code:-1
1019
                                               userInfo:@{NSLocalizedDescriptionKey : errorString}];
1020
                context->handleError(err, __FILE__, ANGLE_FUNCTION, __LINE__);
1021
                return nil;
1022
            }
1023
        }
1008
        // Special attribute slot for default attribute
1024
        // Special attribute slot for default attribute
1009
        if (insertDefaultAttribLayout)
1025
        if (insertDefaultAttribLayout)
1010
        {
1026
        {
Lines 1032-1037 AutoObjCPtr<id<MTLRenderPipelineState>> RenderPipelineCache::createRenderPipelin a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.mm_sec16
1032
    }
1048
    }
1033
}
1049
}
1034
1050
1051
1035
void RenderPipelineCache::recreatePipelineStates(Context *context)
1052
void RenderPipelineCache::recreatePipelineStates(Context *context)
1036
{
1053
{
1037
    for (int hasDefaultAttrib = 0; hasDefaultAttrib <= 1; ++hasDefaultAttrib)
1054
    for (int hasDefaultAttrib = 0; hasDefaultAttrib <= 1; ++hasDefaultAttrib)
Lines 1062-1068 void RenderPipelineCache::clearPipelineStates() a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.mm_sec17
1062
}
1079
}
1063
1080
1064
// StateCache implementation
1081
// StateCache implementation
1065
StateCache::StateCache() {}
1082
StateCache::StateCache(const angle::FeaturesMtl &features) : mFeatures(features) {}
1066
1083
1067
StateCache::~StateCache() {}
1084
StateCache::~StateCache() {}
1068
1085
Lines 1113-1118 AutoObjCPtr<id<MTLSamplerState>> StateCache::getSamplerState(id<MTLDevice> metal a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.mm_sec18
1113
        if (ite == mSamplerStates.end())
1130
        if (ite == mSamplerStates.end())
1114
        {
1131
        {
1115
            AutoObjCObj<MTLSamplerDescriptor> objCDesc = ToObjC(desc);
1132
            AutoObjCObj<MTLSamplerDescriptor> objCDesc = ToObjC(desc);
1133
            if (!mFeatures.allowRuntimeSamplerCompareMode.enabled)
1134
            {
1135
                // Runtime sampler compare mode is not supported, fallback to never.
1136
                objCDesc.get().compareFunction = MTLCompareFunctionNever;
1137
            }
1116
            AutoObjCPtr<id<MTLSamplerState>> newState =
1138
            AutoObjCPtr<id<MTLSamplerState>> newState =
1117
                [[metalDevice newSamplerStateWithDescriptor:objCDesc] ANGLE_MTL_AUTORELEASE];
1139
                [[metalDevice newSamplerStateWithDescriptor:objCDesc] ANGLE_MTL_AUTORELEASE];
1118
1140
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_utils.h -2 / +21 lines
Lines 98-103 AutoObjCPtr<id<MTLLibrary>> CreateShaderLibraryFromBinary(id<MTLDevice> metalDev a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_utils.h_sec1
98
                                                          size_t binarySourceLen,
98
                                                          size_t binarySourceLen,
99
                                                          AutoObjCPtr<NSError *> *error);
99
                                                          AutoObjCPtr<NSError *> *error);
100
100
101
bool SupportsIOSGPUFamily(id<MTLDevice> device, uint8_t iOSFamily);
102
103
bool SupportsMacGPUFamily(id<MTLDevice> device, uint8_t macFamily);
104
101
// Need to define invalid enum value since Metal doesn't define it
105
// Need to define invalid enum value since Metal doesn't define it
102
constexpr MTLTextureType MTLTextureTypeInvalid = static_cast<MTLTextureType>(NSUIntegerMax);
106
constexpr MTLTextureType MTLTextureTypeInvalid = static_cast<MTLTextureType>(NSUIntegerMax);
103
static_assert(sizeof(MTLTextureType) == sizeof(NSUInteger),
107
static_assert(sizeof(MTLTextureType) == sizeof(NSUInteger),
Lines 135-149 MTLTextureSwizzle GetTextureSwizzle(GLenum swizzle); a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_utils.h_sec2
135
139
136
// Get color write mask for a specified format. Some formats such as RGB565 doesn't have alpha
140
// Get color write mask for a specified format. Some formats such as RGB565 doesn't have alpha
137
// channel but is emulated by a RGBA8 format, we need to disable alpha write for this format.
141
// channel but is emulated by a RGBA8 format, we need to disable alpha write for this format.
138
// - isFormatEmulated: if the format is emulated, this pointer will store a true value.
142
// - emulatedChannelsOut: if the format is emulated, this pointer will store a true value.
139
MTLColorWriteMask GetEmulatedColorWriteMask(const mtl::Format &mtlFormat, bool *isFormatEmulated);
143
MTLColorWriteMask GetEmulatedColorWriteMask(const mtl::Format &mtlFormat,
144
                                            bool *emulatedChannelsOut);
140
MTLColorWriteMask GetEmulatedColorWriteMask(const mtl::Format &mtlFormat);
145
MTLColorWriteMask GetEmulatedColorWriteMask(const mtl::Format &mtlFormat);
141
bool IsFormatEmulated(const mtl::Format &mtlFormat);
146
bool IsFormatEmulated(const mtl::Format &mtlFormat);
142
147
148
NSUInteger GetMaxRenderTargetSizeForDeviceInBytes(id<MTLDevice> device);
149
NSUInteger GetMaxNumberOfRenderTargetsForDevice(id<MTLDevice> device);
150
bool DeviceHasMaximumRenderTargetSize(id<MTLDevice> device);
151
143
// Useful to set clear color for texture originally having no alpha in GL, but backend's format
152
// Useful to set clear color for texture originally having no alpha in GL, but backend's format
144
// has alpha channel.
153
// has alpha channel.
145
MTLClearColor EmulatedAlphaClearColor(MTLClearColor color, MTLColorWriteMask colorMask);
154
MTLClearColor EmulatedAlphaClearColor(MTLClearColor color, MTLColorWriteMask colorMask);
146
155
156
157
NSUInteger ComputeTotalSizeUsedForMTLRenderPassDescriptor(const MTLRenderPassDescriptor *descriptor,
158
                                                          const Context *context,
159
                                                          id<MTLDevice> device);
160
161
NSUInteger ComputeTotalSizeUsedForMTLRenderPipelineDescriptor(
162
    const MTLRenderPipelineDescriptor *descriptor,
163
    const Context *context,
164
    id<MTLDevice> device);
165
147
gl::Box MTLRegionToGLBox(const MTLRegion &mtlRegion);
166
gl::Box MTLRegionToGLBox(const MTLRegion &mtlRegion);
148
167
149
MipmapNativeLevel GetNativeMipLevel(GLuint level, GLuint base);
168
MipmapNativeLevel GetNativeMipLevel(GLuint level, GLuint base);
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_utils.mm -32 / +392 lines
Lines 10-18 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_utils.mm_sec1
10
10
11
#include "libANGLE/renderer/metal/mtl_utils.h"
11
#include "libANGLE/renderer/metal/mtl_utils.h"
12
12
13
#include <Availability.h>
13
#include <TargetConditionals.h>
14
#include <TargetConditionals.h>
14
15
15
#include "common/MemoryBuffer.h"
16
#include "common/MemoryBuffer.h"
17
#include "common/system_utils.h"
16
#include "gpu_info_util/SystemInfo.h"
18
#include "gpu_info_util/SystemInfo.h"
17
#include "libANGLE/renderer/metal/ContextMtl.h"
19
#include "libANGLE/renderer/metal/ContextMtl.h"
18
#include "libANGLE/renderer/metal/DisplayMtl.h"
20
#include "libANGLE/renderer/metal/DisplayMtl.h"
Lines 24-29 namespace rx a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_utils.mm_sec2
24
namespace mtl
26
namespace mtl
25
{
27
{
26
28
29
constexpr char kANGLEPrintMSLEnv[] = "ANGLE_METAL_PRINT_MSL_ENABLE";
30
27
namespace
31
namespace
28
{
32
{
29
33
Lines 103-126 angle::Result InitializeTextureContents(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_utils.mm_sec3
103
                                        const ImageNativeIndex &index)
107
                                        const ImageNativeIndex &index)
104
{
108
{
105
    ASSERT(texture && texture->valid());
109
    ASSERT(texture && texture->valid());
106
    // Only one slice can be initialized at a time.
107
    ASSERT(!index.isLayered() || index.getType() == gl::TextureType::_3D);
108
    ContextMtl *contextMtl = mtl::GetImpl(context);
110
    ContextMtl *contextMtl = mtl::GetImpl(context);
109
111
112
    const angle::Format &actualAngleFormat           = textureObjFormat.actualAngleFormat();
110
    const gl::InternalFormat &intendedInternalFormat = textureObjFormat.intendedInternalFormat();
113
    const gl::InternalFormat &intendedInternalFormat = textureObjFormat.intendedInternalFormat();
111
114
112
    // This function is called in many places to initialize the content of a texture.
115
    // This function is called in many places to initialize the content of a texture.
113
    // So it's better we do the initial check here instead of let the callers do it themselves:
116
    // So it's better we do the sanity check here instead of let the callers do it themselves:
114
    if (!textureObjFormat.valid() || intendedInternalFormat.compressed)
117
    if (!textureObjFormat.valid() || actualAngleFormat.isBlock || actualAngleFormat.depthBits > 0 ||
118
        actualAngleFormat.stencilBits > 0)
115
    {
119
    {
120
        // If dst format is compressed, ignore.
116
        return angle::Result::Continue;
121
        return angle::Result::Continue;
117
    }
122
    }
118
123
119
    gl::Extents size = texture->size(index);
124
    gl::Extents size = texture->size(index);
120
125
121
    // Intiialize the content to black
126
    // Intialize the content to black
122
    GLint layer, startDepth;
127
    GLint layer      = 0;
123
    GetSliceAndDepth(index, &layer, &startDepth);
128
    GLint startDepth = 0;
129
    if (index.hasLayer())
130
    {
131
        switch (index.getType())
132
        {
133
            case gl::TextureType::CubeMap:
134
                layer = index.cubeMapFaceIndex();
135
                break;
136
            case gl::TextureType::_2DArray:
137
                layer = index.getLayerIndex();
138
                break;
139
            case gl::TextureType::_3D:
140
                startDepth = index.getLayerIndex();
141
                break;
142
            default:
143
                UNREACHABLE();
144
                break;
145
        }
146
    }
124
147
125
    if (texture->isCPUAccessible() && index.getType() != gl::TextureType::_2DMultisample &&
148
    if (texture->isCPUAccessible() && index.getType() != gl::TextureType::_2DMultisample &&
126
        index.getType() != gl::TextureType::_2DMultisampleArray)
149
        index.getType() != gl::TextureType::_2DMultisampleArray)
Lines 136-141 angle::Result InitializeTextureContents(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_utils.mm_sec4
136
        }
159
        }
137
        else
160
        else
138
        {
161
        {
162
            if (!textureObjFormat.valid() || intendedInternalFormat.compressed ||
163
                intendedInternalFormat.depthBits > 0 || intendedInternalFormat.stencilBits > 0)
164
            {
165
                // If source format is compressed, ignore.
166
                return angle::Result::Continue;
167
            }
168
139
            const angle::Format &srcFormat = angle::Format::Get(
169
            const angle::Format &srcFormat = angle::Format::Get(
140
                intendedInternalFormat.alphaBits > 0 ? angle::FormatID::R8G8B8A8_UNORM
170
                intendedInternalFormat.alphaBits > 0 ? angle::FormatID::R8G8B8A8_UNORM
141
                                                     : angle::FormatID::R8G8B8_UNORM);
171
                                                     : angle::FormatID::R8G8B8_UNORM);
Lines 162-171 angle::Result InitializeTextureContents(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_utils.mm_sec5
162
192
163
                // Upload to texture
193
                // Upload to texture
164
                texture->replace2DRegion(contextMtl, mtlRowRegion, index.getNativeLevel(), layer,
194
                texture->replace2DRegion(contextMtl, mtlRowRegion, index.getNativeLevel(), layer,
165
                                         conversionRow.data(), dstRowPitch);
195
                                       conversionRow.data(), dstRowPitch);
166
            }
196
            }
167
        }
197
        }
168
    }
198
    }  // if (texture->isCPUAccessible())
169
    else
199
    else
170
    {
200
    {
171
        ANGLE_TRY(InitializeTextureContentsGPU(context, texture, textureObjFormat, index,
201
        ANGLE_TRY(InitializeTextureContentsGPU(context, texture, textureObjFormat, index,
Lines 210-216 angle::Result InitializeTextureContentsGPU(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_utils.mm_sec6
210
    RenderTargetMtl tempRtt;
240
    RenderTargetMtl tempRtt;
211
    tempRtt.set(texture, index.getNativeLevel(), sliceOrDepth, textureObjFormat);
241
    tempRtt.set(texture, index.getNativeLevel(), sliceOrDepth, textureObjFormat);
212
242
213
    int clearAlpha = 0;
243
    float clearAlpha = 0;
214
    if (!textureObjFormat.intendedAngleFormat().alphaBits)
244
    if (!textureObjFormat.intendedAngleFormat().alphaBits)
215
    {
245
    {
216
        // if intended format doesn't have alpha, set it to 1.0.
246
        // if intended format doesn't have alpha, set it to 1.0.
Lines 240-250 angle::Result InitializeTextureContentsGPU(const gl::Context *context, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_utils.mm_sec7
240
        ClearColorValue clearColor;
270
        ClearColorValue clearColor;
241
        if (angleFormat.isSint())
271
        if (angleFormat.isSint())
242
        {
272
        {
243
            clearColor.setAsInt(0, 0, 0, clearAlpha);
273
            clearColor.setAsInt(0, 0, 0, (int)clearAlpha);
244
        }
274
        }
245
        else if (angleFormat.isUint())
275
        else if (angleFormat.isUint())
246
        {
276
        {
247
            clearColor.setAsUInt(0, 0, 0, clearAlpha);
277
            clearColor.setAsUInt(0, 0, 0, (int)clearAlpha);
248
        }
278
        }
249
        else
279
        else
250
        {
280
        {
Lines 283-299 angle::Result InitializeDepthStencilTextureContentsGPU(const gl::Context *contex a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_utils.mm_sec8
283
    rpDesc.sampleCount = texture->samples();
313
    rpDesc.sampleCount = texture->samples();
284
    if (angleFormat.depthBits)
314
    if (angleFormat.depthBits)
285
    {
315
    {
286
        rpDesc.depthAttachment.texture      = texture;
316
        rpDesc.depthAttachment.renderTarget->texture      = texture;
287
        rpDesc.depthAttachment.level        = level;
317
        rpDesc.depthAttachment.renderTarget->level        = level;
288
        rpDesc.depthAttachment.sliceOrDepth = layer;
318
        rpDesc.depthAttachment.renderTarget->sliceOrDepth = layer;
289
        rpDesc.depthAttachment.loadAction   = MTLLoadActionClear;
319
        rpDesc.depthAttachment.loadAction   = MTLLoadActionClear;
290
        rpDesc.depthAttachment.clearDepth   = 1.0;
320
        rpDesc.depthAttachment.clearDepth   = 1.0;
291
    }
321
    }
292
    if (angleFormat.stencilBits)
322
    if (angleFormat.stencilBits)
293
    {
323
    {
294
        rpDesc.stencilAttachment.texture      = texture;
324
        rpDesc.stencilAttachment.renderTarget->texture      = texture;
295
        rpDesc.stencilAttachment.level        = level;
325
        rpDesc.stencilAttachment.renderTarget->level        = level;
296
        rpDesc.stencilAttachment.sliceOrDepth = layer;
326
        rpDesc.stencilAttachment.renderTarget->sliceOrDepth = layer;
297
        rpDesc.stencilAttachment.loadAction   = MTLLoadActionClear;
327
        rpDesc.stencilAttachment.loadAction   = MTLLoadActionClear;
298
    }
328
    }
299
329
Lines 456-461 AutoObjCPtr<id<MTLLibrary>> CreateShaderLibrary(id<MTLDevice> metalDevice, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_utils.mm_sec9
456
    return CreateShaderLibrary(metalDevice, source.c_str(), source.size(), error);
486
    return CreateShaderLibrary(metalDevice, source.c_str(), source.size(), error);
457
}
487
}
458
488
489
#if 0
490
static MTLLanguageVersion GetHighestSupportedMSLVersion()
491
{
492
    // https://developer.apple.com/documentation/metal/mtllanguageversion?language=objc
493
    if (ANGLE_APPLE_AVAILABLE_XCI(11.0, 14.0, 14.0))
494
        return MTLLanguageVersion2_3;
495
    if (ANGLE_APPLE_AVAILABLE_XCI(10.15, 13.0, 13.0))
496
        return MTLLanguageVersion2_2;
497
    if (ANGLE_APPLE_AVAILABLE_XCI(10.15, 13.0, 12.0))
498
        return MTLLanguageVersion2_1;
499
    if (ANGLE_APPLE_AVAILABLE_XCI(10.13, 13.0, 11.0))
500
        return MTLLanguageVersion2_0;
501
    if (ANGLE_APPLE_AVAILABLE_XCI(10.12, 13.0, 10.0))
502
        return MTLLanguageVersion1_2;
503
    if (ANGLE_APPLE_AVAILABLE_XCI(10.11, 13.0, 9.0))
504
        return MTLLanguageVersion1_1;
505
#    if TARGET_OS_IOS
506
    if (ANGLE_APPLE_AVAILABLE_I(9.0))
507
        return MTLLanguageVersion1_0;
508
#    endif
509
    return MTLLanguageVersion1_1;
510
}
511
#endif
512
459
AutoObjCPtr<id<MTLLibrary>> CreateShaderLibrary(id<MTLDevice> metalDevice,
513
AutoObjCPtr<id<MTLLibrary>> CreateShaderLibrary(id<MTLDevice> metalDevice,
460
                                                const char *source,
514
                                                const char *source,
461
                                                size_t sourceLen,
515
                                                size_t sourceLen,
Lines 469-476 AutoObjCPtr<id<MTLLibrary>> CreateShaderLibrary(id<MTLDevice> metalDevice, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_utils.mm_sec10
469
                                                     encoding:NSUTF8StringEncoding
523
                                                     encoding:NSUTF8StringEncoding
470
                                                 freeWhenDone:NO];
524
                                                 freeWhenDone:NO];
471
        auto options     = [[[MTLCompileOptions alloc] init] ANGLE_MTL_AUTORELEASE];
525
        auto options     = [[[MTLCompileOptions alloc] init] ANGLE_MTL_AUTORELEASE];
526
        // Mark all positions in VS with attribute invariant as non-optimizable
527
#if (defined(__MAC_11_0) && __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_11_0) ||        \
528
    (defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0) || \
529
    (defined(__TVOS_14_0) && __TV_OS_VERSION_MAX_ALLOWED >= __TVOS_14_0)
530
        options.preserveInvariance = true;
531
#else
532
        // No preserveInvariance available compiling from source, so just disable fastmath.
533
        options.fastMathEnabled = false;
534
#endif
535
        // TODO(jcunningham): workaround for intel driver not preserving invariance on all shaders
536
        if ([metalDevice.name rangeOfString:@"Intel"].location != NSNotFound)
537
        {
538
            options.fastMathEnabled = false;
539
        }
472
        auto library = [metalDevice newLibraryWithSource:nsSource options:options error:&nsError];
540
        auto library = [metalDevice newLibraryWithSource:nsSource options:options error:&nsError];
473
541
        if (angle::GetEnvironmentVar(kANGLEPrintMSLEnv)[0] == '1')
542
        {
543
            NSLog(@"%@\n", nsSource);
544
        }
474
        [nsSource ANGLE_MTL_AUTORELEASE];
545
        [nsSource ANGLE_MTL_AUTORELEASE];
475
546
476
        *errorOut = std::move(nsError);
547
        *errorOut = std::move(nsError);
Lines 772-786 MTLTextureSwizzle GetTextureSwizzle(GLenum swizzle) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_utils.mm_sec11
772
}
843
}
773
#endif
844
#endif
774
845
775
MTLColorWriteMask GetEmulatedColorWriteMask(const mtl::Format &mtlFormat, bool *isEmulatedOut)
846
MTLColorWriteMask GetEmulatedColorWriteMask(const mtl::Format &mtlFormat, bool *emulatedChannelsOut)
776
{
847
{
777
    const angle::Format &intendedFormat = mtlFormat.intendedAngleFormat();
848
    const angle::Format &intendedFormat = mtlFormat.intendedAngleFormat();
778
    const angle::Format &actualFormat   = mtlFormat.actualAngleFormat();
849
    const angle::Format &actualFormat   = mtlFormat.actualAngleFormat();
779
    bool isFormatEmulated               = false;
850
    bool emulatedChannels               = false;
780
    MTLColorWriteMask colorWritableMask = MTLColorWriteMaskAll;
851
    MTLColorWriteMask colorWritableMask = MTLColorWriteMaskAll;
781
    if (intendedFormat.alphaBits == 0 && actualFormat.alphaBits)
852
    if (intendedFormat.alphaBits == 0 && actualFormat.alphaBits)
782
    {
853
    {
783
        isFormatEmulated = true;
854
        emulatedChannels = true;
784
        // Disable alpha write to this texture
855
        // Disable alpha write to this texture
785
        colorWritableMask = colorWritableMask & (~MTLColorWriteMaskAlpha);
856
        colorWritableMask = colorWritableMask & (~MTLColorWriteMaskAlpha);
786
    }
857
    }
Lines 788-828 MTLColorWriteMask GetEmulatedColorWriteMask(const mtl::Format &mtlFormat, bool * a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_utils.mm_sec12
788
    {
859
    {
789
        if (intendedFormat.redBits == 0 && actualFormat.redBits)
860
        if (intendedFormat.redBits == 0 && actualFormat.redBits)
790
        {
861
        {
791
            isFormatEmulated = true;
862
            emulatedChannels = true;
792
            // Disable red write to this texture
863
            // Disable red write to this texture
793
            colorWritableMask = colorWritableMask & (~MTLColorWriteMaskRed);
864
            colorWritableMask = colorWritableMask & (~MTLColorWriteMaskRed);
794
        }
865
        }
795
        if (intendedFormat.greenBits == 0 && actualFormat.greenBits)
866
        if (intendedFormat.greenBits == 0 && actualFormat.greenBits)
796
        {
867
        {
797
            isFormatEmulated = true;
868
            emulatedChannels = true;
798
            // Disable green write to this texture
869
            // Disable green write to this texture
799
            colorWritableMask = colorWritableMask & (~MTLColorWriteMaskGreen);
870
            colorWritableMask = colorWritableMask & (~MTLColorWriteMaskGreen);
800
        }
871
        }
801
        if (intendedFormat.blueBits == 0 && actualFormat.blueBits)
872
        if (intendedFormat.blueBits == 0 && actualFormat.blueBits)
802
        {
873
        {
803
            isFormatEmulated = true;
874
            emulatedChannels = true;
804
            // Disable blue write to this texture
875
            // Disable blue write to this texture
805
            colorWritableMask = colorWritableMask & (~MTLColorWriteMaskBlue);
876
            colorWritableMask = colorWritableMask & (~MTLColorWriteMaskBlue);
806
        }
877
        }
807
    }
878
    }
808
879
809
    *isEmulatedOut = isFormatEmulated;
880
    *emulatedChannelsOut = emulatedChannels;
810
881
811
    return colorWritableMask;
882
    return colorWritableMask;
812
}
883
}
813
884
814
MTLColorWriteMask GetEmulatedColorWriteMask(const mtl::Format &mtlFormat)
885
MTLColorWriteMask GetEmulatedColorWriteMask(const mtl::Format &mtlFormat)
815
{
886
{
816
    // Ignore isFormatEmulated boolean value
887
    // Ignore emulatedChannels boolean value
817
    bool isFormatEmulated;
888
    bool emulatedChannels;
818
    return GetEmulatedColorWriteMask(mtlFormat, &isFormatEmulated);
889
    return GetEmulatedColorWriteMask(mtlFormat, &emulatedChannels);
819
}
890
}
820
891
821
bool IsFormatEmulated(const mtl::Format &mtlFormat)
892
bool IsFormatEmulated(const mtl::Format &mtlFormat)
822
{
893
{
823
    bool isFormatEmulated;
894
    bool emulatedChannels;
824
    (void)GetEmulatedColorWriteMask(mtlFormat, &isFormatEmulated);
895
    (void)GetEmulatedColorWriteMask(mtlFormat, &emulatedChannels);
825
    return isFormatEmulated;
896
    return emulatedChannels;
826
}
897
}
827
898
828
MTLClearColor EmulatedAlphaClearColor(MTLClearColor color, MTLColorWriteMask colorMask)
899
MTLClearColor EmulatedAlphaClearColor(MTLClearColor color, MTLColorWriteMask colorMask)
Lines 837-842 MTLClearColor EmulatedAlphaClearColor(MTLClearColor color, MTLColorWriteMask col a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_utils.mm_sec13
837
    return re;
908
    return re;
838
}
909
}
839
910
911
NSUInteger GetMaxRenderTargetSizeForDeviceInBytes(id<MTLDevice> device)
912
{
913
    if (SupportsIOSGPUFamily(device, 4))
914
    {
915
        return 64;
916
    }
917
    else if (SupportsIOSGPUFamily(device, 2))
918
    {
919
        return 32;
920
    }
921
    else
922
    {
923
        return 16;
924
    }
925
}
926
927
NSUInteger GetMaxNumberOfRenderTargetsForDevice(id<MTLDevice> device)
928
{
929
    if (SupportsIOSGPUFamily(device, 2)||SupportsMacGPUFamily(device, 1))
930
    {
931
        return 8;
932
    }
933
    else
934
    {
935
        return 4;
936
    }
937
}
938
939
bool DeviceHasMaximumRenderTargetSize(id<MTLDevice> device)
940
{
941
        return SupportsIOSGPUFamily(device, 1);
942
}
943
944
bool SupportsIOSGPUFamily(id<MTLDevice> device, uint8_t iOSFamily)
945
{
946
#if (!TARGET_OS_IOS && !TARGET_OS_TV) || TARGET_OS_MACCATALYST
947
    return false;
948
#else
949
#    if (__IPHONE_OS_VERSION_MAX_ALLOWED >= 130000) || (__TV_OS_VERSION_MAX_ALLOWED >= 130000)
950
    // If device supports [MTLDevice supportsFamily:], then use it.
951
    if (ANGLE_APPLE_AVAILABLE_I(13.0))
952
    {
953
        MTLGPUFamily family;
954
        switch (iOSFamily)
955
        {
956
            case 1:
957
                family = MTLGPUFamilyApple1;
958
                break;
959
            case 2:
960
                family = MTLGPUFamilyApple2;
961
                break;
962
            case 3:
963
                family = MTLGPUFamilyApple3;
964
                break;
965
            case 4:
966
                family = MTLGPUFamilyApple4;
967
                break;
968
            case 5:
969
                family = MTLGPUFamilyApple5;
970
                break;
971
#        if TARGET_OS_IOS
972
            case 6:
973
                family = MTLGPUFamilyApple6;
974
                break;
975
#        endif
976
            default:
977
                return false;
978
        }
979
        return [device supportsFamily:family];
980
    }  // Metal 2.2
981
#    endif  // __IPHONE_OS_VERSION_MAX_ALLOWED
982
983
    // If device doesn't support [MTLDevice supportsFamily:], then use
984
    // [MTLDevice supportsFeatureSet:].
985
    MTLFeatureSet featureSet;
986
    switch (iOSFamily)
987
    {
988
#    if TARGET_OS_IOS
989
        case 1:
990
            featureSet = MTLFeatureSet_iOS_GPUFamily1_v1;
991
            break;
992
        case 2:
993
            featureSet = MTLFeatureSet_iOS_GPUFamily2_v1;
994
            break;
995
        case 3:
996
            featureSet = MTLFeatureSet_iOS_GPUFamily3_v1;
997
            break;
998
        case 4:
999
            featureSet = MTLFeatureSet_iOS_GPUFamily4_v1;
1000
            break;
1001
#        if __IPHONE_OS_VERSION_MAX_ALLOWED >= 120000
1002
        case 5:
1003
            featureSet = MTLFeatureSet_iOS_GPUFamily5_v1;
1004
            break;
1005
#        endif  // __IPHONE_OS_VERSION_MAX_ALLOWED
1006
#    elif TARGET_OS_TV
1007
        case 1:
1008
        case 2:
1009
            featureSet = MTLFeatureSet_tvOS_GPUFamily1_v1;
1010
            break;
1011
#        if __TV_OS_VERSION_MAX_ALLOWED >= 110000
1012
        case 3:
1013
            featureSet = MTLFeatureSet_tvOS_GPUFamily2_v1;
1014
            break;
1015
#       endif // __TV_OS_VERSION_MAX_ALLOWED
1016
#    endif  // TARGET_OS_IOS
1017
        default:
1018
            return false;
1019
    }
1020
1021
    return [device supportsFeatureSet:featureSet];
1022
#endif      // TARGET_OS_IOS || TARGET_OS_TV
1023
}
1024
1025
bool SupportsMacGPUFamily(id<MTLDevice> device, uint8_t macFamily)
1026
{
1027
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
1028
#    if defined(__MAC_10_15)
1029
    // If device supports [MTLDevice supportsFamily:], then use it.
1030
    if (ANGLE_APPLE_AVAILABLE_XC(10.15, 13.0))
1031
    {
1032
        MTLGPUFamily family;
1033
1034
        switch (macFamily)
1035
        {
1036
#        if TARGET_OS_MACCATALYST
1037
            case 1:
1038
                family = MTLGPUFamilyMacCatalyst1;
1039
                break;
1040
            case 2:
1041
                family = MTLGPUFamilyMacCatalyst2;
1042
                break;
1043
#        else   // TARGET_OS_MACCATALYST
1044
            case 1:
1045
                family = MTLGPUFamilyMac1;
1046
                break;
1047
            case 2:
1048
                family = MTLGPUFamilyMac2;
1049
                break;
1050
#        endif  // TARGET_OS_MACCATALYST
1051
            default:
1052
                return false;
1053
        }
1054
1055
        return [device supportsFamily:family];
1056
    }  // Metal 2.2
1057
#    endif
1058
1059
    // If device doesn't support [MTLDevice supportsFamily:], then use
1060
    // [MTLDevice supportsFeatureSet:].
1061
#    if TARGET_OS_MACCATALYST
1062
    UNREACHABLE();
1063
    return false;
1064
#    else
1065
    MTLFeatureSet featureSet;
1066
    switch (macFamily)
1067
    {
1068
        case 1:
1069
            featureSet = MTLFeatureSet_macOS_GPUFamily1_v1;
1070
            break;
1071
#        if defined(__MAC_10_14)
1072
        case 2:
1073
            featureSet = MTLFeatureSet_macOS_GPUFamily2_v1;
1074
            break;
1075
#        endif
1076
        default:
1077
            return false;
1078
    }
1079
    return [device supportsFeatureSet:featureSet];
1080
#    endif  // TARGET_OS_MACCATALYST
1081
#else       // #if TARGET_OS_OSX || TARGET_OS_MACCATALYST
1082
1083
    return false;
1084
1085
#endif
1086
}
1087
1088
static NSUInteger getNextLocationForFormat(const FormatCaps &caps,
1089
                                           bool isMSAA,
1090
                                           NSUInteger currentRenderTargetSize)
1091
{
1092
    assert(!caps.compressed);
1093
    uint8_t alignment         = caps.alignment;
1094
    NSUInteger pixelBytes     = caps.pixelBytes;
1095
    NSUInteger pixelBytesMSAA = caps.pixelBytesMSAA;
1096
    pixelBytes                = isMSAA ? pixelBytesMSAA : pixelBytes;
1097
1098
    currentRenderTargetSize = (currentRenderTargetSize + (alignment - 1)) & ~(alignment - 1);
1099
    currentRenderTargetSize += pixelBytes;
1100
    return currentRenderTargetSize;
1101
}
1102
1103
NSUInteger ComputeTotalSizeUsedForMTLRenderPassDescriptor(const MTLRenderPassDescriptor *descriptor,
1104
                                                          const Context *context,
1105
                                                          id<MTLDevice> device)
1106
{
1107
    NSUInteger currentRenderTargetSize = 0;
1108
1109
    for (NSUInteger i = 0; i < GetMaxNumberOfRenderTargetsForDevice(device); i++)
1110
    {
1111
        MTLPixelFormat pixelFormat = descriptor.colorAttachments[i].texture.pixelFormat;
1112
        bool isMsaa                = descriptor.colorAttachments[i].texture.sampleCount > 1;
1113
        if (pixelFormat != MTLPixelFormatInvalid)
1114
        {
1115
            const FormatCaps &caps = context->getDisplay()->getNativeFormatCaps(pixelFormat);
1116
            currentRenderTargetSize =
1117
                getNextLocationForFormat(caps, isMsaa, currentRenderTargetSize);
1118
        }
1119
    }
1120
    if (descriptor.depthAttachment.texture.pixelFormat ==
1121
        descriptor.stencilAttachment.texture.pixelFormat)
1122
    {
1123
        bool isMsaa = descriptor.depthAttachment.texture.sampleCount > 1;
1124
        if (descriptor.depthAttachment.texture.pixelFormat != MTLPixelFormatInvalid)
1125
        {
1126
            const FormatCaps &caps = context->getDisplay()->getNativeFormatCaps(
1127
                descriptor.depthAttachment.texture.pixelFormat);
1128
            currentRenderTargetSize =
1129
                getNextLocationForFormat(caps, isMsaa, currentRenderTargetSize);
1130
        }
1131
    }
1132
    else
1133
    {
1134
        if (descriptor.depthAttachment.texture.pixelFormat != MTLPixelFormatInvalid)
1135
        {
1136
            bool isMsaa            = descriptor.depthAttachment.texture.sampleCount > 1;
1137
            const FormatCaps &caps = context->getDisplay()->getNativeFormatCaps(
1138
                descriptor.depthAttachment.texture.pixelFormat);
1139
            currentRenderTargetSize =
1140
                getNextLocationForFormat(caps, isMsaa, currentRenderTargetSize);
1141
        }
1142
        if (descriptor.stencilAttachment.texture.pixelFormat != MTLPixelFormatInvalid)
1143
        {
1144
            bool isMsaa            = descriptor.stencilAttachment.texture.sampleCount > 1;
1145
            const FormatCaps &caps = context->getDisplay()->getNativeFormatCaps(
1146
                descriptor.stencilAttachment.texture.pixelFormat);
1147
            currentRenderTargetSize =
1148
                getNextLocationForFormat(caps, isMsaa, currentRenderTargetSize);
1149
        }
1150
    }
1151
    return currentRenderTargetSize;
1152
}
1153
NSUInteger ComputeTotalSizeUsedForMTLRenderPipelineDescriptor(
1154
    const MTLRenderPipelineDescriptor *descriptor,
1155
    const Context *context,
1156
    id<MTLDevice> device)
1157
{
1158
    NSUInteger currentRenderTargetSize = 0;
1159
    bool isMsaa                        = descriptor.sampleCount > 1;
1160
    for (NSUInteger i = 0; i < GetMaxNumberOfRenderTargetsForDevice(device); i++)
1161
    {
1162
        MTLRenderPipelineColorAttachmentDescriptor *color = descriptor.colorAttachments[i];
1163
        if (color.pixelFormat != MTLPixelFormatInvalid)
1164
        {
1165
            const FormatCaps &caps = context->getDisplay()->getNativeFormatCaps(color.pixelFormat);
1166
            currentRenderTargetSize =
1167
                getNextLocationForFormat(caps, isMsaa, currentRenderTargetSize);
1168
        }
1169
    }
1170
    if (descriptor.depthAttachmentPixelFormat == descriptor.stencilAttachmentPixelFormat)
1171
    {
1172
        if (descriptor.depthAttachmentPixelFormat != MTLPixelFormatInvalid)
1173
        {
1174
            const FormatCaps &caps =
1175
                context->getDisplay()->getNativeFormatCaps(descriptor.depthAttachmentPixelFormat);
1176
            currentRenderTargetSize =
1177
                getNextLocationForFormat(caps, isMsaa, currentRenderTargetSize);
1178
        }
1179
    }
1180
    else
1181
    {
1182
        if (descriptor.depthAttachmentPixelFormat != MTLPixelFormatInvalid)
1183
        {
1184
            const FormatCaps &caps =
1185
                context->getDisplay()->getNativeFormatCaps(descriptor.depthAttachmentPixelFormat);
1186
            currentRenderTargetSize =
1187
                getNextLocationForFormat(caps, isMsaa, currentRenderTargetSize);
1188
        }
1189
        if (descriptor.stencilAttachmentPixelFormat != MTLPixelFormatInvalid)
1190
        {
1191
            const FormatCaps &caps =
1192
                context->getDisplay()->getNativeFormatCaps(descriptor.stencilAttachmentPixelFormat);
1193
            currentRenderTargetSize =
1194
                getNextLocationForFormat(caps, isMsaa, currentRenderTargetSize);
1195
        }
1196
    }
1197
    return currentRenderTargetSize;
1198
}
1199
840
gl::Box MTLRegionToGLBox(const MTLRegion &mtlRegion)
1200
gl::Box MTLRegionToGLBox(const MTLRegion &mtlRegion)
841
{
1201
{
842
    return gl::Box(static_cast<int>(mtlRegion.origin.x), static_cast<int>(mtlRegion.origin.y),
1202
    return gl::Box(static_cast<int>(mtlRegion.origin.x), static_cast<int>(mtlRegion.origin.y),
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/shaders/blit.metal -2 / +2 lines
Lines 334-340 kernel void blitStencilToBufferCS(ushort2 gIndices [[thread_position_in_grid]], a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/shaders/blit.metal_sec1
334
}
334
}
335
335
336
// Fragment's stencil output is only available since Metal 2.1
336
// Fragment's stencil output is only available since Metal 2.1
337
@@#if __METAL_VERSION__ >= 210
337
#if __METAL_VERSION__ >= 210
338
338
339
struct FragmentStencilOut
339
struct FragmentStencilOut
340
{
340
{
Lines 397-400 fragment FragmentDepthStencilOut blitDepthStencilFS( a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/shaders/blit.metal_sec2
397
                      srcStencilTextureCube, input.texCoords, options.srcLevel, options.srcLayer);
397
                      srcStencilTextureCube, input.texCoords, options.srcLevel, options.srcLayer);
398
    return re;
398
    return re;
399
}
399
}
400
@@#endif  // __METAL_VERSION__ >= 210
400
#endif  // __METAL_VERSION__ >= 210
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/shaders/common.h -2 / +2 lines
Lines 10-17 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/shaders/common.h_sec1
10
10
11
// clang-format off
11
// clang-format off
12
#ifndef SKIP_STD_HEADERS
12
#ifndef SKIP_STD_HEADERS
13
@@#    include <simd/simd.h>
13
#    include <simd/simd.h>
14
@@#    include <metal_stdlib>
14
#    include <metal_stdlib>
15
#endif
15
#endif
16
16
17
#include "constants.h"
17
#include "constants.h"
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/shaders/copy_buffer.metal -4 / +4 lines
Lines 4-25 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/shaders/copy_buffer.metal_sec1
4
// found in the LICENSE file.
4
// found in the LICENSE file.
5
//
5
//
6
// copy_buffer.metal: implements compute shader that copy formatted data from buffer to texture,
6
// copy_buffer.metal: implements compute shader that copy formatted data from buffer to texture,
7
// and from texture to buffer.
7
// from texture to buffer and from buffer to buffer.
8
// NOTE(hqle): This file is a bit hard to read but there are a lot of repeated works, and it would
8
// NOTE(hqle): This file is a bit hard to read but there are a lot of repeated works, and it would
9
// be a pain to implement without the use of macros.
9
// be a pain to implement without the use of macros.
10
//
10
//
11
11
12
@@#include <metal_pack>
12
#include <metal_pack>
13
13
14
#include "common.h"
14
#include "common.h"
15
#include "format_autogen.h"
15
#include "format_autogen.h"
16
16
17
using namespace rx::mtl_shader;
17
using namespace rx::mtl_shader;
18
18
19
constant int kCopyFormatType [[function_constant(10)]];
19
constant int kCopyFormatType [[function_constant(1)]];
20
20
21
/* -------- copy pixel data between buffer and texture ---------*/
21
/* -------- copy pixel data between buffer and texture ---------*/
22
constant int kCopyTextureType [[function_constant(20)]];
22
constant int kCopyTextureType [[function_constant(2)]];
23
constant bool kCopyTextureType2D      = kCopyTextureType == kTextureType2D;
23
constant bool kCopyTextureType2D      = kCopyTextureType == kTextureType2D;
24
constant bool kCopyTextureType2DArray = kCopyTextureType == kTextureType2DArray;
24
constant bool kCopyTextureType2DArray = kCopyTextureType == kTextureType2DArray;
25
constant bool kCopyTextureType2DMS    = kCopyTextureType == kTextureType2DMultisample;
25
constant bool kCopyTextureType2DMS    = kCopyTextureType == kTextureType2DMultisample;
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/shaders/format_autogen.h -2 / +2 lines
Lines 245-249 enum a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/shaders/format_autogen.h_sec1
245
245
246
}
246
}
247
247
248
}  // namespace mtl_shader
248
}
249
}  // namespace rx
249
}
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/shaders/gen_indices.metal -26 / +30 lines
Lines 56-65 inline uint getIndexUnalignedU32(constant uchar *input, uint offset, uint idx) a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/shaders/gen_indices.metal_sec1
56
    return input0 | (input1 << 8) | (input2 << 16) | (input3 << 24);
56
    return input0 | (input1 << 8) | (input2 << 16) | (input3 << 24);
57
}
57
}
58
58
59
kernel void convertIndexU8ToU16(uint idx[[thread_position_in_grid]],
59
kernel void convertIndexU8ToU16(uint idx [[thread_position_in_grid]],
60
                                constant IndexConversionParams &options[[buffer(0)]],
60
                                constant IndexConversionParams &options [[buffer(0)]],
61
                                constant uchar *input[[buffer(1)]],
61
                                constant uchar *input [[buffer(1)]],
62
                                device ushort *output[[buffer(2)]])
62
                                device ushort *output [[buffer(2)]])
63
{
63
{
64
    ANGLE_IDX_CONVERSION_GUARD(idx, options);
64
    ANGLE_IDX_CONVERSION_GUARD(idx, options);
65
65
Lines 75-86 kernel void convertIndexU8ToU16(uint idx[[thread_position_in_grid]], a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/shaders/gen_indices.metal_sec2
75
    }
75
    }
76
}
76
}
77
77
78
kernel void convertIndexU16(
78
kernel void convertIndexU16(uint idx [[thread_position_in_grid]],
79
    uint idx[[thread_position_in_grid]],
79
                            constant IndexConversionParams &options [[buffer(0)]],
80
    constant IndexConversionParams &options[[buffer(0)]],
80
                            constant uchar *input
81
    constant uchar *input[[ buffer(1), function_constant(kSourceBufferUnaligned) ]],
81
                            [[buffer(1), function_constant(kSourceBufferUnaligned)]],
82
    constant ushort *inputAligned[[ buffer(1), function_constant(kSourceBufferAligned) ]],
82
                            constant ushort *inputAligned
83
    device ushort *output[[buffer(2)]])
83
                            [[buffer(1), function_constant(kSourceBufferAligned)]],
84
                            device ushort *output [[buffer(2)]])
84
{
85
{
85
    ANGLE_IDX_CONVERSION_GUARD(idx, options);
86
    ANGLE_IDX_CONVERSION_GUARD(idx, options);
86
87
Lines 96-107 kernel void convertIndexU16( a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/shaders/gen_indices.metal_sec3
96
    output[idx] = value;
97
    output[idx] = value;
97
}
98
}
98
99
99
kernel void convertIndexU32(
100
kernel void convertIndexU32(uint idx [[thread_position_in_grid]],
100
    uint idx[[thread_position_in_grid]],
101
                            constant IndexConversionParams &options [[buffer(0)]],
101
    constant IndexConversionParams &options[[buffer(0)]],
102
                            constant uchar *input
102
    constant uchar *input[[ buffer(1), function_constant(kSourceBufferUnaligned) ]],
103
                            [[buffer(1), function_constant(kSourceBufferUnaligned)]],
103
    constant uint *inputAligned[[ buffer(1), function_constant(kSourceBufferAligned) ]],
104
                            constant uint *inputAligned
104
    device uint *output[[buffer(2)]])
105
                            [[buffer(1), function_constant(kSourceBufferAligned)]],
106
                            device uint *output [[buffer(2)]])
105
{
107
{
106
    ANGLE_IDX_CONVERSION_GUARD(idx, options);
108
    ANGLE_IDX_CONVERSION_GUARD(idx, options);
107
109
Lines 140-148 kernel void genTriFanIndicesFromArray(uint idx [[thread_position_in_grid]], a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/shaders/gen_indices.metal_sec4
140
142
141
inline uint getIndexU32(uint offset,
143
inline uint getIndexU32(uint offset,
142
                        uint idx,
144
                        uint idx,
143
                        constant uchar *inputU8[[function_constant(kUseSourceBufferU8)]],
145
                        constant uchar *inputU8 [[function_constant(kUseSourceBufferU8)]],
144
                        constant ushort *inputU16[[function_constant(kUseSourceBufferU16)]],
146
                        constant ushort *inputU16 [[function_constant(kUseSourceBufferU16)]],
145
                        constant uint *inputU32[[function_constant(kUseSourceBufferU32)]])
147
                        constant uint *inputU32 [[function_constant(kUseSourceBufferU32)]])
146
{
148
{
147
    if (kUseSourceBufferU8)
149
    if (kUseSourceBufferU8)
148
    {
150
    {
Lines 170-182 inline uint getIndexU32(uint offset, a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/shaders/gen_indices.metal_sec5
170
// NOTE(hqle): triangle fan indices generation doesn't support primitive restart.
172
// NOTE(hqle): triangle fan indices generation doesn't support primitive restart.
171
// Generate triangle fan indices from an indices buffer. indexCount options indicates number
173
// Generate triangle fan indices from an indices buffer. indexCount options indicates number
172
// of indices starting from the 3rd.
174
// of indices starting from the 3rd.
173
kernel void genTriFanIndicesFromElements(
175
kernel void genTriFanIndicesFromElements(uint idx [[thread_position_in_grid]],
174
    uint idx[[thread_position_in_grid]],
176
                                         constant IndexConversionParams &options [[buffer(0)]],
175
    constant IndexConversionParams &options[[buffer(0)]],
177
                                         constant uchar *inputU8
176
    constant uchar *inputU8[[ buffer(1), function_constant(kUseSourceBufferU8) ]],
178
                                         [[buffer(1), function_constant(kUseSourceBufferU8)]],
177
    constant ushort *inputU16[[ buffer(1), function_constant(kUseSourceBufferU16) ]],
179
                                         constant ushort *inputU16
178
    constant uint *inputU32[[ buffer(1), function_constant(kUseSourceBufferU32) ]],
180
                                         [[buffer(1), function_constant(kUseSourceBufferU16)]],
179
    device uint *output[[buffer(2)]])
181
                                         constant uint *inputU32
182
                                         [[buffer(1), function_constant(kUseSourceBufferU32)]],
183
                                         device uint *output [[buffer(2)]])
180
{
184
{
181
    ANGLE_IDX_CONVERSION_GUARD(idx, options);
185
    ANGLE_IDX_CONVERSION_GUARD(idx, options);
182
186
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/shaders/gen_mipmap.metal -12 / +347 lines
Lines 23-30 using namespace rx::mtl_shader; a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/shaders/gen_mipmap.metal_sec1
23
23
24
#define TEXEL_LOAD(index) float4(sR[index], sG[index], sB[index], sA[index])
24
#define TEXEL_LOAD(index) float4(sR[index], sG[index], sB[index], sA[index])
25
25
26
#define TO_LINEAR(texel) (options.sRGB ? sRGBtoLinear(texel) : texel)
27
28
#define OUT_OF_BOUND_CHECK(edgeValue, targetValue, condition) \
26
#define OUT_OF_BOUND_CHECK(edgeValue, targetValue, condition) \
29
    (condition) ? (edgeValue) : (targetValue)
27
    (condition) ? (edgeValue) : (targetValue)
30
28
Lines 32-38 struct GenMipParams a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/shaders/gen_mipmap.metal_sec2
32
{
30
{
33
    uint srcLevel;
31
    uint srcLevel;
34
    uint numMipLevelsToGen;
32
    uint numMipLevelsToGen;
35
    bool sRGB;
36
};
33
};
37
34
38
// NOTE(hqle): For numMipLevelsToGen > 1, this function assumes the texture is power of two. If it
35
// NOTE(hqle): For numMipLevelsToGen > 1, this function assumes the texture is power of two. If it
Lines 46-53 kernel void generate3DMipmaps(uint lIndex [[thread_index_in_threadgroup]], a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/shaders/gen_mipmap.metal_sec3
46
                              texture3d<float, access::write> dstMip4 [[texture(4)]],
43
                              texture3d<float, access::write> dstMip4 [[texture(4)]],
47
                              constant GenMipParams &options [[buffer(0)]])
44
                              constant GenMipParams &options [[buffer(0)]])
48
{
45
{
49
    ushort3 mipSize  = ushort3(dstMip1.get_width(), dstMip1.get_height(), dstMip1.get_depth());
46
    ushort3 mipSize    = ushort3(dstMip1.get_width(), dstMip1.get_height(), dstMip1.get_depth());
50
    bool validThread = gIndices.x < mipSize.x && gIndices.y < mipSize.y && gIndices.z < mipSize.z;
47
    bool validThread   = gIndices.x < mipSize.x && gIndices.y < mipSize.y && gIndices.z < mipSize.z;
51
48
52
    constexpr sampler textureSampler(mag_filter::linear, min_filter::linear, mip_filter::linear);
49
    constexpr sampler textureSampler(mag_filter::linear, min_filter::linear, mip_filter::linear);
53
50
Lines 83-92 kernel void generate3DMipmaps(uint lIndex [[thread_index_in_threadgroup]], a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/shaders/gen_mipmap.metal_sec4
83
    // ---- Second mip level --------
80
    // ---- Second mip level --------
84
81
85
    // Write to shared memory
82
    // Write to shared memory
86
    if (options.sRGB)
87
    {
88
        texel1 = linearToSRGB(texel1);
89
    }
90
    TEXEL_STORE(lIndex, texel1);
83
    TEXEL_STORE(lIndex, texel1);
91
84
92
    threadgroup_barrier(mem_flags::mem_threadgroup);
85
    threadgroup_barrier(mem_flags::mem_threadgroup);
Lines 119-125 kernel void generate3DMipmaps(uint lIndex [[thread_index_in_threadgroup]], a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/shaders/gen_mipmap.metal_sec5
119
112
120
        texel1 = (texel1 + texel2 + texel3 + texel4 + texel5 + texel6 + texel7 + texel8) / 8.0;
113
        texel1 = (texel1 + texel2 + texel3 + texel4 + texel5 + texel6 + texel7 + texel8) / 8.0;
121
114
122
        dstMip2.write(TO_LINEAR(texel1), gIndices >> 1);
115
        dstMip2.write(texel1, gIndices >> 1);
123
116
124
        // Write to shared memory
117
        // Write to shared memory
125
        TEXEL_STORE(lIndex, texel1);
118
        TEXEL_STORE(lIndex, texel1);
Lines 165-171 kernel void generate3DMipmaps(uint lIndex [[thread_index_in_threadgroup]], a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/shaders/gen_mipmap.metal_sec6
165
158
166
        texel1 = (texel1 + texel2 + texel3 + texel4 + texel5 + texel6 + texel7 + texel8) / 8.0;
159
        texel1 = (texel1 + texel2 + texel3 + texel4 + texel5 + texel6 + texel7 + texel8) / 8.0;
167
160
168
        dstMip3.write(TO_LINEAR(texel1), gIndices >> 2);
161
        dstMip3.write(texel1, gIndices >> 2);
169
162
170
        // Write to shared memory
163
        // Write to shared memory
171
        TEXEL_STORE(lIndex, texel1);
164
        TEXEL_STORE(lIndex, texel1);
Lines 211-216 kernel void generate3DMipmaps(uint lIndex [[thread_index_in_threadgroup]], a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/shaders/gen_mipmap.metal_sec7
211
204
212
        texel1 = (texel1 + texel2 + texel3 + texel4 + texel5 + texel6 + texel7 + texel8) / 8.0;
205
        texel1 = (texel1 + texel2 + texel3 + texel4 + texel5 + texel6 + texel7 + texel8) / 8.0;
213
206
214
        dstMip4.write(TO_LINEAR(texel1), gIndices >> 3);
207
        dstMip4.write(texel1, gIndices >> 3);
208
    }
209
}
210
211
kernel void generate2DMipmaps(uint lIndex [[thread_index_in_threadgroup]],
212
                              ushort2 gIndices [[thread_position_in_grid]],
213
                              texture2d<float> srcTexture [[texture(0)]],
214
                              texture2d<float, access::write> dstMip1 [[texture(1)]],
215
                              texture2d<float, access::write> dstMip2 [[texture(2)]],
216
                              texture2d<float, access::write> dstMip3 [[texture(3)]],
217
                              texture2d<float, access::write> dstMip4 [[texture(4)]],
218
                              constant GenMipParams &options [[buffer(0)]])
219
{
220
    uint firstMipLevel = options.srcLevel + 1;
221
    ushort2 mipSize =
222
        ushort2(srcTexture.get_width(firstMipLevel), srcTexture.get_height(firstMipLevel));
223
    bool validThread = gIndices.x < mipSize.x && gIndices.y < mipSize.y;
224
225
    constexpr sampler textureSampler(mag_filter::linear, min_filter::linear, mip_filter::linear);
226
227
    // NOTE(hqle): Use simd_group function whenever available. That could avoid barrier use.
228
229
    // Use struct of array style to avoid bank conflict.
230
    threadgroup float sR[kThreadGroupXY];
231
    threadgroup float sG[kThreadGroupXY];
232
    threadgroup float sB[kThreadGroupXY];
233
    threadgroup float sA[kThreadGroupXY];
234
235
    // ----- First mip level -------
236
    float4 texel1;
237
    if (validThread)
238
    {
239
        float2 texCoords = (float2(gIndices) + float2(0.5, 0.5)) / float2(mipSize);
240
        texel1           = srcTexture.sample(textureSampler, texCoords, level(options.srcLevel));
241
242
        // Write to texture
243
        dstMip1.write(texel1, gIndices);
244
    }
245
    else
246
    {
247
        // This will invalidate all subsequent checks
248
        lIndex = 0xffffffff;
249
    }
250
251
    if (options.numMipLevelsToGen == 1)
252
    {
253
        return;
254
    }
255
256
    // ---- Second mip level --------
257
258
    // Write to shared memory
259
    TEXEL_STORE(lIndex, texel1);
260
261
    threadgroup_barrier(mem_flags::mem_threadgroup);
262
263
    // Index must be even
264
    if ((lIndex & 0x09) == 0)  // (lIndex & b001001) == 0
265
    {
266
        bool2 atEdge = gIndices == (mipSize - ushort2(1));
267
268
        // (x+1, y)
269
        // If the width of mip is 1, texel2 will equal to texel1:
270
        float4 texel2 = OUT_OF_BOUND_CHECK(texel1, TEXEL_LOAD(lIndex + 1), atEdge.x);
271
        // (x, y+1)
272
        float4 texel3 = OUT_OF_BOUND_CHECK(texel1, TEXEL_LOAD(lIndex + kThreadGroupX), atEdge.y);
273
        // (x+1, y+1)
274
        float4 texel4 = OUT_OF_BOUND_CHECK(texel2, TEXEL_LOAD(lIndex + (kThreadGroupX + 1)),
275
                                           atEdge.x | atEdge.y);
276
277
        texel1 = (texel1 + texel2 + texel3 + texel4) / 4.0;
278
279
        dstMip2.write(texel1, gIndices >> 1);
280
281
        // Write to shared memory
282
        TEXEL_STORE(lIndex, texel1);
283
    }
284
285
    if (options.numMipLevelsToGen == 2)
286
    {
287
        return;
288
    }
289
290
    // ---- 3rd mip level --------
291
    threadgroup_barrier(mem_flags::mem_threadgroup);
292
293
    // Index must be multiple of 4
294
    if ((lIndex & 0x1b) == 0)  // (lIndex & b011011) == 0
295
    {
296
        mipSize      = max(mipSize >> 1, ushort2(1));
297
        bool2 atEdge = (gIndices >> 1) == (mipSize - ushort2(1));
298
299
        // (x+1, y)
300
        // If the width of mip is 1, texel2 will equal to texel1:
301
        float4 texel2 = OUT_OF_BOUND_CHECK(texel1, TEXEL_LOAD(lIndex + 2), atEdge.x);
302
        // (x, y+1)
303
        float4 texel3 =
304
            OUT_OF_BOUND_CHECK(texel1, TEXEL_LOAD(lIndex + 2 * kThreadGroupX), atEdge.y);
305
        // (x+1, y+1)
306
        float4 texel4 = OUT_OF_BOUND_CHECK(texel2, TEXEL_LOAD(lIndex + (2 * kThreadGroupX + 2)),
307
                                           atEdge.x | atEdge.y);
308
309
        texel1 = (texel1 + texel2 + texel3 + texel4) / 4.0;
310
311
        dstMip3.write(texel1, gIndices >> 2);
312
313
        // Write to shared memory
314
        TEXEL_STORE(lIndex, texel1);
315
    }
316
317
    if (options.numMipLevelsToGen == 3)
318
    {
319
        return;
320
    }
321
322
    // ---- 4th mip level --------
323
    threadgroup_barrier(mem_flags::mem_threadgroup);
324
325
    // Index must be multiple of 8
326
    if ((lIndex & 0x3f) == 0)  // (lIndex & b111111) == 0
327
    {
328
        mipSize      = max(mipSize >> 1, ushort2(1));
329
        bool2 atEdge = (gIndices >> 2) == (mipSize - ushort2(1));
330
331
        // (x+1, y)
332
        // If the width of mip is 1, texel2 will equal to texel1:
333
        float4 texel2 = OUT_OF_BOUND_CHECK(texel1, TEXEL_LOAD(lIndex + 4), atEdge.x);
334
        // (x, y+1)
335
        float4 texel3 =
336
            OUT_OF_BOUND_CHECK(texel1, TEXEL_LOAD(lIndex + 4 * kThreadGroupX), atEdge.y);
337
        // (x+1, y+1)
338
        float4 texel4 = OUT_OF_BOUND_CHECK(texel2, TEXEL_LOAD(lIndex + (4 * kThreadGroupX + 4)),
339
                                           atEdge.x | atEdge.y);
340
341
        texel1 = (texel1 + texel2 + texel3 + texel4) / 4.0;
342
343
        dstMip4.write(texel1, gIndices >> 3);
344
    }
345
}
346
347
template <typename TextureTypeR, typename TextureTypeW>
348
static __attribute__((always_inline)) void generateCubeOr2DArray2ndAndMoreMipmaps(
349
    uint lIndex,
350
    ushort3 gIndices,
351
    TextureTypeR srcTexture,
352
    TextureTypeW dstMip2,
353
    TextureTypeW dstMip3,
354
    TextureTypeW dstMip4,
355
    ushort2 mip1Size,
356
    float4 mip1Texel,
357
    threadgroup float *sR,
358
    threadgroup float *sG,
359
    threadgroup float *sB,
360
    threadgroup float *sA,
361
    constant GenMipParams &options)
362
{
363
    ushort2 mipSize = mip1Size;
364
    float4 texel1   = mip1Texel;
365
366
    // ---- Second mip level --------
367
368
    // Write to shared memory
369
    TEXEL_STORE(lIndex, texel1);
370
371
    threadgroup_barrier(mem_flags::mem_threadgroup);
372
373
    // Index must be even
374
    if ((lIndex & 0x09) == 0)  // (lIndex & b001001) == 0
375
    {
376
        bool2 atEdge = gIndices.xy == (mipSize - ushort2(1));
377
378
        // (x+1, y)
379
        // If the width of mip is 1, texel2 will equal to texel1:
380
        float4 texel2 = OUT_OF_BOUND_CHECK(texel1, TEXEL_LOAD(lIndex + 1), atEdge.x);
381
        // (x, y+1)
382
        float4 texel3 = OUT_OF_BOUND_CHECK(texel1, TEXEL_LOAD(lIndex + kThreadGroupX), atEdge.y);
383
        // (x+1, y+1)
384
        float4 texel4 = OUT_OF_BOUND_CHECK(texel2, TEXEL_LOAD(lIndex + (kThreadGroupX + 1)),
385
                                           atEdge.x | atEdge.y);
386
387
        texel1 = (texel1 + texel2 + texel3 + texel4) / 4.0;
388
389
        dstMip2.write(texel1, gIndices.xy >> 1, gIndices.z);
390
391
        // Write to shared memory
392
        TEXEL_STORE(lIndex, texel1);
215
    }
393
    }
394
395
    if (options.numMipLevelsToGen == 2)
396
    {
397
        return;
398
    }
399
400
    // ---- 3rd mip level --------
401
    threadgroup_barrier(mem_flags::mem_threadgroup);
402
403
    // Index must be multiple of 4
404
    if ((lIndex & 0x1b) == 0)  // (lIndex & b011011) == 0
405
    {
406
        mipSize      = max(mipSize >> 1, ushort2(1));
407
        bool2 atEdge = (gIndices.xy >> 1) == (mipSize - ushort2(1));
408
409
        // (x+1, y)
410
        // If the width of mip is 1, texel2 will equal to texel1:
411
        float4 texel2 = OUT_OF_BOUND_CHECK(texel1, TEXEL_LOAD(lIndex + 2), atEdge.x);
412
        // (x, y+1)
413
        float4 texel3 =
414
            OUT_OF_BOUND_CHECK(texel1, TEXEL_LOAD(lIndex + 2 * kThreadGroupX), atEdge.y);
415
        // (x+1, y+1)
416
        float4 texel4 = OUT_OF_BOUND_CHECK(texel2, TEXEL_LOAD(lIndex + (2 * kThreadGroupX + 2)),
417
                                           atEdge.x | atEdge.y);
418
419
        texel1 = (texel1 + texel2 + texel3 + texel4) / 4.0;
420
421
        dstMip3.write(texel1, gIndices.xy >> 2, gIndices.z);
422
423
        // Write to shared memory
424
        TEXEL_STORE(lIndex, texel1);
425
    }
426
427
    if (options.numMipLevelsToGen == 3)
428
    {
429
        return;
430
    }
431
432
    // ---- 4th mip level --------
433
    threadgroup_barrier(mem_flags::mem_threadgroup);
434
435
    // Index must be multiple of 8
436
    if ((lIndex & 0x3f) == 0)  // (lIndex & b111111) == 0
437
    {
438
        mipSize      = max(mipSize >> 1, ushort2(1));
439
        bool2 atEdge = (gIndices.xy >> 2) == (mipSize - ushort2(1));
440
441
        // (x+1, y)
442
        // If the width of mip is 1, texel2 will equal to texel1:
443
        float4 texel2 = OUT_OF_BOUND_CHECK(texel1, TEXEL_LOAD(lIndex + 4), atEdge.x);
444
        // (x, y+1)
445
        float4 texel3 =
446
            OUT_OF_BOUND_CHECK(texel1, TEXEL_LOAD(lIndex + 4 * kThreadGroupX), atEdge.y);
447
        // (x+1, y+1)
448
        float4 texel4 = OUT_OF_BOUND_CHECK(texel2, TEXEL_LOAD(lIndex + (4 * kThreadGroupX + 4)),
449
                                           atEdge.x | atEdge.y);
450
451
        texel1 = (texel1 + texel2 + texel3 + texel4) / 4.0;
452
453
        dstMip4.write(texel1, gIndices.xy >> 3, gIndices.z);
454
    }
455
}
456
457
kernel void generateCubeMipmaps(uint lIndex [[thread_index_in_threadgroup]],
458
                                ushort3 gIndices [[thread_position_in_grid]],
459
                                texturecube<float> srcTexture [[texture(0)]],
460
                                texturecube<float, access::write> dstMip1 [[texture(1)]],
461
                                texturecube<float, access::write> dstMip2 [[texture(2)]],
462
                                texturecube<float, access::write> dstMip3 [[texture(3)]],
463
                                texturecube<float, access::write> dstMip4 [[texture(4)]],
464
                                constant GenMipParams &options [[buffer(0)]])
465
{
466
    uint firstMipLevel = options.srcLevel + 1;
467
    ushort2 mip1Size =
468
        ushort2(srcTexture.get_width(firstMipLevel), srcTexture.get_height(firstMipLevel));
469
    bool validThread = gIndices.x < mip1Size.x && gIndices.y < mip1Size.y;
470
471
    constexpr sampler textureSampler(mag_filter::linear, min_filter::linear, mip_filter::linear);
472
473
    // ----- First mip level -------
474
    float4 mip1Texel;
475
    if (validThread)
476
    {
477
        float2 texCoords = (float2(gIndices.xy) + float2(0.5, 0.5)) / float2(mip1Size);
478
        mip1Texel = srcTexture.sample(textureSampler, cubeTexcoords(texCoords, int(gIndices.z)),
479
                                      level(options.srcLevel));
480
481
        // Write to texture
482
        dstMip1.write(mip1Texel, gIndices.xy, gIndices.z);
483
    }
484
    else
485
    {
486
        // This will invalidate all subsequent checks
487
        lIndex = 0xffffffff;
488
    }
489
490
    if (options.numMipLevelsToGen == 1)
491
    {
492
        return;
493
    }
494
495
    // Use struct of array style to avoid bank conflict.
496
    threadgroup float sR[kThreadGroupXY];
497
    threadgroup float sG[kThreadGroupXY];
498
    threadgroup float sB[kThreadGroupXY];
499
    threadgroup float sA[kThreadGroupXY];
500
501
    generateCubeOr2DArray2ndAndMoreMipmaps(lIndex, gIndices, srcTexture, dstMip2, dstMip3, dstMip4,
502
                                           mip1Size, mip1Texel, sR, sG, sB, sA, options);
503
}
504
505
kernel void generate2DArrayMipmaps(uint lIndex [[thread_index_in_threadgroup]],
506
                                   ushort3 gIndices [[thread_position_in_grid]],
507
                                   texture2d_array<float> srcTexture [[texture(0)]],
508
                                   texture2d_array<float, access::write> dstMip1 [[texture(1)]],
509
                                   texture2d_array<float, access::write> dstMip2 [[texture(2)]],
510
                                   texture2d_array<float, access::write> dstMip3 [[texture(3)]],
511
                                   texture2d_array<float, access::write> dstMip4 [[texture(4)]],
512
                                   constant GenMipParams &options [[buffer(0)]])
513
{
514
    uint firstMipLevel = options.srcLevel + 1;
515
    ushort2 mip1Size =
516
        ushort2(srcTexture.get_width(firstMipLevel), srcTexture.get_height(firstMipLevel));
517
    bool validThread = gIndices.x < mip1Size.x && gIndices.y < mip1Size.y;
518
519
    constexpr sampler textureSampler(mag_filter::linear, min_filter::linear, mip_filter::linear);
520
521
    // ----- First mip level -------
522
    float4 mip1Texel;
523
    if (validThread)
524
    {
525
        float2 texCoords = (float2(gIndices.xy) + float2(0.5, 0.5)) / float2(mip1Size);
526
        mip1Texel =
527
            srcTexture.sample(textureSampler, texCoords, gIndices.z, level(options.srcLevel));
528
529
        // Write to texture
530
        dstMip1.write(mip1Texel, gIndices.xy, gIndices.z);
531
    }
532
    else
533
    {
534
        // This will invalidate all subsequent checks
535
        lIndex = 0xffffffff;
536
    }
537
538
    if (options.numMipLevelsToGen == 1)
539
    {
540
        return;
541
    }
542
543
    // Use struct of array style to avoid bank conflict.
544
    threadgroup float sR[kThreadGroupXY];
545
    threadgroup float sG[kThreadGroupXY];
546
    threadgroup float sB[kThreadGroupXY];
547
    threadgroup float sA[kThreadGroupXY];
548
549
    generateCubeOr2DArray2ndAndMoreMipmaps(lIndex, gIndices, srcTexture, dstMip2, dstMip3, dstMip4,
550
                                           mip1Size, mip1Texel, sR, sG, sB, sA, options);
216
}
551
}
- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/shaders/visibility.metal -1 / +1 lines
Lines 6-12 a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/shaders/visibility.metal_sec1
6
6
7
#include "common.h"
7
#include "common.h"
8
8
9
constant bool kCombineWithExistingResult [[function_constant(1000)]];
9
constant bool kCombineWithExistingResult [[function_constant(1)]];
10
10
11
// Combine the visibility result of current render pass with previous value from previous render
11
// Combine the visibility result of current render pass with previous value from previous render
12
// pass
12
// pass
- a/Source/ThirdParty/ANGLE/src/libGLESv2/entry_points_egl.cpp -8 / +6 lines
Lines 428-435 EGLBoolean EGLAPIENTRY EGL_DestroyContext(EGLDisplay dpy, EGLContext ctx) a/Source/ThirdParty/ANGLE/src/libGLESv2/entry_points_egl.cpp_sec1
428
428
429
    if (contextWasCurrent)
429
    if (contextWasCurrent)
430
    {
430
    {
431
        ANGLE_EGL_TRY_RETURN(thread, display->makeCurrent(context, nullptr, nullptr, nullptr),
432
                             "eglDestroyContext", GetContextIfValid(display, context), EGL_FALSE);
433
        SetContextCurrent(thread, nullptr);
431
        SetContextCurrent(thread, nullptr);
434
    }
432
    }
435
433
Lines 466-474 EGLBoolean EGLAPIENTRY EGL_MakeCurrent(EGLDisplay dpy, a/Source/ThirdParty/ANGLE/src/libGLESv2/entry_points_egl.cpp_sec2
466
    // Only call makeCurrent if the context or surfaces have changed.
464
    // Only call makeCurrent if the context or surfaces have changed.
467
    if (previousDraw != drawSurface || previousRead != readSurface || previousContext != context)
465
    if (previousDraw != drawSurface || previousRead != readSurface || previousContext != context)
468
    {
466
    {
469
        ANGLE_EGL_TRY_RETURN(
467
        ANGLE_EGL_TRY_RETURN(thread,
470
            thread, display->makeCurrent(previousContext, drawSurface, readSurface, context),
468
                             display->makeCurrent(thread, drawSurface, readSurface, context),
471
            "eglMakeCurrent", GetContextIfValid(display, context), EGL_FALSE);
469
                             "eglMakeCurrent", GetContextIfValid(display, context), EGL_FALSE);
472
470
473
        SetContextCurrent(thread, context);
471
        SetContextCurrent(thread, context);
474
    }
472
    }
Lines 818-826 EGLBoolean EGLAPIENTRY EGL_ReleaseThread(void) a/Source/ThirdParty/ANGLE/src/libGLESv2/entry_points_egl.cpp_sec3
818
        if (previousDraw != EGL_NO_SURFACE || previousRead != EGL_NO_SURFACE ||
816
        if (previousDraw != EGL_NO_SURFACE || previousRead != EGL_NO_SURFACE ||
819
            previousContext != EGL_NO_CONTEXT)
817
            previousContext != EGL_NO_CONTEXT)
820
        {
818
        {
821
            ANGLE_EGL_TRY_RETURN(
819
            ANGLE_EGL_TRY_RETURN(thread,
822
                thread, previousDisplay->makeCurrent(previousContext, nullptr, nullptr, nullptr),
820
                                 previousDisplay->makeCurrent(thread, nullptr, nullptr, nullptr),
823
                "eglReleaseThread", nullptr, EGL_FALSE);
821
                                 "eglReleaseThread", nullptr, EGL_FALSE);
824
        }
822
        }
825
        ANGLE_EGL_TRY_RETURN(thread, previousDisplay->releaseThread(), "eglReleaseThread",
823
        ANGLE_EGL_TRY_RETURN(thread, previousDisplay->releaseThread(), "eglReleaseThread",
826
                             GetDisplayIfValid(previousDisplay), EGL_FALSE);
824
                             GetDisplayIfValid(previousDisplay), EGL_FALSE);

Return to Bug 219759