From 4ea93029c65fd4cdb8b707494855120c0f792952 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Sun, 6 Sep 2020 02:46:51 +0200 Subject: GPUIndexBuf: GL backend Isolation This is part of the Vulkan backend task T68990. There is no real change, only making some code re-organisation. This also make the IndexBuf completely abstract from outside the GPU module. --- source/blender/draw/intern/draw_cache_inline.h | 2 +- source/blender/gpu/CMakeLists.txt | 3 + source/blender/gpu/GPU_index_buffer.h | 35 +-- source/blender/gpu/intern/gpu_backend.hh | 2 + source/blender/gpu/intern/gpu_batch.cc | 18 +- source/blender/gpu/intern/gpu_batch_private.hh | 8 + source/blender/gpu/intern/gpu_index_buffer.cc | 248 +++++++++------------ .../blender/gpu/intern/gpu_index_buffer_private.hh | 125 +++++++++++ source/blender/gpu/opengl/gl_backend.hh | 6 + source/blender/gpu/opengl/gl_batch.cc | 28 +-- source/blender/gpu/opengl/gl_batch.hh | 8 + source/blender/gpu/opengl/gl_drawlist.cc | 37 ++- source/blender/gpu/opengl/gl_drawlist.hh | 2 +- source/blender/gpu/opengl/gl_index_buffer.cc | 62 ++++++ source/blender/gpu/opengl/gl_index_buffer.hh | 68 ++++++ source/blender/gpu/opengl/gl_vertex_array.cc | 3 +- 16 files changed, 433 insertions(+), 222 deletions(-) create mode 100644 source/blender/gpu/intern/gpu_index_buffer_private.hh create mode 100644 source/blender/gpu/opengl/gl_index_buffer.cc create mode 100644 source/blender/gpu/opengl/gl_index_buffer.hh (limited to 'source/blender') diff --git a/source/blender/draw/intern/draw_cache_inline.h b/source/blender/draw/intern/draw_cache_inline.h index 0f0e1785a2a..720cc31b0be 100644 --- a/source/blender/draw/intern/draw_cache_inline.h +++ b/source/blender/draw/intern/draw_cache_inline.h @@ -80,7 +80,7 @@ BLI_INLINE bool DRW_ibo_requested(GPUIndexBuf *ibo) { /* TODO do not rely on data uploaded. This prevents multithreading. * (need access to a gl context) */ - return (ibo != NULL && ibo->ibo_id == 0 && ibo->data == NULL); + return (ibo != NULL && !GPU_indexbuf_is_init(ibo)); } BLI_INLINE void DRW_vbo_request(GPUBatch *batch, GPUVertBuf **vbo) diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index c8a827a993d..3bb188c3fa8 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -93,6 +93,7 @@ set(SRC opengl/gl_debug.cc opengl/gl_framebuffer.cc opengl/gl_immediate.cc + opengl/gl_index_buffer.cc opengl/gl_shader.cc opengl/gl_shader_interface.cc opengl/gl_state.cc @@ -136,6 +137,7 @@ set(SRC intern/gpu_drawlist_private.hh intern/gpu_framebuffer_private.hh intern/gpu_immediate_private.hh + intern/gpu_index_buffer_private.hh intern/gpu_material_library.h intern/gpu_matrix_private.h intern/gpu_node_graph.h @@ -155,6 +157,7 @@ set(SRC opengl/gl_drawlist.hh opengl/gl_framebuffer.hh opengl/gl_immediate.hh + opengl/gl_index_buffer.hh opengl/gl_primitive.hh opengl/gl_shader.hh opengl/gl_shader_interface.hh diff --git a/source/blender/gpu/GPU_index_buffer.h b/source/blender/gpu/GPU_index_buffer.h index b966eabefae..09c12c6e177 100644 --- a/source/blender/gpu/GPU_index_buffer.h +++ b/source/blender/gpu/GPU_index_buffer.h @@ -31,40 +31,21 @@ extern "C" { #endif -#define GPU_TRACK_INDEX_RANGE 1 - -typedef enum { - GPU_INDEX_U16, - GPU_INDEX_U32, -} GPUIndexBufType; - -typedef struct GPUIndexBuf { - uint index_start; - uint index_len; - bool is_subrange; -#if GPU_TRACK_INDEX_RANGE - GPUIndexBufType index_type; - uint32_t gl_index_type; - uint base_index; -#endif - uint32_t ibo_id; /* 0 indicates not yet sent to VRAM */ - union { - void *data; /* non-NULL indicates not yet sent to VRAM */ - struct GPUIndexBuf *src; /* if is_subrange is true, this is the source buffer. */ - }; -} GPUIndexBuf; +/** + * IMPORTANT: Do not allocate manually as the real struct is bigger (i.e: GLIndexBuf). This is only + * the common and "public" part of the struct. Use the provided allocator. + * TODO(fclem) Make the content of this struct hidden and expose getters/setters. + **/ +typedef struct GPUIndexBuf GPUIndexBuf; GPUIndexBuf *GPU_indexbuf_calloc(void); -void GPU_indexbuf_use(GPUIndexBuf *); -uint GPU_indexbuf_size_get(const GPUIndexBuf *); - typedef struct GPUIndexBufBuilder { uint max_allowed_index; uint max_index_len; uint index_len; GPUPrimType prim_type; - uint *data; + uint32_t *data; } GPUIndexBufBuilder; /* supports all primitive types. */ @@ -102,6 +83,8 @@ void GPU_indexbuf_create_subrange_in_place(GPUIndexBuf *elem, void GPU_indexbuf_discard(GPUIndexBuf *); +bool GPU_indexbuf_is_init(GPUIndexBuf *ibo); + int GPU_indexbuf_primitive_len(GPUPrimType prim_type); /* Macros */ diff --git a/source/blender/gpu/intern/gpu_backend.hh b/source/blender/gpu/intern/gpu_backend.hh index 330c7d59b6d..b5162fd820f 100644 --- a/source/blender/gpu/intern/gpu_backend.hh +++ b/source/blender/gpu/intern/gpu_backend.hh @@ -33,6 +33,7 @@ namespace gpu { class Batch; class DrawList; class FrameBuffer; +class IndexBuf; class Shader; class Texture; class UniformBuf; @@ -50,6 +51,7 @@ class GPUBackend { virtual Batch *batch_alloc(void) = 0; virtual DrawList *drawlist_alloc(int list_length) = 0; virtual FrameBuffer *framebuffer_alloc(const char *name) = 0; + virtual IndexBuf *indexbuf_alloc(void) = 0; virtual Shader *shader_alloc(const char *name) = 0; virtual Texture *texture_alloc(const char *name) = 0; virtual UniformBuf *uniformbuf_alloc(int size, const char *name) = 0; diff --git a/source/blender/gpu/intern/gpu_batch.cc b/source/blender/gpu/intern/gpu_batch.cc index 0b0c88a42e2..75419e1a242 100644 --- a/source/blender/gpu/intern/gpu_batch.cc +++ b/source/blender/gpu/intern/gpu_batch.cc @@ -38,13 +38,10 @@ #include "gpu_backend.hh" #include "gpu_batch_private.hh" #include "gpu_context_private.hh" +#include "gpu_index_buffer_private.hh" #include "gpu_shader_private.hh" #include "gpu_vertex_format_private.h" -#include "gl_primitive.hh" /* TODO remove */ - -#include -#include #include using namespace blender::gpu; @@ -257,12 +254,19 @@ void GPU_batch_draw_instanced(GPUBatch *batch, int i_count) GPU_shader_unbind(); } -void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_first, int i_count) +void GPU_batch_draw_advanced( + GPUBatch *gpu_batch, int v_first, int v_count, int i_first, int i_count) { BLI_assert(GPU_context_active_get()->shader != NULL); + Batch *batch = static_cast(gpu_batch); if (v_count == 0) { - v_count = (batch->elem) ? batch->elem->index_len : batch->verts[0]->vertex_len; + if (batch->elem) { + v_count = batch->elem_()->index_len_get(); + } + else { + v_count = batch->verts[0]->vertex_len; + } } if (i_count == 0) { i_count = (batch->inst[0]) ? batch->inst[0]->vertex_len : 1; @@ -277,7 +281,7 @@ void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_fi return; } - static_cast(batch)->draw(v_first, v_count, i_first, i_count); + batch->draw(v_first, v_count, i_first, i_count); } /** \} */ diff --git a/source/blender/gpu/intern/gpu_batch_private.hh b/source/blender/gpu/intern/gpu_batch_private.hh index c0444647fe1..dae9c885ee1 100644 --- a/source/blender/gpu/intern/gpu_batch_private.hh +++ b/source/blender/gpu/intern/gpu_batch_private.hh @@ -29,6 +29,8 @@ #include "GPU_batch.h" #include "GPU_context.h" +#include "gpu_index_buffer_private.hh" + namespace blender { namespace gpu { @@ -42,6 +44,12 @@ class Batch : public GPUBatch { virtual ~Batch(){}; virtual void draw(int v_first, int v_count, int i_first, int i_count) = 0; + + /* Convenience casts. */ + IndexBuf *elem_(void) + { + return unwrap(elem); + }; }; } // namespace gpu diff --git a/source/blender/gpu/intern/gpu_index_buffer.cc b/source/blender/gpu/intern/gpu_index_buffer.cc index 832c5dc76b2..5448e6efbe4 100644 --- a/source/blender/gpu/intern/gpu_index_buffer.cc +++ b/source/blender/gpu/intern/gpu_index_buffer.cc @@ -25,55 +25,22 @@ #include "MEM_guardedalloc.h" -#include "GPU_glew.h" -#include "GPU_index_buffer.h" +#include "BLI_utildefines.h" -#include "gpu_context_private.hh" +#include "gpu_backend.hh" -#include +#include "gpu_index_buffer_private.hh" #define KEEP_SINGLE_COPY 1 #define RESTART_INDEX 0xFFFFFFFF -static GLenum convert_index_type_to_gl(GPUIndexBufType type) -{ -#if GPU_TRACK_INDEX_RANGE - return (type == GPU_INDEX_U32) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT; -#else - return GL_UNSIGNED_INT; -#endif -} - -uint GPU_indexbuf_size_get(const GPUIndexBuf *elem) -{ -#if GPU_TRACK_INDEX_RANGE - return elem->index_len * - ((elem->index_type == GPU_INDEX_U32) ? sizeof(GLuint) : sizeof(GLshort)); -#else - return elem->index_len * sizeof(GLuint); -#endif -} +/* -------------------------------------------------------------------- */ +/** \name IndexBufBuilder + * \{ */ -int GPU_indexbuf_primitive_len(GPUPrimType prim_type) -{ - switch (prim_type) { - case GPU_PRIM_POINTS: - return 1; - case GPU_PRIM_LINES: - return 2; - case GPU_PRIM_TRIS: - return 3; - case GPU_PRIM_LINES_ADJ: - return 4; - default: - break; - } -#if TRUST_NO_ONE - assert(false); -#endif - return -1; -} +using namespace blender; +using namespace blender::gpu; void GPU_indexbuf_init_ex(GPUIndexBufBuilder *builder, GPUPrimType prim_type, @@ -237,46 +204,69 @@ void GPU_indexbuf_set_tri_restart(GPUIndexBufBuilder *builder, uint elem) } } -GPUIndexBuf *GPU_indexbuf_create_subrange(GPUIndexBuf *elem_src, uint start, uint length) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Creation & Deletion + * \{ */ + +namespace blender::gpu { + +IndexBuf::~IndexBuf() { - GPUIndexBuf *elem = (GPUIndexBuf *)MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf"); - GPU_indexbuf_create_subrange_in_place(elem, elem_src, start, length); - return elem; + if (!is_subrange_) { + MEM_SAFE_FREE(data_); + } } -void GPU_indexbuf_create_subrange_in_place(GPUIndexBuf *elem, - GPUIndexBuf *elem_src, - uint start, - uint length) +void IndexBuf::init(uint indices_len, uint32_t *indices) { - BLI_assert(elem_src && !elem_src->is_subrange); - BLI_assert((length == 0) || (start + length <= elem_src->index_len)); + is_init_ = true; + data_ = indices; + index_start_ = 0; + index_len_ = indices_len; + #if GPU_TRACK_INDEX_RANGE - elem->index_type = elem_src->index_type; - elem->gl_index_type = elem_src->gl_index_type; - elem->base_index = elem_src->base_index; + /* Everything remains 32 bit while building to keep things simple. + * Find min/max after, then convert to smallest index type possible. */ + uint min_index, max_index; + uint range = this->index_range(&min_index, &max_index); + /* count the primitive restart index. */ + range += 1; + + if (range <= 0xFFFF) { + index_type_ = GPU_INDEX_U16; + this->squeeze_indices_short(min_index, max_index); + } #endif - elem->is_subrange = true; - elem->src = elem_src; - elem->index_start = start; - elem->index_len = length; } -#if GPU_TRACK_INDEX_RANGE -/* Everything remains 32 bit while building to keep things simple. - * Find min/max after, then convert to smallest index type possible. */ +void IndexBuf::init_subrange(IndexBuf *elem_src, uint start, uint length) +{ + /* We don't support nested subranges. */ + BLI_assert(elem_src && elem_src->is_subrange_ == false); + BLI_assert((length == 0) || (start + length <= elem_src->index_len_)); + + is_init_ = true; + is_subrange_ = true; + src_ = elem_src; + index_start_ = start; + index_len_ = length; + index_base_ = elem_src->index_base_; + index_type_ = elem_src->index_type_; +} -static uint index_range(const uint values[], uint value_len, uint *min_out, uint *max_out) +uint IndexBuf::index_range(uint *r_min, uint *r_max) { - if (value_len == 0) { - *min_out = 0; - *max_out = 0; + if (index_len_ == 0) { + *r_min = *r_max = 0; return 0; } + const uint32_t *uint_idx = (uint32_t *)data_; uint min_value = RESTART_INDEX; uint max_value = 0; - for (uint i = 0; i < value_len; i++) { - const uint value = values[i]; + for (uint i = 0; i < index_len_; i++) { + const uint value = uint_idx[i]; if (value == RESTART_INDEX) { continue; } @@ -288,120 +278,92 @@ static uint index_range(const uint values[], uint value_len, uint *min_out, uint } } if (min_value == RESTART_INDEX) { - *min_out = 0; - *max_out = 0; + *r_min = *r_max = 0; return 0; } - - *min_out = min_value; - *max_out = max_value; + *r_min = min_value; + *r_max = max_value; return max_value - min_value; } -static void squeeze_indices_short(GPUIndexBufBuilder *builder, - GPUIndexBuf *elem, - uint min_index, - uint max_index) +void IndexBuf::squeeze_indices_short(uint min_idx, uint max_idx) { - const uint *values = builder->data; - const uint index_len = elem->index_len; - /* data will never be *larger* than builder->data... * converting in place to avoid extra allocation */ - GLushort *data = (GLushort *)builder->data; + uint16_t *ushort_idx = (uint16_t *)data_; + const uint32_t *uint_idx = (uint32_t *)data_; - if (max_index >= 0xFFFF) { - elem->base_index = min_index; - for (uint i = 0; i < index_len; i++) { - data[i] = (values[i] == RESTART_INDEX) ? 0xFFFF : (GLushort)(values[i] - min_index); + if (max_idx >= 0xFFFF) { + index_base_ = min_idx; + for (uint i = 0; i < index_len_; i++) { + ushort_idx[i] = (uint16_t)MAX2(0xFFFF, uint_idx[i] - min_idx); } } else { - elem->base_index = 0; - for (uint i = 0; i < index_len; i++) { - data[i] = (GLushort)(values[i]); + index_base_ = 0; + for (uint i = 0; i < index_len_; i++) { + ushort_idx[i] = (uint16_t)(uint_idx[i]); } } } -#endif /* GPU_TRACK_INDEX_RANGE */ +} // namespace blender::gpu + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name C-API + * \{ */ GPUIndexBuf *GPU_indexbuf_calloc(void) { - return (GPUIndexBuf *)MEM_callocN(sizeof(GPUIndexBuf), __func__); + return wrap(GPUBackend::get()->indexbuf_alloc()); } GPUIndexBuf *GPU_indexbuf_build(GPUIndexBufBuilder *builder) { - GPUIndexBuf *elem = (GPUIndexBuf *)MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf"); + GPUIndexBuf *elem = GPU_indexbuf_calloc(); GPU_indexbuf_build_in_place(builder, elem); return elem; } -void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *builder, GPUIndexBuf *elem) +GPUIndexBuf *GPU_indexbuf_create_subrange(GPUIndexBuf *elem_src, uint start, uint length) { -#if TRUST_NO_ONE - assert(builder->data != NULL); -#endif - elem->index_len = builder->index_len; - elem->ibo_id = 0; /* Created at first use. */ - -#if GPU_TRACK_INDEX_RANGE - uint min_index, max_index; - uint range = index_range(builder->data, builder->index_len, &min_index, &max_index); - - /* count the primitive restart index. */ - range += 1; - - if (range <= 0xFFFF) { - elem->index_type = GPU_INDEX_U16; - squeeze_indices_short(builder, elem, min_index, max_index); - } - else { - elem->index_type = GPU_INDEX_U32; - elem->base_index = 0; - } - elem->gl_index_type = convert_index_type_to_gl(elem->index_type); -#endif + GPUIndexBuf *elem = GPU_indexbuf_calloc(); + GPU_indexbuf_create_subrange_in_place(elem, elem_src, start, length); + return elem; +} +void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *builder, GPUIndexBuf *elem) +{ + BLI_assert(builder->data != NULL); /* Transfer data ownership to GPUIndexBuf. * It will be uploaded upon first use. */ - elem->data = builder->data; - builder->data = NULL; - /* other fields are safe to leave */ + unwrap(elem)->init(builder->index_len, builder->data); + builder->data = nullptr; } -static void indexbuf_upload_data(GPUIndexBuf *elem) +void GPU_indexbuf_create_subrange_in_place(GPUIndexBuf *elem, + GPUIndexBuf *elem_src, + uint start, + uint length) { - /* send data to GPU */ - glBufferData(GL_ELEMENT_ARRAY_BUFFER, GPU_indexbuf_size_get(elem), elem->data, GL_STATIC_DRAW); - /* No need to keep copy of data in system memory. */ - MEM_freeN(elem->data); - elem->data = NULL; + unwrap(elem)->init_subrange(unwrap(elem_src), start, length); } -void GPU_indexbuf_use(GPUIndexBuf *elem) +void GPU_indexbuf_discard(GPUIndexBuf *elem) { - if (elem->is_subrange) { - GPU_indexbuf_use(elem->src); - return; - } - if (elem->ibo_id == 0) { - elem->ibo_id = GPU_buf_alloc(); - } - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->ibo_id); - if (elem->data != NULL) { - indexbuf_upload_data(elem); - } + delete unwrap(elem); } -void GPU_indexbuf_discard(GPUIndexBuf *elem) +bool GPU_indexbuf_is_init(GPUIndexBuf *elem) { - if (elem->ibo_id) { - GPU_buf_free(elem->ibo_id); - } - if (!elem->is_subrange && elem->data) { - MEM_freeN(elem->data); - } - MEM_freeN(elem); + return unwrap(elem)->is_init(); } + +int GPU_indexbuf_primitive_len(GPUPrimType prim_type) +{ + return indices_per_primitive(prim_type); +} + +/** \} */ diff --git a/source/blender/gpu/intern/gpu_index_buffer_private.hh b/source/blender/gpu/intern/gpu_index_buffer_private.hh new file mode 100644 index 00000000000..9f1334aa4bc --- /dev/null +++ b/source/blender/gpu/intern/gpu_index_buffer_private.hh @@ -0,0 +1,125 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "BLI_assert.h" + +#include "GPU_index_buffer.h" + +#define GPU_TRACK_INDEX_RANGE 1 + +namespace blender::gpu { + +typedef enum { + GPU_INDEX_U16, + GPU_INDEX_U32, +} GPUIndexBufType; + +static inline size_t to_bytesize(GPUIndexBufType type) +{ + return (type == GPU_INDEX_U32) ? sizeof(uint32_t) : sizeof(uint16_t); +} + +/** + * Base class which is then specialized for each implementation (GL, VK, ...). + * + * NOTE: IndexBuf does not hold any GPUPrimType. This is because it can be interpreted + * differently by multiple batches. + **/ +class IndexBuf { + protected: + /** Type of indices used inside this buffer. */ + GPUIndexBufType index_type_ = GPU_INDEX_U32; + /** Offset in this buffer to the first index to render. Is 0 if not a subrange. */ + uint32_t index_start_ = 0; + /** Number of indices to render. */ + uint32_t index_len_ = 0; + /** Base index: Added to all indices after fetching. Allows index compression. */ + uint32_t index_base_ = 0; + /** Bookeeping. */ + bool is_init_ = false; + /** Is this object only a reference to a subrange of another IndexBuf. */ + bool is_subrange_ = false; + + union { + /** Mapped buffer data. non-NULL indicates not yet sent to VRAM. */ + void *data_ = nullptr; + /** If is_subrange is true, this is the source index buffer. */ + IndexBuf *src_; + }; + + public: + IndexBuf(){}; + virtual ~IndexBuf(); + + void init(uint indices_len, uint32_t *indices); + void init_subrange(IndexBuf *elem_src, uint start, uint length); + + uint32_t index_len_get(void) const + { + return index_len_; + } + /* Return size in byte of the drawable data buffer range. Actual buffer size might be bigger. */ + size_t size_get(void) + { + return index_len_ * to_bytesize(index_type_); + }; + + bool is_init(void) const + { + return is_init_; + }; + + private: + inline void squeeze_indices_short(uint min_idx, uint max_idx); + inline uint index_range(uint *r_min, uint *r_max); +}; + +/* Syntacting suggar. */ +static inline GPUIndexBuf *wrap(IndexBuf *indexbuf) +{ + return reinterpret_cast(indexbuf); +} +static inline IndexBuf *unwrap(GPUIndexBuf *indexbuf) +{ + return reinterpret_cast(indexbuf); +} + +static inline int indices_per_primitive(GPUPrimType prim_type) +{ + switch (prim_type) { + case GPU_PRIM_POINTS: + return 1; + case GPU_PRIM_LINES: + return 2; + case GPU_PRIM_TRIS: + return 3; + case GPU_PRIM_LINES_ADJ: + return 4; + default: + return -1; + } +} + +} // namespace blender::gpu diff --git a/source/blender/gpu/opengl/gl_backend.hh b/source/blender/gpu/opengl/gl_backend.hh index f769d9c1cfe..a31a4a45f56 100644 --- a/source/blender/gpu/opengl/gl_backend.hh +++ b/source/blender/gpu/opengl/gl_backend.hh @@ -31,6 +31,7 @@ #include "gl_context.hh" #include "gl_drawlist.hh" #include "gl_framebuffer.hh" +#include "gl_index_buffer.hh" #include "gl_shader.hh" #include "gl_texture.hh" #include "gl_uniform_buffer.hh" @@ -82,6 +83,11 @@ class GLBackend : public GPUBackend { return new GLFrameBuffer(name); }; + IndexBuf *indexbuf_alloc(void) + { + return new GLIndexBuf(); + }; + Shader *shader_alloc(const char *name) { return new GLShader(name); diff --git a/source/blender/gpu/opengl/gl_batch.cc b/source/blender/gpu/opengl/gl_batch.cc index bb7d5654efd..c735d02500b 100644 --- a/source/blender/gpu/opengl/gl_batch.cc +++ b/source/blender/gpu/opengl/gl_batch.cc @@ -34,12 +34,14 @@ #include "gpu_batch_private.hh" #include "gpu_shader_private.hh" -#include "gl_batch.hh" #include "gl_context.hh" #include "gl_debug.hh" +#include "gl_index_buffer.hh" #include "gl_primitive.hh" #include "gl_vertex_array.hh" +#include "gl_batch.hh" + using namespace blender::gpu; /* -------------------------------------------------------------------- */ @@ -295,14 +297,6 @@ GLBatch::~GLBatch() /** \name Drawing * \{ */ -#if GPU_TRACK_INDEX_RANGE -# define BASE_INDEX(el) ((el)->base_index) -# define INDEX_TYPE(el) ((el)->gl_index_type) -#else -# define BASE_INDEX(el) 0 -# define INDEX_TYPE(el) GL_UNSIGNED_INT -#endif - void GLBatch::bind(int i_first) { GPU_context_active_get()->state_manager->apply_state(); @@ -315,7 +309,7 @@ void GLBatch::bind(int i_first) #if GPU_TRACK_INDEX_RANGE /* Can be removed if GL 4.3 is required. */ if (!GLEW_ARB_ES3_compatibility && (elem != NULL)) { - glPrimitiveRestartIndex((elem->index_type == GPU_INDEX_U16) ? 0xFFFFu : 0xFFFFFFFFu); + glPrimitiveRestartIndex(this->gl_elem()->restart_index()); } #endif @@ -340,16 +334,10 @@ void GLBatch::draw(int v_first, int v_count, int i_first, int i_count) GLenum gl_type = to_gl(prim_type); if (elem) { - const GPUIndexBuf *el = elem; - GLenum index_type = INDEX_TYPE(el); - GLint base_index = BASE_INDEX(el); - void *v_first_ofs = (GLuint *)0 + v_first + el->index_start; - -#if GPU_TRACK_INDEX_RANGE - if (el->index_type == GPU_INDEX_U16) { - v_first_ofs = (GLushort *)0 + v_first + el->index_start; - } -#endif + const GLIndexBuf *el = this->gl_elem(); + GLenum index_type = to_gl(el->index_type_); + GLint base_index = el->index_base_; + void *v_first_ofs = el->offset_ptr(v_first); if (GPU_arb_base_instance_is_supported()) { glDrawElementsInstancedBaseVertexBaseInstance( diff --git a/source/blender/gpu/opengl/gl_batch.hh b/source/blender/gpu/opengl/gl_batch.hh index 9399148c68d..e6d9542fc3b 100644 --- a/source/blender/gpu/opengl/gl_batch.hh +++ b/source/blender/gpu/opengl/gl_batch.hh @@ -30,6 +30,8 @@ #include "gpu_batch_private.hh" +#include "gl_index_buffer.hh" + #include "glew-mx.h" namespace blender { @@ -99,6 +101,12 @@ class GLBatch : public Batch { void draw(int v_first, int v_count, int i_first, int i_count) override; void bind(int i_first); + /* Convenience getters. */ + GLIndexBuf *gl_elem(void) + { + return static_cast(unwrap(elem)); + } + MEM_CXX_CLASS_ALLOC_FUNCS("GLBatch"); }; diff --git a/source/blender/gpu/opengl/gl_drawlist.cc b/source/blender/gpu/opengl/gl_drawlist.cc index 35fecc859b8..9670e580819 100644 --- a/source/blender/gpu/opengl/gl_drawlist.cc +++ b/source/blender/gpu/opengl/gl_drawlist.cc @@ -42,15 +42,6 @@ #define USE_MULTI_DRAW_INDIRECT 1 -/* TODO remove. */ -#if GPU_TRACK_INDEX_RANGE -# define BASE_INDEX(el) ((el)->base_index) -# define INDEX_TYPE(el) ((el)->gl_index_type) -#else -# define BASE_INDEX(el) 0 -# define INDEX_TYPE(el) GL_UNSIGNED_INT -#endif - using namespace blender::gpu; typedef struct GLDrawCommand { @@ -129,11 +120,11 @@ void GLDrawList::init(void) command_offset_ = 0; } -void GLDrawList::append(GPUBatch *batch, int i_first, int i_count) +void GLDrawList::append(GPUBatch *gpu_batch, int i_first, int i_count) { /* Fallback when MultiDrawIndirect is not supported/enabled. */ if (MDI_DISABLED) { - GPU_batch_draw_advanced(batch, 0, 0, i_first, i_count); + GPU_batch_draw_advanced(gpu_batch, 0, 0, i_first, i_count); return; } @@ -141,14 +132,16 @@ void GLDrawList::append(GPUBatch *batch, int i_first, int i_count) this->init(); } + GLBatch *batch = static_cast(gpu_batch); if (batch != batch_) { // BLI_assert(batch->flag | GPU_BATCH_INIT); this->submit(); batch_ = batch; /* Cached for faster access. */ - base_index_ = batch->elem ? BASE_INDEX(batch->elem) : UINT_MAX; - v_first_ = batch->elem ? batch->elem->index_start : 0; - v_count_ = batch->elem ? batch->elem->index_len : batch->verts[0]->vertex_len; + GLIndexBuf *el = batch_->gl_elem(); + base_index_ = el ? el->index_base_ : UINT_MAX; + v_first_ = el ? el->index_start_ : 0; + v_count_ = el ? el->index_len_ : batch->verts[0]->vertex_len; } if (v_count_ == 0) { @@ -191,12 +184,9 @@ void GLDrawList::submit(void) BLI_assert(data_); BLI_assert(GPU_context_active_get()->shader != NULL); - GLBatch *batch = static_cast(batch_); - /* Only do multi-draw indirect if doing more than 2 drawcall. This avoids the overhead of * buffer mapping if scene is not very instance friendly. BUT we also need to take into - * account the - * case where only a few instances are needed to finish filling a call buffer. */ + * account the case where only a few instances are needed to finish filling a call buffer. */ const bool is_finishing_a_buffer = (command_offset_ >= data_size_); if (command_len_ > 2 || is_finishing_a_buffer) { GLenum prim = to_gl(batch_->prim_type); @@ -208,10 +198,11 @@ void GLDrawList::submit(void) data_ = NULL; /* Unmapped */ data_offset_ += command_offset_; - batch->bind(0); + batch_->bind(0); if (MDI_INDEXED) { - glMultiDrawElementsIndirect(prim, INDEX_TYPE(batch_->elem), offset, command_len_, 0); + GLenum gl_type = to_gl(batch_->gl_elem()->index_type_); + glMultiDrawElementsIndirect(prim, gl_type, offset, command_len_, 0); } else { glMultiDrawArraysIndirect(prim, offset, command_len_, 0); @@ -223,8 +214,8 @@ void GLDrawList::submit(void) GLDrawCommandIndexed *cmd = (GLDrawCommandIndexed *)data_; for (int i = 0; i < command_len_; i++, cmd++) { /* Index start was already added. Avoid counting it twice. */ - cmd->v_first -= batch->elem->index_start; - batch->draw(cmd->v_first, cmd->v_count, cmd->i_first, cmd->i_count); + cmd->v_first -= v_first_; + batch_->draw(cmd->v_first, cmd->v_count, cmd->i_first, cmd->i_count); } /* Reuse the same data. */ command_offset_ -= command_len_ * sizeof(GLDrawCommandIndexed); @@ -232,7 +223,7 @@ void GLDrawList::submit(void) else { GLDrawCommand *cmd = (GLDrawCommand *)data_; for (int i = 0; i < command_len_; i++, cmd++) { - batch->draw(cmd->v_first, cmd->v_count, cmd->i_first, cmd->i_count); + batch_->draw(cmd->v_first, cmd->v_count, cmd->i_first, cmd->i_count); } /* Reuse the same data. */ command_offset_ -= command_len_ * sizeof(GLDrawCommand); diff --git a/source/blender/gpu/opengl/gl_drawlist.hh b/source/blender/gpu/opengl/gl_drawlist.hh index b690b8f8a98..3a731559e3a 100644 --- a/source/blender/gpu/opengl/gl_drawlist.hh +++ b/source/blender/gpu/opengl/gl_drawlist.hh @@ -55,7 +55,7 @@ class GLDrawList : public DrawList { void init(void); /** Batch for which we are recording commands for. */ - GPUBatch *batch_; + GLBatch *batch_; /** Mapped memory bounds. */ GLbyte *data_; /** Length of the mapped buffer (in byte). */ diff --git a/source/blender/gpu/opengl/gl_index_buffer.cc b/source/blender/gpu/opengl/gl_index_buffer.cc new file mode 100644 index 00000000000..03a9607a00b --- /dev/null +++ b/source/blender/gpu/opengl/gl_index_buffer.cc @@ -0,0 +1,62 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#include "gl_backend.hh" +#include "gl_debug.hh" + +#include "gl_index_buffer.hh" + +namespace blender::gpu { + +GLIndexBuf::~GLIndexBuf() +{ + GLBackend::get()->buf_free(ibo_id_); +} + +void GLIndexBuf::bind(void) +{ + if (is_subrange_) { + static_cast(src_)->bind(); + return; + } + + if (ibo_id_ == 0) { + glGenBuffers(1, &ibo_id_); + + if (data_ == nullptr) { + debug::raise_gl_error("Trying to use Index Buffer but the buffer contains no data"); + } + } + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_id_); + + if (data_ != nullptr) { + size_t size = this->size_get(); + /* Sends data to GPU. */ + glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data_, GL_STATIC_DRAW); + /* No need to keep copy of data in system memory. */ + MEM_SAFE_FREE(data_); + } +} + +} // namespace blender::gpu \ No newline at end of file diff --git a/source/blender/gpu/opengl/gl_index_buffer.hh b/source/blender/gpu/opengl/gl_index_buffer.hh new file mode 100644 index 00000000000..b84934bb77f --- /dev/null +++ b/source/blender/gpu/opengl/gl_index_buffer.hh @@ -0,0 +1,68 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "MEM_guardedalloc.h" + +#include "gpu_index_buffer_private.hh" + +#include "glew-mx.h" + +namespace blender::gpu { + +class GLIndexBuf : public IndexBuf { + friend class GLBatch; + friend class GLDrawList; + + private: + GLuint ibo_id_ = 0; + + public: + ~GLIndexBuf(); + + void bind(void); + + void *offset_ptr(uint additional_vertex_offset) const + { + additional_vertex_offset += index_start_; + if (index_type_ == GPU_INDEX_U32) { + return (GLuint *)0 + additional_vertex_offset; + } + return (GLushort *)0 + additional_vertex_offset; + } + + GLuint restart_index(void) const + { + return (index_type_ == GPU_INDEX_U16) ? 0xFFFFu : 0xFFFFFFFFu; + } + + MEM_CXX_CLASS_ALLOC_FUNCS("GLIndexBuf") +}; + +static inline GLenum to_gl(GPUIndexBufType type) +{ + return (type == GPU_INDEX_U32) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT; +} + +} // namespace blender::gpu diff --git a/source/blender/gpu/opengl/gl_vertex_array.cc b/source/blender/gpu/opengl/gl_vertex_array.cc index 64d44c39587..358b92a9979 100644 --- a/source/blender/gpu/opengl/gl_vertex_array.cc +++ b/source/blender/gpu/opengl/gl_vertex_array.cc @@ -30,6 +30,7 @@ #include "gl_batch.hh" #include "gl_context.hh" +#include "gl_index_buffer.hh" #include "gl_vertex_array.hh" @@ -151,7 +152,7 @@ void GLVertArray::update_bindings(const GLuint vao, if (batch->elem) { /* Binds the index buffer. This state is also saved in the VAO. */ - GPU_indexbuf_use(batch->elem); + static_cast(unwrap(batch->elem))->bind(); } } -- cgit v1.2.3