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