GP: Refactor drawing engine to single VBO
authorAntonioya <blendergit@gmail.com>
Tue, 20 Nov 2018 18:26:16 +0000 (19:26 +0100)
committerAntonioya <blendergit@gmail.com>
Tue, 20 Nov 2018 19:05:37 +0000 (20:05 +0100)
This is part of T57829.

Reduce the number of batches used to only one by shader type.  This reduces GPU overhead and increase a lot the FPS. As the number of batches is small, the time to allocate and free memory was reduced in 90% or more.

Also the code has been simplified and all batch management has been removed because this is not necessary. Now, all shading groups are created after all vertex buffer data for all strokes has been created using DRW_shgroup_call_range_add().

All batch cache data has been moved to the Object runtime struct and not as before where some parts (derived data) were saved inside GPD datablock.

For particles, now the code is faster and cleaner and gets better FPS.

Thanks to ClĂ©ment Foucault for his help and advices to improve speed.

28 files changed:
source/blender/blenkernel/BKE_gpencil.h
source/blender/blenkernel/BKE_gpencil_modifier.h
source/blender/blenkernel/intern/gpencil.c
source/blender/blenloader/intern/readfile.c
source/blender/draw/engines/gpencil/gpencil_cache_utils.c
source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
source/blender/draw/engines/gpencil/gpencil_draw_utils.c
source/blender/draw/engines/gpencil/gpencil_engine.c
source/blender/draw/engines/gpencil/gpencil_engine.h
source/blender/editors/gpencil/gpencil_data.c
source/blender/editors/gpencil/gpencil_utils.c
source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c
source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c
source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c
source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
source/blender/makesdna/DNA_gpencil_types.h

index 3b8df66668a7417bb80dcf564b288994e3409a79..34c610838723d36af1d657d8c9b11434014c7c54 100644 (file)
@@ -65,7 +65,6 @@ bool BKE_gpencil_free_strokes(struct bGPDframe *gpf);
 void BKE_gpencil_free_frames(struct bGPDlayer *gpl);
 void BKE_gpencil_free_layers(struct ListBase *list);
 bool BKE_gpencil_free_frame_runtime_data(struct bGPDframe *derived_gpf);
-void BKE_gpencil_free_derived_frames(struct bGPdata *gpd);
 void BKE_gpencil_free(struct bGPdata *gpd, bool free_all);
 
 void BKE_gpencil_batch_cache_dirty_tag(struct bGPdata *gpd);
index 91f368613cb045deaff9d71cfdd24faef0e15f42..e31f61c909adf5b7f4c4531ece92ec1ed5f23025 100644 (file)
@@ -232,6 +232,11 @@ typedef struct GpencilModifierTypeInfo {
         */
        void (*foreachTexLink)(struct GpencilModifierData *md, struct Object *ob,
                               GreasePencilTexWalkFunc walk, void *userData);
+
+       /* get the number of times the strokes are duplicated in this modifier.
+        * This is used to calculate the size of the GPU VBOs
+        */
+       int (*getDuplicationFactor)(struct GpencilModifierData *md);
 } GpencilModifierTypeInfo;
 
 /* Initialize modifier's global data (type info and some common global storages). */
index f2225bca3f5b980c71bc88a5860298e2f2dca02e..98d255df08030196155cd736f3178e75d39862b6 100644 (file)
@@ -211,46 +211,6 @@ void BKE_gpencil_free_layers(ListBase *list)
        }
 }
 
-/* clear all runtime derived data */
-static void BKE_gpencil_clear_derived(bGPDlayer *gpl)
-{
-       if (gpl->runtime.derived_array == NULL) {
-               return;
-       }
-
-       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*/
-static void BKE_gpencil_free_layers_temp_data(ListBase *list)
-{
-       bGPDlayer *gpl_next;
-
-       /* error checking */
-       if (list == NULL) return;
-       /* delete layers */
-       for (bGPDlayer *gpl = list->first; gpl; gpl = gpl_next) {
-               gpl_next = gpl->next;
-               BKE_gpencil_clear_derived(gpl);
-       }
-}
-
-/* Free temp gpf derived frames */
-void BKE_gpencil_free_derived_frames(bGPdata *gpd)
-{
-       /* error checking */
-       if (gpd == NULL) return;
-       for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
-               BKE_gpencil_clear_derived(gpl);
-       }
-}
-
 /** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */
 void BKE_gpencil_free(bGPdata *gpd, bool free_all)
 {
@@ -258,9 +218,6 @@ void BKE_gpencil_free(bGPdata *gpd, bool free_all)
        BKE_animdata_free(&gpd->id, false);
 
        /* free layers */
-       if (free_all) {
-               BKE_gpencil_free_layers_temp_data(&gpd->layers);
-       }
        BKE_gpencil_free_layers(&gpd->layers);
 
        /* materials */
@@ -639,8 +596,6 @@ 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_array = NULL;
-       gpl_dst->runtime.len_derived = 0;
 
        /* copy frames */
        BLI_listbase_clear(&gpl_dst->frames);
@@ -1031,9 +986,6 @@ void BKE_gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl)
        /* free icon providing preview of icon color */
        BKE_icon_delete(gpl->runtime.icon_id);
 
-       /* free derived data */
-       BKE_gpencil_clear_derived(gpl);
-
        BLI_freelinkN(&gpd->layers, gpl);
 }
 
index 9596df58170905f3a021bfad9c22f476200d1597..50bf2f79fdc91f8d83d23d15c2bea898e6bbeaec 100644 (file)
@@ -6612,8 +6612,6 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
 
                gpl->actframe = newdataadr(fd, gpl->actframe);
 
-               gpl->runtime.derived_array = NULL;
-               gpl->runtime.len_derived = 0;
                gpl->runtime.icon_id = 0;
 
                for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
index 30887e3fb196458a108d40a5ec50eaf8a089349d..15ac3f37addd7477eeba0dca1659d40ac247acd2 100644 (file)
 #include "DRW_engine.h"
 #include "DRW_render.h"
 
-#include "BKE_global.h"
-
 #include "ED_gpencil.h"
 #include "ED_view3d.h"
 
 #include "DNA_gpencil_types.h"
 #include "DNA_view3d_types.h"
 
+#include "BKE_gpencil.h"
+
 #include "gpencil_engine.h"
 
 #include "draw_cache_impl.h"
 #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; i++) {
-               tGPencilObjectCache *cache_elem = &cache_array[i];
-               if (cache_elem->ob == ob) {
-                       *r_index = cache_elem->data_idx;
-                       return true;
-               }
-       }
-       return false;
-}
-
-static bool gpencil_check_datablock_duplicated(
-        tGPencilObjectCache *cache_array, int gp_cache_used,
-        Object *ob, bGPdata *gpd)
-{
-       if (gp_cache_used == 0) {
-               return false;
-       }
-
-       for (int i = 0; i < gp_cache_used; i++) {
-               tGPencilObjectCache *cache_elem = &cache_array[i];
-               if ((cache_elem->ob != ob) &&
-                   (cache_elem->gpd == gpd))
-               {
-                       return true;
-               }
-       }
-       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,
@@ -133,38 +76,15 @@ tGPencilObjectCache *gpencil_object_cache_add(
        copy_m4_m4(cache_elem->obmat, ob->obmat);
        cache_elem->idx = *gp_cache_used;
 
-       /* 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;
-       }
+       /* object is duplicated (particle) */
+       cache_elem->is_dup_ob = ob->base_flag & BASE_FROMDUPLI;
 
        /* save FXs */
        cache_elem->pixfactor = cache_elem->gpd->pixfactor;
        cache_elem->shader_fx = ob_orig->shader_fx;
 
-       cache_elem->init_grp = 0;
-       cache_elem->end_grp = -1;
+       cache_elem->init_grp = NULL;
+       cache_elem->end_grp = NULL;
 
        /* calculate zdepth from point of view */
        float zdepth = 0.0;
@@ -198,6 +118,48 @@ tGPencilObjectCache *gpencil_object_cache_add(
        return cache_array;
 }
 
+/* add a shading group to the cache to create later */
+GpencilBatchGroup *gpencil_group_cache_add(
+       GpencilBatchGroup *cache_array,
+       bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps,
+       const short type, const bool onion,
+       const int vertex_idx,
+       int *grp_size, int *grp_used)
+{
+       GpencilBatchGroup *cache_elem = NULL;
+       GpencilBatchGroup *p = NULL;
+
+       /* By default a cache is created with one block with a predefined number of free slots,
+       if the size is not enough, the cache is reallocated adding a new block of free slots.
+       This is done in order to keep cache small */
+       if (*grp_used + 1 > *grp_size) {
+               if ((*grp_size == 0) || (cache_array == NULL)) {
+                       p = MEM_callocN(sizeof(struct GpencilBatchGroup) * GPENCIL_GROUPS_BLOCK_SIZE, "GpencilBatchGroup");
+                       *grp_size = GPENCIL_GROUPS_BLOCK_SIZE;
+               }
+               else {
+                       *grp_size += GPENCIL_GROUPS_BLOCK_SIZE;
+                       p = MEM_recallocN(cache_array, sizeof(struct GpencilBatchGroup) * *grp_size);
+               }
+               cache_array = p;
+       }
+       /* zero out all data */
+       cache_elem = &cache_array[*grp_used];
+       memset(cache_elem, 0, sizeof(*cache_elem));
+
+       cache_elem->gpl = gpl;
+       cache_elem->gpf = gpf;
+       cache_elem->gps = gps;
+       cache_elem->type = type;
+       cache_elem->onion = onion;
+       cache_elem->vertex_idx = vertex_idx;
+
+       /* increase slots used in cache */
+       (*grp_used)++;
+
+       return cache_array;
+}
+
 /* get current cache data */
 static GpencilBatchCache *gpencil_batch_get_element(Object *ob)
 {
@@ -208,51 +170,33 @@ static GpencilBatchCache *gpencil_batch_get_element(Object *ob)
 /* verify if cache is valid */
 static bool gpencil_batch_cache_valid(GpencilBatchCache *cache, bGPdata *gpd, int cfra)
 {
+       bool valid = true;
        if (cache == NULL) {
                return false;
        }
 
        cache->is_editmode = GPENCIL_ANY_EDIT_MODE(gpd);
-
        if (cfra != cache->cache_frame) {
-               return false;
+               valid = false;
        }
-
-       if (gpd->flag & GP_DATA_CACHE_IS_DIRTY) {
-               return false;
+       else if (gpd->flag & GP_DATA_CACHE_IS_DIRTY) {
+               valid = false;
        }
-
-       if (cache->is_editmode) {
-               return false;
+       else if (gpd->flag & GP_DATA_SHOW_ONIONSKINS) {
+               /* if onion, set as dirty always
+                * This reduces performance, but avoid any crash in the multiple
+                * overlay and multiwindow options and keep all windows working
+                */
+               valid = false;
        }
-
-       if (cache->is_dirty) {
-               return false;
+       else if (cache->is_editmode) {
+               valid = false;
        }
-
-       return true;
-}
-
-/* resize the cache to the number of slots */
-static void gpencil_batch_cache_resize(GpencilBatchCache *cache, int slots)
-{
-       cache->cache_size = slots;
-       cache->batch_stroke = MEM_recallocN(cache->batch_stroke, sizeof(struct Gwn_Batch *) * slots);
-       cache->batch_fill = MEM_recallocN(cache->batch_fill, sizeof(struct Gwn_Batch *) * slots);
-       cache->batch_edit = MEM_recallocN(cache->batch_edit, sizeof(struct Gwn_Batch *) * slots);
-       cache->batch_edlin = MEM_recallocN(cache->batch_edlin, sizeof(struct Gwn_Batch *) * slots);
-}
-
-/* check size and increase if no free slots */
-void gpencil_batch_cache_check_free_slots(Object *ob)
-{
-       GpencilBatchCache *cache = gpencil_batch_get_element(ob);
-
-       /* the memory is reallocated by chunks, not for one slot only to improve speed */
-       if (cache->cache_idx >= cache->cache_size) {
-               cache->cache_size += GPENCIL_MIN_BATCH_SLOTS_CHUNK;
-               gpencil_batch_cache_resize(cache, cache->cache_size);
+       else if (cache->is_dirty) {
+               valid = false;
        }
+
+       return valid;
 }
 
 /* cache init */
@@ -263,10 +207,6 @@ static GpencilBatchCache *gpencil_batch_cache_init(Object *ob, int cfra)
 
        GpencilBatchCache *cache = gpencil_batch_get_element(ob);
 
-       if (G.debug_value >= 664) {
-               printf("gpencil_batch_cache_init: %s\n", ob->id.name);
-       }
-
        if (!cache) {
                cache = MEM_callocN(sizeof(*cache), __func__);
                ob_orig->runtime.gpencil_cache = cache;
@@ -275,19 +215,17 @@ static GpencilBatchCache *gpencil_batch_cache_init(Object *ob, int cfra)
                memset(cache, 0, sizeof(*cache));
        }
 
-       cache->cache_size = GPENCIL_MIN_BATCH_SLOTS_CHUNK;
-       cache->batch_stroke = MEM_callocN(sizeof(struct Gwn_Batch *) * cache->cache_size, "Gpencil_Batch_Stroke");
-       cache->batch_fill = MEM_callocN(sizeof(struct Gwn_Batch *) * cache->cache_size, "Gpencil_Batch_Fill");
-       cache->batch_edit = MEM_callocN(sizeof(struct Gwn_Batch *) * cache->cache_size, "Gpencil_Batch_Edit");
-       cache->batch_edlin = MEM_callocN(sizeof(struct Gwn_Batch *) * cache->cache_size, "Gpencil_Batch_Edlin");
-
        cache->is_editmode = GPENCIL_ANY_EDIT_MODE(gpd);
-       gpd->flag &= ~GP_DATA_CACHE_IS_DIRTY;
 
-       cache->cache_idx = 0;
        cache->is_dirty = true;
+
        cache->cache_frame = cfra;
 
+       /* create array of derived frames equal to number of layers */
+       cache->tot_layers = BLI_listbase_count(&gpd->layers);
+       CLAMP_MIN(cache->tot_layers, 1);
+       cache->derived_array = MEM_callocN(sizeof(struct bGPDframe) * cache->tot_layers, "Derived GPF");
+
        return cache;
 }
 
@@ -298,24 +236,30 @@ static void gpencil_batch_cache_clear(GpencilBatchCache *cache)
                return;
        }
 
-       if (cache->cache_size == 0) {
-               return;
-       }
-
-       if (cache->cache_size > 0) {
-               for (int i = 0; i < cache->cache_size; i++) {
-                       GPU_BATCH_DISCARD_SAFE(cache->batch_stroke[i]);
-                       GPU_BATCH_DISCARD_SAFE(cache->batch_fill[i]);
-                       GPU_BATCH_DISCARD_SAFE(cache->batch_edit[i]);
-                       GPU_BATCH_DISCARD_SAFE(cache->batch_edlin[i]);
-               }
-               MEM_SAFE_FREE(cache->batch_stroke);
-               MEM_SAFE_FREE(cache->batch_fill);
-               MEM_SAFE_FREE(cache->batch_edit);
-               MEM_SAFE_FREE(cache->batch_edlin);
+       GPU_BATCH_DISCARD_SAFE(cache->b_stroke.batch);
+       GPU_BATCH_DISCARD_SAFE(cache->b_point.batch);
+       GPU_BATCH_DISCARD_SAFE(cache->b_fill.batch);
+       GPU_BATCH_DISCARD_SAFE(cache->b_edit.batch);
+       GPU_BATCH_DISCARD_SAFE(cache->b_edlin.batch);
+
+       MEM_SAFE_FREE(cache->b_stroke.batch);
+       MEM_SAFE_FREE(cache->b_point.batch);
+       MEM_SAFE_FREE(cache->b_fill.batch);
+       MEM_SAFE_FREE(cache->b_edit.batch);
+       MEM_SAFE_FREE(cache->b_edlin.batch);
+
+       MEM_SAFE_FREE(cache->grp_cache);
+       cache->grp_size = 0;
+       cache->grp_used = 0;
+
+       /* clear all frames derived data */
+       for (int i = 0; i < cache->tot_layers; i++) {
+               bGPDframe *derived_gpf = &cache->derived_array[i];
+               BKE_gpencil_free_frame_runtime_data(derived_gpf);
+               derived_gpf = NULL;
        }
-
-       cache->cache_size = 0;
+       cache->tot_layers = 0;
+       MEM_SAFE_FREE(cache->derived_array);
 }
 
 /* get cache */
@@ -326,10 +270,6 @@ GpencilBatchCache *gpencil_batch_cache_get(Object *ob, int 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);
-               }
-
                if (cache) {
                        gpencil_batch_cache_clear(cache);
                }
index f255892de4403845295d088c72f01f4f30913512..ec690fdd14bc0492a1d49ffa53adfbb21a7b28d7 100644 (file)
@@ -87,24 +87,33 @@ static void gpencil_set_fill_point(
        GPU_vertbuf_attr_set(vbo, text_id, idx, uv);
 }
 
-/* create batch geometry data for points stroke shader */
-GPUBatch *DRW_gpencil_get_point_geom(bGPDstroke *gps, short thickness, const float ink[4])
+static void gpencil_vbo_ensure_size(GpencilBatchCacheElem *be, int totvertex)
 {
-       static GPUVertFormat format = { 0 };
-       static uint pos_id, color_id, size_id, uvdata_id;
-       if (format.attr_len == 0) {
-               pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
-               color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
-               size_id = GPU_vertformat_attr_add(&format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
-               uvdata_id = GPU_vertformat_attr_add(&format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+       if (be->vbo->vertex_alloc <= be->vbo_len + totvertex) {
+               uint newsize = be->vbo->vertex_alloc + (((totvertex / GPENCIL_VBO_BLOCK_SIZE) + 1) * GPENCIL_VBO_BLOCK_SIZE);
+               GPU_vertbuf_data_resize(be->vbo, newsize);
        }
+}
 
-       GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
-       GPU_vertbuf_data_alloc(vbo, gps->totpoints);
+/* create batch geometry data for points stroke shader */
+void DRW_gpencil_get_point_geom(GpencilBatchCacheElem *be, bGPDstroke *gps, short thickness, const float ink[4])
+{
+       int totvertex = gps->totpoints;
+       if (be->vbo == NULL) {
+               be->pos_id = GPU_vertformat_attr_add(&be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+               be->color_id = GPU_vertformat_attr_add(&be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+               be->thickness_id = GPU_vertformat_attr_add(&be->format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+               be->uvdata_id = GPU_vertformat_attr_add(&be->format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
 
+               be->vbo = GPU_vertbuf_create_with_format(&be->format);
+               GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
+               be->vbo_len = 0;
+       }
+       else {
+               gpencil_vbo_ensure_size(be, totvertex);
+       }
        /* draw stroke curve */
        const bGPDspoint *pt = gps->points;
-       int idx = 0;
        float alpha;
        float col[4];
 
@@ -116,86 +125,124 @@ GPUBatch *DRW_gpencil_get_point_geom(bGPDstroke *gps, short thickness, const flo
 
                float thick = max_ff(pt->pressure * thickness, 1.0f);
 
-               GPU_vertbuf_attr_set(vbo, color_id, idx, col);
-               GPU_vertbuf_attr_set(vbo, size_id, idx, &thick);
+               GPU_vertbuf_attr_set(be->vbo, be->color_id, be->vbo_len, col);
+               GPU_vertbuf_attr_set(be->vbo, be->thickness_id, be->vbo_len, &thick);
 
                /* transfer both values using the same shader variable */
                float uvdata[2] = { pt->uv_fac, pt->uv_rot };
-               GPU_vertbuf_attr_set(vbo, uvdata_id, idx, uvdata);
+               GPU_vertbuf_attr_set(be->vbo, be->uvdata_id, be->vbo_len, uvdata);
 
-               GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x);
-               idx++;
+               GPU_vertbuf_attr_set(be->vbo, be->pos_id, be->vbo_len, &pt->x);
+               be->vbo_len++;
        }
-
-       return GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
 }
 
 /* create batch geometry data for stroke shader */
-GPUBatch *DRW_gpencil_get_stroke_geom(bGPDstroke *gps, short thickness, const float ink[4])
+void DRW_gpencil_get_stroke_geom(struct GpencilBatchCacheElem *be, bGPDstroke *gps, short thickness, const float ink[4])
 {
        bGPDspoint *points = gps->points;
        int totpoints = gps->totpoints;
        /* if cyclic needs more vertex */
        int cyclic_add = (gps->flag & GP_STROKE_CYCLIC) ? 1 : 0;
+       int totvertex = totpoints + cyclic_add + 2;
 
-       static GPUVertFormat format = { 0 };
-       static uint pos_id, color_id, thickness_id, uvdata_id;
-       if (format.attr_len == 0) {
-               pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
-               color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
-               thickness_id = GPU_vertformat_attr_add(&format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
-               uvdata_id = GPU_vertformat_attr_add(&format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-       }
+       if (be->vbo == NULL) {
+               be->pos_id = GPU_vertformat_attr_add(&be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+               be->color_id = GPU_vertformat_attr_add(&be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+               be->thickness_id = GPU_vertformat_attr_add(&be->format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+               be->uvdata_id = GPU_vertformat_attr_add(&be->format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
 
-       GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
-       GPU_vertbuf_data_alloc(vbo, totpoints + cyclic_add + 2);
+               be->vbo = GPU_vertbuf_create_with_format(&be->format);
+               GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
+               be->vbo_len = 0;
+       }
+       else {
+               gpencil_vbo_ensure_size(be, totvertex);
+       }
 
        /* draw stroke curve */
        const bGPDspoint *pt = points;
-       int idx = 0;
        for (int i = 0; i < totpoints; i++, pt++) {
                /* first point for adjacency (not drawn) */
                if (i == 0) {
                        if (gps->flag & GP_STROKE_CYCLIC && totpoints > 2) {
                                gpencil_set_stroke_point(
-                                       vbo, &points[totpoints - 1], idx,
-                                       pos_id, color_id, thickness_id, uvdata_id, thickness, ink);
-                               idx++;
+                                       be->vbo, &points[totpoints - 1], be->vbo_len,
+                                       be->pos_id, be->color_id, be->thickness_id, be->uvdata_id, thickness, ink);
+                               be->vbo_len++;
                        }
                        else {
                                gpencil_set_stroke_point(
-                                       vbo, &points[1], idx,
-                                       pos_id, color_id, thickness_id, uvdata_id, thickness, ink);
-                               idx++;
+                                       be->vbo, &points[1], be->vbo_len,
+                                       be->pos_id, be->color_id, be->thickness_id, be->uvdata_id, thickness, ink);
+                               be->vbo_len++;
                        }
                }
                /* set point */
                gpencil_set_stroke_point(
-                       vbo, pt, idx,
-                       pos_id, color_id, thickness_id, uvdata_id, thickness, ink);
-               idx++;
+                       be->vbo, pt, be->vbo_len,
+                       be->pos_id, be->color_id, be->thickness_id, be->uvdata_id, thickness, ink);
+               be->vbo_len++;
        }
 
        if (gps->flag & GP_STROKE_CYCLIC && totpoints > 2) {
                /* draw line to first point to complete the cycle */
                gpencil_set_stroke_point(
-                       vbo, &points[0], idx,
-                       pos_id, color_id, thickness_id, uvdata_id, thickness, ink);
-               idx++;
+                       be->vbo, &points[0], be->vbo_len,
+                       be->pos_id, be->color_id, be->thickness_id, be->uvdata_id, thickness, ink);
+               be->vbo_len++;
                /* now add adjacency point (not drawn) */
                gpencil_set_stroke_point(
-                       vbo, &points[1], idx,
-                       pos_id, color_id, thickness_id, uvdata_id, thickness, ink);
-               idx++;
+                       be->vbo, &points[1], be->vbo_len,
+                       be->pos_id, be->color_id, be->thickness_id, be->uvdata_id, thickness, ink);
+               be->vbo_len++;
        }
        /* last adjacency point (not drawn) */
        else {
                gpencil_set_stroke_point(
-                       vbo, &points[totpoints - 2], idx,
-                       pos_id, color_id, thickness_id, uvdata_id, thickness, ink);
+                       be->vbo, &points[totpoints - 2], be->vbo_len,
+                       be->pos_id, be->color_id, be->thickness_id, be->uvdata_id, thickness, ink);
+               be->vbo_len++;
        }
+}
 
-       return GPU_batch_create_ex(GPU_PRIM_LINE_STRIP_ADJ, vbo, NULL, GPU_BATCH_OWNS_VBO);
+/* create batch geometry data for stroke shader */
+void DRW_gpencil_get_fill_geom(struct GpencilBatchCacheElem *be, Object *ob, bGPDstroke *gps, const float color[4])
+{
+       BLI_assert(gps->totpoints >= 3);
+
+       /* Calculate triangles cache for filling area (must be done only after changes) */
+       if ((gps->flag & GP_STROKE_RECALC_CACHES) || (gps->tot_triangles == 0) || (gps->triangles == NULL)) {
+               DRW_gpencil_triangulate_stroke_fill(ob, gps);
+               ED_gpencil_calc_stroke_uv(ob, gps);
+       }
+
+       BLI_assert(gps->tot_triangles >= 1);
+       int totvertex = gps->tot_triangles * 3;
+
+       if (be->vbo == NULL) {
+               be->pos_id = GPU_vertformat_attr_add(&be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+               be->color_id = GPU_vertformat_attr_add(&be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+               be->uvdata_id = GPU_vertformat_attr_add(&be->format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+               be->vbo = GPU_vertbuf_create_with_format(&be->format);
+               GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
+               be->vbo_len = 0;
+       }
+       else {
+               gpencil_vbo_ensure_size(be, totvertex);
+       }
+
+       /* Draw all triangles for filling the polygon (cache must be calculated before) */
+       bGPDtriangle *stroke_triangle = gps->triangles;
+       for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) {
+               for (int j = 0; j < 3; j++) {
+                       gpencil_set_fill_point(
+                               be->vbo, be->vbo_len, &gps->points[stroke_triangle->verts[j]], color, stroke_triangle->uv[j],
+                               be->pos_id, be->color_id, be->uvdata_id);
+                       be->vbo_len++;
+               }
+       }
 }
 
 /* create batch geometry data for current buffer stroke shader */
@@ -407,47 +454,8 @@ GPUBatch *DRW_gpencil_get_buffer_fill_geom(bGPdata *gpd)
        return GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
 }
 
-/* create batch geometry data for stroke shader */
-GPUBatch *DRW_gpencil_get_fill_geom(Object *ob, bGPDstroke *gps, const float color[4])
-{
-       BLI_assert(gps->totpoints >= 3);
-
-       /* Calculate triangles cache for filling area (must be done only after changes) */
-       if ((gps->flag & GP_STROKE_RECALC_CACHES) || (gps->tot_triangles == 0) || (gps->triangles == NULL)) {
-               DRW_gpencil_triangulate_stroke_fill(ob, gps);
-               ED_gpencil_calc_stroke_uv(ob, gps);
-       }
-
-       BLI_assert(gps->tot_triangles >= 1);
-
-       static GPUVertFormat format = { 0 };
-       static uint pos_id, color_id, text_id;
-       if (format.attr_len == 0) {
-               pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
-               color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
-               text_id = GPU_vertformat_attr_add(&format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-       }
-
-       GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
-       GPU_vertbuf_data_alloc(vbo, gps->tot_triangles * 3);
-
-       /* Draw all triangles for filling the polygon (cache must be calculated before) */
-       bGPDtriangle *stroke_triangle = gps->triangles;
-       int idx = 0;
-       for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) {
-               for (int j = 0; j < 3; j++) {
-                       gpencil_set_fill_point(
-                               vbo, idx, &gps->points[stroke_triangle->verts[j]], color, stroke_triangle->uv[j],
-                               pos_id, color_id, text_id);
-                       idx++;
-               }
-       }
-
-       return GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
-}
-
 /* Draw selected verts for strokes being edited */
-GPUBatch *DRW_gpencil_get_edit_geom(bGPDstroke *gps, float alpha, short dflag)
+void DRW_gpencil_get_edit_geom(struct GpencilBatchCacheElem *be, bGPDstroke *gps, float alpha, short dflag)
 {
        const DRWContextState *draw_ctx = DRW_context_state_get();
        Object *ob = draw_ctx->obact;
@@ -483,16 +491,18 @@ GPUBatch *DRW_gpencil_get_edit_geom(bGPDstroke *gps, float alpha, short dflag)
        UI_GetThemeColor3fv(TH_GP_VERTEX, unselectColor);
        unselectColor[3] = alpha;
 
-       static GPUVertFormat format = { 0 };
-       static uint pos_id, color_id, size_id;
-       if (format.attr_len == 0) {
-               pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
-               color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
-               size_id = GPU_vertformat_attr_add(&format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
-       }
+       if (be->vbo == NULL) {
+               be->pos_id = GPU_vertformat_attr_add(&be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+               be->color_id = GPU_vertformat_attr_add(&be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+               be->thickness_id = GPU_vertformat_attr_add(&be->format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
 
-       GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
-       GPU_vertbuf_data_alloc(vbo, gps->totpoints);
+               be->vbo = GPU_vertbuf_create_with_format(&be->format);
+               GPU_vertbuf_data_alloc(be->vbo, gps->totpoints);
+               be->vbo_len = 0;
+       }
+       else {
+               gpencil_vbo_ensure_size(be, gps->totpoints);
+       }
 
        /* Draw start and end point differently if enabled stroke direction hint */
        bool show_direction_hint = (dflag & GP_DATA_SHOW_DIRECTION) && (gps->totpoints > 1);
@@ -501,7 +511,6 @@ GPUBatch *DRW_gpencil_get_edit_geom(bGPDstroke *gps, float alpha, short dflag)
        bGPDspoint *pt = gps->points;
        MDeformVert *dvert = gps->dvert;
 
-       int idx = 0;
        float fcolor[4];
        float fsize = 0;
        for (int i = 0; i < gps->totpoints; i++, pt++) {
@@ -535,20 +544,18 @@ GPUBatch *DRW_gpencil_get_edit_geom(bGPDstroke *gps, float alpha, short dflag)
                        }
                }
 
-               GPU_vertbuf_attr_set(vbo, color_id, idx, fcolor);
-               GPU_vertbuf_attr_set(vbo, size_id, idx, &fsize);
-               GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x);
-               idx++;
+               GPU_vertbuf_attr_set(be->vbo, be->color_id, be->vbo_len, fcolor);
+               GPU_vertbuf_attr_set(be->vbo, be->thickness_id, be->vbo_len, &fsize);
+               GPU_vertbuf_attr_set(be->vbo, be->pos_id, be->vbo_len, &pt->x);
+               be->vbo_len++;
                if (gps->dvert != NULL) {
                        dvert++;
                }
        }
-
-       return GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
 }
 
 /* Draw lines for strokes being edited */
-GPUBatch *DRW_gpencil_get_edlin_geom(bGPDstroke *gps, float alpha, short UNUSED(dflag))
+void DRW_gpencil_get_edlin_geom(struct GpencilBatchCacheElem *be, bGPDstroke *gps, float alpha, short UNUSED(dflag))
 {
        const DRWContextState *draw_ctx = DRW_context_state_get();
        Object *ob = draw_ctx->obact;
@@ -566,21 +573,22 @@ GPUBatch *DRW_gpencil_get_edlin_geom(bGPDstroke *gps, float alpha, short UNUSED(
        float linecolor[4];
        copy_v4_v4(linecolor, gpd->line_color);
 
-       static GPUVertFormat format = { 0 };
-       static uint pos_id, color_id;
-       if (format.attr_len == 0) {
-               pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
-               color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
-       }
+       if (be->vbo == NULL) {
+               be->pos_id = GPU_vertformat_attr_add(&be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+               be->color_id = GPU_vertformat_attr_add(&be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
 
-       GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
-       GPU_vertbuf_data_alloc(vbo, gps->totpoints);
+               be->vbo = GPU_vertbuf_create_with_format(&be->format);
+               GPU_vertbuf_data_alloc(be->vbo, gps->totpoints);
+               be->vbo_len = 0;
+       }
+       else {
+               gpencil_vbo_ensure_size(be, gps->totpoints);
+       }
 
        /* Draw all the stroke lines (selected or not) */
        bGPDspoint *pt = gps->points;
        MDeformVert *dvert = gps->dvert;
 
-       int idx = 0;
        float fcolor[4];
        for (int i = 0; i < gps->totpoints; i++, pt++) {
                /* weight paint */
@@ -600,16 +608,14 @@ GPUBatch *DRW_gpencil_get_edlin_geom(bGPDstroke *gps, float alpha, short UNUSED(
                        }
                }
 
-               GPU_vertbuf_attr_set(vbo, color_id, idx, fcolor);
-               GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x);
-               idx++;
+               GPU_vertbuf_attr_set(be->vbo, be->color_id, be->vbo_len, fcolor);
+               GPU_vertbuf_attr_set(be->vbo, be->pos_id, be->vbo_len, &pt->x);
+               be->vbo_len++;
 
                if (gps->dvert != NULL) {
                        dvert++;
                }
        }
-
-       return GPU_batch_create_ex(GPU_PRIM_LINE_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
 }
 
 static void set_grid_point(
index cba5cfccaf66a44f6fdc37bcdf21a6057785c253..9799ab85cfbffa17908ec669b8413f9c52597292 100644 (file)
 
 #define GP_SET_SRC_GPS(src_gps) if (src_gps) src_gps = src_gps->next
 
+/* Get number of vertex for using in GPU VBOs */
+void gpencil_calc_vertex(
+       GPENCIL_StorageList *stl, tGPencilObjectCache *cache_ob,
+       GpencilBatchCache *cache, bGPdata *gpd,
+       int cfra_eval)
+{
+       Object *ob = cache_ob->ob;
+       const DRWContextState *draw_ctx = DRW_context_state_get();
+       bGPDframe *gpf = NULL;
+
+       const bool time_remap = BKE_gpencil_has_time_modifiers(ob);
+
+       cache_ob->tot_vertex = 0;
+       cache_ob->tot_triangles = 0;
+
+       for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+               if (gpl->flag & GP_LAYER_HIDE) {
+                       continue;
+               }
+
+               /* verify time modifiers */
+               if ((time_remap) && (!stl->storage->simplify_modif)) {
+                       int remap_cfra = BKE_gpencil_time_modifier(
+                               draw_ctx->depsgraph, draw_ctx->scene, ob, gpl, cfra_eval,
+                               stl->storage->is_render);
+                       gpf = BKE_gpencil_layer_getframe(gpl, remap_cfra, GP_GETFRAME_USE_PREV);
+               }
+               else {
+                       gpf = gpl->actframe;
+               }
+               
+               if (gpf == NULL) {
+                       continue;
+               }
+
+               for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+                       cache_ob->tot_vertex += gps->totpoints + 3;
+                       cache_ob->tot_triangles += gps->totpoints - 1;
+               }
+       }
+
+       cache->b_fill.tot_vertex = cache_ob->tot_triangles * 3;
+       cache->b_stroke.tot_vertex = cache_ob->tot_vertex;
+       cache->b_point.tot_vertex = cache_ob->tot_vertex;
+
+       /* some modifiers can change the number of points */
+       int factor = 0;
+       GpencilModifierData *md;
+       for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+               const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+               /* only modifiers that change size */
+               if (mti && mti->getDuplicationFactor) {
+                       factor = mti->getDuplicationFactor(md);
+
+                       cache->b_fill.tot_vertex *= factor;
+                       cache->b_stroke.tot_vertex *= factor;
+                       cache->b_point.tot_vertex *= factor;
+               }
+       }
+}
+
 /* Helper for doing all the checks on whether a stroke can be drawn */
 static bool gpencil_can_draw_stroke(
         struct MaterialGPencilStyle *gp_style, const bGPDstroke *gps,
@@ -182,79 +243,6 @@ static void gpencil_stroke_2d_flat(const bGPDspoint *points, int totpoints, floa
        *r_direction = (int)locy[2];
 }
 
-/* Triangulate stroke for high quality fill (this is done only if cache is null or stroke was modified) */
-void DRW_gpencil_triangulate_stroke_fill(Object *ob, bGPDstroke *gps)
-{
-       BLI_assert(gps->totpoints >= 3);
-
-       bGPdata *gpd = (bGPdata *)ob->data;
-
-       /* allocate memory for temporary areas */
-       gps->tot_triangles = gps->totpoints - 2;
-       uint(*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles, "GP Stroke temp triangulation");
-       float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints, "GP Stroke temp 2d points");
-       float(*uv)[2] = MEM_mallocN(sizeof(*uv) * gps->totpoints, "GP Stroke temp 2d uv data");
-
-       int direction = 0;
-
-       /* convert to 2d and triangulate */
-       gpencil_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction);
-       BLI_polyfill_calc(points2d, (uint)gps->totpoints, direction, tmp_triangles);
-
-       /* calc texture coordinates automatically */
-       float minv[2];
-       float maxv[2];
-       /* first needs bounding box data */
-       if (gpd->flag & GP_DATA_UV_ADAPTATIVE) {
-               gpencil_calc_2d_bounding_box(points2d, gps->totpoints, minv, maxv);
-       }
-       else {
-               ARRAY_SET_ITEMS(minv, -1.0f, -1.0f);
-               ARRAY_SET_ITEMS(maxv, 1.0f, 1.0f);
-       }
-
-       /* calc uv data */
-       gpencil_calc_stroke_fill_uv(points2d, gps->totpoints, minv, maxv, uv);
-
-       /* Number of triangles */
-       gps->tot_triangles = gps->totpoints - 2;
-       /* save triangulation data in stroke cache */
-       if (gps->tot_triangles > 0) {
-               if (gps->triangles == NULL) {
-                       gps->triangles = MEM_callocN(sizeof(*gps->triangles) * gps->tot_triangles, "GP Stroke triangulation");
-               }
-               else {
-                       gps->triangles = MEM_recallocN(gps->triangles, sizeof(*gps->triangles) * gps->tot_triangles);
-               }
-
-               for (int i = 0; i < gps->tot_triangles; i++) {
-                       bGPDtriangle *stroke_triangle = &gps->triangles[i];
-                       memcpy(gps->triangles[i].verts, tmp_triangles[i], sizeof(uint[3]));
-                       /* copy texture coordinates */
-                       copy_v2_v2(stroke_triangle->uv[0], uv[tmp_triangles[i][0]]);
-                       copy_v2_v2(stroke_triangle->uv[1], uv[tmp_triangles[i][1]]);
-                       copy_v2_v2(stroke_triangle->uv[2], uv[tmp_triangles[i][2]]);
-               }
-       }
-       else {
-               /* No triangles needed - Free anything allocated previously */
-               if (gps->triangles)
-                       MEM_freeN(gps->triangles);
-
-               gps->triangles = NULL;
-       }
-
-       /* disable recalculation flag */
-       if (gps->flag & GP_STROKE_RECALC_CACHES) {
-               gps->flag &= ~GP_STROKE_RECALC_CACHES;
-       }
-
-       /* clear memory */
-       MEM_SAFE_FREE(tmp_triangles);
-       MEM_SAFE_FREE(points2d);
-       MEM_SAFE_FREE(uv);
-}
-
 /* recalc the internal geometry caches for fill and uvs */
 static void DRW_gpencil_recalc_geometry_caches(Object *ob, MaterialGPencilStyle *gp_style, bGPDstroke *gps)
 {
@@ -466,7 +454,7 @@ DRWShadingGroup *DRW_gpencil_shgroup_stroke_create(
        return grp;
 }
 
-/* create shading group for volumetrics */
+/* create shading group for points */
 static DRWShadingGroup *DRW_gpencil_shgroup_point_create(
         GPENCIL_e_data *e_data, GPENCIL_Data *vedata, DRWPass *pass, GPUShader *shader, Object *ob,
         bGPdata *gpd, MaterialGPencilStyle *gp_style, int id, bool onion)
@@ -559,10 +547,10 @@ static DRWShadingGroup *DRW_gpencil_shgroup_point_create(
        return grp;
 }
 
-/* add fill shading group to pass */
-static void gpencil_add_fill_shgroup(
-        GpencilBatchCache *cache, DRWShadingGroup *fillgrp,
-        Object *ob, bGPDframe *gpf, bGPDstroke *gps,
+/* add fill vertex info  */
+static void gpencil_add_fill_vertexdata(
+        GpencilBatchCache *cache,
+        Object *ob, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps,
         float opacity, const float tintcolor[4], const bool onion, const bool custonion)
 {
        MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
@@ -586,17 +574,24 @@ static void gpencil_add_fill_shgroup(
                                                color = tfill;
                                        }
                                }
-                               gpencil_batch_cache_check_free_slots(ob);
-                               cache->batch_fill[cache->cache_idx] = DRW_gpencil_get_fill_geom(ob, gps, color);
+                               /* create vertex data */
+                               const int old_len = cache->b_fill.vbo_len;
+                               DRW_gpencil_get_fill_geom(&cache->b_fill, ob, gps, color);
+
+                               /* add to list of groups */
+                               if (old_len < cache->b_fill.vbo_len) {
+                                       cache->grp_cache = gpencil_group_cache_add(
+                                               cache->grp_cache, gpl, gpf, gps, eGpencilBatchGroupType_Fill, onion,
+                                               cache->b_fill.vbo_len,
+                                               &cache->grp_size, &cache->grp_used);
+                               }
                        }
-
-                       DRW_shgroup_call_add(fillgrp, cache->batch_fill[cache->cache_idx], gpf->runtime.viewmatrix);
                }
        }
 }
 
-/* add stroke shading group to pass */
-static void gpencil_add_stroke_shgroup(GpencilBatchCache *cache, DRWShadingGroup *strokegrp,
+/* add stroke vertex info */
+static void gpencil_add_stroke_vertexdata(GpencilBatchCache *cache,
        Object *ob, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps,
        const float opacity, const float tintcolor[4], const bool onion,
        const bool custonion)
@@ -632,19 +627,38 @@ static void gpencil_add_stroke_shgroup(GpencilBatchCache *cache, DRWShadingGroup
 
                sthickness = gps->thickness + gpl->line_change;
                CLAMP_MIN(sthickness, 1);
-               gpencil_batch_cache_check_free_slots(ob);
+
                if ((gps->totpoints > 1) && (gp_style->mode == GP_STYLE_MODE_LINE)) {
-                       cache->batch_stroke[cache->cache_idx] = DRW_gpencil_get_stroke_geom(gps, sthickness, ink);
+                       /* create vertex data */
+                       const int old_len = cache->b_stroke.vbo_len;
+                       DRW_gpencil_get_stroke_geom(&cache->b_stroke, gps, sthickness, ink);
+                       
+                       /* add to list of groups */
+                       if (old_len < cache->b_stroke.vbo_len) {
+                               cache->grp_cache = gpencil_group_cache_add(
+                                       cache->grp_cache, gpl, gpf, gps, eGpencilBatchGroupType_Stroke, onion,
+                                       cache->b_stroke.vbo_len,
+                                       &cache->grp_size, &cache->grp_used);
+                       }
                }
                else {
-                       cache->batch_stroke[cache->cache_idx] = DRW_gpencil_get_point_geom(gps, sthickness, ink);
+                       /* create vertex data */
+                       const int old_len = cache->b_point.vbo_len;
+                       DRW_gpencil_get_point_geom(&cache->b_point, gps, sthickness, ink);
+
+                       /* add to list of groups */
+                       if (old_len < cache->b_point.vbo_len) {
+                               cache->grp_cache = gpencil_group_cache_add(
+                                       cache->grp_cache, gpl, gpf, gps, eGpencilBatchGroupType_Point, onion,
+                                       cache->b_point.vbo_len,
+                                       &cache->grp_size, &cache->grp_used);
+                       }
                }
        }
-       DRW_shgroup_call_add(strokegrp, cache->batch_stroke[cache->cache_idx], gpf->runtime.viewmatrix);
 }
 
-/* add edit points shading group to pass */
-static void gpencil_add_editpoints_shgroup(
+/* add edit points vertex info */
+static void gpencil_add_editpoints_vertexdata(
         GPENCIL_StorageList *stl, GpencilBatchCache *cache, ToolSettings *UNUSED(ts), Object *ob,
         bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps)
 {
@@ -662,36 +676,31 @@ static void gpencil_add_editpoints_shgroup(
                }
                const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE);
 
-               /* line of the original stroke */
                if (cache->is_dirty) {
-                       gpencil_batch_cache_check_free_slots(ob);
-                       cache->batch_edlin[cache->cache_idx] = DRW_gpencil_get_edlin_geom(gps, edit_alpha, gpd->flag);
-               }
-               if (cache->batch_edlin[cache->cache_idx]) {
-                       if ((obact) && (obact == ob) &&
-                           ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
-                           (v3d->gp_flag & V3D_GP_SHOW_EDIT_LINES))
+                       if ((obact == ob) &&
+                               ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
+                               (v3d->gp_flag & V3D_GP_SHOW_EDIT_LINES))
                        {
-                               DRW_shgroup_call_add(
-                                       stl->g_data->shgrps_edit_line,
-                                       cache->batch_edlin[cache->cache_idx],
-                                       gpf->runtime.viewmatrix);
+                               /* line of the original stroke */
+                               DRW_gpencil_get_edlin_geom(&cache->b_edlin, gps, edit_alpha, gpd->flag);
+
+                               /* add to list of groups */
+                               cache->grp_cache = gpencil_group_cache_add(
+                                       cache->grp_cache, gpl, gpf, gps, eGpencilBatchGroupType_Edlin, false,
+                                       cache->b_edlin.vbo_len,
+                                       &cache->grp_size, &cache->grp_used);
                        }
-               }
-               /* edit points */
-               if ((gps->flag & GP_STROKE_SELECT) || (is_weight_paint)) {
-                       if ((gpl->flag & GP_LAYER_UNLOCK_COLOR) || ((gp_style->flag & GP_STYLE_COLOR_LOCKED) == 0)) {
-                               if (cache->is_dirty) {
-                                       gpencil_batch_cache_check_free_slots(ob);
-                                       cache->batch_edit[cache->cache_idx] = DRW_gpencil_get_edit_geom(gps, edit_alpha, gpd->flag);
-                               }
-                               if (cache->batch_edit[cache->cache_idx]) {
-                                       if ((obact) && (obact == ob)) {
-                                               /* edit pass */
-                                               DRW_shgroup_call_add(
-                                                       stl->g_data->shgrps_edit_point,
-                                                       cache->batch_edit[cache->cache_idx],
-                                                       gpf->runtime.viewmatrix);
+                       /* edit points */
+                       if ((gps->flag & GP_STROKE_SELECT) || (is_weight_paint)) {
+                               if ((gpl->flag & GP_LAYER_UNLOCK_COLOR) || ((gp_style->flag & GP_STYLE_COLOR_LOCKED) == 0)) {
+                                       if (obact == ob) {
+                                               DRW_gpencil_get_edit_geom(&cache->b_edit, gps, edit_alpha, gpd->flag);
+
+                                               /* add to list of groups */
+                                               cache->grp_cache = gpencil_group_cache_add(
+                                                       cache->grp_cache, gpl, gpf, gps, eGpencilBatchGroupType_Edit, false,
+                                                       cache->b_edit.vbo_len,
+                                                       &cache->grp_size, &cache->grp_used);
                                        }
                                }
                        }
@@ -699,57 +708,6 @@ static void gpencil_add_editpoints_shgroup(
        }
 }
 
-/* function to draw strokes for onion only */
-static void gpencil_draw_onion_strokes(
-        GpencilBatchCache *cache, GPENCIL_e_data *e_data, void *vedata, Object *ob,
-        bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf,
-        const float opacity, const float tintcolor[4], const bool custonion)
-{
-       GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
-       GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
-       Depsgraph *depsgraph = DRW_context_state_get()->depsgraph;
-
-       float viewmatrix[4][4];
-
-       /* get parent matrix and save as static data */
-       ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, viewmatrix);
-       copy_m4_m4(gpf->runtime.viewmatrix, viewmatrix);
-
-       for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
-               MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
-               copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
-               copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba);
-
-               int id = stl->storage->shgroup_id;
-               /* check if stroke can be drawn */
-               if (gpencil_can_draw_stroke(gp_style, gps, true, false) == false) {
-                       continue;
-               }
-               /* limit the number of shading groups */
-               if (id >= GPENCIL_MAX_SHGROUPS) {
-                       continue;
-               }
-
-               stl->shgroups[id].shgrps_fill = NULL;
-               if ((gps->totpoints > 1) && (gp_style->mode == GP_STYLE_MODE_LINE)) {
-                       stl->shgroups[id].shgrps_stroke = DRW_gpencil_shgroup_stroke_create(
-                               e_data, vedata, psl->stroke_pass, e_data->gpencil_stroke_sh, ob, gpd, gp_style, id, true);
-               }
-               else {
-                       stl->shgroups[id].shgrps_stroke = DRW_gpencil_shgroup_point_create(
-                               e_data, vedata, psl->stroke_pass, e_data->gpencil_point_sh, ob, gpd, gp_style, id, true);
-               }
-
-               /* stroke */
-               gpencil_add_stroke_shgroup(
-                       cache, stl->shgroups[id].shgrps_stroke, ob, gpl, gpf, gps, opacity, tintcolor, true, custonion);
-
-               stl->storage->shgroup_id++;
-               cache->cache_idx++;
-       }
-}
-
-
 /* main function to draw strokes */
 static void gpencil_draw_strokes(
         GpencilBatchCache *cache, GPENCIL_e_data *e_data, void *vedata, ToolSettings *ts, Object *ob,
@@ -763,8 +721,6 @@ static void gpencil_draw_strokes(
        Scene *scene = draw_ctx->scene;
        View3D *v3d = draw_ctx->v3d;
        bGPDstroke *gps, *src_gps;
-       DRWShadingGroup *fillgrp;
-       DRWShadingGroup *strokegrp;
        float viewmatrix[4][4];
        const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
        const bool playing = stl->storage->is_playing;
@@ -810,11 +766,6 @@ static void gpencil_draw_strokes(
                        GP_SET_SRC_GPS(src_gps);
                        continue;
                }
-               /* limit the number of shading groups */
-               if (stl->storage->shgroup_id >= GPENCIL_MAX_SHGROUPS) {
-                       GP_SET_SRC_GPS(src_gps);
-                       continue;
-               }
 
                /* be sure recalc all cache in source stroke to avoid recalculation when frame change
                 * and improve fps */
@@ -835,38 +786,6 @@ static void gpencil_draw_strokes(
                if ((gpl->actframe->framenum == derived_gpf->framenum) ||
                    (!is_multiedit) || (overlay_multiedit))
                {
-                       int id = stl->storage->shgroup_id;
-                       if (gps->totpoints > 0) {
-                               if ((gps->totpoints > 2) && (!stl->storage->simplify_fill) &&
-                                   ((gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)) &&
-                                   ((gps->flag & GP_STROKE_NOFILL) == 0) &&
-                                   (gp_style->flag & GP_STYLE_FILL_SHOW))
-                               {
-                                       stl->shgroups[id].shgrps_fill = DRW_gpencil_shgroup_fill_create(
-                                               e_data, vedata, psl->stroke_pass, e_data->gpencil_fill_sh,
-                                               gpd, gpl, gp_style, id);
-                               }
-                               else {
-                                       stl->shgroups[id].shgrps_fill = NULL;
-                               }
-                               if ((gp_style->mode == GP_STYLE_MODE_LINE) && (gps->totpoints > 1)) {
-                                       stl->shgroups[id].shgrps_stroke = DRW_gpencil_shgroup_stroke_create(
-                                               e_data, vedata, psl->stroke_pass, e_data->gpencil_stroke_sh, ob, gpd, gp_style, id, false);
-                               }
-                               else {
-                                       stl->shgroups[id].shgrps_stroke = DRW_gpencil_shgroup_point_create(
-                                               e_data, vedata, psl->stroke_pass, e_data->gpencil_point_sh, ob, gpd, gp_style, id, false);
-                               }
-                       }
-                       else {
-                               stl->shgroups[id].shgrps_fill = NULL;
-                               stl->shgroups[id].shgrps_stroke = NULL;
-                       }
-                       stl->storage->shgroup_id++;
-
-                       fillgrp = stl->shgroups[id].shgrps_fill;
-                       strokegrp = stl->shgroups[id].shgrps_stroke;
-
                        /* copy color to temp fields to apply temporal changes in the stroke */
                        copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
                        copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba);
@@ -879,17 +798,20 @@ static void gpencil_draw_strokes(
                        }
 
                        /* fill */
-                       if ((fillgrp) && (!stl->storage->simplify_fill)) {
-                               gpencil_add_fill_shgroup(
-                                       cache, fillgrp, ob, derived_gpf, gps,
+                       if ((gp_style->flag & GP_STYLE_FILL_SHOW) &&
+                               (!stl->storage->simplify_fill))
+                       {
+                               gpencil_add_fill_vertexdata(
+                                       cache, ob, gpl, derived_gpf, gps,
                                        opacity, tintcolor, false, custonion);
                        }
                        /* stroke */
-                       if (strokegrp) {
-                               const float nop = ((gp_style->flag & GP_STYLE_STROKE_SHOW) == 0) || (gp_style->stroke_rgba[3] < GPENCIL_ALPHA_OPACITY_THRESH) ? 0.0f : opacity;
-                               gpencil_add_stroke_shgroup(
-                                       cache, strokegrp, ob, gpl, derived_gpf, gps,
-                                       nop, tintcolor, false, custonion);
+                       if ((gp_style->flag & GP_STYLE_STROKE_SHOW) &&
+                               (gp_style->stroke_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH))
+                       {
+                               gpencil_add_stroke_vertexdata(
+                                       cache, ob, gpl, derived_gpf, gps,
+                                       opacity, tintcolor, false, custonion);
                        }
                }
 
@@ -907,136 +829,67 @@ static void gpencil_draw_strokes(
                                        DRW_shgroup_uniform_vec2(stl->g_data->shgrps_edit_point, "Viewport", viewport_size, 1);
                                }
 
-                               gpencil_add_editpoints_shgroup(stl, cache, ts, ob, gpd, gpl, derived_gpf, src_gps);
-                       }
-                       else {
-                               gpencil_batch_cache_check_free_slots(ob);
+                               gpencil_add_editpoints_vertexdata(stl, cache, ts, ob, gpd, gpl, derived_gpf, src_gps);
                        }
                }
 
                GP_SET_SRC_GPS(src_gps);
-
-               cache->cache_idx++;
        }
 }
 
- /* draw stroke in drawing buffer */
-void DRW_gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data, void *vedata, ToolSettings *ts, Object *ob)
+/* get alpha factor for onion strokes */
+static void gpencil_get_onion_alpha(float color[4], bGPdata *gpd)
 {
-       GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
-       GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
-       Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
-       bGPdata *gpd_eval = ob->data;
-       /* need the original to avoid cow overhead while drawing */
-       bGPdata *gpd = (bGPdata *)DEG_get_original_id(&gpd_eval->id);
-
-       MaterialGPencilStyle *gp_style = NULL;
-
-       float obscale = mat4_to_scale(ob->obmat);
+#define MIN_ALPHA_VALUE 0.01f
 
-       /* use the brush material */
-       Material *ma = BKE_gpencil_get_material_from_brush(brush);
-       if (ma != NULL) {
-               gp_style = ma->gp_style;
+       /* if fade is disabled, opacity is equal in all frames */
+       if ((gpd->onion_flag & GP_ONION_FADE) == 0) {
+               color[3] = gpd->onion_factor;
        }
-       /* this is not common, but avoid any special situations when brush could be without material */
-       if (gp_style == NULL) {
-               gp_style = BKE_material_gpencil_settings_get(ob, ob->actcol);
+       else {
+               /* add override opacity factor */
+               color[3] += gpd->onion_factor - 0.5f;
        }
 
-       /* drawing strokes */
-       /* Check if may need to draw the active stroke cache, only if this layer is the active layer
-        * that is being edited. (Stroke buffer is currently stored in gp-data)
-        */
-       if (ED_gpencil_session_active() && (gpd->runtime.sbuffer_size > 0)) {
-               if ((gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) {
-                       /* It should also be noted that sbuffer contains temporary point types
-                        * i.e. tGPspoints NOT bGPDspoints
-                        */
-                       short lthick = brush->size * obscale;
-                       /* if only one point, don't need to draw buffer because the user has no time to see it */
-                       if (gpd->runtime.sbuffer_size > 1) {
-                               if ((gp_style) && (gp_style->mode == GP_STYLE_MODE_LINE)) {
-                                       stl->g_data->shgrps_drawing_stroke = DRW_gpencil_shgroup_stroke_create(
-                                               e_data, vedata, psl->drawing_pass, e_data->gpencil_stroke_sh, NULL, gpd, gp_style, -1, false);
-                               }
-                               else {
-                                       stl->g_data->shgrps_drawing_stroke = DRW_gpencil_shgroup_point_create(
-                                               e_data, vedata, psl->drawing_pass, e_data->gpencil_point_sh, NULL, gpd, gp_style, -1, false);
-                               }
+       CLAMP(color[3], MIN_ALPHA_VALUE, 1.0f);
+}
 
-                               /* clean previous version of the batch */
-                               if (stl->storage->buffer_stroke) {
-                                       GPU_BATCH_DISCARD_SAFE(e_data->batch_buffer_stroke);
-                                       MEM_SAFE_FREE(e_data->batch_buffer_stroke);
-                                       stl->storage->buffer_stroke = false;
-                               }
+/* function to draw strokes for onion only */
+static void gpencil_draw_onion_strokes(
+       GpencilBatchCache *cache, GPENCIL_e_data *e_data, void *vedata, Object *ob,
+       bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf,
+       const float opacity, const float tintcolor[4], const bool custonion)
+{
+       GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+       Depsgraph *depsgraph = DRW_context_state_get()->depsgraph;
 
-                               /* use unit matrix because the buffer is in screen space and does not need conversion */
-                               if (gpd->runtime.mode == GP_STYLE_MODE_LINE) {
-                                       e_data->batch_buffer_stroke = DRW_gpencil_get_buffer_stroke_geom(
-                                               gpd, lthick);
-                               }
-                               else {
-                                       e_data->batch_buffer_stroke = DRW_gpencil_get_buffer_point_geom(
-                                               gpd, lthick);
-                               }
+       float viewmatrix[4][4];
 
-                               if (gp_style->flag & GP_STYLE_STROKE_SHOW) {
-                                       DRW_shgroup_call_add(
-                                               stl->g_data->shgrps_drawing_stroke,
-                                               e_data->batch_buffer_stroke,
-                                               stl->storage->unit_matrix);
-                               }
+       /* get parent matrix and save as static data */
+       ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, viewmatrix);
+       copy_m4_m4(gpf->runtime.viewmatrix, viewmatrix);
 
-                               if ((gpd->runtime.sbuffer_size >= 3) &&
-                                   (gpd->runtime.sfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) &&
-                                   ((gpd->runtime.sbuffer_sflag & GP_STROKE_NOFILL) == 0) &&
-                                   ((brush->gpencil_settings->flag & GP_BRUSH_DISSABLE_LASSO) == 0) &&
-                                   (gp_style->flag & GP_STYLE_FILL_SHOW))
-                               {
-                                       /* if not solid, fill is simulated with solid color */
-                                       if (gpd->runtime.bfill_style > 0) {
-                                               gpd->runtime.sfill[3] = 0.5f;
-                                       }
-                                       stl->g_data->shgrps_drawing_fill = DRW_shgroup_create(
-                                               e_data->gpencil_drawing_fill_sh, psl->drawing_pass);
+       for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+               MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+               copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
+               copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba);
 
-                                       /* clean previous version of the batch */
-                                       if (stl->storage->buffer_fill) {
-                                               GPU_BATCH_DISCARD_SAFE(e_data->batch_buffer_fill);
-                                               MEM_SAFE_FREE(e_data->batch_buffer_fill);
-                                               stl->storage->buffer_fill = false;
-                                       }
-
-                                       e_data->batch_buffer_fill = DRW_gpencil_get_buffer_fill_geom(gpd);
-                                       DRW_shgroup_call_add(
-                                               stl->g_data->shgrps_drawing_fill,
-                                               e_data->batch_buffer_fill,
-                                               stl->storage->unit_matrix);
-                                       stl->storage->buffer_fill = true;
-                               }
-                               stl->storage->buffer_stroke = true;
-                       }
+               int id = stl->storage->shgroup_id;
+               /* check if stroke can be drawn */
+               if (gpencil_can_draw_stroke(gp_style, gps, true, false) == false) {
+                       continue;
+               }
+               /* limit the number of shading groups */
+               if (id >= GPENCIL_MAX_SHGROUPS) {
+                       continue;
                }
-       }
-}
 
-/* get alpha factor for onion strokes */
-static void gpencil_get_onion_alpha(float color[4], bGPdata *gpd)
-{
-#define MIN_ALPHA_VALUE 0.01f
+               /* stroke */
+               gpencil_add_stroke_vertexdata(
+                       cache, ob, gpl, gpf, gps, opacity, tintcolor, true, custonion);
 
-       /* if fade is disabled, opacity is equal in all frames */
-       if ((gpd->onion_flag & GP_ONION_FADE) == 0) {
-               color[3] = gpd->onion_factor;
-       }
-       else {
-               /* add override opacity factor */
-               color[3] += gpd->onion_factor - 0.5f;
+               stl->storage->shgroup_id++;
        }
-
-       CLAMP(color[3], MIN_ALPHA_VALUE, 1.0f);
 }
 
 /* draw onion-skinning for a layer */
@@ -1058,7 +911,6 @@ static void gpencil_draw_onionskins(
 
        colflag = (bool)gpd->onion_flag & GP_ONION_GHOST_PREVCOL;
 
-
        /* -------------------------------
         * 1) Draw Previous Frames First
         * ------------------------------- */
@@ -1183,9 +1035,348 @@ static void gpencil_draw_onionskins(
        }
 }
 
+static void 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_m4_m4(derived_gpf->runtime.viewmatrix, gpf->runtime.viewmatrix);
+
+       /* 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);
+       }
+}
+
+/* Triangulate stroke for high quality fill (this is done only if cache is null or stroke was modified) */
+void DRW_gpencil_triangulate_stroke_fill(Object *ob, bGPDstroke *gps)
+{
+       BLI_assert(gps->totpoints >= 3);
+
+       bGPdata *gpd = (bGPdata *)ob->data;
+
+       /* allocate memory for temporary areas */
+       gps->tot_triangles = gps->totpoints - 2;
+       uint(*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles, "GP Stroke temp triangulation");
+       float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints, "GP Stroke temp 2d points");
+       float(*uv)[2] = MEM_mallocN(sizeof(*uv) * gps->totpoints, "GP Stroke temp 2d uv data");
+
+       int direction = 0;
+
+       /* convert to 2d and triangulate */
+       gpencil_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction);
+       BLI_polyfill_calc(points2d, (uint)gps->totpoints, direction, tmp_triangles);
+
+       /* calc texture coordinates automatically */
+       float minv[2];
+       float maxv[2];
+       /* first needs bounding box data */
+       if (gpd->flag & GP_DATA_UV_ADAPTATIVE) {
+               gpencil_calc_2d_bounding_box(points2d, gps->totpoints, minv, maxv);
+       }
+       else {
+               ARRAY_SET_ITEMS(minv, -1.0f, -1.0f);
+               ARRAY_SET_ITEMS(maxv, 1.0f, 1.0f);
+       }
+
+       /* calc uv data */
+       gpencil_calc_stroke_fill_uv(points2d, gps->totpoints, minv, maxv, uv);
+
+       /* Number of triangles */
+       gps->tot_triangles = gps->totpoints - 2;
+       /* save triangulation data in stroke cache */
+       if (gps->tot_triangles > 0) {
+               if (gps->triangles == NULL) {
+                       gps->triangles = MEM_callocN(sizeof(*gps->triangles) * gps->tot_triangles, "GP Stroke triangulation");
+               }
+               else {
+                       gps->triangles = MEM_recallocN(gps->triangles, sizeof(*gps->triangles) * gps->tot_triangles);
+               }
+
+               for (int i = 0; i < gps->tot_triangles; i++) {
+                       bGPDtriangle *stroke_triangle = &gps->triangles[i];
+                       memcpy(gps->triangles[i].verts, tmp_triangles[i], sizeof(uint[3]));
+                       /* copy texture coordinates */
+                       copy_v2_v2(stroke_triangle->uv[0], uv[tmp_triangles[i][0]]);
+                       copy_v2_v2(stroke_triangle->uv[1], uv[tmp_triangles[i][1]]);
+                       copy_v2_v2(stroke_triangle->uv[2], uv[tmp_triangles[i][2]]);
+               }
+       }
+       else {
+               /* No triangles needed - Free anything allocated previously */
+               if (gps->triangles)
+                       MEM_freeN(gps->triangles);
+
+               gps->triangles = NULL;
+       }
+
+       /* disable recalculation flag */
+       if (gps->flag & GP_STROKE_RECALC_CACHES) {
+               gps->flag &= ~GP_STROKE_RECALC_CACHES;
+       }
+
+       /* clear memory */
+       MEM_SAFE_FREE(tmp_triangles);
+       MEM_SAFE_FREE(points2d);
+       MEM_SAFE_FREE(uv);
+}
+
+/* draw stroke in drawing buffer */
+void DRW_gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data, void *vedata, ToolSettings *ts, Object *ob)
+{
+       GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+       GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+       Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
+       bGPdata *gpd_eval = ob->data;
+       /* need the original to avoid cow overhead while drawing */
+       bGPdata *gpd = (bGPdata *)DEG_get_original_id(&gpd_eval->id);
+
+       MaterialGPencilStyle *gp_style = NULL;
+
+       float obscale = mat4_to_scale(ob->obmat);
+
+       /* use the brush material */
+       Material *ma = BKE_gpencil_get_material_from_brush(brush);
+       if (ma != NULL) {
+               gp_style = ma->gp_style;
+       }
+       /* this is not common, but avoid any special situations when brush could be without material */
+       if (gp_style == NULL) {
+               gp_style = BKE_material_gpencil_settings_get(ob, ob->actcol);
+       }
+
+       /* drawing strokes */
+       /* Check if may need to draw the active stroke cache, only if this layer is the active layer
+        * that is being edited. (Stroke buffer is currently stored in gp-data)
+        */
+       if (ED_gpencil_session_active() && (gpd->runtime.sbuffer_size > 0)) {
+               if ((gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) {
+                       /* It should also be noted that sbuffer contains temporary point types
+                        * i.e. tGPspoints NOT bGPDspoints
+                        */
+                       short lthick = brush->size * obscale;
+                       /* if only one point, don't need to draw buffer because the user has no time to see it */
+                       if (gpd->runtime.sbuffer_size > 1) {
+                               if ((gp_style) && (gp_style->mode == GP_STYLE_MODE_LINE)) {
+                                       stl->g_data->shgrps_drawing_stroke = DRW_gpencil_shgroup_stroke_create(
+                                               e_data, vedata, psl->drawing_pass, e_data->gpencil_stroke_sh, NULL, gpd, gp_style, -1, false);
+                               }
+                               else {
+                                       stl->g_data->shgrps_drawing_stroke = DRW_gpencil_shgroup_point_create(
+                                               e_data, vedata, psl->drawing_pass, e_data->gpencil_point_sh, NULL, gpd, gp_style, -1, false);
+                               }
+
+                               /* clean previous version of the batch */
+                               if (stl->storage->buffer_stroke) {
+                                       GPU_BATCH_DISCARD_SAFE(e_data->batch_buffer_stroke);
+                                       MEM_SAFE_FREE(e_data->batch_buffer_stroke);
+                                       stl->storage->buffer_stroke = false;
+                               }
+
+                               /* use unit matrix because the buffer is in screen space and does not need conversion */
+                               if (gpd->runtime.mode == GP_STYLE_MODE_LINE) {
+                                       e_data->batch_buffer_stroke = DRW_gpencil_get_buffer_stroke_geom(
+                                               gpd, lthick);
+                               }
+                               else {
+                                       e_data->batch_buffer_stroke = DRW_gpencil_get_buffer_point_geom(
+                                               gpd, lthick);
+                               }
+
+                               if (gp_style->flag & GP_STYLE_STROKE_SHOW) {
+                                       DRW_shgroup_call_add(
+                                               stl->g_data->shgrps_drawing_stroke,
+                                               e_data->batch_buffer_stroke,
+                                               stl->storage->unit_matrix);
+                               }
+
+                               if ((gpd->runtime.sbuffer_size >= 3) &&
+                                       (gpd->runtime.sfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) &&
+                                       ((gpd->runtime.sbuffer_sflag & GP_STROKE_NOFILL) == 0) &&
+                                       ((brush->gpencil_settings->flag & GP_BRUSH_DISSABLE_LASSO) == 0) &&
+                                       (gp_style->flag & GP_STYLE_FILL_SHOW))
+                               {
+                                       /* if not solid, fill is simulated with solid color */
+                                       if (gpd->runtime.bfill_style > 0) {
+                                               gpd->runtime.sfill[3] = 0.5f;
+                                       }
+                                       stl->g_data->shgrps_drawing_fill = DRW_shgroup_create(
+                                               e_data->gpencil_drawing_fill_sh, psl->drawing_pass);
+
+                                       /* clean previous version of the batch */
+                                       if (stl->storage->buffer_fill) {
+                                               GPU_BATCH_DISCARD_SAFE(e_data->batch_buffer_fill);
+                                               MEM_SAFE_FREE(e_data->batch_buffer_fill);
+                                               stl->storage->buffer_fill = false;
+                                       }
+
+                                       e_data->batch_buffer_fill = DRW_gpencil_get_buffer_fill_geom(gpd);
+                                       DRW_shgroup_call_add(
+                                               stl->g_data->shgrps_drawing_fill,
+                                               e_data->batch_buffer_fill,
+                                               stl->storage->unit_matrix);
+                                       stl->storage->buffer_fill = true;
+                               }
+                               stl->storage->buffer_stroke = true;
+                       }
+               }
+       }
+}
+
+/* create all missing batches */
+static void DRW_gpencil_create_batches(GpencilBatchCache *cache)
+{
+       if ((cache->b_point.vbo) && (cache->b_point.batch == NULL)) {
+               cache->b_point.batch = GPU_batch_create_ex(GPU_PRIM_POINTS, cache->b_point.vbo, NULL, GPU_BATCH_OWNS_VBO);
+       }
+       if ((cache->b_stroke.vbo) && (cache->b_stroke.batch == NULL)) {
+               cache->b_stroke.batch = GPU_batch_create_ex(GPU_PRIM_LINE_STRIP_ADJ, cache->b_stroke.vbo, NULL, GPU_BATCH_OWNS_VBO);
+       }
+       if ((cache->b_fill.vbo) && (cache->b_fill.batch == NULL)) {
+               cache->b_fill.batch = GPU_batch_create_ex(GPU_PRIM_TRIS, cache->b_fill.vbo, NULL, GPU_BATCH_OWNS_VBO);
+       }
+       if ((cache->b_edit.vbo) && (cache->b_edit.batch == NULL)) {
+               cache->b_edit.batch = GPU_batch_create_ex(GPU_PRIM_POINTS, cache->b_edit.vbo, NULL, GPU_BATCH_OWNS_VBO);
+       }
+       if ((cache->b_edlin.vbo) && (cache->b_edlin.batch == NULL)) {
+               cache->b_edlin.batch = GPU_batch_create_ex(GPU_PRIM_LINE_STRIP, cache->b_edlin.vbo, NULL, GPU_BATCH_OWNS_VBO);
+       }
+}
+
+/* create all shading groups */
+static void DRW_gpencil_shgroups_create(
+       GPENCIL_e_data *e_data, void *vedata,
+       Object *ob, bGPdata *gpd,
+       GpencilBatchCache *cache, tGPencilObjectCache *cache_ob)
+{
+       GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+       GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+       DRWShadingGroup *shgrp = NULL;
+
+       int start_stroke = 0;
+       int start_point = 0;
+       int start_fill = 0;
+       int start_edit = 0;
+       int start_edlin = 0;
+
+       cache_ob->init_grp = NULL;
+       cache_ob->end_grp = NULL;
+
+       for (int i = 0; i < cache->grp_used; i++) {
+               GpencilBatchGroup *elm = &cache->grp_cache[i];
+               bGPDlayer *gpl = elm->gpl;
+               bGPDframe *gpf = elm->gpf;
+               bGPDstroke *gps = elm->gps;
+               MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+
+               /* limit the number of shading groups */
+               if (i >= GPENCIL_MAX_SHGROUPS) {
+                       break;
+               }
+
+               switch (elm->type) {
+                       case eGpencilBatchGroupType_Stroke:
+                       {
+                               const int len = elm->vertex_idx - start_stroke;
+
+                               shgrp = DRW_gpencil_shgroup_stroke_create(
+                                       e_data, vedata, psl->stroke_pass, e_data->gpencil_stroke_sh,
+                                       ob, gpd, gp_style, stl->storage->shgroup_id, elm->onion);
+
+                               DRW_shgroup_call_range_add(
+                                       shgrp, cache->b_stroke.batch,
+                                       (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : cache_ob->obmat,
+                                       start_stroke, len);
+
+                               stl->storage->shgroup_id++;
+                               start_stroke = elm->vertex_idx;
+                               break;
+                       }
+                       case eGpencilBatchGroupType_Point:
+                       {
+                               const int len = elm->vertex_idx - start_point;
+
+                               shgrp = DRW_gpencil_shgroup_point_create(
+                                       e_data, vedata, psl->stroke_pass, e_data->gpencil_point_sh,
+                                       ob, gpd, gp_style, stl->storage->shgroup_id, elm->onion);
+
+                               DRW_shgroup_call_range_add(
+                                       shgrp, cache->b_point.batch,
+                                       (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : cache_ob->obmat,
+                                       start_point, len);
+
+                               stl->storage->shgroup_id++;
+                               start_point = elm->vertex_idx;
+                               break;
+                       }
+                       case eGpencilBatchGroupType_Fill:
+                       {
+                               const int len = elm->vertex_idx - start_fill;
+
+                               shgrp = DRW_gpencil_shgroup_fill_create(
+                                       e_data, vedata, psl->stroke_pass, e_data->gpencil_fill_sh,
+                                       gpd, gpl, gp_style, stl->storage->shgroup_id);
+
+                               DRW_shgroup_call_range_add(
+                                       shgrp, cache->b_fill.batch,
+                                       (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : cache_ob->obmat,
+                                       start_fill, len);
+
+                               stl->storage->shgroup_id++;
+                               start_fill = elm->vertex_idx;
+                               break;
+                       }
+                       case eGpencilBatchGroupType_Edit:
+                       {
+                               const int len = elm->vertex_idx - start_edit;
+                               /* use always the same group */
+                               DRW_shgroup_call_range_add(
+                                       stl->g_data->shgrps_edit_point,
+                                       cache->b_edit.batch,
+                                       (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : cache_ob->obmat,
+                                       start_edit, len);
+
+                               start_edit = elm->vertex_idx;
+                               break;
+                       }
+                       case eGpencilBatchGroupType_Edlin:
+                       {
+                               const int len = elm->vertex_idx - start_edlin;
+                               /* use always the same group */
+                               DRW_shgroup_call_range_add(
+                                       stl->g_data->shgrps_edit_line,
+                                       cache->b_edlin.batch,
+                                       (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : cache_ob->obmat,
+                                       start_edlin, len);
+
+                               start_edlin = elm->vertex_idx;
+                               break;
+                       }
+                       default:
+                       {
+                               break;
+                       }
+               }
+               /* save first group */
+               if ((shgrp != NULL) && (cache_ob->init_grp == NULL)) {
+                       cache_ob->init_grp = shgrp;
+               }
+       }
+
+       /* save last group */
+       if (shgrp != NULL) {
+               cache_ob->end_grp = shgrp;
+       }
+}
 /* populate a datablock for multiedit (no onions, no modifiers) */
 void DRW_gpencil_populate_multiedit(
-        GPENCIL_e_data *e_data, void *vedata, Scene *scene, Object *ob,
+        GPENCIL_e_data *e_data, void *vedata, Object *ob,
         tGPencilObjectCache *cache_ob)
 {
        bGPdata *gpd = (bGPdata *)ob->data;
@@ -1195,12 +1386,15 @@ void DRW_gpencil_populate_multiedit(
        const DRWContextState *draw_ctx = DRW_context_state_get();
        int cfra_eval = (int)DEG_get_ctime(draw_ctx->depsgraph);
        GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra_eval);
+       Scene *scene = draw_ctx->scene;
        ToolSettings *ts = scene->toolsettings;
-       cache->cache_idx = 0;
 
        /* check if playing animation */
        bool playing = stl->storage->is_playing;
 
+       /* calc max size of VBOs */
+       gpencil_calc_vertex(stl, cache_ob, cache, gpd, cfra_eval);
+
        /* draw strokes */
        for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
                /* don't draw layer if hidden */
@@ -1228,36 +1422,23 @@ void DRW_gpencil_populate_multiedit(
 
        }
 
-       cache->is_dirty = false;
-}
-
-static void 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;
+       /* create batchs and shading groups */
+       DRW_gpencil_create_batches(cache);
+       DRW_gpencil_shgroups_create(e_data, vedata, ob, gpd, cache, cache_ob);
 
-       /* 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);
-       }
+       cache->is_dirty = false;
 }
 
 /* helper for populate a complete grease pencil datablock */
 void DRW_gpencil_populate_datablock(
         GPENCIL_e_data *e_data, void *vedata,
-        Scene *scene, Object *ob,
+        Object *ob,
         tGPencilObjectCache *cache_ob)
 {
        GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
        const DRWContextState *draw_ctx = DRW_context_state_get();
        const ViewLayer *view_layer = DEG_get_evaluated_view_layer(draw_ctx->depsgraph);
+       Scene *scene = draw_ctx->scene;
 
        bGPdata *gpd_eval = (bGPdata *)ob->data;
        bGPdata *gpd = (bGPdata *)DEG_get_original_id(&gpd_eval->id);
@@ -1273,7 +1454,6 @@ void DRW_gpencil_populate_datablock(
        const bool time_remap = BKE_gpencil_has_time_modifiers(ob);
 
        float opacity;
-       bGPDframe *p = NULL;
        bGPDframe *gpf = NULL;
        bGPDlayer *gpl_active = BKE_gpencil_layer_getactive(gpd);
 
@@ -1281,7 +1461,15 @@ void DRW_gpencil_populate_datablock(
        bool playing = stl->storage->is_playing;
 
        GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra_eval);
-       cache->cache_idx = 0;
+
+       /* if object is duplicate, only create shading groups */
+       if (cache_ob->is_dup_ob) {
+               DRW_gpencil_shgroups_create(e_data, vedata, ob, gpd, cache, cache_ob);
+               return;
+       }
+
+       /* calc max size of VBOs */
+       gpencil_calc_vertex(stl, cache_ob, cache, gpd, cfra_eval);
 
        /* init general modifiers data */
        if (!stl->storage->simplify_modif) {
@@ -1302,16 +1490,15 @@ void DRW_gpencil_populate_datablock(
                        }
                }
 
-               if ((!time_remap) || (stl->storage->simplify_modif)) {
-                       gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV);
+               /* remap time */
+               int remap_cfra = cfra_eval;
+               if ((time_remap) && (!stl->storage->simplify_modif)) {
+                       remap_cfra = BKE_gpencil_time_modifier(
+                               draw_ctx->depsgraph, scene, ob, gpl, cfra_eval,
+                               stl->storage->is_render);
                }
-               else {
-                       int remap_cfra = BKE_gpencil_time_modifier(
-                               draw_ctx->depsgraph, scene, ob, gpl, cfra_eval,
-                               stl->storage->is_render);
 
-                       gpf = BKE_gpencil_layer_getframe(gpl, remap_cfra, GP_GETFRAME_USE_PREV);
-               }
+               gpf = BKE_gpencil_layer_getframe(gpl, remap_cfra, GP_GETFRAME_USE_PREV);
                if (gpf == NULL)
                        continue;
 
@@ -1331,24 +1518,9 @@ void DRW_gpencil_populate_datablock(
                        opacity = opacity * v3d->overlay.gpencil_fade_layer;
                }
 
-               /* 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 {
-                               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];
+               /* create derived frames array data or expand */
+               int derived_idx = BLI_findindex(&gpd->layers, gpl);
+               derived_gpf = &cache->derived_array[derived_idx];
 
                /* if no derived frame or dirty cache, create a new one */
                if ((derived_gpf == NULL) || (cache->is_dirty)) {
@@ -1362,8 +1534,7 @@ void DRW_gpencil_populate_datablock(
 
                /* draw onion skins */
                if (!ID_IS_LINKED(&gpd->id)) {
-                       if ((!cache_ob->is_dup_data) &&
-                           (gpd->flag & GP_DATA_SHOW_ONIONSKINS) &&
+                       if ((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) && (gpd->id.us <= 1))
@@ -1376,18 +1547,9 @@ void DRW_gpencil_populate_datablock(
                        }
                }
                /* draw normal strokes */
-               if (!cache_ob->is_dup_ob) {
-                       /* save batch index */
-                       gpl->runtime.batch_index = cache->cache_idx;
-               }
-               else {
-                       cache->cache_idx = gpl->runtime.batch_index;
-               }
-
                gpencil_draw_strokes(
                        cache, e_data, vedata, ts, ob, gpd, gpl, gpf, derived_gpf,
                        opacity, gpl->tintcolor, false, cache_ob);
-
        }
 
        /* clear any lattice data */
@@ -1395,5 +1557,25 @@ void DRW_gpencil_populate_datablock(
                BKE_gpencil_lattice_clear(ob);
        }
 
+       /* create batchs and shading groups */
+       DRW_gpencil_create_batches(cache);
+       DRW_gpencil_shgroups_create(e_data, vedata, ob, gpd, cache, cache_ob);
+
        cache->is_dirty = false;
 }
+
+void DRW_gpencil_populate_particles(GPENCIL_e_data *e_data, void *vedata)
+{
+       GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+
+       /* add particles */
+       for (int i = 0; i < stl->g_data->gp_cache_used; i++) {
+               tGPencilObjectCache *cache_ob = &stl->g_data->gp_object_cache[i];
+               Object *ob = cache_ob->ob;
+               if (cache_ob->is_dup_ob) {
+                       bGPdata *gpd = (bGPdata *)ob->data;
+                       GpencilBatchCache *cache = ob->runtime.gpencil_cache;
+                       DRW_gpencil_shgroups_create(e_data, vedata, ob, gpd, cache, cache_ob);
+               }
+       }
+}
index 52cd79e4394280df7ea0483c04cce54f730c2190..7be06d501f1a6b157562c0a777f158578b76c6a6 100644 (file)
@@ -315,9 +315,6 @@ void GPENCIL_cache_init(void *vedata)
 
        if (!stl->shgroups) {
                /* Alloc maximum size because count strokes is very slow and can be very complex due onion skinning.
-                  I tried to allocate only one block and using realloc, increasing the size when read a new strokes
-                  in cache_finish, but the realloc produce weird things on screen, so we keep as is while we found
-                  a better solution
                 */
                stl->shgroups = MEM_mallocN(sizeof(GPENCIL_shgroup) * GPENCIL_MAX_SHGROUPS, "GPENCIL_shgroup");
        }
@@ -498,28 +495,22 @@ void GPENCIL_cache_init(void *vedata)
 static void gpencil_add_draw_data(void *vedata, Object *ob)
 {
        GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
-       const DRWContextState *draw_ctx = DRW_context_state_get();
-       Scene *scene = draw_ctx->scene;
        bGPdata *gpd = (bGPdata *)ob->data;
        const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
 
        int i = stl->g_data->gp_cache_used - 1;
        tGPencilObjectCache *cache_ob = &stl->g_data->gp_object_cache[i];
 
-       /* save init shading group */
-       cache_ob->init_grp = stl->storage->shgroup_id;
-
-       /* fill shading groups */
-       if ((!is_multiedit) || (cache_ob->is_dup_ob)) {
-               DRW_gpencil_populate_datablock(&e_data, vedata, scene, ob, cache_ob);
-       }
-       else {
-               DRW_gpencil_populate_multiedit(&e_data, vedata, scene, ob, cache_ob);
+       if (!cache_ob->is_dup_ob) {
+               /* fill shading groups */
+               if (!is_multiedit) {
+                       DRW_gpencil_populate_datablock(&e_data, vedata, ob, cache_ob);
+               }
+               else {
+                       DRW_gpencil_populate_multiedit(&e_data, vedata, ob, cache_ob);
+               }
        }
 
-       /* save end shading group */
-       cache_ob->end_grp = stl->storage->shgroup_id - 1;
-
        /* FX passses */
        cache_ob->has_fx = false;
        if ((!stl->storage->simplify_fx) &&
@@ -549,25 +540,12 @@ void GPENCIL_cache_populate(void *vedata, Object *ob)
        if (ob->type == OB_GPENCIL && ob->data) {
                bGPdata *gpd = (bGPdata *)ob->data;
 
-               /* if onion, set as dirty always
-                * This reduces performance, but avoid any crash in the multiple
-                * overlay and multiwindow options
-                */
-               if (gpd->flag & GP_DATA_SHOW_ONIONSKINS) {
-                       gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
-               }
-
                /* when start/stop animation the cache must be set as dirty to reset all data */
                if (stl->storage->reset_cache) {
                        gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
                        stl->storage->reset_cache = false;
                }
 
-               /* is edit mode only current object, not particle instances */
-               if ((ob->base_flag & BASE_FROMDUPLI) && GPENCIL_ANY_EDIT_MODE(gpd)) {
-                       return;
-               }
-
                if ((stl->g_data->session_flag & GP_DRW_PAINT_READY) == 0) {
 
                        /* save gp objects for drawing later */
@@ -618,10 +596,9 @@ void GPENCIL_cache_populate(void *vedata, Object *ob)
        }
 }
 
-void GPENCIL_cache_finish(void *UNUSED(vedata))
+void GPENCIL_cache_finish(void *vedata)
 {
-       return;
-
+       DRW_gpencil_populate_particles(&e_data, vedata);
 }
 
 /* helper function to sort inverse gpencil objects using qsort */
@@ -657,6 +634,13 @@ static void gpencil_prepare_fast_drawing(
 
 static void gpencil_free_obj_runtime(GPENCIL_StorageList *stl)
 {
+       /* reset all cache flags */
+       for (int i = 0; i < stl->g_data->gp_cache_used; i++) {
+               tGPencilObjectCache *cache_ob = &stl->g_data->gp_object_cache[i];
+               bGPdata *gpd = cache_ob->gpd;
+               gpd->flag &= ~GP_DATA_CACHE_IS_DIRTY;
+       }
+
        /* free the cache itself */
        MEM_SAFE_FREE(stl->g_data->gp_object_cache);
 }
@@ -672,7 +656,6 @@ void GPENCIL_draw_scene(void *ved)
        DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
        GPENCIL_TextureList *txl = ((GPENCIL_Data *)vedata)->txl;
 
-       int init_grp, end_grp;
        tGPencilObjectCache *cache_ob;
        const float clearcol[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
 
@@ -729,33 +712,27 @@ void GPENCIL_draw_scene(void *ved)
                        for (int i = 0; i < stl->g_data->gp_cache_used; i++) {
                                cache_ob = &stl->g_data->gp_object_cache[i];
                                bGPdata *gpd = cache_ob->gpd;
-                               init_grp = cache_ob->init_grp;
-                               end_grp = cache_ob->end_grp;
 
                                /* Render stroke in separated framebuffer */
                                GPU_framebuffer_bind(fbl->temp_fb_a);
                                GPU_framebuffer_clear_color_depth(fbl->temp_fb_a, clearcol, 1.0f);
 
-                               /* Stroke Pass: DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH
-                                * draw only a subset that usually start with a fill and end with stroke because the
-                                * shading groups are created by pairs */
-                               if (end_grp >= init_grp) {
+                               /* Stroke Pass:
+                                * draw only a subset that usually starts with a fill and ends with stroke
+                                */
+                               if (cache_ob->init_grp) {
                                        /* previews don't use AA */
                                        if (!stl->storage->is_mat_preview) {
                                                MULTISAMPLE_GP_SYNC_ENABLE(stl->storage->multisamples, fbl);
                                        }
 
                                        DRW_draw_pass_subset(
-                                               psl->stroke_pass,
-                                               stl->shgroups[init_grp].shgrps_fill != NULL ?
-                                               stl->shgroups[init_grp].shgrps_fill : stl->shgroups[init_grp].shgrps_stroke,
-                                               stl->shgroups[end_grp].shgrps_stroke);
+                                               psl->stroke_pass, cache_ob->init_grp, cache_ob->end_grp);
 
                                        if (!stl->storage->is_mat_preview) {
                                                MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, fbl->temp_fb_a, txl);
                                        }
                                }
-
                                /* Current buffer drawing */
                                if ((!is_render) && (cache_ob->is_dup_ob == false)) {
                                        DRW_draw_pass(psl->drawing_pass);
index 8e68fdef95241ed73293438cdf16e249e1923257..0fe25ba9f0fc26ebd99bdef6f2501ec6f56243a5 100644 (file)
@@ -40,7 +40,10 @@ struct RenderLayer;
 
 #define GPENCIL_CACHE_BLOCK_SIZE 8
 #define GPENCIL_MAX_SHGROUPS 65536
-#define GPENCIL_MIN_BATCH_SLOTS_CHUNK 16
+#define GPENCIL_GROUPS_BLOCK_SIZE 1024
+
+/* used to expand VBOs. Size has a big impact in the speed */
+#define GPENCIL_VBO_BLOCK_SIZE 128
 
 #define GPENCIL_COLOR_SOLID   0
 #define GPENCIL_COLOR_TEXTURE 1
@@ -60,7 +63,8 @@ struct RenderLayer;
 typedef struct tGPencilObjectCache {
        struct Object *ob;
        struct bGPdata *gpd;
-       int init_grp, end_grp;
+       DRWShadingGroup *init_grp;
+       DRWShadingGroup *end_grp;
        int idx;  /*original index, can change after sort */
 
        /* effects */
@@ -82,8 +86,10 @@ 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_data; /* other object uses datablock already */
-       int  data_idx;    /* derived data index */
+
+       /* GPU data size */
+       int tot_vertex;
+       int tot_triangles;
 } tGPencilObjectCache;
 
   /* *********** LISTS *********** */
@@ -98,8 +104,6 @@ typedef struct GPENCIL_shgroup {
        int fill_style;
        int keep_size;
        float obj_scale;
-       struct DRWShadingGroup *shgrps_fill;
-       struct DRWShadingGroup *shgrps_stroke;
 } GPENCIL_shgroup;
 
 typedef struct GPENCIL_Storage {
@@ -276,24 +280,57 @@ typedef struct GPENCIL_e_data {
 } GPENCIL_e_data; /* Engine data */
 
 /* GPUBatch Cache */
+typedef struct GpencilBatchCacheElem {
+       GPUBatch *batch;
+       GPUVertBuf *vbo;
+       int vbo_len;
+       /* attr ids */
+       GPUVertFormat format;
+       uint pos_id;
+       uint color_id;
+       uint thickness_id;
+       uint uvdata_id;
+
+       /* size for VBO alloc */
+       int tot_vertex;
+} GpencilBatchCacheElem;
+
+typedef struct GpencilBatchGroup {
+       bGPDlayer *gpl;         /* reference to original layer */
+       bGPDframe *gpf;         /* reference to original frame */
+       bGPDstroke *gps;        /* reference to original stroke */
+       short type;             /* type of element */
+       bool onion;             /* the group is part of onion skin */
+       int vertex_idx;         /* index of vertex data */
+} GpencilBatchGroup;
+
+typedef enum GpencilBatchGroup_Type {
+       eGpencilBatchGroupType_Stroke = 1,
+       eGpencilBatchGroupType_Point  = 2,
+       eGpencilBatchGroupType_Fill   = 3,
+       eGpencilBatchGroupType_Edit   = 4,
+       eGpencilBatchGroupType_Edlin  = 5,
+} GpencilBatchGroup_Type;
+
 typedef struct GpencilBatchCache {
-       /* For normal strokes, a variable number of batch can be needed depending of number of strokes.
-          It could use the stroke number as total size, but when activate the onion skining, the number
-          can change, so the size is changed dynamically.
-        */
-       GPUBatch **batch_stroke;
-       GPUBatch **batch_fill;
-       GPUBatch **batch_edit;
-       GPUBatch **batch_edlin;
+       GpencilBatchCacheElem b_stroke;
+       GpencilBatchCacheElem b_point;
+       GpencilBatchCacheElem b_fill;
+       GpencilBatchCacheElem b_edit;
+       GpencilBatchCacheElem b_edlin;
 
        /* settings to determine if cache is invalid */
        bool is_dirty;
        bool is_editmode;
        int cache_frame;
 
-       /* keep information about the size of the cache */
-       int cache_size;  /* total batch slots available */
-       int cache_idx;   /* current slot index */
+       /* data with the shading groups */
+       int grp_used;                         /* total groups in arrays */
+       int grp_size;                         /* max size of the array */
+       struct GpencilBatchGroup *grp_cache;  /* array of elements */
+
+       int tot_layers;
+       struct bGPDframe *derived_array;      /* runtime data created by modifiers */
 } GpencilBatchCache;
 
 /* general drawing functions */
@@ -302,23 +339,24 @@ struct DRWShadingGroup *DRW_gpencil_shgroup_stroke_create(
         struct Object *ob, struct bGPdata *gpd, struct MaterialGPencilStyle *gp_style, int id, bool onion);
 void DRW_gpencil_populate_datablock(
         struct GPENCIL_e_data *e_data, void *vedata,
-        struct Scene *scene,
         struct Object *ob, struct tGPencilObjectCache *cache_ob);
 void DRW_gpencil_populate_buffer_strokes(
         struct GPENCIL_e_data *e_data, void *vedata, struct ToolSettings *ts, struct Object *ob);
 void DRW_gpencil_populate_multiedit(
         struct GPENCIL_e_data *e_data, void *vedata,
-        struct Scene *scene, struct Object *ob, struct tGPencilObjectCache *cache_ob);
+        struct Object *ob, struct tGPencilObjectCache *cache_ob);
 void DRW_gpencil_triangulate_stroke_fill(struct Object *ob, struct bGPDstroke *gps);
+void DRW_gpencil_populate_particles(struct GPENCIL_e_data *e_data, void *vedata);
 
 void DRW_gpencil_multisample_ensure(struct GPENCIL_Data *vedata, int rect_w, int rect_h);
 
 /* create geometry functions */
-struct GPUBatch *DRW_gpencil_get_point_geom(struct bGPDstroke *gps, short thickness, const float ink[4]);
-struct GPUBatch *DRW_gpencil_get_stroke_geom(struct bGPDstroke *gps, short thickness, const float ink[4]);
-struct GPUBatch *DRW_gpencil_get_fill_geom(struct Object *ob, struct bGPDstroke *gps, const float color[4]);
-struct GPUBatch *DRW_gpencil_get_edit_geom(struct bGPDstroke *gps, float alpha, short dflag);
-struct GPUBatch *DRW_gpencil_get_edlin_geom(struct bGPDstroke *gps, float alpha, short dflag);
+void DRW_gpencil_get_point_geom(struct GpencilBatchCacheElem *be, struct bGPDstroke *gps, short thickness, const float ink[4]);
+void DRW_gpencil_get_stroke_geom(struct GpencilBatchCacheElem *be, struct bGPDstroke *gps, short thickness, const float ink[4]);
+void DRW_gpencil_get_fill_geom(struct GpencilBatchCacheElem *be, struct Object *ob, struct bGPDstroke *gps, const float color[4]);
+void DRW_gpencil_get_edit_geom(struct GpencilBatchCacheElem *be, struct bGPDstroke *gps, float alpha, short dflag);
+void DRW_gpencil_get_edlin_geom(struct GpencilBatchCacheElem *be, struct bGPDstroke *gps, float alpha, short dflag);
+
 struct GPUBatch *DRW_gpencil_get_buffer_stroke_geom(struct bGPdata *gpd, short thickness);
 struct GPUBatch *DRW_gpencil_get_buffer_fill_geom(struct bGPdata *gpd);
 struct GPUBatch *DRW_gpencil_get_buffer_point_geom(struct bGPdata *gpd, short thickness);
@@ -329,8 +367,15 @@ struct tGPencilObjectCache *gpencil_object_cache_add(
         struct tGPencilObjectCache *cache_array, struct Object *ob,
         int *gp_cache_size, int *gp_cache_used);
 
+/* shading groups cache functions */
+struct GpencilBatchGroup *gpencil_group_cache_add(
+       struct GpencilBatchGroup *cache_array,
+       struct bGPDlayer *gpl, struct bGPDframe *gpf, struct bGPDstroke *gps,
+       const short type, const bool onion,
+       const int vertex_idx,
+       int *grp_size, int *grp_used);
+
 /* geometry batch cache functions */
-void gpencil_batch_cache_check_free_slots(struct Object *ob);
 struct GpencilBatchCache *gpencil_batch_cache_get(struct Object *ob, int cfra);
 
 /* effects */
index 201003540701935b2ec90c52bb2fc63f8e93c4ba..b7568ce20ddd6effe437f81c0348f4b42d39c60a 100644 (file)
@@ -479,8 +479,6 @@ 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_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));
 
index db4ff053537fee460cac40c10f71cc52f1ef2d9f..5078d071dd80e6ef22b8ee0739214e68bf2fb858 100644 (file)
@@ -1844,7 +1844,9 @@ void ED_gpencil_calc_stroke_uv(Object *ob, bGPDstroke *gps)
        float factor;
 
        /* if image, use texture width */
-       if ((gp_style) && (gp_style->sima)) {
+       if ((gp_style) && (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) &&
+               (gp_style->sima))
+       {
                factor = gp_style->sima->gen_x;
        }
        else if (totlen == 0) {
index 69a48a2c93b79b5a35161334a726c3f39ec64ea4..55728ca581f6244d1d361c3754b81e019e943a1e 100644 (file)
@@ -203,4 +203,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Armature = {
        /* foreachObjectLink */ foreachObjectLink,
        /* foreachIDLink */     NULL,
        /* foreachTexLink */    NULL,
+       /* getDuplicationFactor */ NULL,
 };
index 0d0ce7476b9e7d3349894cdf4bd676d2dac4f2aa..553d9087c3f01037e427c451633d08e2f39a98b7 100644 (file)
@@ -315,6 +315,13 @@ static void foreachObjectLink(
        walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
 }
 
+static int getDuplicationFactor(GpencilModifierData *md)
+{
+       ArrayGpencilModifierData *mmd = (ArrayGpencilModifierData *)md;
+       int t = mmd->count;
+       CLAMP_MIN(t, 1);
+       return t;
+}
 
 GpencilModifierTypeInfo modifierType_Gpencil_Array = {
        /* name */              "Array",
@@ -338,4 +345,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Array = {
        /* foreachObjectLink */ foreachObjectLink,
        /* foreachIDLink */     NULL,
        /* foreachTexLink */    NULL,
+       /* getDuplicationFactor */ getDuplicationFactor,
 };
index e2a257fcb433163ca7ba1ed612c97f4bdfd7cfd5..ba814c8538ac3bb06828add60775412c9ef69a9f 100644 (file)
@@ -553,4 +553,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Build = {
        /* foreachObjectLink */ NULL,
        /* foreachIDLink */     NULL,
        /* foreachTexLink */    NULL,
+       /* getDuplicationFactor */ NULL,
 };
index 4c1418fe0e344a384cdfacc7c258bc5944d15abe..94c5e9ddbdf0917b85afd8f46392e38292cc1a35 100644 (file)
@@ -164,4 +164,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Color = {
        /* foreachObjectLink */ NULL,
        /* foreachIDLink */     NULL,
        /* foreachTexLink */    NULL,
+       /* getDuplicationFactor */ NULL,
 };
index 1ec6103939a0dad6bb20129f78609f3b538ce40b..97f260f307f41b0bef5a10fdbcb5eff43b77c548 100644 (file)
@@ -353,4 +353,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Hook = {
        /* foreachObjectLink */ foreachObjectLink,
        /* foreachIDLink */     NULL,
        /* foreachTexLink */    NULL,
+       /* getDuplicationFactor */ NULL,
 };
index d9ec81b70b9b2a2c62802c743a8470463809ebad..1d8f2c20b595a045d9b1858d5fb21aafa1c6d480 100644 (file)
@@ -211,4 +211,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Lattice = {
        /* foreachObjectLink */ foreachObjectLink,
        /* foreachIDLink */     NULL,
        /* foreachTexLink */    NULL,
+       /* getDuplicationFactor */ NULL,
 };
index 9c3d3dc9235acff0a487d52d3dd51000f55a34a0..7599e7e9bce5af85f9ffb638336212cfc83a1772 100644 (file)
@@ -189,6 +189,21 @@ static void foreachObjectLink(
        walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
 }
 
+static int getDuplicationFactor(GpencilModifierData *md)
+{
+       MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md;
+       int factor = 1;
+       /* create a duplication for each axis */
+       for (int xi = 0; xi < 3; ++xi) {
+               if (mmd->flag & (GP_MIRROR_AXIS_X << xi)) {
+                       factor++;
+               }
+       }
+       CLAMP_MIN(factor, 1);
+
+       return factor;
+}
+
 GpencilModifierTypeInfo modifierType_Gpencil_Mirror = {
        /* name */              "Mirror",
        /* structName */        "MirrorGpencilModifierData",
@@ -211,4 +226,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Mirror = {
        /* foreachObjectLink */ foreachObjectLink,
        /* foreachIDLink */     NULL,
        /* foreachTexLink */    NULL,
+       /* getDuplicationFactor */ getDuplicationFactor,
 };
index 399ff27eafbd8579eda7d880cabea0f466a07d6c..097b57027215f23764336fdf80f606040e100110 100644 (file)
@@ -285,4 +285,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Noise = {
        /* foreachObjectLink */ NULL,
        /* foreachIDLink */     NULL,
        /* foreachTexLink */    NULL,
+       /* getDuplicationFactor */ NULL,
 };
index 43af4b94c15ccb785e66d0beb08f2d7af7d446e6..2c2a5c2f994d5e790db6527ece5c8cfa8c0f1cf6 100644 (file)
@@ -143,4 +143,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Offset = {
        /* foreachObjectLink */ NULL,
        /* foreachIDLink */     NULL,
        /* foreachTexLink */    NULL,
+       /* getDuplicationFactor */ NULL,
 };
index b89c37924552dc58e5e4b0579af4d3eebb0094e2..7033b246e1c4a9e033949b53f1756f4a50edfd05 100644 (file)
@@ -183,4 +183,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Opacity = {
        /* foreachObjectLink */ NULL,
        /* foreachIDLink */     NULL,
        /* foreachTexLink */    NULL,
+       /* getDuplicationFactor */ NULL,
 };
index 2d0b90e6de714364854691df9f212d07fe5a1dc9..6ddf40df6c00af8f72c4745a037c907b89cb2aec 100644 (file)
@@ -123,4 +123,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Simplify = {
        /* foreachObjectLink */ NULL,
        /* foreachIDLink */     NULL,
        /* foreachTexLink */    NULL,
+       /* getDuplicationFactor */ NULL,
 };
index 8d93980a9d042e3fc5620dc11b22f97233b3b04e..ece7ebc9816a0a6ec1843ccdc6d46dbdaeb1d47a 100644 (file)
@@ -150,4 +150,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Smooth = {
        /* foreachObjectLink */ NULL,
        /* foreachIDLink */     NULL,
        /* foreachTexLink */    NULL,
+       /* getDuplicationFactor */ NULL,
 };
index 38aa4159632da37e78efbc1b4f8d593c87d7db58..71881de50fca8965a510d93c8e18898be5d8f40b 100644 (file)
@@ -97,6 +97,14 @@ static void bakeModifier(
        }
 }
 
+static int getDuplicationFactor(GpencilModifierData *md)
+{
+       SubdivGpencilModifierData *mmd = (SubdivGpencilModifierData *)md;
+       int t = (mmd->level + 1) * (mmd->level + 1);
+       CLAMP_MIN(t, 2);
+       return t;
+}
+
 GpencilModifierTypeInfo modifierType_Gpencil_Subdiv = {
        /* name */              "Subdivision",
        /* structName */        "SubdivGpencilModifierData",
@@ -119,4 +127,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Subdiv = {
        /* foreachObjectLink */ NULL,
        /* foreachIDLink */     NULL,
        /* foreachTexLink */    NULL,
+       /* getDuplicationFactor */ getDuplicationFactor,
 };
index 8046545ef713c48907feb9f74242252970fd317a..441cab909d3a7f86a33a2dd6575e5378da9fc87b 100644 (file)
@@ -171,4 +171,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Thick = {
        /* foreachObjectLink */ NULL,
        /* foreachIDLink */     NULL,
        /* foreachTexLink */    NULL,
+       /* getDuplicationFactor */ NULL,
 };
index e220d5a5e85158e9de1ed6ed87ede54debe42b84..d90dea91af9057137afbac1e8e5bbc552b29a9dd 100644 (file)
@@ -187,4 +187,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Time = {
        /* foreachObjectLink */ NULL,
        /* foreachIDLink */     NULL,
        /* foreachTexLink */    NULL,
+       /* getDuplicationFactor */ NULL,
 };
index ba3b2d84861a411212e67c8ce33aef045f4fbfb0..385296c943eb7bfedc105aa80d13d0ac820e0c77 100644 (file)
@@ -172,4 +172,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Tint = {
        /* foreachObjectLink */ NULL,
        /* foreachIDLink */     NULL,
        /* foreachTexLink */    NULL,
+       /* getDuplicationFactor */ NULL,
 };
index 503ad2f28d9ac6111ea5c0da5759f9b5a22a9e84..8a1bccc69579cd3ab6804b7d26eef1f9a242ca2b 100644 (file)
@@ -236,10 +236,7 @@ typedef enum eGPDframe_Flag {
 
 /* Runtime temp data for bGPDlayer */
 typedef struct bGPDlayer_Runtime {
-       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;