From 3a08153d7a842b7ab1e40a9048730e1a3ddab5f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Fri, 31 May 2019 01:45:41 +0200 Subject: DRW: Refactor to support draw call batching Reviewers: brecht Differential Revision: D4997 --- source/blender/blenlib/BLI_memblock.h | 11 +- source/blender/blenlib/intern/BLI_memblock.c | 23 +- .../blender/draw/engines/eevee/eevee_materials.c | 64 +- .../draw/engines/gpencil/gpencil_draw_utils.c | 68 +- .../blender/draw/engines/gpencil/gpencil_engine.c | 79 +- .../blender/draw/engines/gpencil/gpencil_engine.h | 1 + .../blender/draw/engines/gpencil/gpencil_render.c | 3 + .../gpencil/shaders/gpencil_edit_point_vert.glsl | 4 +- .../engines/gpencil/shaders/gpencil_fill_vert.glsl | 4 +- .../gpencil/shaders/gpencil_point_vert.glsl | 5 +- .../gpencil/shaders/gpencil_stroke_vert.glsl | 3 +- .../shaders/workbench_forward_depth_frag.glsl | 8 +- .../workbench_forward_transparent_accum_frag.glsl | 28 +- .../workbench/shaders/workbench_prepass_frag.glsl | 12 +- .../workbench/shaders/workbench_prepass_vert.glsl | 12 +- .../workbench/shaders/workbench_volume_frag.glsl | 8 +- .../workbench/shaders/workbench_volume_vert.glsl | 7 +- .../draw/engines/workbench/workbench_deferred.c | 19 +- .../draw/engines/workbench/workbench_forward.c | 50 +- .../draw/engines/workbench/workbench_materials.c | 133 ++-- .../draw/engines/workbench/workbench_private.h | 12 +- .../draw/engines/workbench/workbench_volume.c | 8 +- source/blender/draw/intern/DRW_render.h | 44 +- source/blender/draw/intern/draw_anim_viz.c | 4 +- source/blender/draw/intern/draw_common.c | 2 +- source/blender/draw/intern/draw_hair.c | 41 +- source/blender/draw/intern/draw_instance_data.c | 4 +- source/blender/draw/intern/draw_instance_data.h | 2 +- source/blender/draw/intern/draw_manager.c | 93 ++- source/blender/draw/intern/draw_manager.h | 320 ++++++-- source/blender/draw/intern/draw_manager_data.c | 806 ++++++++++++++------- source/blender/draw/intern/draw_manager_exec.c | 689 +++++++++++++----- source/blender/draw/modes/edit_curve_mode.c | 2 +- source/blender/draw/modes/object_mode.c | 329 +++------ source/blender/draw/modes/overlay_mode.c | 26 +- .../draw/modes/shaders/common_view_lib.glsl | 67 ++ .../modes/shaders/object_lightprobe_grid_vert.glsl | 12 +- .../modes/shaders/object_outline_detect_frag.glsl | 40 +- .../modes/shaders/object_outline_prepass_frag.glsl | 14 +- .../modes/shaders/object_outline_prepass_geom.glsl | 7 +- .../modes/shaders/object_outline_prepass_vert.glsl | 17 +- source/blender/editors/mesh/editmesh_intersect.c | 32 +- source/blender/gpu/CMakeLists.txt | 2 + source/blender/gpu/GPU_batch.h | 11 + source/blender/gpu/GPU_shader_interface.h | 9 +- source/blender/gpu/GPU_viewport.h | 10 +- source/blender/gpu/intern/gpu_batch.c | 244 ++++++- source/blender/gpu/intern/gpu_codegen.c | 35 +- source/blender/gpu/intern/gpu_shader.c | 6 + source/blender/gpu/intern/gpu_shader_interface.c | 5 +- source/blender/gpu/intern/gpu_viewport.c | 25 +- .../gpu/shaders/gpu_shader_common_obinfos_lib.glsl | 19 + .../shaders/gpu_shader_instance_camera_vert.glsl | 8 +- .../gpu_shader_instance_distance_line_vert.glsl | 7 +- ...instance_variying_size_variying_color_vert.glsl | 7 +- ...er_instance_variying_size_variying_id_vert.glsl | 10 +- .../gpu/shaders/gpu_shader_instance_vert.glsl | 2 +- 57 files changed, 2270 insertions(+), 1243 deletions(-) create mode 100644 source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl 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 #include +#include -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()) { @@ -696,6 +739,179 @@ void GPU_draw_primitive(GPUPrimType prim_type, int v_count) // glBindVertexArray(0); } +/* -------------------------------------------------------------------- */ +/** \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 #include +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)); } -- cgit v1.2.3