diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2018-02-27 01:39:09 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2018-02-27 16:50:16 +0300 |
commit | ec0ecbe795200f9f7e3a8c0154f4e37d8be9527e (patch) | |
tree | 420365450e8a96cc178402a3e017547d39675d00 | |
parent | fe80d8ec3c459500258c33d2058558658f1df4f2 (diff) |
DRW: Refactor / Cleanup Builtin uniforms.
-Make the view and object dependant matrices calculation isolated and separated, avoiding non-needed calculation.
-Adding a per drawcall matrix cache so that we can precompute these in advance in the future.
-Replaced integer uniform location of only view dependant builtins by DRWUniforms that are only updated once per shgroup.
-rw-r--r-- | source/blender/draw/intern/draw_manager.c | 631 |
1 files changed, 328 insertions, 303 deletions
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 72edc8d788d..d9c564fd137 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -171,8 +171,6 @@ typedef enum { DRW_UNIFORM_FLOAT, DRW_UNIFORM_TEXTURE, DRW_UNIFORM_BUFFER, - DRW_UNIFORM_MAT3, - DRW_UNIFORM_MAT4, DRW_UNIFORM_BLOCK } DRWUniformType; @@ -205,19 +203,13 @@ struct DRWInterface { int modelinverse; int modelview; int modelviewinverse; - int projection; - int projectioninverse; - int view; - int viewinverse; int modelviewprojection; - int viewprojection; - int viewprojectioninverse; - int normal; - int worldnormal; - int camtexfac; + int normalview; + int normalworld; int orcotexfac; int eye; - int clipplanes; + /* Matrices needed */ + uint16_t matflag; }; struct DRWPass { @@ -231,56 +223,94 @@ struct DRWPass { typedef struct DRWCallHeader { void *prev; - #ifdef USE_GPU_SELECT int select_id; #endif - uchar type; + unsigned char type, state; + uint16_t matflag; + /* Culling: Using Bounding Sphere for now for faster culling. + * Not ideal for planes. */ + struct { + float loc[3], rad; /* Bypassed if radius is < 0.0. */ + } bsphere; + /* Matrices */ + float model[4][4]; + float modelinverse[4][4]; + float modelview[4][4]; + float modelviewinverse[4][4]; + float modelviewprojection[4][4]; + float normalview[3][3]; + float normalworld[3][3]; /* Not view dependant */ + float orcotexfac[2][3]; /* Not view dependant */ + float eyevec[3]; } DRWCallHeader; typedef struct DRWCall { DRWCallHeader head; - float obmat[4][4]; Gwn_Batch *geometry; - - Object *ob; /* Optional */ - ID *ob_data; /* Optional. */ } DRWCall; typedef struct DRWCallGenerate { DRWCallHeader head; - float obmat[4][4]; - DRWCallGenerateFn *geometry_fn; void *user_data; } DRWCallGenerate; +/* Used by DRWCall.flag */ +enum { + DRW_CALL_SINGLE, /* A single batch */ + DRW_CALL_GENERATE, /* Uses a callback to draw with any number of batches. */ +}; + +/* Used by DRWCall.state */ +enum { + DRW_CALL_CULLED = (1 << 0), + DRW_CALL_NEGSCALE = (1 << 1), +}; + +/* Used by DRWCall.flag */ +enum { + DRW_CALL_MODELINVERSE = (1 << 0), + DRW_CALL_MODELVIEW = (1 << 1), + DRW_CALL_MODELVIEWINVERSE = (1 << 2), + DRW_CALL_MODELVIEWPROJECTION = (1 << 3), + DRW_CALL_NORMALVIEW = (1 << 4), + DRW_CALL_NORMALWORLD = (1 << 5), + DRW_CALL_ORCOTEXFAC = (1 << 6), + DRW_CALL_EYEVEC = (1 << 7), + /* 8 bit flag! */ +}; + struct DRWShadingGroup { struct DRWShadingGroup *next; - +#ifdef USE_GPU_SELECT + /* backlink to pass we're in */ + DRWPass *pass_parent; +#endif GPUShader *shader; /* Shader to bind */ DRWInterface interface; /* Uniforms pointers */ - - /* DRWCall or DRWCallDynamic depending of type */ - 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) */ unsigned int stencil_mask; /* Stencil mask to use for stencil test / write operations */ int type; - ID *instance_data; /* Object->data to instance */ - Gwn_Batch *instance_geom; /* Geometry to instance */ - Gwn_Batch *instancing_geom;/* Instances attributes */ - Gwn_Batch *batch_geom; /* Result of call batching */ - -#ifdef USE_GPU_SELECT - /* backlink to pass we're in */ - DRWPass *pass_parent; -#endif + /* Watch this! Can be nasty for debugging. */ + union { + struct { /* DRW_SHG_NORMAL */ + void *calls; /* DRWCall or DRWCallDynamic depending of type */ + void *calls_first; /* To be able to traverse the list in the order of addition */ + }; + struct { /* DRW_SHG_***_BATCH */ + Gwn_Batch *batch_geom; /* Result of call batching */ + }; + struct { /* DRW_SHG_INSTANCE[_EXTERNAL] */ + Gwn_Batch *instance_geom; /* Geometry to instance */ + Gwn_Batch *instancing_geom;/* Instances attributes */ + float instance_orcofac[2][3]; /* TODO find a better place. */ + }; + }; }; /* Used by DRWShadingGroup.type */ @@ -293,16 +323,6 @@ enum { DRW_SHG_INSTANCE_EXTERNAL, }; -/* Used by DRWCall.type */ -enum { - /* A single batch */ - DRW_CALL_SINGLE, - /* Uses a callback to draw with any number of batches. */ - DRW_CALL_GENERATE, - /* Arbitrary number of multiple args. */ - DRW_CALL_DYNAMIC, -}; - /** Render State: No persistent data between draw calls. */ static struct DRWGlobalState { /* Cache generation */ @@ -367,9 +387,13 @@ static struct DRWResourceState { } RST = {NULL}; static struct DRWMatrixOveride { + float original_mat[6][4][4]; float mat[6][4][4]; bool override[6]; -} viewport_matrix_override = {{{{0}}}}; +} viewport_matrices = {{{{0}}}}; + +/* TODO View Ubo */ +static float viewcamtexcofac[4] = {0}; ListBase DRW_engines = {NULL, NULL}; @@ -645,25 +669,57 @@ void DRW_shader_free(GPUShader *shader) /** \name Interface (DRW_interface) * \{ */ -static void drw_interface_init(DRWInterface *interface, GPUShader *shader) +static void drw_interface_builtin_uniform( + DRWShadingGroup *shgroup, int builtin, const void *value, int length, int arraysize) { + int loc = GPU_shader_get_builtin_uniform(shgroup->shader, builtin); + + if (loc == -1) + return; + + DRWUniform *uni = BLI_mempool_alloc(DST.vmempool->uniforms); + uni->location = loc; + uni->type = DRW_UNIFORM_FLOAT; + uni->value = value; + uni->length = length; + uni->arraysize = arraysize; + + /* Prepend */ + uni->next = shgroup->interface.uniforms; + shgroup->interface.uniforms = uni; +} + +static void drw_interface_init(DRWShadingGroup *shgroup, GPUShader *shader) +{ + DRWInterface *interface = &shgroup->interface; 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); interface->modelviewinverse = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MODELVIEW_INV); - interface->projection = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_PROJECTION); - interface->projectioninverse = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_PROJECTION_INV); - interface->view = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_VIEW); - interface->viewinverse = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_VIEW_INV); - interface->viewprojection = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_VIEWPROJECTION); - interface->viewprojectioninverse = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_VIEWPROJECTION_INV); interface->modelviewprojection = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MVP); - interface->normal = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_NORMAL); - interface->worldnormal = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_WORLDNORMAL); - interface->camtexfac = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_CAMERATEXCO); + interface->normalview = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_NORMAL); + interface->normalworld = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_WORLDNORMAL); interface->orcotexfac = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_ORCO); - interface->clipplanes = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_CLIPPLANES); interface->eye = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_EYE); + + interface->matflag = 0; + if (interface->modelinverse > -1) + interface->matflag |= DRW_CALL_MODELINVERSE; + if (interface->modelview > -1) + interface->matflag |= DRW_CALL_MODELVIEW; + if (interface->modelviewinverse > -1) + interface->matflag |= DRW_CALL_MODELVIEWINVERSE; + if (interface->modelviewprojection > -1) + interface->matflag |= DRW_CALL_MODELVIEWPROJECTION; + if (interface->normalview > -1) + interface->matflag |= DRW_CALL_NORMALVIEW; + if (interface->normalworld > -1) + interface->matflag |= DRW_CALL_NORMALWORLD; + if (interface->orcotexfac > -1) + interface->matflag |= DRW_CALL_ORCOTEXFAC; + if (interface->eye > -1) + interface->matflag |= DRW_CALL_EYEVEC; + interface->instance_count = 0; #ifndef NDEBUG interface->attribs_count = 0; @@ -673,13 +729,23 @@ static void drw_interface_init(DRWInterface *interface, GPUShader *shader) interface->inst_selectid = NULL; interface->override_selectid = -1; #endif + + /* TODO : They should be grouped inside a UBO updated once per redraw. */ + drw_interface_builtin_uniform(shgroup, GWN_UNIFORM_VIEW, viewport_matrices.mat[DRW_MAT_VIEW], 16, 1); + drw_interface_builtin_uniform(shgroup, GWN_UNIFORM_VIEW_INV, viewport_matrices.mat[DRW_MAT_VIEWINV], 16, 1); + drw_interface_builtin_uniform(shgroup, GWN_UNIFORM_VIEWPROJECTION, viewport_matrices.mat[DRW_MAT_PERS], 16, 1); + drw_interface_builtin_uniform(shgroup, GWN_UNIFORM_VIEWPROJECTION_INV, viewport_matrices.mat[DRW_MAT_PERSINV], 16, 1); + drw_interface_builtin_uniform(shgroup, GWN_UNIFORM_PROJECTION, viewport_matrices.mat[DRW_MAT_WIN], 16, 1); + drw_interface_builtin_uniform(shgroup, GWN_UNIFORM_PROJECTION_INV, viewport_matrices.mat[DRW_MAT_WININV], 16, 1); + drw_interface_builtin_uniform(shgroup, GWN_UNIFORM_CAMERATEXCO, viewcamtexcofac, 3, 2); + drw_interface_builtin_uniform(shgroup, GWN_UNIFORM_CLIPPLANES, DST.clip_planes_eq, 4, 1); /* TO REMOVE */ } static void drw_interface_instance_init( DRWShadingGroup *shgroup, GPUShader *shader, Gwn_Batch *batch, Gwn_VertFormat *format) { DRWInterface *interface = &shgroup->interface; - drw_interface_init(interface, shader); + drw_interface_init(shgroup, shader); #ifndef NDEBUG interface->attribs_count = (format != NULL) ? format->attrib_ct : 0; @@ -697,7 +763,7 @@ static void drw_interface_batching_init( DRWShadingGroup *shgroup, GPUShader *shader, Gwn_VertFormat *format) { DRWInterface *interface = &shgroup->interface; - drw_interface_init(interface, shader); + drw_interface_init(shgroup, shader); #ifndef NDEBUG interface->attribs_count = (format != NULL) ? format->attrib_ct : 0; @@ -791,11 +857,12 @@ static DRWShadingGroup *drw_shgroup_create_ex(struct GPUShader *shader, DRWPass shgroup->state_extra = 0; shgroup->state_extra_disable = ~0x0; shgroup->stencil_mask = 0; +#if 0 /* All the same in the union! */ shgroup->batch_geom = NULL; + shgroup->instancing_geom = NULL; shgroup->instance_geom = NULL; - shgroup->instance_data = NULL; - +#endif shgroup->calls = NULL; shgroup->calls_first = NULL; @@ -877,13 +944,57 @@ DRWShadingGroup *DRW_shgroup_material_create( DRWShadingGroup *shgroup = drw_shgroup_material_create_ex(gpupass, pass); if (shgroup) { - drw_interface_init(&shgroup->interface, GPU_pass_shader(gpupass)); + drw_interface_init(shgroup, GPU_pass_shader(gpupass)); drw_shgroup_material_inputs(shgroup, material, gpupass); } return shgroup; } +static void drw_call_calc_orco(ID *ob_data, float (*r_orcofacs)[3]) +{ + float *texcoloc = NULL; + float *texcosize = NULL; + if (ob_data != NULL) { + switch (GS(ob_data->name)) { + case ID_ME: + BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, NULL, &texcosize); + break; + case ID_CU: + { + Curve *cu = (Curve *)ob_data; + if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) { + BKE_curve_texspace_calc(cu); + } + texcoloc = cu->loc; + texcosize = cu->size; + break; + } + case ID_MB: + { + MetaBall *mb = (MetaBall *)ob_data; + texcoloc = mb->loc; + texcosize = mb->size; + break; + } + default: + break; + } + } + + if ((texcoloc != NULL) && (texcosize != NULL)) { + mul_v3_v3fl(r_orcofacs[1], texcosize, 2.0f); + invert_v3(r_orcofacs[1]); + sub_v3_v3v3(r_orcofacs[0], texcoloc, texcosize); + negate_v3(r_orcofacs[0]); + mul_v3_v3(r_orcofacs[0], r_orcofacs[1]); /* result in a nice MADD in the shader */ + } + else { + copy_v3_fl(r_orcofacs[0], 0.0f); + copy_v3_fl(r_orcofacs[1], 1.0f); + } +} + DRWShadingGroup *DRW_shgroup_material_instance_create( struct GPUMaterial *material, DRWPass *pass, Gwn_Batch *geom, Object *ob, Gwn_VertFormat *format) { @@ -893,7 +1004,7 @@ DRWShadingGroup *DRW_shgroup_material_instance_create( if (shgroup) { shgroup->type = DRW_SHG_INSTANCE; shgroup->instance_geom = geom; - shgroup->instance_data = ob->data; + drw_call_calc_orco(ob->data, shgroup->instance_orcofac); drw_interface_instance_init(shgroup, GPU_pass_shader(gpupass), geom, format); drw_shgroup_material_inputs(shgroup, material, gpupass); } @@ -912,7 +1023,7 @@ DRWShadingGroup *DRW_shgroup_material_empty_tri_batch_create( if (shgroup) { /* Calling drw_interface_init will cause it to call GWN_draw_primitive(). */ - drw_interface_init(&shgroup->interface, GPU_pass_shader(gpupass)); + drw_interface_init(shgroup, GPU_pass_shader(gpupass)); shgroup->type = DRW_SHG_TRIANGLE_BATCH; shgroup->interface.instance_count = tri_count * 3; drw_shgroup_material_inputs(shgroup, material, gpupass); @@ -924,7 +1035,7 @@ DRWShadingGroup *DRW_shgroup_material_empty_tri_batch_create( DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass) { DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass); - drw_interface_init(&shgroup->interface, shader); + drw_interface_init(shgroup, shader); return shgroup; } @@ -934,7 +1045,7 @@ DRWShadingGroup *DRW_shgroup_instance_create( DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass); shgroup->type = DRW_SHG_INSTANCE; shgroup->instance_geom = geom; - + drw_call_calc_orco(NULL, shgroup->instance_orcofac); drw_interface_instance_init(shgroup, shader, geom, format); return shgroup; @@ -977,7 +1088,7 @@ DRWShadingGroup *DRW_shgroup_empty_tri_batch_create(struct GPUShader *shader, DR DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass); /* Calling drw_interface_init will cause it to call GWN_draw_primitive(). */ - drw_interface_init(&shgroup->interface, shader); + drw_interface_init(shgroup, shader); shgroup->type = DRW_SHG_TRIANGLE_BATCH; shgroup->interface.instance_count = tri_count * 3; @@ -1011,6 +1122,7 @@ void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct Gwn_Batch *batc BLI_assert(shgroup->instancing_geom != NULL); shgroup->type = DRW_SHG_INSTANCE_EXTERNAL; + drw_call_calc_orco(NULL, shgroup->instance_orcofac); /* PERF : This destroys the vaos cache so better check if it's necessary. */ /* Note: This WILL break if batch->verts[0] is destroyed and reallocated * at the same adress. Bindings/VAOs would remain obsolete. */ @@ -1018,36 +1130,49 @@ void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct Gwn_Batch *batc GWN_batch_instbuf_set(shgroup->instancing_geom, batch->verts[0], false); #ifdef USE_GPU_SELECT - DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); - call->head.select_id = g_DRW_select_id; - - CALL_PREPEND(shgroup, call); + shgroup->interface.override_selectid = g_DRW_select_id; #endif } +static void drw_call_set_matrices(DRWCallHeader *head, float (*obmat)[4], ID *ob_data) +{ + /* Matrices */ + if (obmat != NULL) { + copy_m4_m4(head->model, obmat); + + if (is_negative_m4(head->model)) { + head->matflag |= DRW_CALL_NEGSCALE; + } + } + else { + unit_m4(head->model); + } + + /* Orco factors */ + if ((head->matflag & DRW_CALL_ORCOTEXFAC) != 0) { + drw_call_calc_orco(ob_data, head->orcotexfac); + head->matflag &= ~DRW_CALL_ORCOTEXFAC; + } + + /* TODO Set culling bsphere IF needed by the DRWPass */ + head->bsphere.rad = -1.0f; +} + 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); - - CALL_PREPEND(shgroup, call); - call->head.type = DRW_CALL_SINGLE; + call->head.state = 0; + call->head.matflag = shgroup->interface.matflag; #ifdef USE_GPU_SELECT call->head.select_id = g_DRW_select_id; #endif - - if (obmat != NULL) { - copy_m4_m4(call->obmat, obmat); - } - else { - unit_m4(call->obmat); - } - call->geometry = geom; - call->ob_data = NULL; + drw_call_set_matrices(&call->head, obmat, NULL); + CALL_PREPEND(shgroup, call); } void DRW_shgroup_call_object_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, Object *ob) @@ -1056,17 +1181,15 @@ void DRW_shgroup_call_object_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, Obje BLI_assert(shgroup->type == DRW_SHG_NORMAL); DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); - - CALL_PREPEND(shgroup, call); - call->head.type = DRW_CALL_SINGLE; + call->head.state = 0; + call->head.matflag = shgroup->interface.matflag; #ifdef USE_GPU_SELECT call->head.select_id = g_DRW_select_id; #endif - - copy_m4_m4(call->obmat, ob->obmat); call->geometry = geom; - call->ob_data = ob->data; + drw_call_set_matrices(&call->head, ob->obmat, ob->data); + CALL_PREPEND(shgroup, call); } void DRW_shgroup_call_generate_add( @@ -1078,23 +1201,16 @@ void DRW_shgroup_call_generate_add( BLI_assert(shgroup->type == DRW_SHG_NORMAL); DRWCallGenerate *call = BLI_mempool_alloc(DST.vmempool->calls_generate); - - CALL_PREPEND(shgroup, call); - call->head.type = DRW_CALL_GENERATE; + call->head.state = 0; + call->head.matflag = shgroup->interface.matflag; #ifdef USE_GPU_SELECT call->head.select_id = g_DRW_select_id; #endif - - if (obmat != NULL) { - copy_m4_m4(call->obmat, obmat); - } - else { - unit_m4(call->obmat); - } - call->geometry_fn = geometry_fn; call->user_data = user_data; + drw_call_set_matrices(&call->head, obmat, NULL); + CALL_PREPEND(shgroup, call); } static void sculpt_draw_cb( @@ -1254,12 +1370,12 @@ void DRW_shgroup_uniform_ivec3(DRWShadingGroup *shgroup, const char *name, const void DRW_shgroup_uniform_mat3(DRWShadingGroup *shgroup, const char *name, const float *value) { - drw_interface_uniform(shgroup, name, DRW_UNIFORM_MAT3, value, 9, 1); + drw_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 9, 1); } void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const float *value) { - drw_interface_uniform(shgroup, name, DRW_UNIFORM_MAT4, value, 16, 1); + drw_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 16, 1); } /** \} */ @@ -1325,9 +1441,9 @@ static int pass_shgroup_dist_sort(void *thunk, const void *a, const void *b) if (call_b == NULL) return -1; float tmp[3]; - sub_v3_v3v3(tmp, zsortdata->origin, call_a->obmat[3]); + sub_v3_v3v3(tmp, zsortdata->origin, call_a->head.model[3]); const float a_sq = dot_v3v3(zsortdata->axis, tmp); - sub_v3_v3v3(tmp, zsortdata->origin, call_b->obmat[3]); + sub_v3_v3v3(tmp, zsortdata->origin, call_b->head.model[3]); const float b_sq = dot_v3v3(zsortdata->axis, tmp); if (a_sq < b_sq) return 1; @@ -1362,11 +1478,8 @@ static int pass_shgroup_dist_sort(void *thunk, const void *a, const void *b) **/ void DRW_pass_sort_shgroup_z(DRWPass *pass) { - RegionView3D *rv3d = DST.draw_ctx.rv3d; - float (*viewinv)[4]; - viewinv = (viewport_matrix_override.override[DRW_MAT_VIEWINV]) - ? viewport_matrix_override.mat[DRW_MAT_VIEWINV] : rv3d->viewinv; + viewinv = viewport_matrices.mat[DRW_MAT_VIEWINV]; ZSortData zsortdata = {viewinv[2], viewinv[3]}; @@ -1668,116 +1781,77 @@ typedef struct DRWBoundTexture { GPUTexture *tex; } DRWBoundTexture; -static void draw_geometry_prepare( - DRWShadingGroup *shgroup, const float (*obmat)[4], const float *texcoloc, const float *texcosize) +static void draw_matrices_model_prepare(DRWCallHeader *ch) { - RegionView3D *rv3d = DST.draw_ctx.rv3d; - 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}}; - float eye[3] = { 0.0f, 0.0f, 1.0f }; /* looking into the screen */ - float viewcamtexcofac[4] = { 1.0f, 1.0f, 0.0f, 0.0f }; - - if (rv3d != NULL) { - copy_v4_v4(viewcamtexcofac, rv3d->viewcamtexcofac); - } - - bool do_pi = (interface->projectioninverse != -1); - bool do_mvp = (interface->modelviewprojection != -1); - bool do_mi = (interface->modelinverse != -1); - bool do_mv = (interface->modelview != -1); - bool do_mvi = (interface->modelviewinverse != -1); - bool do_n = (interface->normal != -1); - bool do_wn = (interface->worldnormal != -1); - bool do_eye = (interface->eye != -1); - bool do_orco = (interface->orcotexfac != -1) && (texcoloc != NULL) && (texcosize != NULL); - - /* Matrix override */ - float (*persmat)[4]; - float (*persinv)[4]; - float (*viewmat)[4]; - float (*viewinv)[4]; - float (*winmat)[4]; - float (*wininv)[4]; - - persmat = (viewport_matrix_override.override[DRW_MAT_PERS]) - ? viewport_matrix_override.mat[DRW_MAT_PERS] : rv3d->persmat; - persinv = (viewport_matrix_override.override[DRW_MAT_PERSINV]) - ? viewport_matrix_override.mat[DRW_MAT_PERSINV] : rv3d->persinv; - viewmat = (viewport_matrix_override.override[DRW_MAT_VIEW]) - ? viewport_matrix_override.mat[DRW_MAT_VIEW] : rv3d->viewmat; - viewinv = (viewport_matrix_override.override[DRW_MAT_VIEWINV]) - ? viewport_matrix_override.mat[DRW_MAT_VIEWINV] : rv3d->viewinv; - winmat = (viewport_matrix_override.override[DRW_MAT_WIN]) - ? viewport_matrix_override.mat[DRW_MAT_WIN] : rv3d->winmat; - wininv = viewport_matrix_override.mat[DRW_MAT_WININV]; - - if (do_pi) { - if (!viewport_matrix_override.override[DRW_MAT_WININV]) { - invert_m4_m4(pi, winmat); - wininv = pi; - } - } - if (do_mi) { - invert_m4_m4(mi, obmat); - } - if (do_mvp) { - mul_m4_m4m4(mvp, persmat, obmat); - } - if (do_mv || do_mvi || do_n || do_eye) { - mul_m4_m4m4(mv, viewmat, obmat); + /* OPTI : We can optimize further by sharing this computation for each call using the same object. */ + /* Order matters */ + if (ch->matflag & (DRW_CALL_MODELVIEW | DRW_CALL_MODELVIEWINVERSE | + DRW_CALL_NORMALVIEW | DRW_CALL_EYEVEC)) + { + mul_m4_m4m4(ch->modelview, viewport_matrices.mat[DRW_MAT_VIEW], ch->model); } - if (do_mvi) { - invert_m4_m4(mvi, mv); + if (ch->matflag & DRW_CALL_MODELVIEWINVERSE) { + invert_m4_m4(ch->modelviewinverse, ch->modelview); } - if (do_n || do_eye) { - copy_m3_m4(n, mv); - invert_m3(n); - transpose_m3(n); + if (ch->matflag & DRW_CALL_MODELVIEWPROJECTION) { + mul_m4_m4m4(ch->modelviewprojection, viewport_matrices.mat[DRW_MAT_PERS], ch->model); } - if (do_wn) { - copy_m3_m4(wn, obmat); - invert_m3(wn); - transpose_m3(wn); + if (ch->matflag & DRW_CALL_NORMALVIEW) { + copy_m3_m4(ch->normalview, ch->modelview); + invert_m3(ch->normalview); + transpose_m3(ch->normalview); } - if (do_eye) { + if (ch->matflag & DRW_CALL_EYEVEC) { /* Used by orthographic wires */ float tmp[3][3]; - invert_m3_m3(tmp, n); + copy_v3_fl3(ch->eyevec, 0.0f, 0.0f, 1.0f); + invert_m3_m3(tmp, ch->normalview); /* set eye vector, transformed to object coords */ - mul_m3_v3(tmp, eye); + mul_m3_v3(tmp, ch->eyevec); + } + /* Non view dependant */ + if (ch->matflag & DRW_CALL_MODELINVERSE) { + invert_m4_m4(ch->modelinverse, ch->model); + ch->matflag &= ~DRW_CALL_MODELINVERSE; } - if (do_orco) { - mul_v3_v3fl(orcofacs[1], texcosize, 2.0f); - invert_v3(orcofacs[1]); - sub_v3_v3v3(orcofacs[0], texcoloc, texcosize); - negate_v3(orcofacs[0]); - mul_v3_v3(orcofacs[0], orcofacs[1]); /* result in a nice MADD in the shader */ + if (ch->matflag & DRW_CALL_NORMALWORLD) { + copy_m3_m4(ch->normalworld, ch->model); + invert_m3(ch->normalworld); + transpose_m3(ch->normalworld); + ch->matflag &= ~DRW_CALL_NORMALWORLD; } +} + +static void draw_geometry_prepare(DRWShadingGroup *shgroup, DRWCallHeader *head) +{ + DRWInterface *interface = &shgroup->interface; - /* Should be really simple */ /* step 1 : bind object dependent matrices */ - /* TODO : Some of these are not object dependant. - * They should be grouped inside a UBO updated once per redraw. - * The rest can also go into a UBO to reduce API calls. */ - GPU_shader_uniform_vector(shgroup->shader, interface->model, 16, 1, (float *)obmat); - GPU_shader_uniform_vector(shgroup->shader, interface->modelinverse, 16, 1, (float *)mi); - GPU_shader_uniform_vector(shgroup->shader, interface->modelviewprojection, 16, 1, (float *)mvp); - GPU_shader_uniform_vector(shgroup->shader, interface->viewinverse, 16, 1, (float *)viewinv); - GPU_shader_uniform_vector(shgroup->shader, interface->viewprojection, 16, 1, (float *)persmat); - GPU_shader_uniform_vector(shgroup->shader, interface->viewprojectioninverse, 16, 1, (float *)persinv); - GPU_shader_uniform_vector(shgroup->shader, interface->projection, 16, 1, (float *)winmat); - GPU_shader_uniform_vector(shgroup->shader, interface->projectioninverse, 16, 1, (float *)wininv); - GPU_shader_uniform_vector(shgroup->shader, interface->view, 16, 1, (float *)viewmat); - GPU_shader_uniform_vector(shgroup->shader, interface->modelview, 16, 1, (float *)mv); - GPU_shader_uniform_vector(shgroup->shader, interface->modelviewinverse, 16, 1, (float *)mvi); - GPU_shader_uniform_vector(shgroup->shader, interface->normal, 9, 1, (float *)n); - GPU_shader_uniform_vector(shgroup->shader, interface->worldnormal, 9, 1, (float *)wn); - GPU_shader_uniform_vector(shgroup->shader, interface->camtexfac, 4, 1, (float *)viewcamtexcofac); - GPU_shader_uniform_vector(shgroup->shader, interface->orcotexfac, 3, 2, (float *)orcofacs); - GPU_shader_uniform_vector(shgroup->shader, interface->eye, 3, 1, (float *)eye); - GPU_shader_uniform_vector(shgroup->shader, interface->clipplanes, 4, DST.num_clip_planes, (float *)DST.clip_planes_eq); + if (head != NULL) { + /* OPTI/IDEA(clem): Do this preparation in another thread. */ + draw_matrices_model_prepare(head); + GPU_shader_uniform_vector(shgroup->shader, interface->model, 16, 1, (float *)head->model); + GPU_shader_uniform_vector(shgroup->shader, interface->modelinverse, 16, 1, (float *)head->modelinverse); + GPU_shader_uniform_vector(shgroup->shader, interface->modelview, 16, 1, (float *)head->modelview); + GPU_shader_uniform_vector(shgroup->shader, interface->modelviewinverse, 16, 1, (float *)head->modelviewinverse); + GPU_shader_uniform_vector(shgroup->shader, interface->modelviewprojection, 16, 1, (float *)head->modelviewprojection); + GPU_shader_uniform_vector(shgroup->shader, interface->normalview, 9, 1, (float *)head->normalview); + GPU_shader_uniform_vector(shgroup->shader, interface->normalworld, 9, 1, (float *)head->normalworld); + GPU_shader_uniform_vector(shgroup->shader, interface->orcotexfac, 3, 2, (float *)head->orcotexfac); + GPU_shader_uniform_vector(shgroup->shader, interface->eye, 3, 1, (float *)head->eyevec); + } + else { + BLI_assert((interface->normalview == -1) && (interface->normalworld == -1) && (interface->eye == -1)); + /* For instancing and batching. */ + float unitmat[4][4]; + unit_m4(unitmat); + GPU_shader_uniform_vector(shgroup->shader, interface->model, 16, 1, (float *)unitmat); + GPU_shader_uniform_vector(shgroup->shader, interface->modelinverse, 16, 1, (float *)unitmat); + GPU_shader_uniform_vector(shgroup->shader, interface->modelview, 16, 1, (float *)viewport_matrices.mat[DRW_MAT_VIEW]); + GPU_shader_uniform_vector(shgroup->shader, interface->modelviewinverse, 16, 1, (float *)viewport_matrices.mat[DRW_MAT_VIEWINV]); + GPU_shader_uniform_vector(shgroup->shader, interface->modelviewprojection, 16, 1, (float *)viewport_matrices.mat[DRW_MAT_PERS]); + GPU_shader_uniform_vector(shgroup->shader, interface->orcotexfac, 3, 2, (float *)shgroup->instance_orcofac); + } } static void draw_geometry_execute_ex( @@ -1809,45 +1883,6 @@ 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; - - if (ob_data != NULL) { - switch (GS(ob_data->name)) { - case ID_ME: - BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, NULL, &texcosize); - break; - case ID_CU: - { - Curve *cu = (Curve *)ob_data; - if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) { - BKE_curve_texspace_calc(cu); - } - texcoloc = cu->loc; - texcosize = cu->size; - break; - } - case ID_MB: - { - MetaBall *mb = (MetaBall *)ob_data; - texcoloc = mb->loc; - texcosize = mb->size; - break; - } - default: - break; - } - } - - draw_geometry_prepare(shgroup, obmat, texcoloc, texcosize); - - draw_geometry_execute_ex(shgroup, geom, start, count); -} - static void bind_texture(GPUTexture *tex) { int bind_num = GPU_texture_bound_number(tex); @@ -1939,8 +1974,6 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) shgroup->shader, uni->location, uni->length, uni->arraysize, (int *)uni->value); break; case DRW_UNIFORM_FLOAT: - case DRW_UNIFORM_MAT3: - case DRW_UNIFORM_MAT4: GPU_shader_uniform_vector( shgroup->shader, uni->location, uni->length, uni->arraysize, (float *)uni->value); break; @@ -2012,24 +2045,27 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) /* Rendering Calls */ if (!ELEM(shgroup->type, DRW_SHG_NORMAL)) { /* Replacing multiple calls with only one */ - float obmat[4][4]; - unit_m4(obmat); - if (ELEM(shgroup->type, DRW_SHG_INSTANCE, DRW_SHG_INSTANCE_EXTERNAL)) { if (shgroup->type == DRW_SHG_INSTANCE_EXTERNAL) { if (shgroup->instancing_geom != NULL) { - GPU_SELECT_LOAD_IF_PICKSEL((DRWCall *)shgroup->calls_first); - draw_geometry(shgroup, shgroup->instancing_geom, obmat, shgroup->instance_data, 0, 0); + unsigned int count, start; + draw_geometry_prepare(shgroup, NULL); + /* This will only load override_selectid */ + GPU_SELECT_LOAD_IF_PICKSEL_LIST(shgroup, start, count) + { + draw_geometry_execute(shgroup, shgroup->instancing_geom); + } + GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count) } } else { if (shgroup->interface.instance_count > 0) { unsigned int count, start; + Gwn_Batch *geom = (shgroup->instancing_geom) ? shgroup->instancing_geom : shgroup->instance_geom; + draw_geometry_prepare(shgroup, NULL); GPU_SELECT_LOAD_IF_PICKSEL_LIST(shgroup, start, count) { - draw_geometry(shgroup, - (shgroup->instancing_geom) ? shgroup->instancing_geom : shgroup->instance_geom, - obmat, shgroup->instance_data, start, count); + draw_geometry_execute_ex(shgroup, geom, start, count); } GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count) } @@ -2039,40 +2075,43 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) /* Some dynamic batch can have no geom (no call to aggregate) */ if (shgroup->interface.instance_count > 0) { unsigned int count, start; + draw_geometry_prepare(shgroup, NULL); GPU_SELECT_LOAD_IF_PICKSEL_LIST(shgroup, start, count) { - draw_geometry(shgroup, shgroup->batch_geom, obmat, NULL, start, count); + draw_geometry_execute_ex(shgroup, shgroup->batch_geom, start, count); } GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count) } } } else { + bool prev_neg_scale = false; for (DRWCall *call = shgroup->calls_first; call; call = call->head.prev) { - bool neg_scale = is_negative_m4(call->obmat); + if ((call->head.state & DRW_CALL_CULLED) != 0) + continue; /* Negative scale objects */ - if (neg_scale) { - glFrontFace(DST.backface); + bool neg_scale = call->head.state & DRW_CALL_NEGSCALE; + if (neg_scale != prev_neg_scale) { + glFrontFace((neg_scale) ? DST.backface : DST.frontface); + prev_neg_scale = neg_scale; } GPU_SELECT_LOAD_IF_PICKSEL(call); if (call->head.type == DRW_CALL_SINGLE) { - draw_geometry(shgroup, call->geometry, call->obmat, call->ob_data, 0, 0); + draw_geometry_prepare(shgroup, &call->head); + draw_geometry_execute(shgroup, call->geometry); } else { BLI_assert(call->head.type == DRW_CALL_GENERATE); DRWCallGenerate *callgen = ((DRWCallGenerate *)call); - draw_geometry_prepare(shgroup, callgen->obmat, NULL, NULL); + draw_geometry_prepare(shgroup, &callgen->head); callgen->geometry_fn(shgroup, draw_geometry_execute, callgen->user_data); } - - /* Reset state */ - if (neg_scale) { - glFrontFace(DST.frontface); - } } + /* Reset state */ + glFrontFace(DST.frontface); } /* TODO: remove, (currently causes alpha issue with sculpt, need to investigate) */ @@ -2170,6 +2209,7 @@ void DRW_state_invert_facing(void) **/ void DRW_state_clip_planes_add(float plane_eq[4]) { + BLI_assert(DST.num_clip_planes < MAX_CLIP_PLANES-1); copy_v4_v4(DST.clip_planes_eq[DST.num_clip_planes++], plane_eq); } @@ -2665,6 +2705,20 @@ static void drw_viewport_var_init(void) /* Refresh DST.pixelsize */ DST.pixsize = rv3d->pixsize; + + copy_m4_m4(viewport_matrices.original_mat[DRW_MAT_PERS], rv3d->persmat); + copy_m4_m4(viewport_matrices.original_mat[DRW_MAT_PERSINV], rv3d->persinv); + copy_m4_m4(viewport_matrices.original_mat[DRW_MAT_VIEW], rv3d->viewmat); + copy_m4_m4(viewport_matrices.original_mat[DRW_MAT_VIEWINV], rv3d->viewinv); + copy_m4_m4(viewport_matrices.original_mat[DRW_MAT_WIN], rv3d->winmat); + invert_m4_m4(viewport_matrices.original_mat[DRW_MAT_WININV], rv3d->winmat); + + memcpy(viewport_matrices.mat, viewport_matrices.original_mat, sizeof(viewport_matrices.mat)); + + copy_v4_v4(viewcamtexcofac, rv3d->viewcamtexcofac); + } + else { + copy_v4_fl4(viewcamtexcofac, 1.0f, 1.0f, 0.0f, 0.0f); } /* Reset facing */ @@ -2684,55 +2738,28 @@ static void drw_viewport_var_init(void) RST.bound_tex_slots = MEM_callocN(sizeof(bool) * GPU_max_textures(), "Bound Texture Slots"); } - memset(viewport_matrix_override.override, 0x0, sizeof(viewport_matrix_override.override)); + memset(viewport_matrices.override, 0x0, sizeof(viewport_matrices.override)); memset(DST.common_instance_data, 0x0, sizeof(DST.common_instance_data)); } void DRW_viewport_matrix_get(float mat[4][4], DRWViewportMatrixType type) { - RegionView3D *rv3d = DST.draw_ctx.rv3d; BLI_assert(type >= DRW_MAT_PERS && type <= DRW_MAT_WININV); + BLI_assert(viewport_matrices.override[type] || DST.draw_ctx.rv3d != NULL); /* Can't use this in render mode. */ - if (viewport_matrix_override.override[type]) { - copy_m4_m4(mat, viewport_matrix_override.mat[type]); - } - else { - BLI_assert(rv3d != NULL); /* Can't use this in render mode. */ - switch (type) { - case DRW_MAT_PERS: - copy_m4_m4(mat, rv3d->persmat); - break; - case DRW_MAT_PERSINV: - copy_m4_m4(mat, rv3d->persinv); - break; - case DRW_MAT_VIEW: - copy_m4_m4(mat, rv3d->viewmat); - break; - case DRW_MAT_VIEWINV: - copy_m4_m4(mat, rv3d->viewinv); - break; - case DRW_MAT_WIN: - copy_m4_m4(mat, rv3d->winmat); - break; - case DRW_MAT_WININV: - invert_m4_m4(mat, rv3d->winmat); - break; - default: - BLI_assert(!"Matrix type invalid"); - break; - } - } + copy_m4_m4(mat, viewport_matrices.mat[type]); } void DRW_viewport_matrix_override_set(float mat[4][4], DRWViewportMatrixType type) { - copy_m4_m4(viewport_matrix_override.mat[type], mat); - viewport_matrix_override.override[type] = true; + copy_m4_m4(viewport_matrices.mat[type], mat); + viewport_matrices.override[type] = true; } void DRW_viewport_matrix_override_unset(DRWViewportMatrixType type) { - viewport_matrix_override.override[type] = false; + copy_m4_m4(viewport_matrices.mat[type], viewport_matrices.original_mat[type]); + viewport_matrices.override[type] = false; } bool DRW_viewport_is_persp_get(void) @@ -2742,9 +2769,7 @@ bool DRW_viewport_is_persp_get(void) return rv3d->is_persp; } else { - if (viewport_matrix_override.override[DRW_MAT_WIN]) { - return viewport_matrix_override.mat[DRW_MAT_WIN][3][3] == 0.0f; - } + return viewport_matrices.mat[DRW_MAT_WIN][3][3] == 0.0f; } BLI_assert(0); return false; |