1*c8dee2aaSAndroid Build Coastguard Worker/* 2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2018 Google Inc. 3*c8dee2aaSAndroid Build Coastguard Worker * 4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be 5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file. 6*c8dee2aaSAndroid Build Coastguard Worker */ 7*c8dee2aaSAndroid Build Coastguard Worker 8*c8dee2aaSAndroid Build Coastguard Worker#include "include/private/gpu/ganesh/GrTypesPriv.h" 9*c8dee2aaSAndroid Build Coastguard Worker#include "src/gpu/ganesh/GrGpuResourcePriv.h" 10*c8dee2aaSAndroid Build Coastguard Worker#include "src/gpu/ganesh/GrStagingBufferManager.h" 11*c8dee2aaSAndroid Build Coastguard Worker#include "src/gpu/ganesh/mtl/GrMtlBuffer.h" 12*c8dee2aaSAndroid Build Coastguard Worker#include "src/gpu/ganesh/mtl/GrMtlCommandBuffer.h" 13*c8dee2aaSAndroid Build Coastguard Worker#include "src/gpu/ganesh/mtl/GrMtlGpu.h" 14*c8dee2aaSAndroid Build Coastguard Worker 15*c8dee2aaSAndroid Build Coastguard Worker#if !__has_feature(objc_arc) 16*c8dee2aaSAndroid Build Coastguard Worker#error This file must be compiled with Arc. Use -fobjc-arc flag 17*c8dee2aaSAndroid Build Coastguard Worker#endif 18*c8dee2aaSAndroid Build Coastguard Worker 19*c8dee2aaSAndroid Build Coastguard Worker#ifdef SK_DEBUG 20*c8dee2aaSAndroid Build Coastguard Worker#define VALIDATE() this->validate() 21*c8dee2aaSAndroid Build Coastguard Worker#else 22*c8dee2aaSAndroid Build Coastguard Worker#define VALIDATE() do {} while(false) 23*c8dee2aaSAndroid Build Coastguard Worker#endif 24*c8dee2aaSAndroid Build Coastguard Worker 25*c8dee2aaSAndroid Build Coastguard WorkerGR_NORETAIN_BEGIN 26*c8dee2aaSAndroid Build Coastguard Worker 27*c8dee2aaSAndroid Build Coastguard Worker#ifdef SK_ENABLE_MTL_DEBUG_INFO 28*c8dee2aaSAndroid Build Coastguard WorkerNSString* kBufferTypeNames[kGrGpuBufferTypeCount] = { 29*c8dee2aaSAndroid Build Coastguard Worker @"Vertex", 30*c8dee2aaSAndroid Build Coastguard Worker @"Index", 31*c8dee2aaSAndroid Build Coastguard Worker @"Indirect", 32*c8dee2aaSAndroid Build Coastguard Worker @"Xfer CPU to GPU", 33*c8dee2aaSAndroid Build Coastguard Worker @"Xfer GPU to CPU", 34*c8dee2aaSAndroid Build Coastguard Worker @"Uniform", 35*c8dee2aaSAndroid Build Coastguard Worker}; 36*c8dee2aaSAndroid Build Coastguard Worker#endif 37*c8dee2aaSAndroid Build Coastguard Worker 38*c8dee2aaSAndroid Build Coastguard Workersk_sp<GrMtlBuffer> GrMtlBuffer::Make(GrMtlGpu* gpu, 39*c8dee2aaSAndroid Build Coastguard Worker size_t size, 40*c8dee2aaSAndroid Build Coastguard Worker GrGpuBufferType intendedType, 41*c8dee2aaSAndroid Build Coastguard Worker GrAccessPattern accessPattern) { 42*c8dee2aaSAndroid Build Coastguard Worker return sk_sp<GrMtlBuffer>(new GrMtlBuffer(gpu, 43*c8dee2aaSAndroid Build Coastguard Worker size, 44*c8dee2aaSAndroid Build Coastguard Worker intendedType, 45*c8dee2aaSAndroid Build Coastguard Worker accessPattern, 46*c8dee2aaSAndroid Build Coastguard Worker /*label=*/"MakeMtlBuffer")); 47*c8dee2aaSAndroid Build Coastguard Worker} 48*c8dee2aaSAndroid Build Coastguard Worker 49*c8dee2aaSAndroid Build Coastguard WorkerGrMtlBuffer::GrMtlBuffer(GrMtlGpu* gpu, size_t size, GrGpuBufferType intendedType, 50*c8dee2aaSAndroid Build Coastguard Worker GrAccessPattern accessPattern, std::string_view label) 51*c8dee2aaSAndroid Build Coastguard Worker : INHERITED(gpu, size, intendedType, accessPattern, label) 52*c8dee2aaSAndroid Build Coastguard Worker , fIsDynamic(accessPattern != kStatic_GrAccessPattern) { 53*c8dee2aaSAndroid Build Coastguard Worker NSUInteger options = 0; 54*c8dee2aaSAndroid Build Coastguard Worker if (@available(macOS 10.11, iOS 9.0, tvOS 9.0, *)) { 55*c8dee2aaSAndroid Build Coastguard Worker if (fIsDynamic) { 56*c8dee2aaSAndroid Build Coastguard Worker#ifdef SK_BUILD_FOR_MAC 57*c8dee2aaSAndroid Build Coastguard Worker if (gpu->mtlCaps().isMac()) { 58*c8dee2aaSAndroid Build Coastguard Worker options |= MTLResourceStorageModeManaged; 59*c8dee2aaSAndroid Build Coastguard Worker } else { 60*c8dee2aaSAndroid Build Coastguard Worker options |= MTLResourceStorageModeShared; 61*c8dee2aaSAndroid Build Coastguard Worker } 62*c8dee2aaSAndroid Build Coastguard Worker#else 63*c8dee2aaSAndroid Build Coastguard Worker options |= MTLResourceStorageModeShared; 64*c8dee2aaSAndroid Build Coastguard Worker#endif 65*c8dee2aaSAndroid Build Coastguard Worker } else { 66*c8dee2aaSAndroid Build Coastguard Worker options |= MTLResourceStorageModePrivate; 67*c8dee2aaSAndroid Build Coastguard Worker } 68*c8dee2aaSAndroid Build Coastguard Worker } 69*c8dee2aaSAndroid Build Coastguard Worker 70*c8dee2aaSAndroid Build Coastguard Worker size = SkAlignTo(size, gpu->mtlCaps().getMinBufferAlignment()); 71*c8dee2aaSAndroid Build Coastguard Worker fMtlBuffer = size == 0 ? nil : 72*c8dee2aaSAndroid Build Coastguard Worker [gpu->device() newBufferWithLength: size 73*c8dee2aaSAndroid Build Coastguard Worker options: options]; 74*c8dee2aaSAndroid Build Coastguard Worker#ifdef SK_ENABLE_MTL_DEBUG_INFO 75*c8dee2aaSAndroid Build Coastguard Worker fMtlBuffer.label = kBufferTypeNames[(int)intendedType]; 76*c8dee2aaSAndroid Build Coastguard Worker#endif 77*c8dee2aaSAndroid Build Coastguard Worker this->registerWithCache(skgpu::Budgeted::kYes); 78*c8dee2aaSAndroid Build Coastguard Worker VALIDATE(); 79*c8dee2aaSAndroid Build Coastguard Worker} 80*c8dee2aaSAndroid Build Coastguard Worker 81*c8dee2aaSAndroid Build Coastguard WorkerGrMtlBuffer::~GrMtlBuffer() { 82*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fMtlBuffer); 83*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fMapPtr); 84*c8dee2aaSAndroid Build Coastguard Worker} 85*c8dee2aaSAndroid Build Coastguard Worker 86*c8dee2aaSAndroid Build Coastguard Workerbool GrMtlBuffer::onUpdateData(const void *src, size_t offset, size_t size, bool preserve) { 87*c8dee2aaSAndroid Build Coastguard Worker if (fIsDynamic) { 88*c8dee2aaSAndroid Build Coastguard Worker this->internalMap(); 89*c8dee2aaSAndroid Build Coastguard Worker if (!fMapPtr) { 90*c8dee2aaSAndroid Build Coastguard Worker return false; 91*c8dee2aaSAndroid Build Coastguard Worker } 92*c8dee2aaSAndroid Build Coastguard Worker memcpy(SkTAddOffset<void>(fMapPtr, offset), src, size); 93*c8dee2aaSAndroid Build Coastguard Worker this->internalUnmap(offset, size); 94*c8dee2aaSAndroid Build Coastguard Worker return true; 95*c8dee2aaSAndroid Build Coastguard Worker } 96*c8dee2aaSAndroid Build Coastguard Worker // Update via transfer buffer. 97*c8dee2aaSAndroid Build Coastguard Worker 98*c8dee2aaSAndroid Build Coastguard Worker // We have to respect the transfer alignment. So we may transfer some extra bytes before and 99*c8dee2aaSAndroid Build Coastguard Worker // after the region to be updated. 100*c8dee2aaSAndroid Build Coastguard Worker size_t transferAlignment = this->getGpu()->caps()->transferFromBufferToBufferAlignment(); 101*c8dee2aaSAndroid Build Coastguard Worker size_t r = offset%transferAlignment; 102*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!preserve || r == 0); // We can't push extra bytes when preserving. 103*c8dee2aaSAndroid Build Coastguard Worker 104*c8dee2aaSAndroid Build Coastguard Worker offset -= r; 105*c8dee2aaSAndroid Build Coastguard Worker size_t transferSize = SkAlignTo(size + r, transferAlignment); 106*c8dee2aaSAndroid Build Coastguard Worker 107*c8dee2aaSAndroid Build Coastguard Worker GrStagingBufferManager::Slice slice; 108*c8dee2aaSAndroid Build Coastguard Worker slice = this->mtlGpu()->stagingBufferManager()->allocateStagingBufferSlice( 109*c8dee2aaSAndroid Build Coastguard Worker transferSize, this->mtlGpu()->mtlCaps().getMinBufferAlignment()); 110*c8dee2aaSAndroid Build Coastguard Worker if (!slice.fBuffer) { 111*c8dee2aaSAndroid Build Coastguard Worker return false; 112*c8dee2aaSAndroid Build Coastguard Worker } 113*c8dee2aaSAndroid Build Coastguard Worker memcpy(SkTAddOffset<void>(slice.fOffsetMapPtr, r), src, size); 114*c8dee2aaSAndroid Build Coastguard Worker 115*c8dee2aaSAndroid Build Coastguard Worker GrMtlCommandBuffer* cmdBuffer = this->mtlGpu()->commandBuffer(); 116*c8dee2aaSAndroid Build Coastguard Worker id<MTLBlitCommandEncoder> GR_NORETAIN blitCmdEncoder = cmdBuffer->getBlitCommandEncoder(); 117*c8dee2aaSAndroid Build Coastguard Worker if (!blitCmdEncoder) { 118*c8dee2aaSAndroid Build Coastguard Worker return false; 119*c8dee2aaSAndroid Build Coastguard Worker } 120*c8dee2aaSAndroid Build Coastguard Worker GrMtlBuffer* mtlBuffer = static_cast<GrMtlBuffer*>(slice.fBuffer); 121*c8dee2aaSAndroid Build Coastguard Worker id<MTLBuffer> transferBuffer = mtlBuffer->mtlBuffer(); 122*c8dee2aaSAndroid Build Coastguard Worker [blitCmdEncoder copyFromBuffer: transferBuffer 123*c8dee2aaSAndroid Build Coastguard Worker sourceOffset: slice.fOffset 124*c8dee2aaSAndroid Build Coastguard Worker toBuffer: fMtlBuffer 125*c8dee2aaSAndroid Build Coastguard Worker destinationOffset: offset 126*c8dee2aaSAndroid Build Coastguard Worker size: transferSize]; 127*c8dee2aaSAndroid Build Coastguard Worker return true; 128*c8dee2aaSAndroid Build Coastguard Worker} 129*c8dee2aaSAndroid Build Coastguard Worker 130*c8dee2aaSAndroid Build Coastguard Workerinline GrMtlGpu* GrMtlBuffer::mtlGpu() const { 131*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!this->wasDestroyed()); 132*c8dee2aaSAndroid Build Coastguard Worker return static_cast<GrMtlGpu*>(this->getGpu()); 133*c8dee2aaSAndroid Build Coastguard Worker} 134*c8dee2aaSAndroid Build Coastguard Worker 135*c8dee2aaSAndroid Build Coastguard Workervoid GrMtlBuffer::onAbandon() { 136*c8dee2aaSAndroid Build Coastguard Worker fMtlBuffer = nil; 137*c8dee2aaSAndroid Build Coastguard Worker fMapPtr = nullptr; 138*c8dee2aaSAndroid Build Coastguard Worker VALIDATE(); 139*c8dee2aaSAndroid Build Coastguard Worker INHERITED::onAbandon(); 140*c8dee2aaSAndroid Build Coastguard Worker} 141*c8dee2aaSAndroid Build Coastguard Worker 142*c8dee2aaSAndroid Build Coastguard Workervoid GrMtlBuffer::onRelease() { 143*c8dee2aaSAndroid Build Coastguard Worker if (!this->wasDestroyed()) { 144*c8dee2aaSAndroid Build Coastguard Worker VALIDATE(); 145*c8dee2aaSAndroid Build Coastguard Worker fMtlBuffer = nil; 146*c8dee2aaSAndroid Build Coastguard Worker fMapPtr = nullptr; 147*c8dee2aaSAndroid Build Coastguard Worker VALIDATE(); 148*c8dee2aaSAndroid Build Coastguard Worker } 149*c8dee2aaSAndroid Build Coastguard Worker INHERITED::onRelease(); 150*c8dee2aaSAndroid Build Coastguard Worker} 151*c8dee2aaSAndroid Build Coastguard Worker 152*c8dee2aaSAndroid Build Coastguard Workervoid GrMtlBuffer::internalMap() { 153*c8dee2aaSAndroid Build Coastguard Worker if (fIsDynamic) { 154*c8dee2aaSAndroid Build Coastguard Worker VALIDATE(); 155*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!this->isMapped()); 156*c8dee2aaSAndroid Build Coastguard Worker fMapPtr = static_cast<char*>(fMtlBuffer.contents); 157*c8dee2aaSAndroid Build Coastguard Worker VALIDATE(); 158*c8dee2aaSAndroid Build Coastguard Worker } 159*c8dee2aaSAndroid Build Coastguard Worker} 160*c8dee2aaSAndroid Build Coastguard Worker 161*c8dee2aaSAndroid Build Coastguard Workervoid GrMtlBuffer::internalUnmap(size_t writtenOffset, size_t writtenSize) { 162*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fMtlBuffer); 163*c8dee2aaSAndroid Build Coastguard Worker if (fIsDynamic) { 164*c8dee2aaSAndroid Build Coastguard Worker VALIDATE(); 165*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(writtenOffset + writtenSize <= this->size()); 166*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->isMapped()); 167*c8dee2aaSAndroid Build Coastguard Worker#ifdef SK_BUILD_FOR_MAC 168*c8dee2aaSAndroid Build Coastguard Worker if (this->mtlGpu()->mtlCaps().isMac() && writtenSize) { 169*c8dee2aaSAndroid Build Coastguard Worker // We should never write to this type of buffer on the CPU. 170*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->intendedType() != GrGpuBufferType::kXferGpuToCpu); 171*c8dee2aaSAndroid Build Coastguard Worker [fMtlBuffer didModifyRange: NSMakeRange(writtenOffset, writtenSize)]; 172*c8dee2aaSAndroid Build Coastguard Worker } 173*c8dee2aaSAndroid Build Coastguard Worker#endif 174*c8dee2aaSAndroid Build Coastguard Worker fMapPtr = nullptr; 175*c8dee2aaSAndroid Build Coastguard Worker } 176*c8dee2aaSAndroid Build Coastguard Worker} 177*c8dee2aaSAndroid Build Coastguard Worker 178*c8dee2aaSAndroid Build Coastguard Workervoid GrMtlBuffer::onMap(MapType) { 179*c8dee2aaSAndroid Build Coastguard Worker this->internalMap(); 180*c8dee2aaSAndroid Build Coastguard Worker} 181*c8dee2aaSAndroid Build Coastguard Worker 182*c8dee2aaSAndroid Build Coastguard Workervoid GrMtlBuffer::onUnmap(MapType type) { 183*c8dee2aaSAndroid Build Coastguard Worker this->internalUnmap(0, type == MapType::kWriteDiscard ? this-> size() : 0); 184*c8dee2aaSAndroid Build Coastguard Worker} 185*c8dee2aaSAndroid Build Coastguard Worker 186*c8dee2aaSAndroid Build Coastguard Workerbool GrMtlBuffer::onClearToZero() { 187*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fMtlBuffer); 188*c8dee2aaSAndroid Build Coastguard Worker GrMtlCommandBuffer* cmdBuffer = this->mtlGpu()->commandBuffer(); 189*c8dee2aaSAndroid Build Coastguard Worker id<MTLBlitCommandEncoder> GR_NORETAIN blitCmdEncoder = cmdBuffer->getBlitCommandEncoder(); 190*c8dee2aaSAndroid Build Coastguard Worker if (!blitCmdEncoder) { 191*c8dee2aaSAndroid Build Coastguard Worker return false; 192*c8dee2aaSAndroid Build Coastguard Worker } 193*c8dee2aaSAndroid Build Coastguard Worker 194*c8dee2aaSAndroid Build Coastguard Worker NSRange range{0, this->size()}; 195*c8dee2aaSAndroid Build Coastguard Worker [blitCmdEncoder fillBuffer: fMtlBuffer range: range value: 0]; 196*c8dee2aaSAndroid Build Coastguard Worker 197*c8dee2aaSAndroid Build Coastguard Worker cmdBuffer->addGrBuffer(sk_ref_sp(this)); 198*c8dee2aaSAndroid Build Coastguard Worker 199*c8dee2aaSAndroid Build Coastguard Worker return true; 200*c8dee2aaSAndroid Build Coastguard Worker} 201*c8dee2aaSAndroid Build Coastguard Worker 202*c8dee2aaSAndroid Build Coastguard Worker#ifdef SK_DEBUG 203*c8dee2aaSAndroid Build Coastguard Workervoid GrMtlBuffer::validate() const { 204*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fMtlBuffer == nil || 205*c8dee2aaSAndroid Build Coastguard Worker this->intendedType() == GrGpuBufferType::kVertex || 206*c8dee2aaSAndroid Build Coastguard Worker this->intendedType() == GrGpuBufferType::kIndex || 207*c8dee2aaSAndroid Build Coastguard Worker this->intendedType() == GrGpuBufferType::kXferCpuToGpu || 208*c8dee2aaSAndroid Build Coastguard Worker this->intendedType() == GrGpuBufferType::kXferGpuToCpu || 209*c8dee2aaSAndroid Build Coastguard Worker this->intendedType() == GrGpuBufferType::kDrawIndirect || 210*c8dee2aaSAndroid Build Coastguard Worker this->intendedType() == GrGpuBufferType::kUniform); 211*c8dee2aaSAndroid Build Coastguard Worker SkASSERT((fMapPtr && fMtlBuffer) || !fMapPtr); 212*c8dee2aaSAndroid Build Coastguard Worker} 213*c8dee2aaSAndroid Build Coastguard Worker#endif 214*c8dee2aaSAndroid Build Coastguard Worker 215*c8dee2aaSAndroid Build Coastguard Workervoid GrMtlBuffer::onSetLabel() { 216*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fMtlBuffer); 217*c8dee2aaSAndroid Build Coastguard Worker if (!this->getLabel().empty()) { 218*c8dee2aaSAndroid Build Coastguard Worker NSString* labelStr = @(this->getLabel().c_str()); 219*c8dee2aaSAndroid Build Coastguard Worker fMtlBuffer.label = [@"_Skia_" stringByAppendingString:labelStr]; 220*c8dee2aaSAndroid Build Coastguard Worker } 221*c8dee2aaSAndroid Build Coastguard Worker} 222*c8dee2aaSAndroid Build Coastguard Worker 223*c8dee2aaSAndroid Build Coastguard WorkerGR_NORETAIN_END 224