diff --git a/source/blender/blenkernel/BKE_subdiv_modifier.h b/source/blender/blenkernel/BKE_subdiv_modifier.h index d65df26da77..dd01c4ffd07 100644 --- a/source/blender/blenkernel/BKE_subdiv_modifier.h +++ b/source/blender/blenkernel/BKE_subdiv_modifier.h @@ -32,8 +32,13 @@ typedef struct SubsurfRuntimeData { SubdivSettings settings; /* Cached subdivision surface descriptor, with topology and settings. */ - struct Subdiv *subdiv; - bool set_by_draw_code; + struct Subdiv *subdiv_cpu; + struct Subdiv *subdiv_gpu; + + /* Recent usage markers for UI diagnostics. To avoid UI flicker due to races + * between evaluation and UI redraw, they are set to 2 when an evaluator is used, + * and count down every frame. */ + char used_cpu, used_gpu; /* Cached mesh wrapper data, to be used for GPU subdiv or lazy evaluation on CPU. */ bool has_gpu_subdiv; diff --git a/source/blender/blenkernel/intern/mesh_wrapper.cc b/source/blender/blenkernel/intern/mesh_wrapper.cc index 9c8c36cacb8..3b036274477 100644 --- a/source/blender/blenkernel/intern/mesh_wrapper.cc +++ b/source/blender/blenkernel/intern/mesh_wrapper.cc @@ -350,7 +350,7 @@ static Mesh *mesh_wrapper_ensure_subdivision(Mesh *me) BKE_mesh_calc_normals_split(subdiv_mesh); } - if (subdiv != runtime_data->subdiv) { + if (subdiv != runtime_data->subdiv_cpu && subdiv != runtime_data->subdiv_gpu) { BKE_subdiv_free(subdiv); } diff --git a/source/blender/blenkernel/intern/subdiv_modifier.cc b/source/blender/blenkernel/intern/subdiv_modifier.cc index 3221e43d4e6..60d55af215c 100644 --- a/source/blender/blenkernel/intern/subdiv_modifier.cc +++ b/source/blender/blenkernel/intern/subdiv_modifier.cc @@ -49,6 +49,8 @@ bool BKE_subsurf_modifier_runtime_init(SubsurfModifierData *smd, const bool use_ * was already allocated. */ if (runtime_data) { runtime_data->settings = settings; + + runtime_data->used_cpu = runtime_data->used_gpu = 0; } return false; @@ -162,15 +164,18 @@ Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure(SubsurfRuntimeData *runtim const Mesh *mesh, const bool for_draw_code) { - if (runtime_data->subdiv && runtime_data->set_by_draw_code != for_draw_code) { - BKE_subdiv_free(runtime_data->subdiv); - runtime_data->subdiv = nullptr; + if (for_draw_code) { + runtime_data->used_gpu = 2; /* countdown in frames */ + + return runtime_data->subdiv_gpu = BKE_subdiv_update_from_mesh( + runtime_data->subdiv_gpu, &runtime_data->settings, mesh); + } + else { + runtime_data->used_cpu = 2; + + return runtime_data->subdiv_cpu = BKE_subdiv_update_from_mesh( + runtime_data->subdiv_cpu, &runtime_data->settings, mesh); } - Subdiv *subdiv = BKE_subdiv_update_from_mesh( - runtime_data->subdiv, &runtime_data->settings, mesh); - runtime_data->subdiv = subdiv; - runtime_data->set_by_draw_code = for_draw_code; - return subdiv; } int BKE_subsurf_modifier_eval_required_mode(bool is_final_render, bool is_edit_mode) diff --git a/source/blender/modifiers/intern/MOD_subsurf.cc b/source/blender/modifiers/intern/MOD_subsurf.cc index 75377f00bb3..67e8b868f5d 100644 --- a/source/blender/modifiers/intern/MOD_subsurf.cc +++ b/source/blender/modifiers/intern/MOD_subsurf.cc @@ -100,8 +100,11 @@ static void freeRuntimeData(void *runtime_data_v) return; } SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)runtime_data_v; - if (runtime_data->subdiv != nullptr) { - BKE_subdiv_free(runtime_data->subdiv); + if (runtime_data->subdiv_cpu != nullptr) { + BKE_subdiv_free(runtime_data->subdiv_cpu); + } + if (runtime_data->subdiv_gpu != nullptr) { + BKE_subdiv_free(runtime_data->subdiv_gpu); } MEM_freeN(runtime_data); } @@ -227,6 +230,15 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime; + /* Decrement the recent usage counters. */ + if (runtime_data->used_cpu) { + runtime_data->used_cpu--; + } + + if (runtime_data->used_gpu) { + runtime_data->used_gpu--; + } + /* Delay evaluation to the draw code if possible, provided we do not have to apply the modifier. */ if ((ctx->flag & MOD_APPLY_TO_BASE_MESH) == 0) { @@ -273,7 +285,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * CustomData_set_layer_flag(&result->ldata, CD_NORMAL, CD_FLAG_TEMPORARY); } // BKE_subdiv_stats_print(&subdiv->stats); - if (subdiv != runtime_data->subdiv) { + if (subdiv != runtime_data->subdiv_cpu && subdiv != runtime_data->subdiv_gpu) { BKE_subdiv_free(subdiv); } return result; @@ -305,7 +317,7 @@ static void deformMatrices(ModifierData *md, return; } BKE_subdiv_deform_coarse_vertices(subdiv, mesh, vertex_cos, verts_num); - if (subdiv != runtime_data->subdiv) { + if (subdiv != runtime_data->subdiv_cpu && subdiv != runtime_data->subdiv_gpu) { BKE_subdiv_free(subdiv); } } @@ -409,12 +421,29 @@ static void panel_draw(const bContext *C, Panel *panel) uiItemR(layout, ptr, "show_only_control_edges", 0, nullptr, ICON_NONE); + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); SubsurfModifierData *smd = static_cast(ptr->data); - const Object *ob = static_cast(ob_ptr.data); + Object *ob = static_cast(ob_ptr.data); const Mesh *mesh = static_cast(ob->data); if (BKE_subsurf_modifier_force_disable_gpu_evaluation_for_mesh(smd, mesh)) { uiItemL(layout, "Autosmooth or custom normals detected, disabling GPU subdivision", ICON_INFO); } + else if (Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob)) { + if (ModifierData *md_eval = BKE_modifiers_findby_name(ob_eval, smd->modifier.name)) { + if (md_eval->type == eModifierType_Subsurf) { + SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)md_eval->runtime; + + if (runtime_data && runtime_data->used_gpu) { + if (runtime_data->used_cpu) { + uiItemL(layout, "Using both CPU and GPU subdivision", ICON_INFO); + } + else { + uiItemL(layout, "Using GPU subdivision", ICON_INFO); + } + } + } + } + } modifier_panel_end(layout, ptr); }