• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1//
2// Copyright 2019 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6// ProgramMtl.mm:
7//    Implements the class methods for ProgramMtl.
8//
9
10#include "libANGLE/renderer/metal/ProgramMtl.h"
11
12#include <TargetConditionals.h>
13
14#include <sstream>
15
16#include "common/debug.h"
17#include "libANGLE/Context.h"
18#include "libANGLE/ProgramLinkedResources.h"
19#include "libANGLE/renderer/metal/ContextMtl.h"
20#include "libANGLE/renderer/metal/DisplayMtl.h"
21#include "libANGLE/renderer/metal/TextureMtl.h"
22#include "libANGLE/renderer/metal/mtl_glslang_utils.h"
23#include "libANGLE/renderer/metal/mtl_utils.h"
24#include "libANGLE/renderer/renderer_utils.h"
25
26namespace rx
27{
28
29namespace
30{
31
32#define SHADER_ENTRY_NAME @"main0"
33
34void InitDefaultUniformBlock(const std::vector<sh::Uniform> &uniforms,
35                             gl::Shader *shader,
36                             sh::BlockLayoutMap *blockLayoutMapOut,
37                             size_t *blockSizeOut)
38{
39    if (uniforms.empty())
40    {
41        *blockSizeOut = 0;
42        return;
43    }
44
45    sh::Std140BlockEncoder blockEncoder;
46    sh::GetActiveUniformBlockInfo(uniforms, "", &blockEncoder, blockLayoutMapOut);
47
48    size_t blockSize = blockEncoder.getCurrentOffset();
49
50    if (blockSize == 0)
51    {
52        *blockSizeOut = 0;
53        return;
54    }
55
56    // Need to round up to multiple of vec4
57    *blockSizeOut = roundUp(blockSize, static_cast<size_t>(16));
58    return;
59}
60
61template <typename T>
62void UpdateDefaultUniformBlock(GLsizei count,
63                               uint32_t arrayIndex,
64                               int componentCount,
65                               const T *v,
66                               const sh::BlockMemberInfo &layoutInfo,
67                               angle::MemoryBuffer *uniformData)
68{
69    const int elementSize = sizeof(T) * componentCount;
70
71    uint8_t *dst = uniformData->data() + layoutInfo.offset;
72    if (layoutInfo.arrayStride == 0 || layoutInfo.arrayStride == elementSize)
73    {
74        uint32_t arrayOffset = arrayIndex * layoutInfo.arrayStride;
75        uint8_t *writePtr    = dst + arrayOffset;
76        ASSERT(writePtr + (elementSize * count) <= uniformData->data() + uniformData->size());
77        memcpy(writePtr, v, elementSize * count);
78    }
79    else
80    {
81        // Have to respect the arrayStride between each element of the array.
82        int maxIndex = arrayIndex + count;
83        for (int writeIndex = arrayIndex, readIndex = 0; writeIndex < maxIndex;
84             writeIndex++, readIndex++)
85        {
86            const int arrayOffset = writeIndex * layoutInfo.arrayStride;
87            uint8_t *writePtr     = dst + arrayOffset;
88            const T *readPtr      = v + (readIndex * componentCount);
89            ASSERT(writePtr + elementSize <= uniformData->data() + uniformData->size());
90            memcpy(writePtr, readPtr, elementSize);
91        }
92    }
93}
94
95template <typename T>
96void ReadFromDefaultUniformBlock(int componentCount,
97                                 uint32_t arrayIndex,
98                                 T *dst,
99                                 const sh::BlockMemberInfo &layoutInfo,
100                                 const angle::MemoryBuffer *uniformData)
101{
102    ASSERT(layoutInfo.offset != -1);
103
104    const int elementSize = sizeof(T) * componentCount;
105    const uint8_t *source = uniformData->data() + layoutInfo.offset;
106
107    if (layoutInfo.arrayStride == 0 || layoutInfo.arrayStride == elementSize)
108    {
109        const uint8_t *readPtr = source + arrayIndex * layoutInfo.arrayStride;
110        memcpy(dst, readPtr, elementSize);
111    }
112    else
113    {
114        // Have to respect the arrayStride between each element of the array.
115        const int arrayOffset  = arrayIndex * layoutInfo.arrayStride;
116        const uint8_t *readPtr = source + arrayOffset;
117        memcpy(dst, readPtr, elementSize);
118    }
119}
120
121class Std140BlockLayoutEncoderFactory : public gl::CustomBlockLayoutEncoderFactory
122{
123  public:
124    sh::BlockLayoutEncoder *makeEncoder() override { return new sh::Std140BlockEncoder(); }
125};
126
127}  // namespace
128
129// ProgramMtl implementation
130ProgramMtl::DefaultUniformBlock::DefaultUniformBlock() {}
131
132ProgramMtl::DefaultUniformBlock::~DefaultUniformBlock() = default;
133
134ProgramMtl::ProgramMtl(const gl::ProgramState &state) : ProgramImpl(state) {}
135
136ProgramMtl::~ProgramMtl() {}
137
138void ProgramMtl::destroy(const gl::Context *context)
139{
140    auto contextMtl = mtl::GetImpl(context);
141
142    reset(contextMtl);
143}
144
145void ProgramMtl::reset(ContextMtl *context)
146{
147    for (auto &block : mDefaultUniformBlocks)
148    {
149        block.uniformLayout.clear();
150    }
151
152    for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
153    {
154        for (mtl::SamplerBinding &binding :
155             mMslShaderTranslateInfo[shaderType].actualSamplerBindings)
156        {
157            binding.textureBinding = mtl::kMaxShaderSamplers;
158        }
159    }
160
161    mMetalRenderPipelineCache.clear();
162}
163
164std::unique_ptr<rx::LinkEvent> ProgramMtl::load(const gl::Context *context,
165                                                gl::BinaryInputStream *stream,
166                                                gl::InfoLog &infoLog)
167{
168    // NOTE(hqle): support binary shader
169    UNIMPLEMENTED();
170    return std::make_unique<LinkEventDone>(angle::Result::Stop);
171}
172
173void ProgramMtl::save(const gl::Context *context, gl::BinaryOutputStream *stream)
174{
175    // NOTE(hqle): support binary shader
176    UNIMPLEMENTED();
177}
178
179void ProgramMtl::setBinaryRetrievableHint(bool retrievable)
180{
181    UNIMPLEMENTED();
182}
183
184void ProgramMtl::setSeparable(bool separable)
185{
186    UNIMPLEMENTED();
187}
188
189std::unique_ptr<LinkEvent> ProgramMtl::link(const gl::Context *context,
190                                            const gl::ProgramLinkedResources &resources,
191                                            gl::InfoLog &infoLog)
192{
193    // Link resources before calling GetShaderSource to make sure they are ready for the set/binding
194    // assignment done in that function.
195    linkResources(resources);
196
197    // NOTE(hqle): Parallelize linking.
198    return std::make_unique<LinkEventDone>(linkImpl(context, resources, infoLog));
199}
200
201angle::Result ProgramMtl::linkImpl(const gl::Context *glContext,
202                                   const gl::ProgramLinkedResources &resources,
203                                   gl::InfoLog &infoLog)
204{
205    ContextMtl *contextMtl = mtl::GetImpl(glContext);
206    // NOTE(hqle): No transform feedbacks for now, since we only support ES 2.0 atm
207
208    reset(contextMtl);
209
210    ANGLE_TRY(initDefaultUniformBlocks(glContext));
211
212    // Gather variable info and transform sources.
213    gl::ShaderMap<std::string> shaderSources;
214    ShaderMapInterfaceVariableInfoMap variableInfoMap;
215    mtl::GlslangGetShaderSource(mState, resources, &shaderSources, &variableInfoMap);
216
217    // Convert GLSL to spirv code
218    gl::ShaderMap<std::vector<uint32_t>> shaderCodes;
219    ANGLE_TRY(mtl::GlslangGetShaderSpirvCode(
220        contextMtl, mState.getExecutable().getLinkedShaderStages(), contextMtl->getCaps(),
221        shaderSources, variableInfoMap, &shaderCodes));
222
223    // Convert spirv code to MSL
224    ANGLE_TRY(mtl::SpirvCodeToMsl(contextMtl, mState, &shaderCodes, &mMslShaderTranslateInfo,
225                                  &mTranslatedMslShader));
226
227    for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
228    {
229        // Create actual Metal shader
230        ANGLE_TRY(
231            createMslShader(glContext, shaderType, infoLog, mTranslatedMslShader[shaderType]));
232    }
233
234    return angle::Result::Continue;
235}
236
237void ProgramMtl::linkResources(const gl::ProgramLinkedResources &resources)
238{
239    Std140BlockLayoutEncoderFactory std140EncoderFactory;
240    gl::ProgramLinkedResourcesLinker linker(&std140EncoderFactory);
241
242    linker.linkResources(mState, resources);
243}
244
245angle::Result ProgramMtl::initDefaultUniformBlocks(const gl::Context *glContext)
246{
247    ContextMtl *contextMtl = mtl::GetImpl(glContext);
248
249    // Process vertex and fragment uniforms into std140 packing.
250    gl::ShaderMap<sh::BlockLayoutMap> layoutMap;
251    gl::ShaderMap<size_t> requiredBufferSize;
252    requiredBufferSize.fill(0);
253
254    for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
255    {
256        gl::Shader *shader = mState.getAttachedShader(shaderType);
257        if (shader)
258        {
259            const std::vector<sh::Uniform> &uniforms = shader->getUniforms();
260            InitDefaultUniformBlock(uniforms, shader, &layoutMap[shaderType],
261                                    &requiredBufferSize[shaderType]);
262        }
263    }
264
265    // Init the default block layout info.
266    const auto &uniforms         = mState.getUniforms();
267    const auto &uniformLocations = mState.getUniformLocations();
268    for (size_t locSlot = 0; locSlot < uniformLocations.size(); ++locSlot)
269    {
270        const gl::VariableLocation &location = uniformLocations[locSlot];
271        gl::ShaderMap<sh::BlockMemberInfo> layoutInfo;
272
273        if (location.used() && !location.ignored)
274        {
275            const gl::LinkedUniform &uniform = uniforms[location.index];
276            if (uniform.isInDefaultBlock() && !uniform.isSampler())
277            {
278                std::string uniformName = uniform.name;
279                if (uniform.isArray())
280                {
281                    // Gets the uniform name without the [0] at the end.
282                    uniformName = gl::ParseResourceName(uniformName, nullptr);
283                }
284
285                bool found = false;
286
287                for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
288                {
289                    auto it = layoutMap[shaderType].find(uniformName);
290                    if (it != layoutMap[shaderType].end())
291                    {
292                        found                  = true;
293                        layoutInfo[shaderType] = it->second;
294                    }
295                }
296
297                ASSERT(found);
298            }
299        }
300
301        for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
302        {
303            mDefaultUniformBlocks[shaderType].uniformLayout.push_back(layoutInfo[shaderType]);
304        }
305    }
306
307    for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
308    {
309        if (requiredBufferSize[shaderType] > 0)
310        {
311            ASSERT(requiredBufferSize[shaderType] <= mtl::kDefaultUniformsMaxSize);
312
313            if (!mDefaultUniformBlocks[shaderType].uniformData.resize(
314                    requiredBufferSize[shaderType]))
315            {
316                ANGLE_MTL_CHECK(contextMtl, false, GL_OUT_OF_MEMORY);
317            }
318
319            // Initialize uniform buffer memory to zero by default.
320            mDefaultUniformBlocks[shaderType].uniformData.fill(0);
321            mDefaultUniformBlocksDirty.set(shaderType);
322        }
323    }
324
325    return angle::Result::Continue;
326}
327
328angle::Result ProgramMtl::createMslShader(const gl::Context *glContext,
329                                          gl::ShaderType shaderType,
330                                          gl::InfoLog &infoLog,
331                                          const std::string &translatedMsl)
332{
333    ANGLE_MTL_OBJC_SCOPE
334    {
335        ContextMtl *contextMtl  = mtl::GetImpl(glContext);
336        DisplayMtl *display     = contextMtl->getDisplay();
337        id<MTLDevice> mtlDevice = display->getMetalDevice();
338
339        // Convert to actual binary shader
340        mtl::AutoObjCPtr<NSError *> err = nil;
341        mtl::AutoObjCPtr<id<MTLLibrary>> mtlShaderLib =
342            mtl::CreateShaderLibrary(mtlDevice, translatedMsl, &err);
343        if (err && !mtlShaderLib)
344        {
345            std::ostringstream ss;
346            ss << "Internal error compiling Metal shader:\n"
347               << err.get().localizedDescription.UTF8String << "\n";
348
349            ERR() << ss.str();
350
351            infoLog << ss.str();
352
353            ANGLE_MTL_CHECK(contextMtl, false, GL_INVALID_OPERATION);
354        }
355
356        auto mtlShader = [mtlShaderLib.get() newFunctionWithName:SHADER_ENTRY_NAME];
357        [mtlShader ANGLE_MTL_AUTORELEASE];
358        ASSERT(mtlShader);
359        if (shaderType == gl::ShaderType::Vertex)
360        {
361            mMetalRenderPipelineCache.setVertexShader(contextMtl, mtlShader);
362        }
363        else if (shaderType == gl::ShaderType::Fragment)
364        {
365            mMetalRenderPipelineCache.setFragmentShader(contextMtl, mtlShader);
366        }
367
368        return angle::Result::Continue;
369    }
370}
371
372GLboolean ProgramMtl::validate(const gl::Caps &caps, gl::InfoLog *infoLog)
373{
374    // No-op. The spec is very vague about the behavior of validation.
375    return GL_TRUE;
376}
377
378template <typename T>
379void ProgramMtl::setUniformImpl(GLint location, GLsizei count, const T *v, GLenum entryPointType)
380{
381    const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location];
382    const gl::LinkedUniform &linkedUniform   = mState.getUniforms()[locationInfo.index];
383
384    if (linkedUniform.isSampler())
385    {
386        // Sampler binding has changed.
387        mSamplerBindingsDirty.set();
388        return;
389    }
390
391    if (linkedUniform.typeInfo->type == entryPointType)
392    {
393        for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
394        {
395            DefaultUniformBlock &uniformBlock     = mDefaultUniformBlocks[shaderType];
396            const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
397
398            // Assume an offset of -1 means the block is unused.
399            if (layoutInfo.offset == -1)
400            {
401                continue;
402            }
403
404            const GLint componentCount = linkedUniform.typeInfo->componentCount;
405            UpdateDefaultUniformBlock(count, locationInfo.arrayIndex, componentCount, v, layoutInfo,
406                                      &uniformBlock.uniformData);
407            mDefaultUniformBlocksDirty.set(shaderType);
408        }
409    }
410    else
411    {
412        for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
413        {
414            DefaultUniformBlock &uniformBlock     = mDefaultUniformBlocks[shaderType];
415            const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
416
417            // Assume an offset of -1 means the block is unused.
418            if (layoutInfo.offset == -1)
419            {
420                continue;
421            }
422
423            const GLint componentCount = linkedUniform.typeInfo->componentCount;
424
425            ASSERT(linkedUniform.typeInfo->type == gl::VariableBoolVectorType(entryPointType));
426
427            GLint initialArrayOffset =
428                locationInfo.arrayIndex * layoutInfo.arrayStride + layoutInfo.offset;
429            for (GLint i = 0; i < count; i++)
430            {
431                GLint elementOffset = i * layoutInfo.arrayStride + initialArrayOffset;
432                GLint *dest =
433                    reinterpret_cast<GLint *>(uniformBlock.uniformData.data() + elementOffset);
434                const T *source = v + i * componentCount;
435
436                for (int c = 0; c < componentCount; c++)
437                {
438                    dest[c] = (source[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE;
439                }
440            }
441
442            mDefaultUniformBlocksDirty.set(shaderType);
443        }
444    }
445}
446
447template <typename T>
448void ProgramMtl::getUniformImpl(GLint location, T *v, GLenum entryPointType) const
449{
450    const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location];
451    const gl::LinkedUniform &linkedUniform   = mState.getUniforms()[locationInfo.index];
452
453    ASSERT(!linkedUniform.isSampler());
454
455    const gl::ShaderType shaderType = linkedUniform.getFirstShaderTypeWhereActive();
456    ASSERT(shaderType != gl::ShaderType::InvalidEnum);
457
458    const DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType];
459    const sh::BlockMemberInfo &layoutInfo   = uniformBlock.uniformLayout[location];
460
461    ASSERT(linkedUniform.typeInfo->componentType == entryPointType ||
462           linkedUniform.typeInfo->componentType == gl::VariableBoolVectorType(entryPointType));
463
464    if (gl::IsMatrixType(linkedUniform.type))
465    {
466        const uint8_t *ptrToElement = uniformBlock.uniformData.data() + layoutInfo.offset +
467                                      (locationInfo.arrayIndex * layoutInfo.arrayStride);
468        GetMatrixUniform(linkedUniform.type, v, reinterpret_cast<const T *>(ptrToElement), false);
469    }
470    else
471    {
472        ReadFromDefaultUniformBlock(linkedUniform.typeInfo->componentCount, locationInfo.arrayIndex,
473                                    v, layoutInfo, &uniformBlock.uniformData);
474    }
475}
476
477void ProgramMtl::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
478{
479    setUniformImpl(location, count, v, GL_FLOAT);
480}
481
482void ProgramMtl::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
483{
484    setUniformImpl(location, count, v, GL_FLOAT_VEC2);
485}
486
487void ProgramMtl::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
488{
489    setUniformImpl(location, count, v, GL_FLOAT_VEC3);
490}
491
492void ProgramMtl::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
493{
494    setUniformImpl(location, count, v, GL_FLOAT_VEC4);
495}
496
497void ProgramMtl::setUniform1iv(GLint startLocation, GLsizei count, const GLint *v)
498{
499    setUniformImpl(startLocation, count, v, GL_INT);
500}
501
502void ProgramMtl::setUniform2iv(GLint location, GLsizei count, const GLint *v)
503{
504    setUniformImpl(location, count, v, GL_INT_VEC2);
505}
506
507void ProgramMtl::setUniform3iv(GLint location, GLsizei count, const GLint *v)
508{
509    setUniformImpl(location, count, v, GL_INT_VEC3);
510}
511
512void ProgramMtl::setUniform4iv(GLint location, GLsizei count, const GLint *v)
513{
514    setUniformImpl(location, count, v, GL_INT_VEC4);
515}
516
517void ProgramMtl::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
518{
519    setUniformImpl(location, count, v, GL_UNSIGNED_INT);
520}
521
522void ProgramMtl::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
523{
524    setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC2);
525}
526
527void ProgramMtl::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
528{
529    setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC3);
530}
531
532void ProgramMtl::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
533{
534    setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC4);
535}
536
537template <int cols, int rows>
538void ProgramMtl::setUniformMatrixfv(GLint location,
539                                    GLsizei count,
540                                    GLboolean transpose,
541                                    const GLfloat *value)
542{
543    const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location];
544    const gl::LinkedUniform &linkedUniform   = mState.getUniforms()[locationInfo.index];
545
546    for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
547    {
548        DefaultUniformBlock &uniformBlock     = mDefaultUniformBlocks[shaderType];
549        const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
550
551        // Assume an offset of -1 means the block is unused.
552        if (layoutInfo.offset == -1)
553        {
554            continue;
555        }
556
557        SetFloatUniformMatrixGLSL<cols, rows>::Run(
558            locationInfo.arrayIndex, linkedUniform.getArraySizeProduct(), count, transpose, value,
559            uniformBlock.uniformData.data() + layoutInfo.offset);
560
561        mDefaultUniformBlocksDirty.set(shaderType);
562    }
563}
564
565void ProgramMtl::setUniformMatrix2fv(GLint location,
566                                     GLsizei count,
567                                     GLboolean transpose,
568                                     const GLfloat *value)
569{
570    setUniformMatrixfv<2, 2>(location, count, transpose, value);
571}
572
573void ProgramMtl::setUniformMatrix3fv(GLint location,
574                                     GLsizei count,
575                                     GLboolean transpose,
576                                     const GLfloat *value)
577{
578    setUniformMatrixfv<3, 3>(location, count, transpose, value);
579}
580
581void ProgramMtl::setUniformMatrix4fv(GLint location,
582                                     GLsizei count,
583                                     GLboolean transpose,
584                                     const GLfloat *value)
585{
586    setUniformMatrixfv<4, 4>(location, count, transpose, value);
587}
588
589void ProgramMtl::setUniformMatrix2x3fv(GLint location,
590                                       GLsizei count,
591                                       GLboolean transpose,
592                                       const GLfloat *value)
593{
594    setUniformMatrixfv<2, 3>(location, count, transpose, value);
595}
596
597void ProgramMtl::setUniformMatrix3x2fv(GLint location,
598                                       GLsizei count,
599                                       GLboolean transpose,
600                                       const GLfloat *value)
601{
602    setUniformMatrixfv<3, 2>(location, count, transpose, value);
603}
604
605void ProgramMtl::setUniformMatrix2x4fv(GLint location,
606                                       GLsizei count,
607                                       GLboolean transpose,
608                                       const GLfloat *value)
609{
610    setUniformMatrixfv<2, 4>(location, count, transpose, value);
611}
612
613void ProgramMtl::setUniformMatrix4x2fv(GLint location,
614                                       GLsizei count,
615                                       GLboolean transpose,
616                                       const GLfloat *value)
617{
618    setUniformMatrixfv<4, 2>(location, count, transpose, value);
619}
620
621void ProgramMtl::setUniformMatrix3x4fv(GLint location,
622                                       GLsizei count,
623                                       GLboolean transpose,
624                                       const GLfloat *value)
625{
626    setUniformMatrixfv<3, 4>(location, count, transpose, value);
627}
628
629void ProgramMtl::setUniformMatrix4x3fv(GLint location,
630                                       GLsizei count,
631                                       GLboolean transpose,
632                                       const GLfloat *value)
633{
634    setUniformMatrixfv<4, 3>(location, count, transpose, value);
635}
636
637void ProgramMtl::getUniformfv(const gl::Context *context, GLint location, GLfloat *params) const
638{
639    getUniformImpl(location, params, GL_FLOAT);
640}
641
642void ProgramMtl::getUniformiv(const gl::Context *context, GLint location, GLint *params) const
643{
644    getUniformImpl(location, params, GL_INT);
645}
646
647void ProgramMtl::getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const
648{
649    getUniformImpl(location, params, GL_UNSIGNED_INT);
650}
651
652angle::Result ProgramMtl::setupDraw(const gl::Context *glContext,
653                                    mtl::RenderCommandEncoder *cmdEncoder,
654                                    const Optional<mtl::RenderPipelineDesc> &changedPipelineDescOpt,
655                                    bool forceTexturesSetting)
656{
657    ContextMtl *context = mtl::GetImpl(glContext);
658    if (changedPipelineDescOpt.valid())
659    {
660        const auto &changedPipelineDesc = changedPipelineDescOpt.value();
661        // Render pipeline state needs to be changed
662        id<MTLRenderPipelineState> pipelineState =
663            mMetalRenderPipelineCache.getRenderPipelineState(context, changedPipelineDesc);
664        if (!pipelineState)
665        {
666            // Error already logged inside getRenderPipelineState()
667            return angle::Result::Stop;
668        }
669        cmdEncoder->setRenderPipelineState(pipelineState);
670
671        // We need to rebind uniform buffers & textures also
672        mDefaultUniformBlocksDirty.set();
673        mSamplerBindingsDirty.set();
674    }
675
676    ANGLE_TRY(commitUniforms(context, cmdEncoder));
677    ANGLE_TRY(updateTextures(glContext, cmdEncoder, forceTexturesSetting));
678
679    return angle::Result::Continue;
680}
681
682angle::Result ProgramMtl::commitUniforms(ContextMtl *context, mtl::RenderCommandEncoder *cmdEncoder)
683{
684    for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
685    {
686        if (!mDefaultUniformBlocksDirty[shaderType])
687        {
688            continue;
689        }
690        DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType];
691
692        if (!uniformBlock.uniformData.size())
693        {
694            continue;
695        }
696        switch (shaderType)
697        {
698            case gl::ShaderType::Vertex:
699                cmdEncoder->setVertexBytes(uniformBlock.uniformData.data(),
700                                           uniformBlock.uniformData.size(),
701                                           mtl::kDefaultUniformsBindingIndex);
702                break;
703            case gl::ShaderType::Fragment:
704                cmdEncoder->setFragmentBytes(uniformBlock.uniformData.data(),
705                                             uniformBlock.uniformData.size(),
706                                             mtl::kDefaultUniformsBindingIndex);
707                break;
708            default:
709                UNREACHABLE();
710        }
711
712        mDefaultUniformBlocksDirty.reset(shaderType);
713    }
714
715    return angle::Result::Continue;
716}
717
718angle::Result ProgramMtl::updateTextures(const gl::Context *glContext,
719                                         mtl::RenderCommandEncoder *cmdEncoder,
720                                         bool forceUpdate)
721{
722    ContextMtl *contextMtl = mtl::GetImpl(glContext);
723    const auto &glState    = glContext->getState();
724
725    const gl::ActiveTexturesCache &completeTextures = glState.getActiveTexturesCache();
726
727    for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
728    {
729        if (!mSamplerBindingsDirty[shaderType] && !forceUpdate)
730        {
731            continue;
732        }
733
734        for (uint32_t textureIndex = 0; textureIndex < mState.getSamplerBindings().size();
735             ++textureIndex)
736        {
737            const gl::SamplerBinding &samplerBinding = mState.getSamplerBindings()[textureIndex];
738
739            ASSERT(!samplerBinding.unreferenced);
740
741            const mtl::SamplerBinding &mslBinding =
742                mMslShaderTranslateInfo[shaderType].actualSamplerBindings[textureIndex];
743            if (mslBinding.textureBinding >= mtl::kMaxShaderSamplers)
744            {
745                // No binding assigned
746                continue;
747            }
748
749            gl::TextureType textureType = samplerBinding.textureType;
750
751            for (uint32_t arrayElement = 0; arrayElement < samplerBinding.boundTextureUnits.size();
752                 ++arrayElement)
753            {
754                GLuint textureUnit   = samplerBinding.boundTextureUnits[arrayElement];
755                gl::Texture *texture = completeTextures[textureUnit];
756                uint32_t textureSlot = mslBinding.textureBinding + arrayElement;
757                uint32_t samplerSlot = mslBinding.samplerBinding + arrayElement;
758                if (!texture)
759                {
760                    ANGLE_TRY(contextMtl->getIncompleteTexture(glContext, textureType, &texture));
761                }
762
763                TextureMtl *textureMtl = mtl::GetImpl(texture);
764
765                switch (shaderType)
766                {
767                    case gl::ShaderType::Vertex:
768                        ANGLE_TRY(textureMtl->bindVertexShader(glContext, cmdEncoder, textureSlot,
769                                                               samplerSlot));
770                        break;
771                    case gl::ShaderType::Fragment:
772                        ANGLE_TRY(textureMtl->bindFragmentShader(glContext, cmdEncoder, textureSlot,
773                                                                 samplerSlot));
774                        break;
775                    default:
776                        UNREACHABLE();
777                }
778            }  // for array elements
779        }      // for sampler bindings
780    }          // for shader types
781
782    return angle::Result::Continue;
783}
784
785}  // namespace rx
786