Subdiv: Enable topology cache in edit mode
The general idea of this change is to have a runtime data pointer in the ModifierData, so it can be preserved through copy-on-write updates by the dependency graph. This is where subdivision surface modifier can store its topology cache, so it is not getting trashed on every copy-on-write which is happening when moving a vertex. Similar mechanism should be used by multiresolution, dynamic paint and some other modifiers which cache evaluated data. This fixes T61746. Thing to keep in mind, that there are more reports about slow subdivision surface in the tracker, but that boils down to the fact that those have a lot of extraordinary vertices, and hence a lot slower to evaluated topology. Other thing is, this speeds up oeprations which doesn't change topology (i.e. moving vertices). Reviewers: brecht Reviewed By: brecht Maniphest Tasks: T61746 Differential Revision: https://developer.blender.org/D4541
This commit is contained in:
parent
91ffd39e77
commit
8fb0b9aebb
|
@ -233,6 +233,8 @@ typedef struct ModifierTypeInfo {
|
|||
/* Free internal modifier data variables, this function should
|
||||
* not free the md variable itself.
|
||||
*
|
||||
* This function is responsible for freeing the runtime data as well.
|
||||
*
|
||||
* This function is optional.
|
||||
*/
|
||||
void (*freeData)(struct ModifierData *md);
|
||||
|
@ -301,6 +303,18 @@ typedef struct ModifierTypeInfo {
|
|||
*/
|
||||
void (*foreachTexLink)(struct ModifierData *md, struct Object *ob,
|
||||
TexWalkFunc walk, void *userData);
|
||||
|
||||
/* Free given runtime data.
|
||||
*
|
||||
* This data is coming from a modifier of the corresponding type, but actual
|
||||
* modifier data is not known here.
|
||||
*
|
||||
* Notes:
|
||||
* - The data itself is to be de-allocated as well.
|
||||
* - This calback is allowed to receive NULL pointer as a data, so it's
|
||||
* more like "ensure the data is freed".
|
||||
*/
|
||||
void (*freeRuntimeData)(void *runtime_data);
|
||||
} ModifierTypeInfo;
|
||||
|
||||
/* Initialize modifier's global data (type info and some common global storages). */
|
||||
|
|
|
@ -5458,6 +5458,7 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
|
|||
|
||||
for (md = lb->first; md; md = md->next) {
|
||||
md->error = NULL;
|
||||
md->runtime = NULL;
|
||||
|
||||
/* if modifiers disappear, or for upward compatibility */
|
||||
if (NULL == modifierType_getInfo(md->type))
|
||||
|
@ -5467,7 +5468,6 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
|
|||
SubsurfModifierData *smd = (SubsurfModifierData *)md;
|
||||
|
||||
smd->emCache = smd->mCache = NULL;
|
||||
smd->subdiv = NULL;
|
||||
}
|
||||
else if (md->type == eModifierType_Armature) {
|
||||
ArmatureModifierData *amd = (ArmatureModifierData *)md;
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
struct Depsgraph;
|
||||
|
||||
|
@ -46,10 +48,14 @@ namespace DEG {
|
|||
/* Commonly used types. */
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::map;
|
||||
using std::pair;
|
||||
using std::unordered_map;
|
||||
|
||||
/* Commonly used functions. */
|
||||
using std::max;
|
||||
using std::to_string;
|
||||
using std::make_pair;
|
||||
|
||||
/* Function bindings. */
|
||||
using std::function;
|
||||
|
|
|
@ -83,6 +83,7 @@ extern "C" {
|
|||
#include "BKE_armature.h"
|
||||
#include "BKE_editmesh.h"
|
||||
#include "BKE_library_query.h"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_object.h"
|
||||
}
|
||||
|
||||
|
@ -846,43 +847,119 @@ ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph,
|
|||
create_placeholders);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/* Identifier used to match modifiers to backup/restore their runtime data.
|
||||
* Identification is happening using original modifier data pointer and the
|
||||
* modifier type.
|
||||
* It is not enough to only pointer, since it's possible to have a situation
|
||||
* when modifier is removed and a new one added, and due to memory allocation
|
||||
* policy they might have same pointer.
|
||||
* By adding type into matching we are at least ensuring that modifier will not
|
||||
* try to interpret runtime data created by another modifier type. */
|
||||
class ModifierDataBackupID {
|
||||
public:
|
||||
ModifierDataBackupID() : ModifierDataBackupID(NULL, eModifierType_None)
|
||||
{
|
||||
}
|
||||
|
||||
ModifierDataBackupID(ModifierData *modifier_data, ModifierType type)
|
||||
: modifier_data(modifier_data),
|
||||
type(type)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator <(const ModifierDataBackupID& other) const {
|
||||
if (modifier_data < other.modifier_data) {
|
||||
return true;
|
||||
}
|
||||
if (modifier_data == other.modifier_data) {
|
||||
return static_cast<int>(type) < static_cast<int>(other.type);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ModifierData *modifier_data;
|
||||
ModifierType type;
|
||||
};
|
||||
|
||||
/* Storage for backed up runtime modifier data. */
|
||||
typedef map<ModifierDataBackupID, void*> ModifierRuntimeDataBackup;
|
||||
|
||||
struct ObjectRuntimeBackup {
|
||||
ObjectRuntimeBackup()
|
||||
: base_flag(0),
|
||||
base_local_view_bits(0)
|
||||
{
|
||||
/* TODO(sergey): Use something like BKE_object_runtime_reset(). */
|
||||
memset(&runtime, 0, sizeof(runtime));
|
||||
}
|
||||
|
||||
/* Make a backup of object's evaluation runtime data, additionally
|
||||
* make object to be safe for free without invalidating backed up
|
||||
* pointers. */
|
||||
void init_from_object(Object *object);
|
||||
void backup_modifier_runtime_data(Object *object);
|
||||
|
||||
/* Restore all fields to the given object. */
|
||||
void restore_to_object(Object *object);
|
||||
/* NOTE: Will free all runtime data which has not been restored. */
|
||||
void restore_modifier_runtime_data(Object *object);
|
||||
|
||||
Object_Runtime runtime;
|
||||
short base_flag;
|
||||
unsigned short base_local_view_bits;
|
||||
ModifierRuntimeDataBackup modifier_runtime_data;
|
||||
};
|
||||
|
||||
/* Make a backup of object's evaluation runtime data, additionally
|
||||
* make object to be safe for free without invalidating backed up
|
||||
* pointers. */
|
||||
static void deg_backup_object_runtime(
|
||||
Object *object,
|
||||
ObjectRuntimeBackup *object_runtime_backup)
|
||||
void ObjectRuntimeBackup::init_from_object(Object *object)
|
||||
{
|
||||
/* Store evaluated mesh and curve_cache, and make sure we don't free it. */
|
||||
Mesh *mesh_eval = object->runtime.mesh_eval;
|
||||
object_runtime_backup->runtime = object->runtime;
|
||||
runtime = object->runtime;
|
||||
BKE_object_runtime_reset(object);
|
||||
/* Keep bbox (for now at least...). */
|
||||
object->runtime.bb = object_runtime_backup->runtime.bb;
|
||||
/* Keep bbox (for now at least). */
|
||||
object->runtime.bb = runtime.bb;
|
||||
/* Object update will override actual object->data to an evaluated version.
|
||||
* Need to make sure we don't have data set to evaluated one before free
|
||||
* anything. */
|
||||
if (mesh_eval != NULL && object->data == mesh_eval) {
|
||||
object->data = object_runtime_backup->runtime.mesh_orig;
|
||||
object->data = runtime.mesh_orig;
|
||||
}
|
||||
/* Make a backup of base flags. */
|
||||
object_runtime_backup->base_flag = object->base_flag;
|
||||
object_runtime_backup->base_local_view_bits = object->base_local_view_bits;
|
||||
base_flag = object->base_flag;
|
||||
base_local_view_bits = object->base_local_view_bits;
|
||||
/* Backup tuntime data of all modifiers. */
|
||||
backup_modifier_runtime_data(object);
|
||||
}
|
||||
|
||||
static void deg_restore_object_runtime(
|
||||
Object *object,
|
||||
const ObjectRuntimeBackup *object_runtime_backup)
|
||||
inline ModifierDataBackupID create_modifier_data_id(
|
||||
const ModifierData* modifier_data)
|
||||
{
|
||||
return ModifierDataBackupID(modifier_data->orig_modifier_data,
|
||||
static_cast<ModifierType>(modifier_data->type));
|
||||
}
|
||||
|
||||
void ObjectRuntimeBackup::backup_modifier_runtime_data(Object *object)
|
||||
{
|
||||
LISTBASE_FOREACH(ModifierData *, modifier_data, &object->modifiers) {
|
||||
if (modifier_data->runtime == NULL) {
|
||||
continue;
|
||||
}
|
||||
BLI_assert(modifier_data->orig_modifier_data != NULL);
|
||||
ModifierDataBackupID modifier_data_id =
|
||||
create_modifier_data_id(modifier_data);
|
||||
modifier_runtime_data.insert(
|
||||
make_pair(modifier_data_id, modifier_data->runtime));
|
||||
modifier_data->runtime = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectRuntimeBackup::restore_to_object(Object *object)
|
||||
{
|
||||
Mesh *mesh_orig = object->runtime.mesh_orig;
|
||||
BoundBox *bb = object->runtime.bb;
|
||||
object->runtime = object_runtime_backup->runtime;
|
||||
object->runtime = runtime;
|
||||
object->runtime.mesh_orig = mesh_orig;
|
||||
object->runtime.bb = bb;
|
||||
if (object->type == OB_MESH && object->runtime.mesh_eval != NULL) {
|
||||
|
@ -909,60 +986,108 @@ static void deg_restore_object_runtime(
|
|||
mesh_eval->edit_mesh = mesh_orig->edit_mesh;
|
||||
}
|
||||
}
|
||||
object->base_flag = object_runtime_backup->base_flag;
|
||||
object->base_local_view_bits = object_runtime_backup->base_local_view_bits;
|
||||
object->base_flag = base_flag;
|
||||
object->base_local_view_bits = base_local_view_bits;
|
||||
/* Restore modifier's runtime data.
|
||||
* NOTE: Data of unused modifiers will be freed there. */
|
||||
restore_modifier_runtime_data(object);
|
||||
}
|
||||
|
||||
void ObjectRuntimeBackup::restore_modifier_runtime_data(Object *object) {
|
||||
LISTBASE_FOREACH(ModifierData *, modifier_data, &object->modifiers) {
|
||||
BLI_assert(modifier_data->orig_modifier_data != NULL);
|
||||
ModifierDataBackupID modifier_data_id =
|
||||
create_modifier_data_id(modifier_data);
|
||||
ModifierRuntimeDataBackup::iterator runtime_data_iterator =
|
||||
modifier_runtime_data.find(modifier_data_id);
|
||||
if (runtime_data_iterator != modifier_runtime_data.end()) {
|
||||
modifier_data->runtime = runtime_data_iterator->second;
|
||||
runtime_data_iterator->second = NULL;
|
||||
}
|
||||
}
|
||||
for (ModifierRuntimeDataBackup::value_type value : modifier_runtime_data) {
|
||||
const ModifierDataBackupID modifier_data_id = value.first;
|
||||
void *runtime = value.second;
|
||||
if (value.second == NULL) {
|
||||
continue;
|
||||
}
|
||||
const ModifierTypeInfo *modifier_type_info =
|
||||
modifierType_getInfo(modifier_data_id.type);
|
||||
BLI_assert(modifier_type_info != NULL);
|
||||
modifier_type_info->freeRuntimeData(runtime);
|
||||
}
|
||||
}
|
||||
|
||||
class RuntimeBackup {
|
||||
public:
|
||||
RuntimeBackup() : drawdata_ptr(NULL) {
|
||||
drawdata_backup.first = drawdata_backup.last = NULL;
|
||||
}
|
||||
|
||||
/* NOTE: Will reset all runbtime fields which has been backed up to NULL. */
|
||||
void init_from_id(ID *id);
|
||||
|
||||
/* Restore fields to the given ID. */
|
||||
void restore_to_id(ID *id);
|
||||
|
||||
ObjectRuntimeBackup object_backup;
|
||||
DrawDataList drawdata_backup;
|
||||
DrawDataList *drawdata_ptr;
|
||||
};
|
||||
|
||||
void RuntimeBackup::init_from_id(ID *id)
|
||||
{
|
||||
if (!check_datablock_expanded(id)) {
|
||||
return;
|
||||
}
|
||||
const ID_Type id_type = GS(id->name);
|
||||
switch (id_type) {
|
||||
case ID_OB:
|
||||
object_backup.init_from_object(reinterpret_cast<Object*>(id));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* Note that we never free GPU draw data from here since that's not
|
||||
* safe for threading and draw data is likely to be re-used. */
|
||||
drawdata_ptr = DRW_drawdatalist_from_id(id);
|
||||
if (drawdata_ptr != NULL) {
|
||||
drawdata_backup = *drawdata_ptr;
|
||||
drawdata_ptr->first = drawdata_ptr->last = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void RuntimeBackup::restore_to_id(ID *id)
|
||||
{
|
||||
const ID_Type id_type = GS(id->name);
|
||||
switch (id_type) {
|
||||
case ID_OB:
|
||||
object_backup.restore_to_object(reinterpret_cast<Object*>(id));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (drawdata_ptr != NULL) {
|
||||
*drawdata_ptr = drawdata_backup;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph,
|
||||
const IDNode *id_node)
|
||||
{
|
||||
const ID *id_orig = id_node->id_orig;
|
||||
const ID_Type id_type = GS(id_orig->name);
|
||||
ID *id_cow = id_node->id_cow;
|
||||
/* Similar to expansion, no need to do anything here. */
|
||||
if (!deg_copy_on_write_is_needed(id_orig)) {
|
||||
return id_cow;
|
||||
}
|
||||
/* For the rest if datablock types we use simple logic:
|
||||
* - Free previously expanded data, if any.
|
||||
* - Perform full datablock copy.
|
||||
*
|
||||
* Note that we never free GPU draw data from here since that's not
|
||||
* safe for threading and draw data is likely to be re-used. */
|
||||
/* TODO(sergey): Either move this to an utility function or redesign
|
||||
* Copy-on-Write components in a way that only needed parts are being
|
||||
* copied over. */
|
||||
/* TODO(sergey): Wrap GPU draw data backup and object runtime backup to a
|
||||
* generic backup structure. */
|
||||
DrawDataList drawdata_backup;
|
||||
DrawDataList *drawdata_ptr = NULL;
|
||||
ObjectRuntimeBackup object_runtime_backup = {{{0}}};
|
||||
if (check_datablock_expanded(id_cow)) {
|
||||
switch (id_type) {
|
||||
case ID_OB:
|
||||
{
|
||||
Object *ob = (Object *)id_cow;
|
||||
deg_backup_object_runtime(ob, &object_runtime_backup);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
drawdata_ptr = DRW_drawdatalist_from_id(id_cow);
|
||||
if (drawdata_ptr != NULL) {
|
||||
drawdata_backup = *drawdata_ptr;
|
||||
drawdata_ptr->first = drawdata_ptr->last = NULL;
|
||||
}
|
||||
}
|
||||
RuntimeBackup backup;
|
||||
backup.init_from_id(id_cow);
|
||||
deg_free_copy_on_write_datablock(id_cow);
|
||||
deg_expand_copy_on_write_datablock(depsgraph, id_node);
|
||||
/* Restore DrawData. */
|
||||
if (drawdata_ptr != NULL) {
|
||||
*drawdata_ptr = drawdata_backup;
|
||||
}
|
||||
if (id_type == ID_OB) {
|
||||
deg_restore_object_runtime((Object *)id_cow, &object_runtime_backup);
|
||||
}
|
||||
backup.restore_to_id(id_cow);
|
||||
return id_cow;
|
||||
}
|
||||
|
||||
|
|
|
@ -116,7 +116,7 @@ typedef struct ModifierData {
|
|||
|
||||
/* Pointer to a ModifierData in the original domain. */
|
||||
struct ModifierData *orig_modifier_data;
|
||||
void *_pad2;
|
||||
void *runtime;
|
||||
} ModifierData;
|
||||
|
||||
typedef enum {
|
||||
|
@ -170,8 +170,6 @@ typedef struct SubsurfModifierData {
|
|||
|
||||
/* TODO(sergey): Get rid of those with the old CCG subdivision code. */
|
||||
void *emCache, *mCache;
|
||||
/* Cached subdivision surface descriptor, with topology and settings. */
|
||||
struct Subdiv *subdiv;
|
||||
} SubsurfModifierData;
|
||||
|
||||
typedef struct LatticeModifierData {
|
||||
|
|
|
@ -204,4 +204,5 @@ ModifierTypeInfo modifierType_Armature = {
|
|||
/* foreachObjectLink */ foreachObjectLink,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -777,4 +777,5 @@ ModifierTypeInfo modifierType_Array = {
|
|||
/* foreachObjectLink */ foreachObjectLink,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -239,4 +239,5 @@ ModifierTypeInfo modifierType_Bevel = {
|
|||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -360,4 +360,5 @@ ModifierTypeInfo modifierType_Boolean = {
|
|||
/* foreachObjectLink */ foreachObjectLink,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -315,4 +315,5 @@ ModifierTypeInfo modifierType_Build = {
|
|||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -496,4 +496,5 @@ ModifierTypeInfo modifierType_Cast = {
|
|||
/* foreachObjectLink */ foreachObjectLink,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -263,4 +263,5 @@ ModifierTypeInfo modifierType_Cloth = {
|
|||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ foreachIDLink,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -273,4 +273,5 @@ ModifierTypeInfo modifierType_Collision = {
|
|||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -765,4 +765,5 @@ ModifierTypeInfo modifierType_CorrectiveSmooth = {
|
|||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -174,4 +174,5 @@ ModifierTypeInfo modifierType_Curve = {
|
|||
/* foreachObjectLink */ foreachObjectLink,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -240,4 +240,5 @@ ModifierTypeInfo modifierType_DataTransfer = {
|
|||
/* foreachObjectLink */ foreachObjectLink,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -247,4 +247,5 @@ ModifierTypeInfo modifierType_Decimate = {
|
|||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -428,4 +428,5 @@ ModifierTypeInfo modifierType_Displace = {
|
|||
/* foreachObjectLink */ foreachObjectLink,
|
||||
/* foreachIDLink */ foreachIDLink,
|
||||
/* foreachTexLink */ foreachTexLink,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -192,4 +192,5 @@ ModifierTypeInfo modifierType_DynamicPaint = {
|
|||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ foreachIDLink,
|
||||
/* foreachTexLink */ foreachTexLink,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -168,4 +168,5 @@ ModifierTypeInfo modifierType_EdgeSplit = {
|
|||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -1106,4 +1106,5 @@ ModifierTypeInfo modifierType_Explode = {
|
|||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -160,4 +160,5 @@ ModifierTypeInfo modifierType_Fluidsim = {
|
|||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -408,4 +408,5 @@ ModifierTypeInfo modifierType_Hook = {
|
|||
/* foreachObjectLink */ foreachObjectLink,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -793,4 +793,5 @@ ModifierTypeInfo modifierType_LaplacianDeform = {
|
|||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -557,4 +557,5 @@ ModifierTypeInfo modifierType_LaplacianSmooth = {
|
|||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -149,4 +149,5 @@ ModifierTypeInfo modifierType_Lattice = {
|
|||
/* foreachObjectLink */ foreachObjectLink,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -379,4 +379,5 @@ ModifierTypeInfo modifierType_Mask = {
|
|||
/* foreachObjectLink */ foreachObjectLink,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -316,4 +316,5 @@ ModifierTypeInfo modifierType_MeshCache = {
|
|||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -530,4 +530,5 @@ ModifierTypeInfo modifierType_MeshDeform = {
|
|||
/* foreachObjectLink */ foreachObjectLink,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -211,4 +211,5 @@ ModifierTypeInfo modifierType_MeshSequenceCache = {
|
|||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ foreachIDLink,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -454,4 +454,5 @@ ModifierTypeInfo modifierType_Mirror = {
|
|||
/* foreachObjectLink */ foreachObjectLink,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -226,4 +226,5 @@ ModifierTypeInfo modifierType_Multires = {
|
|||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -68,4 +68,5 @@ ModifierTypeInfo modifierType_None = {
|
|||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -578,4 +578,5 @@ ModifierTypeInfo modifierType_NormalEdit = {
|
|||
/* foreachObjectLink */ foreachObjectLink,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -524,4 +524,5 @@ ModifierTypeInfo modifierType_Ocean = {
|
|||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -546,4 +546,5 @@ ModifierTypeInfo modifierType_ParticleInstance = {
|
|||
/* foreachObjectLink */ foreachObjectLink,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -268,4 +268,5 @@ ModifierTypeInfo modifierType_ParticleSystem = {
|
|||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -237,4 +237,5 @@ ModifierTypeInfo modifierType_Remesh = {
|
|||
/* dependsOnNormals */ NULL,
|
||||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -1157,4 +1157,5 @@ ModifierTypeInfo modifierType_Screw = {
|
|||
/* foreachObjectLink */ foreachObjectLink,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -143,4 +143,5 @@ ModifierTypeInfo modifierType_ShapeKey = {
|
|||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -205,4 +205,5 @@ ModifierTypeInfo modifierType_Shrinkwrap = {
|
|||
/* foreachObjectLink */ foreachObjectLink,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -451,4 +451,5 @@ ModifierTypeInfo modifierType_SimpleDeform = {
|
|||
/* foreachObjectLink */ foreachObjectLink,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -1961,4 +1961,5 @@ ModifierTypeInfo modifierType_Skin = {
|
|||
/* dependsOnNormals */ NULL,
|
||||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -187,4 +187,5 @@ ModifierTypeInfo modifierType_Smoke = {
|
|||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ foreachIDLink,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -266,4 +266,5 @@ ModifierTypeInfo modifierType_Smooth = {
|
|||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -98,4 +98,5 @@ ModifierTypeInfo modifierType_Softbody = {
|
|||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -975,4 +975,5 @@ ModifierTypeInfo modifierType_Solidify = {
|
|||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_object_types.h"
|
||||
|
@ -44,6 +46,11 @@
|
|||
|
||||
#include "intern/CCGSubSurf.h"
|
||||
|
||||
typedef struct SubsurfRuntimeData {
|
||||
/* Cached subdivision surface descriptor, with topology and settings. */
|
||||
struct Subdiv *subdiv;
|
||||
} SubsurfRuntimeData;
|
||||
|
||||
static void initData(ModifierData *md)
|
||||
{
|
||||
SubsurfModifierData *smd = (SubsurfModifierData *) md;
|
||||
|
@ -64,7 +71,18 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
|
|||
modifier_copyData_generic(md, target, flag);
|
||||
|
||||
tsmd->emCache = tsmd->mCache = NULL;
|
||||
tsmd->subdiv = NULL;
|
||||
}
|
||||
|
||||
static void freeRuntimeData(void *runtime_data_v)
|
||||
{
|
||||
if (runtime_data_v == NULL) {
|
||||
return;
|
||||
}
|
||||
SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)runtime_data_v;
|
||||
if (runtime_data->subdiv != NULL) {
|
||||
BKE_subdiv_free(runtime_data->subdiv);
|
||||
}
|
||||
MEM_freeN(runtime_data);
|
||||
}
|
||||
|
||||
static void freeData(ModifierData *md)
|
||||
|
@ -79,9 +97,7 @@ static void freeData(ModifierData *md)
|
|||
ccgSubSurf_free(smd->emCache);
|
||||
smd->emCache = NULL;
|
||||
}
|
||||
if (smd->subdiv != NULL) {
|
||||
BKE_subdiv_free(smd->subdiv);
|
||||
}
|
||||
freeRuntimeData(smd->modifier.runtime);
|
||||
}
|
||||
|
||||
static bool isDisabled(const Scene *scene, ModifierData *md, bool useRenderParams)
|
||||
|
@ -121,9 +137,11 @@ static Subdiv *subdiv_descriptor_ensure(SubsurfModifierData *smd,
|
|||
const SubdivSettings *subdiv_settings,
|
||||
const Mesh *mesh)
|
||||
{
|
||||
SubsurfRuntimeData *runtime_data =
|
||||
(SubsurfRuntimeData *)smd->modifier.runtime;
|
||||
Subdiv *subdiv = BKE_subdiv_update_from_mesh(
|
||||
smd->subdiv, subdiv_settings, mesh);
|
||||
smd->subdiv = subdiv;
|
||||
runtime_data->subdiv, subdiv_settings, mesh);
|
||||
runtime_data->subdiv = subdiv;
|
||||
return subdiv;
|
||||
}
|
||||
|
||||
|
@ -181,6 +199,17 @@ static Mesh *subdiv_as_ccg(SubsurfModifierData *smd,
|
|||
return result;
|
||||
}
|
||||
|
||||
static SubsurfRuntimeData *subsurf_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;
|
||||
}
|
||||
|
||||
/* Modifier itself. */
|
||||
|
||||
static Mesh *applyModifier(ModifierData *md,
|
||||
|
@ -195,6 +224,7 @@ static Mesh *applyModifier(ModifierData *md,
|
|||
return result;
|
||||
}
|
||||
BKE_subdiv_settings_validate_for_mesh(&subdiv_settings, mesh);
|
||||
SubsurfRuntimeData *runtime_data = subsurf_ensure_runtime(smd);
|
||||
Subdiv *subdiv = subdiv_descriptor_ensure(smd, &subdiv_settings, mesh);
|
||||
if (subdiv == NULL) {
|
||||
/* Happens on bad topology, but also on empty input mesh. */
|
||||
|
@ -209,7 +239,7 @@ static Mesh *applyModifier(ModifierData *md,
|
|||
result = subdiv_as_ccg(smd, ctx, mesh, subdiv);
|
||||
}
|
||||
// BKE_subdiv_stats_print(&subdiv->stats);
|
||||
if (subdiv != smd->subdiv) {
|
||||
if (subdiv != runtime_data->subdiv) {
|
||||
BKE_subdiv_free(subdiv);
|
||||
}
|
||||
return result;
|
||||
|
@ -250,4 +280,5 @@ ModifierTypeInfo modifierType_Subsurf = {
|
|||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ freeRuntimeData,
|
||||
};
|
||||
|
|
|
@ -217,4 +217,5 @@ ModifierTypeInfo modifierType_Surface = {
|
|||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -1278,4 +1278,5 @@ ModifierTypeInfo modifierType_SurfaceDeform = {
|
|||
/* foreachObjectLink */ foreachObjectLink,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -148,4 +148,5 @@ ModifierTypeInfo modifierType_Triangulate = {
|
|||
/* dependsOnNormals */ NULL,
|
||||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -345,4 +345,5 @@ ModifierTypeInfo modifierType_UVProject = {
|
|||
/* foreachObjectLink */ foreachObjectLink,
|
||||
/* foreachIDLink */ foreachIDLink,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -277,4 +277,5 @@ ModifierTypeInfo modifierType_UVWarp = {
|
|||
/* foreachObjectLink */ foreachObjectLink,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -379,4 +379,5 @@ ModifierTypeInfo modifierType_Warp = {
|
|||
/* foreachObjectLink */ foreachObjectLink,
|
||||
/* foreachIDLink */ foreachIDLink,
|
||||
/* foreachTexLink */ foreachTexLink,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -379,4 +379,5 @@ ModifierTypeInfo modifierType_Wave = {
|
|||
/* foreachObjectLink */ foreachObjectLink,
|
||||
/* foreachIDLink */ foreachIDLink,
|
||||
/* foreachTexLink */ foreachTexLink,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -655,4 +655,5 @@ ModifierTypeInfo modifierType_WeightedNormal = {
|
|||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -301,4 +301,5 @@ ModifierTypeInfo modifierType_WeightVGEdit = {
|
|||
/* foreachObjectLink */ foreachObjectLink,
|
||||
/* foreachIDLink */ foreachIDLink,
|
||||
/* foreachTexLink */ foreachTexLink,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -414,4 +414,5 @@ ModifierTypeInfo modifierType_WeightVGMix = {
|
|||
/* foreachObjectLink */ foreachObjectLink,
|
||||
/* foreachIDLink */ foreachIDLink,
|
||||
/* foreachTexLink */ foreachTexLink,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -586,4 +586,5 @@ ModifierTypeInfo modifierType_WeightVGProximity = {
|
|||
/* foreachObjectLink */ foreachObjectLink,
|
||||
/* foreachIDLink */ foreachIDLink,
|
||||
/* foreachTexLink */ foreachTexLink,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
|
@ -137,4 +137,5 @@ ModifierTypeInfo modifierType_Wireframe = {
|
|||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue