Blender V4.3
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
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/* -------------------------------------------------------------------- */
26GLStorageBuf::GLStorageBuf(size_t size, GPUUsageType usage, const char *name)
27 : StorageBuf(size, name)
28{
29 usage_ = usage;
30 /* Do not create UBO 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::buf_free(read_ssbo_id_);
53 }
54
55 GLContext::buf_free(ssbo_id_);
56}
57
60/* -------------------------------------------------------------------- */
64void GLStorageBuf::init()
65{
67
68 glGenBuffers(1, &ssbo_id_);
69 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_id_);
70 glBufferData(GL_SHADER_STORAGE_BUFFER, size_in_bytes_, nullptr, to_gl(this->usage_));
71
72 debug::object_label(GL_SHADER_STORAGE_BUFFER, ssbo_id_, name_);
73}
74
75void GLStorageBuf::update(const void *data)
76{
77 if (ssbo_id_ == 0) {
78 this->init();
79 }
80
81 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_id_);
82 glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, size_in_bytes_, data);
83 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
84}
85
88/* -------------------------------------------------------------------- */
92void GLStorageBuf::bind(int slot)
93{
94 if (slot >= GLContext::max_ssbo_binds) {
95 fprintf(
96 stderr,
97 "Error: Trying to bind \"%s\" ssbo to slot %d which is above the reported limit of %d.\n",
98 name_,
99 slot,
101 return;
102 }
103
104 if (ssbo_id_ == 0) {
105 this->init();
106 }
107
108 if (data_ != nullptr) {
109 this->update(data_);
111 }
112
113 slot_ = slot;
114 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, slot_, ssbo_id_);
115
116#ifndef NDEBUG
117 BLI_assert(slot < 16);
118 GLContext::get()->bound_ssbo_slots |= 1 << slot;
119#endif
120}
121
122void GLStorageBuf::bind_as(GLenum target)
123{
124 BLI_assert_msg(ssbo_id_ != 0,
125 "Trying to use storage buf as indirect buffer but buffer was never filled.");
126 glBindBuffer(target, ssbo_id_);
127}
128
130{
131#ifndef NDEBUG
132 /* NOTE: This only unbinds the last bound slot. */
133 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, slot_, 0);
134 /* Hope that the context did not change. */
135 GLContext::get()->bound_ssbo_slots &= ~(1 << slot_);
136#endif
137 slot_ = 0;
138}
139
141{
142 if (ssbo_id_ == 0) {
143 this->init();
144 }
145
147 glClearNamedBufferData(ssbo_id_, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, &clear_value);
148 }
149 else {
150 /* WATCH(@fclem): This should be ok since we only use clear outside of drawing functions. */
151 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_id_);
152 glClearBufferData(
153 GL_SHADER_STORAGE_BUFFER, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, &clear_value);
154 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
155 }
156}
157
158void GLStorageBuf::copy_sub(VertBuf *src_, uint dst_offset, uint src_offset, uint copy_size)
159{
160 GLVertBuf *src = static_cast<GLVertBuf *>(src_);
161 GLStorageBuf *dst = this;
162
163 if (dst->ssbo_id_ == 0) {
164 dst->init();
165 }
166 if (src->vbo_id_ == 0) {
167 src->bind();
168 }
169
171 glCopyNamedBufferSubData(src->vbo_id_, dst->ssbo_id_, src_offset, dst_offset, copy_size);
172 }
173 else {
174 /* This binds the buffer to GL_ARRAY_BUFFER and upload the data if any. */
175 src->bind();
176 glBindBuffer(GL_COPY_WRITE_BUFFER, dst->ssbo_id_);
177 glCopyBufferSubData(GL_ARRAY_BUFFER, GL_COPY_WRITE_BUFFER, src_offset, dst_offset, copy_size);
178 glBindBuffer(GL_COPY_WRITE_BUFFER, 0);
179 }
180}
181
183{
184 if (ssbo_id_ == 0) {
185 this->init();
186 }
187
188 if (read_ssbo_id_ == 0) {
189 glGenBuffers(1, &read_ssbo_id_);
190 glBindBuffer(GL_SHADER_STORAGE_BUFFER, read_ssbo_id_);
191 glBufferStorage(GL_SHADER_STORAGE_BUFFER,
193 nullptr,
194 GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT);
195 persistent_ptr_ = glMapBufferRange(
196 GL_SHADER_STORAGE_BUFFER, 0, size_in_bytes_, GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT);
197 BLI_assert(persistent_ptr_);
198 debug::object_label(GL_SHADER_STORAGE_BUFFER, read_ssbo_id_, name_);
199 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
200 }
201
203 glCopyNamedBufferSubData(ssbo_id_, read_ssbo_id_, 0, 0, size_in_bytes_);
204 }
205 else {
206 glBindBuffer(GL_COPY_READ_BUFFER, ssbo_id_);
207 glBindBuffer(GL_COPY_WRITE_BUFFER, read_ssbo_id_);
208 glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, size_in_bytes_);
209 glBindBuffer(GL_COPY_READ_BUFFER, 0);
210 glBindBuffer(GL_COPY_WRITE_BUFFER, 0);
211 }
212
213 glMemoryBarrier(GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT);
214
215 if (read_fence_) {
216 glDeleteSync(read_fence_);
217 }
218 read_fence_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
219}
220
221void GLStorageBuf::read(void *data)
222{
223 if (data == nullptr) {
224 return;
225 }
226
227 if (!persistent_ptr_ || !read_fence_) {
228 this->async_flush_to_host();
229 }
230
231 while (glClientWaitSync(read_fence_, GL_SYNC_FLUSH_COMMANDS_BIT, 1000) == GL_TIMEOUT_EXPIRED) {
232 /* Repeat until the data is ready. */
233 }
234 glDeleteSync(read_fence_);
235 read_fence_ = nullptr;
236
237 memcpy(data, persistent_ptr_, size_in_bytes_);
238}
239
241{
242 bind_as(GL_DRAW_INDIRECT_BUFFER);
243 glMemoryBarrier(GL_COMMAND_BARRIER_BIT);
244 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
245}
246
249} // namespace blender::gpu
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
unsigned int uint
size_t GPU_max_storage_buffer_size()
#define MEM_SAFE_FREE(v)
static void buf_free(GLuint buf_id)
static GLint max_ssbo_binds
Definition gl_context.hh:46
static bool direct_state_access_support
Definition gl_context.hh:52
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
void object_label(GLenum type, GLuint object, const char *name)
Definition gl_debug.cc:344
static GLenum to_gl(const GPUAttachmentType type)
unsigned int uint32_t
Definition stdint.h:80