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