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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2019-05-31 02:45:41 +0300
committerClément Foucault <foucault.clem@gmail.com>2019-09-17 16:16:43 +0300
commit3a08153d7a842b7ab1e40a9048730e1a3ddab5f7 (patch)
tree37e7c902ceb35c5626644ccbbc7e0376e169e56c
parent41299bce936afb5e7da9c332d1140c5a77d49317 (diff)
DRW: Refactor to support draw call batching
Reviewers: brecht Differential Revision: D4997
-rw-r--r--source/blender/blenlib/BLI_memblock.h11
-rw-r--r--source/blender/blenlib/intern/BLI_memblock.c23
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c64
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_utils.c68
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.c79
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.h1
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_render.c3
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl4
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl4
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl5
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl3
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl8
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl28
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl12
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl12
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl8
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl7
-rw-r--r--source/blender/draw/engines/workbench/workbench_deferred.c19
-rw-r--r--source/blender/draw/engines/workbench/workbench_forward.c50
-rw-r--r--source/blender/draw/engines/workbench/workbench_materials.c133
-rw-r--r--source/blender/draw/engines/workbench/workbench_private.h12
-rw-r--r--source/blender/draw/engines/workbench/workbench_volume.c8
-rw-r--r--source/blender/draw/intern/DRW_render.h44
-rw-r--r--source/blender/draw/intern/draw_anim_viz.c4
-rw-r--r--source/blender/draw/intern/draw_common.c2
-rw-r--r--source/blender/draw/intern/draw_hair.c41
-rw-r--r--source/blender/draw/intern/draw_instance_data.c4
-rw-r--r--source/blender/draw/intern/draw_instance_data.h2
-rw-r--r--source/blender/draw/intern/draw_manager.c93
-rw-r--r--source/blender/draw/intern/draw_manager.h320
-rw-r--r--source/blender/draw/intern/draw_manager_data.c806
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c689
-rw-r--r--source/blender/draw/modes/edit_curve_mode.c2
-rw-r--r--source/blender/draw/modes/object_mode.c329
-rw-r--r--source/blender/draw/modes/overlay_mode.c26
-rw-r--r--source/blender/draw/modes/shaders/common_view_lib.glsl67
-rw-r--r--source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl12
-rw-r--r--source/blender/draw/modes/shaders/object_outline_detect_frag.glsl40
-rw-r--r--source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl14
-rw-r--r--source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl7
-rw-r--r--source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl17
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c32
-rw-r--r--source/blender/gpu/CMakeLists.txt2
-rw-r--r--source/blender/gpu/GPU_batch.h11
-rw-r--r--source/blender/gpu/GPU_shader_interface.h9
-rw-r--r--source/blender/gpu/GPU_viewport.h10
-rw-r--r--source/blender/gpu/intern/gpu_batch.c244
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c35
-rw-r--r--source/blender/gpu/intern/gpu_shader.c6
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.c5
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c25
-rw-r--r--source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl19
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl7
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl7
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl10
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_vert.glsl2
57 files changed, 2270 insertions, 1243 deletions
diff --git a/source/blender/blenlib/BLI_memblock.h b/source/blender/blenlib/BLI_memblock.h
index c5ef26ffb91..8bd8642a4e8 100644
--- a/source/blender/blenlib/BLI_memblock.h
+++ b/source/blender/blenlib/BLI_memblock.h
@@ -30,16 +30,20 @@ extern "C" {
#include "BLI_compiler_attrs.h"
+#define BLI_MEM_BLOCK_CHUNK_SIZE (1 << 15) /* 32KiB */
+
struct BLI_memblock;
typedef struct BLI_memblock BLI_memblock;
typedef void (*MemblockValFreeFP)(void *val);
-BLI_memblock *BLI_memblock_create(uint elem_size) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
-void *BLI_memblock_alloc(BLI_memblock *mblk) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+BLI_memblock *BLI_memblock_create_ex(uint elem_size, uint chunk_size) ATTR_WARN_UNUSED_RESULT;
+void *BLI_memblock_alloc(BLI_memblock *mblk) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
void BLI_memblock_clear(BLI_memblock *mblk, MemblockValFreeFP valfreefp) ATTR_NONNULL(1);
void BLI_memblock_destroy(BLI_memblock *mblk, MemblockValFreeFP free_callback) ATTR_NONNULL(1);
+#define BLI_memblock_create(elem_size) BLI_memblock_create_ex(elem_size, BLI_MEM_BLOCK_CHUNK_SIZE)
+
typedef struct BLI_memblock_iter {
void **chunk_list;
int cur_index;
@@ -53,6 +57,9 @@ typedef struct BLI_memblock_iter {
void BLI_memblock_iternew(BLI_memblock *pool, BLI_memblock_iter *iter) ATTR_NONNULL();
void *BLI_memblock_iterstep(BLI_memblock_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+void *BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL();
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/intern/BLI_memblock.c b/source/blender/blenlib/intern/BLI_memblock.c
index f26860afe77..f7239f1b9d1 100644
--- a/source/blender/blenlib/intern/BLI_memblock.c
+++ b/source/blender/blenlib/intern/BLI_memblock.c
@@ -37,7 +37,6 @@
#include "BLI_strict_flags.h" /* keep last */
-#define BLI_MEM_BLOCK_CHUNK_SIZE (1 << 15) /* 32KiB */
#define CHUNK_LIST_SIZE 16
struct BLI_memblock {
@@ -61,18 +60,19 @@ struct BLI_memblock {
int chunk_len;
};
-BLI_memblock *BLI_memblock_create(uint elem_size)
+BLI_memblock *BLI_memblock_create_ex(uint elem_size, uint chunk_size)
{
- BLI_assert(elem_size < BLI_MEM_BLOCK_CHUNK_SIZE);
+ BLI_assert(elem_size < chunk_size);
BLI_memblock *mblk = MEM_mallocN(sizeof(BLI_memblock), "BLI_memblock");
mblk->elem_size = (int)elem_size;
mblk->elem_next = 0;
mblk->elem_last = -1;
- mblk->chunk_size = BLI_MEM_BLOCK_CHUNK_SIZE;
+ mblk->chunk_size = (int)chunk_size;
mblk->chunk_len = CHUNK_LIST_SIZE;
mblk->chunk_list = MEM_callocN(sizeof(void *) * (uint)mblk->chunk_len, "chunk list");
- mblk->chunk_list[0] = MEM_callocN((uint)mblk->chunk_size, "BLI_memblock chunk");
+ mblk->chunk_list[0] = MEM_mallocN_aligned((uint)mblk->chunk_size, 32, "BLI_memblock chunk");
+ memset(mblk->chunk_list[0], 0x0, (uint)mblk->chunk_size);
mblk->chunk_max_ofs = (mblk->chunk_size / mblk->elem_size) * mblk->elem_size;
mblk->elem_next_ofs = 0;
mblk->chunk_next = 0;
@@ -143,8 +143,9 @@ void *BLI_memblock_alloc(BLI_memblock *mblk)
}
if (UNLIKELY(mblk->chunk_list[mblk->chunk_next] == NULL)) {
- mblk->chunk_list[mblk->chunk_next] = MEM_callocN((uint)mblk->chunk_size,
- "BLI_memblock chunk");
+ mblk->chunk_list[mblk->chunk_next] = MEM_mallocN_aligned(
+ (uint)mblk->chunk_size, 32, "BLI_memblock chunk");
+ memset(mblk->chunk_list[mblk->chunk_next], 0x0, (uint)mblk->chunk_size);
}
}
return ptr;
@@ -180,3 +181,11 @@ void *BLI_memblock_iterstep(BLI_memblock_iter *iter)
}
return ptr;
}
+
+/* Direct access. elem is element index inside the chosen chunk. */
+void *BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem)
+{
+ BLI_assert(chunk < mblk->chunk_len);
+ BLI_assert(elem < (mblk->chunk_size / mblk->elem_size));
+ return (char *)(mblk->chunk_list[chunk]) + mblk->elem_size * elem;
+}
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index 712bcc43f52..2158d395d84 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -48,6 +48,9 @@ static struct {
char *frag_shader_lib;
char *vert_shader_str;
char *vert_shadow_shader_str;
+ char *vert_background_shader_str;
+ char *vert_volume_shader_str;
+ char *geom_volume_shader_str;
char *volume_shader_lib;
struct GPUShader *default_prepass_sh;
@@ -565,6 +568,15 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata,
e_data.vert_shadow_shader_str = BLI_string_joinN(
datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_shadow_vert_glsl);
+ e_data.vert_background_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
+ datatoc_background_vert_glsl);
+
+ e_data.vert_volume_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
+ datatoc_volumetric_vert_glsl);
+
+ e_data.geom_volume_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
+ datatoc_volumetric_geom_glsl);
+
e_data.default_background = DRW_shader_create_with_lib(datatoc_background_vert_glsl,
NULL,
datatoc_default_world_frag_glsl,
@@ -637,7 +649,7 @@ struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, Wor
wo,
engine,
options,
- datatoc_background_vert_glsl,
+ e_data.vert_background_shader_str,
NULL,
e_data.frag_shader_lib,
SHADER_DEFINES "#define PROBE_CAPTURE\n",
@@ -657,7 +669,7 @@ struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, Wor
wo,
engine,
options,
- datatoc_background_vert_glsl,
+ e_data.vert_background_shader_str,
NULL,
e_data.frag_shader_lib,
SHADER_DEFINES "#define WORLD_BACKGROUND\n",
@@ -680,8 +692,8 @@ struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, World *
wo,
engine,
options,
- datatoc_volumetric_vert_glsl,
- datatoc_volumetric_geom_glsl,
+ e_data.vert_volume_shader_str,
+ e_data.geom_volume_shader_str,
e_data.volume_shader_lib,
defines,
true);
@@ -741,8 +753,8 @@ struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material
ma,
engine,
options,
- datatoc_volumetric_vert_glsl,
- datatoc_volumetric_geom_glsl,
+ e_data.vert_volume_shader_str,
+ e_data.geom_volume_shader_str,
e_data.volume_shader_lib,
defines,
true);
@@ -1338,6 +1350,24 @@ static void material_transparent(Material *ma,
const float *spec_p = &ma->spec;
const float *rough_p = &ma->roughness;
+ const bool use_prepass = ((ma->blend_flag & MA_BL_HIDE_BACKFACE) != 0);
+
+ DRWState cur_state;
+ DRWState all_state = (DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR | DRW_STATE_CULL_BACK |
+ DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_DEPTH_EQUAL |
+ DRW_STATE_BLEND_CUSTOM);
+
+ /* Depth prepass */
+ if (use_prepass) {
+ *shgrp_depth = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->transparent_pass);
+
+ cur_state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0;
+
+ DRW_shgroup_state_disable(*shgrp_depth, all_state);
+ DRW_shgroup_state_enable(*shgrp_depth, cur_state);
+ }
+
if (ma->use_nodes && ma->nodetree) {
static float error_col[3] = {1.0f, 0.0f, 1.0f};
static float compile_col[3] = {0.5f, 0.5f, 0.5f};
@@ -1394,30 +1424,13 @@ static void material_transparent(Material *ma,
DRW_shgroup_uniform_float(*shgrp, "roughness", rough_p, 1);
}
- const bool use_prepass = ((ma->blend_flag & MA_BL_HIDE_BACKFACE) != 0);
-
- DRWState all_state = (DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR | DRW_STATE_CULL_BACK |
- DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_DEPTH_EQUAL |
- DRW_STATE_BLEND_CUSTOM);
-
- DRWState cur_state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM;
+ cur_state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM;
cur_state |= (use_prepass) ? DRW_STATE_DEPTH_EQUAL : DRW_STATE_DEPTH_LESS_EQUAL;
cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0;
/* Disable other blend modes and use the one we want. */
DRW_shgroup_state_disable(*shgrp, all_state);
DRW_shgroup_state_enable(*shgrp, cur_state);
-
- /* Depth prepass */
- if (use_prepass) {
- *shgrp_depth = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->transparent_pass);
-
- cur_state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0;
-
- DRW_shgroup_state_disable(*shgrp_depth, all_state);
- DRW_shgroup_state_enable(*shgrp_depth, cur_state);
- }
}
/* Return correct material or &defmaterial if slot is empty. */
@@ -1734,6 +1747,9 @@ void EEVEE_materials_free(void)
MEM_SAFE_FREE(e_data.frag_shader_lib);
MEM_SAFE_FREE(e_data.vert_shader_str);
MEM_SAFE_FREE(e_data.vert_shadow_shader_str);
+ MEM_SAFE_FREE(e_data.vert_background_shader_str);
+ MEM_SAFE_FREE(e_data.vert_volume_shader_str);
+ MEM_SAFE_FREE(e_data.geom_volume_shader_str);
MEM_SAFE_FREE(e_data.volume_shader_lib);
DRW_SHADER_FREE_SAFE(e_data.default_hair_prepass_sh);
DRW_SHADER_FREE_SAFE(e_data.default_hair_prepass_clip_sh);
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
index aacddd074aa..19a28031ce0 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
@@ -418,6 +418,7 @@ static DRWShadingGroup *gpencil_shgroup_fill_create(GPENCIL_Data *vedata,
DRWPass *pass,
GPUShader *shader,
Object *ob,
+ float (*obmat)[4],
bGPdata *gpd,
bGPDlayer *gpl,
MaterialGPencilStyle *gp_style,
@@ -431,6 +432,8 @@ static DRWShadingGroup *gpencil_shgroup_fill_create(GPENCIL_Data *vedata,
/* e_data.gpencil_fill_sh */
DRWShadingGroup *grp = DRW_shgroup_create(shader, pass);
+ DRW_shgroup_uniform_mat4(grp, "gpModelMatrix", obmat);
+
DRW_shgroup_uniform_vec4(grp, "color2", gp_style->mix_rgba, 1);
/* set style type */
@@ -564,6 +567,7 @@ DRWShadingGroup *gpencil_shgroup_stroke_create(GPENCIL_Data *vedata,
DRWPass *pass,
GPUShader *shader,
Object *ob,
+ float (*obmat)[4],
bGPdata *gpd,
bGPDlayer *gpl,
bGPDstroke *gps,
@@ -585,6 +589,8 @@ DRWShadingGroup *gpencil_shgroup_stroke_create(GPENCIL_Data *vedata,
DRW_shgroup_uniform_float(grp, "pixsize", stl->storage->pixsize, 1);
+ DRW_shgroup_uniform_mat4(grp, "gpModelMatrix", obmat);
+
/* avoid wrong values */
if ((gpd) && (gpd->pixfactor == 0.0f)) {
gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
@@ -727,6 +733,7 @@ static DRWShadingGroup *gpencil_shgroup_point_create(GPENCIL_Data *vedata,
DRWPass *pass,
GPUShader *shader,
Object *ob,
+ float (*obmat)[4],
bGPdata *gpd,
bGPDlayer *gpl,
bGPDstroke *gps,
@@ -747,6 +754,8 @@ static DRWShadingGroup *gpencil_shgroup_point_create(GPENCIL_Data *vedata,
DRW_shgroup_uniform_vec2(grp, "Viewport", viewport_size, 1);
DRW_shgroup_uniform_float(grp, "pixsize", stl->storage->pixsize, 1);
+ DRW_shgroup_uniform_mat4(grp, "gpModelMatrix", obmat);
+
/* avoid wrong values */
if ((gpd) && (gpd->pixfactor == 0.0f)) {
gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
@@ -1572,6 +1581,9 @@ void gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data,
copy_v2_v2(stl->storage->gradient_s, brush->gpencil_settings->gradient_s);
stl->storage->alignment_mode = (gp_style) ? gp_style->alignment_mode : GP_STYLE_FOLLOW_PATH;
+ static float unit_mat[4][4] = {
+ {1.0, 0.0, 0.0, 0.0}, {0.0, 1.0, 0.0, 0.0}, {0.0, 0.0, 1.0, 0.0}, {0.0, 0.0, 0.0, 1.0}};
+
/* if only one point, don't need to draw buffer because the user has no time to see it */
if (gpd->runtime.sbuffer_used > 1) {
if ((gp_style) && (gp_style->mode == GP_STYLE_MODE_LINE)) {
@@ -1580,6 +1592,7 @@ void gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data,
psl->drawing_pass,
e_data->gpencil_stroke_sh,
NULL,
+ unit_mat,
gpd,
NULL,
NULL,
@@ -1604,6 +1617,7 @@ void gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data,
psl->drawing_pass,
e_data->gpencil_point_sh,
NULL,
+ unit_mat,
gpd,
NULL,
NULL,
@@ -1790,6 +1804,7 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
stroke_pass,
e_data->gpencil_stroke_sh,
ob,
+ obmat,
gpd,
gpl,
gps,
@@ -1798,23 +1813,26 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
elm->onion,
scale,
cache_ob->shading_type);
- if ((do_onion) || (elm->onion == false)) {
- DRW_shgroup_call_range_obmat(shgrp, cache->b_stroke.batch, obmat, start_stroke, len);
- }
- stl->storage->shgroup_id++;
- start_stroke = elm->vertex_idx;
/* set stencil mask id */
if (gpencil_is_stencil_required(gp_style)) {
+ if (stencil_id == 1) {
+ /* Clear previous stencils. */
+ DRW_shgroup_clear_framebuffer(shgrp, GPU_STENCIL_BIT, 0, 0, 0, 0, 0.0f, 0x0);
+ }
DRW_shgroup_stencil_mask(shgrp, stencil_id);
stencil_id++;
}
else {
/* Disable stencil for this type */
DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
- /* set stencil mask id as not used */
- DRW_shgroup_stencil_mask(shgrp, 0x0);
}
+
+ if ((do_onion) || (elm->onion == false)) {
+ DRW_shgroup_call_range(shgrp, cache->b_stroke.batch, start_stroke, len);
+ }
+ stl->storage->shgroup_id++;
+ start_stroke = elm->vertex_idx;
break;
}
case eGpencilBatchGroupType_Point: {
@@ -1824,6 +1842,7 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
stroke_pass,
e_data->gpencil_point_sh,
ob,
+ obmat,
gpd,
gpl,
gps,
@@ -1833,16 +1852,14 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
scale,
cache_ob->shading_type);
+ /* Disable stencil for this type */
+ DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
+
if ((do_onion) || (elm->onion == false)) {
- DRW_shgroup_call_range_obmat(shgrp, cache->b_point.batch, obmat, start_point, len);
+ DRW_shgroup_call_range(shgrp, cache->b_point.batch, start_point, len);
}
stl->storage->shgroup_id++;
start_point = elm->vertex_idx;
-
- /* Disable stencil for this type */
- DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
- /* set stencil mask id as not used */
- DRW_shgroup_stencil_mask(shgrp, 0x0);
break;
}
case eGpencilBatchGroupType_Fill: {
@@ -1852,30 +1869,32 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
stroke_pass,
e_data->gpencil_fill_sh,
ob,
+ obmat,
gpd,
gpl,
gp_style,
stl->storage->shgroup_id,
cache_ob->shading_type);
+ /* Disable stencil for this type */
+ DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
+
if ((do_onion) || (elm->onion == false)) {
- DRW_shgroup_call_range_obmat(shgrp, cache->b_fill.batch, obmat, start_fill, len);
+ DRW_shgroup_call_range(shgrp, cache->b_fill.batch, start_fill, len);
}
stl->storage->shgroup_id++;
start_fill = elm->vertex_idx;
-
- /* Disable stencil for this type */
- DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
- /* set stencil mask id as not used */
- DRW_shgroup_stencil_mask(shgrp, 0x0);
break;
}
case eGpencilBatchGroupType_Edit: {
if (stl->g_data->shgrps_edit_point) {
const int len = elm->vertex_idx - start_edit;
+
+ shgrp = DRW_shgroup_create_sub(stl->g_data->shgrps_edit_point);
+ DRW_shgroup_uniform_mat4(shgrp, "gpModelMatrix", obmat);
/* use always the same group */
- DRW_shgroup_call_range_obmat(
- stl->g_data->shgrps_edit_point, cache->b_edit.batch, obmat, start_edit, len);
+ DRW_shgroup_call_range(
+ stl->g_data->shgrps_edit_point, cache->b_edit.batch, start_edit, len);
start_edit = elm->vertex_idx;
}
@@ -1884,9 +1903,12 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
case eGpencilBatchGroupType_Edlin: {
if (stl->g_data->shgrps_edit_line) {
const int len = elm->vertex_idx - start_edlin;
+
+ shgrp = DRW_shgroup_create_sub(stl->g_data->shgrps_edit_line);
+ DRW_shgroup_uniform_mat4(shgrp, "gpModelMatrix", obmat);
/* use always the same group */
- DRW_shgroup_call_range_obmat(
- stl->g_data->shgrps_edit_line, cache->b_edlin.batch, obmat, start_edlin, len);
+ DRW_shgroup_call_range(
+ stl->g_data->shgrps_edit_line, cache->b_edlin.batch, start_edlin, len);
start_edlin = elm->vertex_idx;
}
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
index 9efae54b376..b2e8cef1db2 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.c
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -61,6 +61,8 @@ extern char datatoc_gpencil_edit_point_geom_glsl[];
extern char datatoc_gpencil_edit_point_frag_glsl[];
extern char datatoc_gpencil_blend_frag_glsl[];
+extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
+
extern char datatoc_common_colormanagement_lib_glsl[];
extern char datatoc_common_view_lib_glsl[];
@@ -221,7 +223,12 @@ static void GPENCIL_create_shaders(void)
/* used for edit lines for edit modes */
if (!e_data.gpencil_line_sh) {
- e_data.gpencil_line_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_FLAT_COLOR);
+ e_data.gpencil_line_sh = DRW_shader_create_with_lib(
+ datatoc_gpencil_edit_point_vert_glsl,
+ NULL,
+ datatoc_gpu_shader_3D_smooth_color_frag_glsl,
+ datatoc_common_view_lib_glsl,
+ NULL);
}
/* used to filling during drawing */
@@ -279,6 +286,7 @@ static void GPENCIL_engine_free(void)
DRW_SHADER_FREE_SAFE(e_data.gpencil_stroke_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_point_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_edit_point_sh);
+ DRW_SHADER_FREE_SAFE(e_data.gpencil_line_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_fullscreen_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_simple_fullscreen_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_blend_fullscreen_sh);
@@ -834,76 +842,13 @@ static void gpencil_draw_pass_range(GPENCIL_FramebufferList *fbl,
const bool do_antialiasing = ((!stl->storage->is_mat_preview) && (multi));
- DRWShadingGroup *shgrp = init_shgrp;
- DRWShadingGroup *from_shgrp = init_shgrp;
- DRWShadingGroup *to_shgrp = init_shgrp;
- int stencil_tot = 0;
- bool do_last = true;
-
if (do_antialiasing) {
MULTISAMPLE_GP_SYNC_ENABLE(stl->storage->multisamples, fbl);
}
- /* Loop all shading groups to separate by stencil groups. */
- while ((shgrp) && (shgrp != end_shgrp)) {
- do_last = true;
- /* Count number of groups using stencil. */
- if (DRW_shgroup_stencil_mask_get(shgrp) != 0) {
- stencil_tot++;
- }
-
- /* Draw stencil group and clear stencil bit. This is required because the number of
- * shading groups can be greater than the limit of 255 stencil values.
- * Only count as stencil if the shading group has an stencil value assigned. This reduces
- * the number of clears because Dots, Fills and some Line strokes don't need stencil.
- */
- if (stencil_tot == 255) {
- DRW_draw_pass_subset(GPENCIL_3D_DRAWMODE(ob, gpd) ? psl->stroke_pass_3d :
- psl->stroke_pass_2d,
- from_shgrp,
- to_shgrp);
- /* Clear Stencil and prepare for next group. */
- if (do_antialiasing) {
- GPU_framebuffer_clear_stencil(fbl->multisample_fb, 0x0);
- }
- else {
- GPU_framebuffer_clear_stencil(fb, 0x0);
- }
-
- /* Set new init group and reset. */
- do_last = false;
-
- shgrp = DRW_shgroup_get_next(shgrp);
- if (shgrp) {
- from_shgrp = to_shgrp = shgrp;
- stencil_tot = 0;
- if (shgrp != end_shgrp) {
- continue;
- }
- else {
- do_last = true;
- break;
- }
- }
- else {
- /* No more groups. */
- break;
- }
- }
-
- /* Still below stencil group limit. */
- shgrp = DRW_shgroup_get_next(shgrp);
- if (shgrp) {
- to_shgrp = shgrp;
- }
- }
-
- /* Draw last pending groups. */
- if (do_last) {
- DRW_draw_pass_subset(GPENCIL_3D_DRAWMODE(ob, gpd) ? psl->stroke_pass_3d : psl->stroke_pass_2d,
- from_shgrp,
- to_shgrp);
- }
+ DRW_draw_pass_subset(GPENCIL_3D_DRAWMODE(ob, gpd) ? psl->stroke_pass_3d : psl->stroke_pass_2d,
+ init_shgrp,
+ end_shgrp);
if (do_antialiasing) {
MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, fb, txl);
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h
index 79bcffac512..27d537c9a20 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.h
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.h
@@ -390,6 +390,7 @@ struct DRWShadingGroup *gpencil_shgroup_stroke_create(struct GPENCIL_Data *vedat
struct DRWPass *pass,
struct GPUShader *shader,
struct Object *ob,
+ float (*obmat)[4],
struct bGPdata *gpd,
struct bGPDlayer *gpl,
struct bGPDstroke *gps,
diff --git a/source/blender/draw/engines/gpencil/gpencil_render.c b/source/blender/draw/engines/gpencil/gpencil_render.c
index d0deb48c019..14e1ed2d6bf 100644
--- a/source/blender/draw/engines/gpencil/gpencil_render.c
+++ b/source/blender/draw/engines/gpencil/gpencil_render.c
@@ -308,6 +308,9 @@ void GPENCIL_render_to_image(void *vedata,
DRW_render_object_iter(vedata, engine, draw_ctx->depsgraph, GPENCIL_render_cache);
GPENCIL_cache_finish(vedata);
+
+ DRW_render_instance_buffer_finish();
+
GPENCIL_draw_scene(vedata);
/* combined data */
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl
index a1cfb2ae4ae..f75322f90e2 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl
@@ -1,4 +1,6 @@
+uniform mat4 gpModelMatrix;
+
in vec3 pos;
in vec4 color;
in float size;
@@ -8,7 +10,7 @@ out float finalThickness;
void main()
{
- gl_Position = point_object_to_ndc(pos);
+ gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz);
finalColor = color;
finalThickness = size;
}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl
index eb452f4c660..263dc570423 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl
@@ -1,4 +1,6 @@
+uniform mat4 gpModelMatrix;
+
in vec3 pos;
in vec4 color;
in vec2 texCoord;
@@ -8,7 +10,7 @@ out vec2 texCoord_interp;
void main(void)
{
- gl_Position = point_object_to_ndc(pos);
+ gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz);
finalColor = color;
texCoord_interp = texCoord;
}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl
index ef8b361373f..87963c66858 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl
@@ -6,6 +6,7 @@ uniform float pixfactor;
uniform int viewport_xray;
uniform int shading_type[2];
uniform vec4 wire_color;
+uniform mat4 gpModelMatrix;
in vec3 pos;
in vec4 color;
@@ -30,8 +31,8 @@ float defaultpixsize = pixsize * (1000.0 / pixfactor);
void main()
{
- gl_Position = point_object_to_ndc(pos);
- finalprev_pos = point_object_to_ndc(prev_pos);
+ gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz);
+ finalprev_pos = point_world_to_ndc((gpModelMatrix * vec4(prev_pos, 1.0)).xyz);
finalColor = color;
if (keep_size == TRUE) {
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl
index c7089f357f9..582b9a7f249 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl
@@ -6,6 +6,7 @@ uniform float pixfactor;
uniform int viewport_xray;
uniform int shading_type[2];
uniform vec4 wire_color;
+uniform mat4 gpModelMatrix;
in vec3 pos;
in vec4 color;
@@ -28,7 +29,7 @@ float defaultpixsize = pixsize * (1000.0 / pixfactor);
void main(void)
{
- gl_Position = point_object_to_ndc(pos);
+ gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz);
finalColor = color;
if (keep_size == TRUE) {
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl
index 505b4822ad6..abd8c1f6579 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl
@@ -1,5 +1,6 @@
-uniform int object_id = 0;
+
layout(location = 0) out uint objectId;
+
uniform float ImageTransparencyCutoff = 0.1;
#ifdef V3D_SHADING_TEXTURE_COLOR
uniform sampler2D image;
@@ -10,11 +11,10 @@ in vec2 uv_interp;
void main()
{
#ifdef V3D_SHADING_TEXTURE_COLOR
- vec4 diffuse_color = texture(image, uv_interp);
- if (diffuse_color.a < ImageTransparencyCutoff) {
+ if (texture(image, uv_interp).a < ImageTransparencyCutoff) {
discard;
}
#endif
- objectId = uint(object_id);
+ objectId = uint(resource_id + 1) & 0xFFu;
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
index 3333dfeff38..f799ce41cb2 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
@@ -8,8 +8,7 @@ uniform float alpha = 0.5;
uniform vec2 invertedViewportSize;
uniform vec4 viewvecs[3];
-uniform vec3 materialDiffuseColor;
-uniform vec3 materialSpecularColor;
+uniform vec4 materialColorAndMetal;
uniform float materialRoughness;
uniform float shadowMultiplier = 0.5;
@@ -42,17 +41,17 @@ layout(location = 1) out
void main()
{
- vec4 diffuse_color;
+ vec4 base_color;
#if defined(V3D_SHADING_TEXTURE_COLOR)
- diffuse_color = workbench_sample_texture(image, uv_interp, imageNearest, imagePremultiplied);
- if (diffuse_color.a < ImageTransparencyCutoff) {
+ base_color = workbench_sample_texture(image, uv_interp, imageNearest, imagePremultiplied);
+ if (base_color.a < ImageTransparencyCutoff) {
discard;
}
#elif defined(V3D_SHADING_VERTEX_COLOR)
- diffuse_color = vec4(vertexColor, 1.0);
+ base_color.rgb = vertexColor;
#else
- diffuse_color = vec4(materialDiffuseColor, 1.0);
+ base_color.rgb = materialColorAndMetal.rgb;
#endif /* V3D_SHADING_TEXTURE_COLOR */
vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize;
@@ -64,7 +63,7 @@ void main()
/* -------- SHADING --------- */
#ifdef V3D_LIGHTING_FLAT
- vec3 shaded_color = diffuse_color.rgb;
+ vec3 shaded_color = base_color.rgb;
#elif defined(V3D_LIGHTING_MATCAP)
bool flipped = world_data.matcap_orientation != 0;
@@ -75,11 +74,20 @@ void main()
# else
vec3 matcap_specular = vec3(0.0);
# endif
- vec3 shaded_color = matcap_diffuse * diffuse_color.rgb + matcap_specular;
+ vec3 shaded_color = matcap_diffuse * base_color.rgb + matcap_specular;
#elif defined(V3D_LIGHTING_STUDIO)
+# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
+ float metallic = materialColorAndMetal.a;
+ vec3 specular_color = mix(vec3(0.05), base_color.rgb, metallic);
+ vec3 diffuse_color = mix(base_color.rgb, vec3(0.0), metallic);
+# else
+ vec3 specular_color = vec3(0.0);
+ vec3 diffuse_color = base_color.rgb;
+# endif
+
vec3 shaded_color = get_world_lighting(
- world_data, diffuse_color.rgb, materialSpecularColor, materialRoughness, nor, I_vs);
+ world_data, diffuse_color, specular_color, materialRoughness, nor, I_vs);
#endif
#ifdef V3D_SHADING_SHADOW
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
index c673b2484de..b5f95f2dcf8 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
@@ -1,7 +1,5 @@
-uniform int object_id = 0;
-uniform vec3 materialDiffuseColor;
-uniform float materialMetallic;
+uniform vec4 materialColorAndMetal;
uniform float materialRoughness;
uniform sampler2D image;
@@ -48,7 +46,7 @@ void main()
# elif defined(V3D_SHADING_VERTEX_COLOR)
color.rgb = vertexColor;
# else
- color.rgb = materialDiffuseColor;
+ color.rgb = materialColorAndMetal.rgb;
# endif
# ifdef V3D_LIGHTING_MATCAP
@@ -56,7 +54,7 @@ void main()
metallic = float(gl_FrontFacing);
roughness = 0.0;
# else
- metallic = materialMetallic;
+ metallic = materialColorAndMetal.a;
roughness = materialRoughness;
# endif
@@ -64,7 +62,7 @@ void main()
/* Add some variation to the hairs to avoid uniform look. */
float hair_variation = hair_rand * 0.1;
color = clamp(color - hair_variation, 0.0, 1.0);
- metallic = clamp(materialMetallic - hair_variation, 0.0, 1.0);
+ metallic = clamp(materialColorAndMetal.a - hair_variation, 0.0, 1.0);
roughness = clamp(materialRoughness - hair_variation, 0.0, 1.0);
# endif
@@ -73,7 +71,7 @@ void main()
#endif /* MATDATA_PASS_ENABLED */
#ifdef OBJECT_ID_PASS_ENABLED
- objectId = uint(object_id);
+ objectId = uint(resource_id + 1) & 0xFFu;
#endif
#ifdef NORMAL_VIEWPORT_PASS_ENABLED
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
index 7eb12dbdeb9..04dd9ab85bb 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
@@ -25,6 +25,10 @@ out vec2 uv_interp;
out vec3 vertexColor;
#endif
+#ifdef OBJECT_ID_PASS_ENABLED
+RESOURCE_ID_VARYING
+#endif
+
/* From http://libnoise.sourceforge.net/noisegen/index.html */
float integer_noise(int n)
{
@@ -91,12 +95,18 @@ void main()
#endif
#ifdef NORMAL_VIEWPORT_PASS_ENABLED
- normal_viewport = normal_object_to_view(nor);
# ifndef HAIR_SHADER
+ normal_viewport = normal_object_to_view(nor);
normal_viewport = normalize(normal_viewport);
+# else
+ normal_viewport = normal_world_to_view(nor);
# endif
#endif
+#ifdef OBJECT_ID_PASS_ENABLED
+ PASS_RESOURCE_ID
+#endif
+
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(world_pos);
#endif
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
index 4a9b0ae3b7d..c24c335189e 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
@@ -1,6 +1,4 @@
-uniform vec3 OrcoTexCoFactors[2];
-
uniform sampler2D depthBuffer;
uniform sampler3D densityTexture;
@@ -216,13 +214,13 @@ void main()
vs_ray_dir /= abs(vs_ray_dir.z);
/* TODO(fclem) Precompute the matrix/ */
- vec3 ls_ray_dir = mat3(ViewMatrixInverse) * vs_ray_dir * OrcoTexCoFactors[1] * 2.0;
+ vec3 ls_ray_dir = mat3(ViewMatrixInverse) * vs_ray_dir * OrcoTexCoFactors[1].xyz * 2.0;
ls_ray_dir = mat3(ModelMatrixInverse) * ls_ray_dir;
vec3 ls_ray_ori = point_view_to_object(vs_ray_ori);
vec3 ls_ray_end = point_view_to_object(vs_ray_end);
- ls_ray_ori = (OrcoTexCoFactors[0] + ls_ray_ori * OrcoTexCoFactors[1]) * 2.0 - 1.0;
- ls_ray_end = (OrcoTexCoFactors[0] + ls_ray_end * OrcoTexCoFactors[1]) * 2.0 - 1.0;
+ ls_ray_ori = (OrcoTexCoFactors[0].xyz + ls_ray_ori * OrcoTexCoFactors[1].xyz) * 2.0 - 1.0;
+ ls_ray_end = (OrcoTexCoFactors[0].xyz + ls_ray_end * OrcoTexCoFactors[1].xyz) * 2.0 - 1.0;
/* TODO: Align rays to volume center so that it mimics old behaviour of slicing the volume. */
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl
index 6f0bb56fafd..3542a1a91fc 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl
@@ -1,10 +1,11 @@
-uniform vec3 OrcoTexCoFactors[2];
uniform float slicePosition;
uniform int sliceAxis; /* -1 is no slice, 0 is X, 1 is Y, 2 is Z. */
in vec3 pos;
+RESOURCE_ID_VARYING
+
#ifdef VOLUME_SLICE
in vec3 uvs;
@@ -27,6 +28,8 @@ void main()
#else
vec3 final_pos = pos;
#endif
- final_pos = ((final_pos * 0.5 + 0.5) - OrcoTexCoFactors[0]) / OrcoTexCoFactors[1];
+ final_pos = ((final_pos * 0.5 + 0.5) - OrcoTexCoFactors[0].xyz) / OrcoTexCoFactors[1].xyz;
gl_Position = point_object_to_ndc(final_pos);
+
+ PASS_RESOURCE_ID
}
diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c
index 262ea7110a4..e41cba1d3bd 100644
--- a/source/blender/draw/engines/workbench/workbench_deferred.c
+++ b/source/blender/draw/engines/workbench/workbench_deferred.c
@@ -83,7 +83,6 @@ static struct {
struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */
SceneDisplay display; /* world light direction for shadows */
- int next_object_id;
struct GPUUniformBuffer *sampling_ubo;
struct GPUTexture *jitter_tx;
@@ -147,6 +146,7 @@ static char *workbench_build_prepass_frag(void)
{
DynStr *ds = BLI_dynstr_new();
+ BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl);
BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl);
BLI_dynstr_append(ds, datatoc_workbench_prepass_frag_glsl);
@@ -330,7 +330,6 @@ static struct GPUTexture *create_jitter_texture(int num_samples)
static void workbench_init_object_data(DrawData *dd)
{
WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)dd;
- data->object_id = ((e_data.next_object_id++) & 0xff) + 1;
data->shadow_bbox_dirty = true;
}
@@ -379,11 +378,10 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
workbench_effect_info_init(stl->effects);
}
- if (!e_data.next_object_id) {
+ if (!e_data.shadow_pass_sh) {
WORKBENCH_DEFERRED_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
memset(sh_data->prepass_sh_cache, 0, sizeof(sh_data->prepass_sh_cache));
memset(e_data.composite_sh_cache, 0, sizeof(e_data.composite_sh_cache));
- e_data.next_object_id = 1;
#ifdef DEBUG_SHADOW_VOLUME
const char *shadow_frag = datatoc_workbench_shadow_debug_frag_glsl;
#else
@@ -868,18 +866,11 @@ static WORKBENCH_MaterialData *get_or_create_material_data(WORKBENCH_Data *vedat
WORKBENCH_PassList *psl = vedata->psl;
WORKBENCH_PrivateData *wpd = stl->g_data;
WORKBENCH_MaterialData *material;
- WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_drawdata_ensure(
- &ob->id,
- &draw_engine_workbench_solid,
- sizeof(WORKBENCH_ObjectData),
- &workbench_init_object_data,
- NULL);
WORKBENCH_MaterialData material_template;
const bool is_ghost = (ob->dtx & OB_DRAWXRAY);
/* Solid */
workbench_material_update_data(wpd, ob, mat, &material_template, color_type);
- material_template.object_id = OBJECT_ID_PASS_ENABLED(wpd) ? engine_object_data->object_id : 1;
material_template.color_type = color_type;
material_template.ima = ima;
material_template.iuser = iuser;
@@ -899,8 +890,7 @@ static WORKBENCH_MaterialData *get_or_create_material_data(WORKBENCH_Data *vedat
shader, (ob->dtx & OB_DRAWXRAY) ? psl->ghost_prepass_pass : psl->prepass_pass);
workbench_material_copy(material, &material_template);
DRW_shgroup_stencil_mask(material->shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF);
- DRW_shgroup_uniform_int(material->shgrp, "object_id", &material->object_id, 1);
- workbench_material_shgroup_uniform(wpd, material->shgrp, material, ob, true, true, interp);
+ workbench_material_shgroup_uniform(wpd, material->shgrp, material, ob, true, interp);
BLI_ghash_insert(wpd->material_hash, POINTER_FROM_UINT(hash), material);
}
return material;
@@ -943,8 +933,7 @@ static void workbench_cache_populate_particles(WORKBENCH_Data *vedata, Object *o
(ob->dtx & OB_DRAWXRAY) ? psl->ghost_prepass_hair_pass : psl->prepass_hair_pass,
shader);
DRW_shgroup_stencil_mask(shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF);
- DRW_shgroup_uniform_int(shgrp, "object_id", &material->object_id, 1);
- workbench_material_shgroup_uniform(wpd, shgrp, material, ob, true, true, interp);
+ workbench_material_shgroup_uniform(wpd, shgrp, material, ob, true, interp);
}
}
}
diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c
index 1cbc60ef858..890359e8fda 100644
--- a/source/blender/draw/engines/workbench/workbench_forward.c
+++ b/source/blender/draw/engines/workbench/workbench_forward.c
@@ -63,8 +63,6 @@ static struct {
struct GPUTexture *transparent_accum_tx; /* ref only, not alloced */
struct GPUTexture *transparent_revealage_tx; /* ref only, not alloced */
struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */
-
- int next_object_id;
} e_data = {{{{NULL}}}};
/* Shaders */
@@ -98,6 +96,18 @@ static char *workbench_build_forward_vert(bool is_hair)
return str;
}
+static char *workbench_build_forward_outline_frag(void)
+{
+ DynStr *ds = BLI_dynstr_new();
+
+ BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
+ BLI_dynstr_append(ds, datatoc_workbench_forward_depth_frag_glsl);
+
+ char *str = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+ return str;
+}
+
static char *workbench_build_forward_transparent_accum_frag(void)
{
DynStr *ds = BLI_dynstr_new();
@@ -129,12 +139,6 @@ static char *workbench_build_forward_composite_frag(void)
return str;
}
-static void workbench_init_object_data(DrawData *dd)
-{
- WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)dd;
- data->object_id = ((e_data.next_object_id++) & 0xff) + 1;
-}
-
WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_Data *vedata,
Object *ob,
Material *mat,
@@ -149,18 +153,11 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_
WORKBENCH_PassList *psl = vedata->psl;
WORKBENCH_PrivateData *wpd = stl->g_data;
WORKBENCH_MaterialData *material;
- WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_drawdata_ensure(
- &ob->id,
- &draw_engine_workbench_solid,
- sizeof(WORKBENCH_ObjectData),
- &workbench_init_object_data,
- NULL);
WORKBENCH_MaterialData material_template;
DRWShadingGroup *grp;
/* Solid */
workbench_material_update_data(wpd, ob, mat, &material_template, color_type);
- material_template.object_id = OBJECT_ID_PASS_ENABLED(wpd) ? engine_object_data->object_id : 1;
material_template.color_type = color_type;
material_template.ima = ima;
material_template.iuser = iuser;
@@ -205,7 +202,7 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_
DRW_shgroup_uniform_float_copy(grp, "shadowFocus", wpd->shadow_focus);
}
- workbench_material_shgroup_uniform(wpd, grp, material, ob, false, false, interp);
+ workbench_material_shgroup_uniform(wpd, grp, material, ob, false, interp);
material->shgrp = grp;
/* Depth */
@@ -219,8 +216,6 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_
material->shgrp_object_outline = DRW_shgroup_create(sh_data->object_outline_sh,
psl->object_outline_pass);
}
- material->object_id = engine_object_data->object_id;
- DRW_shgroup_uniform_int(material->shgrp_object_outline, "object_id", &material->object_id, 1);
if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) {
DRW_shgroup_state_enable(material->shgrp_object_outline, DRW_STATE_CLIP_PLANES);
}
@@ -292,26 +287,30 @@ void workbench_forward_outline_shaders_ensure(WORKBENCH_PrivateData *wpd, eGPUSh
char *defines_texture = workbench_material_build_defines(wpd, true, false, false);
char *defines_hair = workbench_material_build_defines(wpd, false, true, false);
char *forward_vert = workbench_build_forward_vert(false);
+ char *forward_frag = workbench_build_forward_outline_frag();
char *forward_hair_vert = workbench_build_forward_vert(true);
+ const char *define_id_pass = "#define OBJECT_ID_PASS_ENABLED\n";
+
sh_data->object_outline_sh = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg_data->lib, forward_vert, NULL},
- .frag = (const char *[]){datatoc_workbench_forward_depth_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, defines, NULL},
+ .frag = (const char *[]){forward_frag, NULL},
+ .defs = (const char *[]){sh_cfg_data->def, defines, define_id_pass, NULL},
});
sh_data->object_outline_texture_sh = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg_data->lib, forward_vert, NULL},
- .frag = (const char *[]){datatoc_workbench_forward_depth_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, defines_texture, NULL},
+ .frag = (const char *[]){forward_frag, NULL},
+ .defs = (const char *[]){sh_cfg_data->def, defines_texture, define_id_pass, NULL},
});
sh_data->object_outline_hair_sh = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg_data->lib, forward_hair_vert, NULL},
- .frag = (const char *[]){datatoc_workbench_forward_depth_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, defines_hair, NULL},
+ .frag = (const char *[]){forward_frag, NULL},
+ .defs = (const char *[]){sh_cfg_data->def, defines_hair, define_id_pass, NULL},
});
MEM_freeN(forward_hair_vert);
MEM_freeN(forward_vert);
+ MEM_freeN(forward_frag);
MEM_freeN(defines);
MEM_freeN(defines_texture);
MEM_freeN(defines_hair);
@@ -527,7 +526,7 @@ static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, O
DRWShadingGroup *shgrp = DRW_shgroup_hair_create(
ob, psys, md, psl->transparent_accum_pass, shader);
DRW_shgroup_uniform_block(shgrp, "world_block", wpd->world_ubo);
- workbench_material_shgroup_uniform(wpd, shgrp, material, ob, false, false, interp);
+ workbench_material_shgroup_uniform(wpd, shgrp, material, ob, false, interp);
DRW_shgroup_uniform_vec4(shgrp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
/* Hairs have lots of layer and can rapidly become the most prominent surface.
* So lower their alpha artificially. */
@@ -551,7 +550,6 @@ static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, O
WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
shgrp = DRW_shgroup_hair_create(
ob, psys, md, vedata->psl->object_outline_pass, sh_data->object_outline_hair_sh);
- DRW_shgroup_uniform_int(shgrp, "object_id", &material->object_id, 1);
}
}
}
diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c
index e050877187e..c90604678db 100644
--- a/source/blender/draw/engines/workbench/workbench_materials.c
+++ b/source/blender/draw/engines/workbench/workbench_materials.c
@@ -44,20 +44,15 @@ void workbench_material_update_data(WORKBENCH_PrivateData *wpd,
WORKBENCH_MaterialData *data,
int color_type)
{
- copy_v3_fl3(data->diffuse_color, 0.8f, 0.8f, 0.8f);
- copy_v3_v3(data->base_color, data->diffuse_color);
- copy_v3_fl3(data->specular_color, 0.05f, 0.05f, 0.05f); /* Dielectric: 5% reflective. */
data->metallic = 0.0f;
data->roughness = 0.632455532f; /* sqrtf(0.4f); */
data->alpha = wpd->shading.xray_alpha;
if (color_type == V3D_SHADING_SINGLE_COLOR) {
- copy_v3_v3(data->diffuse_color, wpd->shading.single_color);
- copy_v3_v3(data->base_color, data->diffuse_color);
+ copy_v3_v3(data->base_color, wpd->shading.single_color);
}
else if (color_type == V3D_SHADING_ERROR_COLOR) {
- copy_v3_fl3(data->diffuse_color, 0.8, 0.0, 0.8);
- copy_v3_v3(data->base_color, data->diffuse_color);
+ copy_v3_fl3(data->base_color, 0.8, 0.0, 0.8);
}
else if (color_type == V3D_SHADING_RANDOM_COLOR) {
uint hash = BLI_ghashutil_strhash_p_murmur(ob->id.name);
@@ -67,30 +62,24 @@ void workbench_material_update_data(WORKBENCH_PrivateData *wpd,
float hue = BLI_hash_int_01(hash);
float hsv[3] = {hue, HSV_SATURATION, HSV_VALUE};
- hsv_to_rgb_v(hsv, data->diffuse_color);
- copy_v3_v3(data->base_color, data->diffuse_color);
+ hsv_to_rgb_v(hsv, data->base_color);
}
else if (ELEM(color_type, V3D_SHADING_OBJECT_COLOR, V3D_SHADING_VERTEX_COLOR)) {
- copy_v3_v3(data->diffuse_color, ob->color);
- copy_v3_v3(data->base_color, data->diffuse_color);
data->alpha *= ob->color[3];
+ copy_v3_v3(data->base_color, ob->color);
}
else {
/* V3D_SHADING_MATERIAL_COLOR or V3D_SHADING_TEXTURE_COLOR */
if (mat) {
data->alpha *= mat->a;
+ copy_v3_v3(data->base_color, &mat->r);
if (workbench_is_specular_highlight_enabled(wpd)) {
- copy_v3_v3(data->base_color, &mat->r);
- mul_v3_v3fl(data->diffuse_color, &mat->r, 1.0f - mat->metallic);
- mul_v3_v3fl(data->specular_color, &mat->r, mat->metallic);
- add_v3_fl(data->specular_color, 0.05f * (1.0f - mat->metallic));
data->metallic = mat->metallic;
data->roughness = sqrtf(mat->roughness); /* Remap to disney roughness. */
}
- else {
- copy_v3_v3(data->base_color, &mat->r);
- copy_v3_v3(data->diffuse_color, &mat->r);
- }
+ }
+ else {
+ copy_v3_fl(data->base_color, 0.8f);
}
}
}
@@ -160,34 +149,40 @@ char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd,
return str;
}
-uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template, bool is_ghost)
+uint workbench_material_get_hash(WORKBENCH_MaterialData *mat, bool is_ghost)
{
- uint input[4];
- uint result;
- float *color = material_template->diffuse_color;
- input[0] = (uint)(color[0] * 512);
- input[1] = (uint)(color[1] * 512);
- input[2] = (uint)(color[2] * 512);
- input[3] = material_template->object_id;
- result = BLI_ghashutil_uinthash_v4_murmur(input);
-
- color = material_template->specular_color;
- input[0] = (uint)(color[0] * 512);
- input[1] = (uint)(color[1] * 512);
- input[2] = (uint)(color[2] * 512);
- input[3] = (uint)(material_template->roughness * 512);
- result += BLI_ghashutil_uinthash_v4_murmur(input);
-
- result += BLI_ghashutil_uinthash((uint)(material_template->alpha * 512));
- result += BLI_ghashutil_uinthash((uint)is_ghost);
- result += BLI_ghashutil_uinthash(material_template->color_type);
-
- /* add texture reference */
- if (material_template->ima) {
- result += BLI_ghashutil_inthash_p_murmur(material_template->ima);
- }
-
- return result;
+ union {
+ struct {
+ /* WHATCH: Keep in sync with View3DShading.color_type max value. */
+ uchar color_type;
+ uchar diff_r;
+ uchar diff_g;
+ uchar diff_b;
+
+ uchar alpha;
+ uchar ghost;
+ uchar metal;
+ uchar roughness;
+
+ void *ima;
+ };
+ /* HACK to ensure input is 4 uint long. */
+ uint a[4];
+ } input = {.color_type = (uchar)(mat->color_type),
+ .diff_r = (uchar)(mat->base_color[0] * 0xFF),
+ .diff_g = (uchar)(mat->base_color[1] * 0xFF),
+ .diff_b = (uchar)(mat->base_color[2] * 0xFF),
+
+ .alpha = (uint)(mat->alpha * 0xFF),
+ .ghost = (uchar)is_ghost,
+ .metal = (uchar)(mat->metallic * 0xFF),
+ .roughness = (uchar)(mat->roughness * 0xFF),
+
+ .ima = mat->ima};
+
+ BLI_assert(sizeof(input) == sizeof(uint) * 4);
+
+ return BLI_ghashutil_uinthash_v4((uint *)&input);
}
int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd)
@@ -315,35 +310,28 @@ void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
DRWShadingGroup *grp,
WORKBENCH_MaterialData *material,
Object *ob,
- const bool use_metallic,
const bool deferred,
const int interp)
{
- if (!deferred || workbench_is_matdata_pass_enabled(wpd)) {
- if (workbench_material_determine_color_type(wpd, material->ima, ob, false) ==
- V3D_SHADING_TEXTURE_COLOR) {
- GPUTexture *tex = GPU_texture_from_blender(material->ima, material->iuser, GL_TEXTURE_2D);
- DRW_shgroup_uniform_texture(grp, "image", tex);
- DRW_shgroup_uniform_bool_copy(
- grp, "imagePremultiplied", (material->ima->alpha_mode == IMA_ALPHA_PREMUL));
- DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST));
- }
- else {
- DRW_shgroup_uniform_vec3(grp,
- "materialDiffuseColor",
- (use_metallic) ? material->base_color : material->diffuse_color,
- 1);
- }
+ if (!(!deferred || workbench_is_matdata_pass_enabled(wpd))) {
+ return;
+ }
- if (workbench_is_specular_highlight_enabled(wpd)) {
- if (use_metallic) {
- DRW_shgroup_uniform_float(grp, "materialMetallic", &material->metallic, 1);
- }
- else {
- DRW_shgroup_uniform_vec3(grp, "materialSpecularColor", material->specular_color, 1);
- }
- DRW_shgroup_uniform_float(grp, "materialRoughness", &material->roughness, 1);
- }
+ const bool use_highlight = workbench_is_specular_highlight_enabled(wpd);
+ const bool use_texture = (V3D_SHADING_TEXTURE_COLOR == workbench_material_determine_color_type(
+ wpd, material->ima, ob, false));
+ if (use_texture) {
+ GPUTexture *tex = GPU_texture_from_blender(material->ima, material->iuser, GL_TEXTURE_2D);
+ DRW_shgroup_uniform_texture(grp, "image", tex);
+ DRW_shgroup_uniform_bool_copy(
+ grp, "imagePremultiplied", (material->ima->alpha_mode == IMA_ALPHA_PREMUL));
+ DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST));
+ }
+
+ DRW_shgroup_uniform_vec4(grp, "materialColorAndMetal", material->base_color, 1);
+
+ if (use_highlight) {
+ DRW_shgroup_uniform_float(grp, "materialRoughness", &material->roughness, 1);
}
if (WORLD_CLIPPING_ENABLED(wpd)) {
@@ -354,10 +342,7 @@ void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
void workbench_material_copy(WORKBENCH_MaterialData *dest_material,
const WORKBENCH_MaterialData *source_material)
{
- dest_material->object_id = source_material->object_id;
copy_v3_v3(dest_material->base_color, source_material->base_color);
- copy_v3_v3(dest_material->diffuse_color, source_material->diffuse_color);
- copy_v3_v3(dest_material->specular_color, source_material->specular_color);
dest_material->metallic = source_material->metallic;
dest_material->roughness = source_material->roughness;
dest_material->ima = source_material->ima;
diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h
index d880d5d58b5..f51da581827 100644
--- a/source/blender/draw/engines/workbench/workbench_private.h
+++ b/source/blender/draw/engines/workbench/workbench_private.h
@@ -281,13 +281,8 @@ typedef struct WORKBENCH_EffectInfo {
} WORKBENCH_EffectInfo;
typedef struct WORKBENCH_MaterialData {
- float base_color[3];
- float diffuse_color[3];
- float specular_color[3];
- float alpha;
- float metallic;
- float roughness;
- int object_id;
+ float base_color[3], metallic;
+ float roughness, alpha;
int color_type;
int interp;
Image *ima;
@@ -308,8 +303,6 @@ typedef struct WORKBENCH_ObjectData {
float shadow_min[3], shadow_max[3];
BoundBox shadow_bbox;
bool shadow_bbox_dirty;
-
- int object_id;
} WORKBENCH_ObjectData;
/* inline helper functions */
@@ -500,7 +493,6 @@ void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
DRWShadingGroup *grp,
WORKBENCH_MaterialData *material,
Object *ob,
- const bool use_metallic,
const bool deferred,
const int interp);
void workbench_material_copy(WORKBENCH_MaterialData *dest_material,
diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c
index 7ae9d90daff..e017661b6cd 100644
--- a/source/blender/draw/engines/workbench/workbench_volume.c
+++ b/source/blender/draw/engines/workbench/workbench_volume.c
@@ -27,6 +27,7 @@
#include "BLI_rand.h"
#include "BLI_dynstr.h"
+#include "BLI_string_utils.h"
#include "DNA_modifier_types.h"
#include "DNA_object_force_types.h"
@@ -54,6 +55,7 @@ static struct {
extern char datatoc_workbench_volume_vert_glsl[];
extern char datatoc_workbench_volume_frag_glsl[];
extern char datatoc_common_view_lib_glsl[];
+extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
static GPUShader *volume_shader_get(bool slice, bool coba, bool cubic)
{
@@ -78,12 +80,16 @@ static GPUShader *volume_shader_get(bool slice, bool coba, bool cubic)
char *defines = BLI_dynstr_get_cstring(ds);
BLI_dynstr_free(ds);
+ char *libs = BLI_string_joinN(datatoc_common_view_lib_glsl,
+ datatoc_gpu_shader_common_obinfos_lib_glsl);
+
e_data.volume_sh[id] = DRW_shader_create_with_lib(datatoc_workbench_volume_vert_glsl,
NULL,
datatoc_workbench_volume_frag_glsl,
- datatoc_common_view_lib_glsl,
+ libs,
defines);
+ MEM_freeN(libs);
MEM_freeN(defines);
}
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index e3713fdee8f..935920310dd 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -80,8 +80,6 @@ typedef struct DRWPass DRWPass;
typedef struct DRWShadingGroup DRWShadingGroup;
typedef struct DRWUniform DRWUniform;
typedef struct DRWView DRWView;
-
-/* Opaque type to avoid usage as a DRWCall but it is exactly the same thing. */
typedef struct DRWCallBuffer DRWCallBuffer;
/* TODO Put it somewhere else? */
@@ -404,35 +402,29 @@ void DRW_shgroup_call_ex(DRWShadingGroup *shgroup,
Object *ob,
float (*obmat)[4],
struct GPUBatch *geom,
- uint v_sta,
- uint v_ct,
bool bypass_culling,
void *user_data);
/* If ob is NULL, unit modelmatrix is assumed and culling is bypassed. */
-#define DRW_shgroup_call(shgrp, geom, ob) \
- DRW_shgroup_call_ex(shgrp, ob, NULL, geom, 0, 0, false, NULL)
+#define DRW_shgroup_call(shgrp, geom, ob) DRW_shgroup_call_ex(shgrp, ob, NULL, geom, false, NULL)
/* Same as DRW_shgroup_call but override the obmat. Not culled. */
#define DRW_shgroup_call_obmat(shgrp, geom, obmat) \
- DRW_shgroup_call_ex(shgrp, NULL, obmat, geom, 0, 0, false, NULL)
+ DRW_shgroup_call_ex(shgrp, NULL, obmat, geom, false, NULL)
/* TODO(fclem) remove this when we have DRWView */
/* user_data is used by DRWCallVisibilityFn defined in DRWView. */
#define DRW_shgroup_call_with_callback(shgrp, geom, ob, user_data) \
- DRW_shgroup_call_ex(shgrp, ob, NULL, geom, 0, 0, false, user_data)
+ DRW_shgroup_call_ex(shgrp, ob, NULL, geom, false, user_data)
/* Same as DRW_shgroup_call but bypass culling even if ob is not NULL. */
#define DRW_shgroup_call_no_cull(shgrp, geom, ob) \
- DRW_shgroup_call_ex(shgrp, ob, NULL, geom, 0, 0, true, NULL)
-
-/* Only draw a certain range of geom. */
-#define DRW_shgroup_call_range(shgrp, geom, ob, v_sta, v_ct) \
- DRW_shgroup_call_ex(shgrp, ob, NULL, geom, v_sta, v_ct, false, NULL)
+ DRW_shgroup_call_ex(shgrp, ob, NULL, geom, true, NULL)
-/* Same as DRW_shgroup_call_range but override the obmat. Special for gpencil. */
-#define DRW_shgroup_call_range_obmat(shgrp, geom, obmat, v_sta, v_ct) \
- DRW_shgroup_call_ex(shgrp, NULL, obmat, geom, v_sta, v_ct, false, NULL)
+void DRW_shgroup_call_range(DRWShadingGroup *shgroup,
+ struct GPUBatch *geom,
+ uint v_sta,
+ uint v_ct);
void DRW_shgroup_call_procedural_points(DRWShadingGroup *sh, Object *ob, uint point_ct);
void DRW_shgroup_call_procedural_lines(DRWShadingGroup *sh, Object *ob, uint line_ct);
@@ -469,6 +461,16 @@ void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state);
void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state);
void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask);
+/* Issue a clear command. */
+void DRW_shgroup_clear_framebuffer(DRWShadingGroup *shgroup,
+ eGPUFrameBufferBits channels,
+ uchar r,
+ uchar g,
+ uchar b,
+ uchar a,
+ float depth,
+ uchar stencil);
+
void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup,
const char *name,
const struct GPUTexture *tex);
@@ -525,17 +527,17 @@ void DRW_shgroup_uniform_mat3(DRWShadingGroup *shgroup, const char *name, const
void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const float (*value)[4]);
/* Store value instead of referencing it. */
void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, const int value);
+void DRW_shgroup_uniform_ivec2_copy(DRWShadingGroup *shgrp, const char *name, const int *value);
+void DRW_shgroup_uniform_ivec3_copy(DRWShadingGroup *shgrp, const char *name, const int *value);
+void DRW_shgroup_uniform_ivec4_copy(DRWShadingGroup *shgrp, const char *name, const int *value);
void DRW_shgroup_uniform_bool_copy(DRWShadingGroup *shgroup, const char *name, const bool value);
void DRW_shgroup_uniform_float_copy(DRWShadingGroup *shgroup, const char *name, const float value);
void DRW_shgroup_uniform_vec2_copy(DRWShadingGroup *shgroup, const char *name, const float *value);
+void DRW_shgroup_uniform_vec3_copy(DRWShadingGroup *shgroup, const char *name, const float *value);
+void DRW_shgroup_uniform_vec4_copy(DRWShadingGroup *shgroup, const char *name, const float *value);
bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup);
-/* TODO: workaround functions waiting for the clearing operation to be available inside the
- * shgroups. */
-DRWShadingGroup *DRW_shgroup_get_next(DRWShadingGroup *shgroup);
-uint DRW_shgroup_stencil_mask_get(DRWShadingGroup *shgroup);
-
/* Passes */
DRWPass *DRW_pass_create(const char *name, DRWState state);
/* TODO Replace with passes inheritance. */
diff --git a/source/blender/draw/intern/draw_anim_viz.c b/source/blender/draw/intern/draw_anim_viz.c
index 72459309133..2d71fdf0782 100644
--- a/source/blender/draw/intern/draw_anim_viz.c
+++ b/source/blender/draw/intern/draw_anim_viz.c
@@ -215,7 +215,7 @@ static void MPATH_cache_motion_path(MPATH_PassList *psl,
DRW_shgroup_uniform_vec3(shgrp, "customColor", mpath->color, 1);
}
/* Only draw the required range. */
- DRW_shgroup_call_range(shgrp, mpath_batch_line_get(mpath), NULL, start_index, len);
+ DRW_shgroup_call_range(shgrp, mpath_batch_line_get(mpath), start_index, len);
}
/* Draw points. */
@@ -231,7 +231,7 @@ static void MPATH_cache_motion_path(MPATH_PassList *psl,
DRW_shgroup_uniform_vec3(shgrp, "customColor", mpath->color, 1);
}
/* Only draw the required range. */
- DRW_shgroup_call_range(shgrp, mpath_batch_points_get(mpath), NULL, start_index, len);
+ DRW_shgroup_call_range(shgrp, mpath_batch_points_get(mpath), start_index, len);
/* Draw frame numbers at each framestep value */
bool show_kf_no = (avs->path_viewflag & MOTIONPATH_VIEW_KFNOS) != 0;
diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c
index 8e0f713add6..7f679dd5581 100644
--- a/source/blender/draw/intern/draw_common.c
+++ b/source/blender/draw/intern/draw_common.c
@@ -1095,7 +1095,7 @@ struct GPUShader *volume_velocity_shader_get(bool use_needle)
NULL,
datatoc_gpu_shader_flat_color_frag_glsl,
datatoc_common_view_lib_glsl,
- "#define USE_NEEDLE");
+ "#define USE_NEEDLE\n");
}
return sh_data->volume_velocity_needle_sh;
}
diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c
index f77243ca9f1..58085cf08c6 100644
--- a/source/blender/draw/intern/draw_hair.c
+++ b/source/blender/draw/intern/draw_hair.c
@@ -201,30 +201,33 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object,
/* Transform Feedback subdiv. */
if (need_ft_update) {
int final_points_len = hair_cache->final[subdiv].strands_res * hair_cache->strands_len;
- GPUShader *tf_shader = hair_refine_shader_get(PART_REFINE_CATMULL_ROM);
+ if (final_points_len) {
+ GPUShader *tf_shader = hair_refine_shader_get(PART_REFINE_CATMULL_ROM);
#ifdef USE_TRANSFORM_FEEDBACK
- DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create(
- tf_shader, g_tf_pass, hair_cache->final[subdiv].proc_buf);
+ DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create(
+ tf_shader, g_tf_pass, hair_cache->final[subdiv].proc_buf);
#else
- DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass);
-
- ParticleRefineCall *pr_call = MEM_mallocN(sizeof(*pr_call), __func__);
- pr_call->next = g_tf_calls;
- pr_call->vbo = hair_cache->final[subdiv].proc_buf;
- pr_call->shgrp = tf_shgrp;
- pr_call->vert_len = final_points_len;
- g_tf_calls = pr_call;
- DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1);
- DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1);
- DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1);
+ DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass);
+
+ ParticleRefineCall *pr_call = MEM_mallocN(sizeof(*pr_call), __func__);
+ pr_call->next = g_tf_calls;
+ pr_call->vbo = hair_cache->final[subdiv].proc_buf;
+ pr_call->shgrp = tf_shgrp;
+ pr_call->vert_len = final_points_len;
+ g_tf_calls = pr_call;
+ DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1);
+ DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1);
+ DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1);
#endif
- DRW_shgroup_uniform_texture(tf_shgrp, "hairPointBuffer", hair_cache->point_tex);
- DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandBuffer", hair_cache->strand_tex);
- DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandSegBuffer", hair_cache->strand_seg_tex);
- DRW_shgroup_uniform_int(tf_shgrp, "hairStrandsRes", &hair_cache->final[subdiv].strands_res, 1);
- DRW_shgroup_call_procedural_points(tf_shgrp, NULL, final_points_len);
+ DRW_shgroup_uniform_texture(tf_shgrp, "hairPointBuffer", hair_cache->point_tex);
+ DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandBuffer", hair_cache->strand_tex);
+ DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandSegBuffer", hair_cache->strand_seg_tex);
+ DRW_shgroup_uniform_int(
+ tf_shgrp, "hairStrandsRes", &hair_cache->final[subdiv].strands_res, 1);
+ DRW_shgroup_call_procedural_points(tf_shgrp, NULL, final_points_len);
+ }
}
return shgrp;
diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c
index 69756203d66..81b10e095c3 100644
--- a/source/blender/draw/intern/draw_instance_data.c
+++ b/source/blender/draw/intern/draw_instance_data.c
@@ -64,7 +64,7 @@ typedef struct DRWTempBufferHandle {
/** Format pointer for reuse. */
GPUVertFormat *format;
/** Touched vertex length for resize. */
- uint *vert_len;
+ int *vert_len;
} DRWTempBufferHandle;
static ListBase g_idatalists = {NULL, NULL};
@@ -112,7 +112,7 @@ static void instance_batch_free(GPUBatch *geom, void *UNUSED(user_data))
*/
GPUVertBuf *DRW_temp_buffer_request(DRWInstanceDataList *idatalist,
GPUVertFormat *format,
- uint *vert_len)
+ int *vert_len)
{
BLI_assert(format != NULL);
BLI_assert(vert_len != NULL);
diff --git a/source/blender/draw/intern/draw_instance_data.h b/source/blender/draw/intern/draw_instance_data.h
index 2ede68e16d8..524c4cd96d8 100644
--- a/source/blender/draw/intern/draw_instance_data.h
+++ b/source/blender/draw/intern/draw_instance_data.h
@@ -40,7 +40,7 @@ DRWInstanceData *DRW_instance_data_request(DRWInstanceDataList *idatalist, uint
GPUVertBuf *DRW_temp_buffer_request(DRWInstanceDataList *idatalist,
GPUVertFormat *format,
- uint *vert_len);
+ int *vert_len);
GPUBatch *DRW_temp_batch_instance_request(DRWInstanceDataList *idatalist,
GPUVertBuf *buf,
GPUBatch *geom);
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index fde7fdfa222..66e3905b212 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -537,8 +537,11 @@ static void drw_viewport_cache_resize(void)
GPU_texture_free(*tex);
}
- BLI_memblock_clear(DST.vmempool->calls, NULL);
- BLI_memblock_clear(DST.vmempool->states, NULL);
+ BLI_memblock_clear(DST.vmempool->commands, NULL);
+ BLI_memblock_clear(DST.vmempool->commands_small, NULL);
+ BLI_memblock_clear(DST.vmempool->callbuffers, NULL);
+ BLI_memblock_clear(DST.vmempool->obmats, NULL);
+ BLI_memblock_clear(DST.vmempool->obinfos, NULL);
BLI_memblock_clear(DST.vmempool->cullstates, NULL);
BLI_memblock_clear(DST.vmempool->shgroups, NULL);
BLI_memblock_clear(DST.vmempool->uniforms, NULL);
@@ -586,28 +589,28 @@ static void drw_context_state_init(void)
}
}
-static DRWCallState *draw_unit_state_create(void)
+static void draw_unit_state_create(void)
{
- DRWCallState *state = BLI_memblock_alloc(DST.vmempool->states);
- state->flag = 0;
- state->matflag = 0;
+ DRWObjectInfos *infos = BLI_memblock_alloc(DST.vmempool->obinfos);
+ DRWObjectMatrix *mats = BLI_memblock_alloc(DST.vmempool->obmats);
+ DRWCullingState *culling = BLI_memblock_alloc(DST.vmempool->cullstates);
- unit_m4(state->model);
- unit_m4(state->modelinverse);
+ unit_m4(mats->model);
+ unit_m4(mats->modelinverse);
- copy_v3_fl(state->orcotexfac[0], 0.0f);
- copy_v3_fl(state->orcotexfac[1], 1.0f);
+ copy_v3_fl(infos->orcotexfac[0], 0.0f);
+ copy_v3_fl(infos->orcotexfac[1], 1.0f);
- state->ob_index = 0;
- state->ob_random = 0.0f;
- copy_v3_fl(state->ob_color, 1.0f);
+ infos->ob_index = 0;
+ infos->ob_random = 0.0f;
+ infos->ob_neg_scale = 1.0f;
+ copy_v3_fl(infos->ob_color, 1.0f);
/* TODO(fclem) get rid of this. */
- state->culling = BLI_memblock_alloc(DST.vmempool->cullstates);
- state->culling->bsphere.radius = -1.0f;
- state->culling->user_data = NULL;
+ culling->bsphere.radius = -1.0f;
+ culling->user_data = NULL;
- return state;
+ DRW_handle_increment(&DST.resource_handle);
}
/* It also stores viewport variable to an immutable place: DST
@@ -632,33 +635,48 @@ static void drw_viewport_var_init(void)
DST.vmempool = GPU_viewport_mempool_get(DST.viewport);
- if (DST.vmempool->calls == NULL) {
- DST.vmempool->calls = BLI_memblock_create(sizeof(DRWCall));
+ if (DST.vmempool->commands == NULL) {
+ DST.vmempool->commands = BLI_memblock_create(sizeof(DRWCommandChunk));
}
- if (DST.vmempool->states == NULL) {
- DST.vmempool->states = BLI_memblock_create(sizeof(DRWCallState));
+ if (DST.vmempool->commands_small == NULL) {
+ DST.vmempool->commands_small = BLI_memblock_create(sizeof(DRWCommandSmallChunk));
+ }
+ if (DST.vmempool->callbuffers == NULL) {
+ DST.vmempool->callbuffers = BLI_memblock_create(sizeof(DRWCallBuffer));
+ }
+ if (DST.vmempool->obmats == NULL) {
+ uint chunk_len = sizeof(DRWObjectMatrix) * DRW_RESOURCE_CHUNK_LEN;
+ DST.vmempool->obmats = BLI_memblock_create_ex(sizeof(DRWObjectMatrix), chunk_len);
+ }
+ if (DST.vmempool->obinfos == NULL) {
+ uint chunk_len = sizeof(DRWObjectInfos) * DRW_RESOURCE_CHUNK_LEN;
+ DST.vmempool->obinfos = BLI_memblock_create_ex(sizeof(DRWObjectInfos), chunk_len);
}
if (DST.vmempool->cullstates == NULL) {
- DST.vmempool->cullstates = BLI_memblock_create(sizeof(DRWCullingState));
+ uint chunk_len = sizeof(DRWCullingState) * DRW_RESOURCE_CHUNK_LEN;
+ DST.vmempool->cullstates = BLI_memblock_create_ex(sizeof(DRWCullingState), chunk_len);
}
if (DST.vmempool->shgroups == NULL) {
DST.vmempool->shgroups = BLI_memblock_create(sizeof(DRWShadingGroup));
}
if (DST.vmempool->uniforms == NULL) {
- DST.vmempool->uniforms = BLI_memblock_create(sizeof(DRWUniform));
+ DST.vmempool->uniforms = BLI_memblock_create(sizeof(DRWUniformChunk));
}
if (DST.vmempool->views == NULL) {
DST.vmempool->views = BLI_memblock_create(sizeof(DRWView));
}
if (DST.vmempool->passes == NULL) {
- DST.vmempool->passes = BLI_memblock_create(sizeof(DRWPass));
+ uint chunk_len = sizeof(DRWPass) * DRW_RESOURCE_CHUNK_LEN;
+ DST.vmempool->passes = BLI_memblock_create_ex(sizeof(DRWPass), chunk_len);
}
if (DST.vmempool->images == NULL) {
DST.vmempool->images = BLI_memblock_create(sizeof(GPUTexture *));
}
- /* Alloc default unit state */
- DST.unit_state = draw_unit_state_create();
+ DST.resource_handle = 0;
+ DST.pass_handle = 0;
+
+ draw_unit_state_create();
DST.idatalist = GPU_viewport_instance_data_list_get(DST.viewport);
DRW_instance_data_list_reset(DST.idatalist);
@@ -672,8 +690,6 @@ static void drw_viewport_var_init(void)
DST.default_framebuffer = NULL;
DST.vmempool = NULL;
-
- DST.unit_state = NULL;
}
DST.primary_view_ct = 0;
@@ -716,6 +732,10 @@ static void drw_viewport_var_init(void)
G_draw.view_ubo = DRW_uniformbuffer_create(sizeof(DRWViewUboStorage), NULL);
}
+ if (DST.draw_list == NULL) {
+ DST.draw_list = GPU_draw_list_create(DRW_DRAWLIST_LEN);
+ }
+
memset(DST.object_instance_data, 0x0, sizeof(DST.object_instance_data));
}
@@ -1099,7 +1119,7 @@ static void drw_engines_world_update(Scene *scene)
static void drw_engines_cache_populate(Object *ob)
{
- DST.ob_state = NULL;
+ DST.ob_handle = 0;
/* HACK: DrawData is copied by COW from the duplicated object.
* This is valid for IDs that cannot be instantiated but this
@@ -1917,6 +1937,8 @@ void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph
RenderResult *render_result = RE_engine_get_result(engine);
RenderLayer *render_layer = RE_GetRenderLayer(render_result, view_layer->name);
+ DST.buffer_finish_called = false;
+
DRW_render_gpencil_to_image(engine, render_layer, &render_rect);
/* Force cache to reset. */
@@ -2027,13 +2049,15 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph)
RE_SetActiveRenderView(render, render_view->name);
drw_view_reset();
engine_type->draw_engine->render_to_image(data, engine, render_layer, &render_rect);
+ DST.buffer_finish_called = false;
+
/* grease pencil: render result is merged in the previous render result. */
if (DRW_render_check_grease_pencil(depsgraph)) {
DRW_state_reset();
drw_view_reset();
DRW_render_gpencil_to_image(engine, render_layer, &render_rect);
+ DST.buffer_finish_called = false;
}
- DST.buffer_finish_called = false;
}
RE_engine_end_result(engine, render_result, false, false, false);
@@ -2079,7 +2103,7 @@ void DRW_render_object_iter(
if ((object_type_exclude_viewport & (1 << ob->type)) == 0) {
DST.dupli_parent = data_.dupli_parent;
DST.dupli_source = data_.dupli_object_current;
- DST.ob_state = NULL;
+ DST.ob_handle = 0;
drw_duplidata_load(DST.dupli_source);
if (!DST.dupli_source) {
@@ -2186,6 +2210,7 @@ void DRW_render_instance_buffer_finish(void)
BLI_assert(!DST.buffer_finish_called && "DRW_render_instance_buffer_finish called twice!");
DST.buffer_finish_called = true;
DRW_instance_buffer_finish(DST.idatalist);
+ drw_resource_buffer_finish(DST.vmempool);
}
/**
@@ -2209,7 +2234,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
Object *obact = OBACT(view_layer);
Object *obedit = OBEDIT_FROM_OBACT(obact);
#ifndef USE_GPU_SELECT
- UNUSED_VARS(vc, scene, view_layer, v3d, ar, rect);
+ UNUSED_VARS(scene, view_layer, v3d, ar, rect);
#else
RegionView3D *rv3d = ar->regiondata;
@@ -2934,6 +2959,10 @@ void DRW_engines_free(void)
MEM_SAFE_FREE(DST.uniform_names.buffer);
+ if (DST.draw_list) {
+ GPU_draw_list_discard(DST.draw_list);
+ }
+
DRW_opengl_context_disable();
}
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index 85f6cf05e83..b55a84b2765 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -28,8 +28,10 @@
#include "DRW_engine.h"
#include "DRW_render.h"
+#include "BLI_assert.h"
#include "BLI_linklist.h"
#include "BLI_threads.h"
+#include "BLI_memblock.h"
#include "GPU_batch.h"
#include "GPU_context.h"
@@ -43,6 +45,9 @@
/* Use draw manager to call GPU_select, see: DRW_draw_select_loop */
#define USE_GPU_SELECT
+/* Use drawcall batching using instanced rendering. */
+#define USE_BATCHING 1
+
// #define DRW_DEBUG_CULLING
#define DRW_DEBUG_USE_UNIFORM_NAME 0
#define DRW_UNIFORM_BUFFER_NAME 64
@@ -90,20 +95,6 @@
* > DRWUniform
*/
-/* Used by DRWCallState.flag */
-enum {
- DRW_CALL_NEGSCALE = (1 << 1),
-};
-
-/* Used by DRWCallState.matflag */
-enum {
- DRW_CALL_MODELINVERSE = (1 << 0),
- DRW_CALL_MODELVIEWPROJECTION = (1 << 1),
- DRW_CALL_ORCOTEXFAC = (1 << 2),
- DRW_CALL_OBJECTINFO = (1 << 3),
- DRW_CALL_OBJECTCOLOR = (1 << 4),
-};
-
typedef struct DRWCullingState {
uint32_t mask;
/* Culling: Using Bounding Sphere for now for faster culling.
@@ -113,38 +104,161 @@ typedef struct DRWCullingState {
void *user_data;
} DRWCullingState;
-typedef struct DRWCallState {
- DRWCullingState *culling;
- uchar flag;
- uchar matflag; /* Which matrices to compute. */
- short ob_index;
- /* Matrices */
+/* Minimum max UBO size is 64KiB. We take the largest
+ * UBO struct and alloc the max number.
+ * ((1 << 16) / sizeof(DRWObjectMatrix)) = 512
+ * Keep in sync with common_view_lib.glsl */
+#define DRW_RESOURCE_CHUNK_LEN 512
+
+/**
+ * Identifier used to sort similar drawcalls together.
+ * Also used to reference elements inside memory blocks.
+ *
+ * From MSB to LSB
+ * 1 bit for negative scale.
+ * 22 bits for chunk id.
+ * 9 bits for resource id inside the chunk. (can go up to 511)
+ * |-|----------------------|---------|
+ *
+ * Use manual bitsift and mask instead of bitfields to avoid
+ * compiler dependant behavior that would mess the ordering of
+ * the members thus changing the sorting order.
+ */
+typedef uint32_t DRWResourceHandle;
+
+BLI_INLINE uint32_t DRW_handle_negative_scale_get(const DRWResourceHandle *handle)
+{
+ return (*handle & 0x80000000) != 0;
+}
+
+BLI_INLINE uint32_t DRW_handle_chunk_get(const DRWResourceHandle *handle)
+{
+ return (*handle & 0x7FFFFFFF) >> 9;
+}
+
+BLI_INLINE uint32_t DRW_handle_id_get(const DRWResourceHandle *handle)
+{
+ return (*handle & 0x000001FF);
+}
+
+BLI_INLINE void DRW_handle_increment(DRWResourceHandle *handle)
+{
+ *handle += 1;
+}
+
+BLI_INLINE void DRW_handle_negative_scale_enable(DRWResourceHandle *handle)
+{
+ *handle |= 0x80000000;
+}
+
+BLI_INLINE void *DRW_memblock_elem_from_handle(struct BLI_memblock *memblock,
+ const DRWResourceHandle *handle)
+{
+ int elem = DRW_handle_id_get(handle);
+ int chunk = DRW_handle_chunk_get(handle);
+ return BLI_memblock_elem_get(memblock, chunk, elem);
+}
+
+typedef struct DRWObjectMatrix {
float model[4][4];
float modelinverse[4][4];
- float orcotexfac[2][3];
- float ob_random;
+} DRWObjectMatrix;
+
+typedef struct DRWObjectInfos {
+ float orcotexfac[2][4];
float ob_color[4];
-} DRWCallState;
+ float ob_index;
+ float pad; /* UNUSED*/
+ float ob_random;
+ float ob_neg_scale;
+} DRWObjectInfos;
+
+BLI_STATIC_ASSERT_ALIGN(DRWObjectMatrix, 16)
+BLI_STATIC_ASSERT_ALIGN(DRWObjectInfos, 16)
-typedef struct DRWCall {
- struct DRWCall *next;
- DRWCallState *state;
+typedef enum {
+ /* Draw Commands */
+ DRW_CMD_DRAW = 0, /* Only sortable type. Must be 0. */
+ DRW_CMD_DRAW_RANGE = 1,
+ DRW_CMD_DRAW_INSTANCE = 2,
+ DRW_CMD_DRAW_PROCEDURAL = 3,
+ /* Other Commands */
+ DRW_CMD_CLEAR = 12,
+ DRW_CMD_DRWSTATE = 13,
+ DRW_CMD_STENCIL = 14,
+ DRW_CMD_SELECTID = 15,
+ /* Needs to fit in 4bits */
+} eDRWCommandType;
+
+#define DRW_MAX_DRAW_CMD_TYPE DRW_CMD_DRAW_PROCEDURAL
+
+typedef struct DRWCommandDraw {
+ GPUBatch *batch;
+ DRWResourceHandle handle;
+} DRWCommandDraw;
+/* Assume DRWResourceHandle to be 0. */
+typedef struct DRWCommandDrawRange {
GPUBatch *batch;
uint vert_first;
uint vert_count;
+} DRWCommandDrawRange;
+
+typedef struct DRWCommandDrawInstance {
+ GPUBatch *batch;
+ DRWResourceHandle handle;
uint inst_count;
+} DRWCommandDrawInstance;
-#ifdef USE_GPU_SELECT
- /* TODO(fclem) remove once we have a dedicated selection engine. */
- int select_id;
- GPUVertBuf *inst_selectid;
-#endif
-} DRWCall;
+typedef struct DRWCommandDrawProcedural {
+ GPUBatch *batch;
+ DRWResourceHandle handle;
+ uint vert_count;
+} DRWCommandDrawProcedural;
+
+typedef struct DRWCommandSetMutableState {
+ /** State changes (or'd or and'd with the pass's state) */
+ DRWState enable;
+ DRWState disable;
+} DRWCommandSetMutableState;
+
+typedef struct DRWCommandSetStencil {
+ uint mask;
+} DRWCommandSetStencil;
+
+typedef struct DRWCommandSetSelectID {
+ GPUVertBuf *select_buf;
+ uint select_id;
+} DRWCommandSetSelectID;
+
+typedef struct DRWCommandClear {
+ eGPUFrameBufferBits clear_channels;
+ uchar r, g, b, a; /* [0..1] for each channels. Normalized. */
+ float depth; /* [0..1] for depth. Normalized. */
+ uchar stencil; /* Stencil value [0..255] */
+} DRWCommandClear;
+
+typedef union DRWCommand {
+ DRWCommandDraw draw;
+ DRWCommandDrawRange range;
+ DRWCommandDrawInstance instance;
+ DRWCommandDrawProcedural procedural;
+ DRWCommandSetMutableState state;
+ DRWCommandSetStencil stencil;
+ DRWCommandSetSelectID select_id;
+ DRWCommandClear clear;
+} DRWCommand;
+
+/* Used for agregating calls into GPUVertBufs. */
+struct DRWCallBuffer {
+ GPUVertBuf *buf;
+ GPUVertBuf *buf_select;
+ int count;
+};
/* Used by DRWUniform.type */
typedef enum {
- DRW_UNIFORM_INT,
+ DRW_UNIFORM_INT = 0,
DRW_UNIFORM_INT_COPY,
DRW_UNIFORM_FLOAT,
DRW_UNIFORM_FLOAT_COPY,
@@ -153,55 +267,56 @@ typedef enum {
DRW_UNIFORM_TEXTURE_REF,
DRW_UNIFORM_BLOCK,
DRW_UNIFORM_BLOCK_PERSIST,
+ DRW_UNIFORM_TFEEDBACK_TARGET,
+ /** Per drawcall uniforms/UBO */
+ DRW_UNIFORM_BLOCK_OBMATS,
+ DRW_UNIFORM_BLOCK_OBINFOS,
+ DRW_UNIFORM_RESOURCE_CHUNK,
+ /** Legacy / Fallback */
+ DRW_UNIFORM_BASE_INSTANCE,
+ DRW_UNIFORM_MODEL_MATRIX,
+ DRW_UNIFORM_MODEL_MATRIX_INVERSE,
+ DRW_UNIFORM_MODELVIEWPROJECTION_MATRIX,
+ /* WARNING: set DRWUniform->type
+ * bit length accordingly. */
} DRWUniformType;
struct DRWUniform {
- DRWUniform *next; /* single-linked list */
union {
/* For reference or array/vector types. */
const void *pvalue;
/* Single values. */
- float fvalue[2];
- int ivalue[2];
+ float fvalue[4];
+ int ivalue[4];
};
- int name_ofs; /* name offset in name buffer. */
int location;
- char type; /* DRWUniformType */
- char length; /* cannot be more than 16 */
- char arraysize; /* cannot be more than 16 too */
+ uint32_t type : 5; /* DRWUniformType */
+ uint32_t length : 5; /* cannot be more than 16 */
+ uint32_t arraysize : 5; /* cannot be more than 16 too */
+ uint32_t name_ofs : 17; /* name offset in name buffer. */
};
struct DRWShadingGroup {
DRWShadingGroup *next;
- GPUShader *shader; /* Shader to bind */
- DRWUniform *uniforms; /* Uniforms pointers */
+ GPUShader *shader; /* Shader to bind */
+ struct DRWUniformChunk *uniforms; /* Uniforms pointers */
struct {
- DRWCall *first, *last; /* Linked list of DRWCall */
- } calls;
+ /* Chunks of draw calls. */
+ struct DRWCommandChunk *first, *last;
+ } cmd;
- /** TODO Maybe remove from here */
- struct GPUVertBuf *tfeedback_target;
-
- /** State changes for this batch only (or'd with the pass's state) */
- DRWState state_extra;
- /** State changes for this batch only (and'd with the pass's state) */
- DRWState state_extra_disable;
- /** Stencil mask to use for stencil test / write operations */
- uint stencil_mask;
-
- /* Builtin matrices locations */
- int model;
- int modelinverse;
- int modelviewprojection;
- int orcotexfac;
- int callid;
- int objectinfo;
- int objectcolor;
- uchar matflag; /* Matrices needed, same as DRWCall.flag */
-
- DRWPass *pass_parent; /* backlink to pass we're in */
+ union {
+ struct {
+ int objectinfo; /* Equal to 1 if the shader needs obinfos. */
+ DRWResourceHandle pass_handle; /* Memblock key to parent pass. */
+ };
+ struct {
+ float distance; /* Distance from camera. */
+ uint original_index; /* Original position inside the shgroup list. */
+ } z_sorting;
+ };
};
#define MAX_PASS_NAME 32
@@ -213,6 +328,7 @@ struct DRWPass {
DRWShadingGroup *last;
} shgroups;
+ DRWResourceHandle handle;
DRWState state;
char name[MAX_PASS_NAME];
};
@@ -232,6 +348,8 @@ typedef struct DRWViewUboStorage {
float viewcamtexcofac[4];
} DRWViewUboStorage;
+BLI_STATIC_ASSERT_ALIGN(DRWViewUboStorage, 16)
+
#define MAX_CULLED_VIEWS 32
struct DRWView {
@@ -253,13 +371,45 @@ struct DRWView {
void *user_data;
};
-/* TODO(fclem): Future awaits */
-#if 0
-typedef struct ModelUboStorage {
- float model[4][4];
- float modelinverse[4][4];
-} ModelUboStorage;
-#endif
+/* ------------ Data Chunks --------------- */
+/**
+ * In order to keep a cache friendly data structure,
+ * we alloc most of our little data into chunks of multiple item.
+ * Iteration, allocation and memory usage are better.
+ * We loose a bit of memory by allocating more than what we need
+ * but it's counterbalanced by not needing the linked-list pointers
+ * for each item.
+ **/
+
+typedef struct DRWUniformChunk {
+ struct DRWUniformChunk *next; /* single-linked list */
+ uint32_t uniform_len;
+ uint32_t uniform_used;
+ DRWUniform uniforms[10];
+} DRWUniformChunk;
+
+typedef struct DRWCommandChunk {
+ struct DRWCommandChunk *next;
+ uint32_t command_len;
+ uint32_t command_used;
+ /* 4bits for each command. */
+ uint64_t command_type[6];
+ /* -- 64 bytes aligned -- */
+ DRWCommand commands[96];
+ /* -- 64 bytes aligned -- */
+} DRWCommandChunk;
+
+typedef struct DRWCommandSmallChunk {
+ struct DRWCommandChunk *next;
+ uint32_t command_len;
+ uint32_t command_used;
+ /* 4bits for each command. */
+ /* TODO reduce size of command_type. */
+ uint64_t command_type[6];
+ DRWCommand commands[6];
+} DRWCommandSmallChunk;
+
+BLI_STATIC_ASSERT_ALIGN(DRWCommandChunk, 16);
/* ------------- DRAW DEBUG ------------ */
@@ -280,21 +430,31 @@ typedef struct DRWDebugSphere {
#define DST_MAX_SLOTS 64 /* Cannot be changed without modifying RST.bound_tex_slots */
#define MAX_CLIP_PLANES 6 /* GL_MAX_CLIP_PLANES is at least 6 */
#define STENCIL_UNDEFINED 256
+#define DRW_DRAWLIST_LEN 256
typedef struct DRWManager {
/* TODO clean up this struct a bit */
/* Cache generation */
ViewportMemoryPool *vmempool;
DRWInstanceDataList *idatalist;
- DRWInstanceData *object_instance_data[MAX_INSTANCE_DATA_SIZE];
- /* Default Unit model matrix state without culling. */
- DRWCallState *unit_state;
/* State of the object being evaluated if already allocated. */
- DRWCallState *ob_state;
+ DRWResourceHandle ob_handle;
+ /** True if current DST.ob_state has its matching DRWObjectInfos init. */
+ bool ob_state_obinfo_init;
+ /** Handle of current object resource in object resource arrays (DRWObjectMatrices/Infos). */
+ DRWResourceHandle resource_handle;
+ /** Handle of next DRWPass to be allocated. */
+ DRWResourceHandle pass_handle;
+
+ /** Dupli state. NULL if not dupli. */
struct DupliObject *dupli_source;
struct Object *dupli_parent;
struct Object *dupli_origin;
+ /** Ghash containing original objects. */
struct GHash *dupli_ghash;
- void **dupli_datas; /* Array of dupli_data (one for each enabled engine) to handle duplis. */
+ /** TODO(fclem) try to remove usage of this. */
+ DRWInstanceData *object_instance_data[MAX_INSTANCE_DATA_SIZE];
+ /* Array of dupli_data (one for each enabled engine) to handle duplis. */
+ void **dupli_datas;
/* Rendering state */
GPUShader *shader;
@@ -357,6 +517,8 @@ typedef struct DRWManager {
/** Mutex to lock the drw manager and avoid concurrent context usage. */
TicketMutex *gl_context_mutex;
+ GPUDrawList *draw_list;
+
/** GPU Resource State: Memory storage between drawing. */
struct {
/* High end GPUs supports up to 32 binds per shader stage.
@@ -397,9 +559,13 @@ void drw_state_set(DRWState state);
void drw_debug_draw(void);
void drw_debug_init(void);
+eDRWCommandType command_type_get(uint64_t *command_type_bits, int index);
+
void drw_batch_cache_validate(Object *ob);
void drw_batch_cache_generate_requested(struct Object *ob);
+void drw_resource_buffer_finish(ViewportMemoryPool *vmempool);
+
/* Procedural Drawing */
GPUBatch *drw_cache_procedural_points_get(void);
GPUBatch *drw_cache_procedural_lines_get(void);
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index cd174e899d4..cdf2c208351 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -34,6 +34,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meta_types.h"
+#include "BLI_alloca.h"
#include "BLI_hash.h"
#include "BLI_link_utils.h"
#include "BLI_mempool.h"
@@ -51,6 +52,35 @@
/** \name Uniform Buffer Object (DRW_uniformbuffer)
* \{ */
+static void draw_call_sort(DRWCommand *array, DRWCommand *array_tmp, int array_len)
+{
+ /* Count unique batches. Tt's not really important if
+ * there is colisions. If there is a lot of different batches,
+ * the sorting benefit will be negligeable. So at least
+ * sort fast! */
+ uchar idx[128] = {0};
+ /* Shift by 6 positions knowing each GPUBatch is > 64 bytes */
+#define KEY(a) ((((size_t)((a).draw.batch)) >> 6) % ARRAY_SIZE(idx))
+ BLI_assert(array_len <= ARRAY_SIZE(idx));
+
+ for (int i = 0; i < array_len; i++) {
+ /* Early out if nothing to sort. */
+ if (++idx[KEY(array[i])] == array_len)
+ return;
+ }
+ /* Cumulate batch indices */
+ for (int i = 1; i < ARRAY_SIZE(idx); i++) {
+ idx[i] += idx[i - 1];
+ }
+ /* Traverse in reverse to not change the order of the resource ids. */
+ for (int src = array_len - 1; src >= 0; src--) {
+ array_tmp[--idx[KEY(array[src])]] = array[src];
+ }
+#undef KEY
+
+ memcpy(array, array_tmp, sizeof(*array) * array_len);
+}
+
GPUUniformBuffer *DRW_uniformbuffer_create(int size, const void *data)
{
return GPU_uniformbuffer_create(size, data, NULL);
@@ -66,20 +96,94 @@ void DRW_uniformbuffer_free(GPUUniformBuffer *ubo)
GPU_uniformbuffer_free(ubo);
}
+void drw_resource_buffer_finish(ViewportMemoryPool *vmempool)
+{
+ int chunk_id = DRW_handle_chunk_get(&DST.resource_handle);
+ int elem_id = DRW_handle_id_get(&DST.resource_handle);
+ int ubo_len = 1 + chunk_id - ((elem_id == 0) ? 1 : 0);
+ size_t list_size = sizeof(GPUUniformBuffer *) * ubo_len;
+
+ /* TODO find a better system. currently a lot of obinfos UBO are going to be unused
+ * if not rendering with Eevee. */
+
+ if (vmempool->matrices_ubo == NULL) {
+ vmempool->matrices_ubo = MEM_callocN(list_size, __func__);
+ vmempool->obinfos_ubo = MEM_callocN(list_size, __func__);
+ vmempool->ubo_len = ubo_len;
+ }
+
+ /* Remove unecessary buffers */
+ for (int i = ubo_len; i < vmempool->ubo_len; i++) {
+ GPU_uniformbuffer_free(vmempool->matrices_ubo[i]);
+ GPU_uniformbuffer_free(vmempool->obinfos_ubo[i]);
+ }
+
+ if (ubo_len != vmempool->ubo_len) {
+ vmempool->matrices_ubo = MEM_recallocN(vmempool->matrices_ubo, list_size);
+ vmempool->obinfos_ubo = MEM_recallocN(vmempool->obinfos_ubo, list_size);
+ vmempool->ubo_len = ubo_len;
+ }
+
+ /* Create/Update buffers. */
+ for (int i = 0; i < ubo_len; i++) {
+ void *data_obmat = BLI_memblock_elem_get(vmempool->obmats, i, 0);
+ void *data_infos = BLI_memblock_elem_get(vmempool->obinfos, i, 0);
+ if (vmempool->matrices_ubo[i] == NULL) {
+ vmempool->matrices_ubo[i] = GPU_uniformbuffer_create(
+ sizeof(DRWObjectMatrix) * DRW_RESOURCE_CHUNK_LEN, data_obmat, NULL);
+ vmempool->obinfos_ubo[i] = GPU_uniformbuffer_create(
+ sizeof(DRWObjectInfos) * DRW_RESOURCE_CHUNK_LEN, data_infos, NULL);
+ }
+ else {
+ GPU_uniformbuffer_update(vmempool->matrices_ubo[i], data_obmat);
+ GPU_uniformbuffer_update(vmempool->obinfos_ubo[i], data_infos);
+ }
+ }
+
+ /* Aligned alloc to avoid unaligned memcpy. */
+ DRWCommandChunk *chunk_tmp = MEM_mallocN_aligned(sizeof(DRWCommandChunk), 16, "tmp call chunk");
+ DRWCommandChunk *chunk;
+ BLI_memblock_iter iter;
+ BLI_memblock_iternew(vmempool->commands, &iter);
+ while ((chunk = BLI_memblock_iterstep(&iter))) {
+ bool sortable = true;
+ /* We can only sort chunks that contain DRWCommandDraw only. */
+ for (int i = 0; i < ARRAY_SIZE(chunk->command_type) && sortable; i++) {
+ if (chunk->command_type[i] != 0) {
+ sortable = false;
+ }
+ }
+ if (sortable) {
+ draw_call_sort(chunk->commands, chunk_tmp->commands, chunk->command_used);
+ }
+ }
+ MEM_freeN(chunk_tmp);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Uniforms (DRW_shgroup_uniform)
* \{ */
-static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup,
- int loc,
- DRWUniformType type,
- const void *value,
- int length,
- int arraysize)
+static DRWUniform *drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup,
+ int loc,
+ DRWUniformType type,
+ const void *value,
+ int length,
+ int arraysize)
{
- DRWUniform *uni = BLI_memblock_alloc(DST.vmempool->uniforms);
+ DRWUniformChunk *unichunk = shgroup->uniforms;
+ /* Happens on first uniform or if chunk is full. */
+ if (!unichunk || unichunk->uniform_used == unichunk->uniform_len) {
+ unichunk = BLI_memblock_alloc(DST.vmempool->uniforms);
+ unichunk->uniform_len = ARRAY_SIZE(shgroup->uniforms->uniforms);
+ unichunk->uniform_used = 0;
+ BLI_LINKS_PREPEND(shgroup->uniforms, unichunk);
+ }
+
+ DRWUniform *uni = unichunk->uniforms + unichunk->uniform_used++;
+
uni->location = loc;
uni->type = type;
uni->length = length;
@@ -87,11 +191,11 @@ static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup,
switch (type) {
case DRW_UNIFORM_INT_COPY:
- BLI_assert(length <= 2);
+ BLI_assert(length <= 4);
memcpy(uni->ivalue, value, sizeof(int) * length);
break;
case DRW_UNIFORM_FLOAT_COPY:
- BLI_assert(length <= 2);
+ BLI_assert(length <= 4);
memcpy(uni->fvalue, value, sizeof(float) * length);
break;
default:
@@ -99,7 +203,7 @@ static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup,
break;
}
- BLI_LINKS_PREPEND(shgroup->uniforms, uni);
+ return uni;
}
static void drw_shgroup_builtin_uniform(
@@ -136,7 +240,8 @@ static void drw_shgroup_uniform(DRWShadingGroup *shgroup,
BLI_assert(arraysize > 0 && arraysize <= 16);
BLI_assert(length >= 0 && length <= 16);
- drw_shgroup_uniform_create_ex(shgroup, location, type, value, length, arraysize);
+ DRWUniform *uni = drw_shgroup_uniform_create_ex(
+ shgroup, location, type, value, length, arraysize);
/* If location is -2, the uniform has not yet been queried.
* We save the name for query just before drawing. */
@@ -155,7 +260,7 @@ static void drw_shgroup_uniform(DRWShadingGroup *shgroup,
memcpy(dst, name, len); /* Copies NULL terminator. */
DST.uniform_names.buffer_ofs += len;
- shgroup->uniforms->name_ofs = ofs;
+ uni->name_ofs = ofs;
}
}
@@ -286,6 +391,21 @@ void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, co
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT_COPY, &value, 1, 1);
}
+void DRW_shgroup_uniform_ivec2_copy(DRWShadingGroup *shgroup, const char *name, const int *value)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT_COPY, value, 2, 1);
+}
+
+void DRW_shgroup_uniform_ivec3_copy(DRWShadingGroup *shgroup, const char *name, const int *value)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT_COPY, value, 3, 1);
+}
+
+void DRW_shgroup_uniform_ivec4_copy(DRWShadingGroup *shgroup, const char *name, const int *value)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT_COPY, value, 4, 1);
+}
+
void DRW_shgroup_uniform_bool_copy(DRWShadingGroup *shgroup, const char *name, const bool value)
{
int ival = value;
@@ -302,13 +422,23 @@ void DRW_shgroup_uniform_vec2_copy(DRWShadingGroup *shgroup, const char *name, c
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT_COPY, value, 2, 1);
}
+void DRW_shgroup_uniform_vec3_copy(DRWShadingGroup *shgroup, const char *name, const float *value)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT_COPY, value, 3, 1);
+}
+
+void DRW_shgroup_uniform_vec4_copy(DRWShadingGroup *shgroup, const char *name, const float *value)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT_COPY, value, 4, 1);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Draw Call (DRW_calls)
* \{ */
-static void drw_call_calc_orco(Object *ob, float (*r_orcofacs)[3])
+static void drw_call_calc_orco(Object *ob, float (*r_orcofacs)[4])
{
ID *ob_data = (ob) ? ob->data : NULL;
float *texcoloc = NULL;
@@ -351,159 +481,283 @@ static void drw_call_calc_orco(Object *ob, float (*r_orcofacs)[3])
}
}
-static void drw_call_state_update_matflag(DRWCallState *state,
- DRWShadingGroup *shgroup,
- Object *ob)
+BLI_INLINE void drw_call_matrix_init(DRWObjectMatrix *ob_mats, Object *ob, float (*obmat)[4])
{
- uchar new_flags = ((state->matflag ^ shgroup->matflag) & shgroup->matflag);
-
- /* HACK: Here we set the matflags bit to 1 when computing the value
- * so that it's not recomputed for other drawcalls.
- * This is the opposite of what draw_matrices_model_prepare() does. */
- state->matflag |= shgroup->matflag;
-
- if (new_flags & DRW_CALL_MODELINVERSE) {
- if (ob) {
- copy_m4_m4(state->modelinverse, ob->imat);
- }
- else {
- invert_m4_m4(state->modelinverse, state->model);
- }
+ copy_m4_m4(ob_mats->model, obmat);
+ if (ob) {
+ copy_m4_m4(ob_mats->modelinverse, ob->imat);
}
-
- /* Orco factors: We compute this at creation to not have to save the *ob_data */
- if (new_flags & DRW_CALL_ORCOTEXFAC) {
- drw_call_calc_orco(ob, state->orcotexfac);
- }
-
- if (new_flags & DRW_CALL_OBJECTINFO) {
- state->ob_index = ob ? ob->index : 0;
- uint random;
- if (DST.dupli_source) {
- random = DST.dupli_source->random_id;
- }
- else {
- random = BLI_hash_int_2d(BLI_hash_string(ob->id.name + 2), 0);
- }
- state->ob_random = random * (1.0f / (float)0xFFFFFFFF);
- }
-
- if (new_flags & DRW_CALL_OBJECTCOLOR) {
- copy_v4_v4(state->ob_color, ob->color);
+ else {
+ /* WATCH: Can be costly. */
+ invert_m4_m4(ob_mats->modelinverse, ob_mats->model);
}
}
-static DRWCallState *drw_call_state_create(DRWShadingGroup *shgroup, float (*obmat)[4], Object *ob)
+static void drw_call_obinfos_init(DRWObjectInfos *ob_infos, Object *ob)
{
- DRWCallState *state = BLI_memblock_alloc(DST.vmempool->states);
- state->flag = 0;
- state->matflag = 0;
-
- /* Matrices */
- copy_m4_m4(state->model, obmat);
-
- if (ob && (ob->transflag & OB_NEG_SCALE)) {
- state->flag |= DRW_CALL_NEGSCALE;
- }
-
- drw_call_state_update_matflag(state, shgroup, ob);
-
- DRWCullingState *cull = BLI_memblock_alloc(DST.vmempool->cullstates);
- state->culling = cull;
+ BLI_assert(ob);
+ /* Index. */
+ ob_infos->ob_index = ob->index;
+ /* Orco factors. */
+ drw_call_calc_orco(ob, ob_infos->orcotexfac);
+ /* Random float value. */
+ uint random = (DST.dupli_source) ?
+ DST.dupli_source->random_id :
+ /* TODO(fclem) this is rather costly to do at runtime. Maybe we can
+ * put it in ob->runtime and make depsgraph ensure it is up to date. */
+ BLI_hash_int_2d(BLI_hash_string(ob->id.name + 2), 0);
+ ob_infos->ob_random = random * (1.0f / (float)0xFFFFFFFF);
+ /* Negative scalling. */
+ ob_infos->ob_neg_scale = (ob->transflag & OB_NEG_SCALE) ? -1.0f : 1.0f;
+ /* Object Color. */
+ copy_v4_v4(ob_infos->ob_color, ob->color);
+}
+static void drw_call_culling_init(DRWCullingState *cull, Object *ob)
+{
BoundBox *bbox;
if (ob != NULL && (bbox = BKE_object_boundbox_get(ob))) {
float corner[3];
/* Get BoundSphere center and radius from the BoundBox. */
mid_v3_v3v3(cull->bsphere.center, bbox->vec[0], bbox->vec[6]);
- mul_v3_m4v3(corner, obmat, bbox->vec[0]);
- mul_m4_v3(obmat, cull->bsphere.center);
+ mul_v3_m4v3(corner, ob->obmat, bbox->vec[0]);
+ mul_m4_v3(ob->obmat, cull->bsphere.center);
cull->bsphere.radius = len_v3v3(cull->bsphere.center, corner);
}
else {
- /* TODO(fclem) Bypass alloc if we can (see if eevee's
- * probe visibility collection still works). */
/* Bypass test. */
cull->bsphere.radius = -1.0f;
}
+ /* Reset user data */
+ cull->user_data = NULL;
+}
+
+static DRWResourceHandle drw_resource_handle_new(float (*obmat)[4], Object *ob)
+{
+ DRWCullingState *culling = BLI_memblock_alloc(DST.vmempool->cullstates);
+ DRWObjectMatrix *ob_mats = BLI_memblock_alloc(DST.vmempool->obmats);
+ /* FIXME Meh, not always needed but can be accessed after creation.
+ * Also it needs to have the same resource handle. */
+ DRWObjectInfos *ob_infos = BLI_memblock_alloc(DST.vmempool->obinfos);
+ UNUSED_VARS(ob_infos);
+
+ DRWResourceHandle handle = DST.resource_handle;
+ DRW_handle_increment(&DST.resource_handle);
- return state;
+ if (ob && (ob->transflag & OB_NEG_SCALE)) {
+ DRW_handle_negative_scale_enable(&handle);
+ }
+
+ drw_call_matrix_init(ob_mats, ob, obmat);
+ drw_call_culling_init(culling, ob);
+ /* ob_infos is init only if needed. */
+
+ return handle;
}
-static DRWCallState *drw_call_state_object(DRWShadingGroup *shgroup, float (*obmat)[4], Object *ob)
+static DRWResourceHandle drw_resource_handle(DRWShadingGroup *shgroup,
+ float (*obmat)[4],
+ Object *ob)
{
if (ob == NULL) {
if (obmat == NULL) {
- BLI_assert(DST.unit_state);
- return DST.unit_state;
+ DRWResourceHandle handle = 0;
+ return handle;
}
else {
- return drw_call_state_create(shgroup, obmat, ob);
+ return drw_resource_handle_new(obmat, NULL);
}
}
else {
- if (DST.ob_state == NULL) {
- DST.ob_state = drw_call_state_create(shgroup, obmat, ob);
+ if (DST.ob_handle == 0) {
+ DST.ob_handle = drw_resource_handle_new(obmat, ob);
+ DST.ob_state_obinfo_init = false;
}
- else {
- /* If the DRWCallState is reused, add necessary matrices. */
- drw_call_state_update_matflag(DST.ob_state, shgroup, ob);
+
+ if (shgroup->objectinfo) {
+ if (!DST.ob_state_obinfo_init) {
+ DST.ob_state_obinfo_init = true;
+ DRWObjectInfos *ob_infos = DRW_memblock_elem_from_handle(DST.vmempool->obinfos,
+ &DST.ob_handle);
+
+ drw_call_obinfos_init(ob_infos, ob);
+ }
}
- return DST.ob_state;
+ return DST.ob_handle;
+ }
+}
+
+static void command_type_set(uint64_t *command_type_bits, int index, eDRWCommandType type)
+{
+ command_type_bits[index / 16] |= ((uint64_t)type) << ((index % 16) * 4);
+}
+
+eDRWCommandType command_type_get(uint64_t *command_type_bits, int index)
+{
+ return ((command_type_bits[index / 16] >> ((index % 16) * 4)) & 0xF);
+}
+
+static void *drw_command_create(DRWShadingGroup *shgroup, eDRWCommandType type)
+{
+ DRWCommandChunk *chunk = shgroup->cmd.last;
+
+ if (chunk == NULL) {
+ DRWCommandSmallChunk *smallchunk = BLI_memblock_alloc(DST.vmempool->commands_small);
+ smallchunk->command_len = ARRAY_SIZE(smallchunk->commands);
+ smallchunk->command_used = 0;
+ smallchunk->command_type[0] = 0x0lu;
+ chunk = (DRWCommandChunk *)smallchunk;
+ BLI_LINKS_APPEND(&shgroup->cmd, chunk);
}
+ else if (chunk->command_used == chunk->command_len) {
+ chunk = BLI_memblock_alloc(DST.vmempool->commands);
+ chunk->command_len = ARRAY_SIZE(chunk->commands);
+ chunk->command_used = 0;
+ memset(chunk->command_type, 0x0, sizeof(chunk->command_type));
+ BLI_LINKS_APPEND(&shgroup->cmd, chunk);
+ }
+
+ command_type_set(chunk->command_type, chunk->command_used, type);
+
+ return chunk->commands + chunk->command_used++;
+}
+
+static void drw_command_draw(DRWShadingGroup *shgroup, GPUBatch *batch, DRWResourceHandle handle)
+{
+ DRWCommandDraw *cmd = drw_command_create(shgroup, DRW_CMD_DRAW);
+ cmd->batch = batch;
+ cmd->handle = handle;
+}
+
+static void drw_command_draw_range(DRWShadingGroup *shgroup,
+ GPUBatch *batch,
+ uint start,
+ uint count)
+{
+ DRWCommandDrawRange *cmd = drw_command_create(shgroup, DRW_CMD_DRAW_RANGE);
+ cmd->batch = batch;
+ cmd->vert_first = start;
+ cmd->vert_count = count;
+}
+
+static void drw_command_draw_instance(DRWShadingGroup *shgroup,
+ GPUBatch *batch,
+ DRWResourceHandle handle,
+ uint count)
+{
+ DRWCommandDrawInstance *cmd = drw_command_create(shgroup, DRW_CMD_DRAW_INSTANCE);
+ cmd->batch = batch;
+ cmd->handle = handle;
+ cmd->inst_count = count;
+}
+
+static void drw_command_draw_procedural(DRWShadingGroup *shgroup,
+ GPUBatch *batch,
+ DRWResourceHandle handle,
+ uint vert_count)
+{
+ DRWCommandDrawProcedural *cmd = drw_command_create(shgroup, DRW_CMD_DRAW_PROCEDURAL);
+ cmd->batch = batch;
+ cmd->handle = handle;
+ cmd->vert_count = vert_count;
+}
+
+static void drw_command_set_select_id(DRWShadingGroup *shgroup, GPUVertBuf *buf, uint select_id)
+{
+ /* Only one can be valid. */
+ BLI_assert(buf == NULL || select_id == -1);
+ DRWCommandSetSelectID *cmd = drw_command_create(shgroup, DRW_CMD_SELECTID);
+ cmd->select_buf = buf;
+ cmd->select_id = select_id;
+}
+
+static void drw_command_set_stencil_mask(DRWShadingGroup *shgroup, uint mask)
+{
+ BLI_assert(mask <= 0xFF);
+ DRWCommandSetStencil *cmd = drw_command_create(shgroup, DRW_CMD_STENCIL);
+ cmd->mask = mask;
+}
+
+static void drw_command_clear(DRWShadingGroup *shgroup,
+ eGPUFrameBufferBits channels,
+ uchar r,
+ uchar g,
+ uchar b,
+ uchar a,
+ float depth,
+ uchar stencil)
+{
+ DRWCommandClear *cmd = drw_command_create(shgroup, DRW_CMD_CLEAR);
+ cmd->clear_channels = channels;
+ cmd->r = r;
+ cmd->g = g;
+ cmd->b = b;
+ cmd->a = a;
+ cmd->depth = depth;
+ cmd->stencil = stencil;
+}
+
+static void drw_command_set_mutable_state(DRWShadingGroup *shgroup,
+ DRWState enable,
+ DRWState disable)
+{
+ /* TODO Restrict what state can be changed. */
+ DRWCommandSetMutableState *cmd = drw_command_create(shgroup, DRW_CMD_DRWSTATE);
+ cmd->enable = enable;
+ cmd->disable = disable;
}
void DRW_shgroup_call_ex(DRWShadingGroup *shgroup,
Object *ob,
float (*obmat)[4],
struct GPUBatch *geom,
- uint v_sta,
- uint v_ct,
bool bypass_culling,
void *user_data)
{
BLI_assert(geom != NULL);
+ if (G.f & G_FLAG_PICKSEL) {
+ drw_command_set_select_id(shgroup, NULL, DST.select_id);
+ }
+ DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : obmat, ob);
+ drw_command_draw(shgroup, geom, handle);
- DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls);
- BLI_LINKS_APPEND(&shgroup->calls, call);
-
- call->state = drw_call_state_object(shgroup, ob ? ob->obmat : obmat, ob);
- call->batch = geom;
- call->vert_first = v_sta;
- call->vert_count = v_ct; /* 0 means auto from batch. */
- call->inst_count = 0;
-#ifdef USE_GPU_SELECT
- call->select_id = DST.select_id;
- call->inst_selectid = NULL;
-#endif
- if (call->state->culling) {
- call->state->culling->user_data = user_data;
+ /* Culling data. */
+ if (user_data || bypass_culling) {
+ DRWCullingState *culling = DRW_memblock_elem_from_handle(DST.vmempool->cullstates,
+ &DST.ob_handle);
+
+ if (user_data) {
+ culling->user_data = user_data;
+ }
if (bypass_culling) {
/* NOTE this will disable culling for the whole object. */
- call->state->culling->bsphere.radius = -1.0f;
+ culling->bsphere.radius = -1.0f;
}
}
}
+void DRW_shgroup_call_range(DRWShadingGroup *shgroup, struct GPUBatch *geom, uint v_sta, uint v_ct)
+{
+ BLI_assert(geom != NULL);
+ if (G.f & G_FLAG_PICKSEL) {
+ drw_command_set_select_id(shgroup, NULL, DST.select_id);
+ }
+ drw_command_draw_range(shgroup, geom, v_sta, v_ct);
+}
+
static void drw_shgroup_call_procedural_add_ex(DRWShadingGroup *shgroup,
GPUBatch *geom,
Object *ob,
uint vert_count)
{
-
- DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls);
- BLI_LINKS_APPEND(&shgroup->calls, call);
-
- call->state = drw_call_state_object(shgroup, ob ? ob->obmat : NULL, ob);
- call->batch = geom;
- call->vert_first = 0;
- call->vert_count = vert_count;
- call->inst_count = 0;
-#ifdef USE_GPU_SELECT
- call->select_id = DST.select_id;
- call->inst_selectid = NULL;
-#endif
+ BLI_assert(vert_count > 0);
+ BLI_assert(geom != NULL);
+ if (G.f & G_FLAG_PICKSEL) {
+ drw_command_set_select_id(shgroup, NULL, DST.select_id);
+ }
+ DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob);
+ drw_command_draw_procedural(shgroup, geom, handle, vert_count);
}
void DRW_shgroup_call_procedural_points(DRWShadingGroup *shgroup, Object *ob, uint point_len)
@@ -524,25 +778,18 @@ void DRW_shgroup_call_procedural_triangles(DRWShadingGroup *shgroup, Object *ob,
drw_shgroup_call_procedural_add_ex(shgroup, geom, ob, tria_count * 3);
}
+/* Should be removed */
void DRW_shgroup_call_instances(DRWShadingGroup *shgroup,
Object *ob,
struct GPUBatch *geom,
uint count)
{
BLI_assert(geom != NULL);
-
- DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls);
- BLI_LINKS_APPEND(&shgroup->calls, call);
-
- call->state = drw_call_state_object(shgroup, ob ? ob->obmat : NULL, ob);
- call->batch = geom;
- call->vert_first = 0;
- call->vert_count = 0; /* Auto from batch. */
- call->inst_count = count;
-#ifdef USE_GPU_SELECT
- call->select_id = DST.select_id;
- call->inst_selectid = NULL;
-#endif
+ if (G.f & G_FLAG_PICKSEL) {
+ drw_command_set_select_id(shgroup, NULL, DST.select_id);
+ }
+ DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob);
+ drw_command_draw_instance(shgroup, geom, handle, count);
}
void DRW_shgroup_call_instances_with_attribs(DRWShadingGroup *shgroup,
@@ -552,21 +799,13 @@ void DRW_shgroup_call_instances_with_attribs(DRWShadingGroup *shgroup,
{
BLI_assert(geom != NULL);
BLI_assert(inst_attributes->verts[0] != NULL);
-
+ if (G.f & G_FLAG_PICKSEL) {
+ drw_command_set_select_id(shgroup, NULL, DST.select_id);
+ }
+ DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob);
GPUVertBuf *buf_inst = inst_attributes->verts[0];
-
- DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls);
- BLI_LINKS_APPEND(&shgroup->calls, call);
-
- call->state = drw_call_state_object(shgroup, ob ? ob->obmat : NULL, ob);
- call->batch = DRW_temp_batch_instance_request(DST.idatalist, buf_inst, geom);
- call->vert_first = 0;
- call->vert_count = 0; /* Auto from batch. */
- call->inst_count = buf_inst->vertex_len;
-#ifdef USE_GPU_SELECT
- call->select_id = DST.select_id;
- call->inst_selectid = NULL;
-#endif
+ GPUBatch *batch = DRW_temp_batch_instance_request(DST.idatalist, buf_inst, geom);
+ drw_command_draw(shgroup, batch, handle);
}
// #define SCULPT_DEBUG_BUFFERS
@@ -719,27 +958,26 @@ DRWCallBuffer *DRW_shgroup_call_buffer(DRWShadingGroup *shgroup,
BLI_assert(ELEM(prim_type, GPU_PRIM_POINTS, GPU_PRIM_LINES, GPU_PRIM_TRI_FAN));
BLI_assert(format != NULL);
- DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls);
- BLI_LINKS_APPEND(&shgroup->calls, call);
+ DRWCallBuffer *callbuf = BLI_memblock_alloc(DST.vmempool->callbuffers);
+ callbuf->buf = DRW_temp_buffer_request(DST.idatalist, format, &callbuf->count);
+ callbuf->buf_select = NULL;
+ callbuf->count = 0;
- call->state = drw_call_state_object(shgroup, NULL, NULL);
- GPUVertBuf *buf = DRW_temp_buffer_request(DST.idatalist, format, &call->vert_count);
- call->batch = DRW_temp_batch_request(DST.idatalist, buf, prim_type);
- call->vert_first = 0;
- call->vert_count = 0;
- call->inst_count = 0;
-
-#ifdef USE_GPU_SELECT
if (G.f & G_FLAG_PICKSEL) {
/* Not actually used for rendering but alloced in one chunk. */
if (inst_select_format.attr_len == 0) {
GPU_vertformat_attr_add(&inst_select_format, "selectId", GPU_COMP_I32, 1, GPU_FETCH_INT);
}
- call->inst_selectid = DRW_temp_buffer_request(
- DST.idatalist, &inst_select_format, &call->vert_count);
+ callbuf->buf_select = DRW_temp_buffer_request(
+ DST.idatalist, &inst_select_format, &callbuf->count);
+ drw_command_set_select_id(shgroup, callbuf->buf_select, -1);
}
-#endif
- return (DRWCallBuffer *)call;
+
+ DRWResourceHandle handle = drw_resource_handle(shgroup, NULL, NULL);
+ GPUBatch *batch = DRW_temp_batch_request(DST.idatalist, callbuf->buf, prim_type);
+ drw_command_draw(shgroup, batch, handle);
+
+ return callbuf;
}
DRWCallBuffer *DRW_shgroup_call_buffer_instance(DRWShadingGroup *shgroup,
@@ -749,56 +987,52 @@ DRWCallBuffer *DRW_shgroup_call_buffer_instance(DRWShadingGroup *shgroup,
BLI_assert(geom != NULL);
BLI_assert(format != NULL);
- DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls);
- BLI_LINKS_APPEND(&shgroup->calls, call);
+ DRWCallBuffer *callbuf = BLI_memblock_alloc(DST.vmempool->callbuffers);
+ callbuf->buf = DRW_temp_buffer_request(DST.idatalist, format, &callbuf->count);
+ callbuf->buf_select = NULL;
+ callbuf->count = 0;
- call->state = drw_call_state_object(shgroup, NULL, NULL);
- GPUVertBuf *buf = DRW_temp_buffer_request(DST.idatalist, format, &call->inst_count);
- call->batch = DRW_temp_batch_instance_request(DST.idatalist, buf, geom);
- call->vert_first = 0;
- call->vert_count = 0; /* Auto from batch. */
- call->inst_count = 0;
-
-#ifdef USE_GPU_SELECT
if (G.f & G_FLAG_PICKSEL) {
/* Not actually used for rendering but alloced in one chunk. */
if (inst_select_format.attr_len == 0) {
GPU_vertformat_attr_add(&inst_select_format, "selectId", GPU_COMP_I32, 1, GPU_FETCH_INT);
}
- call->inst_selectid = DRW_temp_buffer_request(
- DST.idatalist, &inst_select_format, &call->inst_count);
+ callbuf->buf_select = DRW_temp_buffer_request(
+ DST.idatalist, &inst_select_format, &callbuf->count);
+ drw_command_set_select_id(shgroup, callbuf->buf_select, -1);
}
-#endif
- return (DRWCallBuffer *)call;
+
+ DRWResourceHandle handle = drw_resource_handle(shgroup, NULL, NULL);
+ GPUBatch *batch = DRW_temp_batch_instance_request(DST.idatalist, callbuf->buf, geom);
+ drw_command_draw(shgroup, batch, handle);
+
+ return callbuf;
}
void DRW_buffer_add_entry_array(DRWCallBuffer *callbuf, const void *attr[], uint attr_len)
{
- DRWCall *call = (DRWCall *)callbuf;
- const bool is_instance = call->batch->inst != NULL;
- GPUVertBuf *buf = is_instance ? call->batch->inst : call->batch->verts[0];
- uint count = is_instance ? call->inst_count++ : call->vert_count++;
- const bool resize = (count == buf->vertex_alloc);
+ GPUVertBuf *buf = callbuf->buf;
+ const bool resize = (callbuf->count == buf->vertex_alloc);
BLI_assert(attr_len == buf->format.attr_len);
UNUSED_VARS_NDEBUG(attr_len);
if (UNLIKELY(resize)) {
- GPU_vertbuf_data_resize(buf, count + DRW_BUFFER_VERTS_CHUNK);
+ GPU_vertbuf_data_resize(buf, callbuf->count + DRW_BUFFER_VERTS_CHUNK);
}
for (int i = 0; i < attr_len; i++) {
- GPU_vertbuf_attr_set(buf, i, count, attr[i]);
+ GPU_vertbuf_attr_set(buf, i, callbuf->count, attr[i]);
}
-#ifdef USE_GPU_SELECT
if (G.f & G_FLAG_PICKSEL) {
if (UNLIKELY(resize)) {
- GPU_vertbuf_data_resize(call->inst_selectid, count + DRW_BUFFER_VERTS_CHUNK);
+ GPU_vertbuf_data_resize(callbuf->buf_select, callbuf->count + DRW_BUFFER_VERTS_CHUNK);
}
- GPU_vertbuf_attr_set(call->inst_selectid, 0, count, &DST.select_id);
+ GPU_vertbuf_attr_set(callbuf->buf_select, 0, callbuf->count, &DST.select_id);
}
-#endif
+
+ callbuf->count++;
}
/** \} */
@@ -811,7 +1045,54 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader)
{
shgroup->uniforms = NULL;
+ /* TODO(fclem) make them builtin. */
int view_ubo_location = GPU_shader_get_uniform_block(shader, "viewBlock");
+ int model_ubo_location = GPU_shader_get_uniform_block(shader, "modelBlock");
+ int info_ubo_location = GPU_shader_get_uniform_block(shader, "infoBlock");
+ int baseinst_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_BASE_INSTANCE);
+ int chunkid_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_RESOURCE_CHUNK);
+
+ if (chunkid_location != -1) {
+ drw_shgroup_uniform_create_ex(
+ shgroup, chunkid_location, DRW_UNIFORM_RESOURCE_CHUNK, NULL, 0, 1);
+ }
+
+ if (baseinst_location != -1) {
+ drw_shgroup_uniform_create_ex(
+ shgroup, baseinst_location, DRW_UNIFORM_BASE_INSTANCE, NULL, 0, 1);
+ }
+
+ if (model_ubo_location != -1) {
+ drw_shgroup_uniform_create_ex(
+ shgroup, model_ubo_location, DRW_UNIFORM_BLOCK_OBMATS, NULL, 0, 1);
+ }
+ else {
+ int model = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL);
+ int modelinverse = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL_INV);
+ int modelviewprojection = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MVP);
+ if (model != -1) {
+ drw_shgroup_uniform_create_ex(shgroup, model, DRW_UNIFORM_MODEL_MATRIX, NULL, 0, 1);
+ }
+ if (modelinverse != -1) {
+ drw_shgroup_uniform_create_ex(
+ shgroup, modelinverse, DRW_UNIFORM_MODEL_MATRIX_INVERSE, NULL, 0, 1);
+ }
+ if (modelviewprojection != -1) {
+ drw_shgroup_uniform_create_ex(
+ shgroup, modelviewprojection, DRW_UNIFORM_MODELVIEWPROJECTION_MATRIX, NULL, 0, 1);
+ }
+ }
+
+ if (info_ubo_location != -1) {
+ drw_shgroup_uniform_create_ex(
+ shgroup, info_ubo_location, DRW_UNIFORM_BLOCK_OBINFOS, NULL, 0, 1);
+
+ /* Abusing this loc to tell shgroup we need the obinfos. */
+ shgroup->objectinfo = 1;
+ }
+ else {
+ shgroup->objectinfo = 0;
+ }
if (view_ubo_location != -1) {
drw_shgroup_uniform_create_ex(
@@ -834,31 +1115,6 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader)
BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW_INV) == -1);
BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW) == -1);
BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_NORMAL) == -1);
-
- shgroup->model = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL);
- shgroup->modelinverse = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL_INV);
- shgroup->modelviewprojection = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MVP);
- shgroup->orcotexfac = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_ORCO);
- shgroup->objectinfo = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_OBJECT_INFO);
- shgroup->objectcolor = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_OBJECT_COLOR);
- shgroup->callid = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_CALLID);
-
- shgroup->matflag = 0;
- if (shgroup->modelinverse > -1) {
- shgroup->matflag |= DRW_CALL_MODELINVERSE;
- }
- if (shgroup->modelviewprojection > -1) {
- shgroup->matflag |= DRW_CALL_MODELVIEWPROJECTION;
- }
- if (shgroup->orcotexfac > -1) {
- shgroup->matflag |= DRW_CALL_ORCOTEXFAC;
- }
- if (shgroup->objectinfo > -1) {
- shgroup->matflag |= DRW_CALL_OBJECTINFO;
- }
- if (shgroup->objectcolor > -1) {
- shgroup->matflag |= DRW_CALL_OBJECTCOLOR;
- }
}
static DRWShadingGroup *drw_shgroup_create_ex(struct GPUShader *shader, DRWPass *pass)
@@ -868,13 +1124,9 @@ static DRWShadingGroup *drw_shgroup_create_ex(struct GPUShader *shader, DRWPass
BLI_LINKS_APPEND(&pass->shgroups, shgroup);
shgroup->shader = shader;
- shgroup->state_extra = 0;
- shgroup->state_extra_disable = ~0x0;
- shgroup->stencil_mask = 0;
- shgroup->calls.first = NULL;
- shgroup->calls.last = NULL;
- shgroup->tfeedback_target = NULL;
- shgroup->pass_parent = pass;
+ shgroup->cmd.first = NULL;
+ shgroup->cmd.last = NULL;
+ shgroup->pass_handle = pass->handle;
return shgroup;
}
@@ -975,7 +1227,7 @@ DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader,
BLI_assert(tf_target != NULL);
DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
drw_shgroup_init(shgroup, shader);
- shgroup->tfeedback_target = tf_target;
+ drw_shgroup_uniform_create_ex(shgroup, 0, DRW_UNIFORM_TFEEDBACK_TARGET, tf_target, 0, 1);
return shgroup;
}
@@ -985,37 +1237,42 @@ DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader,
*/
void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state)
{
- shgroup->state_extra |= state;
+ drw_command_set_mutable_state(shgroup, state, 0x0);
}
void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state)
{
- shgroup->state_extra_disable &= ~state;
+ drw_command_set_mutable_state(shgroup, 0x0, state);
}
void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask)
{
- BLI_assert(mask <= 255);
- shgroup->stencil_mask = mask;
-}
-
-bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup)
-{
- return shgroup->calls.first == NULL;
+ drw_command_set_stencil_mask(shgroup, mask);
}
-/* This is a workaround function waiting for the clearing operation to be available inside the
- * shgroups. */
-DRWShadingGroup *DRW_shgroup_get_next(DRWShadingGroup *shgroup)
+void DRW_shgroup_clear_framebuffer(DRWShadingGroup *shgroup,
+ eGPUFrameBufferBits channels,
+ uchar r,
+ uchar g,
+ uchar b,
+ uchar a,
+ float depth,
+ uchar stencil)
{
- return shgroup->next;
+ drw_command_clear(shgroup, channels, r, g, b, a, depth, stencil);
}
-/* This is a workaround function waiting for the clearing operation to be available inside the
- * shgroups. */
-uint DRW_shgroup_stencil_mask_get(DRWShadingGroup *shgroup)
+bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup)
{
- return shgroup->stencil_mask;
+ DRWCommandChunk *chunk = shgroup->cmd.first;
+ for (; chunk; chunk = chunk->next) {
+ for (int i = 0; i < chunk->command_used; i++) {
+ if (command_type_get(chunk->command_type, i) <= DRW_MAX_DRAW_CMD_TYPE) {
+ return false;
+ }
+ }
+ }
+ return true;
}
DRWShadingGroup *DRW_shgroup_create_sub(DRWShadingGroup *shgroup)
@@ -1023,11 +1280,14 @@ DRWShadingGroup *DRW_shgroup_create_sub(DRWShadingGroup *shgroup)
DRWShadingGroup *shgroup_new = BLI_memblock_alloc(DST.vmempool->shgroups);
*shgroup_new = *shgroup;
- shgroup_new->uniforms = NULL;
- shgroup_new->calls.first = NULL;
- shgroup_new->calls.last = NULL;
+ drw_shgroup_init(shgroup_new, shgroup_new->shader);
+ shgroup_new->cmd.first = NULL;
+ shgroup_new->cmd.last = NULL;
- BLI_LINKS_INSERT_AFTER(&shgroup->pass_parent->shgroups, shgroup, shgroup_new);
+ DRWPass *parent_pass = DRW_memblock_elem_from_handle(DST.vmempool->passes,
+ &shgroup->pass_handle);
+
+ BLI_LINKS_INSERT_AFTER(&parent_pass->shgroups, shgroup, shgroup_new);
return shgroup_new;
}
@@ -1522,6 +1782,8 @@ DRWPass *DRW_pass_create(const char *name, DRWState state)
pass->shgroups.first = NULL;
pass->shgroups.last = NULL;
+ pass->handle = DST.pass_handle;
+ DRW_handle_increment(&DST.pass_handle);
return pass;
}
@@ -1565,42 +1827,22 @@ typedef struct ZSortData {
const float *origin;
} ZSortData;
-static int pass_shgroup_dist_sort(void *thunk, const void *a, const void *b)
+static int pass_shgroup_dist_sort(const void *a, const void *b)
{
- const ZSortData *zsortdata = (ZSortData *)thunk;
const DRWShadingGroup *shgrp_a = (const DRWShadingGroup *)a;
const DRWShadingGroup *shgrp_b = (const DRWShadingGroup *)b;
- const DRWCall *call_a = (DRWCall *)shgrp_a->calls.first;
- const DRWCall *call_b = (DRWCall *)shgrp_b->calls.first;
-
- if (call_a == NULL) {
- return -1;
- }
- if (call_b == NULL) {
- return -1;
- }
-
- float tmp[3];
- sub_v3_v3v3(tmp, zsortdata->origin, call_a->state->model[3]);
- const float a_sq = dot_v3v3(zsortdata->axis, tmp);
- sub_v3_v3v3(tmp, zsortdata->origin, call_b->state->model[3]);
- const float b_sq = dot_v3v3(zsortdata->axis, tmp);
-
- if (a_sq < b_sq) {
+ if (shgrp_a->z_sorting.distance < shgrp_b->z_sorting.distance) {
return 1;
}
- else if (a_sq > b_sq) {
+ else if (shgrp_a->z_sorting.distance > shgrp_b->z_sorting.distance) {
return -1;
}
else {
- /* If there is a depth prepass put it before */
- if ((shgrp_a->state_extra & DRW_STATE_WRITE_DEPTH) != 0) {
+ /* If distances are the same, keep original order. */
+ if (shgrp_a->z_sorting.original_index > shgrp_b->z_sorting.original_index) {
return -1;
}
- else if ((shgrp_b->state_extra & DRW_STATE_WRITE_DEPTH) != 0) {
- return 1;
- }
else {
return 0;
}
@@ -1611,35 +1853,61 @@ static int pass_shgroup_dist_sort(void *thunk, const void *a, const void *b)
#define SORT_IMPL_LINKTYPE DRWShadingGroup
-#define SORT_IMPL_USE_THUNK
#define SORT_IMPL_FUNC shgroup_sort_fn_r
#include "../../blenlib/intern/list_sort_impl.h"
#undef SORT_IMPL_FUNC
-#undef SORT_IMPL_USE_THUNK
#undef SORT_IMPL_LINKTYPE
/**
* Sort Shading groups by decreasing Z of their first draw call.
- * This is useful for order dependent effect such as transparency.
+ * This is useful for order dependent effect such as alpha-blending.
*/
void DRW_pass_sort_shgroup_z(DRWPass *pass)
{
const float(*viewinv)[4] = DST.view_active->storage.viewinv;
- ZSortData zsortdata = {viewinv[2], viewinv[3]};
-
- if (pass->shgroups.first && pass->shgroups.first->next) {
- pass->shgroups.first = shgroup_sort_fn_r(
- pass->shgroups.first, pass_shgroup_dist_sort, &zsortdata);
+ if (!(pass->shgroups.first && pass->shgroups.first->next)) {
+ /* Nothing to sort */
+ return;
+ }
- /* Find the next last */
- DRWShadingGroup *last = pass->shgroups.first;
- while ((last = last->next)) {
- /* Do nothing */
+ uint index = 0;
+ DRWShadingGroup *shgroup = pass->shgroups.first;
+ do {
+ DRWResourceHandle handle = 0;
+ /* Find first DRWCommandDraw. */
+ DRWCommandChunk *cmd_chunk = shgroup->cmd.first;
+ for (; cmd_chunk && handle == 0; cmd_chunk = cmd_chunk->next) {
+ for (int i = 0; i < cmd_chunk->command_used && handle == 0; i++) {
+ if (DRW_CMD_DRAW == command_type_get(cmd_chunk->command_type, i)) {
+ handle = cmd_chunk->commands[i].draw.handle;
+ }
+ }
}
- pass->shgroups.last = last;
+ /* To be sorted a shgroup needs to have at least one draw command. */
+ BLI_assert(handle != 0);
+
+ DRWObjectMatrix *obmats = DRW_memblock_elem_from_handle(DST.vmempool->obmats, &handle);
+
+ /* Compute distance to camera. */
+ float tmp[3];
+ sub_v3_v3v3(tmp, viewinv[3], obmats->model[3]);
+ shgroup->z_sorting.distance = dot_v3v3(viewinv[2], tmp);
+ shgroup->z_sorting.original_index = index++;
+
+ } while ((shgroup = shgroup->next));
+
+ /* Sort using computed distances. */
+ pass->shgroups.first = shgroup_sort_fn_r(pass->shgroups.first, pass_shgroup_dist_sort);
+
+ /* Find the new last */
+ DRWShadingGroup *last = pass->shgroups.first;
+ while ((last = last->next)) {
+ /* Reset the pass id for debugging. */
+ last->pass_handle = pass->handle;
}
+ pass->shgroups.last = last;
}
/** \} */
diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c
index 1dcaf39fc19..78da744abf8 100644
--- a/source/blender/draw/intern/draw_manager_exec.c
+++ b/source/blender/draw/intern/draw_manager_exec.c
@@ -36,16 +36,41 @@
# include "GPU_select.h"
#endif
-#ifdef USE_GPU_SELECT
void DRW_select_load_id(uint id)
{
+#ifdef USE_GPU_SELECT
BLI_assert(G.f & G_FLAG_PICKSEL);
DST.select_id = id;
-}
#endif
+}
#define DEBUG_UBO_BINDING
+typedef struct DRWCommandsState {
+ GPUBatch *batch;
+ int resource_chunk;
+ int base_inst;
+ int inst_count;
+ int v_first;
+ int v_count;
+ bool neg_scale;
+ /* Resource location. */
+ int obmats_loc;
+ int obinfos_loc;
+ int baseinst_loc;
+ int chunkid_loc;
+ /* Legacy matrix support. */
+ int obmat_loc;
+ int obinv_loc;
+ int mvp_loc;
+ /* Selection ID state. */
+ GPUVertBuf *select_buf;
+ uint select_id;
+ /* Drawing State */
+ DRWState drw_state_enabled;
+ DRWState drw_state_disabled;
+} DRWCommandsState;
+
/* -------------------------------------------------------------------- */
/** \name Draw State (DRW_state)
* \{ */
@@ -407,9 +432,10 @@ void DRW_state_reset(void)
/** \name Culling (DRW_culling)
* \{ */
-static bool draw_call_is_culled(DRWCall *call, DRWView *view)
+static bool draw_call_is_culled(const DRWResourceHandle *handle, DRWView *view)
{
- return (call->state->culling->mask & view->culling_mask) != 0;
+ DRWCullingState *culling = DRW_memblock_elem_from_handle(DST.vmempool->cullstates, handle);
+ return (culling->mask & view->culling_mask) != 0;
}
/* Set active view for rendering. */
@@ -588,66 +614,96 @@ static void draw_compute_culling(DRWView *view)
/** \name Draw (DRW_draw)
* \{ */
-static void draw_geometry_prepare(DRWShadingGroup *shgroup, DRWCall *call)
+BLI_INLINE void draw_legacy_matrix_update(DRWShadingGroup *shgroup,
+ DRWResourceHandle *handle,
+ float obmat_loc,
+ float obinv_loc,
+ float mvp_loc)
{
- BLI_assert(call);
- DRWCallState *state = call->state;
-
- if (shgroup->model != -1) {
- GPU_shader_uniform_vector(shgroup->shader, shgroup->model, 16, 1, (float *)state->model);
- }
- if (shgroup->modelinverse != -1) {
- GPU_shader_uniform_vector(
- shgroup->shader, shgroup->modelinverse, 16, 1, (float *)state->modelinverse);
- }
- if (shgroup->objectinfo != -1) {
- float infos[4];
- infos[0] = state->ob_index;
- // infos[1]; /* UNUSED. */
- infos[2] = state->ob_random;
- infos[3] = (state->flag & DRW_CALL_NEGSCALE) ? -1.0f : 1.0f;
- GPU_shader_uniform_vector(shgroup->shader, shgroup->objectinfo, 4, 1, (float *)infos);
- }
- if (shgroup->objectcolor != -1) {
- GPU_shader_uniform_vector(
- shgroup->shader, shgroup->objectcolor, 4, 1, (float *)state->ob_color);
+ /* Still supported for compatibility with gpu_shader_* but should be forbidden. */
+ DRWObjectMatrix *ob_mats = DRW_memblock_elem_from_handle(DST.vmempool->obmats, handle);
+ if (obmat_loc != -1) {
+ GPU_shader_uniform_vector(shgroup->shader, obmat_loc, 16, 1, (float *)ob_mats->model);
}
- if (shgroup->orcotexfac != -1) {
- GPU_shader_uniform_vector(
- shgroup->shader, shgroup->orcotexfac, 3, 2, (float *)state->orcotexfac);
+ if (obinv_loc != -1) {
+ GPU_shader_uniform_vector(shgroup->shader, obinv_loc, 16, 1, (float *)ob_mats->modelinverse);
}
/* Still supported for compatibility with gpu_shader_* but should be forbidden
* and is slow (since it does not cache the result). */
- if (shgroup->modelviewprojection != -1) {
+ if (mvp_loc != -1) {
float mvp[4][4];
- mul_m4_m4m4(mvp, DST.view_active->storage.persmat, state->model);
- GPU_shader_uniform_vector(shgroup->shader, shgroup->modelviewprojection, 16, 1, (float *)mvp);
+ mul_m4_m4m4(mvp, DST.view_active->storage.persmat, ob_mats->model);
+ GPU_shader_uniform_vector(shgroup->shader, mvp_loc, 16, 1, (float *)mvp);
}
}
+BLI_INLINE void draw_geometry_bind(DRWShadingGroup *shgroup, GPUBatch *geom)
+{
+ /* XXX hacking #GPUBatch. we don't want to call glUseProgram! (huge performance loss) */
+ if (DST.batch) {
+ DST.batch->program_in_use = false;
+ }
+
+ DST.batch = geom;
+
+ GPU_batch_program_set_no_use(
+ geom, GPU_shader_get_program(shgroup->shader), GPU_shader_get_interface(shgroup->shader));
+
+ geom->program_in_use = true; /* XXX hacking #GPUBatch */
+
+ GPU_batch_bind(geom);
+}
+
BLI_INLINE void draw_geometry_execute(DRWShadingGroup *shgroup,
GPUBatch *geom,
- uint vert_first,
- uint vert_count,
- uint inst_first,
- uint inst_count)
+ int vert_first,
+ int vert_count,
+ int inst_first,
+ int inst_count,
+ int baseinst_loc)
{
+ /* inst_count can be -1. */
+ inst_count = max_ii(0, inst_count);
+
+ if (baseinst_loc != -1) {
+ /* Fallback when ARB_shader_draw_parameters is not supported. */
+ GPU_shader_uniform_vector_int(shgroup->shader, baseinst_loc, 1, 1, (int *)&inst_first);
+ /* Avoids VAO reconfiguration on older hardware. (see GPU_batch_draw_advanced) */
+ inst_first = 0;
+ }
+
/* bind vertex array */
if (DST.batch != geom) {
- DST.batch = geom;
-
- GPU_batch_program_set_no_use(
- geom, GPU_shader_get_program(shgroup->shader), GPU_shader_get_interface(shgroup->shader));
-
- GPU_batch_bind(geom);
+ draw_geometry_bind(shgroup, geom);
}
- /* XXX hacking #GPUBatch. we don't want to call glUseProgram! (huge performance loss) */
- geom->program_in_use = true;
-
GPU_batch_draw_advanced(geom, vert_first, vert_count, inst_first, inst_count);
+}
- geom->program_in_use = false; /* XXX hacking #GPUBatch */
+BLI_INLINE void draw_indirect_call(DRWShadingGroup *shgroup, DRWCommandsState *state)
+{
+ if (state->inst_count == 0) {
+ return;
+ }
+ if (state->baseinst_loc == -1) {
+ /* bind vertex array */
+ if (DST.batch != state->batch) {
+ GPU_draw_list_submit(DST.draw_list);
+ draw_geometry_bind(shgroup, state->batch);
+ }
+ GPU_draw_list_command_add(
+ DST.draw_list, state->v_first, state->v_count, state->base_inst, state->inst_count);
+ }
+ /* Fallback when unsupported */
+ else {
+ draw_geometry_execute(shgroup,
+ state->batch,
+ state->v_first,
+ state->v_count,
+ state->base_inst,
+ state->inst_count,
+ state->baseinst_loc);
+ }
}
enum {
@@ -719,6 +775,9 @@ static void bind_ubo(GPUUniformBuffer *ubo, char bind_type)
/* UBO isn't bound yet. Find an empty slot and bind it. */
idx = get_empty_slot_index(DST.RST.bound_ubo_slots);
+ /* [0..1] are reserved ubo slots. */
+ idx += 2;
+
if (idx < GPU_max_ubo_binds()) {
GPUUniformBuffer **gpu_ubo_slot = &DST.RST.bound_ubos[idx];
/* Unbind any previous UBO. */
@@ -738,10 +797,13 @@ static void bind_ubo(GPUUniformBuffer *ubo, char bind_type)
}
}
else {
+ BLI_assert(idx < 64);
/* This UBO slot was released but the UBO is
* still bound here. Just flag the slot again. */
BLI_assert(DST.RST.bound_ubos[idx] == ubo);
}
+ /* Remove offset for flag bitfield. */
+ idx -= 2;
set_bound_flags(&DST.RST.bound_ubo_slots, &DST.RST.bound_ubo_slots_persist, idx, bind_type);
}
@@ -785,8 +847,12 @@ static bool ubo_bindings_validate(DRWShadingGroup *shgroup)
printf("Trying to draw with missing UBO binding.\n");
valid = false;
}
+
+ DRWPass *parent_pass = DRW_memblock_elem_from_handle(DST.vmempool->passes,
+ &shgroup->pass_handle);
+
printf("Pass : %s, Shader : %s, Block : %s\n",
- shgroup->pass_parent->name,
+ parent_pass->name,
shgroup->shader->name,
blockname);
}
@@ -818,119 +884,331 @@ static void release_ubo_slots(bool with_persist)
}
}
-static void draw_update_uniforms(DRWShadingGroup *shgroup)
+static void draw_update_uniforms(DRWShadingGroup *shgroup,
+ DRWCommandsState *state,
+ bool *use_tfeedback)
{
- for (DRWUniform *uni = shgroup->uniforms; uni; uni = uni->next) {
- GPUTexture *tex;
- GPUUniformBuffer *ubo;
- if (uni->location == -2) {
- uni->location = GPU_shader_get_uniform_ensure(shgroup->shader,
- DST.uniform_names.buffer + uni->name_ofs);
- if (uni->location == -1) {
- continue;
+ for (DRWUniformChunk *unichunk = shgroup->uniforms; unichunk; unichunk = unichunk->next) {
+ DRWUniform *uni = unichunk->uniforms;
+ for (int i = 0; i < unichunk->uniform_used; i++, uni++) {
+ GPUTexture *tex;
+ GPUUniformBuffer *ubo;
+ if (uni->location == -2) {
+ uni->location = GPU_shader_get_uniform_ensure(shgroup->shader,
+ DST.uniform_names.buffer + uni->name_ofs);
+ if (uni->location == -1) {
+ continue;
+ }
+ }
+ const void *data = uni->pvalue;
+ if (ELEM(uni->type, DRW_UNIFORM_INT_COPY, DRW_UNIFORM_FLOAT_COPY)) {
+ data = uni->fvalue;
+ }
+ switch (uni->type) {
+ case DRW_UNIFORM_INT_COPY:
+ case DRW_UNIFORM_INT:
+ GPU_shader_uniform_vector_int(
+ shgroup->shader, uni->location, uni->length, uni->arraysize, data);
+ break;
+ case DRW_UNIFORM_FLOAT_COPY:
+ case DRW_UNIFORM_FLOAT:
+ GPU_shader_uniform_vector(
+ shgroup->shader, uni->location, uni->length, uni->arraysize, data);
+ break;
+ case DRW_UNIFORM_TEXTURE:
+ tex = (GPUTexture *)uni->pvalue;
+ BLI_assert(tex);
+ bind_texture(tex, BIND_TEMP);
+ GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
+ break;
+ case DRW_UNIFORM_TEXTURE_PERSIST:
+ tex = (GPUTexture *)uni->pvalue;
+ BLI_assert(tex);
+ bind_texture(tex, BIND_PERSIST);
+ GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
+ break;
+ case DRW_UNIFORM_TEXTURE_REF:
+ tex = *((GPUTexture **)uni->pvalue);
+ BLI_assert(tex);
+ bind_texture(tex, BIND_TEMP);
+ GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
+ break;
+ case DRW_UNIFORM_BLOCK:
+ ubo = (GPUUniformBuffer *)uni->pvalue;
+ bind_ubo(ubo, BIND_TEMP);
+ GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
+ break;
+ case DRW_UNIFORM_BLOCK_PERSIST:
+ ubo = (GPUUniformBuffer *)uni->pvalue;
+ bind_ubo(ubo, BIND_PERSIST);
+ GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
+ break;
+ case DRW_UNIFORM_BLOCK_OBMATS:
+ state->obmats_loc = uni->location;
+ ubo = DST.vmempool->matrices_ubo[0];
+ GPU_uniformbuffer_bind(ubo, 0);
+ GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
+ break;
+ case DRW_UNIFORM_BLOCK_OBINFOS:
+ state->obinfos_loc = uni->location;
+ ubo = DST.vmempool->obinfos_ubo[0];
+ GPU_uniformbuffer_bind(ubo, 1);
+ GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
+ break;
+ case DRW_UNIFORM_RESOURCE_CHUNK:
+ state->chunkid_loc = uni->location;
+ GPU_shader_uniform_int(shgroup->shader, uni->location, 0);
+ break;
+ case DRW_UNIFORM_TFEEDBACK_TARGET:
+ BLI_assert(data && (*use_tfeedback == false));
+ *use_tfeedback = GPU_shader_transform_feedback_enable(shgroup->shader,
+ ((GPUVertBuf *)data)->vbo_id);
+ break;
+ /* Legacy/Fallback support. */
+ case DRW_UNIFORM_BASE_INSTANCE:
+ state->baseinst_loc = uni->location;
+ break;
+ case DRW_UNIFORM_MODEL_MATRIX:
+ state->obmat_loc = uni->location;
+ break;
+ case DRW_UNIFORM_MODEL_MATRIX_INVERSE:
+ state->obinv_loc = uni->location;
+ break;
+ case DRW_UNIFORM_MODELVIEWPROJECTION_MATRIX:
+ state->mvp_loc = uni->location;
+ break;
}
- }
- const void *data = uni->pvalue;
- if (ELEM(uni->type, DRW_UNIFORM_INT_COPY, DRW_UNIFORM_FLOAT_COPY)) {
- data = uni->fvalue;
- }
- switch (uni->type) {
- case DRW_UNIFORM_INT_COPY:
- case DRW_UNIFORM_INT:
- GPU_shader_uniform_vector_int(
- shgroup->shader, uni->location, uni->length, uni->arraysize, data);
- break;
- case DRW_UNIFORM_FLOAT_COPY:
- case DRW_UNIFORM_FLOAT:
- GPU_shader_uniform_vector(
- shgroup->shader, uni->location, uni->length, uni->arraysize, data);
- break;
- case DRW_UNIFORM_TEXTURE:
- tex = (GPUTexture *)uni->pvalue;
- BLI_assert(tex);
- bind_texture(tex, BIND_TEMP);
- GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
- break;
- case DRW_UNIFORM_TEXTURE_PERSIST:
- tex = (GPUTexture *)uni->pvalue;
- BLI_assert(tex);
- bind_texture(tex, BIND_PERSIST);
- GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
- break;
- case DRW_UNIFORM_TEXTURE_REF:
- tex = *((GPUTexture **)uni->pvalue);
- BLI_assert(tex);
- bind_texture(tex, BIND_TEMP);
- GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
- break;
- case DRW_UNIFORM_BLOCK:
- ubo = (GPUUniformBuffer *)uni->pvalue;
- bind_ubo(ubo, BIND_TEMP);
- GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
- break;
- case DRW_UNIFORM_BLOCK_PERSIST:
- ubo = (GPUUniformBuffer *)uni->pvalue;
- bind_ubo(ubo, BIND_PERSIST);
- GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
- break;
}
}
BLI_assert(ubo_bindings_validate(shgroup));
}
-BLI_INLINE bool draw_select_do_call(DRWShadingGroup *shgroup, DRWCall *call)
+BLI_INLINE void draw_select_buffer(DRWShadingGroup *shgroup,
+ DRWCommandsState *state,
+ GPUBatch *batch,
+ const DRWResourceHandle *handle)
{
-#ifdef USE_GPU_SELECT
- if ((G.f & G_FLAG_PICKSEL) == 0) {
- return false;
+ const bool is_instancing = (batch->inst != NULL);
+ int start = 0;
+ int count = 1;
+ int tot = is_instancing ? batch->inst->vertex_len : batch->verts[0]->vertex_len;
+ /* Hack : get "vbo" data without actually drawing. */
+ int *select_id = (void *)state->select_buf->data;
+
+ /* Batching */
+ if (!is_instancing) {
+ /* FIXME: Meh a bit nasty. */
+ if (batch->gl_prim_type == convert_prim_type_to_gl(GPU_PRIM_TRIS)) {
+ count = 3;
+ }
+ else if (batch->gl_prim_type == convert_prim_type_to_gl(GPU_PRIM_LINES)) {
+ count = 2;
+ }
}
- if (call->inst_selectid != NULL) {
- const bool is_instancing = (call->inst_count != 0);
- uint start = 0;
- uint count = 1;
- uint tot = is_instancing ? call->inst_count : call->vert_count;
- /* Hack : get vbo data without actually drawing. */
- GPUVertBufRaw raw;
- GPU_vertbuf_attr_get_raw_data(call->inst_selectid, 0, &raw);
- int *select_id = GPU_vertbuf_raw_step(&raw);
-
- /* Batching */
- if (!is_instancing) {
- /* FIXME: Meh a bit nasty. */
- if (call->batch->gl_prim_type == convert_prim_type_to_gl(GPU_PRIM_TRIS)) {
- count = 3;
- }
- else if (call->batch->gl_prim_type == convert_prim_type_to_gl(GPU_PRIM_LINES)) {
- count = 2;
- }
+
+ while (start < tot) {
+ GPU_select_load_id(select_id[start]);
+ if (is_instancing) {
+ draw_geometry_execute(shgroup, batch, 0, 0, start, count, state->baseinst_loc);
+ }
+ else {
+ draw_geometry_execute(
+ shgroup, batch, start, count, DRW_handle_id_get(handle), 0, state->baseinst_loc);
}
+ start += count;
+ }
+}
- while (start < tot) {
- GPU_select_load_id(select_id[start]);
- if (is_instancing) {
- draw_geometry_execute(shgroup, call->batch, 0, 0, start, count);
- }
- else {
- draw_geometry_execute(shgroup, call->batch, start, count, 0, 0);
+typedef struct DRWCommandIterator {
+ int cmd_index;
+ DRWCommandChunk *curr_chunk;
+} DRWCommandIterator;
+
+static void draw_command_iter_begin(DRWCommandIterator *iter, DRWShadingGroup *shgroup)
+{
+ iter->curr_chunk = shgroup->cmd.first;
+ iter->cmd_index = 0;
+}
+
+static DRWCommand *draw_command_iter_step(DRWCommandIterator *iter, eDRWCommandType *cmd_type)
+{
+ if (iter->curr_chunk) {
+ if (iter->cmd_index == iter->curr_chunk->command_len) {
+ iter->curr_chunk = iter->curr_chunk->next;
+ iter->cmd_index = 0;
+ }
+ if (iter->curr_chunk) {
+ *cmd_type = command_type_get(iter->curr_chunk->command_type, iter->cmd_index);
+ if (iter->cmd_index < iter->curr_chunk->command_used) {
+ return iter->curr_chunk->commands + iter->cmd_index++;
}
- start += count;
}
- return true;
}
+ return NULL;
+}
+
+static void draw_call_resource_bind(DRWCommandsState *state, const DRWResourceHandle *handle)
+{
+ /* Front face is not a resource but it is inside the resource handle. */
+ bool neg_scale = DRW_handle_negative_scale_get(handle);
+ if (neg_scale != state->neg_scale) {
+ glFrontFace((neg_scale) ? GL_CW : GL_CCW);
+ state->neg_scale = neg_scale;
+ }
+
+ int chunk = DRW_handle_chunk_get(handle);
+ if (state->resource_chunk != chunk) {
+ if (state->chunkid_loc != -1) {
+ GPU_shader_uniform_int(NULL, state->chunkid_loc, chunk);
+ }
+ if (state->obmats_loc != -1) {
+ GPU_uniformbuffer_unbind(DST.vmempool->matrices_ubo[state->resource_chunk]);
+ GPU_uniformbuffer_bind(DST.vmempool->matrices_ubo[chunk], 0);
+ }
+ if (state->obinfos_loc != -1) {
+ GPU_uniformbuffer_unbind(DST.vmempool->obinfos_ubo[state->resource_chunk]);
+ GPU_uniformbuffer_bind(DST.vmempool->obinfos_ubo[chunk], 1);
+ }
+ state->resource_chunk = chunk;
+ }
+}
+
+static void draw_call_batching_flush(DRWShadingGroup *shgroup, DRWCommandsState *state)
+{
+ draw_indirect_call(shgroup, state);
+ GPU_draw_list_submit(DST.draw_list);
+
+ state->batch = NULL;
+ state->inst_count = 0;
+ state->base_inst = -1;
+}
+
+static void draw_call_single_do(DRWShadingGroup *shgroup,
+ DRWCommandsState *state,
+ GPUBatch *batch,
+ DRWResourceHandle handle,
+ int vert_first,
+ int vert_count,
+ int inst_count)
+{
+ draw_call_batching_flush(shgroup, state);
+
+ draw_call_resource_bind(state, &handle);
+
+ /* TODO This is Legacy. Need to be removed. */
+ if (state->obmats_loc == -1 &&
+ (state->obmat_loc != -1 || state->obinv_loc != -1 || state->mvp_loc != -1)) {
+ draw_legacy_matrix_update(
+ shgroup, &handle, state->obmat_loc, state->obinv_loc, state->mvp_loc);
+ }
+
+ if (G.f & G_FLAG_PICKSEL) {
+ if (state->select_buf != NULL) {
+ draw_select_buffer(shgroup, state, batch, &handle);
+ return;
+ }
+ else {
+ GPU_select_load_id(state->select_id);
+ }
+ }
+
+ draw_geometry_execute(shgroup,
+ batch,
+ vert_first,
+ vert_count,
+ DRW_handle_id_get(&handle),
+ inst_count,
+ state->baseinst_loc);
+}
+
+static void draw_call_batching_start(DRWCommandsState *state)
+{
+ state->neg_scale = false;
+ state->resource_chunk = 0;
+ state->base_inst = 0;
+ state->inst_count = 0;
+ state->v_first = 0;
+ state->v_count = 0;
+ state->batch = NULL;
+
+ state->select_id = -1;
+ state->select_buf = NULL;
+}
+
+/* NOTE: Does not support batches with instancing VBOs. */
+static void draw_call_batching_do(DRWShadingGroup *shgroup,
+ DRWCommandsState *state,
+ DRWCommandDraw *call)
+{
+ /* If any condition requires to interupt the merging. */
+ bool neg_scale = DRW_handle_negative_scale_get(&call->handle);
+ int chunk = DRW_handle_chunk_get(&call->handle);
+ int id = DRW_handle_id_get(&call->handle);
+ if ((state->neg_scale != neg_scale) || /* Need to change state. */
+ (state->resource_chunk != chunk) || /* Need to change UBOs. */
+ (state->batch != call->batch) /* Need to change VAO. */
+ ) {
+ draw_call_batching_flush(shgroup, state);
+
+ state->batch = call->batch;
+ state->v_first = (call->batch->elem) ? call->batch->elem->index_start : 0;
+ state->v_count = (call->batch->elem) ? call->batch->elem->index_len :
+ call->batch->verts[0]->vertex_len;
+ state->inst_count = 1;
+ state->base_inst = id;
+
+ draw_call_resource_bind(state, &call->handle);
+
+ GPU_draw_list_init(DST.draw_list, state->batch);
+ }
+ /* Is the id consecutive? */
+ else if (id != state->base_inst + state->inst_count) {
+ /* We need to add a draw command for the pending instances. */
+ draw_indirect_call(shgroup, state);
+ state->inst_count = 1;
+ state->base_inst = id;
+ }
+ /* We avoid a drawcall by merging with the precedent
+ * drawcall using instancing. */
else {
- GPU_select_load_id(call->select_id);
- return false;
+ state->inst_count++;
+ }
+}
+
+/* Flush remaining pending drawcalls. */
+static void draw_call_batching_finish(DRWShadingGroup *shgroup, DRWCommandsState *state)
+{
+ draw_call_batching_flush(shgroup, state);
+
+ /* Reset state */
+ if (state->neg_scale) {
+ glFrontFace(GL_CCW);
+ }
+ if (state->obmats_loc != -1) {
+ GPU_uniformbuffer_unbind(DST.vmempool->matrices_ubo[state->resource_chunk]);
+ }
+ if (state->obinfos_loc != -1) {
+ GPU_uniformbuffer_unbind(DST.vmempool->obinfos_ubo[state->resource_chunk]);
}
-#else
- return false;
-#endif
}
static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
{
BLI_assert(shgroup->shader);
+ DRWCommandsState state = {
+ .obmats_loc = -1,
+ .obinfos_loc = -1,
+ .baseinst_loc = -1,
+ .chunkid_loc = -1,
+ .obmat_loc = -1,
+ .obinv_loc = -1,
+ .mvp_loc = -1,
+ .drw_state_enabled = 0,
+ .drw_state_disabled = 0,
+ };
+
const bool shader_changed = (DST.shader != shgroup->shader);
bool use_tfeedback = false;
@@ -940,56 +1218,116 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
}
GPU_shader_bind(shgroup->shader);
DST.shader = shgroup->shader;
+ /* XXX hacking gawain */
+ if (DST.batch) {
+ DST.batch->program_in_use = false;
+ }
DST.batch = NULL;
}
- if (shgroup->tfeedback_target != NULL) {
- use_tfeedback = GPU_shader_transform_feedback_enable(shgroup->shader,
- shgroup->tfeedback_target->vbo_id);
- }
-
release_ubo_slots(shader_changed);
release_texture_slots(shader_changed);
- drw_state_set((pass_state & shgroup->state_extra_disable) | shgroup->state_extra);
- drw_stencil_set(shgroup->stencil_mask);
+ draw_update_uniforms(shgroup, &state, &use_tfeedback);
- draw_update_uniforms(shgroup);
+ drw_state_set(pass_state);
/* Rendering Calls */
{
- bool prev_neg_scale = false;
- int callid = 0;
- for (DRWCall *call = shgroup->calls.first; call; call = call->next) {
-
- if (draw_call_is_culled(call, DST.view_active)) {
- continue;
- }
-
- /* XXX small exception/optimisation for outline rendering. */
- if (shgroup->callid != -1) {
- GPU_shader_uniform_vector_int(shgroup->shader, shgroup->callid, 1, 1, &callid);
- callid += 1;
- }
-
- /* Negative scale objects */
- bool neg_scale = call->state->flag & DRW_CALL_NEGSCALE;
- if (neg_scale != prev_neg_scale) {
- glFrontFace((neg_scale) ? GL_CW : GL_CCW);
- prev_neg_scale = neg_scale;
+ DRWCommandIterator iter;
+ DRWCommand *cmd;
+ eDRWCommandType cmd_type;
+
+ draw_command_iter_begin(&iter, shgroup);
+
+ draw_call_batching_start(&state);
+
+ while ((cmd = draw_command_iter_step(&iter, &cmd_type))) {
+
+ switch (cmd_type) {
+ case DRW_CMD_DRWSTATE:
+ case DRW_CMD_STENCIL:
+ draw_call_batching_flush(shgroup, &state);
+ break;
+ case DRW_CMD_DRAW:
+ case DRW_CMD_DRAW_PROCEDURAL:
+ case DRW_CMD_DRAW_INSTANCE:
+ if (draw_call_is_culled(&cmd->instance.handle, DST.view_active)) {
+ continue;
+ }
+ break;
+ default:
+ break;
}
- draw_geometry_prepare(shgroup, call);
-
- if (draw_select_do_call(shgroup, call)) {
- continue;
+ switch (cmd_type) {
+ case DRW_CMD_CLEAR:
+ GPU_framebuffer_clear(
+#ifndef NDEBUG
+ GPU_framebuffer_active_get(),
+#else
+ NULL,
+#endif
+ cmd->clear.clear_channels,
+ (float[4]){cmd->clear.r / 255.0f,
+ cmd->clear.g / 255.0f,
+ cmd->clear.b / 255.0f,
+ cmd->clear.a / 255.0f},
+ cmd->clear.depth,
+ cmd->clear.stencil);
+ break;
+ case DRW_CMD_DRWSTATE:
+ state.drw_state_enabled |= cmd->state.enable;
+ state.drw_state_disabled |= cmd->state.disable;
+ drw_state_set((pass_state & ~state.drw_state_disabled) | state.drw_state_enabled);
+ break;
+ case DRW_CMD_STENCIL:
+ drw_stencil_set(cmd->stencil.mask);
+ break;
+ case DRW_CMD_SELECTID:
+ state.select_id = cmd->select_id.select_id;
+ state.select_buf = cmd->select_id.select_buf;
+ break;
+ case DRW_CMD_DRAW:
+ if (!USE_BATCHING || state.obmats_loc == -1 || (G.f & G_FLAG_PICKSEL) ||
+ cmd->draw.batch->inst) {
+ draw_call_single_do(shgroup, &state, cmd->draw.batch, cmd->draw.handle, 0, 0, 0);
+ }
+ else {
+ draw_call_batching_do(shgroup, &state, &cmd->draw);
+ }
+ break;
+ case DRW_CMD_DRAW_PROCEDURAL:
+ draw_call_single_do(shgroup,
+ &state,
+ cmd->procedural.batch,
+ cmd->procedural.handle,
+ 0,
+ cmd->procedural.vert_count,
+ 1);
+ break;
+ case DRW_CMD_DRAW_INSTANCE:
+ draw_call_single_do(shgroup,
+ &state,
+ cmd->instance.batch,
+ cmd->instance.handle,
+ 0,
+ 0,
+ cmd->instance.inst_count);
+ break;
+ case DRW_CMD_DRAW_RANGE:
+ draw_call_single_do(shgroup,
+ &state,
+ cmd->range.batch,
+ (DRWResourceHandle)0,
+ cmd->range.vert_first,
+ cmd->range.vert_count,
+ 1);
+ break;
}
-
- draw_geometry_execute(
- shgroup, call->batch, call->vert_first, call->vert_count, 0, call->inst_count);
}
- /* Reset state */
- glFrontFace(GL_CCW);
+
+ draw_call_batching_finish(shgroup, &state);
}
if (use_tfeedback) {
@@ -1065,6 +1403,11 @@ static void drw_draw_pass_ex(DRWPass *pass,
DST.shader = NULL;
}
+ if (DST.batch) {
+ DST.batch->program_in_use = false;
+ DST.batch = NULL;
+ }
+
/* HACK: Rasterized discard can affect clear commands which are not
* part of a DRWPass (as of now). So disable rasterized discard here
* if it has been enabled. */
diff --git a/source/blender/draw/modes/edit_curve_mode.c b/source/blender/draw/modes/edit_curve_mode.c
index 3d8994191ca..afaaba0712f 100644
--- a/source/blender/draw/modes/edit_curve_mode.c
+++ b/source/blender/draw/modes/edit_curve_mode.c
@@ -126,7 +126,7 @@ static void EDIT_CURVE_engine_init(void *UNUSED(vedata))
datatoc_edit_curve_overlay_normals_vert_glsl,
NULL},
.frag = (const char *[]){datatoc_gpu_shader_uniform_color_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
+ .defs = (const char *[]){sh_cfg_data->def, "#define IN_PLACE_INSTANCES\n", NULL},
});
}
diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c
index ba5ecb143ae..dc7523e4091 100644
--- a/source/blender/draw/modes/object_mode.c
+++ b/source/blender/draw/modes/object_mode.c
@@ -286,15 +286,10 @@ typedef struct OBJECT_PrivateData {
DRWShadingGroup *outlines_transform;
/* Lightprobes */
- DRWCallBuffer *lightprobes_cube_select;
- DRWCallBuffer *lightprobes_cube_select_dupli;
- DRWCallBuffer *lightprobes_cube_active;
- DRWCallBuffer *lightprobes_cube_transform;
-
- DRWCallBuffer *lightprobes_planar_select;
- DRWCallBuffer *lightprobes_planar_select_dupli;
- DRWCallBuffer *lightprobes_planar_active;
- DRWCallBuffer *lightprobes_planar_transform;
+ DRWShadingGroup *probe_outlines_transform;
+ DRWShadingGroup *probe_outlines_select;
+ DRWShadingGroup *probe_outlines_select_dupli;
+ DRWShadingGroup *probe_outlines_active;
/* Objects Centers */
DRWCallBuffer *center_active;
@@ -303,17 +298,6 @@ typedef struct OBJECT_PrivateData {
DRWCallBuffer *center_selected_lib;
DRWCallBuffer *center_deselected_lib;
- /* Outlines id offset (accessed as an array) */
- int id_ofs_active;
- int id_ofs_select;
- int id_ofs_select_dupli;
- int id_ofs_transform;
-
- int id_ofs_prb_active;
- int id_ofs_prb_select;
- int id_ofs_prb_select_dupli;
- int id_ofs_prb_transform;
-
bool xray_enabled;
bool xray_enabled_and_not_wire;
} OBJECT_PrivateData; /* Transient data */
@@ -417,7 +401,10 @@ static void OBJECT_engine_init(void *vedata)
if (!sh_data->outline_resolve) {
/* Outline */
sh_data->outline_prepass = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib, datatoc_gpu_shader_3D_vert_glsl, NULL},
+ .vert = (const char *[]){sh_cfg_data->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_object_outline_prepass_vert_glsl,
+ NULL},
.frag = (const char *[]){datatoc_object_outline_prepass_frag_glsl, NULL},
.defs = (const char *[]){sh_cfg_data->def, NULL},
});
@@ -431,7 +418,7 @@ static void OBJECT_engine_init(void *vedata)
datatoc_object_outline_prepass_geom_glsl,
NULL},
.frag = (const char *[]){datatoc_object_outline_prepass_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
+ .defs = (const char *[]){sh_cfg_data->def, "#define USE_GEOM\n", NULL},
});
sh_data->outline_resolve = DRW_shader_create_fullscreen(
@@ -539,10 +526,11 @@ static void OBJECT_engine_init(void *vedata)
/* Lightprobes */
sh_data->lightprobe_grid = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg_data->lib,
+ datatoc_common_view_lib_glsl,
datatoc_common_globals_lib_glsl,
datatoc_object_lightprobe_grid_vert_glsl,
NULL},
- .frag = (const char *[]){datatoc_gpu_shader_flat_id_frag_glsl, NULL},
+ .frag = (const char *[]){datatoc_object_outline_prepass_frag_glsl, NULL},
.defs = (const char *[]){sh_cfg_data->def, NULL},
});
@@ -697,12 +685,12 @@ static void OBJECT_engine_free(void)
}
static DRWShadingGroup *shgroup_outline(DRWPass *pass,
- const int *ofs,
+ int outline_id,
GPUShader *sh,
eGPUShaderConfig sh_cfg)
{
DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_int(grp, "baseId", ofs, 1);
+ DRW_shgroup_uniform_int_copy(grp, "outlineId", outline_id);
if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
@@ -741,128 +729,89 @@ static DRWShadingGroup *shgroup_points(DRWPass *pass,
return grp;
}
-static int *shgroup_theme_id_to_probe_outline_counter(OBJECT_StorageList *stl,
- int theme_id,
- const int base_flag)
-{
- if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) {
- switch (theme_id) {
- case TH_ACTIVE:
- case TH_SELECT:
- return &stl->g_data->id_ofs_prb_select_dupli;
- case TH_TRANSFORM:
- default:
- return &stl->g_data->id_ofs_prb_transform;
- }
- }
-
- switch (theme_id) {
- case TH_ACTIVE:
- return &stl->g_data->id_ofs_prb_active;
- case TH_SELECT:
- return &stl->g_data->id_ofs_prb_select;
- case TH_TRANSFORM:
- default:
- return &stl->g_data->id_ofs_prb_transform;
- }
-}
-
-static int *shgroup_theme_id_to_outline_counter(OBJECT_StorageList *stl,
- int theme_id,
- const int base_flag)
+static DRWShadingGroup *shgroup_theme_id_to_outline_or_null(OBJECT_StorageList *stl,
+ int theme_id,
+ const int base_flag)
{
if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) {
switch (theme_id) {
case TH_ACTIVE:
case TH_SELECT:
- return &stl->g_data->id_ofs_select_dupli;
+ return stl->g_data->outlines_select_dupli;
case TH_TRANSFORM:
+ return stl->g_data->outlines_transform;
default:
- return &stl->g_data->id_ofs_transform;
+ return NULL;
}
}
switch (theme_id) {
case TH_ACTIVE:
- return &stl->g_data->id_ofs_active;
- case TH_SELECT:
- return &stl->g_data->id_ofs_select;
- case TH_TRANSFORM:
- default:
- return &stl->g_data->id_ofs_transform;
- }
-}
-
-static DRWCallBuffer *buffer_theme_id_to_probe_planar_outline_shgrp(OBJECT_StorageList *stl,
- int theme_id)
-{
- /* does not increment counter */
- switch (theme_id) {
- case TH_ACTIVE:
- return stl->g_data->lightprobes_planar_active;
+ return stl->g_data->outlines_active;
case TH_SELECT:
- return stl->g_data->lightprobes_planar_select;
+ return stl->g_data->outlines_select;
case TH_TRANSFORM:
+ return stl->g_data->outlines_transform;
default:
- return stl->g_data->lightprobes_planar_transform;
+ return NULL;
}
}
-static DRWCallBuffer *buffer_theme_id_to_probe_cube_outline_shgrp(OBJECT_StorageList *stl,
+static DRWShadingGroup *shgroup_theme_id_to_probe_outline_or_null(OBJECT_StorageList *stl,
int theme_id,
const int base_flag)
{
- /* does not increment counter */
+ if (UNLIKELY(DRW_state_is_select())) {
+ return stl->g_data->probe_outlines_select;
+ }
+
if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) {
switch (theme_id) {
case TH_ACTIVE:
case TH_SELECT:
- return stl->g_data->lightprobes_cube_select_dupli;
+ return stl->g_data->probe_outlines_select_dupli;
case TH_TRANSFORM:
+ return stl->g_data->probe_outlines_transform;
default:
- return stl->g_data->lightprobes_cube_transform;
+ return NULL;
}
}
switch (theme_id) {
case TH_ACTIVE:
- return stl->g_data->lightprobes_cube_active;
+ return stl->g_data->probe_outlines_active;
case TH_SELECT:
- return stl->g_data->lightprobes_cube_select;
+ return stl->g_data->probe_outlines_select;
case TH_TRANSFORM:
+ return stl->g_data->probe_outlines_transform;
default:
- return stl->g_data->lightprobes_cube_transform;
+ return NULL;
}
}
-static DRWShadingGroup *shgroup_theme_id_to_outline_or_null(OBJECT_StorageList *stl,
- int theme_id,
- const int base_flag)
+static int shgroup_theme_id_to_outline_id(int theme_id, const int base_flag)
{
- int *counter = shgroup_theme_id_to_outline_counter(stl, theme_id, base_flag);
- *counter += 1;
-
if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) {
switch (theme_id) {
case TH_ACTIVE:
case TH_SELECT:
- return stl->g_data->outlines_select_dupli;
+ return 2;
case TH_TRANSFORM:
- return stl->g_data->outlines_transform;
+ return 0;
default:
- return NULL;
+ return -1;
}
}
switch (theme_id) {
case TH_ACTIVE:
- return stl->g_data->outlines_active;
+ return 3;
case TH_SELECT:
- return stl->g_data->outlines_select;
+ return 1;
case TH_TRANSFORM:
- return stl->g_data->outlines_transform;
+ return 0;
default:
- return NULL;
+ return -1;
}
}
@@ -1346,7 +1295,8 @@ static void OBJECT_cache_init(void *vedata)
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
OBJECT_PrivateData *g_data;
const DRWContextState *draw_ctx = DRW_context_state_get();
- OBJECT_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ eGPUShaderConfig cfg = draw_ctx->sh_cfg;
+ OBJECT_Shaders *sh_data = &e_data.sh_data[cfg];
const float outline_width = UI_GetThemeValuef(TH_OUTLINE_WIDTH);
const bool do_outline_expand = (U.pixelsize > 1.0) || (outline_width > 2.0f);
@@ -1367,59 +1317,25 @@ static void OBJECT_cache_init(void *vedata)
{
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- psl->outlines = DRW_pass_create("Outlines Depth Pass", state);
+ psl->lightprobes = DRW_pass_create("Outlines Probe Pass", state);
GPUShader *sh = sh_data->outline_prepass;
+ g_data->probe_outlines_transform = shgroup_outline(psl->lightprobes, 0, sh, cfg);
+ g_data->probe_outlines_select = shgroup_outline(psl->lightprobes, 1, sh, cfg);
+ g_data->probe_outlines_select_dupli = shgroup_outline(psl->lightprobes, 2, sh, cfg);
+ g_data->probe_outlines_active = shgroup_outline(psl->lightprobes, 3, sh, cfg);
+
+ psl->outlines = DRW_pass_create("Outlines Depth Pass", state);
+
if (g_data->xray_enabled_and_not_wire) {
sh = sh_data->outline_prepass_wire;
}
- g_data->outlines_select = shgroup_outline(
- psl->outlines, &g_data->id_ofs_select, sh, draw_ctx->sh_cfg);
- g_data->outlines_select_dupli = shgroup_outline(
- psl->outlines, &g_data->id_ofs_select_dupli, sh, draw_ctx->sh_cfg);
- g_data->outlines_transform = shgroup_outline(
- psl->outlines, &g_data->id_ofs_transform, sh, draw_ctx->sh_cfg);
- g_data->outlines_active = shgroup_outline(
- psl->outlines, &g_data->id_ofs_active, sh, draw_ctx->sh_cfg);
-
- g_data->id_ofs_select = 0;
- g_data->id_ofs_select_dupli = 0;
- g_data->id_ofs_active = 0;
- g_data->id_ofs_transform = 0;
- }
-
- {
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- DRWPass *pass = psl->lightprobes = DRW_pass_create("Object Probe Pass", state);
- struct GPUBatch *sphere = DRW_cache_sphere_get();
- struct GPUBatch *quad = DRW_cache_quad_get();
-
- /* Cubemap */
- g_data->lightprobes_cube_select = buffer_instance_outline(
- pass, sphere, &g_data->id_ofs_prb_select, draw_ctx->sh_cfg);
- g_data->lightprobes_cube_select_dupli = buffer_instance_outline(
- pass, sphere, &g_data->id_ofs_prb_select_dupli, draw_ctx->sh_cfg);
- g_data->lightprobes_cube_active = buffer_instance_outline(
- pass, sphere, &g_data->id_ofs_prb_active, draw_ctx->sh_cfg);
- g_data->lightprobes_cube_transform = buffer_instance_outline(
- pass, sphere, &g_data->id_ofs_prb_transform, draw_ctx->sh_cfg);
-
- /* Planar */
- g_data->lightprobes_planar_select = buffer_instance_outline(
- pass, quad, &g_data->id_ofs_prb_select, draw_ctx->sh_cfg);
- g_data->lightprobes_planar_select_dupli = buffer_instance_outline(
- pass, quad, &g_data->id_ofs_prb_select_dupli, draw_ctx->sh_cfg);
- g_data->lightprobes_planar_active = buffer_instance_outline(
- pass, quad, &g_data->id_ofs_prb_active, draw_ctx->sh_cfg);
- g_data->lightprobes_planar_transform = buffer_instance_outline(
- pass, quad, &g_data->id_ofs_prb_transform, draw_ctx->sh_cfg);
-
- g_data->id_ofs_prb_select = 0;
- g_data->id_ofs_prb_select_dupli = 0;
- g_data->id_ofs_prb_active = 0;
- g_data->id_ofs_prb_transform = 0;
+ g_data->outlines_transform = shgroup_outline(psl->outlines, 0, sh, cfg);
+ g_data->outlines_select = shgroup_outline(psl->outlines, 1, sh, cfg);
+ g_data->outlines_select_dupli = shgroup_outline(psl->outlines, 2, sh, cfg);
+ g_data->outlines_active = shgroup_outline(psl->outlines, 3, sh, cfg);
}
{
@@ -1438,7 +1354,6 @@ static void OBJECT_cache_init(void *vedata)
DRW_shgroup_uniform_texture_ref(grp, "sceneDepth", &dtxl->depth);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_uniform_float_copy(grp, "alphaOcclu", alphaOcclu);
- DRW_shgroup_uniform_int(grp, "idOffsets", &stl->g_data->id_ofs_active, 4);
DRW_shgroup_call(grp, quad, NULL);
/* This is the bleed pass if do_outline_expand is false. */
@@ -2766,15 +2681,6 @@ static void DRW_shgroup_speaker(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLa
DRW_buffer_add_entry(sgl->speaker, color, &one, ob->obmat);
}
-typedef struct OBJECT_LightProbeEngineData {
- DrawData dd;
-
- float increment_x[3];
- float increment_y[3];
- float increment_z[3];
- float corner[3];
-} OBJECT_LightProbeEngineData;
-
static void DRW_shgroup_lightprobe(OBJECT_Shaders *sh_data,
OBJECT_StorageList *stl,
OBJECT_PassList *psl,
@@ -2791,13 +2697,10 @@ static void DRW_shgroup_lightprobe(OBJECT_Shaders *sh_data,
OBJECT_ShadingGroupList *sgl = (ob->dtx & OB_DRAWXRAY) ? &stl->g_data->sgl_ghost :
&stl->g_data->sgl;
- OBJECT_LightProbeEngineData *prb_data = (OBJECT_LightProbeEngineData *)DRW_drawdata_ensure(
- &ob->id, &draw_engine_object_type, sizeof(OBJECT_LightProbeEngineData), NULL, NULL);
-
if (DRW_state_is_select() || do_outlines) {
- int *call_id = shgroup_theme_id_to_probe_outline_counter(stl, theme_id, ob->base_flag);
-
if (prb->type == LIGHTPROBE_TYPE_GRID) {
+ float corner[3];
+ float increment[3][3];
/* Update transforms */
float cell_dim[3], half_cell_dim[3];
cell_dim[0] = 2.0f / (float)(prb->grid_resolution_x);
@@ -2807,65 +2710,40 @@ static void DRW_shgroup_lightprobe(OBJECT_Shaders *sh_data,
mul_v3_v3fl(half_cell_dim, cell_dim, 0.5f);
/* First cell. */
- copy_v3_fl(prb_data->corner, -1.0f);
- add_v3_v3(prb_data->corner, half_cell_dim);
- mul_m4_v3(ob->obmat, prb_data->corner);
+ copy_v3_fl(corner, -1.0f);
+ add_v3_v3(corner, half_cell_dim);
+ mul_m4_v3(ob->obmat, corner);
/* Opposite neighbor cell. */
- copy_v3_fl3(prb_data->increment_x, cell_dim[0], 0.0f, 0.0f);
- add_v3_v3(prb_data->increment_x, half_cell_dim);
- add_v3_fl(prb_data->increment_x, -1.0f);
- mul_m4_v3(ob->obmat, prb_data->increment_x);
- sub_v3_v3(prb_data->increment_x, prb_data->corner);
-
- copy_v3_fl3(prb_data->increment_y, 0.0f, cell_dim[1], 0.0f);
- add_v3_v3(prb_data->increment_y, half_cell_dim);
- add_v3_fl(prb_data->increment_y, -1.0f);
- mul_m4_v3(ob->obmat, prb_data->increment_y);
- sub_v3_v3(prb_data->increment_y, prb_data->corner);
-
- copy_v3_fl3(prb_data->increment_z, 0.0f, 0.0f, cell_dim[2]);
- add_v3_v3(prb_data->increment_z, half_cell_dim);
- add_v3_fl(prb_data->increment_z, -1.0f);
- mul_m4_v3(ob->obmat, prb_data->increment_z);
- sub_v3_v3(prb_data->increment_z, prb_data->corner);
+ copy_v3_fl3(increment[0], cell_dim[0], 0.0f, 0.0f);
+ copy_v3_fl3(increment[1], 0.0f, cell_dim[1], 0.0f);
+ copy_v3_fl3(increment[2], 0.0f, 0.0f, cell_dim[2]);
+ for (int i = 0; i < 3; i++) {
+ add_v3_v3(increment[i], half_cell_dim);
+ add_v3_fl(increment[i], -1.0f);
+ mul_m4_v3(ob->obmat, increment[i]);
+ sub_v3_v3(increment[i], corner);
+ }
+
+ int outline_id = shgroup_theme_id_to_outline_id(theme_id, ob->base_flag);
uint cell_count = prb->grid_resolution_x * prb->grid_resolution_y * prb->grid_resolution_z;
DRWShadingGroup *grp = DRW_shgroup_create(sh_data->lightprobe_grid, psl->lightprobes);
- DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- DRW_shgroup_uniform_int_copy(grp, "call_id", *call_id);
- DRW_shgroup_uniform_int(grp, "baseId", call_id, 1); /* that's correct */
- DRW_shgroup_uniform_vec3(grp, "corner", prb_data->corner, 1);
- DRW_shgroup_uniform_vec3(grp, "increment_x", prb_data->increment_x, 1);
- DRW_shgroup_uniform_vec3(grp, "increment_y", prb_data->increment_y, 1);
- DRW_shgroup_uniform_vec3(grp, "increment_z", prb_data->increment_z, 1);
- DRW_shgroup_uniform_ivec3(grp, "grid_resolution", &prb->grid_resolution_x, 1);
+ DRW_shgroup_uniform_int_copy(grp, "outlineId", outline_id);
+ DRW_shgroup_uniform_vec3_copy(grp, "corner", corner);
+ DRW_shgroup_uniform_vec3_copy(grp, "increment_x", increment[0]);
+ DRW_shgroup_uniform_vec3_copy(grp, "increment_y", increment[1]);
+ DRW_shgroup_uniform_vec3_copy(grp, "increment_z", increment[2]);
+ DRW_shgroup_uniform_ivec3_copy(grp, "grid_resolution", &prb->grid_resolution_x);
if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
}
DRW_shgroup_call_procedural_points(grp, NULL, cell_count);
- *call_id += 1;
}
- else if (prb->type == LIGHTPROBE_TYPE_CUBE) {
- float draw_size = 1.0f;
- float probe_cube_mat[4][4];
- // prb_data->draw_size = prb->data_draw_size * 0.1f;
- // unit_m4(prb_data->probe_cube_mat);
- // copy_v3_v3(prb_data->probe_cube_mat[3], ob->obmat[3]);
-
- DRWCallBuffer *buf = buffer_theme_id_to_probe_cube_outline_shgrp(
+ else if (prb->type == LIGHTPROBE_TYPE_PLANAR && (prb->flag & LIGHTPROBE_FLAG_SHOW_DATA)) {
+ DRWShadingGroup *grp = shgroup_theme_id_to_probe_outline_or_null(
stl, theme_id, ob->base_flag);
- /* TODO remove or change the drawing of the cube probes. This line draws nothing on purpose
- * to keep the call ids correct. */
- zero_m4(probe_cube_mat);
- DRW_buffer_add_entry(buf, call_id, &draw_size, probe_cube_mat);
- *call_id += 1;
- }
- else if (prb->flag & LIGHTPROBE_FLAG_SHOW_DATA) {
- float draw_size = 1.0f;
- DRWCallBuffer *buf = buffer_theme_id_to_probe_planar_outline_shgrp(stl, theme_id);
- DRW_buffer_add_entry(buf, call_id, &draw_size, ob->obmat);
- *call_id += 1;
+ DRW_shgroup_call_no_cull(grp, DRW_cache_quad_get(), ob);
}
}
@@ -3782,19 +3660,7 @@ static void OBJECT_draw_scene(void *vedata)
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
- int id_len_select = g_data->id_ofs_select;
- int id_len_select_dupli = g_data->id_ofs_select_dupli;
- int id_len_active = g_data->id_ofs_active;
- int id_len_transform = g_data->id_ofs_transform;
-
- int id_len_prb_select = g_data->id_ofs_prb_select;
- int id_len_prb_select_dupli = g_data->id_ofs_prb_select_dupli;
- int id_len_prb_active = g_data->id_ofs_prb_active;
- int id_len_prb_transform = g_data->id_ofs_prb_transform;
-
- int outline_calls = id_len_select + id_len_select_dupli + id_len_active + id_len_transform;
- outline_calls += id_len_prb_select + id_len_prb_select_dupli + id_len_prb_active +
- id_len_prb_transform;
+ int do_outlines = !DRW_pass_is_empty(psl->outlines) || !DRW_pass_is_empty(psl->lightprobes);
float clearcol[4] = {0.0f, 0.0f, 0.0f, 0.0f};
@@ -3802,35 +3668,24 @@ static void OBJECT_draw_scene(void *vedata)
/* Don't draw Transparent passes in MSAA buffer. */
// DRW_draw_pass(psl->bone_envelope); /* Never drawn in Object mode currently. */
- DRW_draw_pass(stl->g_data->sgl.transp_shapes);
+ DRW_draw_pass(g_data->sgl.transp_shapes);
MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl);
- DRW_draw_pass(stl->g_data->sgl.bone_solid);
- DRW_draw_pass(stl->g_data->sgl.bone_wire);
- DRW_draw_pass(stl->g_data->sgl.bone_outline);
- DRW_draw_pass(stl->g_data->sgl.non_meshes);
+ DRW_draw_pass(g_data->sgl.bone_solid);
+ DRW_draw_pass(g_data->sgl.bone_wire);
+ DRW_draw_pass(g_data->sgl.bone_outline);
+ DRW_draw_pass(g_data->sgl.non_meshes);
DRW_draw_pass(psl->particle);
- DRW_draw_pass(stl->g_data->sgl.bone_axes);
+ DRW_draw_pass(g_data->sgl.bone_axes);
MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl);
- DRW_draw_pass(stl->g_data->sgl.image_empties);
+ DRW_draw_pass(g_data->sgl.image_empties);
- if (DRW_state_is_fbo() && outline_calls > 0) {
+ if (DRW_state_is_fbo() && do_outlines) {
DRW_stats_group_start("Outlines");
- g_data->id_ofs_active = 1;
- g_data->id_ofs_select = g_data->id_ofs_active + id_len_active + id_len_prb_active + 1;
- g_data->id_ofs_select_dupli = g_data->id_ofs_select + id_len_select + id_len_prb_select + 1;
- g_data->id_ofs_transform = g_data->id_ofs_select_dupli + id_len_select_dupli +
- id_len_prb_select_dupli + 1;
-
- g_data->id_ofs_prb_active = g_data->id_ofs_active + id_len_active;
- g_data->id_ofs_prb_select = g_data->id_ofs_select + id_len_select;
- g_data->id_ofs_prb_select_dupli = g_data->id_ofs_select_dupli + id_len_select_dupli;
- g_data->id_ofs_prb_transform = g_data->id_ofs_transform + id_len_transform;
-
/* Render filled polygon on a separate framebuffer */
GPU_framebuffer_bind(fbl->outlines_fb);
GPU_framebuffer_clear_color_depth(fbl->outlines_fb, clearcol, 1.0f);
@@ -3865,7 +3720,7 @@ static void OBJECT_draw_scene(void *vedata)
}
/* Combine with scene buffer last */
- if (outline_calls > 0) {
+ if (do_outlines) {
DRW_draw_pass(psl->outlines_resolve);
}
}
diff --git a/source/blender/draw/modes/overlay_mode.c b/source/blender/draw/modes/overlay_mode.c
index a5b1133abf4..2433f4c1df5 100644
--- a/source/blender/draw/modes/overlay_mode.c
+++ b/source/blender/draw/modes/overlay_mode.c
@@ -23,8 +23,6 @@
#include "DNA_mesh_types.h"
#include "DNA_view3d_types.h"
-#include "BIF_glutil.h"
-
#include "BKE_editmesh.h"
#include "BKE_global.h"
#include "BKE_object.h"
@@ -77,7 +75,6 @@ typedef struct OVERLAY_PrivateData {
DRWShadingGroup *face_wires_shgrp;
DRWShadingGroup *face_wires_xray_shgrp;
DRWView *view_wires;
- BLI_mempool *wire_color_mempool;
View3DOverlay overlay;
float wire_step_param;
bool clear_stencil;
@@ -208,10 +205,6 @@ static void overlay_cache_init(void *vedata)
if (v3d->shading.type == OB_WIRE) {
g_data->overlay.flag |= V3D_OVERLAY_WIREFRAMES;
-
- if (ELEM(v3d->shading.wire_color_type, V3D_SHADING_OBJECT_COLOR, V3D_SHADING_RANDOM_COLOR)) {
- g_data->wire_color_mempool = BLI_mempool_create(sizeof(float[3]), 0, 512, 0);
- }
}
{
@@ -256,7 +249,6 @@ static void overlay_cache_init(void *vedata)
}
static void overlay_wire_color_get(const View3D *v3d,
- const OVERLAY_PrivateData *pd,
const Object *ob,
const bool use_coloring,
float **rim_col,
@@ -305,8 +297,10 @@ static void overlay_wire_color_get(const View3D *v3d,
if (v3d->shading.type == OB_WIRE) {
if (ELEM(v3d->shading.wire_color_type, V3D_SHADING_OBJECT_COLOR, V3D_SHADING_RANDOM_COLOR)) {
- *wire_col = BLI_mempool_alloc(pd->wire_color_mempool);
- *rim_col = BLI_mempool_alloc(pd->wire_color_mempool);
+ /* Theses stays valid until next call. So we need to copy them when using them as uniform. */
+ static float wire_col_val[3], rim_col_val[3];
+ *wire_col = wire_col_val;
+ *rim_col = rim_col_val;
if (v3d->shading.wire_color_type == V3D_SHADING_OBJECT_COLOR) {
linearrgb_to_srgb_v3_v3(*wire_col, ob->color);
@@ -427,9 +421,9 @@ static void overlay_cache_populate(void *vedata, Object *ob)
if (!(DRW_state_is_select() || DRW_state_is_depth())) {
float *rim_col, *wire_col;
- overlay_wire_color_get(v3d, pd, ob, use_coloring, &rim_col, &wire_col);
- DRW_shgroup_uniform_vec3(shgrp, "wireColor", wire_col, 1);
- DRW_shgroup_uniform_vec3(shgrp, "rimColor", rim_col, 1);
+ overlay_wire_color_get(v3d, ob, use_coloring, &rim_col, &wire_col);
+ DRW_shgroup_uniform_vec3_copy(shgrp, "wireColor", wire_col);
+ DRW_shgroup_uniform_vec3_copy(shgrp, "rimColor", rim_col);
DRW_shgroup_stencil_mask(shgrp,
(is_xray && (is_wire || !pd->clear_stencil)) ? 0x00 : 0xFF);
}
@@ -506,12 +500,6 @@ static void overlay_draw_scene(void *vedata)
/* TODO(fclem): find a way to unify the multisample pass together
* (non meshes + armature + wireframe) */
MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl);
-
- /* XXX TODO(fclem) do not discard data after drawing! Store them per viewport. */
- if (stl->g_data->wire_color_mempool) {
- BLI_mempool_destroy(stl->g_data->wire_color_mempool);
- stl->g_data->wire_color_mempool = NULL;
- }
}
static void overlay_engine_free(void)
diff --git a/source/blender/draw/modes/shaders/common_view_lib.glsl b/source/blender/draw/modes/shaders/common_view_lib.glsl
index 20a54947db7..a554db7d4a4 100644
--- a/source/blender/draw/modes/shaders/common_view_lib.glsl
+++ b/source/blender/draw/modes/shaders/common_view_lib.glsl
@@ -1,4 +1,5 @@
#define COMMON_VIEW_LIB
+#define DRW_RESOURCE_CHUNK_LEN 512
/* keep in sync with DRWManager.view_data */
layout(std140) uniform viewBlock
@@ -23,8 +24,74 @@ layout(std140) uniform viewBlock
_world_clip_planes_calc_clip_distance(p, clipPlanes)
#endif
+uniform int resourceChunk;
+
+#ifdef GPU_VERTEX_SHADER
+# ifdef GL_ARB_shader_draw_parameters
+# define baseInstance gl_BaseInstanceARB
+# else /* no ARB_shader_draw_parameters */
+uniform int baseInstance;
+# endif
+
+# ifdef IN_PLACE_INSTANCES
+/* When drawing instances of an object at the same position. */
+# define instanceId 0
+# elif defined(GPU_CRAPPY_AMD_DRIVER)
+/* NOTE: This does contain the baseInstance ofset */
+in int _instanceId;
+# define instanceId (_instanceId - baseInstance)
+# else
+# define instanceId gl_InstanceID
+# endif
+
+# define resource_id (baseInstance + instanceId)
+
+/* Use this to declare and pass the value if
+ * the fragment shader uses the resource_id. */
+# define RESOURCE_ID_VARYING flat out int resourceIDFrag;
+# define RESOURCE_ID_VARYING_GEOM flat out int resourceIDGeom;
+# define PASS_RESOURCE_ID resourceIDFrag = resource_id;
+# define PASS_RESOURCE_ID_GEOM resourceIDGeom = resource_id;
+#endif
+
+/* If used in a fragment / geometry shader, we pass
+ * resource_id as varying. */
+#ifdef GPU_GEOMETRY_SHADER
+# define RESOURCE_ID_VARYING \
+ flat out int resourceIDFrag; \
+ flat in int resourceIDGeom[];
+
+# define resource_id resourceIDGeom
+# define PASS_RESOURCE_ID(i) resourceIDFrag = resource_id[i];
+#endif
+
+#ifdef GPU_FRAGMENT_SHADER
+flat in int resourceIDFrag;
+# define resource_id resourceIDFrag
+#endif
+
+#ifndef GPU_INTEL
+struct ObjectMatrices {
+ mat4 drw_modelMatrix;
+ mat4 drw_modelMatrixInverse;
+};
+
+layout(std140) uniform modelBlock
+{
+ ObjectMatrices drw_matrices[DRW_RESOURCE_CHUNK_LEN];
+};
+
+# define ModelMatrix (drw_matrices[resource_id].drw_modelMatrix)
+# define ModelMatrixInverse (drw_matrices[resource_id].drw_modelMatrixInverse)
+
+#else /* GPU_INTEL */
+/* Intel GPU seems to suffer performance impact when the model matrix is in UBO storage.
+ * So for now we just force using the legacy path. */
uniform mat4 ModelMatrix;
uniform mat4 ModelMatrixInverse;
+#endif
+
+#define resource_handle (resourceChunk * DRW_RESOURCE_CHUNK_LEN + resource_id)
/** Transform shortcuts. */
/* Rule of thumb: Try to reuse world positions and normals because converting though viewspace
diff --git a/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl b/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl
index d27d55c3fd6..144024a7d5d 100644
--- a/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl
+++ b/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl
@@ -1,18 +1,11 @@
-uniform mat4 ViewProjectionMatrix;
-
-uniform float sphere_size;
uniform ivec3 grid_resolution;
uniform vec3 corner;
uniform vec3 increment_x;
uniform vec3 increment_y;
uniform vec3 increment_z;
-uniform vec3 screen_vecs[2];
-
-uniform int call_id; /* we don't want the builtin callId which would be 0. */
-uniform int baseId;
-flat out uint finalId;
+flat out int objectId;
void main()
{
@@ -29,7 +22,8 @@ void main()
gl_Position = ViewProjectionMatrix * vec4(ws_cell_location, 1.0);
gl_PointSize = 2.0f;
- finalId = uint(baseId + call_id);
+ /* ID 0 is nothing (background) */
+ objectId = resource_handle + 1;
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(ws_cell_location);
diff --git a/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl b/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl
index 7668a0c2c94..7b86d477a39 100644
--- a/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl
+++ b/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl
@@ -7,30 +7,9 @@ uniform usampler2D outlineId;
uniform sampler2D outlineDepth;
uniform sampler2D sceneDepth;
-uniform int idOffsets[4];
-
uniform float alphaOcclu;
uniform vec2 viewportSize;
-vec4 convert_id_to_color(int id)
-{
- if (id == 0) {
- return vec4(0.0);
- }
- if (id < idOffsets[1]) {
- return colorActive;
- }
- else if (id < idOffsets[2]) {
- return colorSelect;
- }
- else if (id < idOffsets[3]) {
- return colorDupliSelect;
- }
- else {
- return colorTransform;
- }
-}
-
void main()
{
ivec2 texel = ivec2(gl_FragCoord.xy);
@@ -85,7 +64,24 @@ void main()
const float epsilon = 3.0 / 8388608.0;
bool occluded = (ref_depth > scene_depth + epsilon);
- FragColor = convert_id_to_color(int(ref_id));
+ /* WATCH: Keep in sync with outlineId of the prepass. */
+ uint color_id = ref_id >> 14u;
+ if (ref_id == 0u) {
+ FragColor = vec4(0.0);
+ }
+ else if (color_id == 1u) {
+ FragColor = colorSelect;
+ }
+ else if (color_id == 2u) {
+ FragColor = colorDupliSelect;
+ }
+ else if (color_id == 3u) {
+ FragColor = colorActive;
+ }
+ else {
+ FragColor = colorTransform;
+ }
+
FragColor.a *= (occluded) ? alphaOcclu : 1.0;
FragColor.a = (outline) ? FragColor.a : 0.0;
}
diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl
index c3447456ea6..5d6c4881b5b 100644
--- a/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl
+++ b/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl
@@ -1,10 +1,18 @@
-uniform int callId;
-uniform int baseId;
+
+/* Should be 2 bits only [0..3]. */
+uniform int outlineId;
+
+flat in int objectId;
/* using uint because 16bit uint can contain more ids than int. */
out uint outId;
+/* Replace top 2 bits (of the 16bit output) by outlineId.
+ * This leaves 16K different IDs to create outlines between objects.
+ * SHIFT = (32 - (16 - 2)) */
+#define SHIFT 18u
+
void main()
{
- outId = uint(baseId + callId);
+ outId = (uint(outlineId) << 14u) | ((uint(objectId) << SHIFT) >> SHIFT);
}
diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl
index 5a3eb38fb6b..b32913dcd60 100644
--- a/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl
+++ b/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl
@@ -2,12 +2,15 @@
layout(lines_adjacency) in;
layout(line_strip, max_vertices = 2) out;
-in vec4 pPos[];
in vec3 vPos[];
+in int objectId_g[];
+
+flat out int objectId;
void vert_from_gl_in(int v)
{
- gl_Position = pPos[v];
+ gl_Position = gl_in[v].gl_Position;
+ objectId = objectId_g[v];
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_set_clip_distance(gl_in[v].gl_ClipDistance);
#endif
diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl
index e34afe95b5e..7740f9a4af2 100644
--- a/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl
+++ b/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl
@@ -1,16 +1,27 @@
in vec3 pos;
-out vec4 pPos;
+#ifdef USE_GEOM
out vec3 vPos;
+out int objectId_g;
+# define objectId objectId_g
+#else
+
+flat out int objectId;
+#endif
void main()
{
vec3 world_pos = point_object_to_world(pos);
+#ifdef USE_GEOM
vPos = point_world_to_view(world_pos);
- pPos = point_world_to_ndc(world_pos);
+#endif
+ gl_Position = point_world_to_ndc(world_pos);
/* Small bias to always be on top of the geom. */
- pPos.z -= 1e-3;
+ gl_Position.z -= 1e-3;
+
+ /* ID 0 is nothing (background) */
+ objectId = resource_handle + 1;
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(world_pos);
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index 370cc6a2a6d..ec740447f93 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -101,17 +101,19 @@ static int bm_face_isect_pair_swap(BMFace *f, void *UNUSED(user_data))
/**
* Use for intersect and boolean.
*/
-static void edbm_intersect_select(BMEditMesh *em)
+static void edbm_intersect_select(BMEditMesh *em, bool do_select)
{
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
+ if (do_select) {
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
- if (em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) {
- BMIter iter;
- BMEdge *e;
+ if (em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) {
+ BMIter iter;
+ BMEdge *e;
- BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- BM_edge_select_set(em->bm, e, true);
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BM_edge_select_set(em->bm, e, true);
+ }
}
}
}
@@ -210,10 +212,9 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op)
em->bm, BM_elem_cb_check_hflag_enabled_simple(const BMFace *, BM_ELEM_SELECT));
}
- if (has_isect) {
- edbm_intersect_select(em);
- }
- else {
+ edbm_intersect_select(em, has_isect);
+
+ if (!has_isect) {
isect_len++;
}
}
@@ -317,10 +318,9 @@ static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op)
boolean_operation,
eps);
- if (has_isect) {
- edbm_intersect_select(em);
- }
- else {
+ edbm_intersect_select(em, has_isect);
+
+ if (!has_isect) {
isect_len++;
}
}
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 8d2355ff5ac..bc08da4b2cb 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -330,6 +330,8 @@ data_to_c_simple(shaders/gpu_shader_gpencil_fill_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_cfg_world_clip_lib.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_common_obinfos_lib.glsl SRC)
+
if(WITH_MOD_SMOKE)
add_definitions(-DWITH_SMOKE)
diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h
index 175033f70d9..7d8c3347eb4 100644
--- a/source/blender/gpu/GPU_batch.h
+++ b/source/blender/gpu/GPU_batch.h
@@ -193,6 +193,17 @@ GPUBatch *create_BatchInGeneral(GPUPrimType, VertexBufferStuff, ElementListStuff
#endif /* future plans */
+/* GPUDrawList is an API to do lots of similar drawcalls very fast using multidrawindirect.
+ * There is a fallback if the feature is not supported. */
+typedef struct GPUDrawList GPUDrawList;
+
+GPUDrawList *GPU_draw_list_create(int length);
+void GPU_draw_list_discard(GPUDrawList *list);
+void GPU_draw_list_init(GPUDrawList *list, GPUBatch *batch);
+void GPU_draw_list_command_add(
+ GPUDrawList *list, int v_first, int v_count, int i_first, int i_count);
+void GPU_draw_list_submit(GPUDrawList *list);
+
void gpu_batch_init(void);
void gpu_batch_exit(void);
diff --git a/source/blender/gpu/GPU_shader_interface.h b/source/blender/gpu/GPU_shader_interface.h
index ec97e1b085e..e336aa53d24 100644
--- a/source/blender/gpu/GPU_shader_interface.h
+++ b/source/blender/gpu/GPU_shader_interface.h
@@ -45,13 +45,12 @@ typedef enum {
GPU_UNIFORM_VIEWPROJECTION_INV, /* mat4 ViewProjectionMatrixInverse */
GPU_UNIFORM_NORMAL, /* mat3 NormalMatrix */
- GPU_UNIFORM_ORCO, /* vec3 OrcoTexCoFactors[] */
+ GPU_UNIFORM_ORCO, /* vec4 OrcoTexCoFactors[] */
GPU_UNIFORM_CLIPPLANES, /* vec4 WorldClipPlanes[] */
- GPU_UNIFORM_COLOR, /* vec4 color */
- GPU_UNIFORM_CALLID, /* int callId */
- GPU_UNIFORM_OBJECT_INFO, /* vec3 objectInfo */
- GPU_UNIFORM_OBJECT_COLOR, /* vec4 objectColor */
+ GPU_UNIFORM_COLOR, /* vec4 color */
+ GPU_UNIFORM_BASE_INSTANCE, /* int baseInstance */
+ GPU_UNIFORM_RESOURCE_CHUNK, /* int resourceChunk */
GPU_UNIFORM_CUSTOM, /* custom uniform, not one of the above built-ins */
diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h
index e7600279d6f..4bbcb6a4335 100644
--- a/source/blender/gpu/GPU_viewport.h
+++ b/source/blender/gpu/GPU_viewport.h
@@ -37,14 +37,20 @@ typedef struct GPUViewport GPUViewport;
/* Contains memory pools information */
typedef struct ViewportMemoryPool {
- struct BLI_memblock *calls;
- struct BLI_memblock *states;
+ struct BLI_memblock *commands;
+ struct BLI_memblock *commands_small;
+ struct BLI_memblock *callbuffers;
+ struct BLI_memblock *obmats;
+ struct BLI_memblock *obinfos;
struct BLI_memblock *cullstates;
struct BLI_memblock *shgroups;
struct BLI_memblock *uniforms;
struct BLI_memblock *views;
struct BLI_memblock *passes;
struct BLI_memblock *images;
+ struct GPUUniformBuffer **matrices_ubo;
+ struct GPUUniformBuffer **obinfos_ubo;
+ uint ubo_len;
} ViewportMemoryPool;
/* All FramebufferLists are just the same pointers with different names */
diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.c
index e0c0aea576c..e0d77f37512 100644
--- a/source/blender/gpu/intern/gpu_batch.c
+++ b/source/blender/gpu/intern/gpu_batch.c
@@ -39,8 +39,9 @@
#include <stdlib.h>
#include <string.h>
+#include <limits.h>
-static void batch_update_program_bindings(GPUBatch *batch, uint v_first);
+static void batch_update_program_bindings(GPUBatch *batch, uint i_first);
void GPU_batch_vao_cache_clear(GPUBatch *batch)
{
@@ -446,20 +447,51 @@ static void create_bindings(GPUVertBuf *verts,
}
}
-static void batch_update_program_bindings(GPUBatch *batch, uint v_first)
+static void instance_id_workaround(GPUBatch *batch)
+{
+ /**
+ * A driver bug make it so that when using an attribute with GL_INT_2_10_10_10_REV as format,
+ * the gl_InstanceID is incremented by the 2 bit component of the attrib. To workaround this,
+ * we create a new vertex attrib containing the expected value of gl_InstanceID.
+ **/
+ const GPUShaderInput *input = GPU_shaderinterface_attr(batch->interface, "_instanceId");
+ if (input) {
+#define DRW_RESOURCE_CHUNK_LEN 512 /* Keep in sync. */
+ static GLint vbo_id = 0;
+ if (vbo_id == 0) {
+ short data[DRW_RESOURCE_CHUNK_LEN];
+ for (int i = 0; i < DRW_RESOURCE_CHUNK_LEN; i++) {
+ data[i] = i;
+ }
+ /* GPU_context takes care of deleting `vbo_id` at the end. */
+ vbo_id = GPU_buf_alloc();
+ glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
+ }
+ glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
+ glEnableVertexAttribArray(input->location);
+ glVertexAttribIPointer(input->location, 1, GL_SHORT, 0, NULL);
+ glVertexAttribDivisor(input->location, 1);
+ }
+}
+
+static void batch_update_program_bindings(GPUBatch *batch, uint i_first)
{
/* Reverse order so first vbos have more prevalence (in term of attrib override). */
for (int v = GPU_BATCH_VBO_MAX_LEN - 1; v > -1; v--) {
if (batch->verts[v] != NULL) {
- create_bindings(batch->verts[v], batch->interface, (batch->inst) ? 0 : v_first, false);
+ create_bindings(batch->verts[v], batch->interface, 0, false);
}
}
if (batch->inst) {
- create_bindings(batch->inst, batch->interface, v_first, true);
+ create_bindings(batch->inst, batch->interface, i_first, true);
}
if (batch->elem) {
GPU_indexbuf_use(batch->elem);
}
+ if (GPU_crappy_amd_driver()) {
+ instance_id_workaround(batch);
+ }
}
void GPU_batch_program_use_begin(GPUBatch *batch)
@@ -618,12 +650,18 @@ void GPU_batch_draw(GPUBatch *batch)
GPU_batch_program_use_end(batch);
}
+#if GPU_TRACK_INDEX_RANGE
+# define BASE_INDEX(el) ((el)->base_index)
+# define INDEX_TYPE(el) ((el)->gl_index_type)
+#else
+# define BASE_INDEX(el) 0
+# define INDEX_TYPE(el) GL_UNSIGNED_INT
+#endif
+
void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_first, int i_count)
{
-#if TRUST_NO_ONE
BLI_assert(batch->program_in_use);
/* TODO could assert that VAO is bound. */
-#endif
if (v_count == 0) {
v_count = (batch->elem) ? batch->elem->index_len : batch->verts[0]->vertex_len;
@@ -632,8 +670,18 @@ void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_fi
i_count = (batch->inst) ? batch->inst->vertex_len : 1;
}
+ if (v_count == 0 || i_count == 0) {
+ /* Nothing to draw. */
+ return;
+ }
+
+ /* Verify there is enough data do draw. */
+ BLI_assert(i_first + i_count <= batch->inst ? batch->inst->vertex_len : 1);
+ BLI_assert(v_first + v_count <= batch->elem ? batch->elem->index_len :
+ batch->verts[0]->vertex_len);
+
if (!GPU_arb_base_instance_is_supported()) {
- if (i_first > 0 && i_count > 0) {
+ if (i_first > 0) {
/* If using offset drawing with instancing, we must
* use the default VAO and redo bindings. */
glBindVertexArray(GPU_vao_default());
@@ -648,13 +696,8 @@ void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_fi
if (batch->elem) {
const GPUIndexBuf *el = batch->elem;
-#if GPU_TRACK_INDEX_RANGE
- GLenum index_type = el->gl_index_type;
- GLint base_index = el->base_index;
-#else
- GLenum index_type = GL_UNSIGNED_INT;
- GLint base_index = 0;
-#endif
+ GLenum index_type = INDEX_TYPE(el);
+ GLint base_index = BASE_INDEX(el);
void *v_first_ofs = elem_offset(el, v_first);
if (GPU_arb_base_instance_is_supported()) {
@@ -697,6 +740,179 @@ void GPU_draw_primitive(GPUPrimType prim_type, int v_count)
}
/* -------------------------------------------------------------------- */
+/** \name Indirect Draw Calls
+ * \{ */
+
+#if 0
+# define USE_MULTI_DRAW_INDIRECT 0
+#else
+# define USE_MULTI_DRAW_INDIRECT \
+ (GL_ARB_multi_draw_indirect && GPU_arb_base_instance_is_supported())
+#endif
+
+typedef struct GPUDrawCommand {
+ uint v_count;
+ uint i_count;
+ uint v_first;
+ uint i_first;
+} GPUDrawCommand;
+
+typedef struct GPUDrawCommandIndexed {
+ uint v_count;
+ uint i_count;
+ uint v_first;
+ uint base_index;
+ uint i_first;
+} GPUDrawCommandIndexed;
+
+struct GPUDrawList {
+ GPUBatch *batch;
+ uint base_index; /* Avoid dereferencing batch. */
+ uint cmd_offset; /* in bytes, offset inside indirect command buffer. */
+ uint cmd_len; /* Number of used command for the next call. */
+ uint buffer_size; /* in bytes, size of indirect command buffer. */
+ GLuint buffer_id; /* Draw Indirect Buffer id */
+ union {
+ GPUDrawCommand *commands;
+ GPUDrawCommandIndexed *commands_indexed;
+ };
+};
+
+GPUDrawList *GPU_draw_list_create(int length)
+{
+ GPUDrawList *list = MEM_callocN(sizeof(GPUDrawList), "GPUDrawList");
+ /* Alloc the biggest possible command list which is indexed. */
+ list->buffer_size = sizeof(GPUDrawCommandIndexed) * length;
+ if (USE_MULTI_DRAW_INDIRECT) {
+ list->buffer_id = GPU_buf_alloc();
+ glBindBuffer(GL_DRAW_INDIRECT_BUFFER, list->buffer_id);
+ glBufferData(GL_DRAW_INDIRECT_BUFFER, list->buffer_size, NULL, GL_DYNAMIC_DRAW);
+ }
+ else {
+ list->commands = MEM_mallocN(list->buffer_size, "GPUDrawList data");
+ }
+ return list;
+}
+
+void GPU_draw_list_discard(GPUDrawList *list)
+{
+ if (list->buffer_id) {
+ GPU_buf_free(list->buffer_id);
+ }
+ else {
+ MEM_SAFE_FREE(list->commands);
+ }
+ MEM_freeN(list);
+}
+
+void GPU_draw_list_init(GPUDrawList *list, GPUBatch *batch)
+{
+ BLI_assert(batch->phase == GPU_BATCH_READY_TO_DRAW);
+ list->batch = batch;
+ list->base_index = batch->elem ? BASE_INDEX(batch->elem) : UINT_MAX;
+ list->cmd_len = 0;
+
+ if (USE_MULTI_DRAW_INDIRECT) {
+ if (list->commands == NULL) {
+ glBindBuffer(GL_DRAW_INDIRECT_BUFFER, list->buffer_id);
+ if (list->cmd_offset >= list->buffer_size) {
+ /* Orphan buffer data and start fresh. */
+ glBufferData(GL_DRAW_INDIRECT_BUFFER, list->buffer_size, NULL, GL_DYNAMIC_DRAW);
+ list->cmd_offset = 0;
+ }
+ GLenum flags = GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_FLUSH_EXPLICIT_BIT;
+ list->commands = glMapBufferRange(
+ GL_DRAW_INDIRECT_BUFFER, list->cmd_offset, list->buffer_size - list->cmd_offset, flags);
+ }
+ }
+ else {
+ list->cmd_offset = 0;
+ }
+}
+
+void GPU_draw_list_command_add(
+ GPUDrawList *list, int v_first, int v_count, int i_first, int i_count)
+{
+ BLI_assert(list->commands);
+
+ if (list->base_index != UINT_MAX) {
+ GPUDrawCommandIndexed *cmd = list->commands_indexed + list->cmd_len;
+ cmd->v_first = v_first;
+ cmd->v_count = v_count;
+ cmd->i_count = i_count;
+ cmd->base_index = list->base_index;
+ cmd->i_first = i_first;
+ }
+ else {
+ GPUDrawCommand *cmd = list->commands + list->cmd_len;
+ cmd->v_first = v_first;
+ cmd->v_count = v_count;
+ cmd->i_count = i_count;
+ cmd->i_first = i_first;
+ }
+
+ list->cmd_len++;
+ uint offset = list->cmd_offset + list->cmd_len * sizeof(GPUDrawCommandIndexed);
+
+ if (offset == list->buffer_size) {
+ GPU_draw_list_submit(list);
+ GPU_draw_list_init(list, list->batch);
+ }
+}
+
+void GPU_draw_list_submit(GPUDrawList *list)
+{
+ GPUBatch *batch = list->batch;
+
+ if (list->cmd_len == 0)
+ return;
+
+ BLI_assert(list->commands);
+ BLI_assert(batch->program_in_use);
+ /* TODO could assert that VAO is bound. */
+
+ /* TODO We loose a bit of memory here if we only draw arrays. Fix that. */
+ uintptr_t offset = list->cmd_offset;
+ uint cmd_len = list->cmd_len;
+ size_t bytes_used = cmd_len * sizeof(GPUDrawCommandIndexed);
+ list->cmd_offset += bytes_used;
+ list->cmd_len = 0; /* Avoid reuse. */
+
+ if (USE_MULTI_DRAW_INDIRECT) {
+ GLenum prim = batch->gl_prim_type;
+
+ glBindBuffer(GL_DRAW_INDIRECT_BUFFER, list->buffer_id);
+ glFlushMappedBufferRange(GL_DRAW_INDIRECT_BUFFER, 0, bytes_used);
+ glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER);
+ list->commands = NULL; /* Unmapped */
+
+ if (batch->elem) {
+ glMultiDrawElementsIndirect(prim, INDEX_TYPE(batch->elem), (void *)offset, cmd_len, 0);
+ }
+ else {
+ glMultiDrawArraysIndirect(prim, (void *)offset, cmd_len, 0);
+ }
+ }
+ else {
+ /* Fallback */
+ if (batch->elem) {
+ GPUDrawCommandIndexed *cmd = list->commands_indexed;
+ for (int i = 0; i < cmd_len; i++, cmd++) {
+ GPU_batch_draw_advanced(batch, cmd->v_first, cmd->v_count, cmd->i_first, cmd->i_count);
+ }
+ }
+ else {
+ GPUDrawCommand *cmd = list->commands;
+ for (int i = 0; i < cmd_len; i++, cmd++) {
+ GPU_batch_draw_advanced(batch, cmd->v_first, cmd->v_count, cmd->i_first, cmd->i_count);
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Utilities
* \{ */
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 7483be74e01..410e23c9576 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -55,6 +55,12 @@
#include <string.h>
#include <stdarg.h>
+extern char datatoc_gpu_shader_material_glsl[];
+extern char datatoc_gpu_shader_geometry_glsl[];
+
+extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
+extern char datatoc_common_view_lib_glsl[];
+
/* -------------------- GPUPass Cache ------------------ */
/**
* Internal shader cache: This prevent the shader recompilation / stall when
@@ -778,6 +784,12 @@ static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *final
else if (input->builtin == GPU_OBJECT_MATRIX) {
BLI_dynstr_append(ds, "objmat");
}
+ else if (input->builtin == GPU_OBJECT_INFO) {
+ BLI_dynstr_append(ds, "ObjectInfo");
+ }
+ else if (input->builtin == GPU_OBJECT_COLOR) {
+ BLI_dynstr_append(ds, "ObjectColor");
+ }
else if (input->builtin == GPU_INVERSE_OBJECT_MATRIX) {
BLI_dynstr_append(ds, "objinv");
}
@@ -840,6 +852,10 @@ static char *code_generate_fragment(GPUMaterial *material,
codegen_set_unique_ids(nodes);
*rbuiltins = builtins = codegen_process_uniforms_functions(material, ds, nodes);
+ if (builtins & (GPU_OBJECT_INFO | GPU_OBJECT_COLOR)) {
+ BLI_dynstr_append(ds, datatoc_gpu_shader_common_obinfos_lib_glsl);
+ }
+
if (builtins & GPU_BARYCENTRIC_TEXCO) {
BLI_dynstr_append(ds, "in vec2 barycentricTexCo;\n");
}
@@ -988,7 +1004,7 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
/* NOTE : Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */
if (input->attr_type == CD_ORCO) {
/* OPTI : orco is computed from local positions, but only if no modifier is present. */
- BLI_dynstr_append(ds, "uniform vec3 OrcoTexCoFactors[2];\n");
+ BLI_dynstr_append(ds, datatoc_gpu_shader_common_obinfos_lib_glsl);
BLI_dynstr_append(ds, "DEFINE_ATTR(vec4, orco);\n");
}
else if (input->attr_name[0] == '\0') {
@@ -1070,6 +1086,8 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
BLI_dynstr_append(ds, "\n");
+ BLI_dynstr_append(ds, use_geom ? "RESOURCE_ID_VARYING_GEOM\n" : "RESOURCE_ID_VARYING\n");
+
BLI_dynstr_append(ds,
"#define USE_ATTR\n"
"vec3 srgb_to_linear_attr(vec3 c) {\n"
@@ -1099,6 +1117,8 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
BLI_dynstr_append(ds, "void pass_attr(in vec3 position) {\n");
+ BLI_dynstr_append(ds, use_geom ? "\tPASS_RESOURCE_ID_GEOM\n" : "\tPASS_RESOURCE_ID\n");
+
BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n");
if (builtins & GPU_BARYCENTRIC_TEXCO) {
@@ -1125,8 +1145,8 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
}
else if (input->attr_type == CD_ORCO) {
BLI_dynstr_appendf(ds,
- "\tvar%d%s = OrcoTexCoFactors[0] + (ModelMatrixInverse * "
- "vec4(hair_get_strand_pos(), 1.0)).xyz * OrcoTexCoFactors[1];\n",
+ "\tvar%d%s = OrcoTexCoFactors[0].xyz + (ModelMatrixInverse * "
+ "vec4(hair_get_strand_pos(), 1.0)).xyz * OrcoTexCoFactors[1].xyz;\n",
input->attr_id,
use_geom ? "g" : "");
/* TODO: fix ORCO with modifiers. */
@@ -1181,7 +1201,8 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
}
else if (input->attr_type == CD_ORCO) {
BLI_dynstr_appendf(ds,
- "\tvar%d%s = OrcoTexCoFactors[0] + position * OrcoTexCoFactors[1];\n",
+ "\tvar%d%s = OrcoTexCoFactors[0].xyz + position *"
+ " OrcoTexCoFactors[1].xyz;\n",
input->attr_id,
use_geom ? "g" : "");
/* See mesh_create_loop_orco() for explanation. */
@@ -1296,6 +1317,8 @@ static char *code_generate_geometry(ListBase *nodes, const char *geom_code, cons
BLI_dynstr_append(ds, "out vec3 worldNormal;\n");
BLI_dynstr_append(ds, "out vec3 viewNormal;\n");
+ BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
+
BLI_dynstr_append(ds, "void main(){\n");
if (builtins & GPU_BARYCENTRIC_DIST) {
@@ -1340,9 +1363,13 @@ static char *code_generate_geometry(ListBase *nodes, const char *geom_code, cons
BLI_dynstr_append(ds, "}\n");
}
+ BLI_dynstr_append(ds, "RESOURCE_ID_VARYING\n");
+
/* Generate varying assignments. */
BLI_dynstr_append(ds, "void pass_attr(in int vert) {\n");
+ BLI_dynstr_append(ds, "\tPASS_RESOURCE_ID(vert)\n");
+
/* XXX HACK: Eevee specific. */
if (geom_code == NULL) {
BLI_dynstr_append(ds, "\tworldPosition = worldPositiong[vert];\n");
diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c
index 42c21626c05..7e8cb8a4fa0 100644
--- a/source/blender/gpu/intern/gpu_shader.c
+++ b/source/blender/gpu/intern/gpu_shader.c
@@ -248,6 +248,9 @@ static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH])
/* a #version 400 feature, but we use #version 330 maximum so use extension */
strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n");
}
+ if (GLEW_ARB_shader_draw_parameters) {
+ strcat(defines, "#extension GL_ARB_shader_draw_parameters : enable\n");
+ }
}
static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH])
@@ -255,6 +258,9 @@ static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH])
/* some useful defines to detect GPU type */
if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) {
strcat(defines, "#define GPU_ATI\n");
+ if (GPU_crappy_amd_driver()) {
+ strcat(defines, "#define GPU_CRAPPY_AMD_DRIVER\n");
+ }
}
else if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY)) {
strcat(defines, "#define GPU_NVIDIA\n");
diff --git a/source/blender/gpu/intern/gpu_shader_interface.c b/source/blender/gpu/intern/gpu_shader_interface.c
index 083c5bf2b60..983c5dfc27a 100644
--- a/source/blender/gpu/intern/gpu_shader_interface.c
+++ b/source/blender/gpu/intern/gpu_shader_interface.c
@@ -65,9 +65,8 @@ static const char *BuiltinUniform_name(GPUUniformBuiltin u)
[GPU_UNIFORM_CLIPPLANES] = "WorldClipPlanes",
[GPU_UNIFORM_COLOR] = "color",
- [GPU_UNIFORM_CALLID] = "callId",
- [GPU_UNIFORM_OBJECT_INFO] = "unfobjectinfo",
- [GPU_UNIFORM_OBJECT_COLOR] = "unfobjectcolor",
+ [GPU_UNIFORM_BASE_INSTANCE] = "baseInstance",
+ [GPU_UNIFORM_RESOURCE_CHUNK] = "resourceChunk",
[GPU_UNIFORM_CUSTOM] = NULL,
[GPU_NUM_UNIFORMS] = NULL,
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
index fcb1a008226..615af57c1bd 100644
--- a/source/blender/gpu/intern/gpu_viewport.c
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -39,6 +39,7 @@
#include "GPU_immediate.h"
#include "GPU_texture.h"
#include "GPU_viewport.h"
+#include "GPU_uniformbuffer.h"
#include "DRW_engine.h"
@@ -619,11 +620,20 @@ void GPU_viewport_free(GPUViewport *viewport)
MEM_freeN(viewport->fbl);
MEM_freeN(viewport->txl);
- if (viewport->vmempool.calls != NULL) {
- BLI_memblock_destroy(viewport->vmempool.calls, NULL);
+ if (viewport->vmempool.commands != NULL) {
+ BLI_memblock_destroy(viewport->vmempool.commands, NULL);
}
- if (viewport->vmempool.states != NULL) {
- BLI_memblock_destroy(viewport->vmempool.states, NULL);
+ if (viewport->vmempool.commands_small != NULL) {
+ BLI_memblock_destroy(viewport->vmempool.commands_small, NULL);
+ }
+ if (viewport->vmempool.callbuffers != NULL) {
+ BLI_memblock_destroy(viewport->vmempool.callbuffers, NULL);
+ }
+ if (viewport->vmempool.obmats != NULL) {
+ BLI_memblock_destroy(viewport->vmempool.obmats, NULL);
+ }
+ if (viewport->vmempool.obinfos != NULL) {
+ BLI_memblock_destroy(viewport->vmempool.obinfos, NULL);
}
if (viewport->vmempool.cullstates != NULL) {
BLI_memblock_destroy(viewport->vmempool.cullstates, NULL);
@@ -650,6 +660,13 @@ void GPU_viewport_free(GPUViewport *viewport)
BLI_memblock_destroy(viewport->vmempool.images, NULL);
}
+ for (int i = 0; i < viewport->vmempool.ubo_len; i++) {
+ GPU_uniformbuffer_free(viewport->vmempool.matrices_ubo[i]);
+ GPU_uniformbuffer_free(viewport->vmempool.obinfos_ubo[i]);
+ }
+ MEM_SAFE_FREE(viewport->vmempool.matrices_ubo);
+ MEM_SAFE_FREE(viewport->vmempool.obinfos_ubo);
+
DRW_instance_data_list_free(viewport->idatalist);
MEM_freeN(viewport->idatalist);
diff --git a/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl b/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl
new file mode 100644
index 00000000000..aa1d437c307
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl
@@ -0,0 +1,19 @@
+
+/* Need to be included after common_view_lib.glsl for resource_id. */
+#ifndef GPU_OBINFOS_UBO
+#define GPU_OBINFOS_UBO
+struct ObjectInfos {
+ vec4 drw_OrcoTexCoFactors[2];
+ vec4 drw_ObjectColor;
+ vec4 drw_Infos;
+};
+
+layout(std140) uniform infoBlock
+{
+ /* DRW_RESOURCE_CHUNK_LEN = 512 */
+ ObjectInfos drw_infos[512];
+};
+#define OrcoTexCoFactors (drw_infos[resource_id].drw_OrcoTexCoFactors)
+#define ObjectInfo (drw_infos[resource_id].drw_Infos)
+#define ObjectColor (drw_infos[resource_id].drw_ObjectColor)
+#endif
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl
index 31b359dbe6d..f32c47bcec3 100644
--- a/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl
@@ -1,8 +1,5 @@
uniform mat4 ViewProjectionMatrix;
-#ifdef USE_WORLD_CLIP_PLANES
-uniform mat4 ModelMatrix;
-#endif
/* ---- Instantiated Attrs ---- */
in float pos;
@@ -47,11 +44,12 @@ void main()
pPos = vec3(0.0);
}
- gl_Position = ViewProjectionMatrix * InstanceModelMatrix * vec4(pPos, 1.0);
+ vec4 wPos = InstanceModelMatrix * vec4(pPos, 1.0);
+ gl_Position = ViewProjectionMatrix * wPos;
finalColor = vec4(color, 1.0);
#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((ModelMatrix * InstanceModelMatrix * vec4(pPos, 1.0)).xyz);
+ world_clip_planes_calc_clip_distance(wPos.xyz);
#endif
}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl
index d9a0ffbbdac..5bd29c55e42 100644
--- a/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl
@@ -18,13 +18,14 @@ void main()
{
float len = end - start;
vec3 sta = vec3(0.0, 0.0, -start);
- vec4 pos_4d = vec4(pos * -len + sta, 1.0);
- gl_Position = ViewProjectionMatrix * InstanceModelMatrix * pos_4d;
+ vec4 wPos = InstanceModelMatrix * vec4(pos * -len + sta, 1.0);
+
+ gl_Position = ViewProjectionMatrix * wPos;
gl_PointSize = size;
finalColor = vec4(color, 1.0);
#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((InstanceModelMatrix * pos_4d).xyz);
+ world_clip_planes_calc_clip_distance(wPos.xyz);
#endif
}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl
index 3e52e43beae..10228a1e985 100644
--- a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl
@@ -1,6 +1,5 @@
uniform mat4 ViewProjectionMatrix;
-uniform mat4 ModelMatrix;
/* ---- Instantiated Attrs ---- */
in vec3 pos;
@@ -20,10 +19,10 @@ void main()
{
finalColor = color;
- vec4 pos_4d = vec4(pos * size, 1.0);
- gl_Position = ViewProjectionMatrix * InstanceModelMatrix * pos_4d;
+ vec4 wPos = InstanceModelMatrix * vec4(pos * size, 1.0);
+ gl_Position = ViewProjectionMatrix * wPos;
#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((ModelMatrix * InstanceModelMatrix * pos_4d).xyz);
+ world_clip_planes_calc_clip_distance(wPos.xyz);
#endif
}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl
index 130f46e1e33..32db8d17572 100644
--- a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl
@@ -1,8 +1,6 @@
uniform mat4 ViewProjectionMatrix;
-#ifdef USE_WORLD_CLIP_PLANES
-uniform mat4 ModelMatrix;
-#endif
+
uniform int baseId;
/* ---- Instantiated Attrs ---- */
@@ -21,11 +19,11 @@ flat out uint finalId;
void main()
{
- vec4 pos_4d = vec4(pos * size, 1.0);
- gl_Position = ViewProjectionMatrix * InstanceModelMatrix * pos_4d;
+ vec4 wPos = InstanceModelMatrix * vec4(pos * size, 1.0);
+ gl_Position = ViewProjectionMatrix * wPos;
finalId = uint(baseId + callId);
#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((ModelMatrix * InstanceModelMatrix * pos_4d).xyz);
+ world_clip_planes_calc_clip_distance(wPos.xyz);
#endif
}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl
index eeca6e972fa..b8d31f5540a 100644
--- a/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl
@@ -9,5 +9,5 @@ in mat4 InstanceModelMatrix;
void main()
{
- gl_Position = ViewProjectionMatrix * InstanceModelMatrix * vec4(pos, 1.0);
+ gl_Position = ViewProjectionMatrix * (InstanceModelMatrix * vec4(pos, 1.0));
}