1 /*
2 * Copyright 2021 Google Inc.
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 "experimental/graphite/src/DrawBufferManager.h"
9
10 #include "experimental/graphite/src/Buffer.h"
11 #include "experimental/graphite/src/CommandBuffer.h"
12 #include "experimental/graphite/src/ResourceProvider.h"
13
14 namespace skgpu {
15
16 namespace {
17
18 // TODO: Tune these values on real world data
19 static constexpr size_t kVertexBufferSize = 2 << 10;
20 static constexpr size_t kIndexBufferSize = 2 << 10;
21 static constexpr size_t kUniformBufferSize = 2 << 10;
22
map_offset(BindBufferInfo binding)23 void* map_offset(BindBufferInfo binding) {
24 // DrawBufferManager owns the Buffer, and this is only ever called when we know
25 // it's okay to remove 'const' from the Buffer*
26 return SkTAddOffset<void>(const_cast<Buffer*>(binding.fBuffer)->map(),
27 static_cast<ptrdiff_t>(binding.fOffset));
28 }
29
30 } // anonymous namespace
31
DrawBufferManager(ResourceProvider * resourceProvider,size_t uniformStartAlignment)32 DrawBufferManager::DrawBufferManager(ResourceProvider* resourceProvider,
33 size_t uniformStartAlignment)
34 : fResourceProvider(resourceProvider)
35 , fUniformStartAlignment(uniformStartAlignment) {}
36
~DrawBufferManager()37 DrawBufferManager::~DrawBufferManager() {}
38
can_fit(size_t requestedSize,Buffer * buffer,size_t currentOffset,size_t alignment)39 static bool can_fit(size_t requestedSize,
40 Buffer* buffer,
41 size_t currentOffset,
42 size_t alignment) {
43 size_t startOffset = SkAlignTo(currentOffset, alignment);
44 return requestedSize <= (buffer->size() - startOffset);
45 }
46
getVertexWriter(size_t requiredBytes)47 std::tuple<VertexWriter, BindBufferInfo> DrawBufferManager::getVertexWriter(size_t requiredBytes) {
48 if (!requiredBytes) {
49 return {VertexWriter(), BindBufferInfo()};
50 }
51 if (fCurrentVertexBuffer &&
52 !can_fit(requiredBytes, fCurrentVertexBuffer.get(), fVertexOffset, /*alignment=*/1)) {
53 fUsedBuffers.push_back(std::move(fCurrentVertexBuffer));
54 }
55
56 if (!fCurrentVertexBuffer) {
57 SkASSERT(requiredBytes <= kVertexBufferSize);
58 fCurrentVertexBuffer = fResourceProvider->findOrCreateBuffer(kVertexBufferSize,
59 BufferType::kVertex,
60 PrioritizeGpuReads::kNo);
61 fVertexOffset = 0;
62 if (!fCurrentVertexBuffer) {
63 return {VertexWriter(), BindBufferInfo()};
64 }
65 }
66 BindBufferInfo bindInfo;
67 bindInfo.fBuffer = fCurrentVertexBuffer.get();
68 bindInfo.fOffset = fVertexOffset;
69 fVertexOffset += requiredBytes;
70 return {VertexWriter(map_offset(bindInfo), requiredBytes), bindInfo};
71 }
72
getIndexWriter(size_t requiredBytes)73 std::tuple<IndexWriter, BindBufferInfo> DrawBufferManager::getIndexWriter(size_t requiredBytes) {
74 if (!requiredBytes) {
75 return {IndexWriter(), BindBufferInfo()};
76 }
77 if (fCurrentIndexBuffer &&
78 !can_fit(requiredBytes, fCurrentIndexBuffer.get(), fIndexOffset, /*alignment=*/1)) {
79 fUsedBuffers.push_back(std::move(fCurrentIndexBuffer));
80 }
81
82 if (!fCurrentIndexBuffer) {
83 SkASSERT(requiredBytes <= kIndexBufferSize);
84 fCurrentIndexBuffer = fResourceProvider->findOrCreateBuffer(kIndexBufferSize,
85 BufferType::kIndex,
86 PrioritizeGpuReads::kNo);
87 fIndexOffset = 0;
88 if (!fCurrentIndexBuffer) {
89 return {IndexWriter(), BindBufferInfo()};
90 }
91 }
92 BindBufferInfo bindInfo;
93 bindInfo.fBuffer = fCurrentIndexBuffer.get();
94 bindInfo.fOffset = fIndexOffset;
95 fIndexOffset += requiredBytes;
96 return {IndexWriter(map_offset(bindInfo), requiredBytes), bindInfo};
97 }
98
getUniformWriter(size_t requiredBytes)99 std::tuple<UniformWriter, BindBufferInfo> DrawBufferManager::getUniformWriter(
100 size_t requiredBytes) {
101 if (!requiredBytes) {
102 return {UniformWriter(), BindBufferInfo()};
103 }
104 if (fCurrentUniformBuffer &&
105 !can_fit(requiredBytes,
106 fCurrentUniformBuffer.get(),
107 fUniformOffset,
108 fUniformStartAlignment)) {
109 fUsedBuffers.push_back(std::move(fCurrentUniformBuffer));
110 }
111
112 if (!fCurrentUniformBuffer) {
113 SkASSERT(requiredBytes <= kUniformBufferSize);
114 fCurrentUniformBuffer = fResourceProvider->findOrCreateBuffer(kUniformBufferSize,
115 BufferType::kUniform,
116 PrioritizeGpuReads::kNo);
117 fUniformOffset = 0;
118 if (!fCurrentUniformBuffer) {
119 return {UniformWriter(), BindBufferInfo()};
120 }
121 }
122 fUniformOffset = SkAlignTo(fUniformOffset, fUniformStartAlignment);
123 BindBufferInfo bindInfo;
124 bindInfo.fBuffer = fCurrentUniformBuffer.get();
125 bindInfo.fOffset = fUniformOffset;
126 fUniformOffset += requiredBytes;
127 return {UniformWriter(map_offset(bindInfo), requiredBytes), bindInfo};
128 }
129
transferToCommandBuffer(CommandBuffer * commandBuffer)130 void DrawBufferManager::transferToCommandBuffer(CommandBuffer* commandBuffer) {
131 for (auto& buffer : fUsedBuffers) {
132 buffer->unmap();
133 commandBuffer->trackResource(std::move(buffer));
134 }
135 fUsedBuffers.clear();
136 }
137
138 } // namespace skgpu
139