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 NSUInteger options = 0; 39 if (@available(macOS 10.11, iOS 9.0, *)) { 40 if (fIsDynamic) { 41#ifdef SK_BUILD_FOR_MAC 42 options |= MTLResourceStorageModeManaged; 43#else 44 options |= MTLResourceStorageModeShared; 45#endif 46 } else { 47 options |= MTLResourceStorageModePrivate; 48 } 49 } 50#ifdef SK_BUILD_FOR_MAC 51 // Mac requires 4-byte alignment for copies so we need 52 // to ensure we have space for the extra data 53 size = SkAlign4(size); 54#endif 55 fMtlBuffer = size == 0 ? nil : 56 [gpu->device() newBufferWithLength: size 57 options: options]; 58 this->registerWithCache(SkBudgeted::kYes); 59 VALIDATE(); 60} 61 62GrMtlBuffer::~GrMtlBuffer() { 63 SkASSERT(fMtlBuffer == nil); 64 SkASSERT(fMappedBuffer == nil); 65 SkASSERT(fMapPtr == nullptr); 66} 67 68bool GrMtlBuffer::onUpdateData(const void* src, size_t srcInBytes) { 69 if (!fIsDynamic) { 70 if (fMtlBuffer == nil) { 71 return false; 72 } 73 if (srcInBytes > fMtlBuffer.length) { 74 return false; 75 } 76 } 77 VALIDATE(); 78 79 this->internalMap(srcInBytes); 80 if (fMapPtr == nil) { 81 return false; 82 } 83 SkASSERT(fMappedBuffer); 84 if (!fIsDynamic) { 85 SkASSERT(SkAlign4(srcInBytes) == fMappedBuffer.length); 86 } 87 memcpy(fMapPtr, src, srcInBytes); 88 this->internalUnmap(srcInBytes); 89 90 VALIDATE(); 91 return true; 92} 93 94inline GrMtlGpu* GrMtlBuffer::mtlGpu() const { 95 SkASSERT(!this->wasDestroyed()); 96 return static_cast<GrMtlGpu*>(this->getGpu()); 97} 98 99void GrMtlBuffer::onAbandon() { 100 fMtlBuffer = nil; 101 fMappedBuffer = nil; 102 fMapPtr = nullptr; 103 VALIDATE(); 104 INHERITED::onAbandon(); 105} 106 107void GrMtlBuffer::onRelease() { 108 if (!this->wasDestroyed()) { 109 VALIDATE(); 110 fMtlBuffer = nil; 111 fMappedBuffer = nil; 112 fMapPtr = nullptr; 113 VALIDATE(); 114 } 115 INHERITED::onRelease(); 116} 117 118void GrMtlBuffer::internalMap(size_t sizeInBytes) { 119 if (this->wasDestroyed()) { 120 return; 121 } 122 VALIDATE(); 123 SkASSERT(!this->isMapped()); 124 if (fIsDynamic) { 125 fMappedBuffer = fMtlBuffer; 126 fMapPtr = static_cast<char*>(fMtlBuffer.contents) + fOffset; 127 } else { 128 SkASSERT(fMtlBuffer); 129 SkASSERT(fMappedBuffer == nil); 130 NSUInteger options = 0; 131 if (@available(macOS 10.11, iOS 9.0, *)) { 132 options |= MTLResourceStorageModeShared; 133 } 134#ifdef SK_BUILD_FOR_MAC 135 // Mac requires 4-byte alignment for copies so we pad this out 136 sizeInBytes = SkAlign4(sizeInBytes); 137#endif 138 fMappedBuffer = 139 [this->mtlGpu()->device() newBufferWithLength: sizeInBytes 140 options: options]; 141 fMapPtr = fMappedBuffer.contents; 142 } 143 VALIDATE(); 144} 145 146void GrMtlBuffer::internalUnmap(size_t sizeInBytes) { 147 SkASSERT(fMtlBuffer); 148 if (this->wasDestroyed()) { 149 return; 150 } 151 VALIDATE(); 152 SkASSERT(this->isMapped()); 153 if (fMtlBuffer == nil) { 154 fMappedBuffer = nil; 155 fMapPtr = nullptr; 156 return; 157 } 158#ifdef SK_BUILD_FOR_MAC 159 // In both cases the size needs to be 4-byte aligned on Mac 160 sizeInBytes = SkAlign4(sizeInBytes); 161#endif 162 if (fIsDynamic) { 163#ifdef SK_BUILD_FOR_MAC 164 SkASSERT(0 == (fOffset & 0x3)); // should be 4-byte aligned 165 [fMtlBuffer didModifyRange: NSMakeRange(fOffset, sizeInBytes)]; 166#endif 167 } else { 168 GrMtlCommandBuffer* cmdBuffer = this->mtlGpu()->commandBuffer(); 169 id<MTLBlitCommandEncoder> blitCmdEncoder = cmdBuffer->getBlitCommandEncoder(); 170 [blitCmdEncoder copyFromBuffer: fMappedBuffer 171 sourceOffset: 0 172 toBuffer: fMtlBuffer 173 destinationOffset: 0 174 size: sizeInBytes]; 175 } 176 fMappedBuffer = nil; 177 fMapPtr = nullptr; 178} 179 180void GrMtlBuffer::onMap() { 181 this->internalMap(this->size()); 182} 183 184void GrMtlBuffer::onUnmap() { 185 this->internalUnmap(this->size()); 186} 187 188#ifdef SK_DEBUG 189void GrMtlBuffer::validate() const { 190 SkASSERT(fMtlBuffer == nil || 191 this->intendedType() == GrGpuBufferType::kVertex || 192 this->intendedType() == GrGpuBufferType::kIndex || 193 this->intendedType() == GrGpuBufferType::kXferCpuToGpu || 194 this->intendedType() == GrGpuBufferType::kXferGpuToCpu); 195 SkASSERT(fMappedBuffer == nil || fMtlBuffer == nil || 196 fMappedBuffer.length <= fMtlBuffer.length); 197} 198#endif 199