1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2022 Google LLC
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 "src/gpu/graphite/UploadBufferManager.h"
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/Recording.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAlign.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTFitsIn.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Buffer.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Caps.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/CommandBuffer.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/RecordingPriv.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ResourceProvider.h"
18*c8dee2aaSAndroid Build Coastguard Worker
19*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::graphite {
20*c8dee2aaSAndroid Build Coastguard Worker
21*c8dee2aaSAndroid Build Coastguard Worker static constexpr size_t kReusedBufferSize = 64 << 10; // 64 KB
22*c8dee2aaSAndroid Build Coastguard Worker
UploadBufferManager(ResourceProvider * resourceProvider,const Caps * caps)23*c8dee2aaSAndroid Build Coastguard Worker UploadBufferManager::UploadBufferManager(ResourceProvider* resourceProvider,
24*c8dee2aaSAndroid Build Coastguard Worker const Caps* caps)
25*c8dee2aaSAndroid Build Coastguard Worker : fResourceProvider(resourceProvider)
26*c8dee2aaSAndroid Build Coastguard Worker , fMinAlignment(SkTo<uint32_t>(caps->requiredTransferBufferAlignment())) {}
27*c8dee2aaSAndroid Build Coastguard Worker
~UploadBufferManager()28*c8dee2aaSAndroid Build Coastguard Worker UploadBufferManager::~UploadBufferManager() {}
29*c8dee2aaSAndroid Build Coastguard Worker
getTextureUploadWriter(size_t requiredBytes,size_t requiredAlignment)30*c8dee2aaSAndroid Build Coastguard Worker std::tuple<TextureUploadWriter, BindBufferInfo> UploadBufferManager::getTextureUploadWriter(
31*c8dee2aaSAndroid Build Coastguard Worker size_t requiredBytes, size_t requiredAlignment) {
32*c8dee2aaSAndroid Build Coastguard Worker auto[bufferMapPtr, bindInfo] = this->makeBindInfo(requiredBytes,
33*c8dee2aaSAndroid Build Coastguard Worker requiredAlignment,
34*c8dee2aaSAndroid Build Coastguard Worker "TextureUploadBuffer");
35*c8dee2aaSAndroid Build Coastguard Worker if (!bufferMapPtr) {
36*c8dee2aaSAndroid Build Coastguard Worker return {TextureUploadWriter(), BindBufferInfo()};
37*c8dee2aaSAndroid Build Coastguard Worker }
38*c8dee2aaSAndroid Build Coastguard Worker
39*c8dee2aaSAndroid Build Coastguard Worker return {TextureUploadWriter(bufferMapPtr, requiredBytes), bindInfo};
40*c8dee2aaSAndroid Build Coastguard Worker }
41*c8dee2aaSAndroid Build Coastguard Worker
makeBindInfo(size_t requiredBytes,size_t requiredAlignment,std::string_view label)42*c8dee2aaSAndroid Build Coastguard Worker std::tuple<void* /*mappedPtr*/, BindBufferInfo> UploadBufferManager::makeBindInfo(
43*c8dee2aaSAndroid Build Coastguard Worker size_t requiredBytes, size_t requiredAlignment, std::string_view label) {
44*c8dee2aaSAndroid Build Coastguard Worker if (!SkTFitsIn<uint32_t>(requiredBytes)) {
45*c8dee2aaSAndroid Build Coastguard Worker return {nullptr, BindBufferInfo()};
46*c8dee2aaSAndroid Build Coastguard Worker }
47*c8dee2aaSAndroid Build Coastguard Worker
48*c8dee2aaSAndroid Build Coastguard Worker uint32_t requiredAlignment32 = std::max(SkTo<uint32_t>(requiredAlignment), fMinAlignment);
49*c8dee2aaSAndroid Build Coastguard Worker uint32_t requiredBytes32 = SkAlignTo(SkTo<uint32_t>(requiredBytes), requiredAlignment32);
50*c8dee2aaSAndroid Build Coastguard Worker if (requiredBytes32 > kReusedBufferSize) {
51*c8dee2aaSAndroid Build Coastguard Worker // Create a dedicated buffer for this request.
52*c8dee2aaSAndroid Build Coastguard Worker sk_sp<Buffer> buffer = fResourceProvider->findOrCreateBuffer(requiredBytes32,
53*c8dee2aaSAndroid Build Coastguard Worker BufferType::kXferCpuToGpu,
54*c8dee2aaSAndroid Build Coastguard Worker AccessPattern::kHostVisible,
55*c8dee2aaSAndroid Build Coastguard Worker std::move(label));
56*c8dee2aaSAndroid Build Coastguard Worker void* bufferMapPtr = buffer ? buffer->map() : nullptr;
57*c8dee2aaSAndroid Build Coastguard Worker if (!bufferMapPtr) {
58*c8dee2aaSAndroid Build Coastguard Worker // Unlike [Draw|Static]BufferManager, the UploadManager does not track if any buffer
59*c8dee2aaSAndroid Build Coastguard Worker // mapping has failed. This is because it's common for uploads to be scoped to a
60*c8dee2aaSAndroid Build Coastguard Worker // specific image creation. In that case, the image can be returned as null to signal a
61*c8dee2aaSAndroid Build Coastguard Worker // very isolated failure instead of taking down the entire Recording. For the other
62*c8dee2aaSAndroid Build Coastguard Worker // managers, failures to map buffers creates unrecoverable scenarios.
63*c8dee2aaSAndroid Build Coastguard Worker return {nullptr, BindBufferInfo()};
64*c8dee2aaSAndroid Build Coastguard Worker }
65*c8dee2aaSAndroid Build Coastguard Worker
66*c8dee2aaSAndroid Build Coastguard Worker BindBufferInfo bindInfo;
67*c8dee2aaSAndroid Build Coastguard Worker bindInfo.fBuffer = buffer.get();
68*c8dee2aaSAndroid Build Coastguard Worker bindInfo.fOffset = 0;
69*c8dee2aaSAndroid Build Coastguard Worker bindInfo.fSize = requiredBytes32;
70*c8dee2aaSAndroid Build Coastguard Worker
71*c8dee2aaSAndroid Build Coastguard Worker fUsedBuffers.push_back(std::move(buffer));
72*c8dee2aaSAndroid Build Coastguard Worker return {bufferMapPtr, bindInfo};
73*c8dee2aaSAndroid Build Coastguard Worker }
74*c8dee2aaSAndroid Build Coastguard Worker
75*c8dee2aaSAndroid Build Coastguard Worker // Try to reuse an already-allocated buffer.
76*c8dee2aaSAndroid Build Coastguard Worker fReusedBufferOffset = SkAlignTo(fReusedBufferOffset, requiredAlignment32);
77*c8dee2aaSAndroid Build Coastguard Worker if (fReusedBuffer && requiredBytes32 > fReusedBuffer->size() - fReusedBufferOffset) {
78*c8dee2aaSAndroid Build Coastguard Worker fUsedBuffers.push_back(std::move(fReusedBuffer));
79*c8dee2aaSAndroid Build Coastguard Worker }
80*c8dee2aaSAndroid Build Coastguard Worker
81*c8dee2aaSAndroid Build Coastguard Worker if (!fReusedBuffer) {
82*c8dee2aaSAndroid Build Coastguard Worker fReusedBuffer = fResourceProvider->findOrCreateBuffer(kReusedBufferSize,
83*c8dee2aaSAndroid Build Coastguard Worker BufferType::kXferCpuToGpu,
84*c8dee2aaSAndroid Build Coastguard Worker AccessPattern::kHostVisible,
85*c8dee2aaSAndroid Build Coastguard Worker std::move(label));
86*c8dee2aaSAndroid Build Coastguard Worker fReusedBufferOffset = 0;
87*c8dee2aaSAndroid Build Coastguard Worker if (!fReusedBuffer || !fReusedBuffer->map()) {
88*c8dee2aaSAndroid Build Coastguard Worker fReusedBuffer = nullptr;
89*c8dee2aaSAndroid Build Coastguard Worker return {nullptr, BindBufferInfo()};
90*c8dee2aaSAndroid Build Coastguard Worker }
91*c8dee2aaSAndroid Build Coastguard Worker }
92*c8dee2aaSAndroid Build Coastguard Worker
93*c8dee2aaSAndroid Build Coastguard Worker BindBufferInfo bindInfo;
94*c8dee2aaSAndroid Build Coastguard Worker bindInfo.fBuffer = fReusedBuffer.get();
95*c8dee2aaSAndroid Build Coastguard Worker bindInfo.fOffset = fReusedBufferOffset;
96*c8dee2aaSAndroid Build Coastguard Worker bindInfo.fSize = requiredBytes32;
97*c8dee2aaSAndroid Build Coastguard Worker
98*c8dee2aaSAndroid Build Coastguard Worker void* bufferMapPtr = fReusedBuffer->map();
99*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(bufferMapPtr); // Should have been validated when it was created
100*c8dee2aaSAndroid Build Coastguard Worker bufferMapPtr = SkTAddOffset<void>(bufferMapPtr, fReusedBufferOffset);
101*c8dee2aaSAndroid Build Coastguard Worker
102*c8dee2aaSAndroid Build Coastguard Worker fReusedBufferOffset += requiredBytes32;
103*c8dee2aaSAndroid Build Coastguard Worker
104*c8dee2aaSAndroid Build Coastguard Worker return {bufferMapPtr, bindInfo};
105*c8dee2aaSAndroid Build Coastguard Worker }
106*c8dee2aaSAndroid Build Coastguard Worker
transferToRecording(Recording * recording)107*c8dee2aaSAndroid Build Coastguard Worker void UploadBufferManager::transferToRecording(Recording* recording) {
108*c8dee2aaSAndroid Build Coastguard Worker for (sk_sp<Buffer>& buffer : fUsedBuffers) {
109*c8dee2aaSAndroid Build Coastguard Worker buffer->unmap();
110*c8dee2aaSAndroid Build Coastguard Worker recording->priv().addResourceRef(std::move(buffer));
111*c8dee2aaSAndroid Build Coastguard Worker }
112*c8dee2aaSAndroid Build Coastguard Worker fUsedBuffers.clear();
113*c8dee2aaSAndroid Build Coastguard Worker
114*c8dee2aaSAndroid Build Coastguard Worker if (fReusedBuffer) {
115*c8dee2aaSAndroid Build Coastguard Worker fReusedBuffer->unmap();
116*c8dee2aaSAndroid Build Coastguard Worker recording->priv().addResourceRef(std::move(fReusedBuffer));
117*c8dee2aaSAndroid Build Coastguard Worker }
118*c8dee2aaSAndroid Build Coastguard Worker }
119*c8dee2aaSAndroid Build Coastguard Worker
transferToCommandBuffer(CommandBuffer * commandBuffer)120*c8dee2aaSAndroid Build Coastguard Worker void UploadBufferManager::transferToCommandBuffer(CommandBuffer* commandBuffer) {
121*c8dee2aaSAndroid Build Coastguard Worker for (sk_sp<Buffer>& buffer : fUsedBuffers) {
122*c8dee2aaSAndroid Build Coastguard Worker buffer->unmap();
123*c8dee2aaSAndroid Build Coastguard Worker commandBuffer->trackResource(std::move(buffer));
124*c8dee2aaSAndroid Build Coastguard Worker }
125*c8dee2aaSAndroid Build Coastguard Worker fUsedBuffers.clear();
126*c8dee2aaSAndroid Build Coastguard Worker
127*c8dee2aaSAndroid Build Coastguard Worker if (fReusedBuffer) {
128*c8dee2aaSAndroid Build Coastguard Worker fReusedBuffer->unmap();
129*c8dee2aaSAndroid Build Coastguard Worker commandBuffer->trackResource(std::move(fReusedBuffer));
130*c8dee2aaSAndroid Build Coastguard Worker }
131*c8dee2aaSAndroid Build Coastguard Worker }
132*c8dee2aaSAndroid Build Coastguard Worker
133*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::graphite
134