Line data Source code
1 : /* Copyright (C) 2022 Wildfire Games.
2 : * This file is part of 0 A.D.
3 : *
4 : * 0 A.D. is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 2 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * 0 A.D. is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16 : */
17 :
18 : /*
19 : * Encapsulation of backend buffers with batching and sharing.
20 : */
21 :
22 : #ifndef INCLUDED_VERTEXBUFFER
23 : #define INCLUDED_VERTEXBUFFER
24 :
25 : #include "renderer/backend/IBuffer.h"
26 : #include "renderer/backend/IDeviceCommandContext.h"
27 :
28 : #include <memory>
29 : #include <vector>
30 :
31 : /**
32 : * CVertexBuffer: encapsulation of backend buffers, also supplying
33 : * some additional functionality for sharing buffers between multiple objects.
34 : *
35 : * The class can be used in two modes, depending on the usage parameter:
36 : *
37 : * Static buffer: Call Allocate() with backingStore = nullptr. Then call
38 : * UpdateChunkVertices() with any pointer - the data will be immediately copied
39 : * to the buffer. This should be used for vertex data that rarely changes.
40 : *
41 : * Dynamic buffer: Call Allocate() with backingStore pointing
42 : * at some memory that will remain valid for the lifetime of the CVertexBuffer.
43 : * This should be used for vertex data that may change every frame.
44 : * Rendering is expected to occur in two phases:
45 : * - "Prepare" phase:
46 : * If this chunk is going to be used for rendering during the next rendering phase,
47 : * you must call PrepareForRendering().
48 : * If the vertex data in backingStore has been modified since the last uploading phase,
49 : * you must call UpdateChunkVertices().
50 : * - "Upload" phase:
51 : * UploadedIfNeeded() can be called (multiple times). The vertex data will be uploaded
52 : * to the GPU if necessary.
53 : * It is okay to have multiple prepare/upload cycles per frame (though slightly less
54 : * efficient), but they must occur sequentially.
55 : */
56 : class CVertexBuffer
57 : {
58 : NONCOPYABLE(CVertexBuffer);
59 :
60 : public:
61 :
62 : // VBChunk: describes a portion of this vertex buffer
63 : struct VBChunk
64 : {
65 : // Owning (parent) vertex buffer
66 : CVertexBuffer* m_Owner;
67 : // Start index of this chunk in owner
68 : size_t m_Index;
69 : // Number of vertices used by chunk
70 : size_t m_Count;
71 : // If UseStreaming() is true, points at the data for this chunk
72 : void* m_BackingStore;
73 :
74 : // If true, the backend buffer is not consistent with the chunk's
75 : // backing store (and will need to be re-uploaded before rendering with
76 : // this chunk).
77 : bool m_Dirty;
78 :
79 : // If true, we have been told this chunk is going to be used for
80 : // rendering in the next uploading phase and will need to be uploaded
81 : bool m_Needed;
82 :
83 : private:
84 : // Only CVertexBuffer can construct/delete these
85 : // (Other people should use g_VBMan.AllocateChunk)
86 : friend class CVertexBuffer;
87 7 : VBChunk() {}
88 7 : ~VBChunk() {}
89 : };
90 :
91 : public:
92 : // constructor, destructor
93 : CVertexBuffer(
94 : const char* name, const size_t vertexSize,
95 : const Renderer::Backend::IBuffer::Type type, const bool dynamic);
96 : CVertexBuffer(
97 : const char* name, const size_t vertexSize,
98 : const Renderer::Backend::IBuffer::Type type, const bool dynamic,
99 : const size_t maximumBufferSize);
100 : ~CVertexBuffer();
101 :
102 : void UploadIfNeeded(Renderer::Backend::IDeviceCommandContext* deviceCommandContext);
103 :
104 : /// Make the vertex data available for the next usage.
105 : void PrepareForRendering(VBChunk* chunk);
106 :
107 : /// Update vertex data for given chunk. Transfers the provided data to the actual OpenGL vertex buffer.
108 : void UpdateChunkVertices(VBChunk* chunk, void* data);
109 :
110 : size_t GetVertexSize() const { return m_VertexSize; }
111 : size_t GetBytesReserved() const;
112 : size_t GetBytesAllocated() const;
113 :
114 : /// Returns true if this vertex buffer is compatible with the specified vertex type and intended usage.
115 : bool CompatibleVertexType(
116 : const size_t vertexSize, const Renderer::Backend::IBuffer::Type type,
117 : const bool dynamic) const;
118 :
119 : void DumpStatus() const;
120 :
121 : /**
122 : * Given the usage flags of a buffer that has been (or will be) allocated:
123 : *
124 : * If true, we assume the buffer is going to be modified on every frame,
125 : * so we will re-upload the entire buffer every frame using glMapBuffer.
126 : * This requires the buffer's owner to hold onto its backing store.
127 : *
128 : * If false, we assume it will change rarely, and use direct upload to
129 : * update it incrementally. The backing store can be freed to save memory.
130 : */
131 : static bool UseStreaming(const bool dynamic);
132 :
133 0 : Renderer::Backend::IBuffer* GetBuffer() { return m_Buffer.get(); }
134 :
135 : private:
136 : friend class CVertexBufferManager; // allow allocate only via CVertexBufferManager
137 :
138 : /// Try to allocate a buffer of given number of vertices (each of given size),
139 : /// and with the given type - return null if no free chunks available
140 : VBChunk* Allocate(
141 : const size_t vertexSize, const size_t numberOfVertices,
142 : const Renderer::Backend::IBuffer::Type type, const bool dynamic,
143 : void* backingStore);
144 : /// Return given chunk to this buffer
145 : void Release(VBChunk* chunk);
146 :
147 : /// Vertex size of this vertex buffer
148 : size_t m_VertexSize;
149 : /// Number of vertices of above size in this buffer
150 : size_t m_MaxVertices;
151 : /// List of free chunks in this buffer
152 : std::vector<VBChunk*> m_FreeList;
153 : /// List of allocated chunks
154 : std::vector<VBChunk*> m_AllocList;
155 : /// Available free vertices - total of all free vertices in the free list
156 : size_t m_FreeVertices;
157 :
158 : std::unique_ptr<Renderer::Backend::IBuffer> m_Buffer;
159 :
160 : bool m_HasNeededChunks;
161 : };
162 :
163 : #endif // INCLUDED_VERTEXBUFFER
|