blob: febde5127a791d42601dd8567f80a03d356f0b36 [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;
22 int fVertexCount = 0;
23 int fBaseVertex;
24};
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);
48 fChunks->back().fVertexCount = fCurrChunkVertexCount;
49 }
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)) {
57 return {nullptr};
58 }
59 SkASSERT(fCurrChunkVertexCount + count <= fCurrChunkVertexCapacity);
60 fCurrChunkVertexCount += count;
61 return std::exchange(fCurrChunkVertexWriter,
62 fCurrChunkVertexWriter.makeOffset(fStride * count));
63 }
64
65 SK_ALWAYS_INLINE GrVertexWriter appendVertex() { return this->appendVertices(1); }
66
67private:
68 bool allocChunk(int minCount) {
69 if (!fChunks->empty()) {
70 // No need to put back vertices; the buffer is full.
71 fChunks->back().fVertexCount = fCurrChunkVertexCount;
72 }
73 fCurrChunkVertexCount = 0;
74 GrVertexChunk* chunk = &fChunks->push_back();
75 fCurrChunkVertexWriter = {fTarget->makeVertexSpaceAtLeast(fStride,
76 fMinVerticesPerChunk * minCount,
77 fMinVerticesPerChunk * minCount,
78 &chunk->fBuffer,
79 &chunk->fBaseVertex,
80 &fCurrChunkVertexCapacity)};
81 if (!fCurrChunkVertexWriter || !chunk->fBuffer || fCurrChunkVertexCapacity < minCount) {
82 SkDebugf("WARNING: Failed to allocate vertex buffer for GrVertexChunk.\n");
83 fChunks->pop_back();
84 SkASSERT(fCurrChunkVertexCount == 0);
85 fCurrChunkVertexCapacity = 0;
86 return false;
87 }
88 fMinVerticesPerChunk *= 2;
89 return true;
90 }
91
92 GrMeshDrawOp::Target* const fTarget;
93 GrVertexChunkArray* const fChunks;
94 const size_t fStride;
95 size_t fMinVerticesPerChunk;
96
97 GrVertexWriter fCurrChunkVertexWriter;
98 int fCurrChunkVertexCount = 0;
99 int fCurrChunkVertexCapacity = 0;
100};
101
102#endif