Changeset View
Changeset View
Standalone View
Standalone View
source/blender/gpu/intern/gpu_vertex_buffer.cc
| Show All 19 Lines | |||||
| /** \file | /** \file | ||||
| * \ingroup gpu | * \ingroup gpu | ||||
| * | * | ||||
| * GPU vertex buffer | * GPU vertex buffer | ||||
| */ | */ | ||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "gpu_context_private.hh" | #include "gpu_backend.hh" | ||||
| #include "gpu_vertex_format_private.h" | #include "gpu_vertex_format_private.h" | ||||
| #include "gl_vertex_buffer.hh" /* TODO remove */ | |||||
| #include "gpu_context_private.hh" /* TODO remove */ | |||||
| #include "gpu_vertex_buffer_private.hh" | #include "gpu_vertex_buffer_private.hh" | ||||
| #define KEEP_SINGLE_COPY 1 | #include <cstring> | ||||
| /* -------------------------------------------------------------------- */ | |||||
| /** \name VertBuf | |||||
| * \{ */ | |||||
| namespace blender::gpu { | |||||
| static uint vbo_memory_usage; | size_t VertBuf::memory_usage = 0; | ||||
| static GLenum convert_usage_type_to_gl(GPUUsageType type) | VertBuf::VertBuf() | ||||
| { | { | ||||
| switch (type) { | /* Needed by some code check. */ | ||||
| case GPU_USAGE_STREAM: | format.attr_len = 0; | ||||
| 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) | VertBuf::~VertBuf() | ||||
| { | { | ||||
| GPUVertBuf *verts = (GPUVertBuf *)MEM_mallocN(sizeof(GPUVertBuf), "GPUVertBuf"); | /* Should already have been cleared. */ | ||||
| GPU_vertbuf_init(verts, usage); | BLI_assert(flag == GPU_VERTBUF_INVALID); | ||||
| return verts; | |||||
| } | } | ||||
| GPUVertBuf *GPU_vertbuf_create_with_format_ex(const GPUVertFormat *format, GPUUsageType usage) | void VertBuf::init(const GPUVertFormat *format, GPUUsageType usage) | ||||
| { | { | ||||
| GPUVertBuf *verts = GPU_vertbuf_create(usage); | usage_ = usage; | ||||
| GPU_vertformat_copy(&verts->format, format); | flag = GPU_VERTBUF_DATA_DIRTY; | ||||
| GPU_vertformat_copy(&this->format, format); | |||||
| if (!format->packed) { | if (!format->packed) { | ||||
| VertexFormat_pack(&verts->format); | VertexFormat_pack(&this->format); | ||||
| } | |||||
| flag |= GPU_VERTBUF_INIT; | |||||
| } | } | ||||
| verts->flag |= GPU_VERTBUF_INIT; | |||||
| return verts; | |||||
| /* this function might seem redundant, but there is potential for memory savings here... */ | void VertBuf::clear(void) | ||||
| /* TODO: implement those memory savings */ | { | ||||
| this->release_data(); | |||||
| flag = GPU_VERTBUF_INVALID; | |||||
| } | } | ||||
| void GPU_vertbuf_init(GPUVertBuf *verts, GPUUsageType usage) | VertBuf *VertBuf::duplicate(void) | ||||
| { | { | ||||
| memset(verts, 0, sizeof(GPUVertBuf)); | VertBuf *dst = GPUBackend::get()->vertbuf_alloc(); | ||||
| verts->usage = usage; | /* Full copy. */ | ||||
| verts->flag = GPU_VERTBUF_DATA_DIRTY; | *dst = *this; | ||||
| verts->handle_refcount = 1; | /* Almost full copy... */ | ||||
| dst->handle_refcount_ = 1; | |||||
| /* Duplicate all needed implementation specifics data. */ | |||||
| this->duplicate_data(dst); | |||||
| return dst; | |||||
| } | } | ||||
| void GPU_vertbuf_init_with_format_ex(GPUVertBuf *verts, | void VertBuf::allocate(uint vert_len) | ||||
| const GPUVertFormat *format, | |||||
| GPUUsageType usage) | |||||
| { | { | ||||
| GPU_vertbuf_init(verts, usage); | BLI_assert(format.packed); | ||||
| GPU_vertformat_copy(&verts->format, format); | /* Catch any unnecessary usage. */ | ||||
| if (!format->packed) { | BLI_assert(vertex_alloc != vert_len || data == nullptr); | ||||
| VertexFormat_pack(&verts->format); | vertex_len = vertex_alloc = vert_len; | ||||
| this->acquire_data(); | |||||
| flag |= GPU_VERTBUF_DATA_DIRTY; | |||||
| } | } | ||||
| verts->flag |= GPU_VERTBUF_INIT; | |||||
| void VertBuf::resize(uint vert_len) | |||||
| { | |||||
| /* Catch any unnecessary usage. */ | |||||
| BLI_assert(vertex_alloc != vert_len); | |||||
| vertex_len = vertex_alloc = vert_len; | |||||
| this->resize_data(); | |||||
| flag |= GPU_VERTBUF_DATA_DIRTY; | |||||
| } | } | ||||
| GPUVertBuf *GPU_vertbuf_duplicate(GPUVertBuf *verts) | void VertBuf::upload(void) | ||||
| { | { | ||||
| GPUVertBuf *verts_dst = GPU_vertbuf_create(GPU_USAGE_STATIC); | this->upload_data(); | ||||
| /* Full copy. */ | } | ||||
| *verts_dst = *verts; | |||||
| GPU_vertformat_copy(&verts_dst->format, &verts->format); | |||||
| if (verts->vbo_id) { | } // namespace blender::gpu | ||||
| 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); | /** \name C-API | ||||
| * \{ */ | |||||
| glBufferData(GL_COPY_WRITE_BUFFER, buffer_sz, NULL, convert_usage_type_to_gl(verts->usage)); | using namespace blender; | ||||
| using namespace blender::gpu; | |||||
| glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, buffer_sz); | /* -------- Creation & deletion -------- */ | ||||
| #if VRAM_USAGE | |||||
| vbo_memory_usage += GPU_vertbuf_size_get(verts); | GPUVertBuf *GPU_vertbuf_calloc(void) | ||||
| #endif | { | ||||
| return wrap(GPUBackend::get()->vertbuf_alloc()); | |||||
| } | } | ||||
| if (verts->data) { | GPUVertBuf *GPU_vertbuf_create_with_format_ex(const GPUVertFormat *format, GPUUsageType usage) | ||||
| verts_dst->data = (uchar *)MEM_dupallocN(verts->data); | { | ||||
| GPUVertBuf *verts = GPU_vertbuf_calloc(); | |||||
| unwrap(verts)->init(format, usage); | |||||
| return verts; | |||||
| } | } | ||||
| return verts_dst; | |||||
| void GPU_vertbuf_init_with_format_ex(GPUVertBuf *verts_, | |||||
| const GPUVertFormat *format, | |||||
| GPUUsageType usage) | |||||
| { | |||||
| unwrap(verts_)->init(format, usage); | |||||
| } | |||||
| GPUVertBuf *GPU_vertbuf_duplicate(GPUVertBuf *verts_) | |||||
| { | |||||
| return wrap(unwrap(verts_)->duplicate()); | |||||
| } | } | ||||
| /** Same as discard but does not free. */ | /** Same as discard but does not free. */ | ||||
| void GPU_vertbuf_clear(GPUVertBuf *verts) | void GPU_vertbuf_clear(GPUVertBuf *verts) | ||||
| { | { | ||||
| if (verts->vbo_id) { | unwrap(verts)->clear(); | ||||
| 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) | void GPU_vertbuf_discard(GPUVertBuf *verts) | ||||
| { | { | ||||
| GPU_vertbuf_clear(verts); | unwrap(verts)->clear(); | ||||
| GPU_vertbuf_handle_ref_remove(verts); | unwrap(verts)->reference_remove(); | ||||
| } | } | ||||
| void GPU_vertbuf_handle_ref_add(GPUVertBuf *verts) | void GPU_vertbuf_handle_ref_add(GPUVertBuf *verts) | ||||
| { | { | ||||
| verts->handle_refcount++; | unwrap(verts)->reference_add(); | ||||
| } | } | ||||
| void GPU_vertbuf_handle_ref_remove(GPUVertBuf *verts) | void GPU_vertbuf_handle_ref_remove(GPUVertBuf *verts) | ||||
| { | { | ||||
| BLI_assert(verts->handle_refcount > 0); | unwrap(verts)->reference_remove(); | ||||
| verts->handle_refcount--; | |||||
| if (verts->handle_refcount == 0) { | |||||
| /* Should already have been cleared. */ | |||||
| BLI_assert(verts->vbo_id == 0 && verts->data == NULL); | |||||
| MEM_freeN(verts); | |||||
| } | |||||
| } | } | ||||
| uint GPU_vertbuf_size_get(const GPUVertBuf *verts) | /* -------- Data update -------- */ | ||||
| { | |||||
| return vertex_buffer_size(&verts->format, verts->vertex_len); | |||||
| } | |||||
| /* create a new allocation, discarding any existing data */ | /* create a new allocation, discarding any existing data */ | ||||
| void GPU_vertbuf_data_alloc(GPUVertBuf *verts, uint v_len) | void GPU_vertbuf_data_alloc(GPUVertBuf *verts, uint v_len) | ||||
| { | { | ||||
| GPUVertFormat *format = &verts->format; | unwrap(verts)->allocate(v_len); | ||||
| 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->flag |= GPU_VERTBUF_DATA_DIRTY; | |||||
| 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 */ | /* resize buffer keeping existing data */ | ||||
| void GPU_vertbuf_data_resize(GPUVertBuf *verts, uint v_len) | void GPU_vertbuf_data_resize(GPUVertBuf *verts, uint v_len) | ||||
| { | { | ||||
| #if TRUST_NO_ONE | unwrap(verts)->resize(v_len); | ||||
| 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->flag |= GPU_VERTBUF_DATA_DIRTY; | |||||
| 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. | /* Set vertex count but does not change allocation. | ||||
| * Only this many verts will be uploaded to the GPU and rendered. | * Only this many verts will be uploaded to the GPU and rendered. | ||||
| * This is useful for streaming data. */ | * This is useful for streaming data. */ | ||||
| void GPU_vertbuf_data_len_set(GPUVertBuf *verts, uint v_len) | void GPU_vertbuf_data_len_set(GPUVertBuf *verts_, uint v_len) | ||||
| { | { | ||||
| #if TRUST_NO_ONE | VertBuf *verts = unwrap(verts_); | ||||
| assert(verts->data != NULL); /* only for dynamic data */ | BLI_assert(verts->data != NULL); /* Only for dynamic data. */ | ||||
| assert(v_len <= verts->vertex_alloc); | BLI_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; | verts->vertex_len = v_len; | ||||
| } | } | ||||
| void GPU_vertbuf_attr_set(GPUVertBuf *verts, uint a_idx, uint v_idx, const void *data) | void GPU_vertbuf_attr_set(GPUVertBuf *verts_, uint a_idx, uint v_idx, const void *data) | ||||
| { | { | ||||
| VertBuf *verts = unwrap(verts_); | |||||
| const GPUVertFormat *format = &verts->format; | const GPUVertFormat *format = &verts->format; | ||||
| const GPUVertAttr *a = &format->attrs[a_idx]; | const GPUVertAttr *a = &format->attrs[a_idx]; | ||||
| BLI_assert(v_idx < verts->vertex_alloc); | |||||
| #if TRUST_NO_ONE | BLI_assert(a_idx < format->attr_len); | ||||
| assert(a_idx < format->attr_len); | BLI_assert(verts->data != NULL); | ||||
| assert(v_idx < verts->vertex_alloc); | |||||
| assert(verts->data != NULL); | |||||
| #endif | |||||
| verts->flag |= GPU_VERTBUF_DATA_DIRTY; | verts->flag |= GPU_VERTBUF_DATA_DIRTY; | ||||
| memcpy((GLubyte *)verts->data + a->offset + v_idx * format->stride, data, a->sz); | memcpy(verts->data + a->offset + v_idx * format->stride, data, a->sz); | ||||
| } | } | ||||
| void GPU_vertbuf_attr_fill(GPUVertBuf *verts, uint a_idx, const void *data) | void GPU_vertbuf_attr_fill(GPUVertBuf *verts_, uint a_idx, const void *data) | ||||
| { | { | ||||
| VertBuf *verts = unwrap(verts_); | |||||
| const GPUVertFormat *format = &verts->format; | const GPUVertFormat *format = &verts->format; | ||||
| BLI_assert(a_idx < format->attr_len); | |||||
| const GPUVertAttr *a = &format->attrs[a_idx]; | 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 */ | const uint stride = a->sz; /* tightly packed input data */ | ||||
| verts->flag |= GPU_VERTBUF_DATA_DIRTY; | |||||
| GPU_vertbuf_attr_fill_stride(verts, a_idx, stride, data); | GPU_vertbuf_attr_fill_stride(verts_, a_idx, stride, data); | ||||
| } | } | ||||
| /** Fills a whole vertex (all attributes). Data must match packed layout. */ | /** Fills a whole vertex (all attributes). Data must match packed layout. */ | ||||
| void GPU_vertbuf_vert_set(GPUVertBuf *verts, uint v_idx, const void *data) | void GPU_vertbuf_vert_set(GPUVertBuf *verts_, uint v_idx, const void *data) | ||||
| { | { | ||||
| VertBuf *verts = unwrap(verts_); | |||||
| const GPUVertFormat *format = &verts->format; | const GPUVertFormat *format = &verts->format; | ||||
| BLI_assert(v_idx < verts->vertex_alloc); | |||||
| #if TRUST_NO_ONE | BLI_assert(verts->data != NULL); | ||||
| assert(v_idx < verts->vertex_alloc); | |||||
| assert(verts->data != NULL); | |||||
| #endif | |||||
| verts->flag |= GPU_VERTBUF_DATA_DIRTY; | verts->flag |= GPU_VERTBUF_DATA_DIRTY; | ||||
| memcpy((GLubyte *)verts->data + v_idx * format->stride, data, format->stride); | memcpy(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) | void GPU_vertbuf_attr_fill_stride(GPUVertBuf *verts_, uint a_idx, uint stride, const void *data) | ||||
| { | { | ||||
| VertBuf *verts = unwrap(verts_); | |||||
| const GPUVertFormat *format = &verts->format; | const GPUVertFormat *format = &verts->format; | ||||
| const GPUVertAttr *a = &format->attrs[a_idx]; | const GPUVertAttr *a = &format->attrs[a_idx]; | ||||
| BLI_assert(a_idx < format->attr_len); | |||||
| #if TRUST_NO_ONE | BLI_assert(verts->data != NULL); | ||||
| assert(a_idx < format->attr_len); | |||||
| assert(verts->data != NULL); | |||||
| #endif | |||||
| verts->flag |= GPU_VERTBUF_DATA_DIRTY; | verts->flag |= GPU_VERTBUF_DATA_DIRTY; | ||||
| const uint vertex_len = verts->vertex_len; | const uint vertex_len = verts->vertex_len; | ||||
| if (format->attr_len == 1 && stride == format->stride) { | if (format->attr_len == 1 && stride == format->stride) { | ||||
| /* we can copy it all at once */ | /* we can copy it all at once */ | ||||
| memcpy(verts->data, data, vertex_len * a->sz); | memcpy(verts->data, data, vertex_len * a->sz); | ||||
| } | } | ||||
| else { | else { | ||||
| /* we must copy it per vertex */ | /* we must copy it per vertex */ | ||||
| for (uint v = 0; v < vertex_len; v++) { | for (uint v = 0; v < vertex_len; v++) { | ||||
| memcpy((GLubyte *)verts->data + a->offset + v * format->stride, | memcpy( | ||||
| (const GLubyte *)data + v * stride, | verts->data + a->offset + v * format->stride, (const uchar *)data + v * stride, a->sz); | ||||
| a->sz); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void GPU_vertbuf_attr_get_raw_data(GPUVertBuf *verts, uint a_idx, GPUVertBufRaw *access) | void GPU_vertbuf_attr_get_raw_data(GPUVertBuf *verts_, uint a_idx, GPUVertBufRaw *access) | ||||
| { | { | ||||
| VertBuf *verts = unwrap(verts_); | |||||
| const GPUVertFormat *format = &verts->format; | const GPUVertFormat *format = &verts->format; | ||||
| const GPUVertAttr *a = &format->attrs[a_idx]; | const GPUVertAttr *a = &format->attrs[a_idx]; | ||||
| BLI_assert(a_idx < format->attr_len); | |||||
| #if TRUST_NO_ONE | BLI_assert(verts->data != NULL); | ||||
| assert(a_idx < format->attr_len); | |||||
| assert(verts->data != NULL); | |||||
| #endif | |||||
| verts->flag |= GPU_VERTBUF_DATA_DIRTY; | verts->flag |= GPU_VERTBUF_DATA_DIRTY; | ||||
| verts->flag &= ~GPU_VERTBUF_DATA_UPLOADED; | |||||
| access->size = a->sz; | access->size = a->sz; | ||||
| access->stride = format->stride; | access->stride = format->stride; | ||||
| access->data = (GLubyte *)verts->data + a->offset; | access->data = (uchar *)verts->data + a->offset; | ||||
| access->data_init = access->data; | access->data_init = access->data; | ||||
| #if TRUST_NO_ONE | #ifdef DEBUG | ||||
| access->_data_end = access->data_init + (size_t)(verts->vertex_alloc * format->stride); | access->_data_end = access->data_init + (size_t)(verts->vertex_alloc * format->stride); | ||||
| #endif | #endif | ||||
| } | } | ||||
| /* -------- Getters -------- */ | |||||
| /* NOTE: Be careful when using this. The data needs to match the expected format. */ | /* NOTE: Be careful when using this. The data needs to match the expected format. */ | ||||
| void *GPU_vertbuf_get_data(const GPUVertBuf *verts) | void *GPU_vertbuf_get_data(const GPUVertBuf *verts) | ||||
| { | { | ||||
| /* TODO Assert that the format has no padding. */ | /* TODO Assert that the format has no padding. */ | ||||
| return verts->data; | return unwrap(verts)->data; | ||||
| } | } | ||||
| /* Returns the data buffer and set it to null internally to avoid freeing. | /* Returns the data buffer and set it to null internally to avoid freeing. | ||||
| * NOTE: Be careful when using this. The data needs to match the expected format. */ | * NOTE: Be careful when using this. The data needs to match the expected format. */ | ||||
| void *GPU_vertbuf_steal_data(GPUVertBuf *verts) | void *GPU_vertbuf_steal_data(GPUVertBuf *verts_) | ||||
| { | { | ||||
| VertBuf *verts = unwrap(verts_); | |||||
| /* TODO Assert that the format has no padding. */ | /* TODO Assert that the format has no padding. */ | ||||
| BLI_assert(verts->data); | BLI_assert(verts->data); | ||||
| void *data = verts->data; | void *data = verts->data; | ||||
| verts->data = nullptr; | verts->data = nullptr; | ||||
| return data; | return data; | ||||
| } | } | ||||
| const GPUVertFormat *GPU_vertbuf_get_format(const GPUVertBuf *verts) | const GPUVertFormat *GPU_vertbuf_get_format(const GPUVertBuf *verts) | ||||
| { | { | ||||
| return &verts->format; | return &unwrap(verts)->format; | ||||
| } | } | ||||
| uint GPU_vertbuf_get_vertex_alloc(const GPUVertBuf *verts) | uint GPU_vertbuf_get_vertex_alloc(const GPUVertBuf *verts) | ||||
| { | { | ||||
| return verts->vertex_alloc; | return unwrap(verts)->vertex_alloc; | ||||
| } | } | ||||
| uint GPU_vertbuf_get_vertex_len(const GPUVertBuf *verts) | uint GPU_vertbuf_get_vertex_len(const GPUVertBuf *verts) | ||||
| { | { | ||||
| return verts->vertex_len; | return unwrap(verts)->vertex_len; | ||||
| } | } | ||||
| GPUVertBufStatus GPU_vertbuf_get_status(const GPUVertBuf *verts) | GPUVertBufStatus GPU_vertbuf_get_status(const GPUVertBuf *verts) | ||||
| { | { | ||||
| return verts->flag; | return unwrap(verts)->flag; | ||||
| } | } | ||||
| static void VertBuffer_upload_data(GPUVertBuf *verts) | uint GPU_vertbuf_get_memory_usage(void) | ||||
| { | { | ||||
| uint buffer_sz = GPU_vertbuf_size_get(verts); | return VertBuf::memory_usage; | ||||
| /* 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->flag &= ~GPU_VERTBUF_DATA_DIRTY; | |||||
| verts->flag |= GPU_VERTBUF_DATA_UPLOADED; | |||||
| } | } | ||||
| /* Should be rename to GPU_vertbuf_data_upload */ | |||||
| void GPU_vertbuf_use(GPUVertBuf *verts) | void GPU_vertbuf_use(GPUVertBuf *verts) | ||||
| { | { | ||||
| /* only create the buffer the 1st time */ | unwrap(verts)->upload(); | ||||
| if (verts->vbo_id == 0) { | |||||
| verts->vbo_id = GPU_buf_alloc(); | |||||
| } | |||||
| glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id); | |||||
| if (verts->flag & GPU_VERTBUF_DATA_DIRTY) { | |||||
| VertBuffer_upload_data(verts); | |||||
| } | |||||
| } | } | ||||
| uint GPU_vertbuf_get_memory_usage(void) | /** \} */ | ||||
| { | No newline at end of file | ||||
| return vbo_memory_usage; | |||||
| } | |||||