xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/metal/TextureMtl.mm (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker
2*8975f5c5SAndroid Build Coastguard Worker//
3*8975f5c5SAndroid Build Coastguard Worker// Copyright 2019 The ANGLE Project Authors. All rights reserved.
4*8975f5c5SAndroid Build Coastguard Worker// Use of this source code is governed by a BSD-style license that can be
5*8975f5c5SAndroid Build Coastguard Worker// found in the LICENSE file.
6*8975f5c5SAndroid Build Coastguard Worker//
7*8975f5c5SAndroid Build Coastguard Worker// TextureMtl.mm:
8*8975f5c5SAndroid Build Coastguard Worker//    Implements the class methods for TextureMtl.
9*8975f5c5SAndroid Build Coastguard Worker//
10*8975f5c5SAndroid Build Coastguard Worker
11*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/TextureMtl.h"
12*8975f5c5SAndroid Build Coastguard Worker
13*8975f5c5SAndroid Build Coastguard Worker#include <algorithm>
14*8975f5c5SAndroid Build Coastguard Worker#include <initializer_list>
15*8975f5c5SAndroid Build Coastguard Worker
16*8975f5c5SAndroid Build Coastguard Worker#include "common/Color.h"
17*8975f5c5SAndroid Build Coastguard Worker#include "common/MemoryBuffer.h"
18*8975f5c5SAndroid Build Coastguard Worker#include "common/debug.h"
19*8975f5c5SAndroid Build Coastguard Worker#include "common/mathutil.h"
20*8975f5c5SAndroid Build Coastguard Worker#include "image_util/imageformats.h"
21*8975f5c5SAndroid Build Coastguard Worker#include "image_util/loadimage.h"
22*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/Surface.h"
23*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/Format.h"
24*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/BufferMtl.h"
25*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/ContextMtl.h"
26*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/DisplayMtl.h"
27*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/FrameBufferMtl.h"
28*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/ImageMtl.h"
29*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/SamplerMtl.h"
30*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/SurfaceMtl.h"
31*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/mtl_common.h"
32*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/mtl_format_utils.h"
33*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/mtl_utils.h"
34*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/renderer_utils.h"
35*8975f5c5SAndroid Build Coastguard Worker
36*8975f5c5SAndroid Build Coastguard Workernamespace rx
37*8975f5c5SAndroid Build Coastguard Worker{
38*8975f5c5SAndroid Build Coastguard Worker
39*8975f5c5SAndroid Build Coastguard Workernamespace
40*8975f5c5SAndroid Build Coastguard Worker{
41*8975f5c5SAndroid Build Coastguard Worker
42*8975f5c5SAndroid Build Coastguard Workergl::ImageIndex GetZeroLevelIndex(const mtl::TextureRef &image)
43*8975f5c5SAndroid Build Coastguard Worker{
44*8975f5c5SAndroid Build Coastguard Worker    switch (image->textureType())
45*8975f5c5SAndroid Build Coastguard Worker    {
46*8975f5c5SAndroid Build Coastguard Worker        case MTLTextureType2D:
47*8975f5c5SAndroid Build Coastguard Worker            return gl::ImageIndex::Make2D(0);
48*8975f5c5SAndroid Build Coastguard Worker        case MTLTextureTypeCube:
49*8975f5c5SAndroid Build Coastguard Worker            return gl::ImageIndex::MakeFromType(gl::TextureType::CubeMap, 0);
50*8975f5c5SAndroid Build Coastguard Worker        case MTLTextureType2DArray:
51*8975f5c5SAndroid Build Coastguard Worker            return gl::ImageIndex::Make2DArray(0 /** entire layers */);
52*8975f5c5SAndroid Build Coastguard Worker        case MTLTextureType2DMultisample:
53*8975f5c5SAndroid Build Coastguard Worker            return gl::ImageIndex::Make2DMultisample();
54*8975f5c5SAndroid Build Coastguard Worker        case MTLTextureType3D:
55*8975f5c5SAndroid Build Coastguard Worker            return gl::ImageIndex::Make3D(0 /** entire layers */);
56*8975f5c5SAndroid Build Coastguard Worker        default:
57*8975f5c5SAndroid Build Coastguard Worker            UNREACHABLE();
58*8975f5c5SAndroid Build Coastguard Worker            break;
59*8975f5c5SAndroid Build Coastguard Worker    }
60*8975f5c5SAndroid Build Coastguard Worker
61*8975f5c5SAndroid Build Coastguard Worker    return gl::ImageIndex();
62*8975f5c5SAndroid Build Coastguard Worker}
63*8975f5c5SAndroid Build Coastguard Worker
64*8975f5c5SAndroid Build Coastguard Worker// Slice is ignored if texture type is not Cube or 2D array
65*8975f5c5SAndroid Build Coastguard Workergl::ImageIndex GetCubeOrArraySliceMipIndex(const mtl::TextureRef &image,
66*8975f5c5SAndroid Build Coastguard Worker                                           uint32_t slice,
67*8975f5c5SAndroid Build Coastguard Worker                                           uint32_t level)
68*8975f5c5SAndroid Build Coastguard Worker{
69*8975f5c5SAndroid Build Coastguard Worker    switch (image->textureType())
70*8975f5c5SAndroid Build Coastguard Worker    {
71*8975f5c5SAndroid Build Coastguard Worker        case MTLTextureType2D:
72*8975f5c5SAndroid Build Coastguard Worker            return gl::ImageIndex::Make2D(level);
73*8975f5c5SAndroid Build Coastguard Worker        case MTLTextureTypeCube:
74*8975f5c5SAndroid Build Coastguard Worker        {
75*8975f5c5SAndroid Build Coastguard Worker            auto cubeFace = static_cast<gl::TextureTarget>(
76*8975f5c5SAndroid Build Coastguard Worker                static_cast<int>(gl::TextureTarget::CubeMapPositiveX) + slice);
77*8975f5c5SAndroid Build Coastguard Worker            return gl::ImageIndex::MakeCubeMapFace(cubeFace, level);
78*8975f5c5SAndroid Build Coastguard Worker        }
79*8975f5c5SAndroid Build Coastguard Worker        case MTLTextureType2DArray:
80*8975f5c5SAndroid Build Coastguard Worker            return gl::ImageIndex::Make2DArray(level, slice);
81*8975f5c5SAndroid Build Coastguard Worker        case MTLTextureType2DMultisample:
82*8975f5c5SAndroid Build Coastguard Worker            return gl::ImageIndex::Make2DMultisample();
83*8975f5c5SAndroid Build Coastguard Worker        case MTLTextureType3D:
84*8975f5c5SAndroid Build Coastguard Worker            return gl::ImageIndex::Make3D(level);
85*8975f5c5SAndroid Build Coastguard Worker        default:
86*8975f5c5SAndroid Build Coastguard Worker            UNREACHABLE();
87*8975f5c5SAndroid Build Coastguard Worker            break;
88*8975f5c5SAndroid Build Coastguard Worker    }
89*8975f5c5SAndroid Build Coastguard Worker
90*8975f5c5SAndroid Build Coastguard Worker    return gl::ImageIndex();
91*8975f5c5SAndroid Build Coastguard Worker}
92*8975f5c5SAndroid Build Coastguard Worker
93*8975f5c5SAndroid Build Coastguard Worker// layer is ignored if texture type is not Cube or 2D array or 3D
94*8975f5c5SAndroid Build Coastguard Workergl::ImageIndex GetLayerMipIndex(const mtl::TextureRef &image, uint32_t layer, uint32_t level)
95*8975f5c5SAndroid Build Coastguard Worker{
96*8975f5c5SAndroid Build Coastguard Worker    switch (image->textureType())
97*8975f5c5SAndroid Build Coastguard Worker    {
98*8975f5c5SAndroid Build Coastguard Worker        case MTLTextureType2D:
99*8975f5c5SAndroid Build Coastguard Worker            return gl::ImageIndex::Make2D(level);
100*8975f5c5SAndroid Build Coastguard Worker        case MTLTextureTypeCube:
101*8975f5c5SAndroid Build Coastguard Worker        {
102*8975f5c5SAndroid Build Coastguard Worker            auto cubeFace = static_cast<gl::TextureTarget>(
103*8975f5c5SAndroid Build Coastguard Worker                static_cast<int>(gl::TextureTarget::CubeMapPositiveX) + layer);
104*8975f5c5SAndroid Build Coastguard Worker            return gl::ImageIndex::MakeCubeMapFace(cubeFace, level);
105*8975f5c5SAndroid Build Coastguard Worker        }
106*8975f5c5SAndroid Build Coastguard Worker        case MTLTextureType2DArray:
107*8975f5c5SAndroid Build Coastguard Worker            return gl::ImageIndex::Make2DArray(level, layer);
108*8975f5c5SAndroid Build Coastguard Worker        case MTLTextureType2DMultisample:
109*8975f5c5SAndroid Build Coastguard Worker            return gl::ImageIndex::Make2DMultisample();
110*8975f5c5SAndroid Build Coastguard Worker        case MTLTextureType3D:
111*8975f5c5SAndroid Build Coastguard Worker            return gl::ImageIndex::Make3D(level, layer);
112*8975f5c5SAndroid Build Coastguard Worker        default:
113*8975f5c5SAndroid Build Coastguard Worker            UNREACHABLE();
114*8975f5c5SAndroid Build Coastguard Worker            break;
115*8975f5c5SAndroid Build Coastguard Worker    }
116*8975f5c5SAndroid Build Coastguard Worker
117*8975f5c5SAndroid Build Coastguard Worker    return gl::ImageIndex();
118*8975f5c5SAndroid Build Coastguard Worker}
119*8975f5c5SAndroid Build Coastguard Worker
120*8975f5c5SAndroid Build Coastguard WorkerGLuint GetImageLayerIndexFrom(const gl::ImageIndex &index)
121*8975f5c5SAndroid Build Coastguard Worker{
122*8975f5c5SAndroid Build Coastguard Worker    switch (index.getType())
123*8975f5c5SAndroid Build Coastguard Worker    {
124*8975f5c5SAndroid Build Coastguard Worker        case gl::TextureType::_2D:
125*8975f5c5SAndroid Build Coastguard Worker        case gl::TextureType::_2DMultisample:
126*8975f5c5SAndroid Build Coastguard Worker        case gl::TextureType::Rectangle:
127*8975f5c5SAndroid Build Coastguard Worker            return 0;
128*8975f5c5SAndroid Build Coastguard Worker        case gl::TextureType::CubeMap:
129*8975f5c5SAndroid Build Coastguard Worker            return index.cubeMapFaceIndex();
130*8975f5c5SAndroid Build Coastguard Worker        case gl::TextureType::_2DArray:
131*8975f5c5SAndroid Build Coastguard Worker        case gl::TextureType::_3D:
132*8975f5c5SAndroid Build Coastguard Worker            return index.getLayerIndex();
133*8975f5c5SAndroid Build Coastguard Worker        default:
134*8975f5c5SAndroid Build Coastguard Worker            UNREACHABLE();
135*8975f5c5SAndroid Build Coastguard Worker    }
136*8975f5c5SAndroid Build Coastguard Worker
137*8975f5c5SAndroid Build Coastguard Worker    return 0;
138*8975f5c5SAndroid Build Coastguard Worker}
139*8975f5c5SAndroid Build Coastguard Worker
140*8975f5c5SAndroid Build Coastguard WorkerGLuint GetImageCubeFaceIndexOrZeroFrom(const gl::ImageIndex &index)
141*8975f5c5SAndroid Build Coastguard Worker{
142*8975f5c5SAndroid Build Coastguard Worker    switch (index.getType())
143*8975f5c5SAndroid Build Coastguard Worker    {
144*8975f5c5SAndroid Build Coastguard Worker        case gl::TextureType::CubeMap:
145*8975f5c5SAndroid Build Coastguard Worker            return index.cubeMapFaceIndex();
146*8975f5c5SAndroid Build Coastguard Worker        default:
147*8975f5c5SAndroid Build Coastguard Worker            break;
148*8975f5c5SAndroid Build Coastguard Worker    }
149*8975f5c5SAndroid Build Coastguard Worker
150*8975f5c5SAndroid Build Coastguard Worker    return 0;
151*8975f5c5SAndroid Build Coastguard Worker}
152*8975f5c5SAndroid Build Coastguard Worker
153*8975f5c5SAndroid Build Coastguard Worker// Given texture type, get texture type of one image for a glTexImage call.
154*8975f5c5SAndroid Build Coastguard Worker// For example, for texture 2d, one image is also texture 2d.
155*8975f5c5SAndroid Build Coastguard Worker// for texture cube, one image is texture 2d.
156*8975f5c5SAndroid Build Coastguard Workergl::TextureType GetTextureImageType(gl::TextureType texType)
157*8975f5c5SAndroid Build Coastguard Worker{
158*8975f5c5SAndroid Build Coastguard Worker    switch (texType)
159*8975f5c5SAndroid Build Coastguard Worker    {
160*8975f5c5SAndroid Build Coastguard Worker        case gl::TextureType::CubeMap:
161*8975f5c5SAndroid Build Coastguard Worker            return gl::TextureType::_2D;
162*8975f5c5SAndroid Build Coastguard Worker        case gl::TextureType::_2D:
163*8975f5c5SAndroid Build Coastguard Worker        case gl::TextureType::_2DArray:
164*8975f5c5SAndroid Build Coastguard Worker        case gl::TextureType::_2DMultisample:
165*8975f5c5SAndroid Build Coastguard Worker        case gl::TextureType::_3D:
166*8975f5c5SAndroid Build Coastguard Worker        case gl::TextureType::Rectangle:
167*8975f5c5SAndroid Build Coastguard Worker            return texType;
168*8975f5c5SAndroid Build Coastguard Worker        default:
169*8975f5c5SAndroid Build Coastguard Worker            UNREACHABLE();
170*8975f5c5SAndroid Build Coastguard Worker            return gl::TextureType::InvalidEnum;
171*8975f5c5SAndroid Build Coastguard Worker    }
172*8975f5c5SAndroid Build Coastguard Worker}
173*8975f5c5SAndroid Build Coastguard Worker
174*8975f5c5SAndroid Build Coastguard Worker// D24X8 by default writes depth data to high 24 bits of 32 bit integers. However, Metal separate
175*8975f5c5SAndroid Build Coastguard Worker// depth stencil blitting expects depth data to be in low 24 bits of the data.
176*8975f5c5SAndroid Build Coastguard Workervoid WriteDepthStencilToDepth24(const uint8_t *srcPtr, uint8_t *dstPtr)
177*8975f5c5SAndroid Build Coastguard Worker{
178*8975f5c5SAndroid Build Coastguard Worker    auto src = reinterpret_cast<const angle::DepthStencil *>(srcPtr);
179*8975f5c5SAndroid Build Coastguard Worker    auto dst = reinterpret_cast<uint32_t *>(dstPtr);
180*8975f5c5SAndroid Build Coastguard Worker    *dst     = gl::floatToNormalized<24, uint32_t>(static_cast<float>(src->depth));
181*8975f5c5SAndroid Build Coastguard Worker}
182*8975f5c5SAndroid Build Coastguard Worker
183*8975f5c5SAndroid Build Coastguard Workervoid CopyTextureData(const MTLSize &regionSize,
184*8975f5c5SAndroid Build Coastguard Worker                     size_t srcRowPitch,
185*8975f5c5SAndroid Build Coastguard Worker                     size_t src2DImageSize,
186*8975f5c5SAndroid Build Coastguard Worker                     const uint8_t *psrc,
187*8975f5c5SAndroid Build Coastguard Worker                     size_t destRowPitch,
188*8975f5c5SAndroid Build Coastguard Worker                     size_t dest2DImageSize,
189*8975f5c5SAndroid Build Coastguard Worker                     uint8_t *pdst)
190*8975f5c5SAndroid Build Coastguard Worker{
191*8975f5c5SAndroid Build Coastguard Worker    {
192*8975f5c5SAndroid Build Coastguard Worker        size_t rowCopySize = std::min(srcRowPitch, destRowPitch);
193*8975f5c5SAndroid Build Coastguard Worker        for (NSUInteger d = 0; d < regionSize.depth; ++d)
194*8975f5c5SAndroid Build Coastguard Worker        {
195*8975f5c5SAndroid Build Coastguard Worker            for (NSUInteger r = 0; r < regionSize.height; ++r)
196*8975f5c5SAndroid Build Coastguard Worker            {
197*8975f5c5SAndroid Build Coastguard Worker                const uint8_t *pCopySrc = psrc + d * src2DImageSize + r * srcRowPitch;
198*8975f5c5SAndroid Build Coastguard Worker                uint8_t *pCopyDst       = pdst + d * dest2DImageSize + r * destRowPitch;
199*8975f5c5SAndroid Build Coastguard Worker                memcpy(pCopyDst, pCopySrc, rowCopySize);
200*8975f5c5SAndroid Build Coastguard Worker            }
201*8975f5c5SAndroid Build Coastguard Worker        }
202*8975f5c5SAndroid Build Coastguard Worker    }
203*8975f5c5SAndroid Build Coastguard Worker}
204*8975f5c5SAndroid Build Coastguard Worker
205*8975f5c5SAndroid Build Coastguard Workervoid ConvertDepthStencilData(const MTLSize &regionSize,
206*8975f5c5SAndroid Build Coastguard Worker                             const angle::Format &srcAngleFormat,
207*8975f5c5SAndroid Build Coastguard Worker                             size_t srcRowPitch,
208*8975f5c5SAndroid Build Coastguard Worker                             size_t src2DImageSize,
209*8975f5c5SAndroid Build Coastguard Worker                             const uint8_t *psrc,
210*8975f5c5SAndroid Build Coastguard Worker                             const angle::Format &dstAngleFormat,
211*8975f5c5SAndroid Build Coastguard Worker                             rx::PixelWriteFunction pixelWriteFunctionOverride,
212*8975f5c5SAndroid Build Coastguard Worker                             size_t destRowPitch,
213*8975f5c5SAndroid Build Coastguard Worker                             size_t dest2DImageSize,
214*8975f5c5SAndroid Build Coastguard Worker                             uint8_t *pdst)
215*8975f5c5SAndroid Build Coastguard Worker{
216*8975f5c5SAndroid Build Coastguard Worker    if (srcAngleFormat.id == dstAngleFormat.id)
217*8975f5c5SAndroid Build Coastguard Worker    {
218*8975f5c5SAndroid Build Coastguard Worker        size_t rowCopySize = std::min(srcRowPitch, destRowPitch);
219*8975f5c5SAndroid Build Coastguard Worker        for (NSUInteger d = 0; d < regionSize.depth; ++d)
220*8975f5c5SAndroid Build Coastguard Worker        {
221*8975f5c5SAndroid Build Coastguard Worker            for (NSUInteger r = 0; r < regionSize.height; ++r)
222*8975f5c5SAndroid Build Coastguard Worker            {
223*8975f5c5SAndroid Build Coastguard Worker                const uint8_t *pCopySrc = psrc + d * src2DImageSize + r * srcRowPitch;
224*8975f5c5SAndroid Build Coastguard Worker                uint8_t *pCopyDst       = pdst + d * dest2DImageSize + r * destRowPitch;
225*8975f5c5SAndroid Build Coastguard Worker                memcpy(pCopyDst, pCopySrc, rowCopySize);
226*8975f5c5SAndroid Build Coastguard Worker            }
227*8975f5c5SAndroid Build Coastguard Worker        }
228*8975f5c5SAndroid Build Coastguard Worker    }
229*8975f5c5SAndroid Build Coastguard Worker    else
230*8975f5c5SAndroid Build Coastguard Worker    {
231*8975f5c5SAndroid Build Coastguard Worker        rx::PixelWriteFunction pixelWriteFunction = pixelWriteFunctionOverride
232*8975f5c5SAndroid Build Coastguard Worker                                                        ? pixelWriteFunctionOverride
233*8975f5c5SAndroid Build Coastguard Worker                                                        : dstAngleFormat.pixelWriteFunction;
234*8975f5c5SAndroid Build Coastguard Worker        // This is only for depth & stencil case.
235*8975f5c5SAndroid Build Coastguard Worker        ASSERT(srcAngleFormat.depthBits || srcAngleFormat.stencilBits);
236*8975f5c5SAndroid Build Coastguard Worker        ASSERT(srcAngleFormat.pixelReadFunction && pixelWriteFunction);
237*8975f5c5SAndroid Build Coastguard Worker
238*8975f5c5SAndroid Build Coastguard Worker        // cache to store read result of source pixel
239*8975f5c5SAndroid Build Coastguard Worker        angle::DepthStencil depthStencilData;
240*8975f5c5SAndroid Build Coastguard Worker        auto sourcePixelReadData = reinterpret_cast<uint8_t *>(&depthStencilData);
241*8975f5c5SAndroid Build Coastguard Worker        ASSERT(srcAngleFormat.pixelBytes <= sizeof(depthStencilData));
242*8975f5c5SAndroid Build Coastguard Worker
243*8975f5c5SAndroid Build Coastguard Worker        for (NSUInteger d = 0; d < regionSize.depth; ++d)
244*8975f5c5SAndroid Build Coastguard Worker        {
245*8975f5c5SAndroid Build Coastguard Worker            for (NSUInteger r = 0; r < regionSize.height; ++r)
246*8975f5c5SAndroid Build Coastguard Worker            {
247*8975f5c5SAndroid Build Coastguard Worker                for (NSUInteger c = 0; c < regionSize.width; ++c)
248*8975f5c5SAndroid Build Coastguard Worker                {
249*8975f5c5SAndroid Build Coastguard Worker                    const uint8_t *sourcePixelData =
250*8975f5c5SAndroid Build Coastguard Worker                        psrc + d * src2DImageSize + r * srcRowPitch + c * srcAngleFormat.pixelBytes;
251*8975f5c5SAndroid Build Coastguard Worker
252*8975f5c5SAndroid Build Coastguard Worker                    uint8_t *destPixelData = pdst + d * dest2DImageSize + r * destRowPitch +
253*8975f5c5SAndroid Build Coastguard Worker                                             c * dstAngleFormat.pixelBytes;
254*8975f5c5SAndroid Build Coastguard Worker
255*8975f5c5SAndroid Build Coastguard Worker                    srcAngleFormat.pixelReadFunction(sourcePixelData, sourcePixelReadData);
256*8975f5c5SAndroid Build Coastguard Worker                    pixelWriteFunction(sourcePixelReadData, destPixelData);
257*8975f5c5SAndroid Build Coastguard Worker                }
258*8975f5c5SAndroid Build Coastguard Worker            }
259*8975f5c5SAndroid Build Coastguard Worker        }
260*8975f5c5SAndroid Build Coastguard Worker    }
261*8975f5c5SAndroid Build Coastguard Worker}
262*8975f5c5SAndroid Build Coastguard Worker
263*8975f5c5SAndroid Build Coastguard Workermtl::BlitCommandEncoder *GetBlitCommandEncoderForResources(
264*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl,
265*8975f5c5SAndroid Build Coastguard Worker    const std::initializer_list<const mtl::Resource *> &resources)
266*8975f5c5SAndroid Build Coastguard Worker{
267*8975f5c5SAndroid Build Coastguard Worker    if (std::none_of(resources.begin(), resources.end(), [contextMtl](const mtl::Resource *res) {
268*8975f5c5SAndroid Build Coastguard Worker            return res->hasPendingRenderWorks(contextMtl);
269*8975f5c5SAndroid Build Coastguard Worker        }))
270*8975f5c5SAndroid Build Coastguard Worker    {
271*8975f5c5SAndroid Build Coastguard Worker        // If no resource has pending render works waiting to be submitted, then it's safe to
272*8975f5c5SAndroid Build Coastguard Worker        // create a blit encoder without ending current render pass. The blit commands
273*8975f5c5SAndroid Build Coastguard Worker        // will run before any pending render commands.
274*8975f5c5SAndroid Build Coastguard Worker        return contextMtl->getBlitCommandEncoderWithoutEndingRenderEncoder();
275*8975f5c5SAndroid Build Coastguard Worker    }
276*8975f5c5SAndroid Build Coastguard Worker    return contextMtl->getBlitCommandEncoder();
277*8975f5c5SAndroid Build Coastguard Worker}
278*8975f5c5SAndroid Build Coastguard Worker
279*8975f5c5SAndroid Build Coastguard Workerangle::Result CopyDepthStencilTextureContentsToStagingBuffer(
280*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl,
281*8975f5c5SAndroid Build Coastguard Worker    const angle::Format &textureAngleFormat,
282*8975f5c5SAndroid Build Coastguard Worker    const angle::Format &stagingAngleFormat,
283*8975f5c5SAndroid Build Coastguard Worker    rx::PixelWriteFunction pixelWriteFunctionOverride,
284*8975f5c5SAndroid Build Coastguard Worker    const MTLSize &regionSize,
285*8975f5c5SAndroid Build Coastguard Worker    const uint8_t *data,
286*8975f5c5SAndroid Build Coastguard Worker    size_t bytesPerRow,
287*8975f5c5SAndroid Build Coastguard Worker    size_t bytesPer2DImage,
288*8975f5c5SAndroid Build Coastguard Worker    size_t *bufferRowPitchOut,
289*8975f5c5SAndroid Build Coastguard Worker    size_t *buffer2DImageSizeOut,
290*8975f5c5SAndroid Build Coastguard Worker    mtl::BufferRef *bufferOut)
291*8975f5c5SAndroid Build Coastguard Worker{
292*8975f5c5SAndroid Build Coastguard Worker    size_t stagingBufferRowPitch    = regionSize.width * stagingAngleFormat.pixelBytes;
293*8975f5c5SAndroid Build Coastguard Worker    size_t stagingBuffer2DImageSize = stagingBufferRowPitch * regionSize.height;
294*8975f5c5SAndroid Build Coastguard Worker    size_t stagingBufferSize        = stagingBuffer2DImageSize * regionSize.depth;
295*8975f5c5SAndroid Build Coastguard Worker    mtl::BufferRef stagingBuffer;
296*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(mtl::Buffer::MakeBuffer(contextMtl, stagingBufferSize, nullptr, &stagingBuffer));
297*8975f5c5SAndroid Build Coastguard Worker
298*8975f5c5SAndroid Build Coastguard Worker    uint8_t *pdst = stagingBuffer->map(contextMtl);
299*8975f5c5SAndroid Build Coastguard Worker
300*8975f5c5SAndroid Build Coastguard Worker    ConvertDepthStencilData(regionSize, textureAngleFormat, bytesPerRow, bytesPer2DImage, data,
301*8975f5c5SAndroid Build Coastguard Worker                            stagingAngleFormat, pixelWriteFunctionOverride, stagingBufferRowPitch,
302*8975f5c5SAndroid Build Coastguard Worker                            stagingBuffer2DImageSize, pdst);
303*8975f5c5SAndroid Build Coastguard Worker
304*8975f5c5SAndroid Build Coastguard Worker    stagingBuffer->unmap(contextMtl);
305*8975f5c5SAndroid Build Coastguard Worker
306*8975f5c5SAndroid Build Coastguard Worker    *bufferOut            = stagingBuffer;
307*8975f5c5SAndroid Build Coastguard Worker    *bufferRowPitchOut    = stagingBufferRowPitch;
308*8975f5c5SAndroid Build Coastguard Worker    *buffer2DImageSizeOut = stagingBuffer2DImageSize;
309*8975f5c5SAndroid Build Coastguard Worker
310*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
311*8975f5c5SAndroid Build Coastguard Worker}
312*8975f5c5SAndroid Build Coastguard Worker
313*8975f5c5SAndroid Build Coastguard Workerangle::Result CopyTextureContentsToStagingBuffer(ContextMtl *contextMtl,
314*8975f5c5SAndroid Build Coastguard Worker                                                 const angle::Format &textureAngleFormat,
315*8975f5c5SAndroid Build Coastguard Worker                                                 const MTLSize &regionSize,
316*8975f5c5SAndroid Build Coastguard Worker                                                 const uint8_t *data,
317*8975f5c5SAndroid Build Coastguard Worker                                                 size_t bytesPerRow,
318*8975f5c5SAndroid Build Coastguard Worker                                                 size_t bytesPer2DImage,
319*8975f5c5SAndroid Build Coastguard Worker                                                 size_t *bufferRowPitchOut,
320*8975f5c5SAndroid Build Coastguard Worker                                                 size_t *buffer2DImageSizeOut,
321*8975f5c5SAndroid Build Coastguard Worker                                                 mtl::BufferRef *bufferOut)
322*8975f5c5SAndroid Build Coastguard Worker{
323*8975f5c5SAndroid Build Coastguard Worker    size_t stagingBufferRowPitch    = regionSize.width * textureAngleFormat.pixelBytes;
324*8975f5c5SAndroid Build Coastguard Worker    size_t stagingBuffer2DImageSize = stagingBufferRowPitch * regionSize.height;
325*8975f5c5SAndroid Build Coastguard Worker    size_t stagingBufferSize        = stagingBuffer2DImageSize * regionSize.depth;
326*8975f5c5SAndroid Build Coastguard Worker    mtl::BufferRef stagingBuffer;
327*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(mtl::Buffer::MakeBuffer(contextMtl, stagingBufferSize, nullptr, &stagingBuffer));
328*8975f5c5SAndroid Build Coastguard Worker
329*8975f5c5SAndroid Build Coastguard Worker    uint8_t *pdst = stagingBuffer->map(contextMtl);
330*8975f5c5SAndroid Build Coastguard Worker    CopyTextureData(regionSize, bytesPerRow, bytesPer2DImage, data, stagingBufferRowPitch,
331*8975f5c5SAndroid Build Coastguard Worker                    stagingBuffer2DImageSize, pdst);
332*8975f5c5SAndroid Build Coastguard Worker
333*8975f5c5SAndroid Build Coastguard Worker    stagingBuffer->unmap(contextMtl);
334*8975f5c5SAndroid Build Coastguard Worker
335*8975f5c5SAndroid Build Coastguard Worker    *bufferOut            = stagingBuffer;
336*8975f5c5SAndroid Build Coastguard Worker    *bufferRowPitchOut    = stagingBufferRowPitch;
337*8975f5c5SAndroid Build Coastguard Worker    *buffer2DImageSizeOut = stagingBuffer2DImageSize;
338*8975f5c5SAndroid Build Coastguard Worker
339*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
340*8975f5c5SAndroid Build Coastguard Worker}
341*8975f5c5SAndroid Build Coastguard Worker
342*8975f5c5SAndroid Build Coastguard Workerangle::Result CopyCompressedTextureContentsToStagingBuffer(ContextMtl *contextMtl,
343*8975f5c5SAndroid Build Coastguard Worker                                                           const angle::Format &textureAngleFormat,
344*8975f5c5SAndroid Build Coastguard Worker                                                           const MTLSize &regionSizeInBlocks,
345*8975f5c5SAndroid Build Coastguard Worker                                                           const uint8_t *data,
346*8975f5c5SAndroid Build Coastguard Worker                                                           size_t bytesPerBlockRow,
347*8975f5c5SAndroid Build Coastguard Worker                                                           size_t bytesPer2DImage,
348*8975f5c5SAndroid Build Coastguard Worker                                                           size_t *bufferRowPitchOut,
349*8975f5c5SAndroid Build Coastguard Worker                                                           size_t *buffer2DImageSizeOut,
350*8975f5c5SAndroid Build Coastguard Worker                                                           mtl::BufferRef *bufferOut)
351*8975f5c5SAndroid Build Coastguard Worker{
352*8975f5c5SAndroid Build Coastguard Worker    size_t stagingBufferRowPitch    = bytesPerBlockRow;
353*8975f5c5SAndroid Build Coastguard Worker    size_t stagingBuffer2DImageSize = bytesPer2DImage;
354*8975f5c5SAndroid Build Coastguard Worker    size_t stagingBufferSize        = stagingBuffer2DImageSize * regionSizeInBlocks.depth;
355*8975f5c5SAndroid Build Coastguard Worker    mtl::BufferRef stagingBuffer;
356*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(mtl::Buffer::MakeBuffer(contextMtl, stagingBufferSize, nullptr, &stagingBuffer));
357*8975f5c5SAndroid Build Coastguard Worker
358*8975f5c5SAndroid Build Coastguard Worker    uint8_t *pdst = stagingBuffer->map(contextMtl);
359*8975f5c5SAndroid Build Coastguard Worker    CopyTextureData(regionSizeInBlocks, bytesPerBlockRow, bytesPer2DImage, data,
360*8975f5c5SAndroid Build Coastguard Worker                    stagingBufferRowPitch, stagingBuffer2DImageSize, pdst);
361*8975f5c5SAndroid Build Coastguard Worker
362*8975f5c5SAndroid Build Coastguard Worker    stagingBuffer->unmap(contextMtl);
363*8975f5c5SAndroid Build Coastguard Worker
364*8975f5c5SAndroid Build Coastguard Worker    *bufferOut            = stagingBuffer;
365*8975f5c5SAndroid Build Coastguard Worker    *bufferRowPitchOut    = stagingBufferRowPitch;
366*8975f5c5SAndroid Build Coastguard Worker    *buffer2DImageSizeOut = stagingBuffer2DImageSize;
367*8975f5c5SAndroid Build Coastguard Worker
368*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
369*8975f5c5SAndroid Build Coastguard Worker}
370*8975f5c5SAndroid Build Coastguard Worker
371*8975f5c5SAndroid Build Coastguard Workerangle::Result SaturateDepth(ContextMtl *contextMtl,
372*8975f5c5SAndroid Build Coastguard Worker                            mtl::BufferRef srcBuffer,
373*8975f5c5SAndroid Build Coastguard Worker                            mtl::BufferRef dstBuffer,
374*8975f5c5SAndroid Build Coastguard Worker                            uint32_t srcBufferOffset,
375*8975f5c5SAndroid Build Coastguard Worker                            uint32_t srcPitch,
376*8975f5c5SAndroid Build Coastguard Worker                            MTLSize size)
377*8975f5c5SAndroid Build Coastguard Worker{
378*8975f5c5SAndroid Build Coastguard Worker    static_assert(gl::IMPLEMENTATION_MAX_2D_TEXTURE_SIZE <= UINT_MAX);
379*8975f5c5SAndroid Build Coastguard Worker    mtl::DepthSaturationParams params;
380*8975f5c5SAndroid Build Coastguard Worker    params.srcBuffer       = srcBuffer;
381*8975f5c5SAndroid Build Coastguard Worker    params.dstBuffer       = dstBuffer;
382*8975f5c5SAndroid Build Coastguard Worker    params.srcBufferOffset = srcBufferOffset;
383*8975f5c5SAndroid Build Coastguard Worker    params.dstWidth        = static_cast<uint32_t>(size.width);
384*8975f5c5SAndroid Build Coastguard Worker    params.dstHeight       = static_cast<uint32_t>(size.height);
385*8975f5c5SAndroid Build Coastguard Worker    params.srcPitch        = srcPitch;
386*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(contextMtl->getDisplay()->getUtils().saturateDepth(contextMtl, params));
387*8975f5c5SAndroid Build Coastguard Worker
388*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
389*8975f5c5SAndroid Build Coastguard Worker}
390*8975f5c5SAndroid Build Coastguard Worker
391*8975f5c5SAndroid Build Coastguard Worker// This will copy a buffer to:
392*8975f5c5SAndroid Build Coastguard Worker// - the respective level & slice of an original texture if the "dst" texture is a view.
393*8975f5c5SAndroid Build Coastguard Worker// - the "dst" texture if it is not a view.
394*8975f5c5SAndroid Build Coastguard Worker// Notes:
395*8975f5c5SAndroid Build Coastguard Worker// - dstSlice is a slice in the "dst" texture not original texture.
396*8975f5c5SAndroid Build Coastguard Worker// - dstLevel is a level in the "dst" texture not original texture.
397*8975f5c5SAndroid Build Coastguard Worker// This function is needed because some GPUs such as the ones having AMD Bronze driver
398*8975f5c5SAndroid Build Coastguard Worker// have a bug when copying a buffer to a view of a 3D texture.
399*8975f5c5SAndroid Build Coastguard Workervoid CopyBufferToOriginalTextureIfDstIsAView(ContextMtl *contextMtl,
400*8975f5c5SAndroid Build Coastguard Worker                                             mtl::BlitCommandEncoder *blitEncoder,
401*8975f5c5SAndroid Build Coastguard Worker                                             const mtl::BufferRef &src,
402*8975f5c5SAndroid Build Coastguard Worker                                             size_t srcOffset,
403*8975f5c5SAndroid Build Coastguard Worker                                             size_t srcBytesPerRow,
404*8975f5c5SAndroid Build Coastguard Worker                                             size_t srcBytesPerImage,
405*8975f5c5SAndroid Build Coastguard Worker                                             MTLSize srcSize,
406*8975f5c5SAndroid Build Coastguard Worker                                             const mtl::TextureRef &dst,
407*8975f5c5SAndroid Build Coastguard Worker                                             const uint32_t dstSlice,
408*8975f5c5SAndroid Build Coastguard Worker                                             const mtl::MipmapNativeLevel &dstLevel,
409*8975f5c5SAndroid Build Coastguard Worker                                             MTLOrigin dstOrigin,
410*8975f5c5SAndroid Build Coastguard Worker                                             MTLBlitOption blitOption)
411*8975f5c5SAndroid Build Coastguard Worker{
412*8975f5c5SAndroid Build Coastguard Worker    mtl::TextureRef correctedTexture      = dst;
413*8975f5c5SAndroid Build Coastguard Worker    mtl::MipmapNativeLevel correctedLevel = dstLevel;
414*8975f5c5SAndroid Build Coastguard Worker    uint32_t correctedSlice               = dstSlice;
415*8975f5c5SAndroid Build Coastguard Worker    // TODO(b/343734719): Simulator has bug in parentRelativeSlice() so skip this step
416*8975f5c5SAndroid Build Coastguard Worker    // on simulator.
417*8975f5c5SAndroid Build Coastguard Worker    if (!contextMtl->getDisplay()->isSimulator() && correctedTexture->parentTexture())
418*8975f5c5SAndroid Build Coastguard Worker    {
419*8975f5c5SAndroid Build Coastguard Worker        correctedLevel = correctedLevel + correctedTexture->parentRelativeLevel().get();
420*8975f5c5SAndroid Build Coastguard Worker        correctedSlice += correctedTexture->parentRelativeSlice();
421*8975f5c5SAndroid Build Coastguard Worker        correctedTexture = correctedTexture->parentTexture();
422*8975f5c5SAndroid Build Coastguard Worker    }
423*8975f5c5SAndroid Build Coastguard Worker
424*8975f5c5SAndroid Build Coastguard Worker    blitEncoder->copyBufferToTexture(src, srcOffset, srcBytesPerRow, srcBytesPerImage, srcSize,
425*8975f5c5SAndroid Build Coastguard Worker                                     correctedTexture, correctedSlice, correctedLevel, dstOrigin,
426*8975f5c5SAndroid Build Coastguard Worker                                     blitOption);
427*8975f5c5SAndroid Build Coastguard Worker}
428*8975f5c5SAndroid Build Coastguard Worker
429*8975f5c5SAndroid Build Coastguard Workerangle::Result UploadDepthStencilTextureContentsWithStagingBuffer(
430*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl,
431*8975f5c5SAndroid Build Coastguard Worker    const angle::Format &textureAngleFormat,
432*8975f5c5SAndroid Build Coastguard Worker    MTLRegion region,
433*8975f5c5SAndroid Build Coastguard Worker    const mtl::MipmapNativeLevel &mipmapLevel,
434*8975f5c5SAndroid Build Coastguard Worker    uint32_t slice,
435*8975f5c5SAndroid Build Coastguard Worker    const uint8_t *data,
436*8975f5c5SAndroid Build Coastguard Worker    size_t bytesPerRow,
437*8975f5c5SAndroid Build Coastguard Worker    size_t bytesPer2DImage,
438*8975f5c5SAndroid Build Coastguard Worker    const mtl::TextureRef &texture)
439*8975f5c5SAndroid Build Coastguard Worker{
440*8975f5c5SAndroid Build Coastguard Worker    ASSERT(texture && texture->valid());
441*8975f5c5SAndroid Build Coastguard Worker
442*8975f5c5SAndroid Build Coastguard Worker    ASSERT(!texture->isCPUAccessible());
443*8975f5c5SAndroid Build Coastguard Worker
444*8975f5c5SAndroid Build Coastguard Worker    ASSERT(!textureAngleFormat.depthBits || !textureAngleFormat.stencilBits);
445*8975f5c5SAndroid Build Coastguard Worker
446*8975f5c5SAndroid Build Coastguard Worker    // Depth and stencil textures cannot be of 3D type;
447*8975f5c5SAndroid Build Coastguard Worker    // arrays and cube maps must be uploaded per-slice.
448*8975f5c5SAndroid Build Coastguard Worker    ASSERT(region.size.depth == 1);
449*8975f5c5SAndroid Build Coastguard Worker
450*8975f5c5SAndroid Build Coastguard Worker    // Copy data to staging buffer
451*8975f5c5SAndroid Build Coastguard Worker    size_t stagingBufferRowPitch;
452*8975f5c5SAndroid Build Coastguard Worker    size_t stagingBuffer2DImageSize;
453*8975f5c5SAndroid Build Coastguard Worker    mtl::BufferRef stagingBuffer;
454*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(CopyDepthStencilTextureContentsToStagingBuffer(
455*8975f5c5SAndroid Build Coastguard Worker        contextMtl, textureAngleFormat, textureAngleFormat, textureAngleFormat.pixelWriteFunction,
456*8975f5c5SAndroid Build Coastguard Worker        region.size, data, bytesPerRow, bytesPer2DImage, &stagingBufferRowPitch,
457*8975f5c5SAndroid Build Coastguard Worker        &stagingBuffer2DImageSize, &stagingBuffer));
458*8975f5c5SAndroid Build Coastguard Worker
459*8975f5c5SAndroid Build Coastguard Worker    if (textureAngleFormat.id == angle::FormatID::D32_FLOAT)
460*8975f5c5SAndroid Build Coastguard Worker    {
461*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(SaturateDepth(contextMtl, stagingBuffer, stagingBuffer, 0,
462*8975f5c5SAndroid Build Coastguard Worker                                static_cast<uint32_t>(region.size.width), region.size));
463*8975f5c5SAndroid Build Coastguard Worker    }
464*8975f5c5SAndroid Build Coastguard Worker
465*8975f5c5SAndroid Build Coastguard Worker    // Copy staging buffer to texture.
466*8975f5c5SAndroid Build Coastguard Worker    mtl::BlitCommandEncoder *encoder =
467*8975f5c5SAndroid Build Coastguard Worker        GetBlitCommandEncoderForResources(contextMtl, {stagingBuffer.get(), texture.get()});
468*8975f5c5SAndroid Build Coastguard Worker
469*8975f5c5SAndroid Build Coastguard Worker    CopyBufferToOriginalTextureIfDstIsAView(
470*8975f5c5SAndroid Build Coastguard Worker        contextMtl, encoder, stagingBuffer, 0, stagingBufferRowPitch, stagingBuffer2DImageSize,
471*8975f5c5SAndroid Build Coastguard Worker        region.size, texture, slice, mipmapLevel, region.origin, MTLBlitOptionNone);
472*8975f5c5SAndroid Build Coastguard Worker
473*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
474*8975f5c5SAndroid Build Coastguard Worker}
475*8975f5c5SAndroid Build Coastguard Worker
476*8975f5c5SAndroid Build Coastguard Worker// Packed depth stencil upload using staging buffer
477*8975f5c5SAndroid Build Coastguard Workerangle::Result UploadPackedDepthStencilTextureContentsWithStagingBuffer(
478*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl,
479*8975f5c5SAndroid Build Coastguard Worker    const angle::Format &textureAngleFormat,
480*8975f5c5SAndroid Build Coastguard Worker    MTLRegion region,
481*8975f5c5SAndroid Build Coastguard Worker    const mtl::MipmapNativeLevel &mipmapLevel,
482*8975f5c5SAndroid Build Coastguard Worker    uint32_t slice,
483*8975f5c5SAndroid Build Coastguard Worker    const uint8_t *data,
484*8975f5c5SAndroid Build Coastguard Worker    size_t bytesPerRow,
485*8975f5c5SAndroid Build Coastguard Worker    size_t bytesPer2DImage,
486*8975f5c5SAndroid Build Coastguard Worker    const mtl::TextureRef &texture)
487*8975f5c5SAndroid Build Coastguard Worker{
488*8975f5c5SAndroid Build Coastguard Worker    ASSERT(texture && texture->valid());
489*8975f5c5SAndroid Build Coastguard Worker
490*8975f5c5SAndroid Build Coastguard Worker    ASSERT(!texture->isCPUAccessible());
491*8975f5c5SAndroid Build Coastguard Worker
492*8975f5c5SAndroid Build Coastguard Worker    ASSERT(textureAngleFormat.depthBits && textureAngleFormat.stencilBits);
493*8975f5c5SAndroid Build Coastguard Worker
494*8975f5c5SAndroid Build Coastguard Worker    // Depth and stencil textures cannot be of 3D type;
495*8975f5c5SAndroid Build Coastguard Worker    // arrays and cube maps must be uploaded per-slice.
496*8975f5c5SAndroid Build Coastguard Worker    ASSERT(region.size.depth == 1);
497*8975f5c5SAndroid Build Coastguard Worker
498*8975f5c5SAndroid Build Coastguard Worker    // We have to split the depth & stencil data into 2 buffers.
499*8975f5c5SAndroid Build Coastguard Worker    angle::FormatID stagingDepthBufferFormatId;
500*8975f5c5SAndroid Build Coastguard Worker    angle::FormatID stagingStencilBufferFormatId;
501*8975f5c5SAndroid Build Coastguard Worker    // Custom depth write function. We cannot use those in imageformats.cpp since Metal has some
502*8975f5c5SAndroid Build Coastguard Worker    // special cases.
503*8975f5c5SAndroid Build Coastguard Worker    rx::PixelWriteFunction stagingDepthBufferWriteFunctionOverride = nullptr;
504*8975f5c5SAndroid Build Coastguard Worker
505*8975f5c5SAndroid Build Coastguard Worker    switch (textureAngleFormat.id)
506*8975f5c5SAndroid Build Coastguard Worker    {
507*8975f5c5SAndroid Build Coastguard Worker        case angle::FormatID::D24_UNORM_S8_UINT:
508*8975f5c5SAndroid Build Coastguard Worker            // D24_UNORM_X8_UINT writes depth data to high 24 bits. But Metal expects depth data to
509*8975f5c5SAndroid Build Coastguard Worker            // be in low 24 bits.
510*8975f5c5SAndroid Build Coastguard Worker            stagingDepthBufferFormatId              = angle::FormatID::D24_UNORM_X8_UINT;
511*8975f5c5SAndroid Build Coastguard Worker            stagingDepthBufferWriteFunctionOverride = WriteDepthStencilToDepth24;
512*8975f5c5SAndroid Build Coastguard Worker            stagingStencilBufferFormatId            = angle::FormatID::S8_UINT;
513*8975f5c5SAndroid Build Coastguard Worker            break;
514*8975f5c5SAndroid Build Coastguard Worker        case angle::FormatID::D32_FLOAT_S8X24_UINT:
515*8975f5c5SAndroid Build Coastguard Worker            stagingDepthBufferFormatId   = angle::FormatID::D32_FLOAT;
516*8975f5c5SAndroid Build Coastguard Worker            stagingStencilBufferFormatId = angle::FormatID::S8_UINT;
517*8975f5c5SAndroid Build Coastguard Worker            break;
518*8975f5c5SAndroid Build Coastguard Worker        default:
519*8975f5c5SAndroid Build Coastguard Worker            ANGLE_MTL_UNREACHABLE(contextMtl);
520*8975f5c5SAndroid Build Coastguard Worker    }
521*8975f5c5SAndroid Build Coastguard Worker
522*8975f5c5SAndroid Build Coastguard Worker    const angle::Format &angleStagingDepthFormat = angle::Format::Get(stagingDepthBufferFormatId);
523*8975f5c5SAndroid Build Coastguard Worker    const angle::Format &angleStagingStencilFormat =
524*8975f5c5SAndroid Build Coastguard Worker        angle::Format::Get(stagingStencilBufferFormatId);
525*8975f5c5SAndroid Build Coastguard Worker
526*8975f5c5SAndroid Build Coastguard Worker    size_t stagingDepthBufferRowPitch, stagingStencilBufferRowPitch;
527*8975f5c5SAndroid Build Coastguard Worker    size_t stagingDepthBuffer2DImageSize, stagingStencilBuffer2DImageSize;
528*8975f5c5SAndroid Build Coastguard Worker    mtl::BufferRef stagingDepthBuffer, stagingStencilBuffer;
529*8975f5c5SAndroid Build Coastguard Worker
530*8975f5c5SAndroid Build Coastguard Worker    // Copy depth data to staging depth buffer
531*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(CopyDepthStencilTextureContentsToStagingBuffer(
532*8975f5c5SAndroid Build Coastguard Worker        contextMtl, textureAngleFormat, angleStagingDepthFormat,
533*8975f5c5SAndroid Build Coastguard Worker        stagingDepthBufferWriteFunctionOverride, region.size, data, bytesPerRow, bytesPer2DImage,
534*8975f5c5SAndroid Build Coastguard Worker        &stagingDepthBufferRowPitch, &stagingDepthBuffer2DImageSize, &stagingDepthBuffer));
535*8975f5c5SAndroid Build Coastguard Worker
536*8975f5c5SAndroid Build Coastguard Worker    // Copy stencil data to staging stencil buffer
537*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(CopyDepthStencilTextureContentsToStagingBuffer(
538*8975f5c5SAndroid Build Coastguard Worker        contextMtl, textureAngleFormat, angleStagingStencilFormat, nullptr, region.size, data,
539*8975f5c5SAndroid Build Coastguard Worker        bytesPerRow, bytesPer2DImage, &stagingStencilBufferRowPitch,
540*8975f5c5SAndroid Build Coastguard Worker        &stagingStencilBuffer2DImageSize, &stagingStencilBuffer));
541*8975f5c5SAndroid Build Coastguard Worker
542*8975f5c5SAndroid Build Coastguard Worker    if (angleStagingDepthFormat.id == angle::FormatID::D32_FLOAT)
543*8975f5c5SAndroid Build Coastguard Worker    {
544*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(SaturateDepth(contextMtl, stagingDepthBuffer, stagingDepthBuffer, 0,
545*8975f5c5SAndroid Build Coastguard Worker                                static_cast<uint32_t>(region.size.width), region.size));
546*8975f5c5SAndroid Build Coastguard Worker    }
547*8975f5c5SAndroid Build Coastguard Worker
548*8975f5c5SAndroid Build Coastguard Worker    mtl::BlitCommandEncoder *encoder = GetBlitCommandEncoderForResources(
549*8975f5c5SAndroid Build Coastguard Worker        contextMtl, {stagingDepthBuffer.get(), stagingStencilBuffer.get(), texture.get()});
550*8975f5c5SAndroid Build Coastguard Worker
551*8975f5c5SAndroid Build Coastguard Worker    CopyBufferToOriginalTextureIfDstIsAView(
552*8975f5c5SAndroid Build Coastguard Worker        contextMtl, encoder, stagingDepthBuffer, 0, stagingDepthBufferRowPitch,
553*8975f5c5SAndroid Build Coastguard Worker        stagingDepthBuffer2DImageSize, region.size, texture, slice, mipmapLevel, region.origin,
554*8975f5c5SAndroid Build Coastguard Worker        MTLBlitOptionDepthFromDepthStencil);
555*8975f5c5SAndroid Build Coastguard Worker    CopyBufferToOriginalTextureIfDstIsAView(
556*8975f5c5SAndroid Build Coastguard Worker        contextMtl, encoder, stagingStencilBuffer, 0, stagingStencilBufferRowPitch,
557*8975f5c5SAndroid Build Coastguard Worker        stagingStencilBuffer2DImageSize, region.size, texture, slice, mipmapLevel, region.origin,
558*8975f5c5SAndroid Build Coastguard Worker        MTLBlitOptionStencilFromDepthStencil);
559*8975f5c5SAndroid Build Coastguard Worker
560*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
561*8975f5c5SAndroid Build Coastguard Worker}
562*8975f5c5SAndroid Build Coastguard Worker
563*8975f5c5SAndroid Build Coastguard Workerangle::Result UploadTextureContentsWithStagingBuffer(ContextMtl *contextMtl,
564*8975f5c5SAndroid Build Coastguard Worker                                                     const angle::Format &textureAngleFormat,
565*8975f5c5SAndroid Build Coastguard Worker                                                     MTLRegion region,
566*8975f5c5SAndroid Build Coastguard Worker                                                     const mtl::MipmapNativeLevel &mipmapLevel,
567*8975f5c5SAndroid Build Coastguard Worker                                                     uint32_t slice,
568*8975f5c5SAndroid Build Coastguard Worker                                                     const uint8_t *data,
569*8975f5c5SAndroid Build Coastguard Worker                                                     size_t bytesPerRow,
570*8975f5c5SAndroid Build Coastguard Worker                                                     size_t bytesPer2DImage,
571*8975f5c5SAndroid Build Coastguard Worker                                                     const mtl::TextureRef &texture)
572*8975f5c5SAndroid Build Coastguard Worker{
573*8975f5c5SAndroid Build Coastguard Worker    ASSERT(texture && texture->valid());
574*8975f5c5SAndroid Build Coastguard Worker
575*8975f5c5SAndroid Build Coastguard Worker    angle::FormatID stagingBufferFormatID   = textureAngleFormat.id;
576*8975f5c5SAndroid Build Coastguard Worker    const angle::Format &angleStagingFormat = angle::Format::Get(stagingBufferFormatID);
577*8975f5c5SAndroid Build Coastguard Worker
578*8975f5c5SAndroid Build Coastguard Worker    size_t stagingBufferRowPitch;
579*8975f5c5SAndroid Build Coastguard Worker    size_t stagingBuffer2DImageSize;
580*8975f5c5SAndroid Build Coastguard Worker    mtl::BufferRef stagingBuffer;
581*8975f5c5SAndroid Build Coastguard Worker
582*8975f5c5SAndroid Build Coastguard Worker    // Block-compressed formats need a bit of massaging for copy.
583*8975f5c5SAndroid Build Coastguard Worker    if (textureAngleFormat.isBlock)
584*8975f5c5SAndroid Build Coastguard Worker    {
585*8975f5c5SAndroid Build Coastguard Worker        GLenum internalFormat         = textureAngleFormat.glInternalFormat;
586*8975f5c5SAndroid Build Coastguard Worker        const gl::InternalFormat &fmt = gl::GetSizedInternalFormatInfo(internalFormat);
587*8975f5c5SAndroid Build Coastguard Worker        MTLRegion newRegion           = region;
588*8975f5c5SAndroid Build Coastguard Worker        bytesPerRow =
589*8975f5c5SAndroid Build Coastguard Worker            (region.size.width + fmt.compressedBlockWidth - 1) / fmt.compressedBlockWidth * 16;
590*8975f5c5SAndroid Build Coastguard Worker        bytesPer2DImage = (region.size.height + fmt.compressedBlockHeight - 1) /
591*8975f5c5SAndroid Build Coastguard Worker                          fmt.compressedBlockHeight * bytesPerRow;
592*8975f5c5SAndroid Build Coastguard Worker        newRegion.size.width =
593*8975f5c5SAndroid Build Coastguard Worker            (region.size.width + fmt.compressedBlockWidth - 1) / fmt.compressedBlockWidth;
594*8975f5c5SAndroid Build Coastguard Worker        newRegion.size.height =
595*8975f5c5SAndroid Build Coastguard Worker            (region.size.height + fmt.compressedBlockHeight - 1) / fmt.compressedBlockHeight;
596*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(CopyCompressedTextureContentsToStagingBuffer(
597*8975f5c5SAndroid Build Coastguard Worker            contextMtl, angleStagingFormat, newRegion.size, data, bytesPerRow, bytesPer2DImage,
598*8975f5c5SAndroid Build Coastguard Worker            &stagingBufferRowPitch, &stagingBuffer2DImageSize, &stagingBuffer));
599*8975f5c5SAndroid Build Coastguard Worker    }
600*8975f5c5SAndroid Build Coastguard Worker    // Copy to staging buffer before uploading to texture.
601*8975f5c5SAndroid Build Coastguard Worker    else
602*8975f5c5SAndroid Build Coastguard Worker    {
603*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(CopyTextureContentsToStagingBuffer(
604*8975f5c5SAndroid Build Coastguard Worker            contextMtl, angleStagingFormat, region.size, data, bytesPerRow, bytesPer2DImage,
605*8975f5c5SAndroid Build Coastguard Worker            &stagingBufferRowPitch, &stagingBuffer2DImageSize, &stagingBuffer));
606*8975f5c5SAndroid Build Coastguard Worker    }
607*8975f5c5SAndroid Build Coastguard Worker    mtl::BlitCommandEncoder *encoder =
608*8975f5c5SAndroid Build Coastguard Worker        GetBlitCommandEncoderForResources(contextMtl, {stagingBuffer.get(), texture.get()});
609*8975f5c5SAndroid Build Coastguard Worker
610*8975f5c5SAndroid Build Coastguard Worker    CopyBufferToOriginalTextureIfDstIsAView(
611*8975f5c5SAndroid Build Coastguard Worker        contextMtl, encoder, stagingBuffer, 0, stagingBufferRowPitch, stagingBuffer2DImageSize,
612*8975f5c5SAndroid Build Coastguard Worker        region.size, texture, slice, mipmapLevel, region.origin, 0);
613*8975f5c5SAndroid Build Coastguard Worker
614*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
615*8975f5c5SAndroid Build Coastguard Worker}
616*8975f5c5SAndroid Build Coastguard Worker
617*8975f5c5SAndroid Build Coastguard Workerangle::Result UploadTextureContents(const gl::Context *context,
618*8975f5c5SAndroid Build Coastguard Worker                                    const angle::Format &textureAngleFormat,
619*8975f5c5SAndroid Build Coastguard Worker                                    const MTLRegion &region,
620*8975f5c5SAndroid Build Coastguard Worker                                    const mtl::MipmapNativeLevel &mipmapLevel,
621*8975f5c5SAndroid Build Coastguard Worker                                    uint32_t slice,
622*8975f5c5SAndroid Build Coastguard Worker                                    const uint8_t *data,
623*8975f5c5SAndroid Build Coastguard Worker                                    size_t bytesPerRow,
624*8975f5c5SAndroid Build Coastguard Worker                                    size_t bytesPer2DImage,
625*8975f5c5SAndroid Build Coastguard Worker                                    bool avoidStagingBuffers,
626*8975f5c5SAndroid Build Coastguard Worker                                    const mtl::TextureRef &texture)
627*8975f5c5SAndroid Build Coastguard Worker
628*8975f5c5SAndroid Build Coastguard Worker{
629*8975f5c5SAndroid Build Coastguard Worker    ASSERT(texture && texture->valid());
630*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl       = mtl::GetImpl(context);
631*8975f5c5SAndroid Build Coastguard Worker    const mtl::Format &mtlFormat = contextMtl->getPixelFormat(textureAngleFormat.id);
632*8975f5c5SAndroid Build Coastguard Worker
633*8975f5c5SAndroid Build Coastguard Worker    bool preferGPUInitialization =
634*8975f5c5SAndroid Build Coastguard Worker        !avoidStagingBuffers &&
635*8975f5c5SAndroid Build Coastguard Worker        PreferStagedTextureUploads(context, texture, mtlFormat, mtl::StagingPurpose::Upload);
636*8975f5c5SAndroid Build Coastguard Worker    if (texture->isCPUAccessible() && !preferGPUInitialization)
637*8975f5c5SAndroid Build Coastguard Worker    {
638*8975f5c5SAndroid Build Coastguard Worker        if (mtlFormat.isPVRTC())
639*8975f5c5SAndroid Build Coastguard Worker        {
640*8975f5c5SAndroid Build Coastguard Worker            // Replace Region Validation: rowBytes must be 0
641*8975f5c5SAndroid Build Coastguard Worker            bytesPerRow = 0;
642*8975f5c5SAndroid Build Coastguard Worker        }
643*8975f5c5SAndroid Build Coastguard Worker
644*8975f5c5SAndroid Build Coastguard Worker        // If texture is CPU accessible, just call replaceRegion() directly.
645*8975f5c5SAndroid Build Coastguard Worker        texture->replaceRegion(contextMtl, region, mipmapLevel, slice, data, bytesPerRow,
646*8975f5c5SAndroid Build Coastguard Worker                               bytesPer2DImage);
647*8975f5c5SAndroid Build Coastguard Worker
648*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
649*8975f5c5SAndroid Build Coastguard Worker    }
650*8975f5c5SAndroid Build Coastguard Worker
651*8975f5c5SAndroid Build Coastguard Worker    // Texture is not CPU accessible or staging is forced due to a workaround
652*8975f5c5SAndroid Build Coastguard Worker    if (!textureAngleFormat.depthBits && !textureAngleFormat.stencilBits)
653*8975f5c5SAndroid Build Coastguard Worker    {
654*8975f5c5SAndroid Build Coastguard Worker        // Upload color data
655*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(UploadTextureContentsWithStagingBuffer(contextMtl, textureAngleFormat, region,
656*8975f5c5SAndroid Build Coastguard Worker                                                         mipmapLevel, slice, data, bytesPerRow,
657*8975f5c5SAndroid Build Coastguard Worker                                                         bytesPer2DImage, texture));
658*8975f5c5SAndroid Build Coastguard Worker    }
659*8975f5c5SAndroid Build Coastguard Worker    else if (textureAngleFormat.depthBits && textureAngleFormat.stencilBits)
660*8975f5c5SAndroid Build Coastguard Worker    {
661*8975f5c5SAndroid Build Coastguard Worker        // Packed depth-stencil
662*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(UploadPackedDepthStencilTextureContentsWithStagingBuffer(
663*8975f5c5SAndroid Build Coastguard Worker            contextMtl, textureAngleFormat, region, mipmapLevel, slice, data, bytesPerRow,
664*8975f5c5SAndroid Build Coastguard Worker            bytesPer2DImage, texture));
665*8975f5c5SAndroid Build Coastguard Worker    }
666*8975f5c5SAndroid Build Coastguard Worker    else
667*8975f5c5SAndroid Build Coastguard Worker    {
668*8975f5c5SAndroid Build Coastguard Worker        // Depth or stencil
669*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(UploadDepthStencilTextureContentsWithStagingBuffer(
670*8975f5c5SAndroid Build Coastguard Worker            contextMtl, textureAngleFormat, region, mipmapLevel, slice, data, bytesPerRow,
671*8975f5c5SAndroid Build Coastguard Worker            bytesPer2DImage, texture));
672*8975f5c5SAndroid Build Coastguard Worker    }
673*8975f5c5SAndroid Build Coastguard Worker
674*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
675*8975f5c5SAndroid Build Coastguard Worker}
676*8975f5c5SAndroid Build Coastguard Worker
677*8975f5c5SAndroid Build Coastguard Worker// This might be unused on platform not supporting swizzle.
678*8975f5c5SAndroid Build Coastguard WorkerANGLE_APPLE_UNUSED
679*8975f5c5SAndroid Build Coastguard WorkerGLenum OverrideSwizzleValue(const gl::Context *context,
680*8975f5c5SAndroid Build Coastguard Worker                            GLenum swizzle,
681*8975f5c5SAndroid Build Coastguard Worker                            const mtl::Format &format,
682*8975f5c5SAndroid Build Coastguard Worker                            const gl::InternalFormat &glInternalFormat)
683*8975f5c5SAndroid Build Coastguard Worker{
684*8975f5c5SAndroid Build Coastguard Worker    if (format.actualAngleFormat().hasDepthOrStencilBits())
685*8975f5c5SAndroid Build Coastguard Worker    {
686*8975f5c5SAndroid Build Coastguard Worker        ASSERT(!format.swizzled);
687*8975f5c5SAndroid Build Coastguard Worker        if (context->getState().getClientMajorVersion() >= 3 && glInternalFormat.sized)
688*8975f5c5SAndroid Build Coastguard Worker        {
689*8975f5c5SAndroid Build Coastguard Worker            // ES 3.1 spec: treat depth and stencil textures as red textures during sampling.
690*8975f5c5SAndroid Build Coastguard Worker            if (swizzle == GL_GREEN || swizzle == GL_BLUE)
691*8975f5c5SAndroid Build Coastguard Worker            {
692*8975f5c5SAndroid Build Coastguard Worker                return GL_NONE;
693*8975f5c5SAndroid Build Coastguard Worker            }
694*8975f5c5SAndroid Build Coastguard Worker            else if (swizzle == GL_ALPHA)
695*8975f5c5SAndroid Build Coastguard Worker            {
696*8975f5c5SAndroid Build Coastguard Worker                return GL_ONE;
697*8975f5c5SAndroid Build Coastguard Worker            }
698*8975f5c5SAndroid Build Coastguard Worker        }
699*8975f5c5SAndroid Build Coastguard Worker        else
700*8975f5c5SAndroid Build Coastguard Worker        {
701*8975f5c5SAndroid Build Coastguard Worker            // https://www.khronos.org/registry/OpenGL/extensions/OES/OES_depth_texture.txt
702*8975f5c5SAndroid Build Coastguard Worker            // Treat depth texture as luminance texture during sampling.
703*8975f5c5SAndroid Build Coastguard Worker            if (swizzle == GL_GREEN || swizzle == GL_BLUE)
704*8975f5c5SAndroid Build Coastguard Worker            {
705*8975f5c5SAndroid Build Coastguard Worker                return GL_RED;
706*8975f5c5SAndroid Build Coastguard Worker            }
707*8975f5c5SAndroid Build Coastguard Worker            else if (swizzle == GL_ALPHA)
708*8975f5c5SAndroid Build Coastguard Worker            {
709*8975f5c5SAndroid Build Coastguard Worker                return GL_ONE;
710*8975f5c5SAndroid Build Coastguard Worker            }
711*8975f5c5SAndroid Build Coastguard Worker        }
712*8975f5c5SAndroid Build Coastguard Worker    }
713*8975f5c5SAndroid Build Coastguard Worker    else if (format.swizzled)
714*8975f5c5SAndroid Build Coastguard Worker    {
715*8975f5c5SAndroid Build Coastguard Worker        // Combine the swizzles
716*8975f5c5SAndroid Build Coastguard Worker        switch (swizzle)
717*8975f5c5SAndroid Build Coastguard Worker        {
718*8975f5c5SAndroid Build Coastguard Worker            case GL_RED:
719*8975f5c5SAndroid Build Coastguard Worker                return format.swizzle[0];
720*8975f5c5SAndroid Build Coastguard Worker            case GL_GREEN:
721*8975f5c5SAndroid Build Coastguard Worker                return format.swizzle[1];
722*8975f5c5SAndroid Build Coastguard Worker            case GL_BLUE:
723*8975f5c5SAndroid Build Coastguard Worker                return format.swizzle[2];
724*8975f5c5SAndroid Build Coastguard Worker            case GL_ALPHA:
725*8975f5c5SAndroid Build Coastguard Worker                return format.swizzle[3];
726*8975f5c5SAndroid Build Coastguard Worker            default:
727*8975f5c5SAndroid Build Coastguard Worker                break;
728*8975f5c5SAndroid Build Coastguard Worker        }
729*8975f5c5SAndroid Build Coastguard Worker    }
730*8975f5c5SAndroid Build Coastguard Worker
731*8975f5c5SAndroid Build Coastguard Worker    return swizzle;
732*8975f5c5SAndroid Build Coastguard Worker}
733*8975f5c5SAndroid Build Coastguard Worker
734*8975f5c5SAndroid Build Coastguard Workermtl::TextureRef &GetLayerLevelTextureView(
735*8975f5c5SAndroid Build Coastguard Worker    TextureMtl::LayerLevelTextureViewVector *layerLevelTextureViews,
736*8975f5c5SAndroid Build Coastguard Worker    uint32_t layer,
737*8975f5c5SAndroid Build Coastguard Worker    uint32_t level,
738*8975f5c5SAndroid Build Coastguard Worker    uint32_t layerCount,
739*8975f5c5SAndroid Build Coastguard Worker    uint32_t levelCount)
740*8975f5c5SAndroid Build Coastguard Worker{
741*8975f5c5SAndroid Build Coastguard Worker    // Lazily allocate the full layer and level count to not trigger any std::vector reallocations.
742*8975f5c5SAndroid Build Coastguard Worker    if (layerLevelTextureViews->empty())
743*8975f5c5SAndroid Build Coastguard Worker    {
744*8975f5c5SAndroid Build Coastguard Worker        layerLevelTextureViews->resize(layerCount);
745*8975f5c5SAndroid Build Coastguard Worker    }
746*8975f5c5SAndroid Build Coastguard Worker    ASSERT(layerLevelTextureViews->size() > layer);
747*8975f5c5SAndroid Build Coastguard Worker
748*8975f5c5SAndroid Build Coastguard Worker    TextureMtl::TextureViewVector &levelTextureViews = (*layerLevelTextureViews)[layer];
749*8975f5c5SAndroid Build Coastguard Worker
750*8975f5c5SAndroid Build Coastguard Worker    if (levelTextureViews.empty())
751*8975f5c5SAndroid Build Coastguard Worker    {
752*8975f5c5SAndroid Build Coastguard Worker        levelTextureViews.resize(levelCount);
753*8975f5c5SAndroid Build Coastguard Worker    }
754*8975f5c5SAndroid Build Coastguard Worker    ASSERT(levelTextureViews.size() > level);
755*8975f5c5SAndroid Build Coastguard Worker
756*8975f5c5SAndroid Build Coastguard Worker    return levelTextureViews[level];
757*8975f5c5SAndroid Build Coastguard Worker}
758*8975f5c5SAndroid Build Coastguard Worker
759*8975f5c5SAndroid Build Coastguard Worker}  // namespace
760*8975f5c5SAndroid Build Coastguard Worker
761*8975f5c5SAndroid Build Coastguard Worker// TextureMtl::NativeTextureWrapper implementation.
762*8975f5c5SAndroid Build Coastguard Worker// This class uses GL level instead of mtl::MipmapNativeLevel.
763*8975f5c5SAndroid Build Coastguard Worker// It seamlessly translates GL level to native level based on the base GL information passed in the
764*8975f5c5SAndroid Build Coastguard Worker// constructor. The base GL level is unchanged thoughout the lifetime of this object.
765*8975f5c5SAndroid Build Coastguard Worker// Note that NativeTextureWrapper's base GL level doesn't necessarily mean it's the same as a GL
766*8975f5c5SAndroid Build Coastguard Worker// texture's real base level.
767*8975f5c5SAndroid Build Coastguard Worker// - If NativeTextureWrapper holds a native storage of a non-immutable texture,
768*8975f5c5SAndroid Build Coastguard Worker// its base GL level is indeed equal to the GL texture's base level.
769*8975f5c5SAndroid Build Coastguard Worker// - If NativeTextureWrapper holds a native storage of an immutable texture,
770*8975f5c5SAndroid Build Coastguard Worker// it base GL level is actually 0.
771*8975f5c5SAndroid Build Coastguard Worker// - If NativeTextureWrapper holds a view from base level to max level of a GL texture,
772*8975f5c5SAndroid Build Coastguard Worker// then its base GL level is equal to the GL texture's base level.
773*8975f5c5SAndroid Build Coastguard Workerclass TextureMtl::NativeTextureWrapper : angle::NonCopyable
774*8975f5c5SAndroid Build Coastguard Worker{
775*8975f5c5SAndroid Build Coastguard Worker  public:
776*8975f5c5SAndroid Build Coastguard Worker    NativeTextureWrapper(mtl::TextureRef texture, GLuint baseGLLevel)
777*8975f5c5SAndroid Build Coastguard Worker        : mNativeTexture(std::move(texture)), mBaseGLLevel(baseGLLevel)
778*8975f5c5SAndroid Build Coastguard Worker    {
779*8975f5c5SAndroid Build Coastguard Worker        ASSERT(mNativeTexture && mNativeTexture->valid());
780*8975f5c5SAndroid Build Coastguard Worker    }
781*8975f5c5SAndroid Build Coastguard Worker
782*8975f5c5SAndroid Build Coastguard Worker    operator const mtl::TextureRef &() const { return mNativeTexture; }
783*8975f5c5SAndroid Build Coastguard Worker    const mtl::TextureRef &getNativeTexture() const { return mNativeTexture; }
784*8975f5c5SAndroid Build Coastguard Worker
785*8975f5c5SAndroid Build Coastguard Worker    void replaceRegion(ContextMtl *context,
786*8975f5c5SAndroid Build Coastguard Worker                       const MTLRegion &region,
787*8975f5c5SAndroid Build Coastguard Worker                       GLuint glLevel,
788*8975f5c5SAndroid Build Coastguard Worker                       uint32_t slice,
789*8975f5c5SAndroid Build Coastguard Worker                       const uint8_t *data,
790*8975f5c5SAndroid Build Coastguard Worker                       size_t bytesPerRow,
791*8975f5c5SAndroid Build Coastguard Worker                       size_t bytesPer2DImage)
792*8975f5c5SAndroid Build Coastguard Worker    {
793*8975f5c5SAndroid Build Coastguard Worker        mNativeTexture->replaceRegion(context, region, getNativeLevel(glLevel), slice, data,
794*8975f5c5SAndroid Build Coastguard Worker                                      bytesPerRow, bytesPer2DImage);
795*8975f5c5SAndroid Build Coastguard Worker    }
796*8975f5c5SAndroid Build Coastguard Worker
797*8975f5c5SAndroid Build Coastguard Worker    void getBytes(ContextMtl *context,
798*8975f5c5SAndroid Build Coastguard Worker                  size_t bytesPerRow,
799*8975f5c5SAndroid Build Coastguard Worker                  size_t bytesPer2DInage,
800*8975f5c5SAndroid Build Coastguard Worker                  const MTLRegion &region,
801*8975f5c5SAndroid Build Coastguard Worker                  GLuint glLevel,
802*8975f5c5SAndroid Build Coastguard Worker                  uint32_t slice,
803*8975f5c5SAndroid Build Coastguard Worker                  uint8_t *dataOut)
804*8975f5c5SAndroid Build Coastguard Worker    {
805*8975f5c5SAndroid Build Coastguard Worker        mNativeTexture->getBytes(context, bytesPerRow, bytesPer2DInage, region,
806*8975f5c5SAndroid Build Coastguard Worker                                 getNativeLevel(glLevel), slice, dataOut);
807*8975f5c5SAndroid Build Coastguard Worker    }
808*8975f5c5SAndroid Build Coastguard Worker
809*8975f5c5SAndroid Build Coastguard Worker    GLuint getBaseGLLevel() const { return mBaseGLLevel; }
810*8975f5c5SAndroid Build Coastguard Worker    // Get max addressable GL level that this texture supports.
811*8975f5c5SAndroid Build Coastguard Worker    GLuint getMaxSupportedGLLevel() const { return mBaseGLLevel + mipmapLevels() - 1; }
812*8975f5c5SAndroid Build Coastguard Worker    // Check whether a GL level refers to a valid mip in this texture.
813*8975f5c5SAndroid Build Coastguard Worker    bool isGLLevelSupported(GLuint glLevel)
814*8975f5c5SAndroid Build Coastguard Worker    {
815*8975f5c5SAndroid Build Coastguard Worker        return glLevel >= mBaseGLLevel && glLevel <= getMaxSupportedGLLevel();
816*8975f5c5SAndroid Build Coastguard Worker    }
817*8975f5c5SAndroid Build Coastguard Worker    mtl::MipmapNativeLevel getNativeLevel(GLuint glLevel) const
818*8975f5c5SAndroid Build Coastguard Worker    {
819*8975f5c5SAndroid Build Coastguard Worker        return mtl::GetNativeMipLevel(glLevel, mBaseGLLevel);
820*8975f5c5SAndroid Build Coastguard Worker    }
821*8975f5c5SAndroid Build Coastguard Worker    GLuint getGLLevel(const mtl::MipmapNativeLevel &nativeLevel) const
822*8975f5c5SAndroid Build Coastguard Worker    {
823*8975f5c5SAndroid Build Coastguard Worker        return mtl::GetGLMipLevel(nativeLevel, mBaseGLLevel);
824*8975f5c5SAndroid Build Coastguard Worker    }
825*8975f5c5SAndroid Build Coastguard Worker
826*8975f5c5SAndroid Build Coastguard Worker    mtl::TextureRef getStencilView() { return mNativeTexture->getStencilView(); }
827*8975f5c5SAndroid Build Coastguard Worker
828*8975f5c5SAndroid Build Coastguard Worker    MTLTextureType textureType() const { return mNativeTexture->textureType(); }
829*8975f5c5SAndroid Build Coastguard Worker    MTLPixelFormat pixelFormat() const { return mNativeTexture->pixelFormat(); }
830*8975f5c5SAndroid Build Coastguard Worker
831*8975f5c5SAndroid Build Coastguard Worker    uint32_t mipmapLevels() const { return mNativeTexture->mipmapLevels(); }
832*8975f5c5SAndroid Build Coastguard Worker    uint32_t arrayLength() const { return mNativeTexture->arrayLength(); }
833*8975f5c5SAndroid Build Coastguard Worker    uint32_t cubeFaces() const { return mNativeTexture->cubeFaces(); }
834*8975f5c5SAndroid Build Coastguard Worker    uint32_t cubeFacesOrArrayLength() const { return mNativeTexture->cubeFacesOrArrayLength(); }
835*8975f5c5SAndroid Build Coastguard Worker
836*8975f5c5SAndroid Build Coastguard Worker    uint32_t width(GLuint glLevel) const { return mNativeTexture->width(getNativeLevel(glLevel)); }
837*8975f5c5SAndroid Build Coastguard Worker    uint32_t height(GLuint glLevel) const
838*8975f5c5SAndroid Build Coastguard Worker    {
839*8975f5c5SAndroid Build Coastguard Worker        return mNativeTexture->height(getNativeLevel(glLevel));
840*8975f5c5SAndroid Build Coastguard Worker    }
841*8975f5c5SAndroid Build Coastguard Worker    uint32_t depth(GLuint glLevel) const { return mNativeTexture->depth(getNativeLevel(glLevel)); }
842*8975f5c5SAndroid Build Coastguard Worker
843*8975f5c5SAndroid Build Coastguard Worker    gl::Extents size(GLuint glLevel) const { return mNativeTexture->size(getNativeLevel(glLevel)); }
844*8975f5c5SAndroid Build Coastguard Worker
845*8975f5c5SAndroid Build Coastguard Worker    // Get width, height, depth, size at base level.
846*8975f5c5SAndroid Build Coastguard Worker    uint32_t widthAt0() const { return width(mBaseGLLevel); }
847*8975f5c5SAndroid Build Coastguard Worker    uint32_t heightAt0() const { return height(mBaseGLLevel); }
848*8975f5c5SAndroid Build Coastguard Worker    uint32_t depthAt0() const { return depth(mBaseGLLevel); }
849*8975f5c5SAndroid Build Coastguard Worker    gl::Extents sizeAt0() const { return size(mBaseGLLevel); }
850*8975f5c5SAndroid Build Coastguard Worker
851*8975f5c5SAndroid Build Coastguard Worker  protected:
852*8975f5c5SAndroid Build Coastguard Worker    mtl::TextureRef mNativeTexture;
853*8975f5c5SAndroid Build Coastguard Worker    const GLuint mBaseGLLevel;
854*8975f5c5SAndroid Build Coastguard Worker};
855*8975f5c5SAndroid Build Coastguard Worker
856*8975f5c5SAndroid Build Coastguard Worker// This class extends NativeTextureWrapper with support for view creation
857*8975f5c5SAndroid Build Coastguard Workerclass TextureMtl::NativeTextureWrapperWithViewSupport : public NativeTextureWrapper
858*8975f5c5SAndroid Build Coastguard Worker{
859*8975f5c5SAndroid Build Coastguard Worker  public:
860*8975f5c5SAndroid Build Coastguard Worker    NativeTextureWrapperWithViewSupport(mtl::TextureRef texture, GLuint baseGLLevel)
861*8975f5c5SAndroid Build Coastguard Worker        : NativeTextureWrapper(std::move(texture), baseGLLevel)
862*8975f5c5SAndroid Build Coastguard Worker    {}
863*8975f5c5SAndroid Build Coastguard Worker
864*8975f5c5SAndroid Build Coastguard Worker    // Create a view of one slice at a level.
865*8975f5c5SAndroid Build Coastguard Worker    mtl::TextureRef createSliceMipView(uint32_t slice, GLuint glLevel)
866*8975f5c5SAndroid Build Coastguard Worker    {
867*8975f5c5SAndroid Build Coastguard Worker        return mNativeTexture->createSliceMipView(slice, getNativeLevel(glLevel));
868*8975f5c5SAndroid Build Coastguard Worker    }
869*8975f5c5SAndroid Build Coastguard Worker    // Create a levels range view
870*8975f5c5SAndroid Build Coastguard Worker    mtl::TextureRef createMipsView(GLuint glLevel, uint32_t levels)
871*8975f5c5SAndroid Build Coastguard Worker    {
872*8975f5c5SAndroid Build Coastguard Worker        return mNativeTexture->createMipsView(getNativeLevel(glLevel), levels);
873*8975f5c5SAndroid Build Coastguard Worker    }
874*8975f5c5SAndroid Build Coastguard Worker    // Create a view of a level.
875*8975f5c5SAndroid Build Coastguard Worker    mtl::TextureRef createMipView(GLuint glLevel)
876*8975f5c5SAndroid Build Coastguard Worker    {
877*8975f5c5SAndroid Build Coastguard Worker        return mNativeTexture->createMipView(getNativeLevel(glLevel));
878*8975f5c5SAndroid Build Coastguard Worker    }
879*8975f5c5SAndroid Build Coastguard Worker    // Create a view for a shader image binding.
880*8975f5c5SAndroid Build Coastguard Worker    mtl::TextureRef createShaderImageView2D(GLuint glLevel, int layer, MTLPixelFormat format)
881*8975f5c5SAndroid Build Coastguard Worker    {
882*8975f5c5SAndroid Build Coastguard Worker        return mNativeTexture->createShaderImageView2D(getNativeLevel(glLevel), layer, format);
883*8975f5c5SAndroid Build Coastguard Worker    }
884*8975f5c5SAndroid Build Coastguard Worker
885*8975f5c5SAndroid Build Coastguard Worker    // Create a swizzled view
886*8975f5c5SAndroid Build Coastguard Worker    mtl::TextureRef createMipsSwizzleView(GLuint glLevel,
887*8975f5c5SAndroid Build Coastguard Worker                                          uint32_t levels,
888*8975f5c5SAndroid Build Coastguard Worker                                          MTLPixelFormat format,
889*8975f5c5SAndroid Build Coastguard Worker                                          const MTLTextureSwizzleChannels &swizzle)
890*8975f5c5SAndroid Build Coastguard Worker    {
891*8975f5c5SAndroid Build Coastguard Worker        return mNativeTexture->createMipsSwizzleView(getNativeLevel(glLevel), levels, format,
892*8975f5c5SAndroid Build Coastguard Worker                                                     swizzle);
893*8975f5c5SAndroid Build Coastguard Worker    }
894*8975f5c5SAndroid Build Coastguard Worker};
895*8975f5c5SAndroid Build Coastguard Worker
896*8975f5c5SAndroid Build Coastguard Worker// TextureMtl implementation
897*8975f5c5SAndroid Build Coastguard WorkerTextureMtl::TextureMtl(const gl::TextureState &state) : TextureImpl(state) {}
898*8975f5c5SAndroid Build Coastguard Worker
899*8975f5c5SAndroid Build Coastguard WorkerTextureMtl::~TextureMtl() = default;
900*8975f5c5SAndroid Build Coastguard Worker
901*8975f5c5SAndroid Build Coastguard Workervoid TextureMtl::onDestroy(const gl::Context *context)
902*8975f5c5SAndroid Build Coastguard Worker{
903*8975f5c5SAndroid Build Coastguard Worker    deallocateNativeStorage(/*keepImages=*/false);
904*8975f5c5SAndroid Build Coastguard Worker    mBoundSurface = nullptr;
905*8975f5c5SAndroid Build Coastguard Worker}
906*8975f5c5SAndroid Build Coastguard Worker
907*8975f5c5SAndroid Build Coastguard Workervoid TextureMtl::deallocateNativeStorage(bool keepImages, bool keepSamplerStateAndFormat)
908*8975f5c5SAndroid Build Coastguard Worker{
909*8975f5c5SAndroid Build Coastguard Worker
910*8975f5c5SAndroid Build Coastguard Worker    if (!keepImages)
911*8975f5c5SAndroid Build Coastguard Worker    {
912*8975f5c5SAndroid Build Coastguard Worker        mTexImageDefs.clear();
913*8975f5c5SAndroid Build Coastguard Worker        mShaderImageViews.clear();
914*8975f5c5SAndroid Build Coastguard Worker    }
915*8975f5c5SAndroid Build Coastguard Worker    else if (mNativeTextureStorage)
916*8975f5c5SAndroid Build Coastguard Worker    {
917*8975f5c5SAndroid Build Coastguard Worker        // Release native texture but keep its image definitions.
918*8975f5c5SAndroid Build Coastguard Worker        retainImageDefinitions();
919*8975f5c5SAndroid Build Coastguard Worker    }
920*8975f5c5SAndroid Build Coastguard Worker
921*8975f5c5SAndroid Build Coastguard Worker    mNativeTextureStorage       = nullptr;
922*8975f5c5SAndroid Build Coastguard Worker    mViewFromBaseToMaxLevel     = nullptr;
923*8975f5c5SAndroid Build Coastguard Worker    mSwizzleStencilSamplingView = nullptr;
924*8975f5c5SAndroid Build Coastguard Worker
925*8975f5c5SAndroid Build Coastguard Worker    // Clear render target cache for each texture's image. We don't erase them because they
926*8975f5c5SAndroid Build Coastguard Worker    // might still be referenced by a framebuffer.
927*8975f5c5SAndroid Build Coastguard Worker    for (auto &samplesMapRenderTargets : mRenderTargets)
928*8975f5c5SAndroid Build Coastguard Worker    {
929*8975f5c5SAndroid Build Coastguard Worker        for (RenderTargetMtl &perSampleCountRenderTarget : samplesMapRenderTargets.second)
930*8975f5c5SAndroid Build Coastguard Worker        {
931*8975f5c5SAndroid Build Coastguard Worker            perSampleCountRenderTarget.reset();
932*8975f5c5SAndroid Build Coastguard Worker        }
933*8975f5c5SAndroid Build Coastguard Worker    }
934*8975f5c5SAndroid Build Coastguard Worker
935*8975f5c5SAndroid Build Coastguard Worker    for (auto &samplesMapMSTextures : mImplicitMSTextures)
936*8975f5c5SAndroid Build Coastguard Worker    {
937*8975f5c5SAndroid Build Coastguard Worker        for (mtl::TextureRef &perSampleCountMSTexture : samplesMapMSTextures.second)
938*8975f5c5SAndroid Build Coastguard Worker        {
939*8975f5c5SAndroid Build Coastguard Worker            perSampleCountMSTexture.reset();
940*8975f5c5SAndroid Build Coastguard Worker        }
941*8975f5c5SAndroid Build Coastguard Worker    }
942*8975f5c5SAndroid Build Coastguard Worker
943*8975f5c5SAndroid Build Coastguard Worker    for (mtl::TextureRef &view : mLevelViewsWithinBaseMax)
944*8975f5c5SAndroid Build Coastguard Worker    {
945*8975f5c5SAndroid Build Coastguard Worker        view.reset();
946*8975f5c5SAndroid Build Coastguard Worker    }
947*8975f5c5SAndroid Build Coastguard Worker
948*8975f5c5SAndroid Build Coastguard Worker    if (!keepSamplerStateAndFormat)
949*8975f5c5SAndroid Build Coastguard Worker    {
950*8975f5c5SAndroid Build Coastguard Worker        mMetalSamplerState = nil;
951*8975f5c5SAndroid Build Coastguard Worker        mFormat            = mtl::Format();
952*8975f5c5SAndroid Build Coastguard Worker    }
953*8975f5c5SAndroid Build Coastguard Worker}
954*8975f5c5SAndroid Build Coastguard Worker
955*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::ensureNativeStorageCreated(const gl::Context *context)
956*8975f5c5SAndroid Build Coastguard Worker{
957*8975f5c5SAndroid Build Coastguard Worker    if (mNativeTextureStorage)
958*8975f5c5SAndroid Build Coastguard Worker    {
959*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
960*8975f5c5SAndroid Build Coastguard Worker    }
961*8975f5c5SAndroid Build Coastguard Worker
962*8975f5c5SAndroid Build Coastguard Worker    // This should not be called from immutable texture.
963*8975f5c5SAndroid Build Coastguard Worker    ASSERT(!isImmutableOrPBuffer());
964*8975f5c5SAndroid Build Coastguard Worker    ASSERT(mState.getType() != gl::TextureType::_2DMultisample);
965*8975f5c5SAndroid Build Coastguard Worker    ASSERT(mState.getType() != gl::TextureType::_2DMultisampleArray);
966*8975f5c5SAndroid Build Coastguard Worker
967*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
968*8975f5c5SAndroid Build Coastguard Worker
969*8975f5c5SAndroid Build Coastguard Worker    // Create actual texture object:
970*8975f5c5SAndroid Build Coastguard Worker    GLuint mips        = mState.getMipmapMaxLevel() - mState.getEffectiveBaseLevel() + 1;
971*8975f5c5SAndroid Build Coastguard Worker    gl::ImageDesc desc = mState.getBaseLevelDesc();
972*8975f5c5SAndroid Build Coastguard Worker    ANGLE_MTL_CHECK(contextMtl, desc.format.valid(), GL_INVALID_OPERATION);
973*8975f5c5SAndroid Build Coastguard Worker    angle::FormatID angleFormatId =
974*8975f5c5SAndroid Build Coastguard Worker        angle::Format::InternalFormatToID(desc.format.info->sizedInternalFormat);
975*8975f5c5SAndroid Build Coastguard Worker    mFormat = contextMtl->getPixelFormat(angleFormatId);
976*8975f5c5SAndroid Build Coastguard Worker
977*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(createNativeStorage(context, mState.getType(), mips, 0, desc.size));
978*8975f5c5SAndroid Build Coastguard Worker
979*8975f5c5SAndroid Build Coastguard Worker    // Transfer data from defined images to actual texture object
980*8975f5c5SAndroid Build Coastguard Worker    int numCubeFaces = static_cast<int>(mNativeTextureStorage->cubeFaces());
981*8975f5c5SAndroid Build Coastguard Worker    for (int face = 0; face < numCubeFaces; ++face)
982*8975f5c5SAndroid Build Coastguard Worker    {
983*8975f5c5SAndroid Build Coastguard Worker        for (mtl::MipmapNativeLevel actualMip = mtl::kZeroNativeMipLevel; actualMip.get() < mips;
984*8975f5c5SAndroid Build Coastguard Worker             ++actualMip)
985*8975f5c5SAndroid Build Coastguard Worker        {
986*8975f5c5SAndroid Build Coastguard Worker            GLuint imageMipLevel             = mNativeTextureStorage->getGLLevel(actualMip);
987*8975f5c5SAndroid Build Coastguard Worker            mtl::TextureRef &imageToTransfer = mTexImageDefs[face][imageMipLevel].image;
988*8975f5c5SAndroid Build Coastguard Worker
989*8975f5c5SAndroid Build Coastguard Worker            // Only transfer if this mip & slice image has been defined and in correct size &
990*8975f5c5SAndroid Build Coastguard Worker            // format.
991*8975f5c5SAndroid Build Coastguard Worker            gl::Extents actualMipSize = mNativeTextureStorage->size(imageMipLevel);
992*8975f5c5SAndroid Build Coastguard Worker            if (imageToTransfer && imageToTransfer->sizeAt0() == actualMipSize &&
993*8975f5c5SAndroid Build Coastguard Worker                imageToTransfer->arrayLength() == mNativeTextureStorage->arrayLength() &&
994*8975f5c5SAndroid Build Coastguard Worker                imageToTransfer->pixelFormat() == mNativeTextureStorage->pixelFormat())
995*8975f5c5SAndroid Build Coastguard Worker            {
996*8975f5c5SAndroid Build Coastguard Worker                mtl::BlitCommandEncoder *encoder = GetBlitCommandEncoderForResources(
997*8975f5c5SAndroid Build Coastguard Worker                    contextMtl,
998*8975f5c5SAndroid Build Coastguard Worker                    {imageToTransfer.get(), mNativeTextureStorage->getNativeTexture().get()});
999*8975f5c5SAndroid Build Coastguard Worker
1000*8975f5c5SAndroid Build Coastguard Worker                encoder->copyTexture(imageToTransfer, 0, mtl::kZeroNativeMipLevel,
1001*8975f5c5SAndroid Build Coastguard Worker                                     *mNativeTextureStorage, face, actualMip,
1002*8975f5c5SAndroid Build Coastguard Worker                                     imageToTransfer->arrayLength(), 1);
1003*8975f5c5SAndroid Build Coastguard Worker
1004*8975f5c5SAndroid Build Coastguard Worker                // Invalidate texture image definition at this index so that we can make it a
1005*8975f5c5SAndroid Build Coastguard Worker                // view of the native texture at this index later.
1006*8975f5c5SAndroid Build Coastguard Worker                imageToTransfer = nullptr;
1007*8975f5c5SAndroid Build Coastguard Worker            }
1008*8975f5c5SAndroid Build Coastguard Worker        }
1009*8975f5c5SAndroid Build Coastguard Worker    }
1010*8975f5c5SAndroid Build Coastguard Worker
1011*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
1012*8975f5c5SAndroid Build Coastguard Worker}
1013*8975f5c5SAndroid Build Coastguard Worker
1014*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::createNativeStorage(const gl::Context *context,
1015*8975f5c5SAndroid Build Coastguard Worker                                              gl::TextureType type,
1016*8975f5c5SAndroid Build Coastguard Worker                                              GLuint mips,
1017*8975f5c5SAndroid Build Coastguard Worker                                              GLuint samples,
1018*8975f5c5SAndroid Build Coastguard Worker                                              const gl::Extents &size)
1019*8975f5c5SAndroid Build Coastguard Worker{
1020*8975f5c5SAndroid Build Coastguard Worker    ASSERT(samples == 0 || mips == 0);
1021*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
1022*8975f5c5SAndroid Build Coastguard Worker
1023*8975f5c5SAndroid Build Coastguard Worker    // Create actual texture object:
1024*8975f5c5SAndroid Build Coastguard Worker    mSlices              = 1;
1025*8975f5c5SAndroid Build Coastguard Worker    bool allowFormatView = mFormat.hasDepthAndStencilBits() ||
1026*8975f5c5SAndroid Build Coastguard Worker                           needsFormatViewForPixelLocalStorage(
1027*8975f5c5SAndroid Build Coastguard Worker                               contextMtl->getDisplay()->getNativePixelLocalStorageOptions());
1028*8975f5c5SAndroid Build Coastguard Worker    mtl::TextureRef nativeTextureStorage;
1029*8975f5c5SAndroid Build Coastguard Worker    switch (type)
1030*8975f5c5SAndroid Build Coastguard Worker    {
1031*8975f5c5SAndroid Build Coastguard Worker        case gl::TextureType::_2D:
1032*8975f5c5SAndroid Build Coastguard Worker            ANGLE_TRY(mtl::Texture::Make2DTexture(
1033*8975f5c5SAndroid Build Coastguard Worker                contextMtl, mFormat, size.width, size.height, mips,
1034*8975f5c5SAndroid Build Coastguard Worker                /** renderTargetOnly */ false, allowFormatView, &nativeTextureStorage));
1035*8975f5c5SAndroid Build Coastguard Worker            break;
1036*8975f5c5SAndroid Build Coastguard Worker        case gl::TextureType::CubeMap:
1037*8975f5c5SAndroid Build Coastguard Worker            mSlices = 6;
1038*8975f5c5SAndroid Build Coastguard Worker            ANGLE_TRY(mtl::Texture::MakeCubeTexture(contextMtl, mFormat, size.width, mips,
1039*8975f5c5SAndroid Build Coastguard Worker                                                    /** renderTargetOnly */ false, allowFormatView,
1040*8975f5c5SAndroid Build Coastguard Worker                                                    &nativeTextureStorage));
1041*8975f5c5SAndroid Build Coastguard Worker            break;
1042*8975f5c5SAndroid Build Coastguard Worker        case gl::TextureType::_3D:
1043*8975f5c5SAndroid Build Coastguard Worker            ANGLE_TRY(mtl::Texture::Make3DTexture(
1044*8975f5c5SAndroid Build Coastguard Worker                contextMtl, mFormat, size.width, size.height, size.depth, mips,
1045*8975f5c5SAndroid Build Coastguard Worker                /** renderTargetOnly */ false, allowFormatView, &nativeTextureStorage));
1046*8975f5c5SAndroid Build Coastguard Worker            break;
1047*8975f5c5SAndroid Build Coastguard Worker        case gl::TextureType::_2DArray:
1048*8975f5c5SAndroid Build Coastguard Worker            mSlices = size.depth;
1049*8975f5c5SAndroid Build Coastguard Worker            ANGLE_TRY(mtl::Texture::Make2DArrayTexture(
1050*8975f5c5SAndroid Build Coastguard Worker                contextMtl, mFormat, size.width, size.height, mips, mSlices,
1051*8975f5c5SAndroid Build Coastguard Worker                /** renderTargetOnly */ false, allowFormatView, &nativeTextureStorage));
1052*8975f5c5SAndroid Build Coastguard Worker            break;
1053*8975f5c5SAndroid Build Coastguard Worker        case gl::TextureType::_2DMultisample:
1054*8975f5c5SAndroid Build Coastguard Worker            ANGLE_TRY(mtl::Texture::Make2DMSTexture(
1055*8975f5c5SAndroid Build Coastguard Worker                contextMtl, mFormat, size.width, size.height, samples,
1056*8975f5c5SAndroid Build Coastguard Worker                /** renderTargetOnly */ false, allowFormatView, &nativeTextureStorage));
1057*8975f5c5SAndroid Build Coastguard Worker            break;
1058*8975f5c5SAndroid Build Coastguard Worker        default:
1059*8975f5c5SAndroid Build Coastguard Worker            UNREACHABLE();
1060*8975f5c5SAndroid Build Coastguard Worker    }
1061*8975f5c5SAndroid Build Coastguard Worker
1062*8975f5c5SAndroid Build Coastguard Worker    if (mState.getImmutableFormat())
1063*8975f5c5SAndroid Build Coastguard Worker    {
1064*8975f5c5SAndroid Build Coastguard Worker        mNativeTextureStorage = std::make_unique<NativeTextureWrapperWithViewSupport>(
1065*8975f5c5SAndroid Build Coastguard Worker            std::move(nativeTextureStorage), /*baseGLLevel=*/0);
1066*8975f5c5SAndroid Build Coastguard Worker    }
1067*8975f5c5SAndroid Build Coastguard Worker    else
1068*8975f5c5SAndroid Build Coastguard Worker    {
1069*8975f5c5SAndroid Build Coastguard Worker        mNativeTextureStorage = std::make_unique<NativeTextureWrapperWithViewSupport>(
1070*8975f5c5SAndroid Build Coastguard Worker            std::move(nativeTextureStorage), /*baseGLLevel=*/mState.getEffectiveBaseLevel());
1071*8975f5c5SAndroid Build Coastguard Worker    }
1072*8975f5c5SAndroid Build Coastguard Worker
1073*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(checkForEmulatedChannels(context, mFormat, *mNativeTextureStorage));
1074*8975f5c5SAndroid Build Coastguard Worker
1075*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(createViewFromBaseToMaxLevel());
1076*8975f5c5SAndroid Build Coastguard Worker
1077*8975f5c5SAndroid Build Coastguard Worker    // Create sampler state
1078*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(ensureSamplerStateCreated(context));
1079*8975f5c5SAndroid Build Coastguard Worker
1080*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
1081*8975f5c5SAndroid Build Coastguard Worker}
1082*8975f5c5SAndroid Build Coastguard Worker
1083*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::ensureSamplerStateCreated(const gl::Context *context)
1084*8975f5c5SAndroid Build Coastguard Worker{
1085*8975f5c5SAndroid Build Coastguard Worker    if (mMetalSamplerState)
1086*8975f5c5SAndroid Build Coastguard Worker    {
1087*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
1088*8975f5c5SAndroid Build Coastguard Worker    }
1089*8975f5c5SAndroid Build Coastguard Worker
1090*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
1091*8975f5c5SAndroid Build Coastguard Worker
1092*8975f5c5SAndroid Build Coastguard Worker    mtl::SamplerDesc samplerDesc(mState.getSamplerState());
1093*8975f5c5SAndroid Build Coastguard Worker
1094*8975f5c5SAndroid Build Coastguard Worker    if (mFormat.actualAngleFormat().depthBits && !mFormat.getCaps().filterable)
1095*8975f5c5SAndroid Build Coastguard Worker    {
1096*8975f5c5SAndroid Build Coastguard Worker        // On devices not supporting filtering for depth textures, we need to convert to nearest
1097*8975f5c5SAndroid Build Coastguard Worker        // here.
1098*8975f5c5SAndroid Build Coastguard Worker        samplerDesc.minFilter = MTLSamplerMinMagFilterNearest;
1099*8975f5c5SAndroid Build Coastguard Worker        samplerDesc.magFilter = MTLSamplerMinMagFilterNearest;
1100*8975f5c5SAndroid Build Coastguard Worker        if (samplerDesc.mipFilter != MTLSamplerMipFilterNotMipmapped)
1101*8975f5c5SAndroid Build Coastguard Worker        {
1102*8975f5c5SAndroid Build Coastguard Worker            samplerDesc.mipFilter = MTLSamplerMipFilterNearest;
1103*8975f5c5SAndroid Build Coastguard Worker        }
1104*8975f5c5SAndroid Build Coastguard Worker
1105*8975f5c5SAndroid Build Coastguard Worker        samplerDesc.maxAnisotropy = 1;
1106*8975f5c5SAndroid Build Coastguard Worker    }
1107*8975f5c5SAndroid Build Coastguard Worker
1108*8975f5c5SAndroid Build Coastguard Worker    // OpenGL ES 3.x: The rules for texel selection are modified
1109*8975f5c5SAndroid Build Coastguard Worker    // for cube maps so that texture wrap modes are ignored.
1110*8975f5c5SAndroid Build Coastguard Worker    if ((mState.getType() == gl::TextureType::CubeMap ||
1111*8975f5c5SAndroid Build Coastguard Worker         mState.getType() == gl::TextureType::CubeMapArray) &&
1112*8975f5c5SAndroid Build Coastguard Worker        context->getState().getClientMajorVersion() >= 3)
1113*8975f5c5SAndroid Build Coastguard Worker    {
1114*8975f5c5SAndroid Build Coastguard Worker        samplerDesc.rAddressMode = MTLSamplerAddressModeClampToEdge;
1115*8975f5c5SAndroid Build Coastguard Worker        samplerDesc.sAddressMode = MTLSamplerAddressModeClampToEdge;
1116*8975f5c5SAndroid Build Coastguard Worker        samplerDesc.tAddressMode = MTLSamplerAddressModeClampToEdge;
1117*8975f5c5SAndroid Build Coastguard Worker    }
1118*8975f5c5SAndroid Build Coastguard Worker    mMetalSamplerState = contextMtl->getDisplay()->getStateCache().getSamplerState(
1119*8975f5c5SAndroid Build Coastguard Worker        contextMtl->getMetalDevice(), samplerDesc);
1120*8975f5c5SAndroid Build Coastguard Worker
1121*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
1122*8975f5c5SAndroid Build Coastguard Worker}
1123*8975f5c5SAndroid Build Coastguard Worker
1124*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::createViewFromBaseToMaxLevel()
1125*8975f5c5SAndroid Build Coastguard Worker{
1126*8975f5c5SAndroid Build Coastguard Worker    ASSERT(mNativeTextureStorage);
1127*8975f5c5SAndroid Build Coastguard Worker    uint32_t maxLevel =
1128*8975f5c5SAndroid Build Coastguard Worker        std::min(mNativeTextureStorage->getMaxSupportedGLLevel(), mState.getEffectiveMaxLevel());
1129*8975f5c5SAndroid Build Coastguard Worker
1130*8975f5c5SAndroid Build Coastguard Worker    mtl::TextureRef nativeViewFromBaseToMaxLevelRef;
1131*8975f5c5SAndroid Build Coastguard Worker    if (maxLevel == mNativeTextureStorage->getMaxSupportedGLLevel() &&
1132*8975f5c5SAndroid Build Coastguard Worker        mState.getEffectiveBaseLevel() == mNativeTextureStorage->getBaseGLLevel())
1133*8975f5c5SAndroid Build Coastguard Worker    {
1134*8975f5c5SAndroid Build Coastguard Worker        // If base & max level are the same in mNativeTextureStorage, we don't need
1135*8975f5c5SAndroid Build Coastguard Worker        // a dedicated view. Furthermore, Intel driver has some bugs when sampling a view
1136*8975f5c5SAndroid Build Coastguard Worker        // of a stencil texture.
1137*8975f5c5SAndroid Build Coastguard Worker        nativeViewFromBaseToMaxLevelRef = mNativeTextureStorage->getNativeTexture();
1138*8975f5c5SAndroid Build Coastguard Worker    }
1139*8975f5c5SAndroid Build Coastguard Worker    else
1140*8975f5c5SAndroid Build Coastguard Worker    {
1141*8975f5c5SAndroid Build Coastguard Worker        uint32_t baseToMaxLevels = maxLevel - mState.getEffectiveBaseLevel() + 1;
1142*8975f5c5SAndroid Build Coastguard Worker        nativeViewFromBaseToMaxLevelRef =
1143*8975f5c5SAndroid Build Coastguard Worker            mNativeTextureStorage->createMipsView(mState.getEffectiveBaseLevel(), baseToMaxLevels);
1144*8975f5c5SAndroid Build Coastguard Worker    }
1145*8975f5c5SAndroid Build Coastguard Worker
1146*8975f5c5SAndroid Build Coastguard Worker    mViewFromBaseToMaxLevel = std::make_unique<NativeTextureWrapper>(
1147*8975f5c5SAndroid Build Coastguard Worker        nativeViewFromBaseToMaxLevelRef, mState.getEffectiveBaseLevel());
1148*8975f5c5SAndroid Build Coastguard Worker
1149*8975f5c5SAndroid Build Coastguard Worker    // Recreate in bindToShader()
1150*8975f5c5SAndroid Build Coastguard Worker    mSwizzleStencilSamplingView = nullptr;
1151*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
1152*8975f5c5SAndroid Build Coastguard Worker}
1153*8975f5c5SAndroid Build Coastguard Worker
1154*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::onBaseMaxLevelsChanged(const gl::Context *context)
1155*8975f5c5SAndroid Build Coastguard Worker{
1156*8975f5c5SAndroid Build Coastguard Worker    if (!mNativeTextureStorage)
1157*8975f5c5SAndroid Build Coastguard Worker    {
1158*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
1159*8975f5c5SAndroid Build Coastguard Worker    }
1160*8975f5c5SAndroid Build Coastguard Worker
1161*8975f5c5SAndroid Build Coastguard Worker    if (isImmutableOrPBuffer())
1162*8975f5c5SAndroid Build Coastguard Worker    {
1163*8975f5c5SAndroid Build Coastguard Worker        // For immutable texture, only recreate base-max view.
1164*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(createViewFromBaseToMaxLevel());
1165*8975f5c5SAndroid Build Coastguard Worker        // Invalidate base-max per level views so that they can be recreated
1166*8975f5c5SAndroid Build Coastguard Worker        // in generateMipmap()
1167*8975f5c5SAndroid Build Coastguard Worker        for (mtl::TextureRef &view : mLevelViewsWithinBaseMax)
1168*8975f5c5SAndroid Build Coastguard Worker        {
1169*8975f5c5SAndroid Build Coastguard Worker            view.reset();
1170*8975f5c5SAndroid Build Coastguard Worker        }
1171*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
1172*8975f5c5SAndroid Build Coastguard Worker    }
1173*8975f5c5SAndroid Build Coastguard Worker
1174*8975f5c5SAndroid Build Coastguard Worker    if (mState.getEffectiveBaseLevel() == mNativeTextureStorage->getBaseGLLevel() &&
1175*8975f5c5SAndroid Build Coastguard Worker        mState.getMipmapMaxLevel() == mNativeTextureStorage->getMaxSupportedGLLevel())
1176*8975f5c5SAndroid Build Coastguard Worker    {
1177*8975f5c5SAndroid Build Coastguard Worker        ASSERT(mState.getBaseLevelDesc().size == mNativeTextureStorage->sizeAt0());
1178*8975f5c5SAndroid Build Coastguard Worker        // If level range remain the same, don't recreate the texture storage.
1179*8975f5c5SAndroid Build Coastguard Worker        // This might feel unnecessary at first since the front-end might prevent redundant base/max
1180*8975f5c5SAndroid Build Coastguard Worker        // level change already. However, there are cases that cause native storage to be created
1181*8975f5c5SAndroid Build Coastguard Worker        // before base/max level dirty bit is passed to Metal backend and lead to unwanted problems.
1182*8975f5c5SAndroid Build Coastguard Worker        // Example:
1183*8975f5c5SAndroid Build Coastguard Worker        // 1. texture with a non-default base/max level state is set.
1184*8975f5c5SAndroid Build Coastguard Worker        // 2. The texture is used first as a framebuffer attachment. This operation does not fully
1185*8975f5c5SAndroid Build Coastguard Worker        //    sync the texture state and therefore does not unset base/max level dirty bits.
1186*8975f5c5SAndroid Build Coastguard Worker        // 3. The same texture is then used for sampling; this operation fully syncs the texture
1187*8975f5c5SAndroid Build Coastguard Worker        //    state. Base/max level dirty bits may lead to recreating the texture storage thus
1188*8975f5c5SAndroid Build Coastguard Worker        //    invalidating native render target references created in step 2.
1189*8975f5c5SAndroid Build Coastguard Worker        // 4. If the framebuffer created in step 2 is used again, its native render target
1190*8975f5c5SAndroid Build Coastguard Worker        //    references will not be updated to point to the new storage because everything is in
1191*8975f5c5SAndroid Build Coastguard Worker        //    sync from the frontend point of view.
1192*8975f5c5SAndroid Build Coastguard Worker        // 5. Note: if the new range is different, it is expected that native render target
1193*8975f5c5SAndroid Build Coastguard Worker        //    references will be updated during draw framebuffer sync.
1194*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
1195*8975f5c5SAndroid Build Coastguard Worker    }
1196*8975f5c5SAndroid Build Coastguard Worker
1197*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
1198*8975f5c5SAndroid Build Coastguard Worker
1199*8975f5c5SAndroid Build Coastguard Worker    // We need to recreate a new native texture storage with number of levels = max level - base
1200*8975f5c5SAndroid Build Coastguard Worker    // level + 1. This can be achieved by simply deleting the old storage. The storage will be
1201*8975f5c5SAndroid Build Coastguard Worker    // lazily recreated later via ensureNativeStorageCreated().
1202*8975f5c5SAndroid Build Coastguard Worker    // Note: We release the native texture storage but keep old image definitions. So that when the
1203*8975f5c5SAndroid Build Coastguard Worker    // storage is recreated, its levels can be recreated with data from the old image definitions
1204*8975f5c5SAndroid Build Coastguard Worker    // respectively.
1205*8975f5c5SAndroid Build Coastguard Worker    deallocateNativeStorage(/*keepImages=*/true, /*keepSamplerStateAndFormat=*/true);
1206*8975f5c5SAndroid Build Coastguard Worker
1207*8975f5c5SAndroid Build Coastguard Worker    // Tell context to rebind textures
1208*8975f5c5SAndroid Build Coastguard Worker    contextMtl->invalidateCurrentTextures();
1209*8975f5c5SAndroid Build Coastguard Worker
1210*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
1211*8975f5c5SAndroid Build Coastguard Worker}
1212*8975f5c5SAndroid Build Coastguard Worker
1213*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::ensureImageCreated(const gl::Context *context,
1214*8975f5c5SAndroid Build Coastguard Worker                                             const gl::ImageIndex &index)
1215*8975f5c5SAndroid Build Coastguard Worker{
1216*8975f5c5SAndroid Build Coastguard Worker    mtl::TextureRef &image = getImage(index);
1217*8975f5c5SAndroid Build Coastguard Worker    if (!image)
1218*8975f5c5SAndroid Build Coastguard Worker    {
1219*8975f5c5SAndroid Build Coastguard Worker        // Image at this level hasn't been defined yet. We need to define it:
1220*8975f5c5SAndroid Build Coastguard Worker        const gl::ImageDesc &desc = mState.getImageDesc(index);
1221*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(redefineImage(context, index, mFormat, desc.size));
1222*8975f5c5SAndroid Build Coastguard Worker    }
1223*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
1224*8975f5c5SAndroid Build Coastguard Worker}
1225*8975f5c5SAndroid Build Coastguard Worker
1226*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::ensureLevelViewsWithinBaseMaxCreated()
1227*8975f5c5SAndroid Build Coastguard Worker{
1228*8975f5c5SAndroid Build Coastguard Worker    ASSERT(mViewFromBaseToMaxLevel);
1229*8975f5c5SAndroid Build Coastguard Worker    for (mtl::MipmapNativeLevel mip = mtl::kZeroNativeMipLevel;
1230*8975f5c5SAndroid Build Coastguard Worker         mip.get() < mViewFromBaseToMaxLevel->mipmapLevels(); ++mip)
1231*8975f5c5SAndroid Build Coastguard Worker    {
1232*8975f5c5SAndroid Build Coastguard Worker        if (mLevelViewsWithinBaseMax[mip])
1233*8975f5c5SAndroid Build Coastguard Worker        {
1234*8975f5c5SAndroid Build Coastguard Worker            continue;
1235*8975f5c5SAndroid Build Coastguard Worker        }
1236*8975f5c5SAndroid Build Coastguard Worker
1237*8975f5c5SAndroid Build Coastguard Worker        GLuint mipGLLevel = mViewFromBaseToMaxLevel->getGLLevel(mip);
1238*8975f5c5SAndroid Build Coastguard Worker
1239*8975f5c5SAndroid Build Coastguard Worker        if (mViewFromBaseToMaxLevel->textureType() != MTLTextureTypeCube &&
1240*8975f5c5SAndroid Build Coastguard Worker            mTexImageDefs[0][mipGLLevel].image)
1241*8975f5c5SAndroid Build Coastguard Worker        {
1242*8975f5c5SAndroid Build Coastguard Worker            // Reuse texture image view.
1243*8975f5c5SAndroid Build Coastguard Worker            mLevelViewsWithinBaseMax[mip] = mTexImageDefs[0][mipGLLevel].image;
1244*8975f5c5SAndroid Build Coastguard Worker        }
1245*8975f5c5SAndroid Build Coastguard Worker        else
1246*8975f5c5SAndroid Build Coastguard Worker        {
1247*8975f5c5SAndroid Build Coastguard Worker            mLevelViewsWithinBaseMax[mip] = mNativeTextureStorage->createMipView(mipGLLevel);
1248*8975f5c5SAndroid Build Coastguard Worker        }
1249*8975f5c5SAndroid Build Coastguard Worker    }
1250*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
1251*8975f5c5SAndroid Build Coastguard Worker}
1252*8975f5c5SAndroid Build Coastguard Worker
1253*8975f5c5SAndroid Build Coastguard Workermtl::TextureRef TextureMtl::createImageViewFromTextureStorage(GLuint cubeFaceOrZero, GLuint glLevel)
1254*8975f5c5SAndroid Build Coastguard Worker{
1255*8975f5c5SAndroid Build Coastguard Worker    mtl::TextureRef image;
1256*8975f5c5SAndroid Build Coastguard Worker    if (mNativeTextureStorage->textureType() == MTLTextureTypeCube)
1257*8975f5c5SAndroid Build Coastguard Worker    {
1258*8975f5c5SAndroid Build Coastguard Worker        // Cube texture's image is per face.
1259*8975f5c5SAndroid Build Coastguard Worker        image = mNativeTextureStorage->createSliceMipView(cubeFaceOrZero, glLevel);
1260*8975f5c5SAndroid Build Coastguard Worker    }
1261*8975f5c5SAndroid Build Coastguard Worker    else
1262*8975f5c5SAndroid Build Coastguard Worker    {
1263*8975f5c5SAndroid Build Coastguard Worker        if (mViewFromBaseToMaxLevel->isGLLevelSupported(glLevel))
1264*8975f5c5SAndroid Build Coastguard Worker        {
1265*8975f5c5SAndroid Build Coastguard Worker            mtl::MipmapNativeLevel nativeLevel = mViewFromBaseToMaxLevel->getNativeLevel(glLevel);
1266*8975f5c5SAndroid Build Coastguard Worker            if (mLevelViewsWithinBaseMax[nativeLevel])
1267*8975f5c5SAndroid Build Coastguard Worker            {
1268*8975f5c5SAndroid Build Coastguard Worker                // Reuse the native level view
1269*8975f5c5SAndroid Build Coastguard Worker                image = mLevelViewsWithinBaseMax[nativeLevel];
1270*8975f5c5SAndroid Build Coastguard Worker            }
1271*8975f5c5SAndroid Build Coastguard Worker        }
1272*8975f5c5SAndroid Build Coastguard Worker
1273*8975f5c5SAndroid Build Coastguard Worker        if (!image)
1274*8975f5c5SAndroid Build Coastguard Worker        {
1275*8975f5c5SAndroid Build Coastguard Worker            image = mNativeTextureStorage->createMipView(glLevel);
1276*8975f5c5SAndroid Build Coastguard Worker        }
1277*8975f5c5SAndroid Build Coastguard Worker    }
1278*8975f5c5SAndroid Build Coastguard Worker
1279*8975f5c5SAndroid Build Coastguard Worker    return image;
1280*8975f5c5SAndroid Build Coastguard Worker}
1281*8975f5c5SAndroid Build Coastguard Worker
1282*8975f5c5SAndroid Build Coastguard Workervoid TextureMtl::retainImageDefinitions()
1283*8975f5c5SAndroid Build Coastguard Worker{
1284*8975f5c5SAndroid Build Coastguard Worker    if (!mNativeTextureStorage)
1285*8975f5c5SAndroid Build Coastguard Worker    {
1286*8975f5c5SAndroid Build Coastguard Worker        return;
1287*8975f5c5SAndroid Build Coastguard Worker    }
1288*8975f5c5SAndroid Build Coastguard Worker    const GLuint mips = mNativeTextureStorage->mipmapLevels();
1289*8975f5c5SAndroid Build Coastguard Worker
1290*8975f5c5SAndroid Build Coastguard Worker    int numCubeFaces = 1;
1291*8975f5c5SAndroid Build Coastguard Worker    switch (mState.getType())
1292*8975f5c5SAndroid Build Coastguard Worker    {
1293*8975f5c5SAndroid Build Coastguard Worker        case gl::TextureType::CubeMap:
1294*8975f5c5SAndroid Build Coastguard Worker            numCubeFaces = 6;
1295*8975f5c5SAndroid Build Coastguard Worker            break;
1296*8975f5c5SAndroid Build Coastguard Worker        default:
1297*8975f5c5SAndroid Build Coastguard Worker            break;
1298*8975f5c5SAndroid Build Coastguard Worker    }
1299*8975f5c5SAndroid Build Coastguard Worker
1300*8975f5c5SAndroid Build Coastguard Worker    // Create image view per cube face, per mip level
1301*8975f5c5SAndroid Build Coastguard Worker    for (int face = 0; face < numCubeFaces; ++face)
1302*8975f5c5SAndroid Build Coastguard Worker    {
1303*8975f5c5SAndroid Build Coastguard Worker        for (mtl::MipmapNativeLevel mip = mtl::kZeroNativeMipLevel; mip.get() < mips; ++mip)
1304*8975f5c5SAndroid Build Coastguard Worker        {
1305*8975f5c5SAndroid Build Coastguard Worker            GLuint imageMipLevel         = mNativeTextureStorage->getGLLevel(mip);
1306*8975f5c5SAndroid Build Coastguard Worker            ImageDefinitionMtl &imageDef = mTexImageDefs[face][imageMipLevel];
1307*8975f5c5SAndroid Build Coastguard Worker            if (imageDef.image)
1308*8975f5c5SAndroid Build Coastguard Worker            {
1309*8975f5c5SAndroid Build Coastguard Worker                continue;
1310*8975f5c5SAndroid Build Coastguard Worker            }
1311*8975f5c5SAndroid Build Coastguard Worker            imageDef.image    = createImageViewFromTextureStorage(face, imageMipLevel);
1312*8975f5c5SAndroid Build Coastguard Worker            imageDef.formatID = mFormat.intendedFormatId;
1313*8975f5c5SAndroid Build Coastguard Worker        }
1314*8975f5c5SAndroid Build Coastguard Worker    }
1315*8975f5c5SAndroid Build Coastguard Worker}
1316*8975f5c5SAndroid Build Coastguard Worker
1317*8975f5c5SAndroid Build Coastguard Workermtl::TextureRef &TextureMtl::getImage(const gl::ImageIndex &imageIndex)
1318*8975f5c5SAndroid Build Coastguard Worker{
1319*8975f5c5SAndroid Build Coastguard Worker    return getImageDefinition(imageIndex).image;
1320*8975f5c5SAndroid Build Coastguard Worker}
1321*8975f5c5SAndroid Build Coastguard Worker
1322*8975f5c5SAndroid Build Coastguard WorkerImageDefinitionMtl &TextureMtl::getImageDefinition(const gl::ImageIndex &imageIndex)
1323*8975f5c5SAndroid Build Coastguard Worker{
1324*8975f5c5SAndroid Build Coastguard Worker    GLuint cubeFaceOrZero        = GetImageCubeFaceIndexOrZeroFrom(imageIndex);
1325*8975f5c5SAndroid Build Coastguard Worker    ImageDefinitionMtl &imageDef = mTexImageDefs[cubeFaceOrZero][imageIndex.getLevelIndex()];
1326*8975f5c5SAndroid Build Coastguard Worker
1327*8975f5c5SAndroid Build Coastguard Worker    if (!imageDef.image && mNativeTextureStorage)
1328*8975f5c5SAndroid Build Coastguard Worker    {
1329*8975f5c5SAndroid Build Coastguard Worker        // If native texture is already created, and the image at this index is not available,
1330*8975f5c5SAndroid Build Coastguard Worker        // then create a view of native texture at this index, so that modifications of the image
1331*8975f5c5SAndroid Build Coastguard Worker        // are reflected back to native texture's respective index.
1332*8975f5c5SAndroid Build Coastguard Worker        if (!mNativeTextureStorage->isGLLevelSupported(imageIndex.getLevelIndex()))
1333*8975f5c5SAndroid Build Coastguard Worker        {
1334*8975f5c5SAndroid Build Coastguard Worker            // Image outside native texture's mip levels is skipped.
1335*8975f5c5SAndroid Build Coastguard Worker            return imageDef;
1336*8975f5c5SAndroid Build Coastguard Worker        }
1337*8975f5c5SAndroid Build Coastguard Worker
1338*8975f5c5SAndroid Build Coastguard Worker        imageDef.image =
1339*8975f5c5SAndroid Build Coastguard Worker            createImageViewFromTextureStorage(cubeFaceOrZero, imageIndex.getLevelIndex());
1340*8975f5c5SAndroid Build Coastguard Worker        imageDef.formatID = mFormat.intendedFormatId;
1341*8975f5c5SAndroid Build Coastguard Worker    }
1342*8975f5c5SAndroid Build Coastguard Worker
1343*8975f5c5SAndroid Build Coastguard Worker    return imageDef;
1344*8975f5c5SAndroid Build Coastguard Worker}
1345*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::getRenderTarget(ContextMtl *context,
1346*8975f5c5SAndroid Build Coastguard Worker                                          const gl::ImageIndex &imageIndex,
1347*8975f5c5SAndroid Build Coastguard Worker                                          GLsizei implicitSamples,
1348*8975f5c5SAndroid Build Coastguard Worker                                          RenderTargetMtl **renderTargetOut)
1349*8975f5c5SAndroid Build Coastguard Worker{
1350*8975f5c5SAndroid Build Coastguard Worker    ASSERT(imageIndex.getType() == gl::TextureType::_2D ||
1351*8975f5c5SAndroid Build Coastguard Worker           imageIndex.getType() == gl::TextureType::Rectangle ||
1352*8975f5c5SAndroid Build Coastguard Worker           imageIndex.getType() == gl::TextureType::_2DMultisample || imageIndex.hasLayer());
1353*8975f5c5SAndroid Build Coastguard Worker
1354*8975f5c5SAndroid Build Coastguard Worker    const gl::RenderToTextureImageIndex renderToTextureIndex =
1355*8975f5c5SAndroid Build Coastguard Worker        implicitSamples <= 1
1356*8975f5c5SAndroid Build Coastguard Worker            ? gl::RenderToTextureImageIndex::Default
1357*8975f5c5SAndroid Build Coastguard Worker            : static_cast<gl::RenderToTextureImageIndex>(PackSampleCount(implicitSamples));
1358*8975f5c5SAndroid Build Coastguard Worker
1359*8975f5c5SAndroid Build Coastguard Worker    GLuint layer         = GetImageLayerIndexFrom(imageIndex);
1360*8975f5c5SAndroid Build Coastguard Worker    RenderTargetMtl &rtt = mRenderTargets[imageIndex][renderToTextureIndex];
1361*8975f5c5SAndroid Build Coastguard Worker    if (!rtt.getTexture())
1362*8975f5c5SAndroid Build Coastguard Worker    {
1363*8975f5c5SAndroid Build Coastguard Worker        // Lazy initialization of render target:
1364*8975f5c5SAndroid Build Coastguard Worker        mtl::TextureRef &image = getImage(imageIndex);
1365*8975f5c5SAndroid Build Coastguard Worker        if (image)
1366*8975f5c5SAndroid Build Coastguard Worker        {
1367*8975f5c5SAndroid Build Coastguard Worker            if (imageIndex.getType() == gl::TextureType::CubeMap)
1368*8975f5c5SAndroid Build Coastguard Worker            {
1369*8975f5c5SAndroid Build Coastguard Worker                // Cube map is special, the image is already the view of its layer
1370*8975f5c5SAndroid Build Coastguard Worker                rtt.set(image, mtl::kZeroNativeMipLevel, 0, mFormat);
1371*8975f5c5SAndroid Build Coastguard Worker            }
1372*8975f5c5SAndroid Build Coastguard Worker            else
1373*8975f5c5SAndroid Build Coastguard Worker            {
1374*8975f5c5SAndroid Build Coastguard Worker                rtt.set(image, mtl::kZeroNativeMipLevel, layer, mFormat);
1375*8975f5c5SAndroid Build Coastguard Worker            }
1376*8975f5c5SAndroid Build Coastguard Worker        }
1377*8975f5c5SAndroid Build Coastguard Worker    }
1378*8975f5c5SAndroid Build Coastguard Worker
1379*8975f5c5SAndroid Build Coastguard Worker    if (implicitSamples > 1 && !rtt.getImplicitMSTexture())
1380*8975f5c5SAndroid Build Coastguard Worker    {
1381*8975f5c5SAndroid Build Coastguard Worker        // This format must supports implicit resolve
1382*8975f5c5SAndroid Build Coastguard Worker        ANGLE_MTL_CHECK(context, mFormat.getCaps().resolve, GL_INVALID_VALUE);
1383*8975f5c5SAndroid Build Coastguard Worker        mtl::TextureRef &msTexture = mImplicitMSTextures[imageIndex][renderToTextureIndex];
1384*8975f5c5SAndroid Build Coastguard Worker        if (!msTexture)
1385*8975f5c5SAndroid Build Coastguard Worker        {
1386*8975f5c5SAndroid Build Coastguard Worker            const gl::ImageDesc &desc = mState.getImageDesc(imageIndex);
1387*8975f5c5SAndroid Build Coastguard Worker            ANGLE_TRY(mtl::Texture::MakeMemoryLess2DMSTexture(
1388*8975f5c5SAndroid Build Coastguard Worker                context, mFormat, desc.size.width, desc.size.height, implicitSamples, &msTexture));
1389*8975f5c5SAndroid Build Coastguard Worker        }
1390*8975f5c5SAndroid Build Coastguard Worker        rtt.setImplicitMSTexture(msTexture);
1391*8975f5c5SAndroid Build Coastguard Worker    }
1392*8975f5c5SAndroid Build Coastguard Worker
1393*8975f5c5SAndroid Build Coastguard Worker    *renderTargetOut = &rtt;
1394*8975f5c5SAndroid Build Coastguard Worker
1395*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
1396*8975f5c5SAndroid Build Coastguard Worker}
1397*8975f5c5SAndroid Build Coastguard Worker
1398*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setImage(const gl::Context *context,
1399*8975f5c5SAndroid Build Coastguard Worker                                   const gl::ImageIndex &index,
1400*8975f5c5SAndroid Build Coastguard Worker                                   GLenum internalFormat,
1401*8975f5c5SAndroid Build Coastguard Worker                                   const gl::Extents &size,
1402*8975f5c5SAndroid Build Coastguard Worker                                   GLenum format,
1403*8975f5c5SAndroid Build Coastguard Worker                                   GLenum type,
1404*8975f5c5SAndroid Build Coastguard Worker                                   const gl::PixelUnpackState &unpack,
1405*8975f5c5SAndroid Build Coastguard Worker                                   gl::Buffer *unpackBuffer,
1406*8975f5c5SAndroid Build Coastguard Worker                                   const uint8_t *pixels)
1407*8975f5c5SAndroid Build Coastguard Worker{
1408*8975f5c5SAndroid Build Coastguard Worker    const gl::InternalFormat &dstFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
1409*8975f5c5SAndroid Build Coastguard Worker
1410*8975f5c5SAndroid Build Coastguard Worker    return setImageImpl(context, index, dstFormatInfo, size, format, type, unpack, unpackBuffer,
1411*8975f5c5SAndroid Build Coastguard Worker                        pixels);
1412*8975f5c5SAndroid Build Coastguard Worker}
1413*8975f5c5SAndroid Build Coastguard Worker
1414*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setSubImage(const gl::Context *context,
1415*8975f5c5SAndroid Build Coastguard Worker                                      const gl::ImageIndex &index,
1416*8975f5c5SAndroid Build Coastguard Worker                                      const gl::Box &area,
1417*8975f5c5SAndroid Build Coastguard Worker                                      GLenum format,
1418*8975f5c5SAndroid Build Coastguard Worker                                      GLenum type,
1419*8975f5c5SAndroid Build Coastguard Worker                                      const gl::PixelUnpackState &unpack,
1420*8975f5c5SAndroid Build Coastguard Worker                                      gl::Buffer *unpackBuffer,
1421*8975f5c5SAndroid Build Coastguard Worker                                      const uint8_t *pixels)
1422*8975f5c5SAndroid Build Coastguard Worker{
1423*8975f5c5SAndroid Build Coastguard Worker    const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format, type);
1424*8975f5c5SAndroid Build Coastguard Worker
1425*8975f5c5SAndroid Build Coastguard Worker    return setSubImageImpl(context, index, area, formatInfo, type, unpack, unpackBuffer, pixels);
1426*8975f5c5SAndroid Build Coastguard Worker}
1427*8975f5c5SAndroid Build Coastguard Worker
1428*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setCompressedImage(const gl::Context *context,
1429*8975f5c5SAndroid Build Coastguard Worker                                             const gl::ImageIndex &index,
1430*8975f5c5SAndroid Build Coastguard Worker                                             GLenum internalFormat,
1431*8975f5c5SAndroid Build Coastguard Worker                                             const gl::Extents &size,
1432*8975f5c5SAndroid Build Coastguard Worker                                             const gl::PixelUnpackState &unpack,
1433*8975f5c5SAndroid Build Coastguard Worker                                             size_t imageSize,
1434*8975f5c5SAndroid Build Coastguard Worker                                             const uint8_t *pixels)
1435*8975f5c5SAndroid Build Coastguard Worker{
1436*8975f5c5SAndroid Build Coastguard Worker    const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
1437*8975f5c5SAndroid Build Coastguard Worker    const gl::State &glState             = context->getState();
1438*8975f5c5SAndroid Build Coastguard Worker    gl::Buffer *unpackBuffer             = glState.getTargetBuffer(gl::BufferBinding::PixelUnpack);
1439*8975f5c5SAndroid Build Coastguard Worker
1440*8975f5c5SAndroid Build Coastguard Worker    return setImageImpl(context, index, formatInfo, size, internalFormat, GL_UNSIGNED_BYTE, unpack,
1441*8975f5c5SAndroid Build Coastguard Worker                        unpackBuffer, pixels);
1442*8975f5c5SAndroid Build Coastguard Worker}
1443*8975f5c5SAndroid Build Coastguard Worker
1444*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setCompressedSubImage(const gl::Context *context,
1445*8975f5c5SAndroid Build Coastguard Worker                                                const gl::ImageIndex &index,
1446*8975f5c5SAndroid Build Coastguard Worker                                                const gl::Box &area,
1447*8975f5c5SAndroid Build Coastguard Worker                                                GLenum format,
1448*8975f5c5SAndroid Build Coastguard Worker                                                const gl::PixelUnpackState &unpack,
1449*8975f5c5SAndroid Build Coastguard Worker                                                size_t imageSize,
1450*8975f5c5SAndroid Build Coastguard Worker                                                const uint8_t *pixels)
1451*8975f5c5SAndroid Build Coastguard Worker{
1452*8975f5c5SAndroid Build Coastguard Worker
1453*8975f5c5SAndroid Build Coastguard Worker    const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format, GL_UNSIGNED_BYTE);
1454*8975f5c5SAndroid Build Coastguard Worker
1455*8975f5c5SAndroid Build Coastguard Worker    const gl::State &glState = context->getState();
1456*8975f5c5SAndroid Build Coastguard Worker    gl::Buffer *unpackBuffer = glState.getTargetBuffer(gl::BufferBinding::PixelUnpack);
1457*8975f5c5SAndroid Build Coastguard Worker
1458*8975f5c5SAndroid Build Coastguard Worker    return setSubImageImpl(context, index, area, formatInfo, GL_UNSIGNED_BYTE, unpack, unpackBuffer,
1459*8975f5c5SAndroid Build Coastguard Worker                           pixels);
1460*8975f5c5SAndroid Build Coastguard Worker}
1461*8975f5c5SAndroid Build Coastguard Worker
1462*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::copyImage(const gl::Context *context,
1463*8975f5c5SAndroid Build Coastguard Worker                                    const gl::ImageIndex &index,
1464*8975f5c5SAndroid Build Coastguard Worker                                    const gl::Rectangle &sourceArea,
1465*8975f5c5SAndroid Build Coastguard Worker                                    GLenum internalFormat,
1466*8975f5c5SAndroid Build Coastguard Worker                                    gl::Framebuffer *source)
1467*8975f5c5SAndroid Build Coastguard Worker{
1468*8975f5c5SAndroid Build Coastguard Worker    gl::Extents newImageSize(sourceArea.width, sourceArea.height, 1);
1469*8975f5c5SAndroid Build Coastguard Worker    const gl::InternalFormat &internalFormatInfo =
1470*8975f5c5SAndroid Build Coastguard Worker        gl::GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE);
1471*8975f5c5SAndroid Build Coastguard Worker
1472*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
1473*8975f5c5SAndroid Build Coastguard Worker    angle::FormatID angleFormatId =
1474*8975f5c5SAndroid Build Coastguard Worker        angle::Format::InternalFormatToID(internalFormatInfo.sizedInternalFormat);
1475*8975f5c5SAndroid Build Coastguard Worker    const mtl::Format &mtlFormat = contextMtl->getPixelFormat(angleFormatId);
1476*8975f5c5SAndroid Build Coastguard Worker
1477*8975f5c5SAndroid Build Coastguard Worker    FramebufferMtl *srcFramebufferMtl = mtl::GetImpl(source);
1478*8975f5c5SAndroid Build Coastguard Worker    RenderTargetMtl *srcReadRT        = srcFramebufferMtl->getColorReadRenderTarget(context);
1479*8975f5c5SAndroid Build Coastguard Worker    RenderTargetMtl colorReadRT;
1480*8975f5c5SAndroid Build Coastguard Worker    if (srcReadRT)
1481*8975f5c5SAndroid Build Coastguard Worker    {
1482*8975f5c5SAndroid Build Coastguard Worker        // Need to duplicate RenderTargetMtl since the srcReadRT would be invalidated in
1483*8975f5c5SAndroid Build Coastguard Worker        // redefineImage(). This can happen if the source and this texture are the same texture.
1484*8975f5c5SAndroid Build Coastguard Worker        // Duplication ensures the copyImage() will be able to proceed even if the source texture
1485*8975f5c5SAndroid Build Coastguard Worker        // will be redefined.
1486*8975f5c5SAndroid Build Coastguard Worker        colorReadRT.duplicateFrom(*srcReadRT);
1487*8975f5c5SAndroid Build Coastguard Worker    }
1488*8975f5c5SAndroid Build Coastguard Worker
1489*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(redefineImage(context, index, mtlFormat, newImageSize));
1490*8975f5c5SAndroid Build Coastguard Worker
1491*8975f5c5SAndroid Build Coastguard Worker    gl::Extents fbSize = source->getReadColorAttachment()->getSize();
1492*8975f5c5SAndroid Build Coastguard Worker    gl::Rectangle fbRect(0, 0, fbSize.width, fbSize.height);
1493*8975f5c5SAndroid Build Coastguard Worker    if (context->isWebGL() && !fbRect.encloses(sourceArea))
1494*8975f5c5SAndroid Build Coastguard Worker    {
1495*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(initializeContents(context, GL_NONE, index));
1496*8975f5c5SAndroid Build Coastguard Worker    }
1497*8975f5c5SAndroid Build Coastguard Worker
1498*8975f5c5SAndroid Build Coastguard Worker    return copySubImageImpl(context, index, gl::Offset(0, 0, 0), sourceArea, internalFormatInfo,
1499*8975f5c5SAndroid Build Coastguard Worker                            srcFramebufferMtl, &colorReadRT);
1500*8975f5c5SAndroid Build Coastguard Worker}
1501*8975f5c5SAndroid Build Coastguard Worker
1502*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::copySubImage(const gl::Context *context,
1503*8975f5c5SAndroid Build Coastguard Worker                                       const gl::ImageIndex &index,
1504*8975f5c5SAndroid Build Coastguard Worker                                       const gl::Offset &destOffset,
1505*8975f5c5SAndroid Build Coastguard Worker                                       const gl::Rectangle &sourceArea,
1506*8975f5c5SAndroid Build Coastguard Worker                                       gl::Framebuffer *source)
1507*8975f5c5SAndroid Build Coastguard Worker{
1508*8975f5c5SAndroid Build Coastguard Worker    const gl::InternalFormat &currentFormat = *mState.getImageDesc(index).format.info;
1509*8975f5c5SAndroid Build Coastguard Worker    FramebufferMtl *srcFramebufferMtl       = mtl::GetImpl(source);
1510*8975f5c5SAndroid Build Coastguard Worker    RenderTargetMtl *colorReadRT            = srcFramebufferMtl->getColorReadRenderTarget(context);
1511*8975f5c5SAndroid Build Coastguard Worker    return copySubImageImpl(context, index, destOffset, sourceArea, currentFormat,
1512*8975f5c5SAndroid Build Coastguard Worker                            srcFramebufferMtl, colorReadRT);
1513*8975f5c5SAndroid Build Coastguard Worker}
1514*8975f5c5SAndroid Build Coastguard Worker
1515*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::copyTexture(const gl::Context *context,
1516*8975f5c5SAndroid Build Coastguard Worker                                      const gl::ImageIndex &index,
1517*8975f5c5SAndroid Build Coastguard Worker                                      GLenum internalFormat,
1518*8975f5c5SAndroid Build Coastguard Worker                                      GLenum type,
1519*8975f5c5SAndroid Build Coastguard Worker                                      GLint sourceLevel,
1520*8975f5c5SAndroid Build Coastguard Worker                                      bool unpackFlipY,
1521*8975f5c5SAndroid Build Coastguard Worker                                      bool unpackPremultiplyAlpha,
1522*8975f5c5SAndroid Build Coastguard Worker                                      bool unpackUnmultiplyAlpha,
1523*8975f5c5SAndroid Build Coastguard Worker                                      const gl::Texture *source)
1524*8975f5c5SAndroid Build Coastguard Worker{
1525*8975f5c5SAndroid Build Coastguard Worker    const gl::ImageDesc &sourceImageDesc = source->getTextureState().getImageDesc(
1526*8975f5c5SAndroid Build Coastguard Worker        NonCubeTextureTypeToTarget(source->getType()), sourceLevel);
1527*8975f5c5SAndroid Build Coastguard Worker    const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
1528*8975f5c5SAndroid Build Coastguard Worker
1529*8975f5c5SAndroid Build Coastguard Worker    // Only 2D textures are supported.
1530*8975f5c5SAndroid Build Coastguard Worker    ASSERT(sourceImageDesc.size.depth == 1);
1531*8975f5c5SAndroid Build Coastguard Worker
1532*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
1533*8975f5c5SAndroid Build Coastguard Worker    angle::FormatID angleFormatId =
1534*8975f5c5SAndroid Build Coastguard Worker        angle::Format::InternalFormatToID(internalFormatInfo.sizedInternalFormat);
1535*8975f5c5SAndroid Build Coastguard Worker    const mtl::Format &mtlFormat = contextMtl->getPixelFormat(angleFormatId);
1536*8975f5c5SAndroid Build Coastguard Worker
1537*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(redefineImage(context, index, mtlFormat, sourceImageDesc.size));
1538*8975f5c5SAndroid Build Coastguard Worker
1539*8975f5c5SAndroid Build Coastguard Worker    return copySubTextureImpl(
1540*8975f5c5SAndroid Build Coastguard Worker        context, index, gl::Offset(0, 0, 0), internalFormatInfo, sourceLevel,
1541*8975f5c5SAndroid Build Coastguard Worker        gl::Box(0, 0, 0, sourceImageDesc.size.width, sourceImageDesc.size.height, 1), unpackFlipY,
1542*8975f5c5SAndroid Build Coastguard Worker        unpackPremultiplyAlpha, unpackUnmultiplyAlpha, source);
1543*8975f5c5SAndroid Build Coastguard Worker}
1544*8975f5c5SAndroid Build Coastguard Worker
1545*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::copySubTexture(const gl::Context *context,
1546*8975f5c5SAndroid Build Coastguard Worker                                         const gl::ImageIndex &index,
1547*8975f5c5SAndroid Build Coastguard Worker                                         const gl::Offset &destOffset,
1548*8975f5c5SAndroid Build Coastguard Worker                                         GLint sourceLevel,
1549*8975f5c5SAndroid Build Coastguard Worker                                         const gl::Box &sourceBox,
1550*8975f5c5SAndroid Build Coastguard Worker                                         bool unpackFlipY,
1551*8975f5c5SAndroid Build Coastguard Worker                                         bool unpackPremultiplyAlpha,
1552*8975f5c5SAndroid Build Coastguard Worker                                         bool unpackUnmultiplyAlpha,
1553*8975f5c5SAndroid Build Coastguard Worker                                         const gl::Texture *source)
1554*8975f5c5SAndroid Build Coastguard Worker{
1555*8975f5c5SAndroid Build Coastguard Worker    const gl::InternalFormat &currentFormat = *mState.getImageDesc(index).format.info;
1556*8975f5c5SAndroid Build Coastguard Worker
1557*8975f5c5SAndroid Build Coastguard Worker    return copySubTextureImpl(context, index, destOffset, currentFormat, sourceLevel, sourceBox,
1558*8975f5c5SAndroid Build Coastguard Worker                              unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha, source);
1559*8975f5c5SAndroid Build Coastguard Worker}
1560*8975f5c5SAndroid Build Coastguard Worker
1561*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::copyCompressedTexture(const gl::Context *context,
1562*8975f5c5SAndroid Build Coastguard Worker                                                const gl::Texture *source)
1563*8975f5c5SAndroid Build Coastguard Worker{
1564*8975f5c5SAndroid Build Coastguard Worker    UNIMPLEMENTED();
1565*8975f5c5SAndroid Build Coastguard Worker
1566*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Stop;
1567*8975f5c5SAndroid Build Coastguard Worker}
1568*8975f5c5SAndroid Build Coastguard Worker
1569*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setStorage(const gl::Context *context,
1570*8975f5c5SAndroid Build Coastguard Worker                                     gl::TextureType type,
1571*8975f5c5SAndroid Build Coastguard Worker                                     size_t mipmaps,
1572*8975f5c5SAndroid Build Coastguard Worker                                     GLenum internalFormat,
1573*8975f5c5SAndroid Build Coastguard Worker                                     const gl::Extents &size)
1574*8975f5c5SAndroid Build Coastguard Worker{
1575*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl               = mtl::GetImpl(context);
1576*8975f5c5SAndroid Build Coastguard Worker    const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
1577*8975f5c5SAndroid Build Coastguard Worker    angle::FormatID angleFormatId =
1578*8975f5c5SAndroid Build Coastguard Worker        angle::Format::InternalFormatToID(formatInfo.sizedInternalFormat);
1579*8975f5c5SAndroid Build Coastguard Worker    const mtl::Format &mtlFormat = contextMtl->getPixelFormat(angleFormatId);
1580*8975f5c5SAndroid Build Coastguard Worker
1581*8975f5c5SAndroid Build Coastguard Worker    return setStorageImpl(context, type, mState.getImmutableLevels(), 0, mtlFormat, size);
1582*8975f5c5SAndroid Build Coastguard Worker}
1583*8975f5c5SAndroid Build Coastguard Worker
1584*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setStorageExternalMemory(const gl::Context *context,
1585*8975f5c5SAndroid Build Coastguard Worker                                                   gl::TextureType type,
1586*8975f5c5SAndroid Build Coastguard Worker                                                   size_t levels,
1587*8975f5c5SAndroid Build Coastguard Worker                                                   GLenum internalFormat,
1588*8975f5c5SAndroid Build Coastguard Worker                                                   const gl::Extents &size,
1589*8975f5c5SAndroid Build Coastguard Worker                                                   gl::MemoryObject *memoryObject,
1590*8975f5c5SAndroid Build Coastguard Worker                                                   GLuint64 offset,
1591*8975f5c5SAndroid Build Coastguard Worker                                                   GLbitfield createFlags,
1592*8975f5c5SAndroid Build Coastguard Worker                                                   GLbitfield usageFlags,
1593*8975f5c5SAndroid Build Coastguard Worker                                                   const void *imageCreateInfoPNext)
1594*8975f5c5SAndroid Build Coastguard Worker{
1595*8975f5c5SAndroid Build Coastguard Worker    UNIMPLEMENTED();
1596*8975f5c5SAndroid Build Coastguard Worker
1597*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Stop;
1598*8975f5c5SAndroid Build Coastguard Worker}
1599*8975f5c5SAndroid Build Coastguard Worker
1600*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setStorageMultisample(const gl::Context *context,
1601*8975f5c5SAndroid Build Coastguard Worker                                                gl::TextureType type,
1602*8975f5c5SAndroid Build Coastguard Worker                                                GLsizei samples,
1603*8975f5c5SAndroid Build Coastguard Worker                                                GLint internalFormat,
1604*8975f5c5SAndroid Build Coastguard Worker                                                const gl::Extents &size,
1605*8975f5c5SAndroid Build Coastguard Worker                                                bool fixedSampleLocations)
1606*8975f5c5SAndroid Build Coastguard Worker{
1607*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl               = mtl::GetImpl(context);
1608*8975f5c5SAndroid Build Coastguard Worker    const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
1609*8975f5c5SAndroid Build Coastguard Worker    angle::FormatID angleFormatId =
1610*8975f5c5SAndroid Build Coastguard Worker        angle::Format::InternalFormatToID(formatInfo.sizedInternalFormat);
1611*8975f5c5SAndroid Build Coastguard Worker    const mtl::Format &mtlFormat = contextMtl->getPixelFormat(angleFormatId);
1612*8975f5c5SAndroid Build Coastguard Worker
1613*8975f5c5SAndroid Build Coastguard Worker    return setStorageImpl(context, type, 0, mState.getLevelZeroDesc().samples, mtlFormat, size);
1614*8975f5c5SAndroid Build Coastguard Worker}
1615*8975f5c5SAndroid Build Coastguard Worker
1616*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setEGLImageTarget(const gl::Context *context,
1617*8975f5c5SAndroid Build Coastguard Worker                                            gl::TextureType type,
1618*8975f5c5SAndroid Build Coastguard Worker                                            egl::Image *image)
1619*8975f5c5SAndroid Build Coastguard Worker{
1620*8975f5c5SAndroid Build Coastguard Worker    deallocateNativeStorage(/*keepImages=*/false);
1621*8975f5c5SAndroid Build Coastguard Worker
1622*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
1623*8975f5c5SAndroid Build Coastguard Worker
1624*8975f5c5SAndroid Build Coastguard Worker    ImageMtl *imageMtl = mtl::GetImpl(image);
1625*8975f5c5SAndroid Build Coastguard Worker    if (type != imageMtl->getImageTextureType())
1626*8975f5c5SAndroid Build Coastguard Worker    {
1627*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Stop;
1628*8975f5c5SAndroid Build Coastguard Worker    }
1629*8975f5c5SAndroid Build Coastguard Worker
1630*8975f5c5SAndroid Build Coastguard Worker    mNativeTextureStorage = std::make_unique<NativeTextureWrapperWithViewSupport>(
1631*8975f5c5SAndroid Build Coastguard Worker        imageMtl->getTexture(), /*baseGLLevel=*/0);
1632*8975f5c5SAndroid Build Coastguard Worker
1633*8975f5c5SAndroid Build Coastguard Worker    const angle::FormatID angleFormatId =
1634*8975f5c5SAndroid Build Coastguard Worker        angle::Format::InternalFormatToID(image->getFormat().info->sizedInternalFormat);
1635*8975f5c5SAndroid Build Coastguard Worker    mFormat = contextMtl->getPixelFormat(angleFormatId);
1636*8975f5c5SAndroid Build Coastguard Worker
1637*8975f5c5SAndroid Build Coastguard Worker    mSlices = mNativeTextureStorage->cubeFacesOrArrayLength();
1638*8975f5c5SAndroid Build Coastguard Worker
1639*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(ensureSamplerStateCreated(context));
1640*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(createViewFromBaseToMaxLevel());
1641*8975f5c5SAndroid Build Coastguard Worker
1642*8975f5c5SAndroid Build Coastguard Worker    // Tell context to rebind textures
1643*8975f5c5SAndroid Build Coastguard Worker    contextMtl->invalidateCurrentTextures();
1644*8975f5c5SAndroid Build Coastguard Worker
1645*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
1646*8975f5c5SAndroid Build Coastguard Worker}
1647*8975f5c5SAndroid Build Coastguard Worker
1648*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setImageExternal(const gl::Context *context,
1649*8975f5c5SAndroid Build Coastguard Worker                                           gl::TextureType type,
1650*8975f5c5SAndroid Build Coastguard Worker                                           egl::Stream *stream,
1651*8975f5c5SAndroid Build Coastguard Worker                                           const egl::Stream::GLTextureDescription &desc)
1652*8975f5c5SAndroid Build Coastguard Worker{
1653*8975f5c5SAndroid Build Coastguard Worker    UNIMPLEMENTED();
1654*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Stop;
1655*8975f5c5SAndroid Build Coastguard Worker}
1656*8975f5c5SAndroid Build Coastguard Worker
1657*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::generateMipmap(const gl::Context *context)
1658*8975f5c5SAndroid Build Coastguard Worker{
1659*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(ensureNativeStorageCreated(context));
1660*8975f5c5SAndroid Build Coastguard Worker
1661*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
1662*8975f5c5SAndroid Build Coastguard Worker    if (!mViewFromBaseToMaxLevel)
1663*8975f5c5SAndroid Build Coastguard Worker    {
1664*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
1665*8975f5c5SAndroid Build Coastguard Worker    }
1666*8975f5c5SAndroid Build Coastguard Worker
1667*8975f5c5SAndroid Build Coastguard Worker    const mtl::FormatCaps &caps = mFormat.getCaps();
1668*8975f5c5SAndroid Build Coastguard Worker    //
1669*8975f5c5SAndroid Build Coastguard Worker    bool sRGB = mFormat.actualInternalFormat().colorEncoding == GL_SRGB;
1670*8975f5c5SAndroid Build Coastguard Worker
1671*8975f5c5SAndroid Build Coastguard Worker    bool avoidGPUPath =
1672*8975f5c5SAndroid Build Coastguard Worker        contextMtl->getDisplay()->getFeatures().forceNonCSBaseMipmapGeneration.enabled &&
1673*8975f5c5SAndroid Build Coastguard Worker        mViewFromBaseToMaxLevel->widthAt0() < 5;
1674*8975f5c5SAndroid Build Coastguard Worker
1675*8975f5c5SAndroid Build Coastguard Worker    if (!avoidGPUPath && caps.writable && mState.getType() == gl::TextureType::_3D)
1676*8975f5c5SAndroid Build Coastguard Worker    {
1677*8975f5c5SAndroid Build Coastguard Worker        // http://anglebug.com/42263496.
1678*8975f5c5SAndroid Build Coastguard Worker        // Use compute for 3D mipmap generation.
1679*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(ensureLevelViewsWithinBaseMaxCreated());
1680*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(contextMtl->getDisplay()->getUtils().generateMipmapCS(
1681*8975f5c5SAndroid Build Coastguard Worker            contextMtl, *mViewFromBaseToMaxLevel, sRGB, &mLevelViewsWithinBaseMax));
1682*8975f5c5SAndroid Build Coastguard Worker    }
1683*8975f5c5SAndroid Build Coastguard Worker    else if (!avoidGPUPath && caps.filterable && caps.colorRenderable)
1684*8975f5c5SAndroid Build Coastguard Worker    {
1685*8975f5c5SAndroid Build Coastguard Worker        mtl::BlitCommandEncoder *blitEncoder = GetBlitCommandEncoderForResources(
1686*8975f5c5SAndroid Build Coastguard Worker            contextMtl, {mViewFromBaseToMaxLevel->getNativeTexture().get()});
1687*8975f5c5SAndroid Build Coastguard Worker        blitEncoder->generateMipmapsForTexture(*mViewFromBaseToMaxLevel);
1688*8975f5c5SAndroid Build Coastguard Worker    }
1689*8975f5c5SAndroid Build Coastguard Worker    else
1690*8975f5c5SAndroid Build Coastguard Worker    {
1691*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(generateMipmapCPU(context));
1692*8975f5c5SAndroid Build Coastguard Worker    }
1693*8975f5c5SAndroid Build Coastguard Worker
1694*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
1695*8975f5c5SAndroid Build Coastguard Worker}
1696*8975f5c5SAndroid Build Coastguard Worker
1697*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::generateMipmapCPU(const gl::Context *context)
1698*8975f5c5SAndroid Build Coastguard Worker{
1699*8975f5c5SAndroid Build Coastguard Worker    ASSERT(mViewFromBaseToMaxLevel);
1700*8975f5c5SAndroid Build Coastguard Worker
1701*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl           = mtl::GetImpl(context);
1702*8975f5c5SAndroid Build Coastguard Worker    const angle::Format &angleFormat = mFormat.actualAngleFormat();
1703*8975f5c5SAndroid Build Coastguard Worker    // This format must have mip generation function.
1704*8975f5c5SAndroid Build Coastguard Worker    ANGLE_MTL_TRY(contextMtl, angleFormat.mipGenerationFunction);
1705*8975f5c5SAndroid Build Coastguard Worker
1706*8975f5c5SAndroid Build Coastguard Worker    for (uint32_t slice = 0; slice < mSlices; ++slice)
1707*8975f5c5SAndroid Build Coastguard Worker    {
1708*8975f5c5SAndroid Build Coastguard Worker        GLuint baseGLLevel = mViewFromBaseToMaxLevel->getBaseGLLevel();
1709*8975f5c5SAndroid Build Coastguard Worker
1710*8975f5c5SAndroid Build Coastguard Worker        uint32_t prevLevelWidth    = mViewFromBaseToMaxLevel->widthAt0();
1711*8975f5c5SAndroid Build Coastguard Worker        uint32_t prevLevelHeight   = mViewFromBaseToMaxLevel->heightAt0();
1712*8975f5c5SAndroid Build Coastguard Worker        uint32_t prevLevelDepth    = mViewFromBaseToMaxLevel->depthAt0();
1713*8975f5c5SAndroid Build Coastguard Worker        size_t prevLevelRowPitch   = angleFormat.pixelBytes * prevLevelWidth;
1714*8975f5c5SAndroid Build Coastguard Worker        size_t prevLevelDepthPitch = prevLevelRowPitch * prevLevelHeight;
1715*8975f5c5SAndroid Build Coastguard Worker        std::unique_ptr<uint8_t[]> prevLevelData(new (std::nothrow)
1716*8975f5c5SAndroid Build Coastguard Worker                                                     uint8_t[prevLevelDepthPitch * prevLevelDepth]);
1717*8975f5c5SAndroid Build Coastguard Worker        ANGLE_CHECK_GL_ALLOC(contextMtl, prevLevelData);
1718*8975f5c5SAndroid Build Coastguard Worker        std::unique_ptr<uint8_t[]> dstLevelData;
1719*8975f5c5SAndroid Build Coastguard Worker
1720*8975f5c5SAndroid Build Coastguard Worker        // Download base level data
1721*8975f5c5SAndroid Build Coastguard Worker        mViewFromBaseToMaxLevel->getBytes(
1722*8975f5c5SAndroid Build Coastguard Worker            contextMtl, prevLevelRowPitch, prevLevelDepthPitch,
1723*8975f5c5SAndroid Build Coastguard Worker            MTLRegionMake3D(0, 0, 0, prevLevelWidth, prevLevelHeight, prevLevelDepth), baseGLLevel,
1724*8975f5c5SAndroid Build Coastguard Worker            slice, prevLevelData.get());
1725*8975f5c5SAndroid Build Coastguard Worker
1726*8975f5c5SAndroid Build Coastguard Worker        for (GLuint mip = 1; mip < mViewFromBaseToMaxLevel->mipmapLevels(); ++mip)
1727*8975f5c5SAndroid Build Coastguard Worker        {
1728*8975f5c5SAndroid Build Coastguard Worker            GLuint glLevel     = baseGLLevel + mip;
1729*8975f5c5SAndroid Build Coastguard Worker            uint32_t dstWidth  = mViewFromBaseToMaxLevel->width(glLevel);
1730*8975f5c5SAndroid Build Coastguard Worker            uint32_t dstHeight = mViewFromBaseToMaxLevel->height(glLevel);
1731*8975f5c5SAndroid Build Coastguard Worker            uint32_t dstDepth  = mViewFromBaseToMaxLevel->depth(glLevel);
1732*8975f5c5SAndroid Build Coastguard Worker
1733*8975f5c5SAndroid Build Coastguard Worker            size_t dstRowPitch   = angleFormat.pixelBytes * dstWidth;
1734*8975f5c5SAndroid Build Coastguard Worker            size_t dstDepthPitch = dstRowPitch * dstHeight;
1735*8975f5c5SAndroid Build Coastguard Worker            size_t dstDataSize   = dstDepthPitch * dstDepth;
1736*8975f5c5SAndroid Build Coastguard Worker            if (!dstLevelData)
1737*8975f5c5SAndroid Build Coastguard Worker            {
1738*8975f5c5SAndroid Build Coastguard Worker                // Allocate once and reuse the buffer
1739*8975f5c5SAndroid Build Coastguard Worker                dstLevelData.reset(new (std::nothrow) uint8_t[dstDataSize]);
1740*8975f5c5SAndroid Build Coastguard Worker                ANGLE_CHECK_GL_ALLOC(contextMtl, dstLevelData);
1741*8975f5c5SAndroid Build Coastguard Worker            }
1742*8975f5c5SAndroid Build Coastguard Worker
1743*8975f5c5SAndroid Build Coastguard Worker            // Generate mip level
1744*8975f5c5SAndroid Build Coastguard Worker            angleFormat.mipGenerationFunction(
1745*8975f5c5SAndroid Build Coastguard Worker                prevLevelWidth, prevLevelHeight, 1, prevLevelData.get(), prevLevelRowPitch,
1746*8975f5c5SAndroid Build Coastguard Worker                prevLevelDepthPitch, dstLevelData.get(), dstRowPitch, dstDepthPitch);
1747*8975f5c5SAndroid Build Coastguard Worker
1748*8975f5c5SAndroid Build Coastguard Worker            mtl::MipmapNativeLevel nativeLevel = mViewFromBaseToMaxLevel->getNativeLevel(glLevel);
1749*8975f5c5SAndroid Build Coastguard Worker
1750*8975f5c5SAndroid Build Coastguard Worker            // Upload to texture
1751*8975f5c5SAndroid Build Coastguard Worker            ANGLE_TRY(UploadTextureContents(context, angleFormat,
1752*8975f5c5SAndroid Build Coastguard Worker                                            MTLRegionMake3D(0, 0, 0, dstWidth, dstHeight, dstDepth),
1753*8975f5c5SAndroid Build Coastguard Worker                                            nativeLevel, slice, dstLevelData.get(), dstRowPitch,
1754*8975f5c5SAndroid Build Coastguard Worker                                            dstDepthPitch, false, *mViewFromBaseToMaxLevel));
1755*8975f5c5SAndroid Build Coastguard Worker
1756*8975f5c5SAndroid Build Coastguard Worker            prevLevelWidth      = dstWidth;
1757*8975f5c5SAndroid Build Coastguard Worker            prevLevelHeight     = dstHeight;
1758*8975f5c5SAndroid Build Coastguard Worker            prevLevelDepth      = dstDepth;
1759*8975f5c5SAndroid Build Coastguard Worker            prevLevelRowPitch   = dstRowPitch;
1760*8975f5c5SAndroid Build Coastguard Worker            prevLevelDepthPitch = dstDepthPitch;
1761*8975f5c5SAndroid Build Coastguard Worker            std::swap(prevLevelData, dstLevelData);
1762*8975f5c5SAndroid Build Coastguard Worker        }  // for mip level
1763*8975f5c5SAndroid Build Coastguard Worker
1764*8975f5c5SAndroid Build Coastguard Worker    }  // For layers
1765*8975f5c5SAndroid Build Coastguard Worker
1766*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
1767*8975f5c5SAndroid Build Coastguard Worker}
1768*8975f5c5SAndroid Build Coastguard Worker
1769*8975f5c5SAndroid Build Coastguard Workerbool TextureMtl::needsFormatViewForPixelLocalStorage(
1770*8975f5c5SAndroid Build Coastguard Worker    const ShPixelLocalStorageOptions &plsOptions) const
1771*8975f5c5SAndroid Build Coastguard Worker{
1772*8975f5c5SAndroid Build Coastguard Worker    // On iOS devices with GPU family 5 and later, Metal doesn't apply lossless compression to
1773*8975f5c5SAndroid Build Coastguard Worker    // the texture if we set MTLTextureUsagePixelFormatView. This shouldn't be a problem though
1774*8975f5c5SAndroid Build Coastguard Worker    // because iOS devices implement pixel local storage with framebuffer fetch instead of shader
1775*8975f5c5SAndroid Build Coastguard Worker    // images.
1776*8975f5c5SAndroid Build Coastguard Worker    if (plsOptions.type == ShPixelLocalStorageType::ImageLoadStore)
1777*8975f5c5SAndroid Build Coastguard Worker    {
1778*8975f5c5SAndroid Build Coastguard Worker        switch (mFormat.metalFormat)
1779*8975f5c5SAndroid Build Coastguard Worker        {
1780*8975f5c5SAndroid Build Coastguard Worker            case MTLPixelFormatRGBA8Unorm:
1781*8975f5c5SAndroid Build Coastguard Worker            case MTLPixelFormatRGBA8Uint:
1782*8975f5c5SAndroid Build Coastguard Worker            case MTLPixelFormatRGBA8Sint:
1783*8975f5c5SAndroid Build Coastguard Worker                return !plsOptions.supportsNativeRGBA8ImageFormats;
1784*8975f5c5SAndroid Build Coastguard Worker            default:
1785*8975f5c5SAndroid Build Coastguard Worker                break;
1786*8975f5c5SAndroid Build Coastguard Worker        }
1787*8975f5c5SAndroid Build Coastguard Worker    }
1788*8975f5c5SAndroid Build Coastguard Worker    return false;
1789*8975f5c5SAndroid Build Coastguard Worker}
1790*8975f5c5SAndroid Build Coastguard Worker
1791*8975f5c5SAndroid Build Coastguard Workerbool TextureMtl::isImmutableOrPBuffer() const
1792*8975f5c5SAndroid Build Coastguard Worker{
1793*8975f5c5SAndroid Build Coastguard Worker    return mState.getImmutableFormat() || mBoundSurface;
1794*8975f5c5SAndroid Build Coastguard Worker}
1795*8975f5c5SAndroid Build Coastguard Worker
1796*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setBaseLevel(const gl::Context *context, GLuint baseLevel)
1797*8975f5c5SAndroid Build Coastguard Worker{
1798*8975f5c5SAndroid Build Coastguard Worker    return onBaseMaxLevelsChanged(context);
1799*8975f5c5SAndroid Build Coastguard Worker}
1800*8975f5c5SAndroid Build Coastguard Worker
1801*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::bindTexImage(const gl::Context *context, egl::Surface *surface)
1802*8975f5c5SAndroid Build Coastguard Worker{
1803*8975f5c5SAndroid Build Coastguard Worker    deallocateNativeStorage(/*keepImages=*/false);
1804*8975f5c5SAndroid Build Coastguard Worker
1805*8975f5c5SAndroid Build Coastguard Worker    mBoundSurface         = surface;
1806*8975f5c5SAndroid Build Coastguard Worker    auto pBuffer          = GetImplAs<OffscreenSurfaceMtl>(surface);
1807*8975f5c5SAndroid Build Coastguard Worker    mNativeTextureStorage = std::make_unique<NativeTextureWrapperWithViewSupport>(
1808*8975f5c5SAndroid Build Coastguard Worker        pBuffer->getColorTexture(), /*baseGLLevel=*/0);
1809*8975f5c5SAndroid Build Coastguard Worker    mFormat = pBuffer->getColorFormat();
1810*8975f5c5SAndroid Build Coastguard Worker    mSlices = mNativeTextureStorage->cubeFacesOrArrayLength();
1811*8975f5c5SAndroid Build Coastguard Worker
1812*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(ensureSamplerStateCreated(context));
1813*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(createViewFromBaseToMaxLevel());
1814*8975f5c5SAndroid Build Coastguard Worker
1815*8975f5c5SAndroid Build Coastguard Worker    // Tell context to rebind textures
1816*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
1817*8975f5c5SAndroid Build Coastguard Worker    contextMtl->invalidateCurrentTextures();
1818*8975f5c5SAndroid Build Coastguard Worker
1819*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
1820*8975f5c5SAndroid Build Coastguard Worker}
1821*8975f5c5SAndroid Build Coastguard Worker
1822*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::releaseTexImage(const gl::Context *context)
1823*8975f5c5SAndroid Build Coastguard Worker{
1824*8975f5c5SAndroid Build Coastguard Worker    deallocateNativeStorage(/*keepImages=*/false);
1825*8975f5c5SAndroid Build Coastguard Worker    mBoundSurface = nullptr;
1826*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
1827*8975f5c5SAndroid Build Coastguard Worker}
1828*8975f5c5SAndroid Build Coastguard Worker
1829*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::getAttachmentRenderTarget(const gl::Context *context,
1830*8975f5c5SAndroid Build Coastguard Worker                                                    GLenum binding,
1831*8975f5c5SAndroid Build Coastguard Worker                                                    const gl::ImageIndex &imageIndex,
1832*8975f5c5SAndroid Build Coastguard Worker                                                    GLsizei samples,
1833*8975f5c5SAndroid Build Coastguard Worker                                                    FramebufferAttachmentRenderTarget **rtOut)
1834*8975f5c5SAndroid Build Coastguard Worker{
1835*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(ensureNativeStorageCreated(context));
1836*8975f5c5SAndroid Build Coastguard Worker
1837*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
1838*8975f5c5SAndroid Build Coastguard Worker    ANGLE_MTL_TRY(contextMtl, mNativeTextureStorage);
1839*8975f5c5SAndroid Build Coastguard Worker
1840*8975f5c5SAndroid Build Coastguard Worker    RenderTargetMtl *rtt;
1841*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(getRenderTarget(contextMtl, imageIndex, samples, &rtt));
1842*8975f5c5SAndroid Build Coastguard Worker
1843*8975f5c5SAndroid Build Coastguard Worker    *rtOut = rtt;
1844*8975f5c5SAndroid Build Coastguard Worker
1845*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
1846*8975f5c5SAndroid Build Coastguard Worker}
1847*8975f5c5SAndroid Build Coastguard Worker
1848*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::syncState(const gl::Context *context,
1849*8975f5c5SAndroid Build Coastguard Worker                                    const gl::Texture::DirtyBits &dirtyBits,
1850*8975f5c5SAndroid Build Coastguard Worker                                    gl::Command source)
1851*8975f5c5SAndroid Build Coastguard Worker{
1852*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
1853*8975f5c5SAndroid Build Coastguard Worker    for (size_t dirtyBit : dirtyBits)
1854*8975f5c5SAndroid Build Coastguard Worker    {
1855*8975f5c5SAndroid Build Coastguard Worker        switch (dirtyBit)
1856*8975f5c5SAndroid Build Coastguard Worker        {
1857*8975f5c5SAndroid Build Coastguard Worker            case gl::Texture::DIRTY_BIT_COMPARE_MODE:
1858*8975f5c5SAndroid Build Coastguard Worker            case gl::Texture::DIRTY_BIT_COMPARE_FUNC:
1859*8975f5c5SAndroid Build Coastguard Worker                // Tell context to rebind textures so that ProgramMtl has a chance to verify
1860*8975f5c5SAndroid Build Coastguard Worker                // depth texture compare mode.
1861*8975f5c5SAndroid Build Coastguard Worker                contextMtl->invalidateCurrentTextures();
1862*8975f5c5SAndroid Build Coastguard Worker                // fall through
1863*8975f5c5SAndroid Build Coastguard Worker                OS_FALLTHROUGH;
1864*8975f5c5SAndroid Build Coastguard Worker            case gl::Texture::DIRTY_BIT_MIN_FILTER:
1865*8975f5c5SAndroid Build Coastguard Worker            case gl::Texture::DIRTY_BIT_MAG_FILTER:
1866*8975f5c5SAndroid Build Coastguard Worker            case gl::Texture::DIRTY_BIT_WRAP_S:
1867*8975f5c5SAndroid Build Coastguard Worker            case gl::Texture::DIRTY_BIT_WRAP_T:
1868*8975f5c5SAndroid Build Coastguard Worker            case gl::Texture::DIRTY_BIT_WRAP_R:
1869*8975f5c5SAndroid Build Coastguard Worker            case gl::Texture::DIRTY_BIT_MAX_ANISOTROPY:
1870*8975f5c5SAndroid Build Coastguard Worker            case gl::Texture::DIRTY_BIT_MIN_LOD:
1871*8975f5c5SAndroid Build Coastguard Worker            case gl::Texture::DIRTY_BIT_MAX_LOD:
1872*8975f5c5SAndroid Build Coastguard Worker            case gl::Texture::DIRTY_BIT_SRGB_DECODE:
1873*8975f5c5SAndroid Build Coastguard Worker            case gl::Texture::DIRTY_BIT_BORDER_COLOR:
1874*8975f5c5SAndroid Build Coastguard Worker                // Recreate sampler state
1875*8975f5c5SAndroid Build Coastguard Worker                mMetalSamplerState = nil;
1876*8975f5c5SAndroid Build Coastguard Worker                break;
1877*8975f5c5SAndroid Build Coastguard Worker            case gl::Texture::DIRTY_BIT_MAX_LEVEL:
1878*8975f5c5SAndroid Build Coastguard Worker            case gl::Texture::DIRTY_BIT_BASE_LEVEL:
1879*8975f5c5SAndroid Build Coastguard Worker                ANGLE_TRY(onBaseMaxLevelsChanged(context));
1880*8975f5c5SAndroid Build Coastguard Worker                break;
1881*8975f5c5SAndroid Build Coastguard Worker            case gl::Texture::DIRTY_BIT_SWIZZLE_RED:
1882*8975f5c5SAndroid Build Coastguard Worker            case gl::Texture::DIRTY_BIT_SWIZZLE_GREEN:
1883*8975f5c5SAndroid Build Coastguard Worker            case gl::Texture::DIRTY_BIT_SWIZZLE_BLUE:
1884*8975f5c5SAndroid Build Coastguard Worker            case gl::Texture::DIRTY_BIT_SWIZZLE_ALPHA:
1885*8975f5c5SAndroid Build Coastguard Worker            case gl::Texture::DIRTY_BIT_DEPTH_STENCIL_TEXTURE_MODE:
1886*8975f5c5SAndroid Build Coastguard Worker            {
1887*8975f5c5SAndroid Build Coastguard Worker                // Recreate swizzle/stencil view.
1888*8975f5c5SAndroid Build Coastguard Worker                mSwizzleStencilSamplingView = nullptr;
1889*8975f5c5SAndroid Build Coastguard Worker            }
1890*8975f5c5SAndroid Build Coastguard Worker            break;
1891*8975f5c5SAndroid Build Coastguard Worker            default:
1892*8975f5c5SAndroid Build Coastguard Worker                break;
1893*8975f5c5SAndroid Build Coastguard Worker        }
1894*8975f5c5SAndroid Build Coastguard Worker    }
1895*8975f5c5SAndroid Build Coastguard Worker
1896*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(ensureNativeStorageCreated(context));
1897*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(ensureSamplerStateCreated(context));
1898*8975f5c5SAndroid Build Coastguard Worker
1899*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
1900*8975f5c5SAndroid Build Coastguard Worker}
1901*8975f5c5SAndroid Build Coastguard Worker
1902*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::bindToShader(const gl::Context *context,
1903*8975f5c5SAndroid Build Coastguard Worker                                       mtl::RenderCommandEncoder *cmdEncoder,
1904*8975f5c5SAndroid Build Coastguard Worker                                       gl::ShaderType shaderType,
1905*8975f5c5SAndroid Build Coastguard Worker                                       gl::Sampler *sampler,
1906*8975f5c5SAndroid Build Coastguard Worker                                       int textureSlotIndex,
1907*8975f5c5SAndroid Build Coastguard Worker                                       int samplerSlotIndex)
1908*8975f5c5SAndroid Build Coastguard Worker{
1909*8975f5c5SAndroid Build Coastguard Worker    ASSERT(mNativeTextureStorage);
1910*8975f5c5SAndroid Build Coastguard Worker    ASSERT(mViewFromBaseToMaxLevel);
1911*8975f5c5SAndroid Build Coastguard Worker
1912*8975f5c5SAndroid Build Coastguard Worker    float minLodClamp;
1913*8975f5c5SAndroid Build Coastguard Worker    float maxLodClamp;
1914*8975f5c5SAndroid Build Coastguard Worker    id<MTLSamplerState> samplerState;
1915*8975f5c5SAndroid Build Coastguard Worker
1916*8975f5c5SAndroid Build Coastguard Worker    if (!mSwizzleStencilSamplingView)
1917*8975f5c5SAndroid Build Coastguard Worker    {
1918*8975f5c5SAndroid Build Coastguard Worker        ContextMtl *contextMtl             = mtl::GetImpl(context);
1919*8975f5c5SAndroid Build Coastguard Worker        const angle::FeaturesMtl &features = contextMtl->getDisplay()->getFeatures();
1920*8975f5c5SAndroid Build Coastguard Worker
1921*8975f5c5SAndroid Build Coastguard Worker        // Sampling from unused channels of depth and stencil textures is undefined in Metal.
1922*8975f5c5SAndroid Build Coastguard Worker        // ANGLE relies on swizzled views to enforce values required by OpenGL ES specs. Some
1923*8975f5c5SAndroid Build Coastguard Worker        // drivers fail to sample from a swizzled view of a stencil texture so skip this step.
1924*8975f5c5SAndroid Build Coastguard Worker        const bool skipStencilSwizzle = mFormat.actualFormatId == angle::FormatID::S8_UINT &&
1925*8975f5c5SAndroid Build Coastguard Worker                                        features.avoidStencilTextureSwizzle.enabled;
1926*8975f5c5SAndroid Build Coastguard Worker        if (!skipStencilSwizzle &&
1927*8975f5c5SAndroid Build Coastguard Worker            (mState.getSwizzleState().swizzleRequired() ||
1928*8975f5c5SAndroid Build Coastguard Worker             mFormat.actualAngleFormat().hasDepthOrStencilBits() || mFormat.swizzled) &&
1929*8975f5c5SAndroid Build Coastguard Worker            features.hasTextureSwizzle.enabled)
1930*8975f5c5SAndroid Build Coastguard Worker        {
1931*8975f5c5SAndroid Build Coastguard Worker            const gl::InternalFormat &glInternalFormat = *mState.getBaseLevelDesc().format.info;
1932*8975f5c5SAndroid Build Coastguard Worker
1933*8975f5c5SAndroid Build Coastguard Worker            MTLTextureSwizzleChannels swizzle = MTLTextureSwizzleChannelsMake(
1934*8975f5c5SAndroid Build Coastguard Worker                mtl::GetTextureSwizzle(OverrideSwizzleValue(
1935*8975f5c5SAndroid Build Coastguard Worker                    context, mState.getSwizzleState().swizzleRed, mFormat, glInternalFormat)),
1936*8975f5c5SAndroid Build Coastguard Worker                mtl::GetTextureSwizzle(OverrideSwizzleValue(
1937*8975f5c5SAndroid Build Coastguard Worker                    context, mState.getSwizzleState().swizzleGreen, mFormat, glInternalFormat)),
1938*8975f5c5SAndroid Build Coastguard Worker                mtl::GetTextureSwizzle(OverrideSwizzleValue(
1939*8975f5c5SAndroid Build Coastguard Worker                    context, mState.getSwizzleState().swizzleBlue, mFormat, glInternalFormat)),
1940*8975f5c5SAndroid Build Coastguard Worker                mtl::GetTextureSwizzle(OverrideSwizzleValue(
1941*8975f5c5SAndroid Build Coastguard Worker                    context, mState.getSwizzleState().swizzleAlpha, mFormat, glInternalFormat)));
1942*8975f5c5SAndroid Build Coastguard Worker
1943*8975f5c5SAndroid Build Coastguard Worker            MTLPixelFormat format = mViewFromBaseToMaxLevel->pixelFormat();
1944*8975f5c5SAndroid Build Coastguard Worker            if (mState.isStencilMode())
1945*8975f5c5SAndroid Build Coastguard Worker            {
1946*8975f5c5SAndroid Build Coastguard Worker                if (format == MTLPixelFormatDepth32Float_Stencil8)
1947*8975f5c5SAndroid Build Coastguard Worker                {
1948*8975f5c5SAndroid Build Coastguard Worker                    format = MTLPixelFormatX32_Stencil8;
1949*8975f5c5SAndroid Build Coastguard Worker                }
1950*8975f5c5SAndroid Build Coastguard Worker#    if TARGET_OS_OSX || TARGET_OS_MACCATALYST
1951*8975f5c5SAndroid Build Coastguard Worker                else if (format == MTLPixelFormatDepth24Unorm_Stencil8)
1952*8975f5c5SAndroid Build Coastguard Worker                {
1953*8975f5c5SAndroid Build Coastguard Worker                    format = MTLPixelFormatX24_Stencil8;
1954*8975f5c5SAndroid Build Coastguard Worker                }
1955*8975f5c5SAndroid Build Coastguard Worker#    endif
1956*8975f5c5SAndroid Build Coastguard Worker            }
1957*8975f5c5SAndroid Build Coastguard Worker
1958*8975f5c5SAndroid Build Coastguard Worker            mSwizzleStencilSamplingView = mNativeTextureStorage->createMipsSwizzleView(
1959*8975f5c5SAndroid Build Coastguard Worker                mViewFromBaseToMaxLevel->getBaseGLLevel(), mViewFromBaseToMaxLevel->mipmapLevels(),
1960*8975f5c5SAndroid Build Coastguard Worker                format, swizzle);
1961*8975f5c5SAndroid Build Coastguard Worker        }
1962*8975f5c5SAndroid Build Coastguard Worker        else
1963*8975f5c5SAndroid Build Coastguard Worker        {
1964*8975f5c5SAndroid Build Coastguard Worker            mSwizzleStencilSamplingView = mState.isStencilMode()
1965*8975f5c5SAndroid Build Coastguard Worker                                              ? mViewFromBaseToMaxLevel->getStencilView()
1966*8975f5c5SAndroid Build Coastguard Worker                                              : mViewFromBaseToMaxLevel->getNativeTexture();
1967*8975f5c5SAndroid Build Coastguard Worker        }
1968*8975f5c5SAndroid Build Coastguard Worker    }
1969*8975f5c5SAndroid Build Coastguard Worker
1970*8975f5c5SAndroid Build Coastguard Worker    if (!sampler)
1971*8975f5c5SAndroid Build Coastguard Worker    {
1972*8975f5c5SAndroid Build Coastguard Worker        samplerState = mMetalSamplerState;
1973*8975f5c5SAndroid Build Coastguard Worker        minLodClamp  = mState.getSamplerState().getMinLod();
1974*8975f5c5SAndroid Build Coastguard Worker        maxLodClamp  = mState.getSamplerState().getMaxLod();
1975*8975f5c5SAndroid Build Coastguard Worker    }
1976*8975f5c5SAndroid Build Coastguard Worker    else
1977*8975f5c5SAndroid Build Coastguard Worker    {
1978*8975f5c5SAndroid Build Coastguard Worker        SamplerMtl *samplerMtl = mtl::GetImpl(sampler);
1979*8975f5c5SAndroid Build Coastguard Worker        samplerState           = samplerMtl->getSampler(mtl::GetImpl(context));
1980*8975f5c5SAndroid Build Coastguard Worker        minLodClamp            = sampler->getSamplerState().getMinLod();
1981*8975f5c5SAndroid Build Coastguard Worker        maxLodClamp            = sampler->getSamplerState().getMaxLod();
1982*8975f5c5SAndroid Build Coastguard Worker    }
1983*8975f5c5SAndroid Build Coastguard Worker
1984*8975f5c5SAndroid Build Coastguard Worker    minLodClamp = std::max(minLodClamp, 0.f);
1985*8975f5c5SAndroid Build Coastguard Worker
1986*8975f5c5SAndroid Build Coastguard Worker    cmdEncoder->setTexture(shaderType, mSwizzleStencilSamplingView, textureSlotIndex);
1987*8975f5c5SAndroid Build Coastguard Worker    cmdEncoder->setSamplerState(shaderType, samplerState, minLodClamp, maxLodClamp,
1988*8975f5c5SAndroid Build Coastguard Worker                                samplerSlotIndex);
1989*8975f5c5SAndroid Build Coastguard Worker
1990*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
1991*8975f5c5SAndroid Build Coastguard Worker}
1992*8975f5c5SAndroid Build Coastguard Worker
1993*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::bindToShaderImage(const gl::Context *context,
1994*8975f5c5SAndroid Build Coastguard Worker                                            mtl::RenderCommandEncoder *cmdEncoder,
1995*8975f5c5SAndroid Build Coastguard Worker                                            gl::ShaderType shaderType,
1996*8975f5c5SAndroid Build Coastguard Worker                                            int textureSlotIndex,
1997*8975f5c5SAndroid Build Coastguard Worker                                            int level,
1998*8975f5c5SAndroid Build Coastguard Worker                                            int layer,
1999*8975f5c5SAndroid Build Coastguard Worker                                            GLenum format)
2000*8975f5c5SAndroid Build Coastguard Worker{
2001*8975f5c5SAndroid Build Coastguard Worker    ASSERT(mNativeTextureStorage);
2002*8975f5c5SAndroid Build Coastguard Worker    ASSERT(mState.getImmutableFormat());
2003*8975f5c5SAndroid Build Coastguard Worker    ASSERT(0 <= level && static_cast<uint32_t>(level) < mState.getImmutableLevels());
2004*8975f5c5SAndroid Build Coastguard Worker    ASSERT(0 <= layer && static_cast<uint32_t>(layer) < mSlices);
2005*8975f5c5SAndroid Build Coastguard Worker
2006*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl        = mtl::GetImpl(context);
2007*8975f5c5SAndroid Build Coastguard Worker    angle::FormatID angleFormatId = angle::Format::InternalFormatToID(format);
2008*8975f5c5SAndroid Build Coastguard Worker    mtl::Format imageAccessFormat = contextMtl->getPixelFormat(angleFormatId);
2009*8975f5c5SAndroid Build Coastguard Worker    LayerLevelTextureViewVector &textureViewVector =
2010*8975f5c5SAndroid Build Coastguard Worker        mShaderImageViews[imageAccessFormat.metalFormat];
2011*8975f5c5SAndroid Build Coastguard Worker    mtl::TextureRef &textureRef = GetLayerLevelTextureView(&textureViewVector, layer, level,
2012*8975f5c5SAndroid Build Coastguard Worker                                                           mSlices, mState.getImmutableLevels());
2013*8975f5c5SAndroid Build Coastguard Worker
2014*8975f5c5SAndroid Build Coastguard Worker    if (textureRef == nullptr)
2015*8975f5c5SAndroid Build Coastguard Worker    {
2016*8975f5c5SAndroid Build Coastguard Worker        textureRef = mNativeTextureStorage->createShaderImageView2D(level, layer,
2017*8975f5c5SAndroid Build Coastguard Worker                                                                    imageAccessFormat.metalFormat);
2018*8975f5c5SAndroid Build Coastguard Worker    }
2019*8975f5c5SAndroid Build Coastguard Worker
2020*8975f5c5SAndroid Build Coastguard Worker    cmdEncoder->setRWTexture(shaderType, textureRef, textureSlotIndex);
2021*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
2022*8975f5c5SAndroid Build Coastguard Worker}
2023*8975f5c5SAndroid Build Coastguard Worker
2024*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::redefineImage(const gl::Context *context,
2025*8975f5c5SAndroid Build Coastguard Worker                                        const gl::ImageIndex &index,
2026*8975f5c5SAndroid Build Coastguard Worker                                        const mtl::Format &mtlFormat,
2027*8975f5c5SAndroid Build Coastguard Worker                                        const gl::Extents &size)
2028*8975f5c5SAndroid Build Coastguard Worker{
2029*8975f5c5SAndroid Build Coastguard Worker    bool imageWithinNativeStorageLevels = false;
2030*8975f5c5SAndroid Build Coastguard Worker    if (mNativeTextureStorage && mNativeTextureStorage->isGLLevelSupported(index.getLevelIndex()))
2031*8975f5c5SAndroid Build Coastguard Worker    {
2032*8975f5c5SAndroid Build Coastguard Worker        imageWithinNativeStorageLevels = true;
2033*8975f5c5SAndroid Build Coastguard Worker        GLuint glLevel                 = index.getLevelIndex();
2034*8975f5c5SAndroid Build Coastguard Worker        // Calculate the expected size for the index we are defining. If the size is different
2035*8975f5c5SAndroid Build Coastguard Worker        // from the given size, or the format is different, we are redefining the image so we
2036*8975f5c5SAndroid Build Coastguard Worker        // must release it.
2037*8975f5c5SAndroid Build Coastguard Worker        ASSERT(mNativeTextureStorage->textureType() == mtl::GetTextureType(index.getType()));
2038*8975f5c5SAndroid Build Coastguard Worker        if (mFormat != mtlFormat || size != mNativeTextureStorage->size(glLevel))
2039*8975f5c5SAndroid Build Coastguard Worker        {
2040*8975f5c5SAndroid Build Coastguard Worker            // Keep other images
2041*8975f5c5SAndroid Build Coastguard Worker            deallocateNativeStorage(/*keepImages=*/true);
2042*8975f5c5SAndroid Build Coastguard Worker        }
2043*8975f5c5SAndroid Build Coastguard Worker    }
2044*8975f5c5SAndroid Build Coastguard Worker
2045*8975f5c5SAndroid Build Coastguard Worker    // Early-out on empty textures, don't create a zero-sized storage.
2046*8975f5c5SAndroid Build Coastguard Worker    if (size.empty())
2047*8975f5c5SAndroid Build Coastguard Worker    {
2048*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
2049*8975f5c5SAndroid Build Coastguard Worker    }
2050*8975f5c5SAndroid Build Coastguard Worker
2051*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
2052*8975f5c5SAndroid Build Coastguard Worker    // Cache last defined image format:
2053*8975f5c5SAndroid Build Coastguard Worker    mFormat                      = mtlFormat;
2054*8975f5c5SAndroid Build Coastguard Worker    ImageDefinitionMtl &imageDef = getImageDefinition(index);
2055*8975f5c5SAndroid Build Coastguard Worker
2056*8975f5c5SAndroid Build Coastguard Worker    // If native texture still exists, it means the size hasn't been changed, no need to create new
2057*8975f5c5SAndroid Build Coastguard Worker    // image
2058*8975f5c5SAndroid Build Coastguard Worker    if (mNativeTextureStorage && imageDef.image && imageWithinNativeStorageLevels)
2059*8975f5c5SAndroid Build Coastguard Worker    {
2060*8975f5c5SAndroid Build Coastguard Worker        ASSERT(imageDef.image->textureType() ==
2061*8975f5c5SAndroid Build Coastguard Worker                   mtl::GetTextureType(GetTextureImageType(index.getType())) &&
2062*8975f5c5SAndroid Build Coastguard Worker               imageDef.formatID == mFormat.intendedFormatId && imageDef.image->sizeAt0() == size);
2063*8975f5c5SAndroid Build Coastguard Worker    }
2064*8975f5c5SAndroid Build Coastguard Worker    else
2065*8975f5c5SAndroid Build Coastguard Worker    {
2066*8975f5c5SAndroid Build Coastguard Worker        imageDef.formatID    = mtlFormat.intendedFormatId;
2067*8975f5c5SAndroid Build Coastguard Worker        bool allowFormatView = mFormat.hasDepthAndStencilBits() ||
2068*8975f5c5SAndroid Build Coastguard Worker                               needsFormatViewForPixelLocalStorage(
2069*8975f5c5SAndroid Build Coastguard Worker                                   contextMtl->getDisplay()->getNativePixelLocalStorageOptions());
2070*8975f5c5SAndroid Build Coastguard Worker        // Create image to hold texture's data at this level & slice:
2071*8975f5c5SAndroid Build Coastguard Worker        switch (index.getType())
2072*8975f5c5SAndroid Build Coastguard Worker        {
2073*8975f5c5SAndroid Build Coastguard Worker            case gl::TextureType::_2D:
2074*8975f5c5SAndroid Build Coastguard Worker            case gl::TextureType::CubeMap:
2075*8975f5c5SAndroid Build Coastguard Worker                ANGLE_TRY(mtl::Texture::Make2DTexture(
2076*8975f5c5SAndroid Build Coastguard Worker                    contextMtl, mtlFormat, size.width, size.height, 1,
2077*8975f5c5SAndroid Build Coastguard Worker                    /** renderTargetOnly */ false, allowFormatView, &imageDef.image));
2078*8975f5c5SAndroid Build Coastguard Worker                break;
2079*8975f5c5SAndroid Build Coastguard Worker            case gl::TextureType::_3D:
2080*8975f5c5SAndroid Build Coastguard Worker                ANGLE_TRY(mtl::Texture::Make3DTexture(
2081*8975f5c5SAndroid Build Coastguard Worker                    contextMtl, mtlFormat, size.width, size.height, size.depth, 1,
2082*8975f5c5SAndroid Build Coastguard Worker                    /** renderTargetOnly */ false, allowFormatView, &imageDef.image));
2083*8975f5c5SAndroid Build Coastguard Worker                break;
2084*8975f5c5SAndroid Build Coastguard Worker            case gl::TextureType::_2DArray:
2085*8975f5c5SAndroid Build Coastguard Worker                ANGLE_TRY(mtl::Texture::Make2DArrayTexture(
2086*8975f5c5SAndroid Build Coastguard Worker                    contextMtl, mtlFormat, size.width, size.height, 1, size.depth,
2087*8975f5c5SAndroid Build Coastguard Worker                    /** renderTargetOnly */ false, allowFormatView, &imageDef.image));
2088*8975f5c5SAndroid Build Coastguard Worker                break;
2089*8975f5c5SAndroid Build Coastguard Worker            default:
2090*8975f5c5SAndroid Build Coastguard Worker                UNREACHABLE();
2091*8975f5c5SAndroid Build Coastguard Worker        }
2092*8975f5c5SAndroid Build Coastguard Worker
2093*8975f5c5SAndroid Build Coastguard Worker        // Make sure emulated channels are properly initialized in this newly allocated texture.
2094*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(checkForEmulatedChannels(context, mtlFormat, imageDef.image));
2095*8975f5c5SAndroid Build Coastguard Worker    }
2096*8975f5c5SAndroid Build Coastguard Worker
2097*8975f5c5SAndroid Build Coastguard Worker    // Tell context to rebind textures
2098*8975f5c5SAndroid Build Coastguard Worker    contextMtl->invalidateCurrentTextures();
2099*8975f5c5SAndroid Build Coastguard Worker
2100*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
2101*8975f5c5SAndroid Build Coastguard Worker}
2102*8975f5c5SAndroid Build Coastguard Worker
2103*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setStorageImpl(const gl::Context *context,
2104*8975f5c5SAndroid Build Coastguard Worker                                         gl::TextureType type,
2105*8975f5c5SAndroid Build Coastguard Worker                                         GLuint mips,
2106*8975f5c5SAndroid Build Coastguard Worker                                         GLuint samples,
2107*8975f5c5SAndroid Build Coastguard Worker                                         const mtl::Format &mtlFormat,
2108*8975f5c5SAndroid Build Coastguard Worker                                         const gl::Extents &size)
2109*8975f5c5SAndroid Build Coastguard Worker{
2110*8975f5c5SAndroid Build Coastguard Worker    // Don't need to hold old images data.
2111*8975f5c5SAndroid Build Coastguard Worker    deallocateNativeStorage(/*keepImages=*/false);
2112*8975f5c5SAndroid Build Coastguard Worker
2113*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
2114*8975f5c5SAndroid Build Coastguard Worker
2115*8975f5c5SAndroid Build Coastguard Worker    // Tell context to rebind textures
2116*8975f5c5SAndroid Build Coastguard Worker    contextMtl->invalidateCurrentTextures();
2117*8975f5c5SAndroid Build Coastguard Worker
2118*8975f5c5SAndroid Build Coastguard Worker    mFormat = mtlFormat;
2119*8975f5c5SAndroid Build Coastguard Worker
2120*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(createNativeStorage(context, type, mips, samples, size));
2121*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(createViewFromBaseToMaxLevel());
2122*8975f5c5SAndroid Build Coastguard Worker
2123*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
2124*8975f5c5SAndroid Build Coastguard Worker}
2125*8975f5c5SAndroid Build Coastguard Worker
2126*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setImageImpl(const gl::Context *context,
2127*8975f5c5SAndroid Build Coastguard Worker                                       const gl::ImageIndex &index,
2128*8975f5c5SAndroid Build Coastguard Worker                                       const gl::InternalFormat &dstFormatInfo,
2129*8975f5c5SAndroid Build Coastguard Worker                                       const gl::Extents &size,
2130*8975f5c5SAndroid Build Coastguard Worker                                       GLenum srcFormat,
2131*8975f5c5SAndroid Build Coastguard Worker                                       GLenum srcType,
2132*8975f5c5SAndroid Build Coastguard Worker                                       const gl::PixelUnpackState &unpack,
2133*8975f5c5SAndroid Build Coastguard Worker                                       gl::Buffer *unpackBuffer,
2134*8975f5c5SAndroid Build Coastguard Worker                                       const uint8_t *pixels)
2135*8975f5c5SAndroid Build Coastguard Worker{
2136*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
2137*8975f5c5SAndroid Build Coastguard Worker    angle::FormatID angleFormatId =
2138*8975f5c5SAndroid Build Coastguard Worker        angle::Format::InternalFormatToID(dstFormatInfo.sizedInternalFormat);
2139*8975f5c5SAndroid Build Coastguard Worker    const mtl::Format &mtlFormat = contextMtl->getPixelFormat(angleFormatId);
2140*8975f5c5SAndroid Build Coastguard Worker
2141*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(redefineImage(context, index, mtlFormat, size));
2142*8975f5c5SAndroid Build Coastguard Worker
2143*8975f5c5SAndroid Build Coastguard Worker    // Early-out on empty textures, don't create a zero-sized storage.
2144*8975f5c5SAndroid Build Coastguard Worker    if (size.empty())
2145*8975f5c5SAndroid Build Coastguard Worker    {
2146*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
2147*8975f5c5SAndroid Build Coastguard Worker    }
2148*8975f5c5SAndroid Build Coastguard Worker
2149*8975f5c5SAndroid Build Coastguard Worker    // Format of the supplied pixels.
2150*8975f5c5SAndroid Build Coastguard Worker    const gl::InternalFormat *srcFormatInfo;
2151*8975f5c5SAndroid Build Coastguard Worker    if (srcFormat != dstFormatInfo.format || srcType != dstFormatInfo.type)
2152*8975f5c5SAndroid Build Coastguard Worker    {
2153*8975f5c5SAndroid Build Coastguard Worker        srcFormatInfo = &gl::GetInternalFormatInfo(srcFormat, srcType);
2154*8975f5c5SAndroid Build Coastguard Worker    }
2155*8975f5c5SAndroid Build Coastguard Worker    else
2156*8975f5c5SAndroid Build Coastguard Worker    {
2157*8975f5c5SAndroid Build Coastguard Worker        srcFormatInfo = &dstFormatInfo;
2158*8975f5c5SAndroid Build Coastguard Worker    }
2159*8975f5c5SAndroid Build Coastguard Worker    return setSubImageImpl(context, index, gl::Box(0, 0, 0, size.width, size.height, size.depth),
2160*8975f5c5SAndroid Build Coastguard Worker                           *srcFormatInfo, srcType, unpack, unpackBuffer, pixels);
2161*8975f5c5SAndroid Build Coastguard Worker}
2162*8975f5c5SAndroid Build Coastguard Worker
2163*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setSubImageImpl(const gl::Context *context,
2164*8975f5c5SAndroid Build Coastguard Worker                                          const gl::ImageIndex &index,
2165*8975f5c5SAndroid Build Coastguard Worker                                          const gl::Box &area,
2166*8975f5c5SAndroid Build Coastguard Worker                                          const gl::InternalFormat &formatInfo,
2167*8975f5c5SAndroid Build Coastguard Worker                                          GLenum type,
2168*8975f5c5SAndroid Build Coastguard Worker                                          const gl::PixelUnpackState &unpack,
2169*8975f5c5SAndroid Build Coastguard Worker                                          gl::Buffer *unpackBuffer,
2170*8975f5c5SAndroid Build Coastguard Worker                                          const uint8_t *oriPixels)
2171*8975f5c5SAndroid Build Coastguard Worker{
2172*8975f5c5SAndroid Build Coastguard Worker    if (!oriPixels && !unpackBuffer)
2173*8975f5c5SAndroid Build Coastguard Worker    {
2174*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
2175*8975f5c5SAndroid Build Coastguard Worker    }
2176*8975f5c5SAndroid Build Coastguard Worker
2177*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
2178*8975f5c5SAndroid Build Coastguard Worker
2179*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(ensureImageCreated(context, index));
2180*8975f5c5SAndroid Build Coastguard Worker    mtl::TextureRef &image = getImage(index);
2181*8975f5c5SAndroid Build Coastguard Worker
2182*8975f5c5SAndroid Build Coastguard Worker    GLuint sourceRowPitch   = 0;
2183*8975f5c5SAndroid Build Coastguard Worker    GLuint sourceDepthPitch = 0;
2184*8975f5c5SAndroid Build Coastguard Worker    GLuint sourceSkipBytes  = 0;
2185*8975f5c5SAndroid Build Coastguard Worker    ANGLE_CHECK_GL_MATH(contextMtl, formatInfo.computeRowPitch(type, area.width, unpack.alignment,
2186*8975f5c5SAndroid Build Coastguard Worker                                                               unpack.rowLength, &sourceRowPitch));
2187*8975f5c5SAndroid Build Coastguard Worker    ANGLE_CHECK_GL_MATH(
2188*8975f5c5SAndroid Build Coastguard Worker        contextMtl, formatInfo.computeDepthPitch(area.height, unpack.imageHeight, sourceRowPitch,
2189*8975f5c5SAndroid Build Coastguard Worker                                                 &sourceDepthPitch));
2190*8975f5c5SAndroid Build Coastguard Worker    ANGLE_CHECK_GL_MATH(contextMtl,
2191*8975f5c5SAndroid Build Coastguard Worker                        formatInfo.computeSkipBytes(type, sourceRowPitch, sourceDepthPitch, unpack,
2192*8975f5c5SAndroid Build Coastguard Worker                                                    index.usesTex3D(), &sourceSkipBytes));
2193*8975f5c5SAndroid Build Coastguard Worker
2194*8975f5c5SAndroid Build Coastguard Worker    // Get corresponding source data's ANGLE format
2195*8975f5c5SAndroid Build Coastguard Worker    angle::FormatID srcAngleFormatId;
2196*8975f5c5SAndroid Build Coastguard Worker    if (formatInfo.sizedInternalFormat == GL_DEPTH_COMPONENT24)
2197*8975f5c5SAndroid Build Coastguard Worker    {
2198*8975f5c5SAndroid Build Coastguard Worker        // GL_DEPTH_COMPONENT24 is special case, its supplied data is 32 bit depth.
2199*8975f5c5SAndroid Build Coastguard Worker        srcAngleFormatId = angle::FormatID::D32_UNORM;
2200*8975f5c5SAndroid Build Coastguard Worker    }
2201*8975f5c5SAndroid Build Coastguard Worker    else
2202*8975f5c5SAndroid Build Coastguard Worker    {
2203*8975f5c5SAndroid Build Coastguard Worker        srcAngleFormatId = angle::Format::InternalFormatToID(formatInfo.sizedInternalFormat);
2204*8975f5c5SAndroid Build Coastguard Worker    }
2205*8975f5c5SAndroid Build Coastguard Worker    const angle::Format &srcAngleFormat = angle::Format::Get(srcAngleFormatId);
2206*8975f5c5SAndroid Build Coastguard Worker
2207*8975f5c5SAndroid Build Coastguard Worker    const uint8_t *usablePixels = oriPixels + sourceSkipBytes;
2208*8975f5c5SAndroid Build Coastguard Worker
2209*8975f5c5SAndroid Build Coastguard Worker    // Upload to texture
2210*8975f5c5SAndroid Build Coastguard Worker    if (index.getType() == gl::TextureType::_2DArray)
2211*8975f5c5SAndroid Build Coastguard Worker    {
2212*8975f5c5SAndroid Build Coastguard Worker        // OpenGL unifies texture array and texture 3d's box area by using z & depth as array start
2213*8975f5c5SAndroid Build Coastguard Worker        // index & length for texture array. However, Metal treats them differently. We need to
2214*8975f5c5SAndroid Build Coastguard Worker        // handle them in separate code.
2215*8975f5c5SAndroid Build Coastguard Worker        MTLRegion mtlRegion = MTLRegionMake3D(area.x, area.y, 0, area.width, area.height, 1);
2216*8975f5c5SAndroid Build Coastguard Worker
2217*8975f5c5SAndroid Build Coastguard Worker        for (int slice = 0; slice < area.depth; ++slice)
2218*8975f5c5SAndroid Build Coastguard Worker        {
2219*8975f5c5SAndroid Build Coastguard Worker            int sliceIndex           = slice + area.z;
2220*8975f5c5SAndroid Build Coastguard Worker            const uint8_t *srcPixels = usablePixels + slice * sourceDepthPitch;
2221*8975f5c5SAndroid Build Coastguard Worker            ANGLE_TRY(setPerSliceSubImage(context, sliceIndex, mtlRegion, formatInfo, type,
2222*8975f5c5SAndroid Build Coastguard Worker                                          srcAngleFormat, sourceRowPitch, sourceDepthPitch,
2223*8975f5c5SAndroid Build Coastguard Worker                                          unpackBuffer, srcPixels, image));
2224*8975f5c5SAndroid Build Coastguard Worker        }
2225*8975f5c5SAndroid Build Coastguard Worker    }
2226*8975f5c5SAndroid Build Coastguard Worker    else
2227*8975f5c5SAndroid Build Coastguard Worker    {
2228*8975f5c5SAndroid Build Coastguard Worker        MTLRegion mtlRegion =
2229*8975f5c5SAndroid Build Coastguard Worker            MTLRegionMake3D(area.x, area.y, area.z, area.width, area.height, area.depth);
2230*8975f5c5SAndroid Build Coastguard Worker
2231*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(setPerSliceSubImage(context, 0, mtlRegion, formatInfo, type, srcAngleFormat,
2232*8975f5c5SAndroid Build Coastguard Worker                                      sourceRowPitch, sourceDepthPitch, unpackBuffer, usablePixels,
2233*8975f5c5SAndroid Build Coastguard Worker                                      image));
2234*8975f5c5SAndroid Build Coastguard Worker    }
2235*8975f5c5SAndroid Build Coastguard Worker
2236*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
2237*8975f5c5SAndroid Build Coastguard Worker}
2238*8975f5c5SAndroid Build Coastguard Worker
2239*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setPerSliceSubImage(const gl::Context *context,
2240*8975f5c5SAndroid Build Coastguard Worker                                              int slice,
2241*8975f5c5SAndroid Build Coastguard Worker                                              const MTLRegion &mtlArea,
2242*8975f5c5SAndroid Build Coastguard Worker                                              const gl::InternalFormat &internalFormat,
2243*8975f5c5SAndroid Build Coastguard Worker                                              GLenum type,
2244*8975f5c5SAndroid Build Coastguard Worker                                              const angle::Format &pixelsAngleFormat,
2245*8975f5c5SAndroid Build Coastguard Worker                                              size_t pixelsRowPitch,
2246*8975f5c5SAndroid Build Coastguard Worker                                              size_t pixelsDepthPitch,
2247*8975f5c5SAndroid Build Coastguard Worker                                              gl::Buffer *unpackBuffer,
2248*8975f5c5SAndroid Build Coastguard Worker                                              const uint8_t *pixels,
2249*8975f5c5SAndroid Build Coastguard Worker                                              const mtl::TextureRef &image)
2250*8975f5c5SAndroid Build Coastguard Worker{
2251*8975f5c5SAndroid Build Coastguard Worker    // If source pixels are luminance or RGB8, we need to convert them to RGBA
2252*8975f5c5SAndroid Build Coastguard Worker
2253*8975f5c5SAndroid Build Coastguard Worker    if (mFormat.needConversion(pixelsAngleFormat.id))
2254*8975f5c5SAndroid Build Coastguard Worker    {
2255*8975f5c5SAndroid Build Coastguard Worker        return convertAndSetPerSliceSubImage(context, slice, mtlArea, internalFormat, type,
2256*8975f5c5SAndroid Build Coastguard Worker                                             pixelsAngleFormat, pixelsRowPitch, pixelsDepthPitch,
2257*8975f5c5SAndroid Build Coastguard Worker                                             unpackBuffer, pixels, image);
2258*8975f5c5SAndroid Build Coastguard Worker    }
2259*8975f5c5SAndroid Build Coastguard Worker
2260*8975f5c5SAndroid Build Coastguard Worker    // No conversion needed.
2261*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
2262*8975f5c5SAndroid Build Coastguard Worker
2263*8975f5c5SAndroid Build Coastguard Worker    if (unpackBuffer)
2264*8975f5c5SAndroid Build Coastguard Worker    {
2265*8975f5c5SAndroid Build Coastguard Worker        uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
2266*8975f5c5SAndroid Build Coastguard Worker        GLuint minRowPitch;
2267*8975f5c5SAndroid Build Coastguard Worker        ANGLE_CHECK_GL_MATH(contextMtl, internalFormat.computeRowPitch(
2268*8975f5c5SAndroid Build Coastguard Worker                                            type, static_cast<GLint>(mtlArea.size.width),
2269*8975f5c5SAndroid Build Coastguard Worker                                            /** aligment */ 1, /** rowLength */ 0, &minRowPitch));
2270*8975f5c5SAndroid Build Coastguard Worker        if (offset % mFormat.actualAngleFormat().pixelBytes || pixelsRowPitch < minRowPitch)
2271*8975f5c5SAndroid Build Coastguard Worker        {
2272*8975f5c5SAndroid Build Coastguard Worker            // offset is not divisible by pixelByte or the source row pitch is smaller than minimum
2273*8975f5c5SAndroid Build Coastguard Worker            // row pitch, use convertAndSetPerSliceSubImage() function.
2274*8975f5c5SAndroid Build Coastguard Worker            return convertAndSetPerSliceSubImage(context, slice, mtlArea, internalFormat, type,
2275*8975f5c5SAndroid Build Coastguard Worker                                                 pixelsAngleFormat, pixelsRowPitch,
2276*8975f5c5SAndroid Build Coastguard Worker                                                 pixelsDepthPitch, unpackBuffer, pixels, image);
2277*8975f5c5SAndroid Build Coastguard Worker        }
2278*8975f5c5SAndroid Build Coastguard Worker
2279*8975f5c5SAndroid Build Coastguard Worker        BufferMtl *unpackBufferMtl = mtl::GetImpl(unpackBuffer);
2280*8975f5c5SAndroid Build Coastguard Worker
2281*8975f5c5SAndroid Build Coastguard Worker        if (mFormat.hasDepthAndStencilBits())
2282*8975f5c5SAndroid Build Coastguard Worker        {
2283*8975f5c5SAndroid Build Coastguard Worker            // NOTE(hqle): packed depth & stencil texture cannot copy from buffer directly, needs
2284*8975f5c5SAndroid Build Coastguard Worker            // to split its depth & stencil data and copy separately.
2285*8975f5c5SAndroid Build Coastguard Worker            const uint8_t *clientData = unpackBufferMtl->getBufferDataReadOnly(contextMtl);
2286*8975f5c5SAndroid Build Coastguard Worker            clientData += offset;
2287*8975f5c5SAndroid Build Coastguard Worker            ANGLE_TRY(UploadTextureContents(context, mFormat.actualAngleFormat(), mtlArea,
2288*8975f5c5SAndroid Build Coastguard Worker                                            mtl::kZeroNativeMipLevel, slice, clientData,
2289*8975f5c5SAndroid Build Coastguard Worker                                            pixelsRowPitch, pixelsDepthPitch, false, image));
2290*8975f5c5SAndroid Build Coastguard Worker        }
2291*8975f5c5SAndroid Build Coastguard Worker        else
2292*8975f5c5SAndroid Build Coastguard Worker        {
2293*8975f5c5SAndroid Build Coastguard Worker            mtl::BufferRef sourceBuffer = unpackBufferMtl->getCurrentBuffer();
2294*8975f5c5SAndroid Build Coastguard Worker            // PVRTC1 blocks are stored in a reflected Morton order
2295*8975f5c5SAndroid Build Coastguard Worker            // and need to be linearized for buffer uploads in Metal.
2296*8975f5c5SAndroid Build Coastguard Worker            // This step is skipped for textures that have only one block.
2297*8975f5c5SAndroid Build Coastguard Worker            if (mFormat.isPVRTC() && mtlArea.size.height > 4)
2298*8975f5c5SAndroid Build Coastguard Worker            {
2299*8975f5c5SAndroid Build Coastguard Worker                // PVRTC1 inherent requirement.
2300*8975f5c5SAndroid Build Coastguard Worker                ASSERT(gl::isPow2(mtlArea.size.width) && gl::isPow2(mtlArea.size.height));
2301*8975f5c5SAndroid Build Coastguard Worker                // Metal-specific limitation enforced by ANGLE validation.
2302*8975f5c5SAndroid Build Coastguard Worker                ASSERT(mtlArea.size.width == mtlArea.size.height);
2303*8975f5c5SAndroid Build Coastguard Worker                static_assert(gl::IMPLEMENTATION_MAX_2D_TEXTURE_SIZE <= 262144,
2304*8975f5c5SAndroid Build Coastguard Worker                              "The current kernel can handle up to 65536 blocks per dimension.");
2305*8975f5c5SAndroid Build Coastguard Worker
2306*8975f5c5SAndroid Build Coastguard Worker                // Current command buffer implementation does not support 64-bit offsets.
2307*8975f5c5SAndroid Build Coastguard Worker                ANGLE_MTL_CHECK(contextMtl, offset <= std::numeric_limits<uint32_t>::max(),
2308*8975f5c5SAndroid Build Coastguard Worker                                GL_INVALID_OPERATION);
2309*8975f5c5SAndroid Build Coastguard Worker
2310*8975f5c5SAndroid Build Coastguard Worker                mtl::BufferRef stagingBuffer;
2311*8975f5c5SAndroid Build Coastguard Worker                ANGLE_TRY(
2312*8975f5c5SAndroid Build Coastguard Worker                    mtl::Buffer::MakeBuffer(contextMtl, pixelsDepthPitch, nullptr, &stagingBuffer));
2313*8975f5c5SAndroid Build Coastguard Worker
2314*8975f5c5SAndroid Build Coastguard Worker                mtl::BlockLinearizationParams params;
2315*8975f5c5SAndroid Build Coastguard Worker                params.srcBuffer       = sourceBuffer;
2316*8975f5c5SAndroid Build Coastguard Worker                params.dstBuffer       = stagingBuffer;
2317*8975f5c5SAndroid Build Coastguard Worker                params.srcBufferOffset = static_cast<uint32_t>(offset);
2318*8975f5c5SAndroid Build Coastguard Worker                params.blocksWide =
2319*8975f5c5SAndroid Build Coastguard Worker                    static_cast<GLuint>(mtlArea.size.width) / internalFormat.compressedBlockWidth;
2320*8975f5c5SAndroid Build Coastguard Worker                params.blocksHigh =
2321*8975f5c5SAndroid Build Coastguard Worker                    static_cast<GLuint>(mtlArea.size.height) / internalFormat.compressedBlockHeight;
2322*8975f5c5SAndroid Build Coastguard Worker
2323*8975f5c5SAndroid Build Coastguard Worker                // PVRTC1 textures always have at least 2 blocks in each dimension.
2324*8975f5c5SAndroid Build Coastguard Worker                // Enforce correct block layout for 8x8 textures that use 8x4 blocks.
2325*8975f5c5SAndroid Build Coastguard Worker                params.blocksWide = std::max(params.blocksWide, 2u);
2326*8975f5c5SAndroid Build Coastguard Worker
2327*8975f5c5SAndroid Build Coastguard Worker                ANGLE_TRY(contextMtl->getDisplay()->getUtils().linearizeBlocks(contextMtl, params));
2328*8975f5c5SAndroid Build Coastguard Worker
2329*8975f5c5SAndroid Build Coastguard Worker                sourceBuffer = stagingBuffer;
2330*8975f5c5SAndroid Build Coastguard Worker                offset       = 0;
2331*8975f5c5SAndroid Build Coastguard Worker            }
2332*8975f5c5SAndroid Build Coastguard Worker            else if (pixelsAngleFormat.id == angle::FormatID::D32_FLOAT)
2333*8975f5c5SAndroid Build Coastguard Worker            {
2334*8975f5c5SAndroid Build Coastguard Worker                // Current command buffer implementation does not support 64-bit offsets.
2335*8975f5c5SAndroid Build Coastguard Worker                ANGLE_MTL_CHECK(contextMtl, offset <= std::numeric_limits<uint32_t>::max(),
2336*8975f5c5SAndroid Build Coastguard Worker                                GL_INVALID_OPERATION);
2337*8975f5c5SAndroid Build Coastguard Worker
2338*8975f5c5SAndroid Build Coastguard Worker                mtl::BufferRef stagingBuffer;
2339*8975f5c5SAndroid Build Coastguard Worker                ANGLE_TRY(
2340*8975f5c5SAndroid Build Coastguard Worker                    mtl::Buffer::MakeBuffer(contextMtl, pixelsDepthPitch, nullptr, &stagingBuffer));
2341*8975f5c5SAndroid Build Coastguard Worker
2342*8975f5c5SAndroid Build Coastguard Worker                ASSERT(pixelsAngleFormat.pixelBytes == 4 && offset % 4 == 0);
2343*8975f5c5SAndroid Build Coastguard Worker                ANGLE_TRY(SaturateDepth(contextMtl, sourceBuffer, stagingBuffer,
2344*8975f5c5SAndroid Build Coastguard Worker                                        static_cast<uint32_t>(offset),
2345*8975f5c5SAndroid Build Coastguard Worker                                        static_cast<uint32_t>(pixelsRowPitch) / 4, mtlArea.size));
2346*8975f5c5SAndroid Build Coastguard Worker
2347*8975f5c5SAndroid Build Coastguard Worker                sourceBuffer = stagingBuffer;
2348*8975f5c5SAndroid Build Coastguard Worker                offset       = 0;
2349*8975f5c5SAndroid Build Coastguard Worker            }
2350*8975f5c5SAndroid Build Coastguard Worker
2351*8975f5c5SAndroid Build Coastguard Worker            // Use blit encoder to copy
2352*8975f5c5SAndroid Build Coastguard Worker            mtl::BlitCommandEncoder *blitEncoder =
2353*8975f5c5SAndroid Build Coastguard Worker                GetBlitCommandEncoderForResources(contextMtl, {sourceBuffer.get(), image.get()});
2354*8975f5c5SAndroid Build Coastguard Worker            CopyBufferToOriginalTextureIfDstIsAView(
2355*8975f5c5SAndroid Build Coastguard Worker                contextMtl, blitEncoder, sourceBuffer, offset, pixelsRowPitch, pixelsDepthPitch,
2356*8975f5c5SAndroid Build Coastguard Worker                mtlArea.size, image, slice, mtl::kZeroNativeMipLevel, mtlArea.origin,
2357*8975f5c5SAndroid Build Coastguard Worker                mFormat.isPVRTC() ? MTLBlitOptionRowLinearPVRTC : MTLBlitOptionNone);
2358*8975f5c5SAndroid Build Coastguard Worker        }
2359*8975f5c5SAndroid Build Coastguard Worker    }
2360*8975f5c5SAndroid Build Coastguard Worker    else
2361*8975f5c5SAndroid Build Coastguard Worker    {
2362*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(UploadTextureContents(context, mFormat.actualAngleFormat(), mtlArea,
2363*8975f5c5SAndroid Build Coastguard Worker                                        mtl::kZeroNativeMipLevel, slice, pixels, pixelsRowPitch,
2364*8975f5c5SAndroid Build Coastguard Worker                                        pixelsDepthPitch, false, image));
2365*8975f5c5SAndroid Build Coastguard Worker    }
2366*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
2367*8975f5c5SAndroid Build Coastguard Worker}
2368*8975f5c5SAndroid Build Coastguard Worker
2369*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::convertAndSetPerSliceSubImage(const gl::Context *context,
2370*8975f5c5SAndroid Build Coastguard Worker                                                        int slice,
2371*8975f5c5SAndroid Build Coastguard Worker                                                        const MTLRegion &mtlArea,
2372*8975f5c5SAndroid Build Coastguard Worker                                                        const gl::InternalFormat &internalFormat,
2373*8975f5c5SAndroid Build Coastguard Worker                                                        GLenum type,
2374*8975f5c5SAndroid Build Coastguard Worker                                                        const angle::Format &pixelsAngleFormat,
2375*8975f5c5SAndroid Build Coastguard Worker                                                        size_t pixelsRowPitch,
2376*8975f5c5SAndroid Build Coastguard Worker                                                        size_t pixelsDepthPitch,
2377*8975f5c5SAndroid Build Coastguard Worker                                                        gl::Buffer *unpackBuffer,
2378*8975f5c5SAndroid Build Coastguard Worker                                                        const uint8_t *pixels,
2379*8975f5c5SAndroid Build Coastguard Worker                                                        const mtl::TextureRef &image)
2380*8975f5c5SAndroid Build Coastguard Worker{
2381*8975f5c5SAndroid Build Coastguard Worker    ASSERT(image && image->valid());
2382*8975f5c5SAndroid Build Coastguard Worker
2383*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
2384*8975f5c5SAndroid Build Coastguard Worker
2385*8975f5c5SAndroid Build Coastguard Worker    if (unpackBuffer)
2386*8975f5c5SAndroid Build Coastguard Worker    {
2387*8975f5c5SAndroid Build Coastguard Worker        ANGLE_MTL_CHECK(contextMtl,
2388*8975f5c5SAndroid Build Coastguard Worker                        reinterpret_cast<uintptr_t>(pixels) <= std::numeric_limits<uint32_t>::max(),
2389*8975f5c5SAndroid Build Coastguard Worker                        GL_INVALID_OPERATION);
2390*8975f5c5SAndroid Build Coastguard Worker
2391*8975f5c5SAndroid Build Coastguard Worker        uint32_t offset = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(pixels));
2392*8975f5c5SAndroid Build Coastguard Worker
2393*8975f5c5SAndroid Build Coastguard Worker        BufferMtl *unpackBufferMtl = mtl::GetImpl(unpackBuffer);
2394*8975f5c5SAndroid Build Coastguard Worker        if (!mFormat.getCaps().writable || mFormat.hasDepthOrStencilBits() ||
2395*8975f5c5SAndroid Build Coastguard Worker            mFormat.intendedAngleFormat().isBlock)
2396*8975f5c5SAndroid Build Coastguard Worker        {
2397*8975f5c5SAndroid Build Coastguard Worker            // Unsupported format, use CPU path.
2398*8975f5c5SAndroid Build Coastguard Worker            const uint8_t *clientData = unpackBufferMtl->getBufferDataReadOnly(contextMtl);
2399*8975f5c5SAndroid Build Coastguard Worker            clientData += offset;
2400*8975f5c5SAndroid Build Coastguard Worker            ANGLE_TRY(convertAndSetPerSliceSubImage(context, slice, mtlArea, internalFormat, type,
2401*8975f5c5SAndroid Build Coastguard Worker                                                    pixelsAngleFormat, pixelsRowPitch,
2402*8975f5c5SAndroid Build Coastguard Worker                                                    pixelsDepthPitch, nullptr, clientData, image));
2403*8975f5c5SAndroid Build Coastguard Worker        }
2404*8975f5c5SAndroid Build Coastguard Worker        else
2405*8975f5c5SAndroid Build Coastguard Worker        {
2406*8975f5c5SAndroid Build Coastguard Worker            // Use compute shader
2407*8975f5c5SAndroid Build Coastguard Worker            mtl::CopyPixelsFromBufferParams params;
2408*8975f5c5SAndroid Build Coastguard Worker            params.buffer            = unpackBufferMtl->getCurrentBuffer();
2409*8975f5c5SAndroid Build Coastguard Worker            params.bufferStartOffset = offset;
2410*8975f5c5SAndroid Build Coastguard Worker            params.bufferRowPitch    = static_cast<uint32_t>(pixelsRowPitch);
2411*8975f5c5SAndroid Build Coastguard Worker            params.bufferDepthPitch  = static_cast<uint32_t>(pixelsDepthPitch);
2412*8975f5c5SAndroid Build Coastguard Worker            params.texture           = image;
2413*8975f5c5SAndroid Build Coastguard Worker            params.textureArea       = mtl::MTLRegionToGLBox(mtlArea);
2414*8975f5c5SAndroid Build Coastguard Worker
2415*8975f5c5SAndroid Build Coastguard Worker            // If texture is not array, slice must be zero, if texture is array, mtlArea.origin.z
2416*8975f5c5SAndroid Build Coastguard Worker            // must be zero.
2417*8975f5c5SAndroid Build Coastguard Worker            // This is because this function uses Metal convention: where slice is only used for
2418*8975f5c5SAndroid Build Coastguard Worker            // array textures, and z layer of mtlArea.origin is only used for 3D textures.
2419*8975f5c5SAndroid Build Coastguard Worker            ASSERT(slice == 0 || params.textureArea.z == 0);
2420*8975f5c5SAndroid Build Coastguard Worker
2421*8975f5c5SAndroid Build Coastguard Worker            // For mtl::RenderUtils we convert to OpenGL convention: z layer is used as either array
2422*8975f5c5SAndroid Build Coastguard Worker            // texture's slice or 3D texture's layer index.
2423*8975f5c5SAndroid Build Coastguard Worker            params.textureArea.z += slice;
2424*8975f5c5SAndroid Build Coastguard Worker
2425*8975f5c5SAndroid Build Coastguard Worker            ANGLE_TRY(contextMtl->getDisplay()->getUtils().unpackPixelsFromBufferToTexture(
2426*8975f5c5SAndroid Build Coastguard Worker                contextMtl, pixelsAngleFormat, params));
2427*8975f5c5SAndroid Build Coastguard Worker        }
2428*8975f5c5SAndroid Build Coastguard Worker    }  // if (unpackBuffer)
2429*8975f5c5SAndroid Build Coastguard Worker    else
2430*8975f5c5SAndroid Build Coastguard Worker    {
2431*8975f5c5SAndroid Build Coastguard Worker        LoadImageFunctionInfo loadFunctionInfo = mFormat.textureLoadFunctions
2432*8975f5c5SAndroid Build Coastguard Worker                                                     ? mFormat.textureLoadFunctions(type)
2433*8975f5c5SAndroid Build Coastguard Worker                                                     : LoadImageFunctionInfo();
2434*8975f5c5SAndroid Build Coastguard Worker        const angle::Format &dstFormat         = angle::Format::Get(mFormat.actualFormatId);
2435*8975f5c5SAndroid Build Coastguard Worker        const size_t dstRowPitch               = dstFormat.pixelBytes * mtlArea.size.width;
2436*8975f5c5SAndroid Build Coastguard Worker
2437*8975f5c5SAndroid Build Coastguard Worker        // It is very important to avoid allocating a new buffer for each row during these
2438*8975f5c5SAndroid Build Coastguard Worker        // uploads.
2439*8975f5c5SAndroid Build Coastguard Worker        const bool kAvoidStagingBuffers = true;
2440*8975f5c5SAndroid Build Coastguard Worker
2441*8975f5c5SAndroid Build Coastguard Worker        // Check if original image data is compressed:
2442*8975f5c5SAndroid Build Coastguard Worker        if (mFormat.intendedAngleFormat().isBlock)
2443*8975f5c5SAndroid Build Coastguard Worker        {
2444*8975f5c5SAndroid Build Coastguard Worker            if (mFormat.intendedFormatId != mFormat.actualFormatId)
2445*8975f5c5SAndroid Build Coastguard Worker            {
2446*8975f5c5SAndroid Build Coastguard Worker                ASSERT(loadFunctionInfo.loadFunction);
2447*8975f5c5SAndroid Build Coastguard Worker
2448*8975f5c5SAndroid Build Coastguard Worker                // Need to create a buffer to hold entire decompressed image.
2449*8975f5c5SAndroid Build Coastguard Worker                const size_t dstDepthPitch = dstRowPitch * mtlArea.size.height;
2450*8975f5c5SAndroid Build Coastguard Worker                angle::MemoryBuffer decompressBuf;
2451*8975f5c5SAndroid Build Coastguard Worker                ANGLE_CHECK_GL_ALLOC(contextMtl,
2452*8975f5c5SAndroid Build Coastguard Worker                                     decompressBuf.resize(dstDepthPitch * mtlArea.size.depth));
2453*8975f5c5SAndroid Build Coastguard Worker
2454*8975f5c5SAndroid Build Coastguard Worker                // Decompress
2455*8975f5c5SAndroid Build Coastguard Worker                loadFunctionInfo.loadFunction(contextMtl->getImageLoadContext(), mtlArea.size.width,
2456*8975f5c5SAndroid Build Coastguard Worker                                              mtlArea.size.height, mtlArea.size.depth, pixels,
2457*8975f5c5SAndroid Build Coastguard Worker                                              pixelsRowPitch, pixelsDepthPitch,
2458*8975f5c5SAndroid Build Coastguard Worker                                              decompressBuf.data(), dstRowPitch, dstDepthPitch);
2459*8975f5c5SAndroid Build Coastguard Worker
2460*8975f5c5SAndroid Build Coastguard Worker                // Upload to texture
2461*8975f5c5SAndroid Build Coastguard Worker                ANGLE_TRY(UploadTextureContents(
2462*8975f5c5SAndroid Build Coastguard Worker                    context, dstFormat, mtlArea, mtl::kZeroNativeMipLevel, slice,
2463*8975f5c5SAndroid Build Coastguard Worker                    decompressBuf.data(), dstRowPitch, dstDepthPitch, kAvoidStagingBuffers, image));
2464*8975f5c5SAndroid Build Coastguard Worker            }
2465*8975f5c5SAndroid Build Coastguard Worker            else
2466*8975f5c5SAndroid Build Coastguard Worker            {
2467*8975f5c5SAndroid Build Coastguard Worker                // Assert that we're filling the level in it's entierety.
2468*8975f5c5SAndroid Build Coastguard Worker                ASSERT(mtlArea.size.width == static_cast<unsigned int>(image->sizeAt0().width));
2469*8975f5c5SAndroid Build Coastguard Worker                ASSERT(mtlArea.size.height == static_cast<unsigned int>(image->sizeAt0().height));
2470*8975f5c5SAndroid Build Coastguard Worker                const size_t dstDepthPitch = dstRowPitch * mtlArea.size.height;
2471*8975f5c5SAndroid Build Coastguard Worker                ANGLE_TRY(UploadTextureContents(
2472*8975f5c5SAndroid Build Coastguard Worker                    context, dstFormat, mtlArea, mtl::kZeroNativeMipLevel, slice, pixels,
2473*8975f5c5SAndroid Build Coastguard Worker                    dstRowPitch, dstDepthPitch, kAvoidStagingBuffers, image));
2474*8975f5c5SAndroid Build Coastguard Worker            }
2475*8975f5c5SAndroid Build Coastguard Worker        }  // if (mFormat.intendedAngleFormat().isBlock)
2476*8975f5c5SAndroid Build Coastguard Worker        else
2477*8975f5c5SAndroid Build Coastguard Worker        {
2478*8975f5c5SAndroid Build Coastguard Worker            // Create scratch row buffer
2479*8975f5c5SAndroid Build Coastguard Worker            angle::MemoryBuffer conversionRow;
2480*8975f5c5SAndroid Build Coastguard Worker            ANGLE_CHECK_GL_ALLOC(contextMtl, conversionRow.resize(dstRowPitch));
2481*8975f5c5SAndroid Build Coastguard Worker
2482*8975f5c5SAndroid Build Coastguard Worker            // Convert row by row:
2483*8975f5c5SAndroid Build Coastguard Worker            MTLRegion mtlRow   = mtlArea;
2484*8975f5c5SAndroid Build Coastguard Worker            mtlRow.size.height = mtlRow.size.depth = 1;
2485*8975f5c5SAndroid Build Coastguard Worker            for (NSUInteger d = 0; d < mtlArea.size.depth; ++d)
2486*8975f5c5SAndroid Build Coastguard Worker            {
2487*8975f5c5SAndroid Build Coastguard Worker                mtlRow.origin.z = mtlArea.origin.z + d;
2488*8975f5c5SAndroid Build Coastguard Worker                for (NSUInteger r = 0; r < mtlArea.size.height; ++r)
2489*8975f5c5SAndroid Build Coastguard Worker                {
2490*8975f5c5SAndroid Build Coastguard Worker                    const uint8_t *psrc = pixels + d * pixelsDepthPitch + r * pixelsRowPitch;
2491*8975f5c5SAndroid Build Coastguard Worker                    mtlRow.origin.y     = mtlArea.origin.y + r;
2492*8975f5c5SAndroid Build Coastguard Worker
2493*8975f5c5SAndroid Build Coastguard Worker                    // Convert pixels
2494*8975f5c5SAndroid Build Coastguard Worker                    if (loadFunctionInfo.loadFunction)
2495*8975f5c5SAndroid Build Coastguard Worker                    {
2496*8975f5c5SAndroid Build Coastguard Worker                        loadFunctionInfo.loadFunction(contextMtl->getImageLoadContext(),
2497*8975f5c5SAndroid Build Coastguard Worker                                                      mtlRow.size.width, 1, 1, psrc, pixelsRowPitch,
2498*8975f5c5SAndroid Build Coastguard Worker                                                      0, conversionRow.data(), dstRowPitch, 0);
2499*8975f5c5SAndroid Build Coastguard Worker                    }
2500*8975f5c5SAndroid Build Coastguard Worker                    else if (mFormat.hasDepthOrStencilBits())
2501*8975f5c5SAndroid Build Coastguard Worker                    {
2502*8975f5c5SAndroid Build Coastguard Worker                        ConvertDepthStencilData(mtlRow.size, pixelsAngleFormat, pixelsRowPitch, 0,
2503*8975f5c5SAndroid Build Coastguard Worker                                                psrc, dstFormat, nullptr, dstRowPitch, 0,
2504*8975f5c5SAndroid Build Coastguard Worker                                                conversionRow.data());
2505*8975f5c5SAndroid Build Coastguard Worker                    }
2506*8975f5c5SAndroid Build Coastguard Worker                    else
2507*8975f5c5SAndroid Build Coastguard Worker                    {
2508*8975f5c5SAndroid Build Coastguard Worker                        CopyImageCHROMIUM(psrc, pixelsRowPitch, pixelsAngleFormat.pixelBytes, 0,
2509*8975f5c5SAndroid Build Coastguard Worker                                          pixelsAngleFormat.pixelReadFunction, conversionRow.data(),
2510*8975f5c5SAndroid Build Coastguard Worker                                          dstRowPitch, dstFormat.pixelBytes, 0,
2511*8975f5c5SAndroid Build Coastguard Worker                                          dstFormat.pixelWriteFunction, internalFormat.format,
2512*8975f5c5SAndroid Build Coastguard Worker                                          dstFormat.componentType, mtlRow.size.width, 1, 1, false,
2513*8975f5c5SAndroid Build Coastguard Worker                                          false, false);
2514*8975f5c5SAndroid Build Coastguard Worker                    }
2515*8975f5c5SAndroid Build Coastguard Worker
2516*8975f5c5SAndroid Build Coastguard Worker                    // Upload to texture
2517*8975f5c5SAndroid Build Coastguard Worker                    ANGLE_TRY(UploadTextureContents(
2518*8975f5c5SAndroid Build Coastguard Worker                        context, dstFormat, mtlRow, mtl::kZeroNativeMipLevel, slice,
2519*8975f5c5SAndroid Build Coastguard Worker                        conversionRow.data(), dstRowPitch, 0, kAvoidStagingBuffers, image));
2520*8975f5c5SAndroid Build Coastguard Worker                }
2521*8975f5c5SAndroid Build Coastguard Worker            }
2522*8975f5c5SAndroid Build Coastguard Worker        }  // if (mFormat.intendedAngleFormat().isBlock)
2523*8975f5c5SAndroid Build Coastguard Worker    }      // if (unpackBuffer)
2524*8975f5c5SAndroid Build Coastguard Worker
2525*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
2526*8975f5c5SAndroid Build Coastguard Worker}
2527*8975f5c5SAndroid Build Coastguard Worker
2528*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::checkForEmulatedChannels(const gl::Context *context,
2529*8975f5c5SAndroid Build Coastguard Worker                                                   const mtl::Format &mtlFormat,
2530*8975f5c5SAndroid Build Coastguard Worker                                                   const mtl::TextureRef &texture)
2531*8975f5c5SAndroid Build Coastguard Worker{
2532*8975f5c5SAndroid Build Coastguard Worker    bool emulatedChannels = mtl::IsFormatEmulated(mtlFormat);
2533*8975f5c5SAndroid Build Coastguard Worker
2534*8975f5c5SAndroid Build Coastguard Worker    // For emulated channels that GL texture intends to not have,
2535*8975f5c5SAndroid Build Coastguard Worker    // we need to initialize their content.
2536*8975f5c5SAndroid Build Coastguard Worker    if (emulatedChannels)
2537*8975f5c5SAndroid Build Coastguard Worker    {
2538*8975f5c5SAndroid Build Coastguard Worker        uint32_t mipmaps = texture->mipmapLevels();
2539*8975f5c5SAndroid Build Coastguard Worker
2540*8975f5c5SAndroid Build Coastguard Worker        uint32_t layers = texture->cubeFacesOrArrayLength();
2541*8975f5c5SAndroid Build Coastguard Worker        for (uint32_t layer = 0; layer < layers; ++layer)
2542*8975f5c5SAndroid Build Coastguard Worker        {
2543*8975f5c5SAndroid Build Coastguard Worker            for (uint32_t mip = 0; mip < mipmaps; ++mip)
2544*8975f5c5SAndroid Build Coastguard Worker            {
2545*8975f5c5SAndroid Build Coastguard Worker                auto index = mtl::ImageNativeIndex::FromBaseZeroGLIndex(
2546*8975f5c5SAndroid Build Coastguard Worker                    GetCubeOrArraySliceMipIndex(texture, layer, mip));
2547*8975f5c5SAndroid Build Coastguard Worker
2548*8975f5c5SAndroid Build Coastguard Worker                ANGLE_TRY(mtl::InitializeTextureContents(context, texture, mtlFormat, index));
2549*8975f5c5SAndroid Build Coastguard Worker            }
2550*8975f5c5SAndroid Build Coastguard Worker        }
2551*8975f5c5SAndroid Build Coastguard Worker    }
2552*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
2553*8975f5c5SAndroid Build Coastguard Worker}
2554*8975f5c5SAndroid Build Coastguard Worker
2555*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::initializeContents(const gl::Context *context,
2556*8975f5c5SAndroid Build Coastguard Worker                                             GLenum binding,
2557*8975f5c5SAndroid Build Coastguard Worker                                             const gl::ImageIndex &index)
2558*8975f5c5SAndroid Build Coastguard Worker{
2559*8975f5c5SAndroid Build Coastguard Worker    if (index.isLayered())
2560*8975f5c5SAndroid Build Coastguard Worker    {
2561*8975f5c5SAndroid Build Coastguard Worker        // InitializeTextureContents is only able to initialize one layer at a time.
2562*8975f5c5SAndroid Build Coastguard Worker        const gl::ImageDesc &desc = mState.getImageDesc(index);
2563*8975f5c5SAndroid Build Coastguard Worker        uint32_t layerCount;
2564*8975f5c5SAndroid Build Coastguard Worker        if (index.isEntireLevelCubeMap())
2565*8975f5c5SAndroid Build Coastguard Worker        {
2566*8975f5c5SAndroid Build Coastguard Worker            layerCount = 6;
2567*8975f5c5SAndroid Build Coastguard Worker        }
2568*8975f5c5SAndroid Build Coastguard Worker        else
2569*8975f5c5SAndroid Build Coastguard Worker        {
2570*8975f5c5SAndroid Build Coastguard Worker            layerCount = desc.size.depth;
2571*8975f5c5SAndroid Build Coastguard Worker        }
2572*8975f5c5SAndroid Build Coastguard Worker
2573*8975f5c5SAndroid Build Coastguard Worker        gl::ImageIndexIterator ite = index.getLayerIterator(layerCount);
2574*8975f5c5SAndroid Build Coastguard Worker        while (ite.hasNext())
2575*8975f5c5SAndroid Build Coastguard Worker        {
2576*8975f5c5SAndroid Build Coastguard Worker            gl::ImageIndex layerIndex = ite.next();
2577*8975f5c5SAndroid Build Coastguard Worker            ANGLE_TRY(initializeContents(context, GL_NONE, layerIndex));
2578*8975f5c5SAndroid Build Coastguard Worker        }
2579*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
2580*8975f5c5SAndroid Build Coastguard Worker    }
2581*8975f5c5SAndroid Build Coastguard Worker    else if (index.getLayerCount() > 1)
2582*8975f5c5SAndroid Build Coastguard Worker    {
2583*8975f5c5SAndroid Build Coastguard Worker        for (int layer = 0; layer < index.getLayerCount(); ++layer)
2584*8975f5c5SAndroid Build Coastguard Worker        {
2585*8975f5c5SAndroid Build Coastguard Worker            int layerIdx = layer + index.getLayerIndex();
2586*8975f5c5SAndroid Build Coastguard Worker            gl::ImageIndex layerIndex =
2587*8975f5c5SAndroid Build Coastguard Worker                gl::ImageIndex::MakeFromType(index.getType(), index.getLevelIndex(), layerIdx);
2588*8975f5c5SAndroid Build Coastguard Worker            ANGLE_TRY(initializeContents(context, GL_NONE, layerIndex));
2589*8975f5c5SAndroid Build Coastguard Worker        }
2590*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
2591*8975f5c5SAndroid Build Coastguard Worker    }
2592*8975f5c5SAndroid Build Coastguard Worker
2593*8975f5c5SAndroid Build Coastguard Worker    ASSERT(index.getLayerCount() == 1 && !index.isLayered());
2594*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(ensureImageCreated(context, index));
2595*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl       = mtl::GetImpl(context);
2596*8975f5c5SAndroid Build Coastguard Worker    ImageDefinitionMtl &imageDef = getImageDefinition(index);
2597*8975f5c5SAndroid Build Coastguard Worker    const mtl::TextureRef &image = imageDef.image;
2598*8975f5c5SAndroid Build Coastguard Worker    const mtl::Format &format    = contextMtl->getPixelFormat(imageDef.formatID);
2599*8975f5c5SAndroid Build Coastguard Worker    // For Texture's image definition, we always use zero mip level.
2600*8975f5c5SAndroid Build Coastguard Worker    if (format.metalFormat == MTLPixelFormatInvalid)
2601*8975f5c5SAndroid Build Coastguard Worker    {
2602*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Stop;
2603*8975f5c5SAndroid Build Coastguard Worker    }
2604*8975f5c5SAndroid Build Coastguard Worker    return mtl::InitializeTextureContents(
2605*8975f5c5SAndroid Build Coastguard Worker        context, image, format,
2606*8975f5c5SAndroid Build Coastguard Worker        mtl::ImageNativeIndex::FromBaseZeroGLIndex(
2607*8975f5c5SAndroid Build Coastguard Worker            GetLayerMipIndex(image, GetImageLayerIndexFrom(index), /** level */ 0)));
2608*8975f5c5SAndroid Build Coastguard Worker}
2609*8975f5c5SAndroid Build Coastguard Worker
2610*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::copySubImageImpl(const gl::Context *context,
2611*8975f5c5SAndroid Build Coastguard Worker                                           const gl::ImageIndex &index,
2612*8975f5c5SAndroid Build Coastguard Worker                                           const gl::Offset &destOffset,
2613*8975f5c5SAndroid Build Coastguard Worker                                           const gl::Rectangle &sourceArea,
2614*8975f5c5SAndroid Build Coastguard Worker                                           const gl::InternalFormat &internalFormat,
2615*8975f5c5SAndroid Build Coastguard Worker                                           const FramebufferMtl *source,
2616*8975f5c5SAndroid Build Coastguard Worker                                           const RenderTargetMtl *colorReadRT)
2617*8975f5c5SAndroid Build Coastguard Worker{
2618*8975f5c5SAndroid Build Coastguard Worker    if (!colorReadRT || !colorReadRT->getTexture())
2619*8975f5c5SAndroid Build Coastguard Worker    {
2620*8975f5c5SAndroid Build Coastguard Worker        // Is this an error?
2621*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
2622*8975f5c5SAndroid Build Coastguard Worker    }
2623*8975f5c5SAndroid Build Coastguard Worker
2624*8975f5c5SAndroid Build Coastguard Worker    gl::Extents fbSize = colorReadRT->getTexture()->size(colorReadRT->getLevelIndex());
2625*8975f5c5SAndroid Build Coastguard Worker    gl::Rectangle clippedSourceArea;
2626*8975f5c5SAndroid Build Coastguard Worker    if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height),
2627*8975f5c5SAndroid Build Coastguard Worker                       &clippedSourceArea))
2628*8975f5c5SAndroid Build Coastguard Worker    {
2629*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
2630*8975f5c5SAndroid Build Coastguard Worker    }
2631*8975f5c5SAndroid Build Coastguard Worker
2632*8975f5c5SAndroid Build Coastguard Worker    // If negative offsets are given, clippedSourceArea ensures we don't read from those offsets.
2633*8975f5c5SAndroid Build Coastguard Worker    // However, that changes the sourceOffset->destOffset mapping.  Here, destOffset is shifted by
2634*8975f5c5SAndroid Build Coastguard Worker    // the same amount as clipped to correct the error.
2635*8975f5c5SAndroid Build Coastguard Worker    const gl::Offset modifiedDestOffset(destOffset.x + clippedSourceArea.x - sourceArea.x,
2636*8975f5c5SAndroid Build Coastguard Worker                                        destOffset.y + clippedSourceArea.y - sourceArea.y, 0);
2637*8975f5c5SAndroid Build Coastguard Worker
2638*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(ensureImageCreated(context, index));
2639*8975f5c5SAndroid Build Coastguard Worker
2640*8975f5c5SAndroid Build Coastguard Worker    if (!mFormat.getCaps().isRenderable())
2641*8975f5c5SAndroid Build Coastguard Worker    {
2642*8975f5c5SAndroid Build Coastguard Worker        return copySubImageCPU(context, index, modifiedDestOffset, clippedSourceArea,
2643*8975f5c5SAndroid Build Coastguard Worker                               internalFormat, source, colorReadRT);
2644*8975f5c5SAndroid Build Coastguard Worker    }
2645*8975f5c5SAndroid Build Coastguard Worker
2646*8975f5c5SAndroid Build Coastguard Worker    // NOTE(hqle): Use compute shader.
2647*8975f5c5SAndroid Build Coastguard Worker    return copySubImageWithDraw(context, index, modifiedDestOffset, clippedSourceArea,
2648*8975f5c5SAndroid Build Coastguard Worker                                internalFormat, source, colorReadRT);
2649*8975f5c5SAndroid Build Coastguard Worker}
2650*8975f5c5SAndroid Build Coastguard Worker
2651*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::copySubImageWithDraw(const gl::Context *context,
2652*8975f5c5SAndroid Build Coastguard Worker                                               const gl::ImageIndex &index,
2653*8975f5c5SAndroid Build Coastguard Worker                                               const gl::Offset &modifiedDestOffset,
2654*8975f5c5SAndroid Build Coastguard Worker                                               const gl::Rectangle &clippedSourceArea,
2655*8975f5c5SAndroid Build Coastguard Worker                                               const gl::InternalFormat &internalFormat,
2656*8975f5c5SAndroid Build Coastguard Worker                                               const FramebufferMtl *source,
2657*8975f5c5SAndroid Build Coastguard Worker                                               const RenderTargetMtl *colorReadRT)
2658*8975f5c5SAndroid Build Coastguard Worker{
2659*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
2660*8975f5c5SAndroid Build Coastguard Worker    DisplayMtl *displayMtl = contextMtl->getDisplay();
2661*8975f5c5SAndroid Build Coastguard Worker
2662*8975f5c5SAndroid Build Coastguard Worker    RenderTargetMtl *imageRtt;
2663*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(getRenderTarget(contextMtl, index, /*implicitSamples=*/0, &imageRtt));
2664*8975f5c5SAndroid Build Coastguard Worker
2665*8975f5c5SAndroid Build Coastguard Worker    mtl::RenderCommandEncoder *cmdEncoder = contextMtl->getRenderTargetCommandEncoder(*imageRtt);
2666*8975f5c5SAndroid Build Coastguard Worker    mtl::ColorBlitParams blitParams;
2667*8975f5c5SAndroid Build Coastguard Worker
2668*8975f5c5SAndroid Build Coastguard Worker    blitParams.dstTextureSize = imageRtt->getTexture()->size(imageRtt->getLevelIndex());
2669*8975f5c5SAndroid Build Coastguard Worker    blitParams.dstRect        = gl::Rectangle(modifiedDestOffset.x, modifiedDestOffset.y,
2670*8975f5c5SAndroid Build Coastguard Worker                                              clippedSourceArea.width, clippedSourceArea.height);
2671*8975f5c5SAndroid Build Coastguard Worker    blitParams.dstScissorRect = blitParams.dstRect;
2672*8975f5c5SAndroid Build Coastguard Worker
2673*8975f5c5SAndroid Build Coastguard Worker    blitParams.enabledBuffers.set(0);
2674*8975f5c5SAndroid Build Coastguard Worker
2675*8975f5c5SAndroid Build Coastguard Worker    blitParams.src      = colorReadRT->getTexture();
2676*8975f5c5SAndroid Build Coastguard Worker    blitParams.srcLevel = colorReadRT->getLevelIndex();
2677*8975f5c5SAndroid Build Coastguard Worker    blitParams.srcLayer = colorReadRT->getLayerIndex();
2678*8975f5c5SAndroid Build Coastguard Worker
2679*8975f5c5SAndroid Build Coastguard Worker    blitParams.srcNormalizedCoords = mtl::NormalizedCoords(
2680*8975f5c5SAndroid Build Coastguard Worker        clippedSourceArea, colorReadRT->getTexture()->size(blitParams.srcLevel));
2681*8975f5c5SAndroid Build Coastguard Worker    blitParams.srcYFlipped  = source->flipY();
2682*8975f5c5SAndroid Build Coastguard Worker    blitParams.dstLuminance = internalFormat.isLUMA();
2683*8975f5c5SAndroid Build Coastguard Worker
2684*8975f5c5SAndroid Build Coastguard Worker    return displayMtl->getUtils().blitColorWithDraw(
2685*8975f5c5SAndroid Build Coastguard Worker        context, cmdEncoder, colorReadRT->getFormat().actualAngleFormat(), blitParams);
2686*8975f5c5SAndroid Build Coastguard Worker}
2687*8975f5c5SAndroid Build Coastguard Worker
2688*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::copySubImageCPU(const gl::Context *context,
2689*8975f5c5SAndroid Build Coastguard Worker                                          const gl::ImageIndex &index,
2690*8975f5c5SAndroid Build Coastguard Worker                                          const gl::Offset &modifiedDestOffset,
2691*8975f5c5SAndroid Build Coastguard Worker                                          const gl::Rectangle &clippedSourceArea,
2692*8975f5c5SAndroid Build Coastguard Worker                                          const gl::InternalFormat &internalFormat,
2693*8975f5c5SAndroid Build Coastguard Worker                                          const FramebufferMtl *source,
2694*8975f5c5SAndroid Build Coastguard Worker                                          const RenderTargetMtl *colorReadRT)
2695*8975f5c5SAndroid Build Coastguard Worker{
2696*8975f5c5SAndroid Build Coastguard Worker    mtl::TextureRef &image = getImage(index);
2697*8975f5c5SAndroid Build Coastguard Worker    ASSERT(image && image->valid());
2698*8975f5c5SAndroid Build Coastguard Worker
2699*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
2700*8975f5c5SAndroid Build Coastguard Worker
2701*8975f5c5SAndroid Build Coastguard Worker    const angle::Format &dstFormat = angle::Format::Get(mFormat.actualFormatId);
2702*8975f5c5SAndroid Build Coastguard Worker    const int dstRowPitch          = dstFormat.pixelBytes * clippedSourceArea.width;
2703*8975f5c5SAndroid Build Coastguard Worker    angle::MemoryBuffer conversionRow;
2704*8975f5c5SAndroid Build Coastguard Worker    ANGLE_CHECK_GL_ALLOC(contextMtl, conversionRow.resize(dstRowPitch));
2705*8975f5c5SAndroid Build Coastguard Worker
2706*8975f5c5SAndroid Build Coastguard Worker    gl::Rectangle srcRowArea = gl::Rectangle(clippedSourceArea.x, 0, clippedSourceArea.width, 1);
2707*8975f5c5SAndroid Build Coastguard Worker    MTLRegion mtlDstRowArea  = MTLRegionMake2D(modifiedDestOffset.x, 0, clippedSourceArea.width, 1);
2708*8975f5c5SAndroid Build Coastguard Worker    uint32_t dstSlice        = 0;
2709*8975f5c5SAndroid Build Coastguard Worker    switch (index.getType())
2710*8975f5c5SAndroid Build Coastguard Worker    {
2711*8975f5c5SAndroid Build Coastguard Worker        case gl::TextureType::_2D:
2712*8975f5c5SAndroid Build Coastguard Worker        case gl::TextureType::CubeMap:
2713*8975f5c5SAndroid Build Coastguard Worker            dstSlice = 0;
2714*8975f5c5SAndroid Build Coastguard Worker            break;
2715*8975f5c5SAndroid Build Coastguard Worker        case gl::TextureType::_2DArray:
2716*8975f5c5SAndroid Build Coastguard Worker            ASSERT(index.hasLayer());
2717*8975f5c5SAndroid Build Coastguard Worker            dstSlice = index.getLayerIndex();
2718*8975f5c5SAndroid Build Coastguard Worker            break;
2719*8975f5c5SAndroid Build Coastguard Worker        case gl::TextureType::_3D:
2720*8975f5c5SAndroid Build Coastguard Worker            ASSERT(index.hasLayer());
2721*8975f5c5SAndroid Build Coastguard Worker            dstSlice               = 0;
2722*8975f5c5SAndroid Build Coastguard Worker            mtlDstRowArea.origin.z = index.getLayerIndex();
2723*8975f5c5SAndroid Build Coastguard Worker            break;
2724*8975f5c5SAndroid Build Coastguard Worker        default:
2725*8975f5c5SAndroid Build Coastguard Worker            UNREACHABLE();
2726*8975f5c5SAndroid Build Coastguard Worker    }
2727*8975f5c5SAndroid Build Coastguard Worker
2728*8975f5c5SAndroid Build Coastguard Worker    // It is very important to avoid allocating a new buffer for each row during these
2729*8975f5c5SAndroid Build Coastguard Worker    // uploads.
2730*8975f5c5SAndroid Build Coastguard Worker    const bool kAvoidStagingBuffers = true;
2731*8975f5c5SAndroid Build Coastguard Worker
2732*8975f5c5SAndroid Build Coastguard Worker    // Copy row by row:
2733*8975f5c5SAndroid Build Coastguard Worker    for (int r = 0; r < clippedSourceArea.height; ++r)
2734*8975f5c5SAndroid Build Coastguard Worker    {
2735*8975f5c5SAndroid Build Coastguard Worker        mtlDstRowArea.origin.y = modifiedDestOffset.y + r;
2736*8975f5c5SAndroid Build Coastguard Worker        srcRowArea.y           = clippedSourceArea.y + r;
2737*8975f5c5SAndroid Build Coastguard Worker
2738*8975f5c5SAndroid Build Coastguard Worker        PackPixelsParams packParams(srcRowArea, dstFormat, dstRowPitch, false, nullptr, 0);
2739*8975f5c5SAndroid Build Coastguard Worker
2740*8975f5c5SAndroid Build Coastguard Worker        // Read pixels from framebuffer to memory:
2741*8975f5c5SAndroid Build Coastguard Worker        gl::Rectangle flippedSrcRowArea = source->getCorrectFlippedReadArea(context, srcRowArea);
2742*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(source->readPixelsImpl(context, flippedSrcRowArea, packParams, colorReadRT,
2743*8975f5c5SAndroid Build Coastguard Worker                                         conversionRow.data()));
2744*8975f5c5SAndroid Build Coastguard Worker
2745*8975f5c5SAndroid Build Coastguard Worker        // Upload to texture
2746*8975f5c5SAndroid Build Coastguard Worker        ANGLE_TRY(UploadTextureContents(context, dstFormat, mtlDstRowArea, mtl::kZeroNativeMipLevel,
2747*8975f5c5SAndroid Build Coastguard Worker                                        dstSlice, conversionRow.data(), dstRowPitch, 0,
2748*8975f5c5SAndroid Build Coastguard Worker                                        kAvoidStagingBuffers, image));
2749*8975f5c5SAndroid Build Coastguard Worker    }
2750*8975f5c5SAndroid Build Coastguard Worker
2751*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
2752*8975f5c5SAndroid Build Coastguard Worker}
2753*8975f5c5SAndroid Build Coastguard Worker
2754*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::copySubTextureImpl(const gl::Context *context,
2755*8975f5c5SAndroid Build Coastguard Worker                                             const gl::ImageIndex &index,
2756*8975f5c5SAndroid Build Coastguard Worker                                             const gl::Offset &destOffset,
2757*8975f5c5SAndroid Build Coastguard Worker                                             const gl::InternalFormat &internalFormat,
2758*8975f5c5SAndroid Build Coastguard Worker                                             GLint sourceLevel,
2759*8975f5c5SAndroid Build Coastguard Worker                                             const gl::Box &sourceBox,
2760*8975f5c5SAndroid Build Coastguard Worker                                             bool unpackFlipY,
2761*8975f5c5SAndroid Build Coastguard Worker                                             bool unpackPremultiplyAlpha,
2762*8975f5c5SAndroid Build Coastguard Worker                                             bool unpackUnmultiplyAlpha,
2763*8975f5c5SAndroid Build Coastguard Worker                                             const gl::Texture *source)
2764*8975f5c5SAndroid Build Coastguard Worker{
2765*8975f5c5SAndroid Build Coastguard Worker    // Only 2D textures are supported.
2766*8975f5c5SAndroid Build Coastguard Worker    ASSERT(sourceBox.depth == 1);
2767*8975f5c5SAndroid Build Coastguard Worker    ASSERT(source->getType() == gl::TextureType::_2D);
2768*8975f5c5SAndroid Build Coastguard Worker    gl::ImageIndex sourceIndex = gl::ImageIndex::Make2D(sourceLevel);
2769*8975f5c5SAndroid Build Coastguard Worker
2770*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
2771*8975f5c5SAndroid Build Coastguard Worker    TextureMtl *sourceMtl  = mtl::GetImpl(source);
2772*8975f5c5SAndroid Build Coastguard Worker
2773*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(ensureImageCreated(context, index));
2774*8975f5c5SAndroid Build Coastguard Worker
2775*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(sourceMtl->ensureImageCreated(context, sourceIndex));
2776*8975f5c5SAndroid Build Coastguard Worker
2777*8975f5c5SAndroid Build Coastguard Worker    const ImageDefinitionMtl &srcImageDef  = sourceMtl->getImageDefinition(sourceIndex);
2778*8975f5c5SAndroid Build Coastguard Worker    const mtl::TextureRef &sourceImage     = srcImageDef.image;
2779*8975f5c5SAndroid Build Coastguard Worker    const mtl::Format &sourceFormat        = contextMtl->getPixelFormat(srcImageDef.formatID);
2780*8975f5c5SAndroid Build Coastguard Worker    const angle::Format &sourceAngleFormat = sourceFormat.actualAngleFormat();
2781*8975f5c5SAndroid Build Coastguard Worker
2782*8975f5c5SAndroid Build Coastguard Worker    if (!mFormat.getCaps().isRenderable())
2783*8975f5c5SAndroid Build Coastguard Worker    {
2784*8975f5c5SAndroid Build Coastguard Worker        return copySubTextureCPU(context, index, destOffset, internalFormat,
2785*8975f5c5SAndroid Build Coastguard Worker                                 mtl::kZeroNativeMipLevel, sourceBox, sourceAngleFormat,
2786*8975f5c5SAndroid Build Coastguard Worker                                 unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha,
2787*8975f5c5SAndroid Build Coastguard Worker                                 sourceImage);
2788*8975f5c5SAndroid Build Coastguard Worker    }
2789*8975f5c5SAndroid Build Coastguard Worker    return copySubTextureWithDraw(
2790*8975f5c5SAndroid Build Coastguard Worker        context, index, destOffset, internalFormat, mtl::kZeroNativeMipLevel, sourceBox,
2791*8975f5c5SAndroid Build Coastguard Worker        sourceAngleFormat, unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha, sourceImage);
2792*8975f5c5SAndroid Build Coastguard Worker}
2793*8975f5c5SAndroid Build Coastguard Worker
2794*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::copySubTextureWithDraw(const gl::Context *context,
2795*8975f5c5SAndroid Build Coastguard Worker                                                 const gl::ImageIndex &index,
2796*8975f5c5SAndroid Build Coastguard Worker                                                 const gl::Offset &destOffset,
2797*8975f5c5SAndroid Build Coastguard Worker                                                 const gl::InternalFormat &internalFormat,
2798*8975f5c5SAndroid Build Coastguard Worker                                                 const mtl::MipmapNativeLevel &sourceNativeLevel,
2799*8975f5c5SAndroid Build Coastguard Worker                                                 const gl::Box &sourceBox,
2800*8975f5c5SAndroid Build Coastguard Worker                                                 const angle::Format &sourceAngleFormat,
2801*8975f5c5SAndroid Build Coastguard Worker                                                 bool unpackFlipY,
2802*8975f5c5SAndroid Build Coastguard Worker                                                 bool unpackPremultiplyAlpha,
2803*8975f5c5SAndroid Build Coastguard Worker                                                 bool unpackUnmultiplyAlpha,
2804*8975f5c5SAndroid Build Coastguard Worker                                                 const mtl::TextureRef &sourceTexture)
2805*8975f5c5SAndroid Build Coastguard Worker{
2806*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
2807*8975f5c5SAndroid Build Coastguard Worker    DisplayMtl *displayMtl = contextMtl->getDisplay();
2808*8975f5c5SAndroid Build Coastguard Worker
2809*8975f5c5SAndroid Build Coastguard Worker    mtl::TextureRef image = getImage(index);
2810*8975f5c5SAndroid Build Coastguard Worker    ASSERT(image && image->valid());
2811*8975f5c5SAndroid Build Coastguard Worker
2812*8975f5c5SAndroid Build Coastguard Worker    if (internalFormat.colorEncoding == GL_SRGB)
2813*8975f5c5SAndroid Build Coastguard Worker    {
2814*8975f5c5SAndroid Build Coastguard Worker        image = image->getLinearColorView();
2815*8975f5c5SAndroid Build Coastguard Worker    }
2816*8975f5c5SAndroid Build Coastguard Worker
2817*8975f5c5SAndroid Build Coastguard Worker    mtl::RenderCommandEncoder *cmdEncoder = contextMtl->getTextureRenderCommandEncoder(
2818*8975f5c5SAndroid Build Coastguard Worker        image, mtl::ImageNativeIndex::FromBaseZeroGLIndex(GetZeroLevelIndex(image)));
2819*8975f5c5SAndroid Build Coastguard Worker    mtl::ColorBlitParams blitParams;
2820*8975f5c5SAndroid Build Coastguard Worker
2821*8975f5c5SAndroid Build Coastguard Worker    blitParams.dstTextureSize = image->sizeAt0();
2822*8975f5c5SAndroid Build Coastguard Worker    blitParams.dstRect =
2823*8975f5c5SAndroid Build Coastguard Worker        gl::Rectangle(destOffset.x, destOffset.y, sourceBox.width, sourceBox.height);
2824*8975f5c5SAndroid Build Coastguard Worker    blitParams.dstScissorRect = blitParams.dstRect;
2825*8975f5c5SAndroid Build Coastguard Worker
2826*8975f5c5SAndroid Build Coastguard Worker    blitParams.enabledBuffers.set(0);
2827*8975f5c5SAndroid Build Coastguard Worker
2828*8975f5c5SAndroid Build Coastguard Worker    blitParams.src      = sourceTexture;
2829*8975f5c5SAndroid Build Coastguard Worker    blitParams.srcLevel = sourceNativeLevel;
2830*8975f5c5SAndroid Build Coastguard Worker    blitParams.srcLayer = 0;
2831*8975f5c5SAndroid Build Coastguard Worker    blitParams.srcNormalizedCoords =
2832*8975f5c5SAndroid Build Coastguard Worker        mtl::NormalizedCoords(sourceBox.toRect(), sourceTexture->size(sourceNativeLevel));
2833*8975f5c5SAndroid Build Coastguard Worker    blitParams.srcYFlipped            = false;
2834*8975f5c5SAndroid Build Coastguard Worker    blitParams.dstLuminance           = internalFormat.isLUMA();
2835*8975f5c5SAndroid Build Coastguard Worker    blitParams.unpackFlipY            = unpackFlipY;
2836*8975f5c5SAndroid Build Coastguard Worker    blitParams.unpackPremultiplyAlpha = unpackPremultiplyAlpha;
2837*8975f5c5SAndroid Build Coastguard Worker    blitParams.unpackUnmultiplyAlpha  = unpackUnmultiplyAlpha;
2838*8975f5c5SAndroid Build Coastguard Worker    blitParams.transformLinearToSrgb  = sourceAngleFormat.isSRGB;
2839*8975f5c5SAndroid Build Coastguard Worker
2840*8975f5c5SAndroid Build Coastguard Worker    return displayMtl->getUtils().copyTextureWithDraw(context, cmdEncoder, sourceAngleFormat,
2841*8975f5c5SAndroid Build Coastguard Worker                                                      mFormat.actualAngleFormat(), blitParams);
2842*8975f5c5SAndroid Build Coastguard Worker}
2843*8975f5c5SAndroid Build Coastguard Worker
2844*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::copySubTextureCPU(const gl::Context *context,
2845*8975f5c5SAndroid Build Coastguard Worker                                            const gl::ImageIndex &index,
2846*8975f5c5SAndroid Build Coastguard Worker                                            const gl::Offset &destOffset,
2847*8975f5c5SAndroid Build Coastguard Worker                                            const gl::InternalFormat &internalFormat,
2848*8975f5c5SAndroid Build Coastguard Worker                                            const mtl::MipmapNativeLevel &sourceNativeLevel,
2849*8975f5c5SAndroid Build Coastguard Worker                                            const gl::Box &sourceBox,
2850*8975f5c5SAndroid Build Coastguard Worker                                            const angle::Format &sourceAngleFormat,
2851*8975f5c5SAndroid Build Coastguard Worker                                            bool unpackFlipY,
2852*8975f5c5SAndroid Build Coastguard Worker                                            bool unpackPremultiplyAlpha,
2853*8975f5c5SAndroid Build Coastguard Worker                                            bool unpackUnmultiplyAlpha,
2854*8975f5c5SAndroid Build Coastguard Worker                                            const mtl::TextureRef &sourceTexture)
2855*8975f5c5SAndroid Build Coastguard Worker{
2856*8975f5c5SAndroid Build Coastguard Worker    mtl::TextureRef &image = getImage(index);
2857*8975f5c5SAndroid Build Coastguard Worker    ASSERT(image && image->valid());
2858*8975f5c5SAndroid Build Coastguard Worker
2859*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
2860*8975f5c5SAndroid Build Coastguard Worker
2861*8975f5c5SAndroid Build Coastguard Worker    const angle::Format &dstAngleFormat = mFormat.actualAngleFormat();
2862*8975f5c5SAndroid Build Coastguard Worker    const int srcRowPitch               = sourceAngleFormat.pixelBytes * sourceBox.width;
2863*8975f5c5SAndroid Build Coastguard Worker    const int srcImageSize              = srcRowPitch * sourceBox.height;
2864*8975f5c5SAndroid Build Coastguard Worker    const int convRowPitch              = dstAngleFormat.pixelBytes * sourceBox.width;
2865*8975f5c5SAndroid Build Coastguard Worker    const int convImageSize             = convRowPitch * sourceBox.height;
2866*8975f5c5SAndroid Build Coastguard Worker    angle::MemoryBuffer conversionSrc, conversionDst;
2867*8975f5c5SAndroid Build Coastguard Worker    ANGLE_CHECK_GL_ALLOC(contextMtl, conversionSrc.resize(srcImageSize));
2868*8975f5c5SAndroid Build Coastguard Worker    ANGLE_CHECK_GL_ALLOC(contextMtl, conversionDst.resize(convImageSize));
2869*8975f5c5SAndroid Build Coastguard Worker
2870*8975f5c5SAndroid Build Coastguard Worker    MTLRegion mtlSrcArea =
2871*8975f5c5SAndroid Build Coastguard Worker        MTLRegionMake2D(sourceBox.x, sourceBox.y, sourceBox.width, sourceBox.height);
2872*8975f5c5SAndroid Build Coastguard Worker    MTLRegion mtlDstArea =
2873*8975f5c5SAndroid Build Coastguard Worker        MTLRegionMake2D(destOffset.x, destOffset.y, sourceBox.width, sourceBox.height);
2874*8975f5c5SAndroid Build Coastguard Worker
2875*8975f5c5SAndroid Build Coastguard Worker    // Read pixels from source to memory:
2876*8975f5c5SAndroid Build Coastguard Worker    sourceTexture->getBytes(contextMtl, srcRowPitch, 0, mtlSrcArea, sourceNativeLevel, 0,
2877*8975f5c5SAndroid Build Coastguard Worker                            conversionSrc.data());
2878*8975f5c5SAndroid Build Coastguard Worker
2879*8975f5c5SAndroid Build Coastguard Worker    // Convert to destination format
2880*8975f5c5SAndroid Build Coastguard Worker    CopyImageCHROMIUM(conversionSrc.data(), srcRowPitch, sourceAngleFormat.pixelBytes, 0,
2881*8975f5c5SAndroid Build Coastguard Worker                      sourceAngleFormat.pixelReadFunction, conversionDst.data(), convRowPitch,
2882*8975f5c5SAndroid Build Coastguard Worker                      dstAngleFormat.pixelBytes, 0, dstAngleFormat.pixelWriteFunction,
2883*8975f5c5SAndroid Build Coastguard Worker                      internalFormat.format, internalFormat.componentType, sourceBox.width,
2884*8975f5c5SAndroid Build Coastguard Worker                      sourceBox.height, 1, unpackFlipY, unpackPremultiplyAlpha,
2885*8975f5c5SAndroid Build Coastguard Worker                      unpackUnmultiplyAlpha);
2886*8975f5c5SAndroid Build Coastguard Worker
2887*8975f5c5SAndroid Build Coastguard Worker    // Upload to texture
2888*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(UploadTextureContents(context, dstAngleFormat, mtlDstArea, mtl::kZeroNativeMipLevel,
2889*8975f5c5SAndroid Build Coastguard Worker                                    0, conversionDst.data(), convRowPitch, 0, false, image));
2890*8975f5c5SAndroid Build Coastguard Worker
2891*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
2892*8975f5c5SAndroid Build Coastguard Worker}
2893*8975f5c5SAndroid Build Coastguard Worker
2894*8975f5c5SAndroid Build Coastguard Worker}  // namespace rx
2895