xref: /aosp_15_r20/external/skia/src/gpu/ganesh/mtl/GrMtlBuffer.mm (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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