1/*
2 * Copyright 2020 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#ifndef GrAutoMapVertexBuffer_DEFINED
9#define GrAutoMapVertexBuffer_DEFINED
10
11#include "include/private/SkNoncopyable.h"
12#include "src/gpu/GrGpuBuffer.h"
13#include "src/gpu/GrOnFlushResourceProvider.h"
14
15// This class automatically allocates and maps a GPU vertex buffer, and polyfills the mapping
16// functionality with a mirror buffer on CPU if it is not supported.
17class GrAutoMapVertexBuffer : SkNoncopyable {
18public:
19 ~GrAutoMapVertexBuffer() {
20 if (this->isMapped()) {
21 this->unmapBuffer();
22 }
23 }
24
25 const GrGpuBuffer* gpuBuffer() const { return fGpuBuffer.get(); }
26 bool isMapped() const { return SkToBool(fData); }
27 void* data() const { SkASSERT(this->isMapped()); return fData; }
28
29 void resetAndMapBuffer(GrOnFlushResourceProvider* onFlushRP, size_t sizeInBytes) {
30 if (this->isMapped()) {
31 this->unmapBuffer();
32 }
33 fGpuBuffer = onFlushRP->makeBuffer(GrGpuBufferType::kVertex, sizeInBytes);
34 if (!fGpuBuffer) {
35 fSizeInBytes = 0;
36 fData = nullptr;
37 return;
38 }
39 fSizeInBytes = sizeInBytes;
40 fData = fGpuBuffer->map();
41 if (!fData) {
42 // Mapping failed. Allocate a mirror buffer on CPU.
43 fData = sk_malloc_throw(fSizeInBytes);
44 }
45 }
46
47 void unmapBuffer() {
48 SkASSERT(this->isMapped());
49 if (fGpuBuffer->isMapped()) {
50 fGpuBuffer->unmap();
51 } else {
52 // fData is a mirror buffer on CPU.
53 fGpuBuffer->updateData(fData, fSizeInBytes);
54 sk_free(fData);
55 }
56 fData = nullptr;
57 }
58
59protected:
60 sk_sp<GrGpuBuffer> fGpuBuffer;
61 size_t fSizeInBytes = 0;
62 void* fData = nullptr;
63};
64
65template<typename T> class GrTAutoMapVertexBuffer : public GrAutoMapVertexBuffer {
66public:
67 T& operator[](int idx) {
68 SkASSERT(this->isMapped());
69 SkASSERT(idx >= 0 && (size_t)idx < fSizeInBytes / sizeof(T));
70 return ((T*)fData)[idx];
71 }
72};
73
74#endif
75