DwM: optimize mesh batch conversion
authorCampbell Barton <ideasman42@gmail.com>
Thu, 29 Jun 2017 10:11:16 +0000 (20:11 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Thu, 29 Jun 2017 10:11:16 +0000 (20:11 +1000)
- Replace GWN_vertbuf_attr_set with Gwn_VertBufRaw & GWN_vertbuf_raw_step
  to avoid intermediate copy.
- Avoid extra conversion step with: float[3] -> short[3] -> Gwn_PackedNormal.
  We can skip the short[3].

Gives approx 6% speedup here.

source/blender/draw/intern/draw_cache_impl_mesh.c

index 13b94c00dc6a2cd37349104d9d605c2cbca41ccb..6c62cf3b0f6f8cb110c0eb61f55943e8b79afecb 100644 (file)
@@ -190,8 +190,8 @@ typedef struct MeshRenderData {
        float (*poly_normals)[3];
        float (*vert_weight_color)[3];
        char (*vert_color)[3];
-       short (*poly_normals_short)[3];
-       short (*vert_normals_short)[3];
+       Gwn_PackedNormal *poly_normals_pack;
+       Gwn_PackedNormal *vert_normals_pack;
        bool *edge_select_bool;
 } MeshRenderData;
 
@@ -760,8 +760,8 @@ static void mesh_render_data_free(MeshRenderData *rdata)
        MEM_SAFE_FREE(rdata->edges_adjacent_polys);
        MEM_SAFE_FREE(rdata->mlooptri);
        MEM_SAFE_FREE(rdata->poly_normals);
-       MEM_SAFE_FREE(rdata->poly_normals_short);
-       MEM_SAFE_FREE(rdata->vert_normals_short);
+       MEM_SAFE_FREE(rdata->poly_normals_pack);
+       MEM_SAFE_FREE(rdata->vert_normals_pack);
        MEM_SAFE_FREE(rdata->vert_weight_color);
        MEM_SAFE_FREE(rdata->edge_select_bool);
        MEM_SAFE_FREE(rdata->vert_color);
@@ -870,20 +870,20 @@ static int mesh_render_data_polys_len_get(const MeshRenderData *rdata)
 /** \name Internal Cache (Lazy Initialization)
  * \{ */
 
-/** Ensure #MeshRenderData.poly_normals_short */
-static void mesh_render_data_ensure_poly_normals_short(MeshRenderData *rdata)
+/** Ensure #MeshRenderData.poly_normals_pack */
+static void mesh_render_data_ensure_poly_normals_pack(MeshRenderData *rdata)
 {
-       short (*pnors_short)[3] = rdata->poly_normals_short;
-       if (pnors_short == NULL) {
+       Gwn_PackedNormal *pnors_pack = rdata->poly_normals_pack;
+       if (pnors_pack == NULL) {
                if (rdata->edit_bmesh) {
                        BMesh *bm = rdata->edit_bmesh->bm;
                        BMIter fiter;
                        BMFace *efa;
                        int i;
 
-                       pnors_short = rdata->poly_normals_short = MEM_mallocN(sizeof(*pnors_short) * rdata->poly_len, __func__);
+                       pnors_pack = rdata->poly_normals_pack = MEM_mallocN(sizeof(*pnors_pack) * rdata->poly_len, __func__);
                        BM_ITER_MESH_INDEX(efa, &fiter, bm, BM_FACES_OF_MESH, i) {
-                               normal_float_to_short_v3(pnors_short[i], efa->no);
+                               pnors_pack[i] = GWN_normal_convert_i10_v3(efa->no);
                        }
                }
                else {
@@ -896,28 +896,28 @@ static void mesh_render_data_ensure_poly_normals_short(MeshRenderData *rdata)
                                        rdata->mloop, rdata->mpoly, rdata->loop_len, rdata->poly_len, pnors, true);
                        }
 
-                       pnors_short = rdata->poly_normals_short = MEM_mallocN(sizeof(*pnors_short) * rdata->poly_len, __func__);
+                       pnors_pack = rdata->poly_normals_pack = MEM_mallocN(sizeof(*pnors_pack) * rdata->poly_len, __func__);
                        for (int i = 0; i < rdata->poly_len; i++) {
-                               normal_float_to_short_v3(pnors_short[i], pnors[i]);
+                               pnors_pack[i] = GWN_normal_convert_i10_v3(pnors[i]);
                        }
                }
        }
 }
 
-/** Ensure #MeshRenderData.vert_normals_short */
-static void mesh_render_data_ensure_vert_normals_short(MeshRenderData *rdata)
+/** Ensure #MeshRenderData.vert_normals_pack */
+static void mesh_render_data_ensure_vert_normals_pack(MeshRenderData *rdata)
 {
-       short (*vnors_short)[3] = rdata->vert_normals_short;
-       if (vnors_short == NULL) {
+       Gwn_PackedNormal *vnors_pack = rdata->vert_normals_pack;
+       if (vnors_pack == NULL) {
                if (rdata->edit_bmesh) {
                        BMesh *bm = rdata->edit_bmesh->bm;
                        BMIter viter;
                        BMVert *eve;
                        int i;
 
-                       vnors_short = rdata->vert_normals_short = MEM_mallocN(sizeof(*vnors_short) * rdata->vert_len, __func__);
+                       vnors_pack = rdata->vert_normals_pack = MEM_mallocN(sizeof(*vnors_pack) * rdata->vert_len, __func__);
                        BM_ITER_MESH_INDEX(eve, &viter, bm, BM_VERT, i) {
-                               normal_float_to_short_v3(vnors_short[i], eve->no);
+                               vnors_pack[i] = GWN_normal_convert_i10_v3(eve->no);
                        }
                }
                else {
@@ -1268,63 +1268,6 @@ static void mesh_render_data_looptri_tans_get(
        }
 }
 
-static bool mesh_render_data_looptri_cos_nors_smooth_get(
-        MeshRenderData *rdata, const int tri_idx, const bool use_hide,
-        float *(*r_vert_cos)[3], short **r_tri_nor, short *(*r_vert_nors)[3], bool *r_is_smooth)
-{
-       BLI_assert(rdata->types & MR_DATATYPE_VERT);
-       BLI_assert(rdata->types & MR_DATATYPE_LOOPTRI);
-       BLI_assert(rdata->types & MR_DATATYPE_LOOP);
-       BLI_assert(rdata->types & MR_DATATYPE_POLY);
-
-       if (rdata->edit_bmesh) {
-               const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[tri_idx];
-
-               /* Assume 'use_hide' */
-               if (BM_elem_flag_test(bm_looptri[0]->f, BM_ELEM_HIDDEN)) {
-                       return false;
-               }
-
-               mesh_render_data_ensure_poly_normals_short(rdata);
-               mesh_render_data_ensure_vert_normals_short(rdata);
-
-               short (*pnors_short)[3] = rdata->poly_normals_short;
-               short (*vnors_short)[3] = rdata->vert_normals_short;
-
-               (*r_vert_cos)[0] = bm_looptri[0]->v->co;
-               (*r_vert_cos)[1] = bm_looptri[1]->v->co;
-               (*r_vert_cos)[2] = bm_looptri[2]->v->co;
-               *r_tri_nor = pnors_short[BM_elem_index_get(bm_looptri[0]->f)];
-               (*r_vert_nors)[0] = vnors_short[BM_elem_index_get(bm_looptri[0]->v)];
-               (*r_vert_nors)[1] = vnors_short[BM_elem_index_get(bm_looptri[1]->v)];
-               (*r_vert_nors)[2] = vnors_short[BM_elem_index_get(bm_looptri[2]->v)];
-
-               *r_is_smooth = BM_elem_flag_test_bool(bm_looptri[0]->f, BM_ELEM_SMOOTH);
-       }
-       else {
-               const MLoopTri *mlt = &rdata->mlooptri[tri_idx];
-
-               if (use_hide && (rdata->mpoly[mlt->poly].flag & ME_HIDE)) {
-                       return false;
-               }
-
-               mesh_render_data_ensure_poly_normals_short(rdata);
-
-               short (*pnors_short)[3] = rdata->poly_normals_short;
-
-               (*r_vert_cos)[0] = rdata->mvert[rdata->mloop[mlt->tri[0]].v].co;
-               (*r_vert_cos)[1] = rdata->mvert[rdata->mloop[mlt->tri[1]].v].co;
-               (*r_vert_cos)[2] = rdata->mvert[rdata->mloop[mlt->tri[2]].v].co;
-               *r_tri_nor = pnors_short[mlt->poly];
-               (*r_vert_nors)[0] = rdata->mvert[rdata->mloop[mlt->tri[0]].v].no;
-               (*r_vert_nors)[1] = rdata->mvert[rdata->mloop[mlt->tri[1]].v].no;
-               (*r_vert_nors)[2] = rdata->mvert[rdata->mloop[mlt->tri[2]].v].no;
-
-               *r_is_smooth = (rdata->mpoly[mlt->poly].flag & ME_SMOOTH) != 0;
-       }
-       return true;
-}
-
 /* First 2 bytes are bit flags
  * 3rd is for sharp edges
  * 4rd is for creased edges */
@@ -1981,8 +1924,6 @@ static Gwn_VertBuf *mesh_batch_cache_get_tri_pos_and_normals_ex(
        BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY));
 
        if (*r_vbo == NULL) {
-               unsigned int vidx = 0, nidx = 0;
-
                static Gwn_VertFormat format = { 0 };
                static struct { uint pos, nor; } attr_id;
                if (format.attrib_ct == 0) {
@@ -1998,41 +1939,90 @@ static Gwn_VertBuf *mesh_batch_cache_get_tri_pos_and_normals_ex(
                int vbo_len_used = 0;
                GWN_vertbuf_data_alloc(vbo, vbo_len_capacity);
 
-               for (int i = 0; i < tri_len; i++) {
-                       float *tri_vert_cos[3];
-                       short *tri_nor, *tri_vert_nors[3];
-                       bool is_smooth;
+               Gwn_VertBufRaw pos_step, nor_step;
+               GWN_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step);
+               GWN_vertbuf_attr_get_raw_data(vbo, attr_id.nor, &nor_step);
 
-                       if (mesh_render_data_looptri_cos_nors_smooth_get(
-                               rdata, i, use_hide, &tri_vert_cos, &tri_nor, &tri_vert_nors, &is_smooth))
-                       {
-                               if (is_smooth) {
-                                       Gwn_PackedNormal snor_pack[3] = {
-                                               GWN_normal_convert_i10_s3(tri_vert_nors[0]),
-                                               GWN_normal_convert_i10_s3(tri_vert_nors[1]),
-                                               GWN_normal_convert_i10_s3(tri_vert_nors[2])
-                                       };
-                                       Gwn_PackedNormal *snor[3] = { &snor_pack[0], &snor_pack[1], &snor_pack[2] };
-
-                                       GWN_vertbuf_attr_set(vbo, attr_id.nor, nidx++, snor[0]);
-                                       GWN_vertbuf_attr_set(vbo, attr_id.nor, nidx++, snor[1]);
-                                       GWN_vertbuf_attr_set(vbo, attr_id.nor, nidx++, snor[2]);
+               if (rdata->edit_bmesh) {
+                       mesh_render_data_ensure_poly_normals_pack(rdata);
+                       mesh_render_data_ensure_vert_normals_pack(rdata);
+
+                       Gwn_PackedNormal *pnors_pack = rdata->poly_normals_pack;
+                       Gwn_PackedNormal *vnors_pack = rdata->vert_normals_pack;
+
+                       for (int i = 0; i < tri_len; i++) {
+                               const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[i];
+                               const BMFace *bm_face = bm_looptri[0]->f;
+
+                               /* use_hide always for edit-mode */
+                               if (BM_elem_flag_test(bm_face, BM_ELEM_HIDDEN)) {
+                                       continue;
+                               }
+
+                               const uint vtri[3] = {
+                                       BM_elem_index_get(bm_looptri[0]->v),
+                                       BM_elem_index_get(bm_looptri[1]->v),
+                                       BM_elem_index_get(bm_looptri[2]->v),
+                               };
+
+                               if (BM_elem_flag_test(bm_face, BM_ELEM_SMOOTH)) {
+                                       for (uint t = 0; t < 3; t++) {
+                                               *((Gwn_PackedNormal *)GWN_vertbuf_raw_step(&nor_step)) = vnors_pack[vtri[t]];
+                                       }
                                }
                                else {
-                                       Gwn_PackedNormal snor_pack = GWN_normal_convert_i10_s3(tri_nor);
-                                       Gwn_PackedNormal *snor = &snor_pack;
+                                       const Gwn_PackedNormal *snor_pack = &pnors_pack[BM_elem_index_get(bm_face)];
+                                       for (uint t = 0; t < 3; t++) {
+                                               *((Gwn_PackedNormal *)GWN_vertbuf_raw_step(&nor_step)) = *snor_pack;
+                                       }
+                               }
 
-                                       GWN_vertbuf_attr_set(vbo, attr_id.nor, nidx++, snor);
-                                       GWN_vertbuf_attr_set(vbo, attr_id.nor, nidx++, snor);
-                                       GWN_vertbuf_attr_set(vbo, attr_id.nor, nidx++, snor);
+                               for (uint t = 0; t < 3; t++) {
+                                       copy_v3_v3(GWN_vertbuf_raw_step(&pos_step), bm_looptri[t]->v->co);
                                }
+                       }
+               }
+               else {
+
+                       /* Use normals from vertex */
+                       mesh_render_data_ensure_poly_normals_pack(rdata);
 
-                               GWN_vertbuf_attr_set(vbo, attr_id.pos, vidx++, tri_vert_cos[0]);
-                               GWN_vertbuf_attr_set(vbo, attr_id.pos, vidx++, tri_vert_cos[1]);
-                               GWN_vertbuf_attr_set(vbo, attr_id.pos, vidx++, tri_vert_cos[2]);
+                       for (int i = 0; i < tri_len; i++) {
+                               const MLoopTri *mlt = &rdata->mlooptri[i];
+                               const MPoly *mp = &rdata->mpoly[mlt->poly];
+
+                               if (use_hide && (mp->flag & ME_HIDE)) {
+                                       continue;
+                               }
+
+                               const uint vtri[3] = {
+                                       rdata->mloop[mlt->tri[0]].v,
+                                       rdata->mloop[mlt->tri[1]].v,
+                                       rdata->mloop[mlt->tri[2]].v,
+                               };
+
+                               if (mp->flag & ME_SMOOTH) {
+                                       for (uint t = 0; t < 3; t++) {
+                                               const MVert *mv = &rdata->mvert[vtri[t]];
+                                               *((Gwn_PackedNormal *)GWN_vertbuf_raw_step(&nor_step)) = GWN_normal_convert_i10_s3(mv->no);
+                                       }
+                               }
+                               else {
+                                       const Gwn_PackedNormal *pnors_pack = &rdata->poly_normals_pack[mlt->poly];
+                                       for (uint t = 0; t < 3; t++) {
+                                               *((Gwn_PackedNormal *)GWN_vertbuf_raw_step(&nor_step)) = *pnors_pack;
+                                       }
+                               }
+
+                               for (uint t = 0; t < 3; t++) {
+                                       const MVert *mv = &rdata->mvert[vtri[t]];
+                                       copy_v3_v3(GWN_vertbuf_raw_step(&pos_step), mv->co);
+                               }
                        }
                }
-               vbo_len_used = vidx;
+
+               vbo_len_used = GWN_vertbuf_raw_used(&pos_step);
+               BLI_assert(vbo_len_used == GWN_vertbuf_raw_used(&nor_step));
 
                if (vbo_len_capacity != vbo_len_used) {
                        GWN_vertbuf_data_resize(vbo, vbo_len_used);