diff options
Diffstat (limited to 'source/blender/blenkernel/intern/subdiv_eval.c')
-rw-r--r-- | source/blender/blenkernel/intern/subdiv_eval.c | 112 |
1 files changed, 94 insertions, 18 deletions
diff --git a/source/blender/blenkernel/intern/subdiv_eval.c b/source/blender/blenkernel/intern/subdiv_eval.c index 0001eb8a205..9733a1498a6 100644 --- a/source/blender/blenkernel/intern/subdiv_eval.c +++ b/source/blender/blenkernel/intern/subdiv_eval.c @@ -28,6 +28,7 @@ #include "BLI_bitmap.h" #include "BLI_math_vector.h" +#include "BLI_task.h" #include "BLI_utildefines.h" #include "BKE_customdata.h" @@ -38,7 +39,28 @@ #include "opensubdiv_evaluator_capi.h" #include "opensubdiv_topology_refiner_capi.h" -bool BKE_subdiv_eval_begin(Subdiv *subdiv) +/* ============================ Helper Function ============================ */ + +static eOpenSubdivEvaluator opensubdiv_evalutor_from_subdiv_evaluator_type( + eSubdivEvaluatorType evaluator_type) +{ + switch (evaluator_type) { + case SUBDIV_EVALUATOR_TYPE_CPU: { + return OPENSUBDIV_EVALUATOR_CPU; + } + case SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE: { + return OPENSUBDIV_EVALUATOR_GLSL_COMPUTE; + } + } + BLI_assert_msg(0, "Unknown evaluator type"); + return OPENSUBDIV_EVALUATOR_CPU; +} + +/* ====================== Main Subdivision Evaluation ====================== */ + +bool BKE_subdiv_eval_begin(Subdiv *subdiv, + eSubdivEvaluatorType evaluator_type, + OpenSubdiv_EvaluatorCache *evaluator_cache) { BKE_subdiv_stats_reset(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE); if (subdiv->topology_refiner == NULL) { @@ -47,8 +69,11 @@ bool BKE_subdiv_eval_begin(Subdiv *subdiv) return false; } if (subdiv->evaluator == NULL) { + eOpenSubdivEvaluator opensubdiv_evaluator_type = + opensubdiv_evalutor_from_subdiv_evaluator_type(evaluator_type); BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE); - subdiv->evaluator = openSubdiv_createEvaluatorFromTopologyRefiner(subdiv->topology_refiner); + subdiv->evaluator = openSubdiv_createEvaluatorFromTopologyRefiner( + subdiv->topology_refiner, opensubdiv_evaluator_type, evaluator_cache); BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE); if (subdiv->evaluator == NULL) { return false; @@ -80,6 +105,9 @@ static void set_coarse_positions(Subdiv *subdiv, BLI_BITMAP_ENABLE(vertex_used_map, loop->v); } } + /* Use a temporary buffer so we do not upload vertices one at a time to the GPU. */ + float(*buffer)[3] = MEM_mallocN(sizeof(float[3]) * mesh->totvert, "subdiv tmp coarse positions"); + int manifold_vertex_count = 0; for (int vertex_index = 0, manifold_vertex_index = 0; vertex_index < mesh->totvert; vertex_index++) { if (!BLI_BITMAP_TEST_BOOL(vertex_used_map, vertex_index)) { @@ -93,13 +121,49 @@ static void set_coarse_positions(Subdiv *subdiv, const MVert *vertex = &mvert[vertex_index]; vertex_co = vertex->co; } - subdiv->evaluator->setCoarsePositions(subdiv->evaluator, vertex_co, manifold_vertex_index, 1); + copy_v3_v3(&buffer[manifold_vertex_index][0], vertex_co); manifold_vertex_index++; + manifold_vertex_count++; } + subdiv->evaluator->setCoarsePositions( + subdiv->evaluator, &buffer[0][0], 0, manifold_vertex_count); MEM_freeN(vertex_used_map); + MEM_freeN(buffer); +} + +/* Context which is used to fill face varying data in parallel. */ +typedef struct FaceVaryingDataFromUVContext { + OpenSubdiv_TopologyRefiner *topology_refiner; + const Mesh *mesh; + const MLoopUV *mloopuv; + float (*buffer)[2]; + int layer_index; +} FaceVaryingDataFromUVContext; + +static void set_face_varying_data_from_uv_task(void *__restrict userdata, + const int face_index, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + FaceVaryingDataFromUVContext *ctx = userdata; + OpenSubdiv_TopologyRefiner *topology_refiner = ctx->topology_refiner; + const int layer_index = ctx->layer_index; + const Mesh *mesh = ctx->mesh; + const MPoly *mpoly = &mesh->mpoly[face_index]; + const MLoopUV *mluv = &ctx->mloopuv[mpoly->loopstart]; + + /* TODO(sergey): OpenSubdiv's C-API converter can change winding of + * loops of a face, need to watch for that, to prevent wrong UVs assigned. + */ + const int num_face_vertices = topology_refiner->getNumFaceVertices(topology_refiner, face_index); + const int *uv_indices = topology_refiner->getFaceFVarValueIndices( + topology_refiner, face_index, layer_index); + for (int vertex_index = 0; vertex_index < num_face_vertices; vertex_index++, mluv++) { + copy_v2_v2(ctx->buffer[uv_indices[vertex_index]], mluv->uv); + } } static void set_face_varying_data_from_uv(Subdiv *subdiv, + const Mesh *mesh, const MLoopUV *mloopuv, const int layer_index) { @@ -107,25 +171,37 @@ static void set_face_varying_data_from_uv(Subdiv *subdiv, OpenSubdiv_Evaluator *evaluator = subdiv->evaluator; const int num_faces = topology_refiner->getNumFaces(topology_refiner); const MLoopUV *mluv = mloopuv; - /* TODO(sergey): OpenSubdiv's C-API converter can change winding of - * loops of a face, need to watch for that, to prevent wrong UVs assigned. - */ - for (int face_index = 0; face_index < num_faces; face_index++) { - const int num_face_vertices = topology_refiner->getNumFaceVertices(topology_refiner, - face_index); - const int *uv_indices = topology_refiner->getFaceFVarValueIndices( - topology_refiner, face_index, layer_index); - for (int vertex_index = 0; vertex_index < num_face_vertices; vertex_index++, mluv++) { - evaluator->setFaceVaryingData(evaluator, layer_index, mluv->uv, uv_indices[vertex_index], 1); - } - } + + const int num_fvar_values = topology_refiner->getNumFVarValues(topology_refiner, layer_index); + /* Use a temporary buffer so we do not upload UVs one at a time to the GPU. */ + float(*buffer)[2] = MEM_mallocN(sizeof(float[2]) * num_fvar_values, "temp UV storage"); + + FaceVaryingDataFromUVContext ctx; + ctx.topology_refiner = topology_refiner; + ctx.layer_index = layer_index; + ctx.mloopuv = mluv; + ctx.mesh = mesh; + ctx.buffer = buffer; + + TaskParallelSettings parallel_range_settings; + BLI_parallel_range_settings_defaults(¶llel_range_settings); + parallel_range_settings.min_iter_per_thread = 1; + + BLI_task_parallel_range( + 0, num_faces, &ctx, set_face_varying_data_from_uv_task, ¶llel_range_settings); + + evaluator->setFaceVaryingData(evaluator, layer_index, &buffer[0][0], 0, num_fvar_values); + + MEM_freeN(buffer); } bool BKE_subdiv_eval_begin_from_mesh(Subdiv *subdiv, const Mesh *mesh, - const float (*coarse_vertex_cos)[3]) + const float (*coarse_vertex_cos)[3], + eSubdivEvaluatorType evaluator_type, + OpenSubdiv_EvaluatorCache *evaluator_cache) { - if (!BKE_subdiv_eval_begin(subdiv)) { + if (!BKE_subdiv_eval_begin(subdiv, evaluator_type, evaluator_cache)) { return false; } return BKE_subdiv_eval_refine_from_mesh(subdiv, mesh, coarse_vertex_cos); @@ -146,7 +222,7 @@ bool BKE_subdiv_eval_refine_from_mesh(Subdiv *subdiv, const int num_uv_layers = CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV); for (int layer_index = 0; layer_index < num_uv_layers; layer_index++) { const MLoopUV *mloopuv = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPUV, layer_index); - set_face_varying_data_from_uv(subdiv, mloopuv, layer_index); + set_face_varying_data_from_uv(subdiv, mesh, mloopuv, layer_index); } /* Update evaluator to the new coarse geometry. */ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_REFINE); |