This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/gpu/opengl/gl_vertex_buffer.cc
Jeroen Bakker f828ecf4ba GPU: Use same read back API as SSBOs
The GPU module has 2 different styles when reading back data from
GPU buffers. The SSBOs used a memcpy to copy the data to a
pre-allocated buffer. IndexBuf/VertBuf gave back a driver/platform
controlled pointer to the memory.

Readback is done for test cases returning mapped pointers is not safe.
For this reason we settled on using the same approach as the SSBO.
Copy the data to a caller pre-allocated buffer.

Reason why this API is currently changed is that the Vulkan API is more
strict on mapping/unmapping buffers that can lead to potential issues
down the road.

Pull Request #104571
2023-02-13 08:34:19 +01:00

162 lines
3.6 KiB
C++

/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2016 by Mike Erwin. All rights reserved. */
/** \file
* \ingroup gpu
*/
#include "GPU_texture.h"
#include "gl_context.hh"
#include "gl_vertex_buffer.hh"
namespace blender::gpu {
void GLVertBuf::acquire_data()
{
if (usage_ == GPU_USAGE_DEVICE_ONLY) {
return;
}
/* Discard previous data if any. */
MEM_SAFE_FREE(data);
data = (uchar *)MEM_mallocN(sizeof(uchar) * this->size_alloc_get(), __func__);
}
void GLVertBuf::resize_data()
{
if (usage_ == GPU_USAGE_DEVICE_ONLY) {
return;
}
data = (uchar *)MEM_reallocN(data, sizeof(uchar) * this->size_alloc_get());
}
void GLVertBuf::release_data()
{
if (is_wrapper_) {
return;
}
if (vbo_id_ != 0) {
GPU_TEXTURE_FREE_SAFE(buffer_texture_);
GLContext::buf_free(vbo_id_);
vbo_id_ = 0;
memory_usage -= vbo_size_;
}
MEM_SAFE_FREE(data);
}
void GLVertBuf::duplicate_data(VertBuf *dst_)
{
BLI_assert(GLContext::get() != nullptr);
GLVertBuf *src = this;
GLVertBuf *dst = static_cast<GLVertBuf *>(dst_);
dst->buffer_texture_ = nullptr;
if (src->vbo_id_ != 0) {
dst->vbo_size_ = src->size_used_get();
glGenBuffers(1, &dst->vbo_id_);
glBindBuffer(GL_COPY_WRITE_BUFFER, dst->vbo_id_);
glBufferData(GL_COPY_WRITE_BUFFER, dst->vbo_size_, nullptr, to_gl(dst->usage_));
glBindBuffer(GL_COPY_READ_BUFFER, src->vbo_id_);
glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, dst->vbo_size_);
memory_usage += dst->vbo_size_;
}
if (data != nullptr) {
dst->data = (uchar *)MEM_dupallocN(src->data);
}
}
void GLVertBuf::upload_data()
{
this->bind();
}
void GLVertBuf::bind()
{
BLI_assert(GLContext::get() != nullptr);
if (vbo_id_ == 0) {
glGenBuffers(1, &vbo_id_);
}
glBindBuffer(GL_ARRAY_BUFFER, vbo_id_);
if (flag & GPU_VERTBUF_DATA_DIRTY) {
vbo_size_ = this->size_used_get();
/* Orphan the vbo to avoid sync then upload data. */
glBufferData(GL_ARRAY_BUFFER, vbo_size_, nullptr, to_gl(usage_));
/* Do not transfer data from host to device when buffer is device only. */
if (usage_ != GPU_USAGE_DEVICE_ONLY) {
glBufferSubData(GL_ARRAY_BUFFER, 0, vbo_size_, data);
}
memory_usage += vbo_size_;
if (usage_ == GPU_USAGE_STATIC) {
MEM_SAFE_FREE(data);
}
flag &= ~GPU_VERTBUF_DATA_DIRTY;
flag |= GPU_VERTBUF_DATA_UPLOADED;
}
}
void GLVertBuf::bind_as_ssbo(uint binding)
{
bind();
BLI_assert(vbo_id_ != 0);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, binding, vbo_id_);
}
void GLVertBuf::bind_as_texture(uint binding)
{
bind();
BLI_assert(vbo_id_ != 0);
if (buffer_texture_ == nullptr) {
buffer_texture_ = GPU_texture_create_from_vertbuf("vertbuf_as_texture", wrap(this));
}
GPU_texture_bind(buffer_texture_, binding);
}
void GLVertBuf::read(void *data) const
{
BLI_assert(is_active());
void *result = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
memcpy(data, result, size_used_get());
glUnmapBuffer(GL_ARRAY_BUFFER);
}
void GLVertBuf::wrap_handle(uint64_t handle)
{
BLI_assert(vbo_id_ == 0);
BLI_assert(glIsBuffer(uint(handle)));
is_wrapper_ = true;
vbo_id_ = uint(handle);
/* We assume the data is already on the device, so no need to allocate or send it. */
flag = GPU_VERTBUF_DATA_UPLOADED;
}
bool GLVertBuf::is_active() const
{
if (!vbo_id_) {
return false;
}
int active_vbo_id = 0;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &active_vbo_id);
return vbo_id_ == active_vbo_id;
}
void GLVertBuf::update_sub(uint start, uint len, const void *data)
{
glBufferSubData(GL_ARRAY_BUFFER, start, len, data);
}
} // namespace blender::gpu