xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/metal/FrameBufferMtl.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// FramebufferMtl.mm:
7*8975f5c5SAndroid Build Coastguard Worker//    Implements the class methods for FramebufferMtl.
8*8975f5c5SAndroid Build Coastguard Worker//
9*8975f5c5SAndroid Build Coastguard Worker
10*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/angletypes.h"
11*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/ContextMtl.h"
12*8975f5c5SAndroid Build Coastguard Worker
13*8975f5c5SAndroid Build Coastguard Worker#include <TargetConditionals.h>
14*8975f5c5SAndroid Build Coastguard Worker
15*8975f5c5SAndroid Build Coastguard Worker#include "common/MemoryBuffer.h"
16*8975f5c5SAndroid Build Coastguard Worker#include "common/angleutils.h"
17*8975f5c5SAndroid Build Coastguard Worker#include "common/debug.h"
18*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/ErrorStrings.h"
19*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/BufferMtl.h"
20*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/DisplayMtl.h"
21*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/FrameBufferMtl.h"
22*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/SurfaceMtl.h"
23*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/mtl_utils.h"
24*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/renderer_utils.h"
25*8975f5c5SAndroid Build Coastguard Worker
26*8975f5c5SAndroid Build Coastguard Workernamespace rx
27*8975f5c5SAndroid Build Coastguard Worker{
28*8975f5c5SAndroid Build Coastguard Workernamespace
29*8975f5c5SAndroid Build Coastguard Worker{
30*8975f5c5SAndroid Build Coastguard Worker// Override clear color based on texture's write mask
31*8975f5c5SAndroid Build Coastguard Workervoid OverrideMTLClearColor(const mtl::TextureRef &texture,
32*8975f5c5SAndroid Build Coastguard Worker                           const mtl::ClearColorValue &clearColor,
33*8975f5c5SAndroid Build Coastguard Worker                           MTLClearColor *colorOut)
34*8975f5c5SAndroid Build Coastguard Worker{
35*8975f5c5SAndroid Build Coastguard Worker    if (texture)
36*8975f5c5SAndroid Build Coastguard Worker    {
37*8975f5c5SAndroid Build Coastguard Worker        *colorOut = mtl::EmulatedAlphaClearColor(clearColor.toMTLClearColor(),
38*8975f5c5SAndroid Build Coastguard Worker                                                 texture->getColorWritableMask());
39*8975f5c5SAndroid Build Coastguard Worker    }
40*8975f5c5SAndroid Build Coastguard Worker    else
41*8975f5c5SAndroid Build Coastguard Worker    {
42*8975f5c5SAndroid Build Coastguard Worker        *colorOut = clearColor.toMTLClearColor();
43*8975f5c5SAndroid Build Coastguard Worker    }
44*8975f5c5SAndroid Build Coastguard Worker}
45*8975f5c5SAndroid Build Coastguard Worker
46*8975f5c5SAndroid Build Coastguard Workerconst gl::InternalFormat &GetReadAttachmentInfo(const gl::Context *context,
47*8975f5c5SAndroid Build Coastguard Worker                                                RenderTargetMtl *renderTarget)
48*8975f5c5SAndroid Build Coastguard Worker{
49*8975f5c5SAndroid Build Coastguard Worker    GLenum implFormat;
50*8975f5c5SAndroid Build Coastguard Worker
51*8975f5c5SAndroid Build Coastguard Worker    if (renderTarget)
52*8975f5c5SAndroid Build Coastguard Worker    {
53*8975f5c5SAndroid Build Coastguard Worker        implFormat = renderTarget->getFormat().actualAngleFormat().fboImplementationInternalFormat;
54*8975f5c5SAndroid Build Coastguard Worker    }
55*8975f5c5SAndroid Build Coastguard Worker    else
56*8975f5c5SAndroid Build Coastguard Worker    {
57*8975f5c5SAndroid Build Coastguard Worker        implFormat = GL_NONE;
58*8975f5c5SAndroid Build Coastguard Worker    }
59*8975f5c5SAndroid Build Coastguard Worker
60*8975f5c5SAndroid Build Coastguard Worker    return gl::GetSizedInternalFormatInfo(implFormat);
61*8975f5c5SAndroid Build Coastguard Worker}
62*8975f5c5SAndroid Build Coastguard Worker
63*8975f5c5SAndroid Build Coastguard Workerangle::Result CopyTextureSliceLevelToTempBuffer(const gl::Context *context,
64*8975f5c5SAndroid Build Coastguard Worker                                                const mtl::TextureRef &srcTexture,
65*8975f5c5SAndroid Build Coastguard Worker                                                const mtl::MipmapNativeLevel &mipNativeLevel,
66*8975f5c5SAndroid Build Coastguard Worker                                                uint32_t layerIndex,
67*8975f5c5SAndroid Build Coastguard Worker                                                mtl::BufferRef *outBuffer)
68*8975f5c5SAndroid Build Coastguard Worker{
69*8975f5c5SAndroid Build Coastguard Worker    ASSERT(outBuffer);
70*8975f5c5SAndroid Build Coastguard Worker
71*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl           = mtl::GetImpl(context);
72*8975f5c5SAndroid Build Coastguard Worker    auto formatId                    = mtl::Format::MetalToAngleFormatID(srcTexture->pixelFormat());
73*8975f5c5SAndroid Build Coastguard Worker    const mtl::Format &metalFormat   = contextMtl->getPixelFormat(formatId);
74*8975f5c5SAndroid Build Coastguard Worker    const angle::Format &angleFormat = metalFormat.actualAngleFormat();
75*8975f5c5SAndroid Build Coastguard Worker
76*8975f5c5SAndroid Build Coastguard Worker    uint32_t width       = srcTexture->width(mipNativeLevel);
77*8975f5c5SAndroid Build Coastguard Worker    uint32_t height      = srcTexture->height(mipNativeLevel);
78*8975f5c5SAndroid Build Coastguard Worker    uint32_t sizeInBytes = width * height * angleFormat.pixelBytes;
79*8975f5c5SAndroid Build Coastguard Worker
80*8975f5c5SAndroid Build Coastguard Worker    mtl::BufferRef tempBuffer;
81*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(mtl::Buffer::MakeBufferWithStorageMode(
82*8975f5c5SAndroid Build Coastguard Worker        contextMtl, mtl::Buffer::getStorageModeForSharedBuffer(contextMtl), sizeInBytes, nullptr,
83*8975f5c5SAndroid Build Coastguard Worker        &tempBuffer));
84*8975f5c5SAndroid Build Coastguard Worker
85*8975f5c5SAndroid Build Coastguard Worker    gl::Rectangle region(0, 0, width, height);
86*8975f5c5SAndroid Build Coastguard Worker    uint32_t bytesPerRow = angleFormat.pixelBytes * width;
87*8975f5c5SAndroid Build Coastguard Worker    uint32_t destOffset  = 0;
88*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(mtl::ReadTexturePerSliceBytesToBuffer(context, srcTexture, bytesPerRow, region,
89*8975f5c5SAndroid Build Coastguard Worker                                                    mipNativeLevel, layerIndex, destOffset,
90*8975f5c5SAndroid Build Coastguard Worker                                                    tempBuffer));
91*8975f5c5SAndroid Build Coastguard Worker
92*8975f5c5SAndroid Build Coastguard Worker    *outBuffer = tempBuffer;
93*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
94*8975f5c5SAndroid Build Coastguard Worker}
95*8975f5c5SAndroid Build Coastguard Worker
96*8975f5c5SAndroid Build Coastguard Workerangle::Result Copy2DTextureSlice0Level0ToTempTexture(const gl::Context *context,
97*8975f5c5SAndroid Build Coastguard Worker                                                     const mtl::TextureRef &srcTexture,
98*8975f5c5SAndroid Build Coastguard Worker                                                     mtl::TextureRef *outTexture)
99*8975f5c5SAndroid Build Coastguard Worker{
100*8975f5c5SAndroid Build Coastguard Worker    ASSERT(outTexture);
101*8975f5c5SAndroid Build Coastguard Worker
102*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
103*8975f5c5SAndroid Build Coastguard Worker    auto formatId          = mtl::Format::MetalToAngleFormatID(srcTexture->pixelFormat());
104*8975f5c5SAndroid Build Coastguard Worker    const auto &format     = contextMtl->getPixelFormat(formatId);
105*8975f5c5SAndroid Build Coastguard Worker
106*8975f5c5SAndroid Build Coastguard Worker    mtl::TextureRef tempTexture;
107*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(mtl::Texture::Make2DTexture(contextMtl, format, srcTexture->widthAt0(),
108*8975f5c5SAndroid Build Coastguard Worker                                          srcTexture->heightAt0(), srcTexture->mipmapLevels(),
109*8975f5c5SAndroid Build Coastguard Worker                                          false, true, &tempTexture));
110*8975f5c5SAndroid Build Coastguard Worker
111*8975f5c5SAndroid Build Coastguard Worker    auto *blitEncoder = contextMtl->getBlitCommandEncoder();
112*8975f5c5SAndroid Build Coastguard Worker    blitEncoder->copyTexture(srcTexture,
113*8975f5c5SAndroid Build Coastguard Worker                             0,                          // srcStartSlice
114*8975f5c5SAndroid Build Coastguard Worker                             mtl::MipmapNativeLevel(0),  // MipmapNativeLevel
115*8975f5c5SAndroid Build Coastguard Worker                             tempTexture,                // dst
116*8975f5c5SAndroid Build Coastguard Worker                             0,                          // dstStartSlice
117*8975f5c5SAndroid Build Coastguard Worker                             mtl::MipmapNativeLevel(0),  // dstStartLevel
118*8975f5c5SAndroid Build Coastguard Worker                             1,                          // sliceCount,
119*8975f5c5SAndroid Build Coastguard Worker                             1);                         // levelCount
120*8975f5c5SAndroid Build Coastguard Worker
121*8975f5c5SAndroid Build Coastguard Worker    *outTexture = tempTexture;
122*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
123*8975f5c5SAndroid Build Coastguard Worker}
124*8975f5c5SAndroid Build Coastguard Worker
125*8975f5c5SAndroid Build Coastguard Worker}  // namespace
126*8975f5c5SAndroid Build Coastguard Worker
127*8975f5c5SAndroid Build Coastguard Worker// FramebufferMtl implementation
128*8975f5c5SAndroid Build Coastguard WorkerFramebufferMtl::FramebufferMtl(const gl::FramebufferState &state, ContextMtl *context, bool flipY)
129*8975f5c5SAndroid Build Coastguard Worker    : FramebufferImpl(state),
130*8975f5c5SAndroid Build Coastguard Worker      mColorRenderTargets(context->getNativeCaps().maxColorAttachments, nullptr),
131*8975f5c5SAndroid Build Coastguard Worker      mBackbuffer(nullptr),
132*8975f5c5SAndroid Build Coastguard Worker      mFlipY(flipY)
133*8975f5c5SAndroid Build Coastguard Worker{
134*8975f5c5SAndroid Build Coastguard Worker    reset();
135*8975f5c5SAndroid Build Coastguard Worker}
136*8975f5c5SAndroid Build Coastguard Worker
137*8975f5c5SAndroid Build Coastguard WorkerFramebufferMtl::~FramebufferMtl() {}
138*8975f5c5SAndroid Build Coastguard Worker
139*8975f5c5SAndroid Build Coastguard Workervoid FramebufferMtl::reset()
140*8975f5c5SAndroid Build Coastguard Worker{
141*8975f5c5SAndroid Build Coastguard Worker    for (auto &rt : mColorRenderTargets)
142*8975f5c5SAndroid Build Coastguard Worker    {
143*8975f5c5SAndroid Build Coastguard Worker        rt = nullptr;
144*8975f5c5SAndroid Build Coastguard Worker    }
145*8975f5c5SAndroid Build Coastguard Worker    mDepthRenderTarget = mStencilRenderTarget = nullptr;
146*8975f5c5SAndroid Build Coastguard Worker
147*8975f5c5SAndroid Build Coastguard Worker    mRenderPassFirstColorAttachmentFormat = nullptr;
148*8975f5c5SAndroid Build Coastguard Worker
149*8975f5c5SAndroid Build Coastguard Worker    mReadPixelBuffer = nullptr;
150*8975f5c5SAndroid Build Coastguard Worker}
151*8975f5c5SAndroid Build Coastguard Worker
152*8975f5c5SAndroid Build Coastguard Workervoid FramebufferMtl::destroy(const gl::Context *context)
153*8975f5c5SAndroid Build Coastguard Worker{
154*8975f5c5SAndroid Build Coastguard Worker    reset();
155*8975f5c5SAndroid Build Coastguard Worker}
156*8975f5c5SAndroid Build Coastguard Worker
157*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::discard(const gl::Context *context,
158*8975f5c5SAndroid Build Coastguard Worker                                      size_t count,
159*8975f5c5SAndroid Build Coastguard Worker                                      const GLenum *attachments)
160*8975f5c5SAndroid Build Coastguard Worker{
161*8975f5c5SAndroid Build Coastguard Worker    return invalidate(context, count, attachments);
162*8975f5c5SAndroid Build Coastguard Worker}
163*8975f5c5SAndroid Build Coastguard Worker
164*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::invalidate(const gl::Context *context,
165*8975f5c5SAndroid Build Coastguard Worker                                         size_t count,
166*8975f5c5SAndroid Build Coastguard Worker                                         const GLenum *attachments)
167*8975f5c5SAndroid Build Coastguard Worker{
168*8975f5c5SAndroid Build Coastguard Worker    return invalidateImpl(context, count, attachments);
169*8975f5c5SAndroid Build Coastguard Worker}
170*8975f5c5SAndroid Build Coastguard Worker
171*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::invalidateSub(const gl::Context *context,
172*8975f5c5SAndroid Build Coastguard Worker                                            size_t count,
173*8975f5c5SAndroid Build Coastguard Worker                                            const GLenum *attachments,
174*8975f5c5SAndroid Build Coastguard Worker                                            const gl::Rectangle &area)
175*8975f5c5SAndroid Build Coastguard Worker{
176*8975f5c5SAndroid Build Coastguard Worker    if (area.encloses(getCompleteRenderArea()))
177*8975f5c5SAndroid Build Coastguard Worker    {
178*8975f5c5SAndroid Build Coastguard Worker        return invalidateImpl(context, count, attachments);
179*8975f5c5SAndroid Build Coastguard Worker    }
180*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
181*8975f5c5SAndroid Build Coastguard Worker}
182*8975f5c5SAndroid Build Coastguard Worker
183*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::clear(const gl::Context *context, GLbitfield mask)
184*8975f5c5SAndroid Build Coastguard Worker{
185*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
186*8975f5c5SAndroid Build Coastguard Worker
187*8975f5c5SAndroid Build Coastguard Worker    if (ANGLE_UNLIKELY(contextMtl->getForceResyncDrawFramebuffer()))
188*8975f5c5SAndroid Build Coastguard Worker    {
189*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(syncState(context, GL_DRAW_FRAMEBUFFER, gl::Framebuffer::DirtyBits(),
190*8975f5c5SAndroid Build Coastguard Worker                            gl::Command::Clear));
191*8975f5c5SAndroid Build Coastguard Worker    }
192*8975f5c5SAndroid Build Coastguard Worker
193*8975f5c5SAndroid Build Coastguard Worker    mtl::ClearRectParams clearOpts;
194*8975f5c5SAndroid Build Coastguard Worker
195*8975f5c5SAndroid Build Coastguard Worker    bool clearColor   = IsMaskFlagSet(mask, static_cast<GLbitfield>(GL_COLOR_BUFFER_BIT));
196*8975f5c5SAndroid Build Coastguard Worker    bool clearDepth   = IsMaskFlagSet(mask, static_cast<GLbitfield>(GL_DEPTH_BUFFER_BIT));
197*8975f5c5SAndroid Build Coastguard Worker    bool clearStencil = IsMaskFlagSet(mask, static_cast<GLbitfield>(GL_STENCIL_BUFFER_BIT));
198*8975f5c5SAndroid Build Coastguard Worker
199*8975f5c5SAndroid Build Coastguard Worker    gl::DrawBufferMask clearColorBuffers;
200*8975f5c5SAndroid Build Coastguard Worker    if (clearColor)
201*8975f5c5SAndroid Build Coastguard Worker    {
202*8975f5c5SAndroid Build Coastguard Worker        clearColorBuffers    = mState.getEnabledDrawBuffers();
203*8975f5c5SAndroid Build Coastguard Worker        clearOpts.clearColor = contextMtl->getClearColorValue();
204*8975f5c5SAndroid Build Coastguard Worker    }
205*8975f5c5SAndroid Build Coastguard Worker    if (clearDepth)
206*8975f5c5SAndroid Build Coastguard Worker    {
207*8975f5c5SAndroid Build Coastguard Worker        clearOpts.clearDepth = contextMtl->getClearDepthValue();
208*8975f5c5SAndroid Build Coastguard Worker    }
209*8975f5c5SAndroid Build Coastguard Worker    if (clearStencil)
210*8975f5c5SAndroid Build Coastguard Worker    {
211*8975f5c5SAndroid Build Coastguard Worker        clearOpts.clearStencil = contextMtl->getClearStencilValue();
212*8975f5c5SAndroid Build Coastguard Worker    }
213*8975f5c5SAndroid Build Coastguard Worker
214*8975f5c5SAndroid Build Coastguard Worker    return clearImpl(context, clearColorBuffers, &clearOpts);
215*8975f5c5SAndroid Build Coastguard Worker}
216*8975f5c5SAndroid Build Coastguard Worker
217*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::clearBufferfv(const gl::Context *context,
218*8975f5c5SAndroid Build Coastguard Worker                                            GLenum buffer,
219*8975f5c5SAndroid Build Coastguard Worker                                            GLint drawbuffer,
220*8975f5c5SAndroid Build Coastguard Worker                                            const GLfloat *values)
221*8975f5c5SAndroid Build Coastguard Worker{
222*8975f5c5SAndroid Build Coastguard Worker    if (ANGLE_UNLIKELY(mtl::GetImpl(context)->getForceResyncDrawFramebuffer()))
223*8975f5c5SAndroid Build Coastguard Worker    {
224*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(syncState(context, GL_DRAW_FRAMEBUFFER, gl::Framebuffer::DirtyBits(),
225*8975f5c5SAndroid Build Coastguard Worker                            gl::Command::Clear));
226*8975f5c5SAndroid Build Coastguard Worker    }
227*8975f5c5SAndroid Build Coastguard Worker
228*8975f5c5SAndroid Build Coastguard Worker    mtl::ClearRectParams clearOpts;
229*8975f5c5SAndroid Build Coastguard Worker
230*8975f5c5SAndroid Build Coastguard Worker    gl::DrawBufferMask clearColorBuffers;
231*8975f5c5SAndroid Build Coastguard Worker    if (buffer == GL_DEPTH)
232*8975f5c5SAndroid Build Coastguard Worker    {
233*8975f5c5SAndroid Build Coastguard Worker        clearOpts.clearDepth = values[0];
234*8975f5c5SAndroid Build Coastguard Worker    }
235*8975f5c5SAndroid Build Coastguard Worker    else
236*8975f5c5SAndroid Build Coastguard Worker    {
237*8975f5c5SAndroid Build Coastguard Worker        clearColorBuffers.set(drawbuffer);
238*8975f5c5SAndroid Build Coastguard Worker        clearOpts.clearColor = mtl::ClearColorValue(values[0], values[1], values[2], values[3]);
239*8975f5c5SAndroid Build Coastguard Worker    }
240*8975f5c5SAndroid Build Coastguard Worker
241*8975f5c5SAndroid Build Coastguard Worker    return clearImpl(context, clearColorBuffers, &clearOpts);
242*8975f5c5SAndroid Build Coastguard Worker}
243*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::clearBufferuiv(const gl::Context *context,
244*8975f5c5SAndroid Build Coastguard Worker                                             GLenum buffer,
245*8975f5c5SAndroid Build Coastguard Worker                                             GLint drawbuffer,
246*8975f5c5SAndroid Build Coastguard Worker                                             const GLuint *values)
247*8975f5c5SAndroid Build Coastguard Worker{
248*8975f5c5SAndroid Build Coastguard Worker    if (ANGLE_UNLIKELY(mtl::GetImpl(context)->getForceResyncDrawFramebuffer()))
249*8975f5c5SAndroid Build Coastguard Worker    {
250*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(syncState(context, GL_DRAW_FRAMEBUFFER, gl::Framebuffer::DirtyBits(),
251*8975f5c5SAndroid Build Coastguard Worker                            gl::Command::Clear));
252*8975f5c5SAndroid Build Coastguard Worker    }
253*8975f5c5SAndroid Build Coastguard Worker
254*8975f5c5SAndroid Build Coastguard Worker    gl::DrawBufferMask clearColorBuffers;
255*8975f5c5SAndroid Build Coastguard Worker    clearColorBuffers.set(drawbuffer);
256*8975f5c5SAndroid Build Coastguard Worker
257*8975f5c5SAndroid Build Coastguard Worker    mtl::ClearRectParams clearOpts;
258*8975f5c5SAndroid Build Coastguard Worker    clearOpts.clearColor = mtl::ClearColorValue(values[0], values[1], values[2], values[3]);
259*8975f5c5SAndroid Build Coastguard Worker
260*8975f5c5SAndroid Build Coastguard Worker    return clearImpl(context, clearColorBuffers, &clearOpts);
261*8975f5c5SAndroid Build Coastguard Worker}
262*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::clearBufferiv(const gl::Context *context,
263*8975f5c5SAndroid Build Coastguard Worker                                            GLenum buffer,
264*8975f5c5SAndroid Build Coastguard Worker                                            GLint drawbuffer,
265*8975f5c5SAndroid Build Coastguard Worker                                            const GLint *values)
266*8975f5c5SAndroid Build Coastguard Worker{
267*8975f5c5SAndroid Build Coastguard Worker    if (ANGLE_UNLIKELY(mtl::GetImpl(context)->getForceResyncDrawFramebuffer()))
268*8975f5c5SAndroid Build Coastguard Worker    {
269*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(syncState(context, GL_DRAW_FRAMEBUFFER, gl::Framebuffer::DirtyBits(),
270*8975f5c5SAndroid Build Coastguard Worker                            gl::Command::Clear));
271*8975f5c5SAndroid Build Coastguard Worker    }
272*8975f5c5SAndroid Build Coastguard Worker
273*8975f5c5SAndroid Build Coastguard Worker    mtl::ClearRectParams clearOpts;
274*8975f5c5SAndroid Build Coastguard Worker
275*8975f5c5SAndroid Build Coastguard Worker    gl::DrawBufferMask clearColorBuffers;
276*8975f5c5SAndroid Build Coastguard Worker    if (buffer == GL_STENCIL)
277*8975f5c5SAndroid Build Coastguard Worker    {
278*8975f5c5SAndroid Build Coastguard Worker        clearOpts.clearStencil = values[0] & mtl::kStencilMaskAll;
279*8975f5c5SAndroid Build Coastguard Worker    }
280*8975f5c5SAndroid Build Coastguard Worker    else
281*8975f5c5SAndroid Build Coastguard Worker    {
282*8975f5c5SAndroid Build Coastguard Worker        clearColorBuffers.set(drawbuffer);
283*8975f5c5SAndroid Build Coastguard Worker        clearOpts.clearColor = mtl::ClearColorValue(values[0], values[1], values[2], values[3]);
284*8975f5c5SAndroid Build Coastguard Worker    }
285*8975f5c5SAndroid Build Coastguard Worker
286*8975f5c5SAndroid Build Coastguard Worker    return clearImpl(context, clearColorBuffers, &clearOpts);
287*8975f5c5SAndroid Build Coastguard Worker}
288*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::clearBufferfi(const gl::Context *context,
289*8975f5c5SAndroid Build Coastguard Worker                                            GLenum buffer,
290*8975f5c5SAndroid Build Coastguard Worker                                            GLint drawbuffer,
291*8975f5c5SAndroid Build Coastguard Worker                                            GLfloat depth,
292*8975f5c5SAndroid Build Coastguard Worker                                            GLint stencil)
293*8975f5c5SAndroid Build Coastguard Worker{
294*8975f5c5SAndroid Build Coastguard Worker    mtl::ClearRectParams clearOpts;
295*8975f5c5SAndroid Build Coastguard Worker    clearOpts.clearDepth   = depth;
296*8975f5c5SAndroid Build Coastguard Worker    clearOpts.clearStencil = stencil & mtl::kStencilMaskAll;
297*8975f5c5SAndroid Build Coastguard Worker
298*8975f5c5SAndroid Build Coastguard Worker    return clearImpl(context, gl::DrawBufferMask(), &clearOpts);
299*8975f5c5SAndroid Build Coastguard Worker}
300*8975f5c5SAndroid Build Coastguard Worker
301*8975f5c5SAndroid Build Coastguard Workerconst gl::InternalFormat &FramebufferMtl::getImplementationColorReadFormat(
302*8975f5c5SAndroid Build Coastguard Worker    const gl::Context *context) const
303*8975f5c5SAndroid Build Coastguard Worker{
304*8975f5c5SAndroid Build Coastguard Worker    return GetReadAttachmentInfo(context, getColorReadRenderTargetNoCache(context));
305*8975f5c5SAndroid Build Coastguard Worker}
306*8975f5c5SAndroid Build Coastguard Worker
307*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::readPixels(const gl::Context *context,
308*8975f5c5SAndroid Build Coastguard Worker                                         const gl::Rectangle &area,
309*8975f5c5SAndroid Build Coastguard Worker                                         GLenum format,
310*8975f5c5SAndroid Build Coastguard Worker                                         GLenum type,
311*8975f5c5SAndroid Build Coastguard Worker                                         const gl::PixelPackState &pack,
312*8975f5c5SAndroid Build Coastguard Worker                                         gl::Buffer *packBuffer,
313*8975f5c5SAndroid Build Coastguard Worker                                         void *pixels)
314*8975f5c5SAndroid Build Coastguard Worker{
315*8975f5c5SAndroid Build Coastguard Worker    // Clip read area to framebuffer.
316*8975f5c5SAndroid Build Coastguard Worker    const gl::Extents &fbSize = getState().getReadAttachment()->getSize();
317*8975f5c5SAndroid Build Coastguard Worker    const gl::Rectangle fbRect(0, 0, fbSize.width, fbSize.height);
318*8975f5c5SAndroid Build Coastguard Worker
319*8975f5c5SAndroid Build Coastguard Worker    gl::Rectangle clippedArea;
320*8975f5c5SAndroid Build Coastguard Worker    if (!ClipRectangle(area, fbRect, &clippedArea))
321*8975f5c5SAndroid Build Coastguard Worker    {
322*8975f5c5SAndroid Build Coastguard Worker        // nothing to read
323*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
324*8975f5c5SAndroid Build Coastguard Worker    }
325*8975f5c5SAndroid Build Coastguard Worker    gl::Rectangle flippedArea = getCorrectFlippedReadArea(context, clippedArea);
326*8975f5c5SAndroid Build Coastguard Worker
327*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
328*8975f5c5SAndroid Build Coastguard Worker
329*8975f5c5SAndroid Build Coastguard Worker    const gl::InternalFormat &sizedFormatInfo = gl::GetInternalFormatInfo(format, type);
330*8975f5c5SAndroid Build Coastguard Worker
331*8975f5c5SAndroid Build Coastguard Worker    GLuint outputPitch = 0;
332*8975f5c5SAndroid Build Coastguard Worker    ANGLE_CHECK_GL_MATH(contextMtl,
333*8975f5c5SAndroid Build Coastguard Worker                        sizedFormatInfo.computeRowPitch(type, area.width, pack.alignment,
334*8975f5c5SAndroid Build Coastguard Worker                                                        pack.rowLength, &outputPitch));
335*8975f5c5SAndroid Build Coastguard Worker    GLuint outputSkipBytes = 0;
336*8975f5c5SAndroid Build Coastguard Worker    ANGLE_CHECK_GL_MATH(contextMtl, sizedFormatInfo.computeSkipBytes(type, outputPitch, 0, pack,
337*8975f5c5SAndroid Build Coastguard Worker                                                                     false, &outputSkipBytes));
338*8975f5c5SAndroid Build Coastguard Worker
339*8975f5c5SAndroid Build Coastguard Worker    outputSkipBytes += (clippedArea.x - area.x) * sizedFormatInfo.pixelBytes +
340*8975f5c5SAndroid Build Coastguard Worker                       (clippedArea.y - area.y) * outputPitch;
341*8975f5c5SAndroid Build Coastguard Worker
342*8975f5c5SAndroid Build Coastguard Worker    const angle::Format &angleFormat = GetFormatFromFormatType(format, type);
343*8975f5c5SAndroid Build Coastguard Worker
344*8975f5c5SAndroid Build Coastguard Worker    PackPixelsParams params(flippedArea, angleFormat, outputPitch, pack.reverseRowOrder, packBuffer,
345*8975f5c5SAndroid Build Coastguard Worker                            0);
346*8975f5c5SAndroid Build Coastguard Worker
347*8975f5c5SAndroid Build Coastguard Worker    if (params.packBuffer)
348*8975f5c5SAndroid Build Coastguard Worker    {
349*8975f5c5SAndroid Build Coastguard Worker        // If PBO is active, pixels is treated as offset.
350*8975f5c5SAndroid Build Coastguard Worker        params.offset = reinterpret_cast<ptrdiff_t>(pixels) + outputSkipBytes;
351*8975f5c5SAndroid Build Coastguard Worker    }
352*8975f5c5SAndroid Build Coastguard Worker
353*8975f5c5SAndroid Build Coastguard Worker    if (mFlipY)
354*8975f5c5SAndroid Build Coastguard Worker    {
355*8975f5c5SAndroid Build Coastguard Worker        params.reverseRowOrder = !params.reverseRowOrder;
356*8975f5c5SAndroid Build Coastguard Worker    }
357*8975f5c5SAndroid Build Coastguard Worker
358*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(readPixelsImpl(context, flippedArea, params, getColorReadRenderTarget(context),
359*8975f5c5SAndroid Build Coastguard Worker                             static_cast<uint8_t *>(pixels) + outputSkipBytes));
360*8975f5c5SAndroid Build Coastguard Worker
361*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
362*8975f5c5SAndroid Build Coastguard Worker}
363*8975f5c5SAndroid Build Coastguard Worker
364*8975f5c5SAndroid Build Coastguard Workernamespace
365*8975f5c5SAndroid Build Coastguard Worker{
366*8975f5c5SAndroid Build Coastguard Worker
367*8975f5c5SAndroid Build Coastguard Workerusing FloatRectangle = gl::RectangleImpl<float>;
368*8975f5c5SAndroid Build Coastguard Worker
369*8975f5c5SAndroid Build Coastguard Workerfloat clamp0Max(float v, float max)
370*8975f5c5SAndroid Build Coastguard Worker{
371*8975f5c5SAndroid Build Coastguard Worker    return std::max(0.0f, std::min(max, v));
372*8975f5c5SAndroid Build Coastguard Worker}
373*8975f5c5SAndroid Build Coastguard Worker
374*8975f5c5SAndroid Build Coastguard Workervoid ClampToBoundsAndAdjustCorrespondingValue(float a,
375*8975f5c5SAndroid Build Coastguard Worker                                              float originalASize,
376*8975f5c5SAndroid Build Coastguard Worker                                              float maxSize,
377*8975f5c5SAndroid Build Coastguard Worker                                              float b,
378*8975f5c5SAndroid Build Coastguard Worker                                              float originalBSize,
379*8975f5c5SAndroid Build Coastguard Worker                                              float *newA,
380*8975f5c5SAndroid Build Coastguard Worker                                              float *newB)
381*8975f5c5SAndroid Build Coastguard Worker{
382*8975f5c5SAndroid Build Coastguard Worker    float clippedA = clamp0Max(a, maxSize);
383*8975f5c5SAndroid Build Coastguard Worker    float delta    = clippedA - a;
384*8975f5c5SAndroid Build Coastguard Worker    *newA          = clippedA;
385*8975f5c5SAndroid Build Coastguard Worker    *newB          = b + delta * originalBSize / originalASize;
386*8975f5c5SAndroid Build Coastguard Worker}
387*8975f5c5SAndroid Build Coastguard Worker
388*8975f5c5SAndroid Build Coastguard Workervoid ClipRectToBoundsAndAdjustCorrespondingRect(const FloatRectangle &a,
389*8975f5c5SAndroid Build Coastguard Worker                                                const gl::Rectangle &originalA,
390*8975f5c5SAndroid Build Coastguard Worker                                                const gl::Rectangle &clipDimensions,
391*8975f5c5SAndroid Build Coastguard Worker                                                const FloatRectangle &b,
392*8975f5c5SAndroid Build Coastguard Worker                                                const gl::Rectangle &originalB,
393*8975f5c5SAndroid Build Coastguard Worker                                                FloatRectangle *newA,
394*8975f5c5SAndroid Build Coastguard Worker                                                FloatRectangle *newB)
395*8975f5c5SAndroid Build Coastguard Worker{
396*8975f5c5SAndroid Build Coastguard Worker    float newAValues[4];
397*8975f5c5SAndroid Build Coastguard Worker    float newBValues[4];
398*8975f5c5SAndroid Build Coastguard Worker    ClampToBoundsAndAdjustCorrespondingValue(a.x0(), originalA.width, clipDimensions.width, b.x0(),
399*8975f5c5SAndroid Build Coastguard Worker                                             originalB.width, &newAValues[0], &newBValues[0]);
400*8975f5c5SAndroid Build Coastguard Worker    ClampToBoundsAndAdjustCorrespondingValue(a.y0(), originalA.height, clipDimensions.height,
401*8975f5c5SAndroid Build Coastguard Worker                                             b.y0(), originalB.height, &newAValues[1],
402*8975f5c5SAndroid Build Coastguard Worker                                             &newBValues[1]);
403*8975f5c5SAndroid Build Coastguard Worker    ClampToBoundsAndAdjustCorrespondingValue(a.x1(), originalA.width, clipDimensions.width, b.x1(),
404*8975f5c5SAndroid Build Coastguard Worker                                             originalB.width, &newAValues[2], &newBValues[2]);
405*8975f5c5SAndroid Build Coastguard Worker    ClampToBoundsAndAdjustCorrespondingValue(a.y1(), originalA.height, clipDimensions.height,
406*8975f5c5SAndroid Build Coastguard Worker                                             b.y1(), originalB.height, &newAValues[3],
407*8975f5c5SAndroid Build Coastguard Worker                                             &newBValues[3]);
408*8975f5c5SAndroid Build Coastguard Worker
409*8975f5c5SAndroid Build Coastguard Worker    *newA = FloatRectangle(newAValues);
410*8975f5c5SAndroid Build Coastguard Worker    *newB = FloatRectangle(newBValues);
411*8975f5c5SAndroid Build Coastguard Worker}
412*8975f5c5SAndroid Build Coastguard Worker
413*8975f5c5SAndroid Build Coastguard Workervoid ClipRectsToBoundsAndAdjustCorrespondingRect(const FloatRectangle &a,
414*8975f5c5SAndroid Build Coastguard Worker                                                 const gl::Rectangle &originalA,
415*8975f5c5SAndroid Build Coastguard Worker                                                 const gl::Rectangle &aClipDimensions,
416*8975f5c5SAndroid Build Coastguard Worker                                                 const FloatRectangle &b,
417*8975f5c5SAndroid Build Coastguard Worker                                                 const gl::Rectangle &originalB,
418*8975f5c5SAndroid Build Coastguard Worker                                                 const gl::Rectangle &bClipDimensions,
419*8975f5c5SAndroid Build Coastguard Worker                                                 FloatRectangle *newA,
420*8975f5c5SAndroid Build Coastguard Worker                                                 FloatRectangle *newB)
421*8975f5c5SAndroid Build Coastguard Worker{
422*8975f5c5SAndroid Build Coastguard Worker    FloatRectangle tempA;
423*8975f5c5SAndroid Build Coastguard Worker    FloatRectangle tempB;
424*8975f5c5SAndroid Build Coastguard Worker    ClipRectToBoundsAndAdjustCorrespondingRect(a, originalA, aClipDimensions, b, originalB, &tempA,
425*8975f5c5SAndroid Build Coastguard Worker                                               &tempB);
426*8975f5c5SAndroid Build Coastguard Worker    ClipRectToBoundsAndAdjustCorrespondingRect(tempB, originalB, bClipDimensions, tempA, originalA,
427*8975f5c5SAndroid Build Coastguard Worker                                               newB, newA);
428*8975f5c5SAndroid Build Coastguard Worker}
429*8975f5c5SAndroid Build Coastguard Worker
430*8975f5c5SAndroid Build Coastguard Workervoid RoundValueAndAdjustCorrespondingValue(float a,
431*8975f5c5SAndroid Build Coastguard Worker                                           float originalASize,
432*8975f5c5SAndroid Build Coastguard Worker                                           float b,
433*8975f5c5SAndroid Build Coastguard Worker                                           float originalBSize,
434*8975f5c5SAndroid Build Coastguard Worker                                           int *newA,
435*8975f5c5SAndroid Build Coastguard Worker                                           float *newB)
436*8975f5c5SAndroid Build Coastguard Worker{
437*8975f5c5SAndroid Build Coastguard Worker    float roundedA = std::round(a);
438*8975f5c5SAndroid Build Coastguard Worker    float delta    = roundedA - a;
439*8975f5c5SAndroid Build Coastguard Worker    *newA          = static_cast<int>(roundedA);
440*8975f5c5SAndroid Build Coastguard Worker    *newB          = b + delta * originalBSize / originalASize;
441*8975f5c5SAndroid Build Coastguard Worker}
442*8975f5c5SAndroid Build Coastguard Worker
443*8975f5c5SAndroid Build Coastguard Workergl::Rectangle RoundRectToPixelsAndAdjustCorrespondingRectToMatch(const FloatRectangle &a,
444*8975f5c5SAndroid Build Coastguard Worker                                                                 const gl::Rectangle &originalA,
445*8975f5c5SAndroid Build Coastguard Worker                                                                 const FloatRectangle &b,
446*8975f5c5SAndroid Build Coastguard Worker                                                                 const gl::Rectangle &originalB,
447*8975f5c5SAndroid Build Coastguard Worker                                                                 FloatRectangle *newB)
448*8975f5c5SAndroid Build Coastguard Worker{
449*8975f5c5SAndroid Build Coastguard Worker    int newAValues[4];
450*8975f5c5SAndroid Build Coastguard Worker    float newBValues[4];
451*8975f5c5SAndroid Build Coastguard Worker    RoundValueAndAdjustCorrespondingValue(a.x0(), originalA.width, b.x0(), originalB.width,
452*8975f5c5SAndroid Build Coastguard Worker                                          &newAValues[0], &newBValues[0]);
453*8975f5c5SAndroid Build Coastguard Worker    RoundValueAndAdjustCorrespondingValue(a.y0(), originalA.height, b.y0(), originalB.height,
454*8975f5c5SAndroid Build Coastguard Worker                                          &newAValues[1], &newBValues[1]);
455*8975f5c5SAndroid Build Coastguard Worker    RoundValueAndAdjustCorrespondingValue(a.x1(), originalA.width, b.x1(), originalB.width,
456*8975f5c5SAndroid Build Coastguard Worker                                          &newAValues[2], &newBValues[2]);
457*8975f5c5SAndroid Build Coastguard Worker    RoundValueAndAdjustCorrespondingValue(a.y1(), originalA.height, b.y1(), originalB.height,
458*8975f5c5SAndroid Build Coastguard Worker                                          &newAValues[3], &newBValues[3]);
459*8975f5c5SAndroid Build Coastguard Worker
460*8975f5c5SAndroid Build Coastguard Worker    *newB = FloatRectangle(newBValues);
461*8975f5c5SAndroid Build Coastguard Worker    return gl::Rectangle(newAValues[0], newAValues[1], newAValues[2] - newAValues[0],
462*8975f5c5SAndroid Build Coastguard Worker                         newAValues[3] - newAValues[1]);
463*8975f5c5SAndroid Build Coastguard Worker}
464*8975f5c5SAndroid Build Coastguard Worker
465*8975f5c5SAndroid Build Coastguard Worker}  // namespace
466*8975f5c5SAndroid Build Coastguard Worker
467*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::blit(const gl::Context *context,
468*8975f5c5SAndroid Build Coastguard Worker                                   const gl::Rectangle &sourceAreaIn,
469*8975f5c5SAndroid Build Coastguard Worker                                   const gl::Rectangle &destAreaIn,
470*8975f5c5SAndroid Build Coastguard Worker                                   GLbitfield mask,
471*8975f5c5SAndroid Build Coastguard Worker                                   GLenum filter)
472*8975f5c5SAndroid Build Coastguard Worker{
473*8975f5c5SAndroid Build Coastguard Worker    bool blitColorBuffer   = (mask & GL_COLOR_BUFFER_BIT) != 0;
474*8975f5c5SAndroid Build Coastguard Worker    bool blitDepthBuffer   = (mask & GL_DEPTH_BUFFER_BIT) != 0;
475*8975f5c5SAndroid Build Coastguard Worker    bool blitStencilBuffer = (mask & GL_STENCIL_BUFFER_BIT) != 0;
476*8975f5c5SAndroid Build Coastguard Worker
477*8975f5c5SAndroid Build Coastguard Worker    const gl::State &glState                = context->getState();
478*8975f5c5SAndroid Build Coastguard Worker    const gl::Framebuffer *glSrcFramebuffer = glState.getReadFramebuffer();
479*8975f5c5SAndroid Build Coastguard Worker
480*8975f5c5SAndroid Build Coastguard Worker    FramebufferMtl *srcFrameBuffer = mtl::GetImpl(glSrcFramebuffer);
481*8975f5c5SAndroid Build Coastguard Worker
482*8975f5c5SAndroid Build Coastguard Worker    blitColorBuffer =
483*8975f5c5SAndroid Build Coastguard Worker        blitColorBuffer && srcFrameBuffer->getColorReadRenderTarget(context) != nullptr;
484*8975f5c5SAndroid Build Coastguard Worker    blitDepthBuffer   = blitDepthBuffer && srcFrameBuffer->getDepthRenderTarget() != nullptr;
485*8975f5c5SAndroid Build Coastguard Worker    blitStencilBuffer = blitStencilBuffer && srcFrameBuffer->getStencilRenderTarget() != nullptr;
486*8975f5c5SAndroid Build Coastguard Worker
487*8975f5c5SAndroid Build Coastguard Worker    if (!blitColorBuffer && !blitDepthBuffer && !blitStencilBuffer)
488*8975f5c5SAndroid Build Coastguard Worker    {
489*8975f5c5SAndroid Build Coastguard Worker        // No-op
490*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
491*8975f5c5SAndroid Build Coastguard Worker    }
492*8975f5c5SAndroid Build Coastguard Worker
493*8975f5c5SAndroid Build Coastguard Worker    if (ANGLE_UNLIKELY(mtl::GetImpl(context)->getForceResyncDrawFramebuffer()))
494*8975f5c5SAndroid Build Coastguard Worker    {
495*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(syncState(context, GL_DRAW_FRAMEBUFFER, gl::Framebuffer::DirtyBits(),
496*8975f5c5SAndroid Build Coastguard Worker                            gl::Command::Blit));
497*8975f5c5SAndroid Build Coastguard Worker    }
498*8975f5c5SAndroid Build Coastguard Worker
499*8975f5c5SAndroid Build Coastguard Worker    const gl::Rectangle srcFramebufferDimensions = srcFrameBuffer->getCompleteRenderArea();
500*8975f5c5SAndroid Build Coastguard Worker    const gl::Rectangle dstFramebufferDimensions = this->getCompleteRenderArea();
501*8975f5c5SAndroid Build Coastguard Worker
502*8975f5c5SAndroid Build Coastguard Worker    FloatRectangle srcRect(sourceAreaIn);
503*8975f5c5SAndroid Build Coastguard Worker    FloatRectangle dstRect(destAreaIn);
504*8975f5c5SAndroid Build Coastguard Worker
505*8975f5c5SAndroid Build Coastguard Worker    FloatRectangle clippedSrcRect;
506*8975f5c5SAndroid Build Coastguard Worker    FloatRectangle clippedDstRect;
507*8975f5c5SAndroid Build Coastguard Worker    ClipRectsToBoundsAndAdjustCorrespondingRect(srcRect, sourceAreaIn, srcFramebufferDimensions,
508*8975f5c5SAndroid Build Coastguard Worker                                                dstRect, destAreaIn, dstFramebufferDimensions,
509*8975f5c5SAndroid Build Coastguard Worker                                                &clippedSrcRect, &clippedDstRect);
510*8975f5c5SAndroid Build Coastguard Worker
511*8975f5c5SAndroid Build Coastguard Worker    FloatRectangle adjustedSrcRect;
512*8975f5c5SAndroid Build Coastguard Worker    gl::Rectangle srcClippedDestArea = RoundRectToPixelsAndAdjustCorrespondingRectToMatch(
513*8975f5c5SAndroid Build Coastguard Worker        clippedDstRect, destAreaIn, clippedSrcRect, sourceAreaIn, &adjustedSrcRect);
514*8975f5c5SAndroid Build Coastguard Worker
515*8975f5c5SAndroid Build Coastguard Worker    if (srcFrameBuffer->flipY())
516*8975f5c5SAndroid Build Coastguard Worker    {
517*8975f5c5SAndroid Build Coastguard Worker        adjustedSrcRect.y =
518*8975f5c5SAndroid Build Coastguard Worker            srcFramebufferDimensions.height - adjustedSrcRect.y - adjustedSrcRect.height;
519*8975f5c5SAndroid Build Coastguard Worker        adjustedSrcRect = adjustedSrcRect.flip(false, true);
520*8975f5c5SAndroid Build Coastguard Worker    }
521*8975f5c5SAndroid Build Coastguard Worker
522*8975f5c5SAndroid Build Coastguard Worker    // If the destination is flipped in either direction, we will flip the source instead so that
523*8975f5c5SAndroid Build Coastguard Worker    // the destination area is always unflipped.
524*8975f5c5SAndroid Build Coastguard Worker    adjustedSrcRect =
525*8975f5c5SAndroid Build Coastguard Worker        adjustedSrcRect.flip(srcClippedDestArea.isReversedX(), srcClippedDestArea.isReversedY());
526*8975f5c5SAndroid Build Coastguard Worker    srcClippedDestArea = srcClippedDestArea.removeReversal();
527*8975f5c5SAndroid Build Coastguard Worker
528*8975f5c5SAndroid Build Coastguard Worker    // Clip the destination area to the framebuffer size and scissor.
529*8975f5c5SAndroid Build Coastguard Worker    gl::Rectangle scissoredDestArea;
530*8975f5c5SAndroid Build Coastguard Worker    if (!gl::ClipRectangle(ClipRectToScissor(glState, dstFramebufferDimensions, false),
531*8975f5c5SAndroid Build Coastguard Worker                           srcClippedDestArea, &scissoredDestArea))
532*8975f5c5SAndroid Build Coastguard Worker    {
533*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
534*8975f5c5SAndroid Build Coastguard Worker    }
535*8975f5c5SAndroid Build Coastguard Worker
536*8975f5c5SAndroid Build Coastguard Worker    // Use blit with draw
537*8975f5c5SAndroid Build Coastguard Worker    mtl::BlitParams baseParams;
538*8975f5c5SAndroid Build Coastguard Worker    baseParams.dstTextureSize =
539*8975f5c5SAndroid Build Coastguard Worker        gl::Extents(dstFramebufferDimensions.width, dstFramebufferDimensions.height, 1);
540*8975f5c5SAndroid Build Coastguard Worker    baseParams.dstRect        = srcClippedDestArea;
541*8975f5c5SAndroid Build Coastguard Worker    baseParams.dstScissorRect = scissoredDestArea;
542*8975f5c5SAndroid Build Coastguard Worker    baseParams.dstFlipY       = this->flipY();
543*8975f5c5SAndroid Build Coastguard Worker
544*8975f5c5SAndroid Build Coastguard Worker    baseParams.srcNormalizedCoords =
545*8975f5c5SAndroid Build Coastguard Worker        mtl::NormalizedCoords(adjustedSrcRect.x, adjustedSrcRect.y, adjustedSrcRect.width,
546*8975f5c5SAndroid Build Coastguard Worker                              adjustedSrcRect.height, srcFramebufferDimensions);
547*8975f5c5SAndroid Build Coastguard Worker    // This flag is for auto flipping the rect inside RenderUtils. Since we already flip it using
548*8975f5c5SAndroid Build Coastguard Worker    // getCorrectFlippedReadArea(). This flag is not needed.
549*8975f5c5SAndroid Build Coastguard Worker    baseParams.srcYFlipped = false;
550*8975f5c5SAndroid Build Coastguard Worker    baseParams.unpackFlipX = false;
551*8975f5c5SAndroid Build Coastguard Worker    baseParams.unpackFlipY = false;
552*8975f5c5SAndroid Build Coastguard Worker
553*8975f5c5SAndroid Build Coastguard Worker    return blitWithDraw(context, srcFrameBuffer, blitColorBuffer, blitDepthBuffer,
554*8975f5c5SAndroid Build Coastguard Worker                        blitStencilBuffer, filter, baseParams);
555*8975f5c5SAndroid Build Coastguard Worker}
556*8975f5c5SAndroid Build Coastguard Worker
557*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::blitWithDraw(const gl::Context *context,
558*8975f5c5SAndroid Build Coastguard Worker                                           FramebufferMtl *srcFrameBuffer,
559*8975f5c5SAndroid Build Coastguard Worker                                           bool blitColorBuffer,
560*8975f5c5SAndroid Build Coastguard Worker                                           bool blitDepthBuffer,
561*8975f5c5SAndroid Build Coastguard Worker                                           bool blitStencilBuffer,
562*8975f5c5SAndroid Build Coastguard Worker                                           GLenum filter,
563*8975f5c5SAndroid Build Coastguard Worker                                           const mtl::BlitParams &baseParams)
564*8975f5c5SAndroid Build Coastguard Worker{
565*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
566*8975f5c5SAndroid Build Coastguard Worker    // Use blit with draw
567*8975f5c5SAndroid Build Coastguard Worker    mtl::RenderCommandEncoder *renderEncoder = nullptr;
568*8975f5c5SAndroid Build Coastguard Worker
569*8975f5c5SAndroid Build Coastguard Worker    // Blit Depth & stencil
570*8975f5c5SAndroid Build Coastguard Worker    if (blitDepthBuffer || blitStencilBuffer)
571*8975f5c5SAndroid Build Coastguard Worker    {
572*8975f5c5SAndroid Build Coastguard Worker        mtl::DepthStencilBlitParams dsBlitParams;
573*8975f5c5SAndroid Build Coastguard Worker        memcpy(&dsBlitParams, &baseParams, sizeof(baseParams));
574*8975f5c5SAndroid Build Coastguard Worker        RenderTargetMtl *srcDepthRt   = srcFrameBuffer->getDepthRenderTarget();
575*8975f5c5SAndroid Build Coastguard Worker        RenderTargetMtl *srcStencilRt = srcFrameBuffer->getStencilRenderTarget();
576*8975f5c5SAndroid Build Coastguard Worker
577*8975f5c5SAndroid Build Coastguard Worker        if (blitDepthBuffer)
578*8975f5c5SAndroid Build Coastguard Worker        {
579*8975f5c5SAndroid Build Coastguard Worker            dsBlitParams.src      = srcDepthRt->getTexture();
580*8975f5c5SAndroid Build Coastguard Worker            dsBlitParams.srcLevel = srcDepthRt->getLevelIndex();
581*8975f5c5SAndroid Build Coastguard Worker            dsBlitParams.srcLayer = srcDepthRt->getLayerIndex();
582*8975f5c5SAndroid Build Coastguard Worker        }
583*8975f5c5SAndroid Build Coastguard Worker
584*8975f5c5SAndroid Build Coastguard Worker        if (blitStencilBuffer && srcStencilRt->getTexture())
585*8975f5c5SAndroid Build Coastguard Worker        {
586*8975f5c5SAndroid Build Coastguard Worker            dsBlitParams.srcStencil = srcStencilRt->getTexture()->getStencilView();
587*8975f5c5SAndroid Build Coastguard Worker            dsBlitParams.srcLevel   = srcStencilRt->getLevelIndex();
588*8975f5c5SAndroid Build Coastguard Worker            dsBlitParams.srcLayer   = srcStencilRt->getLayerIndex();
589*8975f5c5SAndroid Build Coastguard Worker
590*8975f5c5SAndroid Build Coastguard Worker            if (!contextMtl->getDisplay()->getFeatures().hasShaderStencilOutput.enabled &&
591*8975f5c5SAndroid Build Coastguard Worker                mStencilRenderTarget)
592*8975f5c5SAndroid Build Coastguard Worker            {
593*8975f5c5SAndroid Build Coastguard Worker                // Directly writing to stencil in shader is not supported, use temporary copy buffer
594*8975f5c5SAndroid Build Coastguard Worker                // work around. This is a compute pass.
595*8975f5c5SAndroid Build Coastguard Worker                mtl::StencilBlitViaBufferParams stencilOnlyBlitParams = dsBlitParams;
596*8975f5c5SAndroid Build Coastguard Worker                stencilOnlyBlitParams.dstStencil      = mStencilRenderTarget->getTexture();
597*8975f5c5SAndroid Build Coastguard Worker                stencilOnlyBlitParams.dstStencilLayer = mStencilRenderTarget->getLayerIndex();
598*8975f5c5SAndroid Build Coastguard Worker                stencilOnlyBlitParams.dstStencilLevel = mStencilRenderTarget->getLevelIndex();
599*8975f5c5SAndroid Build Coastguard Worker                stencilOnlyBlitParams.dstPackedDepthStencilFormat =
600*8975f5c5SAndroid Build Coastguard Worker                    mStencilRenderTarget->getFormat().hasDepthAndStencilBits();
601*8975f5c5SAndroid Build Coastguard Worker
602*8975f5c5SAndroid Build Coastguard Worker                ANGLE_TRY(contextMtl->getDisplay()->getUtils().blitStencilViaCopyBuffer(
603*8975f5c5SAndroid Build Coastguard Worker                    context, stencilOnlyBlitParams));
604*8975f5c5SAndroid Build Coastguard Worker
605*8975f5c5SAndroid Build Coastguard Worker                // Prevent the stencil to be blitted with draw again
606*8975f5c5SAndroid Build Coastguard Worker                dsBlitParams.srcStencil = nullptr;
607*8975f5c5SAndroid Build Coastguard Worker            }
608*8975f5c5SAndroid Build Coastguard Worker        }
609*8975f5c5SAndroid Build Coastguard Worker
610*8975f5c5SAndroid Build Coastguard Worker        // The actual blitting of depth and/or stencil
611*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(ensureRenderPassStarted(context, &renderEncoder));
612*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(contextMtl->getDisplay()->getUtils().blitDepthStencilWithDraw(
613*8975f5c5SAndroid Build Coastguard Worker            context, renderEncoder, dsBlitParams));
614*8975f5c5SAndroid Build Coastguard Worker    }  // if (blitDepthBuffer || blitStencilBuffer)
615*8975f5c5SAndroid Build Coastguard Worker    else
616*8975f5c5SAndroid Build Coastguard Worker    {
617*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(ensureRenderPassStarted(context, &renderEncoder));
618*8975f5c5SAndroid Build Coastguard Worker    }
619*8975f5c5SAndroid Build Coastguard Worker
620*8975f5c5SAndroid Build Coastguard Worker    // Blit color
621*8975f5c5SAndroid Build Coastguard Worker    if (blitColorBuffer)
622*8975f5c5SAndroid Build Coastguard Worker    {
623*8975f5c5SAndroid Build Coastguard Worker        mtl::ColorBlitParams colorBlitParams;
624*8975f5c5SAndroid Build Coastguard Worker        memcpy(&colorBlitParams, &baseParams, sizeof(baseParams));
625*8975f5c5SAndroid Build Coastguard Worker
626*8975f5c5SAndroid Build Coastguard Worker        RenderTargetMtl *srcColorRt = srcFrameBuffer->getColorReadRenderTarget(context);
627*8975f5c5SAndroid Build Coastguard Worker        ASSERT(srcColorRt);
628*8975f5c5SAndroid Build Coastguard Worker
629*8975f5c5SAndroid Build Coastguard Worker        colorBlitParams.src      = srcColorRt->getTexture();
630*8975f5c5SAndroid Build Coastguard Worker        colorBlitParams.srcLevel = srcColorRt->getLevelIndex();
631*8975f5c5SAndroid Build Coastguard Worker        colorBlitParams.srcLayer = srcColorRt->getLayerIndex();
632*8975f5c5SAndroid Build Coastguard Worker
633*8975f5c5SAndroid Build Coastguard Worker        colorBlitParams.enabledBuffers = getState().getEnabledDrawBuffers();
634*8975f5c5SAndroid Build Coastguard Worker        colorBlitParams.filter         = filter;
635*8975f5c5SAndroid Build Coastguard Worker        colorBlitParams.dstLuminance   = srcColorRt->getFormat().actualAngleFormat().isLUMA();
636*8975f5c5SAndroid Build Coastguard Worker
637*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(contextMtl->getDisplay()->getUtils().blitColorWithDraw(
638*8975f5c5SAndroid Build Coastguard Worker            context, renderEncoder, srcColorRt->getFormat().actualAngleFormat(), colorBlitParams));
639*8975f5c5SAndroid Build Coastguard Worker    }
640*8975f5c5SAndroid Build Coastguard Worker
641*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
642*8975f5c5SAndroid Build Coastguard Worker}
643*8975f5c5SAndroid Build Coastguard Worker
644*8975f5c5SAndroid Build Coastguard Workerbool FramebufferMtl::totalBitsUsedIsLessThanOrEqualToMaxBitsSupported(
645*8975f5c5SAndroid Build Coastguard Worker    const gl::Context *context) const
646*8975f5c5SAndroid Build Coastguard Worker{
647*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
648*8975f5c5SAndroid Build Coastguard Worker
649*8975f5c5SAndroid Build Coastguard Worker    uint32_t bitsUsed = 0;
650*8975f5c5SAndroid Build Coastguard Worker    for (const gl::FramebufferAttachment &attachment : mState.getColorAttachments())
651*8975f5c5SAndroid Build Coastguard Worker    {
652*8975f5c5SAndroid Build Coastguard Worker        if (attachment.isAttached())
653*8975f5c5SAndroid Build Coastguard Worker        {
654*8975f5c5SAndroid Build Coastguard Worker            bitsUsed += attachment.getRedSize() + attachment.getGreenSize() +
655*8975f5c5SAndroid Build Coastguard Worker                        attachment.getBlueSize() + attachment.getAlphaSize();
656*8975f5c5SAndroid Build Coastguard Worker        }
657*8975f5c5SAndroid Build Coastguard Worker    }
658*8975f5c5SAndroid Build Coastguard Worker
659*8975f5c5SAndroid Build Coastguard Worker    return bitsUsed <= contextMtl->getDisplay()->getMaxColorTargetBits();
660*8975f5c5SAndroid Build Coastguard Worker}
661*8975f5c5SAndroid Build Coastguard Worker
662*8975f5c5SAndroid Build Coastguard Workergl::FramebufferStatus FramebufferMtl::checkStatus(const gl::Context *context) const
663*8975f5c5SAndroid Build Coastguard Worker{
664*8975f5c5SAndroid Build Coastguard Worker    if (mState.hasSeparateDepthAndStencilAttachments())
665*8975f5c5SAndroid Build Coastguard Worker    {
666*8975f5c5SAndroid Build Coastguard Worker        ContextMtl *contextMtl = mtl::GetImpl(context);
667*8975f5c5SAndroid Build Coastguard Worker        if (!contextMtl->getDisplay()->getFeatures().allowSeparateDepthStencilBuffers.enabled)
668*8975f5c5SAndroid Build Coastguard Worker        {
669*8975f5c5SAndroid Build Coastguard Worker            return gl::FramebufferStatus::Incomplete(
670*8975f5c5SAndroid Build Coastguard Worker                GL_FRAMEBUFFER_UNSUPPORTED,
671*8975f5c5SAndroid Build Coastguard Worker                gl::err::kFramebufferIncompleteUnsupportedSeparateDepthStencilBuffers);
672*8975f5c5SAndroid Build Coastguard Worker        }
673*8975f5c5SAndroid Build Coastguard Worker
674*8975f5c5SAndroid Build Coastguard Worker        ASSERT(mState.getDepthAttachment()->getFormat().info->depthBits > 0);
675*8975f5c5SAndroid Build Coastguard Worker        ASSERT(mState.getStencilAttachment()->getFormat().info->stencilBits > 0);
676*8975f5c5SAndroid Build Coastguard Worker        if (mState.getDepthAttachment()->getFormat().info->stencilBits != 0 ||
677*8975f5c5SAndroid Build Coastguard Worker            mState.getStencilAttachment()->getFormat().info->depthBits != 0)
678*8975f5c5SAndroid Build Coastguard Worker        {
679*8975f5c5SAndroid Build Coastguard Worker            return gl::FramebufferStatus::Incomplete(
680*8975f5c5SAndroid Build Coastguard Worker                GL_FRAMEBUFFER_UNSUPPORTED,
681*8975f5c5SAndroid Build Coastguard Worker                gl::err::
682*8975f5c5SAndroid Build Coastguard Worker                    kFramebufferIncompleteUnsupportedSeparateDepthStencilBuffersCombinedFormat);
683*8975f5c5SAndroid Build Coastguard Worker        }
684*8975f5c5SAndroid Build Coastguard Worker    }
685*8975f5c5SAndroid Build Coastguard Worker
686*8975f5c5SAndroid Build Coastguard Worker    if (!totalBitsUsedIsLessThanOrEqualToMaxBitsSupported(context))
687*8975f5c5SAndroid Build Coastguard Worker    {
688*8975f5c5SAndroid Build Coastguard Worker        return gl::FramebufferStatus::Incomplete(
689*8975f5c5SAndroid Build Coastguard Worker            GL_FRAMEBUFFER_UNSUPPORTED,
690*8975f5c5SAndroid Build Coastguard Worker            gl::err::kFramebufferIncompleteColorBitsUsedExceedsMaxColorBitsSupported);
691*8975f5c5SAndroid Build Coastguard Worker    }
692*8975f5c5SAndroid Build Coastguard Worker
693*8975f5c5SAndroid Build Coastguard Worker    return gl::FramebufferStatus::Complete();
694*8975f5c5SAndroid Build Coastguard Worker}
695*8975f5c5SAndroid Build Coastguard Worker
696*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::syncState(const gl::Context *context,
697*8975f5c5SAndroid Build Coastguard Worker                                        GLenum binding,
698*8975f5c5SAndroid Build Coastguard Worker                                        const gl::Framebuffer::DirtyBits &dirtyBits,
699*8975f5c5SAndroid Build Coastguard Worker                                        gl::Command command)
700*8975f5c5SAndroid Build Coastguard Worker{
701*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
702*8975f5c5SAndroid Build Coastguard Worker    bool mustNotifyContext = false;
703*8975f5c5SAndroid Build Coastguard Worker    // Cache old mRenderPassDesc before update*RenderTarget() invalidate it.
704*8975f5c5SAndroid Build Coastguard Worker    mtl::RenderPassDesc oldRenderPassDesc = mRenderPassDesc;
705*8975f5c5SAndroid Build Coastguard Worker
706*8975f5c5SAndroid Build Coastguard Worker    for (size_t dirtyBit : dirtyBits)
707*8975f5c5SAndroid Build Coastguard Worker    {
708*8975f5c5SAndroid Build Coastguard Worker        switch (dirtyBit)
709*8975f5c5SAndroid Build Coastguard Worker        {
710*8975f5c5SAndroid Build Coastguard Worker            case gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT:
711*8975f5c5SAndroid Build Coastguard Worker                ANGLE_TRY(updateDepthRenderTarget(context));
712*8975f5c5SAndroid Build Coastguard Worker                break;
713*8975f5c5SAndroid Build Coastguard Worker            case gl::Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT:
714*8975f5c5SAndroid Build Coastguard Worker                ANGLE_TRY(updateStencilRenderTarget(context));
715*8975f5c5SAndroid Build Coastguard Worker                break;
716*8975f5c5SAndroid Build Coastguard Worker            case gl::Framebuffer::DIRTY_BIT_DEPTH_BUFFER_CONTENTS:
717*8975f5c5SAndroid Build Coastguard Worker                // Restore depth attachment load action as its content may have been updated
718*8975f5c5SAndroid Build Coastguard Worker                // after framebuffer invalidation.
719*8975f5c5SAndroid Build Coastguard Worker                mRenderPassDesc.depthAttachment.loadAction = MTLLoadActionLoad;
720*8975f5c5SAndroid Build Coastguard Worker                break;
721*8975f5c5SAndroid Build Coastguard Worker            case gl::Framebuffer::DIRTY_BIT_STENCIL_BUFFER_CONTENTS:
722*8975f5c5SAndroid Build Coastguard Worker                // Restore stencil attachment load action as its content may have been updated
723*8975f5c5SAndroid Build Coastguard Worker                // after framebuffer invalidation.
724*8975f5c5SAndroid Build Coastguard Worker                mRenderPassDesc.stencilAttachment.loadAction = MTLLoadActionLoad;
725*8975f5c5SAndroid Build Coastguard Worker                break;
726*8975f5c5SAndroid Build Coastguard Worker            case gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS:
727*8975f5c5SAndroid Build Coastguard Worker                mustNotifyContext = true;
728*8975f5c5SAndroid Build Coastguard Worker                break;
729*8975f5c5SAndroid Build Coastguard Worker            case gl::Framebuffer::DIRTY_BIT_READ_BUFFER:
730*8975f5c5SAndroid Build Coastguard Worker            case gl::Framebuffer::DIRTY_BIT_DEFAULT_WIDTH:
731*8975f5c5SAndroid Build Coastguard Worker            case gl::Framebuffer::DIRTY_BIT_DEFAULT_HEIGHT:
732*8975f5c5SAndroid Build Coastguard Worker            case gl::Framebuffer::DIRTY_BIT_DEFAULT_SAMPLES:
733*8975f5c5SAndroid Build Coastguard Worker            case gl::Framebuffer::DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS:
734*8975f5c5SAndroid Build Coastguard Worker                break;
735*8975f5c5SAndroid Build Coastguard Worker            default:
736*8975f5c5SAndroid Build Coastguard Worker            {
737*8975f5c5SAndroid Build Coastguard Worker                static_assert(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0, "FB dirty bits");
738*8975f5c5SAndroid Build Coastguard Worker                if (dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX)
739*8975f5c5SAndroid Build Coastguard Worker                {
740*8975f5c5SAndroid Build Coastguard Worker                    size_t colorIndexGL = static_cast<size_t>(
741*8975f5c5SAndroid Build Coastguard Worker                        dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0);
742*8975f5c5SAndroid Build Coastguard Worker                    ANGLE_TRY(updateColorRenderTarget(context, colorIndexGL));
743*8975f5c5SAndroid Build Coastguard Worker                }
744*8975f5c5SAndroid Build Coastguard Worker                else
745*8975f5c5SAndroid Build Coastguard Worker                {
746*8975f5c5SAndroid Build Coastguard Worker                    ASSERT(dirtyBit >= gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_0 &&
747*8975f5c5SAndroid Build Coastguard Worker                           dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_MAX);
748*8975f5c5SAndroid Build Coastguard Worker                    // NOTE: might need to notify context.
749*8975f5c5SAndroid Build Coastguard Worker
750*8975f5c5SAndroid Build Coastguard Worker                    // Restore color attachment load action as its content may have been updated
751*8975f5c5SAndroid Build Coastguard Worker                    // after framebuffer invalidation.
752*8975f5c5SAndroid Build Coastguard Worker                    size_t colorIndexGL = static_cast<size_t>(
753*8975f5c5SAndroid Build Coastguard Worker                        dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_0);
754*8975f5c5SAndroid Build Coastguard Worker                    mRenderPassDesc.colorAttachments[colorIndexGL].loadAction = MTLLoadActionLoad;
755*8975f5c5SAndroid Build Coastguard Worker                }
756*8975f5c5SAndroid Build Coastguard Worker                break;
757*8975f5c5SAndroid Build Coastguard Worker            }
758*8975f5c5SAndroid Build Coastguard Worker        }
759*8975f5c5SAndroid Build Coastguard Worker    }
760*8975f5c5SAndroid Build Coastguard Worker
761*8975f5c5SAndroid Build Coastguard Worker    // If attachments have been changed and this is the current draw framebuffer,
762*8975f5c5SAndroid Build Coastguard Worker    // update the Metal context's incompatible attachments cache before preparing a render pass.
763*8975f5c5SAndroid Build Coastguard Worker    static_assert(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0, "FB dirty bits");
764*8975f5c5SAndroid Build Coastguard Worker    constexpr gl::Framebuffer::DirtyBits kAttachmentsMask =
765*8975f5c5SAndroid Build Coastguard Worker        gl::Framebuffer::DirtyBits::Mask(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX);
766*8975f5c5SAndroid Build Coastguard Worker    if (mustNotifyContext || (dirtyBits & kAttachmentsMask).any())
767*8975f5c5SAndroid Build Coastguard Worker    {
768*8975f5c5SAndroid Build Coastguard Worker        const gl::State &glState = context->getState();
769*8975f5c5SAndroid Build Coastguard Worker        if (mtl::GetImpl(glState.getDrawFramebuffer()) == this)
770*8975f5c5SAndroid Build Coastguard Worker        {
771*8975f5c5SAndroid Build Coastguard Worker            contextMtl->updateIncompatibleAttachments(glState);
772*8975f5c5SAndroid Build Coastguard Worker        }
773*8975f5c5SAndroid Build Coastguard Worker    }
774*8975f5c5SAndroid Build Coastguard Worker
775*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(prepareRenderPass(context, &mRenderPassDesc, command));
776*8975f5c5SAndroid Build Coastguard Worker    bool renderPassChanged = !oldRenderPassDesc.equalIgnoreLoadStoreOptions(mRenderPassDesc);
777*8975f5c5SAndroid Build Coastguard Worker
778*8975f5c5SAndroid Build Coastguard Worker    if (mustNotifyContext || renderPassChanged)
779*8975f5c5SAndroid Build Coastguard Worker    {
780*8975f5c5SAndroid Build Coastguard Worker        FramebufferMtl *currentDrawFramebuffer =
781*8975f5c5SAndroid Build Coastguard Worker            mtl::GetImpl(context->getState().getDrawFramebuffer());
782*8975f5c5SAndroid Build Coastguard Worker        if (currentDrawFramebuffer == this)
783*8975f5c5SAndroid Build Coastguard Worker        {
784*8975f5c5SAndroid Build Coastguard Worker            contextMtl->onDrawFrameBufferChangedState(context, this, renderPassChanged);
785*8975f5c5SAndroid Build Coastguard Worker        }
786*8975f5c5SAndroid Build Coastguard Worker
787*8975f5c5SAndroid Build Coastguard Worker        // Recreate pixel reading buffer if needed in future.
788*8975f5c5SAndroid Build Coastguard Worker        mReadPixelBuffer = nullptr;
789*8975f5c5SAndroid Build Coastguard Worker    }
790*8975f5c5SAndroid Build Coastguard Worker
791*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
792*8975f5c5SAndroid Build Coastguard Worker}
793*8975f5c5SAndroid Build Coastguard Worker
794*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::getSamplePosition(const gl::Context *context,
795*8975f5c5SAndroid Build Coastguard Worker                                                size_t index,
796*8975f5c5SAndroid Build Coastguard Worker                                                GLfloat *xy) const
797*8975f5c5SAndroid Build Coastguard Worker{
798*8975f5c5SAndroid Build Coastguard Worker    rx::GetSamplePosition(getSamples(), index, xy);
799*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
800*8975f5c5SAndroid Build Coastguard Worker}
801*8975f5c5SAndroid Build Coastguard Worker
802*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::prepareForUse(const gl::Context *context) const
803*8975f5c5SAndroid Build Coastguard Worker{
804*8975f5c5SAndroid Build Coastguard Worker    if (mBackbuffer)
805*8975f5c5SAndroid Build Coastguard Worker    {
806*8975f5c5SAndroid Build Coastguard Worker        // Backbuffer might obtain new drawable, which means it might change the
807*8975f5c5SAndroid Build Coastguard Worker        // the native texture used as the target of the render pass.
808*8975f5c5SAndroid Build Coastguard Worker        // We need to call this before creating render encoder.
809*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(mBackbuffer->ensureCurrentDrawableObtained(context));
810*8975f5c5SAndroid Build Coastguard Worker
811*8975f5c5SAndroid Build Coastguard Worker        if (mBackbuffer->hasRobustResourceInit())
812*8975f5c5SAndroid Build Coastguard Worker        {
813*8975f5c5SAndroid Build Coastguard Worker            ANGLE_TRY(mBackbuffer->initializeContents(context, GL_BACK, gl::ImageIndex::Make2D(0)));
814*8975f5c5SAndroid Build Coastguard Worker            if (mBackbuffer->hasDepthStencil())
815*8975f5c5SAndroid Build Coastguard Worker            {
816*8975f5c5SAndroid Build Coastguard Worker                ANGLE_TRY(
817*8975f5c5SAndroid Build Coastguard Worker                    mBackbuffer->initializeContents(context, GL_DEPTH, gl::ImageIndex::Make2D(0)));
818*8975f5c5SAndroid Build Coastguard Worker            }
819*8975f5c5SAndroid Build Coastguard Worker        }
820*8975f5c5SAndroid Build Coastguard Worker    }
821*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
822*8975f5c5SAndroid Build Coastguard Worker}
823*8975f5c5SAndroid Build Coastguard Worker
824*8975f5c5SAndroid Build Coastguard WorkerRenderTargetMtl *FramebufferMtl::getColorReadRenderTarget(const gl::Context *context) const
825*8975f5c5SAndroid Build Coastguard Worker{
826*8975f5c5SAndroid Build Coastguard Worker    if (mState.getReadIndex() >= mColorRenderTargets.size())
827*8975f5c5SAndroid Build Coastguard Worker    {
828*8975f5c5SAndroid Build Coastguard Worker        return nullptr;
829*8975f5c5SAndroid Build Coastguard Worker    }
830*8975f5c5SAndroid Build Coastguard Worker
831*8975f5c5SAndroid Build Coastguard Worker    if (IsError(prepareForUse(context)))
832*8975f5c5SAndroid Build Coastguard Worker    {
833*8975f5c5SAndroid Build Coastguard Worker        return nullptr;
834*8975f5c5SAndroid Build Coastguard Worker    }
835*8975f5c5SAndroid Build Coastguard Worker
836*8975f5c5SAndroid Build Coastguard Worker    return mColorRenderTargets[mState.getReadIndex()];
837*8975f5c5SAndroid Build Coastguard Worker}
838*8975f5c5SAndroid Build Coastguard Worker
839*8975f5c5SAndroid Build Coastguard WorkerRenderTargetMtl *FramebufferMtl::getColorReadRenderTargetNoCache(const gl::Context *context) const
840*8975f5c5SAndroid Build Coastguard Worker{
841*8975f5c5SAndroid Build Coastguard Worker    if (mState.getReadIndex() >= mColorRenderTargets.size())
842*8975f5c5SAndroid Build Coastguard Worker    {
843*8975f5c5SAndroid Build Coastguard Worker        return nullptr;
844*8975f5c5SAndroid Build Coastguard Worker    }
845*8975f5c5SAndroid Build Coastguard Worker
846*8975f5c5SAndroid Build Coastguard Worker    if (mBackbuffer)
847*8975f5c5SAndroid Build Coastguard Worker    {
848*8975f5c5SAndroid Build Coastguard Worker        // If we have a backbuffer/window surface, we can take the old path here and return
849*8975f5c5SAndroid Build Coastguard Worker        // the cached color render target.
850*8975f5c5SAndroid Build Coastguard Worker        return getColorReadRenderTarget(context);
851*8975f5c5SAndroid Build Coastguard Worker    }
852*8975f5c5SAndroid Build Coastguard Worker    // If we have no backbuffer, get the attachment from state color attachments, as it may have
853*8975f5c5SAndroid Build Coastguard Worker    // changed before syncing.
854*8975f5c5SAndroid Build Coastguard Worker    const gl::FramebufferAttachment *attachment = mState.getColorAttachment(mState.getReadIndex());
855*8975f5c5SAndroid Build Coastguard Worker    RenderTargetMtl *currentTarget              = nullptr;
856*8975f5c5SAndroid Build Coastguard Worker    if (attachment->getRenderTarget(context, attachment->getRenderToTextureSamples(),
857*8975f5c5SAndroid Build Coastguard Worker                                    &currentTarget) == angle::Result::Stop)
858*8975f5c5SAndroid Build Coastguard Worker    {
859*8975f5c5SAndroid Build Coastguard Worker        return nullptr;
860*8975f5c5SAndroid Build Coastguard Worker    }
861*8975f5c5SAndroid Build Coastguard Worker    return currentTarget;
862*8975f5c5SAndroid Build Coastguard Worker}
863*8975f5c5SAndroid Build Coastguard Worker
864*8975f5c5SAndroid Build Coastguard Workerint FramebufferMtl::getSamples() const
865*8975f5c5SAndroid Build Coastguard Worker{
866*8975f5c5SAndroid Build Coastguard Worker    return mRenderPassDesc.rasterSampleCount;
867*8975f5c5SAndroid Build Coastguard Worker}
868*8975f5c5SAndroid Build Coastguard Worker
869*8975f5c5SAndroid Build Coastguard Workergl::Rectangle FramebufferMtl::getCompleteRenderArea() const
870*8975f5c5SAndroid Build Coastguard Worker{
871*8975f5c5SAndroid Build Coastguard Worker    return gl::Rectangle(0, 0, mState.getDimensions().width, mState.getDimensions().height);
872*8975f5c5SAndroid Build Coastguard Worker}
873*8975f5c5SAndroid Build Coastguard Worker
874*8975f5c5SAndroid Build Coastguard Workerbool FramebufferMtl::renderPassHasStarted(ContextMtl *contextMtl) const
875*8975f5c5SAndroid Build Coastguard Worker{
876*8975f5c5SAndroid Build Coastguard Worker    return contextMtl->hasStartedRenderPass(mRenderPassDesc);
877*8975f5c5SAndroid Build Coastguard Worker}
878*8975f5c5SAndroid Build Coastguard Worker
879*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::ensureRenderPassStarted(const gl::Context *context,
880*8975f5c5SAndroid Build Coastguard Worker                                                      mtl::RenderCommandEncoder **encoderOut)
881*8975f5c5SAndroid Build Coastguard Worker{
882*8975f5c5SAndroid Build Coastguard Worker    return ensureRenderPassStarted(context, mRenderPassDesc, encoderOut);
883*8975f5c5SAndroid Build Coastguard Worker}
884*8975f5c5SAndroid Build Coastguard Worker
885*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::ensureRenderPassStarted(const gl::Context *context,
886*8975f5c5SAndroid Build Coastguard Worker                                                      const mtl::RenderPassDesc &desc,
887*8975f5c5SAndroid Build Coastguard Worker                                                      mtl::RenderCommandEncoder **encoderOut)
888*8975f5c5SAndroid Build Coastguard Worker{
889*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
890*8975f5c5SAndroid Build Coastguard Worker
891*8975f5c5SAndroid Build Coastguard Worker    mtl::RenderCommandEncoder *encoder = contextMtl->getRenderCommandEncoder();
892*8975f5c5SAndroid Build Coastguard Worker    if (encoder && encoder->getSerial() == mStartedRenderEncoderSerial)
893*8975f5c5SAndroid Build Coastguard Worker    {
894*8975f5c5SAndroid Build Coastguard Worker        // Already started.
895*8975f5c5SAndroid Build Coastguard Worker        *encoderOut = encoder;
896*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
897*8975f5c5SAndroid Build Coastguard Worker    }
898*8975f5c5SAndroid Build Coastguard Worker
899*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(prepareForUse(context));
900*8975f5c5SAndroid Build Coastguard Worker
901*8975f5c5SAndroid Build Coastguard Worker    // Only support ensureRenderPassStarted() with different load & store options only. The
902*8975f5c5SAndroid Build Coastguard Worker    // texture, level, slice must be the same.
903*8975f5c5SAndroid Build Coastguard Worker    ASSERT(desc.equalIgnoreLoadStoreOptions(mRenderPassDesc));
904*8975f5c5SAndroid Build Coastguard Worker
905*8975f5c5SAndroid Build Coastguard Worker    encoder                     = contextMtl->getRenderPassCommandEncoder(desc);
906*8975f5c5SAndroid Build Coastguard Worker    mStartedRenderEncoderSerial = encoder->getSerial();
907*8975f5c5SAndroid Build Coastguard Worker
908*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(unresolveIfNeeded(context, encoder));
909*8975f5c5SAndroid Build Coastguard Worker
910*8975f5c5SAndroid Build Coastguard Worker    if (mRenderPassCleanStart)
911*8975f5c5SAndroid Build Coastguard Worker    {
912*8975f5c5SAndroid Build Coastguard Worker        // After a clean start we should reset the loadOp to MTLLoadActionLoad in case this render
913*8975f5c5SAndroid Build Coastguard Worker        // pass could be interrupted by a conversion compute shader pass then being resumed later.
914*8975f5c5SAndroid Build Coastguard Worker        mRenderPassCleanStart = false;
915*8975f5c5SAndroid Build Coastguard Worker        for (mtl::RenderPassColorAttachmentDesc &colorAttachment : mRenderPassDesc.colorAttachments)
916*8975f5c5SAndroid Build Coastguard Worker        {
917*8975f5c5SAndroid Build Coastguard Worker            colorAttachment.loadAction = MTLLoadActionLoad;
918*8975f5c5SAndroid Build Coastguard Worker        }
919*8975f5c5SAndroid Build Coastguard Worker        mRenderPassDesc.depthAttachment.loadAction   = MTLLoadActionLoad;
920*8975f5c5SAndroid Build Coastguard Worker        mRenderPassDesc.stencilAttachment.loadAction = MTLLoadActionLoad;
921*8975f5c5SAndroid Build Coastguard Worker    }
922*8975f5c5SAndroid Build Coastguard Worker
923*8975f5c5SAndroid Build Coastguard Worker    *encoderOut = encoder;
924*8975f5c5SAndroid Build Coastguard Worker
925*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
926*8975f5c5SAndroid Build Coastguard Worker}
927*8975f5c5SAndroid Build Coastguard Worker
928*8975f5c5SAndroid Build Coastguard Workervoid FramebufferMtl::setLoadStoreActionOnRenderPassFirstStart(
929*8975f5c5SAndroid Build Coastguard Worker    mtl::RenderPassAttachmentDesc *attachmentOut,
930*8975f5c5SAndroid Build Coastguard Worker    const bool forceDepthStencilMultisampleLoad)
931*8975f5c5SAndroid Build Coastguard Worker{
932*8975f5c5SAndroid Build Coastguard Worker    ASSERT(mRenderPassCleanStart);
933*8975f5c5SAndroid Build Coastguard Worker
934*8975f5c5SAndroid Build Coastguard Worker    mtl::RenderPassAttachmentDesc &attachment = *attachmentOut;
935*8975f5c5SAndroid Build Coastguard Worker
936*8975f5c5SAndroid Build Coastguard Worker    if (!forceDepthStencilMultisampleLoad && attachment.storeAction == MTLStoreActionDontCare)
937*8975f5c5SAndroid Build Coastguard Worker    {
938*8975f5c5SAndroid Build Coastguard Worker        // If we previously discarded attachment's content, then don't need to load it.
939*8975f5c5SAndroid Build Coastguard Worker        attachment.loadAction = MTLLoadActionDontCare;
940*8975f5c5SAndroid Build Coastguard Worker    }
941*8975f5c5SAndroid Build Coastguard Worker    else
942*8975f5c5SAndroid Build Coastguard Worker    {
943*8975f5c5SAndroid Build Coastguard Worker        attachment.loadAction = MTLLoadActionLoad;
944*8975f5c5SAndroid Build Coastguard Worker    }
945*8975f5c5SAndroid Build Coastguard Worker
946*8975f5c5SAndroid Build Coastguard Worker    if (attachment.hasImplicitMSTexture())
947*8975f5c5SAndroid Build Coastguard Worker    {
948*8975f5c5SAndroid Build Coastguard Worker        attachment.storeAction = MTLStoreActionStoreAndMultisampleResolve;
949*8975f5c5SAndroid Build Coastguard Worker    }
950*8975f5c5SAndroid Build Coastguard Worker    else
951*8975f5c5SAndroid Build Coastguard Worker    {
952*8975f5c5SAndroid Build Coastguard Worker        attachment.storeAction = MTLStoreActionStore;  // Default action is store
953*8975f5c5SAndroid Build Coastguard Worker    }
954*8975f5c5SAndroid Build Coastguard Worker}
955*8975f5c5SAndroid Build Coastguard Worker
956*8975f5c5SAndroid Build Coastguard Workervoid FramebufferMtl::onStartedDrawingToFrameBuffer(const gl::Context *context)
957*8975f5c5SAndroid Build Coastguard Worker{
958*8975f5c5SAndroid Build Coastguard Worker    mRenderPassCleanStart = true;
959*8975f5c5SAndroid Build Coastguard Worker
960*8975f5c5SAndroid Build Coastguard Worker    // If any of the render targets need to load their multisample textures, we should do the same
961*8975f5c5SAndroid Build Coastguard Worker    // for depth/stencil.
962*8975f5c5SAndroid Build Coastguard Worker    bool forceDepthStencilMultisampleLoad = false;
963*8975f5c5SAndroid Build Coastguard Worker
964*8975f5c5SAndroid Build Coastguard Worker    // Compute loadOp based on previous storeOp and reset storeOp flags:
965*8975f5c5SAndroid Build Coastguard Worker    for (mtl::RenderPassColorAttachmentDesc &colorAttachment : mRenderPassDesc.colorAttachments)
966*8975f5c5SAndroid Build Coastguard Worker    {
967*8975f5c5SAndroid Build Coastguard Worker        forceDepthStencilMultisampleLoad |=
968*8975f5c5SAndroid Build Coastguard Worker            colorAttachment.storeAction == MTLStoreActionStoreAndMultisampleResolve;
969*8975f5c5SAndroid Build Coastguard Worker        setLoadStoreActionOnRenderPassFirstStart(&colorAttachment, false);
970*8975f5c5SAndroid Build Coastguard Worker    }
971*8975f5c5SAndroid Build Coastguard Worker    // Depth load/store
972*8975f5c5SAndroid Build Coastguard Worker    setLoadStoreActionOnRenderPassFirstStart(&mRenderPassDesc.depthAttachment,
973*8975f5c5SAndroid Build Coastguard Worker                                             forceDepthStencilMultisampleLoad);
974*8975f5c5SAndroid Build Coastguard Worker
975*8975f5c5SAndroid Build Coastguard Worker    // Stencil load/store
976*8975f5c5SAndroid Build Coastguard Worker    setLoadStoreActionOnRenderPassFirstStart(&mRenderPassDesc.stencilAttachment,
977*8975f5c5SAndroid Build Coastguard Worker                                             forceDepthStencilMultisampleLoad);
978*8975f5c5SAndroid Build Coastguard Worker}
979*8975f5c5SAndroid Build Coastguard Worker
980*8975f5c5SAndroid Build Coastguard Workervoid FramebufferMtl::onFrameEnd(const gl::Context *context)
981*8975f5c5SAndroid Build Coastguard Worker{
982*8975f5c5SAndroid Build Coastguard Worker    if (!mBackbuffer || mBackbuffer->preserveBuffer())
983*8975f5c5SAndroid Build Coastguard Worker    {
984*8975f5c5SAndroid Build Coastguard Worker        return;
985*8975f5c5SAndroid Build Coastguard Worker    }
986*8975f5c5SAndroid Build Coastguard Worker
987*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
988*8975f5c5SAndroid Build Coastguard Worker    // Always discard default FBO's depth stencil & multisample buffers at the end of the frame:
989*8975f5c5SAndroid Build Coastguard Worker    if (this->renderPassHasStarted(contextMtl))
990*8975f5c5SAndroid Build Coastguard Worker    {
991*8975f5c5SAndroid Build Coastguard Worker        mtl::RenderCommandEncoder *encoder = contextMtl->getRenderCommandEncoder();
992*8975f5c5SAndroid Build Coastguard Worker
993*8975f5c5SAndroid Build Coastguard Worker        constexpr GLenum dsAttachments[] = {GL_DEPTH, GL_STENCIL};
994*8975f5c5SAndroid Build Coastguard Worker        (void)invalidateImpl(context, 2, dsAttachments);
995*8975f5c5SAndroid Build Coastguard Worker        if (mBackbuffer->getSamples() > 1)
996*8975f5c5SAndroid Build Coastguard Worker        {
997*8975f5c5SAndroid Build Coastguard Worker            encoder->setColorStoreAction(MTLStoreActionMultisampleResolve, 0);
998*8975f5c5SAndroid Build Coastguard Worker        }
999*8975f5c5SAndroid Build Coastguard Worker
1000*8975f5c5SAndroid Build Coastguard Worker        contextMtl->endEncoding(false);
1001*8975f5c5SAndroid Build Coastguard Worker
1002*8975f5c5SAndroid Build Coastguard Worker        // Reset discard flag.
1003*8975f5c5SAndroid Build Coastguard Worker        onStartedDrawingToFrameBuffer(context);
1004*8975f5c5SAndroid Build Coastguard Worker    }
1005*8975f5c5SAndroid Build Coastguard Worker}
1006*8975f5c5SAndroid Build Coastguard Worker
1007*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::updateColorRenderTarget(const gl::Context *context,
1008*8975f5c5SAndroid Build Coastguard Worker                                                      size_t colorIndexGL)
1009*8975f5c5SAndroid Build Coastguard Worker{
1010*8975f5c5SAndroid Build Coastguard Worker    ASSERT(colorIndexGL < mColorRenderTargets.size());
1011*8975f5c5SAndroid Build Coastguard Worker    // Reset load store action
1012*8975f5c5SAndroid Build Coastguard Worker    mRenderPassDesc.colorAttachments[colorIndexGL].reset();
1013*8975f5c5SAndroid Build Coastguard Worker    return updateCachedRenderTarget(context, mState.getColorAttachment(colorIndexGL),
1014*8975f5c5SAndroid Build Coastguard Worker                                    &mColorRenderTargets[colorIndexGL]);
1015*8975f5c5SAndroid Build Coastguard Worker}
1016*8975f5c5SAndroid Build Coastguard Worker
1017*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::updateDepthRenderTarget(const gl::Context *context)
1018*8975f5c5SAndroid Build Coastguard Worker{
1019*8975f5c5SAndroid Build Coastguard Worker    // Reset load store action
1020*8975f5c5SAndroid Build Coastguard Worker    mRenderPassDesc.depthAttachment.reset();
1021*8975f5c5SAndroid Build Coastguard Worker    return updateCachedRenderTarget(context, mState.getDepthAttachment(), &mDepthRenderTarget);
1022*8975f5c5SAndroid Build Coastguard Worker}
1023*8975f5c5SAndroid Build Coastguard Worker
1024*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::updateStencilRenderTarget(const gl::Context *context)
1025*8975f5c5SAndroid Build Coastguard Worker{
1026*8975f5c5SAndroid Build Coastguard Worker    // Reset load store action
1027*8975f5c5SAndroid Build Coastguard Worker    mRenderPassDesc.stencilAttachment.reset();
1028*8975f5c5SAndroid Build Coastguard Worker    return updateCachedRenderTarget(context, mState.getStencilAttachment(), &mStencilRenderTarget);
1029*8975f5c5SAndroid Build Coastguard Worker}
1030*8975f5c5SAndroid Build Coastguard Worker
1031*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::updateCachedRenderTarget(const gl::Context *context,
1032*8975f5c5SAndroid Build Coastguard Worker                                                       const gl::FramebufferAttachment *attachment,
1033*8975f5c5SAndroid Build Coastguard Worker                                                       RenderTargetMtl **cachedRenderTarget)
1034*8975f5c5SAndroid Build Coastguard Worker{
1035*8975f5c5SAndroid Build Coastguard Worker    RenderTargetMtl *newRenderTarget = nullptr;
1036*8975f5c5SAndroid Build Coastguard Worker    if (attachment)
1037*8975f5c5SAndroid Build Coastguard Worker    {
1038*8975f5c5SAndroid Build Coastguard Worker        ASSERT(attachment->isAttached());
1039*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(attachment->getRenderTarget(context, attachment->getRenderToTextureSamples(),
1040*8975f5c5SAndroid Build Coastguard Worker                                              &newRenderTarget));
1041*8975f5c5SAndroid Build Coastguard Worker    }
1042*8975f5c5SAndroid Build Coastguard Worker    *cachedRenderTarget = newRenderTarget;
1043*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
1044*8975f5c5SAndroid Build Coastguard Worker}
1045*8975f5c5SAndroid Build Coastguard Worker
1046*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::prepareRenderPass(const gl::Context *context,
1047*8975f5c5SAndroid Build Coastguard Worker                                                mtl::RenderPassDesc *pDescOut,
1048*8975f5c5SAndroid Build Coastguard Worker                                                gl::Command command)
1049*8975f5c5SAndroid Build Coastguard Worker{
1050*8975f5c5SAndroid Build Coastguard Worker    // Skip incompatible attachments for draw ops to avoid triggering Metal runtime failures.
1051*8975f5c5SAndroid Build Coastguard Worker    const gl::DrawBufferMask incompatibleAttachments =
1052*8975f5c5SAndroid Build Coastguard Worker        (command == gl::Command::Draw) ? mtl::GetImpl(context)->getIncompatibleAttachments()
1053*8975f5c5SAndroid Build Coastguard Worker                                       : gl::DrawBufferMask();
1054*8975f5c5SAndroid Build Coastguard Worker    const gl::DrawBufferMask enabledDrawBuffers =
1055*8975f5c5SAndroid Build Coastguard Worker        getState().getEnabledDrawBuffers() & ~incompatibleAttachments;
1056*8975f5c5SAndroid Build Coastguard Worker
1057*8975f5c5SAndroid Build Coastguard Worker    mtl::RenderPassDesc &desc = *pDescOut;
1058*8975f5c5SAndroid Build Coastguard Worker
1059*8975f5c5SAndroid Build Coastguard Worker    mRenderPassFirstColorAttachmentFormat = nullptr;
1060*8975f5c5SAndroid Build Coastguard Worker    mRenderPassAttachmentsSameColorType   = true;
1061*8975f5c5SAndroid Build Coastguard Worker    uint32_t maxColorAttachments = static_cast<uint32_t>(mState.getColorAttachments().size());
1062*8975f5c5SAndroid Build Coastguard Worker    desc.numColorAttachments     = 0;
1063*8975f5c5SAndroid Build Coastguard Worker    desc.rasterSampleCount       = 1;
1064*8975f5c5SAndroid Build Coastguard Worker    for (uint32_t colorIndexGL = 0; colorIndexGL < maxColorAttachments; ++colorIndexGL)
1065*8975f5c5SAndroid Build Coastguard Worker    {
1066*8975f5c5SAndroid Build Coastguard Worker        ASSERT(colorIndexGL < mColorRenderTargets.size());
1067*8975f5c5SAndroid Build Coastguard Worker
1068*8975f5c5SAndroid Build Coastguard Worker        mtl::RenderPassColorAttachmentDesc &colorAttachment = desc.colorAttachments[colorIndexGL];
1069*8975f5c5SAndroid Build Coastguard Worker        const RenderTargetMtl *colorRenderTarget            = mColorRenderTargets[colorIndexGL];
1070*8975f5c5SAndroid Build Coastguard Worker
1071*8975f5c5SAndroid Build Coastguard Worker        // GL allows data types of fragment shader color outputs to be incompatible with disabled
1072*8975f5c5SAndroid Build Coastguard Worker        // color attachments. To prevent various Metal validation issues, assign textures only to
1073*8975f5c5SAndroid Build Coastguard Worker        // enabled attachments.
1074*8975f5c5SAndroid Build Coastguard Worker        if (colorRenderTarget && enabledDrawBuffers.test(colorIndexGL))
1075*8975f5c5SAndroid Build Coastguard Worker        {
1076*8975f5c5SAndroid Build Coastguard Worker            colorRenderTarget->toRenderPassAttachmentDesc(&colorAttachment);
1077*8975f5c5SAndroid Build Coastguard Worker
1078*8975f5c5SAndroid Build Coastguard Worker            desc.numColorAttachments = std::max(desc.numColorAttachments, colorIndexGL + 1);
1079*8975f5c5SAndroid Build Coastguard Worker            desc.rasterSampleCount =
1080*8975f5c5SAndroid Build Coastguard Worker                std::max(desc.rasterSampleCount, colorRenderTarget->getRenderSamples());
1081*8975f5c5SAndroid Build Coastguard Worker
1082*8975f5c5SAndroid Build Coastguard Worker            if (!mRenderPassFirstColorAttachmentFormat)
1083*8975f5c5SAndroid Build Coastguard Worker            {
1084*8975f5c5SAndroid Build Coastguard Worker                mRenderPassFirstColorAttachmentFormat = &colorRenderTarget->getFormat();
1085*8975f5c5SAndroid Build Coastguard Worker            }
1086*8975f5c5SAndroid Build Coastguard Worker            else
1087*8975f5c5SAndroid Build Coastguard Worker            {
1088*8975f5c5SAndroid Build Coastguard Worker                if (mRenderPassFirstColorAttachmentFormat->actualAngleFormat().isSint() !=
1089*8975f5c5SAndroid Build Coastguard Worker                        colorRenderTarget->getFormat().actualAngleFormat().isSint() ||
1090*8975f5c5SAndroid Build Coastguard Worker                    mRenderPassFirstColorAttachmentFormat->actualAngleFormat().isUint() !=
1091*8975f5c5SAndroid Build Coastguard Worker                        colorRenderTarget->getFormat().actualAngleFormat().isUint())
1092*8975f5c5SAndroid Build Coastguard Worker                {
1093*8975f5c5SAndroid Build Coastguard Worker                    mRenderPassAttachmentsSameColorType = false;
1094*8975f5c5SAndroid Build Coastguard Worker                }
1095*8975f5c5SAndroid Build Coastguard Worker            }
1096*8975f5c5SAndroid Build Coastguard Worker        }
1097*8975f5c5SAndroid Build Coastguard Worker        else
1098*8975f5c5SAndroid Build Coastguard Worker        {
1099*8975f5c5SAndroid Build Coastguard Worker            colorAttachment.reset();
1100*8975f5c5SAndroid Build Coastguard Worker        }
1101*8975f5c5SAndroid Build Coastguard Worker    }
1102*8975f5c5SAndroid Build Coastguard Worker
1103*8975f5c5SAndroid Build Coastguard Worker    if (mDepthRenderTarget)
1104*8975f5c5SAndroid Build Coastguard Worker    {
1105*8975f5c5SAndroid Build Coastguard Worker        mDepthRenderTarget->toRenderPassAttachmentDesc(&desc.depthAttachment);
1106*8975f5c5SAndroid Build Coastguard Worker        desc.rasterSampleCount =
1107*8975f5c5SAndroid Build Coastguard Worker            std::max(desc.rasterSampleCount, mDepthRenderTarget->getRenderSamples());
1108*8975f5c5SAndroid Build Coastguard Worker    }
1109*8975f5c5SAndroid Build Coastguard Worker    else
1110*8975f5c5SAndroid Build Coastguard Worker    {
1111*8975f5c5SAndroid Build Coastguard Worker        desc.depthAttachment.reset();
1112*8975f5c5SAndroid Build Coastguard Worker    }
1113*8975f5c5SAndroid Build Coastguard Worker
1114*8975f5c5SAndroid Build Coastguard Worker    if (mStencilRenderTarget)
1115*8975f5c5SAndroid Build Coastguard Worker    {
1116*8975f5c5SAndroid Build Coastguard Worker        mStencilRenderTarget->toRenderPassAttachmentDesc(&desc.stencilAttachment);
1117*8975f5c5SAndroid Build Coastguard Worker        desc.rasterSampleCount =
1118*8975f5c5SAndroid Build Coastguard Worker            std::max(desc.rasterSampleCount, mStencilRenderTarget->getRenderSamples());
1119*8975f5c5SAndroid Build Coastguard Worker    }
1120*8975f5c5SAndroid Build Coastguard Worker    else
1121*8975f5c5SAndroid Build Coastguard Worker    {
1122*8975f5c5SAndroid Build Coastguard Worker        desc.stencilAttachment.reset();
1123*8975f5c5SAndroid Build Coastguard Worker    }
1124*8975f5c5SAndroid Build Coastguard Worker
1125*8975f5c5SAndroid Build Coastguard Worker    if (desc.numColorAttachments == 0 && mDepthRenderTarget == nullptr &&
1126*8975f5c5SAndroid Build Coastguard Worker        mStencilRenderTarget == nullptr)
1127*8975f5c5SAndroid Build Coastguard Worker    {
1128*8975f5c5SAndroid Build Coastguard Worker        desc.defaultWidth  = mState.getDefaultWidth();
1129*8975f5c5SAndroid Build Coastguard Worker        desc.defaultHeight = mState.getDefaultHeight();
1130*8975f5c5SAndroid Build Coastguard Worker    }
1131*8975f5c5SAndroid Build Coastguard Worker
1132*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
1133*8975f5c5SAndroid Build Coastguard Worker}
1134*8975f5c5SAndroid Build Coastguard Worker
1135*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::clearWithLoadOp(const gl::Context *context,
1136*8975f5c5SAndroid Build Coastguard Worker                                              gl::DrawBufferMask clearColorBuffers,
1137*8975f5c5SAndroid Build Coastguard Worker                                              const mtl::ClearRectParams &clearOpts)
1138*8975f5c5SAndroid Build Coastguard Worker{
1139*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl             = mtl::GetImpl(context);
1140*8975f5c5SAndroid Build Coastguard Worker    bool startedRenderPass             = contextMtl->hasStartedRenderPass(mRenderPassDesc);
1141*8975f5c5SAndroid Build Coastguard Worker    mtl::RenderCommandEncoder *encoder = nullptr;
1142*8975f5c5SAndroid Build Coastguard Worker
1143*8975f5c5SAndroid Build Coastguard Worker    if (startedRenderPass)
1144*8975f5c5SAndroid Build Coastguard Worker    {
1145*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(ensureRenderPassStarted(context, &encoder));
1146*8975f5c5SAndroid Build Coastguard Worker        if (encoder->hasDrawCalls())
1147*8975f5c5SAndroid Build Coastguard Worker        {
1148*8975f5c5SAndroid Build Coastguard Worker            // Render pass already has draw calls recorded, it is better to use clear with draw
1149*8975f5c5SAndroid Build Coastguard Worker            // operation.
1150*8975f5c5SAndroid Build Coastguard Worker            return clearWithDraw(context, clearColorBuffers, clearOpts);
1151*8975f5c5SAndroid Build Coastguard Worker        }
1152*8975f5c5SAndroid Build Coastguard Worker        else
1153*8975f5c5SAndroid Build Coastguard Worker        {
1154*8975f5c5SAndroid Build Coastguard Worker            // If render pass has started but there is no draw call yet. It is OK to change the
1155*8975f5c5SAndroid Build Coastguard Worker            // loadOp.
1156*8975f5c5SAndroid Build Coastguard Worker            return clearWithLoadOpRenderPassStarted(context, clearColorBuffers, clearOpts, encoder);
1157*8975f5c5SAndroid Build Coastguard Worker        }
1158*8975f5c5SAndroid Build Coastguard Worker    }
1159*8975f5c5SAndroid Build Coastguard Worker    else
1160*8975f5c5SAndroid Build Coastguard Worker    {
1161*8975f5c5SAndroid Build Coastguard Worker        return clearWithLoadOpRenderPassNotStarted(context, clearColorBuffers, clearOpts);
1162*8975f5c5SAndroid Build Coastguard Worker    }
1163*8975f5c5SAndroid Build Coastguard Worker}
1164*8975f5c5SAndroid Build Coastguard Worker
1165*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::clearWithLoadOpRenderPassNotStarted(
1166*8975f5c5SAndroid Build Coastguard Worker    const gl::Context *context,
1167*8975f5c5SAndroid Build Coastguard Worker    gl::DrawBufferMask clearColorBuffers,
1168*8975f5c5SAndroid Build Coastguard Worker    const mtl::ClearRectParams &clearOpts)
1169*8975f5c5SAndroid Build Coastguard Worker{
1170*8975f5c5SAndroid Build Coastguard Worker    mtl::RenderPassDesc tempDesc = mRenderPassDesc;
1171*8975f5c5SAndroid Build Coastguard Worker
1172*8975f5c5SAndroid Build Coastguard Worker    for (uint32_t colorIndexGL = 0; colorIndexGL < tempDesc.numColorAttachments; ++colorIndexGL)
1173*8975f5c5SAndroid Build Coastguard Worker    {
1174*8975f5c5SAndroid Build Coastguard Worker        ASSERT(colorIndexGL < tempDesc.colorAttachments.size());
1175*8975f5c5SAndroid Build Coastguard Worker
1176*8975f5c5SAndroid Build Coastguard Worker        mtl::RenderPassColorAttachmentDesc &colorAttachment =
1177*8975f5c5SAndroid Build Coastguard Worker            tempDesc.colorAttachments[colorIndexGL];
1178*8975f5c5SAndroid Build Coastguard Worker        const mtl::TextureRef &texture = colorAttachment.texture;
1179*8975f5c5SAndroid Build Coastguard Worker
1180*8975f5c5SAndroid Build Coastguard Worker        if (clearColorBuffers.test(colorIndexGL))
1181*8975f5c5SAndroid Build Coastguard Worker        {
1182*8975f5c5SAndroid Build Coastguard Worker            colorAttachment.loadAction = MTLLoadActionClear;
1183*8975f5c5SAndroid Build Coastguard Worker            OverrideMTLClearColor(texture, clearOpts.clearColor.value(),
1184*8975f5c5SAndroid Build Coastguard Worker                                  &colorAttachment.clearColor);
1185*8975f5c5SAndroid Build Coastguard Worker        }
1186*8975f5c5SAndroid Build Coastguard Worker        else
1187*8975f5c5SAndroid Build Coastguard Worker        {
1188*8975f5c5SAndroid Build Coastguard Worker            colorAttachment.loadAction = MTLLoadActionLoad;
1189*8975f5c5SAndroid Build Coastguard Worker        }
1190*8975f5c5SAndroid Build Coastguard Worker
1191*8975f5c5SAndroid Build Coastguard Worker        if (colorAttachment.hasImplicitMSTexture())
1192*8975f5c5SAndroid Build Coastguard Worker        {
1193*8975f5c5SAndroid Build Coastguard Worker            colorAttachment.storeAction = MTLStoreActionStoreAndMultisampleResolve;
1194*8975f5c5SAndroid Build Coastguard Worker        }
1195*8975f5c5SAndroid Build Coastguard Worker        else
1196*8975f5c5SAndroid Build Coastguard Worker        {
1197*8975f5c5SAndroid Build Coastguard Worker            colorAttachment.storeAction = MTLStoreActionStore;
1198*8975f5c5SAndroid Build Coastguard Worker        }
1199*8975f5c5SAndroid Build Coastguard Worker    }
1200*8975f5c5SAndroid Build Coastguard Worker
1201*8975f5c5SAndroid Build Coastguard Worker    if (clearOpts.clearDepth.valid())
1202*8975f5c5SAndroid Build Coastguard Worker    {
1203*8975f5c5SAndroid Build Coastguard Worker        tempDesc.depthAttachment.loadAction = MTLLoadActionClear;
1204*8975f5c5SAndroid Build Coastguard Worker        tempDesc.depthAttachment.clearDepth = clearOpts.clearDepth.value();
1205*8975f5c5SAndroid Build Coastguard Worker    }
1206*8975f5c5SAndroid Build Coastguard Worker    else
1207*8975f5c5SAndroid Build Coastguard Worker    {
1208*8975f5c5SAndroid Build Coastguard Worker        tempDesc.depthAttachment.loadAction = MTLLoadActionLoad;
1209*8975f5c5SAndroid Build Coastguard Worker    }
1210*8975f5c5SAndroid Build Coastguard Worker
1211*8975f5c5SAndroid Build Coastguard Worker    if (tempDesc.depthAttachment.hasImplicitMSTexture())
1212*8975f5c5SAndroid Build Coastguard Worker    {
1213*8975f5c5SAndroid Build Coastguard Worker        tempDesc.depthAttachment.storeAction = MTLStoreActionStoreAndMultisampleResolve;
1214*8975f5c5SAndroid Build Coastguard Worker    }
1215*8975f5c5SAndroid Build Coastguard Worker    else
1216*8975f5c5SAndroid Build Coastguard Worker    {
1217*8975f5c5SAndroid Build Coastguard Worker        tempDesc.depthAttachment.storeAction = MTLStoreActionStore;
1218*8975f5c5SAndroid Build Coastguard Worker    }
1219*8975f5c5SAndroid Build Coastguard Worker
1220*8975f5c5SAndroid Build Coastguard Worker    if (clearOpts.clearStencil.valid())
1221*8975f5c5SAndroid Build Coastguard Worker    {
1222*8975f5c5SAndroid Build Coastguard Worker        tempDesc.stencilAttachment.loadAction   = MTLLoadActionClear;
1223*8975f5c5SAndroid Build Coastguard Worker        tempDesc.stencilAttachment.clearStencil = clearOpts.clearStencil.value();
1224*8975f5c5SAndroid Build Coastguard Worker    }
1225*8975f5c5SAndroid Build Coastguard Worker    else
1226*8975f5c5SAndroid Build Coastguard Worker    {
1227*8975f5c5SAndroid Build Coastguard Worker        tempDesc.stencilAttachment.loadAction = MTLLoadActionLoad;
1228*8975f5c5SAndroid Build Coastguard Worker    }
1229*8975f5c5SAndroid Build Coastguard Worker
1230*8975f5c5SAndroid Build Coastguard Worker    if (tempDesc.stencilAttachment.hasImplicitMSTexture())
1231*8975f5c5SAndroid Build Coastguard Worker    {
1232*8975f5c5SAndroid Build Coastguard Worker        tempDesc.stencilAttachment.storeAction = MTLStoreActionStoreAndMultisampleResolve;
1233*8975f5c5SAndroid Build Coastguard Worker    }
1234*8975f5c5SAndroid Build Coastguard Worker    else
1235*8975f5c5SAndroid Build Coastguard Worker    {
1236*8975f5c5SAndroid Build Coastguard Worker        tempDesc.stencilAttachment.storeAction = MTLStoreActionStore;
1237*8975f5c5SAndroid Build Coastguard Worker    }
1238*8975f5c5SAndroid Build Coastguard Worker
1239*8975f5c5SAndroid Build Coastguard Worker    // Start new render encoder with loadOp=Clear
1240*8975f5c5SAndroid Build Coastguard Worker    mtl::RenderCommandEncoder *encoder;
1241*8975f5c5SAndroid Build Coastguard Worker    return ensureRenderPassStarted(context, tempDesc, &encoder);
1242*8975f5c5SAndroid Build Coastguard Worker}
1243*8975f5c5SAndroid Build Coastguard Worker
1244*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::clearWithLoadOpRenderPassStarted(
1245*8975f5c5SAndroid Build Coastguard Worker    const gl::Context *context,
1246*8975f5c5SAndroid Build Coastguard Worker    gl::DrawBufferMask clearColorBuffers,
1247*8975f5c5SAndroid Build Coastguard Worker    const mtl::ClearRectParams &clearOpts,
1248*8975f5c5SAndroid Build Coastguard Worker    mtl::RenderCommandEncoder *encoder)
1249*8975f5c5SAndroid Build Coastguard Worker{
1250*8975f5c5SAndroid Build Coastguard Worker    ASSERT(!encoder->hasDrawCalls());
1251*8975f5c5SAndroid Build Coastguard Worker
1252*8975f5c5SAndroid Build Coastguard Worker    for (uint32_t colorIndexGL = 0; colorIndexGL < mRenderPassDesc.numColorAttachments;
1253*8975f5c5SAndroid Build Coastguard Worker         ++colorIndexGL)
1254*8975f5c5SAndroid Build Coastguard Worker    {
1255*8975f5c5SAndroid Build Coastguard Worker        ASSERT(colorIndexGL < mRenderPassDesc.colorAttachments.size());
1256*8975f5c5SAndroid Build Coastguard Worker
1257*8975f5c5SAndroid Build Coastguard Worker        mtl::RenderPassColorAttachmentDesc &colorAttachment =
1258*8975f5c5SAndroid Build Coastguard Worker            mRenderPassDesc.colorAttachments[colorIndexGL];
1259*8975f5c5SAndroid Build Coastguard Worker        const mtl::TextureRef &texture = colorAttachment.texture;
1260*8975f5c5SAndroid Build Coastguard Worker
1261*8975f5c5SAndroid Build Coastguard Worker        if (clearColorBuffers.test(colorIndexGL))
1262*8975f5c5SAndroid Build Coastguard Worker        {
1263*8975f5c5SAndroid Build Coastguard Worker            MTLClearColor clearVal;
1264*8975f5c5SAndroid Build Coastguard Worker            OverrideMTLClearColor(texture, clearOpts.clearColor.value(), &clearVal);
1265*8975f5c5SAndroid Build Coastguard Worker
1266*8975f5c5SAndroid Build Coastguard Worker            encoder->setColorLoadAction(MTLLoadActionClear, clearVal, colorIndexGL);
1267*8975f5c5SAndroid Build Coastguard Worker        }
1268*8975f5c5SAndroid Build Coastguard Worker    }
1269*8975f5c5SAndroid Build Coastguard Worker
1270*8975f5c5SAndroid Build Coastguard Worker    if (clearOpts.clearDepth.valid())
1271*8975f5c5SAndroid Build Coastguard Worker    {
1272*8975f5c5SAndroid Build Coastguard Worker        encoder->setDepthLoadAction(MTLLoadActionClear, clearOpts.clearDepth.value());
1273*8975f5c5SAndroid Build Coastguard Worker    }
1274*8975f5c5SAndroid Build Coastguard Worker
1275*8975f5c5SAndroid Build Coastguard Worker    if (clearOpts.clearStencil.valid())
1276*8975f5c5SAndroid Build Coastguard Worker    {
1277*8975f5c5SAndroid Build Coastguard Worker        encoder->setStencilLoadAction(MTLLoadActionClear, clearOpts.clearStencil.value());
1278*8975f5c5SAndroid Build Coastguard Worker    }
1279*8975f5c5SAndroid Build Coastguard Worker
1280*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
1281*8975f5c5SAndroid Build Coastguard Worker}
1282*8975f5c5SAndroid Build Coastguard Worker
1283*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::clearWithDraw(const gl::Context *context,
1284*8975f5c5SAndroid Build Coastguard Worker                                            gl::DrawBufferMask clearColorBuffers,
1285*8975f5c5SAndroid Build Coastguard Worker                                            const mtl::ClearRectParams &clearOpts)
1286*8975f5c5SAndroid Build Coastguard Worker{
1287*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
1288*8975f5c5SAndroid Build Coastguard Worker    DisplayMtl *display    = contextMtl->getDisplay();
1289*8975f5c5SAndroid Build Coastguard Worker
1290*8975f5c5SAndroid Build Coastguard Worker    if (mRenderPassAttachmentsSameColorType)
1291*8975f5c5SAndroid Build Coastguard Worker    {
1292*8975f5c5SAndroid Build Coastguard Worker        // Start new render encoder if not already.
1293*8975f5c5SAndroid Build Coastguard Worker        mtl::RenderCommandEncoder *encoder;
1294*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(ensureRenderPassStarted(context, mRenderPassDesc, &encoder));
1295*8975f5c5SAndroid Build Coastguard Worker
1296*8975f5c5SAndroid Build Coastguard Worker        return display->getUtils().clearWithDraw(context, encoder, clearOpts);
1297*8975f5c5SAndroid Build Coastguard Worker    }
1298*8975f5c5SAndroid Build Coastguard Worker
1299*8975f5c5SAndroid Build Coastguard Worker    // Not all attachments have the same color type.
1300*8975f5c5SAndroid Build Coastguard Worker    mtl::ClearRectParams overrideClearOps = clearOpts;
1301*8975f5c5SAndroid Build Coastguard Worker    overrideClearOps.enabledBuffers.reset();
1302*8975f5c5SAndroid Build Coastguard Worker
1303*8975f5c5SAndroid Build Coastguard Worker    // First clear depth/stencil without color attachment
1304*8975f5c5SAndroid Build Coastguard Worker    if (clearOpts.clearDepth.valid() || clearOpts.clearStencil.valid())
1305*8975f5c5SAndroid Build Coastguard Worker    {
1306*8975f5c5SAndroid Build Coastguard Worker        mtl::RenderPassDesc dsOnlyDesc     = mRenderPassDesc;
1307*8975f5c5SAndroid Build Coastguard Worker        dsOnlyDesc.numColorAttachments     = 0;
1308*8975f5c5SAndroid Build Coastguard Worker        mtl::RenderCommandEncoder *encoder = contextMtl->getRenderPassCommandEncoder(dsOnlyDesc);
1309*8975f5c5SAndroid Build Coastguard Worker
1310*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(display->getUtils().clearWithDraw(context, encoder, overrideClearOps));
1311*8975f5c5SAndroid Build Coastguard Worker    }
1312*8975f5c5SAndroid Build Coastguard Worker
1313*8975f5c5SAndroid Build Coastguard Worker    // Clear the color attachment one by one.
1314*8975f5c5SAndroid Build Coastguard Worker    overrideClearOps.enabledBuffers.set(0);
1315*8975f5c5SAndroid Build Coastguard Worker    for (size_t drawbuffer : clearColorBuffers)
1316*8975f5c5SAndroid Build Coastguard Worker    {
1317*8975f5c5SAndroid Build Coastguard Worker        if (drawbuffer >= mRenderPassDesc.numColorAttachments)
1318*8975f5c5SAndroid Build Coastguard Worker        {
1319*8975f5c5SAndroid Build Coastguard Worker            // Iteration over drawbuffer indices always goes in ascending order
1320*8975f5c5SAndroid Build Coastguard Worker            break;
1321*8975f5c5SAndroid Build Coastguard Worker        }
1322*8975f5c5SAndroid Build Coastguard Worker        RenderTargetMtl *renderTarget = mColorRenderTargets[drawbuffer];
1323*8975f5c5SAndroid Build Coastguard Worker        if (!renderTarget || !renderTarget->getTexture())
1324*8975f5c5SAndroid Build Coastguard Worker        {
1325*8975f5c5SAndroid Build Coastguard Worker            continue;
1326*8975f5c5SAndroid Build Coastguard Worker        }
1327*8975f5c5SAndroid Build Coastguard Worker        const mtl::Format &format     = renderTarget->getFormat();
1328*8975f5c5SAndroid Build Coastguard Worker        mtl::PixelType clearColorType = overrideClearOps.clearColor.value().getType();
1329*8975f5c5SAndroid Build Coastguard Worker        if ((clearColorType == mtl::PixelType::Int && !format.actualAngleFormat().isSint()) ||
1330*8975f5c5SAndroid Build Coastguard Worker            (clearColorType == mtl::PixelType::UInt && !format.actualAngleFormat().isUint()) ||
1331*8975f5c5SAndroid Build Coastguard Worker            (clearColorType == mtl::PixelType::Float && format.actualAngleFormat().isInt()))
1332*8975f5c5SAndroid Build Coastguard Worker        {
1333*8975f5c5SAndroid Build Coastguard Worker            continue;
1334*8975f5c5SAndroid Build Coastguard Worker        }
1335*8975f5c5SAndroid Build Coastguard Worker
1336*8975f5c5SAndroid Build Coastguard Worker        overrideClearOps.clearWriteMaskArray[0] = overrideClearOps.clearWriteMaskArray[drawbuffer];
1337*8975f5c5SAndroid Build Coastguard Worker
1338*8975f5c5SAndroid Build Coastguard Worker        mtl::RenderCommandEncoder *encoder =
1339*8975f5c5SAndroid Build Coastguard Worker            contextMtl->getRenderTargetCommandEncoder(*renderTarget);
1340*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(display->getUtils().clearWithDraw(context, encoder, overrideClearOps));
1341*8975f5c5SAndroid Build Coastguard Worker    }
1342*8975f5c5SAndroid Build Coastguard Worker
1343*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
1344*8975f5c5SAndroid Build Coastguard Worker}
1345*8975f5c5SAndroid Build Coastguard Worker
1346*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::clearImpl(const gl::Context *context,
1347*8975f5c5SAndroid Build Coastguard Worker                                        gl::DrawBufferMask clearColorBuffers,
1348*8975f5c5SAndroid Build Coastguard Worker                                        mtl::ClearRectParams *pClearOpts)
1349*8975f5c5SAndroid Build Coastguard Worker{
1350*8975f5c5SAndroid Build Coastguard Worker    auto &clearOpts = *pClearOpts;
1351*8975f5c5SAndroid Build Coastguard Worker
1352*8975f5c5SAndroid Build Coastguard Worker    if (!clearOpts.clearColor.valid() && !clearOpts.clearDepth.valid() &&
1353*8975f5c5SAndroid Build Coastguard Worker        !clearOpts.clearStencil.valid())
1354*8975f5c5SAndroid Build Coastguard Worker    {
1355*8975f5c5SAndroid Build Coastguard Worker        // No Op.
1356*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
1357*8975f5c5SAndroid Build Coastguard Worker    }
1358*8975f5c5SAndroid Build Coastguard Worker
1359*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
1360*8975f5c5SAndroid Build Coastguard Worker    const gl::Rectangle renderArea(0, 0, mState.getDimensions().width,
1361*8975f5c5SAndroid Build Coastguard Worker                                   mState.getDimensions().height);
1362*8975f5c5SAndroid Build Coastguard Worker
1363*8975f5c5SAndroid Build Coastguard Worker    clearOpts.colorFormat    = mRenderPassFirstColorAttachmentFormat;
1364*8975f5c5SAndroid Build Coastguard Worker    clearOpts.dstTextureSize = mState.getExtents();
1365*8975f5c5SAndroid Build Coastguard Worker    clearOpts.clearArea      = ClipRectToScissor(contextMtl->getState(), renderArea, false);
1366*8975f5c5SAndroid Build Coastguard Worker    clearOpts.flipY          = mFlipY;
1367*8975f5c5SAndroid Build Coastguard Worker
1368*8975f5c5SAndroid Build Coastguard Worker    // Discard clear altogether if scissor has 0 width or height.
1369*8975f5c5SAndroid Build Coastguard Worker    if (clearOpts.clearArea.width == 0 || clearOpts.clearArea.height == 0)
1370*8975f5c5SAndroid Build Coastguard Worker    {
1371*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
1372*8975f5c5SAndroid Build Coastguard Worker    }
1373*8975f5c5SAndroid Build Coastguard Worker
1374*8975f5c5SAndroid Build Coastguard Worker    clearOpts.clearWriteMaskArray = contextMtl->getWriteMaskArray();
1375*8975f5c5SAndroid Build Coastguard Worker    uint32_t stencilMask          = contextMtl->getStencilMask();
1376*8975f5c5SAndroid Build Coastguard Worker    if (!contextMtl->getDepthMask())
1377*8975f5c5SAndroid Build Coastguard Worker    {
1378*8975f5c5SAndroid Build Coastguard Worker        // Disable depth clearing, since depth write is disable
1379*8975f5c5SAndroid Build Coastguard Worker        clearOpts.clearDepth.reset();
1380*8975f5c5SAndroid Build Coastguard Worker    }
1381*8975f5c5SAndroid Build Coastguard Worker
1382*8975f5c5SAndroid Build Coastguard Worker    // Only clear enabled buffers
1383*8975f5c5SAndroid Build Coastguard Worker    clearOpts.enabledBuffers = clearColorBuffers;
1384*8975f5c5SAndroid Build Coastguard Worker
1385*8975f5c5SAndroid Build Coastguard Worker    bool allBuffersUnmasked = true;
1386*8975f5c5SAndroid Build Coastguard Worker    for (size_t enabledBuffer : clearColorBuffers)
1387*8975f5c5SAndroid Build Coastguard Worker    {
1388*8975f5c5SAndroid Build Coastguard Worker        if (clearOpts.clearWriteMaskArray[enabledBuffer] != MTLColorWriteMaskAll)
1389*8975f5c5SAndroid Build Coastguard Worker        {
1390*8975f5c5SAndroid Build Coastguard Worker            allBuffersUnmasked = false;
1391*8975f5c5SAndroid Build Coastguard Worker            break;
1392*8975f5c5SAndroid Build Coastguard Worker        }
1393*8975f5c5SAndroid Build Coastguard Worker    }
1394*8975f5c5SAndroid Build Coastguard Worker
1395*8975f5c5SAndroid Build Coastguard Worker    if (clearOpts.clearArea == renderArea &&
1396*8975f5c5SAndroid Build Coastguard Worker        (!clearOpts.clearColor.valid() || allBuffersUnmasked) &&
1397*8975f5c5SAndroid Build Coastguard Worker        (!clearOpts.clearStencil.valid() ||
1398*8975f5c5SAndroid Build Coastguard Worker         (stencilMask & mtl::kStencilMaskAll) == mtl::kStencilMaskAll))
1399*8975f5c5SAndroid Build Coastguard Worker    {
1400*8975f5c5SAndroid Build Coastguard Worker        return clearWithLoadOp(context, clearColorBuffers, clearOpts);
1401*8975f5c5SAndroid Build Coastguard Worker    }
1402*8975f5c5SAndroid Build Coastguard Worker
1403*8975f5c5SAndroid Build Coastguard Worker    return clearWithDraw(context, clearColorBuffers, clearOpts);
1404*8975f5c5SAndroid Build Coastguard Worker}
1405*8975f5c5SAndroid Build Coastguard Worker
1406*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::invalidateImpl(const gl::Context *context,
1407*8975f5c5SAndroid Build Coastguard Worker                                             size_t count,
1408*8975f5c5SAndroid Build Coastguard Worker                                             const GLenum *attachments)
1409*8975f5c5SAndroid Build Coastguard Worker{
1410*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
1411*8975f5c5SAndroid Build Coastguard Worker    gl::DrawBufferMask invalidateColorBuffers;
1412*8975f5c5SAndroid Build Coastguard Worker    bool invalidateDepthBuffer   = false;
1413*8975f5c5SAndroid Build Coastguard Worker    bool invalidateStencilBuffer = false;
1414*8975f5c5SAndroid Build Coastguard Worker
1415*8975f5c5SAndroid Build Coastguard Worker    for (size_t i = 0; i < count; ++i)
1416*8975f5c5SAndroid Build Coastguard Worker    {
1417*8975f5c5SAndroid Build Coastguard Worker        const GLenum attachment = attachments[i];
1418*8975f5c5SAndroid Build Coastguard Worker
1419*8975f5c5SAndroid Build Coastguard Worker        switch (attachment)
1420*8975f5c5SAndroid Build Coastguard Worker        {
1421*8975f5c5SAndroid Build Coastguard Worker            case GL_DEPTH:
1422*8975f5c5SAndroid Build Coastguard Worker            case GL_DEPTH_ATTACHMENT:
1423*8975f5c5SAndroid Build Coastguard Worker                invalidateDepthBuffer = true;
1424*8975f5c5SAndroid Build Coastguard Worker                break;
1425*8975f5c5SAndroid Build Coastguard Worker            case GL_STENCIL:
1426*8975f5c5SAndroid Build Coastguard Worker            case GL_STENCIL_ATTACHMENT:
1427*8975f5c5SAndroid Build Coastguard Worker                invalidateStencilBuffer = true;
1428*8975f5c5SAndroid Build Coastguard Worker                break;
1429*8975f5c5SAndroid Build Coastguard Worker            case GL_DEPTH_STENCIL_ATTACHMENT:
1430*8975f5c5SAndroid Build Coastguard Worker                invalidateDepthBuffer   = true;
1431*8975f5c5SAndroid Build Coastguard Worker                invalidateStencilBuffer = true;
1432*8975f5c5SAndroid Build Coastguard Worker                break;
1433*8975f5c5SAndroid Build Coastguard Worker            default:
1434*8975f5c5SAndroid Build Coastguard Worker                ASSERT(
1435*8975f5c5SAndroid Build Coastguard Worker                    (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15) ||
1436*8975f5c5SAndroid Build Coastguard Worker                    (attachment == GL_COLOR));
1437*8975f5c5SAndroid Build Coastguard Worker
1438*8975f5c5SAndroid Build Coastguard Worker                invalidateColorBuffers.set(
1439*8975f5c5SAndroid Build Coastguard Worker                    attachment == GL_COLOR ? 0u : (attachment - GL_COLOR_ATTACHMENT0));
1440*8975f5c5SAndroid Build Coastguard Worker        }
1441*8975f5c5SAndroid Build Coastguard Worker    }
1442*8975f5c5SAndroid Build Coastguard Worker
1443*8975f5c5SAndroid Build Coastguard Worker    // Set the appropriate storeOp for attachments.
1444*8975f5c5SAndroid Build Coastguard Worker    // If we already start the render pass, then need to set the store action now.
1445*8975f5c5SAndroid Build Coastguard Worker    bool renderPassStarted = contextMtl->hasStartedRenderPass(mRenderPassDesc);
1446*8975f5c5SAndroid Build Coastguard Worker    mtl::RenderCommandEncoder *encoder =
1447*8975f5c5SAndroid Build Coastguard Worker        renderPassStarted ? contextMtl->getRenderCommandEncoder() : nullptr;
1448*8975f5c5SAndroid Build Coastguard Worker
1449*8975f5c5SAndroid Build Coastguard Worker    for (uint32_t i = 0; i < mRenderPassDesc.numColorAttachments; ++i)
1450*8975f5c5SAndroid Build Coastguard Worker    {
1451*8975f5c5SAndroid Build Coastguard Worker        if (invalidateColorBuffers.test(i))
1452*8975f5c5SAndroid Build Coastguard Worker        {
1453*8975f5c5SAndroid Build Coastguard Worker            // Some opaque formats, like RGB8, are emulated as RGBA with alpha channel initialized
1454*8975f5c5SAndroid Build Coastguard Worker            // to 1.0. Invalidating such attachments may lead to random values in their alpha
1455*8975f5c5SAndroid Build Coastguard Worker            // channel, so skip invalidation in this case.
1456*8975f5c5SAndroid Build Coastguard Worker            RenderTargetMtl *renderTarget = mColorRenderTargets[i];
1457*8975f5c5SAndroid Build Coastguard Worker            if (renderTarget && renderTarget->getTexture())
1458*8975f5c5SAndroid Build Coastguard Worker            {
1459*8975f5c5SAndroid Build Coastguard Worker                const mtl::Format &mtlFormat        = renderTarget->getFormat();
1460*8975f5c5SAndroid Build Coastguard Worker                const angle::Format &intendedFormat = mtlFormat.intendedAngleFormat();
1461*8975f5c5SAndroid Build Coastguard Worker                const angle::Format &actualFormat   = mtlFormat.actualAngleFormat();
1462*8975f5c5SAndroid Build Coastguard Worker                if (intendedFormat.alphaBits == 0 && actualFormat.alphaBits)
1463*8975f5c5SAndroid Build Coastguard Worker                {
1464*8975f5c5SAndroid Build Coastguard Worker                    continue;
1465*8975f5c5SAndroid Build Coastguard Worker                }
1466*8975f5c5SAndroid Build Coastguard Worker            }
1467*8975f5c5SAndroid Build Coastguard Worker
1468*8975f5c5SAndroid Build Coastguard Worker            mtl::RenderPassColorAttachmentDesc &colorAttachment =
1469*8975f5c5SAndroid Build Coastguard Worker                mRenderPassDesc.colorAttachments[i];
1470*8975f5c5SAndroid Build Coastguard Worker            colorAttachment.storeAction = MTLStoreActionDontCare;
1471*8975f5c5SAndroid Build Coastguard Worker            if (renderPassStarted)
1472*8975f5c5SAndroid Build Coastguard Worker            {
1473*8975f5c5SAndroid Build Coastguard Worker                encoder->setColorStoreAction(MTLStoreActionDontCare, i);
1474*8975f5c5SAndroid Build Coastguard Worker            }
1475*8975f5c5SAndroid Build Coastguard Worker        }
1476*8975f5c5SAndroid Build Coastguard Worker    }
1477*8975f5c5SAndroid Build Coastguard Worker
1478*8975f5c5SAndroid Build Coastguard Worker    if (invalidateDepthBuffer && mDepthRenderTarget)
1479*8975f5c5SAndroid Build Coastguard Worker    {
1480*8975f5c5SAndroid Build Coastguard Worker        mRenderPassDesc.depthAttachment.storeAction = MTLStoreActionDontCare;
1481*8975f5c5SAndroid Build Coastguard Worker        if (renderPassStarted)
1482*8975f5c5SAndroid Build Coastguard Worker        {
1483*8975f5c5SAndroid Build Coastguard Worker            encoder->setDepthStoreAction(MTLStoreActionDontCare);
1484*8975f5c5SAndroid Build Coastguard Worker        }
1485*8975f5c5SAndroid Build Coastguard Worker    }
1486*8975f5c5SAndroid Build Coastguard Worker
1487*8975f5c5SAndroid Build Coastguard Worker    if (invalidateStencilBuffer && mStencilRenderTarget)
1488*8975f5c5SAndroid Build Coastguard Worker    {
1489*8975f5c5SAndroid Build Coastguard Worker        mRenderPassDesc.stencilAttachment.storeAction = MTLStoreActionDontCare;
1490*8975f5c5SAndroid Build Coastguard Worker        if (renderPassStarted)
1491*8975f5c5SAndroid Build Coastguard Worker        {
1492*8975f5c5SAndroid Build Coastguard Worker            encoder->setStencilStoreAction(MTLStoreActionDontCare);
1493*8975f5c5SAndroid Build Coastguard Worker        }
1494*8975f5c5SAndroid Build Coastguard Worker    }
1495*8975f5c5SAndroid Build Coastguard Worker
1496*8975f5c5SAndroid Build Coastguard Worker    // Do not encode any further commands in this render pass which can affect the
1497*8975f5c5SAndroid Build Coastguard Worker    // framebuffer, or their effects will be lost.
1498*8975f5c5SAndroid Build Coastguard Worker    contextMtl->endEncoding(false);
1499*8975f5c5SAndroid Build Coastguard Worker    // Reset discard flag.
1500*8975f5c5SAndroid Build Coastguard Worker    onStartedDrawingToFrameBuffer(context);
1501*8975f5c5SAndroid Build Coastguard Worker
1502*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
1503*8975f5c5SAndroid Build Coastguard Worker}
1504*8975f5c5SAndroid Build Coastguard Worker
1505*8975f5c5SAndroid Build Coastguard Workergl::Rectangle FramebufferMtl::getCorrectFlippedReadArea(const gl::Context *context,
1506*8975f5c5SAndroid Build Coastguard Worker                                                        const gl::Rectangle &glArea) const
1507*8975f5c5SAndroid Build Coastguard Worker{
1508*8975f5c5SAndroid Build Coastguard Worker    RenderTargetMtl *readRT = getColorReadRenderTarget(context);
1509*8975f5c5SAndroid Build Coastguard Worker    if (!readRT)
1510*8975f5c5SAndroid Build Coastguard Worker    {
1511*8975f5c5SAndroid Build Coastguard Worker        readRT = mDepthRenderTarget;
1512*8975f5c5SAndroid Build Coastguard Worker    }
1513*8975f5c5SAndroid Build Coastguard Worker    if (!readRT)
1514*8975f5c5SAndroid Build Coastguard Worker    {
1515*8975f5c5SAndroid Build Coastguard Worker        readRT = mStencilRenderTarget;
1516*8975f5c5SAndroid Build Coastguard Worker    }
1517*8975f5c5SAndroid Build Coastguard Worker    ASSERT(readRT);
1518*8975f5c5SAndroid Build Coastguard Worker    gl::Rectangle flippedArea = glArea;
1519*8975f5c5SAndroid Build Coastguard Worker    if (mFlipY)
1520*8975f5c5SAndroid Build Coastguard Worker    {
1521*8975f5c5SAndroid Build Coastguard Worker        flippedArea.y = readRT->getTexture()->height(readRT->getLevelIndex()) - flippedArea.y -
1522*8975f5c5SAndroid Build Coastguard Worker                        flippedArea.height;
1523*8975f5c5SAndroid Build Coastguard Worker    }
1524*8975f5c5SAndroid Build Coastguard Worker
1525*8975f5c5SAndroid Build Coastguard Worker    return flippedArea;
1526*8975f5c5SAndroid Build Coastguard Worker}
1527*8975f5c5SAndroid Build Coastguard Worker
1528*8975f5c5SAndroid Build Coastguard Workernamespace
1529*8975f5c5SAndroid Build Coastguard Worker{
1530*8975f5c5SAndroid Build Coastguard Worker
1531*8975f5c5SAndroid Build Coastguard Workerangle::Result readPixelsCopyImpl(
1532*8975f5c5SAndroid Build Coastguard Worker    const gl::Context *context,
1533*8975f5c5SAndroid Build Coastguard Worker    const gl::Rectangle &area,
1534*8975f5c5SAndroid Build Coastguard Worker    const PackPixelsParams &packPixelsParams,
1535*8975f5c5SAndroid Build Coastguard Worker    const RenderTargetMtl *renderTarget,
1536*8975f5c5SAndroid Build Coastguard Worker    const std::function<angle::Result(const gl::Rectangle &region, const uint8_t *&src)> &getDataFn,
1537*8975f5c5SAndroid Build Coastguard Worker    uint8_t *pixels)
1538*8975f5c5SAndroid Build Coastguard Worker{
1539*8975f5c5SAndroid Build Coastguard Worker    const mtl::Format &readFormat        = renderTarget->getFormat();
1540*8975f5c5SAndroid Build Coastguard Worker    const angle::Format &readAngleFormat = readFormat.actualAngleFormat();
1541*8975f5c5SAndroid Build Coastguard Worker
1542*8975f5c5SAndroid Build Coastguard Worker    auto packPixelsRowParams = packPixelsParams;
1543*8975f5c5SAndroid Build Coastguard Worker    gl::Rectangle srcRowRegion(area.x, area.y, area.width, 1);
1544*8975f5c5SAndroid Build Coastguard Worker    int bufferRowPitch = area.width * readAngleFormat.pixelBytes;
1545*8975f5c5SAndroid Build Coastguard Worker
1546*8975f5c5SAndroid Build Coastguard Worker    int rowOffset = packPixelsParams.reverseRowOrder ? -1 : 1;
1547*8975f5c5SAndroid Build Coastguard Worker    int startRow  = packPixelsParams.reverseRowOrder ? (area.y1() - 1) : area.y;
1548*8975f5c5SAndroid Build Coastguard Worker
1549*8975f5c5SAndroid Build Coastguard Worker    // Copy pixels row by row
1550*8975f5c5SAndroid Build Coastguard Worker    packPixelsRowParams.area.height     = 1;
1551*8975f5c5SAndroid Build Coastguard Worker    packPixelsRowParams.reverseRowOrder = false;
1552*8975f5c5SAndroid Build Coastguard Worker    for (int r = startRow, i = 0; i < area.height;
1553*8975f5c5SAndroid Build Coastguard Worker         ++i, r += rowOffset, pixels += packPixelsRowParams.outputPitch)
1554*8975f5c5SAndroid Build Coastguard Worker    {
1555*8975f5c5SAndroid Build Coastguard Worker        srcRowRegion.y             = r;
1556*8975f5c5SAndroid Build Coastguard Worker        packPixelsRowParams.area.y = packPixelsParams.area.y + i;
1557*8975f5c5SAndroid Build Coastguard Worker
1558*8975f5c5SAndroid Build Coastguard Worker        const uint8_t *src;
1559*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(getDataFn(srcRowRegion, src));
1560*8975f5c5SAndroid Build Coastguard Worker        PackPixels(packPixelsRowParams, readAngleFormat, bufferRowPitch, src, pixels);
1561*8975f5c5SAndroid Build Coastguard Worker    }
1562*8975f5c5SAndroid Build Coastguard Worker
1563*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
1564*8975f5c5SAndroid Build Coastguard Worker}
1565*8975f5c5SAndroid Build Coastguard Worker
1566*8975f5c5SAndroid Build Coastguard Worker}  // namespace
1567*8975f5c5SAndroid Build Coastguard Worker
1568*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::readPixelsImpl(const gl::Context *context,
1569*8975f5c5SAndroid Build Coastguard Worker                                             const gl::Rectangle &area,
1570*8975f5c5SAndroid Build Coastguard Worker                                             const PackPixelsParams &packPixelsParams,
1571*8975f5c5SAndroid Build Coastguard Worker                                             const RenderTargetMtl *renderTarget,
1572*8975f5c5SAndroid Build Coastguard Worker                                             uint8_t *pixels) const
1573*8975f5c5SAndroid Build Coastguard Worker{
1574*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl             = mtl::GetImpl(context);
1575*8975f5c5SAndroid Build Coastguard Worker    const angle::FeaturesMtl &features = contextMtl->getDisplay()->getFeatures();
1576*8975f5c5SAndroid Build Coastguard Worker
1577*8975f5c5SAndroid Build Coastguard Worker    if (!renderTarget)
1578*8975f5c5SAndroid Build Coastguard Worker    {
1579*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
1580*8975f5c5SAndroid Build Coastguard Worker    }
1581*8975f5c5SAndroid Build Coastguard Worker
1582*8975f5c5SAndroid Build Coastguard Worker    if (packPixelsParams.packBuffer)
1583*8975f5c5SAndroid Build Coastguard Worker    {
1584*8975f5c5SAndroid Build Coastguard Worker        return readPixelsToPBO(context, area, packPixelsParams, renderTarget);
1585*8975f5c5SAndroid Build Coastguard Worker    }
1586*8975f5c5SAndroid Build Coastguard Worker
1587*8975f5c5SAndroid Build Coastguard Worker    mtl::TextureRef texture;
1588*8975f5c5SAndroid Build Coastguard Worker    if (mBackbuffer)
1589*8975f5c5SAndroid Build Coastguard Worker    {
1590*8975f5c5SAndroid Build Coastguard Worker        // Backbuffer might have MSAA texture as render target, needs to obtain the
1591*8975f5c5SAndroid Build Coastguard Worker        // resolved texture to be able to read pixels.
1592*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(mBackbuffer->ensureColorTextureReadyForReadPixels(context));
1593*8975f5c5SAndroid Build Coastguard Worker        texture = mBackbuffer->getColorTexture();
1594*8975f5c5SAndroid Build Coastguard Worker    }
1595*8975f5c5SAndroid Build Coastguard Worker    else
1596*8975f5c5SAndroid Build Coastguard Worker    {
1597*8975f5c5SAndroid Build Coastguard Worker        texture = renderTarget->getTexture();
1598*8975f5c5SAndroid Build Coastguard Worker        // For non-default framebuffer, MSAA read pixels is disallowed.
1599*8975f5c5SAndroid Build Coastguard Worker        if (!texture)
1600*8975f5c5SAndroid Build Coastguard Worker        {
1601*8975f5c5SAndroid Build Coastguard Worker            return angle::Result::Stop;
1602*8975f5c5SAndroid Build Coastguard Worker        }
1603*8975f5c5SAndroid Build Coastguard Worker        ANGLE_MTL_CHECK(contextMtl, texture->samples() == 1, GL_INVALID_OPERATION);
1604*8975f5c5SAndroid Build Coastguard Worker    }
1605*8975f5c5SAndroid Build Coastguard Worker
1606*8975f5c5SAndroid Build Coastguard Worker    const mtl::Format &readFormat        = renderTarget->getFormat();
1607*8975f5c5SAndroid Build Coastguard Worker    const angle::Format &readAngleFormat = readFormat.actualAngleFormat();
1608*8975f5c5SAndroid Build Coastguard Worker
1609*8975f5c5SAndroid Build Coastguard Worker    if (features.copyIOSurfaceToNonIOSurfaceForReadOptimization.enabled &&
1610*8975f5c5SAndroid Build Coastguard Worker        texture->hasIOSurface() && texture->mipmapLevels() == 1 &&
1611*8975f5c5SAndroid Build Coastguard Worker        texture->textureType() == MTLTextureType2D)
1612*8975f5c5SAndroid Build Coastguard Worker    {
1613*8975f5c5SAndroid Build Coastguard Worker        // Reading a texture may be slow if it's an IOSurface because metal has to lock/unlock the
1614*8975f5c5SAndroid Build Coastguard Worker        // surface, whereas copying the texture to non IOSurface texture and then reading from that
1615*8975f5c5SAndroid Build Coastguard Worker        // may be fast depending on the GPU/driver.
1616*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(Copy2DTextureSlice0Level0ToTempTexture(context, texture, &texture));
1617*8975f5c5SAndroid Build Coastguard Worker    }
1618*8975f5c5SAndroid Build Coastguard Worker
1619*8975f5c5SAndroid Build Coastguard Worker    if (features.copyTextureToBufferForReadOptimization.enabled)
1620*8975f5c5SAndroid Build Coastguard Worker    {
1621*8975f5c5SAndroid Build Coastguard Worker        mtl::BufferRef buffer;
1622*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(CopyTextureSliceLevelToTempBuffer(context, texture, renderTarget->getLevelIndex(),
1623*8975f5c5SAndroid Build Coastguard Worker                                                    renderTarget->getLayerIndex(), &buffer));
1624*8975f5c5SAndroid Build Coastguard Worker
1625*8975f5c5SAndroid Build Coastguard Worker        int bufferRowPitch =
1626*8975f5c5SAndroid Build Coastguard Worker            texture->width(renderTarget->getLevelIndex()) * readAngleFormat.pixelBytes;
1627*8975f5c5SAndroid Build Coastguard Worker
1628*8975f5c5SAndroid Build Coastguard Worker        buffer->syncContent(contextMtl, contextMtl->getBlitCommandEncoder());
1629*8975f5c5SAndroid Build Coastguard Worker        const uint8_t *bufferData = buffer->mapReadOnly(contextMtl);
1630*8975f5c5SAndroid Build Coastguard Worker
1631*8975f5c5SAndroid Build Coastguard Worker        angle::Result result = readPixelsCopyImpl(
1632*8975f5c5SAndroid Build Coastguard Worker            context, area, packPixelsParams, renderTarget,
1633*8975f5c5SAndroid Build Coastguard Worker            [&](const gl::Rectangle &region, const uint8_t *&src) {
1634*8975f5c5SAndroid Build Coastguard Worker                src =
1635*8975f5c5SAndroid Build Coastguard Worker                    bufferData + region.y * bufferRowPitch + region.x * readAngleFormat.pixelBytes;
1636*8975f5c5SAndroid Build Coastguard Worker                return angle::Result::Continue;
1637*8975f5c5SAndroid Build Coastguard Worker            },
1638*8975f5c5SAndroid Build Coastguard Worker            pixels);
1639*8975f5c5SAndroid Build Coastguard Worker
1640*8975f5c5SAndroid Build Coastguard Worker        buffer->unmap(contextMtl);
1641*8975f5c5SAndroid Build Coastguard Worker
1642*8975f5c5SAndroid Build Coastguard Worker        return result;
1643*8975f5c5SAndroid Build Coastguard Worker    }
1644*8975f5c5SAndroid Build Coastguard Worker
1645*8975f5c5SAndroid Build Coastguard Worker    if (texture->isBeingUsedByGPU(contextMtl))
1646*8975f5c5SAndroid Build Coastguard Worker    {
1647*8975f5c5SAndroid Build Coastguard Worker        contextMtl->flushCommandBuffer(mtl::WaitUntilFinished);
1648*8975f5c5SAndroid Build Coastguard Worker    }
1649*8975f5c5SAndroid Build Coastguard Worker
1650*8975f5c5SAndroid Build Coastguard Worker    angle::MemoryBuffer readPixelRowBuffer;
1651*8975f5c5SAndroid Build Coastguard Worker    int bufferRowPitch = area.width * readAngleFormat.pixelBytes;
1652*8975f5c5SAndroid Build Coastguard Worker    ANGLE_CHECK_GL_ALLOC(contextMtl, readPixelRowBuffer.resize(bufferRowPitch));
1653*8975f5c5SAndroid Build Coastguard Worker    return readPixelsCopyImpl(
1654*8975f5c5SAndroid Build Coastguard Worker        context, area, packPixelsParams, renderTarget,
1655*8975f5c5SAndroid Build Coastguard Worker        [&](const gl::Rectangle &region, const uint8_t *&src) {
1656*8975f5c5SAndroid Build Coastguard Worker            // Read the pixels data to the row buffer
1657*8975f5c5SAndroid Build Coastguard Worker            ANGLE_TRY(mtl::ReadTexturePerSliceBytes(
1658*8975f5c5SAndroid Build Coastguard Worker                context, texture, bufferRowPitch, region, renderTarget->getLevelIndex(),
1659*8975f5c5SAndroid Build Coastguard Worker                renderTarget->getLayerIndex(), readPixelRowBuffer.data()));
1660*8975f5c5SAndroid Build Coastguard Worker            src = readPixelRowBuffer.data();
1661*8975f5c5SAndroid Build Coastguard Worker            return angle::Result::Continue;
1662*8975f5c5SAndroid Build Coastguard Worker        },
1663*8975f5c5SAndroid Build Coastguard Worker        pixels);
1664*8975f5c5SAndroid Build Coastguard Worker}
1665*8975f5c5SAndroid Build Coastguard Worker
1666*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::readPixelsToPBO(const gl::Context *context,
1667*8975f5c5SAndroid Build Coastguard Worker                                              const gl::Rectangle &area,
1668*8975f5c5SAndroid Build Coastguard Worker                                              const PackPixelsParams &packPixelsParams,
1669*8975f5c5SAndroid Build Coastguard Worker                                              const RenderTargetMtl *renderTarget) const
1670*8975f5c5SAndroid Build Coastguard Worker{
1671*8975f5c5SAndroid Build Coastguard Worker    ASSERT(packPixelsParams.packBuffer);
1672*8975f5c5SAndroid Build Coastguard Worker    ASSERT(renderTarget);
1673*8975f5c5SAndroid Build Coastguard Worker
1674*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
1675*8975f5c5SAndroid Build Coastguard Worker
1676*8975f5c5SAndroid Build Coastguard Worker    ANGLE_MTL_CHECK(contextMtl, packPixelsParams.offset <= std::numeric_limits<uint32_t>::max(),
1677*8975f5c5SAndroid Build Coastguard Worker                    GL_INVALID_OPERATION);
1678*8975f5c5SAndroid Build Coastguard Worker    uint32_t offset = static_cast<uint32_t>(packPixelsParams.offset);
1679*8975f5c5SAndroid Build Coastguard Worker
1680*8975f5c5SAndroid Build Coastguard Worker    BufferMtl *packBufferMtl = mtl::GetImpl(packPixelsParams.packBuffer);
1681*8975f5c5SAndroid Build Coastguard Worker    mtl::BufferRef dstBuffer = packBufferMtl->getCurrentBuffer();
1682*8975f5c5SAndroid Build Coastguard Worker
1683*8975f5c5SAndroid Build Coastguard Worker    return readPixelsToBuffer(context, area, renderTarget, packPixelsParams.reverseRowOrder,
1684*8975f5c5SAndroid Build Coastguard Worker                              *packPixelsParams.destFormat, offset, packPixelsParams.outputPitch,
1685*8975f5c5SAndroid Build Coastguard Worker                              &dstBuffer);
1686*8975f5c5SAndroid Build Coastguard Worker}
1687*8975f5c5SAndroid Build Coastguard Worker
1688*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::readPixelsToBuffer(const gl::Context *context,
1689*8975f5c5SAndroid Build Coastguard Worker                                                 const gl::Rectangle &area,
1690*8975f5c5SAndroid Build Coastguard Worker                                                 const RenderTargetMtl *renderTarget,
1691*8975f5c5SAndroid Build Coastguard Worker                                                 bool reverseRowOrder,
1692*8975f5c5SAndroid Build Coastguard Worker                                                 const angle::Format &dstAngleFormat,
1693*8975f5c5SAndroid Build Coastguard Worker                                                 uint32_t dstBufferOffset,
1694*8975f5c5SAndroid Build Coastguard Worker                                                 uint32_t dstBufferRowPitch,
1695*8975f5c5SAndroid Build Coastguard Worker                                                 const mtl::BufferRef *pDstBuffer) const
1696*8975f5c5SAndroid Build Coastguard Worker{
1697*8975f5c5SAndroid Build Coastguard Worker    ASSERT(renderTarget);
1698*8975f5c5SAndroid Build Coastguard Worker
1699*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
1700*8975f5c5SAndroid Build Coastguard Worker
1701*8975f5c5SAndroid Build Coastguard Worker    const mtl::Format &readFormat        = renderTarget->getFormat();
1702*8975f5c5SAndroid Build Coastguard Worker    const angle::Format &readAngleFormat = readFormat.actualAngleFormat();
1703*8975f5c5SAndroid Build Coastguard Worker
1704*8975f5c5SAndroid Build Coastguard Worker    mtl::TextureRef texture = renderTarget->getTexture();
1705*8975f5c5SAndroid Build Coastguard Worker
1706*8975f5c5SAndroid Build Coastguard Worker    const mtl::BufferRef &dstBuffer = *pDstBuffer;
1707*8975f5c5SAndroid Build Coastguard Worker
1708*8975f5c5SAndroid Build Coastguard Worker    if (dstAngleFormat.id != readAngleFormat.id || texture->samples() > 1 ||
1709*8975f5c5SAndroid Build Coastguard Worker        (dstBufferOffset % dstAngleFormat.pixelBytes) ||
1710*8975f5c5SAndroid Build Coastguard Worker        (dstBufferOffset % mtl::kTextureToBufferBlittingAlignment) ||
1711*8975f5c5SAndroid Build Coastguard Worker        (dstBufferRowPitch < area.width * dstAngleFormat.pixelBytes))
1712*8975f5c5SAndroid Build Coastguard Worker    {
1713*8975f5c5SAndroid Build Coastguard Worker        const angle::Format *actualDstAngleFormat;
1714*8975f5c5SAndroid Build Coastguard Worker
1715*8975f5c5SAndroid Build Coastguard Worker        // SRGB is special case: We need to write sRGB values to buffer, not linear values.
1716*8975f5c5SAndroid Build Coastguard Worker        switch (readAngleFormat.id)
1717*8975f5c5SAndroid Build Coastguard Worker        {
1718*8975f5c5SAndroid Build Coastguard Worker            case angle::FormatID::B8G8R8A8_UNORM_SRGB:
1719*8975f5c5SAndroid Build Coastguard Worker            case angle::FormatID::R8G8B8_UNORM_SRGB:
1720*8975f5c5SAndroid Build Coastguard Worker            case angle::FormatID::R8G8B8A8_UNORM_SRGB:
1721*8975f5c5SAndroid Build Coastguard Worker                if (dstAngleFormat.id != readAngleFormat.id)
1722*8975f5c5SAndroid Build Coastguard Worker                {
1723*8975f5c5SAndroid Build Coastguard Worker                    switch (dstAngleFormat.id)
1724*8975f5c5SAndroid Build Coastguard Worker                    {
1725*8975f5c5SAndroid Build Coastguard Worker                        case angle::FormatID::B8G8R8A8_UNORM:
1726*8975f5c5SAndroid Build Coastguard Worker                            actualDstAngleFormat =
1727*8975f5c5SAndroid Build Coastguard Worker                                &angle::Format::Get(angle::FormatID::B8G8R8A8_UNORM_SRGB);
1728*8975f5c5SAndroid Build Coastguard Worker                            break;
1729*8975f5c5SAndroid Build Coastguard Worker                        case angle::FormatID::R8G8B8A8_UNORM:
1730*8975f5c5SAndroid Build Coastguard Worker                            actualDstAngleFormat =
1731*8975f5c5SAndroid Build Coastguard Worker                                &angle::Format::Get(angle::FormatID::R8G8B8A8_UNORM_SRGB);
1732*8975f5c5SAndroid Build Coastguard Worker                            break;
1733*8975f5c5SAndroid Build Coastguard Worker                        default:
1734*8975f5c5SAndroid Build Coastguard Worker                            // Unsupported format.
1735*8975f5c5SAndroid Build Coastguard Worker                            ANGLE_MTL_CHECK(contextMtl, false, GL_INVALID_ENUM);
1736*8975f5c5SAndroid Build Coastguard Worker                    }
1737*8975f5c5SAndroid Build Coastguard Worker                    break;
1738*8975f5c5SAndroid Build Coastguard Worker                }
1739*8975f5c5SAndroid Build Coastguard Worker                OS_FALLTHROUGH;
1740*8975f5c5SAndroid Build Coastguard Worker            default:
1741*8975f5c5SAndroid Build Coastguard Worker                actualDstAngleFormat = &dstAngleFormat;
1742*8975f5c5SAndroid Build Coastguard Worker        }
1743*8975f5c5SAndroid Build Coastguard Worker
1744*8975f5c5SAndroid Build Coastguard Worker        // Use compute shader
1745*8975f5c5SAndroid Build Coastguard Worker        mtl::CopyPixelsToBufferParams params;
1746*8975f5c5SAndroid Build Coastguard Worker        params.buffer            = dstBuffer;
1747*8975f5c5SAndroid Build Coastguard Worker        params.bufferStartOffset = dstBufferOffset;
1748*8975f5c5SAndroid Build Coastguard Worker        params.bufferRowPitch    = dstBufferRowPitch;
1749*8975f5c5SAndroid Build Coastguard Worker
1750*8975f5c5SAndroid Build Coastguard Worker        params.texture                = texture;
1751*8975f5c5SAndroid Build Coastguard Worker        params.textureArea            = area;
1752*8975f5c5SAndroid Build Coastguard Worker        params.textureLevel           = renderTarget->getLevelIndex();
1753*8975f5c5SAndroid Build Coastguard Worker        params.textureSliceOrDeph     = renderTarget->getLayerIndex();
1754*8975f5c5SAndroid Build Coastguard Worker        params.reverseTextureRowOrder = reverseRowOrder;
1755*8975f5c5SAndroid Build Coastguard Worker
1756*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(contextMtl->getDisplay()->getUtils().packPixelsFromTextureToBuffer(
1757*8975f5c5SAndroid Build Coastguard Worker            contextMtl, *actualDstAngleFormat, params));
1758*8975f5c5SAndroid Build Coastguard Worker    }
1759*8975f5c5SAndroid Build Coastguard Worker    else
1760*8975f5c5SAndroid Build Coastguard Worker    {
1761*8975f5c5SAndroid Build Coastguard Worker        // Use blit command encoder
1762*8975f5c5SAndroid Build Coastguard Worker        if (!reverseRowOrder)
1763*8975f5c5SAndroid Build Coastguard Worker        {
1764*8975f5c5SAndroid Build Coastguard Worker            ANGLE_TRY(mtl::ReadTexturePerSliceBytesToBuffer(
1765*8975f5c5SAndroid Build Coastguard Worker                context, texture, dstBufferRowPitch, area, renderTarget->getLevelIndex(),
1766*8975f5c5SAndroid Build Coastguard Worker                renderTarget->getLayerIndex(), dstBufferOffset, dstBuffer));
1767*8975f5c5SAndroid Build Coastguard Worker        }
1768*8975f5c5SAndroid Build Coastguard Worker        else
1769*8975f5c5SAndroid Build Coastguard Worker        {
1770*8975f5c5SAndroid Build Coastguard Worker            gl::Rectangle srcRowRegion(area.x, area.y, area.width, 1);
1771*8975f5c5SAndroid Build Coastguard Worker
1772*8975f5c5SAndroid Build Coastguard Worker            int startRow = area.y1() - 1;
1773*8975f5c5SAndroid Build Coastguard Worker
1774*8975f5c5SAndroid Build Coastguard Worker            uint32_t bufferRowOffset = dstBufferOffset;
1775*8975f5c5SAndroid Build Coastguard Worker            // Copy pixels row by row
1776*8975f5c5SAndroid Build Coastguard Worker            for (int r = startRow, copiedRows = 0; copiedRows < area.height;
1777*8975f5c5SAndroid Build Coastguard Worker                 ++copiedRows, --r, bufferRowOffset += dstBufferRowPitch)
1778*8975f5c5SAndroid Build Coastguard Worker            {
1779*8975f5c5SAndroid Build Coastguard Worker                srcRowRegion.y = r;
1780*8975f5c5SAndroid Build Coastguard Worker
1781*8975f5c5SAndroid Build Coastguard Worker                // Read the pixels data to the buffer's row
1782*8975f5c5SAndroid Build Coastguard Worker                ANGLE_TRY(mtl::ReadTexturePerSliceBytesToBuffer(
1783*8975f5c5SAndroid Build Coastguard Worker                    context, texture, dstBufferRowPitch, srcRowRegion,
1784*8975f5c5SAndroid Build Coastguard Worker                    renderTarget->getLevelIndex(), renderTarget->getLayerIndex(), bufferRowOffset,
1785*8975f5c5SAndroid Build Coastguard Worker                    dstBuffer));
1786*8975f5c5SAndroid Build Coastguard Worker            }
1787*8975f5c5SAndroid Build Coastguard Worker        }
1788*8975f5c5SAndroid Build Coastguard Worker    }
1789*8975f5c5SAndroid Build Coastguard Worker
1790*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
1791*8975f5c5SAndroid Build Coastguard Worker}
1792*8975f5c5SAndroid Build Coastguard Worker
1793*8975f5c5SAndroid Build Coastguard Workerangle::Result FramebufferMtl::unresolveIfNeeded(const gl::Context *context,
1794*8975f5c5SAndroid Build Coastguard Worker                                                mtl::RenderCommandEncoder *encoder)
1795*8975f5c5SAndroid Build Coastguard Worker{
1796*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
1797*8975f5c5SAndroid Build Coastguard Worker    DisplayMtl *display    = contextMtl->getDisplay();
1798*8975f5c5SAndroid Build Coastguard Worker
1799*8975f5c5SAndroid Build Coastguard Worker    const mtl::RenderPassDesc &renderPassDesc = encoder->renderPassDesc();
1800*8975f5c5SAndroid Build Coastguard Worker    const gl::Rectangle renderArea            = this->getCompleteRenderArea();
1801*8975f5c5SAndroid Build Coastguard Worker
1802*8975f5c5SAndroid Build Coastguard Worker    mtl::BlitParams baseParams;
1803*8975f5c5SAndroid Build Coastguard Worker    baseParams.dstTextureSize = gl::Extents(renderArea.width, renderArea.height, 1);
1804*8975f5c5SAndroid Build Coastguard Worker    baseParams.dstRect        = renderArea;
1805*8975f5c5SAndroid Build Coastguard Worker    baseParams.dstScissorRect = renderArea;
1806*8975f5c5SAndroid Build Coastguard Worker    baseParams.dstFlipY       = false;
1807*8975f5c5SAndroid Build Coastguard Worker
1808*8975f5c5SAndroid Build Coastguard Worker    baseParams.srcNormalizedCoords =
1809*8975f5c5SAndroid Build Coastguard Worker        mtl::NormalizedCoords(0, 0, renderArea.width, renderArea.height, renderArea);
1810*8975f5c5SAndroid Build Coastguard Worker
1811*8975f5c5SAndroid Build Coastguard Worker    baseParams.srcYFlipped = false;
1812*8975f5c5SAndroid Build Coastguard Worker    baseParams.unpackFlipX = false;
1813*8975f5c5SAndroid Build Coastguard Worker    baseParams.unpackFlipY = false;
1814*8975f5c5SAndroid Build Coastguard Worker
1815*8975f5c5SAndroid Build Coastguard Worker    // Unresolve any color attachment if the intended loadAction = MTLLoadActionLoad and the
1816*8975f5c5SAndroid Build Coastguard Worker    // respective MS texture is memoryless.
1817*8975f5c5SAndroid Build Coastguard Worker    mtl::ColorBlitParams colorBlitParams;
1818*8975f5c5SAndroid Build Coastguard Worker    colorBlitParams.BlitParams::operator=(baseParams);
1819*8975f5c5SAndroid Build Coastguard Worker    for (uint32_t colorIndexGL = 0; colorIndexGL < renderPassDesc.numColorAttachments;
1820*8975f5c5SAndroid Build Coastguard Worker         ++colorIndexGL)
1821*8975f5c5SAndroid Build Coastguard Worker    {
1822*8975f5c5SAndroid Build Coastguard Worker        const mtl::RenderPassColorAttachmentDesc &colorAttachment =
1823*8975f5c5SAndroid Build Coastguard Worker            renderPassDesc.colorAttachments[colorIndexGL];
1824*8975f5c5SAndroid Build Coastguard Worker
1825*8975f5c5SAndroid Build Coastguard Worker        if (colorAttachment.loadAction != MTLLoadActionLoad ||
1826*8975f5c5SAndroid Build Coastguard Worker            !colorAttachment.hasImplicitMSTexture() ||
1827*8975f5c5SAndroid Build Coastguard Worker            !colorAttachment.implicitMSTexture->shouldNotLoadStore())
1828*8975f5c5SAndroid Build Coastguard Worker        {
1829*8975f5c5SAndroid Build Coastguard Worker            continue;
1830*8975f5c5SAndroid Build Coastguard Worker        }
1831*8975f5c5SAndroid Build Coastguard Worker        const RenderTargetMtl *colorRenderTarget = mColorRenderTargets[colorIndexGL];
1832*8975f5c5SAndroid Build Coastguard Worker        const angle::Format &angleFormat = colorRenderTarget->getFormat().actualAngleFormat();
1833*8975f5c5SAndroid Build Coastguard Worker
1834*8975f5c5SAndroid Build Coastguard Worker        // Blit the resolve texture to the MS texture.
1835*8975f5c5SAndroid Build Coastguard Worker        colorBlitParams.src      = colorAttachment.texture;
1836*8975f5c5SAndroid Build Coastguard Worker        colorBlitParams.srcLevel = colorAttachment.level;
1837*8975f5c5SAndroid Build Coastguard Worker        colorBlitParams.srcLayer = colorAttachment.sliceOrDepth;
1838*8975f5c5SAndroid Build Coastguard Worker
1839*8975f5c5SAndroid Build Coastguard Worker        colorBlitParams.enabledBuffers.reset();
1840*8975f5c5SAndroid Build Coastguard Worker        colorBlitParams.enabledBuffers.set(colorIndexGL);
1841*8975f5c5SAndroid Build Coastguard Worker        colorBlitParams.filter       = GL_NEAREST;
1842*8975f5c5SAndroid Build Coastguard Worker        colorBlitParams.dstLuminance = angleFormat.isLUMA();
1843*8975f5c5SAndroid Build Coastguard Worker
1844*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(
1845*8975f5c5SAndroid Build Coastguard Worker            display->getUtils().blitColorWithDraw(context, encoder, angleFormat, colorBlitParams));
1846*8975f5c5SAndroid Build Coastguard Worker    }
1847*8975f5c5SAndroid Build Coastguard Worker
1848*8975f5c5SAndroid Build Coastguard Worker    // Similarly, unresolve depth/stencil attachments.
1849*8975f5c5SAndroid Build Coastguard Worker    mtl::DepthStencilBlitParams dsBlitParams;
1850*8975f5c5SAndroid Build Coastguard Worker    dsBlitParams.BlitParams::operator=(baseParams);
1851*8975f5c5SAndroid Build Coastguard Worker    const mtl::RenderPassDepthAttachmentDesc &depthAttachment = renderPassDesc.depthAttachment;
1852*8975f5c5SAndroid Build Coastguard Worker    if (depthAttachment.loadAction == MTLLoadActionLoad && depthAttachment.hasImplicitMSTexture() &&
1853*8975f5c5SAndroid Build Coastguard Worker        depthAttachment.implicitMSTexture->shouldNotLoadStore())
1854*8975f5c5SAndroid Build Coastguard Worker    {
1855*8975f5c5SAndroid Build Coastguard Worker        dsBlitParams.src      = depthAttachment.texture;
1856*8975f5c5SAndroid Build Coastguard Worker        dsBlitParams.srcLevel = depthAttachment.level;
1857*8975f5c5SAndroid Build Coastguard Worker        dsBlitParams.srcLayer = depthAttachment.sliceOrDepth;
1858*8975f5c5SAndroid Build Coastguard Worker    }
1859*8975f5c5SAndroid Build Coastguard Worker
1860*8975f5c5SAndroid Build Coastguard Worker    const mtl::RenderPassStencilAttachmentDesc &stencilAttachment =
1861*8975f5c5SAndroid Build Coastguard Worker        renderPassDesc.stencilAttachment;
1862*8975f5c5SAndroid Build Coastguard Worker    if (stencilAttachment.loadAction == MTLLoadActionLoad &&
1863*8975f5c5SAndroid Build Coastguard Worker        stencilAttachment.hasImplicitMSTexture() &&
1864*8975f5c5SAndroid Build Coastguard Worker        stencilAttachment.implicitMSTexture->shouldNotLoadStore())
1865*8975f5c5SAndroid Build Coastguard Worker    {
1866*8975f5c5SAndroid Build Coastguard Worker        if (mState.hasSeparateDepthAndStencilAttachments())
1867*8975f5c5SAndroid Build Coastguard Worker        {
1868*8975f5c5SAndroid Build Coastguard Worker            // Blit depth/stencil separately.
1869*8975f5c5SAndroid Build Coastguard Worker            ANGLE_TRY(contextMtl->getDisplay()->getUtils().blitDepthStencilWithDraw(
1870*8975f5c5SAndroid Build Coastguard Worker                context, encoder, dsBlitParams));
1871*8975f5c5SAndroid Build Coastguard Worker            dsBlitParams.src = nullptr;
1872*8975f5c5SAndroid Build Coastguard Worker        }
1873*8975f5c5SAndroid Build Coastguard Worker
1874*8975f5c5SAndroid Build Coastguard Worker        dsBlitParams.srcStencil = stencilAttachment.texture->getStencilView();
1875*8975f5c5SAndroid Build Coastguard Worker        dsBlitParams.srcLevel   = stencilAttachment.level;
1876*8975f5c5SAndroid Build Coastguard Worker        dsBlitParams.srcLayer   = stencilAttachment.sliceOrDepth;
1877*8975f5c5SAndroid Build Coastguard Worker    }
1878*8975f5c5SAndroid Build Coastguard Worker
1879*8975f5c5SAndroid Build Coastguard Worker    if (dsBlitParams.src || dsBlitParams.srcStencil)
1880*8975f5c5SAndroid Build Coastguard Worker    {
1881*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(contextMtl->getDisplay()->getUtils().blitDepthStencilWithDraw(context, encoder,
1882*8975f5c5SAndroid Build Coastguard Worker                                                                                dsBlitParams));
1883*8975f5c5SAndroid Build Coastguard Worker    }
1884*8975f5c5SAndroid Build Coastguard Worker
1885*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
1886*8975f5c5SAndroid Build Coastguard Worker}
1887*8975f5c5SAndroid Build Coastguard Worker
1888*8975f5c5SAndroid Build Coastguard Worker}  // namespace rx
1889