Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntonioya <blendergit@gmail.com>2018-10-19 21:39:21 +0300
committerAntonioya <blendergit@gmail.com>2018-10-20 10:08:34 +0300
commit541d07045b79cef52bdcf8bd1d90fc60793c9872 (patch)
treec8fcaaf79ce0d3a0cea526338e65d63a6de6048f /source/blender/draw
parentb634bf9fb64930e0073c17bc115b6c3436b9a8e2 (diff)
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.
Diffstat (limited to 'source/blender/draw')
-rw-r--r--source/blender/draw/DRW_engine.h1
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_cache_utils.c158
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_utils.c84
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.h5
4 files changed, 143 insertions, 105 deletions
diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h
index d61958931e5..f99ce1be894 100644
--- a/source/blender/draw/DRW_engine.h
+++ b/source/blender/draw/DRW_engine.h
@@ -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);
diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
index e8f8254bb5b..9d8c4b6d0f8 100644
--- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
+++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
@@ -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;
}
}
+
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
index 943bd5202db..6d15c8145e1 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
@@ -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;
+ /* 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;
}
- derived_gpf = NULL;
- }
+ else {
+ gpl->runtime.len_derived++;
+ p = MEM_recallocN(gpl->runtime.derived_array, sizeof(struct bGPDframe) * gpl->runtime.len_derived);
+ }
+ gpl->runtime.derived_array = p;
- if (derived_gpf == NULL) {
- cache->is_dirty = true;
+ derived_gpf = &gpl->runtime.derived_array[cache_ob->data_idx];
}
- if ((!cache_ob->is_dup_ob) && (cache->is_dirty)) {
+
+ 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 */
- 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);
- }
- else {
- BLI_ghash_reinsert(gpl->runtime.derived_data, ob->id.name, derived_gpf, NULL, NULL);
- }
+ /* 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)))
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h
index b8844d3c3e9..e2e6bf4edf0 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.h
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.h
@@ -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 *********** */