Blender V5.0
gl_storage_buffer.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2022 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_string.h"
10
11#include "GPU_capabilities.hh"
12#include "gpu_backend.hh"
14
15#include "gl_backend.hh"
16#include "gl_debug.hh"
17#include "gl_storage_buffer.hh"
18#include "gl_vertex_buffer.hh"
19
20namespace blender::gpu {
21
22/* -------------------------------------------------------------------- */
25
28{
29 usage_ = usage;
30 /* Do not create SSBO GL buffer here to allow allocation from any thread. */
32}
33
35{
36 if (read_fence_) {
37 glDeleteSync(read_fence_);
38 }
39
40 if (persistent_ptr_) {
42 glUnmapNamedBuffer(read_ssbo_id_);
43 }
44 else {
45 glBindBuffer(GL_SHADER_STORAGE_BUFFER, read_ssbo_id_);
46 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
47 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
48 }
49 }
50
51 if (read_ssbo_id_) {
52 GLContext::buffer_free(read_ssbo_id_);
53 }
54
55 GLContext::buffer_free(ssbo_id_);
56}
57
59
60/* -------------------------------------------------------------------- */
63
64void GLStorageBuf::init()
65{
67
68 alloc_size_in_bytes_ = ceil_to_multiple_ul(size_in_bytes_, 16);
69 glGenBuffers(1, &ssbo_id_);
70 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_id_);
71 glBufferData(GL_SHADER_STORAGE_BUFFER, alloc_size_in_bytes_, nullptr, to_gl(this->usage_));
72
73 debug::object_label(GL_SHADER_STORAGE_BUFFER, ssbo_id_, name_);
74}
75
76void GLStorageBuf::update(const void *data)
77{
78 if (ssbo_id_ == 0) {
79 this->init();
80 }
81
82 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_id_);
83 glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, size_in_bytes_, data);
84 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
85}
86
88
89/* -------------------------------------------------------------------- */
92
93void GLStorageBuf::bind(int slot)
94{
95 if (slot >= GLContext::max_ssbo_binds) {
96 fprintf(
97 stderr,
98 "Error: Trying to bind \"%s\" ssbo to slot %d which is above the reported limit of %d.\n",
99 name_,
100 slot,
102 return;
103 }
104
105 if (ssbo_id_ == 0) {
106 this->init();
107 }
108
109 if (data_ != nullptr) {
110 this->update(data_);
112 }
113
114 slot_ = slot;
115 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, slot_, ssbo_id_);
116
117#ifndef NDEBUG
118 BLI_assert(slot < 16);
119 GLContext::get()->bound_ssbo_slots |= 1 << slot;
120#endif
121}
122
123void GLStorageBuf::bind_as(GLenum target)
124{
125 BLI_assert_msg(ssbo_id_ != 0,
126 "Trying to use storage buffer as indirect buffer but buffer was never filled.");
127 glBindBuffer(target, ssbo_id_);
128}
129
131{
132#ifndef NDEBUG
133 /* NOTE: This only unbinds the last bound slot. */
134 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, slot_, 0);
135 /* Hope that the context did not change. */
136 GLContext::get()->bound_ssbo_slots &= ~(1 << slot_);
137#endif
138 slot_ = 0;
139}
140
141void GLStorageBuf::clear(uint32_t clear_value)
142{
143 if (ssbo_id_ == 0) {
144 this->init();
145 }
146
148 glClearNamedBufferData(ssbo_id_, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, &clear_value);
149 }
150 else {
151 /* WATCH(@fclem): This should be ok since we only use clear outside of drawing functions. */
152 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_id_);
153 glClearBufferData(
154 GL_SHADER_STORAGE_BUFFER, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, &clear_value);
155 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
156 }
157}
158
159void GLStorageBuf::copy_sub(VertBuf *src_, uint dst_offset, uint src_offset, uint copy_size)
160{
161 GLVertBuf *src = static_cast<GLVertBuf *>(src_);
162 GLStorageBuf *dst = this;
163
164 if (dst->ssbo_id_ == 0) {
165 dst->init();
166 }
167 if (src->vbo_id_ == 0) {
168 src->bind();
169 }
170
172 glCopyNamedBufferSubData(src->vbo_id_, dst->ssbo_id_, src_offset, dst_offset, copy_size);
173 }
174 else {
175 /* This binds the buffer to GL_ARRAY_BUFFER and upload the data if any. */
176 src->bind();
177 glBindBuffer(GL_COPY_WRITE_BUFFER, dst->ssbo_id_);
178 glCopyBufferSubData(GL_ARRAY_BUFFER, GL_COPY_WRITE_BUFFER, src_offset, dst_offset, copy_size);
179 glBindBuffer(GL_COPY_WRITE_BUFFER, 0);
180 }
181}
182
184{
185 if (ssbo_id_ == 0) {
186 this->init();
187 }
188
189 if (read_ssbo_id_ == 0) {
190 glGenBuffers(1, &read_ssbo_id_);
191 glBindBuffer(GL_SHADER_STORAGE_BUFFER, read_ssbo_id_);
192 glBufferStorage(GL_SHADER_STORAGE_BUFFER,
193 alloc_size_in_bytes_,
194 nullptr,
195 GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT);
196 persistent_ptr_ = glMapBufferRange(GL_SHADER_STORAGE_BUFFER,
197 0,
198 alloc_size_in_bytes_,
199 GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT);
200 BLI_assert(persistent_ptr_);
201 debug::object_label(GL_SHADER_STORAGE_BUFFER, read_ssbo_id_, name_);
202 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
203 }
204
206 glCopyNamedBufferSubData(ssbo_id_, read_ssbo_id_, 0, 0, alloc_size_in_bytes_);
207 }
208 else {
209 glBindBuffer(GL_COPY_READ_BUFFER, ssbo_id_);
210 glBindBuffer(GL_COPY_WRITE_BUFFER, read_ssbo_id_);
211 glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, alloc_size_in_bytes_);
212 glBindBuffer(GL_COPY_READ_BUFFER, 0);
213 glBindBuffer(GL_COPY_WRITE_BUFFER, 0);
214 }
215
216 glMemoryBarrier(GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT);
217
218 if (read_fence_) {
219 glDeleteSync(read_fence_);
220 }
221 read_fence_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
222}
223
225{
226 if (data == nullptr) {
227 return;
228 }
229
230 if (!read_fence_) {
231 /* Synchronous path. */
233 glGetNamedBufferSubData(ssbo_id_, 0, size_in_bytes_, data);
234 }
235 else {
236 glBindBuffer(GL_COPY_READ_BUFFER, ssbo_id_);
237 glGetBufferSubData(GL_COPY_READ_BUFFER, 0, size_in_bytes_, data);
238 glBindBuffer(GL_COPY_READ_BUFFER, 0);
239 }
240 return;
241 }
242
243 while (glClientWaitSync(read_fence_, GL_SYNC_FLUSH_COMMANDS_BIT, 1000) == GL_TIMEOUT_EXPIRED) {
244 /* Repeat until the data is ready. */
245 }
246 glDeleteSync(read_fence_);
247 read_fence_ = nullptr;
248
249 BLI_assert(persistent_ptr_);
250 memcpy(data, persistent_ptr_, size_in_bytes_);
251}
252
254{
255 bind_as(GL_DRAW_INDIRECT_BUFFER);
256 glMemoryBarrier(GL_COMMAND_BARRIER_BIT);
257 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
258}
259
261
262} // namespace blender::gpu
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
MINLINE uint64_t ceil_to_multiple_ul(uint64_t a, uint64_t b)
unsigned int uint
size_t GPU_max_storage_buffer_size()
#define MEM_SAFE_FREE(v)
BMesh const char void * data
void init()
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static void buffer_free(GLuint buf_id)
static GLint max_ssbo_binds
Definition gl_context.hh:56
static bool direct_state_access_support
Definition gl_context.hh:61
static GLContext * get()
void bind(int slot) override
void update(const void *data) override
void sync_as_indirect_buffer() override
GLStorageBuf(size_t size, GPUUsageType usage, const char *name)
void read(void *data) override
void clear(uint32_t clear_value) override
void copy_sub(VertBuf *src, uint dst_offset, uint src_offset, uint copy_size) override
StorageBuf(size_t size, const char *name)
void object_label(GLenum type, GLuint object, const char *name)
Definition gl_debug.cc:329
static GLenum to_gl(const GPUAttachmentType type)
const char * name