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