diff options
-rw-r--r-- | source/blender/draw/CMakeLists.txt | 2 | ||||
-rw-r--r-- | source/blender/draw/DRW_engine.h | 3 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_instance_data.c | 226 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_instance_data.h | 41 | ||||
-rw-r--r-- | source/blender/gpu/GPU_viewport.h | 1 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_viewport.c | 10 |
6 files changed, 283 insertions, 0 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 03ab9cf9435..c45af4c3807 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -62,6 +62,7 @@ set(SRC intern/draw_cache_impl_metaball.c intern/draw_cache_impl_particles.c intern/draw_common.c + intern/draw_instance_data.c intern/draw_manager.c intern/draw_manager_text.c intern/draw_manager_profiling.c @@ -104,6 +105,7 @@ set(SRC intern/draw_cache.h intern/draw_cache_impl.h intern/draw_common.h + intern/draw_instance_data.h intern/draw_manager_text.h intern/draw_manager_profiling.h intern/draw_view.h diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h index 3f09f38147e..7fa640683e1 100644 --- a/source/blender/draw/DRW_engine.h +++ b/source/blender/draw/DRW_engine.h @@ -30,6 +30,7 @@ struct ARegion; struct CollectionEngineSettings; struct Depsgraph; struct DRWPass; +struct DRWInstanceDataList; struct Main; struct Material; struct Scene; @@ -109,6 +110,8 @@ void DRW_draw_depth_loop( /* This is here because GPUViewport needs it */ void DRW_pass_free(struct DRWPass *pass); +struct DRWInstanceDataList *DRW_instance_data_list_create(void); +void DRW_instance_data_list_free(struct DRWInstanceDataList *idatalist); /* Mode engines initialization */ void OBJECT_collection_settings_create(struct IDProperty *properties); diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c new file mode 100644 index 00000000000..5cfd4991f38 --- /dev/null +++ b/source/blender/draw/intern/draw_instance_data.c @@ -0,0 +1,226 @@ +/* + * Copyright 2016, Blender Foundation. + * + * 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. + * + * Contributor(s): Blender Institute + * + */ + +/** \file blender/draw/intern/draw_instance_data.c + * \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 gawain each instance data one by one and unecessary memcpy. + * Since we loose 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.h" +#include "DRW_engine.h" + +#include "MEM_guardedalloc.h" +#include "BLI_utildefines.h" + +#define MAX_INSTANCE_DATA_SIZE 28 /* Can be adjusted for more */ + +struct DRWInstanceData { + struct DRWInstanceData *next; + bool used; /* If this data is used or not. */ + size_t chunk_size; /* Current size of the whole chunk. */ + size_t data_size; /* Size of one instance data. */ + size_t instance_group; /* How many instance to allocate at a time. */ + size_t offset; /* Offset to the next instance data. */ + float *memchunk; /* Should be float no matter what. */ +}; + +struct DRWInstanceDataList { + /* Linked lists for all possible data pool size */ + /* Not entirely sure if we should separate them in the first place. + * This is done to minimize the reattribution misses. */ + DRWInstanceData *idata_head[MAX_INSTANCE_DATA_SIZE]; + DRWInstanceData *idata_tail[MAX_INSTANCE_DATA_SIZE]; +}; + +/* -------------------------------------------------------------------- */ + +/** \name Instance Data (DRWInstanceData) + * \{ */ + +static DRWInstanceData *drw_instance_data_create( + DRWInstanceDataList *idatalist, unsigned int attrib_size, unsigned int instance_group) +{ + DRWInstanceData *idata = MEM_mallocN(sizeof(DRWInstanceData), "DRWInstanceData"); + idata->next = NULL; + idata->used = true; + idata->data_size = attrib_size; + idata->instance_group = instance_group; + idata->chunk_size = idata->data_size * instance_group; + idata->offset = 0; + idata->memchunk = MEM_mallocN(idata->chunk_size * sizeof(float), "DRWInstanceData memchunk"); + + BLI_assert(attrib_size > 0); + + /* Push to linked list. */ + if (idatalist->idata_head[attrib_size-1] == NULL) { + idatalist->idata_head[attrib_size-1] = idata; + } + else { + idatalist->idata_tail[attrib_size-1]->next = idata; + } + idatalist->idata_tail[attrib_size-1] = idata; + + return idata; +} + +static void DRW_instance_data_free(DRWInstanceData *idata) +{ + MEM_freeN(idata->memchunk); +} + +/** + * Return a pointer to the next instance data space. + * DO NOT SAVE/REUSE THIS POINTER after the next call + * to this function since the chunk may have been + * reallocated. + **/ +void *DRW_instance_data_next(DRWInstanceData *idata) +{ + idata->offset += idata->data_size; + + /* Check if chunk is large enough. realloc otherwise. */ + if (idata->offset > idata->chunk_size) { + idata->chunk_size += idata->data_size * idata->instance_group; + idata->memchunk = MEM_reallocN(idata->memchunk, idata->chunk_size * sizeof(float)); + } + + return idata->memchunk + (idata->offset - idata->data_size); +} + +void *DRW_instance_data_get(DRWInstanceData *idata) +{ + return (void *)idata->memchunk; +} + +DRWInstanceData *DRW_instance_data_request( + DRWInstanceDataList *idatalist, unsigned int attrib_size, unsigned int instance_group) +{ + BLI_assert(attrib_size > 0 && attrib_size <= MAX_INSTANCE_DATA_SIZE); + + DRWInstanceData *idata = idatalist->idata_head[attrib_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, attrib_size, instance_group); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ + +/** \name Instance Data List (DRWInstanceDataList) + * \{ */ + +DRWInstanceDataList *DRW_instance_data_list_create(void) +{ + return MEM_callocN(sizeof(DRWInstanceDataList), "DRWInstanceDataList"); +} + +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] = NULL; + idatalist->idata_tail[i] = NULL; + } +} + +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; + idata->offset = 0; + } + } +} + +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] = NULL; + 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 garanteed 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] != NULL) { + 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) { + /* Rounding up to nearest chunk size to compare. */ + size_t fac = idata->data_size * idata->instance_group; + size_t tmp = idata->offset + fac - 1; + size_t rounded_offset = tmp - tmp % fac; + if (rounded_offset < idata->chunk_size) { + idata->chunk_size = rounded_offset; + idata->memchunk = MEM_reallocN(idata->memchunk, idata->chunk_size * sizeof(float)); + } + } + } +} + +/** \} */ diff --git a/source/blender/draw/intern/draw_instance_data.h b/source/blender/draw/intern/draw_instance_data.h new file mode 100644 index 00000000000..637c0e3cc24 --- /dev/null +++ b/source/blender/draw/intern/draw_instance_data.h @@ -0,0 +1,41 @@ +/* + * Copyright 2016, Blender Foundation. + * + * 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. + * + * Contributor(s): Blender Institute + * + */ + +/** \file draw_instance_data.h + * \ingroup draw + */ + +#ifndef __DRAW_INSTANCE_DATA_H__ +#define __DRAW_INSTANCE_DATA_H__ + +typedef struct DRWInstanceData DRWInstanceData; +typedef struct DRWInstanceDataList DRWInstanceDataList; + +void *DRW_instance_data_next(DRWInstanceData *idata); +void *DRW_instance_data_get(DRWInstanceData *idata); +DRWInstanceData *DRW_instance_data_request( + DRWInstanceDataList *idatalist, unsigned int attrib_size, unsigned int instance_group); + +void DRW_instance_data_list_reset(DRWInstanceDataList *idatalist); +void DRW_instance_data_list_free_unused(DRWInstanceDataList *idatalist); +void DRW_instance_data_list_resize(DRWInstanceDataList *idatalist); + +#endif /* __DRAW_INSTANCE_DATA_H__ */ diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h index f2bb05a6d1e..a34a901ac63 100644 --- a/source/blender/gpu/GPU_viewport.h +++ b/source/blender/gpu/GPU_viewport.h @@ -106,6 +106,7 @@ GPUViewport *GPU_viewport_create_from_offscreen(struct GPUOffScreen *ofs); void GPU_viewport_clear_from_offscreen(GPUViewport *viewport); ViewportMemoryPool *GPU_viewport_mempool_get(GPUViewport *viewport); +struct DRWInstanceDataList *GPU_viewport_instance_data_list_get(GPUViewport *viewport); void *GPU_viewport_engine_data_create(GPUViewport *viewport, void *engine_type); void *GPU_viewport_engine_data_get(GPUViewport *viewport, void *engine_type); diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c index bd563a36f57..c97822dcc2a 100644 --- a/source/blender/gpu/intern/gpu_viewport.c +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -84,6 +84,7 @@ struct GPUViewport { DefaultTextureList *txl; ViewportMemoryPool vmempool; /* Used for rendering data structure. */ + struct DRWInstanceDataList *idatalist; /* Used for rendering data structure. */ ListBase tex_pool; /* ViewportTempTexture list : Temporary textures shared across draw engines */ }; @@ -114,6 +115,7 @@ GPUViewport *GPU_viewport_create(void) GPUViewport *viewport = MEM_callocN(sizeof(GPUViewport), "GPUViewport"); viewport->fbl = MEM_callocN(sizeof(DefaultFramebufferList), "FramebufferList"); viewport->txl = MEM_callocN(sizeof(DefaultTextureList), "TextureList"); + viewport->idatalist = DRW_instance_data_list_create(); viewport->size[0] = viewport->size[1] = -1; @@ -210,6 +212,11 @@ ViewportMemoryPool *GPU_viewport_mempool_get(GPUViewport *viewport) return &viewport->vmempool; } +struct DRWInstanceDataList *GPU_viewport_instance_data_list_get(GPUViewport *viewport) +{ + return viewport->idatalist; +} + void *GPU_viewport_framebuffer_list_get(GPUViewport *viewport) { return viewport->fbl; @@ -599,6 +606,9 @@ void GPU_viewport_free(GPUViewport *viewport) BLI_mempool_destroy(viewport->vmempool.passes); } + DRW_instance_data_list_free(viewport->idatalist); + MEM_freeN(viewport->idatalist); + GPU_viewport_debug_depth_free(viewport); } |