• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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// ProgramMtl.mm:
7//    Implements the class methods for ProgramMtl.
8//
9
10#include "libANGLE/renderer/metal/ProgramMtl.h"
11
12#include <TargetConditionals.h>
13
14#include <sstream>
15
16#include "common/debug.h"
17#include "common/system_utils.h"
18#include "libANGLE/Context.h"
19#include "libANGLE/ProgramLinkedResources.h"
20#include "libANGLE/renderer/metal/BufferMtl.h"
21#include "libANGLE/renderer/metal/CompilerMtl.h"
22#include "libANGLE/renderer/metal/ContextMtl.h"
23#include "libANGLE/renderer/metal/DisplayMtl.h"
24#include "libANGLE/renderer/metal/TextureMtl.h"
25#include "libANGLE/renderer/metal/mtl_glslang_mtl_utils.h"
26#include "libANGLE/renderer/metal/mtl_utils.h"
27#include "libANGLE/renderer/renderer_utils.h"
28
29#if ANGLE_ENABLE_METAL_SPIRV
30#    include "libANGLE/renderer/metal/mtl_glslang_utils.h"
31#endif
32
33namespace rx
34{
35
36namespace
37{
38
39#define SHADER_ENTRY_NAME @"main0"
40#if ANGLE_ENABLE_METAL_SPIRV
41constexpr char kSpirvCrossSpecConstSuffix[] = "_tmp";
42#endif
43template <typename T>
44class ANGLE_NO_DISCARD ScopedAutoClearVector
45{
46  public:
47    ScopedAutoClearVector(std::vector<T> *array) : mArray(*array) {}
48    ~ScopedAutoClearVector() { mArray.clear(); }
49
50  private:
51    std::vector<T> &mArray;
52};
53
54angle::Result StreamUniformBufferData(ContextMtl *contextMtl,
55                                      mtl::BufferPool *dynamicBuffer,
56                                      const uint8_t *sourceData,
57                                      size_t bytesToAllocate,
58                                      size_t sizeToCopy,
59                                      mtl::BufferRef *bufferOut,
60                                      size_t *bufferOffsetOut)
61{
62    uint8_t *dst = nullptr;
63    dynamicBuffer->releaseInFlightBuffers(contextMtl);
64    ANGLE_TRY(dynamicBuffer->allocate(contextMtl, bytesToAllocate, &dst, bufferOut, bufferOffsetOut,
65                                      nullptr));
66    memcpy(dst, sourceData, sizeToCopy);
67
68    ANGLE_TRY(dynamicBuffer->commit(contextMtl));
69    return angle::Result::Continue;
70}
71
72void InitDefaultUniformBlock(const std::vector<sh::Uniform> &uniforms,
73                             gl::Shader *shader,
74                             sh::BlockLayoutMap *blockLayoutMapOut,
75                             size_t *blockSizeOut)
76{
77    if (uniforms.empty())
78    {
79        *blockSizeOut = 0;
80        return;
81    }
82
83    sh::Std140BlockEncoder blockEncoder;
84    sh::GetActiveUniformBlockInfo(uniforms, "", &blockEncoder, blockLayoutMapOut);
85
86    size_t blockSize = blockEncoder.getCurrentOffset();
87
88    // TODO(jmadill): I think we still need a valid block for the pipeline even if zero sized.
89    if (blockSize == 0)
90    {
91        *blockSizeOut = 0;
92        return;
93    }
94
95    // Need to round up to multiple of vec4
96    *blockSizeOut = roundUp(blockSize, static_cast<size_t>(16));
97    return;
98}
99
100inline NSDictionary<NSString *, NSObject *> *getDefaultSubstitutionDictionary()
101{
102    return @{};
103}
104
105template <typename T>
106void UpdateDefaultUniformBlock(GLsizei count,
107                               uint32_t arrayIndex,
108                               int componentCount,
109                               const T *v,
110                               const sh::BlockMemberInfo &layoutInfo,
111                               angle::MemoryBuffer *uniformData)
112{
113    const int elementSize = sizeof(T) * componentCount;
114
115    uint8_t *dst = uniformData->data() + layoutInfo.offset;
116    if (layoutInfo.arrayStride == 0 || layoutInfo.arrayStride == elementSize)
117    {
118        uint32_t arrayOffset = arrayIndex * layoutInfo.arrayStride;
119        uint8_t *writePtr    = dst + arrayOffset;
120        ASSERT(writePtr + (elementSize * count) <= uniformData->data() + uniformData->size());
121        memcpy(writePtr, v, elementSize * count);
122    }
123    else
124    {
125        // Have to respect the arrayStride between each element of the array.
126        int maxIndex = arrayIndex + count;
127        for (int writeIndex = arrayIndex, readIndex = 0; writeIndex < maxIndex;
128             writeIndex++, readIndex++)
129        {
130            const int arrayOffset = writeIndex * layoutInfo.arrayStride;
131            uint8_t *writePtr     = dst + arrayOffset;
132            const T *readPtr      = v + (readIndex * componentCount);
133            ASSERT(writePtr + elementSize <= uniformData->data() + uniformData->size());
134            memcpy(writePtr, readPtr, elementSize);
135        }
136    }
137}
138
139template <typename T>
140void ReadFromDefaultUniformBlock(int componentCount,
141                                 uint32_t arrayIndex,
142                                 T *dst,
143                                 const sh::BlockMemberInfo &layoutInfo,
144                                 const angle::MemoryBuffer *uniformData)
145{
146    ASSERT(layoutInfo.offset != -1);
147
148    const int elementSize = sizeof(T) * componentCount;
149    const uint8_t *source = uniformData->data() + layoutInfo.offset;
150
151    if (layoutInfo.arrayStride == 0 || layoutInfo.arrayStride == elementSize)
152    {
153        const uint8_t *readPtr = source + arrayIndex * layoutInfo.arrayStride;
154        memcpy(dst, readPtr, elementSize);
155    }
156    else
157    {
158        // Have to respect the arrayStride between each element of the array.
159        const int arrayOffset  = arrayIndex * layoutInfo.arrayStride;
160        const uint8_t *readPtr = source + arrayOffset;
161        memcpy(dst, readPtr, elementSize);
162    }
163}
164
165class Std140BlockLayoutEncoderFactory : public gl::CustomBlockLayoutEncoderFactory
166{
167  public:
168    sh::BlockLayoutEncoder *makeEncoder() override { return new sh::Std140BlockEncoder(); }
169};
170
171void InitArgumentBufferEncoder(mtl::Context *context,
172                               id<MTLFunction> function,
173                               uint32_t bufferIndex,
174                               ProgramArgumentBufferEncoderMtl *encoder)
175{
176    encoder->metalArgBufferEncoder = [function newArgumentEncoderWithBufferIndex:bufferIndex];
177    if (encoder->metalArgBufferEncoder)
178    {
179        encoder->bufferPool.initialize(context, encoder->metalArgBufferEncoder.get().encodedLength,
180                                       mtl::kArgumentBufferOffsetAlignment, 0);
181    }
182}
183
184}  // namespace
185
186// ProgramArgumentBufferEncoderMtl implementation
187void ProgramArgumentBufferEncoderMtl::reset(ContextMtl *contextMtl)
188{
189    metalArgBufferEncoder = nil;
190    bufferPool.destroy(contextMtl);
191}
192
193// ProgramShaderObjVariantMtl implementation
194void ProgramShaderObjVariantMtl::reset(ContextMtl *contextMtl)
195{
196    metalShader = nil;
197
198    uboArgBufferEncoder.reset(contextMtl);
199
200    translatedSrcInfo = nullptr;
201}
202
203// ProgramMtl implementation
204ProgramMtl::DefaultUniformBlock::DefaultUniformBlock() {}
205
206ProgramMtl::DefaultUniformBlock::~DefaultUniformBlock() = default;
207
208ProgramMtl::ProgramMtl(const gl::ProgramState &state)
209    : ProgramImpl(state),
210      mProgramHasFlatAttributes(false),
211      mShadowCompareModes(),
212      mMetalRenderPipelineCache(this),
213      mAuxBufferPool(nullptr)
214{}
215
216ProgramMtl::~ProgramMtl() {}
217
218void ProgramMtl::destroy(const gl::Context *context)
219{
220    auto contextMtl = mtl::GetImpl(context);
221    if (mAuxBufferPool)
222    {
223        mAuxBufferPool->destroy(contextMtl);
224        delete mAuxBufferPool;
225        mAuxBufferPool = nullptr;
226    }
227    reset(contextMtl);
228}
229
230void ProgramMtl::reset(ContextMtl *context)
231{
232    mProgramHasFlatAttributes = false;
233
234    for (auto &block : mDefaultUniformBlocks)
235    {
236        block.uniformLayout.clear();
237    }
238
239    for (gl::ShaderType shaderType : gl::AllShaderTypes())
240    {
241        mMslShaderTranslateInfo[shaderType].reset();
242        mCurrentShaderVariants[shaderType] = nullptr;
243    }
244    mMslXfbOnlyVertexShaderInfo.reset();
245
246    for (ProgramShaderObjVariantMtl &var : mVertexShaderVariants)
247    {
248        var.reset(context);
249    }
250    for (ProgramShaderObjVariantMtl &var : mFragmentShaderVariants)
251    {
252        var.reset(context);
253    }
254    if (mAuxBufferPool)
255    {
256        if (mAuxBufferPool->reset(context, mtl::kDefaultUniformsMaxSize * 2,
257                                  mtl::kUniformBufferSettingOffsetMinAlignment,
258                                  3) != angle::Result::Continue)
259        {
260            mAuxBufferPool->destroy(context);
261            delete mAuxBufferPool;
262            mAuxBufferPool = nullptr;
263        }
264    }
265    mMetalRenderPipelineCache.clear();
266}
267
268void ProgramMtl::saveTranslatedShaders(gl::BinaryOutputStream *stream)
269{
270    // Write out shader sources for all shader types
271    for (const gl::ShaderType shaderType : gl::AllShaderTypes())
272    {
273        stream->writeString(mMslShaderTranslateInfo[shaderType].metalShaderSource);
274    }
275    stream->writeString(mMslXfbOnlyVertexShaderInfo.metalShaderSource);
276}
277
278void ProgramMtl::loadTranslatedShaders(gl::BinaryInputStream *stream)
279{
280    // Read in shader sources for all shader types
281    for (const gl::ShaderType shaderType : gl::AllShaderTypes())
282    {
283        mMslShaderTranslateInfo[shaderType].metalShaderSource = stream->readString();
284    }
285    mMslXfbOnlyVertexShaderInfo.metalShaderSource = stream->readString();
286}
287
288std::unique_ptr<rx::LinkEvent> ProgramMtl::load(const gl::Context *context,
289                                                gl::BinaryInputStream *stream,
290                                                gl::InfoLog &infoLog)
291{
292
293    return std::make_unique<LinkEventDone>(linkTranslatedShaders(context, stream, infoLog));
294}
295
296void ProgramMtl::save(const gl::Context *context, gl::BinaryOutputStream *stream)
297{
298    saveTranslatedShaders(stream);
299    saveShaderInternalInfo(stream);
300    saveDefaultUniformBlocksInfo(stream);
301}
302
303void ProgramMtl::setBinaryRetrievableHint(bool retrievable)
304{
305    UNIMPLEMENTED();
306}
307
308void ProgramMtl::setSeparable(bool separable)
309{
310    UNIMPLEMENTED();
311}
312
313std::unique_ptr<LinkEvent> ProgramMtl::link(const gl::Context *context,
314                                            const gl::ProgramLinkedResources &resources,
315                                            gl::InfoLog &infoLog,
316                                            const gl::ProgramMergedVaryings &mergedVaryings)
317{
318    // Link resources before calling GetShaderSource to make sure they are ready for the set/binding
319    // assignment done in that function.
320    linkResources(resources);
321
322    // NOTE(hqle): Parallelize linking.
323    return std::make_unique<LinkEventDone>(linkImpl(context, resources, infoLog));
324}
325
326#if ANGLE_ENABLE_METAL_SPIRV
327angle::Result ProgramMtl::linkImplSpirv(const gl::Context *glContext,
328                                        const gl::ProgramLinkedResources &resources,
329                                        gl::InfoLog &infoLog)
330{
331    ContextMtl *contextMtl = mtl::GetImpl(glContext);
332
333    reset(contextMtl);
334
335    ANGLE_TRY(initDefaultUniformBlocks(glContext));
336
337    // Gather variable info and transform sources.
338    gl::ShaderMap<const angle::spirv::Blob *> spirvBlobs;
339    ShaderInterfaceVariableInfoMap variableInfoMap;
340    ShaderInterfaceVariableInfoMap xfbOnlyVariableInfoMap;
341    mtl::GlslangGetShaderSpirvCode(mState, resources, &spirvBlobs, &variableInfoMap,
342                                   &xfbOnlyVariableInfoMap);
343
344    // Convert GLSL to spirv code
345    gl::ShaderMap<angle::spirv::Blob> shaderCodes;
346    gl::ShaderMap<angle::spirv::Blob> xfbOnlyShaderCodes;  // only vertex shader is needed.
347    ANGLE_TRY(mtl::GlslangTransformSpirvCode(mState.getExecutable().getLinkedShaderStages(),
348                                             spirvBlobs, false, variableInfoMap, &shaderCodes));
349
350    if (!mState.getLinkedTransformFeedbackVaryings().empty())
351    {
352        gl::ShaderBitSet onlyVS;
353        onlyVS.set(gl::ShaderType::Vertex);
354        ANGLE_TRY(mtl::GlslangTransformSpirvCode(onlyVS, spirvBlobs, true, xfbOnlyVariableInfoMap,
355                                                 &xfbOnlyShaderCodes));
356    }
357
358    // Convert spirv code to MSL
359    ANGLE_TRY(mtl::SpirvCodeToMsl(contextMtl, mState, xfbOnlyVariableInfoMap, &shaderCodes,
360                                  &xfbOnlyShaderCodes[gl::ShaderType::Vertex],
361                                  &mMslShaderTranslateInfo, &mMslXfbOnlyVertexShaderInfo));
362
363    for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes)
364    {
365        // Create actual Metal shader library
366        ANGLE_TRY(createMslShaderLib(contextMtl, shaderType, infoLog,
367                                     &mMslShaderTranslateInfo[shaderType],
368                                     getDefaultSubstitutionDictionary()));
369    }
370
371    return angle::Result::Continue;
372}
373#endif
374
375angle::Result ProgramMtl::linkImplDirect(const gl::Context *glContext,
376                                         const gl::ProgramLinkedResources &resources,
377                                         gl::InfoLog &infoLog)
378{
379    ContextMtl *contextMtl = mtl::GetImpl(glContext);
380
381    reset(contextMtl);
382    ANGLE_TRY(initDefaultUniformBlocks(glContext));
383    ShaderInterfaceVariableInfoMap variableInfoMap;
384
385    gl::ShaderMap<std::string> shaderSources;
386    gl::ShaderMap<std::string> translatedMslShaders;
387    mtl::MSLGetShaderSource(mState, resources, &shaderSources, &variableInfoMap);
388
389    ANGLE_TRY(mtl::GlslangGetMSL(glContext, mState, contextMtl->getCaps(), shaderSources,
390                                 variableInfoMap, &mMslShaderTranslateInfo, &translatedMslShaders,
391                                 mState.getExecutable().getTransformFeedbackBufferCount()));
392    mMslXfbOnlyVertexShaderInfo = mMslShaderTranslateInfo[gl::ShaderType::Vertex];
393    for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes)
394    {
395        // Create actual Metal shader
396        ANGLE_TRY(createMslShaderLib(contextMtl, shaderType, infoLog,
397                                     &mMslShaderTranslateInfo[shaderType],
398                                     getDefaultSubstitutionDictionary()));
399    }
400    return angle::Result::Continue;
401}
402
403void ProgramMtl::linkUpdateHasFlatAttributes()
404{
405    mProgramHasFlatAttributes = false;
406
407    const auto &programInputs = mState.getProgramInputs();
408    for (auto &attribute : programInputs)
409    {
410        if (attribute.interpolation == sh::INTERPOLATION_FLAT)
411        {
412            mProgramHasFlatAttributes = true;
413            return;
414        }
415    }
416
417    const auto &flatVaryings =
418        mState.getAttachedShader(gl::ShaderType::Vertex)->getOutputVaryings();
419    for (auto &attribute : flatVaryings)
420    {
421        if (attribute.interpolation == sh::INTERPOLATION_FLAT)
422        {
423            mProgramHasFlatAttributes = true;
424            return;
425        }
426    }
427}
428
429angle::Result ProgramMtl::linkImpl(const gl::Context *glContext,
430                                   const gl::ProgramLinkedResources &resources,
431                                   gl::InfoLog &infoLog)
432{
433#if ANGLE_ENABLE_METAL_SPIRV
434    ContextMtl *contextMtl = mtl::GetImpl(glContext);
435    if (contextMtl->getDisplay()->useDirectToMetalCompiler())
436    {
437        ANGLE_TRY(linkImplDirect(glContext, resources, infoLog));
438    }
439    else
440    {
441        ANGLE_TRY(linkImplSpirv(glContext, resources, infoLog));
442    }
443#else
444    ANGLE_TRY(linkImplDirect(glContext, resources, infoLog));
445#endif
446    linkUpdateHasFlatAttributes();
447    return angle::Result::Continue;
448}
449
450angle::Result ProgramMtl::linkTranslatedShaders(const gl::Context *glContext,
451                                                gl::BinaryInputStream *stream,
452                                                gl::InfoLog &infoLog)
453{
454    ContextMtl *contextMtl = mtl::GetImpl(glContext);
455    // NOTE(hqle): No transform feedbacks for now, since we only support ES 2.0 atm
456
457    reset(contextMtl);
458
459    loadTranslatedShaders(stream);
460    loadShaderInternalInfo(stream);
461    ANGLE_TRY(loadDefaultUniformBlocksInfo(glContext, stream));
462    ANGLE_TRY(createMslShaderLib(contextMtl, gl::ShaderType::Vertex, infoLog,
463                                 &mMslShaderTranslateInfo[gl::ShaderType::Vertex],
464                                 getDefaultSubstitutionDictionary()));
465    ANGLE_TRY(createMslShaderLib(contextMtl, gl::ShaderType::Fragment, infoLog,
466                                 &mMslShaderTranslateInfo[gl::ShaderType::Fragment],
467                                 getDefaultSubstitutionDictionary()));
468
469    return angle::Result::Continue;
470}
471
472mtl::BufferPool *ProgramMtl::getBufferPool(ContextMtl *context)
473{
474    if (mAuxBufferPool == nullptr)
475    {
476        mAuxBufferPool = new mtl::BufferPool(true);
477        mAuxBufferPool->initialize(context, mtl::kDefaultUniformsMaxSize * 2,
478                                   mtl::kUniformBufferSettingOffsetMinAlignment, 3);
479    }
480    return mAuxBufferPool;
481}
482void ProgramMtl::linkResources(const gl::ProgramLinkedResources &resources)
483{
484    Std140BlockLayoutEncoderFactory std140EncoderFactory;
485    gl::ProgramLinkedResourcesLinker linker(&std140EncoderFactory);
486
487    linker.linkResources(mState, resources);
488}
489
490angle::Result ProgramMtl::initDefaultUniformBlocks(const gl::Context *glContext)
491{
492    // Process vertex and fragment uniforms into std140 packing.
493    gl::ShaderMap<sh::BlockLayoutMap> layoutMap;
494    gl::ShaderMap<size_t> requiredBufferSize;
495    requiredBufferSize.fill(0);
496
497    for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes)
498    {
499        gl::Shader *shader = mState.getAttachedShader(shaderType);
500        if (shader)
501        {
502            const std::vector<sh::Uniform> &uniforms = shader->getUniforms();
503            InitDefaultUniformBlock(uniforms, shader, &layoutMap[shaderType],
504                                    &requiredBufferSize[shaderType]);
505        }
506    }
507
508    // Init the default block layout info.
509    const auto &uniforms         = mState.getUniforms();
510    const auto &uniformLocations = mState.getUniformLocations();
511    for (size_t locSlot = 0; locSlot < uniformLocations.size(); ++locSlot)
512    {
513        const gl::VariableLocation &location = uniformLocations[locSlot];
514        gl::ShaderMap<sh::BlockMemberInfo> layoutInfo;
515
516        if (location.used() && !location.ignored)
517        {
518            const gl::LinkedUniform &uniform = uniforms[location.index];
519            if (uniform.isInDefaultBlock() && !uniform.isSampler())
520            {
521                std::string uniformName = uniform.name;
522                if (uniform.isArray())
523                {
524                    // Gets the uniform name without the [0] at the end.
525                    uniformName = gl::ParseResourceName(uniformName, nullptr);
526                }
527
528                bool found = false;
529
530                for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes)
531                {
532                    auto it = layoutMap[shaderType].find(uniformName);
533                    if (it != layoutMap[shaderType].end())
534                    {
535                        found                  = true;
536                        layoutInfo[shaderType] = it->second;
537                    }
538                }
539
540                ASSERT(found);
541            }
542        }
543
544        for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes)
545        {
546            mDefaultUniformBlocks[shaderType].uniformLayout.push_back(layoutInfo[shaderType]);
547        }
548    }
549
550    return resizeDefaultUniformBlocksMemory(glContext, requiredBufferSize);
551}
552
553angle::Result ProgramMtl::resizeDefaultUniformBlocksMemory(
554    const gl::Context *glContext,
555    const gl::ShaderMap<size_t> &requiredBufferSize)
556{
557    ContextMtl *contextMtl = mtl::GetImpl(glContext);
558
559    for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes)
560    {
561        if (requiredBufferSize[shaderType] > 0)
562        {
563            ASSERT(requiredBufferSize[shaderType] <= mtl::kDefaultUniformsMaxSize);
564
565            if (!mDefaultUniformBlocks[shaderType].uniformData.resize(
566                    requiredBufferSize[shaderType]))
567            {
568                ANGLE_MTL_CHECK(contextMtl, false, GL_OUT_OF_MEMORY);
569            }
570
571            // Initialize uniform buffer memory to zero by default.
572            mDefaultUniformBlocks[shaderType].uniformData.fill(0);
573            mDefaultUniformBlocksDirty.set(shaderType);
574        }
575    }
576
577    return angle::Result::Continue;
578}
579
580angle::Result ProgramMtl::getSpecializedShader(ContextMtl *context,
581                                               gl::ShaderType shaderType,
582                                               const mtl::RenderPipelineDesc &renderPipelineDesc,
583                                               id<MTLFunction> *shaderOut)
584{
585    static_assert(YES == 1, "YES should have value of 1");
586#if ANGLE_ENABLE_METAL_SPIRV
587    const bool useSpirv = !context->getDisplay()->useDirectToMetalCompiler();
588#endif
589
590    mtl::TranslatedShaderInfo *translatedMslInfo = &mMslShaderTranslateInfo[shaderType];
591    ProgramShaderObjVariantMtl *shaderVariant;
592    mtl::AutoObjCObj<MTLFunctionConstantValues> funcConstants;
593
594    if (shaderType == gl::ShaderType::Vertex)
595    {
596        // For vertex shader, we need to create 3 variants, one with emulated rasterization
597        // discard, one with true rasterization discard and one without.
598        shaderVariant = &mVertexShaderVariants[renderPipelineDesc.rasterizationType];
599        if (shaderVariant->metalShader)
600        {
601            // Already created.
602            *shaderOut = shaderVariant->metalShader;
603            return angle::Result::Continue;
604        }
605
606        if (renderPipelineDesc.rasterizationType == mtl::RenderPipelineRasterization::Disabled)
607        {
608            // Special case: XFB output only vertex shader.
609            ASSERT(!mState.getLinkedTransformFeedbackVaryings().empty());
610            translatedMslInfo = &mMslXfbOnlyVertexShaderInfo;
611            if (!translatedMslInfo->metalLibrary)
612            {
613                // Lazily compile XFB only shader
614                gl::InfoLog infoLog;
615                ANGLE_TRY(createMslShaderLib(context, shaderType, infoLog,
616                                             &mMslXfbOnlyVertexShaderInfo,
617                                             @{@"TRANSFORM_FEEDBACK_ENABLED" : @"1"}));
618                translatedMslInfo->metalLibrary.get().label = @"TransformFeedback";
619            }
620        }
621
622        ANGLE_MTL_OBJC_SCOPE
623        {
624            BOOL emulateDiscard = renderPipelineDesc.rasterizationType ==
625                                  mtl::RenderPipelineRasterization::EmulatedDiscard;
626
627            NSString *discardEnabledStr;
628#if ANGLE_ENABLE_METAL_SPIRV
629            if (useSpirv)
630            {
631                discardEnabledStr =
632                    [NSString stringWithFormat:@"%s%s", sh::mtl::kRasterizerDiscardEnabledConstName,
633                                               kSpirvCrossSpecConstSuffix];
634            }
635            else
636#endif
637            {
638                discardEnabledStr =
639                    [NSString stringWithUTF8String:sh::mtl::kRasterizerDiscardEnabledConstName];
640            }
641
642            funcConstants = mtl::adoptObjCObj([[MTLFunctionConstantValues alloc] init]);
643            [funcConstants setConstantValue:&emulateDiscard
644                                       type:MTLDataTypeBool
645                                   withName:discardEnabledStr];
646        }
647    }  // if (shaderType == gl::ShaderType::Vertex)
648    else if (shaderType == gl::ShaderType::Fragment)
649    {
650        // For fragment shader, we need to create 2 variants, one with sample coverage mask
651        // disabled, one with the mask enabled.
652        BOOL emulateCoverageMask = renderPipelineDesc.emulateCoverageMask;
653        shaderVariant            = &mFragmentShaderVariants[emulateCoverageMask];
654        if (shaderVariant->metalShader)
655        {
656            // Already created.
657            *shaderOut = shaderVariant->metalShader;
658            return angle::Result::Continue;
659        }
660
661        ANGLE_MTL_OBJC_SCOPE
662        {
663            NSString *coverageMaskEnabledStr;
664#if ANGLE_ENABLE_METAL_SPIRV
665            if (useSpirv)
666            {
667                coverageMaskEnabledStr =
668                    [NSString stringWithFormat:@"%s%s", sh::mtl::kCoverageMaskEnabledConstName,
669                                               kSpirvCrossSpecConstSuffix];
670            }
671            else
672#endif
673            {
674                coverageMaskEnabledStr =
675                    [NSString stringWithUTF8String:sh::mtl::kCoverageMaskEnabledConstName];
676            }
677
678            NSString *depthWriteEnabledStr =
679                [NSString stringWithUTF8String:sh::mtl::kDepthWriteEnabledConstName];
680
681            funcConstants = mtl::adoptObjCObj([[MTLFunctionConstantValues alloc] init]);
682            [funcConstants setConstantValue:&emulateCoverageMask
683                                       type:MTLDataTypeBool
684                                   withName:coverageMaskEnabledStr];
685
686            MTLPixelFormat depthPixelFormat =
687                (MTLPixelFormat)renderPipelineDesc.outputDescriptor.depthAttachmentPixelFormat;
688            BOOL fragDepthWriteEnabled = depthPixelFormat != MTLPixelFormatInvalid;
689            [funcConstants setConstantValue:&fragDepthWriteEnabled
690                                       type:MTLDataTypeBool
691                                   withName:depthWriteEnabledStr];
692        }
693
694    }  // gl::ShaderType::Fragment
695    else
696    {
697        UNREACHABLE();
698        return angle::Result::Stop;
699    }
700    [funcConstants
701        setConstantValue:&(context->getDisplay()->getFeatures().allowSamplerCompareGradient.enabled)
702                    type:MTLDataTypeBool
703                withName:@"ANGLEUseSampleCompareGradient"];
704    [funcConstants
705        setConstantValue:&(context->getDisplay()->getFeatures().allowSamplerCompareLod.enabled)
706                    type:MTLDataTypeBool
707                withName:@"ANGLEUseSampleCompareLod"];
708    // Create Metal shader object
709    ANGLE_MTL_OBJC_SCOPE
710    {
711        ANGLE_TRY(CreateMslShader(context, translatedMslInfo->metalLibrary, SHADER_ENTRY_NAME,
712                                  funcConstants.get(), &shaderVariant->metalShader));
713    }
714
715    // Store reference to the translated source for easily querying mapped bindings later.
716    shaderVariant->translatedSrcInfo = translatedMslInfo;
717
718    // Initialize argument buffer encoder if required
719    if (translatedMslInfo->hasUBOArgumentBuffer)
720    {
721        InitArgumentBufferEncoder(context, shaderVariant->metalShader,
722                                  mtl::kUBOArgumentBufferBindingIndex,
723                                  &shaderVariant->uboArgBufferEncoder);
724    }
725
726    *shaderOut = shaderVariant->metalShader;
727
728    return angle::Result::Continue;
729}
730
731bool ProgramMtl::hasSpecializedShader(gl::ShaderType shaderType,
732                                      const mtl::RenderPipelineDesc &renderPipelineDesc)
733{
734    return true;
735}
736
737angle::Result ProgramMtl::createMslShaderLib(
738    ContextMtl *context,
739    gl::ShaderType shaderType,
740    gl::InfoLog &infoLog,
741    mtl::TranslatedShaderInfo *translatedMslInfo,
742    NSDictionary<NSString *, NSObject *> *substitutionMacros)
743{
744    ANGLE_MTL_OBJC_SCOPE
745    {
746        const mtl::ContextDevice &metalDevice = context->getMetalDevice();
747
748        // Convert to actual binary shader
749        mtl::AutoObjCPtr<NSError *> err = nil;
750        bool disableFastMath = (context->getDisplay()->getFeatures().intelDisableFastMath.enabled &&
751                                translatedMslInfo->hasInvariantOrAtan);
752        translatedMslInfo->metalLibrary =
753            mtl::CreateShaderLibrary(metalDevice, translatedMslInfo->metalShaderSource,
754                                     substitutionMacros, !disableFastMath, &err);
755        if (err && !translatedMslInfo->metalLibrary)
756        {
757            std::ostringstream ss;
758            ss << "Internal error compiling shader with Metal backend.\n";
759#if !defined(NDEBUG)
760            ss << err.get().localizedDescription.UTF8String << "\n";
761            ss << "-----\n";
762            ss << translatedMslInfo->metalShaderSource;
763            ss << "-----\n";
764#else
765            ss << "Please submit this shader, or website as a bug to https://bugs.webkit.org\n";
766#endif
767            ERR() << ss.str();
768
769            infoLog << ss.str();
770
771            ANGLE_MTL_CHECK(context, false, GL_INVALID_OPERATION);
772        }
773
774        return angle::Result::Continue;
775    }
776}
777
778void ProgramMtl::saveDefaultUniformBlocksInfo(gl::BinaryOutputStream *stream)
779{
780    // Serializes the uniformLayout data of mDefaultUniformBlocks
781    for (gl::ShaderType shaderType : gl::AllShaderTypes())
782    {
783        const size_t uniformCount = mDefaultUniformBlocks[shaderType].uniformLayout.size();
784        stream->writeInt<size_t>(uniformCount);
785        for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
786        {
787            sh::BlockMemberInfo &blockInfo =
788                mDefaultUniformBlocks[shaderType].uniformLayout[uniformIndex];
789            gl::WriteBlockMemberInfo(stream, blockInfo);
790        }
791    }
792
793    // Serializes required uniform block memory sizes
794    for (gl::ShaderType shaderType : gl::AllShaderTypes())
795    {
796        stream->writeInt(mDefaultUniformBlocks[shaderType].uniformData.size());
797    }
798}
799
800angle::Result ProgramMtl::loadDefaultUniformBlocksInfo(const gl::Context *glContext,
801                                                       gl::BinaryInputStream *stream)
802{
803    gl::ShaderMap<size_t> requiredBufferSize;
804    requiredBufferSize.fill(0);
805
806    // Deserializes the uniformLayout data of mDefaultUniformBlocks
807    for (gl::ShaderType shaderType : gl::AllShaderTypes())
808    {
809        const size_t uniformCount = stream->readInt<size_t>();
810        for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
811        {
812            sh::BlockMemberInfo blockInfo;
813            gl::LoadBlockMemberInfo(stream, &blockInfo);
814            mDefaultUniformBlocks[shaderType].uniformLayout.push_back(blockInfo);
815        }
816    }
817
818    // Deserializes required uniform block memory sizes
819    for (gl::ShaderType shaderType : gl::AllShaderTypes())
820    {
821        requiredBufferSize[shaderType] = stream->readInt<size_t>();
822    }
823
824    return resizeDefaultUniformBlocksMemory(glContext, requiredBufferSize);
825}
826
827void ProgramMtl::saveShaderInternalInfo(gl::BinaryOutputStream *stream)
828{
829    for (gl::ShaderType shaderType : gl::AllShaderTypes())
830    {
831        stream->writeInt<int>(mMslShaderTranslateInfo[shaderType].hasUBOArgumentBuffer);
832        for (const mtl::SamplerBinding &binding :
833             mMslShaderTranslateInfo[shaderType].actualSamplerBindings)
834        {
835            stream->writeInt<uint32_t>(binding.textureBinding);
836            stream->writeInt<uint32_t>(binding.samplerBinding);
837        }
838
839        for (uint32_t uboBinding : mMslShaderTranslateInfo[shaderType].actualUBOBindings)
840        {
841            stream->writeInt<uint32_t>(uboBinding);
842        }
843        stream->writeBool(mMslShaderTranslateInfo[shaderType].hasInvariantOrAtan);
844    }
845    for (size_t xfbBindIndex = 0; xfbBindIndex < mtl::kMaxShaderXFBs; xfbBindIndex++)
846    {
847        stream->writeInt(
848            mMslShaderTranslateInfo[gl::ShaderType::Vertex].actualXFBBindings[xfbBindIndex]);
849    }
850
851    // Write out XFB info.
852    {
853        stream->writeInt<int>(mMslXfbOnlyVertexShaderInfo.hasUBOArgumentBuffer);
854        for (mtl::SamplerBinding &binding : mMslXfbOnlyVertexShaderInfo.actualSamplerBindings)
855        {
856            stream->writeInt<uint32_t>(binding.textureBinding);
857            stream->writeInt<uint32_t>(binding.samplerBinding);
858        }
859
860        for (uint32_t &uboBinding : mMslXfbOnlyVertexShaderInfo.actualUBOBindings)
861        {
862            stream->writeInt<uint32_t>(uboBinding);
863        }
864        for (size_t xfbBindIndex = 0; xfbBindIndex < mtl::kMaxShaderXFBs; xfbBindIndex++)
865        {
866            stream->writeInt(mMslXfbOnlyVertexShaderInfo.actualXFBBindings[xfbBindIndex]);
867        }
868    }
869
870    stream->writeBool(mProgramHasFlatAttributes);
871}
872
873void ProgramMtl::loadShaderInternalInfo(gl::BinaryInputStream *stream)
874{
875    for (gl::ShaderType shaderType : gl::AllShaderTypes())
876    {
877        mMslShaderTranslateInfo[shaderType].hasUBOArgumentBuffer = stream->readInt<int>() != 0;
878        for (mtl::SamplerBinding &binding :
879             mMslShaderTranslateInfo[shaderType].actualSamplerBindings)
880        {
881            binding.textureBinding = stream->readInt<uint32_t>();
882            binding.samplerBinding = stream->readInt<uint32_t>();
883        }
884
885        for (uint32_t &uboBinding : mMslShaderTranslateInfo[shaderType].actualUBOBindings)
886        {
887            uboBinding = stream->readInt<uint32_t>();
888        }
889        mMslShaderTranslateInfo[shaderType].hasInvariantOrAtan = stream->readBool();
890    }
891
892    for (size_t xfbBindIndex = 0; xfbBindIndex < mtl::kMaxShaderXFBs; xfbBindIndex++)
893    {
894        stream->readInt(
895            &mMslShaderTranslateInfo[gl::ShaderType::Vertex].actualXFBBindings[xfbBindIndex]);
896    }
897    // Load Transform Feedback info
898    {
899        mMslXfbOnlyVertexShaderInfo.hasUBOArgumentBuffer = stream->readInt<int>() != 0;
900        for (mtl::SamplerBinding &binding : mMslXfbOnlyVertexShaderInfo.actualSamplerBindings)
901        {
902            binding.textureBinding = stream->readInt<uint32_t>();
903            binding.samplerBinding = stream->readInt<uint32_t>();
904        }
905
906        for (uint32_t &uboBinding : mMslXfbOnlyVertexShaderInfo.actualUBOBindings)
907        {
908            uboBinding = stream->readInt<uint32_t>();
909        }
910        for (size_t xfbBindIndex = 0; xfbBindIndex < mtl::kMaxShaderXFBs; xfbBindIndex++)
911        {
912            stream->readInt(&mMslXfbOnlyVertexShaderInfo.actualXFBBindings[xfbBindIndex]);
913        }
914        mMslXfbOnlyVertexShaderInfo.metalLibrary = nullptr;
915    }
916
917    mProgramHasFlatAttributes = stream->readBool();
918}
919
920GLboolean ProgramMtl::validate(const gl::Caps &caps, gl::InfoLog *infoLog)
921{
922    // No-op. The spec is very vague about the behavior of validation.
923    return GL_TRUE;
924}
925
926template <typename T>
927void ProgramMtl::setUniformImpl(GLint location, GLsizei count, const T *v, GLenum entryPointType)
928{
929    const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location];
930    const gl::LinkedUniform &linkedUniform   = mState.getUniforms()[locationInfo.index];
931
932    if (linkedUniform.isSampler())
933    {
934        // Sampler binding has changed.
935        mSamplerBindingsDirty.set();
936        return;
937    }
938
939    if (linkedUniform.typeInfo->type == entryPointType)
940    {
941        for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes)
942        {
943            DefaultUniformBlock &uniformBlock     = mDefaultUniformBlocks[shaderType];
944            const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
945
946            // Assume an offset of -1 means the block is unused.
947            if (layoutInfo.offset == -1)
948            {
949                continue;
950            }
951
952            const GLint componentCount = linkedUniform.typeInfo->componentCount;
953            UpdateDefaultUniformBlock(count, locationInfo.arrayIndex, componentCount, v, layoutInfo,
954                                      &uniformBlock.uniformData);
955            mDefaultUniformBlocksDirty.set(shaderType);
956        }
957    }
958    else
959    {
960        for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes)
961        {
962            DefaultUniformBlock &uniformBlock     = mDefaultUniformBlocks[shaderType];
963            const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
964
965            // Assume an offset of -1 means the block is unused.
966            if (layoutInfo.offset == -1)
967            {
968                continue;
969            }
970
971            const GLint componentCount = linkedUniform.typeInfo->componentCount;
972
973            ASSERT(linkedUniform.typeInfo->type == gl::VariableBoolVectorType(entryPointType));
974
975            GLint initialArrayOffset =
976                locationInfo.arrayIndex * layoutInfo.arrayStride + layoutInfo.offset;
977            for (GLint i = 0; i < count; i++)
978            {
979                GLint elementOffset = i * layoutInfo.arrayStride + initialArrayOffset;
980                GLint *dest =
981                    reinterpret_cast<GLint *>(uniformBlock.uniformData.data() + elementOffset);
982                const T *source = v + i * componentCount;
983
984                for (int c = 0; c < componentCount; c++)
985                {
986                    dest[c] = (source[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE;
987                }
988            }
989
990            mDefaultUniformBlocksDirty.set(shaderType);
991        }
992    }
993}
994
995template <typename T>
996void ProgramMtl::getUniformImpl(GLint location, T *v, GLenum entryPointType) const
997{
998    const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location];
999    const gl::LinkedUniform &linkedUniform   = mState.getUniforms()[locationInfo.index];
1000
1001    ASSERT(!linkedUniform.isSampler());
1002
1003    const gl::ShaderType shaderType = linkedUniform.getFirstShaderTypeWhereActive();
1004    ASSERT(shaderType != gl::ShaderType::InvalidEnum);
1005
1006    const DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType];
1007    const sh::BlockMemberInfo &layoutInfo   = uniformBlock.uniformLayout[location];
1008
1009    ASSERT(linkedUniform.typeInfo->componentType == entryPointType ||
1010           linkedUniform.typeInfo->componentType == gl::VariableBoolVectorType(entryPointType));
1011
1012    if (gl::IsMatrixType(linkedUniform.type))
1013    {
1014        const uint8_t *ptrToElement = uniformBlock.uniformData.data() + layoutInfo.offset +
1015                                      (locationInfo.arrayIndex * layoutInfo.arrayStride);
1016        GetMatrixUniform(linkedUniform.type, v, reinterpret_cast<const T *>(ptrToElement), false);
1017    }
1018    else
1019    {
1020        ReadFromDefaultUniformBlock(linkedUniform.typeInfo->componentCount, locationInfo.arrayIndex,
1021                                    v, layoutInfo, &uniformBlock.uniformData);
1022    }
1023}
1024
1025void ProgramMtl::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1026{
1027    setUniformImpl(location, count, v, GL_FLOAT);
1028}
1029
1030void ProgramMtl::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1031{
1032    setUniformImpl(location, count, v, GL_FLOAT_VEC2);
1033}
1034
1035void ProgramMtl::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1036{
1037    setUniformImpl(location, count, v, GL_FLOAT_VEC3);
1038}
1039
1040void ProgramMtl::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1041{
1042    setUniformImpl(location, count, v, GL_FLOAT_VEC4);
1043}
1044
1045void ProgramMtl::setUniform1iv(GLint startLocation, GLsizei count, const GLint *v)
1046{
1047    setUniformImpl(startLocation, count, v, GL_INT);
1048}
1049
1050void ProgramMtl::setUniform2iv(GLint location, GLsizei count, const GLint *v)
1051{
1052    setUniformImpl(location, count, v, GL_INT_VEC2);
1053}
1054
1055void ProgramMtl::setUniform3iv(GLint location, GLsizei count, const GLint *v)
1056{
1057    setUniformImpl(location, count, v, GL_INT_VEC3);
1058}
1059
1060void ProgramMtl::setUniform4iv(GLint location, GLsizei count, const GLint *v)
1061{
1062    setUniformImpl(location, count, v, GL_INT_VEC4);
1063}
1064
1065void ProgramMtl::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
1066{
1067    setUniformImpl(location, count, v, GL_UNSIGNED_INT);
1068}
1069
1070void ProgramMtl::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
1071{
1072    setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC2);
1073}
1074
1075void ProgramMtl::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
1076{
1077    setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC3);
1078}
1079
1080void ProgramMtl::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
1081{
1082    setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC4);
1083}
1084
1085template <int cols, int rows>
1086void ProgramMtl::setUniformMatrixfv(GLint location,
1087                                    GLsizei count,
1088                                    GLboolean transpose,
1089                                    const GLfloat *value)
1090{
1091    const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location];
1092    const gl::LinkedUniform &linkedUniform   = mState.getUniforms()[locationInfo.index];
1093
1094    for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes)
1095    {
1096        DefaultUniformBlock &uniformBlock     = mDefaultUniformBlocks[shaderType];
1097        const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
1098
1099        // Assume an offset of -1 means the block is unused.
1100        if (layoutInfo.offset == -1)
1101        {
1102            continue;
1103        }
1104
1105        SetFloatUniformMatrixGLSL<cols, rows>::Run(
1106            locationInfo.arrayIndex, linkedUniform.getArraySizeProduct(), count, transpose, value,
1107            uniformBlock.uniformData.data() + layoutInfo.offset);
1108
1109        mDefaultUniformBlocksDirty.set(shaderType);
1110    }
1111}
1112
1113void ProgramMtl::setUniformMatrix2fv(GLint location,
1114                                     GLsizei count,
1115                                     GLboolean transpose,
1116                                     const GLfloat *value)
1117{
1118    setUniformMatrixfv<2, 2>(location, count, transpose, value);
1119}
1120
1121void ProgramMtl::setUniformMatrix3fv(GLint location,
1122                                     GLsizei count,
1123                                     GLboolean transpose,
1124                                     const GLfloat *value)
1125{
1126    setUniformMatrixfv<3, 3>(location, count, transpose, value);
1127}
1128
1129void ProgramMtl::setUniformMatrix4fv(GLint location,
1130                                     GLsizei count,
1131                                     GLboolean transpose,
1132                                     const GLfloat *value)
1133{
1134    setUniformMatrixfv<4, 4>(location, count, transpose, value);
1135}
1136
1137void ProgramMtl::setUniformMatrix2x3fv(GLint location,
1138                                       GLsizei count,
1139                                       GLboolean transpose,
1140                                       const GLfloat *value)
1141{
1142    setUniformMatrixfv<2, 3>(location, count, transpose, value);
1143}
1144
1145void ProgramMtl::setUniformMatrix3x2fv(GLint location,
1146                                       GLsizei count,
1147                                       GLboolean transpose,
1148                                       const GLfloat *value)
1149{
1150    setUniformMatrixfv<3, 2>(location, count, transpose, value);
1151}
1152
1153void ProgramMtl::setUniformMatrix2x4fv(GLint location,
1154                                       GLsizei count,
1155                                       GLboolean transpose,
1156                                       const GLfloat *value)
1157{
1158    setUniformMatrixfv<2, 4>(location, count, transpose, value);
1159}
1160
1161void ProgramMtl::setUniformMatrix4x2fv(GLint location,
1162                                       GLsizei count,
1163                                       GLboolean transpose,
1164                                       const GLfloat *value)
1165{
1166    setUniformMatrixfv<4, 2>(location, count, transpose, value);
1167}
1168
1169void ProgramMtl::setUniformMatrix3x4fv(GLint location,
1170                                       GLsizei count,
1171                                       GLboolean transpose,
1172                                       const GLfloat *value)
1173{
1174    setUniformMatrixfv<3, 4>(location, count, transpose, value);
1175}
1176
1177void ProgramMtl::setUniformMatrix4x3fv(GLint location,
1178                                       GLsizei count,
1179                                       GLboolean transpose,
1180                                       const GLfloat *value)
1181{
1182    setUniformMatrixfv<4, 3>(location, count, transpose, value);
1183}
1184
1185void ProgramMtl::getUniformfv(const gl::Context *context, GLint location, GLfloat *params) const
1186{
1187    getUniformImpl(location, params, GL_FLOAT);
1188}
1189
1190void ProgramMtl::getUniformiv(const gl::Context *context, GLint location, GLint *params) const
1191{
1192    getUniformImpl(location, params, GL_INT);
1193}
1194
1195void ProgramMtl::getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const
1196{
1197    getUniformImpl(location, params, GL_UNSIGNED_INT);
1198}
1199
1200angle::Result ProgramMtl::setupDraw(const gl::Context *glContext,
1201                                    mtl::RenderCommandEncoder *cmdEncoder,
1202                                    const mtl::RenderPipelineDesc &pipelineDesc,
1203                                    bool pipelineDescChanged,
1204                                    bool forceTexturesSetting,
1205                                    bool uniformBuffersDirty)
1206{
1207    ContextMtl *context = mtl::GetImpl(glContext);
1208    if (pipelineDescChanged)
1209    {
1210        // Render pipeline state needs to be changed
1211        id<MTLRenderPipelineState> pipelineState =
1212            mMetalRenderPipelineCache.getRenderPipelineState(context, pipelineDesc);
1213        if (!pipelineState)
1214        {
1215            // Error already logged inside getRenderPipelineState()
1216            return angle::Result::Stop;
1217        }
1218        cmdEncoder->setRenderPipelineState(pipelineState);
1219
1220        // We need to rebind uniform buffers & textures also
1221        mDefaultUniformBlocksDirty.set();
1222        mSamplerBindingsDirty.set();
1223
1224        // Cache current shader variant references for easier querying.
1225        mCurrentShaderVariants[gl::ShaderType::Vertex] =
1226            &mVertexShaderVariants[pipelineDesc.rasterizationType];
1227        mCurrentShaderVariants[gl::ShaderType::Fragment] =
1228            pipelineDesc.rasterizationEnabled()
1229                ? &mFragmentShaderVariants[pipelineDesc.emulateCoverageMask]
1230                : nullptr;
1231    }
1232
1233    ANGLE_TRY(commitUniforms(context, cmdEncoder));
1234    ANGLE_TRY(updateTextures(glContext, cmdEncoder, forceTexturesSetting));
1235
1236    if (uniformBuffersDirty || pipelineDescChanged)
1237    {
1238        ANGLE_TRY(updateUniformBuffers(context, cmdEncoder, pipelineDesc));
1239    }
1240
1241    if (pipelineDescChanged)
1242    {
1243        ANGLE_TRY(updateXfbBuffers(context, cmdEncoder, pipelineDesc));
1244    }
1245
1246    return angle::Result::Continue;
1247}
1248
1249angle::Result ProgramMtl::commitUniforms(ContextMtl *context, mtl::RenderCommandEncoder *cmdEncoder)
1250{
1251    for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes)
1252    {
1253        if (!mDefaultUniformBlocksDirty[shaderType] || !mCurrentShaderVariants[shaderType])
1254        {
1255            continue;
1256        }
1257        DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType];
1258
1259        if (!uniformBlock.uniformData.size())
1260        {
1261            continue;
1262        }
1263        // If we exceed the default uniform max size, try to allocate a buffer. Worst case
1264        // scenario, fall back on a large setBytes.
1265        bool needsCommitUniform = true;
1266        if (needsCommitUniform)
1267        {
1268            ASSERT(uniformBlock.uniformData.size() <= mtl::kDefaultUniformsMaxSize);
1269            cmdEncoder->setBytes(shaderType, uniformBlock.uniformData.data(),
1270                                 uniformBlock.uniformData.size(),
1271                                 mtl::kDefaultUniformsBindingIndex);
1272        }
1273
1274        mDefaultUniformBlocksDirty.reset(shaderType);
1275    }
1276
1277    return angle::Result::Continue;
1278}
1279
1280angle::Result ProgramMtl::updateTextures(const gl::Context *glContext,
1281                                         mtl::RenderCommandEncoder *cmdEncoder,
1282                                         bool forceUpdate)
1283{
1284    ContextMtl *contextMtl                          = mtl::GetImpl(glContext);
1285    const auto &glState                             = glContext->getState();
1286    const gl::ActiveTexturesCache &completeTextures = glState.getActiveTexturesCache();
1287
1288    for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes)
1289    {
1290        if ((!mSamplerBindingsDirty[shaderType] && !forceUpdate) ||
1291            !mCurrentShaderVariants[shaderType])
1292        {
1293            continue;
1294        }
1295
1296        const mtl::TranslatedShaderInfo &shaderInfo =
1297            mCurrentShaderVariants[shaderType]->translatedSrcInfo
1298                ? *mCurrentShaderVariants[shaderType]->translatedSrcInfo
1299                : mMslShaderTranslateInfo[shaderType];
1300        bool hasDepthSampler = false;
1301
1302        for (uint32_t textureIndex = 0; textureIndex < mState.getSamplerBindings().size();
1303             ++textureIndex)
1304        {
1305            const gl::SamplerBinding &samplerBinding = mState.getSamplerBindings()[textureIndex];
1306            const mtl::SamplerBinding &mslBinding = shaderInfo.actualSamplerBindings[textureIndex];
1307            if (mslBinding.textureBinding >= mtl::kMaxShaderSamplers)
1308            {
1309                // No binding assigned
1310                continue;
1311            }
1312
1313            gl::TextureType textureType = samplerBinding.textureType;
1314
1315            for (uint32_t arrayElement = 0; arrayElement < samplerBinding.boundTextureUnits.size();
1316                 ++arrayElement)
1317            {
1318                GLuint textureUnit   = samplerBinding.boundTextureUnits[arrayElement];
1319                gl::Texture *texture = completeTextures[textureUnit];
1320                gl::Sampler *sampler = contextMtl->getState().getSampler(textureUnit);
1321                uint32_t textureSlot = mslBinding.textureBinding + arrayElement;
1322                uint32_t samplerSlot = mslBinding.samplerBinding + arrayElement;
1323                if (!texture)
1324                {
1325                    ANGLE_TRY(contextMtl->getIncompleteTexture(glContext, textureType, &texture));
1326                }
1327                const gl::SamplerState *samplerState =
1328                    sampler ? &sampler->getSamplerState() : &texture->getSamplerState();
1329                TextureMtl *textureMtl = mtl::GetImpl(texture);
1330                if (samplerBinding.format == gl::SamplerFormat::Shadow)
1331                {
1332                    hasDepthSampler                  = true;
1333                    mShadowCompareModes[textureSlot] = mtl::MslGetShaderShadowCompareMode(
1334                        samplerState->getCompareMode(), samplerState->getCompareFunc());
1335                }
1336                ANGLE_TRY(textureMtl->bindToShader(glContext, cmdEncoder, shaderType, sampler,
1337                                                   textureSlot, samplerSlot));
1338            }  // for array elements
1339        }      // for sampler bindings
1340
1341        if (hasDepthSampler)
1342        {
1343            cmdEncoder->setData(shaderType, mShadowCompareModes,
1344                                mtl::kShadowSamplerCompareModesBindingIndex);
1345        }
1346    }  // for shader types
1347
1348    return angle::Result::Continue;
1349}
1350
1351angle::Result ProgramMtl::updateUniformBuffers(ContextMtl *context,
1352                                               mtl::RenderCommandEncoder *cmdEncoder,
1353                                               const mtl::RenderPipelineDesc &pipelineDesc)
1354{
1355    const std::vector<gl::InterfaceBlock> &blocks = mState.getUniformBlocks();
1356    if (blocks.empty())
1357    {
1358        return angle::Result::Continue;
1359    }
1360
1361    // This array is only used inside this function and its callees.
1362    ScopedAutoClearVector<uint32_t> scopeArrayClear(&mArgumentBufferRenderStageUsages);
1363    ScopedAutoClearVector<std::pair<mtl::BufferRef, uint32_t>> scopeArrayClear2(
1364        &mLegalizedOffsetedUniformBuffers);
1365    mArgumentBufferRenderStageUsages.resize(blocks.size());
1366    mLegalizedOffsetedUniformBuffers.resize(blocks.size());
1367
1368    ANGLE_TRY(legalizeUniformBufferOffsets(context, blocks));
1369
1370    const gl::State &glState = context->getState();
1371
1372    for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes)
1373    {
1374        if (!mCurrentShaderVariants[shaderType])
1375        {
1376            continue;
1377        }
1378
1379        if (mCurrentShaderVariants[shaderType]->translatedSrcInfo->hasUBOArgumentBuffer)
1380        {
1381            ANGLE_TRY(
1382                encodeUniformBuffersInfoArgumentBuffer(context, cmdEncoder, blocks, shaderType));
1383        }
1384        else
1385        {
1386            ANGLE_TRY(bindUniformBuffersToDiscreteSlots(context, cmdEncoder, blocks, shaderType));
1387        }
1388    }  // for shader types
1389
1390    // After encode the uniform buffers into an argument buffer, we need to tell Metal that
1391    // the buffers are being used by what shader stages.
1392    for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex)
1393    {
1394        const gl::InterfaceBlock &block = blocks[bufferIndex];
1395        const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
1396            glState.getIndexedUniformBuffer(block.binding);
1397        if (bufferBinding.get() == nullptr)
1398        {
1399            continue;
1400        }
1401
1402        // Remove any other stages other than vertex and fragment.
1403        uint32_t stages = mArgumentBufferRenderStageUsages[bufferIndex] &
1404                          (mtl::kRenderStageVertex | mtl::kRenderStageFragment);
1405
1406        if (stages == 0)
1407        {
1408            continue;
1409        }
1410
1411        cmdEncoder->useResource(mLegalizedOffsetedUniformBuffers[bufferIndex].first,
1412                                MTLResourceUsageRead, static_cast<mtl::RenderStages>(stages));
1413    }
1414
1415    return angle::Result::Continue;
1416}
1417
1418angle::Result ProgramMtl::legalizeUniformBufferOffsets(
1419    ContextMtl *context,
1420    const std::vector<gl::InterfaceBlock> &blocks)
1421{
1422    const gl::State &glState = context->getState();
1423
1424    for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex)
1425    {
1426        const gl::InterfaceBlock &block = blocks[bufferIndex];
1427        const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
1428            glState.getIndexedUniformBuffer(block.binding);
1429
1430        if (bufferBinding.get() == nullptr)
1431        {
1432            continue;
1433        }
1434
1435        BufferMtl *bufferMtl = mtl::GetImpl(bufferBinding.get());
1436        size_t srcOffset     = std::min<size_t>(bufferBinding.getOffset(), bufferMtl->size());
1437        size_t offsetModulo  = srcOffset % mtl::kUniformBufferSettingOffsetMinAlignment;
1438        if (offsetModulo)
1439        {
1440            ConversionBufferMtl *conversion =
1441                bufferMtl->getUniformConversionBuffer(context, offsetModulo);
1442            // Has the content of the buffer has changed since last conversion?
1443            if (conversion->dirty)
1444            {
1445                const uint8_t *srcBytes = bufferMtl->getClientShadowCopyData(context);
1446                srcBytes += offsetModulo;
1447                size_t sizeToCopy      = bufferMtl->size() - offsetModulo;
1448                size_t bytesToAllocate = roundUp<size_t>(sizeToCopy, 16u);
1449                ANGLE_TRY(StreamUniformBufferData(
1450                    context, &conversion->data, srcBytes, bytesToAllocate, sizeToCopy,
1451                    &conversion->convertedBuffer, &conversion->convertedOffset));
1452#ifndef NDEBUG
1453                ANGLE_MTL_OBJC_SCOPE
1454                {
1455                    conversion->convertedBuffer->get().label = [NSString
1456                        stringWithFormat:@"Converted from %p offset=%zu", bufferMtl, offsetModulo];
1457                }
1458#endif
1459                conversion->dirty = false;
1460            }
1461            // reuse the converted buffer
1462            mLegalizedOffsetedUniformBuffers[bufferIndex].first = conversion->convertedBuffer;
1463            mLegalizedOffsetedUniformBuffers[bufferIndex].second =
1464                static_cast<uint32_t>(conversion->convertedOffset + srcOffset - offsetModulo);
1465        }
1466        else
1467        {
1468            mLegalizedOffsetedUniformBuffers[bufferIndex].first = bufferMtl->getCurrentBuffer();
1469            mLegalizedOffsetedUniformBuffers[bufferIndex].second =
1470                static_cast<uint32_t>(bufferBinding.getOffset());
1471        }
1472    }
1473    return angle::Result::Continue;
1474}
1475
1476angle::Result ProgramMtl::bindUniformBuffersToDiscreteSlots(
1477    ContextMtl *context,
1478    mtl::RenderCommandEncoder *cmdEncoder,
1479    const std::vector<gl::InterfaceBlock> &blocks,
1480    gl::ShaderType shaderType)
1481{
1482    const gl::State &glState = context->getState();
1483    const mtl::TranslatedShaderInfo &shaderInfo =
1484        *mCurrentShaderVariants[shaderType]->translatedSrcInfo;
1485    for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex)
1486    {
1487        const gl::InterfaceBlock &block = blocks[bufferIndex];
1488        const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
1489            glState.getIndexedUniformBuffer(block.binding);
1490
1491        if (bufferBinding.get() == nullptr || !block.activeShaders().test(shaderType))
1492        {
1493            continue;
1494        }
1495
1496        uint32_t actualBufferIdx = shaderInfo.actualUBOBindings[bufferIndex];
1497
1498        if (actualBufferIdx >= mtl::kMaxShaderBuffers)
1499        {
1500            continue;
1501        }
1502
1503        mtl::BufferRef mtlBuffer = mLegalizedOffsetedUniformBuffers[bufferIndex].first;
1504        uint32_t offset          = mLegalizedOffsetedUniformBuffers[bufferIndex].second;
1505        cmdEncoder->setBuffer(shaderType, mtlBuffer, offset, actualBufferIdx);
1506    }
1507    return angle::Result::Continue;
1508}
1509angle::Result ProgramMtl::encodeUniformBuffersInfoArgumentBuffer(
1510    ContextMtl *context,
1511    mtl::RenderCommandEncoder *cmdEncoder,
1512    const std::vector<gl::InterfaceBlock> &blocks,
1513    gl::ShaderType shaderType)
1514{
1515    const gl::State &glState = context->getState();
1516    ASSERT(mCurrentShaderVariants[shaderType]->translatedSrcInfo);
1517    const mtl::TranslatedShaderInfo &shaderInfo =
1518        *mCurrentShaderVariants[shaderType]->translatedSrcInfo;
1519
1520    // Encode all uniform buffers into an argument buffer.
1521    ProgramArgumentBufferEncoderMtl &bufferEncoder =
1522        mCurrentShaderVariants[shaderType]->uboArgBufferEncoder;
1523
1524    mtl::BufferRef argumentBuffer;
1525    size_t argumentBufferOffset;
1526    bufferEncoder.bufferPool.releaseInFlightBuffers(context);
1527    ANGLE_TRY(bufferEncoder.bufferPool.allocate(
1528        context, bufferEncoder.metalArgBufferEncoder.get().encodedLength, nullptr, &argumentBuffer,
1529        &argumentBufferOffset));
1530
1531    [bufferEncoder.metalArgBufferEncoder setArgumentBuffer:argumentBuffer->get()
1532                                                    offset:argumentBufferOffset];
1533
1534    constexpr gl::ShaderMap<MTLRenderStages> kShaderStageMap = {
1535        {gl::ShaderType::Vertex, mtl::kRenderStageVertex},
1536        {gl::ShaderType::Fragment, mtl::kRenderStageFragment},
1537    };
1538
1539    auto mtlRenderStage = kShaderStageMap[shaderType];
1540
1541    for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex)
1542    {
1543        const gl::InterfaceBlock &block = blocks[bufferIndex];
1544        const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
1545            glState.getIndexedUniformBuffer(block.binding);
1546
1547        if (bufferBinding.get() == nullptr || !block.activeShaders().test(shaderType))
1548        {
1549            continue;
1550        }
1551
1552        mArgumentBufferRenderStageUsages[bufferIndex] |= mtlRenderStage;
1553
1554        uint32_t actualBufferIdx = shaderInfo.actualUBOBindings[bufferIndex];
1555        if (actualBufferIdx >= mtl::kMaxShaderBuffers)
1556        {
1557            continue;
1558        }
1559
1560        mtl::BufferRef mtlBuffer = mLegalizedOffsetedUniformBuffers[bufferIndex].first;
1561        uint32_t offset          = mLegalizedOffsetedUniformBuffers[bufferIndex].second;
1562        [bufferEncoder.metalArgBufferEncoder setBuffer:mtlBuffer->get()
1563                                                offset:offset
1564                                               atIndex:actualBufferIdx];
1565    }
1566
1567    ANGLE_TRY(bufferEncoder.bufferPool.commit(context));
1568
1569    cmdEncoder->setBuffer(shaderType, argumentBuffer, static_cast<uint32_t>(argumentBufferOffset),
1570                          mtl::kUBOArgumentBufferBindingIndex);
1571    return angle::Result::Continue;
1572}
1573
1574angle::Result ProgramMtl::updateXfbBuffers(ContextMtl *context,
1575                                           mtl::RenderCommandEncoder *cmdEncoder,
1576                                           const mtl::RenderPipelineDesc &pipelineDesc)
1577{
1578    const gl::State &glState                 = context->getState();
1579    gl::TransformFeedback *transformFeedback = glState.getCurrentTransformFeedback();
1580
1581    if (pipelineDesc.rasterizationEnabled() || !glState.isTransformFeedbackActiveUnpaused() ||
1582        ANGLE_UNLIKELY(!transformFeedback))
1583    {
1584        // XFB output can only be used with rasterization disabled.
1585        return angle::Result::Continue;
1586    }
1587
1588    size_t xfbBufferCount = glState.getProgramExecutable()->getTransformFeedbackBufferCount();
1589
1590    ASSERT(xfbBufferCount > 0);
1591    ASSERT(mState.getTransformFeedbackBufferMode() != GL_INTERLEAVED_ATTRIBS ||
1592           xfbBufferCount == 1);
1593
1594    for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
1595    {
1596        uint32_t actualBufferIdx = mMslXfbOnlyVertexShaderInfo.actualXFBBindings[bufferIndex];
1597
1598        if (actualBufferIdx >= mtl::kMaxShaderBuffers)
1599        {
1600            continue;
1601        }
1602
1603        const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
1604            transformFeedback->getIndexedBuffer(bufferIndex);
1605        gl::Buffer *buffer = bufferBinding.get();
1606        ASSERT((bufferBinding.getOffset() % 4) == 0);
1607        ASSERT(buffer != nullptr);
1608
1609        BufferMtl *bufferMtl = mtl::GetImpl(buffer);
1610
1611        // Use offset=0, actual offset will be set in Driver Uniform inside ContextMtl.
1612        cmdEncoder->setBufferForWrite(gl::ShaderType::Vertex, bufferMtl->getCurrentBuffer(), 0,
1613                                      actualBufferIdx);
1614    }
1615
1616    return angle::Result::Continue;
1617}
1618
1619}  // namespace rx
1620