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