Especially through DRW_render.hh, there were a lot of unnecessary includes almost everywhere in the module. This typically makes dependencies less explicit and slows down compile times, so switch to including what files actual use. Pull Request: https://projects.blender.org/blender/blender/pulls/133450
205 lines
5.6 KiB
C++
205 lines
5.6 KiB
C++
/* SPDX-FileCopyrightText: 2016 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup draw
|
|
*/
|
|
|
|
/**
|
|
* DRW Instance Data Manager
|
|
* This is a special memory manager that keeps memory blocks ready to send as VBO data in one
|
|
* continuous allocation. This way we avoid feeding #gpu::Batch each instance data one by one and
|
|
* unnecessary `memcpy`. Since we lose which memory block was used each #DRWShadingGroup we need to
|
|
* redistribute them in the same order/size to avoid to realloc each frame. This is why
|
|
* #DRWInstanceDatas are sorted in a list for each different data size.
|
|
*/
|
|
|
|
#include "draw_instance_data.hh"
|
|
|
|
#include "DRW_engine.hh"
|
|
#include "DRW_render.hh" /* For DRW_shgroup_get_instance_count() */
|
|
|
|
#include "BLI_listbase.h"
|
|
#include "BLI_mempool.h"
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
struct DRWInstanceData {
|
|
DRWInstanceData *next;
|
|
bool used; /* If this data is used or not. */
|
|
size_t data_size; /* Size of one instance data. */
|
|
BLI_mempool *mempool;
|
|
};
|
|
|
|
struct DRWInstanceDataList {
|
|
DRWInstanceDataList *next, *prev;
|
|
/* Linked lists for all possible data pool size */
|
|
DRWInstanceData *idata_head[MAX_INSTANCE_DATA_SIZE];
|
|
DRWInstanceData *idata_tail[MAX_INSTANCE_DATA_SIZE];
|
|
};
|
|
|
|
struct DRWTempBufferHandle {
|
|
blender::gpu::VertBuf *buf;
|
|
/** Format pointer for reuse. */
|
|
GPUVertFormat *format;
|
|
/** Touched vertex length for resize. */
|
|
int *vert_len;
|
|
};
|
|
|
|
struct DRWTempInstancingHandle {
|
|
/** Copy of geom but with the per-instance attributes. */
|
|
blender::gpu::Batch *batch;
|
|
/** Batch containing instancing attributes. */
|
|
blender::gpu::Batch *instancer;
|
|
/** Call-buffer to be used instead of instancer. */
|
|
blender::gpu::VertBuf *buf;
|
|
/** Original non-instanced batch pointer. */
|
|
blender::gpu::Batch *geom;
|
|
};
|
|
|
|
static ListBase g_idatalists = {nullptr, nullptr};
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Instance Data (DRWInstanceData)
|
|
* \{ */
|
|
|
|
static DRWInstanceData *drw_instance_data_create(DRWInstanceDataList *idatalist, uint attr_size)
|
|
{
|
|
DRWInstanceData *idata = static_cast<DRWInstanceData *>(
|
|
MEM_callocN(sizeof(DRWInstanceData), "DRWInstanceData"));
|
|
idata->next = nullptr;
|
|
idata->used = true;
|
|
idata->data_size = attr_size;
|
|
idata->mempool = BLI_mempool_create(sizeof(float) * idata->data_size, 0, 16, 0);
|
|
|
|
BLI_assert(attr_size > 0);
|
|
|
|
/* Push to linked list. */
|
|
if (idatalist->idata_head[attr_size - 1] == nullptr) {
|
|
idatalist->idata_head[attr_size - 1] = idata;
|
|
}
|
|
else {
|
|
idatalist->idata_tail[attr_size - 1]->next = idata;
|
|
}
|
|
idatalist->idata_tail[attr_size - 1] = idata;
|
|
|
|
return idata;
|
|
}
|
|
|
|
static void DRW_instance_data_free(DRWInstanceData *idata)
|
|
{
|
|
BLI_mempool_destroy(idata->mempool);
|
|
}
|
|
|
|
void *DRW_instance_data_next(DRWInstanceData *idata)
|
|
{
|
|
return BLI_mempool_alloc(idata->mempool);
|
|
}
|
|
|
|
DRWInstanceData *DRW_instance_data_request(DRWInstanceDataList *idatalist, uint attr_size)
|
|
{
|
|
BLI_assert(attr_size > 0 && attr_size <= MAX_INSTANCE_DATA_SIZE);
|
|
|
|
DRWInstanceData *idata = idatalist->idata_head[attr_size - 1];
|
|
|
|
/* Search for an unused data chunk. */
|
|
for (; idata; idata = idata->next) {
|
|
if (idata->used == false) {
|
|
idata->used = true;
|
|
return idata;
|
|
}
|
|
}
|
|
|
|
return drw_instance_data_create(idatalist, attr_size);
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Instance Data List (DRWInstanceDataList)
|
|
* \{ */
|
|
|
|
DRWInstanceDataList *DRW_instance_data_list_create()
|
|
{
|
|
DRWInstanceDataList *idatalist = static_cast<DRWInstanceDataList *>(
|
|
MEM_callocN(sizeof(DRWInstanceDataList), "DRWInstanceDataList"));
|
|
|
|
BLI_addtail(&g_idatalists, idatalist);
|
|
|
|
return idatalist;
|
|
}
|
|
|
|
void DRW_instance_data_list_free(DRWInstanceDataList *idatalist)
|
|
{
|
|
DRWInstanceData *idata, *next_idata;
|
|
|
|
for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; i++) {
|
|
for (idata = idatalist->idata_head[i]; idata; idata = next_idata) {
|
|
next_idata = idata->next;
|
|
DRW_instance_data_free(idata);
|
|
MEM_freeN(idata);
|
|
}
|
|
idatalist->idata_head[i] = nullptr;
|
|
idatalist->idata_tail[i] = nullptr;
|
|
}
|
|
|
|
BLI_remlink(&g_idatalists, idatalist);
|
|
|
|
MEM_freeN(idatalist);
|
|
}
|
|
|
|
void DRW_instance_data_list_reset(DRWInstanceDataList *idatalist)
|
|
{
|
|
DRWInstanceData *idata;
|
|
|
|
for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; i++) {
|
|
for (idata = idatalist->idata_head[i]; idata; idata = idata->next) {
|
|
idata->used = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
void DRW_instance_data_list_free_unused(DRWInstanceDataList *idatalist)
|
|
{
|
|
DRWInstanceData *idata, *next_idata;
|
|
|
|
/* Remove unused data blocks and sanitize each list. */
|
|
for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; i++) {
|
|
idatalist->idata_tail[i] = nullptr;
|
|
for (idata = idatalist->idata_head[i]; idata; idata = next_idata) {
|
|
next_idata = idata->next;
|
|
if (idata->used == false) {
|
|
if (idatalist->idata_head[i] == idata) {
|
|
idatalist->idata_head[i] = next_idata;
|
|
}
|
|
else {
|
|
/* idatalist->idata_tail[i] is guaranteed not to be null in this case. */
|
|
idatalist->idata_tail[i]->next = next_idata;
|
|
}
|
|
DRW_instance_data_free(idata);
|
|
MEM_freeN(idata);
|
|
}
|
|
else {
|
|
if (idatalist->idata_tail[i] != nullptr) {
|
|
idatalist->idata_tail[i]->next = idata;
|
|
}
|
|
idatalist->idata_tail[i] = idata;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void DRW_instance_data_list_resize(DRWInstanceDataList *idatalist)
|
|
{
|
|
DRWInstanceData *idata;
|
|
|
|
for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; i++) {
|
|
for (idata = idatalist->idata_head[i]; idata; idata = idata->next) {
|
|
BLI_mempool_clear_ex(idata->mempool, BLI_mempool_len(idata->mempool));
|
|
}
|
|
}
|
|
}
|
|
|
|
/** \} */
|