Modernize loops by using the `for(type variable : container)` syntax. Some loops were trivial to fix, whereas others required more attention to avoid semantic changes. I couldn't address all old-style loops, so this commit doesn't enable the `modernize-loop-convert` rule. Although Clang-Tidy's auto-fixer prefers to use `auto` for the loop variable declaration, I made as many declarations as possible explicit. To me this increases local readability, as you don't need to fully understand the container in order to understand the loop variable type. No functional changes.
329 lines
9.1 KiB
C++
329 lines
9.1 KiB
C++
/*
|
|
* 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
|
|
*
|
|
* GPU geometry batch
|
|
* Contains VAOs + VBOs + Shader representing a drawable entity.
|
|
*/
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "BLI_math_base.h"
|
|
|
|
#include "GPU_batch.h"
|
|
#include "GPU_batch_presets.h"
|
|
#include "GPU_matrix.h"
|
|
#include "GPU_platform.h"
|
|
#include "GPU_shader.h"
|
|
|
|
#include "gpu_backend.hh"
|
|
#include "gpu_context_private.hh"
|
|
#include "gpu_index_buffer_private.hh"
|
|
#include "gpu_shader_private.hh"
|
|
#include "gpu_vertex_buffer_private.hh"
|
|
|
|
#include "gpu_batch_private.hh"
|
|
|
|
#include <cstring>
|
|
|
|
using namespace blender::gpu;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Creation & Deletion
|
|
* \{ */
|
|
|
|
GPUBatch *GPU_batch_calloc(void)
|
|
{
|
|
GPUBatch *batch = GPUBackend::get()->batch_alloc();
|
|
memset(batch, 0, sizeof(*batch));
|
|
return batch;
|
|
}
|
|
|
|
GPUBatch *GPU_batch_create_ex(GPUPrimType prim_type,
|
|
GPUVertBuf *verts,
|
|
GPUIndexBuf *elem,
|
|
eGPUBatchFlag owns_flag)
|
|
{
|
|
GPUBatch *batch = GPU_batch_calloc();
|
|
GPU_batch_init_ex(batch, prim_type, verts, elem, owns_flag);
|
|
return batch;
|
|
}
|
|
|
|
void GPU_batch_init_ex(GPUBatch *batch,
|
|
GPUPrimType prim_type,
|
|
GPUVertBuf *verts,
|
|
GPUIndexBuf *elem,
|
|
eGPUBatchFlag owns_flag)
|
|
{
|
|
BLI_assert(verts != nullptr);
|
|
/* Do not pass any other flag */
|
|
BLI_assert((owns_flag & ~(GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX)) == 0);
|
|
|
|
batch->verts[0] = verts;
|
|
for (int v = 1; v < GPU_BATCH_VBO_MAX_LEN; v++) {
|
|
batch->verts[v] = nullptr;
|
|
}
|
|
for (auto & v : batch->inst) {
|
|
v = nullptr;
|
|
}
|
|
batch->elem = elem;
|
|
batch->prim_type = prim_type;
|
|
batch->flag = owns_flag | GPU_BATCH_INIT | GPU_BATCH_DIRTY;
|
|
batch->shader = nullptr;
|
|
}
|
|
|
|
/* This will share the VBOs with the new batch. */
|
|
void GPU_batch_copy(GPUBatch *batch_dst, GPUBatch *batch_src)
|
|
{
|
|
GPU_batch_init_ex(
|
|
batch_dst, GPU_PRIM_POINTS, batch_src->verts[0], batch_src->elem, GPU_BATCH_INVALID);
|
|
|
|
batch_dst->prim_type = batch_src->prim_type;
|
|
for (int v = 1; v < GPU_BATCH_VBO_MAX_LEN; v++) {
|
|
batch_dst->verts[v] = batch_src->verts[v];
|
|
}
|
|
}
|
|
|
|
void GPU_batch_clear(GPUBatch *batch)
|
|
{
|
|
if (batch->flag & GPU_BATCH_OWNS_INDEX) {
|
|
GPU_indexbuf_discard(batch->elem);
|
|
}
|
|
if (batch->flag & GPU_BATCH_OWNS_VBO_ANY) {
|
|
for (int v = 0; (v < GPU_BATCH_VBO_MAX_LEN) && batch->verts[v]; v++) {
|
|
if (batch->flag & (GPU_BATCH_OWNS_VBO << v)) {
|
|
GPU_VERTBUF_DISCARD_SAFE(batch->verts[v]);
|
|
}
|
|
}
|
|
}
|
|
if (batch->flag & GPU_BATCH_OWNS_INST_VBO_ANY) {
|
|
for (int v = 0; (v < GPU_BATCH_INST_VBO_MAX_LEN) && batch->inst[v]; v++) {
|
|
if (batch->flag & (GPU_BATCH_OWNS_INST_VBO << v)) {
|
|
GPU_VERTBUF_DISCARD_SAFE(batch->inst[v]);
|
|
}
|
|
}
|
|
}
|
|
batch->flag = GPU_BATCH_INVALID;
|
|
}
|
|
|
|
void GPU_batch_discard(GPUBatch *batch)
|
|
{
|
|
GPU_batch_clear(batch);
|
|
|
|
delete static_cast<Batch *>(batch);
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Buffers Management
|
|
* \{ */
|
|
|
|
/* NOTE: Override ONLY the first instance vbo (and free them if owned). */
|
|
void GPU_batch_instbuf_set(GPUBatch *batch, GPUVertBuf *inst, bool own_vbo)
|
|
{
|
|
BLI_assert(inst);
|
|
batch->flag |= GPU_BATCH_DIRTY;
|
|
|
|
if (batch->inst[0] && (batch->flag & GPU_BATCH_OWNS_INST_VBO)) {
|
|
GPU_vertbuf_discard(batch->inst[0]);
|
|
}
|
|
batch->inst[0] = inst;
|
|
|
|
SET_FLAG_FROM_TEST(batch->flag, own_vbo, GPU_BATCH_OWNS_INST_VBO);
|
|
}
|
|
|
|
/* NOTE: Override any previously assigned elem (and free it if owned). */
|
|
void GPU_batch_elembuf_set(GPUBatch *batch, GPUIndexBuf *elem, bool own_ibo)
|
|
{
|
|
BLI_assert(elem);
|
|
batch->flag |= GPU_BATCH_DIRTY;
|
|
|
|
if (batch->elem && (batch->flag & GPU_BATCH_OWNS_INDEX)) {
|
|
GPU_indexbuf_discard(batch->elem);
|
|
}
|
|
batch->elem = elem;
|
|
|
|
SET_FLAG_FROM_TEST(batch->flag, own_ibo, GPU_BATCH_OWNS_INDEX);
|
|
}
|
|
|
|
int GPU_batch_instbuf_add_ex(GPUBatch *batch, GPUVertBuf *insts, bool own_vbo)
|
|
{
|
|
BLI_assert(insts);
|
|
batch->flag |= GPU_BATCH_DIRTY;
|
|
|
|
for (uint v = 0; v < GPU_BATCH_INST_VBO_MAX_LEN; v++) {
|
|
if (batch->inst[v] == nullptr) {
|
|
/* for now all VertexBuffers must have same vertex_len */
|
|
if (batch->inst[0]) {
|
|
/* Allow for different size of vertex buffer (will choose the smallest number of verts). */
|
|
// BLI_assert(insts->vertex_len == batch->inst[0]->vertex_len);
|
|
}
|
|
|
|
batch->inst[v] = insts;
|
|
SET_FLAG_FROM_TEST(batch->flag, own_vbo, (eGPUBatchFlag)(GPU_BATCH_OWNS_INST_VBO << v));
|
|
return v;
|
|
}
|
|
}
|
|
/* we only make it this far if there is no room for another GPUVertBuf */
|
|
BLI_assert(0 && "Not enough Instance VBO slot in batch");
|
|
return -1;
|
|
}
|
|
|
|
/* Returns the index of verts in the batch. */
|
|
int GPU_batch_vertbuf_add_ex(GPUBatch *batch, GPUVertBuf *verts, bool own_vbo)
|
|
{
|
|
BLI_assert(verts);
|
|
batch->flag |= GPU_BATCH_DIRTY;
|
|
|
|
for (uint v = 0; v < GPU_BATCH_VBO_MAX_LEN; v++) {
|
|
if (batch->verts[v] == nullptr) {
|
|
/* for now all VertexBuffers must have same vertex_len */
|
|
if (batch->verts[0] != nullptr) {
|
|
/* This is an issue for the HACK inside DRW_vbo_request(). */
|
|
// BLI_assert(verts->vertex_len == batch->verts[0]->vertex_len);
|
|
}
|
|
batch->verts[v] = verts;
|
|
SET_FLAG_FROM_TEST(batch->flag, own_vbo, (eGPUBatchFlag)(GPU_BATCH_OWNS_VBO << v));
|
|
return v;
|
|
}
|
|
}
|
|
/* we only make it this far if there is no room for another GPUVertBuf */
|
|
BLI_assert(0 && "Not enough VBO slot in batch");
|
|
return -1;
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Uniform setters
|
|
*
|
|
* TODO(fclem): port this to GPUShader.
|
|
* \{ */
|
|
|
|
void GPU_batch_set_shader(GPUBatch *batch, GPUShader *shader)
|
|
{
|
|
batch->shader = shader;
|
|
GPU_shader_bind(batch->shader);
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Drawing / Drawcall functions
|
|
* \{ */
|
|
|
|
void GPU_batch_draw(GPUBatch *batch)
|
|
{
|
|
GPU_shader_bind(batch->shader);
|
|
GPU_batch_draw_advanced(batch, 0, 0, 0, 0);
|
|
}
|
|
|
|
void GPU_batch_draw_range(GPUBatch *batch, int v_first, int v_count)
|
|
{
|
|
GPU_shader_bind(batch->shader);
|
|
GPU_batch_draw_advanced(batch, v_first, v_count, 0, 0);
|
|
}
|
|
|
|
/* Draw multiple instance of a batch without having any instance attributes. */
|
|
void GPU_batch_draw_instanced(GPUBatch *batch, int i_count)
|
|
{
|
|
BLI_assert(batch->inst[0] == nullptr);
|
|
|
|
GPU_shader_bind(batch->shader);
|
|
GPU_batch_draw_advanced(batch, 0, 0, 0, i_count);
|
|
}
|
|
|
|
void GPU_batch_draw_advanced(
|
|
GPUBatch *gpu_batch, int v_first, int v_count, int i_first, int i_count)
|
|
{
|
|
BLI_assert(Context::get()->shader != nullptr);
|
|
Batch *batch = static_cast<Batch *>(gpu_batch);
|
|
|
|
if (v_count == 0) {
|
|
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;
|
|
/* Meh. This is to be able to use different numbers of verts in instance vbos. */
|
|
if (batch->inst[1] != nullptr) {
|
|
i_count = min_ii(i_count, batch->inst_(1)->vertex_len);
|
|
}
|
|
}
|
|
|
|
if (v_count == 0 || i_count == 0) {
|
|
/* Nothing to draw. */
|
|
return;
|
|
}
|
|
|
|
batch->draw(v_first, v_count, i_first, i_count);
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Utilities
|
|
* \{ */
|
|
|
|
void GPU_batch_program_set_builtin_with_config(GPUBatch *batch,
|
|
eGPUBuiltinShader shader_id,
|
|
eGPUShaderConfig sh_cfg)
|
|
{
|
|
GPUShader *shader = GPU_shader_get_builtin_shader_with_config(shader_id, sh_cfg);
|
|
GPU_batch_set_shader(batch, shader);
|
|
}
|
|
|
|
void GPU_batch_program_set_builtin(GPUBatch *batch, eGPUBuiltinShader shader_id)
|
|
{
|
|
GPU_batch_program_set_builtin_with_config(batch, shader_id, GPU_SHADER_CFG_DEFAULT);
|
|
}
|
|
|
|
/* Bind program bound to IMM to the batch.
|
|
* XXX Use this with much care. Drawing with the GPUBatch API is not compatible with IMM.
|
|
* DO NOT DRAW WITH THE BATCH BEFORE CALLING immUnbindProgram. */
|
|
void GPU_batch_program_set_imm_shader(GPUBatch *batch)
|
|
{
|
|
GPU_batch_set_shader(batch, immGetShader());
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Init/Exit
|
|
* \{ */
|
|
|
|
void gpu_batch_init(void)
|
|
{
|
|
gpu_batch_presets_init();
|
|
}
|
|
|
|
void gpu_batch_exit(void)
|
|
{
|
|
gpu_batch_presets_exit();
|
|
}
|
|
|
|
/** \} */
|