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