diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2018-01-09 16:21:55 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2018-01-09 16:54:11 +0300 |
commit | 377915b08144e0945ed1984338def3dcad267a6d (patch) | |
tree | 4abc64e3ae9290d7f71abf7a16a45f67101ce06c /source/blender/draw | |
parent | aa0097ad5e80278c0e08f64472b7bd1b402838da (diff) |
DRW: Make use of DRWInstanceData.
This modify the selection code quite a bit but it's for the better.
When using selection we use the same batching / instancing process but we draw each element at a time using a an offset to the first element we want to draw and by drawing only one element.
This result much less memory allocation and better draw time.
Diffstat (limited to 'source/blender/draw')
-rw-r--r-- | source/blender/draw/intern/draw_manager.c | 270 | ||||
-rw-r--r-- | source/blender/draw/modes/object_mode.c | 3 |
2 files changed, 143 insertions, 130 deletions
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index eda2f775028..9aead1d4c33 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -88,6 +88,8 @@ /* only for callbacks */ #include "draw_cache_impl.h" +#include "draw_instance_data.h" + #include "draw_mode_engines.h" #include "engines/clay/clay_engine.h" #include "engines/eevee/eevee_engine.h" @@ -221,6 +223,12 @@ struct DRWInterface { /* Dynamic batch */ Gwn_Batch *instance_batch; /* contains instances attributes */ GLuint instance_vbo; /* same as instance_batch but generated from DRWCalls */ + struct DRWInstanceData *inst_data; +#ifdef USE_GPU_SELECT + struct DRWInstanceData *inst_selectid; + /* Override for single object instances. */ + int override_selectid; +#endif int instance_count; Gwn_VertFormat vbo_format; }; @@ -328,6 +336,7 @@ static struct DRWGlobalState { DRWCallGenerate *last_callgenerate; DRWCallDynamic *last_calldynamic; DRWShadingGroup *last_shgroup; + DRWInstanceDataList *idatalist; /* Rendering state */ GPUShader *shader; @@ -686,12 +695,14 @@ static void drw_interface_create(DRWInterface *interface, GPUShader *shader) interface->attribs_stride = 0; interface->instance_vbo = 0; interface->instance_batch = NULL; + interface->inst_data = NULL; + interface->uniforms = NULL; +#ifdef USE_GPU_SELECT + interface->inst_selectid = NULL; + interface->override_selectid = -1; +#endif memset(&interface->vbo_format, 0, sizeof(Gwn_VertFormat)); - - interface->uniforms = NULL; - interface->attribs = NULL; - interface->attribs_first = NULL; } @@ -729,14 +740,22 @@ static void drw_interface_uniform(DRWShadingGroup *shgroup, const char *name, shgroup->interface.uniforms = uni; } -static void drw_interface_attrib(DRWShadingGroup *shgroup, const char *name, DRWAttribType type, int size, bool dummy) +static void drw_interface_attrib(DRWShadingGroup *shgroup, const char *name, DRWAttribType UNUSED(type), int size, bool dummy) { - DRWAttrib *attrib = BLI_mempool_alloc(DST.vmempool->attribs); + unsigned int attrib_id = shgroup->interface.attribs_count; GLuint program = GPU_shader_get_program(shgroup->shader); - attrib->location = glGetAttribLocation(program, name); - attrib->type = type; - attrib->size = size; + shgroup->interface.attribs_loc[attrib_id] = glGetAttribLocation(program, name); + shgroup->interface.attribs_size[attrib_id] = size; + shgroup->interface.attribs_stride += size; + shgroup->interface.attribs_count += 1; + + if (shgroup->type != DRW_SHG_INSTANCE) { + BLI_assert(size <= 4); /* Matrices are not supported by Gawain. */ + GWN_vertformat_attr_add(&shgroup->interface.vbo_format, name, GWN_COMP_F32, size, GWN_FETCH_FLOAT); + } + + BLI_assert(shgroup->interface.attribs_count < MAX_ATTRIB_COUNT); /* Adding attribute even if not found for now (to keep memory alignment). * Should ideally take vertex format automatically from batch eventually */ @@ -751,23 +770,6 @@ static void drw_interface_attrib(DRWShadingGroup *shgroup, const char *name, DRW #else UNUSED_VARS(dummy); #endif - - BLI_assert(BLI_strnlen(name, 32) < 32); - BLI_strncpy(attrib->name, name, 32); - - shgroup->interface.attribs_count += 1; - BLI_assert(shgroup->interface.attribs_count < MAX_ATTRIB_COUNT); - - /* 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; } /** \} */ @@ -965,14 +967,6 @@ void DRW_shgroup_free(struct DRWShadingGroup *shgroup) 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); - - shgroup->interface.instance_batch = instances; -} - #define CALL_PREPEND(shgroup, call) { \ if (shgroup->calls == NULL) { \ shgroup->calls = call; \ @@ -985,10 +979,25 @@ void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct Gwn_Batch *inst call->head.prev = NULL; \ } ((void)0) +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); + + shgroup->interface.instance_batch = instances; + +#ifdef USE_GPU_SELECT + DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); + call->head.select_id = g_DRW_select_id; + + CALL_PREPEND(shgroup, call); +#endif +} void DRW_shgroup_call_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, float (*obmat)[4]) { BLI_assert(geom != NULL); + BLI_assert(shgroup->type == DRW_SHG_NORMAL); DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); @@ -1010,6 +1019,7 @@ void DRW_shgroup_call_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, float (*obm void DRW_shgroup_call_object_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, Object *ob) { BLI_assert(geom != NULL); + BLI_assert(shgroup->type == DRW_SHG_NORMAL); DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); @@ -1031,6 +1041,7 @@ void DRW_shgroup_call_generate_add( float (*obmat)[4]) { BLI_assert(geometry_fn != NULL); + BLI_assert(shgroup->type == DRW_SHG_NORMAL); DRWCallGenerate *call = BLI_mempool_alloc(DST.vmempool->calls_generate); @@ -1074,43 +1085,30 @@ void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup, const void *at DRWInterface *interface = &shgroup->interface; #ifdef USE_GPU_SELECT - if ((G.f & G_PICKSEL) && (interface->instance_count > 0)) { - DRWShadingGroup *original_shgroup = shgroup; - shgroup = BLI_mempool_alloc(DST.vmempool->shgroups); - memcpy(shgroup, original_shgroup, sizeof(DRWShadingGroup)); - - shgroup->calls = NULL; - shgroup->calls_first = NULL; - - interface = &shgroup->interface; - interface->instance_count = 0; - - /* Append */ - if (shgroup->pass_parent->shgroups != NULL) { - shgroup->pass_parent->shgroups_last->next = shgroup; - } - else { - shgroup->pass_parent->shgroups = shgroup; + if (G.f & G_PICKSEL) { + if (interface->inst_selectid == NULL) { + interface->inst_selectid = DRW_instance_data_request(DST.idatalist, 1, 128); } - shgroup->pass_parent->shgroups_last = shgroup; - shgroup->next = NULL; + + int *select_id = DRW_instance_data_next(interface->inst_selectid); + *select_id = g_DRW_select_id; } #endif - DRWCallDynamic *call = BLI_mempool_alloc(DST.vmempool->calls_dynamic); - - CALL_PREPEND(shgroup, call); - BLI_assert(attr_len == interface->attribs_count); UNUSED_VARS_NDEBUG(attr_len); - call->head.type = DRW_CALL_DYNAMIC; -#ifdef USE_GPU_SELECT - call->head.select_id = g_DRW_select_id; -#endif + if (interface->attribs_stride > 0) { + if (interface->inst_data == NULL) { + interface->inst_data = DRW_instance_data_request(DST.idatalist, interface->attribs_stride, 16); + } + + float *data = DRW_instance_data_next(interface->inst_data); - if (interface->attribs_count != 0) { - memcpy((void *)call->data, attr, sizeof(void *) * interface->attribs_count); + for (int i = 0; i < interface->attribs_count; ++i) { + memcpy(data, attr[i], sizeof(float) * interface->attribs_size[i]); + data = data + interface->attribs_size[i]; + } } interface->instance_count += 1; @@ -1121,8 +1119,15 @@ void DRW_shgroup_set_instance_count(DRWShadingGroup *shgroup, int count) { DRWInterface *interface = &shgroup->interface; + BLI_assert(interface->instance_count == 0); BLI_assert(interface->attribs_count == 0); +#ifdef USE_GPU_SELECT + if (G.f & G_PICKSEL) { + interface->override_selectid = g_DRW_select_id; + } +#endif + interface->instance_count = count; } @@ -1238,33 +1243,8 @@ static void shgroup_dynamic_batch(DRWShadingGroup *shgroup) return; /* Upload Data */ - if (interface->vbo_format.attrib_ct == 0) { - 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( - &interface->vbo_format, attrib->name, GWN_COMP_F32, attrib->size, GWN_FETCH_FLOAT); - } - else if (attrib->type == DRW_ATTRIB_INT) { - attrib->format_id = GWN_vertformat_attr_add( - &interface->vbo_format, attrib->name, GWN_COMP_I8, attrib->size, GWN_FETCH_INT); - } - else { - BLI_assert(false); - } - } - } - Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&interface->vbo_format); - GWN_vertbuf_data_alloc(vbo, nbr); - - int j = 0; - for (DRWCallDynamic *call = shgroup->calls_first; call; call = call->head.prev, j++) { - int i = 0; - for (DRWAttrib *attrib = interface->attribs_first; attrib; attrib = attrib->prev, i++) { - GWN_vertbuf_attr_set(vbo, attrib->format_id, j, call->data[i]); - } - } + GWN_vertbuf_data_set(vbo, nbr, DRW_instance_data_get(interface->inst_data), false); /* TODO make the batch dynamic instead of freeing it every times */ if (shgroup->batch_geom) @@ -1275,10 +1255,9 @@ static void shgroup_dynamic_batch(DRWShadingGroup *shgroup) static void shgroup_dynamic_instance(DRWShadingGroup *shgroup) { - int i = 0; - int offset = 0; DRWInterface *interface = &shgroup->interface; int buffer_size = 0; + void *data = NULL; if (interface->instance_batch != NULL) { return; @@ -1293,26 +1272,8 @@ static void shgroup_dynamic_instance(DRWShadingGroup *shgroup) return; } - /* only once */ - if (interface->attribs_stride == 0) { - 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; - interface->attribs_loc[i] = attrib->location; - } - } - /* Gather Data */ buffer_size = sizeof(float) * interface->attribs_stride * interface->instance_count; - float *data = MEM_mallocN(buffer_size, "Instance VBO data"); - - 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]; - } - } /* TODO poke mike to add this to gawain */ if (interface->instance_vbo) { @@ -1320,11 +1281,13 @@ static void shgroup_dynamic_instance(DRWShadingGroup *shgroup) interface->instance_vbo = 0; } + if (interface->inst_data) { + data = DRW_instance_data_get(interface->inst_data); + } + glGenBuffers(1, &interface->instance_vbo); glBindBuffer(GL_ARRAY_BUFFER, interface->instance_vbo); glBufferData(GL_ARRAY_BUFFER, buffer_size, data, GL_STATIC_DRAW); - - MEM_freeN(data); } static void shgroup_dynamic_batch_from_calls(DRWShadingGroup *shgroup) @@ -1846,28 +1809,37 @@ static void draw_geometry_prepare( GPU_shader_uniform_vector(shgroup->shader, interface->clipplanes, 4, DST.num_clip_planes, (float *)DST.clip_planes_eq); } -static void draw_geometry_execute(DRWShadingGroup *shgroup, Gwn_Batch *geom) +static void draw_geometry_execute_ex( + DRWShadingGroup *shgroup, Gwn_Batch *geom, unsigned int start, unsigned int count) { 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) { + /* Used for Particles. Cannot do partial drawing. */ GWN_batch_draw_stupid_instanced_with_batch(geom, interface->instance_batch); } else if (interface->instance_vbo) { GWN_batch_draw_stupid_instanced( - geom, interface->instance_vbo, 0, interface->instance_count, interface->attribs_count, + geom, interface->instance_vbo, start, count, interface->attribs_count, interface->attribs_stride, interface->attribs_size, interface->attribs_loc); } else { - GWN_batch_draw_stupid(geom, 0, 0); + GWN_batch_draw_stupid(geom, start, count); } /* XXX this just tells gawain we are done with the shader. * This does not unbind the shader. */ GWN_batch_program_unset(geom); } -static void draw_geometry(DRWShadingGroup *shgroup, Gwn_Batch *geom, const float (*obmat)[4], ID *ob_data) +static void draw_geometry_execute(DRWShadingGroup *shgroup, Gwn_Batch *geom) +{ + draw_geometry_execute_ex(shgroup, geom, 0, 0); +} + +static void draw_geometry( + DRWShadingGroup *shgroup, Gwn_Batch *geom, const float (*obmat)[4], ID *ob_data, + unsigned int start, unsigned int count) { float *texcoloc = NULL; float *texcosize = NULL; @@ -1901,7 +1873,7 @@ static void draw_geometry(DRWShadingGroup *shgroup, Gwn_Batch *geom, const float draw_geometry_prepare(shgroup, obmat, texcoloc, texcosize); - draw_geometry_execute(shgroup, geom); + draw_geometry_execute_ex(shgroup, geom, start, count); } static void bind_texture(GPUTexture *tex) @@ -2035,15 +2007,39 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) GPU_select_load_id((_call)->head.select_id); \ } ((void)0) -# 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) +# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(_shgroup, _start, _count) \ + _start = 0; \ + _count = _shgroup->interface.instance_count; \ + int *select_id = NULL; \ + if (G.f & G_PICKSEL) { \ + if (_shgroup->interface.override_selectid == -1) { \ + select_id = DRW_instance_data_get(_shgroup->interface.inst_selectid); \ + switch (_shgroup->type) { \ + case DRW_SHG_TRIANGLE_BATCH: _count = 3; break; \ + case DRW_SHG_LINE_BATCH: _count = 2; break; \ + default: _count = 1; break; \ + } \ + } \ + else { \ + GPU_select_load_id(_shgroup->interface.override_selectid); \ + } \ + } \ + while (_start < _shgroup->interface.instance_count) { \ + if (select_id) { \ + GPU_select_load_id(select_id[_start]); \ + } + +# define GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(_start, _count) \ + _start += _count; \ + } #else # define GPU_SELECT_LOAD_IF_PICKSEL(call) -# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(call, _call_first) +# define GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count) +# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(_shgroup, _start, _count) \ + _start = 0; \ + _count = _shgroup->interface.instance_count; + #endif /* Rendering Calls */ @@ -2055,14 +2051,28 @@ 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, shgroup->calls_first); - draw_geometry(shgroup, shgroup->instance_geom, obmat, shgroup->instance_data); + if (interface->instance_batch != NULL) { + GPU_SELECT_LOAD_IF_PICKSEL((DRWCall *)shgroup->calls_first); + draw_geometry(shgroup, shgroup->instance_geom, obmat, shgroup->instance_data, 0, 0); + } + else { + unsigned int count, start; + GPU_SELECT_LOAD_IF_PICKSEL_LIST(shgroup, start, count) + { + draw_geometry(shgroup, shgroup->instance_geom, obmat, shgroup->instance_data, start, count); + } + GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count) + } } else { /* Some dynamic batch can have no geom (no call to aggregate) */ if (shgroup->batch_geom) { - GPU_SELECT_LOAD_IF_PICKSEL_LIST(shgroup->calls, shgroup->calls_first); - draw_geometry(shgroup, shgroup->batch_geom, obmat, NULL); + unsigned int count, start; + GPU_SELECT_LOAD_IF_PICKSEL_LIST(shgroup, start, count) + { + draw_geometry(shgroup, shgroup->batch_geom, obmat, NULL, start, count); + } + GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count) } } } @@ -2078,7 +2088,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) GPU_SELECT_LOAD_IF_PICKSEL(call); if (call->head.type == DRW_CALL_SINGLE) { - draw_geometry(shgroup, call->geometry, call->obmat, call->ob_data); + draw_geometry(shgroup, call->geometry, call->obmat, call->ob_data, 0, 0); } else { BLI_assert(call->head.type == DRW_CALL_GENERATE); @@ -2583,6 +2593,9 @@ static void drw_viewport_cache_resize(void) 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)); } + + DRW_instance_data_list_free_unused(DST.idatalist); + DRW_instance_data_list_resize(DST.idatalist); } /* It also stores viewport variable to an immutable place: DST @@ -2626,6 +2639,9 @@ static void drw_viewport_var_init(void) if (DST.vmempool->passes == NULL) { DST.vmempool->passes = BLI_mempool_create(sizeof(DRWPass), 0, 64, 0); } + + DST.idatalist = GPU_viewport_instance_data_list_get(DST.viewport); + DRW_instance_data_list_reset(DST.idatalist); } else { DST.size[0] = 0; diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c index af0af3dca43..4e19eff3cfb 100644 --- a/source/blender/draw/modes/object_mode.c +++ b/source/blender/draw/modes/object_mode.c @@ -1500,9 +1500,6 @@ static void DRW_shgroup_lightprobe(OBJECT_StorageList *stl, OBJECT_PassList *psl sub_v3_v3(prb_data->increment_z, prb_data->corner); DRWShadingGroup *grp = DRW_shgroup_instance_create(e_data.lightprobe_grid_sh, psl->lightprobes, DRW_cache_sphere_get()); - /* Dummy call just to save select ID */ - DRW_shgroup_call_dynamic_add_empty(grp); - /* Then overide the instance count */ DRW_shgroup_set_instance_count(grp, prb->grid_resolution_x * prb->grid_resolution_y * prb->grid_resolution_z); DRW_shgroup_uniform_vec4(grp, "color", color, 1); DRW_shgroup_uniform_vec3(grp, "corner", prb_data->corner, 1); |