xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/metal/ProgramExecutableMtl.mm (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1//
2// Copyright 2023 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// ProgramExecutableMtl.cpp: Implementation of ProgramExecutableMtl.
7
8#include "libANGLE/renderer/metal/ProgramExecutableMtl.h"
9
10#include "libANGLE/renderer/metal/BufferMtl.h"
11#include "libANGLE/renderer/metal/ContextMtl.h"
12#include "libANGLE/renderer/metal/TextureMtl.h"
13#include "libANGLE/renderer/metal/blocklayoutMetal.h"
14#include "libANGLE/renderer/metal/renderermtl_utils.h"
15
16namespace rx
17{
18namespace
19{
20#define SHADER_ENTRY_NAME @"main0"
21
22bool CompareBlockInfo(const sh::BlockMemberInfo &a, const sh::BlockMemberInfo &b)
23{
24    return a.offset < b.offset;
25}
26
27size_t GetAlignmentOfUniformGroup(sh::BlockLayoutMap *blockLayoutMap)
28{
29    size_t align = 1;
30    for (auto layoutIter = blockLayoutMap->begin(); layoutIter != blockLayoutMap->end();
31         ++layoutIter)
32    {
33        align = std::max(mtl::GetMetalAlignmentForGLType(layoutIter->second.type), align);
34    }
35    return align;
36}
37
38void InitDefaultUniformBlock(const std::vector<sh::Uniform> &uniforms,
39                             sh::BlockLayoutMap *blockLayoutMapOut,
40                             size_t *blockSizeOut)
41{
42    if (uniforms.empty())
43    {
44        *blockSizeOut = 0;
45        return;
46    }
47
48    mtl::BlockLayoutEncoderMTL blockEncoder;
49    sh::GetActiveUniformBlockInfo(uniforms, "", &blockEncoder, blockLayoutMapOut);
50    size_t blockAlign = GetAlignmentOfUniformGroup(blockLayoutMapOut);
51    size_t blockSize  = roundUp(blockEncoder.getCurrentOffset(), blockAlign);
52
53    // TODO(jmadill): I think we still need a valid block for the pipeline even if zero sized.
54    if (blockSize == 0)
55    {
56        *blockSizeOut = 0;
57        return;
58    }
59
60    *blockSizeOut = blockSize;
61    return;
62}
63
64template <typename T>
65class [[nodiscard]] ScopedAutoClearVector
66{
67  public:
68    ScopedAutoClearVector(std::vector<T> *array) : mArray(*array) {}
69    ~ScopedAutoClearVector() { mArray.clear(); }
70
71  private:
72    std::vector<T> &mArray;
73};
74
75inline void memcpy_guarded(void *dst, const void *src, const void *maxSrcPtr, size_t size)
76{
77    size_t bytesAvailable = maxSrcPtr > src ? (const uint8_t *)maxSrcPtr - (const uint8_t *)src : 0;
78    size_t bytesToCopy    = std::min(size, bytesAvailable);
79    size_t bytesToZero    = size - bytesToCopy;
80
81    if (bytesToCopy)
82        memcpy(dst, src, bytesToCopy);
83    if (bytesToZero)
84        memset((uint8_t *)dst + bytesToCopy, 0, bytesToZero);
85}
86
87// Copy matrix one column at a time
88inline void copy_matrix(void *dst,
89                        const void *src,
90                        const void *maxSrcPtr,
91                        size_t srcStride,
92                        size_t dstStride,
93                        GLenum type)
94{
95    size_t elemSize      = mtl::GetMetalSizeForGLType(gl::VariableComponentType(type));
96    const size_t dstRows = gl::VariableRowCount(type);
97    const size_t dstCols = gl::VariableColumnCount(type);
98
99    for (size_t col = 0; col < dstCols; col++)
100    {
101        size_t srcOffset = col * srcStride;
102        memcpy_guarded(((uint8_t *)dst) + dstStride * col, (const uint8_t *)src + srcOffset,
103                       maxSrcPtr, elemSize * dstRows);
104    }
105}
106
107// Copy matrix one element at a time to transpose.
108inline void copy_matrix_row_major(void *dst,
109                                  const void *src,
110                                  const void *maxSrcPtr,
111                                  size_t srcStride,
112                                  size_t dstStride,
113                                  GLenum type)
114{
115    size_t elemSize      = mtl::GetMetalSizeForGLType(gl::VariableComponentType(type));
116    const size_t dstRows = gl::VariableRowCount(type);
117    const size_t dstCols = gl::VariableColumnCount(type);
118
119    for (size_t col = 0; col < dstCols; col++)
120    {
121        for (size_t row = 0; row < dstRows; row++)
122        {
123            size_t srcOffset = row * srcStride + col * elemSize;
124            memcpy_guarded((uint8_t *)dst + dstStride * col + row * elemSize,
125                           (const uint8_t *)src + srcOffset, maxSrcPtr, elemSize);
126        }
127    }
128}
129// TODO(angleproject:7979) Upgrade ANGLE Uniform buffer remapper to compute shaders
130angle::Result ConvertUniformBufferData(ContextMtl *contextMtl,
131                                       const UBOConversionInfo &blockConversionInfo,
132                                       mtl::BufferPool *dynamicBuffer,
133                                       const uint8_t *sourceData,
134                                       size_t sizeToCopy,
135                                       mtl::BufferRef *bufferOut,
136                                       size_t *bufferOffsetOut)
137{
138    uint8_t *dst             = nullptr;
139    const uint8_t *maxSrcPtr = sourceData + sizeToCopy;
140    dynamicBuffer->releaseInFlightBuffers(contextMtl);
141
142    // When converting a UBO buffer, we convert all of the data
143    // supplied in a buffer at once (sizeToCopy = bufferMtl->size() - initial offset).
144    // It's possible that a buffer could represent multiple instances of
145    // a uniform block, so we loop over the number of block conversions we intend
146    // to do.
147    size_t numBlocksToCopy =
148        (sizeToCopy + blockConversionInfo.stdSize() - 1) / blockConversionInfo.stdSize();
149    size_t bytesToAllocate = numBlocksToCopy * blockConversionInfo.metalSize();
150    ANGLE_TRY(dynamicBuffer->allocate(contextMtl, bytesToAllocate, &dst, bufferOut, bufferOffsetOut,
151                                      nullptr));
152
153    const std::vector<sh::BlockMemberInfo> &stdConversions = blockConversionInfo.stdInfo();
154    const std::vector<sh::BlockMemberInfo> &mtlConversions = blockConversionInfo.metalInfo();
155    for (size_t i = 0; i < numBlocksToCopy; ++i)
156    {
157        auto stdIterator = stdConversions.begin();
158        auto mtlIterator = mtlConversions.begin();
159
160        while (stdIterator != stdConversions.end())
161        {
162            for (int arraySize = 0; arraySize < stdIterator->arraySize; ++arraySize)
163            {
164                // For every entry in an array, calculate the offset based off of the
165                // array element size.
166
167                // Offset of a single entry is
168                // blockIndex*blockSize + arrayOffset*arraySize + offset of field in base struct.
169                // Fields are copied per block, per member, per array entry of member.
170
171                size_t stdArrayOffset = stdIterator->arrayStride * arraySize;
172                size_t mtlArrayOffset = mtlIterator->arrayStride * arraySize;
173
174                if (gl::IsMatrixType(mtlIterator->type))
175                {
176
177                    void *dstMat = dst + mtlIterator->offset + mtlArrayOffset +
178                                   blockConversionInfo.metalSize() * i;
179                    const void *srcMat = sourceData + stdIterator->offset + stdArrayOffset +
180                                         blockConversionInfo.stdSize() * i;
181                    // Transpose matricies into column major order, if they're row major encoded.
182                    if (stdIterator->isRowMajorMatrix)
183                    {
184                        copy_matrix_row_major(dstMat, srcMat, maxSrcPtr, stdIterator->matrixStride,
185                                              mtlIterator->matrixStride, mtlIterator->type);
186                    }
187                    else
188                    {
189                        copy_matrix(dstMat, srcMat, maxSrcPtr, stdIterator->matrixStride,
190                                    mtlIterator->matrixStride, mtlIterator->type);
191                    }
192                }
193                // Compress bool from four bytes to one byte because bool values in GLSL
194                // are uint-sized: ES 3.0 Section 2.12.6.3 "Uniform Buffer Object Storage".
195                // Bools in metal are byte-sized. (Metal shading language spec Table 2.2)
196                else if (gl::VariableComponentType(mtlIterator->type) == GL_BOOL)
197                {
198                    for (int boolCol = 0; boolCol < gl::VariableComponentCount(mtlIterator->type);
199                         boolCol++)
200                    {
201                        const uint8_t *srcBool =
202                            (sourceData + stdIterator->offset + stdArrayOffset +
203                             blockConversionInfo.stdSize() * i +
204                             gl::VariableComponentSize(GL_BOOL) * boolCol);
205                        unsigned int srcValue =
206                            srcBool < maxSrcPtr ? *((unsigned int *)(srcBool)) : 0;
207                        uint8_t *dstBool = dst + mtlIterator->offset + mtlArrayOffset +
208                                           blockConversionInfo.metalSize() * i +
209                                           sizeof(bool) * boolCol;
210                        *dstBool = (srcValue != 0);
211                    }
212                }
213                else
214                {
215                    memcpy_guarded(dst + mtlIterator->offset + mtlArrayOffset +
216                                       blockConversionInfo.metalSize() * i,
217                                   sourceData + stdIterator->offset + stdArrayOffset +
218                                       blockConversionInfo.stdSize() * i,
219                                   maxSrcPtr, mtl::GetMetalSizeForGLType(mtlIterator->type));
220                }
221            }
222            ++stdIterator;
223            ++mtlIterator;
224        }
225    }
226
227    ANGLE_TRY(dynamicBuffer->commit(contextMtl));
228    return angle::Result::Continue;
229}
230
231constexpr size_t PipelineParametersToFragmentShaderVariantIndex(bool multisampledRendering,
232                                                                bool allowFragDepthWrite)
233{
234    const size_t index = (allowFragDepthWrite << 1) | multisampledRendering;
235    ASSERT(index < kFragmentShaderVariants);
236    return index;
237}
238
239void InitArgumentBufferEncoder(mtl::Context *context,
240                               id<MTLFunction> function,
241                               uint32_t bufferIndex,
242                               ProgramArgumentBufferEncoderMtl *encoder)
243{
244    encoder->metalArgBufferEncoder =
245        mtl::adoptObjCObj([function newArgumentEncoderWithBufferIndex:bufferIndex]);
246    if (encoder->metalArgBufferEncoder)
247    {
248        encoder->bufferPool.initialize(context, encoder->metalArgBufferEncoder.get().encodedLength,
249                                       mtl::kArgumentBufferOffsetAlignment, 0);
250    }
251}
252
253template <typename T>
254void UpdateDefaultUniformBlockWithElementSize(GLsizei count,
255                                              uint32_t arrayIndex,
256                                              int componentCount,
257                                              const T *v,
258                                              size_t baseElementSize,
259                                              const sh::BlockMemberInfo &layoutInfo,
260                                              angle::MemoryBuffer *uniformData)
261{
262    const int elementSize = (int)(baseElementSize * componentCount);
263
264    uint8_t *dst = uniformData->data() + layoutInfo.offset;
265    if (layoutInfo.arrayStride == 0 || layoutInfo.arrayStride == elementSize)
266    {
267        uint32_t arrayOffset = arrayIndex * layoutInfo.arrayStride;
268        uint8_t *writePtr    = dst + arrayOffset;
269        ASSERT(writePtr + (elementSize * count) <= uniformData->data() + uniformData->size());
270        memcpy(writePtr, v, elementSize * count);
271    }
272    else
273    {
274        // Have to respect the arrayStride between each element of the array.
275        int maxIndex = arrayIndex + count;
276        for (int writeIndex = arrayIndex, readIndex = 0; writeIndex < maxIndex;
277             writeIndex++, readIndex++)
278        {
279            const int arrayOffset = writeIndex * layoutInfo.arrayStride;
280            uint8_t *writePtr     = dst + arrayOffset;
281            const T *readPtr      = v + (readIndex * componentCount);
282            ASSERT(writePtr + elementSize <= uniformData->data() + uniformData->size());
283            memcpy(writePtr, readPtr, elementSize);
284        }
285    }
286}
287template <typename T>
288void ReadFromDefaultUniformBlock(int componentCount,
289                                 uint32_t arrayIndex,
290                                 T *dst,
291                                 size_t elementSize,
292                                 const sh::BlockMemberInfo &layoutInfo,
293                                 const angle::MemoryBuffer *uniformData)
294{
295    ReadFromDefaultUniformBlockWithElementSize(componentCount, arrayIndex, dst, sizeof(T),
296                                               layoutInfo, uniformData);
297}
298
299void ReadFromDefaultUniformBlockWithElementSize(int componentCount,
300                                                uint32_t arrayIndex,
301                                                void *dst,
302                                                size_t baseElementSize,
303                                                const sh::BlockMemberInfo &layoutInfo,
304                                                const angle::MemoryBuffer *uniformData)
305{
306    ASSERT(layoutInfo.offset != -1);
307
308    const size_t elementSize = (baseElementSize * componentCount);
309    const uint8_t *source    = uniformData->data() + layoutInfo.offset;
310
311    if (layoutInfo.arrayStride == 0 || (size_t)layoutInfo.arrayStride == elementSize)
312    {
313        const uint8_t *readPtr = source + arrayIndex * layoutInfo.arrayStride;
314        memcpy(dst, readPtr, elementSize);
315    }
316    else
317    {
318        // Have to respect the arrayStride between each element of the array.
319        const int arrayOffset  = arrayIndex * layoutInfo.arrayStride;
320        const uint8_t *readPtr = source + arrayOffset;
321        memcpy(dst, readPtr, elementSize);
322    }
323}
324
325class Std140BlockLayoutEncoderFactory : public gl::CustomBlockLayoutEncoderFactory
326{
327  public:
328    sh::BlockLayoutEncoder *makeEncoder() override { return new sh::Std140BlockEncoder(); }
329};
330
331class Std430BlockLayoutEncoderFactory : public gl::CustomBlockLayoutEncoderFactory
332{
333  public:
334    sh::BlockLayoutEncoder *makeEncoder() override { return new sh::Std430BlockEncoder(); }
335};
336
337class StdMTLBLockLayoutEncoderFactory : public gl::CustomBlockLayoutEncoderFactory
338{
339  public:
340    sh::BlockLayoutEncoder *makeEncoder() override { return new mtl::BlockLayoutEncoderMTL(); }
341};
342}  // anonymous namespace
343
344angle::Result CreateMslShaderLib(mtl::Context *context,
345                                 gl::InfoLog &infoLog,
346                                 mtl::TranslatedShaderInfo *translatedMslInfo,
347                                 const std::map<std::string, std::string> &substitutionMacros)
348{
349    ANGLE_MTL_OBJC_SCOPE
350    {
351        mtl::LibraryCache &libraryCache = context->getDisplay()->getLibraryCache();
352
353        // Convert to actual binary shader
354        mtl::AutoObjCPtr<NSError *> err = nil;
355        const bool disableFastMath =
356            context->getDisplay()->getFeatures().intelDisableFastMath.enabled ||
357            translatedMslInfo->hasIsnanOrIsinf;
358        const bool usesInvariance       = translatedMslInfo->hasInvariant;
359        translatedMslInfo->metalLibrary = libraryCache.getOrCompileShaderLibrary(
360            context->getDisplay(), translatedMslInfo->metalShaderSource, substitutionMacros,
361            disableFastMath, usesInvariance, &err);
362        if (err && !translatedMslInfo->metalLibrary)
363        {
364            std::ostringstream ss;
365            ss << "Internal error compiling shader with Metal backend.\n";
366            ss << err.get().localizedDescription.UTF8String << "\n";
367            ss << "-----\n";
368            ss << *(translatedMslInfo->metalShaderSource);
369            ss << "-----\n";
370
371            infoLog << ss.str();
372
373            ANGLE_MTL_HANDLE_ERROR(context, ss.str().c_str(), GL_INVALID_OPERATION);
374            return angle::Result::Stop;
375        }
376
377        return angle::Result::Continue;
378    }
379}
380DefaultUniformBlockMtl::DefaultUniformBlockMtl() {}
381
382DefaultUniformBlockMtl::~DefaultUniformBlockMtl() = default;
383
384ProgramExecutableMtl::ProgramExecutableMtl(const gl::ProgramExecutable *executable)
385    : ProgramExecutableImpl(executable), mProgramHasFlatAttributes(false), mShadowCompareModes{}
386{
387    mCurrentShaderVariants.fill(nullptr);
388
389    for (gl::ShaderType shaderType : gl::AllShaderTypes())
390    {
391        mMslShaderTranslateInfo[shaderType].reset();
392    }
393    mMslXfbOnlyVertexShaderInfo.reset();
394}
395
396ProgramExecutableMtl::~ProgramExecutableMtl() {}
397
398void ProgramExecutableMtl::destroy(const gl::Context *context)
399{
400    auto contextMtl = mtl::GetImpl(context);
401    reset(contextMtl);
402}
403
404void ProgramExecutableMtl::reset(ContextMtl *context)
405{
406    mProgramHasFlatAttributes = false;
407
408    for (auto &block : mDefaultUniformBlocks)
409    {
410        block.uniformLayout.clear();
411    }
412
413    for (gl::ShaderType shaderType : gl::AllShaderTypes())
414    {
415        mMslShaderTranslateInfo[shaderType].reset();
416        mCurrentShaderVariants[shaderType] = nullptr;
417    }
418    mMslXfbOnlyVertexShaderInfo.reset();
419
420    for (ProgramShaderObjVariantMtl &var : mVertexShaderVariants)
421    {
422        var.reset(context);
423    }
424    for (ProgramShaderObjVariantMtl &var : mFragmentShaderVariants)
425    {
426        var.reset(context);
427    }
428
429    for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes)
430    {
431        if (mDefaultUniformBufferPools[shaderType])
432        {
433            mDefaultUniformBufferPools[shaderType]->destroy(context);
434            mDefaultUniformBufferPools[shaderType].reset();
435        }
436    }
437}
438
439angle::Result ProgramExecutableMtl::load(ContextMtl *contextMtl, gl::BinaryInputStream *stream)
440{
441    loadTranslatedShaders(stream);
442    loadShaderInternalInfo(stream);
443    ANGLE_TRY(loadDefaultUniformBlocksInfo(contextMtl, stream));
444    return loadInterfaceBlockInfo(stream);
445}
446
447void ProgramExecutableMtl::save(gl::BinaryOutputStream *stream)
448{
449    saveTranslatedShaders(stream);
450    saveShaderInternalInfo(stream);
451    saveDefaultUniformBlocksInfo(stream);
452    saveInterfaceBlockInfo(stream);
453}
454
455void ProgramExecutableMtl::saveInterfaceBlockInfo(gl::BinaryOutputStream *stream)
456{
457    // Serializes the uniformLayout data of mDefaultUniformBlocks
458    // First, save the number of Ib's to process
459    stream->writeInt<unsigned int>((unsigned int)mUniformBlockConversions.size());
460    // Next, iterate through all of the conversions.
461    for (auto conversion : mUniformBlockConversions)
462    {
463        // Write the name of the conversion
464        stream->writeString(conversion.first);
465        // Write the number of entries in the conversion
466        const UBOConversionInfo &conversionInfo = conversion.second;
467        stream->writeVector(conversionInfo.stdInfo());
468        stream->writeVector(conversionInfo.metalInfo());
469        stream->writeInt<size_t>(conversionInfo.stdSize());
470        stream->writeInt<size_t>(conversionInfo.metalSize());
471    }
472}
473
474angle::Result ProgramExecutableMtl::loadInterfaceBlockInfo(gl::BinaryInputStream *stream)
475{
476    mUniformBlockConversions.clear();
477    // First, load the number of Ib's to process
478    uint32_t numBlocks = stream->readInt<uint32_t>();
479    // Next, iterate through all of the conversions.
480    for (uint32_t nBlocks = 0; nBlocks < numBlocks; ++nBlocks)
481    {
482        // Read the name of the conversion
483        std::string blockName = stream->readString();
484        // Read the number of entries in the conversion
485        std::vector<sh::BlockMemberInfo> stdInfo, metalInfo;
486        stream->readVector(&stdInfo);
487        stream->readVector(&metalInfo);
488        size_t stdSize   = stream->readInt<size_t>();
489        size_t metalSize = stream->readInt<size_t>();
490        mUniformBlockConversions.insert(
491            {blockName, UBOConversionInfo(stdInfo, metalInfo, stdSize, metalSize)});
492    }
493    return angle::Result::Continue;
494}
495
496void ProgramExecutableMtl::saveDefaultUniformBlocksInfo(gl::BinaryOutputStream *stream)
497{
498    // Serializes the uniformLayout data of mDefaultUniformBlocks
499    for (gl::ShaderType shaderType : gl::AllShaderTypes())
500    {
501        stream->writeVector(mDefaultUniformBlocks[shaderType].uniformLayout);
502    }
503
504    // Serializes required uniform block memory sizes
505    for (gl::ShaderType shaderType : gl::AllShaderTypes())
506    {
507        stream->writeInt(mDefaultUniformBlocks[shaderType].uniformData.size());
508    }
509}
510
511angle::Result ProgramExecutableMtl::loadDefaultUniformBlocksInfo(mtl::Context *context,
512                                                                 gl::BinaryInputStream *stream)
513{
514    gl::ShaderMap<size_t> requiredBufferSize;
515    requiredBufferSize.fill(0);
516    // Deserializes the uniformLayout data of mDefaultUniformBlocks
517    for (gl::ShaderType shaderType : gl::AllShaderTypes())
518    {
519        stream->readVector(&mDefaultUniformBlocks[shaderType].uniformLayout);
520    }
521
522    // Deserializes required uniform block memory sizes
523    for (gl::ShaderType shaderType : gl::AllShaderTypes())
524    {
525        requiredBufferSize[shaderType] = stream->readInt<size_t>();
526    }
527
528    return resizeDefaultUniformBlocksMemory(context, requiredBufferSize);
529}
530
531void ProgramExecutableMtl::saveShaderInternalInfo(gl::BinaryOutputStream *stream)
532{
533    for (gl::ShaderType shaderType : gl::AllShaderTypes())
534    {
535        stream->writeInt<int>(mMslShaderTranslateInfo[shaderType].hasUBOArgumentBuffer);
536        for (const mtl::SamplerBinding &binding :
537             mMslShaderTranslateInfo[shaderType].actualSamplerBindings)
538        {
539            stream->writeInt<uint32_t>(binding.textureBinding);
540            stream->writeInt<uint32_t>(binding.samplerBinding);
541        }
542        for (int rwTextureBinding : mMslShaderTranslateInfo[shaderType].actualImageBindings)
543        {
544            stream->writeInt<int>(rwTextureBinding);
545        }
546
547        for (uint32_t uboBinding : mMslShaderTranslateInfo[shaderType].actualUBOBindings)
548        {
549            stream->writeInt<uint32_t>(uboBinding);
550        }
551        stream->writeBool(mMslShaderTranslateInfo[shaderType].hasInvariant);
552    }
553    for (size_t xfbBindIndex = 0; xfbBindIndex < mtl::kMaxShaderXFBs; xfbBindIndex++)
554    {
555        stream->writeInt(
556            mMslShaderTranslateInfo[gl::ShaderType::Vertex].actualXFBBindings[xfbBindIndex]);
557    }
558
559    // Write out XFB info.
560    {
561        stream->writeInt<int>(mMslXfbOnlyVertexShaderInfo.hasUBOArgumentBuffer);
562        for (mtl::SamplerBinding &binding : mMslXfbOnlyVertexShaderInfo.actualSamplerBindings)
563        {
564            stream->writeInt<uint32_t>(binding.textureBinding);
565            stream->writeInt<uint32_t>(binding.samplerBinding);
566        }
567        for (int rwTextureBinding : mMslXfbOnlyVertexShaderInfo.actualImageBindings)
568        {
569            stream->writeInt<int>(rwTextureBinding);
570        }
571
572        for (uint32_t &uboBinding : mMslXfbOnlyVertexShaderInfo.actualUBOBindings)
573        {
574            stream->writeInt<uint32_t>(uboBinding);
575        }
576        for (size_t xfbBindIndex = 0; xfbBindIndex < mtl::kMaxShaderXFBs; xfbBindIndex++)
577        {
578            stream->writeInt(mMslXfbOnlyVertexShaderInfo.actualXFBBindings[xfbBindIndex]);
579        }
580    }
581
582    stream->writeBool(mProgramHasFlatAttributes);
583}
584
585void ProgramExecutableMtl::loadShaderInternalInfo(gl::BinaryInputStream *stream)
586{
587    for (gl::ShaderType shaderType : gl::AllShaderTypes())
588    {
589        mMslShaderTranslateInfo[shaderType].hasUBOArgumentBuffer = stream->readInt<int>() != 0;
590        for (mtl::SamplerBinding &binding :
591             mMslShaderTranslateInfo[shaderType].actualSamplerBindings)
592        {
593            binding.textureBinding = stream->readInt<uint32_t>();
594            binding.samplerBinding = stream->readInt<uint32_t>();
595        }
596        for (int &rwTextureBinding : mMslShaderTranslateInfo[shaderType].actualImageBindings)
597        {
598            rwTextureBinding = stream->readInt<int>();
599        }
600
601        for (uint32_t &uboBinding : mMslShaderTranslateInfo[shaderType].actualUBOBindings)
602        {
603            uboBinding = stream->readInt<uint32_t>();
604        }
605        mMslShaderTranslateInfo[shaderType].hasInvariant = stream->readBool();
606    }
607
608    for (size_t xfbBindIndex = 0; xfbBindIndex < mtl::kMaxShaderXFBs; xfbBindIndex++)
609    {
610        stream->readInt(
611            &mMslShaderTranslateInfo[gl::ShaderType::Vertex].actualXFBBindings[xfbBindIndex]);
612    }
613    // Load Transform Feedback info
614    {
615        mMslXfbOnlyVertexShaderInfo.hasUBOArgumentBuffer = stream->readInt<int>() != 0;
616        for (mtl::SamplerBinding &binding : mMslXfbOnlyVertexShaderInfo.actualSamplerBindings)
617        {
618            binding.textureBinding = stream->readInt<uint32_t>();
619            binding.samplerBinding = stream->readInt<uint32_t>();
620        }
621        for (int &rwTextureBinding : mMslXfbOnlyVertexShaderInfo.actualImageBindings)
622        {
623            rwTextureBinding = stream->readInt<int>();
624        }
625
626        for (uint32_t &uboBinding : mMslXfbOnlyVertexShaderInfo.actualUBOBindings)
627        {
628            uboBinding = stream->readInt<uint32_t>();
629        }
630        for (size_t xfbBindIndex = 0; xfbBindIndex < mtl::kMaxShaderXFBs; xfbBindIndex++)
631        {
632            stream->readInt(&mMslXfbOnlyVertexShaderInfo.actualXFBBindings[xfbBindIndex]);
633        }
634        mMslXfbOnlyVertexShaderInfo.metalLibrary = nullptr;
635    }
636
637    mProgramHasFlatAttributes = stream->readBool();
638}
639
640void ProgramExecutableMtl::saveTranslatedShaders(gl::BinaryOutputStream *stream)
641{
642    auto writeTranslatedSource = [](gl::BinaryOutputStream *stream,
643                                    const mtl::TranslatedShaderInfo &shaderInfo) {
644        const std::string &source =
645            shaderInfo.metalShaderSource ? *shaderInfo.metalShaderSource : std::string();
646        stream->writeString(source);
647    };
648
649    // Write out shader sources for all shader types
650    for (const gl::ShaderType shaderType : gl::AllShaderTypes())
651    {
652        writeTranslatedSource(stream, mMslShaderTranslateInfo[shaderType]);
653    }
654    writeTranslatedSource(stream, mMslXfbOnlyVertexShaderInfo);
655}
656
657void ProgramExecutableMtl::loadTranslatedShaders(gl::BinaryInputStream *stream)
658{
659    auto readTranslatedSource = [](gl::BinaryInputStream *stream,
660                                   mtl::TranslatedShaderInfo &shaderInfo) {
661        std::string source = stream->readString();
662        if (!source.empty())
663        {
664            shaderInfo.metalShaderSource = std::make_shared<const std::string>(std::move(source));
665        }
666        else
667        {
668            shaderInfo.metalShaderSource = nullptr;
669        }
670    };
671
672    // Read in shader sources for all shader types
673    for (const gl::ShaderType shaderType : gl::AllShaderTypes())
674    {
675        readTranslatedSource(stream, mMslShaderTranslateInfo[shaderType]);
676    }
677    readTranslatedSource(stream, mMslXfbOnlyVertexShaderInfo);
678}
679
680void ProgramExecutableMtl::linkUpdateHasFlatAttributes(
681    const gl::SharedCompiledShaderState &vertexShader)
682{
683    mProgramHasFlatAttributes = false;
684
685    const auto &programInputs = mExecutable->getProgramInputs();
686    for (auto &attribute : programInputs)
687    {
688        if (attribute.getInterpolation() == sh::INTERPOLATION_FLAT)
689        {
690            mProgramHasFlatAttributes = true;
691            return;
692        }
693    }
694
695    const auto &flatVaryings = vertexShader->outputVaryings;
696    for (auto &attribute : flatVaryings)
697    {
698        if (attribute.interpolation == sh::INTERPOLATION_FLAT)
699        {
700            mProgramHasFlatAttributes = true;
701            return;
702        }
703    }
704}
705
706angle::Result ProgramExecutableMtl::initDefaultUniformBlocks(
707    mtl::Context *context,
708    const gl::ShaderMap<gl::SharedCompiledShaderState> &shaders)
709{
710    // Process vertex and fragment uniforms into std140 packing.
711    gl::ShaderMap<sh::BlockLayoutMap> layoutMap;
712    gl::ShaderMap<size_t> requiredBufferSize;
713    requiredBufferSize.fill(0);
714
715    for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes)
716    {
717        const gl::SharedCompiledShaderState &shader = shaders[shaderType];
718        if (shader)
719        {
720            const std::vector<sh::Uniform> &uniforms = shader->uniforms;
721            InitDefaultUniformBlock(uniforms, &layoutMap[shaderType],
722                                    &requiredBufferSize[shaderType]);
723            // Set up block conversion buffer
724            initUniformBlocksRemapper(shader);
725        }
726    }
727
728    // Init the default block layout info.
729    const auto &uniforms         = mExecutable->getUniforms();
730    const auto &uniformNames     = mExecutable->getUniformNames();
731    const auto &uniformLocations = mExecutable->getUniformLocations();
732    for (size_t locSlot = 0; locSlot < uniformLocations.size(); ++locSlot)
733    {
734        const gl::VariableLocation &location = uniformLocations[locSlot];
735        gl::ShaderMap<sh::BlockMemberInfo> layoutInfo;
736
737        if (location.used() && !location.ignored)
738        {
739            const gl::LinkedUniform &uniform = uniforms[location.index];
740            if (uniform.isInDefaultBlock() && !uniform.isSampler() && !uniform.isImage())
741            {
742                std::string uniformName = uniformNames[location.index];
743                if (uniform.isArray())
744                {
745                    // Gets the uniform name without the [0] at the end.
746                    uniformName = gl::ParseResourceName(uniformName, nullptr);
747                }
748
749                bool found = false;
750
751                for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes)
752                {
753                    auto it = layoutMap[shaderType].find(uniformName);
754                    if (it != layoutMap[shaderType].end())
755                    {
756                        found                  = true;
757                        layoutInfo[shaderType] = it->second;
758                    }
759                }
760
761                ASSERT(found);
762            }
763        }
764
765        for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes)
766        {
767            mDefaultUniformBlocks[shaderType].uniformLayout.push_back(layoutInfo[shaderType]);
768        }
769    }
770
771    return resizeDefaultUniformBlocksMemory(context, requiredBufferSize);
772}
773
774angle::Result ProgramExecutableMtl::resizeDefaultUniformBlocksMemory(
775    mtl::Context *context,
776    const gl::ShaderMap<size_t> &requiredBufferSize)
777{
778    for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes)
779    {
780        if (requiredBufferSize[shaderType] > 0)
781        {
782            ASSERT(requiredBufferSize[shaderType] <= mtl::kDefaultUniformsMaxSize);
783
784            if (!mDefaultUniformBlocks[shaderType].uniformData.resize(
785                    requiredBufferSize[shaderType]))
786            {
787                ANGLE_MTL_CHECK(context, false, GL_OUT_OF_MEMORY);
788            }
789
790            // Initialize uniform buffer memory to zero by default.
791            mDefaultUniformBlocks[shaderType].uniformData.fill(0);
792            mDefaultUniformBlocksDirty.set(shaderType);
793        }
794    }
795
796    return angle::Result::Continue;
797}
798
799// TODO(angleproject:7979) Upgrade ANGLE Uniform buffer remapper to compute shaders
800void ProgramExecutableMtl::initUniformBlocksRemapper(const gl::SharedCompiledShaderState &shader)
801{
802    std::unordered_map<std::string, UBOConversionInfo> conversionMap;
803    const std::vector<sh::InterfaceBlock> ibs = shader->uniformBlocks;
804    for (size_t i = 0; i < ibs.size(); ++i)
805    {
806
807        const sh::InterfaceBlock &ib = ibs[i];
808        if (mUniformBlockConversions.find(ib.name) == mUniformBlockConversions.end())
809        {
810            mtl::BlockLayoutEncoderMTL metalEncoder;
811            sh::BlockLayoutEncoder *encoder;
812            switch (ib.layout)
813            {
814                case sh::BLOCKLAYOUT_PACKED:
815                case sh::BLOCKLAYOUT_SHARED:
816                case sh::BLOCKLAYOUT_STD140:
817                {
818                    Std140BlockLayoutEncoderFactory factory;
819                    encoder = factory.makeEncoder();
820                }
821                break;
822                case sh::BLOCKLAYOUT_STD430:
823                {
824                    Std430BlockLayoutEncoderFactory factory;
825                    encoder = factory.makeEncoder();
826                }
827                break;
828            }
829            sh::BlockLayoutMap blockLayoutMapOut, stdMapOut;
830
831            sh::GetInterfaceBlockInfo(ib.fields, "", &metalEncoder, &blockLayoutMapOut);
832            sh::GetInterfaceBlockInfo(ib.fields, "", encoder, &stdMapOut);
833
834            auto stdIterator = stdMapOut.begin();
835            auto mtlIterator = blockLayoutMapOut.begin();
836
837            std::vector<sh::BlockMemberInfo> stdConversions, mtlConversions;
838            while (stdIterator != stdMapOut.end())
839            {
840                stdConversions.push_back(stdIterator->second);
841                mtlConversions.push_back(mtlIterator->second);
842                stdIterator++;
843                mtlIterator++;
844            }
845            std::sort(stdConversions.begin(), stdConversions.end(), CompareBlockInfo);
846            std::sort(mtlConversions.begin(), mtlConversions.end(), CompareBlockInfo);
847
848            size_t stdSize    = encoder->getCurrentOffset();
849            size_t metalAlign = GetAlignmentOfUniformGroup(&blockLayoutMapOut);
850            size_t metalSize  = roundUp(metalEncoder.getCurrentOffset(), metalAlign);
851
852            conversionMap.insert(
853                {ib.name, UBOConversionInfo(stdConversions, mtlConversions, stdSize, metalSize)});
854            SafeDelete(encoder);
855        }
856    }
857    mUniformBlockConversions.insert(conversionMap.begin(), conversionMap.end());
858}
859
860mtl::BufferPool *ProgramExecutableMtl::getBufferPool(ContextMtl *context, gl::ShaderType shaderType)
861{
862    auto &pool = mDefaultUniformBufferPools[shaderType];
863    if (pool == nullptr)
864    {
865        DefaultUniformBlockMtl &uniformBlock = mDefaultUniformBlocks[shaderType];
866
867        // Size each buffer to hold 10 draw calls worth of uniform updates before creating extra
868        // buffers. This number was chosen loosely to balance the size of buffers versus the total
869        // number allocated. Without any sub-allocation, the total buffer count can reach the
870        // thousands when many draw calls are issued with the same program.
871        size_t bufferSize =
872            std::max(uniformBlock.uniformData.size() * 10, mtl::kDefaultUniformsMaxSize * 2);
873
874        pool.reset(new mtl::BufferPool(false));
875
876        // Allow unbounded growth of the buffer count. Doing a full CPU/GPU sync waiting for new
877        // uniform uploads has catastrophic performance cost.
878        pool->initialize(context, bufferSize, mtl::kUniformBufferSettingOffsetMinAlignment, 0);
879    }
880    return pool.get();
881}
882
883angle::Result ProgramExecutableMtl::setupDraw(const gl::Context *glContext,
884                                              mtl::RenderCommandEncoder *cmdEncoder,
885                                              const mtl::RenderPipelineDesc &pipelineDesc,
886                                              bool pipelineDescChanged,
887                                              bool forceTexturesSetting,
888                                              bool uniformBuffersDirty)
889{
890    ContextMtl *context = mtl::GetImpl(glContext);
891
892    if (pipelineDescChanged)
893    {
894        id<MTLFunction> vertexShader = nil;
895        ANGLE_TRY(
896            getSpecializedShader(context, gl::ShaderType::Vertex, pipelineDesc, &vertexShader));
897
898        id<MTLFunction> fragmentShader = nil;
899        ANGLE_TRY(
900            getSpecializedShader(context, gl::ShaderType::Fragment, pipelineDesc, &fragmentShader));
901
902        mtl::AutoObjCPtr<id<MTLRenderPipelineState>> pipelineState;
903        ANGLE_TRY(context->getPipelineCache().getRenderPipeline(
904            context, vertexShader, fragmentShader, pipelineDesc, &pipelineState));
905
906        cmdEncoder->setRenderPipelineState(pipelineState);
907
908        // We need to rebind uniform buffers & textures also
909        mDefaultUniformBlocksDirty.set();
910        mSamplerBindingsDirty.set();
911
912        // Cache current shader variant references for easier querying.
913        mCurrentShaderVariants[gl::ShaderType::Vertex] =
914            &mVertexShaderVariants[pipelineDesc.rasterizationType];
915
916        const bool multisampledRendering = pipelineDesc.outputDescriptor.rasterSampleCount > 1;
917        const bool allowFragDepthWrite =
918            pipelineDesc.outputDescriptor.depthAttachmentPixelFormat != 0;
919        mCurrentShaderVariants[gl::ShaderType::Fragment] =
920            pipelineDesc.rasterizationEnabled()
921                ? &mFragmentShaderVariants[PipelineParametersToFragmentShaderVariantIndex(
922                      multisampledRendering, allowFragDepthWrite)]
923                : nullptr;
924    }
925
926    ANGLE_TRY(commitUniforms(context, cmdEncoder));
927    ANGLE_TRY(updateTextures(glContext, cmdEncoder, forceTexturesSetting));
928
929    if (uniformBuffersDirty || pipelineDescChanged)
930    {
931        ANGLE_TRY(updateUniformBuffers(context, cmdEncoder, pipelineDesc));
932    }
933
934    if (pipelineDescChanged)
935    {
936        ANGLE_TRY(updateXfbBuffers(context, cmdEncoder, pipelineDesc));
937    }
938
939    return angle::Result::Continue;
940}
941
942angle::Result ProgramExecutableMtl::getSpecializedShader(
943    ContextMtl *context,
944    gl::ShaderType shaderType,
945    const mtl::RenderPipelineDesc &renderPipelineDesc,
946    id<MTLFunction> *shaderOut)
947{
948    static_assert(YES == 1, "YES should have value of 1");
949
950    mtl::TranslatedShaderInfo *translatedMslInfo = &mMslShaderTranslateInfo[shaderType];
951    ProgramShaderObjVariantMtl *shaderVariant;
952    mtl::AutoObjCObj<MTLFunctionConstantValues> funcConstants;
953
954    if (shaderType == gl::ShaderType::Vertex)
955    {
956        // For vertex shader, we need to create 3 variants, one with emulated rasterization
957        // discard, one with true rasterization discard and one without.
958        shaderVariant = &mVertexShaderVariants[renderPipelineDesc.rasterizationType];
959        if (shaderVariant->metalShader)
960        {
961            // Already created.
962            *shaderOut = shaderVariant->metalShader;
963            return angle::Result::Continue;
964        }
965
966        if (renderPipelineDesc.rasterizationType == mtl::RenderPipelineRasterization::Disabled)
967        {
968            // Special case: XFB output only vertex shader.
969            ASSERT(!mExecutable->getLinkedTransformFeedbackVaryings().empty());
970            translatedMslInfo = &mMslXfbOnlyVertexShaderInfo;
971            if (!translatedMslInfo->metalLibrary)
972            {
973                // Lazily compile XFB only shader
974                gl::InfoLog infoLog;
975                ANGLE_TRY(CreateMslShaderLib(context, infoLog, &mMslXfbOnlyVertexShaderInfo,
976                                             {{"TRANSFORM_FEEDBACK_ENABLED", "1"}}));
977                translatedMslInfo->metalLibrary.get().label = @"TransformFeedback";
978            }
979        }
980
981        ANGLE_MTL_OBJC_SCOPE
982        {
983            BOOL emulateDiscard = renderPipelineDesc.rasterizationType ==
984                                  mtl::RenderPipelineRasterization::EmulatedDiscard;
985
986            NSString *discardEnabledStr =
987                [NSString stringWithUTF8String:sh::mtl::kRasterizerDiscardEnabledConstName];
988
989            funcConstants = mtl::adoptObjCObj([[MTLFunctionConstantValues alloc] init]);
990            [funcConstants setConstantValue:&emulateDiscard
991                                       type:MTLDataTypeBool
992                                   withName:discardEnabledStr];
993        }
994    }  // if (shaderType == gl::ShaderType::Vertex)
995    else if (shaderType == gl::ShaderType::Fragment)
996    {
997        // For fragment shader, we need to create 4 variants,
998        // combining multisampled rendering and depth write enabled states.
999        const bool multisampledRendering =
1000            renderPipelineDesc.outputDescriptor.rasterSampleCount > 1;
1001        const bool allowFragDepthWrite =
1002            renderPipelineDesc.outputDescriptor.depthAttachmentPixelFormat != 0;
1003        shaderVariant = &mFragmentShaderVariants[PipelineParametersToFragmentShaderVariantIndex(
1004            multisampledRendering, allowFragDepthWrite)];
1005        if (shaderVariant->metalShader)
1006        {
1007            // Already created.
1008            *shaderOut = shaderVariant->metalShader;
1009            return angle::Result::Continue;
1010        }
1011
1012        ANGLE_MTL_OBJC_SCOPE
1013        {
1014            NSString *multisampledRenderingStr =
1015                [NSString stringWithUTF8String:sh::mtl::kMultisampledRenderingConstName];
1016
1017            NSString *depthWriteEnabledStr =
1018                [NSString stringWithUTF8String:sh::mtl::kDepthWriteEnabledConstName];
1019
1020            funcConstants = mtl::adoptObjCObj([[MTLFunctionConstantValues alloc] init]);
1021            [funcConstants setConstantValue:&multisampledRendering
1022                                       type:MTLDataTypeBool
1023                                   withName:multisampledRenderingStr];
1024            [funcConstants setConstantValue:&allowFragDepthWrite
1025                                       type:MTLDataTypeBool
1026                                   withName:depthWriteEnabledStr];
1027        }
1028
1029    }  // gl::ShaderType::Fragment
1030    else
1031    {
1032        UNREACHABLE();
1033        return angle::Result::Stop;
1034    }
1035    [funcConstants
1036        setConstantValue:&(context->getDisplay()->getFeatures().allowSamplerCompareGradient.enabled)
1037                    type:MTLDataTypeBool
1038                withName:@"ANGLEUseSampleCompareGradient"];
1039    [funcConstants
1040        setConstantValue:&(context->getDisplay()->getFeatures().emulateAlphaToCoverage.enabled)
1041                    type:MTLDataTypeBool
1042                withName:@"ANGLEEmulateAlphaToCoverage"];
1043    [funcConstants
1044        setConstantValue:&(context->getDisplay()->getFeatures().writeHelperSampleMask.enabled)
1045                    type:MTLDataTypeBool
1046                withName:@"ANGLEWriteHelperSampleMask"];
1047    // Create Metal shader object
1048    ANGLE_MTL_OBJC_SCOPE
1049    {
1050        ANGLE_TRY(CreateMslShader(context, translatedMslInfo->metalLibrary, SHADER_ENTRY_NAME,
1051                                  funcConstants.get(), &shaderVariant->metalShader));
1052    }
1053
1054    // Store reference to the translated source for easily querying mapped bindings later.
1055    shaderVariant->translatedSrcInfo = translatedMslInfo;
1056
1057    // Initialize argument buffer encoder if required
1058    if (translatedMslInfo->hasUBOArgumentBuffer)
1059    {
1060        InitArgumentBufferEncoder(context, shaderVariant->metalShader,
1061                                  mtl::kUBOArgumentBufferBindingIndex,
1062                                  &shaderVariant->uboArgBufferEncoder);
1063    }
1064
1065    *shaderOut = shaderVariant->metalShader;
1066
1067    return angle::Result::Continue;
1068}
1069
1070angle::Result ProgramExecutableMtl::commitUniforms(ContextMtl *context,
1071                                                   mtl::RenderCommandEncoder *cmdEncoder)
1072{
1073    for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes)
1074    {
1075        if (!mDefaultUniformBlocksDirty[shaderType] || !mCurrentShaderVariants[shaderType])
1076        {
1077            continue;
1078        }
1079        DefaultUniformBlockMtl &uniformBlock = mDefaultUniformBlocks[shaderType];
1080
1081        if (!uniformBlock.uniformData.size())
1082        {
1083            continue;
1084        }
1085
1086        // If we exceed the default inline max size, try to allocate a buffer
1087        bool needsCommitUniform = true;
1088        if (needsCommitUniform && uniformBlock.uniformData.size() <= mtl::kInlineConstDataMaxSize)
1089        {
1090            ASSERT(uniformBlock.uniformData.size() <= mtl::kInlineConstDataMaxSize);
1091            cmdEncoder->setBytes(shaderType, uniformBlock.uniformData.data(),
1092                                 uniformBlock.uniformData.size(),
1093                                 mtl::kDefaultUniformsBindingIndex);
1094        }
1095        else if (needsCommitUniform)
1096        {
1097            mtl::BufferPool *bufferPool = getBufferPool(context, shaderType);
1098            bufferPool->releaseInFlightBuffers(context);
1099
1100            ASSERT(uniformBlock.uniformData.size() <= mtl::kDefaultUniformsMaxSize);
1101            mtl::BufferRef mtlBufferOut;
1102            size_t offsetOut;
1103            uint8_t *ptrOut;
1104            // Allocate a new Uniform buffer
1105            ANGLE_TRY(bufferPool->allocate(context, uniformBlock.uniformData.size(), &ptrOut,
1106                                           &mtlBufferOut, &offsetOut));
1107            // Copy the uniform result
1108            memcpy(ptrOut, uniformBlock.uniformData.data(), uniformBlock.uniformData.size());
1109            // Commit
1110            ANGLE_TRY(bufferPool->commit(context));
1111            // Set buffer
1112            cmdEncoder->setBuffer(shaderType, mtlBufferOut, (uint32_t)offsetOut,
1113                                  mtl::kDefaultUniformsBindingIndex);
1114        }
1115
1116        mDefaultUniformBlocksDirty.reset(shaderType);
1117    }
1118    return angle::Result::Continue;
1119}
1120
1121angle::Result ProgramExecutableMtl::updateTextures(const gl::Context *glContext,
1122                                                   mtl::RenderCommandEncoder *cmdEncoder,
1123                                                   bool forceUpdate)
1124{
1125    ContextMtl *contextMtl                          = mtl::GetImpl(glContext);
1126    const auto &glState                             = glContext->getState();
1127    const gl::ActiveTexturesCache &completeTextures = glState.getActiveTexturesCache();
1128
1129    for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes)
1130    {
1131        if ((!mSamplerBindingsDirty[shaderType] && !forceUpdate) ||
1132            !mCurrentShaderVariants[shaderType])
1133        {
1134            continue;
1135        }
1136
1137        const mtl::TranslatedShaderInfo &shaderInfo =
1138            mCurrentShaderVariants[shaderType]->translatedSrcInfo
1139                ? *mCurrentShaderVariants[shaderType]->translatedSrcInfo
1140                : mMslShaderTranslateInfo[shaderType];
1141        bool hasDepthSampler = false;
1142
1143        for (uint32_t textureIndex = 0; textureIndex < mExecutable->getSamplerBindings().size();
1144             ++textureIndex)
1145        {
1146            const gl::SamplerBinding &samplerBinding =
1147                mExecutable->getSamplerBindings()[textureIndex];
1148            const mtl::SamplerBinding &mslBinding = shaderInfo.actualSamplerBindings[textureIndex];
1149            if (mslBinding.textureBinding >= mtl::kMaxShaderSamplers)
1150            {
1151                // No binding assigned
1152                continue;
1153            }
1154
1155            gl::TextureType textureType = samplerBinding.textureType;
1156
1157            for (uint32_t arrayElement = 0; arrayElement < samplerBinding.textureUnitsCount;
1158                 ++arrayElement)
1159            {
1160                GLuint textureUnit = samplerBinding.getTextureUnit(
1161                    mExecutable->getSamplerBoundTextureUnits(), arrayElement);
1162                gl::Texture *texture = completeTextures[textureUnit];
1163                gl::Sampler *sampler = contextMtl->getState().getSampler(textureUnit);
1164                uint32_t textureSlot = mslBinding.textureBinding + arrayElement;
1165                uint32_t samplerSlot = mslBinding.samplerBinding + arrayElement;
1166                if (!texture)
1167                {
1168                    ANGLE_TRY(contextMtl->getIncompleteTexture(glContext, textureType,
1169                                                               samplerBinding.format, &texture));
1170                }
1171                const gl::SamplerState *samplerState =
1172                    sampler ? &sampler->getSamplerState() : &texture->getSamplerState();
1173                TextureMtl *textureMtl = mtl::GetImpl(texture);
1174                if (samplerBinding.format == gl::SamplerFormat::Shadow)
1175                {
1176                    hasDepthSampler                  = true;
1177                    mShadowCompareModes[textureSlot] = mtl::MslGetShaderShadowCompareMode(
1178                        samplerState->getCompareMode(), samplerState->getCompareFunc());
1179                }
1180                ANGLE_TRY(textureMtl->bindToShader(glContext, cmdEncoder, shaderType, sampler,
1181                                                   textureSlot, samplerSlot));
1182            }  // for array elements
1183        }      // for sampler bindings
1184
1185        if (hasDepthSampler)
1186        {
1187            cmdEncoder->setData(shaderType, mShadowCompareModes,
1188                                mtl::kShadowSamplerCompareModesBindingIndex);
1189        }
1190
1191        for (const gl::ImageBinding &imageBinding : mExecutable->getImageBindings())
1192        {
1193            if (imageBinding.boundImageUnits.size() != 1)
1194            {
1195                UNIMPLEMENTED();
1196                continue;
1197            }
1198
1199            int glslImageBinding    = imageBinding.boundImageUnits[0];
1200            int mtlRWTextureBinding = shaderInfo.actualImageBindings[glslImageBinding];
1201            ASSERT(mtlRWTextureBinding < static_cast<int>(mtl::kMaxShaderImages));
1202            if (mtlRWTextureBinding < 0)
1203            {
1204                continue;  // The program does not have an image bound at this unit.
1205            }
1206
1207            const gl::ImageUnit &imageUnit = glState.getImageUnit(glslImageBinding);
1208            TextureMtl *textureMtl         = mtl::GetImpl(imageUnit.texture.get());
1209            if (imageUnit.layered)
1210            {
1211                UNIMPLEMENTED();
1212                continue;
1213            }
1214            ANGLE_TRY(textureMtl->bindToShaderImage(
1215                glContext, cmdEncoder, shaderType, static_cast<uint32_t>(mtlRWTextureBinding),
1216                imageUnit.level, imageUnit.layer, imageUnit.format));
1217        }
1218    }  // for shader types
1219
1220    return angle::Result::Continue;
1221}
1222
1223angle::Result ProgramExecutableMtl::updateUniformBuffers(
1224    ContextMtl *context,
1225    mtl::RenderCommandEncoder *cmdEncoder,
1226    const mtl::RenderPipelineDesc &pipelineDesc)
1227{
1228    const std::vector<gl::InterfaceBlock> &blocks = mExecutable->getUniformBlocks();
1229    if (blocks.empty())
1230    {
1231        return angle::Result::Continue;
1232    }
1233
1234    // This array is only used inside this function and its callees.
1235    ScopedAutoClearVector<uint32_t> scopeArrayClear(&mArgumentBufferRenderStageUsages);
1236    ScopedAutoClearVector<std::pair<mtl::BufferRef, uint32_t>> scopeArrayClear2(
1237        &mLegalizedOffsetedUniformBuffers);
1238    mArgumentBufferRenderStageUsages.resize(blocks.size());
1239    mLegalizedOffsetedUniformBuffers.resize(blocks.size());
1240
1241    ANGLE_TRY(legalizeUniformBufferOffsets(context));
1242
1243    const gl::State &glState = context->getState();
1244
1245    for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes)
1246    {
1247        if (!mCurrentShaderVariants[shaderType])
1248        {
1249            continue;
1250        }
1251
1252        if (mCurrentShaderVariants[shaderType]->translatedSrcInfo->hasUBOArgumentBuffer)
1253        {
1254            ANGLE_TRY(encodeUniformBuffersInfoArgumentBuffer(context, cmdEncoder, shaderType));
1255        }
1256        else
1257        {
1258            ANGLE_TRY(bindUniformBuffersToDiscreteSlots(context, cmdEncoder, shaderType));
1259        }
1260    }  // for shader types
1261
1262    // After encode the uniform buffers into an argument buffer, we need to tell Metal that
1263    // the buffers are being used by what shader stages.
1264    for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex)
1265    {
1266        const GLuint binding = mExecutable->getUniformBlockBinding(bufferIndex);
1267        const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
1268            glState.getIndexedUniformBuffer(binding);
1269        if (bufferBinding.get() == nullptr)
1270        {
1271            continue;
1272        }
1273
1274        // Remove any other stages other than vertex and fragment.
1275        uint32_t stages = mArgumentBufferRenderStageUsages[bufferIndex] &
1276                          (MTLRenderStageVertex | MTLRenderStageFragment);
1277
1278        if (stages == 0)
1279        {
1280            continue;
1281        }
1282
1283        cmdEncoder->useResource(mLegalizedOffsetedUniformBuffers[bufferIndex].first,
1284                                MTLResourceUsageRead, static_cast<MTLRenderStages>(stages));
1285    }
1286
1287    return angle::Result::Continue;
1288}
1289
1290angle::Result ProgramExecutableMtl::legalizeUniformBufferOffsets(ContextMtl *context)
1291{
1292    const gl::State &glState                      = context->getState();
1293    const std::vector<gl::InterfaceBlock> &blocks = mExecutable->getUniformBlocks();
1294
1295    for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex)
1296    {
1297        const gl::InterfaceBlock &block = blocks[bufferIndex];
1298        const GLuint binding            = mExecutable->getUniformBlockBinding(bufferIndex);
1299        const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
1300            glState.getIndexedUniformBuffer(binding);
1301
1302        if (bufferBinding.get() == nullptr)
1303        {
1304            continue;
1305        }
1306
1307        BufferMtl *bufferMtl = mtl::GetImpl(bufferBinding.get());
1308        size_t srcOffset     = std::min<size_t>(bufferBinding.getOffset(), bufferMtl->size());
1309        ASSERT(mUniformBlockConversions.find(block.name) != mUniformBlockConversions.end());
1310        const UBOConversionInfo &conversionInfo = mUniformBlockConversions.at(block.name);
1311
1312        size_t spaceAvailable  = bufferMtl->size() - srcOffset;
1313        bool haveSpaceInBuffer = conversionInfo.metalSize() <= spaceAvailable;
1314        if (conversionInfo.needsConversion() || !haveSpaceInBuffer)
1315        {
1316
1317            UniformConversionBufferMtl *conversion =
1318                (UniformConversionBufferMtl *)bufferMtl->getUniformConversionBuffer(
1319                    context, std::pair<size_t, size_t>(bufferIndex, srcOffset),
1320                    conversionInfo.stdSize());
1321            // Has the content of the buffer has changed since last conversion?
1322            if (conversion->dirty)
1323            {
1324                const uint8_t *srcBytes = bufferMtl->getBufferDataReadOnly(context);
1325                srcBytes += conversion->initialSrcOffset();
1326                size_t sizeToCopy = bufferMtl->size() - conversion->initialSrcOffset();
1327
1328                ANGLE_TRY(ConvertUniformBufferData(
1329                    context, conversionInfo, &conversion->data, srcBytes, sizeToCopy,
1330                    &conversion->convertedBuffer, &conversion->convertedOffset));
1331
1332                conversion->dirty = false;
1333            }
1334            // Calculate offset in new block.
1335            size_t dstOffsetSource = srcOffset - conversion->initialSrcOffset();
1336            ASSERT(dstOffsetSource % conversionInfo.stdSize() == 0);
1337            unsigned int numBlocksToOffset =
1338                (unsigned int)(dstOffsetSource / conversionInfo.stdSize());
1339            size_t bytesToOffset = numBlocksToOffset * conversionInfo.metalSize();
1340
1341            mLegalizedOffsetedUniformBuffers[bufferIndex].first = conversion->convertedBuffer;
1342            mLegalizedOffsetedUniformBuffers[bufferIndex].second =
1343                static_cast<uint32_t>(conversion->convertedOffset + bytesToOffset);
1344            // Ensure that the converted info can fit in the buffer.
1345            ASSERT(conversion->convertedOffset + bytesToOffset + conversionInfo.metalSize() <=
1346                   conversion->convertedBuffer->size());
1347        }
1348        else
1349        {
1350            mLegalizedOffsetedUniformBuffers[bufferIndex].first = bufferMtl->getCurrentBuffer();
1351            mLegalizedOffsetedUniformBuffers[bufferIndex].second =
1352                static_cast<uint32_t>(bufferBinding.getOffset());
1353        }
1354    }
1355    return angle::Result::Continue;
1356}
1357
1358angle::Result ProgramExecutableMtl::bindUniformBuffersToDiscreteSlots(
1359    ContextMtl *context,
1360    mtl::RenderCommandEncoder *cmdEncoder,
1361    gl::ShaderType shaderType)
1362{
1363    const gl::State &glState                      = context->getState();
1364    const std::vector<gl::InterfaceBlock> &blocks = mExecutable->getUniformBlocks();
1365    const mtl::TranslatedShaderInfo &shaderInfo =
1366        *mCurrentShaderVariants[shaderType]->translatedSrcInfo;
1367
1368    for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex)
1369    {
1370        const gl::InterfaceBlock &block = blocks[bufferIndex];
1371        const GLuint binding            = mExecutable->getUniformBlockBinding(bufferIndex);
1372        const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
1373            glState.getIndexedUniformBuffer(binding);
1374
1375        if (bufferBinding.get() == nullptr || !block.activeShaders().test(shaderType))
1376        {
1377            continue;
1378        }
1379
1380        uint32_t actualBufferIdx = shaderInfo.actualUBOBindings[bufferIndex];
1381
1382        if (actualBufferIdx >= mtl::kMaxShaderBuffers)
1383        {
1384            continue;
1385        }
1386
1387        mtl::BufferRef mtlBuffer = mLegalizedOffsetedUniformBuffers[bufferIndex].first;
1388        uint32_t offset          = mLegalizedOffsetedUniformBuffers[bufferIndex].second;
1389        cmdEncoder->setBuffer(shaderType, mtlBuffer, offset, actualBufferIdx);
1390    }
1391    return angle::Result::Continue;
1392}
1393
1394angle::Result ProgramExecutableMtl::encodeUniformBuffersInfoArgumentBuffer(
1395    ContextMtl *context,
1396    mtl::RenderCommandEncoder *cmdEncoder,
1397    gl::ShaderType shaderType)
1398{
1399    const gl::State &glState                      = context->getState();
1400    const std::vector<gl::InterfaceBlock> &blocks = mExecutable->getUniformBlocks();
1401
1402    ASSERT(mCurrentShaderVariants[shaderType]->translatedSrcInfo);
1403    const mtl::TranslatedShaderInfo &shaderInfo =
1404        *mCurrentShaderVariants[shaderType]->translatedSrcInfo;
1405
1406    // Encode all uniform buffers into an argument buffer.
1407    ProgramArgumentBufferEncoderMtl &bufferEncoder =
1408        mCurrentShaderVariants[shaderType]->uboArgBufferEncoder;
1409
1410    mtl::BufferRef argumentBuffer;
1411    size_t argumentBufferOffset;
1412    bufferEncoder.bufferPool.releaseInFlightBuffers(context);
1413    ANGLE_TRY(bufferEncoder.bufferPool.allocate(
1414        context, bufferEncoder.metalArgBufferEncoder.get().encodedLength, nullptr, &argumentBuffer,
1415        &argumentBufferOffset));
1416
1417    // MTLArgumentEncoder is modifying the buffer indirectly on CPU. We need to call map()
1418    // so that the buffer's data changes could be flushed to the GPU side later.
1419    ANGLE_UNUSED_VARIABLE(argumentBuffer->mapWithOpt(context, /*readonly=*/false, /*noSync=*/true));
1420
1421    [bufferEncoder.metalArgBufferEncoder setArgumentBuffer:argumentBuffer->get()
1422                                                    offset:argumentBufferOffset];
1423
1424    constexpr gl::ShaderMap<MTLRenderStages> kShaderStageMap = {
1425        {gl::ShaderType::Vertex, MTLRenderStageVertex},
1426        {gl::ShaderType::Fragment, MTLRenderStageFragment},
1427    };
1428
1429    auto mtlRenderStage = kShaderStageMap[shaderType];
1430
1431    for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex)
1432    {
1433        const gl::InterfaceBlock &block = blocks[bufferIndex];
1434        const GLuint binding            = mExecutable->getUniformBlockBinding(bufferIndex);
1435        const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
1436            glState.getIndexedUniformBuffer(binding);
1437
1438        if (bufferBinding.get() == nullptr || !block.activeShaders().test(shaderType))
1439        {
1440            continue;
1441        }
1442
1443        mArgumentBufferRenderStageUsages[bufferIndex] |= mtlRenderStage;
1444
1445        uint32_t actualBufferIdx = shaderInfo.actualUBOBindings[bufferIndex];
1446        if (actualBufferIdx >= mtl::kMaxShaderBuffers)
1447        {
1448            continue;
1449        }
1450
1451        mtl::BufferRef mtlBuffer = mLegalizedOffsetedUniformBuffers[bufferIndex].first;
1452        uint32_t offset          = mLegalizedOffsetedUniformBuffers[bufferIndex].second;
1453        [bufferEncoder.metalArgBufferEncoder setBuffer:mtlBuffer->get()
1454                                                offset:offset
1455                                               atIndex:actualBufferIdx];
1456    }
1457
1458    // Flush changes made by MTLArgumentEncoder to GPU.
1459    argumentBuffer->unmapAndFlushSubset(context, argumentBufferOffset,
1460                                        bufferEncoder.metalArgBufferEncoder.get().encodedLength);
1461
1462    cmdEncoder->setBuffer(shaderType, argumentBuffer, static_cast<uint32_t>(argumentBufferOffset),
1463                          mtl::kUBOArgumentBufferBindingIndex);
1464    return angle::Result::Continue;
1465}
1466
1467angle::Result ProgramExecutableMtl::updateXfbBuffers(ContextMtl *context,
1468                                                     mtl::RenderCommandEncoder *cmdEncoder,
1469                                                     const mtl::RenderPipelineDesc &pipelineDesc)
1470{
1471    const gl::State &glState                 = context->getState();
1472    gl::TransformFeedback *transformFeedback = glState.getCurrentTransformFeedback();
1473
1474    if (pipelineDesc.rasterizationEnabled() || !glState.isTransformFeedbackActiveUnpaused() ||
1475        ANGLE_UNLIKELY(!transformFeedback))
1476    {
1477        // XFB output can only be used with rasterization disabled.
1478        return angle::Result::Continue;
1479    }
1480
1481    size_t xfbBufferCount = glState.getProgramExecutable()->getTransformFeedbackBufferCount();
1482
1483    ASSERT(xfbBufferCount > 0);
1484    ASSERT(mExecutable->getTransformFeedbackBufferMode() != GL_INTERLEAVED_ATTRIBS ||
1485           xfbBufferCount == 1);
1486
1487    for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
1488    {
1489        uint32_t actualBufferIdx = mMslXfbOnlyVertexShaderInfo.actualXFBBindings[bufferIndex];
1490
1491        if (actualBufferIdx >= mtl::kMaxShaderBuffers)
1492        {
1493            continue;
1494        }
1495
1496        const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
1497            transformFeedback->getIndexedBuffer(bufferIndex);
1498        gl::Buffer *buffer = bufferBinding.get();
1499        ASSERT((bufferBinding.getOffset() % 4) == 0);
1500        ASSERT(buffer != nullptr);
1501
1502        BufferMtl *bufferMtl = mtl::GetImpl(buffer);
1503
1504        // Use offset=0, actual offset will be set in Driver Uniform inside ContextMtl.
1505        cmdEncoder->setBufferForWrite(gl::ShaderType::Vertex, bufferMtl->getCurrentBuffer(), 0,
1506                                      actualBufferIdx);
1507    }
1508
1509    return angle::Result::Continue;
1510}
1511
1512template <typename T>
1513void ProgramExecutableMtl::setUniformImpl(GLint location,
1514                                          GLsizei count,
1515                                          const T *v,
1516                                          GLenum entryPointType)
1517{
1518    const std::vector<gl::VariableLocation> &uniformLocations = mExecutable->getUniformLocations();
1519    const gl::VariableLocation &locationInfo                  = uniformLocations[location];
1520
1521    const std::vector<gl::LinkedUniform> &linkedUniforms = mExecutable->getUniforms();
1522    const gl::LinkedUniform &linkedUniform               = linkedUniforms[locationInfo.index];
1523
1524    if (linkedUniform.isSampler())
1525    {
1526        // Sampler binding has changed.
1527        mSamplerBindingsDirty.set();
1528        return;
1529    }
1530
1531    if (linkedUniform.getType() == entryPointType)
1532    {
1533        for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes)
1534        {
1535            DefaultUniformBlockMtl &uniformBlock  = mDefaultUniformBlocks[shaderType];
1536            const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
1537
1538            // Assume an offset of -1 means the block is unused.
1539            if (layoutInfo.offset == -1)
1540            {
1541                continue;
1542            }
1543
1544            const GLint componentCount    = (GLint)linkedUniform.getElementComponents();
1545            const GLint baseComponentSize = (GLint)mtl::GetMetalSizeForGLType(
1546                gl::VariableComponentType(linkedUniform.getType()));
1547            UpdateDefaultUniformBlockWithElementSize(count, locationInfo.arrayIndex, componentCount,
1548                                                     v, baseComponentSize, layoutInfo,
1549                                                     &uniformBlock.uniformData);
1550            mDefaultUniformBlocksDirty.set(shaderType);
1551        }
1552    }
1553    else
1554    {
1555        for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes)
1556        {
1557            DefaultUniformBlockMtl &uniformBlock  = mDefaultUniformBlocks[shaderType];
1558            const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
1559
1560            // Assume an offset of -1 means the block is unused.
1561            if (layoutInfo.offset == -1)
1562            {
1563                continue;
1564            }
1565
1566            const GLint componentCount = linkedUniform.getElementComponents();
1567
1568            ASSERT(linkedUniform.getType() == gl::VariableBoolVectorType(entryPointType));
1569
1570            GLint initialArrayOffset =
1571                locationInfo.arrayIndex * layoutInfo.arrayStride + layoutInfo.offset;
1572            for (GLint i = 0; i < count; i++)
1573            {
1574                GLint elementOffset = i * layoutInfo.arrayStride + initialArrayOffset;
1575                bool *dest =
1576                    reinterpret_cast<bool *>(uniformBlock.uniformData.data() + elementOffset);
1577                const T *source = v + i * componentCount;
1578
1579                for (int c = 0; c < componentCount; c++)
1580                {
1581                    dest[c] = (source[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE;
1582                }
1583            }
1584
1585            mDefaultUniformBlocksDirty.set(shaderType);
1586        }
1587    }
1588}
1589
1590template <typename T>
1591void ProgramExecutableMtl::getUniformImpl(GLint location, T *v, GLenum entryPointType) const
1592{
1593    const gl::VariableLocation &locationInfo = mExecutable->getUniformLocations()[location];
1594    const gl::LinkedUniform &linkedUniform   = mExecutable->getUniforms()[locationInfo.index];
1595
1596    ASSERT(!linkedUniform.isSampler());
1597
1598    const gl::ShaderType shaderType = linkedUniform.getFirstActiveShaderType();
1599    ASSERT(shaderType != gl::ShaderType::InvalidEnum);
1600
1601    const DefaultUniformBlockMtl &uniformBlock = mDefaultUniformBlocks[shaderType];
1602    const sh::BlockMemberInfo &layoutInfo      = uniformBlock.uniformLayout[location];
1603
1604    ASSERT(linkedUniform.getUniformTypeInfo().componentType == entryPointType ||
1605           linkedUniform.getUniformTypeInfo().componentType ==
1606               gl::VariableBoolVectorType(entryPointType));
1607    const GLint baseComponentSize =
1608        (GLint)mtl::GetMetalSizeForGLType(gl::VariableComponentType(linkedUniform.getType()));
1609
1610    if (gl::IsMatrixType(linkedUniform.getType()))
1611    {
1612        const uint8_t *ptrToElement = uniformBlock.uniformData.data() + layoutInfo.offset +
1613                                      (locationInfo.arrayIndex * layoutInfo.arrayStride);
1614        mtl::GetMatrixUniformMetal(linkedUniform.getType(), v,
1615                                   reinterpret_cast<const T *>(ptrToElement), false);
1616    }
1617    // Decompress bool from one byte to four bytes because bool values in GLSL
1618    // are uint-sized: ES 3.0 Section 2.12.6.3 "Uniform Buffer Object Storage".
1619    else if (gl::VariableComponentType(linkedUniform.getType()) == GL_BOOL)
1620    {
1621        bool bVals[4] = {0};
1622        ReadFromDefaultUniformBlockWithElementSize(
1623            linkedUniform.getElementComponents(), locationInfo.arrayIndex, bVals, baseComponentSize,
1624            layoutInfo, &uniformBlock.uniformData);
1625        for (int bCol = 0; bCol < linkedUniform.getElementComponents(); ++bCol)
1626        {
1627            unsigned int data = bVals[bCol];
1628            *(v + bCol)       = static_cast<T>(data);
1629        }
1630    }
1631    else
1632    {
1633
1634        assert(baseComponentSize == sizeof(T));
1635        ReadFromDefaultUniformBlockWithElementSize(linkedUniform.getElementComponents(),
1636                                                   locationInfo.arrayIndex, v, baseComponentSize,
1637                                                   layoutInfo, &uniformBlock.uniformData);
1638    }
1639}
1640
1641void ProgramExecutableMtl::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1642{
1643    setUniformImpl(location, count, v, GL_FLOAT);
1644}
1645
1646void ProgramExecutableMtl::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1647{
1648    setUniformImpl(location, count, v, GL_FLOAT_VEC2);
1649}
1650
1651void ProgramExecutableMtl::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1652{
1653    setUniformImpl(location, count, v, GL_FLOAT_VEC3);
1654}
1655
1656void ProgramExecutableMtl::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1657{
1658    setUniformImpl(location, count, v, GL_FLOAT_VEC4);
1659}
1660
1661void ProgramExecutableMtl::setUniform1iv(GLint startLocation, GLsizei count, const GLint *v)
1662{
1663    setUniformImpl(startLocation, count, v, GL_INT);
1664}
1665
1666void ProgramExecutableMtl::setUniform2iv(GLint location, GLsizei count, const GLint *v)
1667{
1668    setUniformImpl(location, count, v, GL_INT_VEC2);
1669}
1670
1671void ProgramExecutableMtl::setUniform3iv(GLint location, GLsizei count, const GLint *v)
1672{
1673    setUniformImpl(location, count, v, GL_INT_VEC3);
1674}
1675
1676void ProgramExecutableMtl::setUniform4iv(GLint location, GLsizei count, const GLint *v)
1677{
1678    setUniformImpl(location, count, v, GL_INT_VEC4);
1679}
1680
1681void ProgramExecutableMtl::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
1682{
1683    setUniformImpl(location, count, v, GL_UNSIGNED_INT);
1684}
1685
1686void ProgramExecutableMtl::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
1687{
1688    setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC2);
1689}
1690
1691void ProgramExecutableMtl::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
1692{
1693    setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC3);
1694}
1695
1696void ProgramExecutableMtl::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
1697{
1698    setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC4);
1699}
1700
1701template <int cols, int rows>
1702void ProgramExecutableMtl::setUniformMatrixfv(GLint location,
1703                                              GLsizei count,
1704                                              GLboolean transpose,
1705                                              const GLfloat *value)
1706{
1707    const gl::VariableLocation &locationInfo = mExecutable->getUniformLocations()[location];
1708    const gl::LinkedUniform &linkedUniform   = mExecutable->getUniforms()[locationInfo.index];
1709
1710    for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes)
1711    {
1712        DefaultUniformBlockMtl &uniformBlock  = mDefaultUniformBlocks[shaderType];
1713        const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
1714
1715        // Assume an offset of -1 means the block is unused.
1716        if (layoutInfo.offset == -1)
1717        {
1718            continue;
1719        }
1720
1721        mtl::SetFloatUniformMatrixMetal<cols, rows>::Run(
1722            locationInfo.arrayIndex, linkedUniform.getBasicTypeElementCount(), count, transpose,
1723            value, uniformBlock.uniformData.data() + layoutInfo.offset);
1724
1725        mDefaultUniformBlocksDirty.set(shaderType);
1726    }
1727}
1728
1729void ProgramExecutableMtl::setUniformMatrix2fv(GLint location,
1730                                               GLsizei count,
1731                                               GLboolean transpose,
1732                                               const GLfloat *value)
1733{
1734    setUniformMatrixfv<2, 2>(location, count, transpose, value);
1735}
1736
1737void ProgramExecutableMtl::setUniformMatrix3fv(GLint location,
1738                                               GLsizei count,
1739                                               GLboolean transpose,
1740                                               const GLfloat *value)
1741{
1742    setUniformMatrixfv<3, 3>(location, count, transpose, value);
1743}
1744
1745void ProgramExecutableMtl::setUniformMatrix4fv(GLint location,
1746                                               GLsizei count,
1747                                               GLboolean transpose,
1748                                               const GLfloat *value)
1749{
1750    setUniformMatrixfv<4, 4>(location, count, transpose, value);
1751}
1752
1753void ProgramExecutableMtl::setUniformMatrix2x3fv(GLint location,
1754                                                 GLsizei count,
1755                                                 GLboolean transpose,
1756                                                 const GLfloat *value)
1757{
1758    setUniformMatrixfv<2, 3>(location, count, transpose, value);
1759}
1760
1761void ProgramExecutableMtl::setUniformMatrix3x2fv(GLint location,
1762                                                 GLsizei count,
1763                                                 GLboolean transpose,
1764                                                 const GLfloat *value)
1765{
1766    setUniformMatrixfv<3, 2>(location, count, transpose, value);
1767}
1768
1769void ProgramExecutableMtl::setUniformMatrix2x4fv(GLint location,
1770                                                 GLsizei count,
1771                                                 GLboolean transpose,
1772                                                 const GLfloat *value)
1773{
1774    setUniformMatrixfv<2, 4>(location, count, transpose, value);
1775}
1776
1777void ProgramExecutableMtl::setUniformMatrix4x2fv(GLint location,
1778                                                 GLsizei count,
1779                                                 GLboolean transpose,
1780                                                 const GLfloat *value)
1781{
1782    setUniformMatrixfv<4, 2>(location, count, transpose, value);
1783}
1784
1785void ProgramExecutableMtl::setUniformMatrix3x4fv(GLint location,
1786                                                 GLsizei count,
1787                                                 GLboolean transpose,
1788                                                 const GLfloat *value)
1789{
1790    setUniformMatrixfv<3, 4>(location, count, transpose, value);
1791}
1792
1793void ProgramExecutableMtl::setUniformMatrix4x3fv(GLint location,
1794                                                 GLsizei count,
1795                                                 GLboolean transpose,
1796                                                 const GLfloat *value)
1797{
1798    setUniformMatrixfv<4, 3>(location, count, transpose, value);
1799}
1800
1801void ProgramExecutableMtl::getUniformfv(const gl::Context *context,
1802                                        GLint location,
1803                                        GLfloat *params) const
1804{
1805    getUniformImpl(location, params, GL_FLOAT);
1806}
1807
1808void ProgramExecutableMtl::getUniformiv(const gl::Context *context,
1809                                        GLint location,
1810                                        GLint *params) const
1811{
1812    getUniformImpl(location, params, GL_INT);
1813}
1814
1815void ProgramExecutableMtl::getUniformuiv(const gl::Context *context,
1816                                         GLint location,
1817                                         GLuint *params) const
1818{
1819    getUniformImpl(location, params, GL_UNSIGNED_INT);
1820}
1821}  // namespace rx
1822