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