diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2017-11-06 18:47:23 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2017-11-06 19:43:14 +0300 |
commit | ed555750eb8294005f54425094cb692f29830631 (patch) | |
tree | e0b0149dd5959080ca39bd53b3baefe527413f99 /source | |
parent | 5d70e847dd6f5182fa67c3b08260fbb5366009b5 (diff) |
DRW: Use pseudo persistent memory pool for the rendering data structure.
This gets rid of the bottleneck of allocation / free of thousands of elements every frame.
Cache time (Eevee) (test scene is default file with cube duplicated 3241 times)
pre-patch: 23ms
post-patch: 14ms
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/draw/intern/draw_manager.c | 392 | ||||
-rw-r--r-- | source/blender/gpu/GPU_viewport.h | 16 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_viewport.c | 54 |
3 files changed, 264 insertions, 198 deletions
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 57489153ba0..f18bc9969b1 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -27,6 +27,7 @@ #include "BLI_dynstr.h" #include "BLI_listbase.h" +#include "BLI_mempool.h" #include "BLI_rect.h" #include "BLI_string.h" @@ -130,13 +131,6 @@ /* Use draw manager to call GPU_select, see: DRW_draw_select_loop */ #define USE_GPU_SELECT -/* Use BLI_memiter */ -#define USE_MEM_ITER - -#ifdef USE_MEM_ITER -#include "BLI_memiter.h" -#endif - #ifdef USE_GPU_SELECT # include "ED_view3d.h" # include "ED_armature.h" @@ -147,6 +141,7 @@ #define MAX_ATTRIB_NAME 32 +#define MAX_ATTRIB_COUNT 6 /* Can be adjusted for more */ #define MAX_PASS_NAME 32 #define MAX_CLIP_PLANES 6 /* GL_MAX_CLIP_PLANES is at least 6 */ @@ -177,7 +172,7 @@ typedef enum { } DRWAttribType; struct DRWUniform { - struct DRWUniform *next, *prev; + struct DRWUniform *next; DRWUniformType type; int location; int length; @@ -186,7 +181,7 @@ struct DRWUniform { }; typedef struct DRWAttrib { - struct DRWAttrib *next, *prev; + struct DRWAttrib *prev; char name[MAX_ATTRIB_NAME]; int location; int format_id; @@ -195,8 +190,9 @@ typedef struct DRWAttrib { } DRWAttrib; struct DRWInterface { - ListBase uniforms; /* DRWUniform */ - ListBase attribs; /* DRWAttrib */ + DRWUniform *uniforms; /* DRWUniform, single-linked list */ + DRWAttrib *attribs; /* DRWAttrib, single-linked list */ + DRWAttrib *attribs_first; /* First added attrib to traverse in the right order */ int attribs_count; int attribs_stride; int attribs_size[16]; @@ -227,15 +223,16 @@ struct DRWInterface { }; struct DRWPass { - ListBase shgroups; /* DRWShadingGroup */ + /* Single linked list with last member to append */ + DRWShadingGroup *shgroups; + DRWShadingGroup *shgroups_last; + DRWState state; char name[MAX_PASS_NAME]; }; typedef struct DRWCallHeader { -#ifndef USE_MEM_ITER - void *next, *prev; -#endif + void *prev; #ifdef USE_GPU_SELECT int select_id; @@ -265,21 +262,18 @@ typedef struct DRWCallGenerate { typedef struct DRWCallDynamic { DRWCallHeader head; - const void *data[]; + const void *data[MAX_ATTRIB_COUNT]; } DRWCallDynamic; struct DRWShadingGroup { - struct DRWShadingGroup *next, *prev; + struct DRWShadingGroup *next; GPUShader *shader; /* Shader to bind */ - DRWInterface *interface; /* Uniforms pointers */ + DRWInterface interface; /* Uniforms pointers */ /* DRWCall or DRWCallDynamic depending of type */ -#ifdef USE_MEM_ITER - BLI_memiter *calls; -#else - ListBase calls; -#endif + void *calls; + void *calls_first; /* To be able to traverse the list in the order of addition */ DRWState state_extra; /* State changes for this batch only (or'd with the pass's state) */ DRWState state_extra_disable; /* State changes for this batch only (and'd with the pass's state) */ @@ -322,6 +316,15 @@ enum { /** Render State: No persistent data between draw calls. */ static struct DRWGlobalState { + /* Cache generation */ + ViewportMemoryPool *vmempool; + DRWUniform *last_uniform; + DRWAttrib *last_attrib; + DRWCall *last_call; + DRWCallGenerate *last_callgenerate; + DRWCallDynamic *last_calldynamic; + DRWShadingGroup *last_shgroup; + /* Rendering state */ GPUShader *shader; @@ -652,10 +655,8 @@ void DRW_shader_free(GPUShader *shader) /** \name Interface (DRW_interface) * \{ */ -static DRWInterface *DRW_interface_create(GPUShader *shader) +static void DRW_interface_create(DRWInterface *interface, GPUShader *shader) { - DRWInterface *interface = MEM_mallocN(sizeof(DRWInterface), "DRWInterface"); - interface->model = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MODEL); interface->modelinverse = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MODEL_INV); interface->modelview = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MODELVIEW); @@ -681,21 +682,11 @@ static DRWInterface *DRW_interface_create(GPUShader *shader) memset(&interface->vbo_format, 0, sizeof(Gwn_VertFormat)); - BLI_listbase_clear(&interface->uniforms); - BLI_listbase_clear(&interface->attribs); - - return interface; + interface->uniforms = NULL; + interface->attribs = NULL; + interface->attribs_first = NULL; } -#ifdef USE_GPU_SELECT -static DRWInterface *DRW_interface_duplicate(DRWInterface *interface_src) -{ - DRWInterface *interface_dst = MEM_dupallocN(interface_src); - BLI_duplicatelist(&interface_dst->uniforms, &interface_src->uniforms); - BLI_duplicatelist(&interface_dst->attribs, &interface_src->attribs); - return interface_dst; -} -#endif static void DRW_interface_uniform(DRWShadingGroup *shgroup, const char *name, DRWUniformType type, const void *value, int length, int arraysize) @@ -716,7 +707,7 @@ static void DRW_interface_uniform(DRWShadingGroup *shgroup, const char *name, return; } - DRWUniform *uni = MEM_mallocN(sizeof(DRWUniform), "DRWUniform"); + DRWUniform *uni = BLI_mempool_alloc(DST.vmempool->uniforms); BLI_assert(arraysize > 0); @@ -726,12 +717,14 @@ static void DRW_interface_uniform(DRWShadingGroup *shgroup, const char *name, uni->length = length; uni->arraysize = arraysize; - BLI_addtail(&shgroup->interface->uniforms, uni); + /* Prepend */ + uni->next = shgroup->interface.uniforms; + shgroup->interface.uniforms = uni; } static void DRW_interface_attrib(DRWShadingGroup *shgroup, const char *name, DRWAttribType type, int size, bool dummy) { - DRWAttrib *attrib = MEM_mallocN(sizeof(DRWAttrib), "DRWAttrib"); + DRWAttrib *attrib = BLI_mempool_alloc(DST.vmempool->attribs); GLuint program = GPU_shader_get_program(shgroup->shader); attrib->location = glGetAttribLocation(program, name); @@ -755,9 +748,19 @@ static void DRW_interface_attrib(DRWShadingGroup *shgroup, const char *name, DRW BLI_assert(BLI_strnlen(name, 32) < 32); BLI_strncpy(attrib->name, name, 32); - shgroup->interface->attribs_count += 1; + shgroup->interface.attribs_count += 1; + BLI_assert(shgroup->interface.attribs_count < MAX_ATTRIB_COUNT); - BLI_addtail(&shgroup->interface->attribs, attrib); + /* Prepend */ + if (shgroup->interface.attribs == NULL) { + shgroup->interface.attribs = attrib; + shgroup->interface.attribs_first = attrib; + } + else { + shgroup->interface.attribs->prev = attrib; + shgroup->interface.attribs = attrib; + } + attrib->prev = NULL; } /** \} */ @@ -770,23 +773,30 @@ static void DRW_interface_attrib(DRWShadingGroup *shgroup, const char *name, DRW DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass) { - DRWShadingGroup *shgroup = MEM_mallocN(sizeof(DRWShadingGroup), "DRWShadingGroup"); - BLI_addtail(&pass->shgroups, shgroup); + DRWShadingGroup *shgroup = BLI_mempool_alloc(DST.vmempool->shgroups); + + /* Append */ + if (pass->shgroups != NULL) { + pass->shgroups_last->next = shgroup; + } + else { + pass->shgroups = shgroup; + } + pass->shgroups_last = shgroup; + shgroup->next = NULL; + + DRW_interface_create(&shgroup->interface, shader); shgroup->type = DRW_SHG_NORMAL; shgroup->shader = shader; - shgroup->interface = DRW_interface_create(shader); shgroup->state_extra = 0; shgroup->state_extra_disable = ~0x0; shgroup->batch_geom = NULL; shgroup->instance_geom = NULL; shgroup->instance_data = NULL; -#ifdef USE_MEM_ITER - shgroup->calls = BLI_memiter_create(BLI_MEMITER_DEFAULT_SIZE); -#else - BLI_listbase_clear(&shgroup->calls); -#endif + shgroup->calls = NULL; + shgroup->calls_first = NULL; #ifdef USE_GPU_SELECT shgroup->pass_parent = pass; @@ -885,7 +895,7 @@ DRWShadingGroup *DRW_shgroup_material_empty_tri_batch_create( if (shgroup) { shgroup->type = DRW_SHG_TRIANGLE_BATCH; - shgroup->interface->instance_count = size * 3; + shgroup->interface.instance_count = size * 3; DRW_interface_attrib(shgroup, "dummy", DRW_ATTRIB_FLOAT, 1, true); } @@ -930,7 +940,7 @@ DRWShadingGroup *DRW_shgroup_empty_tri_batch_create(struct GPUShader *shader, DR DRWShadingGroup *shgroup = DRW_shgroup_create(shader, pass); shgroup->type = DRW_SHG_TRIANGLE_BATCH; - shgroup->interface->instance_count = size * 3; + shgroup->interface.instance_count = size * 3; DRW_interface_attrib(shgroup, "dummy", DRW_ATTRIB_FLOAT, 1, true); return shgroup; @@ -938,46 +948,43 @@ DRWShadingGroup *DRW_shgroup_empty_tri_batch_create(struct GPUShader *shader, DR void DRW_shgroup_free(struct DRWShadingGroup *shgroup) { -#ifdef USE_MEM_ITER - BLI_memiter_destroy(shgroup->calls); -#else - BLI_freelistN(&shgroup->calls); -#endif - - BLI_freelistN(&shgroup->interface->uniforms); - BLI_freelistN(&shgroup->interface->attribs); - - if (shgroup->interface->instance_vbo && - (shgroup->interface->instance_batch == 0)) + if (shgroup->interface.instance_vbo && + (shgroup->interface.instance_batch == 0)) { - glDeleteBuffers(1, &shgroup->interface->instance_vbo); + glDeleteBuffers(1, &shgroup->interface.instance_vbo); } - MEM_freeN(shgroup->interface); - GWN_BATCH_DISCARD_SAFE(shgroup->batch_geom); } void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct Gwn_Batch *instances) { BLI_assert(shgroup->type == DRW_SHG_INSTANCE); - BLI_assert(shgroup->interface->instance_batch == NULL); + BLI_assert(shgroup->interface.instance_batch == NULL); - shgroup->interface->instance_batch = instances; + shgroup->interface.instance_batch = instances; } +#define CALL_PREPEND(shgroup, call) { \ + if (shgroup->calls == NULL) { \ + shgroup->calls = call; \ + shgroup->calls_first = call; \ + } \ + else { \ + ((typeof(call))shgroup->calls)->head.prev = call; \ + shgroup->calls = call; \ + } \ + call->head.prev = NULL; \ +} ((void)0) + + void DRW_shgroup_call_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, float (*obmat)[4]) { BLI_assert(geom != NULL); - DRWCall *call; + DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); -#ifdef USE_MEM_ITER - call = BLI_memiter_calloc(shgroup->calls, sizeof(DRWCall)); -#else - call = MEM_callocN(sizeof(DRWCall), "DRWCall"); - BLI_addtail(&shgroup->calls, call); -#endif + CALL_PREPEND(shgroup, call); call->head.type = DRW_CALL_SINGLE; #ifdef USE_GPU_SELECT @@ -989,20 +996,16 @@ void DRW_shgroup_call_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, float (*obm } call->geometry = geom; + call->ob_data = NULL; } void DRW_shgroup_call_object_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, Object *ob) { BLI_assert(geom != NULL); - DRWCall *call; + DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); -#ifdef USE_MEM_ITER - call = BLI_memiter_calloc(shgroup->calls, sizeof(DRWCall)); -#else - call = MEM_callocN(sizeof(DRWCall), "DRWCall"); - BLI_addtail(&shgroup->calls, call); -#endif + CALL_PREPEND(shgroup, call); call->head.type = DRW_CALL_SINGLE; #ifdef USE_GPU_SELECT @@ -1021,14 +1024,9 @@ void DRW_shgroup_call_generate_add( { BLI_assert(geometry_fn != NULL); - DRWCallGenerate *call; + DRWCallGenerate *call = BLI_mempool_alloc(DST.vmempool->calls_generate); -#ifdef USE_MEM_ITER - call = BLI_memiter_calloc(shgroup->calls, sizeof(DRWCallGenerate)); -#else - call = MEM_callocN(sizeof(DRWCallGenerate), "DRWCallGenerate"); - BLI_addtail(&shgroup->calls, call); -#endif + CALL_PREPEND(shgroup, call); call->head.type = DRW_CALL_GENERATE; #ifdef USE_GPU_SELECT @@ -1065,38 +1063,35 @@ void DRW_shgroup_call_sculpt_add(DRWShadingGroup *shgroup, Object *ob, float (*o void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup, const void *attr[], unsigned int attr_len) { - DRWInterface *interface = shgroup->interface; + DRWInterface *interface = &shgroup->interface; #ifdef USE_GPU_SELECT if ((G.f & G_PICKSEL) && (interface->instance_count > 0)) { - shgroup = MEM_dupallocN(shgroup); + DRWShadingGroup *original_shgroup = shgroup; + shgroup = BLI_mempool_alloc(DST.vmempool->shgroups); + memcpy(shgroup, original_shgroup, sizeof(DRWShadingGroup)); -#ifdef USE_MEM_ITER - shgroup->calls = BLI_memiter_create(BLI_MEMITER_DEFAULT_SIZE); -#else - BLI_listbase_clear(&shgroup->calls); -#endif + shgroup->calls = NULL; + shgroup->calls_first = NULL; - shgroup->interface = interface = DRW_interface_duplicate(interface); + interface = &shgroup->interface; interface->instance_count = 0; - BLI_addtail(&shgroup->pass_parent->shgroups, shgroup); + /* Append */ + if (shgroup->pass_parent->shgroups != NULL) { + shgroup->pass_parent->shgroups_last->next = shgroup; + } + else { + shgroup->pass_parent->shgroups = shgroup; + } + shgroup->pass_parent->shgroups_last = shgroup; + shgroup->next = NULL; } #endif - unsigned int data_size = sizeof(void *) * interface->attribs_count; - int size = sizeof(DRWCallDynamic) + data_size; + DRWCallDynamic *call = BLI_mempool_alloc(DST.vmempool->calls_dynamic); - DRWCallDynamic *call; - -#ifdef USE_MEM_ITER - call = BLI_memiter_alloc(shgroup->calls, size); -#else - call = MEM_mallocN(size, "DRWCallDynamic"); - BLI_addtail(&shgroup->calls, call); -#endif - - memset(call, 0x0, sizeof(DRWCallDynamic)); + CALL_PREPEND(shgroup, call); BLI_assert(attr_len == interface->attribs_count); UNUSED_VARS_NDEBUG(attr_len); @@ -1106,8 +1101,8 @@ void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup, const void *at call->head.select_id = g_DRW_select_id; #endif - if (data_size != 0) { - memcpy((void *)call->data, attr, data_size); + if (interface->attribs_count != 0) { + memcpy((void *)call->data, attr, sizeof(void *) * interface->attribs_count); } interface->instance_count += 1; @@ -1116,7 +1111,7 @@ void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup, const void *at /* Used for instancing with no attributes */ void DRW_shgroup_set_instance_count(DRWShadingGroup *shgroup, int count) { - DRWInterface *interface = shgroup->interface; + DRWInterface *interface = &shgroup->interface; BLI_assert(interface->attribs_count == 0); @@ -1220,7 +1215,7 @@ void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const /* Creates a VBO containing OGL primitives for all DRWCallDynamic */ static void shgroup_dynamic_batch(DRWShadingGroup *shgroup) { - DRWInterface *interface = shgroup->interface; + DRWInterface *interface = &shgroup->interface; int nbr = interface->instance_count; Gwn_PrimType type = (shgroup->type == DRW_SHG_POINT_BATCH) ? GWN_PRIM_POINTS : @@ -1231,7 +1226,7 @@ static void shgroup_dynamic_batch(DRWShadingGroup *shgroup) /* Upload Data */ if (interface->vbo_format.attrib_ct == 0) { - for (DRWAttrib *attrib = interface->attribs.first; attrib; attrib = attrib->next) { + for (DRWAttrib *attrib = interface->attribs_first; attrib; attrib = attrib->prev) { BLI_assert(attrib->size <= 4); /* matrices have no place here for now */ if (attrib->type == DRW_ATTRIB_FLOAT) { attrib->format_id = GWN_vertformat_attr_add( @@ -1251,16 +1246,9 @@ static void shgroup_dynamic_batch(DRWShadingGroup *shgroup) GWN_vertbuf_data_alloc(vbo, nbr); int j = 0; -#ifdef USE_MEM_ITER - BLI_memiter_handle calls_iter; - BLI_memiter_iter_init(shgroup->calls, &calls_iter); - for (DRWCallDynamic *call; (call = BLI_memiter_iter_step(&calls_iter)); j++) -#else - for (DRWCallDynamic *call = shgroup->calls.first; call; call = call->head.next, j++) -#endif - { + for (DRWCallDynamic *call = shgroup->calls_first; call; call = call->head.prev, j++) { int i = 0; - for (DRWAttrib *attrib = interface->attribs.first; attrib; attrib = attrib->next, i++) { + for (DRWAttrib *attrib = interface->attribs_first; attrib; attrib = attrib->prev, i++) { GWN_vertbuf_attr_set(vbo, attrib->format_id, j, call->data[i]); } } @@ -1276,7 +1264,7 @@ static void shgroup_dynamic_instance(DRWShadingGroup *shgroup) { int i = 0; int offset = 0; - DRWInterface *interface = shgroup->interface; + DRWInterface *interface = &shgroup->interface; int buffer_size = 0; if (interface->instance_batch != NULL) { @@ -1294,7 +1282,7 @@ static void shgroup_dynamic_instance(DRWShadingGroup *shgroup) /* only once */ if (interface->attribs_stride == 0) { - for (DRWAttrib *attrib = interface->attribs.first; attrib; attrib = attrib->next, i++) { + for (DRWAttrib *attrib = interface->attribs_first; attrib; attrib = attrib->prev, i++) { BLI_assert(attrib->type == DRW_ATTRIB_FLOAT); /* Only float for now */ interface->attribs_stride += attrib->size; interface->attribs_size[i] = attrib->size; @@ -1306,14 +1294,7 @@ static void shgroup_dynamic_instance(DRWShadingGroup *shgroup) buffer_size = sizeof(float) * interface->attribs_stride * interface->instance_count; float *data = MEM_mallocN(buffer_size, "Instance VBO data"); -#ifdef USE_MEM_ITER - BLI_memiter_handle calls_iter; - BLI_memiter_iter_init(shgroup->calls, &calls_iter); - for (DRWCallDynamic *call; (call = BLI_memiter_iter_step(&calls_iter)); ) -#else - for (DRWCallDynamic *call = shgroup->calls.first; call; call = call->head.next) -#endif - { + for (DRWCallDynamic *call = shgroup->calls_first; call; call = call->head.prev) { for (int j = 0; j < interface->attribs_count; ++j) { memcpy(data + offset, call->data[j], sizeof(float) * interface->attribs_size[j]); offset += interface->attribs_size[j]; @@ -1335,7 +1316,7 @@ static void shgroup_dynamic_instance(DRWShadingGroup *shgroup) static void shgroup_dynamic_batch_from_calls(DRWShadingGroup *shgroup) { - if ((shgroup->interface->instance_vbo || shgroup->batch_geom) && + if ((shgroup->interface.instance_vbo || shgroup->batch_geom) && (G.debug_value == 667)) { return; @@ -1359,27 +1340,29 @@ static void shgroup_dynamic_batch_from_calls(DRWShadingGroup *shgroup) DRWPass *DRW_pass_create(const char *name, DRWState state) { - DRWPass *pass = MEM_callocN(sizeof(DRWPass), name); + DRWPass *pass = BLI_mempool_alloc(DST.vmempool->passes); pass->state = state; BLI_strncpy(pass->name, name, MAX_PASS_NAME); - BLI_listbase_clear(&pass->shgroups); + pass->shgroups = NULL; + pass->shgroups_last = NULL; return pass; } void DRW_pass_free(DRWPass *pass) { - for (DRWShadingGroup *shgroup = pass->shgroups.first; shgroup; shgroup = shgroup->next) { + for (DRWShadingGroup *shgroup = pass->shgroups; shgroup; shgroup = shgroup->next) { DRW_shgroup_free(shgroup); } - BLI_freelistN(&pass->shgroups); + pass->shgroups = NULL; + pass->shgroups_last = NULL; } void DRW_pass_foreach_shgroup(DRWPass *pass, void (*callback)(void *userData, DRWShadingGroup *shgrp), void *userData) { - for (DRWShadingGroup *shgroup = pass->shgroups.first; shgroup; shgroup = shgroup->next) { + for (DRWShadingGroup *shgroup = pass->shgroups; shgroup; shgroup = shgroup->next) { callback(userData, shgroup); } } @@ -1398,13 +1381,8 @@ static int pass_shgroup_dist_sort(void *thunk, const void *a, const void *b) const DRWCall *call_a; const DRWCall *call_b; -#ifdef USE_MEM_ITER - call_a = BLI_memiter_elem_first(shgrp_a->calls); - call_b = BLI_memiter_elem_first(shgrp_b->calls); -#else - call_a = shgrp_a->calls.first; - call_b = shgrp_b->calls.first; -#endif + call_a = shgrp_a->calls_first; + call_b = shgrp_b->calls_first; if (call_a == NULL) return -1; if (call_b == NULL) return -1; @@ -1429,6 +1407,18 @@ static int pass_shgroup_dist_sort(void *thunk, const void *a, const void *b) } } +/* ------------------ Shading group sorting --------------------- */ + +#define SORT_IMPL_LINKTYPE DRWShadingGroup + +#define SORT_IMPL_USE_THUNK +#define SORT_IMPL_FUNC shgroup_sort_fn_r +#include "../../blenlib/intern/list_sort_impl.h" +#undef SORT_IMPL_FUNC +#undef SORT_IMPL_USE_THUNK + +#undef SORT_IMPL_LINKTYPE + /** * Sort Shading groups by decreasing Z of their first draw call. * This is usefull for order dependant effect such as transparency. @@ -1442,7 +1432,17 @@ void DRW_pass_sort_shgroup_z(DRWPass *pass) ? viewport_matrix_override.mat[DRW_MAT_VIEWINV] : rv3d->viewinv; ZSortData zsortdata = {viewinv[2], viewinv[3]}; - BLI_listbase_sort_r(&pass->shgroups, pass_shgroup_dist_sort, &zsortdata); + + if (pass->shgroups && pass->shgroups->next) { + pass->shgroups = shgroup_sort_fn_r(pass->shgroups, pass_shgroup_dist_sort, &zsortdata); + + /* Find the next last */ + DRWShadingGroup *last = pass->shgroups; + while ((last = last->next)) { + /* Do nothing */ + }; + pass->shgroups_last = last; + } } /** \} */ @@ -1722,7 +1722,7 @@ static void draw_geometry_prepare( DRWShadingGroup *shgroup, const float (*obmat)[4], const float *texcoloc, const float *texcosize) { RegionView3D *rv3d = DST.draw_ctx.rv3d; - DRWInterface *interface = shgroup->interface; + DRWInterface *interface = &shgroup->interface; float mvp[4][4], mv[4][4], mi[4][4], mvi[4][4], pi[4][4], n[3][3], wn[3][3]; float orcofacs[2][3] = {{0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f}}; @@ -1827,7 +1827,7 @@ static void draw_geometry_prepare( static void draw_geometry_execute(DRWShadingGroup *shgroup, Gwn_Batch *geom) { - DRWInterface *interface = shgroup->interface; + DRWInterface *interface = &shgroup->interface; /* step 2 : bind vertex array & draw */ GWN_batch_program_set(geom, GPU_shader_get_program(shgroup->shader), GPU_shader_get_interface(shgroup->shader)); if (interface->instance_batch) { @@ -1918,9 +1918,8 @@ static void release_ubo_slots(void) static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) { BLI_assert(shgroup->shader); - BLI_assert(shgroup->interface); - DRWInterface *interface = shgroup->interface; + DRWInterface *interface = &shgroup->interface; GPUTexture *tex; GPUUniformBuffer *ubo; int val; @@ -1946,7 +1945,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) /* Binding Uniform */ /* Don't check anything, Interface should already contain the least uniform as possible */ - for (DRWUniform *uni = interface->uniforms.first; uni; uni = uni->next) { + for (DRWUniform *uni = interface->uniforms; uni; uni = uni->next) { switch (uni->type) { case DRW_UNIFORM_SHORT_TO_INT: val = (int)*((short *)uni->value); @@ -1999,26 +1998,15 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) GPU_select_load_id((_call)->head.select_id); \ } ((void)0) -#ifdef USE_MEM_ITER -# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(_call_ls) \ - if (G.f & G_PICKSEL) { \ - DRWCall *call_test = BLI_memiter_elem_first(*(_call_ls)); \ - if (call_test != NULL) { \ - BLI_assert(BLI_memiter_count(*(_call_ls)) == 1); \ - GPU_select_load_id(call_test->head.select_id); \ - } \ - } ((void)0) -#else -# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(_call_ls) \ - if ((G.f & G_PICKSEL) && (_call_ls)->first) { \ - BLI_assert(BLI_listbase_is_single(_call_ls)); \ - GPU_select_load_id(((DRWCall *)(_call_ls)->first)->head.select_id); \ +# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(_call_last, _call_first) \ + if ((G.f & G_PICKSEL) && _call_first) { \ + BLI_assert(_call_first && (_call_first == _call_last)); \ + GPU_select_load_id(((DRWCall *)_call_first)->head.select_id); \ } ((void)0) -#endif #else # define GPU_SELECT_LOAD_IF_PICKSEL(call) -# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(call) +# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(call, _call_first) #endif /* Rendering Calls */ @@ -2030,25 +2018,19 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) if (shgroup->type == DRW_SHG_INSTANCE && (interface->instance_count > 0 || interface->instance_batch != NULL)) { - GPU_SELECT_LOAD_IF_PICKSEL_LIST(&shgroup->calls); + GPU_SELECT_LOAD_IF_PICKSEL_LIST(shgroup->calls, shgroup->calls_first); draw_geometry(shgroup, shgroup->instance_geom, obmat, shgroup->instance_data); } else { /* Some dynamic batch can have no geom (no call to aggregate) */ if (shgroup->batch_geom) { - GPU_SELECT_LOAD_IF_PICKSEL_LIST(&shgroup->calls); + GPU_SELECT_LOAD_IF_PICKSEL_LIST(shgroup->calls, shgroup->calls_first); draw_geometry(shgroup, shgroup->batch_geom, obmat, NULL); } } } else { -#ifdef USE_MEM_ITER - BLI_memiter_handle calls_iter; - BLI_memiter_iter_init(shgroup->calls, &calls_iter); - for (DRWCall *call; (call = BLI_memiter_iter_step(&calls_iter)); ) -#else - for (DRWCall *call = shgroup->calls.first; call; call = call->head.next) -#endif + for (DRWCall *call = shgroup->calls_first; call; call = call->head.prev) { bool neg_scale = is_negative_m4(call->obmat); @@ -2115,7 +2097,7 @@ static void DRW_draw_pass_ex(DRWPass *pass, DRWShadingGroup *start_group, DRWSha void DRW_draw_pass(DRWPass *pass) { - DRW_draw_pass_ex(pass, pass->shgroups.first, pass->shgroups.last); + DRW_draw_pass_ex(pass, pass->shgroups, pass->shgroups_last); } /* Draw only a subset of shgroups. Used in special situations as grease pencil strokes */ @@ -2537,6 +2519,22 @@ 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) { + BLI_mempool_clear_ex(DST.vmempool->calls, BLI_mempool_count(DST.vmempool->calls)); + BLI_mempool_clear_ex(DST.vmempool->calls_generate, BLI_mempool_count(DST.vmempool->calls_generate)); + BLI_mempool_clear_ex(DST.vmempool->calls_dynamic, BLI_mempool_count(DST.vmempool->calls_dynamic)); + BLI_mempool_clear_ex(DST.vmempool->shgroups, BLI_mempool_count(DST.vmempool->shgroups)); + BLI_mempool_clear_ex(DST.vmempool->uniforms, BLI_mempool_count(DST.vmempool->uniforms)); + BLI_mempool_clear_ex(DST.vmempool->attribs, BLI_mempool_count(DST.vmempool->attribs)); + BLI_mempool_clear_ex(DST.vmempool->passes, BLI_mempool_count(DST.vmempool->passes)); + } +} + /* 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 @@ -2554,12 +2552,37 @@ static void DRW_viewport_var_init(void) DefaultFramebufferList *fbl = (DefaultFramebufferList *)GPU_viewport_framebuffer_list_get(DST.viewport); DST.default_framebuffer = fbl->default_fb; + + DST.vmempool = GPU_viewport_mempool_get(DST.viewport); + + if (DST.vmempool->calls == NULL) { + DST.vmempool->calls = BLI_mempool_create(sizeof(DRWCall), 0, 512, 0); + } + if (DST.vmempool->calls_generate == NULL) { + DST.vmempool->calls_generate = BLI_mempool_create(sizeof(DRWCallGenerate), 0, 512, 0); + } + if (DST.vmempool->calls_dynamic == NULL) { + DST.vmempool->calls_dynamic = BLI_mempool_create(sizeof(DRWCallDynamic), 0, 512, 0); + } + if (DST.vmempool->shgroups == NULL) { + DST.vmempool->shgroups = BLI_mempool_create(sizeof(DRWShadingGroup), 0, 256, 0); + } + if (DST.vmempool->uniforms == NULL) { + DST.vmempool->uniforms = BLI_mempool_create(sizeof(DRWUniform), 0, 512, 0); + } + if (DST.vmempool->attribs == NULL) { + DST.vmempool->attribs = BLI_mempool_create(sizeof(DRWAttrib), 0, 256, 0); + } + if (DST.vmempool->passes == NULL) { + DST.vmempool->passes = BLI_mempool_create(sizeof(DRWPass), 0, 64, 0); + } } else { DST.size[0] = 0; DST.size[1] = 0; DST.default_framebuffer = NULL; + DST.vmempool = NULL; } /* Refresh DST.screenvecs */ copy_v3_v3(DST.screenvecs[0], rv3d->viewinv[0]); @@ -3258,12 +3281,11 @@ void DRW_draw_render_loop_ex( DST.draw_ctx.evil_C = evil_C; - bool cache_is_dirty; DST.viewport = rv3d->viewport; v3d->zbuf = true; /* Setup viewport */ - cache_is_dirty = GPU_viewport_cache_validate(DST.viewport, DRW_engines_get_hash()); + GPU_viewport_engines_data_validate(DST.viewport, DRW_engines_get_hash()); DST.draw_ctx = (DRWContextState){ ar, rv3d, v3d, scene, scene_layer, OBACT_NEW(scene_layer), engine, @@ -3286,7 +3308,7 @@ void DRW_draw_render_loop_ex( /* TODO : tag to refresh by the deps graph */ /* ideally only refresh when objects are added/removed */ /* or render properties / materials change */ - if (cache_is_dirty) { + { PROFILE_START(stime); DRW_engines_cache_init(); @@ -3366,6 +3388,8 @@ void DRW_draw_render_loop_ex( DRW_state_reset(); DRW_engines_disable(); + DRW_viewport_cache_resize(); + #ifdef DEBUG /* Avoid accidental reuse. */ memset(&DST, 0xFF, sizeof(DST)); diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h index 622b3b301e4..f2bb05a6d1e 100644 --- a/source/blender/gpu/GPU_viewport.h +++ b/source/blender/gpu/GPU_viewport.h @@ -43,6 +43,17 @@ typedef struct GPUViewport GPUViewport; +/* Contains memory pools informations */ +typedef struct ViewportMemoryPool { + struct BLI_mempool *calls; + struct BLI_mempool *calls_generate; + struct BLI_mempool *calls_dynamic; + struct BLI_mempool *shgroups; + struct BLI_mempool *uniforms; + struct BLI_mempool *attribs; + struct BLI_mempool *passes; +} ViewportMemoryPool; + /* All FramebufferLists are just the same pointers with different names */ typedef struct FramebufferList { struct GPUFrameBuffer *framebuffers[0]; @@ -94,6 +105,8 @@ void GPU_viewport_free(GPUViewport *viewport); GPUViewport *GPU_viewport_create_from_offscreen(struct GPUOffScreen *ofs); void GPU_viewport_clear_from_offscreen(GPUViewport *viewport); +ViewportMemoryPool *GPU_viewport_mempool_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); void *GPU_viewport_framebuffer_list_get(GPUViewport *viewport); @@ -107,7 +120,8 @@ bool GPU_viewport_do_update(GPUViewport *viewport); /* Texture pool */ GPUTexture *GPU_viewport_texture_pool_query(GPUViewport *viewport, void *engine, int width, int height, int channels, int format); -bool GPU_viewport_cache_validate(GPUViewport *viewport, unsigned int hash); +bool GPU_viewport_engines_data_validate(GPUViewport *viewport, unsigned int hash); +void GPU_viewport_cache_release(GPUViewport *viewport); /* debug */ bool GPU_viewport_debug_depth_create(GPUViewport *viewport, int width, int height, char err_out[256]); diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c index 058f6ced40b..bdbf829a1ca 100644 --- a/source/blender/gpu/intern/gpu_viewport.c +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -36,6 +36,7 @@ #include "BLI_listbase.h" #include "BLI_rect.h" #include "BLI_string.h" +#include "BLI_mempool.h" #include "DNA_vec_types.h" #include "DNA_userdef_types.h" @@ -82,6 +83,8 @@ struct GPUViewport { DefaultFramebufferList *fbl; DefaultTextureList *txl; + ViewportMemoryPool vmempool; /* Used for rendering data structure. */ + ListBase tex_pool; /* ViewportTempTexture list : Temporary textures shared across draw engines */ }; @@ -202,6 +205,11 @@ void *GPU_viewport_engine_data_get(GPUViewport *viewport, void *engine_type) return NULL; } +ViewportMemoryPool *GPU_viewport_mempool_get(GPUViewport *viewport) +{ + return &viewport->vmempool; +} + void *GPU_viewport_framebuffer_list_get(GPUViewport *viewport) { return viewport->fbl; @@ -296,21 +304,10 @@ static void gpu_viewport_texture_pool_free(GPUViewport *viewport) BLI_freelistN(&viewport->tex_pool); } -bool GPU_viewport_cache_validate(GPUViewport *viewport, unsigned int hash) +bool GPU_viewport_engines_data_validate(GPUViewport *viewport, unsigned int hash) { bool dirty = false; - /* TODO for testing only, we need proper cache invalidation */ - if (ELEM(G.debug_value, 666, 667) == false) { - for (LinkData *link = viewport->data.first; link; link = link->next) { - ViewportEngineData *data = link->data; - int psl_len; - DRW_engine_viewport_data_size_get(data->engine_type, NULL, NULL, &psl_len, NULL); - gpu_viewport_passes_free(data->psl, psl_len); - } - dirty = true; - } - if (viewport->data_hash != hash) { gpu_viewport_engines_data_free(viewport); dirty = true; @@ -321,6 +318,16 @@ bool GPU_viewport_cache_validate(GPUViewport *viewport, unsigned int hash) return dirty; } +void GPU_viewport_cache_release(GPUViewport *viewport) +{ + for (LinkData *link = viewport->data.first; link; link = link->next) { + ViewportEngineData *data = link->data; + int psl_len; + DRW_engine_viewport_data_size_get(data->engine_type, NULL, NULL, &psl_len, NULL); + gpu_viewport_passes_free(data->psl, psl_len); + } +} + void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect) { DefaultFramebufferList *dfbl = viewport->fbl; @@ -551,7 +558,6 @@ static void gpu_viewport_passes_free(PassList *psl, int psl_len) struct DRWPass *pass = psl->passes[i]; if (pass) { DRW_pass_free(pass); - MEM_freeN(pass); psl->passes[i] = NULL; } } @@ -570,6 +576,28 @@ void GPU_viewport_free(GPUViewport *viewport) MEM_freeN(viewport->fbl); MEM_freeN(viewport->txl); + if (viewport->vmempool.calls != NULL) { + BLI_mempool_destroy(viewport->vmempool.calls); + } + if (viewport->vmempool.calls_generate != NULL) { + BLI_mempool_destroy(viewport->vmempool.calls_generate); + } + if (viewport->vmempool.calls_dynamic != NULL) { + BLI_mempool_destroy(viewport->vmempool.calls_dynamic); + } + if (viewport->vmempool.shgroups != NULL) { + BLI_mempool_destroy(viewport->vmempool.shgroups); + } + if (viewport->vmempool.uniforms != NULL) { + BLI_mempool_destroy(viewport->vmempool.uniforms); + } + if (viewport->vmempool.attribs != NULL) { + BLI_mempool_destroy(viewport->vmempool.attribs); + } + if (viewport->vmempool.passes != NULL) { + BLI_mempool_destroy(viewport->vmempool.passes); + } + GPU_viewport_debug_depth_free(viewport); } |