Mesh Batch Cache: get rid of the ORCO VBO data, and reconstruct it in shader.

With only one MADD instruction we recover the orco data and reduce both the storage and the fetching cost of an attrib layer.
This commit is contained in:
Clément Foucault 2017-05-15 16:12:51 +02:00
parent ae9da3786a
commit e053fade99
8 changed files with 86 additions and 54 deletions

View File

@ -151,6 +151,7 @@ MINLINE void negate_v3_short(short r[3]);
MINLINE void negate_v3_db(double r[3]);
MINLINE void invert_v2(float r[2]);
MINLINE void invert_v3(float r[3]);
MINLINE void abs_v2(float r[2]);
MINLINE void abs_v2_v2(float r[2], const float a[2]);

View File

@ -658,6 +658,14 @@ MINLINE void invert_v2(float r[2])
r[1] = 1.0f / r[1];
}
MINLINE void invert_v3(float r[3])
{
BLI_assert(!ELEM(0.0f, r[0], r[1], r[2]));
r[0] = 1.0f / r[0];
r[1] = 1.0f / r[1];
r[2] = 1.0f / r[2];
}
MINLINE void abs_v2(float r[2])
{
r[0] = fabsf(r[0]);

View File

@ -564,7 +564,7 @@ static void EEVEE_cache_populate(void *vedata, Object *ob)
DRW_shgroup_call_sculpt_add((do_cull) ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp, ob, ob->obmat);
}
else {
DRW_shgroup_call_add((do_cull) ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp, geom, ob->obmat);
DRW_shgroup_call_object_add((do_cull) ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp, geom, ob);
}
/* Get per-material split surface */
@ -605,7 +605,7 @@ static void EEVEE_cache_populate(void *vedata, Object *ob)
DRW_shgroup_call_sculpt_add(shgrp, ob, ob->obmat);
}
else {
DRW_shgroup_call_add(shgrp, mat_geom[i], ob->obmat);
DRW_shgroup_call_object_add(shgrp, mat_geom[i], ob);
}
}
else {
@ -625,7 +625,7 @@ static void EEVEE_cache_populate(void *vedata, Object *ob)
DRW_shgroup_call_sculpt_add(shgrp, ob, ob->obmat);
}
else {
DRW_shgroup_call_add(shgrp, mat_geom[i], ob->obmat);
DRW_shgroup_call_object_add(shgrp, mat_geom[i], ob);
}
}
}
@ -642,7 +642,7 @@ static void EEVEE_cache_populate(void *vedata, Object *ob)
DRW_shgroup_call_sculpt_add(shgrp, ob, ob->obmat);
}
else {
DRW_shgroup_call_add(shgrp, mat_geom[i], ob->obmat);
DRW_shgroup_call_object_add(shgrp, mat_geom[i], ob);
}
}
}

View File

@ -23,6 +23,6 @@ void main() {
worldNormal = normalize(WorldNormalMatrix * nor);
#ifdef ATTRIB
pass_attrib();
pass_attrib(pos);
#endif
}

View File

@ -271,6 +271,7 @@ typedef void (DRWCallGenerateFn)(
void DRW_shgroup_free(struct DRWShadingGroup *shgroup);
void DRW_shgroup_call_add(DRWShadingGroup *shgroup, struct Batch *geom, float (*obmat)[4]);
void DRW_shgroup_call_object_add(DRWShadingGroup *shgroup, struct Batch *geom, struct Object *ob);
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]);

View File

@ -1167,25 +1167,6 @@ static void mesh_render_data_looptri_tans_get(
}
}
static void mesh_render_data_looptri_orcos_get(
MeshRenderData *rdata, const int tri_idx,
float *(*r_vert_orcos)[3])
{
BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_SHADING));
if (rdata->edit_bmesh) {
const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[tri_idx];
(*r_vert_orcos)[0] = rdata->orco[BM_elem_index_get(bm_looptri[0]->v)];
(*r_vert_orcos)[1] = rdata->orco[BM_elem_index_get(bm_looptri[1]->v)];
(*r_vert_orcos)[2] = rdata->orco[BM_elem_index_get(bm_looptri[2]->v)];
}
else {
const MLoopTri *mlt = &rdata->mlooptri[tri_idx];
(*r_vert_orcos)[0] = rdata->orco[rdata->mloop[mlt->tri[0]].v];
(*r_vert_orcos)[1] = rdata->orco[rdata->mloop[mlt->tri[1]].v];
(*r_vert_orcos)[2] = rdata->orco[rdata->mloop[mlt->tri[2]].v];
}
}
static bool mesh_render_data_looptri_cos_nors_smooth_get(
MeshRenderData *rdata, const int tri_idx,
float *(*r_vert_cos)[3], short **r_tri_nor, short *(*r_vert_nors)[3], bool *r_is_smooth)
@ -1926,16 +1907,15 @@ static VertexBuffer *mesh_batch_cache_get_tri_shading_data(MeshRenderData *rdata
unsigned int vidx = 0;
const char *attrib_name;
if (rdata->uv_len + rdata->vcol_len == 0) {
return NULL;
}
VertexFormat *format = &cache->shaded_triangles_format;
VertexFormat_clear(format);
/* initialize vertex format */
#ifdef USE_COMP_MESH_DATA
unsigned int orco_id = VertexFormat_add_attrib(format, "orco", COMP_I16, 3, NORMALIZE_INT_TO_FLOAT);
#else
unsigned int orco_id = VertexFormat_add_attrib(format, "orco", COMP_F32, 3, KEEP_FLOAT);
#endif
unsigned int *uv_id = MEM_mallocN(sizeof(*uv_id) * rdata->uv_len, "UV attrib format");
unsigned int *vcol_id = MEM_mallocN(sizeof(*vcol_id) * rdata->vcol_len, "Vcol attrib format");
unsigned int *tangent_id = MEM_mallocN(sizeof(*tangent_id) * rdata->uv_len, "Tangent attrib format");
@ -1999,7 +1979,7 @@ static VertexBuffer *mesh_batch_cache_get_tri_shading_data(MeshRenderData *rdata
/* TODO deduplicate all verts and make use of ElementList in mesh_batch_cache_get_shaded_triangles_in_order. */
for (int i = 0; i < tri_len; i++) {
float *tri_uvs[3], *tri_tans[3], *tri_orcos[3];
float *tri_uvs[3], *tri_tans[3];
unsigned char *tri_cols[3];
if (rdata->edit_bmesh == NULL ||
@ -2052,19 +2032,7 @@ static VertexBuffer *mesh_batch_cache_get_tri_shading_data(MeshRenderData *rdata
VertexBuffer_set_attrib(vbo, vcol_id[j], vidx + 2, tri_cols[2]);
}
/* ORCO */
mesh_render_data_looptri_orcos_get(rdata, i, &tri_orcos);
#ifdef USE_COMP_MESH_DATA
short s_orco[3][3];
normal_float_to_short_v3(s_orco[0], tri_orcos[0]);
normal_float_to_short_v3(s_orco[1], tri_orcos[1]);
normal_float_to_short_v3(s_orco[2], tri_orcos[2]);
#else
float **s_orco = tri_orcos;
#endif
VertexBuffer_set_attrib(vbo, orco_id, vidx++, s_orco[0]);
VertexBuffer_set_attrib(vbo, orco_id, vidx++, s_orco[1]);
VertexBuffer_set_attrib(vbo, orco_id, vidx++, s_orco[2]);
vidx += 3;
}
}
vbo_len_used = vidx;
@ -3298,8 +3266,11 @@ Batch **DRW_mesh_batch_cache_get_surface_shaded(Mesh *me)
VertexBuffer *vbo = mesh_batch_cache_get_tri_pos_and_normals(rdata, cache);
for (int i = 0; i < mat_len; ++i) {
cache->shaded_triangles[i] = Batch_create(
PRIM_TRIANGLES, mesh_batch_cache_get_tri_shading_data(rdata, cache), el[i]);
Batch_add_VertexBuffer(cache->shaded_triangles[i], vbo);
PRIM_TRIANGLES, vbo, el[i]);
VertexBuffer *vbo_shading = mesh_batch_cache_get_tri_shading_data(rdata, cache);
if (vbo_shading) {
Batch_add_VertexBuffer(cache->shaded_triangles[i], vbo_shading);
}
}

View File

@ -34,6 +34,7 @@
#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_object.h"
#include "BKE_pbvh.h"
#include "BKE_paint.h"
@ -166,6 +167,7 @@ struct DRWInterface {
int normal;
int worldnormal;
int camtexfac;
int orcotexfac;
int eye;
/* Textures */
int tex_bind; /* next texture binding point */
@ -197,6 +199,8 @@ typedef struct DRWCall {
int type;
float (*obmat)[4];
Batch *geometry;
Object *ob; /* Optionnal */
} DRWCall;
typedef struct DRWCallGenerate {
@ -559,6 +563,7 @@ static DRWInterface *DRW_interface_create(GPUShader *shader)
interface->normal = GPU_shader_get_uniform(shader, "NormalMatrix");
interface->worldnormal = GPU_shader_get_uniform(shader, "WorldNormalMatrix");
interface->camtexfac = GPU_shader_get_uniform(shader, "CameraTexCoFactors");
interface->orcotexfac = GPU_shader_get_uniform(shader, "OrcoTexCoFactors[0]");
interface->eye = GPU_shader_get_uniform(shader, "eye");
interface->instance_count = 0;
interface->attribs_count = 0;
@ -821,6 +826,24 @@ void DRW_shgroup_call_add(DRWShadingGroup *shgroup, Batch *geom, float (*obmat)[
BLI_addtail(&shgroup->calls, call);
}
void DRW_shgroup_call_object_add(DRWShadingGroup *shgroup, Batch *geom, Object *ob)
{
BLI_assert(geom != NULL);
DRWCall *call = MEM_callocN(sizeof(DRWCall), "DRWCall");
call->type = DRW_CALL_SINGLE;
call->obmat = ob->obmat;
call->geometry = geom;
call->ob = ob;
#ifdef USE_GPU_SELECT
call->select_id = g_DRW_select_id;
#endif
BLI_addtail(&shgroup->calls, call);
}
void DRW_shgroup_call_generate_add(
DRWShadingGroup *shgroup,
DRWCallGenerateFn *geometry_fn, void *user_data,
@ -1418,12 +1441,14 @@ typedef struct DRWBoundTexture {
GPUTexture *tex;
} DRWBoundTexture;
static void draw_geometry_prepare(DRWShadingGroup *shgroup, const float (*obmat)[4])
static void draw_geometry_prepare(
DRWShadingGroup *shgroup, const float (*obmat)[4], const float *texcoloc, const float *texcosize)
{
RegionView3D *rv3d = DST.draw_ctx.rv3d;
DRWInterface *interface = shgroup->interface;
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 */
bool do_pi = (interface->projectioninverse != -1);
@ -1434,6 +1459,7 @@ static void draw_geometry_prepare(DRWShadingGroup *shgroup, const float (*obmat)
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);
if (do_pi) {
invert_m4_m4(pi, rv3d->winmat);
@ -1467,6 +1493,13 @@ static void draw_geometry_prepare(DRWShadingGroup *shgroup, const float (*obmat)
/* set eye vector, transformed to object coords */
mul_m3_v3(tmp, eye);
}
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 */
}
/* Should be really simple */
/* step 1 : bind object dependent matrices */
@ -1512,6 +1545,9 @@ static void draw_geometry_prepare(DRWShadingGroup *shgroup, const float (*obmat)
if (interface->camtexfac != -1) {
GPU_shader_uniform_vector(shgroup->shader, interface->camtexfac, 4, 1, (float *)rv3d->viewcamtexcofac);
}
if (interface->orcotexfac != -1) {
GPU_shader_uniform_vector(shgroup->shader, interface->orcotexfac, 3, 2, (float *)orcofacs);
}
if (interface->eye != -1) {
GPU_shader_uniform_vector(shgroup->shader, interface->eye, 3, 1, (float *)eye);
}
@ -1531,9 +1567,16 @@ static void draw_geometry_execute(DRWShadingGroup *shgroup, Batch *geom)
}
}
static void draw_geometry(DRWShadingGroup *shgroup, Batch *geom, const float (*obmat)[4])
static void draw_geometry(DRWShadingGroup *shgroup, Batch *geom, const float (*obmat)[4], Object *ob)
{
draw_geometry_prepare(shgroup, obmat);
float *texcoloc = NULL;
float *texcosize = NULL;
if (ob != NULL) {
BKE_object_obdata_texspace_get(ob, NULL, &texcoloc, &texcosize, NULL);
}
draw_geometry_prepare(shgroup, obmat, texcoloc, texcosize);
draw_geometry_execute(shgroup, geom);
}
@ -1637,13 +1680,13 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
if (shgroup->type == DRW_SHG_INSTANCE && interface->instance_count > 0) {
GPU_SELECT_LOAD_IF_PICKSEL_LIST(&shgroup->calls);
draw_geometry(shgroup, shgroup->instance_geom, obmat);
draw_geometry(shgroup, shgroup->instance_geom, obmat, NULL);
}
else {
/* Some dynamic batch can have no geom (no call to aggregate) */
if (shgroup->batch_geom) {
GPU_SELECT_LOAD_IF_PICKSEL_LIST(&shgroup->calls);
draw_geometry(shgroup, shgroup->batch_geom, obmat);
draw_geometry(shgroup, shgroup->batch_geom, obmat, NULL);
}
}
}
@ -1659,11 +1702,11 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
GPU_SELECT_LOAD_IF_PICKSEL(call);
if (call->type == DRW_CALL_SINGLE) {
draw_geometry(shgroup, call->geometry, call->obmat);
draw_geometry(shgroup, call->geometry, call->obmat, call->ob);
}
else {
DRWCallGenerate *callgen = ((DRWCallGenerate *)call);
draw_geometry_prepare(shgroup, callgen->obmat);
draw_geometry_prepare(shgroup, callgen->obmat, NULL, NULL);
callgen->geometry_fn(shgroup, draw_geometry_execute, callgen->user_data);
}

View File

@ -787,7 +787,11 @@ static char *code_generate_vertex_new(ListBase *nodes, const char *vert_code)
if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
/* XXX FIXME : see notes in mesh_render_data_create() */
/* NOTE : Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */
if (input->attribname[0] == '\0') {
if (input->attribtype == CD_ORCO) {
/* orco is computed from local positions, see bellow */
BLI_dynstr_appendf(ds, "uniform vec3 OrcoTexCoFactors[2];\n");
}
else if (input->attribname[0] == '\0') {
BLI_dynstr_appendf(ds, "in %s %s;\n", GPU_DATATYPE_STR[input->type], attrib_prefix_get(input->attribtype));
BLI_dynstr_appendf(ds, "#define att%d %s\n", input->attribid, attrib_prefix_get(input->attribtype));
}
@ -808,7 +812,7 @@ static char *code_generate_vertex_new(ListBase *nodes, const char *vert_code)
BLI_dynstr_append(ds, "#define ATTRIB\n");
BLI_dynstr_append(ds, "uniform mat3 NormalMatrix;\n");
BLI_dynstr_append(ds, "void pass_attrib(void) {\n");
BLI_dynstr_append(ds, "void pass_attrib(in vec3 position) {\n");
for (node = nodes->first; node; node = node->next) {
for (input = node->inputs.first; input; input = input->next) {
@ -821,6 +825,10 @@ static char *code_generate_vertex_new(ListBase *nodes, const char *vert_code)
ds, "\tvar%d.w = att%d.w;\n",
input->attribid, input->attribid);
}
else if (input->attribtype == CD_ORCO) {
BLI_dynstr_appendf(ds, "\tvar%d = OrcoTexCoFactors[0] + position * OrcoTexCoFactors[1];\n",
input->attribid);
}
else {
BLI_dynstr_appendf(ds, "\tvar%d = att%d;\n",
input->attribid, input->attribid);