blob: b559bfc33aba28cc8b92724cb2d88cc7da353790 [file] [log] [blame]
Chris Dalton8ed7a8d2021-03-31 10:40:29 -06001/*
2 * Copyright 2021 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#ifndef GrVertexChunkArray_DEFINED
9#define GrVertexChunkArray_DEFINED
10
11#include "include/private/SkNoncopyable.h"
12#include "include/private/SkTArray.h"
13#include "src/gpu/GrBuffer.h"
14#include "src/gpu/GrVertexWriter.h"
15#include "src/gpu/ops/GrMeshDrawOp.h"
16
17// Represents a chunk of vertex data. Use with GrVertexChunkArray and GrVertexChunkBuilder. We write
18// the data out in chunks when we don't start out knowing exactly how many vertices (or instances)
19// we will end up writing.
20struct GrVertexChunk {
21 sk_sp<const GrBuffer> fBuffer;
Chris Dalton82007f52021-04-20 00:45:50 -060022 int fCount = 0;
23 int fBase; // baseVertex or baseInstance, depending on the use case.
Chris Dalton8ed7a8d2021-03-31 10:40:29 -060024};
25
26// Represents an array of GrVertexChunks.
27//
28// We only preallocate 1 chunk because if the array needs to grow, then we're also allocating a
29// brand new GPU buffer anyway.
30using GrVertexChunkArray = SkSTArray<1, GrVertexChunk>;
31
32// Builds a GrVertexChunkArray. The provided Target must not be used externally throughout the
33// entire lifetime of this object.
34class GrVertexChunkBuilder : SkNoncopyable {
35public:
36 GrVertexChunkBuilder(GrMeshDrawOp::Target* target, GrVertexChunkArray* chunks, size_t stride,
37 int minVerticesPerChunk)
38 : fTarget(target)
39 , fChunks(chunks)
40 , fStride(stride)
41 , fMinVerticesPerChunk(minVerticesPerChunk) {
42 SkASSERT(fMinVerticesPerChunk > 0);
43 }
44
45 ~GrVertexChunkBuilder() {
46 if (!fChunks->empty()) {
47 fTarget->putBackVertices(fCurrChunkVertexCapacity - fCurrChunkVertexCount, fStride);
Chris Dalton82007f52021-04-20 00:45:50 -060048 fChunks->back().fCount = fCurrChunkVertexCount;
Chris Dalton8ed7a8d2021-03-31 10:40:29 -060049 }
50 }
51
52 // Appends 'count' contiguous vertices. These vertices are not guaranteed to be contiguous with
53 // previous or future calls to appendVertices.
54 SK_ALWAYS_INLINE GrVertexWriter appendVertices(int count) {
55 SkASSERT(count > 0);
56 if (fCurrChunkVertexCount + count > fCurrChunkVertexCapacity && !this->allocChunk(count)) {
Chris Dalton8447f132021-05-21 15:54:23 -060057 SkDEBUGCODE(fLastAppendAmount = 0;)
Chris Dalton8ed7a8d2021-03-31 10:40:29 -060058 return {nullptr};
59 }
60 SkASSERT(fCurrChunkVertexCount + count <= fCurrChunkVertexCapacity);
61 fCurrChunkVertexCount += count;
Chris Dalton8447f132021-05-21 15:54:23 -060062 SkDEBUGCODE(fLastAppendAmount = count;)
Chris Dalton8ed7a8d2021-03-31 10:40:29 -060063 return std::exchange(fCurrChunkVertexWriter,
64 fCurrChunkVertexWriter.makeOffset(fStride * count));
65 }
66
67 SK_ALWAYS_INLINE GrVertexWriter appendVertex() { return this->appendVertices(1); }
68
Chris Dalton8447f132021-05-21 15:54:23 -060069 // Pops the most recent 'count' contiguous vertices. Since there is no guarantee of contiguity
70 // between appends, 'count' may be no larger than the most recent call to appendVertices().
71 void popVertices(int count) {
72 SkASSERT(count <= fLastAppendAmount);
73 SkASSERT(fLastAppendAmount <= fCurrChunkVertexCount);
74 SkASSERT(count >= 0);
75 fCurrChunkVertexCount -= count;
76 fCurrChunkVertexWriter = fCurrChunkVertexWriter.makeOffset(fStride * -count);
77 SkDEBUGCODE(fLastAppendAmount -= count;)
78 }
79
Chris Dalton8ed7a8d2021-03-31 10:40:29 -060080private:
81 bool allocChunk(int minCount) {
82 if (!fChunks->empty()) {
83 // No need to put back vertices; the buffer is full.
Chris Dalton82007f52021-04-20 00:45:50 -060084 fChunks->back().fCount = fCurrChunkVertexCount;
Chris Dalton8ed7a8d2021-03-31 10:40:29 -060085 }
86 fCurrChunkVertexCount = 0;
87 GrVertexChunk* chunk = &fChunks->push_back();
Chris Dalton1c933f82021-05-20 19:25:53 -060088 int minAllocCount = std::max(minCount, fMinVerticesPerChunk);
89 fCurrChunkVertexWriter = {fTarget->makeVertexSpaceAtLeast(fStride, minAllocCount,
90 minAllocCount, &chunk->fBuffer,
Chris Dalton82007f52021-04-20 00:45:50 -060091 &chunk->fBase,
Chris Dalton8ed7a8d2021-03-31 10:40:29 -060092 &fCurrChunkVertexCapacity)};
93 if (!fCurrChunkVertexWriter || !chunk->fBuffer || fCurrChunkVertexCapacity < minCount) {
94 SkDebugf("WARNING: Failed to allocate vertex buffer for GrVertexChunk.\n");
95 fChunks->pop_back();
96 SkASSERT(fCurrChunkVertexCount == 0);
97 fCurrChunkVertexCapacity = 0;
98 return false;
99 }
100 fMinVerticesPerChunk *= 2;
101 return true;
102 }
103
104 GrMeshDrawOp::Target* const fTarget;
105 GrVertexChunkArray* const fChunks;
106 const size_t fStride;
Chris Dalton1c933f82021-05-20 19:25:53 -0600107 int fMinVerticesPerChunk;
Chris Dalton8ed7a8d2021-03-31 10:40:29 -0600108
109 GrVertexWriter fCurrChunkVertexWriter;
110 int fCurrChunkVertexCount = 0;
111 int fCurrChunkVertexCapacity = 0;
Chris Dalton8447f132021-05-21 15:54:23 -0600112
113 SkDEBUGCODE(int fLastAppendAmount = 0;)
Chris Dalton8ed7a8d2021-03-31 10:40:29 -0600114};
115
116#endif