Commit: c0d9c7cf4671c85e30959a3526f9a3eb4b5c1382
Author: Alexander Gavrilov
Date:   Wed Jan 25 11:34:58 2023 +0200
Branches: temp-angavrilov
https://developer.blender.org/rBc0d9c7cf4671c85e30959a3526f9a3eb4b5c1382

Subdivision Surface: fix a serious performance hit when mixing CPU & GPU.

Subdivision surface efficiency relies on caching pre-computed topology
data for evaluation between frames. However, while rBeed45d2a239a
introduced a second GPU subdiv evaluator type, it still only kept
one slot for caching this runtime data per mesh.

The result is that if the mesh is also needed on CPU, for instance
due to a modifier on a different object (e.g. shrinkwrap), the two
evaluators are used at the same time and fight over the single slot.
This causes the topology data to be discarded and recomputed twice
per frame.

Since avoiding duplicate evaluation is a complex task, this fix
simply adds a second separate cache slot for the GPU data, so that
the cost is simply running subdivision twice, not recomputing topology
twice.

To help diagnostics, I also add a message to show when GPU evaluation
is actually used to the modifier panel. Two frame counters are used
to suppress flicker in the UI panel.

Differential Revision: https://developer.blender.org/D17117

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

M       source/blender/blenkernel/BKE_subdiv_modifier.h
M       source/blender/blenkernel/intern/mesh_wrapper.cc
M       source/blender/blenkernel/intern/subdiv_modifier.cc
M       source/blender/modifiers/intern/MOD_subsurf.cc

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

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..7f6a9696b56 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<SubsurfModifierData *>(ptr->data);
-  const Object *ob = static_cast<const Object *>(ob_ptr.data);
+  Object *ob = static_cast<Object *>(ob_ptr.data);
   const Mesh *mesh = static_cast<const Mesh *>(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_ERROR);
+          }
+          else {
+            uiItemL(layout, "Using GPU subdivision", ICON_INFO);
+          }
+        }
+      }
+    }
+  }
 
   modifier_panel_end(layout, ptr);
 }

_______________________________________________
Bf-blender-cvs mailing list
Bf-blender-cvs@blender.org
List details, subscription details or unsubscribe:
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to