star-enclosures-3d

Extract enclosures from 3D geometry
git clone git://git.meso-star.fr/star-enclosures-3d.git
Log | Files | Refs | README | LICENSE

commit 89ee753dce248d7343357d8274bd491272b7345d
parent 7dd027bdfd4639cf36f07b80e9aba1ae7edb3f01
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Fri, 16 Mar 2018 14:39:44 +0100

Additional openmp stuff; mostly about many enclosure scenario

Diffstat:
Msrc/senc_scene_analyze.c | 310+++++++++++++++++++++++++++++++++++++++++++------------------------------------
1 file changed, 169 insertions(+), 141 deletions(-)

diff --git a/src/senc_scene_analyze.c b/src/senc_scene_analyze.c @@ -137,19 +137,68 @@ get_side_from_stack return id; } +static void +get_scn_indices(const unsigned itri, unsigned ids[3], void* ctx) { + int i; + const struct senc_scene* scene = ctx; + const struct triangle_in* trg = + darray_triangle_in_cdata_get(&scene->triangles_in) + itri; + FOR_EACH(i, 0, 3) { + ASSERT(trg->vertice_id[i] < scene->nverts); + ids[i] = (unsigned) trg->vertice_id[i]; /* Back to API type */ + } +} + +static void +get_scn_position(const unsigned ivert, float pos[3], void* ctx) { + const struct senc_scene* scene = ctx; + const union double3* pt = + darray_position_cdata_get(&scene->vertices) + ivert; + f3_set_d3(pos, pt->vec); +} + +static int +self_hit_filter +(const struct s3d_hit* hit, + const float ray_org[3], + const float ray_dir[3], + void* ray_data, + void* filter_data) +{ + const struct darray_triangle_comp* triangles_comp = filter_data; + const component_id_t* origin_component = ray_data; + const struct triangle_comp* hit_trg_comp; + enum side_id hit_side; + component_id_t hit_component; + + (void) ray_org; (void) ray_dir; + ASSERT(hit && triangles_comp && origin_component); + ASSERT(hit->prim.prim_id < darray_triangle_comp_size_get(triangles_comp)); + hit_trg_comp = darray_triangle_comp_cdata_get(triangles_comp) + + hit->prim.prim_id; + hit_side = (hit->normal[2] > 0) ? SIDE_FRONT : SIDE_BACK; + hit_component = hit_trg_comp->component[hit_side]; + + /* Not self hit or distance should be small */ + ASSERT(hit_component != *origin_component || hit->distance < 1e-6); + return (hit_component == *origin_component); +} + static res_T extract_connex_components (struct senc_descriptor* desc, struct trgside* trgsides, struct darray_ptr_component_descriptor* connex_components, const struct darray_triangle_tmp* triangles_tmp_array, - struct darray_triangle_comp* triangles_comp) + struct darray_triangle_comp* triangles_comp, + struct s3d_scene_view** s3d_view) { res_T res = RES_OK; const struct senc_scene* scn; struct mem_allocator* alloc; ATOMIC component_count = 0; - int mm; + volatile int exit_for = 0; + int64_t mm; #ifndef NDEBUG trg_id_t t; component_id_t c; @@ -162,7 +211,7 @@ extract_connex_components /* Just a hint; to avoid contention on first loop */ OK2(darray_ptr_component_descriptor_reserve(connex_components, 2 * scn->nmeds), - error_); /* Cannot jump into openmp block */ + error_); /* Cannot goto into openmp block */ #ifndef NDEBUG FOR_EACH(t, 0, scn->nutris) { @@ -183,13 +232,14 @@ extract_connex_components struct darray_side_id stack; darray_side_id_init(alloc, &stack); - #pragma omp for schedule(dynamic) - for(mm = 0; mm < (int)scn->nmeds; mm++) { /* Process all media */ + #pragma omp for schedule(dynamic) nowait + for(mm = 0; mm < (int64_t)scn->nmeds; mm++) { /* Process all media */ const medium_id_t m = (medium_id_t)mm; struct cc_descriptor* cc; /* Any not-already-used side is used as a starting point */ side_id_t first_side_not_in_component; - if(res != RES_OK) continue; + + if(exit_for) continue; first_side_not_in_component = darray_side_range_cdata_get(&scn->media_use)[m].first; if(first_side_not_in_component == SIDE_NULL__) @@ -202,8 +252,8 @@ extract_connex_components side_id_t crt_side_id = start_side_id; side_id_t last_side_id = start_side_id; ASSERT(start_side_id == SIDE_NULL__ || start_side_id < 2 * scn->nutris); - if(start_side_id == SIDE_NULL__) /* start_side_id=SIDE_NULL__ => done! */ - break; + if(start_side_id == SIDE_NULL__) + break; /* start_side_id=SIDE_NULL__ => done! */ ASSERT(trgsides[start_side_id].list_id == FLAG_LIST_SIDE_LIST); #ifndef NDEBUG @@ -219,7 +269,7 @@ extract_connex_components cc = MEM_ALLOC(alloc, sizeof(struct cc_descriptor)); if(!cc) { res = RES_MEM_ERR; - goto error; + goto error1; } cc_descriptor_init(alloc, cc); ASSERT(m == trgsides[start_side_id].medium); @@ -321,7 +371,7 @@ extract_connex_components side_id_t neighbour_id = crt_side->facing_side_id[i]; trg_id_t nbour_trg_id = TRGSIDE_2_TRG(neighbour_id); const struct trgside* neighbour = trgsides + neighbour_id; - CHK(m == crt_side->medium); + ASSERT(m == crt_side->medium); if(neighbour->medium != crt_side->medium) { /* Found medium discontinuity! Model topology is broken. */ const struct triangle_in* triangles_in @@ -350,7 +400,7 @@ extract_connex_components log_err(desc->scene->dev, "Media: %lu VS %lu\n", (unsigned long)neighbour->medium, (unsigned long)crt_side->medium); res = RES_BAD_ARG; - goto error; + goto error1; } if(neighbour->list_id == FLAG_LIST_COMPONENT) { /* Already processed */ @@ -373,7 +423,7 @@ extract_connex_components cc->side_range.last = last_side_id; /* Need to synchronize connex_components growth as this global structure * is accessed by multipe threads */ -#pragma omp critical + #pragma omp critical { struct cc_descriptor** components; size_t sz = darray_ptr_component_descriptor_size_get(connex_components); @@ -390,11 +440,46 @@ extract_connex_components components[cc->cc_id] = cc; } } + OK2(res, error1); } - error: - continue; /* Cannot exit openmp block */ + continue; + error1: + /* Cannot goto out of openmp block */ + exit_for = 1; + continue; } + /* No barrier here (nowait clause). + * The first thread executes the single block */ darray_side_id_release(&stack); + #pragma omp single nowait + { + struct s3d_device* s3d = NULL; + struct s3d_scene* s3d_scn = NULL; + struct s3d_shape* s3d_shp = NULL; + struct s3d_vertex_data attribs; + + attribs.type = S3D_FLOAT3; + attribs.usage = S3D_POSITION; + attribs.get = get_scn_position; + + /* Put geometry in a 3D view */ + OK(s3d_device_create(desc->scene->dev->logger, alloc, 0, &s3d)); + OK(s3d_scene_create(s3d, &s3d_scn)); + OK(s3d_shape_create_mesh(s3d, &s3d_shp)); + + /* Back to API type for ntris and nverts */ + ASSERT(desc->scene->nutris < UINT_MAX); + ASSERT(desc->scene->nuverts < UINT_MAX); + OK(s3d_mesh_setup_indexed_vertices(s3d_shp, (unsigned) desc->scene->nutris, + get_scn_indices, (unsigned) desc->scene->nuverts, &attribs, 1, desc->scene)); + s3d_mesh_set_hit_filter_function(s3d_shp, self_hit_filter, triangles_comp); + OK(s3d_scene_attach_shape(s3d_scn, s3d_shp)); + OK(s3d_scene_view_create(s3d_scn, S3D_TRACE, s3d_view)); + error: + if(s3d) S3D(device_ref_put(s3d)); + if(s3d_scn) S3D(scene_ref_put(s3d_scn)); + if(s3d_shp) S3D(shape_ref_put(s3d_shp)); + } } OK2(res, error_); @@ -424,73 +509,23 @@ error_: goto exit; } -static void -get_scn_indices(const unsigned itri, unsigned ids[3], void* ctx) { - int i; - const struct senc_scene* scene = ctx; - const struct triangle_in* trg = - darray_triangle_in_cdata_get(&scene->triangles_in) + itri; - FOR_EACH(i, 0, 3) { - ASSERT(trg->vertice_id[i] < scene->nverts); - ids[i] = (unsigned)trg->vertice_id[i]; /* Back to API type */ - } -} - -static void -get_scn_position(const unsigned ivert, float pos[3], void* ctx) { - const struct senc_scene* scene = ctx; - const union double3* pt = - darray_position_cdata_get(&scene->vertices) + ivert; - f3_set_d3(pos, pt->vec); -} - -static int -self_hit_filter -(const struct s3d_hit* hit, - const float ray_org[3], - const float ray_dir[3], - void* ray_data, - void* filter_data) -{ - const struct darray_triangle_comp* triangles_comp = filter_data; - const component_id_t* origin_component = ray_data; - const struct triangle_comp* hit_trg_comp; - enum side_id hit_side; - component_id_t hit_component; - - (void)ray_org; (void)ray_dir; - ASSERT(hit && triangles_comp && origin_component); - ASSERT(hit->prim.prim_id < darray_triangle_comp_size_get(triangles_comp)); - hit_trg_comp = darray_triangle_comp_cdata_get(triangles_comp) - + hit->prim.prim_id; - hit_side = (hit->normal[2] > 0) ? SIDE_FRONT : SIDE_BACK; - hit_component = hit_trg_comp->component[hit_side]; - - /* Not self hit or distance should be small */ - ASSERT(hit_component != *origin_component || hit->distance < 1e-6); - return (hit_component == *origin_component); -} - static res_T group_connex_components (struct senc_descriptor* desc, struct trgside* trgsides, struct darray_triangle_comp* triangles_comp, - struct darray_ptr_component_descriptor* connex_components) + struct darray_ptr_component_descriptor* connex_components, + struct s3d_scene_view* s3d_view) { res_T res = RES_OK; struct mem_allocator* alloc; struct cc_descriptor** descriptors; - struct s3d_device* s3d = NULL; - struct s3d_scene* s3d_scn = NULL; - struct s3d_shape* s3d_shp = NULL; - struct s3d_scene_view* s3d_view = NULL; - struct s3d_vertex_data attribs; size_t tmp; - component_id_t cc_count, c; - medium_id_t infinite_medium = MEDIUM_NULL__; - side_id_t infinite_medium_first_side = SIDE_MAX__; - unsigned char infinite_medium_is_known = 0; + component_id_t cc_count; + int64_t ccc; + volatile int exit_for = 0; + ATOMIC next_enclosure_id = desc->enclosures_count; + struct cc_descriptor* infinity_first_cc = NULL; (void)trgsides; ASSERT(desc && trgsides && triangles_comp && connex_components); @@ -500,28 +535,10 @@ group_connex_components ASSERT(tmp <= COMPONENT_MAX__); cc_count = (component_id_t)tmp; - if(!cc_count) return RES_OK; /* No component to group */ - - attribs.type = S3D_FLOAT3; - attribs.usage = S3D_POSITION; - attribs.get = get_scn_position; - - /* Put geometry in a 3D view */ - OK(s3d_device_create(desc->scene->dev->logger, alloc, 0, &s3d)); - OK(s3d_scene_create(s3d, &s3d_scn)); - OK(s3d_shape_create_mesh(s3d, &s3d_shp)); - - /* Back to API type for ntris and nverts */ - ASSERT(desc->scene->nutris < UINT_MAX); - ASSERT(desc->scene->nuverts < UINT_MAX); - OK(s3d_mesh_setup_indexed_vertices(s3d_shp, (unsigned)desc->scene->nutris, - get_scn_indices, (unsigned)desc->scene->nuverts, &attribs, 1, desc->scene)); - s3d_mesh_set_hit_filter_function(s3d_shp, self_hit_filter, triangles_comp); - OK(s3d_scene_attach_shape(s3d_scn, s3d_shp)); - OK(s3d_scene_view_create(s3d_scn, S3D_TRACE, &s3d_view)); - /* Cast rays to find links between connex components */ - FOR_EACH(c, 0, cc_count) { + #pragma omp parallel for + for(ccc = 0; ccc < (int64_t)cc_count; ccc++) { + component_id_t c = (component_id_t)ccc; struct s3d_hit hit = S3D_HIT_NULL; float origin[3]; const float dir[3] = { 0, 0, 1 }; @@ -532,14 +549,17 @@ group_connex_components component_id_t self_hit_component = origin_trg->component[1 - TRGSIDE_2_SIDE(cc->max_z_side_id)]; + if(exit_for) continue; ASSERT(cc->cc_id == c); ASSERT(cc->cc_group_root == CC_GROUP_ID_NONE); if(cc->max_z_nz < 0) { + size_t id; /* Don't need to cast a ray */ cc->cc_group_root = cc->cc_id; /* New group with self as root */ - ASSERT(desc->enclosures_count < ENCLOSURE_MAX__); - cc->enclosure_id = desc->enclosures_count++; + id = ATOMIC_INCR(&next_enclosure_id) - 1; + ASSERT(id < ENCLOSURE_MAX__); + cc->enclosure_id = (enclosure_id_t)id; continue; } @@ -555,21 +575,19 @@ group_connex_components == TRGSIDE_OPPOSITE(cc->max_z_side_id)))); f3_set_d3(origin, cc->max_vrtx); /* Self-hit data: self hit if hit this component "on the other side" */ - OK(s3d_scene_view_trace_ray(s3d_view, origin, dir, range, - &self_hit_component, &hit)); + OK2(s3d_scene_view_trace_ray(s3d_view, origin, dir, range, + &self_hit_component, &hit), error_); /* If no hit, the component is facing an infinite medium */ if(S3D_HIT_NONE(&hit)) { cc->cc_group_root = CC_GROUP_ROOT_INFINITE; cc->enclosure_id = 0; - if(!infinite_medium_is_known) { - infinite_medium_is_known = 1; - infinite_medium = cc->medium; - infinite_medium_first_side = cc->max_z_side_id; - continue; - } - if(infinite_medium != cc->medium) { + /* Keep the first component facing infinity */ + ATOMIC_CAS(&(intptr_t)infinity_first_cc, (intptr_t)cc, (intptr_t)NULL); + if(infinity_first_cc->medium != cc->medium) { + const side_id_t infinity_first_side = infinity_first_cc->max_z_side_id; + const medium_id_t infinity_medium = infinity_first_cc->medium; /* Medium mismatch! Model topology is broken. */ - const trg_id_t t1 = TRGSIDE_2_TRG(infinite_medium_first_side); + const trg_id_t t1 = TRGSIDE_2_TRG(infinity_first_side); const trg_id_t t2 = TRGSIDE_2_TRG(cc->max_z_side_id); const struct triangle_in* triangles_in = darray_triangle_in_cdata_get(&desc->scene->triangles_in); @@ -579,7 +597,7 @@ group_connex_components "Medium mismatch found between triangle %lu %s side and triangle" " %lu %s side, both facing infinity.\n", (unsigned long)triangles_in[t1].global_id, - TRGSIDE_IS_FRONT(infinite_medium_first_side) ? "front" : "back", + TRGSIDE_IS_FRONT(infinity_first_side) ? "front" : "back", (unsigned long)triangles_in[t2].global_id, TRGSIDE_IS_FRONT(cc->max_z_side_id) ? "front" : "back"); log_err(desc->scene->dev, @@ -595,9 +613,9 @@ group_connex_components SPLIT3(positions[triangles_in[t2].vertice_id[1]].vec), SPLIT3(positions[triangles_in[t2].vertice_id[2]].vec)); log_err(desc->scene->dev, "Media: %lu VS %lu\n", - (unsigned long)infinite_medium, (unsigned long)cc->medium); + (unsigned long)infinity_medium, (unsigned long)cc->medium); res = RES_BAD_ARG; - goto error; + goto error_; } /* Same medium as previous members of the group: OK */ continue; @@ -657,14 +675,22 @@ group_connex_components (unsigned long)cc->medium); res = RES_BAD_ARG; - goto error; + goto error_; } } + continue; + error_: + exit_for = 1; + continue; } + ASSERT(next_enclosure_id < ENCLOSURE_MAX__); + desc->enclosures_count = (enclosure_id_t)next_enclosure_id; + OK(res); /* Post-process links to group connex components */ OK(darray_enclosure_resize(&desc->enclosures, desc->enclosures_count)); - FOR_EACH(c, 0, cc_count) { + FOR_EACH(ccc, 0, cc_count) { + component_id_t c = (component_id_t)ccc; struct cc_descriptor* const cc = descriptors[c]; const struct cc_descriptor* other_desc = cc; struct enclosure_data* enclosures @@ -693,11 +719,6 @@ group_connex_components } exit: - /* Local Star3D stuff is no longer useful */ - if(s3d) S3D(device_ref_put(s3d)); - if(s3d_scn) S3D(scene_ref_put(s3d_scn)); - if(s3d_shp) S3D(shape_ref_put(s3d_shp)); - if(s3d_view) S3D(scene_view_ref_put(s3d_view)); return res; error: goto exit; @@ -931,8 +952,9 @@ build_result const struct triangle_in* triangles_in; struct triangle_enc* triangles_enc; const struct triangle_comp* triangles_comp; - int tt; - int ee; + volatile int exit_for = 0; + int64_t tt; + int64_t ee; ASSERT(desc && connex_components && triangles_comp_array); @@ -946,31 +968,34 @@ build_result error_); triangles_enc = darray_triangle_enc_data_get(&desc->triangles_enc); - /* Build global enclosure information */ - #pragma omp parallel for - for(tt = 0; tt < (int)desc->scene->nutris; tt++) { - trg_id_t t = (trg_id_t)tt; - const component_id_t cf_id = triangles_comp[t].component[SIDE_FRONT]; - const component_id_t cb_id = triangles_comp[t].component[SIDE_BACK]; - const struct cc_descriptor* cf = cc_descriptors[cf_id]; - const struct cc_descriptor* cb = cc_descriptors[cb_id]; - const enclosure_id_t ef_id = cf->enclosure_id; - const enclosure_id_t eb_id = cb->enclosure_id; - ASSERT(triangles_enc[t].enclosure[SIDE_FRONT] == ENCLOSURE_NULL__); - triangles_enc[t].enclosure[SIDE_FRONT] = ef_id; - ASSERT(triangles_enc[t].enclosure[SIDE_BACK] == ENCLOSURE_NULL__); - triangles_enc[t].enclosure[SIDE_BACK] = eb_id; - } - - /* Resize/push operations on enclosure's fields are valid in the - * openmp block as a given enclosure is processed by a single thread */ #pragma omp parallel { struct htable_vrtx_id vtable; + + /* Build global enclosure information */ + #pragma omp for + for(tt = 0; tt < (int64_t) desc->scene->nutris; tt++) { + trg_id_t t = (trg_id_t)tt; + const component_id_t cf_id = triangles_comp[t].component[SIDE_FRONT]; + const component_id_t cb_id = triangles_comp[t].component[SIDE_BACK]; + const struct cc_descriptor* cf = cc_descriptors[cf_id]; + const struct cc_descriptor* cb = cc_descriptors[cb_id]; + const enclosure_id_t ef_id = cf->enclosure_id; + const enclosure_id_t eb_id = cb->enclosure_id; + ASSERT(triangles_enc[t].enclosure[SIDE_FRONT] == ENCLOSURE_NULL__); + triangles_enc[t].enclosure[SIDE_FRONT] = ef_id; + ASSERT(triangles_enc[t].enclosure[SIDE_BACK] == ENCLOSURE_NULL__); + triangles_enc[t].enclosure[SIDE_BACK] = eb_id; + } + /* Implicit barrier here */ + + /* Resize/push operations on enclosure's fields are valid in the + * openmp block as a given enclosure is processed by a single thread */ htable_vrtx_id_init(alloc, &vtable); - #pragma omp for schedule(dynamic) - for(ee = 0; ee < (int)desc->enclosures_count; ee++) { + ASSERT(desc->enclosures_count <= ENCLOSURE_MAX__); + #pragma omp for schedule(dynamic) nowait + for(ee = 0; ee < (int64_t)desc->enclosures_count; ee++) { const enclosure_id_t e = (enclosure_id_t)ee; struct enclosure_data* enc = enclosures + e; const struct cc_descriptor* current = cc_descriptors[enc->first_component]; @@ -979,10 +1004,9 @@ build_result trg_id_t t; ASSERT(enc->first_component < darray_ptr_component_descriptor_size_get(connex_components)); - ASSERT(ee <= ENCLOSURE_MAX__); ASSERT(current->cc_id == enc->first_component); - if(res != RES_OK) continue; + if(exit_for) continue; ASSERT(e <= UINT_MAX); enc->header.enclosure_id = (unsigned)e; /* Back to API type */ ASSERT(current->enclosure_id == enc->header.enclosure_id); @@ -1052,8 +1076,10 @@ build_result } if(fst_idx == sgd_idx) break; } + continue; error: - /* Cannot exit openmp block */ + /* Cannot goto out of openmp block */ + exit_for = 1; continue; } htable_vrtx_id_release(&vtable); @@ -1089,6 +1115,7 @@ senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc) char triangles_comp_initialized = 0; /* Array of triangle sides. */ struct trgside* trgsides = NULL; + struct s3d_scene_view* s3d_view = NULL; if(!scn || !out_desc) return RES_BAD_ARG; @@ -1128,7 +1155,7 @@ senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc) /* Step 2: extract triangle connex components */ res = extract_connex_components(desc, trgsides, &connex_components, - &triangles_tmp, &triangles_comp); + &triangles_tmp, &triangles_comp, &s3d_view); if(res != RES_OK) { log_err(scn->dev, "%s: could not extract connex components from scene.\n", FUNC_NAME); @@ -1140,7 +1167,8 @@ senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc) /* Step 3: group components */ res = group_connex_components(desc, trgsides, &triangles_comp, - &connex_components); + &connex_components, s3d_view); + if (s3d_view) S3D(scene_view_ref_put(s3d_view)); if(res != RES_OK) { log_err(scn->dev, "%s: could not group connex components from scene.\n", FUNC_NAME);