Fix T98813: crash with GPU subdiv in edit mode and instanced geometry

Instancing with geometry nodes uses just the evaluated Mesh, and ignores the
Object that it came from. That meant that it would try to look up the subsurf
modifier on the instancer object which does not have the subsurf modifier.

Instead of storing a session UUID and looking up the modifier data, store a
point to the subsurf modifier runtime data. Unlike the modifier data, this
runtime data is preserved across depsgraph CoW. It must be for the subdiv
descriptor contained in it to stay valid along with the draw cache.

As a bonus, this moves various Mesh_Runtime variables into the subsurf runtime
data, reducing memory usage for meshes not using subdivision surfaces.

Also fixes T98693, issues with subdivision level >= 8 due to integer overflow.

Differential Revision: https://developer.blender.org/D15184
This commit is contained in:
Brecht Van Lommel 2022-06-13 15:21:05 +02:00 committed by Philipp Oeser
parent 589a8104c3
commit a8c92331cb
Notes: blender-bot 2023-02-14 04:07:50 +01:00
Referenced by issue #98813, Regression: GPU subdivision crash when switched to edit mode
Referenced by issue #98693, Regression: Issue with subdivision subsurface modifier and >= 8 levels
Referenced by issue #98661, 3.2: Potential candidates for corrective releases
11 changed files with 146 additions and 150 deletions

View File

@ -7,6 +7,8 @@
#pragma once
#include "BKE_subdiv.h"
#include "BLI_sys_types.h"
#ifdef __cplusplus
@ -24,9 +26,30 @@ struct Subdiv;
struct SubdivSettings;
struct SubsurfModifierData;
void BKE_subsurf_modifier_subdiv_settings_init(struct SubdivSettings *settings,
const struct SubsurfModifierData *smd,
bool use_render_params);
/* Runtime subsurf modifier data, cached in modifier on evaluated meshes. */
typedef struct SubsurfRuntimeData {
/* Subdivision settings, exists before descriptor or mesh wrapper is created. */
SubdivSettings settings;
/* Cached subdivision surface descriptor, with topology and settings. */
struct Subdiv *subdiv;
bool set_by_draw_code;
/* Cached mesh wrapper data, to be used for GPU subdiv or lazy evaluation on CPU. */
bool has_gpu_subdiv;
int resolution;
bool use_optimal_display;
bool calc_loop_normals;
bool use_loop_normals;
/* Cached from the draw code for stats display. */
int stats_totvert;
int stats_totedge;
int stats_totpoly;
int stats_totloop;
} SubsurfRuntimeData;
bool BKE_subsurf_modifier_runtime_init(struct SubsurfModifierData *smd, bool use_render_params);
bool BKE_subsurf_modifier_use_custom_loop_normals(const struct SubsurfModifierData *smd,
const struct Mesh *mesh);
@ -57,12 +80,7 @@ extern void (*BKE_subsurf_modifier_free_gpu_cache_cb)(struct Subdiv *subdiv);
* which matches settings and topology.
*/
struct Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure(
const struct SubsurfModifierData *smd,
const struct SubdivSettings *subdiv_settings,
const struct Mesh *mesh,
bool for_draw_code);
struct SubsurfRuntimeData *BKE_subsurf_modifier_ensure_runtime(struct SubsurfModifierData *smd);
struct SubsurfRuntimeData *runtime_data, const struct Mesh *mesh, bool for_draw_code);
/**
* Return the #ModifierMode required for the evaluation of the subsurf modifier,

View File

@ -52,6 +52,7 @@
#include "BKE_object.h"
#include "BKE_object_deform.h"
#include "BKE_paint.h"
#include "BKE_subdiv_modifier.h"
#include "BLI_sys_types.h" /* for intptr_t support */
@ -613,10 +614,10 @@ static bool mesh_has_modifier_final_normals(const Mesh *mesh_input,
/* Test if mesh has the required loop normals, in case an additional modifier
* evaluation from another instance or from an operator requests it but the
* initial normals were not loop normals. */
const bool do_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
(final_datamask->lmask & CD_MASK_NORMAL) != 0);
const bool calc_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
(final_datamask->lmask & CD_MASK_NORMAL) != 0);
return (!do_loop_normals || CustomData_has_layer(&mesh_final->ldata, CD_NORMAL));
return (!calc_loop_normals || CustomData_has_layer(&mesh_final->ldata, CD_NORMAL));
}
static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
@ -625,16 +626,19 @@ static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
Mesh *mesh_final)
{
/* Compute normals. */
const bool do_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
(final_datamask->lmask & CD_MASK_NORMAL) != 0);
const bool calc_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
(final_datamask->lmask & CD_MASK_NORMAL) != 0);
/* Needed as `final_datamask` is not preserved outside modifier stack evaluation. */
mesh_final->runtime.subsurf_do_loop_normals = do_loop_normals;
SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime.subsurf_runtime_data;
if (subsurf_runtime_data) {
subsurf_runtime_data->calc_loop_normals = calc_loop_normals;
}
if (do_loop_normals) {
if (calc_loop_normals) {
/* Compute loop normals (NOTE: will compute poly and vert normals as well, if needed!). In case
* of deferred CPU subdivision, this will be computed when the wrapper is generated. */
if (mesh_final->runtime.subsurf_resolution == 0) {
if (!subsurf_runtime_data || subsurf_runtime_data->resolution == 0) {
BKE_mesh_calc_normals_split(mesh_final);
}
}
@ -1281,15 +1285,18 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
return;
}
const bool do_loop_normals = ((mesh_final->flag & ME_AUTOSMOOTH) != 0 ||
(final_datamask->lmask & CD_MASK_NORMAL) != 0);
const bool calc_loop_normals = ((mesh_final->flag & ME_AUTOSMOOTH) != 0 ||
(final_datamask->lmask & CD_MASK_NORMAL) != 0);
mesh_final->runtime.subsurf_do_loop_normals = do_loop_normals;
SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime.subsurf_runtime_data;
if (subsurf_runtime_data) {
subsurf_runtime_data->calc_loop_normals = calc_loop_normals;
}
if (do_loop_normals) {
if (calc_loop_normals) {
/* Compute loop normals. In case of deferred CPU subdivision, this will be computed when the
* wrapper is generated. */
if (mesh_final->runtime.subsurf_resolution == 0) {
if (!subsurf_runtime_data || subsurf_runtime_data->resolution == 0) {
BKE_mesh_calc_normals_split(mesh_final);
}
}

View File

@ -314,28 +314,23 @@ static Mesh *mesh_wrapper_ensure_subdivision(const Object *ob, Mesh *me)
return me;
}
SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
if (runtime_data == nullptr || runtime_data->settings.level == 0) {
return me;
}
/* Initialize the settings before ensuring the descriptor as this is checked to decide whether
* subdivision is needed at all, and checking the descriptor status might involve checking if the
* data is out-of-date, which is a very expensive operation. */
SubdivToMeshSettings mesh_settings;
mesh_settings.resolution = me->runtime.subsurf_resolution;
mesh_settings.use_optimal_display = me->runtime.subsurf_use_optimal_display;
mesh_settings.resolution = runtime_data->resolution;
mesh_settings.use_optimal_display = runtime_data->use_optimal_display;
if (mesh_settings.resolution < 3) {
return me;
}
const bool apply_render = me->runtime.subsurf_apply_render;
SubdivSettings subdiv_settings;
BKE_subsurf_modifier_subdiv_settings_init(&subdiv_settings, smd, apply_render);
if (subdiv_settings.level == 0) {
return me;
}
SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(smd, &subdiv_settings, me, false);
Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, me, false);
if (subdiv == nullptr) {
/* Happens on bad topology, but also on empty input mesh. */
return me;
@ -358,7 +353,7 @@ static Mesh *mesh_wrapper_ensure_subdivision(const Object *ob, Mesh *me)
CustomData_set_layer_flag(&me->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
CustomData_set_layer_flag(&subdiv_mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
}
else if (me->runtime.subsurf_do_loop_normals) {
else if (runtime_data->calc_loop_normals) {
BKE_mesh_calc_normals_split(subdiv_mesh);
}

View File

@ -3,8 +3,6 @@
#include "BKE_subdiv_modifier.h"
#include "BLI_session_uuid.h"
#include "MEM_guardedalloc.h"
#include "DNA_mesh_types.h"
@ -21,22 +19,40 @@
#include "opensubdiv_capi.h"
void BKE_subsurf_modifier_subdiv_settings_init(SubdivSettings *settings,
const SubsurfModifierData *smd,
const bool use_render_params)
bool BKE_subsurf_modifier_runtime_init(SubsurfModifierData *smd, const bool use_render_params)
{
const int requested_levels = (use_render_params) ? smd->renderLevels : smd->levels;
settings->is_simple = (smd->subdivType == SUBSURF_TYPE_SIMPLE);
settings->is_adaptive = !(smd->flags & eSubsurfModifierFlag_UseRecursiveSubdivision);
settings->level = settings->is_simple ?
1 :
(settings->is_adaptive ? smd->quality : requested_levels);
settings->use_creases = (smd->flags & eSubsurfModifierFlag_UseCrease);
settings->vtx_boundary_interpolation = BKE_subdiv_vtx_boundary_interpolation_from_subsurf(
SubdivSettings settings;
settings.is_simple = (smd->subdivType == SUBSURF_TYPE_SIMPLE);
settings.is_adaptive = !(smd->flags & eSubsurfModifierFlag_UseRecursiveSubdivision);
settings.level = settings.is_simple ? 1 :
(settings.is_adaptive ? smd->quality : requested_levels);
settings.use_creases = (smd->flags & eSubsurfModifierFlag_UseCrease);
settings.vtx_boundary_interpolation = BKE_subdiv_vtx_boundary_interpolation_from_subsurf(
smd->boundary_smooth);
settings->fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth(
settings.fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth(
smd->uv_smooth);
SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
if (settings.level == 0) {
/* Modifier is effectively disabled, but still update settings if runtime data
* was already allocated. */
if (runtime_data) {
runtime_data->settings = settings;
}
return false;
}
else {
/* Allocate runtime data if it did not exist yet. */
if (runtime_data == NULL) {
runtime_data = MEM_callocN(sizeof(*runtime_data), "subsurf runtime");
smd->modifier.runtime = runtime_data;
}
runtime_data->settings = settings;
return true;
}
}
static ModifierData *modifier_get_last_enabled_for_mode(const Scene *scene,
@ -133,37 +149,27 @@ bool BKE_subsurf_modifier_can_do_gpu_subdiv(const Scene *scene,
bool BKE_subsurf_modifier_has_gpu_subdiv(const Mesh *mesh)
{
return BLI_session_uuid_is_generated(&mesh->runtime.subsurf_session_uuid);
SubsurfRuntimeData *runtime_data = mesh->runtime.subsurf_runtime_data;
return runtime_data && runtime_data->has_gpu_subdiv;
}
void (*BKE_subsurf_modifier_free_gpu_cache_cb)(Subdiv *subdiv) = NULL;
Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure(const SubsurfModifierData *smd,
const SubdivSettings *subdiv_settings,
Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure(SubsurfRuntimeData *runtime_data,
const Mesh *mesh,
const bool for_draw_code)
{
SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
if (runtime_data->subdiv && runtime_data->set_by_draw_code != for_draw_code) {
BKE_subdiv_free(runtime_data->subdiv);
runtime_data->subdiv = NULL;
}
Subdiv *subdiv = BKE_subdiv_update_from_mesh(runtime_data->subdiv, subdiv_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;
}
SubsurfRuntimeData *BKE_subsurf_modifier_ensure_runtime(SubsurfModifierData *smd)
{
SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
if (runtime_data == NULL) {
runtime_data = MEM_callocN(sizeof(*runtime_data), "subsurf runtime");
smd->modifier.runtime = runtime_data;
}
return runtime_data;
}
int BKE_subsurf_modifier_eval_required_mode(bool is_final_render, bool is_edit_mode)
{
if (is_final_render) {

View File

@ -2167,8 +2167,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
}
if (do_subdivision) {
DRW_create_subdivision(scene,
ob,
DRW_create_subdivision(ob,
me,
cache,
&cache->final,

View File

@ -1023,14 +1023,10 @@ static void build_vertex_face_adjacency_maps(DRWSubdivCache *cache)
static bool draw_subdiv_build_cache(DRWSubdivCache *cache,
Subdiv *subdiv,
Mesh *mesh_eval,
const Scene *scene,
const SubsurfModifierData *smd,
const bool is_final_render)
const SubsurfRuntimeData *runtime_data)
{
const int requested_levels = (is_final_render) ? smd->renderLevels : smd->levels;
const int level = get_render_subsurf_level(&scene->r, requested_levels, is_final_render);
SubdivToMeshSettings to_mesh_settings;
to_mesh_settings.resolution = (1 << level) + 1;
to_mesh_settings.resolution = runtime_data->resolution;
to_mesh_settings.use_optimal_display = false;
if (cache->resolution != to_mesh_settings.resolution) {
@ -1960,8 +1956,7 @@ static void draw_subdiv_cache_ensure_mat_offsets(DRWSubdivCache *cache,
MEM_freeN(per_polygon_mat_offset);
}
static bool draw_subdiv_create_requested_buffers(const Scene *scene,
Object *ob,
static bool draw_subdiv_create_requested_buffers(Object *ob,
Mesh *mesh,
struct MeshBatchCache *batch_cache,
MeshBufferCache *mbc,
@ -1975,16 +1970,10 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
const bool use_hide,
OpenSubdiv_EvaluatorCache *evaluator_cache)
{
SubsurfModifierData *smd = reinterpret_cast<SubsurfModifierData *>(
BKE_modifiers_findby_session_uuid(ob, &mesh->runtime.subsurf_session_uuid));
BLI_assert(smd);
SubsurfRuntimeData *runtime_data = mesh->runtime.subsurf_runtime_data;
BLI_assert(runtime_data && runtime_data->has_gpu_subdiv);
const bool is_final_render = DRW_state_is_scene_render();
SubdivSettings settings;
BKE_subsurf_modifier_subdiv_settings_init(&settings, smd, is_final_render);
if (settings.level == 0) {
if (runtime_data->settings.level == 0) {
return false;
}
@ -1995,9 +1984,7 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
bm = mesh->edit_mesh->bm;
}
BKE_subsurf_modifier_ensure_runtime(smd);
Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(smd, &settings, mesh_eval, true);
Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh_eval, true);
if (!subdiv) {
return false;
}
@ -2016,13 +2003,13 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
}
DRWSubdivCache *draw_cache = mesh_batch_cache_ensure_subdiv_cache(batch_cache);
if (!draw_subdiv_build_cache(draw_cache, subdiv, mesh_eval, scene, smd, is_final_render)) {
if (!draw_subdiv_build_cache(draw_cache, subdiv, mesh_eval, runtime_data)) {
return false;
}
/* Edges which do not come from coarse edges should not be drawn in edit mode, only in object
* mode when optimal display in turned off. */
const bool optimal_display = (smd->flags & eSubsurfModifierFlag_ControlEdges) || is_editmode;
const bool optimal_display = runtime_data->use_optimal_display || is_editmode;
draw_cache->bm = bm;
draw_cache->mesh = mesh_eval;
@ -2030,14 +2017,13 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
draw_cache->optimal_display = optimal_display;
draw_cache->num_subdiv_triangles = tris_count_from_number_of_loops(draw_cache->num_subdiv_loops);
/* Copy topology information for stats display. Use `mesh` directly, as `mesh_eval` could be the
* edit mesh. */
mesh->runtime.subsurf_totvert = draw_cache->num_subdiv_verts;
mesh->runtime.subsurf_totedge = draw_cache->num_subdiv_edges;
mesh->runtime.subsurf_totpoly = draw_cache->num_subdiv_quads;
mesh->runtime.subsurf_totloop = draw_cache->num_subdiv_loops;
/* Copy topology information for stats display. */
runtime_data->stats_totvert = draw_cache->num_subdiv_verts;
runtime_data->stats_totedge = draw_cache->num_subdiv_edges;
runtime_data->stats_totpoly = draw_cache->num_subdiv_quads;
runtime_data->stats_totloop = draw_cache->num_subdiv_loops;
draw_cache->use_custom_loop_normals = (smd->flags & eSubsurfModifierFlag_UseCustomNormals) &&
draw_cache->use_custom_loop_normals = (runtime_data->use_loop_normals) &&
(mesh_eval->flag & ME_AUTOSMOOTH) &&
CustomData_has_layer(&mesh_eval->ldata,
CD_CUSTOMLOOPNORMAL);
@ -2159,8 +2145,7 @@ blender::Span<DRWSubdivLooseVertex> draw_subdiv_cache_get_loose_verts(const DRWS
static OpenSubdiv_EvaluatorCache *g_evaluator_cache = nullptr;
void DRW_create_subdivision(const Scene *scene,
Object *ob,
void DRW_create_subdivision(Object *ob,
Mesh *mesh,
struct MeshBatchCache *batch_cache,
MeshBufferCache *mbc,
@ -2183,8 +2168,7 @@ void DRW_create_subdivision(const Scene *scene,
const double begin_time = PIL_check_seconds_timer();
#endif
if (!draw_subdiv_create_requested_buffers(scene,
ob,
if (!draw_subdiv_create_requested_buffers(ob,
mesh,
batch_cache,
mbc,

View File

@ -185,8 +185,7 @@ void draw_subdiv_cache_free(DRWSubdivCache *cache);
/** \} */
void DRW_create_subdivision(const struct Scene *scene,
struct Object *ob,
void DRW_create_subdivision(struct Object *ob,
struct Mesh *mesh,
struct MeshBatchCache *batch_cache,
struct MeshBufferCache *mbc,

View File

@ -46,6 +46,7 @@
#include "BKE_pbvh.h"
#include "BKE_scene.h"
#include "BKE_subdiv_ccg.h"
#include "BKE_subdiv_modifier.h"
#include "DEG_depsgraph_query.h"
@ -92,15 +93,18 @@ static bool stats_mesheval(const Mesh *me_eval, bool is_selected, SceneStats *st
}
int totvert, totedge, totface, totloop;
if (me_eval->runtime.subdiv_ccg != nullptr) {
const SubdivCCG *subdiv_ccg = me_eval->runtime.subdiv_ccg;
const SubdivCCG *subdiv_ccg = me_eval->runtime.subdiv_ccg;
const SubsurfRuntimeData *subsurf_runtime_data = me_eval->runtime.subsurf_runtime_data;
if (subdiv_ccg != nullptr) {
BKE_subdiv_ccg_topology_counters(subdiv_ccg, &totvert, &totedge, &totface, &totloop);
}
else if (me_eval->runtime.subsurf_resolution != 0) {
totvert = me_eval->runtime.subsurf_totvert;
totedge = me_eval->runtime.subsurf_totedge;
totface = me_eval->runtime.subsurf_totpoly;
totloop = me_eval->runtime.subsurf_totloop;
else if (subsurf_runtime_data && subsurf_runtime_data->resolution != 0) {
totvert = subsurf_runtime_data->stats_totvert;
totedge = subsurf_runtime_data->stats_totedge;
totface = subsurf_runtime_data->stats_totpoly;
totloop = subsurf_runtime_data->stats_totloop;
}
else {
totvert = me_eval->totvert;

View File

@ -32,6 +32,7 @@ struct MVert;
struct Material;
struct Mesh;
struct SubdivCCG;
struct SubsurfRuntimeData;
#
#
@ -123,26 +124,18 @@ typedef struct Mesh_Runtime {
/**
* Settings for lazily evaluating the subdivision on the CPU if needed. These are
* set in the modifier when GPU subdivision can be performed.
* set in the modifier when GPU subdivision can be performed, and owned by the by
* the modifier in the object.
*/
SessionUUID subsurf_session_uuid;
char subsurf_resolution;
char subsurf_do_loop_normals;
char subsurf_apply_render;
char subsurf_use_optimal_display;
/* Cached from the draw code for stats display. */
int subsurf_totvert;
int subsurf_totedge;
int subsurf_totpoly;
int subsurf_totloop;
char _pad2[2];
struct SubsurfRuntimeData *subsurf_runtime_data;
void *_pad1;
/**
* Caches for lazily computed vertex and polygon normals. These are stored here rather than in
* #CustomData because they can be calculated on a const mesh, and adding custom data layers on a
* const mesh is not thread-safe.
*/
char _pad2[6];
char vert_normals_dirty;
char poly_normals_dirty;
float (*vert_normals)[3];

View File

@ -178,13 +178,6 @@ typedef enum {
SUBSURF_BOUNDARY_SMOOTH_PRESERVE_CORNERS = 1,
} eSubsurfBoundarySmooth;
typedef struct SubsurfRuntimeData {
/* Cached subdivision surface descriptor, with topology and settings. */
struct Subdiv *subdiv;
char set_by_draw_code;
char _pad[7];
} SubsurfRuntimeData;
typedef struct SubsurfModifierData {
ModifierData modifier;

View File

@ -196,16 +196,21 @@ static Mesh *subdiv_as_ccg(SubsurfModifierData *smd,
/* Cache settings for lazy CPU evaluation. */
static void subdiv_cache_cpu_evaluation_settings(const ModifierEvalContext *ctx,
Mesh *me,
SubsurfModifierData *smd)
static void subdiv_cache_mesh_wrapper_settings(const ModifierEvalContext *ctx,
Mesh *mesh,
SubsurfModifierData *smd,
SubsurfRuntimeData *runtime_data)
{
SubdivToMeshSettings mesh_settings;
subdiv_mesh_settings_init(&mesh_settings, smd, ctx);
me->runtime.subsurf_apply_render = (ctx->flag & MOD_APPLY_RENDER) != 0;
me->runtime.subsurf_resolution = mesh_settings.resolution;
me->runtime.subsurf_use_optimal_display = mesh_settings.use_optimal_display;
me->runtime.subsurf_session_uuid = smd->modifier.session_uuid;
runtime_data->has_gpu_subdiv = true;
runtime_data->resolution = mesh_settings.resolution;
runtime_data->use_optimal_display = mesh_settings.use_optimal_display;
runtime_data->calc_loop_normals = false; /* Set at the end of modifier stack evaluation. */
runtime_data->use_loop_normals = (smd->flags & eSubsurfModifierFlag_UseCustomNormals);
mesh->runtime.subsurf_runtime_data = runtime_data;
}
/* Modifier itself. */
@ -218,13 +223,11 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
return result;
#endif
SubsurfModifierData *smd = (SubsurfModifierData *)md;
SubdivSettings subdiv_settings;
BKE_subsurf_modifier_subdiv_settings_init(
&subdiv_settings, smd, (ctx->flag & MOD_APPLY_RENDER) != 0);
if (subdiv_settings.level == 0) {
if (!BKE_subsurf_modifier_runtime_init(smd, (ctx->flag & MOD_APPLY_RENDER) != 0)) {
return result;
}
SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
/* Delay evaluation to the draw code if possible, provided we do not have to apply the modifier.
*/
@ -237,13 +240,12 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
const bool is_editmode = (mesh->edit_mesh != NULL);
const int required_mode = BKE_subsurf_modifier_eval_required_mode(is_render_mode, is_editmode);
if (BKE_subsurf_modifier_can_do_gpu_subdiv(scene, ctx->object, mesh, smd, required_mode)) {
subdiv_cache_cpu_evaluation_settings(ctx, mesh, smd);
subdiv_cache_mesh_wrapper_settings(ctx, mesh, smd, runtime_data);
return result;
}
}
Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(
smd, &subdiv_settings, mesh, false);
Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh, false);
if (subdiv == NULL) {
/* Happens on bad topology, but also on empty input mesh. */
return result;
@ -294,15 +296,11 @@ static void deformMatrices(ModifierData *md,
(void)deform_matrices;
SubsurfModifierData *smd = (SubsurfModifierData *)md;
SubdivSettings subdiv_settings;
BKE_subsurf_modifier_subdiv_settings_init(
&subdiv_settings, smd, (ctx->flag & MOD_APPLY_RENDER) != 0);
if (subdiv_settings.level == 0) {
if (!BKE_subsurf_modifier_runtime_init(smd, (ctx->flag & MOD_APPLY_RENDER) != 0)) {
return;
}
SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(
smd, &subdiv_settings, mesh, false);
SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh, false);
if (subdiv == NULL) {
/* Happens on bad topology, but also on empty input mesh. */
return;