• 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// ContextMtl.mm:
7//    Implements the class methods for ContextMtl.
8//
9
10#include "libANGLE/renderer/metal/ContextMtl.h"
11
12#include <TargetConditionals.h>
13#include <cstdint>
14
15#include "GLSLANG/ShaderLang.h"
16#include "common/debug.h"
17#include "image_util/loadimage.h"
18#include "libANGLE/Display.h"
19#include "libANGLE/Query.h"
20#include "libANGLE/TransformFeedback.h"
21#include "libANGLE/renderer/OverlayImpl.h"
22#include "libANGLE/renderer/metal/BufferMtl.h"
23#include "libANGLE/renderer/metal/CompilerMtl.h"
24#include "libANGLE/renderer/metal/DisplayMtl.h"
25#include "libANGLE/renderer/metal/FrameBufferMtl.h"
26#include "libANGLE/renderer/metal/ProgramExecutableMtl.h"
27#include "libANGLE/renderer/metal/ProgramMtl.h"
28#include "libANGLE/renderer/metal/QueryMtl.h"
29#include "libANGLE/renderer/metal/RenderBufferMtl.h"
30#include "libANGLE/renderer/metal/RenderTargetMtl.h"
31#include "libANGLE/renderer/metal/SamplerMtl.h"
32#include "libANGLE/renderer/metal/ShaderMtl.h"
33#include "libANGLE/renderer/metal/SyncMtl.h"
34#include "libANGLE/renderer/metal/TextureMtl.h"
35#include "libANGLE/renderer/metal/TransformFeedbackMtl.h"
36#include "libANGLE/renderer/metal/VertexArrayMtl.h"
37#include "libANGLE/renderer/metal/mtl_command_buffer.h"
38#include "libANGLE/renderer/metal/mtl_common.h"
39#include "libANGLE/renderer/metal/mtl_context_device.h"
40#include "libANGLE/renderer/metal/mtl_format_utils.h"
41#include "libANGLE/renderer/metal/mtl_utils.h"
42
43namespace rx
44{
45
46namespace
47{
48#if TARGET_OS_OSX
49// Unlimited triangle fan buffers
50constexpr uint32_t kMaxTriFanLineLoopBuffersPerFrame = 0;
51#else
52// Allow up to 10 buffers for trifan/line loop generation without stalling the GPU.
53constexpr uint32_t kMaxTriFanLineLoopBuffersPerFrame = 10;
54#endif
55
56#define ANGLE_MTL_XFB_DRAW(DRAW_PROC)                                                            \
57    if (!mState.isTransformFeedbackActiveUnpaused())                                             \
58    {                                                                                            \
59        /* Normal draw call */                                                                   \
60        DRAW_PROC(false);                                                                        \
61    }                                                                                            \
62    else                                                                                         \
63    {                                                                                            \
64        /* First pass: write to XFB buffers in vertex shader, fragment shader inactive */        \
65        bool rasterizationNotDisabled =                                                          \
66            mRenderPipelineDesc.rasterizationType != mtl::RenderPipelineRasterization::Disabled; \
67        if (rasterizationNotDisabled)                                                            \
68        {                                                                                        \
69            invalidateRenderPipeline();                                                          \
70        }                                                                                        \
71        DRAW_PROC(true);                                                                         \
72        if (rasterizationNotDisabled)                                                            \
73        {                                                                                        \
74            /* Second pass: full rasterization: vertex shader + fragment shader are active.      \
75               Vertex shader writes to stage output but won't write to XFB buffers */            \
76            invalidateRenderPipeline();                                                          \
77            DRAW_PROC(false);                                                                    \
78        }                                                                                        \
79    }
80
81angle::Result AllocateTriangleFanBufferFromPool(ContextMtl *context,
82                                                GLsizei vertexCount,
83                                                mtl::BufferPool *pool,
84                                                mtl::BufferRef *bufferOut,
85                                                uint32_t *offsetOut,
86                                                uint32_t *numElemsOut)
87{
88    uint32_t numIndices;
89    ANGLE_TRY(mtl::GetTriangleFanIndicesCount(context, vertexCount, &numIndices));
90
91    size_t offset;
92    pool->releaseInFlightBuffers(context);
93    ANGLE_TRY(pool->allocate(context, numIndices * sizeof(uint32_t), nullptr, bufferOut, &offset,
94                             nullptr));
95
96    *offsetOut   = static_cast<uint32_t>(offset);
97    *numElemsOut = numIndices;
98
99    return angle::Result::Continue;
100}
101
102angle::Result AllocateBufferFromPool(ContextMtl *context,
103                                     GLsizei indicesToReserve,
104                                     mtl::BufferPool *pool,
105                                     mtl::BufferRef *bufferOut,
106                                     uint32_t *offsetOut)
107{
108    size_t offset;
109    pool->releaseInFlightBuffers(context);
110    ANGLE_TRY(pool->allocate(context, indicesToReserve * sizeof(uint32_t), nullptr, bufferOut,
111                             &offset, nullptr));
112
113    *offsetOut = static_cast<uint32_t>(offset);
114
115    return angle::Result::Continue;
116}
117
118bool NeedToInvertDepthRange(float near, float far)
119{
120    return near > far;
121}
122
123bool IsTransformFeedbackOnly(const gl::State &glState)
124{
125    return glState.isTransformFeedbackActiveUnpaused() && glState.isRasterizerDiscardEnabled();
126}
127
128std::string ConvertMarkerToString(GLsizei length, const char *marker)
129{
130    std::string cppString;
131    if (length == 0)
132    {
133        cppString = marker;
134    }
135    else
136    {
137        cppString.assign(marker, length);
138    }
139    return cppString;
140}
141
142// This class constructs line loop's last segment buffer inside begin() method
143// and perform the draw of the line loop's last segment inside destructor
144class LineLoopLastSegmentHelper
145{
146  public:
147    LineLoopLastSegmentHelper() {}
148
149    ~LineLoopLastSegmentHelper()
150    {
151        if (!mLineLoopIndexBuffer)
152        {
153            return;
154        }
155
156        // Draw last segment of line loop here
157        mtl::RenderCommandEncoder *encoder = mContextMtl->getRenderCommandEncoder();
158        ASSERT(encoder);
159        encoder->drawIndexed(MTLPrimitiveTypeLine, 2, MTLIndexTypeUInt32, mLineLoopIndexBuffer, 0);
160    }
161
162    angle::Result begin(const gl::Context *context,
163                        mtl::BufferPool *indexBufferPool,
164                        GLint firstVertex,
165                        GLsizei vertexOrIndexCount,
166                        gl::DrawElementsType indexTypeOrNone,
167                        const void *indices)
168    {
169        mContextMtl = mtl::GetImpl(context);
170
171        indexBufferPool->releaseInFlightBuffers(mContextMtl);
172
173        ANGLE_TRY(indexBufferPool->allocate(mContextMtl, 2 * sizeof(uint32_t), nullptr,
174                                            &mLineLoopIndexBuffer, nullptr, nullptr));
175
176        if (indexTypeOrNone == gl::DrawElementsType::InvalidEnum)
177        {
178            ANGLE_TRY(mContextMtl->getDisplay()->getUtils().generateLineLoopLastSegment(
179                mContextMtl, firstVertex, firstVertex + vertexOrIndexCount - 1,
180                mLineLoopIndexBuffer, 0));
181        }
182        else
183        {
184            ASSERT(firstVertex == 0);
185            ANGLE_TRY(
186                mContextMtl->getDisplay()->getUtils().generateLineLoopLastSegmentFromElementsArray(
187                    mContextMtl,
188                    {indexTypeOrNone, vertexOrIndexCount, indices, mLineLoopIndexBuffer, 0}));
189        }
190
191        ANGLE_TRY(indexBufferPool->commit(mContextMtl));
192
193        return angle::Result::Continue;
194    }
195
196  private:
197    ContextMtl *mContextMtl = nullptr;
198    mtl::BufferRef mLineLoopIndexBuffer;
199};
200
201GLint GetOwnershipIdentity(const egl::AttributeMap &attribs)
202{
203    return attribs.getAsInt(EGL_CONTEXT_METAL_OWNERSHIP_IDENTITY_ANGLE, 0);
204}
205
206}  // namespace
207
208ContextMtl::ContextMtl(const gl::State &state,
209                       gl::ErrorSet *errorSet,
210                       const egl::AttributeMap &attribs,
211                       DisplayMtl *display)
212    : ContextImpl(state, errorSet),
213      mtl::Context(display),
214      mCmdBuffer(&display->cmdQueue()),
215      mRenderEncoder(&mCmdBuffer,
216                     mOcclusionQueryPool,
217                     display->getFeatures().emulateDontCareLoadWithRandomClear.enabled),
218      mBlitEncoder(&mCmdBuffer),
219      mComputeEncoder(&mCmdBuffer),
220      mDriverUniforms{},
221      mProvokingVertexHelper(this),
222      mContextDevice(GetOwnershipIdentity(attribs))
223{}
224
225ContextMtl::~ContextMtl() {}
226
227angle::Result ContextMtl::initialize(const angle::ImageLoadContext &imageLoadContext)
228{
229    for (mtl::BlendDesc &blendDesc : mBlendDescArray)
230    {
231        blendDesc.reset();
232    }
233
234    mWriteMaskArray.fill(MTLColorWriteMaskAll);
235
236    mDepthStencilDesc.reset();
237
238    mTriFanIndexBuffer.initialize(this, 0, mtl::kIndexBufferOffsetAlignment,
239                                  kMaxTriFanLineLoopBuffersPerFrame);
240    mLineLoopIndexBuffer.initialize(this, 0, mtl::kIndexBufferOffsetAlignment,
241                                    kMaxTriFanLineLoopBuffersPerFrame);
242    mLineLoopLastSegmentIndexBuffer.initialize(this, 2 * sizeof(uint32_t),
243                                               mtl::kIndexBufferOffsetAlignment,
244                                               kMaxTriFanLineLoopBuffersPerFrame);
245
246    mContextDevice.set(mDisplay->getMetalDevice());
247
248    mImageLoadContext = imageLoadContext;
249
250    return angle::Result::Continue;
251}
252
253void ContextMtl::onDestroy(const gl::Context *context)
254{
255    mTriFanIndexBuffer.destroy(this);
256    mLineLoopIndexBuffer.destroy(this);
257    mLineLoopLastSegmentIndexBuffer.destroy(this);
258    mOcclusionQueryPool.destroy(this);
259
260    mIncompleteTextures.onDestroy(context);
261    mProvokingVertexHelper.onDestroy(this);
262    mDummyXFBRenderTexture = nullptr;
263
264    mContextDevice.reset();
265}
266
267// Flush and finish.
268angle::Result ContextMtl::flush(const gl::Context *context)
269{
270    // MTLSharedEvent is available on these platforms, and callers
271    // are expected to use the EGL_ANGLE_metal_shared_event_sync
272    // extension to synchronize with ANGLE's Metal backend, if
273    // needed. This is typically required if two MTLDevices are
274    // operating on the same IOSurface.
275    flushCommandBuffer(mtl::NoWait);
276    return checkCommandBufferError();
277}
278angle::Result ContextMtl::finish(const gl::Context *context)
279{
280    ANGLE_TRY(finishCommandBuffer());
281    return checkCommandBufferError();
282}
283
284ANGLE_INLINE angle::Result ContextMtl::resyncDrawFramebufferIfNeeded(const gl::Context *context)
285{
286    // Resync the draw framebuffer if
287    // - it has incompatible attachments; OR
288    // - it had incompatible attachments during the previous operation.
289    if (ANGLE_UNLIKELY(mIncompatibleAttachments.any() || mForceResyncDrawFramebuffer))
290    {
291        if (mIncompatibleAttachments.any())
292        {
293            ANGLE_PERF_WARNING(context->getState().getDebug(), GL_DEBUG_SEVERITY_LOW,
294                               "Resyncing the draw framebuffer because it has active attachments "
295                               "incompatible with the current program outputs.");
296        }
297
298        // Ensure sync on the next operation if the current state has incompatible attachments.
299        mForceResyncDrawFramebuffer = mIncompatibleAttachments.any();
300
301        FramebufferMtl *fbo = mtl::GetImpl(getState().getDrawFramebuffer());
302        ASSERT(fbo != nullptr);
303        return fbo->syncState(context, GL_DRAW_FRAMEBUFFER, gl::Framebuffer::DirtyBits(),
304                              gl::Command::Draw);
305    }
306    return angle::Result::Continue;
307}
308
309// Drawing methods.
310angle::Result ContextMtl::drawTriFanArraysWithBaseVertex(const gl::Context *context,
311                                                         GLint first,
312                                                         GLsizei count,
313                                                         GLsizei instances,
314                                                         GLuint baseInstance)
315{
316    ASSERT((getDisplay()->getFeatures().hasBaseVertexInstancedDraw.enabled));
317
318    uint32_t genIndicesCount;
319    ANGLE_TRY(mtl::GetTriangleFanIndicesCount(this, count, &genIndicesCount));
320
321    size_t indexBufferSize = genIndicesCount * sizeof(uint32_t);
322    // We can reuse the previously generated index buffer if it has more than enough indices
323    // data already.
324    if (mTriFanArraysIndexBuffer == nullptr || mTriFanArraysIndexBuffer->size() < indexBufferSize)
325    {
326        // Re-generate a new index buffer, which the first index will be zero.
327        ANGLE_TRY(
328            mtl::Buffer::MakeBuffer(this, indexBufferSize, nullptr, &mTriFanArraysIndexBuffer));
329        ANGLE_TRY(getDisplay()->getUtils().generateTriFanBufferFromArrays(
330            this, {0, static_cast<uint32_t>(count), mTriFanArraysIndexBuffer, 0}));
331    }
332
333    ASSERT(!getState().isTransformFeedbackActiveUnpaused());
334    bool isNoOp = false;
335    ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, first, count, instances,
336                        gl::DrawElementsType::InvalidEnum, reinterpret_cast<const void *>(0), false,
337                        &isNoOp));
338    if (!isNoOp)
339    {
340        // Draw with the zero starting index buffer, shift the vertex index using baseVertex
341        // instanced draw:
342        mRenderEncoder.drawIndexedInstancedBaseVertexBaseInstance(
343            MTLPrimitiveTypeTriangle, genIndicesCount, MTLIndexTypeUInt32, mTriFanArraysIndexBuffer,
344            0, instances, first, baseInstance);
345    }
346
347    return angle::Result::Continue;
348}
349angle::Result ContextMtl::drawTriFanArraysLegacy(const gl::Context *context,
350                                                 GLint first,
351                                                 GLsizei count,
352                                                 GLsizei instances)
353{
354    // Legacy method is only used for GPU lacking instanced base vertex draw capabilities.
355    mtl::BufferRef genIdxBuffer;
356    uint32_t genIdxBufferOffset;
357    uint32_t genIndicesCount;
358    ANGLE_TRY(AllocateTriangleFanBufferFromPool(this, count, &mTriFanIndexBuffer, &genIdxBuffer,
359                                                &genIdxBufferOffset, &genIndicesCount));
360    ANGLE_TRY(getDisplay()->getUtils().generateTriFanBufferFromArrays(
361        this, {static_cast<uint32_t>(first), static_cast<uint32_t>(count), genIdxBuffer,
362               genIdxBufferOffset}));
363
364    ANGLE_TRY(mTriFanIndexBuffer.commit(this));
365
366    ASSERT(!getState().isTransformFeedbackActiveUnpaused());
367    bool isNoOp = false;
368    ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, first, count, instances,
369                        gl::DrawElementsType::InvalidEnum, reinterpret_cast<const void *>(0), false,
370                        &isNoOp));
371    if (!isNoOp)
372    {
373        mRenderEncoder.drawIndexedInstanced(MTLPrimitiveTypeTriangle, genIndicesCount,
374                                            MTLIndexTypeUInt32, genIdxBuffer, genIdxBufferOffset,
375                                            instances);
376    }
377    return angle::Result::Continue;
378}
379angle::Result ContextMtl::drawTriFanArrays(const gl::Context *context,
380                                           GLint first,
381                                           GLsizei count,
382                                           GLsizei instances,
383                                           GLuint baseInstance)
384{
385    if (count <= 3 && baseInstance == 0)
386    {
387        return drawArraysImpl(context, gl::PrimitiveMode::Triangles, first, count, instances, 0);
388    }
389    if (getDisplay()->getFeatures().hasBaseVertexInstancedDraw.enabled)
390    {
391        return drawTriFanArraysWithBaseVertex(context, first, count, instances, baseInstance);
392    }
393    return drawTriFanArraysLegacy(context, first, count, instances);
394}
395
396angle::Result ContextMtl::drawLineLoopArraysNonInstanced(const gl::Context *context,
397                                                         GLint first,
398                                                         GLsizei count)
399{
400    // Generate line loop's last segment. It will be rendered when this function exits.
401    LineLoopLastSegmentHelper lineloopHelper;
402    // Line loop helper needs to generate last segment indices before rendering command encoder
403    // starts.
404    ANGLE_TRY(lineloopHelper.begin(context, &mLineLoopLastSegmentIndexBuffer, first, count,
405                                   gl::DrawElementsType::InvalidEnum, nullptr));
406
407    return drawArraysImpl(context, gl::PrimitiveMode::LineStrip, first, count, 0, 0);
408}
409
410angle::Result ContextMtl::drawLineLoopArrays(const gl::Context *context,
411                                             GLint first,
412                                             GLsizei count,
413                                             GLsizei instances,
414                                             GLuint baseInstance)
415{
416    if (instances <= 1 && baseInstance == 0)
417    {
418        return drawLineLoopArraysNonInstanced(context, first, count);
419    }
420
421    mtl::BufferRef genIdxBuffer;
422    uint32_t genIdxBufferOffset;
423    uint32_t genIndicesCount = count + 1;
424
425    ANGLE_TRY(AllocateBufferFromPool(this, genIndicesCount, &mLineLoopIndexBuffer, &genIdxBuffer,
426                                     &genIdxBufferOffset));
427    ANGLE_TRY(getDisplay()->getUtils().generateLineLoopBufferFromArrays(
428        this, {static_cast<uint32_t>(first), static_cast<uint32_t>(count), genIdxBuffer,
429               genIdxBufferOffset}));
430
431    ANGLE_TRY(mLineLoopIndexBuffer.commit(this));
432
433    ASSERT(!getState().isTransformFeedbackActiveUnpaused());
434    bool isNoOp = false;
435    ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::LineLoop, first, count, instances,
436                        gl::DrawElementsType::InvalidEnum, nullptr, false, &isNoOp));
437    if (!isNoOp)
438    {
439        if (baseInstance == 0)
440        {
441            mRenderEncoder.drawIndexedInstanced(MTLPrimitiveTypeLineStrip, genIndicesCount,
442                                                MTLIndexTypeUInt32, genIdxBuffer,
443                                                genIdxBufferOffset, instances);
444        }
445        else
446        {
447            mRenderEncoder.drawIndexedInstancedBaseVertexBaseInstance(
448                MTLPrimitiveTypeLineStrip, genIndicesCount, MTLIndexTypeUInt32, genIdxBuffer,
449                genIdxBufferOffset, instances, 0, baseInstance);
450        }
451    }
452
453    return angle::Result::Continue;
454}
455
456angle::Result ContextMtl::drawArraysImpl(const gl::Context *context,
457                                         gl::PrimitiveMode mode,
458                                         GLint first,
459                                         GLsizei count,
460                                         GLsizei instances,
461                                         GLuint baseInstance)
462{
463    // Real instances count. Zero means this is not instanced draw.
464    GLsizei instanceCount = instances ? instances : 1;
465
466    if (mCullAllPolygons && gl::IsPolygonMode(mode))
467    {
468        return angle::Result::Continue;
469    }
470    if (requiresIndexRewrite(context->getState(), mode))
471    {
472        return drawArraysProvokingVertexImpl(context, mode, first, count, instances, baseInstance);
473    }
474    if (mode == gl::PrimitiveMode::TriangleFan)
475    {
476        return drawTriFanArrays(context, first, count, instanceCount, baseInstance);
477    }
478    else if (mode == gl::PrimitiveMode::LineLoop)
479    {
480        return drawLineLoopArrays(context, first, count, instanceCount, baseInstance);
481    }
482
483    MTLPrimitiveType mtlType = mtl::GetPrimitiveType(mode);
484
485#define DRAW_GENERIC_ARRAY(xfbPass)                                                                \
486    {                                                                                              \
487        bool isNoOp = false;                                                                       \
488        ANGLE_TRY(setupDraw(context, mode, first, count, instances,                                \
489                            gl::DrawElementsType::InvalidEnum, nullptr, xfbPass, &isNoOp));        \
490        if (!isNoOp)                                                                               \
491        {                                                                                          \
492                                                                                                   \
493            if (instances == 0)                                                                    \
494            {                                                                                      \
495                /* This method is called from normal drawArrays() */                               \
496                mRenderEncoder.draw(mtlType, first, count);                                        \
497            }                                                                                      \
498            else                                                                                   \
499            {                                                                                      \
500                if (baseInstance == 0)                                                             \
501                {                                                                                  \
502                    mRenderEncoder.drawInstanced(mtlType, first, count, instanceCount);            \
503                }                                                                                  \
504                else                                                                               \
505                {                                                                                  \
506                    mRenderEncoder.drawInstancedBaseInstance(mtlType, first, count, instanceCount, \
507                                                             baseInstance);                        \
508                }                                                                                  \
509            }                                                                                      \
510        }                                                                                          \
511    }
512
513    ANGLE_MTL_XFB_DRAW(DRAW_GENERIC_ARRAY)
514
515    return angle::Result::Continue;
516}
517
518angle::Result ContextMtl::drawArrays(const gl::Context *context,
519                                     gl::PrimitiveMode mode,
520                                     GLint first,
521                                     GLsizei count)
522{
523    ANGLE_TRY(resyncDrawFramebufferIfNeeded(context));
524    return drawArraysImpl(context, mode, first, count, 0, 0);
525}
526
527angle::Result ContextMtl::drawArraysInstanced(const gl::Context *context,
528                                              gl::PrimitiveMode mode,
529                                              GLint first,
530                                              GLsizei count,
531                                              GLsizei instances)
532{
533    // Instanced draw calls with zero instances are skipped in the frontend.
534    // The drawArraysImpl function would treat them as non-instanced.
535    ASSERT(instances > 0);
536    ANGLE_TRY(resyncDrawFramebufferIfNeeded(context));
537    return drawArraysImpl(context, mode, first, count, instances, 0);
538}
539
540angle::Result ContextMtl::drawArraysInstancedBaseInstance(const gl::Context *context,
541                                                          gl::PrimitiveMode mode,
542                                                          GLint first,
543                                                          GLsizei count,
544                                                          GLsizei instanceCount,
545                                                          GLuint baseInstance)
546{
547    // Instanced draw calls with zero instances are skipped in the frontend.
548    // The drawArraysImpl function would treat them as non-instanced.
549    ASSERT(instanceCount > 0);
550    ANGLE_TRY(resyncDrawFramebufferIfNeeded(context));
551    return drawArraysImpl(context, mode, first, count, instanceCount, baseInstance);
552}
553
554angle::Result ContextMtl::drawTriFanElements(const gl::Context *context,
555                                             GLsizei count,
556                                             gl::DrawElementsType type,
557                                             const void *indices,
558                                             GLsizei instances,
559                                             GLint baseVertex,
560                                             GLuint baseInstance)
561{
562    if (count > 3)
563    {
564        mtl::BufferRef genIdxBuffer;
565        uint32_t genIdxBufferOffset;
566        uint32_t genIndicesCount;
567        bool primitiveRestart = getState().isPrimitiveRestartEnabled();
568        ANGLE_TRY(AllocateTriangleFanBufferFromPool(this, count, &mTriFanIndexBuffer, &genIdxBuffer,
569                                                    &genIdxBufferOffset, &genIndicesCount));
570
571        ANGLE_TRY(getDisplay()->getUtils().generateTriFanBufferFromElementsArray(
572            this, {type, count, indices, genIdxBuffer, genIdxBufferOffset, primitiveRestart},
573            &genIndicesCount));
574
575        ANGLE_TRY(mTriFanIndexBuffer.commit(this));
576        bool isNoOp = false;
577        ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, 0, count, instances, type,
578                            indices, false, &isNoOp));
579        if (!isNoOp && genIndicesCount > 0)
580        {
581            if (baseVertex == 0 && baseInstance == 0)
582            {
583                mRenderEncoder.drawIndexedInstanced(MTLPrimitiveTypeTriangle, genIndicesCount,
584                                                    MTLIndexTypeUInt32, genIdxBuffer,
585                                                    genIdxBufferOffset, instances);
586            }
587            else
588            {
589                mRenderEncoder.drawIndexedInstancedBaseVertexBaseInstance(
590                    MTLPrimitiveTypeTriangle, genIndicesCount, MTLIndexTypeUInt32, genIdxBuffer,
591                    genIdxBufferOffset, instances, baseVertex, baseInstance);
592            }
593        }
594
595        return angle::Result::Continue;
596    }  // if (count > 3)
597    return drawElementsImpl(context, gl::PrimitiveMode::Triangles, count, type, indices, instances,
598                            baseVertex, baseInstance);
599}
600
601angle::Result ContextMtl::drawLineLoopElementsNonInstancedNoPrimitiveRestart(
602    const gl::Context *context,
603    GLsizei count,
604    gl::DrawElementsType type,
605    const void *indices)
606{
607    // Generate line loop's last segment. It will be rendered when this function exits.
608    LineLoopLastSegmentHelper lineloopHelper;
609    // Line loop helper needs to generate index before rendering command encoder starts.
610    ANGLE_TRY(
611        lineloopHelper.begin(context, &mLineLoopLastSegmentIndexBuffer, 0, count, type, indices));
612
613    return drawElementsImpl(context, gl::PrimitiveMode::LineStrip, count, type, indices, 0, 0, 0);
614}
615
616angle::Result ContextMtl::drawLineLoopElements(const gl::Context *context,
617                                               GLsizei count,
618                                               gl::DrawElementsType type,
619                                               const void *indices,
620                                               GLsizei instances,
621                                               GLint baseVertex,
622                                               GLuint baseInstance)
623{
624    if (count >= 2)
625    {
626        bool primitiveRestart = getState().isPrimitiveRestartEnabled();
627        if (instances <= 1 && !primitiveRestart && baseVertex == 0 && baseInstance == 0)
628        {
629            // Non instanced draw and no primitive restart, just use faster version.
630            return drawLineLoopElementsNonInstancedNoPrimitiveRestart(context, count, type,
631                                                                      indices);
632        }
633
634        mtl::BufferRef genIdxBuffer;
635        uint32_t genIdxBufferOffset;
636        uint32_t reservedIndices = count * 2;
637        uint32_t genIndicesCount;
638        ANGLE_TRY(AllocateBufferFromPool(this, reservedIndices, &mLineLoopIndexBuffer,
639                                         &genIdxBuffer, &genIdxBufferOffset));
640
641        ANGLE_TRY(getDisplay()->getUtils().generateLineLoopBufferFromElementsArray(
642            this, {type, count, indices, genIdxBuffer, genIdxBufferOffset, primitiveRestart},
643            &genIndicesCount));
644
645        ANGLE_TRY(mLineLoopIndexBuffer.commit(this));
646        bool isNoOp = false;
647        ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::LineLoop, 0, count, instances, type,
648                            indices, false, &isNoOp));
649        if (!isNoOp && genIndicesCount > 0)
650        {
651            if (baseVertex == 0 && baseInstance == 0)
652            {
653                mRenderEncoder.drawIndexedInstanced(MTLPrimitiveTypeLineStrip, genIndicesCount,
654                                                    MTLIndexTypeUInt32, genIdxBuffer,
655                                                    genIdxBufferOffset, instances);
656            }
657            else
658            {
659                mRenderEncoder.drawIndexedInstancedBaseVertexBaseInstance(
660                    MTLPrimitiveTypeLineStrip, genIndicesCount, MTLIndexTypeUInt32, genIdxBuffer,
661                    genIdxBufferOffset, instances, baseVertex, baseInstance);
662            }
663        }
664
665        return angle::Result::Continue;
666    }  // if (count >= 2)
667    return drawElementsImpl(context, gl::PrimitiveMode::Lines, count, type, indices, instances,
668                            baseVertex, baseInstance);
669}
670
671angle::Result ContextMtl::drawArraysProvokingVertexImpl(const gl::Context *context,
672                                                        gl::PrimitiveMode mode,
673                                                        GLsizei first,
674                                                        GLsizei count,
675                                                        GLsizei instances,
676                                                        GLuint baseInstance)
677{
678
679    size_t outIndexCount               = 0;
680    size_t outIndexOffset              = 0;
681    gl::DrawElementsType convertedType = gl::DrawElementsType::UnsignedInt;
682    gl::PrimitiveMode outIndexMode     = gl::PrimitiveMode::InvalidEnum;
683
684    mtl::BufferRef drawIdxBuffer;
685    ANGLE_TRY(mProvokingVertexHelper.generateIndexBuffer(
686        mtl::GetImpl(context), first, count, mode, convertedType, outIndexCount, outIndexOffset,
687        outIndexMode, drawIdxBuffer));
688    GLsizei outIndexCounti32 = static_cast<GLsizei>(outIndexCount);
689
690    // Note: we don't need to pass the generated index buffer to ContextMtl::setupDraw.
691    // Because setupDraw only needs to operate on the original vertex buffers & PrimitiveMode.
692    // setupDraw might convert vertex attributes if the offset & alignment are not natively
693    // supported by Metal. However, the converted attributes have the same order as the original
694    // vertices. Hence the conversion doesn't need to know about the newly generated index buffer.
695#define DRAW_PROVOKING_VERTEX_ARRAY(xfbPass)                                                       \
696    if (xfbPass)                                                                                   \
697    {                                                                                              \
698        bool isNoOp = false;                                                                       \
699        ANGLE_TRY(setupDraw(context, mode, first, count, instances,                                \
700                            gl::DrawElementsType::InvalidEnum, nullptr, xfbPass, &isNoOp));        \
701        if (!isNoOp)                                                                               \
702        {                                                                                          \
703            MTLPrimitiveType mtlType = mtl::GetPrimitiveType(mode);                                \
704            if (instances == 0)                                                                    \
705            {                                                                                      \
706                /* This method is called from normal drawArrays() */                               \
707                mRenderEncoder.draw(mtlType, first, count);                                        \
708            }                                                                                      \
709            else                                                                                   \
710            {                                                                                      \
711                if (baseInstance == 0)                                                             \
712                {                                                                                  \
713                    mRenderEncoder.drawInstanced(mtlType, first, count, instances);                \
714                }                                                                                  \
715                else                                                                               \
716                {                                                                                  \
717                    mRenderEncoder.drawInstancedBaseInstance(mtlType, first, count, instances,     \
718                                                             baseInstance);                        \
719                }                                                                                  \
720            }                                                                                      \
721        }                                                                                          \
722    }                                                                                              \
723    else                                                                                           \
724    {                                                                                              \
725        bool isNoOp = false;                                                                       \
726        ANGLE_TRY(setupDraw(context, mode, first, count, instances,                                \
727                            gl::DrawElementsType::InvalidEnum, nullptr, xfbPass, &isNoOp));        \
728                                                                                                   \
729        if (!isNoOp)                                                                               \
730        {                                                                                          \
731            MTLPrimitiveType mtlType = mtl::GetPrimitiveType(outIndexMode);                        \
732            MTLIndexType mtlIdxType  = mtl::GetIndexType(convertedType);                           \
733            if (instances == 0)                                                                    \
734            {                                                                                      \
735                mRenderEncoder.drawIndexed(mtlType, outIndexCounti32, mtlIdxType, drawIdxBuffer,   \
736                                           outIndexOffset);                                        \
737            }                                                                                      \
738            else                                                                                   \
739            {                                                                                      \
740                if (baseInstance == 0)                                                             \
741                {                                                                                  \
742                    mRenderEncoder.drawIndexedInstanced(mtlType, outIndexCounti32, mtlIdxType,     \
743                                                        drawIdxBuffer, outIndexOffset, instances); \
744                }                                                                                  \
745                else                                                                               \
746                {                                                                                  \
747                    mRenderEncoder.drawIndexedInstancedBaseVertexBaseInstance(                     \
748                        mtlType, outIndexCounti32, mtlIdxType, drawIdxBuffer, outIndexOffset,      \
749                        instances, 0, baseInstance);                                               \
750                }                                                                                  \
751            }                                                                                      \
752        }                                                                                          \
753    }
754
755    ANGLE_MTL_XFB_DRAW(DRAW_PROVOKING_VERTEX_ARRAY)
756    return angle::Result::Continue;
757}
758
759angle::Result ContextMtl::drawElementsImpl(const gl::Context *context,
760                                           gl::PrimitiveMode mode,
761                                           GLsizei count,
762                                           gl::DrawElementsType type,
763                                           const void *indices,
764                                           GLsizei instances,
765                                           GLint baseVertex,
766                                           GLuint baseInstance)
767{
768    // Real instances count. Zero means this is not instanced draw.
769    GLsizei instanceCount = instances ? instances : 1;
770
771    if (mCullAllPolygons && gl::IsPolygonMode(mode))
772    {
773        return angle::Result::Continue;
774    }
775
776    if (mode == gl::PrimitiveMode::TriangleFan)
777    {
778        return drawTriFanElements(context, count, type, indices, instanceCount, baseVertex,
779                                  baseInstance);
780    }
781    else if (mode == gl::PrimitiveMode::LineLoop)
782    {
783        return drawLineLoopElements(context, count, type, indices, instanceCount, baseVertex,
784                                    baseInstance);
785    }
786
787    mtl::BufferRef idxBuffer;
788    mtl::BufferRef drawIdxBuffer;
789    size_t convertedOffset             = 0;
790    gl::DrawElementsType convertedType = type;
791
792    ANGLE_TRY(mVertexArray->getIndexBuffer(context, type, count, indices, &idxBuffer,
793                                           &convertedOffset, &convertedType));
794
795    ASSERT(idxBuffer);
796    ASSERT((convertedType == gl::DrawElementsType::UnsignedShort && (convertedOffset % 2) == 0) ||
797           (convertedType == gl::DrawElementsType::UnsignedInt && (convertedOffset % 4) == 0));
798
799    uint32_t convertedCounti32 = (uint32_t)count;
800
801    size_t provokingVertexAdditionalOffset = 0;
802
803    if (requiresIndexRewrite(context->getState(), mode))
804    {
805        size_t outIndexCount      = 0;
806        gl::PrimitiveMode newMode = gl::PrimitiveMode::InvalidEnum;
807        ANGLE_TRY(mProvokingVertexHelper.preconditionIndexBuffer(
808            mtl::GetImpl(context), idxBuffer, count, convertedOffset,
809            mState.isPrimitiveRestartEnabled(), mode, convertedType, outIndexCount,
810            provokingVertexAdditionalOffset, newMode, drawIdxBuffer));
811        // Line strips and triangle strips are rewritten to flat line arrays and tri arrays.
812        convertedCounti32 = (uint32_t)outIndexCount;
813        mode              = newMode;
814    }
815    else
816    {
817        drawIdxBuffer = idxBuffer;
818    }
819    // Draw commands will only be broken up if transform feedback is enabled,
820    // if the mode is a simple type, and if the buffer contained any restart
821    // indices.
822    // It's safe to use idxBuffer in this case, as it will contain the same count and restart ranges
823    // as drawIdxBuffer.
824    const std::vector<DrawCommandRange> drawCommands = mVertexArray->getDrawIndices(
825        context, type, convertedType, mode, idxBuffer, convertedCounti32, convertedOffset);
826    bool isNoOp = false;
827    ANGLE_TRY(setupDraw(context, mode, 0, count, instances, type, indices, false, &isNoOp));
828    if (!isNoOp)
829    {
830        MTLPrimitiveType mtlType = mtl::GetPrimitiveType(mode);
831
832        MTLIndexType mtlIdxType = mtl::GetIndexType(convertedType);
833
834        if (instances == 0 && baseVertex == 0 && baseInstance == 0)
835        {
836            // Normal draw
837            for (auto &command : drawCommands)
838            {
839                mRenderEncoder.drawIndexed(mtlType, command.count, mtlIdxType, drawIdxBuffer,
840                                           command.offset + provokingVertexAdditionalOffset);
841            }
842        }
843        else
844        {
845            // Instanced draw
846            if (baseVertex == 0 && baseInstance == 0)
847            {
848                for (auto &command : drawCommands)
849                {
850                    mRenderEncoder.drawIndexedInstanced(
851                        mtlType, command.count, mtlIdxType, drawIdxBuffer,
852                        command.offset + provokingVertexAdditionalOffset, instanceCount);
853                }
854            }
855            else
856            {
857                for (auto &command : drawCommands)
858                {
859                    mRenderEncoder.drawIndexedInstancedBaseVertexBaseInstance(
860                        mtlType, command.count, mtlIdxType, drawIdxBuffer,
861                        command.offset + provokingVertexAdditionalOffset, instanceCount, baseVertex,
862                        baseInstance);
863                }
864            }
865        }
866    }
867    return angle::Result::Continue;
868}
869
870angle::Result ContextMtl::drawElements(const gl::Context *context,
871                                       gl::PrimitiveMode mode,
872                                       GLsizei count,
873                                       gl::DrawElementsType type,
874                                       const void *indices)
875{
876    ANGLE_TRY(resyncDrawFramebufferIfNeeded(context));
877    return drawElementsImpl(context, mode, count, type, indices, 0, 0, 0);
878}
879
880angle::Result ContextMtl::drawElementsBaseVertex(const gl::Context *context,
881                                                 gl::PrimitiveMode mode,
882                                                 GLsizei count,
883                                                 gl::DrawElementsType type,
884                                                 const void *indices,
885                                                 GLint baseVertex)
886{
887    UNIMPLEMENTED();
888    return angle::Result::Stop;
889}
890
891angle::Result ContextMtl::drawElementsInstanced(const gl::Context *context,
892                                                gl::PrimitiveMode mode,
893                                                GLsizei count,
894                                                gl::DrawElementsType type,
895                                                const void *indices,
896                                                GLsizei instanceCount)
897{
898    ANGLE_TRY(resyncDrawFramebufferIfNeeded(context));
899    // Instanced draw calls with zero instances are skipped in the frontend.
900    // The drawElementsImpl function would treat them as non-instanced.
901    ASSERT(instanceCount > 0);
902    return drawElementsImpl(context, mode, count, type, indices, instanceCount, 0, 0);
903}
904
905angle::Result ContextMtl::drawElementsInstancedBaseVertex(const gl::Context *context,
906                                                          gl::PrimitiveMode mode,
907                                                          GLsizei count,
908                                                          gl::DrawElementsType type,
909                                                          const void *indices,
910                                                          GLsizei instanceCount,
911                                                          GLint baseVertex)
912{
913    ANGLE_TRY(resyncDrawFramebufferIfNeeded(context));
914    // Instanced draw calls with zero instances are skipped in the frontend.
915    // The drawElementsImpl function would treat them as non-instanced.
916    ASSERT(instanceCount > 0);
917    return drawElementsImpl(context, mode, count, type, indices, instanceCount, baseVertex, 0);
918}
919
920angle::Result ContextMtl::drawElementsInstancedBaseVertexBaseInstance(const gl::Context *context,
921                                                                      gl::PrimitiveMode mode,
922                                                                      GLsizei count,
923                                                                      gl::DrawElementsType type,
924                                                                      const void *indices,
925                                                                      GLsizei instances,
926                                                                      GLint baseVertex,
927                                                                      GLuint baseInstance)
928{
929    ANGLE_TRY(resyncDrawFramebufferIfNeeded(context));
930    // Instanced draw calls with zero instances are skipped in the frontend.
931    // The drawElementsImpl function would treat them as non-instanced.
932    ASSERT(instances > 0);
933    return drawElementsImpl(context, mode, count, type, indices, instances, baseVertex,
934                            baseInstance);
935}
936
937angle::Result ContextMtl::drawRangeElements(const gl::Context *context,
938                                            gl::PrimitiveMode mode,
939                                            GLuint start,
940                                            GLuint end,
941                                            GLsizei count,
942                                            gl::DrawElementsType type,
943                                            const void *indices)
944{
945    ANGLE_TRY(resyncDrawFramebufferIfNeeded(context));
946    return drawElementsImpl(context, mode, count, type, indices, 0, 0, 0);
947}
948
949angle::Result ContextMtl::drawRangeElementsBaseVertex(const gl::Context *context,
950                                                      gl::PrimitiveMode mode,
951                                                      GLuint start,
952                                                      GLuint end,
953                                                      GLsizei count,
954                                                      gl::DrawElementsType type,
955                                                      const void *indices,
956                                                      GLint baseVertex)
957{
958    // NOTE(hqle): ES 3.2
959    UNIMPLEMENTED();
960    return angle::Result::Stop;
961}
962
963angle::Result ContextMtl::drawArraysIndirect(const gl::Context *context,
964                                             gl::PrimitiveMode mode,
965                                             const void *indirect)
966{
967    // NOTE(hqle): ES 3.0
968    UNIMPLEMENTED();
969    return angle::Result::Stop;
970}
971angle::Result ContextMtl::drawElementsIndirect(const gl::Context *context,
972                                               gl::PrimitiveMode mode,
973                                               gl::DrawElementsType type,
974                                               const void *indirect)
975{
976    // NOTE(hqle): ES 3.0
977    UNIMPLEMENTED();
978    return angle::Result::Stop;
979}
980
981angle::Result ContextMtl::multiDrawArrays(const gl::Context *context,
982                                          gl::PrimitiveMode mode,
983                                          const GLint *firsts,
984                                          const GLsizei *counts,
985                                          GLsizei drawcount)
986{
987    return rx::MultiDrawArraysGeneral(this, context, mode, firsts, counts, drawcount);
988}
989
990angle::Result ContextMtl::multiDrawArraysInstanced(const gl::Context *context,
991                                                   gl::PrimitiveMode mode,
992                                                   const GLint *firsts,
993                                                   const GLsizei *counts,
994                                                   const GLsizei *instanceCounts,
995                                                   GLsizei drawcount)
996{
997    return rx::MultiDrawArraysInstancedGeneral(this, context, mode, firsts, counts, instanceCounts,
998                                               drawcount);
999}
1000
1001angle::Result ContextMtl::multiDrawArraysIndirect(const gl::Context *context,
1002                                                  gl::PrimitiveMode mode,
1003                                                  const void *indirect,
1004                                                  GLsizei drawcount,
1005                                                  GLsizei stride)
1006{
1007    return rx::MultiDrawArraysIndirectGeneral(this, context, mode, indirect, drawcount, stride);
1008}
1009
1010angle::Result ContextMtl::multiDrawElements(const gl::Context *context,
1011                                            gl::PrimitiveMode mode,
1012                                            const GLsizei *counts,
1013                                            gl::DrawElementsType type,
1014                                            const GLvoid *const *indices,
1015                                            GLsizei drawcount)
1016{
1017    return rx::MultiDrawElementsGeneral(this, context, mode, counts, type, indices, drawcount);
1018}
1019
1020angle::Result ContextMtl::multiDrawElementsInstanced(const gl::Context *context,
1021                                                     gl::PrimitiveMode mode,
1022                                                     const GLsizei *counts,
1023                                                     gl::DrawElementsType type,
1024                                                     const GLvoid *const *indices,
1025                                                     const GLsizei *instanceCounts,
1026                                                     GLsizei drawcount)
1027{
1028    return rx::MultiDrawElementsInstancedGeneral(this, context, mode, counts, type, indices,
1029                                                 instanceCounts, drawcount);
1030}
1031
1032angle::Result ContextMtl::multiDrawElementsIndirect(const gl::Context *context,
1033                                                    gl::PrimitiveMode mode,
1034                                                    gl::DrawElementsType type,
1035                                                    const void *indirect,
1036                                                    GLsizei drawcount,
1037                                                    GLsizei stride)
1038{
1039    return rx::MultiDrawElementsIndirectGeneral(this, context, mode, type, indirect, drawcount,
1040                                                stride);
1041}
1042
1043angle::Result ContextMtl::multiDrawArraysInstancedBaseInstance(const gl::Context *context,
1044                                                               gl::PrimitiveMode mode,
1045                                                               const GLint *firsts,
1046                                                               const GLsizei *counts,
1047                                                               const GLsizei *instanceCounts,
1048                                                               const GLuint *baseInstances,
1049                                                               GLsizei drawcount)
1050{
1051    return rx::MultiDrawArraysInstancedBaseInstanceGeneral(
1052        this, context, mode, firsts, counts, instanceCounts, baseInstances, drawcount);
1053}
1054
1055angle::Result ContextMtl::multiDrawElementsInstancedBaseVertexBaseInstance(
1056    const gl::Context *context,
1057    gl::PrimitiveMode mode,
1058    const GLsizei *counts,
1059    gl::DrawElementsType type,
1060    const GLvoid *const *indices,
1061    const GLsizei *instanceCounts,
1062    const GLint *baseVertices,
1063    const GLuint *baseInstances,
1064    GLsizei drawcount)
1065{
1066    return rx::MultiDrawElementsInstancedBaseVertexBaseInstanceGeneral(
1067        this, context, mode, counts, type, indices, instanceCounts, baseVertices, baseInstances,
1068        drawcount);
1069}
1070
1071// Device loss
1072gl::GraphicsResetStatus ContextMtl::getResetStatus()
1073{
1074    return gl::GraphicsResetStatus::NoError;
1075}
1076
1077// EXT_debug_marker
1078angle::Result ContextMtl::insertEventMarker(GLsizei length, const char *marker)
1079{
1080    return checkCommandBufferError();
1081}
1082
1083angle::Result ContextMtl::pushGroupMarker(GLsizei length, const char *marker)
1084{
1085    mCmdBuffer.pushDebugGroup(ConvertMarkerToString(length, marker));
1086    return checkCommandBufferError();
1087}
1088
1089angle::Result ContextMtl::popGroupMarker()
1090{
1091    mCmdBuffer.popDebugGroup();
1092    return checkCommandBufferError();
1093}
1094
1095// KHR_debug
1096angle::Result ContextMtl::pushDebugGroup(const gl::Context *context,
1097                                         GLenum source,
1098                                         GLuint id,
1099                                         const std::string &message)
1100{
1101    return checkCommandBufferError();
1102}
1103
1104angle::Result ContextMtl::popDebugGroup(const gl::Context *context)
1105{
1106    return checkCommandBufferError();
1107}
1108
1109void ContextMtl::updateIncompatibleAttachments(const gl::State &glState)
1110{
1111    const gl::ProgramExecutable *programExecutable = glState.getProgramExecutable();
1112    gl::Framebuffer *drawFramebuffer               = glState.getDrawFramebuffer();
1113    if (programExecutable == nullptr || drawFramebuffer == nullptr)
1114    {
1115        mIncompatibleAttachments.reset();
1116        return;
1117    }
1118
1119    // Cache a mask of incompatible attachments ignoring unused outputs and disabled draw buffers.
1120    mIncompatibleAttachments =
1121        gl::GetComponentTypeMaskDiff(drawFramebuffer->getDrawBufferTypeMask(),
1122                                     programExecutable->getFragmentOutputsTypeMask()) &
1123        drawFramebuffer->getDrawBufferMask() & programExecutable->getActiveOutputVariablesMask();
1124}
1125
1126// State sync with dirty bits.
1127angle::Result ContextMtl::syncState(const gl::Context *context,
1128                                    const gl::state::DirtyBits dirtyBits,
1129                                    const gl::state::DirtyBits bitMask,
1130                                    const gl::state::ExtendedDirtyBits extendedDirtyBits,
1131                                    const gl::state::ExtendedDirtyBits extendedBitMask,
1132                                    gl::Command command)
1133{
1134    const gl::State &glState = context->getState();
1135
1136    // Metal's blend state is set at once, while ANGLE tracks separate dirty
1137    // bits: ENABLED, FUNCS, and EQUATIONS. Merge all three of them to the first one.
1138    // PS: these can not be statically initialized on some architectures as there is
1139    // no constuctor for DirtyBits that takes an int (which becomes BitSetArray<64>).
1140    gl::state::DirtyBits checkBlendBitsMask;
1141    checkBlendBitsMask.set(gl::state::DIRTY_BIT_BLEND_ENABLED);
1142    checkBlendBitsMask.set(gl::state::DIRTY_BIT_BLEND_FUNCS);
1143    checkBlendBitsMask.set(gl::state::DIRTY_BIT_BLEND_EQUATIONS);
1144    gl::state::DirtyBits resetBlendBitsMask;
1145    resetBlendBitsMask.set(gl::state::DIRTY_BIT_BLEND_FUNCS);
1146    resetBlendBitsMask.set(gl::state::DIRTY_BIT_BLEND_EQUATIONS);
1147
1148    gl::state::DirtyBits mergedDirtyBits = gl::state::DirtyBits(dirtyBits) & ~resetBlendBitsMask;
1149    mergedDirtyBits.set(gl::state::DIRTY_BIT_BLEND_ENABLED, (dirtyBits & checkBlendBitsMask).any());
1150
1151    for (auto iter = mergedDirtyBits.begin(), endIter = mergedDirtyBits.end(); iter != endIter;
1152         ++iter)
1153    {
1154        size_t dirtyBit = *iter;
1155        switch (dirtyBit)
1156        {
1157            case gl::state::DIRTY_BIT_SCISSOR_TEST_ENABLED:
1158            case gl::state::DIRTY_BIT_SCISSOR:
1159                updateScissor(glState);
1160                break;
1161            case gl::state::DIRTY_BIT_VIEWPORT:
1162            {
1163                FramebufferMtl *framebufferMtl = mtl::GetImpl(glState.getDrawFramebuffer());
1164                updateViewport(framebufferMtl, glState.getViewport(), glState.getNearPlane(),
1165                               glState.getFarPlane());
1166                // Update the scissor, which will be constrained to the viewport
1167                updateScissor(glState);
1168                break;
1169            }
1170            case gl::state::DIRTY_BIT_DEPTH_RANGE:
1171                updateDepthRange(glState.getNearPlane(), glState.getFarPlane());
1172                break;
1173            case gl::state::DIRTY_BIT_BLEND_COLOR:
1174                mDirtyBits.set(DIRTY_BIT_BLEND_COLOR);
1175                break;
1176            case gl::state::DIRTY_BIT_BLEND_ENABLED:
1177                updateBlendDescArray(glState.getBlendStateExt());
1178                break;
1179            case gl::state::DIRTY_BIT_COLOR_MASK:
1180            {
1181                const gl::BlendStateExt &blendStateExt = glState.getBlendStateExt();
1182                size_t i                               = 0;
1183                for (; i < blendStateExt.getDrawBufferCount(); i++)
1184                {
1185                    mBlendDescArray[i].updateWriteMask(blendStateExt.getColorMaskIndexed(i));
1186                    mWriteMaskArray[i] = mBlendDescArray[i].writeMask;
1187                }
1188                for (; i < mBlendDescArray.size(); i++)
1189                {
1190                    mBlendDescArray[i].updateWriteMask(0);
1191                    mWriteMaskArray[i] = mBlendDescArray[i].writeMask;
1192                }
1193                invalidateRenderPipeline();
1194                break;
1195            }
1196            case gl::state::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED:
1197                if (getDisplay()->getFeatures().emulateAlphaToCoverage.enabled)
1198                {
1199                    invalidateDriverUniforms();
1200                }
1201                else
1202                {
1203                    invalidateRenderPipeline();
1204                }
1205                break;
1206            case gl::state::DIRTY_BIT_SAMPLE_COVERAGE_ENABLED:
1207            case gl::state::DIRTY_BIT_SAMPLE_COVERAGE:
1208            case gl::state::DIRTY_BIT_SAMPLE_MASK_ENABLED:
1209            case gl::state::DIRTY_BIT_SAMPLE_MASK:
1210                invalidateDriverUniforms();
1211                break;
1212            case gl::state::DIRTY_BIT_DEPTH_TEST_ENABLED:
1213                mDepthStencilDesc.updateDepthTestEnabled(glState.getDepthStencilState());
1214                mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC);
1215                break;
1216            case gl::state::DIRTY_BIT_DEPTH_FUNC:
1217                mDepthStencilDesc.updateDepthCompareFunc(glState.getDepthStencilState());
1218                mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC);
1219                break;
1220            case gl::state::DIRTY_BIT_DEPTH_MASK:
1221                mDepthStencilDesc.updateDepthWriteEnabled(glState.getDepthStencilState());
1222                mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC);
1223                break;
1224            case gl::state::DIRTY_BIT_STENCIL_TEST_ENABLED:
1225                mDepthStencilDesc.updateStencilTestEnabled(glState.getDepthStencilState());
1226                mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC);
1227                break;
1228            case gl::state::DIRTY_BIT_STENCIL_FUNCS_FRONT:
1229                mDepthStencilDesc.updateStencilFrontFuncs(glState.getDepthStencilState());
1230                mStencilRefFront = glState.getStencilRef();  // clamped on the frontend
1231                mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC);
1232                mDirtyBits.set(DIRTY_BIT_STENCIL_REF);
1233                break;
1234            case gl::state::DIRTY_BIT_STENCIL_FUNCS_BACK:
1235                mDepthStencilDesc.updateStencilBackFuncs(glState.getDepthStencilState());
1236                mStencilRefBack = glState.getStencilBackRef();  // clamped on the frontend
1237                mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC);
1238                mDirtyBits.set(DIRTY_BIT_STENCIL_REF);
1239                break;
1240            case gl::state::DIRTY_BIT_STENCIL_OPS_FRONT:
1241                mDepthStencilDesc.updateStencilFrontOps(glState.getDepthStencilState());
1242                mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC);
1243                break;
1244            case gl::state::DIRTY_BIT_STENCIL_OPS_BACK:
1245                mDepthStencilDesc.updateStencilBackOps(glState.getDepthStencilState());
1246                mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC);
1247                break;
1248            case gl::state::DIRTY_BIT_STENCIL_WRITEMASK_FRONT:
1249                mDepthStencilDesc.updateStencilFrontWriteMask(glState.getDepthStencilState());
1250                mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC);
1251                break;
1252            case gl::state::DIRTY_BIT_STENCIL_WRITEMASK_BACK:
1253                mDepthStencilDesc.updateStencilBackWriteMask(glState.getDepthStencilState());
1254                mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC);
1255                break;
1256            case gl::state::DIRTY_BIT_CULL_FACE_ENABLED:
1257            case gl::state::DIRTY_BIT_CULL_FACE:
1258                updateCullMode(glState);
1259                break;
1260            case gl::state::DIRTY_BIT_FRONT_FACE:
1261                updateFrontFace(glState);
1262                break;
1263            case gl::state::DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED:
1264            case gl::state::DIRTY_BIT_POLYGON_OFFSET:
1265                mDirtyBits.set(DIRTY_BIT_DEPTH_BIAS);
1266                break;
1267            case gl::state::DIRTY_BIT_RASTERIZER_DISCARD_ENABLED:
1268                mDirtyBits.set(DIRTY_BIT_RASTERIZER_DISCARD);
1269                break;
1270            case gl::state::DIRTY_BIT_LINE_WIDTH:
1271                // Do nothing
1272                break;
1273            case gl::state::DIRTY_BIT_PRIMITIVE_RESTART_ENABLED:
1274                // NOTE(hqle): ES 3.0 feature.
1275                break;
1276            case gl::state::DIRTY_BIT_CLEAR_COLOR:
1277                mClearColor = mtl::ClearColorValue(
1278                    glState.getColorClearValue().red, glState.getColorClearValue().green,
1279                    glState.getColorClearValue().blue, glState.getColorClearValue().alpha);
1280                break;
1281            case gl::state::DIRTY_BIT_CLEAR_DEPTH:
1282                break;
1283            case gl::state::DIRTY_BIT_CLEAR_STENCIL:
1284                mClearStencil = glState.getStencilClearValue() & mtl::kStencilMaskAll;
1285                break;
1286            case gl::state::DIRTY_BIT_UNPACK_STATE:
1287                // This is a no-op, its only important to use the right unpack state when we do
1288                // setImage or setSubImage in TextureMtl, which is plumbed through the frontend call
1289                break;
1290            case gl::state::DIRTY_BIT_UNPACK_BUFFER_BINDING:
1291                break;
1292            case gl::state::DIRTY_BIT_PACK_STATE:
1293                // This is a no-op, its only important to use the right pack state when we do
1294                // call readPixels later on.
1295                break;
1296            case gl::state::DIRTY_BIT_PACK_BUFFER_BINDING:
1297                break;
1298            case gl::state::DIRTY_BIT_DITHER_ENABLED:
1299                break;
1300            case gl::state::DIRTY_BIT_READ_FRAMEBUFFER_BINDING:
1301                break;
1302            case gl::state::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING:
1303                updateIncompatibleAttachments(glState);
1304                updateDrawFrameBufferBinding(context);
1305                break;
1306            case gl::state::DIRTY_BIT_RENDERBUFFER_BINDING:
1307                break;
1308            case gl::state::DIRTY_BIT_VERTEX_ARRAY_BINDING:
1309                updateVertexArray(context);
1310                break;
1311            case gl::state::DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING:
1312                break;
1313            case gl::state::DIRTY_BIT_DISPATCH_INDIRECT_BUFFER_BINDING:
1314                break;
1315            case gl::state::DIRTY_BIT_PROGRAM_BINDING:
1316                static_assert(
1317                    gl::state::DIRTY_BIT_PROGRAM_EXECUTABLE > gl::state::DIRTY_BIT_PROGRAM_BINDING,
1318                    "Dirty bit order");
1319                iter.setLaterBit(gl::state::DIRTY_BIT_PROGRAM_EXECUTABLE);
1320                break;
1321            case gl::state::DIRTY_BIT_PROGRAM_EXECUTABLE:
1322            {
1323                updateIncompatibleAttachments(glState);
1324                const gl::ProgramExecutable *executable = mState.getProgramExecutable();
1325                ASSERT(executable);
1326                mExecutable = mtl::GetImpl(executable);
1327                updateProgramExecutable(context);
1328                break;
1329            }
1330            case gl::state::DIRTY_BIT_TEXTURE_BINDINGS:
1331                invalidateCurrentTextures();
1332                break;
1333            case gl::state::DIRTY_BIT_SAMPLER_BINDINGS:
1334                invalidateCurrentTextures();
1335                break;
1336            case gl::state::DIRTY_BIT_TRANSFORM_FEEDBACK_BINDING:
1337                // Nothing to do.
1338                break;
1339            case gl::state::DIRTY_BIT_SHADER_STORAGE_BUFFER_BINDING:
1340                // NOTE(hqle): ES 3.0 feature.
1341                break;
1342            case gl::state::DIRTY_BIT_UNIFORM_BUFFER_BINDINGS:
1343                mDirtyBits.set(DIRTY_BIT_UNIFORM_BUFFERS_BINDING);
1344                break;
1345            case gl::state::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING:
1346                break;
1347            case gl::state::DIRTY_BIT_IMAGE_BINDINGS:
1348                // NOTE(hqle): properly handle GLSL images.
1349                invalidateCurrentTextures();
1350                break;
1351            case gl::state::DIRTY_BIT_MULTISAMPLING:
1352                // NOTE(hqle): MSAA on/off.
1353                break;
1354            case gl::state::DIRTY_BIT_SAMPLE_ALPHA_TO_ONE:
1355                // NOTE(hqle): this is part of EXT_multisample_compatibility.
1356                // NOTE(hqle): MSAA feature.
1357                break;
1358            case gl::state::DIRTY_BIT_COVERAGE_MODULATION:
1359                break;
1360            case gl::state::DIRTY_BIT_FRAMEBUFFER_SRGB_WRITE_CONTROL_MODE:
1361                break;
1362            case gl::state::DIRTY_BIT_CURRENT_VALUES:
1363            {
1364                invalidateDefaultAttributes(glState.getAndResetDirtyCurrentValues());
1365                break;
1366            }
1367            case gl::state::DIRTY_BIT_PROVOKING_VERTEX:
1368                break;
1369            case gl::state::DIRTY_BIT_EXTENDED:
1370                updateExtendedState(glState, extendedDirtyBits);
1371                break;
1372            case gl::state::DIRTY_BIT_SAMPLE_SHADING:
1373                // Nothing to do until OES_sample_shading is implemented.
1374                break;
1375            case gl::state::DIRTY_BIT_PATCH_VERTICES:
1376                // Nothing to do until EXT_tessellation_shader is implemented.
1377                break;
1378            default:
1379                UNREACHABLE();
1380                break;
1381        }
1382    }
1383
1384    return angle::Result::Continue;
1385}
1386
1387void ContextMtl::updateExtendedState(const gl::State &glState,
1388                                     const gl::state::ExtendedDirtyBits extendedDirtyBits)
1389{
1390    for (size_t extendedDirtyBit : extendedDirtyBits)
1391    {
1392        switch (extendedDirtyBit)
1393        {
1394            case gl::state::EXTENDED_DIRTY_BIT_CLIP_CONTROL:
1395                updateFrontFace(glState);
1396                invalidateDriverUniforms();
1397                break;
1398            case gl::state::EXTENDED_DIRTY_BIT_CLIP_DISTANCES:
1399                invalidateDriverUniforms();
1400                break;
1401            case gl::state::EXTENDED_DIRTY_BIT_DEPTH_CLAMP_ENABLED:
1402                mDirtyBits.set(DIRTY_BIT_DEPTH_CLIP_MODE);
1403                break;
1404            case gl::state::EXTENDED_DIRTY_BIT_POLYGON_MODE:
1405                mDirtyBits.set(DIRTY_BIT_FILL_MODE);
1406                mDirtyBits.set(DIRTY_BIT_DEPTH_BIAS);
1407                break;
1408            case gl::state::EXTENDED_DIRTY_BIT_POLYGON_OFFSET_LINE_ENABLED:
1409                mDirtyBits.set(DIRTY_BIT_DEPTH_BIAS);
1410                break;
1411            default:
1412                break;
1413        }
1414    }
1415}
1416
1417// Disjoint timer queries
1418GLint ContextMtl::getGPUDisjoint()
1419{
1420    // Implementation currently is not affected by this.
1421    return 0;
1422}
1423
1424GLint64 ContextMtl::getTimestamp()
1425{
1426    // Timestamps are currently unsupported. An implementation
1427    // strategy is written up in anglebug.com/42266300 if they're needed
1428    // in the future.
1429    return 0;
1430}
1431
1432// Context switching
1433angle::Result ContextMtl::onMakeCurrent(const gl::Context *context)
1434{
1435    invalidateState(context);
1436    gl::Query *query = mState.getActiveQuery(gl::QueryType::TimeElapsed);
1437    if (query)
1438    {
1439        GetImplAs<QueryMtl>(query)->onContextMakeCurrent(context);
1440    }
1441    mBufferManager.incrementNumContextSwitches();
1442    return checkCommandBufferError();
1443}
1444angle::Result ContextMtl::onUnMakeCurrent(const gl::Context *context)
1445{
1446    flushCommandBuffer(mtl::WaitUntilScheduled);
1447    // Note: this 2nd flush is needed because if there is a query in progress
1448    // then during flush, new command buffers are allocated that also need
1449    // to be flushed. This is a temporary fix and we should probably refactor
1450    // this later. See TODO(anglebug.com/42265611)
1451    flushCommandBuffer(mtl::WaitUntilScheduled);
1452    gl::Query *query = mState.getActiveQuery(gl::QueryType::TimeElapsed);
1453    if (query)
1454    {
1455        GetImplAs<QueryMtl>(query)->onContextUnMakeCurrent(context);
1456    }
1457    return checkCommandBufferError();
1458}
1459
1460// Native capabilities, unmodified by gl::Context.
1461gl::Caps ContextMtl::getNativeCaps() const
1462{
1463    return getDisplay()->getNativeCaps();
1464}
1465const gl::TextureCapsMap &ContextMtl::getNativeTextureCaps() const
1466{
1467    return getDisplay()->getNativeTextureCaps();
1468}
1469const gl::Extensions &ContextMtl::getNativeExtensions() const
1470{
1471    return getDisplay()->getNativeExtensions();
1472}
1473const gl::Limitations &ContextMtl::getNativeLimitations() const
1474{
1475    return getDisplay()->getNativeLimitations();
1476}
1477const ShPixelLocalStorageOptions &ContextMtl::getNativePixelLocalStorageOptions() const
1478{
1479    return getDisplay()->getNativePixelLocalStorageOptions();
1480}
1481
1482// Shader creation
1483CompilerImpl *ContextMtl::createCompiler()
1484{
1485    return new CompilerMtl();
1486}
1487ShaderImpl *ContextMtl::createShader(const gl::ShaderState &state)
1488{
1489    return new ShaderMtl(state);
1490}
1491ProgramImpl *ContextMtl::createProgram(const gl::ProgramState &state)
1492{
1493    return new ProgramMtl(state);
1494}
1495
1496ProgramExecutableImpl *ContextMtl::createProgramExecutable(const gl::ProgramExecutable *executable)
1497{
1498    return new ProgramExecutableMtl(executable);
1499}
1500
1501// Framebuffer creation
1502FramebufferImpl *ContextMtl::createFramebuffer(const gl::FramebufferState &state)
1503{
1504    return new FramebufferMtl(state, this, /* flipY */ false);
1505}
1506
1507// Texture creation
1508TextureImpl *ContextMtl::createTexture(const gl::TextureState &state)
1509{
1510    return new TextureMtl(state);
1511}
1512
1513// Renderbuffer creation
1514RenderbufferImpl *ContextMtl::createRenderbuffer(const gl::RenderbufferState &state)
1515{
1516    return new RenderbufferMtl(state);
1517}
1518
1519// Buffer creation
1520BufferImpl *ContextMtl::createBuffer(const gl::BufferState &state)
1521{
1522    return new BufferMtl(state);
1523}
1524
1525// Vertex Array creation
1526VertexArrayImpl *ContextMtl::createVertexArray(const gl::VertexArrayState &state)
1527{
1528    return new VertexArrayMtl(state, this);
1529}
1530
1531// Query and Fence creation
1532QueryImpl *ContextMtl::createQuery(gl::QueryType type)
1533{
1534    return new QueryMtl(type);
1535}
1536FenceNVImpl *ContextMtl::createFenceNV()
1537{
1538    return new FenceNVMtl();
1539}
1540SyncImpl *ContextMtl::createSync()
1541{
1542    return new SyncMtl();
1543}
1544
1545// Transform Feedback creation
1546TransformFeedbackImpl *ContextMtl::createTransformFeedback(const gl::TransformFeedbackState &state)
1547{
1548    // NOTE(hqle): ES 3.0
1549    return new TransformFeedbackMtl(state);
1550}
1551
1552// Sampler object creation
1553SamplerImpl *ContextMtl::createSampler(const gl::SamplerState &state)
1554{
1555    return new SamplerMtl(state);
1556}
1557
1558// Program Pipeline object creation
1559ProgramPipelineImpl *ContextMtl::createProgramPipeline(const gl::ProgramPipelineState &data)
1560{
1561    // NOTE(hqle): ES 3.0
1562    UNIMPLEMENTED();
1563    return nullptr;
1564}
1565
1566// Memory object creation.
1567MemoryObjectImpl *ContextMtl::createMemoryObject()
1568{
1569    UNIMPLEMENTED();
1570    return nullptr;
1571}
1572
1573// Semaphore creation.
1574SemaphoreImpl *ContextMtl::createSemaphore()
1575{
1576    UNIMPLEMENTED();
1577    return nullptr;
1578}
1579
1580OverlayImpl *ContextMtl::createOverlay(const gl::OverlayState &state)
1581{
1582    // Not implemented.
1583    return new OverlayImpl(state);
1584}
1585
1586angle::Result ContextMtl::dispatchCompute(const gl::Context *context,
1587                                          GLuint numGroupsX,
1588                                          GLuint numGroupsY,
1589                                          GLuint numGroupsZ)
1590{
1591    // NOTE(hqle): ES 3.0
1592    UNIMPLEMENTED();
1593    return angle::Result::Stop;
1594}
1595angle::Result ContextMtl::dispatchComputeIndirect(const gl::Context *context, GLintptr indirect)
1596{
1597    // NOTE(hqle): ES 3.0
1598    UNIMPLEMENTED();
1599    return angle::Result::Stop;
1600}
1601
1602angle::Result ContextMtl::memoryBarrier(const gl::Context *context, GLbitfield barriers)
1603{
1604    if (barriers == 0)
1605    {
1606        return checkCommandBufferError();
1607    }
1608    if (context->getClientVersion() >= gl::Version{3, 1})
1609    {
1610        // We expect ES 3.0, and as such we don't consider ES 3.1+ objects in this function yet.
1611        UNIMPLEMENTED();
1612        return angle::Result::Stop;
1613    }
1614    MTLBarrierScope scope;
1615    switch (barriers)
1616    {
1617        case GL_ALL_BARRIER_BITS:
1618            scope = MTLBarrierScopeTextures | MTLBarrierScopeBuffers;
1619#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
1620            if (getDisplay()->hasFragmentMemoryBarriers())
1621            {
1622                scope |= MTLBarrierScopeRenderTargets;
1623            }
1624#endif
1625            break;
1626        case GL_SHADER_IMAGE_ACCESS_BARRIER_BIT:
1627            scope = MTLBarrierScopeTextures;
1628#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
1629            if (getDisplay()->hasFragmentMemoryBarriers())
1630            {
1631                // SHADER_IMAGE_ACCESS_BARRIER_BIT (and SHADER_STORAGE_BARRIER_BIT) require that all
1632                // prior types of accesses are finished before writes to the resource. Since this is
1633                // the case, we also have to include render targets in our barrier to ensure any
1634                // rendering completes before an imageLoad().
1635                //
1636                // NOTE: Apple Silicon doesn't support MTLBarrierScopeRenderTargets. This seems to
1637                // work anyway though, and on that hardware we use programmable blending for pixel
1638                // local storage instead of read_write textures anyway.
1639                scope |= MTLBarrierScopeRenderTargets;
1640            }
1641#endif
1642            break;
1643        default:
1644            UNIMPLEMENTED();
1645            return angle::Result::Stop;
1646    }
1647    // The GL API doesn't provide a distinction between different shader stages.
1648    // ES 3.0 doesn't have compute.
1649    MTLRenderStages stages = MTLRenderStageVertex;
1650    if (getDisplay()->hasFragmentMemoryBarriers())
1651    {
1652        stages |= MTLRenderStageFragment;
1653    }
1654    mRenderEncoder.memoryBarrier(scope, stages, stages);
1655    return checkCommandBufferError();
1656}
1657
1658angle::Result ContextMtl::memoryBarrierByRegion(const gl::Context *context, GLbitfield barriers)
1659{
1660    // NOTE(hqle): ES 3.0
1661    UNIMPLEMENTED();
1662    return angle::Result::Stop;
1663}
1664
1665// override mtl::ErrorHandler
1666void ContextMtl::handleError(GLenum glErrorCode,
1667                             const char *message,
1668                             const char *file,
1669                             const char *function,
1670                             unsigned int line)
1671{
1672    mErrors->handleError(glErrorCode, message, file, function, line);
1673}
1674
1675void ContextMtl::invalidateState(const gl::Context *context)
1676{
1677    mDirtyBits.set();
1678
1679    invalidateDefaultAttributes(context->getStateCache().getActiveDefaultAttribsMask());
1680}
1681
1682void ContextMtl::invalidateDefaultAttribute(size_t attribIndex)
1683{
1684    mDirtyDefaultAttribsMask.set(attribIndex);
1685    mDirtyBits.set(DIRTY_BIT_DEFAULT_ATTRIBS);
1686}
1687
1688void ContextMtl::invalidateDefaultAttributes(const gl::AttributesMask &dirtyMask)
1689{
1690    if (dirtyMask.any())
1691    {
1692        mDirtyDefaultAttribsMask |= dirtyMask;
1693        mDirtyBits.set(DIRTY_BIT_DEFAULT_ATTRIBS);
1694    }
1695
1696    // TODO(anglebug.com/40096755): determine how to merge this.
1697#if 0
1698    if (getDisplay()->getFeatures().hasExplicitMemBarrier.enabled)
1699    {
1700        const gl::ProgramExecutable *executable = mState.getProgramExecutable();
1701        ASSERT(executable);
1702        ASSERT(executable->hasTransformFeedbackOutput() || mState.isTransformFeedbackActive());
1703        TransformFeedbackMtl *transformFeedbackMtl = mtl::GetImpl(mState.getCurrentTransformFeedback());
1704        size_t bufferCount                         = executable->getTransformFeedbackBufferCount();
1705        const gl::TransformFeedbackBuffersArray<BufferMtl *> &bufferHandles =
1706            transformFeedbackMtl->getBufferHandles();
1707        for (size_t i = 0; i < bufferCount; i++)
1708        {
1709            const mtl::BufferRef & constBufferRef = bufferHandles[i]->getCurrentBuffer();
1710            mRenderEncoder.memoryBarrierWithResource(constBufferRef, mtl::kRenderStageVertex, mtl::kRenderStageVertex);
1711        }
1712    }
1713    else
1714    {
1715        //End the command encoder, so any Transform Feedback changes are available to subsequent draw calls.
1716        endEncoding(false);
1717    }
1718#endif
1719}
1720
1721void ContextMtl::invalidateCurrentTextures()
1722{
1723    mDirtyBits.set(DIRTY_BIT_TEXTURES);
1724}
1725
1726void ContextMtl::invalidateDriverUniforms()
1727{
1728    mDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS);
1729}
1730
1731void ContextMtl::invalidateRenderPipeline()
1732{
1733    mDirtyBits.set(DIRTY_BIT_RENDER_PIPELINE);
1734}
1735
1736const mtl::ClearColorValue &ContextMtl::getClearColorValue() const
1737{
1738    return mClearColor;
1739}
1740const mtl::WriteMaskArray &ContextMtl::getWriteMaskArray() const
1741{
1742    return mWriteMaskArray;
1743}
1744float ContextMtl::getClearDepthValue() const
1745{
1746    return getState().getDepthClearValue();
1747}
1748uint32_t ContextMtl::getClearStencilValue() const
1749{
1750    return mClearStencil;
1751}
1752uint32_t ContextMtl::getStencilMask() const
1753{
1754    return getState().getDepthStencilState().stencilWritemask & mtl::kStencilMaskAll;
1755}
1756
1757bool ContextMtl::getDepthMask() const
1758{
1759    return getState().getDepthStencilState().depthMask;
1760}
1761
1762const mtl::Format &ContextMtl::getPixelFormat(angle::FormatID angleFormatId) const
1763{
1764    return getDisplay()->getPixelFormat(angleFormatId);
1765}
1766
1767// See mtl::FormatTable::getVertexFormat()
1768const mtl::VertexFormat &ContextMtl::getVertexFormat(angle::FormatID angleFormatId,
1769                                                     bool tightlyPacked) const
1770{
1771    return getDisplay()->getVertexFormat(angleFormatId, tightlyPacked);
1772}
1773
1774const mtl::FormatCaps &ContextMtl::getNativeFormatCaps(MTLPixelFormat mtlFormat) const
1775{
1776    return getDisplay()->getNativeFormatCaps(mtlFormat);
1777}
1778
1779angle::Result ContextMtl::getIncompleteTexture(const gl::Context *context,
1780                                               gl::TextureType type,
1781                                               gl::SamplerFormat format,
1782                                               gl::Texture **textureOut)
1783{
1784    return mIncompleteTextures.getIncompleteTexture(context, type, format, nullptr, textureOut);
1785}
1786
1787void ContextMtl::endRenderEncoding(mtl::RenderCommandEncoder *encoder)
1788{
1789    // End any pending visibility query in the render pass
1790    if (mOcclusionQuery)
1791    {
1792        disableActiveOcclusionQueryInRenderPass();
1793    }
1794
1795    if (mBlitEncoder.valid())
1796    {
1797        mBlitEncoder.endEncoding();
1798    }
1799
1800    mOcclusionQueryPool.prepareRenderPassVisibilityPoolBuffer(this);
1801
1802    encoder->endEncoding();
1803
1804    // Resolve visibility results
1805    mOcclusionQueryPool.resolveVisibilityResults(this);
1806}
1807
1808void ContextMtl::endBlitAndComputeEncoding()
1809{
1810    if (mBlitEncoder.valid())
1811    {
1812        mBlitEncoder.endEncoding();
1813    }
1814
1815    if (mComputeEncoder.valid())
1816    {
1817        mComputeEncoder.endEncoding();
1818        mProvokingVertexHelper.releaseInFlightBuffers(this);
1819    }
1820}
1821
1822void ContextMtl::endEncoding(bool forceSaveRenderPassContent)
1823{
1824    endBlitAndComputeEncoding();
1825
1826    if (mRenderEncoder.valid())
1827    {
1828        if (forceSaveRenderPassContent)
1829        {
1830            // Save the work in progress.
1831            mRenderEncoder.setStoreAction(MTLStoreActionStore);
1832        }
1833
1834        endRenderEncoding(&mRenderEncoder);
1835    }
1836    // End blit encoder after render encoder, as endRenderEncoding() might create a
1837    // blit encoder to resolve the visibility results.
1838    if (mBlitEncoder.valid())
1839    {
1840        mBlitEncoder.endEncoding();
1841    }
1842}
1843
1844void ContextMtl::flushCommandBuffer(mtl::CommandBufferFinishOperation operation)
1845{
1846    mRenderPassesSinceFlush = 0;
1847    if (mCmdBuffer.ready())
1848    {
1849        endEncoding(true);
1850        mCmdBuffer.commit(operation);
1851        mBufferManager.incrementNumCommandBufferCommits();
1852    }
1853    else
1854    {
1855        mCmdBuffer.wait(operation);
1856    }
1857}
1858
1859void ContextMtl::flushCommandBufferIfNeeded()
1860{
1861    if (mRenderPassesSinceFlush >= mtl::kMaxRenderPassesPerCommandBuffer ||
1862        mCmdBuffer.needsFlushForDrawCallLimits())
1863    {
1864        // Ensure that we don't accumulate too many unflushed render passes. Don't wait until they
1865        // are submitted, other components handle backpressure so don't create uneccessary CPU/GPU
1866        // synchronization.
1867        flushCommandBuffer(mtl::NoWait);
1868    }
1869}
1870
1871void ContextMtl::present(const gl::Context *context, id<CAMetalDrawable> presentationDrawable)
1872{
1873    ensureCommandBufferReady();
1874
1875    FramebufferMtl *currentframebuffer = mtl::GetImpl(getState().getDrawFramebuffer());
1876    if (currentframebuffer)
1877    {
1878        currentframebuffer->onFrameEnd(context);
1879    }
1880
1881    endEncoding(false);
1882    mCmdBuffer.present(presentationDrawable);
1883    mCmdBuffer.commit(mtl::NoWait);
1884    mRenderPassesSinceFlush = 0;
1885}
1886
1887angle::Result ContextMtl::finishCommandBuffer()
1888{
1889    flushCommandBuffer(mtl::WaitUntilFinished);
1890    return checkCommandBufferError();
1891}
1892
1893bool ContextMtl::hasStartedRenderPass(const mtl::RenderPassDesc &desc)
1894{
1895    return mRenderEncoder.valid() &&
1896           mRenderEncoder.renderPassDesc().equalIgnoreLoadStoreOptions(desc);
1897}
1898
1899bool ContextMtl::isCurrentRenderEncoderSerial(uint64_t serial)
1900{
1901    if (!mRenderEncoder.valid())
1902    {
1903        return false;
1904    }
1905
1906    return serial == mRenderEncoder.getSerial();
1907}
1908
1909// Get current render encoder
1910mtl::RenderCommandEncoder *ContextMtl::getRenderCommandEncoder()
1911{
1912    if (!mRenderEncoder.valid())
1913    {
1914        return nullptr;
1915    }
1916
1917    return &mRenderEncoder;
1918}
1919
1920mtl::RenderCommandEncoder *ContextMtl::getRenderPassCommandEncoder(const mtl::RenderPassDesc &desc)
1921{
1922    if (hasStartedRenderPass(desc))
1923    {
1924        return &mRenderEncoder;
1925    }
1926
1927    endEncoding(false);
1928
1929    ensureCommandBufferReady();
1930    ++mRenderPassesSinceFlush;
1931
1932    // Need to re-apply everything on next draw call.
1933    mDirtyBits.set();
1934
1935    const mtl::ContextDevice &metalDevice = getMetalDevice();
1936    if (mtl::DeviceHasMaximumRenderTargetSize(metalDevice))
1937    {
1938        NSUInteger maxSize = mtl::GetMaxRenderTargetSizeForDeviceInBytes(metalDevice);
1939        NSUInteger renderTargetSize =
1940            ComputeTotalSizeUsedForMTLRenderPassDescriptor(desc, this, metalDevice);
1941        if (renderTargetSize > maxSize)
1942        {
1943            std::stringstream errorStream;
1944            errorStream << "This set of render targets requires " << renderTargetSize
1945                        << " bytes of pixel storage. This device supports " << maxSize << " bytes.";
1946            handleError(GL_INVALID_OPERATION, errorStream.str().c_str(), __FILE__, ANGLE_FUNCTION,
1947                        __LINE__);
1948            return nullptr;
1949        }
1950    }
1951    return &mRenderEncoder.restart(desc, getNativeCaps().maxColorAttachments);
1952}
1953
1954// Utilities to quickly create render command encoder to a specific texture:
1955// The previous content of texture will be loaded
1956mtl::RenderCommandEncoder *ContextMtl::getTextureRenderCommandEncoder(
1957    const mtl::TextureRef &textureTarget,
1958    const mtl::ImageNativeIndex &index)
1959{
1960    ASSERT(textureTarget && textureTarget->valid());
1961
1962    mtl::RenderPassDesc rpDesc;
1963
1964    rpDesc.colorAttachments[0].texture      = textureTarget;
1965    rpDesc.colorAttachments[0].level        = index.getNativeLevel();
1966    rpDesc.colorAttachments[0].sliceOrDepth = index.hasLayer() ? index.getLayerIndex() : 0;
1967    rpDesc.numColorAttachments              = 1;
1968    rpDesc.rasterSampleCount                = textureTarget->samples();
1969
1970    return getRenderPassCommandEncoder(rpDesc);
1971}
1972
1973// The previous content of texture will be loaded if clearColor is not provided
1974mtl::RenderCommandEncoder *ContextMtl::getRenderTargetCommandEncoderWithClear(
1975    const RenderTargetMtl &renderTarget,
1976    const Optional<MTLClearColor> &clearColor)
1977{
1978    ASSERT(renderTarget.getTexture());
1979
1980    mtl::RenderPassDesc rpDesc;
1981    renderTarget.toRenderPassAttachmentDesc(&rpDesc.colorAttachments[0]);
1982    rpDesc.numColorAttachments = 1;
1983    rpDesc.rasterSampleCount   = renderTarget.getRenderSamples();
1984
1985    if (clearColor.valid())
1986    {
1987        rpDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
1988        rpDesc.colorAttachments[0].clearColor = mtl::EmulatedAlphaClearColor(
1989            clearColor.value(), renderTarget.getTexture()->getColorWritableMask());
1990
1991        endEncoding(true);
1992    }
1993
1994    return getRenderPassCommandEncoder(rpDesc);
1995}
1996// The previous content of texture will be loaded
1997mtl::RenderCommandEncoder *ContextMtl::getRenderTargetCommandEncoder(
1998    const RenderTargetMtl &renderTarget)
1999{
2000    return getRenderTargetCommandEncoderWithClear(renderTarget, Optional<MTLClearColor>());
2001}
2002
2003mtl::BlitCommandEncoder *ContextMtl::getBlitCommandEncoder()
2004{
2005    if (mRenderEncoder.valid() || mComputeEncoder.valid())
2006    {
2007        endEncoding(true);
2008    }
2009
2010    if (mBlitEncoder.valid())
2011    {
2012        return &mBlitEncoder;
2013    }
2014
2015    endEncoding(true);
2016    ensureCommandBufferReady();
2017
2018    return &mBlitEncoder.restart();
2019}
2020
2021mtl::BlitCommandEncoder *ContextMtl::getBlitCommandEncoderWithoutEndingRenderEncoder()
2022{
2023    if (mBlitEncoder.valid())
2024    {
2025        return &mBlitEncoder;
2026    }
2027
2028    endBlitAndComputeEncoding();
2029    ensureCommandBufferReady();
2030
2031    return &mBlitEncoder.restart();
2032}
2033
2034mtl::ComputeCommandEncoder *ContextMtl::getComputeCommandEncoder()
2035{
2036    if (mRenderEncoder.valid() || mBlitEncoder.valid())
2037    {
2038        endEncoding(true);
2039    }
2040
2041    if (mComputeEncoder.valid())
2042    {
2043        return &mComputeEncoder;
2044    }
2045
2046    endEncoding(true);
2047    ensureCommandBufferReady();
2048
2049    return &mComputeEncoder.restart();
2050}
2051
2052mtl::ComputeCommandEncoder *ContextMtl::getComputeCommandEncoderWithoutEndingRenderEncoder()
2053{
2054    if (mComputeEncoder.valid())
2055    {
2056        return &mComputeEncoder;
2057    }
2058
2059    endBlitAndComputeEncoding();
2060    ensureCommandBufferReady();
2061
2062    return &mComputeEncoder.restart();
2063}
2064
2065mtl::ComputeCommandEncoder *ContextMtl::getIndexPreprocessingCommandEncoder()
2066{
2067    return getComputeCommandEncoder();
2068}
2069
2070void ContextMtl::ensureCommandBufferReady()
2071{
2072    flushCommandBufferIfNeeded();
2073
2074    if (!mCmdBuffer.ready())
2075    {
2076        mCmdBuffer.restart();
2077    }
2078
2079    ASSERT(mCmdBuffer.ready());
2080}
2081
2082void ContextMtl::updateViewport(FramebufferMtl *framebufferMtl,
2083                                const gl::Rectangle &viewport,
2084                                float nearPlane,
2085                                float farPlane)
2086{
2087    mViewport = mtl::GetViewport(viewport, framebufferMtl->getState().getDimensions().height,
2088                                 framebufferMtl->flipY(), nearPlane, farPlane);
2089    mDirtyBits.set(DIRTY_BIT_VIEWPORT);
2090
2091    invalidateDriverUniforms();
2092}
2093
2094void ContextMtl::updateDepthRange(float nearPlane, float farPlane)
2095{
2096    if (NeedToInvertDepthRange(nearPlane, farPlane))
2097    {
2098        // We also need to invert the depth in shader later by using scale value stored in driver
2099        // uniform depthRange.reserved
2100        std::swap(nearPlane, farPlane);
2101    }
2102    mViewport.znear = nearPlane;
2103    mViewport.zfar  = farPlane;
2104    mDirtyBits.set(DIRTY_BIT_VIEWPORT);
2105
2106    invalidateDriverUniforms();
2107}
2108
2109void ContextMtl::updateBlendDescArray(const gl::BlendStateExt &blendStateExt)
2110{
2111    for (size_t i = 0; i < mBlendDescArray.size(); i++)
2112    {
2113        mtl::BlendDesc &blendDesc = mBlendDescArray[i];
2114        if (blendStateExt.getEnabledMask().test(i))
2115        {
2116            blendDesc.blendingEnabled = true;
2117
2118            blendDesc.sourceRGBBlendFactor =
2119                mtl::GetBlendFactor(blendStateExt.getSrcColorIndexed(i));
2120            blendDesc.sourceAlphaBlendFactor =
2121                mtl::GetBlendFactor(blendStateExt.getSrcAlphaIndexed(i));
2122            blendDesc.destinationRGBBlendFactor =
2123                mtl::GetBlendFactor(blendStateExt.getDstColorIndexed(i));
2124            blendDesc.destinationAlphaBlendFactor =
2125                mtl::GetBlendFactor(blendStateExt.getDstAlphaIndexed(i));
2126
2127            blendDesc.rgbBlendOperation = mtl::GetBlendOp(blendStateExt.getEquationColorIndexed(i));
2128            blendDesc.alphaBlendOperation =
2129                mtl::GetBlendOp(blendStateExt.getEquationAlphaIndexed(i));
2130        }
2131        else
2132        {
2133            // Enforce default state when blending is disabled,
2134            blendDesc.reset(blendDesc.writeMask);
2135        }
2136    }
2137    invalidateRenderPipeline();
2138}
2139
2140void ContextMtl::updateScissor(const gl::State &glState)
2141{
2142    FramebufferMtl *framebufferMtl = mtl::GetImpl(glState.getDrawFramebuffer());
2143    gl::Rectangle renderArea       = framebufferMtl->getCompleteRenderArea();
2144
2145    ANGLE_MTL_LOG("renderArea = %d,%d,%d,%d", renderArea.x, renderArea.y, renderArea.width,
2146                  renderArea.height);
2147
2148    // Clip the render area to the viewport.
2149    gl::Rectangle viewportClippedRenderArea;
2150    if (!gl::ClipRectangle(renderArea, glState.getViewport(), &viewportClippedRenderArea))
2151    {
2152        viewportClippedRenderArea = gl::Rectangle();
2153    }
2154
2155    gl::Rectangle scissoredArea = ClipRectToScissor(getState(), viewportClippedRenderArea, false);
2156    if (framebufferMtl->flipY())
2157    {
2158        scissoredArea.y = renderArea.height - scissoredArea.y - scissoredArea.height;
2159    }
2160
2161    ANGLE_MTL_LOG("scissoredArea = %d,%d,%d,%d", scissoredArea.x, scissoredArea.y,
2162                  scissoredArea.width, scissoredArea.height);
2163
2164    mScissorRect = mtl::GetScissorRect(scissoredArea);
2165    mDirtyBits.set(DIRTY_BIT_SCISSOR);
2166}
2167
2168void ContextMtl::updateCullMode(const gl::State &glState)
2169{
2170    const gl::RasterizerState &rasterState = glState.getRasterizerState();
2171
2172    mCullAllPolygons = false;
2173    if (!rasterState.cullFace)
2174    {
2175        mCullMode = MTLCullModeNone;
2176    }
2177    else
2178    {
2179        switch (rasterState.cullMode)
2180        {
2181            case gl::CullFaceMode::Back:
2182                mCullMode = MTLCullModeBack;
2183                break;
2184            case gl::CullFaceMode::Front:
2185                mCullMode = MTLCullModeFront;
2186                break;
2187            case gl::CullFaceMode::FrontAndBack:
2188                mCullAllPolygons = true;
2189                break;
2190            default:
2191                UNREACHABLE();
2192                break;
2193        }
2194    }
2195
2196    mDirtyBits.set(DIRTY_BIT_CULL_MODE);
2197}
2198
2199void ContextMtl::updateFrontFace(const gl::State &glState)
2200{
2201    FramebufferMtl *framebufferMtl = mtl::GetImpl(glState.getDrawFramebuffer());
2202    const bool upperLeftOrigin     = mState.getClipOrigin() == gl::ClipOrigin::UpperLeft;
2203    mWinding = mtl::GetFrontfaceWinding(glState.getRasterizerState().frontFace,
2204                                        framebufferMtl->flipY() == upperLeftOrigin);
2205    mDirtyBits.set(DIRTY_BIT_WINDING);
2206}
2207
2208// Index rewrite is required if:
2209// Provkoing vertex mode is 'last'
2210// Program has at least one 'flat' attribute
2211// PrimitiveMode is not POINTS.
2212bool ContextMtl::requiresIndexRewrite(const gl::State &state, gl::PrimitiveMode mode)
2213{
2214    return mode != gl::PrimitiveMode::Points && mExecutable->hasFlatAttribute() &&
2215           (state.getProvokingVertex() == gl::ProvokingVertexConvention::LastVertexConvention);
2216}
2217
2218void ContextMtl::updateDrawFrameBufferBinding(const gl::Context *context)
2219{
2220    const gl::State &glState = getState();
2221
2222    FramebufferMtl *newDrawFramebuffer = mtl::GetImpl(glState.getDrawFramebuffer());
2223    if (newDrawFramebuffer != mDrawFramebuffer)
2224    {
2225        // Reset this flag if the framebuffer has changed to not sync it twice
2226        mForceResyncDrawFramebuffer = false;
2227    }
2228
2229    mDrawFramebuffer = newDrawFramebuffer;
2230
2231    mDrawFramebuffer->onStartedDrawingToFrameBuffer(context);
2232
2233    onDrawFrameBufferChangedState(context, mDrawFramebuffer, true);
2234}
2235
2236void ContextMtl::onDrawFrameBufferChangedState(const gl::Context *context,
2237                                               FramebufferMtl *framebuffer,
2238                                               bool renderPassChanged)
2239{
2240    const gl::State &glState = getState();
2241    ASSERT(framebuffer == mtl::GetImpl(glState.getDrawFramebuffer()));
2242
2243    updateViewport(framebuffer, glState.getViewport(), glState.getNearPlane(),
2244                   glState.getFarPlane());
2245    updateFrontFace(glState);
2246    updateScissor(glState);
2247
2248    if (renderPassChanged)
2249    {
2250        // End any render encoding using the old render pass.
2251        endEncoding(false);
2252        // Need to re-apply state to RenderCommandEncoder
2253        invalidateState(context);
2254    }
2255    else
2256    {
2257        // Invalidate current pipeline only.
2258        invalidateRenderPipeline();
2259    }
2260}
2261
2262void ContextMtl::onBackbufferResized(const gl::Context *context, WindowSurfaceMtl *backbuffer)
2263{
2264    const gl::State &glState    = getState();
2265    FramebufferMtl *framebuffer = mtl::GetImpl(glState.getDrawFramebuffer());
2266    if (framebuffer->getAttachedBackbuffer() != backbuffer)
2267    {
2268        return;
2269    }
2270
2271    onDrawFrameBufferChangedState(context, framebuffer, true);
2272}
2273
2274angle::Result ContextMtl::onOcclusionQueryBegin(const gl::Context *context, QueryMtl *query)
2275{
2276    ASSERT(mOcclusionQuery == nullptr);
2277    mOcclusionQuery = query;
2278
2279    if (mRenderEncoder.valid())
2280    {
2281        // if render pass has started, start the query in the encoder
2282        return startOcclusionQueryInRenderPass(query, true);
2283    }
2284    else
2285    {
2286        query->resetVisibilityResult(this);
2287    }
2288
2289    return angle::Result::Continue;
2290}
2291void ContextMtl::onOcclusionQueryEnd(const gl::Context *context, QueryMtl *query)
2292{
2293    ASSERT(mOcclusionQuery == query);
2294
2295    if (mRenderEncoder.valid())
2296    {
2297        // if render pass has started, end the query in the encoder
2298        disableActiveOcclusionQueryInRenderPass();
2299    }
2300
2301    mOcclusionQuery = nullptr;
2302}
2303void ContextMtl::onOcclusionQueryDestroy(const gl::Context *context, QueryMtl *query)
2304{
2305    if (query->getAllocatedVisibilityOffsets().empty())
2306    {
2307        return;
2308    }
2309    if (mOcclusionQuery == query)
2310    {
2311        onOcclusionQueryEnd(context, query);
2312    }
2313    mOcclusionQueryPool.deallocateQueryOffset(this, query);
2314}
2315
2316void ContextMtl::disableActiveOcclusionQueryInRenderPass()
2317{
2318    if (!mOcclusionQuery || mOcclusionQuery->getAllocatedVisibilityOffsets().empty())
2319    {
2320        return;
2321    }
2322
2323    ASSERT(mRenderEncoder.valid());
2324    mRenderEncoder.setVisibilityResultMode(MTLVisibilityResultModeDisabled,
2325                                           mOcclusionQuery->getAllocatedVisibilityOffsets().back());
2326}
2327
2328angle::Result ContextMtl::restartActiveOcclusionQueryInRenderPass()
2329{
2330    if (!mOcclusionQuery || mOcclusionQuery->getAllocatedVisibilityOffsets().empty())
2331    {
2332        return angle::Result::Continue;
2333    }
2334
2335    return startOcclusionQueryInRenderPass(mOcclusionQuery, false);
2336}
2337
2338angle::Result ContextMtl::startOcclusionQueryInRenderPass(QueryMtl *query, bool clearOldValue)
2339{
2340    ASSERT(mRenderEncoder.valid());
2341
2342    ANGLE_TRY(mOcclusionQueryPool.allocateQueryOffset(this, query, clearOldValue));
2343
2344    mRenderEncoder.setVisibilityResultMode(MTLVisibilityResultModeBoolean,
2345                                           query->getAllocatedVisibilityOffsets().back());
2346
2347    // We need to mark the query's buffer as being written in this command buffer now. Since the
2348    // actual writing is deferred until the render pass ends and user could try to read the query
2349    // result before the render pass ends.
2350    mCmdBuffer.setWriteDependency(query->getVisibilityResultBuffer(), /*isRenderCommand=*/true);
2351
2352    return angle::Result::Continue;
2353}
2354
2355void ContextMtl::onTransformFeedbackActive(const gl::Context *context, TransformFeedbackMtl *xfb)
2356{
2357    // NOTE(hqle): We have to end current render pass to enable synchronization before XFB
2358    // buffers could be used as vertex input. Consider a better approach.
2359    endEncoding(true);
2360}
2361
2362void ContextMtl::onTransformFeedbackInactive(const gl::Context *context, TransformFeedbackMtl *xfb)
2363{
2364    // NOTE(hqle): We have to end current render pass to enable synchronization before XFB
2365    // buffers could be used as vertex input. Consider a better approach.
2366    endEncoding(true);
2367}
2368
2369uint64_t ContextMtl::queueEventSignal(id<MTLEvent> event, uint64_t value)
2370{
2371    ensureCommandBufferReady();
2372    // Event is queued to be signaled after current render pass. If we have helper blit or
2373    // compute encoders, avoid queueing by stopping them immediately so we get to insert the event
2374    // right away.
2375    endBlitAndComputeEncoding();
2376    return mCmdBuffer.queueEventSignal(event, value);
2377}
2378
2379void ContextMtl::serverWaitEvent(id<MTLEvent> event, uint64_t value)
2380{
2381    ensureCommandBufferReady();
2382
2383    // Event waiting cannot be encoded if there is active encoder.
2384    endEncoding(true);
2385
2386    mCmdBuffer.serverWaitEvent(event, value);
2387}
2388
2389void ContextMtl::updateProgramExecutable(const gl::Context *context)
2390{
2391    // Need to rebind textures
2392    invalidateCurrentTextures();
2393    // Need to re-upload default attributes
2394    invalidateDefaultAttributes(context->getStateCache().getActiveDefaultAttribsMask());
2395    // Render pipeline need to be re-applied
2396    invalidateRenderPipeline();
2397}
2398
2399void ContextMtl::updateVertexArray(const gl::Context *context)
2400{
2401    const gl::State &glState = getState();
2402    mVertexArray             = mtl::GetImpl(glState.getVertexArray());
2403    invalidateDefaultAttributes(context->getStateCache().getActiveDefaultAttribsMask());
2404    invalidateRenderPipeline();
2405}
2406
2407angle::Result ContextMtl::updateDefaultAttribute(size_t attribIndex)
2408{
2409    const gl::State &glState = mState;
2410    const gl::VertexAttribCurrentValueData &defaultValue =
2411        glState.getVertexAttribCurrentValues()[attribIndex];
2412
2413    constexpr size_t kDefaultGLAttributeValueSize =
2414        sizeof(gl::VertexAttribCurrentValueData::Values);
2415
2416    static_assert(kDefaultGLAttributeValueSize == mtl::kDefaultAttributeSize,
2417                  "Unexpected default attribute size");
2418    memcpy(mDefaultAttributes[attribIndex].values, &defaultValue.Values,
2419           mtl::kDefaultAttributeSize);
2420
2421    return angle::Result::Continue;
2422}
2423
2424static bool isDrawNoOp(const mtl::RenderPipelineDesc &descriptor,
2425                       ContextMtl *context,
2426                       const mtl::ContextDevice &device)
2427{
2428    // Ensure there is at least one valid render target.
2429    bool hasValidRenderTarget = false;
2430
2431    const NSUInteger maxColorRenderTargets = GetMaxNumberOfRenderTargetsForDevice(device);
2432    for (NSUInteger i = 0; i < maxColorRenderTargets; ++i)
2433    {
2434        const auto &colorAttachment = descriptor.outputDescriptor.colorAttachments[i];
2435        if (colorAttachment.pixelFormat != MTLPixelFormatInvalid)
2436        {
2437            hasValidRenderTarget = true;
2438            break;
2439        }
2440    }
2441
2442    if (!hasValidRenderTarget &&
2443        descriptor.outputDescriptor.depthAttachmentPixelFormat != MTLPixelFormatInvalid)
2444    {
2445        hasValidRenderTarget = true;
2446    }
2447
2448    if (!hasValidRenderTarget &&
2449        descriptor.outputDescriptor.stencilAttachmentPixelFormat != MTLPixelFormatInvalid)
2450    {
2451        hasValidRenderTarget = true;
2452    }
2453
2454    if (!hasValidRenderTarget)
2455    {
2456        FramebufferMtl *framebufferMtl = mtl::GetImpl(context->getState().getDrawFramebuffer());
2457        hasValidRenderTarget           = framebufferMtl->renderPassHasDefaultWidthOrHeight();
2458    }
2459
2460    // Draw is no op if there is no valid render target, and we're not in a
2461    // rasterization-disabled draw.
2462
2463    bool noRenderTarget        = !hasValidRenderTarget;
2464    bool rasterizationDisabled = !descriptor.rasterizationEnabled();
2465    return !rasterizationDisabled && noRenderTarget;
2466}
2467
2468angle::Result ContextMtl::setupDraw(const gl::Context *context,
2469                                    gl::PrimitiveMode mode,
2470                                    GLint firstVertex,
2471                                    GLsizei vertexOrIndexCount,
2472                                    GLsizei instances,
2473                                    gl::DrawElementsType indexTypeOrNone,
2474                                    const void *indices,
2475                                    bool xfbPass,
2476                                    bool *isNoOp)
2477{
2478    ANGLE_TRY(setupDrawImpl(context, mode, firstVertex, vertexOrIndexCount, instances,
2479                            indexTypeOrNone, indices, xfbPass, isNoOp));
2480    if (*isNoOp)
2481    {
2482        return angle::Result::Continue;
2483    }
2484    if (!mRenderEncoder.valid())
2485    {
2486        // Flush occurred during setup, due to running out of memory while setting up the render
2487        // pass state. This would happen for example when there is no more space in the uniform
2488        // buffers in the uniform buffer pool. The rendering would be flushed to free the uniform
2489        // buffer memory for new usage. In this case, re-run the setup.
2490        ANGLE_TRY(setupDrawImpl(context, mode, firstVertex, vertexOrIndexCount, instances,
2491                                indexTypeOrNone, indices, xfbPass, isNoOp));
2492
2493        if (*isNoOp)
2494        {
2495            return checkCommandBufferError();
2496        }
2497        // Setup with flushed state should either produce a working encoder or fail with an error
2498        // result.
2499        ASSERT(mRenderEncoder.valid());
2500    }
2501    return angle::Result::Continue;
2502}
2503
2504angle::Result ContextMtl::setupDrawImpl(const gl::Context *context,
2505                                        gl::PrimitiveMode mode,
2506                                        GLint firstVertex,
2507                                        GLsizei vertexOrIndexCount,
2508                                        GLsizei instances,
2509                                        gl::DrawElementsType indexTypeOrNone,
2510                                        const void *indices,
2511                                        bool xfbPass,
2512                                        bool *isNoOp)
2513{
2514    ASSERT(mExecutable);
2515    *isNoOp = false;
2516    // instances=0 means no instanced draw.
2517    GLsizei instanceCount = instances ? instances : 1;
2518
2519    if (context->getStateCache().hasAnyActiveClientAttrib())
2520    {
2521        ANGLE_TRY(mVertexArray->updateClientAttribs(context, firstVertex, vertexOrIndexCount,
2522                                                    instanceCount, indexTypeOrNone, indices));
2523    }
2524
2525    // This must be called before render command encoder is started.
2526    bool textureChanged = false;
2527    if (mDirtyBits.test(DIRTY_BIT_TEXTURES))
2528    {
2529        textureChanged = true;
2530        ANGLE_TRY(handleDirtyActiveTextures(context));
2531    }
2532
2533    if (mDirtyBits.test(DIRTY_BIT_RASTERIZER_DISCARD))
2534    {
2535        if (getState().isTransformFeedbackActiveUnpaused())
2536        {
2537            // If XFB is active we need to reset render pass since we could use a dummy render
2538            // target if only XFB is needed.
2539            invalidateState(context);
2540        }
2541        else
2542        {
2543            invalidateRenderPipeline();
2544        }
2545    }
2546
2547    if (!mRenderEncoder.valid())
2548    {
2549        // re-apply everything
2550        invalidateState(context);
2551    }
2552
2553    if (mDirtyBits.test(DIRTY_BIT_DRAW_FRAMEBUFFER))
2554    {
2555        ANGLE_TRY(handleDirtyRenderPass(context));
2556    }
2557
2558    if (mOcclusionQuery && mOcclusionQueryPool.getNumRenderPassAllocatedQueries() == 0)
2559    {
2560        // The occlusion query is still active, and a new render pass has started.
2561        // We need to continue the querying process in the new render encoder.
2562        ANGLE_TRY(startOcclusionQueryInRenderPass(mOcclusionQuery, false));
2563    }
2564
2565    bool isPipelineDescChanged;
2566    ANGLE_TRY(checkIfPipelineChanged(context, mode, xfbPass, &isPipelineDescChanged));
2567
2568    bool uniformBuffersDirty = false;
2569
2570    if (IsTransformFeedbackOnly(getState()))
2571    {
2572        // Filter out unneeded dirty bits
2573        filterOutXFBOnlyDirtyBits(context);
2574    }
2575
2576    for (size_t bit : mDirtyBits)
2577    {
2578        switch (bit)
2579        {
2580            case DIRTY_BIT_TEXTURES:
2581                // Already handled.
2582                break;
2583            case DIRTY_BIT_DEFAULT_ATTRIBS:
2584                ANGLE_TRY(handleDirtyDefaultAttribs(context));
2585                break;
2586            case DIRTY_BIT_DRIVER_UNIFORMS:
2587                ANGLE_TRY(handleDirtyDriverUniforms(context, firstVertex, vertexOrIndexCount));
2588                break;
2589            case DIRTY_BIT_DEPTH_STENCIL_DESC:
2590                ANGLE_TRY(handleDirtyDepthStencilState(context));
2591                break;
2592            case DIRTY_BIT_DEPTH_BIAS:
2593                ANGLE_TRY(handleDirtyDepthBias(context));
2594                break;
2595            case DIRTY_BIT_DEPTH_CLIP_MODE:
2596                mRenderEncoder.setDepthClipMode(
2597                    mState.isDepthClampEnabled() ? MTLDepthClipModeClamp : MTLDepthClipModeClip);
2598                break;
2599            case DIRTY_BIT_STENCIL_REF:
2600                mRenderEncoder.setStencilRefVals(mStencilRefFront, mStencilRefBack);
2601                break;
2602            case DIRTY_BIT_BLEND_COLOR:
2603                mRenderEncoder.setBlendColor(
2604                    mState.getBlendColor().red, mState.getBlendColor().green,
2605                    mState.getBlendColor().blue, mState.getBlendColor().alpha);
2606                break;
2607            case DIRTY_BIT_VIEWPORT:
2608                mRenderEncoder.setViewport(mViewport);
2609                break;
2610            case DIRTY_BIT_SCISSOR:
2611                mRenderEncoder.setScissorRect(mScissorRect);
2612                break;
2613            case DIRTY_BIT_DRAW_FRAMEBUFFER:
2614                // Already handled.
2615                break;
2616            case DIRTY_BIT_CULL_MODE:
2617                mRenderEncoder.setCullMode(mCullMode);
2618                break;
2619            case DIRTY_BIT_FILL_MODE:
2620                mRenderEncoder.setTriangleFillMode(mState.getPolygonMode() == gl::PolygonMode::Fill
2621                                                       ? MTLTriangleFillModeFill
2622                                                       : MTLTriangleFillModeLines);
2623                break;
2624            case DIRTY_BIT_WINDING:
2625                mRenderEncoder.setFrontFacingWinding(mWinding);
2626                break;
2627            case DIRTY_BIT_RENDER_PIPELINE:
2628                // Already handled. See checkIfPipelineChanged().
2629                break;
2630            case DIRTY_BIT_UNIFORM_BUFFERS_BINDING:
2631                uniformBuffersDirty = true;
2632                break;
2633            case DIRTY_BIT_RASTERIZER_DISCARD:
2634                // Already handled.
2635                break;
2636            default:
2637                UNREACHABLE();
2638                break;
2639        }
2640    }
2641
2642    if (xfbPass && !mDirtyBits.test(DIRTY_BIT_DRIVER_UNIFORMS))
2643    {
2644        // If handleDirtyDriverUniforms() was not called and this is XFB pass, we still need to
2645        // update XFB related uniforms
2646        ANGLE_TRY(
2647            fillDriverXFBUniforms(firstVertex, vertexOrIndexCount, /** skippedInstances */ 0));
2648        mRenderEncoder.setVertexData(mDriverUniforms, mtl::kDriverUniformsBindingIndex);
2649    }
2650
2651    mDirtyBits.reset();
2652    // Check to see if our state would lead to a no-op draw.
2653    // If so, skip program setup until we end up with a state that requires a program.
2654    if (isDrawNoOp(mRenderPipelineDesc, this, mContextDevice))
2655    {
2656        *isNoOp = true;
2657    }
2658    else
2659    {
2660        ANGLE_TRY(mExecutable->setupDraw(context, &mRenderEncoder, mRenderPipelineDesc,
2661                                         isPipelineDescChanged, textureChanged,
2662                                         uniformBuffersDirty));
2663    }
2664
2665    return checkCommandBufferError();
2666}
2667
2668void ContextMtl::filterOutXFBOnlyDirtyBits(const gl::Context *context)
2669{
2670    ASSERT(IsTransformFeedbackOnly(getState()));
2671
2672    ASSERT(mRenderEncoder.renderPassDesc().colorAttachments[0].texture == mDummyXFBRenderTexture);
2673
2674    // In transform feedback only pass, only vertex shader's related states are needed.
2675    constexpr size_t kUnneededBits =
2676        angle::Bit<size_t>(DIRTY_BIT_DEPTH_STENCIL_DESC) |
2677        angle::Bit<size_t>(DIRTY_BIT_DEPTH_BIAS) | angle::Bit<size_t>(DIRTY_BIT_STENCIL_REF) |
2678        angle::Bit<size_t>(DIRTY_BIT_BLEND_COLOR) | angle::Bit<size_t>(DIRTY_BIT_VIEWPORT) |
2679        angle::Bit<size_t>(DIRTY_BIT_SCISSOR) | angle::Bit<size_t>(DIRTY_BIT_CULL_MODE) |
2680        angle::Bit<size_t>(DIRTY_BIT_FILL_MODE) | angle::Bit<size_t>(DIRTY_BIT_WINDING);
2681
2682    mDirtyBits &= ~kUnneededBits;
2683}
2684
2685angle::Result ContextMtl::handleDirtyRenderPass(const gl::Context *context)
2686{
2687    if (!IsTransformFeedbackOnly(mState))
2688    {
2689        // Start new render command encoder
2690        mtl::RenderCommandEncoder *encoder;
2691        ANGLE_TRY(mDrawFramebuffer->ensureRenderPassStarted(context, &encoder));
2692    }
2693    else
2694    {
2695        // XFB is active and rasterization is disabled. Use dummy render target.
2696        // We currently need to end the render pass when XFB is activated/deactivated so using
2697        // a small dummy render target would make the render pass ending very cheap.
2698        if (!mDummyXFBRenderTexture)
2699        {
2700            ANGLE_TRY(mtl::Texture::Make2DTexture(this,
2701                                                  getPixelFormat(angle::FormatID::R8G8B8A8_UNORM),
2702                                                  1, 1, 1, true, false, &mDummyXFBRenderTexture));
2703        }
2704        mtl::RenderCommandEncoder *encoder = getTextureRenderCommandEncoder(
2705            mDummyXFBRenderTexture,
2706            mtl::ImageNativeIndex::FromBaseZeroGLIndex(gl::ImageIndex::Make2D(0)));
2707        encoder->setColorLoadAction(MTLLoadActionDontCare, MTLClearColor(), 0);
2708        encoder->setColorStoreAction(MTLStoreActionDontCare);
2709
2710#ifndef NDEBUG
2711        encoder->setLabel(@"TransformFeedbackOnlyPass");
2712#endif
2713    }
2714
2715    // re-apply everything
2716    invalidateState(context);
2717
2718    return angle::Result::Continue;
2719}
2720
2721angle::Result ContextMtl::handleDirtyActiveTextures(const gl::Context *context)
2722{
2723    const gl::State &glState                = mState;
2724    const gl::ProgramExecutable *executable = glState.getProgramExecutable();
2725
2726    constexpr auto ensureTextureStorageCreated = [](const gl::Context *context,
2727                                                    gl::Texture *texture) -> angle::Result {
2728        if (texture == nullptr)
2729        {
2730            return angle::Result::Continue;
2731        }
2732
2733        TextureMtl *textureMtl = mtl::GetImpl(texture);
2734
2735        // Make sure texture's image definitions will be transferred to GPU.
2736        ANGLE_TRY(textureMtl->ensureNativeStorageCreated(context));
2737
2738        // The binding of this texture will be done by ProgramMtl.
2739        return angle::Result::Continue;
2740    };
2741
2742    const gl::ActiveTexturesCache &textures     = glState.getActiveTexturesCache();
2743    const gl::ActiveTextureMask &activeTextures = executable->getActiveSamplersMask();
2744
2745    for (size_t textureUnit : activeTextures)
2746    {
2747        ANGLE_TRY(ensureTextureStorageCreated(context, textures[textureUnit]));
2748    }
2749
2750    for (size_t imageUnit : executable->getActiveImagesMask())
2751    {
2752        ANGLE_TRY(
2753            ensureTextureStorageCreated(context, glState.getImageUnit(imageUnit).texture.get()));
2754    }
2755
2756    return angle::Result::Continue;
2757}
2758
2759angle::Result ContextMtl::handleDirtyDefaultAttribs(const gl::Context *context)
2760{
2761    for (size_t attribIndex : mDirtyDefaultAttribsMask)
2762    {
2763        ANGLE_TRY(updateDefaultAttribute(attribIndex));
2764    }
2765
2766    ASSERT(mRenderEncoder.valid());
2767    mRenderEncoder.setVertexData(mDefaultAttributes, mtl::kDefaultAttribsBindingIndex);
2768
2769    mDirtyDefaultAttribsMask.reset();
2770    return angle::Result::Continue;
2771}
2772
2773angle::Result ContextMtl::handleDirtyDriverUniforms(const gl::Context *context,
2774                                                    GLint drawCallFirstVertex,
2775                                                    uint32_t verticesPerInstance)
2776{
2777    mDriverUniforms.depthRange[0] = mState.getNearPlane();
2778    mDriverUniforms.depthRange[1] = mState.getFarPlane();
2779
2780    mDriverUniforms.renderArea = mDrawFramebuffer->getState().getDimensions().height << 16 |
2781                                 mDrawFramebuffer->getState().getDimensions().width;
2782
2783    const float flipX      = 1.0;
2784    const float flipY      = mDrawFramebuffer->flipY() ? -1.0f : 1.0f;
2785    mDriverUniforms.flipXY = gl::PackSnorm4x8(
2786        flipX, flipY, flipX, mState.getClipOrigin() == gl::ClipOrigin::LowerLeft ? -flipY : flipY);
2787
2788    // gl_ClipDistance
2789    const uint32_t enabledClipDistances = mState.getEnabledClipDistances().bits();
2790    ASSERT((enabledClipDistances & ~sh::vk::kDriverUniformsMiscEnabledClipPlanesMask) == 0);
2791
2792    // GL_CLIP_DEPTH_MODE_EXT
2793    const uint32_t transformDepth = !mState.isClipDepthModeZeroToOne();
2794    ASSERT((transformDepth & ~sh::vk::kDriverUniformsMiscTransformDepthMask) == 0);
2795
2796    // GL_SAMPLE_ALPHA_TO_COVERAGE
2797    const uint32_t alphaToCoverage = mState.isSampleAlphaToCoverageEnabled();
2798    ASSERT((alphaToCoverage & ~sh::vk::kDriverUniformsMiscAlphaToCoverageMask) == 0);
2799
2800    mDriverUniforms.misc =
2801        (enabledClipDistances << sh::vk::kDriverUniformsMiscEnabledClipPlanesOffset) |
2802        (transformDepth << sh::vk::kDriverUniformsMiscTransformDepthOffset) |
2803        (alphaToCoverage << sh::vk::kDriverUniformsMiscAlphaToCoverageOffset);
2804
2805    // Sample coverage mask
2806    if (mState.isSampleCoverageEnabled())
2807    {
2808        const uint32_t sampleBitCount = mDrawFramebuffer->getSamples();
2809        ASSERT(sampleBitCount < 32);
2810        const uint32_t coverageSampleBitCount =
2811            static_cast<uint32_t>(std::round(mState.getSampleCoverageValue() * sampleBitCount));
2812        uint32_t coverageMask = (1u << coverageSampleBitCount) - 1;
2813        if (mState.getSampleCoverageInvert())
2814        {
2815            const uint32_t sampleMask = (1u << sampleBitCount) - 1;
2816            coverageMask              = sampleMask & (~coverageMask);
2817        }
2818        mDriverUniforms.coverageMask = coverageMask;
2819    }
2820    else
2821    {
2822        mDriverUniforms.coverageMask = 0xFFFFFFFFu;
2823    }
2824
2825    // Sample mask
2826    if (mState.isSampleMaskEnabled())
2827    {
2828        mDriverUniforms.coverageMask &= mState.getSampleMaskWord(0);
2829    }
2830
2831    ANGLE_TRY(
2832        fillDriverXFBUniforms(drawCallFirstVertex, verticesPerInstance, /** skippedInstances */ 0));
2833
2834    ASSERT(mRenderEncoder.valid());
2835    mRenderEncoder.setFragmentData(mDriverUniforms, mtl::kDriverUniformsBindingIndex);
2836    mRenderEncoder.setVertexData(mDriverUniforms, mtl::kDriverUniformsBindingIndex);
2837
2838    return angle::Result::Continue;
2839}
2840
2841angle::Result ContextMtl::fillDriverXFBUniforms(GLint drawCallFirstVertex,
2842                                                uint32_t verticesPerInstance,
2843                                                uint32_t skippedInstances)
2844{
2845    gl::TransformFeedback *transformFeedback = getState().getCurrentTransformFeedback();
2846
2847    bool xfbActiveUnpaused = getState().isTransformFeedbackActiveUnpaused();
2848    if (!transformFeedback || !xfbActiveUnpaused)
2849    {
2850        return angle::Result::Continue;
2851    }
2852
2853    mDriverUniforms.xfbVerticesPerInstance = verticesPerInstance;
2854
2855    TransformFeedbackMtl *transformFeedbackMtl = mtl::GetImpl(transformFeedback);
2856
2857    return transformFeedbackMtl->getBufferOffsets(this, drawCallFirstVertex,
2858                                                  verticesPerInstance * skippedInstances,
2859                                                  mDriverUniforms.xfbBufferOffsets);
2860}
2861
2862angle::Result ContextMtl::handleDirtyDepthStencilState(const gl::Context *context)
2863{
2864    ASSERT(mRenderEncoder.valid());
2865
2866    // Need to handle the case when render pass doesn't have depth/stencil attachment.
2867    mtl::DepthStencilDesc dsDesc              = mDepthStencilDesc;
2868    const mtl::RenderPassDesc &renderPassDesc = mRenderEncoder.renderPassDesc();
2869
2870    if (!renderPassDesc.depthAttachment.texture)
2871    {
2872        dsDesc.depthWriteEnabled    = false;
2873        dsDesc.depthCompareFunction = MTLCompareFunctionAlways;
2874    }
2875
2876    if (!renderPassDesc.stencilAttachment.texture)
2877    {
2878        dsDesc.frontFaceStencil.reset();
2879        dsDesc.backFaceStencil.reset();
2880    }
2881
2882    // Apply depth stencil state
2883    mRenderEncoder.setDepthStencilState(
2884        getDisplay()->getStateCache().getDepthStencilState(getMetalDevice(), dsDesc));
2885
2886    return angle::Result::Continue;
2887}
2888
2889angle::Result ContextMtl::handleDirtyDepthBias(const gl::Context *context)
2890{
2891    const gl::RasterizerState &rasterState = mState.getRasterizerState();
2892    ASSERT(mRenderEncoder.valid());
2893    if (!mState.isPolygonOffsetEnabled())
2894    {
2895        mRenderEncoder.setDepthBias(0, 0, 0);
2896    }
2897    else
2898    {
2899        mRenderEncoder.setDepthBias(rasterState.polygonOffsetUnits, rasterState.polygonOffsetFactor,
2900                                    rasterState.polygonOffsetClamp);
2901    }
2902
2903    return angle::Result::Continue;
2904}
2905
2906angle::Result ContextMtl::checkIfPipelineChanged(const gl::Context *context,
2907                                                 gl::PrimitiveMode primitiveMode,
2908                                                 bool xfbPass,
2909                                                 bool *isPipelineDescChanged)
2910{
2911    ASSERT(mRenderEncoder.valid());
2912    MTLPrimitiveTopologyClass topologyClass = mtl::GetPrimitiveTopologyClass(primitiveMode);
2913
2914    bool rppChange = mDirtyBits.test(DIRTY_BIT_RENDER_PIPELINE) ||
2915                     topologyClass != mRenderPipelineDesc.inputPrimitiveTopology;
2916
2917    // Obtain RenderPipelineDesc's vertex array descriptor.
2918    ANGLE_TRY(mVertexArray->setupDraw(context, &mRenderEncoder, &rppChange,
2919                                      &mRenderPipelineDesc.vertexDescriptor));
2920
2921    if (rppChange)
2922    {
2923        const mtl::RenderPassDesc &renderPassDesc = mRenderEncoder.renderPassDesc();
2924        // Obtain RenderPipelineDesc's output descriptor.
2925        renderPassDesc.populateRenderPipelineOutputDesc(mBlendDescArray,
2926                                                        &mRenderPipelineDesc.outputDescriptor);
2927
2928        if (xfbPass)
2929        {
2930            // In XFB pass, we disable fragment shader.
2931            mRenderPipelineDesc.rasterizationType = mtl::RenderPipelineRasterization::Disabled;
2932        }
2933        else if (mState.isRasterizerDiscardEnabled())
2934        {
2935            // If XFB is not active and rasterizer discard is enabled, we need to emulate the
2936            // discard. Because in this case, vertex shader might write to stage output values and
2937            // Metal doesn't allow rasterization to be disabled.
2938            mRenderPipelineDesc.rasterizationType =
2939                mtl::RenderPipelineRasterization::EmulatedDiscard;
2940        }
2941        else
2942        {
2943            mRenderPipelineDesc.rasterizationType = mtl::RenderPipelineRasterization::Enabled;
2944        }
2945        mRenderPipelineDesc.inputPrimitiveTopology = topologyClass;
2946        mRenderPipelineDesc.alphaToCoverageEnabled =
2947            mState.isSampleAlphaToCoverageEnabled() &&
2948            mRenderPipelineDesc.outputDescriptor.rasterSampleCount > 1 &&
2949            !getDisplay()->getFeatures().emulateAlphaToCoverage.enabled;
2950
2951        mRenderPipelineDesc.outputDescriptor.updateEnabledDrawBuffers(
2952            mDrawFramebuffer->getState().getEnabledDrawBuffers());
2953    }
2954
2955    *isPipelineDescChanged = rppChange;
2956
2957    return angle::Result::Continue;
2958}
2959
2960angle::Result ContextMtl::checkCommandBufferError()
2961{
2962    ANGLE_CHECK_GL_ALLOC(
2963        this, mCmdBuffer.cmdQueue().popCmdBufferError() != MTLCommandBufferErrorOutOfMemory);
2964    return angle::Result::Continue;
2965}
2966
2967}  // namespace rx
2968