xref: /aosp_15_r20/external/skia/src/gpu/graphite/UploadBufferManager.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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