1/* 2 * Copyright 2018 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "include/private/GrTypesPriv.h" 9#include "src/gpu/GrGpuResourcePriv.h" 10#include "src/gpu/mtl/GrMtlBuffer.h" 11#include "src/gpu/mtl/GrMtlCommandBuffer.h" 12#include "src/gpu/mtl/GrMtlGpu.h" 13 14#if !__has_feature(objc_arc) 15#error This file must be compiled with Arc. Use -fobjc-arc flag 16#endif 17 18#ifdef SK_DEBUG 19#define VALIDATE() this->validate() 20#else 21#define VALIDATE() do {} while(false) 22#endif 23 24sk_sp<GrMtlBuffer> GrMtlBuffer::Make(GrMtlGpu* gpu, size_t size, GrGpuBufferType intendedType, 25 GrAccessPattern accessPattern, const void* data) { 26 sk_sp<GrMtlBuffer> buffer(new GrMtlBuffer(gpu, size, intendedType, accessPattern)); 27 if (data && !buffer->onUpdateData(data, size)) { 28 return nullptr; 29 } 30 return buffer; 31} 32 33GrMtlBuffer::GrMtlBuffer(GrMtlGpu* gpu, size_t size, GrGpuBufferType intendedType, 34 GrAccessPattern accessPattern) 35 : INHERITED(gpu, size, intendedType, accessPattern) 36 , fIsDynamic(accessPattern != kStatic_GrAccessPattern) 37 , fOffset(0) { 38 // In most cases, we'll allocate dynamic buffers when we map them, below. 39 if (!fIsDynamic) { 40 NSUInteger options = 0; 41 if (@available(macOS 10.11, iOS 9.0, *)) { 42 options |= MTLResourceStorageModePrivate; 43 } 44 fMtlBuffer = size == 0 ? nil : 45 [gpu->device() newBufferWithLength: size 46 options: options]; 47 } 48 this->registerWithCache(SkBudgeted::kYes); 49 VALIDATE(); 50} 51 52GrMtlBuffer::~GrMtlBuffer() { 53 SkASSERT(fMtlBuffer == nil); 54 SkASSERT(fMappedBuffer == nil); 55 SkASSERT(fMapPtr == nullptr); 56} 57 58void GrMtlBuffer::bind() { 59 SkASSERT(fIsDynamic && GrGpuBufferType::kXferGpuToCpu == this->intendedType()); 60 fMtlBuffer = this->mtlGpu()->resourceProvider().getDynamicBuffer(this->size(), &fOffset); 61} 62 63bool GrMtlBuffer::onUpdateData(const void* src, size_t srcInBytes) { 64 if (!fIsDynamic) { 65 if (fMtlBuffer == nil) { 66 return false; 67 } 68 if (srcInBytes > fMtlBuffer.length) { 69 return false; 70 } 71 } 72 VALIDATE(); 73 74 this->internalMap(srcInBytes); 75 if (fMapPtr == nil) { 76 return false; 77 } 78 SkASSERT(fMappedBuffer); 79 if (!fIsDynamic) { 80 SkASSERT(srcInBytes == fMappedBuffer.length); 81 } 82 memcpy(fMapPtr, src, srcInBytes); 83 this->internalUnmap(srcInBytes); 84 85 VALIDATE(); 86 return true; 87} 88 89inline GrMtlGpu* GrMtlBuffer::mtlGpu() const { 90 SkASSERT(!this->wasDestroyed()); 91 return static_cast<GrMtlGpu*>(this->getGpu()); 92} 93 94void GrMtlBuffer::onAbandon() { 95 fMtlBuffer = nil; 96 fMappedBuffer = nil; 97 fMapPtr = nullptr; 98 VALIDATE(); 99 INHERITED::onAbandon(); 100} 101 102void GrMtlBuffer::onRelease() { 103 if (!this->wasDestroyed()) { 104 VALIDATE(); 105 fMtlBuffer = nil; 106 fMappedBuffer = nil; 107 fMapPtr = nullptr; 108 VALIDATE(); 109 } 110 INHERITED::onRelease(); 111} 112 113void GrMtlBuffer::internalMap(size_t sizeInBytes) { 114 if (this->wasDestroyed()) { 115 return; 116 } 117 VALIDATE(); 118 SkASSERT(!this->isMapped()); 119 if (fIsDynamic) { 120 if (GrGpuBufferType::kXferGpuToCpu != this->intendedType()) { 121 fMtlBuffer = this->mtlGpu()->resourceProvider().getDynamicBuffer(sizeInBytes, &fOffset); 122 } 123 fMappedBuffer = fMtlBuffer; 124 fMapPtr = static_cast<char*>(fMtlBuffer.contents) + fOffset; 125 } else { 126 SkASSERT(fMtlBuffer); 127 SkASSERT(fMappedBuffer == nil); 128 NSUInteger options = 0; 129 if (@available(macOS 10.11, iOS 9.0, *)) { 130 options |= MTLResourceStorageModeShared; 131 } 132 fMappedBuffer = 133 [this->mtlGpu()->device() newBufferWithLength: sizeInBytes 134 options: options]; 135 fMapPtr = fMappedBuffer.contents; 136 } 137 VALIDATE(); 138} 139 140void GrMtlBuffer::internalUnmap(size_t sizeInBytes) { 141 SkASSERT(fMtlBuffer); 142 if (this->wasDestroyed()) { 143 return; 144 } 145 VALIDATE(); 146 SkASSERT(this->isMapped()); 147 if (fMtlBuffer == nil) { 148 fMappedBuffer = nil; 149 fMapPtr = nullptr; 150 return; 151 } 152 if (fIsDynamic) { 153#ifdef SK_BUILD_FOR_MAC 154 // TODO: need to make sure offset and size have valid alignments. 155 [fMtlBuffer didModifyRange: NSMakeRange(fOffset, sizeInBytes)]; 156#endif 157 } else { 158 GrMtlCommandBuffer* cmdBuffer = this->mtlGpu()->commandBuffer(); 159 id<MTLBlitCommandEncoder> blitCmdEncoder = cmdBuffer->getBlitCommandEncoder(); 160 [blitCmdEncoder copyFromBuffer: fMappedBuffer 161 sourceOffset: 0 162 toBuffer: fMtlBuffer 163 destinationOffset: 0 164 size: sizeInBytes]; 165 } 166 fMappedBuffer = nil; 167 fMapPtr = nullptr; 168} 169 170void GrMtlBuffer::onMap() { 171 this->internalMap(this->size()); 172} 173 174void GrMtlBuffer::onUnmap() { 175 this->internalUnmap(this->size()); 176} 177 178#ifdef SK_DEBUG 179void GrMtlBuffer::validate() const { 180 SkASSERT(fMtlBuffer == nil || 181 this->intendedType() == GrGpuBufferType::kVertex || 182 this->intendedType() == GrGpuBufferType::kIndex || 183 this->intendedType() == GrGpuBufferType::kXferCpuToGpu || 184 this->intendedType() == GrGpuBufferType::kXferGpuToCpu); 185 SkASSERT(fMappedBuffer == nil || fMtlBuffer == nil || 186 fMappedBuffer.length <= fMtlBuffer.length); 187} 188#endif 189