fennec
Loading...
Searching...
No Matches
buffer.h
1// =====================================================================================================================
2// fennec, a free and open source game engine
3// Copyright © 2025 Medusa Slockbower
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <https://www.gnu.org/licenses/>.
17// =====================================================================================================================
18
19#ifndef FENNEC_RENDERERS_OPENGL_LIB_BUFFER_H
20#define FENNEC_RENDERERS_OPENGL_LIB_BUFFER_H
21
22#include <fennec/math/common.h>
23#include <fennec/renderers/opengl/lib/fwd.h>
24#include <fennec/renderers/opengl/lib/enum.h>
25
26namespace fennec
27{
28
29namespace gl
30{
31
32template<GLbitfield FlagsV, GLboolean ImmutableV> using vertex_buffer = buffer<VERTEX, FlagsV, ImmutableV>;
33template<GLbitfield FlagsV, GLboolean ImmutableV> using element_buffer = buffer<ELEMENT, FlagsV, ImmutableV>;
34template<GLbitfield FlagsV, GLboolean ImmutableV> using uniform_buffer = buffer<UNIFORM, FlagsV, ImmutableV>;
35template<GLbitfield FlagsV, GLboolean ImmutableV> using shader_storage_buffer = buffer<SHADER_STORAGE, FlagsV, ImmutableV>;
36template<GLbitfield FlagsV, GLboolean ImmutableV> using query_buffer = buffer<QUERY, FlagsV, ImmutableV>;
37template<GLbitfield FlagsV, GLboolean ImmutableV> using texture_buffer = buffer<TEXTURE, FlagsV, ImmutableV>;
38template<GLbitfield FlagsV, GLboolean ImmutableV> using transform_feedback_buffer = buffer<TRANSFORM_FEEDBACK, FlagsV, ImmutableV>;
39template<GLbitfield FlagsV, GLboolean ImmutableV> using atomic_counter_buffer = buffer<ATOMIC_COUNTER, FlagsV, ImmutableV>;
40template<GLbitfield FlagsV, GLboolean ImmutableV> using parameter_buffer = buffer<PARAMETER, FlagsV, ImmutableV>;
41template<GLbitfield FlagsV, GLboolean ImmutableV> using indirect_draw_buffer = buffer<INDIRECT_DRAW, FlagsV, ImmutableV>;
42template<GLbitfield FlagsV, GLboolean ImmutableV> using indirect_dispatch_buffer = buffer<INDIRECT_DISPATCH, FlagsV, ImmutableV>;
43template<GLbitfield FlagsV, GLboolean ImmutableV> using copy_read_buffer = buffer<COPY_READ, FlagsV, ImmutableV>;
44template<GLbitfield FlagsV, GLboolean ImmutableV> using copy_write_buffer = buffer<COPY_WRITE, FlagsV, ImmutableV>;
45template<GLbitfield FlagsV, GLboolean ImmutableV> using pixel_pack_buffer = buffer<PIXEL_PACK, FlagsV, ImmutableV>;
46template<GLbitfield FlagsV, GLboolean ImmutableV> using pixel_unpack_buffer = buffer<PIXEL_UNPACK, FlagsV, ImmutableV>;
47
48template<GLenum TypeV, GLbitfield FlagsV, GLboolean ImmutableV>
49class buffer {
50
51// HELPER FUNCTIONS ====================================================================================================
52
53private:
54 static constexpr GLenum get_mutable_traits() {
55 GLenum res;
56
57 // Set READ/DRAW/COPY
58 if constexpr (map_read) {
59 res = GL_STREAM_READ;
60 } else if constexpr (map_write) {
61 res = GL_STREAM_DRAW;
62 } else {
63 res = GL_STREAM_COPY;
64 }
65
66 // Set STATIC/DYNAMIC/STREAM
67 if constexpr (client or coherent) {
68 // do nothing
69 } else if constexpr (dynamic or persistent) {
70 res += 6;
71 } else {
72 res += 3;
73 }
74
75 return res;
76 }
77
78
79// CONSTANTS ===========================================================================================================
80
81public:
82 static constexpr GLenum type = TypeV;
83 static constexpr GLboolean immutable = ImmutableV;
84 static constexpr GLbitfield flags = FlagsV;
85 static constexpr GLboolean indexed = type == ATOMIC_COUNTER or type == SHADER_STORAGE or type == TRANSFORM_FEEDBACK or type == UNIFORM;
86 static constexpr GLboolean map_read = flags & READ;
87 static constexpr GLboolean map_write = flags & WRITE;
88 static constexpr GLboolean mapped = map_read or map_write;
89 static constexpr GLboolean dynamic = flags & DYNAMIC;
90 static constexpr GLboolean persistent = flags & PERSISTENT;
91 static constexpr GLboolean coherent = flags & COHERENT;
92 static constexpr GLboolean client = flags & CLIENT;
93 static constexpr GLenum usage = get_mutable_traits();
94
95 static_assert(not persistent or persistent == mapped);
96 static_assert(not coherent or coherent == persistent);
97
98
99// CONSTRUCTORS & ASSIGNMENT ===========================================================================================
100
101 constexpr buffer(const void* data, GLsizeiptr size)
102 : _handle()
103 , _size(size) {
104 glGenBuffers(1, &_handle);
105 start();
106 if constexpr(immutable) {
107 glBufferStorage(type, _size, data, flags);
108 } else {
109 glBufferData(type, _size, data, usage);
110 }
111 }
112
113 constexpr buffer(buffer&& buff) noexcept
114 : _handle(buff)
115 , _size(buff._size)
116 , _mapping(nullptr) {
117 }
118
119 constexpr buffer& operator=(buffer&& buff) noexcept {
120 glDeleteBuffers(1, &_handle);
121 _handle = buff._handle;
122 _size = buff._size;
123 return *this;
124 }
125
126 constexpr buffer(const buffer&) = delete;
127 constexpr buffer& operator=(const buffer&) = delete;
128
129
130// OBJECT FUNCTIONS ====================================================================================================
131
132 constexpr void start() const {
133 glBindBuffer(type, _handle);
134 }
135
136 constexpr void end() const {
137 glBindBuffer(type, NULL);
138 }
139
140 constexpr void bind(GLuint i, GLsizeiptr size = -1, GLintptr offset = 0) {
141 offset = max(offset, GLintptr(0));
142 size = size < 0 ? _size : size;
143 size = min(size, _size - offset);
144 if (size <= 0) return;
145 glBindBufferRange(type, i, _handle, offset, size);
146 }
147
148
149// BASIC BUFFER FUNCTIONS ==============================================================================================
150
151 constexpr void resize(GLsizei size) requires not immutable {
152 unmap();
153 glBufferData(type, _size = size, nullptr, usage);
154 }
155
156 constexpr void* map(GLbitfield access, GLsizeiptr size, GLintptr offset = 0) {
157 if (_mapping) {
158 return _mapping;
159 }
160 offset = max(offset, GLintptr(0));
161 size = size < 0 ? _size : size;
162 size = min(size, _size - offset);
163 if (size <= 0) return nullptr;
164 return _mapping = glMapBufferRange(type, offset, size, _mapflags = access);
165 }
166
167 constexpr void unmap() {
168 glUnmapBuffer(type);
169 _mapping = nullptr;
170 }
171
172 constexpr void clear(GLsizeiptr size = -1, GLintptr offset = 0, const void* data = nullptr, GLenum data_type = BYTE, GLenum format = R, GLenum internal = R8) {
173 offset = max(offset, GLintptr(0));
174 size = size < 0 ? _size : size;
175 size = min(size, _size - offset);
176 if (size <= 0) return;
177 glClearBufferSubData(type, internal, offset, size, format, type, data);
178 }
179
180 template<GLenum OTypeV, GLbitfield OFlagsV, GLboolean OImmutableV>
181 constexpr void copy(const buffer<OTypeV, OFlagsV, OImmutableV>& cpy, GLsizeiptr size = -1, GLintptr write_offset = 0, GLintptr read_offset = 0) {
182 write_offset = max(write_offset, GLintptr(0));
183 read_offset = max(read_offset, GLintptr(0));
184 size = size < 0 ? _size : size;
185 size = fennec::min(size, cpy._size - read_offset);
186 size = fennec::min(size, _size - write_offset);
187 if (size <= 0) return;
188 glBindBuffer(COPY_READ, cpy._handle);
189 glBindBuffer(COPY_WRITE, _handle);
190 glCopyBufferSubData(COPY_READ, COPY_WRITE, read_offset, write_offset, size);
191 glBindBuffer(COPY_READ, NULL);
192 glBindBuffer(COPY_WRITE, NULL);
193 }
194
195 constexpr void read(void* data, GLsizeiptr size, GLintptr offset = 0) const {
196 static_assert(dynamic or persistent and not (client or coherent));
197 offset = max(offset, GLintptr(0));
198 size = size < 0 ? _size : size;
199 size = min(size, _size - offset);
200 if (size <= 0) return;
201 glGetBufferSubData(type, offset, size, data);
202 }
203
204 constexpr void write(const void* data, GLsizeiptr size, GLintptr offset = 0) {
205 static_assert(dynamic or persistent and not (client or coherent));
206 offset = max(offset, GLintptr(0));
207 size = size < 0 ? _size : size;
208 size = min(size, _size - offset);
209 if (size <= 0) return;
210 glBufferSubData(type, offset, size, data);
211 }
212
213 constexpr void flush(GLsizeiptr size = -1, GLintptr offset = 0) {
214 if (not _mapping) return;
215 if (not (_mapflags & EXPLICIT_FLUSH)) return;
216 offset = max(offset, GLintptr(0));
217 size = size < 0 ? _size : size;
218 size = min(size, _size - offset);
219 if (size <= 0) return;
220 glFlushMappedBufferRange(type, offset, size);
221 }
222
223 constexpr void invalidate(GLsizeiptr size, GLintptr offset = 0) {
224 offset = max(offset, GLintptr(0));
225 size = size < 0 ? _size : size;
226 size = min(size, _size - offset);
227 if (size <= 0) return;
228 glInvalidateBufferSubData(type, offset, size);
229 }
230
231
232// TYPED FUNCTIONS =====================================================================================================
233
234 template<typename TypeT>
235 constexpr TypeT* map(GLbitfield access, GLsizeiptr n, GLintptr offset = 0) {
236 return static_cast<TypeT*>(map(access, n * sizeof(TypeT), offset * sizeof(TypeT)));
237 }
238
239private:
240 GLuint _handle;
241 GLsizeiptr _size;
242 void* _mapping;
243 GLbitfield _mapflags;
244};
245
246}
247
248}
249
250#endif // FENNEC_PLATFORM_OPENGL_LIB_H
Common
constexpr genType min(genType x, genType y)
Returns if otherwise it returns .
Definition common.h:688
constexpr genType max(genType x, genType y)
Returns if , otherwise it returns .
Definition common.h:705
constexpr const remove_reference_t< T > & copy(T &&x) noexcept
produces an r-value type to indicate x may be "copied"
Definition utility.h:104