2023-08-16 00:20:26 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2022 Blender Authors
|
2023-05-31 16:19:06 +02:00
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2022-02-08 23:17:31 +01:00
|
|
|
|
|
|
|
|
/** \file
|
|
|
|
|
* \ingroup gpu
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "BLI_string.h"
|
|
|
|
|
|
2024-03-23 01:24:18 +01:00
|
|
|
#include "GPU_capabilities.hh"
|
2022-02-08 23:17:31 +01:00
|
|
|
#include "gpu_backend.hh"
|
|
|
|
|
#include "gpu_context_private.hh"
|
|
|
|
|
|
|
|
|
|
#include "gl_backend.hh"
|
|
|
|
|
#include "gl_debug.hh"
|
|
|
|
|
#include "gl_storage_buffer.hh"
|
|
|
|
|
#include "gl_vertex_buffer.hh"
|
|
|
|
|
|
|
|
|
|
namespace blender::gpu {
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Creation & Deletion
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
GLStorageBuf::GLStorageBuf(size_t size, GPUUsageType usage, const char *name)
|
|
|
|
|
: StorageBuf(size, name)
|
|
|
|
|
{
|
|
|
|
|
usage_ = usage;
|
2025-09-25 09:44:12 +02:00
|
|
|
/* Do not create SSBO GL buffer here to allow allocation from any thread. */
|
2023-10-11 19:26:40 +02:00
|
|
|
BLI_assert(size <= GPU_max_storage_buffer_size());
|
2022-02-08 23:17:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GLStorageBuf::~GLStorageBuf()
|
|
|
|
|
{
|
2024-02-09 16:11:33 +01:00
|
|
|
if (read_fence_) {
|
|
|
|
|
glDeleteSync(read_fence_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (persistent_ptr_) {
|
|
|
|
|
if (GLContext::direct_state_access_support) {
|
|
|
|
|
glUnmapNamedBuffer(read_ssbo_id_);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, read_ssbo_id_);
|
|
|
|
|
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
|
|
|
|
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (read_ssbo_id_) {
|
2025-09-25 12:28:14 +02:00
|
|
|
GLContext::buffer_free(read_ssbo_id_);
|
2024-02-09 16:11:33 +01:00
|
|
|
}
|
|
|
|
|
|
2025-09-25 12:28:14 +02:00
|
|
|
GLContext::buffer_free(ssbo_id_);
|
2022-02-08 23:17:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Data upload / update
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
void GLStorageBuf::init()
|
|
|
|
|
{
|
|
|
|
|
BLI_assert(GLContext::get());
|
|
|
|
|
|
2025-03-13 15:05:16 +01:00
|
|
|
alloc_size_in_bytes_ = ceil_to_multiple_ul(size_in_bytes_, 16);
|
2022-02-08 23:17:31 +01:00
|
|
|
glGenBuffers(1, &ssbo_id_);
|
|
|
|
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_id_);
|
2025-03-13 15:05:16 +01:00
|
|
|
glBufferData(GL_SHADER_STORAGE_BUFFER, alloc_size_in_bytes_, nullptr, to_gl(this->usage_));
|
2022-02-08 23:17:31 +01:00
|
|
|
|
|
|
|
|
debug::object_label(GL_SHADER_STORAGE_BUFFER, ssbo_id_, name_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GLStorageBuf::update(const void *data)
|
|
|
|
|
{
|
|
|
|
|
if (ssbo_id_ == 0) {
|
|
|
|
|
this->init();
|
|
|
|
|
}
|
2024-02-09 16:11:33 +01:00
|
|
|
|
2022-02-08 23:17:31 +01:00
|
|
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_id_);
|
|
|
|
|
glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, size_in_bytes_, data);
|
|
|
|
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Usage
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
void GLStorageBuf::bind(int slot)
|
|
|
|
|
{
|
|
|
|
|
if (slot >= GLContext::max_ssbo_binds) {
|
|
|
|
|
fprintf(
|
|
|
|
|
stderr,
|
2022-08-09 12:40:31 +02:00
|
|
|
"Error: Trying to bind \"%s\" ssbo to slot %d which is above the reported limit of %d.\n",
|
2022-02-08 23:17:31 +01:00
|
|
|
name_,
|
|
|
|
|
slot,
|
|
|
|
|
GLContext::max_ssbo_binds);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ssbo_id_ == 0) {
|
|
|
|
|
this->init();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (data_ != nullptr) {
|
|
|
|
|
this->update(data_);
|
|
|
|
|
MEM_SAFE_FREE(data_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
slot_ = slot;
|
|
|
|
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, slot_, ssbo_id_);
|
|
|
|
|
|
2023-12-04 15:13:06 +01:00
|
|
|
#ifndef NDEBUG
|
2022-02-08 23:17:31 +01:00
|
|
|
BLI_assert(slot < 16);
|
2024-04-17 11:06:39 +02:00
|
|
|
GLContext::get()->bound_ssbo_slots |= 1 << slot;
|
2022-02-08 23:17:31 +01:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-16 08:58:59 +01:00
|
|
|
void GLStorageBuf::bind_as(GLenum target)
|
|
|
|
|
{
|
|
|
|
|
BLI_assert_msg(ssbo_id_ != 0,
|
2025-10-07 08:54:24 +11:00
|
|
|
"Trying to use storage buffer as indirect buffer but buffer was never filled.");
|
2022-03-16 08:58:59 +01:00
|
|
|
glBindBuffer(target, ssbo_id_);
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-08 23:17:31 +01:00
|
|
|
void GLStorageBuf::unbind()
|
|
|
|
|
{
|
2023-12-04 15:13:06 +01:00
|
|
|
#ifndef NDEBUG
|
2022-02-08 23:17:31 +01:00
|
|
|
/* NOTE: This only unbinds the last bound slot. */
|
|
|
|
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, slot_, 0);
|
|
|
|
|
/* Hope that the context did not change. */
|
2024-04-17 11:06:39 +02:00
|
|
|
GLContext::get()->bound_ssbo_slots &= ~(1 << slot_);
|
2022-02-08 23:17:31 +01:00
|
|
|
#endif
|
|
|
|
|
slot_ = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-09 18:46:28 +01:00
|
|
|
void GLStorageBuf::clear(uint32_t clear_value)
|
2022-03-16 08:42:12 +01:00
|
|
|
{
|
|
|
|
|
if (ssbo_id_ == 0) {
|
|
|
|
|
this->init();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (GLContext::direct_state_access_support) {
|
2023-03-09 18:46:28 +01:00
|
|
|
glClearNamedBufferData(ssbo_id_, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, &clear_value);
|
2022-03-16 08:42:12 +01:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* WATCH(@fclem): This should be ok since we only use clear outside of drawing functions. */
|
|
|
|
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_id_);
|
2023-03-09 18:46:28 +01:00
|
|
|
glClearBufferData(
|
|
|
|
|
GL_SHADER_STORAGE_BUFFER, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, &clear_value);
|
2022-03-16 08:42:12 +01:00
|
|
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-18 21:49:08 +02:00
|
|
|
void GLStorageBuf::copy_sub(VertBuf *src_, uint dst_offset, uint src_offset, uint copy_size)
|
|
|
|
|
{
|
|
|
|
|
GLVertBuf *src = static_cast<GLVertBuf *>(src_);
|
|
|
|
|
GLStorageBuf *dst = this;
|
|
|
|
|
|
|
|
|
|
if (dst->ssbo_id_ == 0) {
|
|
|
|
|
dst->init();
|
|
|
|
|
}
|
|
|
|
|
if (src->vbo_id_ == 0) {
|
|
|
|
|
src->bind();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (GLContext::direct_state_access_support) {
|
|
|
|
|
glCopyNamedBufferSubData(src->vbo_id_, dst->ssbo_id_, src_offset, dst_offset, copy_size);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* This binds the buffer to GL_ARRAY_BUFFER and upload the data if any. */
|
|
|
|
|
src->bind();
|
|
|
|
|
glBindBuffer(GL_COPY_WRITE_BUFFER, dst->ssbo_id_);
|
|
|
|
|
glCopyBufferSubData(GL_ARRAY_BUFFER, GL_COPY_WRITE_BUFFER, src_offset, dst_offset, copy_size);
|
|
|
|
|
glBindBuffer(GL_COPY_WRITE_BUFFER, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-20 17:04:36 +02:00
|
|
|
void GLStorageBuf::async_flush_to_host()
|
2022-08-30 21:52:09 +02:00
|
|
|
{
|
|
|
|
|
if (ssbo_id_ == 0) {
|
|
|
|
|
this->init();
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-09 16:11:33 +01:00
|
|
|
if (read_ssbo_id_ == 0) {
|
|
|
|
|
glGenBuffers(1, &read_ssbo_id_);
|
|
|
|
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, read_ssbo_id_);
|
|
|
|
|
glBufferStorage(GL_SHADER_STORAGE_BUFFER,
|
2025-03-13 15:05:16 +01:00
|
|
|
alloc_size_in_bytes_,
|
2024-02-09 16:11:33 +01:00
|
|
|
nullptr,
|
|
|
|
|
GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT);
|
2025-03-13 15:05:16 +01:00
|
|
|
persistent_ptr_ = glMapBufferRange(GL_SHADER_STORAGE_BUFFER,
|
|
|
|
|
0,
|
|
|
|
|
alloc_size_in_bytes_,
|
|
|
|
|
GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT);
|
2024-02-09 16:11:33 +01:00
|
|
|
BLI_assert(persistent_ptr_);
|
|
|
|
|
debug::object_label(GL_SHADER_STORAGE_BUFFER, read_ssbo_id_, name_);
|
2024-06-25 19:52:39 +02:00
|
|
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
|
2024-02-09 16:11:33 +01:00
|
|
|
}
|
|
|
|
|
|
2022-08-30 21:52:09 +02:00
|
|
|
if (GLContext::direct_state_access_support) {
|
2025-03-13 15:05:16 +01:00
|
|
|
glCopyNamedBufferSubData(ssbo_id_, read_ssbo_id_, 0, 0, alloc_size_in_bytes_);
|
2022-08-30 21:52:09 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2024-02-09 16:11:33 +01:00
|
|
|
glBindBuffer(GL_COPY_READ_BUFFER, ssbo_id_);
|
|
|
|
|
glBindBuffer(GL_COPY_WRITE_BUFFER, read_ssbo_id_);
|
2025-03-13 15:05:16 +01:00
|
|
|
glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, alloc_size_in_bytes_);
|
2024-02-09 16:11:33 +01:00
|
|
|
glBindBuffer(GL_COPY_READ_BUFFER, 0);
|
|
|
|
|
glBindBuffer(GL_COPY_WRITE_BUFFER, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
glMemoryBarrier(GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT);
|
|
|
|
|
|
|
|
|
|
if (read_fence_) {
|
|
|
|
|
glDeleteSync(read_fence_);
|
2022-08-30 21:52:09 +02:00
|
|
|
}
|
2024-02-09 16:11:33 +01:00
|
|
|
read_fence_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GLStorageBuf::read(void *data)
|
|
|
|
|
{
|
|
|
|
|
if (data == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!persistent_ptr_ || !read_fence_) {
|
|
|
|
|
this->async_flush_to_host();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (glClientWaitSync(read_fence_, GL_SYNC_FLUSH_COMMANDS_BIT, 1000) == GL_TIMEOUT_EXPIRED) {
|
2024-04-04 11:26:00 +11:00
|
|
|
/* Repeat until the data is ready. */
|
2024-02-09 16:11:33 +01:00
|
|
|
}
|
|
|
|
|
glDeleteSync(read_fence_);
|
2024-08-26 11:34:42 +10:00
|
|
|
read_fence_ = nullptr;
|
2024-02-09 16:11:33 +01:00
|
|
|
|
|
|
|
|
memcpy(data, persistent_ptr_, size_in_bytes_);
|
2022-08-30 21:52:09 +02:00
|
|
|
}
|
|
|
|
|
|
2024-02-01 17:26:08 +01:00
|
|
|
void GLStorageBuf::sync_as_indirect_buffer()
|
|
|
|
|
{
|
|
|
|
|
bind_as(GL_DRAW_INDIRECT_BUFFER);
|
|
|
|
|
glMemoryBarrier(GL_COMMAND_BARRIER_BIT);
|
|
|
|
|
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-08 23:17:31 +01:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
} // namespace blender::gpu
|