diff options
Diffstat (limited to 'source/blender/draw/intern')
-rw-r--r-- | source/blender/draw/intern/DRW_render.h | 3 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_instance_data.c | 2 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_manager.c | 747 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_manager.h | 59 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_manager_data.c | 18 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_manager_profiling.c | 7 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_manager_text.h | 8 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_manager_texture.c | 3 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_texture_pool.cc | 140 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_texture_pool.h | 47 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_view_data.cc | 243 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_view_data.h | 139 |
12 files changed, 1012 insertions, 404 deletions
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index fb8b8536897..c1cab931f6a 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -24,8 +24,6 @@ #pragma once -#include "DRW_engine_types.h" - #include "BLI_listbase.h" #include "BLI_math_matrix.h" #include "BLI_math_vector.h" @@ -56,6 +54,7 @@ #include "draw_debug.h" #include "draw_manager_profiling.h" +#include "draw_view_data.h" #include "MEM_guardedalloc.h" diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c index e055192eb21..29112ee4788 100644 --- a/source/blender/draw/intern/draw_instance_data.c +++ b/source/blender/draw/intern/draw_instance_data.c @@ -364,6 +364,8 @@ void DRW_instance_data_list_free(DRWInstanceDataList *idatalist) BLI_memblock_destroy(idatalist->pool_batching, (MemblockValFreeFP)temp_batch_free); BLI_remlink(&g_idatalists, idatalist); + + MEM_freeN(idatalist); } void DRW_instance_data_list_reset(DRWInstanceDataList *idatalist) diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index e65fdce5f2e..7a41142b177 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -84,10 +84,12 @@ #include "wm_window.h" #include "draw_color_management.h" +#include "draw_manager.h" #include "draw_manager_profiling.h" #include "draw_manager_testing.h" #include "draw_manager_text.h" #include "draw_shader.h" +#include "draw_texture_pool.h" /* only for callbacks */ #include "draw_cache_impl.h" @@ -111,7 +113,10 @@ /** Render State: No persistent data between draw calls. */ DRWManager DST = {NULL}; -static ListBase DRW_engines = {NULL, NULL}; +static struct { + ListBase /*DRWRegisteredDrawEngine*/ engines; + int len; +} g_registered_engines = {{NULL}}; static void drw_state_prepare_clean_for_draw(DRWManager *dst) { @@ -315,35 +320,6 @@ struct DupliObject *DRW_object_get_dupli(const Object *UNUSED(ob)) /** \name Viewport (DRW_viewport) * \{ */ -void *drw_viewport_engine_data_ensure(void *engine_type) -{ - void *data = GPU_viewport_engine_data_get(DST.viewport, engine_type); - - if (data == NULL) { - data = GPU_viewport_engine_data_create(DST.viewport, engine_type); - } - return data; -} - -void DRW_engine_viewport_data_size_get( - const void *engine_type_v, int *r_fbl_len, int *r_txl_len, int *r_psl_len, int *r_stl_len) -{ - const DrawEngineType *engine_type = engine_type_v; - - if (r_fbl_len) { - *r_fbl_len = engine_type->vedata_size->fbl_len; - } - if (r_txl_len) { - *r_txl_len = engine_type->vedata_size->txl_len; - } - if (r_psl_len) { - *r_psl_len = engine_type->vedata_size->psl_len; - } - if (r_stl_len) { - *r_stl_len = engine_type->vedata_size->stl_len; - } -} - /* WARNING: only use for custom pipeline. 99% of the time, you don't want to use this. */ void DRW_render_viewport_size_set(const int size[2]) { @@ -373,39 +349,6 @@ const float *DRW_viewport_pixelsize_get(void) return &DST.pixsize; } -static void drw_viewport_cache_resize(void) -{ - /* Release the memiter before clearing the mempools that references them */ - GPU_viewport_cache_release(DST.viewport); - - if (DST.vmempool != NULL) { - /* Release Image textures. */ - BLI_memblock_iter iter; - GPUTexture **tex; - BLI_memblock_iternew(DST.vmempool->images, &iter); - while ((tex = BLI_memblock_iterstep(&iter))) { - GPU_texture_free(*tex); - } - - BLI_memblock_clear(DST.vmempool->commands, NULL); - BLI_memblock_clear(DST.vmempool->commands_small, NULL); - BLI_memblock_clear(DST.vmempool->callbuffers, NULL); - BLI_memblock_clear(DST.vmempool->obmats, NULL); - BLI_memblock_clear(DST.vmempool->obinfos, NULL); - BLI_memblock_clear(DST.vmempool->cullstates, NULL); - BLI_memblock_clear(DST.vmempool->shgroups, NULL); - BLI_memblock_clear(DST.vmempool->uniforms, NULL); - BLI_memblock_clear(DST.vmempool->passes, NULL); - BLI_memblock_clear(DST.vmempool->views, NULL); - BLI_memblock_clear(DST.vmempool->images, NULL); - - DRW_uniform_attrs_pool_clear_all(DST.vmempool->obattrs_ubo_pool); - } - - DRW_instance_data_list_free_unused(DST.idatalist); - DRW_instance_data_list_resize(DST.idatalist); -} - /* Not a viewport variable, we could split this out. */ static void drw_context_state_init(void) { @@ -465,107 +408,207 @@ static void draw_unit_state_create(void) DRW_handle_increment(&DST.resource_handle); } -/* It also stores viewport variable to an immutable place: DST - * This is because a cache uniform only store reference - * to its value. And we don't want to invalidate the cache - * if this value change per viewport */ -static void drw_viewport_var_init(void) +DRWData *DRW_viewport_data_create(void) { - RegionView3D *rv3d = DST.draw_ctx.rv3d; - ARegion *region = DST.draw_ctx.region; + DRWData *drw_data = MEM_callocN(sizeof(DRWData), "DRWData"); - /* Refresh DST.size */ - if (DST.viewport) { - int size[2]; - GPU_viewport_size_get(DST.viewport, size); - DST.size[0] = size[0]; - DST.size[1] = size[1]; - DST.inv_size[0] = 1.0f / size[0]; - DST.inv_size[1] = 1.0f / size[1]; + drw_data->texture_pool = DRW_texture_pool_create(); + + drw_data->idatalist = DRW_instance_data_list_create(); - DefaultFramebufferList *fbl = (DefaultFramebufferList *)GPU_viewport_framebuffer_list_get( - DST.viewport); - DST.default_framebuffer = fbl->default_fb; + drw_data->commands = BLI_memblock_create(sizeof(DRWCommandChunk)); + drw_data->commands_small = BLI_memblock_create(sizeof(DRWCommandSmallChunk)); + drw_data->callbuffers = BLI_memblock_create(sizeof(DRWCallBuffer)); + drw_data->shgroups = BLI_memblock_create(sizeof(DRWShadingGroup)); + drw_data->uniforms = BLI_memblock_create(sizeof(DRWUniformChunk)); + drw_data->views = BLI_memblock_create(sizeof(DRWView)); + drw_data->images = BLI_memblock_create(sizeof(GPUTexture *)); + drw_data->obattrs_ubo_pool = DRW_uniform_attrs_pool_new(); + { + uint chunk_len = sizeof(DRWObjectMatrix) * DRW_RESOURCE_CHUNK_LEN; + drw_data->obmats = BLI_memblock_create_ex(sizeof(DRWObjectMatrix), chunk_len); + } + { + uint chunk_len = sizeof(DRWObjectInfos) * DRW_RESOURCE_CHUNK_LEN; + drw_data->obinfos = BLI_memblock_create_ex(sizeof(DRWObjectInfos), chunk_len); + } + { + uint chunk_len = sizeof(DRWCullingState) * DRW_RESOURCE_CHUNK_LEN; + drw_data->cullstates = BLI_memblock_create_ex(sizeof(DRWCullingState), chunk_len); + } + { + uint chunk_len = sizeof(DRWPass) * DRW_RESOURCE_CHUNK_LEN; + drw_data->passes = BLI_memblock_create_ex(sizeof(DRWPass), chunk_len); + } - DST.vmempool = GPU_viewport_mempool_get(DST.viewport); + for (int i = 0; i < 2; i++) { + drw_data->view_data[i] = DRW_view_data_create(&g_registered_engines.engines); + } + return drw_data; +} - if (DST.vmempool->commands == NULL) { - DST.vmempool->commands = BLI_memblock_create(sizeof(DRWCommandChunk)); - } - if (DST.vmempool->commands_small == NULL) { - DST.vmempool->commands_small = BLI_memblock_create(sizeof(DRWCommandSmallChunk)); - } - if (DST.vmempool->callbuffers == NULL) { - DST.vmempool->callbuffers = BLI_memblock_create(sizeof(DRWCallBuffer)); - } - if (DST.vmempool->obmats == NULL) { - uint chunk_len = sizeof(DRWObjectMatrix) * DRW_RESOURCE_CHUNK_LEN; - DST.vmempool->obmats = BLI_memblock_create_ex(sizeof(DRWObjectMatrix), chunk_len); - } - if (DST.vmempool->obinfos == NULL) { - uint chunk_len = sizeof(DRWObjectInfos) * DRW_RESOURCE_CHUNK_LEN; - DST.vmempool->obinfos = BLI_memblock_create_ex(sizeof(DRWObjectInfos), chunk_len); - } - if (DST.vmempool->cullstates == NULL) { - uint chunk_len = sizeof(DRWCullingState) * DRW_RESOURCE_CHUNK_LEN; - DST.vmempool->cullstates = BLI_memblock_create_ex(sizeof(DRWCullingState), chunk_len); - } - if (DST.vmempool->shgroups == NULL) { - DST.vmempool->shgroups = BLI_memblock_create(sizeof(DRWShadingGroup)); - } - if (DST.vmempool->uniforms == NULL) { - DST.vmempool->uniforms = BLI_memblock_create(sizeof(DRWUniformChunk)); - } - if (DST.vmempool->views == NULL) { - DST.vmempool->views = BLI_memblock_create(sizeof(DRWView)); - } - if (DST.vmempool->passes == NULL) { - uint chunk_len = sizeof(DRWPass) * DRW_RESOURCE_CHUNK_LEN; - DST.vmempool->passes = BLI_memblock_create_ex(sizeof(DRWPass), chunk_len); - } - if (DST.vmempool->images == NULL) { - DST.vmempool->images = BLI_memblock_create(sizeof(GPUTexture *)); - } - if (DST.vmempool->obattrs_ubo_pool == NULL) { - DST.vmempool->obattrs_ubo_pool = DRW_uniform_attrs_pool_new(); +/* Reduce ref count of the textures used by a viewport. */ +static void draw_texture_release(DRWData *drw_data) +{ + /* Release Image textures. */ + BLI_memblock_iter iter; + GPUTexture **tex; + BLI_memblock_iternew(drw_data->images, &iter); + while ((tex = BLI_memblock_iterstep(&iter))) { + GPU_texture_free(*tex); + } +} + +static void drw_viewport_data_reset(DRWData *drw_data) +{ + draw_texture_release(drw_data); + + BLI_memblock_clear(drw_data->commands, NULL); + BLI_memblock_clear(drw_data->commands_small, NULL); + BLI_memblock_clear(drw_data->callbuffers, NULL); + BLI_memblock_clear(drw_data->obmats, NULL); + BLI_memblock_clear(drw_data->obinfos, NULL); + BLI_memblock_clear(drw_data->cullstates, NULL); + BLI_memblock_clear(drw_data->shgroups, NULL); + BLI_memblock_clear(drw_data->uniforms, NULL); + BLI_memblock_clear(drw_data->passes, NULL); + BLI_memblock_clear(drw_data->views, NULL); + BLI_memblock_clear(drw_data->images, NULL); + DRW_uniform_attrs_pool_clear_all(drw_data->obattrs_ubo_pool); + DRW_instance_data_list_free_unused(drw_data->idatalist); + DRW_instance_data_list_resize(drw_data->idatalist); + DRW_instance_data_list_reset(drw_data->idatalist); + DRW_texture_pool_reset(drw_data->texture_pool); +} + +void DRW_viewport_data_free(DRWData *drw_data) +{ + draw_texture_release(drw_data); + + BLI_memblock_destroy(drw_data->commands, NULL); + BLI_memblock_destroy(drw_data->commands_small, NULL); + BLI_memblock_destroy(drw_data->callbuffers, NULL); + BLI_memblock_destroy(drw_data->obmats, NULL); + BLI_memblock_destroy(drw_data->obinfos, NULL); + BLI_memblock_destroy(drw_data->cullstates, NULL); + BLI_memblock_destroy(drw_data->shgroups, NULL); + BLI_memblock_destroy(drw_data->uniforms, NULL); + BLI_memblock_destroy(drw_data->views, NULL); + BLI_memblock_destroy(drw_data->passes, NULL); + BLI_memblock_destroy(drw_data->images, NULL); + DRW_uniform_attrs_pool_free(drw_data->obattrs_ubo_pool); + DRW_instance_data_list_free(drw_data->idatalist); + DRW_texture_pool_free(drw_data->texture_pool); + for (int i = 0; i < 2; i++) { + DRW_view_data_free(drw_data->view_data[i]); + } + if (drw_data->matrices_ubo != NULL) { + for (int i = 0; i < drw_data->ubo_len; i++) { + GPU_uniformbuf_free(drw_data->matrices_ubo[i]); + GPU_uniformbuf_free(drw_data->obinfos_ubo[i]); } + MEM_freeN(drw_data->matrices_ubo); + MEM_freeN(drw_data->obinfos_ubo); + } + MEM_freeN(drw_data); +} - DST.resource_handle = 0; - DST.pass_handle = 0; +static DRWData *drw_viewport_data_ensure(GPUViewport *viewport) +{ + DRWData **vmempool_p = GPU_viewport_data_get(viewport); + DRWData *vmempool = *vmempool_p; - draw_unit_state_create(); + if (vmempool == NULL) { + *vmempool_p = vmempool = DRW_viewport_data_create(); + } + return vmempool; +} - DST.idatalist = GPU_viewport_instance_data_list_get(DST.viewport); - DRW_instance_data_list_reset(DST.idatalist); +/** + * Sets DST.viewport, DST.size and a lot of other important variables. + * Needs to be called before enabling any draw engine. + * - viewport can be NULL. In this case the data will not be stored and will be free at + * drw_manager_exit(). + * - size can be NULL to get it from viewport. + * - if viewport and size are NULL, size is set to (1, 1). + * + * Important: drw_manager_init can be called multiple times before drw_manager_exit. + */ +static void drw_manager_init(DRWManager *dst, GPUViewport *viewport, const int size[2]) +{ + RegionView3D *rv3d = dst->draw_ctx.rv3d; + ARegion *region = dst->draw_ctx.region; + + int view = (viewport) ? GPU_viewport_active_view_get(viewport) : 0; + + if (!dst->viewport && dst->vmempool) { + /* Manager was init first without a viewport, created DRWData, but is being re-init. + * In this case, keep the old data. */ + /* If it is being re-init with a valid viewport, it means there is something wrong. */ + BLI_assert(viewport == NULL); + } + else if (viewport) { + /* Use viewport's persistent DRWData. */ + dst->vmempool = drw_viewport_data_ensure(viewport); } else { - DST.size[0] = 0; - DST.size[1] = 0; + /* Create temporary DRWData. Freed in drw_manager_exit(). */ + dst->vmempool = DRW_viewport_data_create(); + } - DST.inv_size[0] = 0; - DST.inv_size[1] = 0; + dst->viewport = viewport; + dst->view_data_active = dst->vmempool->view_data[view]; + dst->resource_handle = 0; + dst->pass_handle = 0; + dst->primary_view_ct = 0; - DST.default_framebuffer = NULL; - DST.vmempool = NULL; + drw_viewport_data_reset(dst->vmempool); + + if (size == NULL && viewport == NULL) { + /* Avoid division by 0. Engines will either overide this or not use it. */ + dst->size[0] = 1.0f; + dst->size[1] = 1.0f; + } + else if (size == NULL) { + BLI_assert(viewport); + GPUTexture *tex = GPU_viewport_color_texture(viewport, 0); + dst->size[0] = GPU_texture_width(tex); + dst->size[1] = GPU_texture_height(tex); } + else { + BLI_assert(size); + dst->size[0] = size[0]; + dst->size[1] = size[1]; + } + dst->inv_size[0] = 1.0f / dst->size[0]; + dst->inv_size[1] = 1.0f / dst->size[1]; + + DRW_view_data_texture_list_size_validate(dst->view_data_active, (int[2]){UNPACK2(dst->size)}); + + if (viewport) { + DRW_view_data_default_lists_from_viewport(dst->view_data_active, viewport); + } + + DefaultFramebufferList *dfbl = DRW_view_data_default_framebuffer_list_get(dst->view_data_active); + dst->default_framebuffer = dfbl->default_fb; - DST.primary_view_ct = 0; + draw_unit_state_create(); if (rv3d != NULL) { - normalize_v3_v3(DST.screenvecs[0], rv3d->viewinv[0]); - normalize_v3_v3(DST.screenvecs[1], rv3d->viewinv[1]); + normalize_v3_v3(dst->screenvecs[0], rv3d->viewinv[0]); + normalize_v3_v3(dst->screenvecs[1], rv3d->viewinv[1]); - DST.pixsize = rv3d->pixsize; - DST.view_default = DRW_view_create(rv3d->viewmat, rv3d->winmat, NULL, NULL, NULL); - DRW_view_camtexco_set(DST.view_default, rv3d->viewcamtexcofac); + dst->pixsize = rv3d->pixsize; + dst->view_default = DRW_view_create(rv3d->viewmat, rv3d->winmat, NULL, NULL, NULL); + DRW_view_camtexco_set(dst->view_default, rv3d->viewcamtexcofac); - if (DST.draw_ctx.sh_cfg == GPU_SHADER_CFG_CLIPPED) { + if (dst->draw_ctx.sh_cfg == GPU_SHADER_CFG_CLIPPED) { int plane_len = (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXCLIP) ? 4 : 6; - DRW_view_clip_planes_set(DST.view_default, rv3d->clip, plane_len); + DRW_view_clip_planes_set(dst->view_default, rv3d->clip, plane_len); } - DST.view_active = DST.view_default; - DST.view_previous = NULL; + dst->view_active = dst->view_default; + dst->view_previous = NULL; } else if (region) { View2D *v2d = ®ion->v2d; @@ -581,49 +624,64 @@ static void drw_viewport_var_init(void) winmat[3][0] = -1.0f; winmat[3][1] = -1.0f; - DST.view_default = DRW_view_create(viewmat, winmat, NULL, NULL, NULL); - DST.view_active = DST.view_default; - DST.view_previous = NULL; + dst->view_default = DRW_view_create(viewmat, winmat, NULL, NULL, NULL); + dst->view_active = dst->view_default; + dst->view_previous = NULL; } else { - zero_v3(DST.screenvecs[0]); - zero_v3(DST.screenvecs[1]); + zero_v3(dst->screenvecs[0]); + zero_v3(dst->screenvecs[1]); - DST.pixsize = 1.0f; - DST.view_default = NULL; - DST.view_active = NULL; - DST.view_previous = NULL; + dst->pixsize = 1.0f; + dst->view_default = NULL; + dst->view_active = NULL; + dst->view_previous = NULL; } /* fclem: Is this still needed ? */ - if (DST.draw_ctx.object_edit && rv3d) { - ED_view3d_init_mats_rv3d(DST.draw_ctx.object_edit, rv3d); + if (dst->draw_ctx.object_edit && rv3d) { + ED_view3d_init_mats_rv3d(dst->draw_ctx.object_edit, rv3d); } if (G_draw.view_ubo == NULL) { G_draw.view_ubo = GPU_uniformbuf_create_ex(sizeof(DRWViewUboStorage), NULL, "G_draw.view_ubo"); } - if (DST.draw_list == NULL) { - DST.draw_list = GPU_draw_list_create(DRW_DRAWLIST_LEN); + if (dst->draw_list == NULL) { + dst->draw_list = GPU_draw_list_create(DRW_DRAWLIST_LEN); } - memset(DST.object_instance_data, 0x0, sizeof(DST.object_instance_data)); + memset(dst->object_instance_data, 0x0, sizeof(dst->object_instance_data)); +} + +static void drw_manager_exit(DRWManager *dst) +{ + if (dst->vmempool != NULL && dst->viewport == NULL) { + DRW_viewport_data_free(dst->vmempool); + } + dst->vmempool = NULL; + dst->viewport = NULL; +#ifdef DEBUG + /* Avoid accidental reuse. */ + drw_state_ensure_not_reused(dst); +#endif } DefaultFramebufferList *DRW_viewport_framebuffer_list_get(void) { - return GPU_viewport_framebuffer_list_get(DST.viewport); + return DRW_view_data_default_framebuffer_list_get(DST.view_data_active); } DefaultTextureList *DRW_viewport_texture_list_get(void) { - return GPU_viewport_texture_list_get(DST.viewport); + return DRW_view_data_default_texture_list_get(DST.view_data_active); } void DRW_viewport_request_redraw(void) { - GPU_viewport_tag_update(DST.viewport); + if (DST.viewport) { + GPU_viewport_tag_update(DST.viewport); + } } /** \} */ @@ -671,7 +729,7 @@ static void drw_duplidata_load(Object *ob) void **value; if (!BLI_ghash_ensure_p(DST.dupli_ghash, key, &value)) { - *value = MEM_callocN(sizeof(void *) * DST.enabled_engine_count, __func__); + *value = MEM_callocN(sizeof(void *) * g_registered_engines.len, __func__); /* TODO: Meh a bit out of place but this is nice as it is * only done once per instance type. */ @@ -686,7 +744,7 @@ static void drw_duplidata_load(Object *ob) static void duplidata_value_free(void *val) { void **dupli_datas = val; - for (int i = 0; i < DST.enabled_engine_count; i++) { + for (int i = 0; i < g_registered_engines.len; i++) { MEM_SAFE_FREE(dupli_datas[i]); } MEM_freeN(val); @@ -720,13 +778,9 @@ void **DRW_duplidata_get(void *vedata) if (DST.dupli_source == NULL) { return NULL; } - /* XXX Search engine index by using vedata array */ - for (int i = 0; i < DST.enabled_engine_count; i++) { - if (DST.vedata_array[i] == vedata) { - return &DST.dupli_datas[i]; - } - } - return NULL; + ViewportEngineData *ved = (ViewportEngineData *)vedata; + DRWRegisteredDrawEngine *engine_type = (DRWRegisteredDrawEngine *)ved->engine_type; + return &DST.dupli_datas[engine_type->index]; } /** \} */ @@ -873,7 +927,7 @@ DrawData *DRW_drawdata_ensure(ID *id, size_t fsize = size / sizeof(float); BLI_assert(fsize < MAX_INSTANCE_DATA_SIZE); if (DST.object_instance_data[fsize] == NULL) { - DST.object_instance_data[fsize] = DRW_instance_data_request(DST.idatalist, fsize); + DST.object_instance_data[fsize] = DRW_instance_data_request(DST.vmempool->idatalist, fsize); } dd = (DrawData *)DRW_instance_data_next(DST.object_instance_data[fsize]); memset(dd, 0, size); @@ -967,11 +1021,12 @@ void DRW_cache_free_old_batches(Main *bmain) static void drw_engines_init(void) { - LISTBASE_FOREACH (LinkData *, link, &DST.enabled_engines) { - DrawEngineType *engine = link->data; - ViewportEngineData *data = drw_viewport_engine_data_ensure(engine); + DRW_ENABLED_ENGINE_ITER (DST.view_data_active, engine, data) { PROFILE_START(stime); + const DrawEngineDataSize *data_size = engine->vedata_size; + memset(data->psl->passes, 0, sizeof(*data->psl->passes) * data_size->psl_len); + if (engine->engine_init) { engine->engine_init(data); } @@ -982,15 +1037,7 @@ static void drw_engines_init(void) static void drw_engines_cache_init(void) { - DST.enabled_engine_count = BLI_listbase_count(&DST.enabled_engines); - DST.vedata_array = MEM_mallocN(sizeof(void *) * DST.enabled_engine_count, __func__); - - int i = 0; - for (LinkData *link = DST.enabled_engines.first; link; link = link->next, i++) { - DrawEngineType *engine = link->data; - ViewportEngineData *data = drw_viewport_engine_data_ensure(engine); - DST.vedata_array[i] = data; - + DRW_ENABLED_ENGINE_ITER (DST.view_data_active, engine, data) { if (data->text_draw_cache) { DRW_text_cache_destroy(data->text_draw_cache); data->text_draw_cache = NULL; @@ -1011,10 +1058,7 @@ static void drw_engines_world_update(Scene *scene) return; } - LISTBASE_FOREACH (LinkData *, link, &DST.enabled_engines) { - DrawEngineType *engine = link->data; - ViewportEngineData *data = drw_viewport_engine_data_ensure(engine); - + DRW_ENABLED_ENGINE_ITER (DST.view_data_active, engine, data) { if (engine->id_update) { engine->id_update(data, &scene->world->id); } @@ -1036,11 +1080,7 @@ static void drw_engines_cache_populate(Object *ob) drw_batch_cache_validate(ob); } - int i = 0; - for (LinkData *link = DST.enabled_engines.first; link; link = link->next, i++) { - DrawEngineType *engine = link->data; - ViewportEngineData *data = DST.vedata_array[i]; - + DRW_ENABLED_ENGINE_ITER (DST.view_data_active, engine, data) { if (engine->id_update) { engine->id_update(data, &ob->id); } @@ -1063,25 +1103,17 @@ static void drw_engines_cache_populate(Object *ob) static void drw_engines_cache_finish(void) { - int i = 0; - for (LinkData *link = DST.enabled_engines.first; link; link = link->next, i++) { - DrawEngineType *engine = link->data; - ViewportEngineData *data = DST.vedata_array[i]; - + DRW_ENABLED_ENGINE_ITER (DST.view_data_active, engine, data) { if (engine->cache_finish) { engine->cache_finish(data); } } - MEM_freeN(DST.vedata_array); } static void drw_engines_draw_scene(void) { - LISTBASE_FOREACH (LinkData *, link, &DST.enabled_engines) { - DrawEngineType *engine = link->data; - ViewportEngineData *data = drw_viewport_engine_data_ensure(engine); + DRW_ENABLED_ENGINE_ITER (DST.view_data_active, engine, data) { PROFILE_START(stime); - if (engine->draw_scene) { DRW_stats_group_start(engine->idname); engine->draw_scene(data); @@ -1091,7 +1123,6 @@ static void drw_engines_draw_scene(void) } DRW_stats_group_end(); } - PROFILE_END_UPDATE(data->render_time, stime); } /* Reset state after drawing */ @@ -1100,9 +1131,7 @@ static void drw_engines_draw_scene(void) static void drw_engines_draw_text(void) { - LISTBASE_FOREACH (LinkData *, link, &DST.enabled_engines) { - DrawEngineType *engine = link->data; - ViewportEngineData *data = drw_viewport_engine_data_ensure(engine); + DRW_ENABLED_ENGINE_ITER (DST.view_data_active, engine, data) { PROFILE_START(stime); if (data->text_draw_cache) { @@ -1116,10 +1145,7 @@ static void drw_engines_draw_text(void) /* Draw render engine info. */ void DRW_draw_region_engine_info(int xoffset, int *yoffset, int line_height) { - LISTBASE_FOREACH (LinkData *, link, &DST.enabled_engines) { - DrawEngineType *engine = link->data; - ViewportEngineData *data = drw_viewport_engine_data_ensure(engine); - + DRW_ENABLED_ENGINE_ITER (DST.view_data_active, engine, data) { if (data->info[0] != '\0') { char *chr_current = data->info; char *chr_start = chr_current; @@ -1158,12 +1184,10 @@ void DRW_draw_region_engine_info(int xoffset, int *yoffset, int line_height) static void use_drw_engine(DrawEngineType *engine) { - LinkData *ld = MEM_callocN(sizeof(LinkData), "enabled engine link data"); - ld->data = engine; - BLI_addtail(&DST.enabled_engines, ld); + DRW_view_data_use_engine(DST.view_data_active, engine); } -/* Gather all draw engines needed and store them in DST.enabled_engines +/* Gather all draw engines needed and store them in DST.view_data_active * That also define the rendering order of engines */ static void drw_engines_enable_from_engine(const RenderEngineType *engine_type, eDrawType drawtype) { @@ -1252,22 +1276,12 @@ static void drw_engines_enable(ViewLayer *UNUSED(view_layer), static void drw_engines_disable(void) { - BLI_freelistN(&DST.enabled_engines); + DRW_view_data_reset(DST.view_data_active); } static void drw_engines_data_validate(void) { - int enabled_engines = BLI_listbase_count(&DST.enabled_engines); - void **engine_handle_array = BLI_array_alloca(engine_handle_array, enabled_engines + 1); - int i = 0; - - LISTBASE_FOREACH (LinkData *, link, &DST.enabled_engines) { - DrawEngineType *engine = link->data; - engine_handle_array[i++] = engine; - } - engine_handle_array[i] = NULL; - - GPU_viewport_engines_data_validate(DST.viewport, engine_handle_array); + DRW_view_data_free_unused(DST.view_data_active); } /* Fast check to see if gpencil drawing engine is needed. @@ -1294,55 +1308,57 @@ void DRW_notify_view_update(const DRWUpdateContext *update_ctx) Scene *scene = update_ctx->scene; ViewLayer *view_layer = update_ctx->view_layer; + GPUViewport *viewport = WM_draw_region_get_viewport(region); + if (!viewport) { + return; + } + const bool gpencil_engine_needed = drw_gpencil_engine_needed(depsgraph, v3d); - /* Separate update for each stereo view. */ - for (int view = 0; view < 2; view++) { - GPUViewport *viewport = WM_draw_region_get_viewport(region); - if (!viewport) { - continue; - } + /* XXX Really nasty locking. But else this could + * be executed by the material previews thread + * while rendering a viewport. */ + BLI_ticket_mutex_lock(DST.gl_context_mutex); - /* XXX Really nasty locking. But else this could - * be executed by the material previews thread - * while rendering a viewport. */ - BLI_ticket_mutex_lock(DST.gl_context_mutex); + /* Reset before using it. */ + drw_state_prepare_clean_for_draw(&DST); - /* Reset before using it. */ - drw_state_prepare_clean_for_draw(&DST); + DST.draw_ctx = (DRWContextState){ + .region = region, + .rv3d = rv3d, + .v3d = v3d, + .scene = scene, + .view_layer = view_layer, + .obact = OBACT(view_layer), + .engine_type = engine_type, + .depsgraph = depsgraph, + .object_mode = OB_MODE_OBJECT, + }; - DST.viewport = viewport; - GPU_viewport_active_view_set(viewport, view); - DST.draw_ctx = (DRWContextState){ - .region = region, - .rv3d = rv3d, - .v3d = v3d, - .scene = scene, - .view_layer = view_layer, - .obact = OBACT(view_layer), - .engine_type = engine_type, - .depsgraph = depsgraph, - .object_mode = OB_MODE_OBJECT, - }; + /* Custom lightweight init to avoid reseting the mempools. */ + DST.viewport = viewport; + DST.vmempool = drw_viewport_data_ensure(DST.viewport); + + /* Separate update for each stereo view. */ + int view_count = GPU_viewport_is_stereo_get(viewport) ? 2 : 1; + for (int view = 0; view < view_count; view++) { + DST.view_data_active = DST.vmempool->view_data[view]; drw_engines_enable(view_layer, engine_type, gpencil_engine_needed); drw_engines_data_validate(); - LISTBASE_FOREACH (LinkData *, link, &DST.enabled_engines) { - DrawEngineType *draw_engine = link->data; - ViewportEngineData *data = drw_viewport_engine_data_ensure(draw_engine); - + DRW_ENABLED_ENGINE_ITER (DST.view_data_active, draw_engine, data) { if (draw_engine->view_update) { draw_engine->view_update(data); } } - DST.viewport = NULL; - drw_engines_disable(); - - BLI_ticket_mutex_unlock(DST.gl_context_mutex); } + + drw_manager_exit(&DST); + + BLI_ticket_mutex_unlock(DST.gl_context_mutex); } /** \} */ @@ -1513,8 +1529,6 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, RegionView3D *rv3d = region->regiondata; DST.draw_ctx.evil_C = evil_C; - DST.viewport = viewport; - /* Setup viewport */ DST.draw_ctx = (DRWContextState){ .region = region, .rv3d = rv3d, @@ -1531,8 +1545,8 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, drw_task_graph_init(); drw_context_state_init(); - drw_viewport_var_init(); - DRW_viewport_colormanagement_set(DST.viewport); + drw_manager_init(&DST, viewport, NULL); + DRW_viewport_colormanagement_set(viewport); const int object_type_exclude_viewport = v3d->object_type_exclude_viewport; /* Check if scene needs to perform the populate loop */ @@ -1591,7 +1605,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, DRW_render_instance_buffer_finish(); #ifdef USE_PROFILE - double *cache_time = GPU_viewport_cache_time_get(DST.viewport); + double *cache_time = DRW_view_data_cache_time_get(DST.view_data_active); PROFILE_END_UPDATE(*cache_time, stime); #endif } @@ -1631,12 +1645,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, DRW_state_reset(); drw_engines_disable(); - drw_viewport_cache_resize(); - -#ifdef DEBUG - /* Avoid accidental reuse. */ - drw_state_ensure_not_reused(&DST); -#endif + drw_manager_exit(&DST); } void DRW_draw_render_loop(struct Depsgraph *depsgraph, @@ -1674,6 +1683,9 @@ void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph, GPU_viewport_bind_from_offscreen(render_viewport, ofs); + /* Just here to avoid an assert but shouldn't be required in practice. */ + GPU_framebuffer_restore(); + /* Reset before using it. */ drw_state_prepare_clean_for_draw(&DST); DST.options.is_image_render = is_image_render; @@ -1735,7 +1747,8 @@ static void DRW_render_gpencil_to_image(RenderEngine *engine, const rcti *rect) { if (draw_engine_gpencil_type.render_to_image) { - ViewportEngineData *gpdata = drw_viewport_engine_data_ensure(&draw_engine_gpencil_type); + ViewportEngineData *gpdata = DRW_view_data_engine_data_get_ensure(DST.view_data_active, + &draw_engine_gpencil_type); draw_engine_gpencil_type.render_to_image(gpdata, engine, render_layer, rect); } } @@ -1769,11 +1782,9 @@ void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph }; drw_context_state_init(); - DST.viewport = GPU_viewport_create(); const int size[2] = {engine->resolution_x, engine->resolution_y}; - GPU_viewport_size_set(DST.viewport, size); - drw_viewport_var_init(); + drw_manager_init(&DST, NULL, size); /* Main rendering. */ rctf view_rect; @@ -1793,13 +1804,12 @@ void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph DRW_render_gpencil_to_image(engine, render_layer, &render_rect); } - /* Force cache to reset. */ - drw_viewport_cache_resize(); - GPU_viewport_free(DST.viewport); DRW_state_reset(); GPU_depth_test(GPU_DEPTH_NONE); + drw_manager_exit(&DST); + /* Restore Drawing area. */ GPU_framebuffer_restore(); @@ -1848,13 +1858,12 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph) }; drw_context_state_init(); - DST.viewport = GPU_viewport_create(); const int size[2] = {engine->resolution_x, engine->resolution_y}; - GPU_viewport_size_set(DST.viewport, size); - drw_viewport_var_init(); + drw_manager_init(&DST, NULL, size); - ViewportEngineData *data = drw_viewport_engine_data_ensure(draw_engine_type); + ViewportEngineData *data = DRW_view_data_engine_data_get_ensure(DST.view_data_active, + draw_engine_type); /* Main rendering. */ rctf view_rect; @@ -1898,16 +1907,9 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph) engine_type->draw_engine->store_metadata(data, final_render_result); } - /* Force cache to reset. */ - drw_viewport_cache_resize(); - - GPU_viewport_free(DST.viewport); GPU_framebuffer_restore(); -#ifdef DEBUG - /* Avoid accidental reuse. */ - drw_state_ensure_not_reused(&DST); -#endif + drw_manager_exit(&DST); /* Reset state after drawing */ DRW_state_reset(); @@ -1976,21 +1978,17 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type, }; drw_context_state_init(); - DST.viewport = GPU_viewport_create(); - const int size[2] = {1, 1}; - GPU_viewport_size_set(DST.viewport, size); - - drw_viewport_var_init(); + drw_manager_init(&DST, NULL, NULL); DRW_hair_init(); - ViewportEngineData *data = drw_viewport_engine_data_ensure(draw_engine_type); + ViewportEngineData *data = DRW_view_data_engine_data_get_ensure(DST.view_data_active, + draw_engine_type); /* Execute the callback */ callback(data, user_data); DST.buffer_finish_called = false; - GPU_viewport_free(DST.viewport); GPU_framebuffer_restore(); /* The use of custom pipeline in other thread using the same @@ -1999,33 +1997,18 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type, * GPU_finish to sync seems to fix the issue. (see T62997) */ GPU_finish(); -#ifdef DEBUG - /* Avoid accidental reuse. */ - drw_state_ensure_not_reused(&DST); -#endif + drw_manager_exit(&DST); } /* Used when the render engine want to redo another cache populate inside the same render frame. */ void DRW_cache_restart(void) { - /* Save viewport size. */ - float size[2], inv_size[2]; - copy_v2_v2(size, DST.size); - copy_v2_v2(inv_size, DST.inv_size); - - /* Force cache to reset. */ - drw_viewport_cache_resize(); - - drw_viewport_var_init(); + drw_manager_init(&DST, DST.viewport, (int[2]){UNPACK2(DST.size)}); DST.buffer_finish_called = false; DRW_hair_init(); - - /* Restore. */ - copy_v2_v2(DST.size, size); - copy_v2_v2(DST.inv_size, inv_size); } void DRW_draw_render_loop_2d_ex(struct Depsgraph *depsgraph, @@ -2037,9 +2020,6 @@ void DRW_draw_render_loop_2d_ex(struct Depsgraph *depsgraph, ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph); DST.draw_ctx.evil_C = evil_C; - DST.viewport = viewport; - - /* Setup viewport */ DST.draw_ctx = (DRWContextState){ .region = region, .scene = scene, @@ -2053,8 +2033,8 @@ void DRW_draw_render_loop_2d_ex(struct Depsgraph *depsgraph, }; drw_context_state_init(); - drw_viewport_var_init(); - DRW_viewport_colormanagement_set(DST.viewport); + drw_manager_init(&DST, viewport, NULL); + DRW_viewport_colormanagement_set(viewport); /* TODO(jbakker): Only populate when editor needs to draw object. * for the image editor this is when showing UV's. */ @@ -2098,7 +2078,7 @@ void DRW_draw_render_loop_2d_ex(struct Depsgraph *depsgraph, DRW_render_instance_buffer_finish(); #ifdef USE_PROFILE - double *cache_time = GPU_viewport_cache_time_get(DST.viewport); + double *cache_time = DRW_view_data_cache_time_get(DST.view_data_active); PROFILE_END_UPDATE(*cache_time, stime); #endif } @@ -2180,12 +2160,7 @@ void DRW_draw_render_loop_2d_ex(struct Depsgraph *depsgraph, DRW_state_reset(); drw_engines_disable(); - drw_viewport_cache_resize(); - -#ifdef DEBUG - /* Avoid accidental reuse. */ - drw_state_ensure_not_reused(&DST); -#endif + drw_manager_exit(&DST); } static struct DRWSelectBuffer { @@ -2222,7 +2197,7 @@ void DRW_render_instance_buffer_finish(void) { BLI_assert_msg(!DST.buffer_finish_called, "DRW_render_instance_buffer_finish called twice!"); DST.buffer_finish_called = true; - DRW_instance_buffer_finish(DST.idatalist); + DRW_instance_buffer_finish(DST.vmempool->idatalist); drw_resource_buffer_finish(DST.vmempool); } @@ -2305,11 +2280,22 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, } } + /* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */ + DST.draw_ctx = (DRWContextState){ + .region = region, + .rv3d = rv3d, + .v3d = v3d, + .scene = scene, + .view_layer = view_layer, + .obact = obact, + .engine_type = engine_type, + .depsgraph = depsgraph, + }; + drw_context_state_init(); + const int viewport_size[2] = {BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)}; - struct GPUViewport *viewport = GPU_viewport_create(); - GPU_viewport_size_set(viewport, viewport_size); + drw_manager_init(&DST, NULL, viewport_size); - DST.viewport = viewport; DST.options.is_select = true; DST.options.is_material_select = do_material_sub_selection; drw_task_graph_init(); @@ -2337,22 +2323,6 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, } drw_engines_data_validate(); - /* Setup viewport */ - - /* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */ - DST.draw_ctx = (DRWContextState){ - .region = region, - .rv3d = rv3d, - .v3d = v3d, - .scene = scene, - .view_layer = view_layer, - .obact = obact, - .engine_type = engine_type, - .depsgraph = depsgraph, - }; - drw_context_state_init(); - drw_viewport_var_init(); - /* Update UBO's */ DRW_globals_update(); @@ -2456,14 +2426,10 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, DRW_state_reset(); drw_engines_disable(); -# ifdef DEBUG - /* Avoid accidental reuse. */ - drw_state_ensure_not_reused(&DST); -# endif + drw_manager_exit(&DST); + GPU_framebuffer_restore(); - /* Cleanup for selection state */ - GPU_viewport_free(viewport); #endif /* USE_GPU_SELECT */ } @@ -2485,7 +2451,6 @@ static void drw_draw_depth_loop_impl(struct Depsgraph *depsgraph, DRW_opengl_context_enable(); } - DST.viewport = viewport; DST.options.is_depth = true; /* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */ @@ -2499,18 +2464,21 @@ static void drw_draw_depth_loop_impl(struct Depsgraph *depsgraph, .engine_type = engine_type, .depsgraph = depsgraph, }; + drw_context_state_init(); drw_task_graph_init(); - drw_engines_data_validate(); /* Setup frame-buffer. */ - DefaultFramebufferList *fbl = (DefaultFramebufferList *)GPU_viewport_framebuffer_list_get( - DST.viewport); - GPU_framebuffer_bind(fbl->depth_only_fb); - GPU_framebuffer_clear_depth(fbl->depth_only_fb, 1.0f); + GPUTexture *depth_tx = GPU_viewport_depth_texture(viewport); - /* Setup viewport */ - drw_context_state_init(); - drw_viewport_var_init(); + GPUFrameBuffer *depth_fb = NULL; + GPU_framebuffer_ensure_config(&depth_fb, + { + GPU_ATTACHMENT_TEXTURE(depth_tx), + GPU_ATTACHMENT_NONE, + }); + + GPU_framebuffer_bind(depth_fb); + GPU_framebuffer_clear_depth(depth_fb, 1.0f); /* Update UBO's */ DRW_globals_update(); @@ -2559,15 +2527,11 @@ static void drw_draw_depth_loop_impl(struct Depsgraph *depsgraph, /* TODO: Reading depth for operators should be done here. */ GPU_framebuffer_restore(); + GPU_framebuffer_free(depth_fb); drw_engines_disable(); - drw_viewport_cache_resize(); - -#ifdef DEBUG - /* Avoid accidental reuse. */ - drw_state_ensure_not_reused(&DST); -#endif + drw_manager_exit(&DST); /* Changing context. */ if (use_opengl_context) { @@ -2586,6 +2550,11 @@ void DRW_draw_depth_loop(struct Depsgraph *depsgraph, /* Reset before using it. */ drw_state_prepare_clean_for_draw(&DST); + /* Required by `drw_manager_init()` */ + DST.draw_ctx.region = region; + DST.draw_ctx.rv3d = region->regiondata; + drw_manager_init(&DST, viewport, NULL); + /* Get list of enabled engines */ { /* Required by `DRW_state_draw_support()` */ @@ -2611,6 +2580,11 @@ void DRW_draw_depth_loop_gpencil(struct Depsgraph *depsgraph, /* Reset before using it. */ drw_state_prepare_clean_for_draw(&DST); + /* Required by `drw_manager_init()` */ + DST.draw_ctx.region = region; + DST.draw_ctx.rv3d = region->regiondata; + drw_manager_init(&DST, viewport, NULL); + use_drw_engine(&draw_engine_gpencil_type); drw_draw_depth_loop_impl(depsgraph, region, v3d, viewport, false); @@ -2648,9 +2622,7 @@ void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *region, View3D *v3d, cons drw_task_graph_init(); drw_context_state_init(); - /* Setup viewport */ - DST.viewport = viewport; - drw_viewport_var_init(); + drw_manager_init(&DST, viewport, NULL); /* Update UBO's */ UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW); @@ -2677,7 +2649,7 @@ void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *region, View3D *v3d, cons DRW_render_instance_buffer_finish(); #else DST.buffer_finish_called = true; - // DRW_instance_buffer_finish(DST.idatalist); + // DRW_instance_buffer_finish(DST.vmempool->idatalist); drw_resource_buffer_finish(DST.vmempool); #endif } @@ -2689,12 +2661,7 @@ void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *region, View3D *v3d, cons drw_engines_disable(); - drw_viewport_cache_resize(); - -#ifdef DEBUG - /* Avoid accidental reuse. */ - drw_state_ensure_not_reused(&DST); -#endif + drw_manager_exit(&DST); } /** @@ -2710,10 +2677,17 @@ void DRW_draw_depth_object( GPU_matrix_mul(object->obmat); /* Setup frame-buffer. */ - DefaultFramebufferList *fbl = GPU_viewport_framebuffer_list_get(viewport); + GPUTexture *depth_tx = GPU_viewport_depth_texture(viewport); + + GPUFrameBuffer *depth_fb = NULL; + GPU_framebuffer_ensure_config(&depth_fb, + { + GPU_ATTACHMENT_TEXTURE(depth_tx), + GPU_ATTACHMENT_NONE, + }); - GPU_framebuffer_bind(fbl->depth_only_fb); - GPU_framebuffer_clear_depth(fbl->depth_only_fb, 1.0f); + GPU_framebuffer_bind(depth_fb); + GPU_framebuffer_clear_depth(depth_fb, 1.0f); GPU_depth_test(GPU_DEPTH_LESS_EQUAL); const float(*world_clip_planes)[4] = NULL; @@ -2763,6 +2737,9 @@ void DRW_draw_depth_object( GPU_matrix_set(rv3d->viewmat); GPU_depth_test(GPU_DEPTH_NONE); GPU_framebuffer_restore(); + + GPU_framebuffer_free(depth_fb); + DRW_opengl_context_disable(); } /** \} */ @@ -2895,7 +2872,12 @@ bool DRW_engine_render_support(DrawEngineType *draw_engine_type) void DRW_engine_register(DrawEngineType *draw_engine_type) { - BLI_addtail(&DRW_engines, draw_engine_type); + DRWRegisteredDrawEngine *draw_engine = MEM_mallocN(sizeof(DRWRegisteredDrawEngine), __func__); + draw_engine->draw_engine = draw_engine_type; + draw_engine->index = g_registered_engines.len; + + BLI_addtail(&g_registered_engines.engines, draw_engine); + g_registered_engines.len = BLI_listbase_count(&g_registered_engines.engines); } void DRW_engines_register(void) @@ -2966,14 +2948,15 @@ void DRW_engines_free(void) DRW_stats_free(); DRW_globals_free(); - DrawEngineType *next; - for (DrawEngineType *type = DRW_engines.first; type; type = next) { + DRWRegisteredDrawEngine *next; + for (DRWRegisteredDrawEngine *type = g_registered_engines.engines.first; type; type = next) { next = type->next; BLI_remlink(&R_engines, type); - if (type->engine_free) { - type->engine_free(); + if (type->draw_engine->engine_free) { + type->draw_engine->engine_free(); } + MEM_freeN(type); } DRW_UBO_FREE_SAFE(G_draw.block_ubo); diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h index c09126c98ef..1bb1ee06354 100644 --- a/source/blender/draw/intern/draw_manager.h +++ b/source/blender/draw/intern/draw_manager.h @@ -98,6 +98,17 @@ struct Object; /* ------------ Data Structure --------------- */ /** + * Data structure to for registered draw engines that can store draw manager + * specific data. + */ +typedef struct DRWRegisteredDrawEngine { + void /*DRWRegisteredDrawEngine*/ *next, *prev; + DrawEngineType *draw_engine; + /** Index of the type in the lists. Index is used for dupli data. */ + int index; +} DRWRegisteredDrawEngine; + +/** * Data structure containing all drawcalls organized by passes and materials. * DRWPass > DRWShadingGroup > DRWCall > DRWCallState * > DRWUniform @@ -495,6 +506,35 @@ typedef struct DRWDebugSphere { float color[4]; } DRWDebugSphere; +/* ------------- Memory Pools ------------ */ + +/* Contains memory pools information */ +typedef struct DRWData { + /** Instance data. */ + DRWInstanceDataList *idatalist; + /** Mempools for drawcalls. */ + struct BLI_memblock *commands; + struct BLI_memblock *commands_small; + struct BLI_memblock *callbuffers; + struct BLI_memblock *obmats; + struct BLI_memblock *obinfos; + struct BLI_memblock *cullstates; + struct BLI_memblock *shgroups; + struct BLI_memblock *uniforms; + struct BLI_memblock *views; + struct BLI_memblock *passes; + struct BLI_memblock *images; + struct GPUUniformBuf **matrices_ubo; + struct GPUUniformBuf **obinfos_ubo; + struct GHash *obattrs_ubo_pool; + uint ubo_len; + /** Texture pool to reuse temp texture across engines. */ + /* TODO(fclem) the pool could be shared even between viewports. */ + struct DRWTexturePool *texture_pool; + /** Per stereo view data. Contains engine data and default framebuffers. */ + struct DRWViewData *view_data[2]; +} DRWData; + /* ------------- DRAW MANAGER ------------ */ typedef struct DupliKey { @@ -509,8 +549,10 @@ typedef struct DupliKey { typedef struct DRWManager { /* TODO: clean up this struct a bit. */ /* Cache generation */ - ViewportMemoryPool *vmempool; - DRWInstanceDataList *idatalist; + /* TODO(fclem) Rename to data. */ + DRWData *vmempool; + /** Active view data structure for one of the 2 stereo view. Not related to DRWView. */ + struct DRWViewData *view_data_active; /* State of the object being evaluated if already allocated. */ DRWResourceHandle ob_handle; /** True if current DST.ob_state has its matching DRWObjectInfos init. */ @@ -567,10 +609,6 @@ typedef struct DRWManager { /* Convenience pointer to text_store owned by the viewport */ struct DRWTextStore **text_store_p; - ListBase enabled_engines; /* RenderEngineType */ - void **vedata_array; /* ViewportEngineData */ - int enabled_engine_count; /* Length of enabled_engines list. */ - bool buffer_finish_called; /* Avoid bad usage of DRW_render_instance_buffer_finish */ DRWView *view_default; @@ -627,7 +665,7 @@ void drw_batch_cache_validate(Object *ob); void drw_batch_cache_generate_requested(struct Object *ob); void drw_batch_cache_generate_requested_delayed(Object *ob); -void drw_resource_buffer_finish(ViewportMemoryPool *vmempool); +void drw_resource_buffer_finish(DRWData *vmempool); /* Procedural Drawing */ GPUBatch *drw_cache_procedural_points_get(void); @@ -641,6 +679,13 @@ void drw_uniform_attrs_pool_update(struct GHash *table, struct Object *dupli_parent, struct DupliObject *dupli_source); +double *drw_engine_data_cache_time_get(GPUViewport *viewport); +void *drw_engine_data_engine_data_create(GPUViewport *viewport, void *engine_type); +void *drw_engine_data_engine_data_get(GPUViewport *viewport, void *engine_handle); +bool drw_engine_data_engines_data_validate(GPUViewport *viewport, void **engine_handle_array); +void drw_engine_data_cache_release(GPUViewport *viewport); +void drw_engine_data_free(GPUViewport *viewport); + #ifdef __cplusplus } #endif diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index af331c86a8b..f96bd474aec 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -87,7 +87,7 @@ static void draw_call_sort(DRWCommand *array, DRWCommand *array_tmp, int array_l memcpy(array, array_tmp, sizeof(*array) * array_len); } -void drw_resource_buffer_finish(ViewportMemoryPool *vmempool) +void drw_resource_buffer_finish(DRWData *vmempool) { int chunk_id = DRW_handle_chunk_get(&DST.resource_handle); int elem_id = DRW_handle_id_get(&DST.resource_handle); @@ -908,7 +908,8 @@ void DRW_shgroup_call_instances_with_attrs(DRWShadingGroup *shgroup, drw_command_set_select_id(shgroup, NULL, DST.select_id); } DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob); - GPUBatch *batch = DRW_temp_batch_instance_request(DST.idatalist, NULL, inst_attributes, geom); + GPUBatch *batch = DRW_temp_batch_instance_request( + DST.vmempool->idatalist, NULL, inst_attributes, geom); drw_command_draw_instance(shgroup, batch, handle, 0, true); } @@ -1128,7 +1129,7 @@ DRWCallBuffer *DRW_shgroup_call_buffer(DRWShadingGroup *shgroup, BLI_assert(format != NULL); DRWCallBuffer *callbuf = BLI_memblock_alloc(DST.vmempool->callbuffers); - callbuf->buf = DRW_temp_buffer_request(DST.idatalist, format, &callbuf->count); + callbuf->buf = DRW_temp_buffer_request(DST.vmempool->idatalist, format, &callbuf->count); callbuf->buf_select = NULL; callbuf->count = 0; @@ -1138,12 +1139,12 @@ DRWCallBuffer *DRW_shgroup_call_buffer(DRWShadingGroup *shgroup, GPU_vertformat_attr_add(&inst_select_format, "selectId", GPU_COMP_I32, 1, GPU_FETCH_INT); } callbuf->buf_select = DRW_temp_buffer_request( - DST.idatalist, &inst_select_format, &callbuf->count); + DST.vmempool->idatalist, &inst_select_format, &callbuf->count); drw_command_set_select_id(shgroup, callbuf->buf_select, -1); } DRWResourceHandle handle = drw_resource_handle(shgroup, NULL, NULL); - GPUBatch *batch = DRW_temp_batch_request(DST.idatalist, callbuf->buf, prim_type); + GPUBatch *batch = DRW_temp_batch_request(DST.vmempool->idatalist, callbuf->buf, prim_type); drw_command_draw(shgroup, batch, handle); return callbuf; @@ -1157,7 +1158,7 @@ DRWCallBuffer *DRW_shgroup_call_buffer_instance(DRWShadingGroup *shgroup, BLI_assert(format != NULL); DRWCallBuffer *callbuf = BLI_memblock_alloc(DST.vmempool->callbuffers); - callbuf->buf = DRW_temp_buffer_request(DST.idatalist, format, &callbuf->count); + callbuf->buf = DRW_temp_buffer_request(DST.vmempool->idatalist, format, &callbuf->count); callbuf->buf_select = NULL; callbuf->count = 0; @@ -1167,12 +1168,13 @@ DRWCallBuffer *DRW_shgroup_call_buffer_instance(DRWShadingGroup *shgroup, GPU_vertformat_attr_add(&inst_select_format, "selectId", GPU_COMP_I32, 1, GPU_FETCH_INT); } callbuf->buf_select = DRW_temp_buffer_request( - DST.idatalist, &inst_select_format, &callbuf->count); + DST.vmempool->idatalist, &inst_select_format, &callbuf->count); drw_command_set_select_id(shgroup, callbuf->buf_select, -1); } DRWResourceHandle handle = drw_resource_handle(shgroup, NULL, NULL); - GPUBatch *batch = DRW_temp_batch_instance_request(DST.idatalist, callbuf->buf, NULL, geom); + GPUBatch *batch = DRW_temp_batch_instance_request( + DST.vmempool->idatalist, callbuf->buf, NULL, geom); drw_command_draw(shgroup, batch, handle); return callbuf; diff --git a/source/blender/draw/intern/draw_manager_profiling.c b/source/blender/draw/intern/draw_manager_profiling.c index d9ba2cbf932..70fe12270f5 100644 --- a/source/blender/draw/intern/draw_manager_profiling.c +++ b/source/blender/draw/intern/draw_manager_profiling.c @@ -257,10 +257,9 @@ void DRW_stats_draw(const rcti *rect) /* Engines rows */ char time_to_txt[16]; - LISTBASE_FOREACH (LinkData *, link, &DST.enabled_engines) { + DRW_ENABLED_ENGINE_ITER(DST.view_data_active, engine, data) + { u = 0; - DrawEngineType *engine = link->data; - ViewportEngineData *data = drw_viewport_engine_data_ensure(engine); draw_stat_5row(rect, u++, v, engine->idname, sizeof(engine->idname)); @@ -297,7 +296,7 @@ void DRW_stats_draw(const rcti *rect) v += 2; u = 0; - double *cache_time = GPU_viewport_cache_time_get(DST.viewport); + double *cache_time = DRW_view_data_cache_time_get(DST.view_data_active); sprintf(col_label, "Cache Time"); draw_stat_5row(rect, u++, v, col_label, sizeof(col_label)); sprintf(time_to_txt, "%.2fms", *cache_time); diff --git a/source/blender/draw/intern/draw_manager_text.h b/source/blender/draw/intern/draw_manager_text.h index 760259018bb..4f3a6153775 100644 --- a/source/blender/draw/intern/draw_manager_text.h +++ b/source/blender/draw/intern/draw_manager_text.h @@ -22,6 +22,10 @@ #pragma once +#ifdef __cplusplus +extern "C" { +#endif + struct ARegion; struct DRWTextStore; struct Object; @@ -57,3 +61,7 @@ enum { /* draw_manager.c */ struct DRWTextStore *DRW_text_cache_ensure(void); + +#ifdef __cplusplus +} +#endif
\ No newline at end of file diff --git a/source/blender/draw/intern/draw_manager_texture.c b/source/blender/draw/intern/draw_manager_texture.c index 99e8ba968a2..86242468e4a 100644 --- a/source/blender/draw/intern/draw_manager_texture.c +++ b/source/blender/draw/intern/draw_manager_texture.c @@ -21,6 +21,7 @@ */ #include "draw_manager.h" +#include "draw_texture_pool.h" #ifndef NDEBUG /* Maybe gpu_texture.c is a better place for this. */ @@ -147,7 +148,7 @@ GPUTexture *DRW_texture_pool_query_2d(int w, DrawEngineType *engine_type) { BLI_assert(drw_texture_format_supports_framebuffer(format)); - GPUTexture *tex = GPU_viewport_texture_pool_query(DST.viewport, engine_type, w, h, format); + GPUTexture *tex = DRW_texture_pool_query(DST.vmempool->texture_pool, w, h, format, engine_type); return tex; } diff --git a/source/blender/draw/intern/draw_texture_pool.cc b/source/blender/draw/intern/draw_texture_pool.cc new file mode 100644 index 00000000000..544a763ddb9 --- /dev/null +++ b/source/blender/draw/intern/draw_texture_pool.cc @@ -0,0 +1,140 @@ +/* + * 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. + * + * Copyright 2021, Blender Foundation. + */ + +/** \file + * \ingroup draw + */ + +#include "BKE_global.h" + +#include "BLI_vector.hh" + +#include "draw_texture_pool.h" + +using namespace blender; + +typedef struct DRWTexturePoolHandle { + uint64_t users_bits; + GPUTexture *texture; +} DRWTexturePoolHandle; + +struct DRWTexturePool { + Vector<void *, 16> users; + Vector<DRWTexturePoolHandle> handles; + /* Cache last result to avoid linear search each time. */ + int last_user_id = -1; +}; + +DRWTexturePool *DRW_texture_pool_create(void) +{ + return new DRWTexturePool(); +} + +void DRW_texture_pool_free(DRWTexturePool *pool) +{ + /* Reseting the pool twice will effectively free all textures. */ + DRW_texture_pool_reset(pool); + DRW_texture_pool_reset(pool); + delete pool; +} + +/** + * Try to find a texture corresponding to params into the texture pool. + * If no texture was found, create one and add it to the pool. + */ +GPUTexture *DRW_texture_pool_query( + DRWTexturePool *pool, int width, int height, eGPUTextureFormat format, void *user) +{ + int user_id = pool->last_user_id; + /* Try cached value. */ + if (user_id != -1) { + if (pool->users[user_id] != user) { + user_id = -1; + } + } + /* Try to find inside previous users. */ + if (user_id == -1) { + user_id = pool->users.first_index_of_try(user); + } + /* No chance, needs to add it to the user list. */ + if (user_id == -1) { + user_id = pool->users.size(); + pool->users.append(user); + /* If there is more than 63 users, better refactor this system. */ + BLI_assert(user_id < 64); + } + pool->last_user_id = user_id; + + uint64_t user_bit = 1llu << user_id; + for (DRWTexturePoolHandle &handle : pool->handles) { + /* Skip if the user is already using this texture. */ + if (user_bit & handle.users_bits) { + continue; + } + /* If everthing matches reuse the texture. */ + if ((GPU_texture_format(handle.texture) == format) && + (GPU_texture_width(handle.texture) == width) && + (GPU_texture_height(handle.texture) == height)) { + handle.users_bits |= user_bit; + return handle.texture; + } + } + + char name[16] = "DRW_tex_pool"; + if (G.debug & G_DEBUG_GPU) { + int texture_id = pool->handles.size(); + SNPRINTF(name, "DRW_tex_pool_%d", texture_id); + } + + DRWTexturePoolHandle handle; + handle.users_bits = user_bit; + handle.texture = GPU_texture_create_2d(name, width, height, 1, format, nullptr); + pool->handles.append(handle); + /* Doing filtering for depth does not make sense when not doing shadow mapping, + * and enabling texture filtering on integer texture make them unreadable. */ + bool do_filter = !GPU_texture_depth(handle.texture) && !GPU_texture_integer(handle.texture); + GPU_texture_filter_mode(handle.texture, do_filter); + + return handle.texture; +} + +/* Resets the user bits for each texture in the pool and delete unused ones. */ +void DRW_texture_pool_reset(DRWTexturePool *pool) +{ + pool->last_user_id = -1; + + for (auto it = pool->handles.rbegin(); it != pool->handles.rend(); ++it) { + DRWTexturePoolHandle &handle = *it; + if (handle.users_bits == 0) { + if (handle.texture) { + GPU_texture_free(handle.texture); + handle.texture = nullptr; + } + } + else { + handle.users_bits = 0; + } + } + + /* Reverse iteration to make sure we only reorder with known good handles. */ + for (int i = pool->handles.size() - 1; i >= 0; i--) { + if (!pool->handles[i].texture) { + pool->handles.remove_and_reorder(i); + } + } +}
\ No newline at end of file diff --git a/source/blender/draw/intern/draw_texture_pool.h b/source/blender/draw/intern/draw_texture_pool.h new file mode 100644 index 00000000000..f0b8f775c75 --- /dev/null +++ b/source/blender/draw/intern/draw_texture_pool.h @@ -0,0 +1,47 @@ +/* + * 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. + * + * Copyright 2021, Blender Foundation. + */ + +/** \file + * \ingroup draw + * + * Texture pool + * A pool that gives temporary render targets that can be reused through other parts of the + * render pipeline. + * Expect texture data is garbage when acquiring it. + */ + +#pragma once + +#include "GPU_texture.h" + +typedef struct DRWTexturePool DRWTexturePool; + +#ifdef __cplusplus +extern "C" { +#endif + +DRWTexturePool *DRW_texture_pool_create(void); +void DRW_texture_pool_free(DRWTexturePool *pool); + +GPUTexture *DRW_texture_pool_query( + DRWTexturePool *pool, int width, int height, eGPUTextureFormat format, void *user); +void DRW_texture_pool_reset(DRWTexturePool *pool); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/draw/intern/draw_view_data.cc b/source/blender/draw/intern/draw_view_data.cc new file mode 100644 index 00000000000..55ebbf82c29 --- /dev/null +++ b/source/blender/draw/intern/draw_view_data.cc @@ -0,0 +1,243 @@ +/* + * 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. + * + * Copyright 2021, Blender Foundation. + */ + +/** \file + * \ingroup draw + */ + +#include "BLI_vector.hh" + +#include "GPU_viewport.h" + +#include "DRW_render.h" + +#include "draw_instance_data.h" + +#include "draw_manager_text.h" + +#include "draw_manager.h" +#include "draw_view_data.h" + +using namespace blender; + +struct DRWViewData { + DefaultFramebufferList dfbl = {}; + DefaultTextureList dtxl = {}; + /** True indicates the textures inside dtxl are from the viewport and should not be freed. */ + bool from_viewport = false; + /** Common size for texture in the engines texture list. + * We free all texture lists if it changes. */ + int texture_list_size[2] = {0, 0}; + + double cache_time = 0.0; + + Vector<ViewportEngineData> engines; + Vector<ViewportEngineData *> enabled_engines; +}; + +/** + * Creates a view data with all possible engines type for this view. + * + * `engine_types` contains `DRWRegisteredDrawEngine`. + * */ +DRWViewData *DRW_view_data_create(ListBase *engine_types) +{ + DRWViewData *view_data = new DRWViewData(); + LISTBASE_FOREACH (DRWRegisteredDrawEngine *, type, engine_types) { + ViewportEngineData engine = {}; + engine.engine_type = type; + view_data->engines.append(engine); + } + return view_data; +} + +void DRW_view_data_default_lists_from_viewport(DRWViewData *view_data, GPUViewport *viewport) +{ + int active_view = GPU_viewport_active_view_get(viewport); + view_data->from_viewport = true; + + DefaultFramebufferList *dfbl = &view_data->dfbl; + DefaultTextureList *dtxl = &view_data->dtxl; + /* Depth texture is shared between both stereo views. */ + dtxl->depth = GPU_viewport_depth_texture(viewport); + dtxl->color = GPU_viewport_color_texture(viewport, active_view); + dtxl->color_overlay = GPU_viewport_overlay_texture(viewport, active_view); + + GPU_framebuffer_ensure_config(&dfbl->default_fb, + { + GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_TEXTURE(dtxl->color), + }); + GPU_framebuffer_ensure_config(&dfbl->overlay_fb, + { + GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_TEXTURE(dtxl->color_overlay), + }); + GPU_framebuffer_ensure_config(&dfbl->depth_only_fb, + { + GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_NONE, + }); + GPU_framebuffer_ensure_config(&dfbl->color_only_fb, + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(dtxl->color), + }); + GPU_framebuffer_ensure_config(&dfbl->overlay_only_fb, + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(dtxl->color_overlay), + }); +} + +static void draw_viewport_engines_data_clear(ViewportEngineData *data) +{ + DrawEngineType *engine_type = data->engine_type->draw_engine; + const DrawEngineDataSize *data_size = engine_type->vedata_size; + + for (int i = 0; data->fbl && i < data_size->fbl_len; i++) { + GPU_FRAMEBUFFER_FREE_SAFE(data->fbl->framebuffers[i]); + } + for (int i = 0; data->txl && i < data_size->txl_len; i++) { + GPU_TEXTURE_FREE_SAFE(data->txl->textures[i]); + } + for (int i = 0; data->stl && i < data_size->stl_len; i++) { + MEM_SAFE_FREE(data->stl->storage[i]); + } + + MEM_SAFE_FREE(data->fbl); + MEM_SAFE_FREE(data->txl); + MEM_SAFE_FREE(data->psl); + MEM_SAFE_FREE(data->stl); + + if (data->text_draw_cache) { + DRW_text_cache_destroy(data->text_draw_cache); + data->text_draw_cache = nullptr; + } +} + +static void draw_view_data_clear(DRWViewData *view_data) +{ + GPU_FRAMEBUFFER_FREE_SAFE(view_data->dfbl.default_fb); + GPU_FRAMEBUFFER_FREE_SAFE(view_data->dfbl.overlay_fb); + GPU_FRAMEBUFFER_FREE_SAFE(view_data->dfbl.in_front_fb); + GPU_FRAMEBUFFER_FREE_SAFE(view_data->dfbl.color_only_fb); + GPU_FRAMEBUFFER_FREE_SAFE(view_data->dfbl.depth_only_fb); + GPU_FRAMEBUFFER_FREE_SAFE(view_data->dfbl.overlay_only_fb); + + if (!view_data->from_viewport) { + GPU_TEXTURE_FREE_SAFE(view_data->dtxl.color); + GPU_TEXTURE_FREE_SAFE(view_data->dtxl.color_overlay); + GPU_TEXTURE_FREE_SAFE(view_data->dtxl.depth); + } + GPU_TEXTURE_FREE_SAFE(view_data->dtxl.depth_in_front); + + for (ViewportEngineData &engine : view_data->engines) { + draw_viewport_engines_data_clear(&engine); + } + + view_data->texture_list_size[0] = view_data->texture_list_size[1] = 0; + view_data->cache_time = 0.0f; +} + +void DRW_view_data_free(DRWViewData *view_data) +{ + draw_view_data_clear(view_data); + delete view_data; +} + +void DRW_view_data_texture_list_size_validate(DRWViewData *view_data, const int size[2]) +{ + if (!equals_v2v2_int(view_data->texture_list_size, size)) { + draw_view_data_clear(view_data); + copy_v2_v2_int(view_data->texture_list_size, size); + } +} + +ViewportEngineData *DRW_view_data_engine_data_get_ensure(DRWViewData *view_data, + DrawEngineType *engine_type) +{ + for (ViewportEngineData &engine : view_data->engines) { + if (engine.engine_type->draw_engine == engine_type) { + if (engine.fbl == nullptr) { + const DrawEngineDataSize *data_size = engine_type->vedata_size; + engine.fbl = (FramebufferList *)MEM_calloc_arrayN( + data_size->fbl_len, sizeof(GPUFrameBuffer *), "FramebufferList"); + engine.txl = (TextureList *)MEM_calloc_arrayN( + data_size->txl_len, sizeof(GPUTexture *), "TextureList"); + engine.psl = (PassList *)MEM_calloc_arrayN( + data_size->psl_len, sizeof(DRWPass *), "PassList"); + engine.stl = (StorageList *)MEM_calloc_arrayN( + data_size->stl_len, sizeof(void *), "StorageList"); + } + return &engine; + } + } + return nullptr; +} + +void DRW_view_data_use_engine(DRWViewData *view_data, DrawEngineType *engine_type) +{ + ViewportEngineData *engine = DRW_view_data_engine_data_get_ensure(view_data, engine_type); + view_data->enabled_engines.append(engine); +} + +void DRW_view_data_reset(DRWViewData *view_data) +{ + view_data->enabled_engines.clear(); +} + +void DRW_view_data_free_unused(DRWViewData *view_data) +{ + for (ViewportEngineData &engine : view_data->engines) { + if (view_data->enabled_engines.first_index_of_try(&engine) == -1) { + draw_viewport_engines_data_clear(&engine); + } + } +} + +double *DRW_view_data_cache_time_get(DRWViewData *view_data) +{ + return &view_data->cache_time; +} + +DefaultFramebufferList *DRW_view_data_default_framebuffer_list_get(DRWViewData *view_data) +{ + return &view_data->dfbl; +} + +DefaultTextureList *DRW_view_data_default_texture_list_get(DRWViewData *view_data) +{ + return &view_data->dtxl; +} + +void DRW_view_data_enabled_engine_iter_begin(DRWEngineIterator *iterator, DRWViewData *view_data) +{ + iterator->id = 0; + iterator->end = view_data->enabled_engines.size(); + iterator->engines = view_data->enabled_engines.data(); +} + +ViewportEngineData *DRW_view_data_enabled_engine_iter_step(DRWEngineIterator *iterator) +{ + if (iterator->id >= iterator->end) { + return nullptr; + } + ViewportEngineData *engine = iterator->engines[iterator->id++]; + return engine; +} diff --git a/source/blender/draw/intern/draw_view_data.h b/source/blender/draw/intern/draw_view_data.h new file mode 100644 index 00000000000..c8176170a61 --- /dev/null +++ b/source/blender/draw/intern/draw_view_data.h @@ -0,0 +1,139 @@ +/* + * 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. + * + * Copyright 2021, Blender Foundation. + */ + +/** \file + * \ingroup draw + * + * Engine data + * Structure containing each draw engine instance data. + */ + +#pragma once + +#define GPU_INFO_SIZE 512 /* IMA_MAX_RENDER_TEXT */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct GPUViewport; +struct DrawEngineType; +struct DRWRegisteredDrawEngine; + +/* NOTE these structs are only here for reading the actual lists from the engine. + * The actual length of them is stored in a ViewportEngineData_Info. + * The length of 1 is just here to avoid compiler warning. */ +typedef struct FramebufferList { + struct GPUFrameBuffer *framebuffers[1]; +} FramebufferList; + +typedef struct TextureList { + struct GPUTexture *textures[1]; +} TextureList; + +typedef struct PassList { + struct DRWPass *passes[1]; +} PassList; + +/* Stores custom structs from the engine that have been MEM_(m/c)allocN'ed. */ +typedef struct StorageList { + void *storage[1]; +} StorageList; + +typedef struct ViewportEngineData { + /* Not owning pointer to the draw engine. */ + struct DRWRegisteredDrawEngine *engine_type; + + FramebufferList *fbl; + TextureList *txl; + PassList *psl; + StorageList *stl; + char info[GPU_INFO_SIZE]; + + /* we may want to put this elsewhere */ + struct DRWTextStore *text_draw_cache; + + /* Profiling data */ + double init_time; + double render_time; + double background_time; +} ViewportEngineData; + +typedef struct ViewportEngineData_Info { + int fbl_len; + int txl_len; + int psl_len; + int stl_len; +} ViewportEngineData_Info; + +/* Buffer and textures used by the viewport by default */ +typedef struct DefaultFramebufferList { + struct GPUFrameBuffer *default_fb; + struct GPUFrameBuffer *overlay_fb; + struct GPUFrameBuffer *in_front_fb; + struct GPUFrameBuffer *color_only_fb; + struct GPUFrameBuffer *depth_only_fb; + struct GPUFrameBuffer *overlay_only_fb; +} DefaultFramebufferList; + +typedef struct DefaultTextureList { + struct GPUTexture *color; + struct GPUTexture *color_overlay; + struct GPUTexture *depth; + struct GPUTexture *depth_in_front; +} DefaultTextureList; + +typedef struct DRWViewData DRWViewData; + +DRWViewData *DRW_view_data_create(ListBase *engine_types); +void DRW_view_data_free(DRWViewData *view_data); + +void DRW_view_data_default_lists_from_viewport(DRWViewData *view_data, + struct GPUViewport *viewport); +void DRW_view_data_texture_list_size_validate(DRWViewData *view_data, const int size[2]); +ViewportEngineData *DRW_view_data_engine_data_get_ensure(DRWViewData *view_data, + struct DrawEngineType *engine_type_); +void DRW_view_data_use_engine(DRWViewData *view_data, struct DrawEngineType *engine_type); +void DRW_view_data_reset(DRWViewData *view_data); +void DRW_view_data_free_unused(DRWViewData *view_data); +double *DRW_view_data_cache_time_get(DRWViewData *view_data); +DefaultFramebufferList *DRW_view_data_default_framebuffer_list_get(DRWViewData *view_data); +DefaultTextureList *DRW_view_data_default_texture_list_get(DRWViewData *view_data); + +typedef struct DRWEngineIterator { + int id, end; + ViewportEngineData **engines; +} DRWEngineIterator; + +/* Iterate over used engines of this view_data. */ +void DRW_view_data_enabled_engine_iter_begin(DRWEngineIterator *iterator, DRWViewData *view_data); +ViewportEngineData *DRW_view_data_enabled_engine_iter_step(DRWEngineIterator *iterator); + +#define DRW_ENABLED_ENGINE_ITER(view_data_, engine_, data_) \ + DRWEngineIterator iterator; \ + ViewportEngineData *data_; \ + struct DrawEngineType *engine_; \ + DRW_view_data_enabled_engine_iter_begin(&iterator, view_data_); \ + /* WATCH Comma operator trickery ahead! This tests engine_ == NULL. */ \ + while ((data_ = DRW_view_data_enabled_engine_iter_step(&iterator), \ + engine_ = (data_ != NULL) ? (struct DrawEngineType *)data_->engine_type->draw_engine : \ + NULL)) + +#ifdef __cplusplus +} +#endif |