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