blob: be813572c4c58fdf00074d0ff7373dae11730fc8 [file] [log] [blame]
Timothy Liang49528b62018-08-02 14:18:37 -04001/*
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 "GrMtlBuffer.h"
9#include "GrMtlGpu.h"
10#include "GrGpuResourcePriv.h"
11#include "GrTypesPriv.h"
12
13#ifdef SK_DEBUG
14#define VALIDATE() this->validate()
15#else
16#define VALIDATE() do {} while(false)
17#endif
18
Brian Salomonae64c192019-02-05 09:41:37 -050019sk_sp<GrMtlBuffer> GrMtlBuffer::Make(GrMtlGpu* gpu, size_t size, GrGpuBufferType intendedType,
Brian Salomon12d22642019-01-29 14:38:50 -050020 GrAccessPattern accessPattern, const void* data) {
Timothy Liang49528b62018-08-02 14:18:37 -040021 sk_sp<GrMtlBuffer> buffer(new GrMtlBuffer(gpu, size, intendedType, accessPattern));
22 if (data && !buffer->onUpdateData(data, size)) {
23 return nullptr;
24 }
Brian Salomon12d22642019-01-29 14:38:50 -050025 return buffer;
Timothy Liang49528b62018-08-02 14:18:37 -040026}
27
Brian Salomonae64c192019-02-05 09:41:37 -050028GrMtlBuffer::GrMtlBuffer(GrMtlGpu* gpu, size_t size, GrGpuBufferType intendedType,
Timothy Liang49528b62018-08-02 14:18:37 -040029 GrAccessPattern accessPattern)
30 : INHERITED(gpu, size, intendedType, accessPattern)
Timothy Liang49528b62018-08-02 14:18:37 -040031 , fIsDynamic(accessPattern == kDynamic_GrAccessPattern) {
Timothy Liang49528b62018-08-02 14:18:37 -040032 // TODO: We are treating all buffers as static access since we don't have an implementation to
33 // synchronize gpu and cpu access of a resource yet. See comments in GrMtlBuffer::internalMap()
34 // and interalUnmap() for more details.
35 fIsDynamic = false;
Timothy Liang4e679842018-08-08 14:21:12 -040036
37 // The managed resource mode is only available for macOS. iOS should use shared.
Greg Danield742b6b2019-02-05 15:15:31 -050038 fMtlBuffer = size == 0 ? nil :
Timothy Liang4e679842018-08-08 14:21:12 -040039 [gpu->device() newBufferWithLength: size
40 options: !fIsDynamic ? MTLResourceStorageModePrivate
41#ifdef SK_BUILD_FOR_MAC
42 : MTLResourceStorageModeManaged];
43#else
44 : MTLResourceStorageModeShared];
45#endif
46 this->registerWithCache(SkBudgeted::kYes);
Timothy Liang9047c062018-08-03 10:00:50 -040047 VALIDATE();
Timothy Liang49528b62018-08-02 14:18:37 -040048}
49
50GrMtlBuffer::~GrMtlBuffer() {
51 SkASSERT(fMtlBuffer == nil);
52 SkASSERT(fMappedBuffer == nil);
53 SkASSERT(fMapPtr == nullptr);
54}
55
56bool GrMtlBuffer::onUpdateData(const void* src, size_t srcInBytes) {
57 if (fMtlBuffer == nil) {
58 return false;
59 }
60 if (srcInBytes > fMtlBuffer.length) {
61 return false;
62 }
Timothy Liang49528b62018-08-02 14:18:37 -040063 VALIDATE();
64
65 this->internalMap(srcInBytes);
66 if (fMapPtr == nil) {
67 return false;
68 }
69 SkASSERT(fMappedBuffer);
70 SkASSERT(srcInBytes == fMappedBuffer.length);
71 memcpy(fMapPtr, src, srcInBytes);
72 this->internalUnmap(srcInBytes);
73
74 VALIDATE();
75 return true;
76}
77
78inline GrMtlGpu* GrMtlBuffer::mtlGpu() const {
79 SkASSERT(!this->wasDestroyed());
80 return static_cast<GrMtlGpu*>(this->getGpu());
81}
82
83void GrMtlBuffer::onAbandon() {
84 fMtlBuffer = nil;
85 fMappedBuffer = nil;
86 fMapPtr = nullptr;
87 VALIDATE();
88 INHERITED::onAbandon();
89}
90
91void GrMtlBuffer::onRelease() {
92 if (!this->wasDestroyed()) {
93 VALIDATE();
94 fMtlBuffer = nil;
95 fMappedBuffer = nil;
96 fMapPtr = nullptr;
97 VALIDATE();
98 }
99 INHERITED::onRelease();
100}
101
102void GrMtlBuffer::internalMap(size_t sizeInBytes) {
103 SkASSERT(fMtlBuffer);
104 if (this->wasDestroyed()) {
105 return;
106 }
107 VALIDATE();
108 SkASSERT(!this->isMapped());
109 if (fIsDynamic) {
110 // TODO: We will want to decide if we need to create a new buffer here in order to avoid
111 // possibly invalidating a buffer which is being used by the gpu.
112 fMappedBuffer = fMtlBuffer;
113 fMapPtr = fMappedBuffer.contents;
114 } else {
115 // TODO: We can't ensure that map will only be called once on static access buffers until
116 // we actually enable dynamic access.
117 // SkASSERT(fMappedBuffer == nil);
118 fMappedBuffer =
119 [this->mtlGpu()->device() newBufferWithLength: sizeInBytes
Timothy Liang4e679842018-08-08 14:21:12 -0400120#ifdef SK_BUILD_FOR_MAC
Timothy Liang49528b62018-08-02 14:18:37 -0400121 options: MTLResourceStorageModeManaged];
Timothy Liang4e679842018-08-08 14:21:12 -0400122#else
123 options: MTLResourceStorageModeShared];
124#endif
Timothy Liang49528b62018-08-02 14:18:37 -0400125 fMapPtr = fMappedBuffer.contents;
126 }
127 VALIDATE();
128}
129
130void GrMtlBuffer::internalUnmap(size_t sizeInBytes) {
131 SkASSERT(fMtlBuffer);
132 if (this->wasDestroyed()) {
133 return;
134 }
135 VALIDATE();
136 SkASSERT(this->isMapped());
137 if (fMtlBuffer == nil) {
138 fMappedBuffer = nil;
139 fMapPtr = nullptr;
140 return;
141 }
Timothy Liang4e679842018-08-08 14:21:12 -0400142#ifdef SK_BUILD_FOR_MAC
Timothy Liang49528b62018-08-02 14:18:37 -0400143 // TODO: by calling didModifyRange here we invalidate the buffer. This will cause problems for
144 // dynamic access buffers if they are being used by the gpu.
145 [fMappedBuffer didModifyRange: NSMakeRange(0, sizeInBytes)];
Timothy Liang4e679842018-08-08 14:21:12 -0400146#endif
Timothy Liang49528b62018-08-02 14:18:37 -0400147 if (!fIsDynamic) {
148 id<MTLBlitCommandEncoder> blitCmdEncoder =
149 [this->mtlGpu()->commandBuffer() blitCommandEncoder];
150 [blitCmdEncoder copyFromBuffer: fMappedBuffer
151 sourceOffset: 0
152 toBuffer: fMtlBuffer
153 destinationOffset: 0
154 size: sizeInBytes];
155 [blitCmdEncoder endEncoding];
156 }
157 fMappedBuffer = nil;
158 fMapPtr = nullptr;
159}
160
161void GrMtlBuffer::onMap() {
162 this->internalMap(fMtlBuffer.length);
163}
164
165void GrMtlBuffer::onUnmap() {
166 this->internalUnmap(fMappedBuffer.length);
167}
168
169#ifdef SK_DEBUG
170void GrMtlBuffer::validate() const {
171 SkASSERT(fMtlBuffer == nil ||
Brian Salomon95548f62019-02-05 16:07:56 -0500172 this->intendedType() == GrGpuBufferType::kVertex ||
173 this->intendedType() == GrGpuBufferType::kIndex ||
174 this->intendedType() == GrGpuBufferType::kXferCpuToGpu ||
175 this->intendedType() == GrGpuBufferType::kXferGpuToCpu);
Timothy Liang49528b62018-08-02 14:18:37 -0400176 SkASSERT(fMappedBuffer == nil || fMtlBuffer == nil ||
177 fMappedBuffer.length <= fMtlBuffer.length);
178 SkASSERT(fIsDynamic == false); // TODO: implement synchronization to allow dynamic access.
179}
180#endif