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