GP: Redesign drawing cache to support particles

Full redesign of the cache system used for drawing strokes and handle derived frame data.

Before, the cache was saved in bGPdata and a hash was used to manage several objects with the same datablock.

Old design made the use of particles very inefficient and prone to bugs and segment faults, and especially when this was mixed with onion skinning and multiple objects using same datablock. Also, there were some conflicts with the depsgrah logic (the old design was done before despgraph was in place) that made the use of hash not working.

The new design saves the data in the object runtime struct and avoid the use of any hash to find the right data. This improves the speed and reduce a lot the complexity of the code, memory allocation, hash overload and adds full support for particles and reused datablocks.

The particles can reuse the modifiers and shader effects of the original grease pencil object.
This commit is contained in:
Antonio Vazquez 2018-10-19 20:39:21 +02:00
parent b634bf9fb6
commit 541d07045b
Notes: blender-bot 2023-02-14 05:07:04 +01:00
Referenced by issue #57579, Grease Pencil render with Cycles fails
11 changed files with 171 additions and 153 deletions

View File

@ -169,8 +169,6 @@ bool BKE_gpencil_free_frame_runtime_data(bGPDframe *derived_gpf)
}
BLI_listbase_clear(&derived_gpf->strokes);
MEM_SAFE_FREE(derived_gpf);
return true;
}
@ -216,18 +214,17 @@ void BKE_gpencil_free_layers(ListBase *list)
/* clear all runtime derived data */
static void BKE_gpencil_clear_derived(bGPDlayer *gpl)
{
GHashIterator gh_iter;
if (gpl->runtime.derived_data == NULL) {
if (gpl->runtime.derived_array == NULL) {
return;
}
GHASH_ITER(gh_iter, gpl->runtime.derived_data) {
bGPDframe *gpf = (bGPDframe *)BLI_ghashIterator_getValue(&gh_iter);
if (gpf) {
BKE_gpencil_free_frame_runtime_data(gpf);
}
for (int i = 0; i < gpl->runtime.len_derived; i++) {
bGPDframe *derived_gpf = &gpl->runtime.derived_array[i];
BKE_gpencil_free_frame_runtime_data(derived_gpf);
derived_gpf = NULL;
}
gpl->runtime.len_derived = 0;
MEM_SAFE_FREE(gpl->runtime.derived_array);
}
/* Free all of the gp-layers temp data*/
@ -241,11 +238,6 @@ static void BKE_gpencil_free_layers_temp_data(ListBase *list)
for (bGPDlayer *gpl = list->first; gpl; gpl = gpl_next) {
gpl_next = gpl->next;
BKE_gpencil_clear_derived(gpl);
if (gpl->runtime.derived_data) {
BLI_ghash_free(gpl->runtime.derived_data, NULL, NULL);
gpl->runtime.derived_data = NULL;
}
}
}
@ -256,11 +248,6 @@ void BKE_gpencil_free_derived_frames(bGPdata *gpd)
if (gpd == NULL) return;
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
BKE_gpencil_clear_derived(gpl);
if (gpl->runtime.derived_data) {
BLI_ghash_free(gpl->runtime.derived_data, NULL, NULL);
gpl->runtime.derived_data = NULL;
}
}
}
@ -464,7 +451,6 @@ bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[])
ARRAY_SET_ITEMS(gpd->line_color, 0.6f, 0.6f, 0.6f, 0.5f);
gpd->xray_mode = GP_XRAY_3DSPACE;
gpd->runtime.batch_cache_data = NULL;
gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
/* grid settings */
@ -645,7 +631,8 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src)
/* make a copy of source layer */
gpl_dst = MEM_dupallocN(gpl_src);
gpl_dst->prev = gpl_dst->next = NULL;
gpl_dst->runtime.derived_data = NULL;
gpl_dst->runtime.derived_array = NULL;
gpl_dst->runtime.len_derived = 0;
/* copy frames */
BLI_listbase_clear(&gpl_dst->frames);
@ -673,9 +660,6 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src)
*/
void BKE_gpencil_copy_data(bGPdata *gpd_dst, const bGPdata *gpd_src, const int UNUSED(flag))
{
/* cache data is not duplicated */
gpd_dst->runtime.batch_cache_data = NULL;
/* duplicate material array */
if (gpd_src->mat) {
gpd_dst->mat = MEM_dupallocN(gpd_src->mat);
@ -721,7 +705,6 @@ bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool in
else {
BLI_assert(bmain != NULL);
BKE_id_copy_ex(bmain, &gpd_src->id, (ID **)&gpd_dst, 0, false);
gpd_dst->runtime.batch_cache_data = NULL;
}
/* Copy internal data (layers, etc.) */
@ -1035,10 +1018,6 @@ void BKE_gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl)
/* free derived data */
BKE_gpencil_clear_derived(gpl);
if (gpl->runtime.derived_data) {
BLI_ghash_free(gpl->runtime.derived_data, NULL, NULL);
gpl->runtime.derived_data = NULL;
}
BLI_freelinkN(&gpd->layers, gpl);
}

View File

@ -481,6 +481,9 @@ void BKE_object_free_derived_caches(Object *ob)
}
BKE_object_free_curve_cache(ob);
/* clear grease pencil data */
DRW_gpencil_freecache(ob);
}
void BKE_object_free_derived_mesh_caches(struct Object *ob)
@ -1406,10 +1409,6 @@ void BKE_object_copy_data(Main *bmain, Object *ob_dst, const Object *ob_src, con
BLI_listbase_clear((ListBase *)&ob_dst->drawdata);
BLI_listbase_clear(&ob_dst->pc_ids);
/* grease pencil: clean derived data */
if (ob_dst->type == OB_GPENCIL)
BKE_gpencil_free_derived_frames(ob_dst->data);
ob_dst->avs = ob_src->avs;
ob_dst->mpath = animviz_copy_motionpath(ob_src->mpath);

View File

@ -6574,9 +6574,6 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
}
}
/* clear drawing cache */
gpd->runtime.batch_cache_data = NULL;
/* materials */
gpd->mat = newdataadr(fd, gpd->mat);
test_pointer_array(fd, (void **)&gpd->mat);
@ -6590,7 +6587,8 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
gpl->actframe = newdataadr(fd, gpl->actframe);
gpl->runtime.derived_data = NULL;
gpl->runtime.derived_array = NULL;
gpl->runtime.len_derived = 0;
gpl->runtime.icon_id = 0;
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {

View File

@ -128,6 +128,7 @@ void DRW_draw_depth_loop(
/* grease pencil render */
void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph);
void DRW_gpencil_freecache(struct Object *ob);
/* This is here because GPUViewport needs it */
void DRW_pass_free(struct DRWPass *pass);

View File

@ -37,17 +37,20 @@
#include "draw_cache_impl.h"
static bool gpencil_check_ob_duplicated(tGPencilObjectCache *cache_array, int gp_cache_used, Object *ob)
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
static bool gpencil_check_ob_duplicated(tGPencilObjectCache *cache_array,
int gp_cache_used, Object *ob, int *r_index)
{
if (gp_cache_used == 0) {
return false;
}
for (int i = 0; i < gp_cache_used + 1; i++) {
for (int i = 0; i < gp_cache_used; i++) {
tGPencilObjectCache *cache_elem = &cache_array[i];
if (STREQ(cache_elem->ob_name, ob->id.name) &&
(cache_elem->is_dup_ob == false))
{
if (cache_elem->ob == ob) {
*r_index = cache_elem->data_idx;
return true;
}
}
@ -62,9 +65,9 @@ static bool gpencil_check_datablock_duplicated(
return false;
}
for (int i = 0; i < gp_cache_used + 1; i++) {
for (int i = 0; i < gp_cache_used; i++) {
tGPencilObjectCache *cache_elem = &cache_array[i];
if (!STREQ(cache_elem->ob_name, ob->id.name) &&
if ((cache_elem->ob != ob) &&
(cache_elem->gpd == gpd))
{
return true;
@ -73,6 +76,27 @@ static bool gpencil_check_datablock_duplicated(
return false;
}
static int gpencil_len_datablock_duplicated(
tGPencilObjectCache *cache_array, int gp_cache_used,
Object *ob, bGPdata *gpd)
{
int tot = 0;
if (gp_cache_used == 0) {
return 0;
}
for (int i = 0; i < gp_cache_used; i++) {
tGPencilObjectCache *cache_elem = &cache_array[i];
if ((cache_elem->ob != ob) &&
(cache_elem->gpd == gpd) &&
(!cache_elem->is_dup_ob))
{
tot++;
}
}
return tot;
}
/* add a gpencil object to cache to defer drawing */
tGPencilObjectCache *gpencil_object_cache_add(
tGPencilObjectCache *cache_array, Object *ob,
@ -101,22 +125,41 @@ tGPencilObjectCache *gpencil_object_cache_add(
cache_elem = &cache_array[*gp_cache_used];
memset(cache_elem, 0, sizeof(*cache_elem));
cache_elem->is_dup_ob = gpencil_check_ob_duplicated(cache_array, *gp_cache_used, ob);
STRNCPY(cache_elem->ob_name, ob->id.name);
cache_elem->gpd = (bGPdata *)ob->data;
Object *ob_orig = (Object *)DEG_get_original_id(&ob->id);
cache_elem->ob = ob_orig;
cache_elem->gpd = (bGPdata *)ob_orig->data;
copy_v3_v3(cache_elem->loc, ob->loc);
copy_m4_m4(cache_elem->obmat, ob->obmat);
cache_elem->idx = *gp_cache_used;
cache_elem->is_dup_onion = gpencil_check_datablock_duplicated(
cache_array, *gp_cache_used,
ob, cache_elem->gpd);
/* check if object is duplicated */
cache_elem->is_dup_ob = gpencil_check_ob_duplicated(cache_array,
*gp_cache_used, ob_orig,
&cache_elem->data_idx);
if (!cache_elem->is_dup_ob) {
/* check if object reuse datablock */
cache_elem->is_dup_data = gpencil_check_datablock_duplicated(
cache_array, *gp_cache_used,
ob_orig, cache_elem->gpd);
if (cache_elem->is_dup_data) {
cache_elem->data_idx = gpencil_len_datablock_duplicated(
cache_array, *gp_cache_used,
ob_orig, cache_elem->gpd);
cache_elem->gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
}
else {
cache_elem->data_idx = 0;
}
}
else {
cache_elem->is_dup_data = false;
}
/* save FXs */
cache_elem->pixfactor = cache_elem->gpd->pixfactor;
cache_elem->shader_fx = ob->shader_fx;
cache_elem->shader_fx = ob_orig->shader_fx;
cache_elem->init_grp = 0;
cache_elem->end_grp = -1;
@ -156,20 +199,13 @@ tGPencilObjectCache *gpencil_object_cache_add(
/* get current cache data */
static GpencilBatchCache *gpencil_batch_get_element(Object *ob)
{
bGPdata *gpd = (bGPdata *)ob->data;
if (gpd->runtime.batch_cache_data == NULL) {
gpd->runtime.batch_cache_data = BLI_ghash_str_new("GP batch cache data");
return NULL;
}
return (GpencilBatchCache *) BLI_ghash_lookup(gpd->runtime.batch_cache_data, ob->id.name);
Object *ob_orig = (Object *)DEG_get_original_id(&ob->id);
return ob_orig->runtime.gpencil_cache;
}
/* verify if cache is valid */
static bool gpencil_batch_cache_valid(Object *ob, bGPdata *gpd, int cfra)
static bool gpencil_batch_cache_valid(GpencilBatchCache *cache, bGPdata *gpd, int cfra)
{
GpencilBatchCache *cache = gpencil_batch_get_element(ob);
if (cache == NULL) {
return false;
}
@ -218,10 +254,12 @@ void gpencil_batch_cache_check_free_slots(Object *ob)
}
/* cache init */
static void gpencil_batch_cache_init(Object *ob, int cfra)
static GpencilBatchCache *gpencil_batch_cache_init(Object *ob, int cfra)
{
Object *ob_orig = (Object *)DEG_get_original_id(&ob->id);
bGPdata *gpd = (bGPdata *)ob_orig->data;
GpencilBatchCache *cache = gpencil_batch_get_element(ob);
bGPdata *gpd = ob->data;
if (G.debug_value >= 664) {
printf("gpencil_batch_cache_init: %s\n", ob->id.name);
@ -229,7 +267,7 @@ static void gpencil_batch_cache_init(Object *ob, int cfra)
if (!cache) {
cache = MEM_callocN(sizeof(*cache), __func__);
BLI_ghash_insert(gpd->runtime.batch_cache_data, ob->id.name, cache);
ob_orig->runtime.gpencil_cache = cache;
}
else {
memset(cache, 0, sizeof(*cache));
@ -247,6 +285,8 @@ static void gpencil_batch_cache_init(Object *ob, int cfra)
cache->cache_idx = 0;
cache->is_dirty = true;
cache->cache_frame = cfra;
return cache;
}
/* clear cache */
@ -273,68 +313,54 @@ static void gpencil_batch_cache_clear(GpencilBatchCache *cache)
MEM_SAFE_FREE(cache->batch_edlin);
}
MEM_SAFE_FREE(cache);
cache->cache_size = 0;
}
/* get cache */
GpencilBatchCache *gpencil_batch_cache_get(Object *ob, int cfra)
{
bGPdata *gpd = ob->data;
Object *ob_orig = (Object *)DEG_get_original_id(&ob->id);
bGPdata *gpd = (bGPdata *)ob_orig->data;
if (!gpencil_batch_cache_valid(ob, gpd, cfra)) {
GpencilBatchCache *cache = gpencil_batch_get_element(ob);
if (!gpencil_batch_cache_valid(cache, gpd, cfra)) {
if (G.debug_value >= 664) {
printf("gpencil_batch_cache: %s\n", gpd->id.name);
}
GpencilBatchCache *cache = gpencil_batch_get_element(ob);
if (cache) {
gpencil_batch_cache_clear(cache);
BLI_ghash_remove(gpd->runtime.batch_cache_data, ob->id.name, NULL, NULL);
}
gpencil_batch_cache_init(ob, cfra);
return gpencil_batch_cache_init(ob, cfra);
}
else {
return cache;
}
return gpencil_batch_get_element(ob);
}
/* set cache as dirty */
void DRW_gpencil_batch_cache_dirty_tag(bGPdata *gpd)
{
if (gpd->runtime.batch_cache_data == NULL) {
return;
}
GHashIterator *ihash = BLI_ghashIterator_new(gpd->runtime.batch_cache_data);
while (!BLI_ghashIterator_done(ihash)) {
GpencilBatchCache *cache = (GpencilBatchCache *)BLI_ghashIterator_getValue(ihash);
if (cache) {
cache->is_dirty = true;
}
BLI_ghashIterator_step(ihash);
}
BLI_ghashIterator_free(ihash);
bGPdata *gpd_orig = (bGPdata *)DEG_get_original_id(&gpd->id);
gpd_orig->flag |= GP_DATA_CACHE_IS_DIRTY;
}
/* free batch cache */
void DRW_gpencil_batch_cache_free(bGPdata *gpd)
{
if (gpd->runtime.batch_cache_data == NULL) {
return;
}
return;
}
GHashIterator *ihash = BLI_ghashIterator_new(gpd->runtime.batch_cache_data);
while (!BLI_ghashIterator_done(ihash)) {
GpencilBatchCache *cache = (GpencilBatchCache *)BLI_ghashIterator_getValue(ihash);
if (cache) {
gpencil_batch_cache_clear(cache);
/* wrapper to clear cache */
void DRW_gpencil_freecache(struct Object *ob)
{
if ((ob) && (ob->type == OB_GPENCIL)) {
gpencil_batch_cache_clear(ob->runtime.gpencil_cache);
MEM_SAFE_FREE(ob->runtime.gpencil_cache);
bGPdata *gpd = (bGPdata *)ob->data;
if (gpd) {
gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
}
BLI_ghashIterator_step(ihash);
}
BLI_ghashIterator_free(ihash);
/* free hash */
if (gpd->runtime.batch_cache_data) {
BLI_ghash_free(gpd->runtime.batch_cache_data, NULL, NULL);
gpd->runtime.batch_cache_data = NULL;
}
}

View File

@ -1218,6 +1218,24 @@ void DRW_gpencil_populate_multiedit(
cache->is_dirty = false;
}
void static gpencil_copy_frame(bGPDframe *gpf, bGPDframe *derived_gpf)
{
derived_gpf->prev = gpf->prev;
derived_gpf->next = gpf->next;
derived_gpf->framenum = gpf->framenum;
derived_gpf->flag = gpf->flag;
derived_gpf->key_type = gpf->key_type;
derived_gpf->runtime = gpf->runtime;
/* copy strokes */
BLI_listbase_clear(&derived_gpf->strokes);
for (bGPDstroke *gps_src = gpf->strokes.first; gps_src; gps_src = gps_src->next) {
/* make copy of source stroke */
bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src);
BLI_addtail(&derived_gpf->strokes, gps_dst);
}
}
/* helper for populate a complete grease pencil datablock */
void DRW_gpencil_populate_datablock(
GPENCIL_e_data *e_data, void *vedata,
@ -1226,7 +1244,9 @@ void DRW_gpencil_populate_datablock(
{
GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
const DRWContextState *draw_ctx = DRW_context_state_get();
bGPdata *gpd = (bGPdata *)ob->data;
bGPdata *gpd_eval = (bGPdata *)ob->data;
bGPdata *gpd = (bGPdata *)DEG_get_original_id(&gpd_eval->id);
View3D *v3d = draw_ctx->v3d;
int cfra_eval = (int)DEG_get_ctime(draw_ctx->depsgraph);
ToolSettings *ts = scene->toolsettings;
@ -1235,6 +1255,7 @@ void DRW_gpencil_populate_datablock(
const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && main_onion;
const bool overlay = v3d != NULL ? (bool)((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) : true;
float opacity;
bGPDframe *p = NULL;
/* check if playing animation */
bool playing = stl->storage->is_playing;
@ -1260,7 +1281,7 @@ void DRW_gpencil_populate_datablock(
/* if pose mode, maybe the overlay to fade geometry is enabled */
if ((draw_ctx->obact) && (draw_ctx->object_mode == OB_MODE_POSE) &&
(v3d->overlay.flag & V3D_OVERLAY_BONE_SELECT))
(v3d->overlay.flag & V3D_OVERLAY_BONE_SELECT))
{
opacity = gpl->opacity * v3d->overlay.bone_select_alpha;
}
@ -1268,53 +1289,42 @@ void DRW_gpencil_populate_datablock(
opacity = gpl->opacity;
}
/* create GHash if need */
if (gpl->runtime.derived_data == NULL) {
gpl->runtime.derived_data = (GHash *)BLI_ghash_str_new(gpl->info);
}
if (BLI_ghash_haskey(gpl->runtime.derived_data, ob->id.name)) {
derived_gpf = BLI_ghash_lookup(gpl->runtime.derived_data, ob->id.name);
}
else {
/* verify we have frame duplicated already */
if (cache_ob->is_dup_ob) {
continue;
}
derived_gpf = NULL;
}
if (derived_gpf == NULL) {
cache->is_dirty = true;
}
if ((!cache_ob->is_dup_ob) && (cache->is_dirty)) {
if (derived_gpf != NULL) {
/* first clear temp data */
if (BLI_ghash_haskey(gpl->runtime.derived_data, ob->id.name)) {
BLI_ghash_remove(gpl->runtime.derived_data, ob->id.name, NULL, NULL);
}
BKE_gpencil_free_frame_runtime_data(derived_gpf);
}
/* create new data */
derived_gpf = BKE_gpencil_frame_duplicate(gpf);
if (!BLI_ghash_haskey(gpl->runtime.derived_data, ob->id.name)) {
BLI_ghash_insert(gpl->runtime.derived_data, ob->id.name, derived_gpf);
/* create derived array data or expand */
if (cache_ob->data_idx + 1 > gpl->runtime.len_derived) {
if ((gpl->runtime.len_derived == 0) ||
(gpl->runtime.derived_array == NULL))
{
p = MEM_callocN(sizeof(struct bGPDframe), "bGPDframe array");
gpl->runtime.len_derived = 1;
}
else {
BLI_ghash_reinsert(gpl->runtime.derived_data, ob->id.name, derived_gpf, NULL, NULL);
gpl->runtime.len_derived++;
p = MEM_recallocN(gpl->runtime.derived_array, sizeof(struct bGPDframe) * gpl->runtime.len_derived);
}
gpl->runtime.derived_array = p;
derived_gpf = &gpl->runtime.derived_array[cache_ob->data_idx];
}
derived_gpf = &gpl->runtime.derived_array[cache_ob->data_idx];
/* if no derived frame or dirty cache, create a new one */
if ((derived_gpf == NULL) || (cache->is_dirty)) {
if (derived_gpf != NULL) {
/* first clear temp data */
BKE_gpencil_free_frame_runtime_data(derived_gpf);
}
/* create new data (do not assign new memory)*/
gpencil_copy_frame(gpf, derived_gpf);
}
/* draw onion skins */
if (!ID_IS_LINKED(&gpd->id)) {
ID *orig_id = gpd->id.orig_id;
/* GPXX: Now only a datablock with one use is allowed to be compatible
* with instances
*/
if ((!cache_ob->is_dup_onion) && (gpd->flag & GP_DATA_SHOW_ONIONSKINS) &&
if ((!cache_ob->is_dup_data) &&
(gpd->flag & GP_DATA_SHOW_ONIONSKINS) &&
(do_onion) && (gpl->onion_flag & GP_LAYER_ONIONSKIN) &&
((!playing) || (gpd->onion_flag & GP_ONION_GHOST_ALWAYS)) &&
(!cache_ob->is_dup_ob) && (orig_id->us <= 1))
(!cache_ob->is_dup_ob) && (gpd->id.us <= 1))
{
if (((!stl->storage->is_render) && (overlay)) ||
((stl->storage->is_render) && (gpd->onion_flag & GP_ONION_GHOST_ALWAYS)))

View File

@ -58,8 +58,8 @@ struct RenderLayer;
/* used to save gpencil object data for drawing */
typedef struct tGPencilObjectCache {
struct Object *ob;
struct bGPdata *gpd;
char ob_name[64];
int init_grp, end_grp;
int idx; /*original index, can change after sort */
@ -82,7 +82,8 @@ typedef struct tGPencilObjectCache {
float obmat[4][4];
float zdepth; /* z-depth value to sort gp object */
bool is_dup_ob; /* flag to tag duplicate objects */
bool is_dup_onion; /* other object display onion already */
bool is_dup_data; /* other object uses datablock already */
int data_idx; /* derived data index */
} tGPencilObjectCache;
/* *********** LISTS *********** */

View File

@ -479,7 +479,8 @@ static int gp_layer_duplicate_object_exec(bContext *C, wmOperator *op)
/* make copy of layer */
bGPDlayer *gpl_dst = MEM_dupallocN(gpl_src);
gpl_dst->prev = gpl_dst->next = NULL;
gpl_dst->runtime.derived_data = NULL;
gpl_dst->runtime.derived_array = NULL;
gpl_dst->runtime.len_derived = 0;
BLI_addtail(&gpd_dst->layers, gpl_dst);
BLI_uniquename(&gpd_dst->layers, gpl_dst, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl_dst->info));

View File

@ -235,9 +235,11 @@ typedef enum eGPDframe_Flag {
/* Runtime temp data for bGPDlayer */
typedef struct bGPDlayer_Runtime {
struct GHash *derived_data; /* runtime data created by modifiers */
struct bGPDframe *derived_array;/* runtime data created by modifiers */
int icon_id; /* id for dynamic icon used to show annotation color preview for layer */
int batch_index; /* batch used for dupli instances */
int len_derived; /* len of the derived array */
char pad_[4];
} bGPDlayer_Runtime;
/* Grease-Pencil Annotations - 'Layer' */
@ -304,8 +306,6 @@ typedef enum eGPDlayer_OnionFlag {
/* Runtime temp data for bGPdata */
typedef struct bGPdata_Runtime {
/* Drawing Manager cache */
struct GHash *batch_cache_data;
void *sbuffer; /* stroke buffer (can hold GP_STROKE_BUFFER_MAX) */
/* GP Object drawing */

View File

@ -58,7 +58,7 @@ struct DerivedMesh;
struct SculptSession;
struct bGPdata;
struct RigidBodyOb;
struct GpencilBatchCache;
/* Vertex Groups - Name Info */
typedef struct bDeformGroup {
@ -146,6 +146,9 @@ typedef struct Object_Runtime {
/* Runtime evaluated curve-specific data, not stored in the file. */
struct CurveCache *curve_cache;
/* Runtime grease pencil drawing data */
struct GpencilBatchCache *gpencil_cache;
} Object_Runtime;
typedef struct Object {

View File

@ -161,7 +161,7 @@ static char *rna_ShaderFx_path(PointerRNA *ptr)
static void rna_ShaderFx_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
DEG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NC_GPENCIL, ptr->id.data);
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ptr->id.data);
}
static void rna_ShaderFx_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)