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