Refactor: Move Paint_Runtime out of DNA

This commit takes the previously defined `Paint_Runtime` struct and
moves it into the BKE namespace, initializing it on demand instead of it
being a default-allocated member. This data does not need to be
persisted and is runtime only.

Pull Request: https://projects.blender.org/blender/blender/pulls/141413
This commit is contained in:
Sean Kim
2025-07-07 16:53:12 +02:00
committed by Sean Kim
parent a6f92974ac
commit 7f3aa617ce
9 changed files with 106 additions and 52 deletions

View File

@@ -0,0 +1,25 @@
/* SPDX-FileCopyrightText: 2025 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include "BLI_utildefines.h"
#include "BLI_utility_mixins.hh"
/** \file
* \ingroup bke
*/
struct AssetWeakReference;
namespace blender::bke {
struct PaintRuntime : NonCopyable, NonMovable {
bool initialized = false;
uint16_t ob_mode = 0;
AssetWeakReference *previous_active_brush_reference = nullptr;
PaintRuntime();
~PaintRuntime();
};
}; // namespace blender::bke

View File

@@ -253,6 +253,7 @@ set(SRC
intern/packedFile.cc
intern/paint.cc
intern/paint_canvas.cc
intern/paint_runtime.cc
intern/particle.cc
intern/particle_child.cc
intern/particle_distribute.cc
@@ -491,6 +492,7 @@ set(SRC
BKE_outliner_treehash.hh
BKE_packedFile.hh
BKE_paint.hh
BKE_paint_types.hh
BKE_paint_bvh.hh
BKE_paint_bvh_pixels.hh
BKE_particle.h

View File

@@ -63,6 +63,7 @@
#include "BKE_object.hh"
#include "BKE_paint.hh"
#include "BKE_paint_bvh.hh"
#include "BKE_paint_types.hh"
#include "BKE_scene.hh"
#include "BKE_subdiv_ccg.hh"
#include "BKE_subsurf.hh"
@@ -592,7 +593,7 @@ PaintMode BKE_paintmode_get_from_tool(const bToolRef *tref)
bool BKE_paint_use_unified_color(const Paint *paint)
{
/* Grease pencil draw mode never uses unified paint. */
if (paint->runtime.ob_mode == OB_MODE_PAINT_GREASE_PENCIL) {
if (paint->runtime->ob_mode == OB_MODE_PAINT_GREASE_PENCIL) {
return false;
}
@@ -623,7 +624,7 @@ static bool paint_brush_update_from_asset_reference(Main *bmain, Paint *paint)
/* Ensure we have a brush with appropriate mode to assign.
* Could happen if contents of asset blend was manually changed. */
if (brush == nullptr || (paint->runtime.ob_mode & brush->ob_mode) == 0) {
if (brush == nullptr || (paint->runtime->ob_mode & brush->ob_mode) == 0) {
MEM_delete(paint->brush_asset_reference);
paint->brush_asset_reference = nullptr;
return false;
@@ -648,7 +649,7 @@ bool BKE_paint_brush_poll(const Paint *paint, const Brush *brush)
if (paint == nullptr) {
return false;
}
return !brush || (paint->runtime.ob_mode & brush->ob_mode) != 0;
return !brush || (paint->runtime->ob_mode & brush->ob_mode) != 0;
}
static AssetWeakReference *asset_reference_create_from_brush(Brush *brush)
@@ -790,9 +791,9 @@ static void paint_brush_set_essentials_reference(Paint *paint, const char *name)
/* Set brush asset reference to a named brush in the essentials asset library. */
MEM_delete(paint->brush_asset_reference);
BLI_assert(paint->runtime.initialized);
BLI_assert(paint->runtime->initialized);
paint->brush_asset_reference = paint_brush_asset_reference_ptr_from_essentials(
name, eObjectMode(paint->runtime.ob_mode));
name, eObjectMode(paint->runtime->ob_mode));
paint->brush = nullptr;
}
@@ -801,9 +802,9 @@ static void paint_eraser_brush_set_essentials_reference(Paint *paint, const char
/* Set brush asset reference to a named brush in the essentials asset library. */
MEM_delete(paint->eraser_brush_asset_reference);
BLI_assert(paint->runtime.initialized);
BLI_assert(paint->runtime->initialized);
paint->eraser_brush_asset_reference = paint_brush_asset_reference_ptr_from_essentials(
name, eObjectMode(paint->runtime.ob_mode));
name, eObjectMode(paint->runtime->ob_mode));
paint->eraser_brush = nullptr;
}
@@ -1031,7 +1032,7 @@ static void paint_brush_set_default_reference(Paint *paint,
const bool do_regular = true,
const bool do_eraser = true)
{
if (!paint->runtime.initialized) {
if (!paint->runtime->initialized) {
/* Can happen when loading old file where toolsettings are created in versioning, without
* calling #paint_runtime_init(). Will be done later when necessary. */
return;
@@ -1041,7 +1042,7 @@ static void paint_brush_set_default_reference(Paint *paint,
blender::StringRefNull eraser_name;
paint_brush_default_essentials_name_get(
eObjectMode(paint->runtime.ob_mode), std::nullopt, &name, &eraser_name);
eObjectMode(paint->runtime->ob_mode), std::nullopt, &name, &eraser_name);
if (do_regular && !name.is_empty()) {
paint_brush_set_essentials_reference(paint, name.c_str());
@@ -1095,15 +1096,15 @@ bool BKE_paint_brush_set_essentials(Main *bmain, Paint *paint, const char *name)
void BKE_paint_previous_asset_reference_set(Paint *paint,
AssetWeakReference &&asset_weak_reference)
{
if (!paint->runtime.previous_active_brush_reference) {
paint->runtime.previous_active_brush_reference = MEM_new<AssetWeakReference>(__func__);
if (!paint->runtime->previous_active_brush_reference) {
paint->runtime->previous_active_brush_reference = MEM_new<AssetWeakReference>(__func__);
}
*paint->runtime.previous_active_brush_reference = asset_weak_reference;
*paint->runtime->previous_active_brush_reference = asset_weak_reference;
}
void BKE_paint_previous_asset_reference_clear(Paint *paint)
{
MEM_SAFE_DELETE(paint->runtime.previous_active_brush_reference);
MEM_SAFE_DELETE(paint->runtime->previous_active_brush_reference);
}
void BKE_paint_brushes_validate(Main *bmain, Paint *paint)
@@ -1111,13 +1112,13 @@ void BKE_paint_brushes_validate(Main *bmain, Paint *paint)
/* Clear brush with invalid mode. Unclear if this can still happen,
* but kept from old paint tool-slots code. */
Brush *brush = BKE_paint_brush(paint);
if (brush && (paint->runtime.ob_mode & brush->ob_mode) == 0) {
if (brush && (paint->runtime->ob_mode & brush->ob_mode) == 0) {
BKE_paint_brush_set(paint, nullptr);
BKE_paint_brush_set_default(bmain, paint);
}
Brush *eraser_brush = BKE_paint_eraser_brush(paint);
if (eraser_brush && (paint->runtime.ob_mode & eraser_brush->ob_mode) == 0) {
if (eraser_brush && (paint->runtime->ob_mode & eraser_brush->ob_mode) == 0) {
BKE_paint_eraser_brush_set(paint, nullptr);
BKE_paint_eraser_brush_set_default(bmain, paint);
}
@@ -1143,7 +1144,7 @@ static bool paint_eraser_brush_set_from_asset_reference(Main *bmain, Paint *pain
/* Ensure we have a brush with appropriate mode to assign.
* Could happen if contents of asset blend was manually changed. */
if (brush == nullptr || (paint->runtime.ob_mode & brush->ob_mode) == 0) {
if (brush == nullptr || (paint->runtime->ob_mode & brush->ob_mode) == 0) {
MEM_delete(paint->eraser_brush_asset_reference);
paint->eraser_brush_asset_reference = nullptr;
return false;
@@ -1168,7 +1169,7 @@ bool BKE_paint_eraser_brush_set(Paint *paint, Brush *brush)
if (paint == nullptr || paint->eraser_brush == brush) {
return false;
}
if (brush && (paint->runtime.ob_mode & brush->ob_mode) == 0) {
if (brush && (paint->runtime->ob_mode & brush->ob_mode) == 0) {
return false;
}
@@ -1214,39 +1215,42 @@ bool BKE_paint_eraser_brush_set_essentials(Main *bmain, Paint *paint, const char
static void paint_runtime_init(const ToolSettings *ts, Paint *paint)
{
if (!paint->runtime) {
paint->runtime = MEM_new<blender::bke::PaintRuntime>(__func__);
}
if (paint == &ts->imapaint.paint) {
paint->runtime.ob_mode = OB_MODE_TEXTURE_PAINT;
paint->runtime->ob_mode = OB_MODE_TEXTURE_PAINT;
}
else if (ts->sculpt && paint == &ts->sculpt->paint) {
paint->runtime.ob_mode = OB_MODE_SCULPT;
paint->runtime->ob_mode = OB_MODE_SCULPT;
}
else if (ts->vpaint && paint == &ts->vpaint->paint) {
paint->runtime.ob_mode = OB_MODE_VERTEX_PAINT;
paint->runtime->ob_mode = OB_MODE_VERTEX_PAINT;
}
else if (ts->wpaint && paint == &ts->wpaint->paint) {
paint->runtime.ob_mode = OB_MODE_WEIGHT_PAINT;
paint->runtime->ob_mode = OB_MODE_WEIGHT_PAINT;
}
else if (ts->gp_paint && paint == &ts->gp_paint->paint) {
paint->runtime.ob_mode = OB_MODE_PAINT_GREASE_PENCIL;
paint->runtime->ob_mode = OB_MODE_PAINT_GREASE_PENCIL;
}
else if (ts->gp_vertexpaint && paint == &ts->gp_vertexpaint->paint) {
paint->runtime.ob_mode = OB_MODE_VERTEX_GREASE_PENCIL;
paint->runtime->ob_mode = OB_MODE_VERTEX_GREASE_PENCIL;
}
else if (ts->gp_sculptpaint && paint == &ts->gp_sculptpaint->paint) {
paint->runtime.ob_mode = OB_MODE_SCULPT_GREASE_PENCIL;
paint->runtime->ob_mode = OB_MODE_SCULPT_GREASE_PENCIL;
}
else if (ts->gp_weightpaint && paint == &ts->gp_weightpaint->paint) {
paint->runtime.ob_mode = OB_MODE_WEIGHT_GREASE_PENCIL;
paint->runtime->ob_mode = OB_MODE_WEIGHT_GREASE_PENCIL;
}
else if (ts->curves_sculpt && paint == &ts->curves_sculpt->paint) {
paint->runtime.ob_mode = OB_MODE_SCULPT_CURVES;
paint->runtime->ob_mode = OB_MODE_SCULPT_CURVES;
}
else {
BLI_assert_unreachable();
}
paint->runtime.initialized = true;
paint->runtime.previous_active_brush_reference = nullptr;
paint->runtime->initialized = true;
}
uint BKE_paint_get_brush_type_offset_from_paintmode(const PaintMode mode)
@@ -1698,10 +1702,10 @@ bool BKE_paint_ensure(ToolSettings *ts, Paint **r_paint)
{
Paint *paint = nullptr;
if (*r_paint) {
if (!(*r_paint)->runtime.initialized) {
/* Currently only image painting is initialized this way, others have to be allocated. */
BLI_assert(ELEM(*r_paint, (Paint *)&ts->imapaint));
if (!(*r_paint)->runtime) {
(*r_paint)->runtime = MEM_new<blender::bke::PaintRuntime>(__func__);
}
if (!(*r_paint)->runtime->initialized && *r_paint == (Paint *)&ts->imapaint) {
paint_runtime_init(ts, *r_paint);
}
else {
@@ -1721,7 +1725,7 @@ bool BKE_paint_ensure(ToolSettings *ts, Paint **r_paint)
paint_runtime_init(ts, *r_paint);
/* Swap so debug doesn't hide errors when release fails. */
std::swap(**r_paint, paint_test);
BLI_assert(paint_test.runtime.ob_mode == (*r_paint)->runtime.ob_mode);
BLI_assert(paint_test.runtime->ob_mode == (*r_paint)->runtime->ob_mode);
#endif
}
return true;
@@ -1833,11 +1837,11 @@ void BKE_paint_free(Paint *paint)
MEM_delete(brush_ref->brush_asset_reference);
MEM_delete(brush_ref);
}
MEM_delete(paint->runtime.previous_active_brush_reference);
BKE_curvemapping_free(paint->unified_paint_settings.curve_rand_hue);
BKE_curvemapping_free(paint->unified_paint_settings.curve_rand_saturation);
BKE_curvemapping_free(paint->unified_paint_settings.curve_rand_value);
MEM_SAFE_DELETE(paint->runtime);
}
void BKE_paint_copy(const Paint *src, Paint *dst, const int flag)
@@ -1877,6 +1881,8 @@ void BKE_paint_copy(const Paint *src, Paint *dst, const int flag)
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
id_us_plus((ID *)dst->palette);
}
dst->runtime = MEM_new<blender::bke::PaintRuntime>(__func__);
}
void BKE_paint_stroke_get_average(const Paint *paint, const Object *ob, float stroke[3])
@@ -2058,6 +2064,8 @@ void BKE_paint_blend_read_data(BlendDataReader *reader, const Scene *scene, Pain
zero_v3(ups->last_location);
ups->last_hit = 0;
paint->runtime = MEM_new<blender::bke::PaintRuntime>(__func__);
paint_runtime_init(scene->toolsettings, paint);
}

View File

@@ -0,0 +1,21 @@
/* SPDX-FileCopyrightText: 2005 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup bke
*/
#include "MEM_guardedalloc.h"
#include "DNA_asset_types.h"
#include "BKE_paint_types.hh"
namespace blender::bke {
PaintRuntime::PaintRuntime() = default;
PaintRuntime::~PaintRuntime()
{
MEM_delete(this->previous_active_brush_reference);
}
} // namespace blender::bke

View File

@@ -20,6 +20,7 @@
#include "BKE_global.hh"
#include "BKE_lib_id.hh"
#include "BKE_paint.hh"
#include "BKE_paint_types.hh"
#include "BKE_preferences.h"
#include "BKE_preview_image.hh"
#include "BKE_report.hh"
@@ -76,8 +77,8 @@ static wmOperatorStatus brush_asset_activate_exec(bContext *C, wmOperator *op)
if (use_toggle) {
BLI_assert(paint->brush_asset_reference);
if (brush_asset_reference == *paint->brush_asset_reference) {
if (paint->runtime.previous_active_brush_reference != nullptr) {
brush_asset_reference = *paint->runtime.previous_active_brush_reference;
if (paint->runtime->previous_active_brush_reference != nullptr) {
brush_asset_reference = *paint->runtime->previous_active_brush_reference;
}
}
else {

View File

@@ -47,6 +47,7 @@
#include "BKE_object.hh"
#include "BKE_object_types.hh"
#include "BKE_paint.hh"
#include "BKE_paint_types.hh"
#include "DEG_depsgraph.hh"
@@ -200,7 +201,7 @@ bool brush_use_accumulate_ex(const Brush &brush, const eObjectMode ob_mode)
bool brush_use_accumulate(const VPaint &vp)
{
const Brush *brush = BKE_paint_brush_for_read(&vp.paint);
return brush_use_accumulate_ex(*brush, eObjectMode(vp.paint.runtime.ob_mode));
return brush_use_accumulate_ex(*brush, eObjectMode(vp.paint.runtime->ob_mode));
}
void init_stroke(Depsgraph &depsgraph, Object &ob)

View File

@@ -44,15 +44,18 @@ struct bNodeTree;
#ifdef __cplusplus
namespace blender {
namespace bke {
struct PaintRuntime;
class SceneRuntime;
}
} // namespace bke
namespace ocio {
class ColorSpace;
}
} // namespace blender
using PaintRuntimeHandle = blender::bke::PaintRuntime;
using SceneRuntimeHandle = blender::bke::SceneRuntime;
using ColorSpaceHandle = blender::ocio::ColorSpace;
#else // __cplusplus
typedef struct PaintRuntimeHandle PaintRuntimeHandle;
typedef struct SceneRuntimeHandle SceneRuntimeHandle;
typedef struct ColorSpaceHandle ColorSpaceHandle;
#endif // __cplusplus
@@ -1132,15 +1135,6 @@ typedef struct UnifiedPaintSettings {
#define PAINT_MAX_INPUT_SAMPLES 64
typedef struct Paint_Runtime {
/** Avoid having to compare with scene pointer everywhere. */
unsigned int initialized;
unsigned short ob_mode;
char _pad[2];
/** The last brush that was active. Used to support toggling. */
struct AssetWeakReference *previous_active_brush_reference;
} Paint_Runtime;
typedef struct NamedBrushAssetReference {
struct NamedBrushAssetReference *next, *prev;
@@ -1220,7 +1214,7 @@ typedef struct Paint {
char _pad2[4];
struct UnifiedPaintSettings unified_paint_settings;
struct Paint_Runtime runtime;
PaintRuntimeHandle *runtime;
} Paint;
/** \} */

View File

@@ -110,6 +110,7 @@ const EnumPropertyItem rna_enum_symmetrize_direction_items[] = {
# include "BKE_material.hh"
# include "BKE_object.hh"
# include "BKE_paint.hh"
# include "BKE_paint_types.hh"
# include "BKE_particle.h"
# include "BKE_pointcache.h"
@@ -277,7 +278,7 @@ static bool rna_Paint_brush_poll(PointerRNA *ptr, PointerRNA value)
const Paint *paint = static_cast<Paint *>(ptr->data);
const Brush *brush = static_cast<Brush *>(value.data);
return (brush == nullptr) || (paint->runtime.ob_mode & brush->ob_mode) != 0;
return (brush == nullptr) || (paint->runtime->ob_mode & brush->ob_mode) != 0;
}
static PointerRNA rna_Paint_eraser_brush_get(PointerRNA *ptr)
@@ -303,7 +304,7 @@ static bool rna_Paint_eraser_brush_poll(PointerRNA *ptr, PointerRNA value)
const Paint *paint = static_cast<Paint *>(ptr->data);
const Brush *brush = static_cast<Brush *>(value.data);
return (brush == nullptr) || (paint->runtime.ob_mode & brush->ob_mode) != 0;
return (brush == nullptr) || (paint->runtime->ob_mode & brush->ob_mode) != 0;
}
static void rna_Sculpt_update(bContext *C, PointerRNA * /*ptr*/)

View File

@@ -43,6 +43,7 @@
#include "BKE_lib_id.hh"
#include "BKE_main.hh"
#include "BKE_paint.hh"
#include "BKE_paint_types.hh"
#include "BKE_workspace.hh"
#include "RNA_access.hh"
@@ -391,7 +392,7 @@ static void toolsystem_brush_activate_from_toolref_for_object_paint(Main *bmain,
return *brush_ref->brush_asset_reference;
}
/* No remembered brush found for this type, use a default for the type. */
return BKE_paint_brush_type_default_reference(eObjectMode(paint->runtime.ob_mode),
return BKE_paint_brush_type_default_reference(eObjectMode(paint->runtime->ob_mode),
tref_rt->brush_type);
}();
@@ -411,7 +412,7 @@ static void toolsystem_brush_activate_from_toolref_for_object_paint(Main *bmain,
if (paint->tool_brush_bindings.main_brush_asset_reference) {
return *paint->tool_brush_bindings.main_brush_asset_reference;
}
return BKE_paint_brush_type_default_reference(eObjectMode(paint->runtime.ob_mode),
return BKE_paint_brush_type_default_reference(eObjectMode(paint->runtime->ob_mode),
std::nullopt);
}();