1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2017 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/gpu/mtl/GrMtlGpu.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/private/GrTypesPriv.h"
11cb93a386Sopenharmony_ci#include "src/core/SkCompressedDataUtils.h"
12cb93a386Sopenharmony_ci#include "src/core/SkConvertPixels.h"
13cb93a386Sopenharmony_ci#include "src/core/SkMathPriv.h"
14cb93a386Sopenharmony_ci#include "src/core/SkMipmap.h"
15cb93a386Sopenharmony_ci#include "src/gpu/GrBackendUtils.h"
16cb93a386Sopenharmony_ci#include "src/gpu/GrDataUtils.h"
17cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h"
18cb93a386Sopenharmony_ci#include "src/gpu/GrRenderTarget.h"
19cb93a386Sopenharmony_ci#include "src/gpu/GrResourceProvider.h"
20cb93a386Sopenharmony_ci#include "src/gpu/GrTexture.h"
21cb93a386Sopenharmony_ci#include "src/gpu/GrThreadSafePipelineBuilder.h"
22cb93a386Sopenharmony_ci#include "src/gpu/mtl/GrMtlBuffer.h"
23cb93a386Sopenharmony_ci#include "src/gpu/mtl/GrMtlCommandBuffer.h"
24cb93a386Sopenharmony_ci#include "src/gpu/mtl/GrMtlOpsRenderPass.h"
25cb93a386Sopenharmony_ci#include "src/gpu/mtl/GrMtlPipelineStateBuilder.h"
26cb93a386Sopenharmony_ci#include "src/gpu/mtl/GrMtlRenderCommandEncoder.h"
27cb93a386Sopenharmony_ci#include "src/gpu/mtl/GrMtlSemaphore.h"
28cb93a386Sopenharmony_ci#include "src/gpu/mtl/GrMtlTexture.h"
29cb93a386Sopenharmony_ci#include "src/gpu/mtl/GrMtlTextureRenderTarget.h"
30cb93a386Sopenharmony_ci#include "src/gpu/mtl/GrMtlUtil.h"
31cb93a386Sopenharmony_ci
32cb93a386Sopenharmony_ci#import <simd/simd.h>
33cb93a386Sopenharmony_ci
34cb93a386Sopenharmony_ci#if !__has_feature(objc_arc)
35cb93a386Sopenharmony_ci#error This file must be compiled with Arc. Use -fobjc-arc flag
36cb93a386Sopenharmony_ci#endif
37cb93a386Sopenharmony_ci
38cb93a386Sopenharmony_ciGR_NORETAIN_BEGIN
39cb93a386Sopenharmony_ci
40cb93a386Sopenharmony_ci#if GR_TEST_UTILS
41cb93a386Sopenharmony_ci// set to 1 if you want to do GPU capture of each commandBuffer
42cb93a386Sopenharmony_ci#define GR_METAL_CAPTURE_COMMANDBUFFER 0
43cb93a386Sopenharmony_ci#endif
44cb93a386Sopenharmony_ci
45cb93a386Sopenharmony_cisk_sp<GrGpu> GrMtlGpu::Make(const GrMtlBackendContext& context, const GrContextOptions& options,
46cb93a386Sopenharmony_ci                            GrDirectContext* direct) {
47cb93a386Sopenharmony_ci    if (!context.fDevice || !context.fQueue) {
48cb93a386Sopenharmony_ci        return nullptr;
49cb93a386Sopenharmony_ci    }
50cb93a386Sopenharmony_ci    if (@available(macOS 10.14, iOS 10.0, *)) {
51cb93a386Sopenharmony_ci        // no warning needed
52cb93a386Sopenharmony_ci    } else {
53cb93a386Sopenharmony_ci        SkDebugf("*** Error ***: Skia's Metal backend no longer supports this OS version.\n");
54cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_IOS
55cb93a386Sopenharmony_ci        SkDebugf("Minimum supported version is iOS 10.0.\n");
56cb93a386Sopenharmony_ci#else
57cb93a386Sopenharmony_ci        SkDebugf("Minimum supported version is MacOS 10.14.\n");
58cb93a386Sopenharmony_ci#endif
59cb93a386Sopenharmony_ci        return nullptr;
60cb93a386Sopenharmony_ci    }
61cb93a386Sopenharmony_ci
62cb93a386Sopenharmony_ci    id<MTLDevice> GR_NORETAIN device = (__bridge id<MTLDevice>)(context.fDevice.get());
63cb93a386Sopenharmony_ci    id<MTLCommandQueue> GR_NORETAIN queue = (__bridge id<MTLCommandQueue>)(context.fQueue.get());
64cb93a386Sopenharmony_ci
65cb93a386Sopenharmony_ci    return sk_sp<GrGpu>(new GrMtlGpu(direct, options, device, queue, context.fBinaryArchive.get()));
66cb93a386Sopenharmony_ci}
67cb93a386Sopenharmony_ci
68cb93a386Sopenharmony_ci// This constant determines how many OutstandingCommandBuffers are allocated together as a block in
69cb93a386Sopenharmony_ci// the deque. As such it needs to balance allocating too much memory vs. incurring
70cb93a386Sopenharmony_ci// allocation/deallocation thrashing. It should roughly correspond to the max number of outstanding
71cb93a386Sopenharmony_ci// command buffers we expect to see.
72cb93a386Sopenharmony_cistatic const int kDefaultOutstandingAllocCnt = 8;
73cb93a386Sopenharmony_ci
74cb93a386Sopenharmony_ciGrMtlGpu::GrMtlGpu(GrDirectContext* direct, const GrContextOptions& options,
75cb93a386Sopenharmony_ci                   id<MTLDevice> device, id<MTLCommandQueue> queue, GrMTLHandle binaryArchive)
76cb93a386Sopenharmony_ci        : INHERITED(direct)
77cb93a386Sopenharmony_ci        , fDevice(device)
78cb93a386Sopenharmony_ci        , fQueue(queue)
79cb93a386Sopenharmony_ci        , fOutstandingCommandBuffers(sizeof(OutstandingCommandBuffer), kDefaultOutstandingAllocCnt)
80cb93a386Sopenharmony_ci        , fResourceProvider(this)
81cb93a386Sopenharmony_ci        , fStagingBufferManager(this)
82cb93a386Sopenharmony_ci        , fUniformsRingBuffer(this, 128 * 1024, 256, GrGpuBufferType::kUniform)
83cb93a386Sopenharmony_ci        , fDisconnected(false) {
84cb93a386Sopenharmony_ci    fMtlCaps.reset(new GrMtlCaps(options, fDevice));
85cb93a386Sopenharmony_ci    this->initCapsAndCompiler(fMtlCaps);
86cb93a386Sopenharmony_ci#if GR_METAL_CAPTURE_COMMANDBUFFER
87cb93a386Sopenharmony_ci    this->testingOnly_startCapture();
88cb93a386Sopenharmony_ci#endif
89cb93a386Sopenharmony_ci    fCurrentCmdBuffer = GrMtlCommandBuffer::Make(fQueue);
90cb93a386Sopenharmony_ci#if GR_METAL_SDK_VERSION >= 230
91cb93a386Sopenharmony_ci    if (@available(macOS 11.0, iOS 14.0, *)) {
92cb93a386Sopenharmony_ci        fBinaryArchive = (__bridge id<MTLBinaryArchive>)(binaryArchive);
93cb93a386Sopenharmony_ci    }
94cb93a386Sopenharmony_ci#endif
95cb93a386Sopenharmony_ci}
96cb93a386Sopenharmony_ci
97cb93a386Sopenharmony_ciGrMtlGpu::~GrMtlGpu() {
98cb93a386Sopenharmony_ci    if (!fDisconnected) {
99cb93a386Sopenharmony_ci        this->destroyResources();
100cb93a386Sopenharmony_ci    }
101cb93a386Sopenharmony_ci}
102cb93a386Sopenharmony_ci
103cb93a386Sopenharmony_civoid GrMtlGpu::disconnect(DisconnectType type) {
104cb93a386Sopenharmony_ci    INHERITED::disconnect(type);
105cb93a386Sopenharmony_ci
106cb93a386Sopenharmony_ci    if (!fDisconnected) {
107cb93a386Sopenharmony_ci        this->destroyResources();
108cb93a386Sopenharmony_ci        fDisconnected = true;
109cb93a386Sopenharmony_ci    }
110cb93a386Sopenharmony_ci}
111cb93a386Sopenharmony_ci
112cb93a386Sopenharmony_ciGrThreadSafePipelineBuilder* GrMtlGpu::pipelineBuilder() {
113cb93a386Sopenharmony_ci    return nullptr;
114cb93a386Sopenharmony_ci}
115cb93a386Sopenharmony_ci
116cb93a386Sopenharmony_cisk_sp<GrThreadSafePipelineBuilder> GrMtlGpu::refPipelineBuilder() {
117cb93a386Sopenharmony_ci    return nullptr;
118cb93a386Sopenharmony_ci}
119cb93a386Sopenharmony_ci
120cb93a386Sopenharmony_civoid GrMtlGpu::destroyResources() {
121cb93a386Sopenharmony_ci    this->submitCommandBuffer(SyncQueue::kForce_SyncQueue);
122cb93a386Sopenharmony_ci    // if there's no work we won't release the command buffer, so we do it here
123cb93a386Sopenharmony_ci    fCurrentCmdBuffer = nil;
124cb93a386Sopenharmony_ci
125cb93a386Sopenharmony_ci    // We used a placement new for each object in fOutstandingCommandBuffers, so we're responsible
126cb93a386Sopenharmony_ci    // for calling the destructor on each of them as well.
127cb93a386Sopenharmony_ci    while (!fOutstandingCommandBuffers.empty()) {
128cb93a386Sopenharmony_ci        OutstandingCommandBuffer* buffer =
129cb93a386Sopenharmony_ci                (OutstandingCommandBuffer*)fOutstandingCommandBuffers.front();
130cb93a386Sopenharmony_ci        // make sure we remove before deleting as deletion might try to kick off another submit
131cb93a386Sopenharmony_ci        fOutstandingCommandBuffers.pop_front();
132cb93a386Sopenharmony_ci        buffer->~OutstandingCommandBuffer();
133cb93a386Sopenharmony_ci    }
134cb93a386Sopenharmony_ci
135cb93a386Sopenharmony_ci    fStagingBufferManager.reset();
136cb93a386Sopenharmony_ci
137cb93a386Sopenharmony_ci    fResourceProvider.destroyResources();
138cb93a386Sopenharmony_ci
139cb93a386Sopenharmony_ci    fQueue = nil;
140cb93a386Sopenharmony_ci    fDevice = nil;
141cb93a386Sopenharmony_ci}
142cb93a386Sopenharmony_ci
143cb93a386Sopenharmony_ciGrOpsRenderPass* GrMtlGpu::onGetOpsRenderPass(
144cb93a386Sopenharmony_ci            GrRenderTarget* renderTarget, bool useMSAASurface, GrAttachment* stencil,
145cb93a386Sopenharmony_ci            GrSurfaceOrigin origin, const SkIRect& bounds,
146cb93a386Sopenharmony_ci            const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
147cb93a386Sopenharmony_ci            const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
148cb93a386Sopenharmony_ci            const SkTArray<GrSurfaceProxy*, true>& sampledProxies,
149cb93a386Sopenharmony_ci            GrXferBarrierFlags renderPassXferBarriers) {
150cb93a386Sopenharmony_ci    // For the given render target and requested render pass features we need to find a compatible
151cb93a386Sopenharmony_ci    // framebuffer to use.
152cb93a386Sopenharmony_ci    GrMtlRenderTarget* mtlRT = static_cast<GrMtlRenderTarget*>(renderTarget);
153cb93a386Sopenharmony_ci
154cb93a386Sopenharmony_ci    // TODO: support DMSAA
155cb93a386Sopenharmony_ci    SkASSERT(!useMSAASurface ||
156cb93a386Sopenharmony_ci             (renderTarget->numSamples() > 1));
157cb93a386Sopenharmony_ci
158cb93a386Sopenharmony_ci    bool withResolve = false;
159cb93a386Sopenharmony_ci
160cb93a386Sopenharmony_ci    // Figure out if we can use a Resolve store action for this render pass. When we set up
161cb93a386Sopenharmony_ci    // the render pass we'll update the color load/store ops since we don't want to ever load
162cb93a386Sopenharmony_ci    // or store the msaa color attachment, but may need to for the resolve attachment.
163cb93a386Sopenharmony_ci    if (useMSAASurface && this->mtlCaps().renderTargetSupportsDiscardableMSAA(mtlRT)) {
164cb93a386Sopenharmony_ci        withResolve = true;
165cb93a386Sopenharmony_ci    }
166cb93a386Sopenharmony_ci
167cb93a386Sopenharmony_ci    sk_sp<GrMtlFramebuffer> framebuffer =
168cb93a386Sopenharmony_ci            sk_ref_sp(mtlRT->getFramebuffer(withResolve, SkToBool(stencil)));
169cb93a386Sopenharmony_ci    if (!framebuffer) {
170cb93a386Sopenharmony_ci        return nullptr;
171cb93a386Sopenharmony_ci    }
172cb93a386Sopenharmony_ci
173cb93a386Sopenharmony_ci    return new GrMtlOpsRenderPass(this, renderTarget, std::move(framebuffer), origin, colorInfo,
174cb93a386Sopenharmony_ci                                  stencilInfo);
175cb93a386Sopenharmony_ci}
176cb93a386Sopenharmony_ci
177cb93a386Sopenharmony_ciGrMtlCommandBuffer* GrMtlGpu::commandBuffer() {
178cb93a386Sopenharmony_ci    if (!fCurrentCmdBuffer) {
179cb93a386Sopenharmony_ci#if GR_METAL_CAPTURE_COMMANDBUFFER
180cb93a386Sopenharmony_ci        this->testingOnly_startCapture();
181cb93a386Sopenharmony_ci#endif
182cb93a386Sopenharmony_ci        // Create a new command buffer for the next submit
183cb93a386Sopenharmony_ci        fCurrentCmdBuffer = GrMtlCommandBuffer::Make(fQueue);
184cb93a386Sopenharmony_ci    }
185cb93a386Sopenharmony_ci
186cb93a386Sopenharmony_ci    SkASSERT(fCurrentCmdBuffer);
187cb93a386Sopenharmony_ci    return fCurrentCmdBuffer.get();
188cb93a386Sopenharmony_ci}
189cb93a386Sopenharmony_ci
190cb93a386Sopenharmony_civoid GrMtlGpu::takeOwnershipOfBuffer(sk_sp<GrGpuBuffer> buffer) {
191cb93a386Sopenharmony_ci    SkASSERT(buffer);
192cb93a386Sopenharmony_ci    this->commandBuffer()->addGrBuffer(std::move(buffer));
193cb93a386Sopenharmony_ci}
194cb93a386Sopenharmony_ci
195cb93a386Sopenharmony_civoid GrMtlGpu::submit(GrOpsRenderPass* renderPass) {
196cb93a386Sopenharmony_ci    GrMtlOpsRenderPass* mtlRenderPass = reinterpret_cast<GrMtlOpsRenderPass*>(renderPass);
197cb93a386Sopenharmony_ci    mtlRenderPass->submit();
198cb93a386Sopenharmony_ci    delete renderPass;
199cb93a386Sopenharmony_ci}
200cb93a386Sopenharmony_ci
201cb93a386Sopenharmony_cibool GrMtlGpu::submitCommandBuffer(SyncQueue sync) {
202cb93a386Sopenharmony_ci    if (!fCurrentCmdBuffer || !fCurrentCmdBuffer->hasWork()) {
203cb93a386Sopenharmony_ci        if (sync == SyncQueue::kForce_SyncQueue) {
204cb93a386Sopenharmony_ci            this->finishOutstandingGpuWork();
205cb93a386Sopenharmony_ci            this->checkForFinishedCommandBuffers();
206cb93a386Sopenharmony_ci        }
207cb93a386Sopenharmony_ci        // We need to manually call the finishedCallbacks since we don't add this
208cb93a386Sopenharmony_ci        // to the OutstandingCommandBuffer list
209cb93a386Sopenharmony_ci        if (fCurrentCmdBuffer) {
210cb93a386Sopenharmony_ci            fCurrentCmdBuffer->callFinishedCallbacks();
211cb93a386Sopenharmony_ci        }
212cb93a386Sopenharmony_ci        return true;
213cb93a386Sopenharmony_ci    }
214cb93a386Sopenharmony_ci
215cb93a386Sopenharmony_ci    SkASSERT(fCurrentCmdBuffer);
216cb93a386Sopenharmony_ci    bool didCommit = fCurrentCmdBuffer->commit(sync == SyncQueue::kForce_SyncQueue);
217cb93a386Sopenharmony_ci    if (didCommit) {
218cb93a386Sopenharmony_ci        new (fOutstandingCommandBuffers.push_back()) OutstandingCommandBuffer(fCurrentCmdBuffer);
219cb93a386Sopenharmony_ci    }
220cb93a386Sopenharmony_ci
221cb93a386Sopenharmony_ci    // We don't create a new command buffer here because we may end up using it
222cb93a386Sopenharmony_ci    // in the next frame, and that confuses the GPU debugger. Instead we
223cb93a386Sopenharmony_ci    // create when we next need one.
224cb93a386Sopenharmony_ci    fCurrentCmdBuffer.reset();
225cb93a386Sopenharmony_ci
226cb93a386Sopenharmony_ci    // If the freeing of any resources held by a finished command buffer causes us to send
227cb93a386Sopenharmony_ci    // a new command to the gpu we'll create the new command buffer in commandBuffer(), above.
228cb93a386Sopenharmony_ci    this->checkForFinishedCommandBuffers();
229cb93a386Sopenharmony_ci
230cb93a386Sopenharmony_ci#if GR_METAL_CAPTURE_COMMANDBUFFER
231cb93a386Sopenharmony_ci    this->testingOnly_endCapture();
232cb93a386Sopenharmony_ci#endif
233cb93a386Sopenharmony_ci    return didCommit;
234cb93a386Sopenharmony_ci}
235cb93a386Sopenharmony_ci
236cb93a386Sopenharmony_civoid GrMtlGpu::checkForFinishedCommandBuffers() {
237cb93a386Sopenharmony_ci    // Iterate over all the outstanding command buffers to see if any have finished. The command
238cb93a386Sopenharmony_ci    // buffers are in order from oldest to newest, so we start at the front to check if their fence
239cb93a386Sopenharmony_ci    // has signaled. If so we pop it off and move onto the next.
240cb93a386Sopenharmony_ci    // Repeat till we find a command list that has not finished yet (and all others afterwards are
241cb93a386Sopenharmony_ci    // also guaranteed to not have finished).
242cb93a386Sopenharmony_ci    OutstandingCommandBuffer* front = (OutstandingCommandBuffer*)fOutstandingCommandBuffers.front();
243cb93a386Sopenharmony_ci    while (front && (*front)->isCompleted()) {
244cb93a386Sopenharmony_ci        // Make sure we remove before deleting as deletion might try to kick off another submit
245cb93a386Sopenharmony_ci        fOutstandingCommandBuffers.pop_front();
246cb93a386Sopenharmony_ci        // Since we used placement new we are responsible for calling the destructor manually.
247cb93a386Sopenharmony_ci        front->~OutstandingCommandBuffer();
248cb93a386Sopenharmony_ci        front = (OutstandingCommandBuffer*)fOutstandingCommandBuffers.front();
249cb93a386Sopenharmony_ci    }
250cb93a386Sopenharmony_ci}
251cb93a386Sopenharmony_ci
252cb93a386Sopenharmony_civoid GrMtlGpu::finishOutstandingGpuWork() {
253cb93a386Sopenharmony_ci    // wait for the last command buffer we've submitted to finish
254cb93a386Sopenharmony_ci    OutstandingCommandBuffer* back =
255cb93a386Sopenharmony_ci            (OutstandingCommandBuffer*)fOutstandingCommandBuffers.back();
256cb93a386Sopenharmony_ci    if (back) {
257cb93a386Sopenharmony_ci        (*back)->waitUntilCompleted();
258cb93a386Sopenharmony_ci    }
259cb93a386Sopenharmony_ci}
260cb93a386Sopenharmony_ci
261cb93a386Sopenharmony_civoid GrMtlGpu::addFinishedProc(GrGpuFinishedProc finishedProc,
262cb93a386Sopenharmony_ci                               GrGpuFinishedContext finishedContext) {
263cb93a386Sopenharmony_ci    SkASSERT(finishedProc);
264cb93a386Sopenharmony_ci    this->addFinishedCallback(GrRefCntedCallback::Make(finishedProc, finishedContext));
265cb93a386Sopenharmony_ci}
266cb93a386Sopenharmony_ci
267cb93a386Sopenharmony_civoid GrMtlGpu::addFinishedCallback(sk_sp<GrRefCntedCallback> finishedCallback) {
268cb93a386Sopenharmony_ci    SkASSERT(finishedCallback);
269cb93a386Sopenharmony_ci    // Besides the current commandbuffer, we also add the finishedCallback to the newest outstanding
270cb93a386Sopenharmony_ci    // commandbuffer. Our contract for calling the proc is that all previous submitted cmdbuffers
271cb93a386Sopenharmony_ci    // have finished when we call it. However, if our current command buffer has no work when it is
272cb93a386Sopenharmony_ci    // flushed it will drop its ref to the callback immediately. But the previous work may not have
273cb93a386Sopenharmony_ci    // finished. It is safe to only add the proc to the newest outstanding commandbuffer cause that
274cb93a386Sopenharmony_ci    // must finish after all previously submitted command buffers.
275cb93a386Sopenharmony_ci    OutstandingCommandBuffer* back = (OutstandingCommandBuffer*)fOutstandingCommandBuffers.back();
276cb93a386Sopenharmony_ci    if (back) {
277cb93a386Sopenharmony_ci        (*back)->addFinishedCallback(finishedCallback);
278cb93a386Sopenharmony_ci    }
279cb93a386Sopenharmony_ci    commandBuffer()->addFinishedCallback(std::move(finishedCallback));
280cb93a386Sopenharmony_ci}
281cb93a386Sopenharmony_ci
282cb93a386Sopenharmony_cibool GrMtlGpu::onSubmitToGpu(bool syncCpu) {
283cb93a386Sopenharmony_ci    if (syncCpu) {
284cb93a386Sopenharmony_ci        return this->submitCommandBuffer(kForce_SyncQueue);
285cb93a386Sopenharmony_ci    } else {
286cb93a386Sopenharmony_ci        return this->submitCommandBuffer(kSkip_SyncQueue);
287cb93a386Sopenharmony_ci    }
288cb93a386Sopenharmony_ci}
289cb93a386Sopenharmony_ci
290cb93a386Sopenharmony_cistd::unique_ptr<GrSemaphore> GrMtlGpu::prepareTextureForCrossContextUsage(GrTexture*) {
291cb93a386Sopenharmony_ci    this->submitToGpu(false);
292cb93a386Sopenharmony_ci    return nullptr;
293cb93a386Sopenharmony_ci}
294cb93a386Sopenharmony_ci
295cb93a386Sopenharmony_cisk_sp<GrGpuBuffer> GrMtlGpu::onCreateBuffer(size_t size, GrGpuBufferType type,
296cb93a386Sopenharmony_ci                                            GrAccessPattern accessPattern, const void* data) {
297cb93a386Sopenharmony_ci    return GrMtlBuffer::Make(this, size, type, accessPattern, data);
298cb93a386Sopenharmony_ci}
299cb93a386Sopenharmony_ci
300cb93a386Sopenharmony_cistatic bool check_max_blit_width(int widthInPixels) {
301cb93a386Sopenharmony_ci    if (widthInPixels > 32767) {
302cb93a386Sopenharmony_ci        SkASSERT(false); // surfaces should not be this wide anyway
303cb93a386Sopenharmony_ci        return false;
304cb93a386Sopenharmony_ci    }
305cb93a386Sopenharmony_ci    return true;
306cb93a386Sopenharmony_ci}
307cb93a386Sopenharmony_ci
308cb93a386Sopenharmony_cibool GrMtlGpu::uploadToTexture(GrMtlTexture* tex,
309cb93a386Sopenharmony_ci                               SkIRect rect,
310cb93a386Sopenharmony_ci                               GrColorType dataColorType,
311cb93a386Sopenharmony_ci                               const GrMipLevel texels[],
312cb93a386Sopenharmony_ci                               int mipLevelCount) {
313cb93a386Sopenharmony_ci    SkASSERT(this->mtlCaps().isFormatTexturable(tex->mtlTexture().pixelFormat));
314cb93a386Sopenharmony_ci    // The assumption is either that we have no mipmaps, or that our rect is the entire texture
315cb93a386Sopenharmony_ci    SkASSERT(mipLevelCount == 1 || rect == SkIRect::MakeSize(tex->dimensions()));
316cb93a386Sopenharmony_ci
317cb93a386Sopenharmony_ci    // We assume that if the texture has mip levels, we either upload to all the levels or just the
318cb93a386Sopenharmony_ci    // first.
319cb93a386Sopenharmony_ci    SkASSERT(mipLevelCount == 1 || mipLevelCount == (tex->maxMipmapLevel() + 1));
320cb93a386Sopenharmony_ci
321cb93a386Sopenharmony_ci    if (!check_max_blit_width(rect.width())) {
322cb93a386Sopenharmony_ci        return false;
323cb93a386Sopenharmony_ci    }
324cb93a386Sopenharmony_ci    if (rect.isEmpty()) {
325cb93a386Sopenharmony_ci        return false;
326cb93a386Sopenharmony_ci    }
327cb93a386Sopenharmony_ci
328cb93a386Sopenharmony_ci    SkASSERT(this->mtlCaps().surfaceSupportsWritePixels(tex));
329cb93a386Sopenharmony_ci    SkASSERT(this->mtlCaps().areColorTypeAndFormatCompatible(dataColorType, tex->backendFormat()));
330cb93a386Sopenharmony_ci
331cb93a386Sopenharmony_ci    id<MTLTexture> GR_NORETAIN mtlTexture = tex->mtlTexture();
332cb93a386Sopenharmony_ci    SkASSERT(mtlTexture);
333cb93a386Sopenharmony_ci    // Either upload only the first miplevel or all miplevels
334cb93a386Sopenharmony_ci    SkASSERT(1 == mipLevelCount || mipLevelCount == (int)mtlTexture.mipmapLevelCount);
335cb93a386Sopenharmony_ci
336cb93a386Sopenharmony_ci    if (mipLevelCount == 1 && !texels[0].fPixels) {
337cb93a386Sopenharmony_ci        return true;   // no data to upload
338cb93a386Sopenharmony_ci    }
339cb93a386Sopenharmony_ci
340cb93a386Sopenharmony_ci    for (int i = 0; i < mipLevelCount; ++i) {
341cb93a386Sopenharmony_ci        // We do not allow any gaps in the mip data
342cb93a386Sopenharmony_ci        if (!texels[i].fPixels) {
343cb93a386Sopenharmony_ci            return false;
344cb93a386Sopenharmony_ci        }
345cb93a386Sopenharmony_ci    }
346cb93a386Sopenharmony_ci
347cb93a386Sopenharmony_ci    size_t bpp = GrColorTypeBytesPerPixel(dataColorType);
348cb93a386Sopenharmony_ci
349cb93a386Sopenharmony_ci    SkTArray<size_t> individualMipOffsets(mipLevelCount);
350cb93a386Sopenharmony_ci    size_t combinedBufferSize = GrComputeTightCombinedBufferSize(bpp,
351cb93a386Sopenharmony_ci                                                                 rect.size(),
352cb93a386Sopenharmony_ci                                                                 &individualMipOffsets,
353cb93a386Sopenharmony_ci                                                                 mipLevelCount);
354cb93a386Sopenharmony_ci    SkASSERT(combinedBufferSize);
355cb93a386Sopenharmony_ci
356cb93a386Sopenharmony_ci
357cb93a386Sopenharmony_ci    // offset value must be a multiple of the destination texture's pixel size in bytes
358cb93a386Sopenharmony_ci    size_t alignment = std::max(bpp, this->mtlCaps().getMinBufferAlignment());
359cb93a386Sopenharmony_ci    GrStagingBufferManager::Slice slice = fStagingBufferManager.allocateStagingBufferSlice(
360cb93a386Sopenharmony_ci            combinedBufferSize, alignment);
361cb93a386Sopenharmony_ci    if (!slice.fBuffer) {
362cb93a386Sopenharmony_ci        return false;
363cb93a386Sopenharmony_ci    }
364cb93a386Sopenharmony_ci    char* bufferData = (char*)slice.fOffsetMapPtr;
365cb93a386Sopenharmony_ci    GrMtlBuffer* mtlBuffer = static_cast<GrMtlBuffer*>(slice.fBuffer);
366cb93a386Sopenharmony_ci
367cb93a386Sopenharmony_ci    int currentWidth = rect.width();
368cb93a386Sopenharmony_ci    int currentHeight = rect.height();
369cb93a386Sopenharmony_ci    SkDEBUGCODE(int layerHeight = tex->height());
370cb93a386Sopenharmony_ci    MTLOrigin origin = MTLOriginMake(rect.left(), rect.top(), 0);
371cb93a386Sopenharmony_ci
372cb93a386Sopenharmony_ci    auto cmdBuffer = this->commandBuffer();
373cb93a386Sopenharmony_ci    id<MTLBlitCommandEncoder> GR_NORETAIN blitCmdEncoder = cmdBuffer->getBlitCommandEncoder();
374cb93a386Sopenharmony_ci    if (!blitCmdEncoder) {
375cb93a386Sopenharmony_ci        return false;
376cb93a386Sopenharmony_ci    }
377cb93a386Sopenharmony_ci#ifdef SK_ENABLE_MTL_DEBUG_INFO
378cb93a386Sopenharmony_ci    [blitCmdEncoder pushDebugGroup:@"uploadToTexture"];
379cb93a386Sopenharmony_ci#endif
380cb93a386Sopenharmony_ci    for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
381cb93a386Sopenharmony_ci        if (texels[currentMipLevel].fPixels) {
382cb93a386Sopenharmony_ci            SkASSERT(1 == mipLevelCount || currentHeight == layerHeight);
383cb93a386Sopenharmony_ci            const size_t trimRowBytes = currentWidth * bpp;
384cb93a386Sopenharmony_ci            const size_t rowBytes = texels[currentMipLevel].fRowBytes;
385cb93a386Sopenharmony_ci
386cb93a386Sopenharmony_ci            // copy data into the buffer, skipping any trailing bytes
387cb93a386Sopenharmony_ci            char* dst = bufferData + individualMipOffsets[currentMipLevel];
388cb93a386Sopenharmony_ci            const char* src = (const char*)texels[currentMipLevel].fPixels;
389cb93a386Sopenharmony_ci            SkRectMemcpy(dst, trimRowBytes, src, rowBytes, trimRowBytes, currentHeight);
390cb93a386Sopenharmony_ci
391cb93a386Sopenharmony_ci            [blitCmdEncoder copyFromBuffer: mtlBuffer->mtlBuffer()
392cb93a386Sopenharmony_ci                              sourceOffset: slice.fOffset + individualMipOffsets[currentMipLevel]
393cb93a386Sopenharmony_ci                         sourceBytesPerRow: trimRowBytes
394cb93a386Sopenharmony_ci                       sourceBytesPerImage: trimRowBytes*currentHeight
395cb93a386Sopenharmony_ci                                sourceSize: MTLSizeMake(currentWidth, currentHeight, 1)
396cb93a386Sopenharmony_ci                                 toTexture: mtlTexture
397cb93a386Sopenharmony_ci                          destinationSlice: 0
398cb93a386Sopenharmony_ci                          destinationLevel: currentMipLevel
399cb93a386Sopenharmony_ci                         destinationOrigin: origin];
400cb93a386Sopenharmony_ci        }
401cb93a386Sopenharmony_ci        currentWidth = std::max(1, currentWidth/2);
402cb93a386Sopenharmony_ci        currentHeight = std::max(1, currentHeight/2);
403cb93a386Sopenharmony_ci        SkDEBUGCODE(layerHeight = currentHeight);
404cb93a386Sopenharmony_ci    }
405cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_MAC
406cb93a386Sopenharmony_ci    if (this->mtlCaps().isMac()) {
407cb93a386Sopenharmony_ci        [mtlBuffer->mtlBuffer() didModifyRange: NSMakeRange(slice.fOffset, combinedBufferSize)];
408cb93a386Sopenharmony_ci    }
409cb93a386Sopenharmony_ci#endif
410cb93a386Sopenharmony_ci#ifdef SK_ENABLE_MTL_DEBUG_INFO
411cb93a386Sopenharmony_ci    [blitCmdEncoder popDebugGroup];
412cb93a386Sopenharmony_ci#endif
413cb93a386Sopenharmony_ci
414cb93a386Sopenharmony_ci    if (mipLevelCount < (int) tex->mtlTexture().mipmapLevelCount) {
415cb93a386Sopenharmony_ci        tex->markMipmapsDirty();
416cb93a386Sopenharmony_ci    }
417cb93a386Sopenharmony_ci
418cb93a386Sopenharmony_ci    return true;
419cb93a386Sopenharmony_ci}
420cb93a386Sopenharmony_ci
421cb93a386Sopenharmony_cibool GrMtlGpu::clearTexture(GrMtlTexture* tex, size_t bpp, uint32_t levelMask) {
422cb93a386Sopenharmony_ci    SkASSERT(this->mtlCaps().isFormatTexturable(tex->mtlTexture().pixelFormat));
423cb93a386Sopenharmony_ci
424cb93a386Sopenharmony_ci    if (!levelMask) {
425cb93a386Sopenharmony_ci        return true;
426cb93a386Sopenharmony_ci    }
427cb93a386Sopenharmony_ci
428cb93a386Sopenharmony_ci    id<MTLTexture> GR_NORETAIN mtlTexture = tex->mtlTexture();
429cb93a386Sopenharmony_ci    SkASSERT(mtlTexture);
430cb93a386Sopenharmony_ci    // Either upload only the first miplevel or all miplevels
431cb93a386Sopenharmony_ci    int mipLevelCount = (int)mtlTexture.mipmapLevelCount;
432cb93a386Sopenharmony_ci
433cb93a386Sopenharmony_ci    SkTArray<size_t> individualMipOffsets(mipLevelCount);
434cb93a386Sopenharmony_ci    size_t combinedBufferSize = 0;
435cb93a386Sopenharmony_ci    int currentWidth = tex->width();
436cb93a386Sopenharmony_ci    int currentHeight = tex->height();
437cb93a386Sopenharmony_ci
438cb93a386Sopenharmony_ci    // The alignment must be at least 4 bytes and a multiple of the bytes per pixel of the image
439cb93a386Sopenharmony_ci    // config. This works with the assumption that the bytes in pixel config is always a power of 2.
440cb93a386Sopenharmony_ci    // TODO: can we just copy from a single buffer the size of the largest cleared level w/o a perf
441cb93a386Sopenharmony_ci    // penalty?
442cb93a386Sopenharmony_ci    SkASSERT((bpp & (bpp - 1)) == 0);
443cb93a386Sopenharmony_ci    const size_t alignmentMask = 0x3 | (bpp - 1);
444cb93a386Sopenharmony_ci    for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
445cb93a386Sopenharmony_ci        if (levelMask & (1 << currentMipLevel)) {
446cb93a386Sopenharmony_ci            const size_t trimmedSize = currentWidth * bpp * currentHeight;
447cb93a386Sopenharmony_ci            const size_t alignmentDiff = combinedBufferSize & alignmentMask;
448cb93a386Sopenharmony_ci            if (alignmentDiff != 0) {
449cb93a386Sopenharmony_ci                combinedBufferSize += alignmentMask - alignmentDiff + 1;
450cb93a386Sopenharmony_ci            }
451cb93a386Sopenharmony_ci            individualMipOffsets.push_back(combinedBufferSize);
452cb93a386Sopenharmony_ci            combinedBufferSize += trimmedSize;
453cb93a386Sopenharmony_ci        }
454cb93a386Sopenharmony_ci        currentWidth = std::max(1, currentWidth/2);
455cb93a386Sopenharmony_ci        currentHeight = std::max(1, currentHeight/2);
456cb93a386Sopenharmony_ci    }
457cb93a386Sopenharmony_ci    SkASSERT(combinedBufferSize > 0 && !individualMipOffsets.empty());
458cb93a386Sopenharmony_ci
459cb93a386Sopenharmony_ci    size_t alignment = std::max(bpp, this->mtlCaps().getMinBufferAlignment());
460cb93a386Sopenharmony_ci    GrStagingBufferManager::Slice slice = fStagingBufferManager.allocateStagingBufferSlice(
461cb93a386Sopenharmony_ci            combinedBufferSize, alignment);
462cb93a386Sopenharmony_ci    if (!slice.fBuffer) {
463cb93a386Sopenharmony_ci        return false;
464cb93a386Sopenharmony_ci    }
465cb93a386Sopenharmony_ci    GrMtlBuffer* mtlBuffer = static_cast<GrMtlBuffer*>(slice.fBuffer);
466cb93a386Sopenharmony_ci    id<MTLBuffer> transferBuffer = mtlBuffer->mtlBuffer();
467cb93a386Sopenharmony_ci
468cb93a386Sopenharmony_ci    auto cmdBuffer = this->commandBuffer();
469cb93a386Sopenharmony_ci    id<MTLBlitCommandEncoder> GR_NORETAIN blitCmdEncoder = cmdBuffer->getBlitCommandEncoder();
470cb93a386Sopenharmony_ci    if (!blitCmdEncoder) {
471cb93a386Sopenharmony_ci        return false;
472cb93a386Sopenharmony_ci    }
473cb93a386Sopenharmony_ci#ifdef SK_ENABLE_MTL_DEBUG_INFO
474cb93a386Sopenharmony_ci    [blitCmdEncoder pushDebugGroup:@"clearTexture"];
475cb93a386Sopenharmony_ci#endif
476cb93a386Sopenharmony_ci    // clear the buffer to transparent black
477cb93a386Sopenharmony_ci    NSRange clearRange;
478cb93a386Sopenharmony_ci    clearRange.location = 0;
479cb93a386Sopenharmony_ci    clearRange.length = combinedBufferSize;
480cb93a386Sopenharmony_ci    [blitCmdEncoder fillBuffer: transferBuffer
481cb93a386Sopenharmony_ci                         range: clearRange
482cb93a386Sopenharmony_ci                         value: 0];
483cb93a386Sopenharmony_ci
484cb93a386Sopenharmony_ci    // now copy buffer to texture
485cb93a386Sopenharmony_ci    currentWidth = tex->width();
486cb93a386Sopenharmony_ci    currentHeight = tex->height();
487cb93a386Sopenharmony_ci    MTLOrigin origin = MTLOriginMake(0, 0, 0);
488cb93a386Sopenharmony_ci    for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
489cb93a386Sopenharmony_ci        if (levelMask & (1 << currentMipLevel)) {
490cb93a386Sopenharmony_ci            const size_t rowBytes = currentWidth * bpp;
491cb93a386Sopenharmony_ci
492cb93a386Sopenharmony_ci            [blitCmdEncoder copyFromBuffer: transferBuffer
493cb93a386Sopenharmony_ci                              sourceOffset: individualMipOffsets[currentMipLevel]
494cb93a386Sopenharmony_ci                         sourceBytesPerRow: rowBytes
495cb93a386Sopenharmony_ci                       sourceBytesPerImage: rowBytes * currentHeight
496cb93a386Sopenharmony_ci                                sourceSize: MTLSizeMake(currentWidth, currentHeight, 1)
497cb93a386Sopenharmony_ci                                 toTexture: mtlTexture
498cb93a386Sopenharmony_ci                          destinationSlice: 0
499cb93a386Sopenharmony_ci                          destinationLevel: currentMipLevel
500cb93a386Sopenharmony_ci                         destinationOrigin: origin];
501cb93a386Sopenharmony_ci        }
502cb93a386Sopenharmony_ci        currentWidth = std::max(1, currentWidth/2);
503cb93a386Sopenharmony_ci        currentHeight = std::max(1, currentHeight/2);
504cb93a386Sopenharmony_ci    }
505cb93a386Sopenharmony_ci    // Don't need didModifyRange: here because fillBuffer: happens on the GPU
506cb93a386Sopenharmony_ci#ifdef SK_ENABLE_MTL_DEBUG_INFO
507cb93a386Sopenharmony_ci    [blitCmdEncoder popDebugGroup];
508cb93a386Sopenharmony_ci#endif
509cb93a386Sopenharmony_ci
510cb93a386Sopenharmony_ci    if (mipLevelCount < (int) tex->mtlTexture().mipmapLevelCount) {
511cb93a386Sopenharmony_ci        tex->markMipmapsDirty();
512cb93a386Sopenharmony_ci    }
513cb93a386Sopenharmony_ci
514cb93a386Sopenharmony_ci    return true;
515cb93a386Sopenharmony_ci}
516cb93a386Sopenharmony_ci
517cb93a386Sopenharmony_cisk_sp<GrAttachment> GrMtlGpu::makeStencilAttachment(const GrBackendFormat& /*colorFormat*/,
518cb93a386Sopenharmony_ci                                                    SkISize dimensions, int numStencilSamples) {
519cb93a386Sopenharmony_ci    MTLPixelFormat sFmt = this->mtlCaps().preferredStencilFormat();
520cb93a386Sopenharmony_ci
521cb93a386Sopenharmony_ci    fStats.incStencilAttachmentCreates();
522cb93a386Sopenharmony_ci    return GrMtlAttachment::GrMtlAttachment::MakeStencil(this, dimensions, numStencilSamples, sFmt);
523cb93a386Sopenharmony_ci}
524cb93a386Sopenharmony_ci
525cb93a386Sopenharmony_cisk_sp<GrAttachment> GrMtlGpu::makeMSAAAttachment(SkISize dimensions,
526cb93a386Sopenharmony_ci                                                 const GrBackendFormat& format,
527cb93a386Sopenharmony_ci                                                 int numSamples,
528cb93a386Sopenharmony_ci                                                 GrProtected isProtected,
529cb93a386Sopenharmony_ci                                                 GrMemoryless isMemoryless) {
530cb93a386Sopenharmony_ci    // Metal doesn't support protected textures
531cb93a386Sopenharmony_ci    SkASSERT(isProtected == GrProtected::kNo);
532cb93a386Sopenharmony_ci    // TODO: add memoryless support
533cb93a386Sopenharmony_ci    SkASSERT(isMemoryless == GrMemoryless::kNo);
534cb93a386Sopenharmony_ci
535cb93a386Sopenharmony_ci    MTLPixelFormat pixelFormat = (MTLPixelFormat) format.asMtlFormat();
536cb93a386Sopenharmony_ci    SkASSERT(pixelFormat != MTLPixelFormatInvalid);
537cb93a386Sopenharmony_ci    SkASSERT(!GrMtlFormatIsCompressed(pixelFormat));
538cb93a386Sopenharmony_ci    SkASSERT(this->mtlCaps().isFormatRenderable(pixelFormat, numSamples));
539cb93a386Sopenharmony_ci
540cb93a386Sopenharmony_ci    fStats.incMSAAAttachmentCreates();
541cb93a386Sopenharmony_ci    return GrMtlAttachment::MakeMSAA(this, dimensions, numSamples, pixelFormat);
542cb93a386Sopenharmony_ci}
543cb93a386Sopenharmony_ci
544cb93a386Sopenharmony_cisk_sp<GrTexture> GrMtlGpu::onCreateTexture(SkISize dimensions,
545cb93a386Sopenharmony_ci                                           const GrBackendFormat& format,
546cb93a386Sopenharmony_ci                                           GrRenderable renderable,
547cb93a386Sopenharmony_ci                                           int renderTargetSampleCnt,
548cb93a386Sopenharmony_ci                                           SkBudgeted budgeted,
549cb93a386Sopenharmony_ci                                           GrProtected isProtected,
550cb93a386Sopenharmony_ci                                           int mipLevelCount,
551cb93a386Sopenharmony_ci                                           uint32_t levelClearMask) {
552cb93a386Sopenharmony_ci    // We don't support protected textures in Metal.
553cb93a386Sopenharmony_ci    if (isProtected == GrProtected::kYes) {
554cb93a386Sopenharmony_ci        return nullptr;
555cb93a386Sopenharmony_ci    }
556cb93a386Sopenharmony_ci    SkASSERT(mipLevelCount > 0);
557cb93a386Sopenharmony_ci
558cb93a386Sopenharmony_ci    MTLPixelFormat mtlPixelFormat = GrBackendFormatAsMTLPixelFormat(format);
559cb93a386Sopenharmony_ci    SkASSERT(mtlPixelFormat != MTLPixelFormatInvalid);
560cb93a386Sopenharmony_ci    SkASSERT(!this->caps()->isFormatCompressed(format));
561cb93a386Sopenharmony_ci
562cb93a386Sopenharmony_ci    sk_sp<GrMtlTexture> tex;
563cb93a386Sopenharmony_ci    GrMipmapStatus mipmapStatus =
564cb93a386Sopenharmony_ci            mipLevelCount > 1 ? GrMipmapStatus::kDirty : GrMipmapStatus::kNotAllocated;
565cb93a386Sopenharmony_ci    if (renderable == GrRenderable::kYes) {
566cb93a386Sopenharmony_ci        tex = GrMtlTextureRenderTarget::MakeNewTextureRenderTarget(
567cb93a386Sopenharmony_ci                this, budgeted, dimensions, renderTargetSampleCnt, mtlPixelFormat, mipLevelCount,
568cb93a386Sopenharmony_ci                mipmapStatus);
569cb93a386Sopenharmony_ci    } else {
570cb93a386Sopenharmony_ci        tex = GrMtlTexture::MakeNewTexture(this, budgeted, dimensions, mtlPixelFormat,
571cb93a386Sopenharmony_ci                                           mipLevelCount, mipmapStatus);
572cb93a386Sopenharmony_ci    }
573cb93a386Sopenharmony_ci
574cb93a386Sopenharmony_ci    if (!tex) {
575cb93a386Sopenharmony_ci        return nullptr;
576cb93a386Sopenharmony_ci    }
577cb93a386Sopenharmony_ci
578cb93a386Sopenharmony_ci    if (levelClearMask) {
579cb93a386Sopenharmony_ci        this->clearTexture(tex.get(), GrMtlFormatBytesPerBlock(mtlPixelFormat), levelClearMask);
580cb93a386Sopenharmony_ci    }
581cb93a386Sopenharmony_ci
582cb93a386Sopenharmony_ci    return std::move(tex);
583cb93a386Sopenharmony_ci}
584cb93a386Sopenharmony_ci
585cb93a386Sopenharmony_cisk_sp<GrTexture> GrMtlGpu::onCreateCompressedTexture(SkISize dimensions,
586cb93a386Sopenharmony_ci                                                     const GrBackendFormat& format,
587cb93a386Sopenharmony_ci                                                     SkBudgeted budgeted,
588cb93a386Sopenharmony_ci                                                     GrMipmapped mipMapped,
589cb93a386Sopenharmony_ci                                                     GrProtected isProtected,
590cb93a386Sopenharmony_ci                                                     const void* data, size_t dataSize) {
591cb93a386Sopenharmony_ci    // We don't support protected textures in Metal.
592cb93a386Sopenharmony_ci    if (isProtected == GrProtected::kYes) {
593cb93a386Sopenharmony_ci        return nullptr;
594cb93a386Sopenharmony_ci    }
595cb93a386Sopenharmony_ci
596cb93a386Sopenharmony_ci    SkASSERT(this->caps()->isFormatTexturable(format, GrTextureType::k2D));
597cb93a386Sopenharmony_ci    SkASSERT(data);
598cb93a386Sopenharmony_ci
599cb93a386Sopenharmony_ci    if (!check_max_blit_width(dimensions.width())) {
600cb93a386Sopenharmony_ci        return nullptr;
601cb93a386Sopenharmony_ci    }
602cb93a386Sopenharmony_ci
603cb93a386Sopenharmony_ci    MTLPixelFormat mtlPixelFormat = GrBackendFormatAsMTLPixelFormat(format);
604cb93a386Sopenharmony_ci    SkASSERT(this->caps()->isFormatCompressed(format));
605cb93a386Sopenharmony_ci
606cb93a386Sopenharmony_ci    int numMipLevels = 1;
607cb93a386Sopenharmony_ci    if (mipMapped == GrMipmapped::kYes) {
608cb93a386Sopenharmony_ci        numMipLevels = SkMipmap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
609cb93a386Sopenharmony_ci    }
610cb93a386Sopenharmony_ci
611cb93a386Sopenharmony_ci    GrMipmapStatus mipmapStatus = (mipMapped == GrMipmapped::kYes)
612cb93a386Sopenharmony_ci                                                                ? GrMipmapStatus::kValid
613cb93a386Sopenharmony_ci                                                                : GrMipmapStatus::kNotAllocated;
614cb93a386Sopenharmony_ci
615cb93a386Sopenharmony_ci    auto tex = GrMtlTexture::MakeNewTexture(this, budgeted, dimensions, mtlPixelFormat,
616cb93a386Sopenharmony_ci                                            numMipLevels, mipmapStatus);
617cb93a386Sopenharmony_ci    if (!tex) {
618cb93a386Sopenharmony_ci        return nullptr;
619cb93a386Sopenharmony_ci    }
620cb93a386Sopenharmony_ci
621cb93a386Sopenharmony_ci    // Upload to texture
622cb93a386Sopenharmony_ci    id<MTLTexture> GR_NORETAIN mtlTexture = tex->mtlTexture();
623cb93a386Sopenharmony_ci    SkASSERT(mtlTexture);
624cb93a386Sopenharmony_ci
625cb93a386Sopenharmony_ci    auto compressionType = GrBackendFormatToCompressionType(format);
626cb93a386Sopenharmony_ci    SkASSERT(compressionType != SkImage::CompressionType::kNone);
627cb93a386Sopenharmony_ci
628cb93a386Sopenharmony_ci    SkTArray<size_t> individualMipOffsets(numMipLevels);
629cb93a386Sopenharmony_ci    SkDEBUGCODE(size_t combinedBufferSize =) SkCompressedDataSize(compressionType, dimensions,
630cb93a386Sopenharmony_ci                                                                  &individualMipOffsets,
631cb93a386Sopenharmony_ci                                                                  mipMapped == GrMipmapped::kYes);
632cb93a386Sopenharmony_ci    SkASSERT(individualMipOffsets.count() == numMipLevels);
633cb93a386Sopenharmony_ci    SkASSERT(dataSize == combinedBufferSize);
634cb93a386Sopenharmony_ci
635cb93a386Sopenharmony_ci    // offset value must be a multiple of the destination texture's pixel size in bytes
636cb93a386Sopenharmony_ci    // for compressed textures, this is the block size
637cb93a386Sopenharmony_ci    size_t alignment = SkCompressedBlockSize(compressionType);
638cb93a386Sopenharmony_ci    GrStagingBufferManager::Slice slice = fStagingBufferManager.allocateStagingBufferSlice(
639cb93a386Sopenharmony_ci            dataSize, alignment);
640cb93a386Sopenharmony_ci    if (!slice.fBuffer) {
641cb93a386Sopenharmony_ci        return nullptr;
642cb93a386Sopenharmony_ci    }
643cb93a386Sopenharmony_ci    char* bufferData = (char*)slice.fOffsetMapPtr;
644cb93a386Sopenharmony_ci    GrMtlBuffer* mtlBuffer = static_cast<GrMtlBuffer*>(slice.fBuffer);
645cb93a386Sopenharmony_ci
646cb93a386Sopenharmony_ci    MTLOrigin origin = MTLOriginMake(0, 0, 0);
647cb93a386Sopenharmony_ci
648cb93a386Sopenharmony_ci    auto cmdBuffer = this->commandBuffer();
649cb93a386Sopenharmony_ci    id<MTLBlitCommandEncoder> GR_NORETAIN blitCmdEncoder = cmdBuffer->getBlitCommandEncoder();
650cb93a386Sopenharmony_ci    if (!blitCmdEncoder) {
651cb93a386Sopenharmony_ci        return nullptr;
652cb93a386Sopenharmony_ci    }
653cb93a386Sopenharmony_ci#ifdef SK_ENABLE_MTL_DEBUG_INFO
654cb93a386Sopenharmony_ci    [blitCmdEncoder pushDebugGroup:@"onCreateCompressedTexture"];
655cb93a386Sopenharmony_ci#endif
656cb93a386Sopenharmony_ci
657cb93a386Sopenharmony_ci    // copy data into the buffer, skipping any trailing bytes
658cb93a386Sopenharmony_ci    memcpy(bufferData, data, dataSize);
659cb93a386Sopenharmony_ci
660cb93a386Sopenharmony_ci    SkISize levelDimensions = dimensions;
661cb93a386Sopenharmony_ci    for (int currentMipLevel = 0; currentMipLevel < numMipLevels; currentMipLevel++) {
662cb93a386Sopenharmony_ci        const size_t levelRowBytes = GrCompressedRowBytes(compressionType, levelDimensions.width());
663cb93a386Sopenharmony_ci        size_t levelSize = SkCompressedDataSize(compressionType, levelDimensions, nullptr, false);
664cb93a386Sopenharmony_ci
665cb93a386Sopenharmony_ci        // TODO: can this all be done in one go?
666cb93a386Sopenharmony_ci        [blitCmdEncoder copyFromBuffer: mtlBuffer->mtlBuffer()
667cb93a386Sopenharmony_ci                          sourceOffset: slice.fOffset + individualMipOffsets[currentMipLevel]
668cb93a386Sopenharmony_ci                     sourceBytesPerRow: levelRowBytes
669cb93a386Sopenharmony_ci                   sourceBytesPerImage: levelSize
670cb93a386Sopenharmony_ci                            sourceSize: MTLSizeMake(levelDimensions.width(),
671cb93a386Sopenharmony_ci                                                    levelDimensions.height(), 1)
672cb93a386Sopenharmony_ci                             toTexture: mtlTexture
673cb93a386Sopenharmony_ci                      destinationSlice: 0
674cb93a386Sopenharmony_ci                      destinationLevel: currentMipLevel
675cb93a386Sopenharmony_ci                     destinationOrigin: origin];
676cb93a386Sopenharmony_ci
677cb93a386Sopenharmony_ci        levelDimensions = {std::max(1, levelDimensions.width() /2),
678cb93a386Sopenharmony_ci                           std::max(1, levelDimensions.height()/2)};
679cb93a386Sopenharmony_ci    }
680cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_MAC
681cb93a386Sopenharmony_ci    if (this->mtlCaps().isMac()) {
682cb93a386Sopenharmony_ci        [mtlBuffer->mtlBuffer() didModifyRange: NSMakeRange(slice.fOffset, dataSize)];
683cb93a386Sopenharmony_ci    }
684cb93a386Sopenharmony_ci#endif
685cb93a386Sopenharmony_ci#ifdef SK_ENABLE_MTL_DEBUG_INFO
686cb93a386Sopenharmony_ci    [blitCmdEncoder popDebugGroup];
687cb93a386Sopenharmony_ci#endif
688cb93a386Sopenharmony_ci
689cb93a386Sopenharmony_ci    return std::move(tex);
690cb93a386Sopenharmony_ci}
691cb93a386Sopenharmony_ci
692cb93a386Sopenharmony_ci// TODO: Extra retain/release can't be avoided here because of getMtlTextureInfo copying the
693cb93a386Sopenharmony_ci// sk_cfp. It would be useful to have a (possibly-internal-only?) API to get the raw pointer.
694cb93a386Sopenharmony_cistatic id<MTLTexture> get_texture_from_backend(const GrBackendTexture& backendTex) {
695cb93a386Sopenharmony_ci    GrMtlTextureInfo textureInfo;
696cb93a386Sopenharmony_ci    if (!backendTex.getMtlTextureInfo(&textureInfo)) {
697cb93a386Sopenharmony_ci        return nil;
698cb93a386Sopenharmony_ci    }
699cb93a386Sopenharmony_ci    return GrGetMTLTexture(textureInfo.fTexture.get());
700cb93a386Sopenharmony_ci}
701cb93a386Sopenharmony_ci
702cb93a386Sopenharmony_cistatic id<MTLTexture> get_texture_from_backend(const GrBackendRenderTarget& backendRT) {
703cb93a386Sopenharmony_ci    GrMtlTextureInfo textureInfo;
704cb93a386Sopenharmony_ci    if (!backendRT.getMtlTextureInfo(&textureInfo)) {
705cb93a386Sopenharmony_ci        return nil;
706cb93a386Sopenharmony_ci    }
707cb93a386Sopenharmony_ci    return GrGetMTLTexture(textureInfo.fTexture.get());
708cb93a386Sopenharmony_ci}
709cb93a386Sopenharmony_ci
710cb93a386Sopenharmony_cisk_sp<GrTexture> GrMtlGpu::onWrapBackendTexture(const GrBackendTexture& backendTex,
711cb93a386Sopenharmony_ci                                                GrWrapOwnership,
712cb93a386Sopenharmony_ci                                                GrWrapCacheable cacheable,
713cb93a386Sopenharmony_ci                                                GrIOType ioType) {
714cb93a386Sopenharmony_ci    id<MTLTexture> mtlTexture = get_texture_from_backend(backendTex);
715cb93a386Sopenharmony_ci    if (!mtlTexture) {
716cb93a386Sopenharmony_ci        return nullptr;
717cb93a386Sopenharmony_ci    }
718cb93a386Sopenharmony_ci    // We don't currently support sampling from a MSAA texture in shaders.
719cb93a386Sopenharmony_ci    if (mtlTexture.sampleCount != 1) {
720cb93a386Sopenharmony_ci        return nullptr;
721cb93a386Sopenharmony_ci    }
722cb93a386Sopenharmony_ci
723cb93a386Sopenharmony_ci    return GrMtlTexture::MakeWrappedTexture(this, backendTex.dimensions(), mtlTexture, cacheable,
724cb93a386Sopenharmony_ci                                            ioType);
725cb93a386Sopenharmony_ci}
726cb93a386Sopenharmony_ci
727cb93a386Sopenharmony_cisk_sp<GrTexture> GrMtlGpu::onWrapCompressedBackendTexture(const GrBackendTexture& backendTex,
728cb93a386Sopenharmony_ci                                                          GrWrapOwnership,
729cb93a386Sopenharmony_ci                                                          GrWrapCacheable cacheable) {
730cb93a386Sopenharmony_ci    id<MTLTexture> mtlTexture = get_texture_from_backend(backendTex);
731cb93a386Sopenharmony_ci    if (!mtlTexture) {
732cb93a386Sopenharmony_ci        return nullptr;
733cb93a386Sopenharmony_ci    }
734cb93a386Sopenharmony_ci    // We don't currently support sampling from a MSAA texture in shaders.
735cb93a386Sopenharmony_ci    if (mtlTexture.sampleCount != 1) {
736cb93a386Sopenharmony_ci        return nullptr;
737cb93a386Sopenharmony_ci    }
738cb93a386Sopenharmony_ci
739cb93a386Sopenharmony_ci    return GrMtlTexture::MakeWrappedTexture(this, backendTex.dimensions(), mtlTexture, cacheable,
740cb93a386Sopenharmony_ci                                            kRead_GrIOType);
741cb93a386Sopenharmony_ci}
742cb93a386Sopenharmony_ci
743cb93a386Sopenharmony_cisk_sp<GrTexture> GrMtlGpu::onWrapRenderableBackendTexture(const GrBackendTexture& backendTex,
744cb93a386Sopenharmony_ci                                                          int sampleCnt,
745cb93a386Sopenharmony_ci                                                          GrWrapOwnership,
746cb93a386Sopenharmony_ci                                                          GrWrapCacheable cacheable) {
747cb93a386Sopenharmony_ci    id<MTLTexture> mtlTexture = get_texture_from_backend(backendTex);
748cb93a386Sopenharmony_ci    if (!mtlTexture) {
749cb93a386Sopenharmony_ci        return nullptr;
750cb93a386Sopenharmony_ci    }
751cb93a386Sopenharmony_ci    // We don't currently support sampling from a MSAA texture in shaders.
752cb93a386Sopenharmony_ci    if (mtlTexture.sampleCount != 1) {
753cb93a386Sopenharmony_ci        return nullptr;
754cb93a386Sopenharmony_ci    }
755cb93a386Sopenharmony_ci
756cb93a386Sopenharmony_ci    const GrMtlCaps& caps = this->mtlCaps();
757cb93a386Sopenharmony_ci
758cb93a386Sopenharmony_ci    MTLPixelFormat format = mtlTexture.pixelFormat;
759cb93a386Sopenharmony_ci    if (!caps.isFormatRenderable(format, sampleCnt)) {
760cb93a386Sopenharmony_ci        return nullptr;
761cb93a386Sopenharmony_ci    }
762cb93a386Sopenharmony_ci
763cb93a386Sopenharmony_ci    if (@available(macOS 10.11, iOS 9.0, *)) {
764cb93a386Sopenharmony_ci        SkASSERT(MTLTextureUsageRenderTarget & mtlTexture.usage);
765cb93a386Sopenharmony_ci    }
766cb93a386Sopenharmony_ci
767cb93a386Sopenharmony_ci    sampleCnt = caps.getRenderTargetSampleCount(sampleCnt, format);
768cb93a386Sopenharmony_ci    SkASSERT(sampleCnt);
769cb93a386Sopenharmony_ci
770cb93a386Sopenharmony_ci    return GrMtlTextureRenderTarget::MakeWrappedTextureRenderTarget(
771cb93a386Sopenharmony_ci            this, backendTex.dimensions(), sampleCnt, mtlTexture, cacheable);
772cb93a386Sopenharmony_ci}
773cb93a386Sopenharmony_ci
774cb93a386Sopenharmony_cisk_sp<GrRenderTarget> GrMtlGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& backendRT) {
775cb93a386Sopenharmony_ci    if (!this->caps()->isFormatRenderable(backendRT.getBackendFormat(), backendRT.sampleCnt())) {
776cb93a386Sopenharmony_ci        return nullptr;
777cb93a386Sopenharmony_ci    }
778cb93a386Sopenharmony_ci
779cb93a386Sopenharmony_ci    id<MTLTexture> mtlTexture = get_texture_from_backend(backendRT);
780cb93a386Sopenharmony_ci    if (!mtlTexture) {
781cb93a386Sopenharmony_ci        return nullptr;
782cb93a386Sopenharmony_ci    }
783cb93a386Sopenharmony_ci
784cb93a386Sopenharmony_ci    if (@available(macOS 10.11, iOS 9.0, *)) {
785cb93a386Sopenharmony_ci        SkASSERT(MTLTextureUsageRenderTarget & mtlTexture.usage);
786cb93a386Sopenharmony_ci    }
787cb93a386Sopenharmony_ci
788cb93a386Sopenharmony_ci    return GrMtlRenderTarget::MakeWrappedRenderTarget(this, backendRT.dimensions(),
789cb93a386Sopenharmony_ci                                                      backendRT.sampleCnt(), mtlTexture);
790cb93a386Sopenharmony_ci}
791cb93a386Sopenharmony_ci
792cb93a386Sopenharmony_cibool GrMtlGpu::onRegenerateMipMapLevels(GrTexture* texture) {
793cb93a386Sopenharmony_ci    GrMtlTexture* grMtlTexture = static_cast<GrMtlTexture*>(texture);
794cb93a386Sopenharmony_ci    id<MTLTexture> GR_NORETAIN mtlTexture = grMtlTexture->mtlTexture();
795cb93a386Sopenharmony_ci
796cb93a386Sopenharmony_ci    // Automatic mipmap generation is only supported by color-renderable formats
797cb93a386Sopenharmony_ci    if (!fMtlCaps->isFormatRenderable(mtlTexture.pixelFormat, 1) &&
798cb93a386Sopenharmony_ci        // We have pixel configs marked as textureable-only that use RGBA8 as the internal format
799cb93a386Sopenharmony_ci        MTLPixelFormatRGBA8Unorm != mtlTexture.pixelFormat) {
800cb93a386Sopenharmony_ci        return false;
801cb93a386Sopenharmony_ci    }
802cb93a386Sopenharmony_ci
803cb93a386Sopenharmony_ci    auto cmdBuffer = this->commandBuffer();
804cb93a386Sopenharmony_ci    id<MTLBlitCommandEncoder> GR_NORETAIN blitCmdEncoder = cmdBuffer->getBlitCommandEncoder();
805cb93a386Sopenharmony_ci    if (!blitCmdEncoder) {
806cb93a386Sopenharmony_ci        return false;
807cb93a386Sopenharmony_ci    }
808cb93a386Sopenharmony_ci    [blitCmdEncoder generateMipmapsForTexture: mtlTexture];
809cb93a386Sopenharmony_ci    this->commandBuffer()->addGrSurface(sk_ref_sp<const GrSurface>(grMtlTexture->attachment()));
810cb93a386Sopenharmony_ci
811cb93a386Sopenharmony_ci    return true;
812cb93a386Sopenharmony_ci}
813cb93a386Sopenharmony_ci
814cb93a386Sopenharmony_ci// Used to "clear" a backend texture to a constant color by transferring.
815cb93a386Sopenharmony_cistatic GrColorType mtl_format_to_backend_tex_clear_colortype(MTLPixelFormat format) {
816cb93a386Sopenharmony_ci    switch(format) {
817cb93a386Sopenharmony_ci        case MTLPixelFormatA8Unorm:         return GrColorType::kAlpha_8;
818cb93a386Sopenharmony_ci        case MTLPixelFormatR8Unorm:         return GrColorType::kR_8;
819cb93a386Sopenharmony_ci
820cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_IOS
821cb93a386Sopenharmony_ci        case MTLPixelFormatB5G6R5Unorm:     return GrColorType::kBGR_565;
822cb93a386Sopenharmony_ci        case MTLPixelFormatABGR4Unorm:      return GrColorType::kABGR_4444;
823cb93a386Sopenharmony_ci#endif
824cb93a386Sopenharmony_ci        case MTLPixelFormatRGBA8Unorm:      return GrColorType::kRGBA_8888;
825cb93a386Sopenharmony_ci        case MTLPixelFormatRGBA8Unorm_sRGB: return GrColorType::kRGBA_8888_SRGB;
826cb93a386Sopenharmony_ci
827cb93a386Sopenharmony_ci        case MTLPixelFormatRG8Unorm:        return GrColorType::kRG_88;
828cb93a386Sopenharmony_ci        case MTLPixelFormatBGRA8Unorm:      return GrColorType::kBGRA_8888;
829cb93a386Sopenharmony_ci        case MTLPixelFormatRGB10A2Unorm:    return GrColorType::kRGBA_1010102;
830cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_MAC
831cb93a386Sopenharmony_ci        case MTLPixelFormatBGR10A2Unorm:    return GrColorType::kBGRA_1010102;
832cb93a386Sopenharmony_ci#endif
833cb93a386Sopenharmony_ci        case MTLPixelFormatR16Float:        return GrColorType::kR_F16;
834cb93a386Sopenharmony_ci        case MTLPixelFormatRGBA16Float:     return GrColorType::kRGBA_F16;
835cb93a386Sopenharmony_ci        case MTLPixelFormatR16Unorm:        return GrColorType::kR_16;
836cb93a386Sopenharmony_ci        case MTLPixelFormatRG16Unorm:       return GrColorType::kRG_1616;
837cb93a386Sopenharmony_ci        case MTLPixelFormatRGBA16Unorm:     return GrColorType::kRGBA_16161616;
838cb93a386Sopenharmony_ci        case MTLPixelFormatRG16Float:       return GrColorType::kRG_F16;
839cb93a386Sopenharmony_ci        default:                            return GrColorType::kUnknown;
840cb93a386Sopenharmony_ci    }
841cb93a386Sopenharmony_ci
842cb93a386Sopenharmony_ci    SkUNREACHABLE;
843cb93a386Sopenharmony_ci}
844cb93a386Sopenharmony_ci
845cb93a386Sopenharmony_civoid copy_src_data(char* dst,
846cb93a386Sopenharmony_ci                   size_t bytesPerPixel,
847cb93a386Sopenharmony_ci                   const SkTArray<size_t>& individualMipOffsets,
848cb93a386Sopenharmony_ci                   const GrPixmap srcData[],
849cb93a386Sopenharmony_ci                   int numMipLevels,
850cb93a386Sopenharmony_ci                   size_t bufferSize) {
851cb93a386Sopenharmony_ci    SkASSERT(srcData && numMipLevels);
852cb93a386Sopenharmony_ci    SkASSERT(individualMipOffsets.count() == numMipLevels);
853cb93a386Sopenharmony_ci
854cb93a386Sopenharmony_ci    for (int level = 0; level < numMipLevels; ++level) {
855cb93a386Sopenharmony_ci        const size_t trimRB = srcData[level].width() * bytesPerPixel;
856cb93a386Sopenharmony_ci        SkASSERT(individualMipOffsets[level] + trimRB * srcData[level].height() <= bufferSize);
857cb93a386Sopenharmony_ci        SkRectMemcpy(dst + individualMipOffsets[level], trimRB,
858cb93a386Sopenharmony_ci                     srcData[level].addr(), srcData[level].rowBytes(),
859cb93a386Sopenharmony_ci                     trimRB, srcData[level].height());
860cb93a386Sopenharmony_ci    }
861cb93a386Sopenharmony_ci}
862cb93a386Sopenharmony_ci
863cb93a386Sopenharmony_cibool GrMtlGpu::createMtlTextureForBackendSurface(MTLPixelFormat mtlFormat,
864cb93a386Sopenharmony_ci                                                 SkISize dimensions,
865cb93a386Sopenharmony_ci                                                 int sampleCnt,
866cb93a386Sopenharmony_ci                                                 GrTexturable texturable,
867cb93a386Sopenharmony_ci                                                 GrRenderable renderable,
868cb93a386Sopenharmony_ci                                                 GrMipmapped mipMapped,
869cb93a386Sopenharmony_ci                                                 GrMtlTextureInfo* info) {
870cb93a386Sopenharmony_ci    SkASSERT(texturable == GrTexturable::kYes || renderable == GrRenderable::kYes);
871cb93a386Sopenharmony_ci
872cb93a386Sopenharmony_ci    if (texturable == GrTexturable::kYes && !fMtlCaps->isFormatTexturable(mtlFormat)) {
873cb93a386Sopenharmony_ci        return false;
874cb93a386Sopenharmony_ci    }
875cb93a386Sopenharmony_ci    if (renderable == GrRenderable::kYes && !fMtlCaps->isFormatRenderable(mtlFormat, 1)) {
876cb93a386Sopenharmony_ci        return false;
877cb93a386Sopenharmony_ci    }
878cb93a386Sopenharmony_ci
879cb93a386Sopenharmony_ci    if (!check_max_blit_width(dimensions.width())) {
880cb93a386Sopenharmony_ci        return false;
881cb93a386Sopenharmony_ci    }
882cb93a386Sopenharmony_ci
883cb93a386Sopenharmony_ci    auto desc = [[MTLTextureDescriptor alloc] init];
884cb93a386Sopenharmony_ci    desc.pixelFormat = mtlFormat;
885cb93a386Sopenharmony_ci    desc.width = dimensions.width();
886cb93a386Sopenharmony_ci    desc.height = dimensions.height();
887cb93a386Sopenharmony_ci    if (mipMapped == GrMipMapped::kYes) {
888cb93a386Sopenharmony_ci        desc.mipmapLevelCount = 1 + SkPrevLog2(std::max(dimensions.width(), dimensions.height()));
889cb93a386Sopenharmony_ci    }
890cb93a386Sopenharmony_ci    if (@available(macOS 10.11, iOS 9.0, *)) {
891cb93a386Sopenharmony_ci        desc.storageMode = MTLStorageModePrivate;
892cb93a386Sopenharmony_ci        MTLTextureUsage usage = texturable == GrTexturable::kYes ? MTLTextureUsageShaderRead : 0;
893cb93a386Sopenharmony_ci        usage |= renderable == GrRenderable::kYes ? MTLTextureUsageRenderTarget : 0;
894cb93a386Sopenharmony_ci        desc.usage = usage;
895cb93a386Sopenharmony_ci    }
896cb93a386Sopenharmony_ci    if (sampleCnt != 1) {
897cb93a386Sopenharmony_ci        desc.sampleCount = sampleCnt;
898cb93a386Sopenharmony_ci        desc.textureType = MTLTextureType2DMultisample;
899cb93a386Sopenharmony_ci    }
900cb93a386Sopenharmony_ci    id<MTLTexture> testTexture = [fDevice newTextureWithDescriptor: desc];
901cb93a386Sopenharmony_ci#ifdef SK_ENABLE_MTL_DEBUG_INFO
902cb93a386Sopenharmony_ci    testTexture.label = @"testTexture";
903cb93a386Sopenharmony_ci#endif
904cb93a386Sopenharmony_ci    info->fTexture.reset(GrRetainPtrFromId(testTexture));
905cb93a386Sopenharmony_ci    return true;
906cb93a386Sopenharmony_ci}
907cb93a386Sopenharmony_ci
908cb93a386Sopenharmony_ciGrBackendTexture GrMtlGpu::onCreateBackendTexture(SkISize dimensions,
909cb93a386Sopenharmony_ci                                                  const GrBackendFormat& format,
910cb93a386Sopenharmony_ci                                                  GrRenderable renderable,
911cb93a386Sopenharmony_ci                                                  GrMipmapped mipMapped,
912cb93a386Sopenharmony_ci                                                  GrProtected isProtected) {
913cb93a386Sopenharmony_ci    const MTLPixelFormat mtlFormat = GrBackendFormatAsMTLPixelFormat(format);
914cb93a386Sopenharmony_ci
915cb93a386Sopenharmony_ci    GrMtlTextureInfo info;
916cb93a386Sopenharmony_ci    if (!this->createMtlTextureForBackendSurface(mtlFormat, dimensions, 1, GrTexturable::kYes,
917cb93a386Sopenharmony_ci                                                 renderable, mipMapped, &info)) {
918cb93a386Sopenharmony_ci        return {};
919cb93a386Sopenharmony_ci    }
920cb93a386Sopenharmony_ci
921cb93a386Sopenharmony_ci    GrBackendTexture backendTex(dimensions.width(), dimensions.height(), mipMapped, info);
922cb93a386Sopenharmony_ci    return backendTex;
923cb93a386Sopenharmony_ci}
924cb93a386Sopenharmony_ci
925cb93a386Sopenharmony_cibool GrMtlGpu::onClearBackendTexture(const GrBackendTexture& backendTexture,
926cb93a386Sopenharmony_ci                                     sk_sp<GrRefCntedCallback> finishedCallback,
927cb93a386Sopenharmony_ci                                     std::array<float, 4> color) {
928cb93a386Sopenharmony_ci    GrMtlTextureInfo info;
929cb93a386Sopenharmony_ci    SkAssertResult(backendTexture.getMtlTextureInfo(&info));
930cb93a386Sopenharmony_ci
931cb93a386Sopenharmony_ci    id<MTLTexture> GR_NORETAIN mtlTexture = GrGetMTLTexture(info.fTexture.get());
932cb93a386Sopenharmony_ci
933cb93a386Sopenharmony_ci    const MTLPixelFormat mtlFormat = mtlTexture.pixelFormat;
934cb93a386Sopenharmony_ci
935cb93a386Sopenharmony_ci    // Create a transfer buffer and fill with data.
936cb93a386Sopenharmony_ci    size_t bytesPerPixel = GrMtlFormatBytesPerBlock(mtlFormat);
937cb93a386Sopenharmony_ci    size_t combinedBufferSize;
938cb93a386Sopenharmony_ci
939cb93a386Sopenharmony_ci    // Reuse the same buffer for all levels. Should be ok since we made the row bytes tight.
940cb93a386Sopenharmony_ci    combinedBufferSize = bytesPerPixel*backendTexture.width()*backendTexture.height();
941cb93a386Sopenharmony_ci
942cb93a386Sopenharmony_ci    size_t alignment = std::max(bytesPerPixel, this->mtlCaps().getMinBufferAlignment());
943cb93a386Sopenharmony_ci    GrStagingBufferManager::Slice slice = fStagingBufferManager.allocateStagingBufferSlice(
944cb93a386Sopenharmony_ci            combinedBufferSize, alignment);
945cb93a386Sopenharmony_ci    if (!slice.fBuffer) {
946cb93a386Sopenharmony_ci        return false;
947cb93a386Sopenharmony_ci    }
948cb93a386Sopenharmony_ci    char* buffer = (char*)slice.fOffsetMapPtr;
949cb93a386Sopenharmony_ci
950cb93a386Sopenharmony_ci    auto colorType = mtl_format_to_backend_tex_clear_colortype(mtlFormat);
951cb93a386Sopenharmony_ci    if (colorType == GrColorType::kUnknown) {
952cb93a386Sopenharmony_ci        return false;
953cb93a386Sopenharmony_ci    }
954cb93a386Sopenharmony_ci    GrImageInfo ii(colorType, kUnpremul_SkAlphaType, nullptr, backendTexture.dimensions());
955cb93a386Sopenharmony_ci    auto rb = ii.minRowBytes();
956cb93a386Sopenharmony_ci    SkASSERT(rb == bytesPerPixel*backendTexture.width());
957cb93a386Sopenharmony_ci    if (!GrClearImage(ii, buffer, rb, color)) {
958cb93a386Sopenharmony_ci        return false;
959cb93a386Sopenharmony_ci    }
960cb93a386Sopenharmony_ci
961cb93a386Sopenharmony_ci    // Transfer buffer contents to texture
962cb93a386Sopenharmony_ci    MTLOrigin origin = MTLOriginMake(0, 0, 0);
963cb93a386Sopenharmony_ci
964cb93a386Sopenharmony_ci    GrMtlCommandBuffer* cmdBuffer = this->commandBuffer();
965cb93a386Sopenharmony_ci    id<MTLBlitCommandEncoder> GR_NORETAIN blitCmdEncoder = cmdBuffer->getBlitCommandEncoder();
966cb93a386Sopenharmony_ci    if (!blitCmdEncoder) {
967cb93a386Sopenharmony_ci        return false;
968cb93a386Sopenharmony_ci    }
969cb93a386Sopenharmony_ci#ifdef SK_ENABLE_MTL_DEBUG_INFO
970cb93a386Sopenharmony_ci    [blitCmdEncoder pushDebugGroup:@"onClearBackendTexture"];
971cb93a386Sopenharmony_ci#endif
972cb93a386Sopenharmony_ci    GrMtlBuffer* mtlBuffer = static_cast<GrMtlBuffer*>(slice.fBuffer);
973cb93a386Sopenharmony_ci
974cb93a386Sopenharmony_ci    SkISize levelDimensions(backendTexture.dimensions());
975cb93a386Sopenharmony_ci    int numMipLevels = mtlTexture.mipmapLevelCount;
976cb93a386Sopenharmony_ci    for (int currentMipLevel = 0; currentMipLevel < numMipLevels; currentMipLevel++) {
977cb93a386Sopenharmony_ci        size_t levelRowBytes;
978cb93a386Sopenharmony_ci        size_t levelSize;
979cb93a386Sopenharmony_ci
980cb93a386Sopenharmony_ci        levelRowBytes = levelDimensions.width() * bytesPerPixel;
981cb93a386Sopenharmony_ci        levelSize = levelRowBytes * levelDimensions.height();
982cb93a386Sopenharmony_ci
983cb93a386Sopenharmony_ci        // TODO: can this all be done in one go?
984cb93a386Sopenharmony_ci        [blitCmdEncoder copyFromBuffer: mtlBuffer->mtlBuffer()
985cb93a386Sopenharmony_ci                          sourceOffset: slice.fOffset
986cb93a386Sopenharmony_ci                     sourceBytesPerRow: levelRowBytes
987cb93a386Sopenharmony_ci                   sourceBytesPerImage: levelSize
988cb93a386Sopenharmony_ci                            sourceSize: MTLSizeMake(levelDimensions.width(),
989cb93a386Sopenharmony_ci                                                    levelDimensions.height(),
990cb93a386Sopenharmony_ci                                                    1)
991cb93a386Sopenharmony_ci                             toTexture: mtlTexture
992cb93a386Sopenharmony_ci                      destinationSlice: 0
993cb93a386Sopenharmony_ci                      destinationLevel: currentMipLevel
994cb93a386Sopenharmony_ci                     destinationOrigin: origin];
995cb93a386Sopenharmony_ci
996cb93a386Sopenharmony_ci        levelDimensions = {std::max(1, levelDimensions.width() / 2),
997cb93a386Sopenharmony_ci                           std::max(1, levelDimensions.height() / 2)};
998cb93a386Sopenharmony_ci    }
999cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_MAC
1000cb93a386Sopenharmony_ci    if (this->mtlCaps().isMac()) {
1001cb93a386Sopenharmony_ci        [mtlBuffer->mtlBuffer() didModifyRange: NSMakeRange(slice.fOffset, combinedBufferSize)];
1002cb93a386Sopenharmony_ci    }
1003cb93a386Sopenharmony_ci#endif
1004cb93a386Sopenharmony_ci    [blitCmdEncoder popDebugGroup];
1005cb93a386Sopenharmony_ci
1006cb93a386Sopenharmony_ci    if (finishedCallback) {
1007cb93a386Sopenharmony_ci        this->addFinishedCallback(std::move(finishedCallback));
1008cb93a386Sopenharmony_ci    }
1009cb93a386Sopenharmony_ci
1010cb93a386Sopenharmony_ci    return true;
1011cb93a386Sopenharmony_ci}
1012cb93a386Sopenharmony_ci
1013cb93a386Sopenharmony_ciGrBackendTexture GrMtlGpu::onCreateCompressedBackendTexture(
1014cb93a386Sopenharmony_ci        SkISize dimensions, const GrBackendFormat& format, GrMipmapped mipMapped,
1015cb93a386Sopenharmony_ci        GrProtected isProtected) {
1016cb93a386Sopenharmony_ci    const MTLPixelFormat mtlFormat = GrBackendFormatAsMTLPixelFormat(format);
1017cb93a386Sopenharmony_ci
1018cb93a386Sopenharmony_ci    GrMtlTextureInfo info;
1019cb93a386Sopenharmony_ci    if (!this->createMtlTextureForBackendSurface(mtlFormat, dimensions, 1, GrTexturable::kYes,
1020cb93a386Sopenharmony_ci                                                 GrRenderable::kNo, mipMapped, &info)) {
1021cb93a386Sopenharmony_ci        return {};
1022cb93a386Sopenharmony_ci    }
1023cb93a386Sopenharmony_ci
1024cb93a386Sopenharmony_ci    return GrBackendTexture(dimensions.width(), dimensions.height(), mipMapped, info);
1025cb93a386Sopenharmony_ci}
1026cb93a386Sopenharmony_ci
1027cb93a386Sopenharmony_cibool GrMtlGpu::onUpdateCompressedBackendTexture(const GrBackendTexture& backendTexture,
1028cb93a386Sopenharmony_ci                                                sk_sp<GrRefCntedCallback> finishedCallback,
1029cb93a386Sopenharmony_ci                                                const void* data,
1030cb93a386Sopenharmony_ci                                                size_t size) {
1031cb93a386Sopenharmony_ci    GrMtlTextureInfo info;
1032cb93a386Sopenharmony_ci    SkAssertResult(backendTexture.getMtlTextureInfo(&info));
1033cb93a386Sopenharmony_ci
1034cb93a386Sopenharmony_ci    id<MTLTexture> mtlTexture = GrGetMTLTexture(info.fTexture.get());
1035cb93a386Sopenharmony_ci
1036cb93a386Sopenharmony_ci    int numMipLevels = mtlTexture.mipmapLevelCount;
1037cb93a386Sopenharmony_ci    GrMipmapped mipMapped = numMipLevels > 1 ? GrMipmapped::kYes : GrMipmapped::kNo;
1038cb93a386Sopenharmony_ci
1039cb93a386Sopenharmony_ci    SkImage::CompressionType compression =
1040cb93a386Sopenharmony_ci            GrBackendFormatToCompressionType(backendTexture.getBackendFormat());
1041cb93a386Sopenharmony_ci    SkASSERT(compression != SkImage::CompressionType::kNone);
1042cb93a386Sopenharmony_ci
1043cb93a386Sopenharmony_ci    // Create a transfer buffer and fill with data.
1044cb93a386Sopenharmony_ci    SkSTArray<16, size_t> individualMipOffsets;
1045cb93a386Sopenharmony_ci    size_t combinedBufferSize;
1046cb93a386Sopenharmony_ci    combinedBufferSize = SkCompressedDataSize(compression,
1047cb93a386Sopenharmony_ci                                              backendTexture.dimensions(),
1048cb93a386Sopenharmony_ci                                              &individualMipOffsets,
1049cb93a386Sopenharmony_ci                                              mipMapped == GrMipmapped::kYes);
1050cb93a386Sopenharmony_ci    SkASSERT(individualMipOffsets.count() == numMipLevels);
1051cb93a386Sopenharmony_ci
1052cb93a386Sopenharmony_ci    size_t alignment = std::max(SkCompressedBlockSize(compression),
1053cb93a386Sopenharmony_ci                                this->mtlCaps().getMinBufferAlignment());
1054cb93a386Sopenharmony_ci    GrStagingBufferManager::Slice slice =
1055cb93a386Sopenharmony_ci            fStagingBufferManager.allocateStagingBufferSlice(combinedBufferSize, alignment);
1056cb93a386Sopenharmony_ci    if (!slice.fBuffer) {
1057cb93a386Sopenharmony_ci        return false;
1058cb93a386Sopenharmony_ci    }
1059cb93a386Sopenharmony_ci    char* buffer = (char*)slice.fOffsetMapPtr;
1060cb93a386Sopenharmony_ci
1061cb93a386Sopenharmony_ci    memcpy(buffer, data, size);
1062cb93a386Sopenharmony_ci
1063cb93a386Sopenharmony_ci    // Transfer buffer contents to texture
1064cb93a386Sopenharmony_ci    MTLOrigin origin = MTLOriginMake(0, 0, 0);
1065cb93a386Sopenharmony_ci
1066cb93a386Sopenharmony_ci    GrMtlCommandBuffer* cmdBuffer = this->commandBuffer();
1067cb93a386Sopenharmony_ci    id<MTLBlitCommandEncoder> blitCmdEncoder = cmdBuffer->getBlitCommandEncoder();
1068cb93a386Sopenharmony_ci    if (!blitCmdEncoder) {
1069cb93a386Sopenharmony_ci        return false;
1070cb93a386Sopenharmony_ci    }
1071cb93a386Sopenharmony_ci#ifdef SK_ENABLE_MTL_DEBUG_INFO
1072cb93a386Sopenharmony_ci    [blitCmdEncoder pushDebugGroup:@"onUpdateCompressedBackendTexture"];
1073cb93a386Sopenharmony_ci#endif
1074cb93a386Sopenharmony_ci    GrMtlBuffer* mtlBuffer = static_cast<GrMtlBuffer*>(slice.fBuffer);
1075cb93a386Sopenharmony_ci
1076cb93a386Sopenharmony_ci    SkISize levelDimensions(backendTexture.dimensions());
1077cb93a386Sopenharmony_ci    for (int currentMipLevel = 0; currentMipLevel < numMipLevels; currentMipLevel++) {
1078cb93a386Sopenharmony_ci        size_t levelRowBytes;
1079cb93a386Sopenharmony_ci        size_t levelSize;
1080cb93a386Sopenharmony_ci
1081cb93a386Sopenharmony_ci        levelRowBytes = GrCompressedRowBytes(compression, levelDimensions.width());
1082cb93a386Sopenharmony_ci        levelSize = SkCompressedDataSize(compression, levelDimensions, nullptr, false);
1083cb93a386Sopenharmony_ci
1084cb93a386Sopenharmony_ci        // TODO: can this all be done in one go?
1085cb93a386Sopenharmony_ci        [blitCmdEncoder copyFromBuffer: mtlBuffer->mtlBuffer()
1086cb93a386Sopenharmony_ci                          sourceOffset: slice.fOffset + individualMipOffsets[currentMipLevel]
1087cb93a386Sopenharmony_ci                     sourceBytesPerRow: levelRowBytes
1088cb93a386Sopenharmony_ci                   sourceBytesPerImage: levelSize
1089cb93a386Sopenharmony_ci                            sourceSize: MTLSizeMake(levelDimensions.width(),
1090cb93a386Sopenharmony_ci                                                    levelDimensions.height(),
1091cb93a386Sopenharmony_ci                                                    1)
1092cb93a386Sopenharmony_ci                             toTexture: mtlTexture
1093cb93a386Sopenharmony_ci                      destinationSlice: 0
1094cb93a386Sopenharmony_ci                      destinationLevel: currentMipLevel
1095cb93a386Sopenharmony_ci                     destinationOrigin: origin];
1096cb93a386Sopenharmony_ci
1097cb93a386Sopenharmony_ci        levelDimensions = {std::max(1, levelDimensions.width() / 2),
1098cb93a386Sopenharmony_ci                           std::max(1, levelDimensions.height() / 2)};
1099cb93a386Sopenharmony_ci    }
1100cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_MAC
1101cb93a386Sopenharmony_ci    if (this->mtlCaps().isMac()) {
1102cb93a386Sopenharmony_ci        [mtlBuffer->mtlBuffer() didModifyRange:NSMakeRange(slice.fOffset, combinedBufferSize)];
1103cb93a386Sopenharmony_ci    }
1104cb93a386Sopenharmony_ci#endif
1105cb93a386Sopenharmony_ci    [blitCmdEncoder popDebugGroup];
1106cb93a386Sopenharmony_ci
1107cb93a386Sopenharmony_ci    if (finishedCallback) {
1108cb93a386Sopenharmony_ci        this->addFinishedCallback(std::move(finishedCallback));
1109cb93a386Sopenharmony_ci    }
1110cb93a386Sopenharmony_ci
1111cb93a386Sopenharmony_ci    return true;
1112cb93a386Sopenharmony_ci}
1113cb93a386Sopenharmony_ci
1114cb93a386Sopenharmony_civoid GrMtlGpu::deleteBackendTexture(const GrBackendTexture& tex) {
1115cb93a386Sopenharmony_ci    SkASSERT(GrBackendApi::kMetal == tex.backend());
1116cb93a386Sopenharmony_ci    // Nothing to do here, will get cleaned up when the GrBackendTexture object goes away
1117cb93a386Sopenharmony_ci}
1118cb93a386Sopenharmony_ci
1119cb93a386Sopenharmony_cibool GrMtlGpu::compile(const GrProgramDesc& desc, const GrProgramInfo& programInfo) {
1120cb93a386Sopenharmony_ci
1121cb93a386Sopenharmony_ci    GrThreadSafePipelineBuilder::Stats::ProgramCacheResult stat;
1122cb93a386Sopenharmony_ci
1123cb93a386Sopenharmony_ci    auto pipelineState = this->resourceProvider().findOrCreateCompatiblePipelineState(
1124cb93a386Sopenharmony_ci                                 desc, programInfo, &stat);
1125cb93a386Sopenharmony_ci    if (!pipelineState) {
1126cb93a386Sopenharmony_ci        return false;
1127cb93a386Sopenharmony_ci    }
1128cb93a386Sopenharmony_ci
1129cb93a386Sopenharmony_ci    return stat != GrThreadSafePipelineBuilder::Stats::ProgramCacheResult::kHit;
1130cb93a386Sopenharmony_ci}
1131cb93a386Sopenharmony_ci
1132cb93a386Sopenharmony_cibool GrMtlGpu::precompileShader(const SkData& key, const SkData& data) {
1133cb93a386Sopenharmony_ci    return this->resourceProvider().precompileShader(key, data);
1134cb93a386Sopenharmony_ci}
1135cb93a386Sopenharmony_ci
1136cb93a386Sopenharmony_ci#if GR_TEST_UTILS
1137cb93a386Sopenharmony_cibool GrMtlGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
1138cb93a386Sopenharmony_ci    SkASSERT(GrBackendApi::kMetal == tex.backend());
1139cb93a386Sopenharmony_ci
1140cb93a386Sopenharmony_ci    GrMtlTextureInfo info;
1141cb93a386Sopenharmony_ci    if (!tex.getMtlTextureInfo(&info)) {
1142cb93a386Sopenharmony_ci        return false;
1143cb93a386Sopenharmony_ci    }
1144cb93a386Sopenharmony_ci    id<MTLTexture> mtlTexture = GrGetMTLTexture(info.fTexture.get());
1145cb93a386Sopenharmony_ci    if (!mtlTexture) {
1146cb93a386Sopenharmony_ci        return false;
1147cb93a386Sopenharmony_ci    }
1148cb93a386Sopenharmony_ci    if (@available(macOS 10.11, iOS 9.0, *)) {
1149cb93a386Sopenharmony_ci        return mtlTexture.usage & MTLTextureUsageShaderRead;
1150cb93a386Sopenharmony_ci    } else {
1151cb93a386Sopenharmony_ci        return true; // best we can do
1152cb93a386Sopenharmony_ci    }
1153cb93a386Sopenharmony_ci}
1154cb93a386Sopenharmony_ci
1155cb93a386Sopenharmony_ciGrBackendRenderTarget GrMtlGpu::createTestingOnlyBackendRenderTarget(SkISize dimensions,
1156cb93a386Sopenharmony_ci                                                                     GrColorType ct,
1157cb93a386Sopenharmony_ci                                                                     int sampleCnt,
1158cb93a386Sopenharmony_ci                                                                     GrProtected isProtected) {
1159cb93a386Sopenharmony_ci    if (dimensions.width()  > this->caps()->maxRenderTargetSize() ||
1160cb93a386Sopenharmony_ci        dimensions.height() > this->caps()->maxRenderTargetSize()) {
1161cb93a386Sopenharmony_ci        return {};
1162cb93a386Sopenharmony_ci    }
1163cb93a386Sopenharmony_ci    if (isProtected == GrProtected::kYes) {
1164cb93a386Sopenharmony_ci        return {};
1165cb93a386Sopenharmony_ci    }
1166cb93a386Sopenharmony_ci
1167cb93a386Sopenharmony_ci    MTLPixelFormat format = this->mtlCaps().getFormatFromColorType(ct);
1168cb93a386Sopenharmony_ci    sampleCnt = this->mtlCaps().getRenderTargetSampleCount(sampleCnt, format);
1169cb93a386Sopenharmony_ci    if (sampleCnt == 0) {
1170cb93a386Sopenharmony_ci        return {};
1171cb93a386Sopenharmony_ci    }
1172cb93a386Sopenharmony_ci
1173cb93a386Sopenharmony_ci    GrMtlTextureInfo info;
1174cb93a386Sopenharmony_ci    if (!this->createMtlTextureForBackendSurface(format, dimensions, sampleCnt, GrTexturable::kNo,
1175cb93a386Sopenharmony_ci                                                 GrRenderable::kYes, GrMipmapped::kNo, &info)) {
1176cb93a386Sopenharmony_ci        return {};
1177cb93a386Sopenharmony_ci    }
1178cb93a386Sopenharmony_ci
1179cb93a386Sopenharmony_ci    return GrBackendRenderTarget(dimensions.width(), dimensions.height(), info);
1180cb93a386Sopenharmony_ci}
1181cb93a386Sopenharmony_ci
1182cb93a386Sopenharmony_civoid GrMtlGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget& rt) {
1183cb93a386Sopenharmony_ci    SkASSERT(GrBackendApi::kMetal == rt.backend());
1184cb93a386Sopenharmony_ci
1185cb93a386Sopenharmony_ci    GrMtlTextureInfo info;
1186cb93a386Sopenharmony_ci    if (rt.getMtlTextureInfo(&info)) {
1187cb93a386Sopenharmony_ci        this->submitToGpu(true);
1188cb93a386Sopenharmony_ci        // Nothing else to do here, will get cleaned up when the GrBackendRenderTarget
1189cb93a386Sopenharmony_ci        // is deleted.
1190cb93a386Sopenharmony_ci    }
1191cb93a386Sopenharmony_ci}
1192cb93a386Sopenharmony_ci#endif // GR_TEST_UTILS
1193cb93a386Sopenharmony_ci
1194cb93a386Sopenharmony_civoid GrMtlGpu::copySurfaceAsResolve(GrSurface* dst, GrSurface* src) {
1195cb93a386Sopenharmony_ci    // TODO: Add support for subrectangles
1196cb93a386Sopenharmony_ci    GrMtlRenderTarget* srcRT = static_cast<GrMtlRenderTarget*>(src->asRenderTarget());
1197cb93a386Sopenharmony_ci    GrRenderTarget* dstRT = dst->asRenderTarget();
1198cb93a386Sopenharmony_ci    GrMtlAttachment* dstAttachment;
1199cb93a386Sopenharmony_ci    if (dstRT) {
1200cb93a386Sopenharmony_ci        GrMtlRenderTarget* mtlRT = static_cast<GrMtlRenderTarget*>(dstRT);
1201cb93a386Sopenharmony_ci        dstAttachment = mtlRT->colorAttachment();
1202cb93a386Sopenharmony_ci    } else {
1203cb93a386Sopenharmony_ci        SkASSERT(dst->asTexture());
1204cb93a386Sopenharmony_ci        dstAttachment = static_cast<GrMtlTexture*>(dst->asTexture())->attachment();
1205cb93a386Sopenharmony_ci    }
1206cb93a386Sopenharmony_ci
1207cb93a386Sopenharmony_ci    this->resolve(dstAttachment, srcRT->colorAttachment());
1208cb93a386Sopenharmony_ci}
1209cb93a386Sopenharmony_ci
1210cb93a386Sopenharmony_civoid GrMtlGpu::copySurfaceAsBlit(GrSurface* dst, GrSurface* src,
1211cb93a386Sopenharmony_ci                                 GrMtlAttachment* dstAttachment, GrMtlAttachment* srcAttachment,
1212cb93a386Sopenharmony_ci                                 const SkIRect& srcRect, const SkIPoint& dstPoint) {
1213cb93a386Sopenharmony_ci#ifdef SK_DEBUG
1214cb93a386Sopenharmony_ci    SkASSERT(this->mtlCaps().canCopyAsBlit(dstAttachment->mtlFormat(), dstAttachment->numSamples(),
1215cb93a386Sopenharmony_ci                                           srcAttachment->mtlFormat(), dstAttachment->numSamples(),
1216cb93a386Sopenharmony_ci                                           srcRect, dstPoint, dst == src));
1217cb93a386Sopenharmony_ci#endif
1218cb93a386Sopenharmony_ci    id<MTLTexture> GR_NORETAIN dstTex = dstAttachment->mtlTexture();
1219cb93a386Sopenharmony_ci    id<MTLTexture> GR_NORETAIN srcTex = srcAttachment->mtlTexture();
1220cb93a386Sopenharmony_ci
1221cb93a386Sopenharmony_ci    auto cmdBuffer = this->commandBuffer();
1222cb93a386Sopenharmony_ci    id<MTLBlitCommandEncoder> GR_NORETAIN blitCmdEncoder = cmdBuffer->getBlitCommandEncoder();
1223cb93a386Sopenharmony_ci    if (!blitCmdEncoder) {
1224cb93a386Sopenharmony_ci        return;
1225cb93a386Sopenharmony_ci    }
1226cb93a386Sopenharmony_ci#ifdef SK_ENABLE_MTL_DEBUG_INFO
1227cb93a386Sopenharmony_ci    [blitCmdEncoder pushDebugGroup:@"copySurfaceAsBlit"];
1228cb93a386Sopenharmony_ci#endif
1229cb93a386Sopenharmony_ci    [blitCmdEncoder copyFromTexture: srcTex
1230cb93a386Sopenharmony_ci                        sourceSlice: 0
1231cb93a386Sopenharmony_ci                        sourceLevel: 0
1232cb93a386Sopenharmony_ci                       sourceOrigin: MTLOriginMake(srcRect.x(), srcRect.y(), 0)
1233cb93a386Sopenharmony_ci                         sourceSize: MTLSizeMake(srcRect.width(), srcRect.height(), 1)
1234cb93a386Sopenharmony_ci                          toTexture: dstTex
1235cb93a386Sopenharmony_ci                   destinationSlice: 0
1236cb93a386Sopenharmony_ci                   destinationLevel: 0
1237cb93a386Sopenharmony_ci                  destinationOrigin: MTLOriginMake(dstPoint.fX, dstPoint.fY, 0)];
1238cb93a386Sopenharmony_ci#ifdef SK_ENABLE_MTL_DEBUG_INFO
1239cb93a386Sopenharmony_ci    [blitCmdEncoder popDebugGroup];
1240cb93a386Sopenharmony_ci#endif
1241cb93a386Sopenharmony_ci    cmdBuffer->addGrSurface(sk_ref_sp<const GrSurface>(dst));
1242cb93a386Sopenharmony_ci    cmdBuffer->addGrSurface(sk_ref_sp<const GrSurface>(src));
1243cb93a386Sopenharmony_ci}
1244cb93a386Sopenharmony_ci
1245cb93a386Sopenharmony_cibool GrMtlGpu::onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
1246cb93a386Sopenharmony_ci                             const SkIPoint& dstPoint) {
1247cb93a386Sopenharmony_ci    SkASSERT(!src->isProtected() && !dst->isProtected());
1248cb93a386Sopenharmony_ci
1249cb93a386Sopenharmony_ci    GrMtlAttachment* dstAttachment;
1250cb93a386Sopenharmony_ci    GrMtlAttachment* srcAttachment;
1251cb93a386Sopenharmony_ci    GrRenderTarget* dstRT = dst->asRenderTarget();
1252cb93a386Sopenharmony_ci    if (dstRT) {
1253cb93a386Sopenharmony_ci        GrMtlRenderTarget* mtlRT = static_cast<GrMtlRenderTarget*>(dstRT);
1254cb93a386Sopenharmony_ci        // This will technically return true for single sample rts that used DMSAA in which case we
1255cb93a386Sopenharmony_ci        // don't have to pick the resolve attachment. But in that case the resolve and color
1256cb93a386Sopenharmony_ci        // attachments will be the same anyways.
1257cb93a386Sopenharmony_ci        if (this->mtlCaps().renderTargetSupportsDiscardableMSAA(mtlRT)) {
1258cb93a386Sopenharmony_ci            dstAttachment = mtlRT->resolveAttachment();
1259cb93a386Sopenharmony_ci        } else {
1260cb93a386Sopenharmony_ci            dstAttachment = mtlRT->colorAttachment();
1261cb93a386Sopenharmony_ci        }
1262cb93a386Sopenharmony_ci    } else if (dst->asTexture()) {
1263cb93a386Sopenharmony_ci        dstAttachment = static_cast<GrMtlTexture*>(dst->asTexture())->attachment();
1264cb93a386Sopenharmony_ci    } else {
1265cb93a386Sopenharmony_ci        // The surface in a GrAttachment already
1266cb93a386Sopenharmony_ci        dstAttachment = static_cast<GrMtlAttachment*>(dst);
1267cb93a386Sopenharmony_ci    }
1268cb93a386Sopenharmony_ci    GrRenderTarget* srcRT = src->asRenderTarget();
1269cb93a386Sopenharmony_ci    if (srcRT) {
1270cb93a386Sopenharmony_ci        GrMtlRenderTarget* mtlRT = static_cast<GrMtlRenderTarget*>(srcRT);
1271cb93a386Sopenharmony_ci        // This will technically return true for single sample rts that used DMSAA in which case we
1272cb93a386Sopenharmony_ci        // don't have to pick the resolve attachment. But in that case the resolve and color
1273cb93a386Sopenharmony_ci        // attachments will be the same anyways.
1274cb93a386Sopenharmony_ci        if (this->mtlCaps().renderTargetSupportsDiscardableMSAA(mtlRT)) {
1275cb93a386Sopenharmony_ci            srcAttachment = mtlRT->resolveAttachment();
1276cb93a386Sopenharmony_ci        } else {
1277cb93a386Sopenharmony_ci            srcAttachment = mtlRT->colorAttachment();
1278cb93a386Sopenharmony_ci        }
1279cb93a386Sopenharmony_ci    } else if (src->asTexture()) {
1280cb93a386Sopenharmony_ci        SkASSERT(src->asTexture());
1281cb93a386Sopenharmony_ci        srcAttachment = static_cast<GrMtlTexture*>(src->asTexture())->attachment();
1282cb93a386Sopenharmony_ci    } else {
1283cb93a386Sopenharmony_ci        // The surface in a GrAttachment already
1284cb93a386Sopenharmony_ci        srcAttachment = static_cast<GrMtlAttachment*>(src);
1285cb93a386Sopenharmony_ci    }
1286cb93a386Sopenharmony_ci
1287cb93a386Sopenharmony_ci    MTLPixelFormat dstFormat = dstAttachment->mtlFormat();
1288cb93a386Sopenharmony_ci    MTLPixelFormat srcFormat = srcAttachment->mtlFormat();
1289cb93a386Sopenharmony_ci
1290cb93a386Sopenharmony_ci    int dstSampleCnt = dstAttachment->sampleCount();
1291cb93a386Sopenharmony_ci    int srcSampleCnt = srcAttachment->sampleCount();
1292cb93a386Sopenharmony_ci
1293cb93a386Sopenharmony_ci    if (this->mtlCaps().canCopyAsResolve(dstFormat, dstSampleCnt,
1294cb93a386Sopenharmony_ci                                         srcFormat, srcSampleCnt,
1295cb93a386Sopenharmony_ci                                         SkToBool(srcRT), src->dimensions(),
1296cb93a386Sopenharmony_ci                                         srcRect, dstPoint,
1297cb93a386Sopenharmony_ci                                         dstAttachment == srcAttachment)) {
1298cb93a386Sopenharmony_ci        this->copySurfaceAsResolve(dst, src);
1299cb93a386Sopenharmony_ci        return true;
1300cb93a386Sopenharmony_ci    }
1301cb93a386Sopenharmony_ci
1302cb93a386Sopenharmony_ci    if (srcAttachment->framebufferOnly() || dstAttachment->framebufferOnly()) {
1303cb93a386Sopenharmony_ci        return false;
1304cb93a386Sopenharmony_ci    }
1305cb93a386Sopenharmony_ci
1306cb93a386Sopenharmony_ci    if (this->mtlCaps().canCopyAsBlit(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt,
1307cb93a386Sopenharmony_ci                                      srcRect, dstPoint, dstAttachment == srcAttachment)) {
1308cb93a386Sopenharmony_ci        this->copySurfaceAsBlit(dst, src, dstAttachment, srcAttachment, srcRect, dstPoint);
1309cb93a386Sopenharmony_ci        return true;
1310cb93a386Sopenharmony_ci    }
1311cb93a386Sopenharmony_ci
1312cb93a386Sopenharmony_ci    return false;
1313cb93a386Sopenharmony_ci}
1314cb93a386Sopenharmony_ci
1315cb93a386Sopenharmony_cibool GrMtlGpu::onWritePixels(GrSurface* surface,
1316cb93a386Sopenharmony_ci                             SkIRect rect,
1317cb93a386Sopenharmony_ci                             GrColorType surfaceColorType,
1318cb93a386Sopenharmony_ci                             GrColorType srcColorType,
1319cb93a386Sopenharmony_ci                             const GrMipLevel texels[],
1320cb93a386Sopenharmony_ci                             int mipLevelCount,
1321cb93a386Sopenharmony_ci                             bool prepForTexSampling) {
1322cb93a386Sopenharmony_ci    GrMtlTexture* mtlTexture = static_cast<GrMtlTexture*>(surface->asTexture());
1323cb93a386Sopenharmony_ci    // TODO: In principle we should be able to support pure rendertargets as well, but
1324cb93a386Sopenharmony_ci    // until we find a use case we'll only support texture rendertargets.
1325cb93a386Sopenharmony_ci    if (!mtlTexture) {
1326cb93a386Sopenharmony_ci        return false;
1327cb93a386Sopenharmony_ci    }
1328cb93a386Sopenharmony_ci    if (!mipLevelCount) {
1329cb93a386Sopenharmony_ci        return false;
1330cb93a386Sopenharmony_ci    }
1331cb93a386Sopenharmony_ci#ifdef SK_DEBUG
1332cb93a386Sopenharmony_ci    for (int i = 0; i < mipLevelCount; i++) {
1333cb93a386Sopenharmony_ci        SkASSERT(texels[i].fPixels);
1334cb93a386Sopenharmony_ci    }
1335cb93a386Sopenharmony_ci#endif
1336cb93a386Sopenharmony_ci    return this->uploadToTexture(mtlTexture, rect, srcColorType, texels, mipLevelCount);
1337cb93a386Sopenharmony_ci}
1338cb93a386Sopenharmony_ci
1339cb93a386Sopenharmony_cibool GrMtlGpu::onReadPixels(GrSurface* surface,
1340cb93a386Sopenharmony_ci                            SkIRect rect,
1341cb93a386Sopenharmony_ci                            GrColorType surfaceColorType,
1342cb93a386Sopenharmony_ci                            GrColorType dstColorType,
1343cb93a386Sopenharmony_ci                            void* buffer,
1344cb93a386Sopenharmony_ci                            size_t rowBytes) {
1345cb93a386Sopenharmony_ci    SkASSERT(surface);
1346cb93a386Sopenharmony_ci
1347cb93a386Sopenharmony_ci    if (surfaceColorType != dstColorType) {
1348cb93a386Sopenharmony_ci        return false;
1349cb93a386Sopenharmony_ci    }
1350cb93a386Sopenharmony_ci
1351cb93a386Sopenharmony_ci    int bpp = GrColorTypeBytesPerPixel(dstColorType);
1352cb93a386Sopenharmony_ci    size_t transBufferRowBytes = bpp*rect.width();
1353cb93a386Sopenharmony_ci    size_t transBufferImageBytes = transBufferRowBytes*rect.height();
1354cb93a386Sopenharmony_ci
1355cb93a386Sopenharmony_ci    GrResourceProvider* resourceProvider = this->getContext()->priv().resourceProvider();
1356cb93a386Sopenharmony_ci    sk_sp<GrGpuBuffer> transferBuffer = resourceProvider->createBuffer(
1357cb93a386Sopenharmony_ci            transBufferImageBytes, GrGpuBufferType::kXferGpuToCpu,
1358cb93a386Sopenharmony_ci            kDynamic_GrAccessPattern);
1359cb93a386Sopenharmony_ci
1360cb93a386Sopenharmony_ci    if (!transferBuffer) {
1361cb93a386Sopenharmony_ci        return false;
1362cb93a386Sopenharmony_ci    }
1363cb93a386Sopenharmony_ci
1364cb93a386Sopenharmony_ci    GrMtlBuffer* grMtlBuffer = static_cast<GrMtlBuffer*>(transferBuffer.get());
1365cb93a386Sopenharmony_ci    if (!this->readOrTransferPixels(surface,
1366cb93a386Sopenharmony_ci                                    rect,
1367cb93a386Sopenharmony_ci                                    dstColorType,
1368cb93a386Sopenharmony_ci                                    grMtlBuffer->mtlBuffer(),
1369cb93a386Sopenharmony_ci                                    0,
1370cb93a386Sopenharmony_ci                                    transBufferImageBytes,
1371cb93a386Sopenharmony_ci                                    transBufferRowBytes)) {
1372cb93a386Sopenharmony_ci        return false;
1373cb93a386Sopenharmony_ci    }
1374cb93a386Sopenharmony_ci    this->submitCommandBuffer(kForce_SyncQueue);
1375cb93a386Sopenharmony_ci
1376cb93a386Sopenharmony_ci    const void* mappedMemory = grMtlBuffer->mtlBuffer().contents;
1377cb93a386Sopenharmony_ci
1378cb93a386Sopenharmony_ci    SkRectMemcpy(buffer,
1379cb93a386Sopenharmony_ci                 rowBytes,
1380cb93a386Sopenharmony_ci                 mappedMemory,
1381cb93a386Sopenharmony_ci                 transBufferRowBytes,
1382cb93a386Sopenharmony_ci                 transBufferRowBytes,
1383cb93a386Sopenharmony_ci                 rect.height());
1384cb93a386Sopenharmony_ci
1385cb93a386Sopenharmony_ci    return true;
1386cb93a386Sopenharmony_ci}
1387cb93a386Sopenharmony_ci
1388cb93a386Sopenharmony_cibool GrMtlGpu::onTransferPixelsTo(GrTexture* texture,
1389cb93a386Sopenharmony_ci                                  SkIRect rect,
1390cb93a386Sopenharmony_ci                                  GrColorType textureColorType,
1391cb93a386Sopenharmony_ci                                  GrColorType bufferColorType,
1392cb93a386Sopenharmony_ci                                  sk_sp<GrGpuBuffer> transferBuffer,
1393cb93a386Sopenharmony_ci                                  size_t offset,
1394cb93a386Sopenharmony_ci                                  size_t rowBytes) {
1395cb93a386Sopenharmony_ci    SkASSERT(texture);
1396cb93a386Sopenharmony_ci    SkASSERT(transferBuffer);
1397cb93a386Sopenharmony_ci    if (textureColorType != bufferColorType) {
1398cb93a386Sopenharmony_ci        return false;
1399cb93a386Sopenharmony_ci    }
1400cb93a386Sopenharmony_ci
1401cb93a386Sopenharmony_ci    GrMtlTexture* grMtlTexture = static_cast<GrMtlTexture*>(texture);
1402cb93a386Sopenharmony_ci    id<MTLTexture> GR_NORETAIN mtlTexture = grMtlTexture->mtlTexture();
1403cb93a386Sopenharmony_ci    SkASSERT(mtlTexture);
1404cb93a386Sopenharmony_ci
1405cb93a386Sopenharmony_ci    GrMtlBuffer* grMtlBuffer = static_cast<GrMtlBuffer*>(transferBuffer.get());
1406cb93a386Sopenharmony_ci    id<MTLBuffer> GR_NORETAIN mtlBuffer = grMtlBuffer->mtlBuffer();
1407cb93a386Sopenharmony_ci    SkASSERT(mtlBuffer);
1408cb93a386Sopenharmony_ci
1409cb93a386Sopenharmony_ci    size_t bpp = GrColorTypeBytesPerPixel(bufferColorType);
1410cb93a386Sopenharmony_ci    if (offset % bpp) {
1411cb93a386Sopenharmony_ci        return false;
1412cb93a386Sopenharmony_ci    }
1413cb93a386Sopenharmony_ci    if (GrBackendFormatBytesPerPixel(texture->backendFormat()) != bpp) {
1414cb93a386Sopenharmony_ci        return false;
1415cb93a386Sopenharmony_ci    }
1416cb93a386Sopenharmony_ci
1417cb93a386Sopenharmony_ci    MTLOrigin origin = MTLOriginMake(rect.left(), rect.top(), 0);
1418cb93a386Sopenharmony_ci
1419cb93a386Sopenharmony_ci    auto cmdBuffer = this->commandBuffer();
1420cb93a386Sopenharmony_ci    id<MTLBlitCommandEncoder> GR_NORETAIN blitCmdEncoder = cmdBuffer->getBlitCommandEncoder();
1421cb93a386Sopenharmony_ci    if (!blitCmdEncoder) {
1422cb93a386Sopenharmony_ci        return false;
1423cb93a386Sopenharmony_ci    }
1424cb93a386Sopenharmony_ci#ifdef SK_ENABLE_MTL_DEBUG_INFO
1425cb93a386Sopenharmony_ci    [blitCmdEncoder pushDebugGroup:@"onTransferPixelsTo"];
1426cb93a386Sopenharmony_ci#endif
1427cb93a386Sopenharmony_ci    [blitCmdEncoder copyFromBuffer: mtlBuffer
1428cb93a386Sopenharmony_ci                      sourceOffset: offset
1429cb93a386Sopenharmony_ci                 sourceBytesPerRow: rowBytes
1430cb93a386Sopenharmony_ci               sourceBytesPerImage: rowBytes*rect.height()
1431cb93a386Sopenharmony_ci                        sourceSize: MTLSizeMake(rect.width(), rect.height(), 1)
1432cb93a386Sopenharmony_ci                         toTexture: mtlTexture
1433cb93a386Sopenharmony_ci                  destinationSlice: 0
1434cb93a386Sopenharmony_ci                  destinationLevel: 0
1435cb93a386Sopenharmony_ci                 destinationOrigin: origin];
1436cb93a386Sopenharmony_ci#ifdef SK_ENABLE_MTL_DEBUG_INFO
1437cb93a386Sopenharmony_ci    [blitCmdEncoder popDebugGroup];
1438cb93a386Sopenharmony_ci#endif
1439cb93a386Sopenharmony_ci
1440cb93a386Sopenharmony_ci    return true;
1441cb93a386Sopenharmony_ci}
1442cb93a386Sopenharmony_ci
1443cb93a386Sopenharmony_cibool GrMtlGpu::onTransferPixelsFrom(GrSurface* surface,
1444cb93a386Sopenharmony_ci                                    SkIRect rect,
1445cb93a386Sopenharmony_ci                                    GrColorType surfaceColorType,
1446cb93a386Sopenharmony_ci                                    GrColorType bufferColorType,
1447cb93a386Sopenharmony_ci                                    sk_sp<GrGpuBuffer> transferBuffer,
1448cb93a386Sopenharmony_ci                                    size_t offset) {
1449cb93a386Sopenharmony_ci    SkASSERT(surface);
1450cb93a386Sopenharmony_ci    SkASSERT(transferBuffer);
1451cb93a386Sopenharmony_ci
1452cb93a386Sopenharmony_ci    if (surfaceColorType != bufferColorType) {
1453cb93a386Sopenharmony_ci        return false;
1454cb93a386Sopenharmony_ci    }
1455cb93a386Sopenharmony_ci
1456cb93a386Sopenharmony_ci    // Metal only supports offsets that are aligned to a pixel.
1457cb93a386Sopenharmony_ci    size_t bpp = GrColorTypeBytesPerPixel(bufferColorType);
1458cb93a386Sopenharmony_ci    if (offset % bpp) {
1459cb93a386Sopenharmony_ci        return false;
1460cb93a386Sopenharmony_ci    }
1461cb93a386Sopenharmony_ci    if (GrBackendFormatBytesPerPixel(surface->backendFormat()) != bpp) {
1462cb93a386Sopenharmony_ci        return false;
1463cb93a386Sopenharmony_ci    }
1464cb93a386Sopenharmony_ci
1465cb93a386Sopenharmony_ci    GrMtlBuffer* grMtlBuffer = static_cast<GrMtlBuffer*>(transferBuffer.get());
1466cb93a386Sopenharmony_ci
1467cb93a386Sopenharmony_ci    size_t transBufferRowBytes = bpp*rect.width();
1468cb93a386Sopenharmony_ci    size_t transBufferImageBytes = transBufferRowBytes*rect.height();
1469cb93a386Sopenharmony_ci
1470cb93a386Sopenharmony_ci    return this->readOrTransferPixels(surface,
1471cb93a386Sopenharmony_ci                                      rect,
1472cb93a386Sopenharmony_ci                                      bufferColorType,
1473cb93a386Sopenharmony_ci                                      grMtlBuffer->mtlBuffer(),
1474cb93a386Sopenharmony_ci                                      offset,
1475cb93a386Sopenharmony_ci                                      transBufferImageBytes,
1476cb93a386Sopenharmony_ci                                      transBufferRowBytes);
1477cb93a386Sopenharmony_ci}
1478cb93a386Sopenharmony_ci
1479cb93a386Sopenharmony_cibool GrMtlGpu::readOrTransferPixels(GrSurface* surface,
1480cb93a386Sopenharmony_ci                                    SkIRect rect,
1481cb93a386Sopenharmony_ci                                    GrColorType dstColorType,
1482cb93a386Sopenharmony_ci                                    id<MTLBuffer> transferBuffer,
1483cb93a386Sopenharmony_ci                                    size_t offset,
1484cb93a386Sopenharmony_ci                                    size_t imageBytes,
1485cb93a386Sopenharmony_ci                                    size_t rowBytes) {
1486cb93a386Sopenharmony_ci    if (!check_max_blit_width(rect.width())) {
1487cb93a386Sopenharmony_ci        return false;
1488cb93a386Sopenharmony_ci    }
1489cb93a386Sopenharmony_ci
1490cb93a386Sopenharmony_ci    id<MTLTexture> mtlTexture;
1491cb93a386Sopenharmony_ci    if (GrMtlRenderTarget* rt = static_cast<GrMtlRenderTarget*>(surface->asRenderTarget())) {
1492cb93a386Sopenharmony_ci        if (rt->numSamples() > 1) {
1493cb93a386Sopenharmony_ci            SkASSERT(rt->requiresManualMSAAResolve());  // msaa-render-to-texture not yet supported.
1494cb93a386Sopenharmony_ci            mtlTexture = rt->resolveMTLTexture();
1495cb93a386Sopenharmony_ci        } else {
1496cb93a386Sopenharmony_ci            SkASSERT(!rt->requiresManualMSAAResolve());
1497cb93a386Sopenharmony_ci            mtlTexture = rt->colorMTLTexture();
1498cb93a386Sopenharmony_ci        }
1499cb93a386Sopenharmony_ci    } else if (GrMtlTexture* texture = static_cast<GrMtlTexture*>(surface->asTexture())) {
1500cb93a386Sopenharmony_ci        mtlTexture = texture->mtlTexture();
1501cb93a386Sopenharmony_ci    }
1502cb93a386Sopenharmony_ci    if (!mtlTexture) {
1503cb93a386Sopenharmony_ci        return false;
1504cb93a386Sopenharmony_ci    }
1505cb93a386Sopenharmony_ci
1506cb93a386Sopenharmony_ci    auto cmdBuffer = this->commandBuffer();
1507cb93a386Sopenharmony_ci    id<MTLBlitCommandEncoder> GR_NORETAIN blitCmdEncoder = cmdBuffer->getBlitCommandEncoder();
1508cb93a386Sopenharmony_ci    if (!blitCmdEncoder) {
1509cb93a386Sopenharmony_ci        return false;
1510cb93a386Sopenharmony_ci    }
1511cb93a386Sopenharmony_ci#ifdef SK_ENABLE_MTL_DEBUG_INFO
1512cb93a386Sopenharmony_ci    [blitCmdEncoder pushDebugGroup:@"readOrTransferPixels"];
1513cb93a386Sopenharmony_ci#endif
1514cb93a386Sopenharmony_ci    [blitCmdEncoder copyFromTexture: mtlTexture
1515cb93a386Sopenharmony_ci                        sourceSlice: 0
1516cb93a386Sopenharmony_ci                        sourceLevel: 0
1517cb93a386Sopenharmony_ci                       sourceOrigin: MTLOriginMake(rect.left(), rect.top(), 0)
1518cb93a386Sopenharmony_ci                         sourceSize: MTLSizeMake(rect.width(), rect.height(), 1)
1519cb93a386Sopenharmony_ci                           toBuffer: transferBuffer
1520cb93a386Sopenharmony_ci                  destinationOffset: offset
1521cb93a386Sopenharmony_ci             destinationBytesPerRow: rowBytes
1522cb93a386Sopenharmony_ci           destinationBytesPerImage: imageBytes];
1523cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_MAC
1524cb93a386Sopenharmony_ci    if (this->mtlCaps().isMac()) {
1525cb93a386Sopenharmony_ci        // Sync GPU data back to the CPU
1526cb93a386Sopenharmony_ci        [blitCmdEncoder synchronizeResource: transferBuffer];
1527cb93a386Sopenharmony_ci    }
1528cb93a386Sopenharmony_ci#endif
1529cb93a386Sopenharmony_ci#ifdef SK_ENABLE_MTL_DEBUG_INFO
1530cb93a386Sopenharmony_ci    [blitCmdEncoder popDebugGroup];
1531cb93a386Sopenharmony_ci#endif
1532cb93a386Sopenharmony_ci
1533cb93a386Sopenharmony_ci    return true;
1534cb93a386Sopenharmony_ci}
1535cb93a386Sopenharmony_ci
1536cb93a386Sopenharmony_ciGrFence SK_WARN_UNUSED_RESULT GrMtlGpu::insertFence() {
1537cb93a386Sopenharmony_ci    GrMtlCommandBuffer* cmdBuffer = this->commandBuffer();
1538cb93a386Sopenharmony_ci    // We create a semaphore and signal it within the current
1539cb93a386Sopenharmony_ci    // command buffer's completion handler.
1540cb93a386Sopenharmony_ci    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
1541cb93a386Sopenharmony_ci    cmdBuffer->addCompletedHandler(^(id <MTLCommandBuffer>commandBuffer) {
1542cb93a386Sopenharmony_ci        dispatch_semaphore_signal(semaphore);
1543cb93a386Sopenharmony_ci    });
1544cb93a386Sopenharmony_ci
1545cb93a386Sopenharmony_ci    const void* cfFence = (__bridge_retained const void*) semaphore;
1546cb93a386Sopenharmony_ci    return (GrFence) cfFence;
1547cb93a386Sopenharmony_ci}
1548cb93a386Sopenharmony_ci
1549cb93a386Sopenharmony_cibool GrMtlGpu::waitFence(GrFence fence) {
1550cb93a386Sopenharmony_ci    const void* cfFence = (const void*) fence;
1551cb93a386Sopenharmony_ci    dispatch_semaphore_t semaphore = (__bridge dispatch_semaphore_t)cfFence;
1552cb93a386Sopenharmony_ci
1553cb93a386Sopenharmony_ci    long result = dispatch_semaphore_wait(semaphore, 0);
1554cb93a386Sopenharmony_ci
1555cb93a386Sopenharmony_ci    return !result;
1556cb93a386Sopenharmony_ci}
1557cb93a386Sopenharmony_ci
1558cb93a386Sopenharmony_civoid GrMtlGpu::deleteFence(GrFence fence) const {
1559cb93a386Sopenharmony_ci    const void* cfFence = (const void*) fence;
1560cb93a386Sopenharmony_ci    // In this case it's easier to release in CoreFoundation than depend on ARC
1561cb93a386Sopenharmony_ci    CFRelease(cfFence);
1562cb93a386Sopenharmony_ci}
1563cb93a386Sopenharmony_ci
1564cb93a386Sopenharmony_cistd::unique_ptr<GrSemaphore> SK_WARN_UNUSED_RESULT GrMtlGpu::makeSemaphore(bool /*isOwned*/) {
1565cb93a386Sopenharmony_ci    SkASSERT(this->caps()->semaphoreSupport());
1566cb93a386Sopenharmony_ci    return GrMtlSemaphore::Make(this);
1567cb93a386Sopenharmony_ci}
1568cb93a386Sopenharmony_ci
1569cb93a386Sopenharmony_cistd::unique_ptr<GrSemaphore> GrMtlGpu::wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
1570cb93a386Sopenharmony_ci                                                            GrSemaphoreWrapType /* wrapType */,
1571cb93a386Sopenharmony_ci                                                            GrWrapOwnership /*ownership*/) {
1572cb93a386Sopenharmony_ci    SkASSERT(this->caps()->semaphoreSupport());
1573cb93a386Sopenharmony_ci    return GrMtlSemaphore::MakeWrapped(semaphore.mtlSemaphore(), semaphore.mtlValue());
1574cb93a386Sopenharmony_ci}
1575cb93a386Sopenharmony_ci
1576cb93a386Sopenharmony_civoid GrMtlGpu::insertSemaphore(GrSemaphore* semaphore) {
1577cb93a386Sopenharmony_ci    if (@available(macOS 10.14, iOS 12.0, *)) {
1578cb93a386Sopenharmony_ci        SkASSERT(semaphore);
1579cb93a386Sopenharmony_ci        GrMtlSemaphore* mtlSem = static_cast<GrMtlSemaphore*>(semaphore);
1580cb93a386Sopenharmony_ci
1581cb93a386Sopenharmony_ci        this->commandBuffer()->encodeSignalEvent(mtlSem->event(), mtlSem->value());
1582cb93a386Sopenharmony_ci    }
1583cb93a386Sopenharmony_ci}
1584cb93a386Sopenharmony_ci
1585cb93a386Sopenharmony_civoid GrMtlGpu::waitSemaphore(GrSemaphore* semaphore) {
1586cb93a386Sopenharmony_ci    if (@available(macOS 10.14, iOS 12.0, *)) {
1587cb93a386Sopenharmony_ci        SkASSERT(semaphore);
1588cb93a386Sopenharmony_ci        GrMtlSemaphore* mtlSem = static_cast<GrMtlSemaphore*>(semaphore);
1589cb93a386Sopenharmony_ci
1590cb93a386Sopenharmony_ci        this->commandBuffer()->encodeWaitForEvent(mtlSem->event(), mtlSem->value());
1591cb93a386Sopenharmony_ci    }
1592cb93a386Sopenharmony_ci}
1593cb93a386Sopenharmony_ci
1594cb93a386Sopenharmony_civoid GrMtlGpu::onResolveRenderTarget(GrRenderTarget* target, const SkIRect&) {
1595cb93a386Sopenharmony_ci    SkASSERT(target->numSamples() > 1);
1596cb93a386Sopenharmony_ci    GrMtlRenderTarget* rt = static_cast<GrMtlRenderTarget*>(target);
1597cb93a386Sopenharmony_ci
1598cb93a386Sopenharmony_ci    if (rt->resolveAttachment() && this->mtlCaps().renderTargetSupportsDiscardableMSAA(rt)) {
1599cb93a386Sopenharmony_ci        // We would have resolved the RT during the render pass.
1600cb93a386Sopenharmony_ci        return;
1601cb93a386Sopenharmony_ci    }
1602cb93a386Sopenharmony_ci
1603cb93a386Sopenharmony_ci    this->resolve(static_cast<GrMtlRenderTarget*>(target)->resolveAttachment(),
1604cb93a386Sopenharmony_ci                  static_cast<GrMtlRenderTarget*>(target)->colorAttachment());
1605cb93a386Sopenharmony_ci}
1606cb93a386Sopenharmony_ci
1607cb93a386Sopenharmony_civoid GrMtlGpu::resolve(GrMtlAttachment* resolveAttachment,
1608cb93a386Sopenharmony_ci                       GrMtlAttachment* msaaAttachment) {
1609cb93a386Sopenharmony_ci    auto renderPassDesc = [[MTLRenderPassDescriptor alloc] init];
1610cb93a386Sopenharmony_ci    auto colorAttachment = renderPassDesc.colorAttachments[0];
1611cb93a386Sopenharmony_ci    colorAttachment.texture = msaaAttachment->mtlTexture();
1612cb93a386Sopenharmony_ci    colorAttachment.resolveTexture = resolveAttachment->mtlTexture();
1613cb93a386Sopenharmony_ci    colorAttachment.loadAction = MTLLoadActionLoad;
1614cb93a386Sopenharmony_ci    colorAttachment.storeAction = MTLStoreActionMultisampleResolve;
1615cb93a386Sopenharmony_ci
1616cb93a386Sopenharmony_ci    GrMtlRenderCommandEncoder* cmdEncoder =
1617cb93a386Sopenharmony_ci            this->commandBuffer()->getRenderCommandEncoder(renderPassDesc, nullptr, nullptr);
1618cb93a386Sopenharmony_ci    if (cmdEncoder) {
1619cb93a386Sopenharmony_ci        cmdEncoder->setLabel(@"resolveTexture");
1620cb93a386Sopenharmony_ci        this->commandBuffer()->addGrSurface(sk_ref_sp<const GrSurface>(resolveAttachment));
1621cb93a386Sopenharmony_ci        this->commandBuffer()->addGrSurface(sk_ref_sp<const GrSurface>(msaaAttachment));
1622cb93a386Sopenharmony_ci    }
1623cb93a386Sopenharmony_ci}
1624cb93a386Sopenharmony_ci
1625cb93a386Sopenharmony_ciGrMtlRenderCommandEncoder* GrMtlGpu::loadMSAAFromResolve(
1626cb93a386Sopenharmony_ci        GrAttachment* dst, GrMtlAttachment* src, const SkIRect& srcRect,
1627cb93a386Sopenharmony_ci        MTLRenderPassStencilAttachmentDescriptor* stencil) {
1628cb93a386Sopenharmony_ci    if (!dst) {
1629cb93a386Sopenharmony_ci        return nil;
1630cb93a386Sopenharmony_ci    }
1631cb93a386Sopenharmony_ci    if (!src || src->framebufferOnly()) {
1632cb93a386Sopenharmony_ci        return nil;
1633cb93a386Sopenharmony_ci    }
1634cb93a386Sopenharmony_ci
1635cb93a386Sopenharmony_ci    GrMtlAttachment* mtlDst = static_cast<GrMtlAttachment*>(dst);
1636cb93a386Sopenharmony_ci
1637cb93a386Sopenharmony_ci    MTLPixelFormat stencilFormat = stencil.texture.pixelFormat;
1638cb93a386Sopenharmony_ci    auto renderPipeline = this->resourceProvider().findOrCreateMSAALoadPipeline(mtlDst->mtlFormat(),
1639cb93a386Sopenharmony_ci                                                                                dst->numSamples(),
1640cb93a386Sopenharmony_ci                                                                                stencilFormat);
1641cb93a386Sopenharmony_ci
1642cb93a386Sopenharmony_ci    // Set up rendercommandencoder
1643cb93a386Sopenharmony_ci    auto renderPassDesc = [MTLRenderPassDescriptor new];
1644cb93a386Sopenharmony_ci    auto colorAttachment = renderPassDesc.colorAttachments[0];
1645cb93a386Sopenharmony_ci    colorAttachment.texture = mtlDst->mtlTexture();
1646cb93a386Sopenharmony_ci    colorAttachment.loadAction = MTLLoadActionDontCare;
1647cb93a386Sopenharmony_ci    colorAttachment.storeAction = MTLStoreActionMultisampleResolve;
1648cb93a386Sopenharmony_ci    colorAttachment.resolveTexture = src->mtlTexture();
1649cb93a386Sopenharmony_ci
1650cb93a386Sopenharmony_ci    renderPassDesc.stencilAttachment = stencil;
1651cb93a386Sopenharmony_ci
1652cb93a386Sopenharmony_ci    // We know in this case that the preceding renderCommandEncoder will not be compatible.
1653cb93a386Sopenharmony_ci    // Either it's using a different rendertarget, or we are reading from the resolve and
1654cb93a386Sopenharmony_ci    // hence we need to let the previous resolve finish. So we create a new one without checking.
1655cb93a386Sopenharmony_ci    auto renderCmdEncoder =
1656cb93a386Sopenharmony_ci                this->commandBuffer()->getRenderCommandEncoder(renderPassDesc, nullptr);
1657cb93a386Sopenharmony_ci    if (!renderCmdEncoder) {
1658cb93a386Sopenharmony_ci        return nullptr;
1659cb93a386Sopenharmony_ci    }
1660cb93a386Sopenharmony_ci
1661cb93a386Sopenharmony_ci    // Bind pipeline
1662cb93a386Sopenharmony_ci    renderCmdEncoder->setRenderPipelineState(renderPipeline->mtlPipelineState());
1663cb93a386Sopenharmony_ci    this->commandBuffer()->addResource(sk_ref_sp(renderPipeline));
1664cb93a386Sopenharmony_ci
1665cb93a386Sopenharmony_ci    // Bind src as input texture
1666cb93a386Sopenharmony_ci    renderCmdEncoder->setFragmentTexture(src->mtlTexture(), 0);
1667cb93a386Sopenharmony_ci    // No sampler needed
1668cb93a386Sopenharmony_ci    this->commandBuffer()->addGrSurface(sk_ref_sp<GrSurface>(src));
1669cb93a386Sopenharmony_ci
1670cb93a386Sopenharmony_ci    // Scissor and viewport should default to size of color attachment
1671cb93a386Sopenharmony_ci
1672cb93a386Sopenharmony_ci    // Update and bind uniform data
1673cb93a386Sopenharmony_ci    int w = srcRect.width();
1674cb93a386Sopenharmony_ci    int h = srcRect.height();
1675cb93a386Sopenharmony_ci
1676cb93a386Sopenharmony_ci    // dst rect edges in NDC (-1 to 1)
1677cb93a386Sopenharmony_ci    int dw = dst->width();
1678cb93a386Sopenharmony_ci    int dh = dst->height();
1679cb93a386Sopenharmony_ci    float dx0 = 2.f * srcRect.fLeft / dw - 1.f;
1680cb93a386Sopenharmony_ci    float dx1 = 2.f * (srcRect.fLeft + w) / dw - 1.f;
1681cb93a386Sopenharmony_ci    float dy0 = 2.f * srcRect.fTop / dh - 1.f;
1682cb93a386Sopenharmony_ci    float dy1 = 2.f * (srcRect.fTop + h) / dh - 1.f;
1683cb93a386Sopenharmony_ci
1684cb93a386Sopenharmony_ci    struct {
1685cb93a386Sopenharmony_ci        float posXform[4];
1686cb93a386Sopenharmony_ci        int textureSize[2];
1687cb93a386Sopenharmony_ci        int pad[2];
1688cb93a386Sopenharmony_ci    } uniData = {{dx1 - dx0, dy1 - dy0, dx0, dy0}, {dw, dh}, {0, 0}};
1689cb93a386Sopenharmony_ci
1690cb93a386Sopenharmony_ci    constexpr size_t uniformSize = 32;
1691cb93a386Sopenharmony_ci    if (@available(macOS 10.11, iOS 8.3, *)) {
1692cb93a386Sopenharmony_ci        SkASSERT(uniformSize <= this->caps()->maxPushConstantsSize());
1693cb93a386Sopenharmony_ci        renderCmdEncoder->setVertexBytes(&uniData, uniformSize, 0);
1694cb93a386Sopenharmony_ci    } else {
1695cb93a386Sopenharmony_ci        // upload the data
1696cb93a386Sopenharmony_ci        GrRingBuffer::Slice slice = this->uniformsRingBuffer()->suballocate(uniformSize);
1697cb93a386Sopenharmony_ci        GrMtlBuffer* buffer = (GrMtlBuffer*) slice.fBuffer;
1698cb93a386Sopenharmony_ci        char* destPtr = static_cast<char*>(slice.fBuffer->map()) + slice.fOffset;
1699cb93a386Sopenharmony_ci        memcpy(destPtr, &uniData, uniformSize);
1700cb93a386Sopenharmony_ci
1701cb93a386Sopenharmony_ci        renderCmdEncoder->setVertexBuffer(buffer->mtlBuffer(), slice.fOffset, 0);
1702cb93a386Sopenharmony_ci    }
1703cb93a386Sopenharmony_ci
1704cb93a386Sopenharmony_ci    renderCmdEncoder->drawPrimitives(MTLPrimitiveTypeTriangleStrip, (NSUInteger)0, (NSUInteger)4);
1705cb93a386Sopenharmony_ci
1706cb93a386Sopenharmony_ci    return renderCmdEncoder;
1707cb93a386Sopenharmony_ci}
1708cb93a386Sopenharmony_ci
1709cb93a386Sopenharmony_ci#if GR_TEST_UTILS
1710cb93a386Sopenharmony_civoid GrMtlGpu::testingOnly_startCapture() {
1711cb93a386Sopenharmony_ci    if (@available(macOS 10.13, iOS 11.0, *)) {
1712cb93a386Sopenharmony_ci        // TODO: add Metal 3 interface as well
1713cb93a386Sopenharmony_ci        MTLCaptureManager* captureManager = [MTLCaptureManager sharedCaptureManager];
1714cb93a386Sopenharmony_ci        if (captureManager.isCapturing) {
1715cb93a386Sopenharmony_ci            return;
1716cb93a386Sopenharmony_ci        }
1717cb93a386Sopenharmony_ci        if (@available(macOS 10.15, iOS 13.0, *)) {
1718cb93a386Sopenharmony_ci            MTLCaptureDescriptor* captureDescriptor = [[MTLCaptureDescriptor alloc] init];
1719cb93a386Sopenharmony_ci            captureDescriptor.captureObject = fQueue;
1720cb93a386Sopenharmony_ci
1721cb93a386Sopenharmony_ci            NSError *error;
1722cb93a386Sopenharmony_ci            if (![captureManager startCaptureWithDescriptor: captureDescriptor error:&error])
1723cb93a386Sopenharmony_ci            {
1724cb93a386Sopenharmony_ci                NSLog(@"Failed to start capture, error %@", error);
1725cb93a386Sopenharmony_ci            }
1726cb93a386Sopenharmony_ci        } else {
1727cb93a386Sopenharmony_ci            [captureManager startCaptureWithCommandQueue: fQueue];
1728cb93a386Sopenharmony_ci        }
1729cb93a386Sopenharmony_ci     }
1730cb93a386Sopenharmony_ci}
1731cb93a386Sopenharmony_ci
1732cb93a386Sopenharmony_civoid GrMtlGpu::testingOnly_endCapture() {
1733cb93a386Sopenharmony_ci    if (@available(macOS 10.13, iOS 11.0, *)) {
1734cb93a386Sopenharmony_ci        MTLCaptureManager* captureManager = [MTLCaptureManager sharedCaptureManager];
1735cb93a386Sopenharmony_ci        if (captureManager.isCapturing) {
1736cb93a386Sopenharmony_ci            [captureManager stopCapture];
1737cb93a386Sopenharmony_ci        }
1738cb93a386Sopenharmony_ci    }
1739cb93a386Sopenharmony_ci}
1740cb93a386Sopenharmony_ci#endif
1741cb93a386Sopenharmony_ci
1742cb93a386Sopenharmony_ci#ifdef SK_ENABLE_DUMP_GPU
1743cb93a386Sopenharmony_ci#include "src/utils/SkJSONWriter.h"
1744cb93a386Sopenharmony_civoid GrMtlGpu::onDumpJSON(SkJSONWriter* writer) const {
1745cb93a386Sopenharmony_ci    // We are called by the base class, which has already called beginObject(). We choose to nest
1746cb93a386Sopenharmony_ci    // all of our caps information in a named sub-object.
1747cb93a386Sopenharmony_ci    writer->beginObject("Metal GPU");
1748cb93a386Sopenharmony_ci
1749cb93a386Sopenharmony_ci    writer->beginObject("Device");
1750cb93a386Sopenharmony_ci    writer->appendString("name", fDevice.name.UTF8String);
1751cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_MAC
1752cb93a386Sopenharmony_ci    if (@available(macOS 10.11, *)) {
1753cb93a386Sopenharmony_ci        writer->appendBool("isHeadless", fDevice.isHeadless);
1754cb93a386Sopenharmony_ci        writer->appendBool("isLowPower", fDevice.isLowPower);
1755cb93a386Sopenharmony_ci    }
1756cb93a386Sopenharmony_ci    if (@available(macOS 10.13, *)) {
1757cb93a386Sopenharmony_ci        writer->appendBool("isRemovable", fDevice.isRemovable);
1758cb93a386Sopenharmony_ci    }
1759cb93a386Sopenharmony_ci#endif
1760cb93a386Sopenharmony_ci    if (@available(macOS 10.13, iOS 11.0, *)) {
1761cb93a386Sopenharmony_ci        writer->appendU64("registryID", fDevice.registryID);
1762cb93a386Sopenharmony_ci    }
1763cb93a386Sopenharmony_ci#if defined(SK_BUILD_FOR_MAC) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 101500
1764cb93a386Sopenharmony_ci    if (@available(macOS 10.15, *)) {
1765cb93a386Sopenharmony_ci        switch (fDevice.location) {
1766cb93a386Sopenharmony_ci            case MTLDeviceLocationBuiltIn:
1767cb93a386Sopenharmony_ci                writer->appendString("location", "builtIn");
1768cb93a386Sopenharmony_ci                break;
1769cb93a386Sopenharmony_ci            case MTLDeviceLocationSlot:
1770cb93a386Sopenharmony_ci                writer->appendString("location", "slot");
1771cb93a386Sopenharmony_ci                break;
1772cb93a386Sopenharmony_ci            case MTLDeviceLocationExternal:
1773cb93a386Sopenharmony_ci                writer->appendString("location", "external");
1774cb93a386Sopenharmony_ci                break;
1775cb93a386Sopenharmony_ci            case MTLDeviceLocationUnspecified:
1776cb93a386Sopenharmony_ci                writer->appendString("location", "unspecified");
1777cb93a386Sopenharmony_ci                break;
1778cb93a386Sopenharmony_ci            default:
1779cb93a386Sopenharmony_ci                writer->appendString("location", "unknown");
1780cb93a386Sopenharmony_ci                break;
1781cb93a386Sopenharmony_ci        }
1782cb93a386Sopenharmony_ci        writer->appendU64("locationNumber", fDevice.locationNumber);
1783cb93a386Sopenharmony_ci        writer->appendU64("maxTransferRate", fDevice.maxTransferRate);
1784cb93a386Sopenharmony_ci    }
1785cb93a386Sopenharmony_ci#endif  // SK_BUILD_FOR_MAC
1786cb93a386Sopenharmony_ci#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101500 || __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
1787cb93a386Sopenharmony_ci    if (@available(macOS 10.15, iOS 13.0, *)) {
1788cb93a386Sopenharmony_ci        writer->appendBool("hasUnifiedMemory", fDevice.hasUnifiedMemory);
1789cb93a386Sopenharmony_ci    }
1790cb93a386Sopenharmony_ci#endif
1791cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_MAC
1792cb93a386Sopenharmony_ci#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101500
1793cb93a386Sopenharmony_ci    if (@available(macOS 10.15, *)) {
1794cb93a386Sopenharmony_ci        writer->appendU64("peerGroupID", fDevice.peerGroupID);
1795cb93a386Sopenharmony_ci        writer->appendU32("peerCount", fDevice.peerCount);
1796cb93a386Sopenharmony_ci        writer->appendU32("peerIndex", fDevice.peerIndex);
1797cb93a386Sopenharmony_ci    }
1798cb93a386Sopenharmony_ci#endif
1799cb93a386Sopenharmony_ci    if (@available(macOS 10.12, *)) {
1800cb93a386Sopenharmony_ci        writer->appendU64("recommendedMaxWorkingSetSize", fDevice.recommendedMaxWorkingSetSize);
1801cb93a386Sopenharmony_ci    }
1802cb93a386Sopenharmony_ci#endif  // SK_BUILD_FOR_MAC
1803cb93a386Sopenharmony_ci    if (@available(macOS 10.13, iOS 11.0, *)) {
1804cb93a386Sopenharmony_ci        writer->appendU64("currentAllocatedSize", fDevice.currentAllocatedSize);
1805cb93a386Sopenharmony_ci        writer->appendU64("maxThreadgroupMemoryLength", fDevice.maxThreadgroupMemoryLength);
1806cb93a386Sopenharmony_ci    }
1807cb93a386Sopenharmony_ci
1808cb93a386Sopenharmony_ci    if (@available(macOS 10.11, iOS 9.0, *)) {
1809cb93a386Sopenharmony_ci        writer->beginObject("maxThreadsPerThreadgroup");
1810cb93a386Sopenharmony_ci        writer->appendU64("width", fDevice.maxThreadsPerThreadgroup.width);
1811cb93a386Sopenharmony_ci        writer->appendU64("height", fDevice.maxThreadsPerThreadgroup.height);
1812cb93a386Sopenharmony_ci        writer->appendU64("depth", fDevice.maxThreadsPerThreadgroup.depth);
1813cb93a386Sopenharmony_ci        writer->endObject();
1814cb93a386Sopenharmony_ci    }
1815cb93a386Sopenharmony_ci
1816cb93a386Sopenharmony_ci    if (@available(macOS 10.13, iOS 11.0, *)) {
1817cb93a386Sopenharmony_ci        writer->appendBool("areProgrammableSamplePositionsSupported",
1818cb93a386Sopenharmony_ci                           fDevice.areProgrammableSamplePositionsSupported);
1819cb93a386Sopenharmony_ci        writer->appendBool("areRasterOrderGroupsSupported",
1820cb93a386Sopenharmony_ci                           fDevice.areRasterOrderGroupsSupported);
1821cb93a386Sopenharmony_ci    }
1822cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_MAC
1823cb93a386Sopenharmony_ci    if (@available(macOS 10.11, *)) {
1824cb93a386Sopenharmony_ci        writer->appendBool("isDepth24Stencil8PixelFormatSupported",
1825cb93a386Sopenharmony_ci                           fDevice.isDepth24Stencil8PixelFormatSupported);
1826cb93a386Sopenharmony_ci
1827cb93a386Sopenharmony_ci    }
1828cb93a386Sopenharmony_ci#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101500
1829cb93a386Sopenharmony_ci    if (@available(macOS 10.15, *)) {
1830cb93a386Sopenharmony_ci        writer->appendBool("areBarycentricCoordsSupported",
1831cb93a386Sopenharmony_ci                           fDevice.areBarycentricCoordsSupported);
1832cb93a386Sopenharmony_ci        writer->appendBool("supportsShaderBarycentricCoordinates",
1833cb93a386Sopenharmony_ci                           fDevice.supportsShaderBarycentricCoordinates);
1834cb93a386Sopenharmony_ci    }
1835cb93a386Sopenharmony_ci#endif
1836cb93a386Sopenharmony_ci#endif  // SK_BUILD_FOR_MAC
1837cb93a386Sopenharmony_ci    if (@available(macOS 10.14, iOS 12.0, *)) {
1838cb93a386Sopenharmony_ci        writer->appendU64("maxBufferLength", fDevice.maxBufferLength);
1839cb93a386Sopenharmony_ci    }
1840cb93a386Sopenharmony_ci    if (@available(macOS 10.13, iOS 11.0, *)) {
1841cb93a386Sopenharmony_ci        switch (fDevice.readWriteTextureSupport) {
1842cb93a386Sopenharmony_ci            case MTLReadWriteTextureTier1:
1843cb93a386Sopenharmony_ci                writer->appendString("readWriteTextureSupport", "tier1");
1844cb93a386Sopenharmony_ci                break;
1845cb93a386Sopenharmony_ci            case MTLReadWriteTextureTier2:
1846cb93a386Sopenharmony_ci                writer->appendString("readWriteTextureSupport", "tier2");
1847cb93a386Sopenharmony_ci                break;
1848cb93a386Sopenharmony_ci            case MTLReadWriteTextureTierNone:
1849cb93a386Sopenharmony_ci                writer->appendString("readWriteTextureSupport", "tierNone");
1850cb93a386Sopenharmony_ci                break;
1851cb93a386Sopenharmony_ci            default:
1852cb93a386Sopenharmony_ci                writer->appendString("readWriteTextureSupport", "unknown");
1853cb93a386Sopenharmony_ci                break;
1854cb93a386Sopenharmony_ci        }
1855cb93a386Sopenharmony_ci        switch (fDevice.argumentBuffersSupport) {
1856cb93a386Sopenharmony_ci            case MTLArgumentBuffersTier1:
1857cb93a386Sopenharmony_ci                writer->appendString("argumentBuffersSupport", "tier1");
1858cb93a386Sopenharmony_ci                break;
1859cb93a386Sopenharmony_ci            case MTLArgumentBuffersTier2:
1860cb93a386Sopenharmony_ci                writer->appendString("argumentBuffersSupport", "tier2");
1861cb93a386Sopenharmony_ci                break;
1862cb93a386Sopenharmony_ci            default:
1863cb93a386Sopenharmony_ci                writer->appendString("argumentBuffersSupport", "unknown");
1864cb93a386Sopenharmony_ci                break;
1865cb93a386Sopenharmony_ci        }
1866cb93a386Sopenharmony_ci    }
1867cb93a386Sopenharmony_ci    if (@available(macOS 10.14, iOS 12.0, *)) {
1868cb93a386Sopenharmony_ci        writer->appendU64("maxArgumentBufferSamplerCount", fDevice.maxArgumentBufferSamplerCount);
1869cb93a386Sopenharmony_ci    }
1870cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_IOS
1871cb93a386Sopenharmony_ci    if (@available(iOS 13.0, *)) {
1872cb93a386Sopenharmony_ci        writer->appendU64("sparseTileSizeInBytes", fDevice.sparseTileSizeInBytes);
1873cb93a386Sopenharmony_ci    }
1874cb93a386Sopenharmony_ci#endif
1875cb93a386Sopenharmony_ci    writer->endObject();
1876cb93a386Sopenharmony_ci
1877cb93a386Sopenharmony_ci    writer->appendString("queue", fQueue.label.UTF8String);
1878cb93a386Sopenharmony_ci    writer->appendBool("disconnected", fDisconnected);
1879cb93a386Sopenharmony_ci
1880cb93a386Sopenharmony_ci    writer->endObject();
1881cb93a386Sopenharmony_ci}
1882cb93a386Sopenharmony_ci#endif
1883cb93a386Sopenharmony_ci
1884cb93a386Sopenharmony_ciGR_NORETAIN_END
1885