diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2018-03-01 21:27:38 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2018-03-02 20:35:59 +0300 |
commit | d63829117c21c0d926cf0a9df645c3ed5cd8057a (patch) | |
tree | 5497f58c4b52cd894f4811fb35da3727fb059d8f /source/blender/draw/intern | |
parent | 62390527b2e9b6a6a2939df120f87b5b2a54e74b (diff) |
DRW: Refactor simple instancing.
Instead of creating a new instancing shading group without attrib, we now have instancing calls. The benefits is that they can be culled.
They can be used in conjuction with the standard and generate calls but shader must support it (which is generally not the case).
We store a pointer to the actual count so that the number can be tweaked between redraw.
This will makes multi layer rendering more efficient.
Diffstat (limited to 'source/blender/draw/intern')
-rw-r--r-- | source/blender/draw/intern/DRW_render.h | 8 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_manager.h | 6 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_manager_data.c | 60 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_manager_exec.c | 37 |
4 files changed, 71 insertions, 40 deletions
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index c83b67b00e5..1713960597e 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -347,6 +347,11 @@ void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct Gwn_Batch *batc void DRW_shgroup_free(struct DRWShadingGroup *shgroup); void DRW_shgroup_call_add(DRWShadingGroup *shgroup, struct Gwn_Batch *geom, float (*obmat)[4]); void DRW_shgroup_call_object_add(DRWShadingGroup *shgroup, struct Gwn_Batch *geom, struct Object *ob); +/* Used for drawing a batch with instancing without instance attribs. */ +void DRW_shgroup_call_instances_add( + DRWShadingGroup *shgroup, struct Gwn_Batch *geom, float (*obmat)[4], unsigned int *count); +void DRW_shgroup_call_object_instances_add( + DRWShadingGroup *shgroup, struct Gwn_Batch *geom, struct Object *ob, unsigned int *count); void DRW_shgroup_call_sculpt_add(DRWShadingGroup *shgroup, struct Object *ob, float (*obmat)[4]); void DRW_shgroup_call_generate_add( DRWShadingGroup *shgroup, DRWCallGenerateFn *geometry_fn, void *user_data, float (*obmat)[4]); @@ -355,8 +360,7 @@ void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup, const void *at const void *array[] = {__VA_ARGS__}; \ DRW_shgroup_call_dynamic_add_array(shgroup, array, (sizeof(array) / sizeof(*array))); \ } while (0) -/* Use this to set a high number of instances. */ -void DRW_shgroup_set_instance_count(DRWShadingGroup *shgroup, unsigned int count); + unsigned int DRW_shgroup_get_instance_count(const DRWShadingGroup *shgroup); void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state); diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h index a037915fff1..58973471c4e 100644 --- a/source/blender/draw/intern/draw_manager.h +++ b/source/blender/draw/intern/draw_manager.h @@ -128,6 +128,7 @@ typedef struct DRWCallState { typedef enum { DRW_CALL_SINGLE, /* A single batch */ + DRW_CALL_INSTANCES, /* Draw instances without any instancing attribs. */ DRW_CALL_GENERATE, /* Uses a callback to draw with any number of batches. */ } DRWCallType; @@ -139,6 +140,11 @@ typedef struct DRWCall { struct { /* type == DRW_CALL_SINGLE */ Gwn_Batch *geometry; } single; + struct { /* type == DRW_CALL_INSTANCES */ + Gwn_Batch *geometry; + /* Count can be adjusted between redraw. If needed, we can add fixed count. */ + unsigned int *count; + } instances; struct { /* type == DRW_CALL_GENERATE */ DRWCallGenerateFn *geometry_fn; void *user_data; diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index b955bd3000c..fd4652a0305 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -335,6 +335,41 @@ void DRW_shgroup_call_object_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, Obje BLI_LINKS_APPEND(&shgroup->calls, call); } +void DRW_shgroup_call_instances_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, float (*obmat)[4], unsigned int *count) +{ + BLI_assert(geom != NULL); + BLI_assert(shgroup->type == DRW_SHG_NORMAL); + + DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); + call->state = drw_call_state_create(shgroup, obmat, NULL); + call->type = DRW_CALL_INSTANCES; + call->instances.geometry = geom; + call->instances.count = count; +#ifdef USE_GPU_SELECT + call->select_id = DST.select_id; +#endif + + BLI_LINKS_APPEND(&shgroup->calls, call); +} + +/* These calls can be culled and are optimized for redraw */ +void DRW_shgroup_call_object_instances_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, Object *ob, unsigned int *count) +{ + BLI_assert(geom != NULL); + BLI_assert(shgroup->type == DRW_SHG_NORMAL); + + DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); + call->state = drw_call_state_object(shgroup, ob->obmat, ob); + call->type = DRW_CALL_INSTANCES; + call->instances.geometry = geom; + call->instances.count = count; +#ifdef USE_GPU_SELECT + call->select_id = DST.select_id; +#endif + + BLI_LINKS_APPEND(&shgroup->calls, call); +} + void DRW_shgroup_call_generate_add( DRWShadingGroup *shgroup, DRWCallGenerateFn *geometry_fn, void *user_data, @@ -466,18 +501,17 @@ static void drw_interface_instance_init( { BLI_assert(shgroup->type == DRW_SHG_INSTANCE); BLI_assert(batch != NULL); + BLI_assert(format != NULL); drw_interface_init(shgroup, shader); shgroup->instance_geom = batch; #ifndef NDEBUG - shgroup->attribs_count = (format != NULL) ? format->attrib_ct : 0; + shgroup->attribs_count = format->attrib_ct; #endif - if (format != NULL) { - DRW_instancing_buffer_request(DST.idatalist, format, batch, shgroup, - &shgroup->instance_geom, &shgroup->instance_vbo); - } + DRW_instancing_buffer_request(DST.idatalist, format, batch, shgroup, + &shgroup->instance_geom, &shgroup->instance_vbo); } static void drw_interface_batching_init( @@ -741,22 +775,6 @@ void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct Gwn_Batch *batc #endif } -/* Used for instancing with no attributes */ -void DRW_shgroup_set_instance_count(DRWShadingGroup *shgroup, unsigned int count) -{ - BLI_assert(shgroup->type == DRW_SHG_INSTANCE); - BLI_assert(shgroup->instance_count == 0); - BLI_assert(shgroup->attribs_count == 0); - -#ifdef USE_GPU_SELECT - if (G.f & G_PICKSEL) { - shgroup->override_selectid = DST.select_id; - } -#endif - - shgroup->instance_count = count; -} - unsigned int DRW_shgroup_get_instance_count(const DRWShadingGroup *shgroup) { return shgroup->instance_count; diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c index 0cdf5d78a43..055baff6a96 100644 --- a/source/blender/draw/intern/draw_manager_exec.c +++ b/source/blender/draw/intern/draw_manager_exec.c @@ -618,7 +618,7 @@ static void draw_geometry_prepare(DRWShadingGroup *shgroup, DRWCallState *state) } static void draw_geometry_execute_ex( - DRWShadingGroup *shgroup, Gwn_Batch *geom, unsigned int start, unsigned int count) + DRWShadingGroup *shgroup, Gwn_Batch *geom, unsigned int start, unsigned int count, bool draw_instance) { /* Special case: empty drawcall, placement is done via shader, don't bind anything. */ if (geom == NULL) { @@ -632,18 +632,15 @@ static void draw_geometry_execute_ex( GWN_batch_program_set_no_use(geom, GPU_shader_get_program(shgroup->shader), GPU_shader_get_interface(shgroup->shader)); /* XXX hacking gawain. we don't want to call glUseProgram! (huge performance loss) */ geom->program_in_use = true; - if (ELEM(shgroup->type, DRW_SHG_INSTANCE, DRW_SHG_INSTANCE_EXTERNAL)) { - GWN_batch_draw_range_ex(geom, start, count, true); - } - else { - GWN_batch_draw_range(geom, start, count); - } + + GWN_batch_draw_range_ex(geom, start, count, draw_instance); + geom->program_in_use = false; /* XXX hacking gawain */ } static void draw_geometry_execute(DRWShadingGroup *shgroup, Gwn_Batch *geom) { - draw_geometry_execute_ex(shgroup, geom, 0, 0); + draw_geometry_execute_ex(shgroup, geom, 0, 0, false); } static void bind_texture(GPUTexture *tex) @@ -817,7 +814,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) if (shgroup->instance_geom != NULL) { GPU_SELECT_LOAD_IF_PICKSEL(shgroup->override_selectid); draw_geometry_prepare(shgroup, NULL); - draw_geometry_execute(shgroup, shgroup->instance_geom); + draw_geometry_execute_ex(shgroup, shgroup->instance_geom, 0, 0, true); } } else { @@ -826,7 +823,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) draw_geometry_prepare(shgroup, NULL); GPU_SELECT_LOAD_IF_PICKSEL_LIST(shgroup, start, count) { - draw_geometry_execute_ex(shgroup, shgroup->instance_geom, start, count); + draw_geometry_execute_ex(shgroup, shgroup->instance_geom, start, count, true); } GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count) } @@ -839,7 +836,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) draw_geometry_prepare(shgroup, NULL); GPU_SELECT_LOAD_IF_PICKSEL_LIST(shgroup, start, count) { - draw_geometry_execute_ex(shgroup, shgroup->batch_geom, start, count); + draw_geometry_execute_ex(shgroup, shgroup->batch_geom, start, count, false); } GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count) } @@ -865,12 +862,18 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) GPU_SELECT_LOAD_IF_PICKSEL_CALL(call); draw_geometry_prepare(shgroup, call->state); - if (call->type == DRW_CALL_SINGLE) { - draw_geometry_execute(shgroup, call->single.geometry); - } - else { - BLI_assert(call->type == DRW_CALL_GENERATE); - call->generate.geometry_fn(shgroup, draw_geometry_execute, call->generate.user_data); + switch (call->type) { + case DRW_CALL_SINGLE: + draw_geometry_execute(shgroup, call->single.geometry); + break; + case DRW_CALL_INSTANCES: + draw_geometry_execute_ex(shgroup, call->instances.geometry, 0, *call->instances.count, true); + break; + case DRW_CALL_GENERATE: + call->generate.geometry_fn(shgroup, draw_geometry_execute, call->generate.user_data); + break; + default: + BLI_assert(0); } } /* Reset state */ |