2016-09-13 02:41:43 -04:00
|
|
|
|
2017-04-15 15:42:58 -04:00
|
|
|
// Gawain vertex buffer
|
2016-09-13 02:41:43 -04:00
|
|
|
//
|
|
|
|
// This code is part of the Gawain library, with modifications
|
|
|
|
// specific to integration with Blender.
|
|
|
|
//
|
|
|
|
// Copyright 2016 Mike Erwin
|
|
|
|
//
|
|
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
|
|
|
|
// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
|
|
|
2017-08-16 00:20:14 +10:00
|
|
|
#include "gwn_vertex_buffer.h"
|
|
|
|
#include "gwn_buffer_id.h"
|
|
|
|
#include "gwn_vertex_format_private.h"
|
2016-09-14 16:28:16 +02:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2016-09-13 02:41:43 -04:00
|
|
|
|
2016-09-15 16:51:10 +02:00
|
|
|
#define KEEP_SINGLE_COPY 1
|
|
|
|
|
2017-05-04 21:22:41 +02:00
|
|
|
static unsigned vbo_memory_usage;
|
|
|
|
|
2017-06-19 20:18:04 +10:00
|
|
|
Gwn_VertBuf* GWN_vertbuf_create(void)
|
2016-09-14 16:28:16 +02:00
|
|
|
{
|
2017-06-19 20:18:04 +10:00
|
|
|
Gwn_VertBuf* verts = malloc(sizeof(Gwn_VertBuf));
|
|
|
|
GWN_vertbuf_init(verts);
|
2016-09-14 16:28:16 +02:00
|
|
|
return verts;
|
|
|
|
}
|
|
|
|
|
2017-06-19 20:18:04 +10:00
|
|
|
Gwn_VertBuf* GWN_vertbuf_create_with_format(const Gwn_VertFormat* format)
|
2016-09-15 21:45:10 +02:00
|
|
|
{
|
2017-06-19 20:18:04 +10:00
|
|
|
Gwn_VertBuf* verts = GWN_vertbuf_create();
|
|
|
|
GWN_vertformat_copy(&verts->format, format);
|
2016-09-15 21:45:10 +02:00
|
|
|
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-02-14 17:59:48 +01:00
|
|
|
Gwn_VertBuf* GWN_vertbuf_create_dynamic_with_format(const Gwn_VertFormat* format)
|
|
|
|
{
|
|
|
|
Gwn_VertBuf* verts = GWN_vertbuf_create_with_format(format);
|
|
|
|
verts->data_dynamic = true;
|
|
|
|
return verts;
|
|
|
|
}
|
|
|
|
|
2017-06-19 20:18:04 +10:00
|
|
|
void GWN_vertbuf_init(Gwn_VertBuf* verts)
|
2016-09-14 16:28:16 +02:00
|
|
|
{
|
2017-06-19 20:18:04 +10:00
|
|
|
memset(verts, 0, sizeof(Gwn_VertBuf));
|
2016-09-14 16:28:16 +02:00
|
|
|
}
|
|
|
|
|
2017-06-19 20:18:04 +10:00
|
|
|
void GWN_vertbuf_init_with_format(Gwn_VertBuf* verts, const Gwn_VertFormat* format)
|
2016-09-15 21:45:10 +02:00
|
|
|
{
|
2017-06-19 20:18:04 +10:00
|
|
|
GWN_vertbuf_init(verts);
|
|
|
|
GWN_vertformat_copy(&verts->format, format);
|
2016-09-15 21:45:10 +02:00
|
|
|
if (!format->packed)
|
|
|
|
VertexFormat_pack(&verts->format);
|
|
|
|
}
|
|
|
|
|
2017-07-13 00:28:18 +10:00
|
|
|
/**
|
|
|
|
* Like #GWN_vertbuf_discard but doesn't free.
|
|
|
|
*/
|
|
|
|
void GWN_vertbuf_clear(Gwn_VertBuf* verts)
|
|
|
|
{
|
|
|
|
if (verts->vbo_id) {
|
|
|
|
GWN_buf_id_free(verts->vbo_id);
|
2018-02-14 17:59:48 +01:00
|
|
|
#if VRAM_USAGE
|
|
|
|
vbo_memory_usage -= verts->vram_size;
|
2017-07-13 00:28:18 +10:00
|
|
|
#endif
|
2018-02-14 17:59:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (verts->data)
|
2017-07-13 00:28:18 +10:00
|
|
|
{
|
|
|
|
free(verts->data);
|
|
|
|
verts->data = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-19 20:18:04 +10:00
|
|
|
void GWN_vertbuf_discard(Gwn_VertBuf* verts)
|
2016-10-23 23:16:54 -04:00
|
|
|
{
|
2018-01-09 13:37:52 +01:00
|
|
|
if (verts->vbo_id)
|
|
|
|
{
|
2017-06-19 20:18:04 +10:00
|
|
|
GWN_buf_id_free(verts->vbo_id);
|
2018-02-14 17:59:48 +01:00
|
|
|
#if VRAM_USAGE
|
|
|
|
vbo_memory_usage -= verts->vram_size;
|
2016-11-29 00:12:50 -05:00
|
|
|
#endif
|
2018-02-14 17:59:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (verts->data)
|
2018-01-09 13:37:52 +01:00
|
|
|
{
|
2016-11-29 00:12:50 -05:00
|
|
|
free(verts->data);
|
2018-01-09 13:37:52 +01:00
|
|
|
}
|
2016-11-29 00:12:50 -05:00
|
|
|
|
2017-05-04 21:22:41 +02:00
|
|
|
|
2016-11-29 00:12:50 -05:00
|
|
|
free(verts);
|
2016-10-23 23:16:54 -04:00
|
|
|
}
|
|
|
|
|
2017-06-19 20:18:04 +10:00
|
|
|
unsigned GWN_vertbuf_size_get(const Gwn_VertBuf* verts)
|
2016-09-15 21:45:10 +02:00
|
|
|
{
|
|
|
|
return vertex_buffer_size(&verts->format, verts->vertex_ct);
|
|
|
|
}
|
|
|
|
|
2017-06-19 20:18:04 +10:00
|
|
|
void GWN_vertbuf_data_alloc(Gwn_VertBuf* verts, unsigned v_ct)
|
2016-09-14 16:28:16 +02:00
|
|
|
{
|
2017-06-19 20:18:04 +10:00
|
|
|
Gwn_VertFormat* format = &verts->format;
|
2016-09-14 16:28:16 +02:00
|
|
|
if (!format->packed)
|
2016-09-15 21:45:10 +02:00
|
|
|
VertexFormat_pack(format);
|
2016-09-14 16:28:16 +02:00
|
|
|
|
|
|
|
verts->vertex_ct = v_ct;
|
|
|
|
|
|
|
|
// Data initially lives in main memory. Will be transferred to VRAM when we "prime" it.
|
2017-06-19 20:18:04 +10:00
|
|
|
verts->data = malloc(GWN_vertbuf_size_get(verts));
|
2016-09-15 21:45:10 +02:00
|
|
|
}
|
|
|
|
|
2017-06-19 20:18:04 +10:00
|
|
|
void GWN_vertbuf_data_resize(Gwn_VertBuf* verts, unsigned v_ct)
|
2016-09-15 21:45:10 +02:00
|
|
|
{
|
|
|
|
#if TRUST_NO_ONE
|
|
|
|
assert(verts->vertex_ct != v_ct); // allow this?
|
|
|
|
assert(verts->data != NULL); // has already been allocated
|
2018-02-14 17:59:48 +01:00
|
|
|
assert(verts->vbo_id == 0 || verts->data_dynamic); // has not been sent to VRAM
|
2016-09-15 21:45:10 +02:00
|
|
|
#endif
|
|
|
|
|
2018-02-14 17:59:48 +01:00
|
|
|
// for dynamic buffers
|
|
|
|
verts->data_resized = true;
|
|
|
|
|
2016-09-15 21:45:10 +02:00
|
|
|
verts->vertex_ct = v_ct;
|
2017-06-19 20:18:04 +10:00
|
|
|
verts->data = realloc(verts->data, GWN_vertbuf_size_get(verts));
|
2016-09-15 21:45:10 +02:00
|
|
|
// TODO: skip realloc if v_ct < existing vertex count
|
|
|
|
// extra space will be reclaimed, and never sent to VRAM (see VertexBuffer_prime)
|
2016-09-14 16:28:16 +02:00
|
|
|
}
|
|
|
|
|
2017-06-19 20:18:04 +10:00
|
|
|
void GWN_vertbuf_attr_set(Gwn_VertBuf* verts, unsigned a_idx, unsigned v_idx, const void* data)
|
2016-09-14 16:28:16 +02:00
|
|
|
{
|
2017-06-19 20:18:04 +10:00
|
|
|
const Gwn_VertFormat* format = &verts->format;
|
|
|
|
const Gwn_VertAttr* a = format->attribs + a_idx;
|
2016-09-14 16:28:16 +02:00
|
|
|
|
2018-02-14 17:59:48 +01:00
|
|
|
verts->data_dirty = true;
|
|
|
|
|
2016-09-14 16:28:16 +02:00
|
|
|
#if TRUST_NO_ONE
|
|
|
|
assert(a_idx < format->attrib_ct);
|
|
|
|
assert(v_idx < verts->vertex_ct);
|
|
|
|
assert(verts->data != NULL); // data must be in main mem
|
|
|
|
#endif
|
|
|
|
|
|
|
|
memcpy((GLubyte*)verts->data + a->offset + v_idx * format->stride, data, a->sz);
|
|
|
|
}
|
|
|
|
|
2017-06-19 20:18:04 +10:00
|
|
|
void GWN_vertbuf_attr_fill(Gwn_VertBuf* verts, unsigned a_idx, const void* data)
|
2016-09-14 16:28:16 +02:00
|
|
|
{
|
2017-06-19 20:18:04 +10:00
|
|
|
const Gwn_VertFormat* format = &verts->format;
|
|
|
|
const Gwn_VertAttr* a = format->attribs + a_idx;
|
2016-09-14 16:28:16 +02:00
|
|
|
|
2018-02-14 17:59:48 +01:00
|
|
|
verts->data_dirty = true;
|
|
|
|
|
2016-09-14 16:28:16 +02:00
|
|
|
#if TRUST_NO_ONE
|
|
|
|
assert(a_idx < format->attrib_ct);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
const unsigned stride = a->sz; // tightly packed input data
|
|
|
|
|
2017-06-19 20:18:04 +10:00
|
|
|
GWN_vertbuf_attr_fill_stride(verts, a_idx, stride, data);
|
2016-09-14 16:28:16 +02:00
|
|
|
}
|
|
|
|
|
2017-06-19 20:18:04 +10:00
|
|
|
void GWN_vertbuf_attr_fill_stride(Gwn_VertBuf* verts, unsigned a_idx, unsigned stride, const void* data)
|
2016-09-14 16:28:16 +02:00
|
|
|
{
|
2017-06-19 20:18:04 +10:00
|
|
|
const Gwn_VertFormat* format = &verts->format;
|
|
|
|
const Gwn_VertAttr* a = format->attribs + a_idx;
|
2016-09-14 16:28:16 +02:00
|
|
|
|
2018-02-14 17:59:48 +01:00
|
|
|
verts->data_dirty = true;
|
|
|
|
|
2016-09-14 16:28:16 +02:00
|
|
|
#if TRUST_NO_ONE
|
|
|
|
assert(a_idx < format->attrib_ct);
|
|
|
|
assert(verts->data != NULL); // data must be in main mem
|
|
|
|
#endif
|
|
|
|
|
|
|
|
const unsigned vertex_ct = verts->vertex_ct;
|
|
|
|
|
|
|
|
if (format->attrib_ct == 1 && stride == format->stride)
|
|
|
|
{
|
|
|
|
// we can copy it all at once
|
|
|
|
memcpy(verts->data, data, vertex_ct * a->sz);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// we must copy it per vertex
|
|
|
|
for (unsigned v = 0; v < vertex_ct; ++v)
|
|
|
|
memcpy((GLubyte*)verts->data + a->offset + v * format->stride, (const GLubyte*)data + v * stride, a->sz);
|
|
|
|
}
|
|
|
|
}
|
2016-09-15 16:51:10 +02:00
|
|
|
|
2017-06-29 20:09:05 +10:00
|
|
|
void GWN_vertbuf_attr_get_raw_data(Gwn_VertBuf* verts, unsigned a_idx, Gwn_VertBufRaw *access)
|
|
|
|
{
|
|
|
|
const Gwn_VertFormat* format = &verts->format;
|
|
|
|
const Gwn_VertAttr* a = format->attribs + a_idx;
|
|
|
|
|
|
|
|
#if TRUST_NO_ONE
|
|
|
|
assert(a_idx < format->attrib_ct);
|
|
|
|
assert(verts->data != NULL); // data must be in main mem
|
|
|
|
#endif
|
|
|
|
|
|
|
|
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_ct * format->stride);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-06-19 20:18:04 +10:00
|
|
|
static void VertexBuffer_prime(Gwn_VertBuf* verts)
|
2016-09-15 16:51:10 +02:00
|
|
|
{
|
2018-02-14 17:59:48 +01:00
|
|
|
unsigned buffer_sz = GWN_vertbuf_size_get(verts);
|
|
|
|
|
|
|
|
#if VRAM_USAGE
|
|
|
|
vbo_memory_usage += buffer_sz;
|
|
|
|
verts->vram_size = buffer_sz;
|
|
|
|
#endif
|
2016-09-15 16:51:10 +02:00
|
|
|
|
2017-06-19 20:18:04 +10:00
|
|
|
verts->vbo_id = GWN_buf_id_alloc();
|
2016-09-15 16:51:10 +02:00
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id);
|
|
|
|
// fill with delicious data & send to GPU the first time only
|
2018-03-15 13:31:49 +01:00
|
|
|
glBufferData(GL_ARRAY_BUFFER, buffer_sz, verts->data, (verts->data_dynamic) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
|
2017-05-04 21:22:41 +02:00
|
|
|
|
2016-09-15 16:51:10 +02:00
|
|
|
// now that GL has a copy, discard original
|
2018-02-14 17:59:48 +01:00
|
|
|
if (!verts->data_dynamic)
|
2018-01-09 13:37:52 +01:00
|
|
|
{
|
|
|
|
free(verts->data);
|
|
|
|
verts->data = NULL;
|
|
|
|
}
|
2018-02-14 17:59:48 +01:00
|
|
|
|
|
|
|
verts->data_dirty = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void VertexBuffer_update(Gwn_VertBuf* verts)
|
|
|
|
{
|
|
|
|
unsigned buffer_sz = GWN_vertbuf_size_get(verts);
|
|
|
|
|
|
|
|
#if VRAM_USAGE
|
|
|
|
vbo_memory_usage -= verts->vram_size;
|
|
|
|
vbo_memory_usage += buffer_sz;
|
|
|
|
verts->vram_size = buffer_sz;
|
2016-09-15 16:51:10 +02:00
|
|
|
#endif
|
2018-02-14 17:59:48 +01:00
|
|
|
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id);
|
|
|
|
|
|
|
|
// fill with delicious data & send to GPU ... AGAIN
|
|
|
|
if (verts->data_resized)
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, buffer_sz, verts->data, GL_DYNAMIC_DRAW);
|
|
|
|
else
|
|
|
|
glBufferSubData(GL_ARRAY_BUFFER, 0, buffer_sz, verts->data); // .. todo try glMapBuffer
|
|
|
|
|
|
|
|
verts->data_dirty = false;
|
|
|
|
verts->data_resized = false;
|
2016-09-15 16:51:10 +02:00
|
|
|
}
|
|
|
|
|
2017-06-19 20:18:04 +10:00
|
|
|
void GWN_vertbuf_use(Gwn_VertBuf* verts)
|
2016-09-15 16:51:10 +02:00
|
|
|
{
|
2018-02-14 17:59:48 +01:00
|
|
|
if (!verts->vbo_id)
|
2016-09-15 16:51:10 +02:00
|
|
|
VertexBuffer_prime(verts);
|
2018-02-14 17:59:48 +01:00
|
|
|
else if (verts->data_dirty)
|
|
|
|
VertexBuffer_update(verts);
|
|
|
|
else
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id);
|
2016-09-15 16:51:10 +02:00
|
|
|
}
|
2017-05-04 21:22:41 +02:00
|
|
|
|
2017-06-19 20:18:04 +10:00
|
|
|
unsigned GWN_vertbuf_get_memory_usage(void)
|
2017-05-04 21:22:41 +02:00
|
|
|
{
|
2017-05-15 13:05:32 -04:00
|
|
|
return vbo_memory_usage;
|
|
|
|
}
|