This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/gpu/intern/gpu_vertex_buffer.cc

325 lines
8.7 KiB
C++
Raw Normal View History

/*
* 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.hh"
#include "gpu_vertex_format_private.h"
#include <stdlib.h>
#include <string.h>
#define KEEP_SINGLE_COPY 1
static uint vbo_memory_usage;
static GLenum convert_usage_type_to_gl(GPUUsageType type)
{
2020-07-28 02:15:22 +02:00
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;
}
}
2018-07-18 23:09:31 +10:00
GPUVertBuf *GPU_vertbuf_create(GPUUsageType usage)
{
2020-07-28 02:15:22 +02:00
GPUVertBuf *verts = (GPUVertBuf *)MEM_mallocN(sizeof(GPUVertBuf), "GPUVertBuf");
GPU_vertbuf_init(verts, usage);
return verts;
}
2018-07-18 23:09:31 +10:00
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 */
}
2018-07-18 23:09:31 +10:00
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) {
2020-07-28 02:15:22 +02:00
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);
}
2018-07-18 23:09:31 +10:00
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 */
2018-07-18 23:09:31 +10:00
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;
2020-07-28 02:15:22 +02:00
verts->data = (uchar *)MEM_mallocN(sizeof(GLubyte) * GPU_vertbuf_size_get(verts), __func__);
}
/* resize buffer keeping existing data */
2018-07-18 23:09:31 +10:00
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;
2020-07-28 02:15:22 +02:00
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;
}
2018-07-18 23:09:31 +10:00
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);
}
2018-07-18 23:09:31 +10:00
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. */
Overlay Engine: Refactor & Cleanup This is the unification of all overlays into one overlay engine as described in T65347. I went over all the code making it more future proof with less hacks and removing old / not relevent parts. Goals / Acheivements: - Remove internal shader usage (only drw shaders) - Remove viewportSize and viewportSizeInv and put them in gloabl ubo - Fixed some drawing issues: Missing probe option and Missing Alt+B clipping of some shader - Remove old (legacy) shaders dependancy (not using view UBO). - Less shader variation (less compilation time at first load and less patching needed for vulkan) - removed some geom shaders when I could - Remove static e_data (except shaders storage where it is OK) - Clear the way to fix some anoying limitations (dithered transparency, background image compositing etc...) - Wireframe drawing now uses the same batching capabilities as workbench & eevee (indirect drawing). - Reduced complexity, removed ~3000 Lines of code in draw (also removed a lot of unused shader in GPU). - Post AA to avoid complexity and cost of MSAA. Remaining issues: - ~~Armature edits, overlay toggles, (... others?) are not refreshing viewport after AA is complete~~ - FXAA is not the best for wires, maybe investigate SMAA - Maybe do something more temporally stable for AA. - ~~Paint overlays are not working with AA.~~ - ~~infront objects are difficult to select.~~ - ~~the infront wires sometimes goes through they solid counterpart (missing clear maybe?) (toggle overlays on-off when using infront+wireframe overlay in solid shading)~~ Note: I made some decision to change slightly the appearance of some objects to simplify their drawing. Namely the empty arrows end (which is now hollow/wire) and distance points of the cameras/spots being done by lines. Reviewed By: jbakker Differential Revision: https://developer.blender.org/D6296
2019-12-02 01:40:58 +01:00
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);
}
2018-07-18 23:09:31 +10:00
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);
}
}
}
2018-07-18 23:09:31 +10:00
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
}
2018-07-18 23:09:31 +10:00
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;
}
2018-07-18 23:09:31 +10:00
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;
}