GPUDrawList: GL backend isolation

This commit is contained in:
2020-08-08 15:24:52 +02:00
parent cb2565195e
commit 38ef35b1ed
13 changed files with 493 additions and 225 deletions

View File

@@ -35,6 +35,7 @@
#include "GPU_batch.h"
#include "GPU_context.h"
#include "GPU_drawlist.h"
#include "GPU_framebuffer.h"
#include "GPU_shader.h"
#include "GPU_uniformbuffer.h"

View File

@@ -54,8 +54,6 @@ typedef struct DRWCommandsState {
int resource_id;
int base_inst;
int inst_count;
int v_first;
int v_count;
bool neg_scale;
/* Resource location. */
int obmats_loc;
@@ -714,18 +712,12 @@ BLI_INLINE void draw_indirect_call(DRWShadingGroup *shgroup, DRWCommandsState *s
GPU_draw_list_submit(DST.draw_list);
draw_geometry_bind(shgroup, state->batch);
}
GPU_draw_list_command_add(
DST.draw_list, state->v_first, state->v_count, state->base_inst, state->inst_count);
GPU_draw_list_append(DST.draw_list, state->batch, state->base_inst, state->inst_count);
}
/* Fallback when unsupported */
else {
draw_geometry_execute(shgroup,
state->batch,
state->v_first,
state->v_count,
state->base_inst,
state->inst_count,
state->baseinst_loc);
draw_geometry_execute(
shgroup, state->batch, 0, 0, state->base_inst, state->inst_count, state->baseinst_loc);
}
}
@@ -1015,8 +1007,6 @@ static void draw_call_batching_start(DRWCommandsState *state)
state->resource_id = -1;
state->base_inst = 0;
state->inst_count = 0;
state->v_first = 0;
state->v_count = 0;
state->batch = NULL;
state->select_id = -1;
@@ -1039,15 +1029,10 @@ static void draw_call_batching_do(DRWShadingGroup *shgroup,
draw_call_batching_flush(shgroup, state);
state->batch = call->batch;
state->v_first = (call->batch->elem) ? call->batch->elem->index_start : 0;
state->v_count = (call->batch->elem) ? call->batch->elem->index_len :
call->batch->verts[0]->vertex_len;
state->inst_count = 1;
state->base_inst = id;
draw_call_resource_bind(state, &call->handle);
GPU_draw_list_init(DST.draw_list, state->batch);
}
/* Is the id consecutive? */
else if (id != state->base_inst + state->inst_count) {

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -795,193 +795,6 @@ void GPU_draw_primitive(GPUPrimType prim_type, int v_count)
// glBindVertexArray(0);
}
/* -------------------------------------------------------------------- */
/** \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
* \{ */

View File

@@ -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;
}

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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;
}
/** \} */

View File

@@ -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