From f84342d7e19f34bb445423cc8bf8267c1675a643 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Tue, 28 Jul 2020 02:15:22 +0200 Subject: GPU: Move gpu_vertex_buffer.c to C++ --- source/blender/gpu/CMakeLists.txt | 2 +- source/blender/gpu/GPU_vertex_buffer.h | 6 +- source/blender/gpu/intern/gpu_vertex_buffer.c | 319 ------------------------ source/blender/gpu/intern/gpu_vertex_buffer.cc | 324 +++++++++++++++++++++++++ 4 files changed, 328 insertions(+), 323 deletions(-) delete mode 100644 source/blender/gpu/intern/gpu_vertex_buffer.c create mode 100644 source/blender/gpu/intern/gpu_vertex_buffer.cc (limited to 'source') diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 8c55de8a18c..fd04f56bd13 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -82,7 +82,7 @@ set(SRC intern/gpu_texture_image.cc intern/gpu_texture_smoke.cc intern/gpu_uniformbuffer.c - intern/gpu_vertex_buffer.c + intern/gpu_vertex_buffer.cc intern/gpu_vertex_format.cc intern/gpu_viewport.c diff --git a/source/blender/gpu/GPU_vertex_buffer.h b/source/blender/gpu/GPU_vertex_buffer.h index f9bdf726930..d1693852c1a 100644 --- a/source/blender/gpu/GPU_vertex_buffer.h +++ b/source/blender/gpu/GPU_vertex_buffer.h @@ -59,10 +59,10 @@ typedef struct GPUVertBuf { /** 0 indicates not yet allocated. */ uint32_t vbo_id; /** Usage hint for GL optimisation. */ - uint usage : 2; + GPUUsageType usage; /** Data has been touched and need to be reuploaded to GPU. */ - uint dirty : 1; - unsigned char *data; /* NULL indicates data in VRAM (unmapped) */ + bool dirty; + uchar *data; /* NULL indicates data in VRAM (unmapped) */ } GPUVertBuf; GPUVertBuf *GPU_vertbuf_create(GPUUsageType); diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.c b/source/blender/gpu/intern/gpu_vertex_buffer.c deleted file mode 100644 index 3b4d469542c..00000000000 --- a/source/blender/gpu/intern/gpu_vertex_buffer.c +++ /dev/null @@ -1,319 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - */ - -/** \file - * \ingroup gpu - * - * GPU vertex buffer - */ - -#include "MEM_guardedalloc.h" - -#include "GPU_vertex_buffer.h" - -#include "gpu_context_private.h" -#include "gpu_vertex_format_private.h" - -#include -#include - -#define KEEP_SINGLE_COPY 1 - -static uint vbo_memory_usage; - -static GLenum convert_usage_type_to_gl(GPUUsageType type) -{ - static const GLenum table[] = { - [GPU_USAGE_STREAM] = GL_STREAM_DRAW, - [GPU_USAGE_STATIC] = GL_STATIC_DRAW, - [GPU_USAGE_DYNAMIC] = GL_DYNAMIC_DRAW, - }; - return table[type]; -} - -GPUVertBuf *GPU_vertbuf_create(GPUUsageType usage) -{ - GPUVertBuf *verts = MEM_mallocN(sizeof(GPUVertBuf), "GPUVertBuf"); - GPU_vertbuf_init(verts, usage); - return verts; -} - -GPUVertBuf *GPU_vertbuf_create_with_format_ex(const GPUVertFormat *format, GPUUsageType usage) -{ - GPUVertBuf *verts = GPU_vertbuf_create(usage); - GPU_vertformat_copy(&verts->format, format); - if (!format->packed) { - VertexFormat_pack(&verts->format); - } - return verts; - - /* this function might seem redundant, but there is potential for memory savings here... */ - /* TODO: implement those memory savings */ -} - -void GPU_vertbuf_init(GPUVertBuf *verts, GPUUsageType usage) -{ - memset(verts, 0, sizeof(GPUVertBuf)); - verts->usage = usage; - verts->dirty = true; -} - -void GPU_vertbuf_init_with_format_ex(GPUVertBuf *verts, - const GPUVertFormat *format, - GPUUsageType usage) -{ - GPU_vertbuf_init(verts, usage); - GPU_vertformat_copy(&verts->format, format); - if (!format->packed) { - VertexFormat_pack(&verts->format); - } -} - -GPUVertBuf *GPU_vertbuf_duplicate(GPUVertBuf *verts) -{ - GPUVertBuf *verts_dst = GPU_vertbuf_create(GPU_USAGE_STATIC); - /* Full copy. */ - *verts_dst = *verts; - GPU_vertformat_copy(&verts_dst->format, &verts->format); - - if (verts->vbo_id) { - uint buffer_sz = GPU_vertbuf_size_get(verts); - - verts_dst->vbo_id = GPU_buf_alloc(); - - glBindBuffer(GL_COPY_READ_BUFFER, verts->vbo_id); - glBindBuffer(GL_COPY_WRITE_BUFFER, verts_dst->vbo_id); - - glBufferData(GL_COPY_WRITE_BUFFER, buffer_sz, NULL, convert_usage_type_to_gl(verts->usage)); - - glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, buffer_sz); -#if VRAM_USAGE - vbo_memory_usage += GPU_vertbuf_size_get(verts); -#endif - } - - if (verts->data) { - verts_dst->data = MEM_dupallocN(verts->data); - } - return verts_dst; -} - -/** Same as discard but does not free. */ -void GPU_vertbuf_clear(GPUVertBuf *verts) -{ - if (verts->vbo_id) { - GPU_buf_free(verts->vbo_id); - verts->vbo_id = 0; -#if VRAM_USAGE - vbo_memory_usage -= GPU_vertbuf_size_get(verts); -#endif - } - if (verts->data) { - MEM_SAFE_FREE(verts->data); - } -} - -void GPU_vertbuf_discard(GPUVertBuf *verts) -{ - GPU_vertbuf_clear(verts); - MEM_freeN(verts); -} - -uint GPU_vertbuf_size_get(const GPUVertBuf *verts) -{ - return vertex_buffer_size(&verts->format, verts->vertex_len); -} - -/* create a new allocation, discarding any existing data */ -void GPU_vertbuf_data_alloc(GPUVertBuf *verts, uint v_len) -{ - GPUVertFormat *format = &verts->format; - if (!format->packed) { - VertexFormat_pack(format); - } -#if TRUST_NO_ONE - /* catch any unnecessary use */ - assert(verts->vertex_alloc != v_len || verts->data == NULL); -#endif - /* discard previous data if any */ - if (verts->data) { - MEM_freeN(verts->data); - } -#if VRAM_USAGE - uint new_size = vertex_buffer_size(&verts->format, v_len); - vbo_memory_usage += new_size - GPU_vertbuf_size_get(verts); -#endif - verts->dirty = true; - verts->vertex_len = verts->vertex_alloc = v_len; - verts->data = MEM_mallocN(sizeof(GLubyte) * GPU_vertbuf_size_get(verts), "GPUVertBuf data"); -} - -/* resize buffer keeping existing data */ -void GPU_vertbuf_data_resize(GPUVertBuf *verts, uint v_len) -{ -#if TRUST_NO_ONE - assert(verts->data != NULL); - assert(verts->vertex_alloc != v_len); -#endif - -#if VRAM_USAGE - uint new_size = vertex_buffer_size(&verts->format, v_len); - vbo_memory_usage += new_size - GPU_vertbuf_size_get(verts); -#endif - verts->dirty = true; - verts->vertex_len = verts->vertex_alloc = v_len; - verts->data = MEM_reallocN(verts->data, sizeof(GLubyte) * GPU_vertbuf_size_get(verts)); -} - -/* Set vertex count but does not change allocation. - * Only this many verts will be uploaded to the GPU and rendered. - * This is useful for streaming data. */ -void GPU_vertbuf_data_len_set(GPUVertBuf *verts, uint v_len) -{ -#if TRUST_NO_ONE - assert(verts->data != NULL); /* only for dynamic data */ - assert(v_len <= verts->vertex_alloc); -#endif - -#if VRAM_USAGE - uint new_size = vertex_buffer_size(&verts->format, v_len); - vbo_memory_usage += new_size - GPU_vertbuf_size_get(verts); -#endif - verts->vertex_len = v_len; -} - -void GPU_vertbuf_attr_set(GPUVertBuf *verts, uint a_idx, uint v_idx, const void *data) -{ - const GPUVertFormat *format = &verts->format; - const GPUVertAttr *a = &format->attrs[a_idx]; - -#if TRUST_NO_ONE - assert(a_idx < format->attr_len); - assert(v_idx < verts->vertex_alloc); - assert(verts->data != NULL); -#endif - verts->dirty = true; - memcpy((GLubyte *)verts->data + a->offset + v_idx * format->stride, data, a->sz); -} - -void GPU_vertbuf_attr_fill(GPUVertBuf *verts, uint a_idx, const void *data) -{ - const GPUVertFormat *format = &verts->format; - const GPUVertAttr *a = &format->attrs[a_idx]; - -#if TRUST_NO_ONE - assert(a_idx < format->attr_len); -#endif - const uint stride = a->sz; /* tightly packed input data */ - - GPU_vertbuf_attr_fill_stride(verts, a_idx, stride, data); -} - -/** Fills a whole vertex (all attributes). Data must match packed layout. */ -void GPU_vertbuf_vert_set(GPUVertBuf *verts, uint v_idx, const void *data) -{ - const GPUVertFormat *format = &verts->format; - -#if TRUST_NO_ONE - assert(v_idx < verts->vertex_alloc); - assert(verts->data != NULL); -#endif - verts->dirty = true; - memcpy((GLubyte *)verts->data + v_idx * format->stride, data, format->stride); -} - -void GPU_vertbuf_attr_fill_stride(GPUVertBuf *verts, uint a_idx, uint stride, const void *data) -{ - const GPUVertFormat *format = &verts->format; - const GPUVertAttr *a = &format->attrs[a_idx]; - -#if TRUST_NO_ONE - assert(a_idx < format->attr_len); - assert(verts->data != NULL); -#endif - verts->dirty = true; - const uint vertex_len = verts->vertex_len; - - if (format->attr_len == 1 && stride == format->stride) { - /* we can copy it all at once */ - memcpy(verts->data, data, vertex_len * a->sz); - } - else { - /* we must copy it per vertex */ - for (uint v = 0; v < vertex_len; v++) { - memcpy((GLubyte *)verts->data + a->offset + v * format->stride, - (const GLubyte *)data + v * stride, - a->sz); - } - } -} - -void GPU_vertbuf_attr_get_raw_data(GPUVertBuf *verts, uint a_idx, GPUVertBufRaw *access) -{ - const GPUVertFormat *format = &verts->format; - const GPUVertAttr *a = &format->attrs[a_idx]; - -#if TRUST_NO_ONE - assert(a_idx < format->attr_len); - assert(verts->data != NULL); -#endif - - verts->dirty = true; - - access->size = a->sz; - access->stride = format->stride; - access->data = (GLubyte *)verts->data + a->offset; - access->data_init = access->data; -#if TRUST_NO_ONE - access->_data_end = access->data_init + (size_t)(verts->vertex_alloc * format->stride); -#endif -} - -static void VertBuffer_upload_data(GPUVertBuf *verts) -{ - uint buffer_sz = GPU_vertbuf_size_get(verts); - - /* orphan the vbo to avoid sync */ - glBufferData(GL_ARRAY_BUFFER, buffer_sz, NULL, convert_usage_type_to_gl(verts->usage)); - /* upload data */ - glBufferSubData(GL_ARRAY_BUFFER, 0, buffer_sz, verts->data); - - if (verts->usage == GPU_USAGE_STATIC) { - MEM_freeN(verts->data); - verts->data = NULL; - } - verts->dirty = false; -} - -void GPU_vertbuf_use(GPUVertBuf *verts) -{ - /* only create the buffer the 1st time */ - if (verts->vbo_id == 0) { - verts->vbo_id = GPU_buf_alloc(); - } - glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id); - if (verts->dirty) { - VertBuffer_upload_data(verts); - } -} - -uint GPU_vertbuf_get_memory_usage(void) -{ - return vbo_memory_usage; -} diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.cc b/source/blender/gpu/intern/gpu_vertex_buffer.cc new file mode 100644 index 00000000000..eda6d1c7300 --- /dev/null +++ b/source/blender/gpu/intern/gpu_vertex_buffer.cc @@ -0,0 +1,324 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * GPU vertex buffer + */ + +#include "MEM_guardedalloc.h" + +#include "GPU_vertex_buffer.h" + +#include "gpu_context_private.h" +#include "gpu_vertex_format_private.h" + +#include +#include + +#define KEEP_SINGLE_COPY 1 + +static uint vbo_memory_usage; + +static GLenum convert_usage_type_to_gl(GPUUsageType type) +{ + switch (type) { + case GPU_USAGE_STREAM: + return GL_STREAM_DRAW; + case GPU_USAGE_DYNAMIC: + return GL_DYNAMIC_DRAW; + case GPU_USAGE_STATIC: + return GL_STATIC_DRAW; + default: + BLI_assert(0); + return GL_STATIC_DRAW; + } +} + +GPUVertBuf *GPU_vertbuf_create(GPUUsageType usage) +{ + GPUVertBuf *verts = (GPUVertBuf *)MEM_mallocN(sizeof(GPUVertBuf), "GPUVertBuf"); + GPU_vertbuf_init(verts, usage); + return verts; +} + +GPUVertBuf *GPU_vertbuf_create_with_format_ex(const GPUVertFormat *format, GPUUsageType usage) +{ + GPUVertBuf *verts = GPU_vertbuf_create(usage); + GPU_vertformat_copy(&verts->format, format); + if (!format->packed) { + VertexFormat_pack(&verts->format); + } + return verts; + + /* this function might seem redundant, but there is potential for memory savings here... */ + /* TODO: implement those memory savings */ +} + +void GPU_vertbuf_init(GPUVertBuf *verts, GPUUsageType usage) +{ + memset(verts, 0, sizeof(GPUVertBuf)); + verts->usage = usage; + verts->dirty = true; +} + +void GPU_vertbuf_init_with_format_ex(GPUVertBuf *verts, + const GPUVertFormat *format, + GPUUsageType usage) +{ + GPU_vertbuf_init(verts, usage); + GPU_vertformat_copy(&verts->format, format); + if (!format->packed) { + VertexFormat_pack(&verts->format); + } +} + +GPUVertBuf *GPU_vertbuf_duplicate(GPUVertBuf *verts) +{ + GPUVertBuf *verts_dst = GPU_vertbuf_create(GPU_USAGE_STATIC); + /* Full copy. */ + *verts_dst = *verts; + GPU_vertformat_copy(&verts_dst->format, &verts->format); + + if (verts->vbo_id) { + uint buffer_sz = GPU_vertbuf_size_get(verts); + + verts_dst->vbo_id = GPU_buf_alloc(); + + glBindBuffer(GL_COPY_READ_BUFFER, verts->vbo_id); + glBindBuffer(GL_COPY_WRITE_BUFFER, verts_dst->vbo_id); + + glBufferData(GL_COPY_WRITE_BUFFER, buffer_sz, NULL, convert_usage_type_to_gl(verts->usage)); + + glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, buffer_sz); +#if VRAM_USAGE + vbo_memory_usage += GPU_vertbuf_size_get(verts); +#endif + } + + if (verts->data) { + verts_dst->data = (uchar *)MEM_dupallocN(verts->data); + } + return verts_dst; +} + +/** Same as discard but does not free. */ +void GPU_vertbuf_clear(GPUVertBuf *verts) +{ + if (verts->vbo_id) { + GPU_buf_free(verts->vbo_id); + verts->vbo_id = 0; +#if VRAM_USAGE + vbo_memory_usage -= GPU_vertbuf_size_get(verts); +#endif + } + if (verts->data) { + MEM_SAFE_FREE(verts->data); + } +} + +void GPU_vertbuf_discard(GPUVertBuf *verts) +{ + GPU_vertbuf_clear(verts); + MEM_freeN(verts); +} + +uint GPU_vertbuf_size_get(const GPUVertBuf *verts) +{ + return vertex_buffer_size(&verts->format, verts->vertex_len); +} + +/* create a new allocation, discarding any existing data */ +void GPU_vertbuf_data_alloc(GPUVertBuf *verts, uint v_len) +{ + GPUVertFormat *format = &verts->format; + if (!format->packed) { + VertexFormat_pack(format); + } +#if TRUST_NO_ONE + /* catch any unnecessary use */ + assert(verts->vertex_alloc != v_len || verts->data == NULL); +#endif + /* discard previous data if any */ + if (verts->data) { + MEM_freeN(verts->data); + } +#if VRAM_USAGE + uint new_size = vertex_buffer_size(&verts->format, v_len); + vbo_memory_usage += new_size - GPU_vertbuf_size_get(verts); +#endif + verts->dirty = true; + verts->vertex_len = verts->vertex_alloc = v_len; + verts->data = (uchar *)MEM_mallocN(sizeof(GLubyte) * GPU_vertbuf_size_get(verts), __func__); +} + +/* resize buffer keeping existing data */ +void GPU_vertbuf_data_resize(GPUVertBuf *verts, uint v_len) +{ +#if TRUST_NO_ONE + assert(verts->data != NULL); + assert(verts->vertex_alloc != v_len); +#endif + +#if VRAM_USAGE + uint new_size = vertex_buffer_size(&verts->format, v_len); + vbo_memory_usage += new_size - GPU_vertbuf_size_get(verts); +#endif + verts->dirty = true; + verts->vertex_len = verts->vertex_alloc = v_len; + verts->data = (uchar *)MEM_reallocN(verts->data, sizeof(GLubyte) * GPU_vertbuf_size_get(verts)); +} + +/* Set vertex count but does not change allocation. + * Only this many verts will be uploaded to the GPU and rendered. + * This is useful for streaming data. */ +void GPU_vertbuf_data_len_set(GPUVertBuf *verts, uint v_len) +{ +#if TRUST_NO_ONE + assert(verts->data != NULL); /* only for dynamic data */ + assert(v_len <= verts->vertex_alloc); +#endif + +#if VRAM_USAGE + uint new_size = vertex_buffer_size(&verts->format, v_len); + vbo_memory_usage += new_size - GPU_vertbuf_size_get(verts); +#endif + verts->vertex_len = v_len; +} + +void GPU_vertbuf_attr_set(GPUVertBuf *verts, uint a_idx, uint v_idx, const void *data) +{ + const GPUVertFormat *format = &verts->format; + const GPUVertAttr *a = &format->attrs[a_idx]; + +#if TRUST_NO_ONE + assert(a_idx < format->attr_len); + assert(v_idx < verts->vertex_alloc); + assert(verts->data != NULL); +#endif + verts->dirty = true; + memcpy((GLubyte *)verts->data + a->offset + v_idx * format->stride, data, a->sz); +} + +void GPU_vertbuf_attr_fill(GPUVertBuf *verts, uint a_idx, const void *data) +{ + const GPUVertFormat *format = &verts->format; + const GPUVertAttr *a = &format->attrs[a_idx]; + +#if TRUST_NO_ONE + assert(a_idx < format->attr_len); +#endif + const uint stride = a->sz; /* tightly packed input data */ + + GPU_vertbuf_attr_fill_stride(verts, a_idx, stride, data); +} + +/** Fills a whole vertex (all attributes). Data must match packed layout. */ +void GPU_vertbuf_vert_set(GPUVertBuf *verts, uint v_idx, const void *data) +{ + const GPUVertFormat *format = &verts->format; + +#if TRUST_NO_ONE + assert(v_idx < verts->vertex_alloc); + assert(verts->data != NULL); +#endif + verts->dirty = true; + memcpy((GLubyte *)verts->data + v_idx * format->stride, data, format->stride); +} + +void GPU_vertbuf_attr_fill_stride(GPUVertBuf *verts, uint a_idx, uint stride, const void *data) +{ + const GPUVertFormat *format = &verts->format; + const GPUVertAttr *a = &format->attrs[a_idx]; + +#if TRUST_NO_ONE + assert(a_idx < format->attr_len); + assert(verts->data != NULL); +#endif + verts->dirty = true; + const uint vertex_len = verts->vertex_len; + + if (format->attr_len == 1 && stride == format->stride) { + /* we can copy it all at once */ + memcpy(verts->data, data, vertex_len * a->sz); + } + else { + /* we must copy it per vertex */ + for (uint v = 0; v < vertex_len; v++) { + memcpy((GLubyte *)verts->data + a->offset + v * format->stride, + (const GLubyte *)data + v * stride, + a->sz); + } + } +} + +void GPU_vertbuf_attr_get_raw_data(GPUVertBuf *verts, uint a_idx, GPUVertBufRaw *access) +{ + const GPUVertFormat *format = &verts->format; + const GPUVertAttr *a = &format->attrs[a_idx]; + +#if TRUST_NO_ONE + assert(a_idx < format->attr_len); + assert(verts->data != NULL); +#endif + + verts->dirty = true; + + access->size = a->sz; + access->stride = format->stride; + access->data = (GLubyte *)verts->data + a->offset; + access->data_init = access->data; +#if TRUST_NO_ONE + access->_data_end = access->data_init + (size_t)(verts->vertex_alloc * format->stride); +#endif +} + +static void VertBuffer_upload_data(GPUVertBuf *verts) +{ + uint buffer_sz = GPU_vertbuf_size_get(verts); + + /* orphan the vbo to avoid sync */ + glBufferData(GL_ARRAY_BUFFER, buffer_sz, NULL, convert_usage_type_to_gl(verts->usage)); + /* upload data */ + glBufferSubData(GL_ARRAY_BUFFER, 0, buffer_sz, verts->data); + + if (verts->usage == GPU_USAGE_STATIC) { + MEM_freeN(verts->data); + verts->data = NULL; + } + verts->dirty = false; +} + +void GPU_vertbuf_use(GPUVertBuf *verts) +{ + /* only create the buffer the 1st time */ + if (verts->vbo_id == 0) { + verts->vbo_id = GPU_buf_alloc(); + } + glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id); + if (verts->dirty) { + VertBuffer_upload_data(verts); + } +} + +uint GPU_vertbuf_get_memory_usage(void) +{ + return vbo_memory_usage; +} -- cgit v1.2.3