Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2018-02-27 01:39:09 +0300
committerClément Foucault <foucault.clem@gmail.com>2018-02-27 16:50:16 +0300
commitec0ecbe795200f9f7e3a8c0154f4e37d8be9527e (patch)
tree420365450e8a96cc178402a3e017547d39675d00
parentfe80d8ec3c459500258c33d2058558658f1df4f2 (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.c631
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;