Commit: f6f9582d2771dc8eced248f7175ec080f33cf731
Author: Bastien Montagne
Date:   Fri Aug 8 14:20:11 2014 +0200
Branches: temp_custom_loop_normals
https://developer.blender.org/rBf6f9582d2771dc8eced248f7175ec080f33cf731

Use BLI_task for some split normals code - wrong solution

Looks like tasks are not suited for many little elements
(this code is at least two times slower as mono-thread previous one!).
And probably things like calling `BLI_stack_new()` in each task instead of
once globally does not help either. :/

Will refactor into a few worker tasks feeded with a queue...

===================================================================

M       source/blender/blenkernel/intern/mesh_evaluate.c

===================================================================

diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c 
b/source/blender/blenkernel/intern/mesh_evaluate.c
index 396ed2b..c8acead 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -47,6 +47,7 @@
 #include "BLI_linklist_stack.h"
 #include "BLI_alloca.h"
 #include "BLI_stack.h"
+#include "BLI_task.h"
 
 #include "BKE_customdata.h"
 #include "BKE_mesh.h"
@@ -485,6 +486,336 @@ void BKE_lnor_space_custom_normal_to_data(MLoopNorSpace 
*lnor_space, const float
        }
 }
 
+typedef struct LoopSplitTaskDataCommon {
+       /* Common to all instances, read/write.
+        * Note we do not need to protect it, though, since two different tasks 
will *always* affect different
+        * elements in the arrays. */
+       MLoopsNorSpaces *lnors_spaces;
+       float (*loopnors)[3];
+       short (*clnors_data)[2];
+
+       /* Common to all instances, and read-only. */
+       const MVert *mverts;
+       const MEdge *medges;
+       const MLoop *mloops;
+       const MPoly *mpolys;
+       const int (*edge_to_loops)[2];
+       const int *loop_to_poly;
+       const float (*polynors)[3];
+} LoopSplitTaskDataCommon;
+
+typedef struct LoopSplitTaskData {
+       /* Specific to each instance (each task). */
+       MLoopNorSpace *lnor_space;  /* We have to create those outside of 
tasks, since afaik memarena is not threadsafe. */
+       float (*lnor)[3];
+       const MLoop *ml_curr;
+       const MLoop *ml_prev;
+       int ml_curr_index;
+       int ml_prev_index;
+       const int *e2l_prev;
+       int mp_index;
+
+       LoopSplitTaskDataCommon *common;
+} LoopSplitTaskData;
+
+static void exec_split_loop_nor_single(TaskPool *UNUSED(pool), void *taskdata, 
int UNUSED(threadid))
+{
+       LoopSplitTaskData *data = (LoopSplitTaskData *)taskdata;
+
+       MLoopsNorSpaces *lnors_spaces = data->common->lnors_spaces;
+       short (*clnors_data)[2] = data->common->clnors_data;
+
+       const MVert *mverts = data->common->mverts;
+       const MEdge *medges = data->common->medges;
+       const float (*polynors)[3] = data->common->polynors;
+
+       MLoopNorSpace *lnor_space = data->lnor_space;
+       float (*lnor)[3] = data->lnor;
+       const MLoop *ml_curr = data->ml_curr;
+       const MLoop *ml_prev = data->ml_prev;
+       const int ml_curr_index = data->ml_curr_index;
+#if 0  /* Not needed for 'single' loop. */
+       const int ml_prev_index = data->ml_prev_index;
+       const int *e2l_prev = data->e2l_prev;
+#endif
+       const int mp_index = data->mp_index;
+
+       /* Simple case (both edges around that vertex are sharp in current 
polygon),
+        * this loop just takes its poly normal.
+        */
+       copy_v3_v3(*lnor, polynors[mp_index]);
+
+       /* printf("BASIC: handling loop %d / edge %d / vert %d\n", 
ml_curr_index, ml_curr->e, ml_curr->v); */
+
+       /* If needed, generate this (simple!) lnor space. */
+       if (lnors_spaces) {
+               float vec_curr[3], vec_prev[3];
+
+               const unsigned int mv_pivot_index = ml_curr->v;  /* The vertex 
we are "fanning" around! */
+               const MVert *mv_pivot = &mverts[mv_pivot_index];
+               const MEdge *me_curr = &medges[ml_curr->e];
+               const MVert *mv_2 = (me_curr->v1 == mv_pivot_index) ? 
&mverts[me_curr->v2] : &mverts[me_curr->v1];
+               const MEdge *me_prev = &medges[ml_prev->e];
+               const MVert *mv_3 = (me_prev->v1 == mv_pivot_index) ? 
&mverts[me_prev->v2] : &mverts[me_prev->v1];
+
+               sub_v3_v3v3(vec_curr, mv_2->co, mv_pivot->co);
+               normalize_v3(vec_curr);
+               sub_v3_v3v3(vec_prev, mv_3->co, mv_pivot->co);
+               normalize_v3(vec_prev);
+
+               BKE_lnor_space_define(lnor_space, *lnor, vec_curr, vec_prev, 
NULL);
+               /* We know there is only one loop in this space, no need to 
create a linklist in this case... */
+               BKE_lnor_space_add_loop(lnors_spaces, lnor_space, 
ml_curr_index, false);
+
+               if (clnors_data) {
+                       BKE_lnor_space_custom_data_to_normal(lnor_space, *lnor, 
clnors_data[ml_curr_index]);
+               }
+       }
+}
+
+#define INDEX_UNSET INT_MIN
+#define INDEX_INVALID -1
+/* See comment about edge_to_loops below. */
+#define IS_EDGE_SHARP(_e2l) (ELEM((_e2l)[1], INDEX_UNSET, INDEX_INVALID))
+
+static void exec_split_loop_nor_fan(TaskPool *UNUSED(pool), void *taskdata, 
int UNUSED(threadid))
+{
+       LoopSplitTaskData *data = (LoopSplitTaskData *)taskdata;
+
+       MLoopsNorSpaces *lnors_spaces = data->common->lnors_spaces;
+       float (*loopnors)[3] = data->common->loopnors;
+       short (*clnors_data)[2] = data->common->clnors_data;
+
+       const MVert *mverts = data->common->mverts;
+       const MEdge *medges = data->common->medges;
+       const MLoop *mloops = data->common->mloops;
+       const MPoly *mpolys = data->common->mpolys;
+       const int (*edge_to_loops)[2] = data->common->edge_to_loops;
+       const int *loop_to_poly = data->common->loop_to_poly;
+       const float (*polynors)[3] = data->common->polynors;
+
+       MLoopNorSpace *lnor_space = data->lnor_space;
+#if 0  /* Not needed for 'fan' loops. */
+       float (*lnor)[3] = data->lnor;
+#endif
+       const MLoop *ml_curr = data->ml_curr;
+       const MLoop *ml_prev = data->ml_prev;
+       const int ml_curr_index = data->ml_curr_index;
+       const int ml_prev_index = data->ml_prev_index;
+       const int mp_index = data->mp_index;
+       const int *e2l_prev = data->e2l_prev;
+
+       /* Gah... We have to fan around current vertex, until we find the other 
non-smooth edge,
+        * and accumulate face normals into the vertex!
+        * Note in case this vertex has only one sharp edges, this is a waste 
because the normal is the same as
+        * the vertex normal, but I do not see any easy way to detect that 
(would need to count number
+        * of sharp edges per vertex, I doubt the additional memory usage would 
be worth it, especially as
+        * it should not be a common case in real-life meshes anyway).
+        */
+       const unsigned int mv_pivot_index = ml_curr->v;  /* The vertex we are 
"fanning" around! */
+       const MVert *mv_pivot = &mverts[mv_pivot_index];
+       const MEdge *me_org = &medges[ml_curr->e];  /* ml_curr would be 
mlfan_prev if we needed that one */
+       const int *e2lfan_curr;
+       float vec_curr[3], vec_prev[3], vec_org[3];
+       const MLoop *mlfan_curr, *mlfan_next;
+       const MPoly *mpfan_next;
+       float lnor[3] = {0.0f, 0.0f, 0.0f};
+       /* mlfan_vert_index: the loop of our current edge might not be the loop 
of our current vertex! */
+       int mlfan_curr_index, mlfan_vert_index, mpfan_curr_index;
+
+       /* We validate clnors data on the fly - cheapest way to do! */
+       int clnors_avg[2] = {0, 0};
+       short (*clnor_ref)[2] = NULL;
+       int clnors_nbr = 0;
+       bool clnors_invalid = false;
+
+       /* Temp loop normal stack. */
+       BLI_SMALLSTACK_DECLARE(normal, float *);
+       /* Temp clnors stack. */
+       BLI_SMALLSTACK_DECLARE(clnors, short *);
+       /* Temp edge vectors stack, only used when computing lnor spaces. */
+       BLI_Stack *edge_vectors = lnors_spaces ? 
BLI_stack_new(sizeof(float[3]), __func__) : NULL;
+
+       e2lfan_curr = e2l_prev;
+       mlfan_curr = ml_prev;
+       mlfan_curr_index = ml_prev_index;
+       mlfan_vert_index = ml_curr_index;
+       mpfan_curr_index = mp_index;
+
+       BLI_assert(mlfan_curr_index >= 0);
+       BLI_assert(mlfan_vert_index >= 0);
+       BLI_assert(mpfan_curr_index >= 0);
+
+       BLI_assert((edge_vectors == NULL) || BLI_stack_is_empty(edge_vectors));
+
+       /* Only need to compute previous edge's vector once, then we can just 
reuse old current one! */
+       {
+               const MVert *mv_2 = (me_org->v1 == mv_pivot_index) ? 
&mverts[me_org->v2] : &mverts[me_org->v1];
+
+               sub_v3_v3v3(vec_org, mv_2->co, mv_pivot->co);
+               normalize_v3(vec_org);
+               copy_v3_v3(vec_prev, vec_org);
+
+               if (lnors_spaces) {
+                       BLI_stack_push(edge_vectors, vec_org);
+               }
+       }
+
+       /* printf("FAN: vert %d, start edge %d\n", mv_pivot_index, ml_curr->e); 
*/
+
+       while (true) {
+               const MEdge *me_curr = &medges[mlfan_curr->e];
+               /* Compute edge vectors.
+                * NOTE: We could pre-compute those into an array, in the first 
iteration, instead of computing them
+                *       twice (or more) here. However, time gained is not 
worth memory and time lost,
+                *       given the fact that this code should not be called 
that much in real-life meshes...
+                */
+               {
+                       const MVert *mv_2 = (me_curr->v1 == mv_pivot_index) ? 
&mverts[me_curr->v2] : &mverts[me_curr->v1];
+
+                       sub_v3_v3v3(vec_curr, mv_2->co, mv_pivot->co);
+                       normalize_v3(vec_curr);
+               }
+
+               /* printf("\thandling edge %d / loop %d\n", mlfan_curr->e, 
mlfan_curr_index); */
+
+               {
+                       /* Code similar to accumulate_vertex_normals_poly. */
+                       /* Calculate angle between the two poly edges incident 
on this vertex. */
+                       const float fac = saacos(dot_v3v3(vec_curr, vec_prev));
+                       /* Accumulate */
+                       madd_v3_v3fl(lnor, polynors[mpfan_curr_index], fac);
+
+                       if (clnors_data) {
+                               /* Accumulate all clnors, if they are not all 
equal we have to fix that! */
+                               short (*clnor)[2] = 
&clnors_data[mlfan_vert_index];
+                               if (clnors_nbr) {
+                                       clnors_invalid |= ((*clnor_ref)[0] != 
(*clnor)[0] || (*clnor_ref)[1] != (*clnor)[1]);
+                               }
+                               else {
+                                       clnor_ref = clnor;
+                               }
+                               clnors_avg[0] += (*clnor)[0];
+                               clnors_avg[1] += (*clnor)[1];
+                               clnors_nbr++;
+                               /* We store here a pointer to all custom lnors 
processed. */
+                               BLI_SMALLSTACK_PUSH(clnors, (short *)*clnor);
+                       }
+               }
+
+               /* We store here a pointer to all loop-normals processed. */
+               BLI_SMALLSTACK_PUSH(normal, (float 
*)(loopnors[mlfan_vert_index]));
+
+               if (lnors_spaces) {
+                       /* Assign current lnor space to current 'vertex' loop. 
*/
+                       BKE_lnor_space_add_loop(lnors_spaces, lnor_space, 
mlfan_vert_index, true);
+                       if (me_curr != me_org) {
+                               /* We store here all edges-normalized vectors 
processed. */
+                               BLI_stack_push(edge_vectors, vec_curr);
+                       }
+               }
+
+               if (IS_EDGE_SHARP(e2lfan_curr) || (me_curr == me_org)) {
+                       /* Current edge is sharp and we have finished with this 
fan of faces around this vert,
+                        * or this vert is smooth, and we have completed a full 
turn around it.
+                        */
+                       /* printf("FAN: Finished!\n"); */
+                       break;
+               }
+
+               copy_v3_v3(vec_prev, vec_curr);
+
+               /* Warning! This is rather complex!
+                * We have to find our next edge around the vertex (fan mode).
+                * First we find the next loop, which is either previous or 
next to mlfan_curr_index, depending
+                * whether both loops using current edge are in the same 
direction or not, and whether
+                * mlfan_curr_index actually uses the vertex we are fanning 
around!
+                * mlfan_curr_index is the index of mlfan_next here, and 
mlfan_next is not the real next one
+                * (i.e. not the future mlfan_curr)...
+                */
+               mlfan_curr_index = (e2lfan_curr[0] == mlfan_curr_index) ? 
e2lfan_

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to