Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2020-08-08 16:24:52 +0300
committerClément Foucault <foucault.clem@gmail.com>2020-08-13 15:20:23 +0300
commit38ef35b1ed1d38ab58c7d7fb121f4f3b33869810 (patch)
tree6b3d8317b9e43a5875eb05cadb79ce2ebae859de /source/blender/gpu
parentcb2565195e72ee4dc5c0b53b7cd5037b2169d55f (diff)
GPUDrawList: GL backend isolation
Diffstat (limited to 'source/blender/gpu')
-rw-r--r--source/blender/gpu/CMakeLists.txt5
-rw-r--r--source/blender/gpu/GPU_batch.h13
-rw-r--r--source/blender/gpu/GPU_drawlist.h46
-rw-r--r--source/blender/gpu/intern/gpu_backend.hh12
-rw-r--r--source/blender/gpu/intern/gpu_batch.cc187
-rw-r--r--source/blender/gpu/intern/gpu_context.cc10
-rw-r--r--source/blender/gpu/intern/gpu_drawlist.cc59
-rw-r--r--source/blender/gpu/intern/gpu_drawlist_private.hh40
-rw-r--r--source/blender/gpu/opengl/gl_backend.hh6
-rw-r--r--source/blender/gpu/opengl/gl_drawlist.cc238
-rw-r--r--source/blender/gpu/opengl/gl_drawlist.hh80
11 files changed, 489 insertions, 207 deletions
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 80ea28aca3c..fe5c5d4fa7b 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -63,6 +63,7 @@ set(SRC
intern/gpu_codegen.c
intern/gpu_context.cc
intern/gpu_debug.cc
+ intern/gpu_drawlist.cc
intern/gpu_element.cc
intern/gpu_extensions.cc
intern/gpu_framebuffer.cc
@@ -89,6 +90,7 @@ set(SRC
intern/gpu_viewport.c
opengl/gl_context.cc
+ opengl/gl_drawlist.cc
GPU_attr_binding.h
GPU_batch.h
@@ -98,6 +100,7 @@ set(SRC
GPU_common.h
GPU_context.h
GPU_debug.h
+ GPU_drawlist.h
GPU_element.h
GPU_extensions.h
GPU_framebuffer.h
@@ -125,6 +128,7 @@ set(SRC
intern/gpu_batch_private.h
intern/gpu_codegen.h
intern/gpu_context_private.hh
+ intern/gpu_drawlist_private.hh
intern/gpu_material_library.h
intern/gpu_matrix_private.h
intern/gpu_node_graph.h
@@ -136,6 +140,7 @@ set(SRC
opengl/gl_backend.hh
opengl/gl_context.hh
+ opengl/gl_drawlist.hh
)
set(LIB
diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h
index 855214c279c..4b79b175fec 100644
--- a/source/blender/gpu/GPU_batch.h
+++ b/source/blender/gpu/GPU_batch.h
@@ -199,19 +199,6 @@ GPUBatch *create_BatchInGeneral(GPUPrimType, VertexBufferStuff, ElementListStuff
#endif /* future plans */
-/**
- * #GPUDrawList is an API to do lots of similar draw-calls very fast using multi-draw-indirect.
- * There is a fallback if the feature is not supported.
- */
-typedef struct GPUDrawList GPUDrawList;
-
-GPUDrawList *GPU_draw_list_create(int length);
-void GPU_draw_list_discard(GPUDrawList *list);
-void GPU_draw_list_init(GPUDrawList *list, GPUBatch *batch);
-void GPU_draw_list_command_add(
- GPUDrawList *list, int v_first, int v_count, int i_first, int i_count);
-void GPU_draw_list_submit(GPUDrawList *list);
-
void gpu_batch_init(void);
void gpu_batch_exit(void);
diff --git a/source/blender/gpu/GPU_drawlist.h b/source/blender/gpu/GPU_drawlist.h
new file mode 100644
index 00000000000..27f70da8cf8
--- /dev/null
+++ b/source/blender/gpu/GPU_drawlist.h
@@ -0,0 +1,46 @@
+/*
+ * 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
+ *
+ * GPUDrawList is an API to do lots of similar draw-calls very fast using
+ * multi-draw-indirect. There is a fallback if the feature is not supported.
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct GPUBatch;
+
+typedef void *GPUDrawList; /* Opaque pointer. */
+
+/* Create a list with at least length drawcalls. Length can affect performance. */
+GPUDrawList GPU_draw_list_create(int length);
+void GPU_draw_list_discard(GPUDrawList list);
+
+void GPU_draw_list_append(GPUDrawList list, GPUBatch *batch, int i_first, int i_count);
+void GPU_draw_list_submit(GPUDrawList list);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/gpu/intern/gpu_backend.hh b/source/blender/gpu/intern/gpu_backend.hh
index 24f592f214f..4dd6036e672 100644
--- a/source/blender/gpu/intern/gpu_backend.hh
+++ b/source/blender/gpu/intern/gpu_backend.hh
@@ -25,13 +25,21 @@
#pragma once
-struct GPUContext;
+#include "gpu_context_private.hh"
+#include "gpu_drawlist_private.hh"
+
+namespace blender {
+namespace gpu {
class GPUBackend {
public:
virtual ~GPUBackend(){};
+ static GPUBackend *get(void);
+
virtual GPUContext *context_alloc(void *ghost_window) = 0;
+ virtual DrawList *drawlist_alloc(int list_length) = 0;
};
-GPUBackend *gpu_backend_get(void);
+} // namespace gpu
+} // namespace blender
diff --git a/source/blender/gpu/intern/gpu_batch.cc b/source/blender/gpu/intern/gpu_batch.cc
index a6ba4d3d89a..5b8a3c4636b 100644
--- a/source/blender/gpu/intern/gpu_batch.cc
+++ b/source/blender/gpu/intern/gpu_batch.cc
@@ -796,193 +796,6 @@ void GPU_draw_primitive(GPUPrimType prim_type, int v_count)
}
/* -------------------------------------------------------------------- */
-/** \name Indirect Draw Calls
- * \{ */
-
-#if 0
-# define USE_MULTI_DRAW_INDIRECT 0
-#else
-# define USE_MULTI_DRAW_INDIRECT \
- (GL_ARB_multi_draw_indirect && GPU_arb_base_instance_is_supported())
-#endif
-
-typedef struct GPUDrawCommand {
- uint v_count;
- uint i_count;
- uint v_first;
- uint i_first;
-} GPUDrawCommand;
-
-typedef struct GPUDrawCommandIndexed {
- uint v_count;
- uint i_count;
- uint v_first;
- uint base_index;
- uint i_first;
-} GPUDrawCommandIndexed;
-
-struct GPUDrawList {
- GPUBatch *batch;
- uint base_index; /* Avoid dereferencing batch. */
- uint cmd_offset; /* in bytes, offset inside indirect command buffer. */
- uint cmd_len; /* Number of used command for the next call. */
- uint buffer_size; /* in bytes, size of indirect command buffer. */
- GLuint buffer_id; /* Draw Indirect Buffer id */
- union {
- GPUDrawCommand *commands;
- GPUDrawCommandIndexed *commands_indexed;
- };
-};
-
-GPUDrawList *GPU_draw_list_create(int length)
-{
- GPUDrawList *list = (GPUDrawList *)MEM_callocN(sizeof(GPUDrawList), "GPUDrawList");
- /* Alloc the biggest possible command list which is indexed. */
- list->buffer_size = sizeof(GPUDrawCommandIndexed) * length;
- if (USE_MULTI_DRAW_INDIRECT) {
- list->buffer_id = GPU_buf_alloc();
- glBindBuffer(GL_DRAW_INDIRECT_BUFFER, list->buffer_id);
- glBufferData(GL_DRAW_INDIRECT_BUFFER, list->buffer_size, NULL, GL_DYNAMIC_DRAW);
- }
- else {
- list->commands = (GPUDrawCommand *)MEM_mallocN(list->buffer_size, "GPUDrawList data");
- }
- return list;
-}
-
-void GPU_draw_list_discard(GPUDrawList *list)
-{
- if (list->buffer_id) {
- GPU_buf_free(list->buffer_id);
- }
- else {
- MEM_SAFE_FREE(list->commands);
- }
- MEM_freeN(list);
-}
-
-void GPU_draw_list_init(GPUDrawList *list, GPUBatch *batch)
-{
- BLI_assert(batch->phase == GPU_BATCH_READY_TO_DRAW);
- list->batch = batch;
- list->base_index = batch->elem ? BASE_INDEX(batch->elem) : UINT_MAX;
- list->cmd_len = 0;
-
- if (USE_MULTI_DRAW_INDIRECT) {
- if (list->commands == NULL) {
- glBindBuffer(GL_DRAW_INDIRECT_BUFFER, list->buffer_id);
- if (list->cmd_offset >= list->buffer_size) {
- /* Orphan buffer data and start fresh. */
- glBufferData(GL_DRAW_INDIRECT_BUFFER, list->buffer_size, NULL, GL_DYNAMIC_DRAW);
- list->cmd_offset = 0;
- }
- GLenum flags = GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_FLUSH_EXPLICIT_BIT;
- list->commands = (GPUDrawCommand *)glMapBufferRange(
- GL_DRAW_INDIRECT_BUFFER, list->cmd_offset, list->buffer_size - list->cmd_offset, flags);
- }
- }
- else {
- list->cmd_offset = 0;
- }
-}
-
-void GPU_draw_list_command_add(
- GPUDrawList *list, int v_first, int v_count, int i_first, int i_count)
-{
- BLI_assert(list->commands);
-
- if (v_count == 0 || i_count == 0) {
- return;
- }
-
- if (list->base_index != UINT_MAX) {
- GPUDrawCommandIndexed *cmd = list->commands_indexed + list->cmd_len;
- cmd->v_first = v_first;
- cmd->v_count = v_count;
- cmd->i_count = i_count;
- cmd->base_index = list->base_index;
- cmd->i_first = i_first;
- }
- else {
- GPUDrawCommand *cmd = list->commands + list->cmd_len;
- cmd->v_first = v_first;
- cmd->v_count = v_count;
- cmd->i_count = i_count;
- cmd->i_first = i_first;
- }
-
- list->cmd_len++;
- uint offset = list->cmd_offset + list->cmd_len * sizeof(GPUDrawCommandIndexed);
-
- if (offset == list->buffer_size) {
- GPU_draw_list_submit(list);
- GPU_draw_list_init(list, list->batch);
- }
-}
-
-void GPU_draw_list_submit(GPUDrawList *list)
-{
- GPUBatch *batch = list->batch;
-
- if (list->cmd_len == 0) {
- return;
- }
-
- BLI_assert(list->commands);
- BLI_assert(batch->program_in_use);
- /* TODO could assert that VAO is bound. */
-
- /* TODO We loose a bit of memory here if we only draw arrays. Fix that. */
- uintptr_t offset = list->cmd_offset;
- uint cmd_len = list->cmd_len;
- size_t bytes_used = cmd_len * sizeof(GPUDrawCommandIndexed);
- list->cmd_len = 0; /* Avoid reuse. */
-
- /* 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. */
- const bool do_mdi = (cmd_len > 2) || (list->cmd_offset + bytes_used == list->buffer_size);
-
- if (USE_MULTI_DRAW_INDIRECT && do_mdi) {
- GLenum prim = batch->gl_prim_type;
-
- glBindBuffer(GL_DRAW_INDIRECT_BUFFER, list->buffer_id);
- glFlushMappedBufferRange(GL_DRAW_INDIRECT_BUFFER, 0, bytes_used);
- glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER);
- list->commands = NULL; /* Unmapped */
- list->cmd_offset += bytes_used;
-
- if (batch->elem) {
- glMultiDrawElementsIndirect(prim, INDEX_TYPE(batch->elem), (void *)offset, cmd_len, 0);
- }
- else {
- glMultiDrawArraysIndirect(prim, (void *)offset, cmd_len, 0);
- }
- }
- else {
- /* Fallback */
- if (batch->elem) {
- GPUDrawCommandIndexed *cmd = list->commands_indexed;
- for (int i = 0; i < cmd_len; i++, cmd++) {
- /* Index start was added by Draw manager. Avoid counting it twice. */
- cmd->v_first -= batch->elem->index_start;
- GPU_batch_draw_advanced(batch, cmd->v_first, cmd->v_count, cmd->i_first, cmd->i_count);
- }
- }
- else {
- GPUDrawCommand *cmd = list->commands;
- for (int i = 0; i < cmd_len; i++, cmd++) {
- GPU_batch_draw_advanced(batch, cmd->v_first, cmd->v_count, cmd->i_first, cmd->i_count);
- }
- }
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Utilities
* \{ */
diff --git a/source/blender/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc
index 283784aec20..da0d3cd395f 100644
--- a/source/blender/gpu/intern/gpu_context.cc
+++ b/source/blender/gpu/intern/gpu_context.cc
@@ -83,12 +83,12 @@ bool GPUContext::is_active_on_thread(void)
GPUContext *GPU_context_create(void *ghost_window)
{
- if (gpu_backend_get() == NULL) {
+ if (GPUBackend::get() == NULL) {
/* TODO move where it make sense. */
GPU_backend_init(GPU_BACKEND_OPENGL);
}
- GPUContext *ctx = gpu_backend_get()->context_alloc(ghost_window);
+ GPUContext *ctx = GPUBackend::get()->context_alloc(ghost_window);
GPU_context_active_set(ctx);
return ctx;
@@ -173,14 +173,14 @@ void GPU_fbo_free(GLuint fbo_id, GPUContext *ctx)
void GPU_buf_free(GLuint buf_id)
{
/* TODO avoid using backend */
- GPUBackend *backend = gpu_backend_get();
+ GPUBackend *backend = GPUBackend::get();
static_cast<GLBackend *>(backend)->buf_free(buf_id);
}
void GPU_tex_free(GLuint tex_id)
{
/* TODO avoid using backend */
- GPUBackend *backend = gpu_backend_get();
+ GPUBackend *backend = GPUBackend::get();
static_cast<GLBackend *>(backend)->tex_free(tex_id);
}
@@ -285,7 +285,7 @@ void GPU_backend_exit(void)
delete g_backend;
}
-GPUBackend *gpu_backend_get(void)
+GPUBackend *GPUBackend::get(void)
{
return g_backend;
}
diff --git a/source/blender/gpu/intern/gpu_drawlist.cc b/source/blender/gpu/intern/gpu_drawlist.cc
new file mode 100644
index 00000000000..7b807a2fa80
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_drawlist.cc
@@ -0,0 +1,59 @@
+/*
+ * 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
+ *
+ * Implementation of Multi Draw Indirect.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "GPU_batch.h"
+#include "GPU_drawlist.h"
+
+#include "gpu_backend.hh"
+
+#include "gpu_drawlist_private.hh"
+
+using namespace blender::gpu;
+
+GPUDrawList GPU_draw_list_create(int list_length)
+{
+ DrawList *list_ptr = GPUBackend::get()->drawlist_alloc(list_length);
+ return reinterpret_cast<DrawList *>(list_ptr);
+}
+
+void GPU_draw_list_discard(GPUDrawList list)
+{
+ DrawList *list_ptr = reinterpret_cast<DrawList *>(list);
+ delete list_ptr;
+}
+
+void GPU_draw_list_append(GPUDrawList list, GPUBatch *batch, int i_first, int i_count)
+{
+ DrawList *list_ptr = reinterpret_cast<DrawList *>(list);
+ list_ptr->append(batch, i_first, i_count);
+}
+
+void GPU_draw_list_submit(GPUDrawList list)
+{
+ DrawList *list_ptr = reinterpret_cast<DrawList *>(list);
+ list_ptr->submit();
+}
diff --git a/source/blender/gpu/intern/gpu_drawlist_private.hh b/source/blender/gpu/intern/gpu_drawlist_private.hh
new file mode 100644
index 00000000000..04cc18a5ffd
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_drawlist_private.hh
@@ -0,0 +1,40 @@
+/*
+ * 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"
+
+namespace blender {
+namespace gpu {
+
+class DrawList {
+ public:
+ virtual ~DrawList(){};
+
+ virtual void append(GPUBatch *batch, int i_first, int i_count) = 0;
+ virtual void submit() = 0;
+};
+
+} // namespace gpu
+} // namespace blender
diff --git a/source/blender/gpu/opengl/gl_backend.hh b/source/blender/gpu/opengl/gl_backend.hh
index f7c01b2f184..a1e0e53f329 100644
--- a/source/blender/gpu/opengl/gl_backend.hh
+++ b/source/blender/gpu/opengl/gl_backend.hh
@@ -28,6 +28,7 @@
#include "BLI_vector.hh"
#include "gl_context.hh"
+#include "gl_drawlist.hh"
namespace blender {
namespace gpu {
@@ -42,6 +43,11 @@ class GLBackend : public GPUBackend {
return new GLContext(ghost_window, shared_orphan_list_);
};
+ DrawList *drawlist_alloc(int list_length)
+ {
+ return new GLDrawList(list_length);
+ };
+
/* TODO remove */
void buf_free(GLuint buf_id);
void tex_free(GLuint tex_id);
diff --git a/source/blender/gpu/opengl/gl_drawlist.cc b/source/blender/gpu/opengl/gl_drawlist.cc
new file mode 100644
index 00000000000..3fc6985e582
--- /dev/null
+++ b/source/blender/gpu/opengl/gl_drawlist.cc
@@ -0,0 +1,238 @@
+/*
+ * 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
+ *
+ * Implementation of Multi Draw Indirect using OpenGL.
+ * Fallback if the needed extensions are not supported.
+ */
+
+#include "BLI_assert.h"
+
+#include "GPU_batch.h"
+#include "GPU_extensions.h"
+
+#include "glew-mx.h"
+
+#include "gpu_context_private.hh"
+#include "gpu_drawlist_private.hh"
+
+#include "gl_backend.hh"
+#include "gl_drawlist.hh"
+
+#include <limits.h>
+
+#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 {
+ GLuint v_count;
+ GLuint i_count;
+ GLuint v_first;
+ GLuint i_first;
+} GLDrawCommand;
+
+typedef struct GLDrawCommandIndexed {
+ GLuint v_count;
+ GLuint i_count;
+ GLuint v_first;
+ GLuint base_index;
+ GLuint i_first;
+} GLDrawCommandIndexed;
+
+#define MDI_ENABLED (buffer_size_ != 0)
+#define MDI_DISABLED (buffer_size_ == 0)
+#define MDI_INDEXED (base_index_ != UINT_MAX)
+
+GLDrawList::GLDrawList(int length)
+{
+ BLI_assert(length > 0);
+ batch_ = NULL;
+ buffer_id_ = 0;
+ command_len_ = 0;
+ command_offset_ = 0;
+ data_offset_ = 0;
+ data_size_ = 0;
+ data_ = NULL;
+
+ if (USE_MULTI_DRAW_INDIRECT && GLEW_ARB_multi_draw_indirect &&
+ GPU_arb_base_instance_is_supported()) {
+ /* Alloc the biggest possible command list, which is indexed. */
+ buffer_size_ = sizeof(GLDrawCommandIndexed) * length;
+ }
+ else {
+ /* Indicates MDI is not supported. */
+ buffer_size_ = 0;
+ }
+}
+
+GLDrawList::~GLDrawList()
+{
+ /* TODO This ... */
+ static_cast<GLBackend *>(GPUBackend::get())->buf_free(buffer_id_);
+ /* ... should be this. */
+ // context_->buf_free(buffer_id_)
+}
+
+void GLDrawList::init(void)
+{
+ BLI_assert(GPU_context_active_get());
+ BLI_assert(MDI_ENABLED);
+ BLI_assert(data_ == NULL);
+ batch_ = NULL;
+ command_len_ = 0;
+
+ if (buffer_id_ == 0) {
+ /* Allocate on first use. */
+ glGenBuffers(1, &buffer_id_);
+ context_ = static_cast<GLContext *>(GPU_context_active_get());
+ }
+
+ glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buffer_id_);
+ /* If buffer is full, orphan buffer data and start fresh. */
+ // if (command_offset_ >= data_size_) {
+ glBufferData(GL_DRAW_INDIRECT_BUFFER, buffer_size_, NULL, GL_DYNAMIC_DRAW);
+ data_offset_ = 0;
+ // }
+ /* Map the remaining range. */
+ GLbitfield flag = GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_FLUSH_EXPLICIT_BIT;
+ data_size_ = buffer_size_ - data_offset_;
+ data_ = (GLbyte *)glMapBufferRange(GL_DRAW_INDIRECT_BUFFER, data_offset_, data_size_, flag);
+ command_offset_ = 0;
+}
+
+void GLDrawList::append(GPUBatch *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);
+ return;
+ }
+
+ if (data_ == NULL) {
+ this->init();
+ }
+
+ 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;
+ }
+
+ if (MDI_INDEXED) {
+ GLDrawCommandIndexed *cmd = reinterpret_cast<GLDrawCommandIndexed *>(data_ + command_offset_);
+ cmd->v_first = v_first_;
+ cmd->v_count = v_count_;
+ cmd->i_count = i_count;
+ cmd->base_index = base_index_;
+ cmd->i_first = i_first;
+ command_offset_ += sizeof(GLDrawCommandIndexed);
+ }
+ else {
+ GLDrawCommand *cmd = reinterpret_cast<GLDrawCommand *>(data_ + command_offset_);
+ cmd->v_first = v_first_;
+ cmd->v_count = v_count_;
+ cmd->i_count = i_count;
+ cmd->i_first = i_first;
+ command_offset_ += sizeof(GLDrawCommand);
+ }
+
+ command_len_++;
+
+ if (command_offset_ >= data_size_) {
+ this->submit();
+ }
+}
+
+void GLDrawList::submit(void)
+{
+ if (command_len_ == 0) {
+ return;
+ }
+ /* Something's wrong if we get here without MDI support. */
+ BLI_assert(MDI_ENABLED);
+ BLI_assert(data_);
+ /* TODO fix this assert */
+ // BLI_assert(batch_->program_in_use);
+ /* TODO could assert that VAO is bound. */
+
+ /* 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. */
+ const bool is_finishing_a_buffer = (command_offset_ >= data_size_);
+ if (command_len_ > 2 || is_finishing_a_buffer) {
+ // GLenum prim = convert_prim_type_to_gl(batch_->prim_type);
+ GLenum prim = batch_->gl_prim_type;
+ void *offset = (void *)data_offset_;
+
+ glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buffer_id_);
+ glFlushMappedBufferRange(GL_DRAW_INDIRECT_BUFFER, 0, command_offset_);
+ glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER);
+ data_ = NULL; /* Unmapped */
+ data_offset_ += command_offset_;
+
+ if (MDI_INDEXED) {
+ glMultiDrawElementsIndirect(prim, INDEX_TYPE(batch_->elem), offset, command_len_, 0);
+ }
+ else {
+ glMultiDrawArraysIndirect(prim, offset, command_len_, 0);
+ }
+ }
+ else {
+ /* Fallback do simple drawcalls, and don't unmap the buffer. */
+ if (MDI_INDEXED) {
+ 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;
+ GPU_batch_draw_advanced(batch_, cmd->v_first, cmd->v_count, cmd->i_first, cmd->i_count);
+ }
+ /* Reuse the same data. */
+ command_offset_ -= command_len_ * sizeof(GLDrawCommandIndexed);
+ }
+ else {
+ GLDrawCommand *cmd = (GLDrawCommand *)data_;
+ for (int i = 0; i < command_len_; i++, cmd++) {
+ GPU_batch_draw_advanced(batch_, cmd->v_first, cmd->v_count, cmd->i_first, cmd->i_count);
+ }
+ /* Reuse the same data. */
+ command_offset_ -= command_len_ * sizeof(GLDrawCommand);
+ }
+ }
+ /* Do not submit this buffer again. */
+ command_len_ = 0;
+}
+
+/** \} */ \ No newline at end of file
diff --git a/source/blender/gpu/opengl/gl_drawlist.hh b/source/blender/gpu/opengl/gl_drawlist.hh
new file mode 100644
index 00000000000..4f085149388
--- /dev/null
+++ b/source/blender/gpu/opengl/gl_drawlist.hh
@@ -0,0 +1,80 @@
+/*
+ * 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 "BLI_sys_types.h"
+
+#include "GPU_batch.h"
+#include "GPU_glew.h"
+
+#include "gpu_drawlist_private.hh"
+
+#include "gl_context.hh"
+
+namespace blender {
+namespace gpu {
+
+class GLDrawList : public DrawList {
+ public:
+ GLDrawList(int length);
+ ~GLDrawList();
+
+ void append(GPUBatch *batch, int i_first, int i_count) override;
+ void submit(void) override;
+
+ private:
+ void init(void);
+
+ /** Batch for which we are recording commands for. */
+ GPUBatch *batch_;
+ /** Mapped memory bounds. */
+ GLbyte *data_;
+ /** Length of the mapped buffer (in byte). */
+ GLsizeiptr data_size_;
+ /** Current offset inside the mapped buffer (in byte). */
+ GLintptr command_offset_;
+ /** Current number of command recorded inside the mapped buffer. */
+ uint command_len_;
+ /** Is UINT_MAX if not drawing indexed geom. Also Avoid dereferencing batch. */
+ GLuint base_index_;
+ /** Also Avoid dereferencing batch. */
+ GLuint v_first_, v_count_;
+
+ /** GL Indirect Buffer id. 0 means MultiDrawIndirect is not supported/enabled. */
+ GLuint buffer_id_;
+ /** Length of whole the buffer (in byte). */
+ GLsizeiptr buffer_size_;
+ /** Offset of data_ inside the whole buffer (in byte). */
+ GLintptr data_offset_;
+
+ /** To free the buffer_id_. */
+ GLContext *context_;
+
+ MEM_CXX_CLASS_ALLOC_FUNCS("GLDrawList");
+};
+
+} // namespace gpu
+} // namespace blender