1 /*
2 * Copyright 2023 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/ganesh/GrMeshBuffers.h"
9
10 #include "include/core/SkData.h"
11 #include "include/core/SkMesh.h"
12 #include "include/gpu/ganesh/GrDirectContext.h"
13 #include "include/gpu/ganesh/SkMeshGanesh.h"
14 #include "include/private/base/SkAssert.h"
15 #include "include/private/gpu/ganesh/GrTypesPriv.h"
16 #include "src/core/SkMeshPriv.h"
17 #include "src/gpu/ganesh/GrCaps.h"
18 #include "src/gpu/ganesh/GrDirectContextPriv.h"
19 #include "src/gpu/ganesh/GrDrawingManager.h"
20 #include "src/gpu/ganesh/GrGpu.h"
21 #include "src/gpu/ganesh/GrGpuBuffer.h"
22 #include "src/gpu/ganesh/GrResourceCache.h"
23 #include "src/gpu/ganesh/GrResourceProvider.h"
24 #include "src/gpu/ganesh/GrStagingBufferManager.h"
25
26 #include <cstring>
27 #include <utility>
28
~GrMeshBuffer()29 template <typename Base, GrGpuBufferType Type> GrMeshBuffer<Base, Type>::~GrMeshBuffer() {
30 GrResourceCache::ReturnResourceFromThread(std::move(fBuffer), fContextID);
31 }
32
33 template <typename Base, GrGpuBufferType Type>
Make(GrDirectContext * dc,const void * data,size_t size)34 sk_sp<Base> GrMeshBuffer<Base, Type>::Make(GrDirectContext* dc, const void* data, size_t size) {
35 SkASSERT(dc);
36
37 sk_sp<GrGpuBuffer> buffer = dc->priv().resourceProvider()->createBuffer(
38 size,
39 Type,
40 kStatic_GrAccessPattern,
41 data ? GrResourceProvider::ZeroInit::kNo : GrResourceProvider::ZeroInit::kYes);
42 if (!buffer) {
43 return nullptr;
44 }
45
46 if (data && !buffer->updateData(data, 0, size, /*preserve=*/false)) {
47 return nullptr;
48 }
49
50 auto result = new GrMeshBuffer;
51 result->fBuffer = std::move(buffer);
52 result->fContextID = dc->directContextID();
53 return sk_sp<Base>(result);
54 }
55
56 template <typename Base, GrGpuBufferType Type>
onUpdate(GrDirectContext * dc,const void * data,size_t offset,size_t size)57 bool GrMeshBuffer<Base, Type>::onUpdate(GrDirectContext* dc,
58 const void* data,
59 size_t offset,
60 size_t size) {
61 if (!dc || dc != fBuffer->getContext()) {
62 return false;
63 }
64 SkASSERT(!dc->abandoned()); // If dc is abandoned then fBuffer->getContext() should be null.
65
66 if (!dc->priv().caps()->transferFromBufferToBufferSupport()) {
67 auto ownedData = SkData::MakeWithCopy(data, size);
68 dc->priv().drawingManager()->newBufferUpdateTask(
69 std::move(ownedData), fBuffer, offset);
70 return true;
71 }
72
73 sk_sp<GrGpuBuffer> tempBuffer;
74 size_t tempOffset = 0;
75 if (auto* sbm = dc->priv().getGpu()->stagingBufferManager()) {
76 auto alignment = dc->priv().caps()->transferFromBufferToBufferAlignment();
77 auto [sliceBuffer, sliceOffset, ptr] = sbm->allocateStagingBufferSlice(size, alignment);
78 if (sliceBuffer) {
79 std::memcpy(ptr, data, size);
80 tempBuffer.reset(SkRef(sliceBuffer));
81 tempOffset = sliceOffset;
82 }
83 }
84
85 if (!tempBuffer) {
86 tempBuffer = dc->priv().resourceProvider()->createBuffer(size,
87 GrGpuBufferType::kXferCpuToGpu,
88 kDynamic_GrAccessPattern,
89 GrResourceProvider::ZeroInit::kNo);
90 if (!tempBuffer) {
91 return false;
92 }
93 if (!tempBuffer->updateData(data, 0, size, /*preserve=*/false)) {
94 return false;
95 }
96 }
97
98 dc->priv().drawingManager()->newBufferTransferTask(
99 std::move(tempBuffer), tempOffset, fBuffer, offset, size);
100
101 return true;
102 }
103
104 namespace SkMeshes {
MakeIndexBuffer(GrDirectContext * dc,const void * data,size_t size)105 sk_sp<SkMesh::IndexBuffer> MakeIndexBuffer(GrDirectContext* dc, const void* data, size_t size) {
106 if (!dc) {
107 // Fallback to a CPU buffer.
108 return MakeIndexBuffer(data, size);
109 }
110 return SkMeshPriv::GaneshIndexBuffer::Make(dc, data, size);
111 }
112
CopyIndexBuffer(GrDirectContext * dc,sk_sp<SkMesh::IndexBuffer> src)113 sk_sp<SkMesh::IndexBuffer> CopyIndexBuffer(GrDirectContext* dc, sk_sp<SkMesh::IndexBuffer> src) {
114 if (!src) {
115 return nullptr;
116 }
117 auto* ib = static_cast<SkMeshPriv::IB*>(src.get());
118 const void* data = ib->peek();
119 if (!data) {
120 return nullptr;
121 }
122 if (!dc) {
123 return MakeIndexBuffer(data, ib->size());
124 }
125 return MakeIndexBuffer(dc, data, ib->size());
126 }
127
MakeVertexBuffer(GrDirectContext * dc,const void * data,size_t size)128 sk_sp<SkMesh::VertexBuffer> MakeVertexBuffer(GrDirectContext* dc, const void* data, size_t size) {
129 if (!dc) {
130 return MakeVertexBuffer(data, size);
131 }
132 return SkMeshPriv::GaneshVertexBuffer::Make(dc, data, size);
133 }
134
CopyVertexBuffer(GrDirectContext * dc,sk_sp<SkMesh::VertexBuffer> src)135 sk_sp<SkMesh::VertexBuffer> CopyVertexBuffer(GrDirectContext* dc, sk_sp<SkMesh::VertexBuffer> src) {
136 if (!src) {
137 return nullptr;
138 }
139 auto* vb = static_cast<SkMeshPriv::VB*>(src.get());
140 const void* data = vb->peek();
141 if (!data) {
142 return nullptr;
143 }
144 if (!dc) {
145 return MakeVertexBuffer(data, vb->size());
146 }
147 return MakeVertexBuffer(dc, data, vb->size());
148 }
149 } // namespace SkMeshes
150