diff options
Diffstat (limited to 'source/blender/draw')
65 files changed, 2287 insertions, 2935 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index d9f7a3acae0..aeecb452217 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -34,6 +34,7 @@ set(INC ../imbuf ../makesdna ../makesrna + ../nodes ../render/extern/include ../render/intern/include ../windowmanager @@ -317,8 +318,8 @@ data_to_c_simple(engines/select/shaders/selection_id_3D_vert.glsl SRC) data_to_c_simple(engines/select/shaders/selection_id_frag.glsl SRC) data_to_c_simple(engines/basic/shaders/conservative_depth_geom.glsl SRC) -data_to_c_simple(engines/basic/shaders/conservative_depth_vert.glsl SRC) -data_to_c_simple(engines/basic/shaders/conservative_depth_frag.glsl SRC) +data_to_c_simple(engines/basic/shaders/depth_vert.glsl SRC) +data_to_c_simple(engines/basic/shaders/depth_frag.glsl SRC) if(WITH_LANPR) data_to_c_simple(engines/lanpr/shaders/lanpr_dpix_preview_geom.glsl SRC) diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c index 6658fea7825..bbc3c407f14 100644 --- a/source/blender/draw/engines/basic/basic_engine.c +++ b/source/blender/draw/engines/basic/basic_engine.c @@ -37,8 +37,8 @@ #define BASIC_ENGINE "BLENDER_BASIC" -extern char datatoc_conservative_depth_frag_glsl[]; -extern char datatoc_conservative_depth_vert_glsl[]; +extern char datatoc_depth_frag_glsl[]; +extern char datatoc_depth_vert_glsl[]; extern char datatoc_conservative_depth_geom_glsl[]; extern char datatoc_common_view_lib_glsl[]; @@ -91,22 +91,28 @@ static void basic_engine_init(void *UNUSED(vedata)) /* Depth prepass */ if (!sh_data->depth) { - sh_data->depth = DRW_shader_create_3d_depth_only(draw_ctx->sh_cfg); - const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg]; + + sh_data->depth = GPU_shader_create_from_arrays({ + .vert = (const char *[]){sh_cfg->lib, + datatoc_common_view_lib_glsl, + datatoc_depth_vert_glsl, + NULL}, + .frag = (const char *[]){datatoc_depth_frag_glsl, NULL}, + .defs = (const char *[]){sh_cfg->def, NULL}, + }); + sh_data->depth_conservative = GPU_shader_create_from_arrays({ .vert = (const char *[]){sh_cfg->lib, datatoc_common_view_lib_glsl, - datatoc_conservative_depth_vert_glsl, + datatoc_depth_vert_glsl, NULL}, .geom = (const char *[]){sh_cfg->lib, datatoc_common_view_lib_glsl, datatoc_conservative_depth_geom_glsl, NULL}, - .frag = (const char *[]){datatoc_common_view_lib_glsl, - datatoc_conservative_depth_frag_glsl, - NULL}, - .defs = (const char *[]){sh_cfg->def, NULL}, + .frag = (const char *[]){datatoc_depth_frag_glsl, NULL}, + .defs = (const char *[]){sh_cfg->def, "#define CONSERVATIVE_RASTER\n", NULL}, }); } } @@ -233,6 +239,7 @@ static void basic_engine_free(void) { for (int i = 0; i < GPU_SHADER_CFG_LEN; i++) { BASIC_Shaders *sh_data = &e_data.sh_data[i]; + DRW_SHADER_FREE_SAFE(sh_data->depth); DRW_SHADER_FREE_SAFE(sh_data->depth_conservative); } } diff --git a/source/blender/draw/engines/basic/shaders/conservative_depth_frag.glsl b/source/blender/draw/engines/basic/shaders/depth_frag.glsl index ff4a015c335..ff4a015c335 100644 --- a/source/blender/draw/engines/basic/shaders/conservative_depth_frag.glsl +++ b/source/blender/draw/engines/basic/shaders/depth_frag.glsl diff --git a/source/blender/draw/engines/basic/shaders/conservative_depth_vert.glsl b/source/blender/draw/engines/basic/shaders/depth_vert.glsl index c55a3211ff2..318d0acef6f 100644 --- a/source/blender/draw/engines/basic/shaders/conservative_depth_vert.glsl +++ b/source/blender/draw/engines/basic/shaders/depth_vert.glsl @@ -1,12 +1,16 @@ +#ifdef CONSERVATIVE_RASTER RESOURCE_ID_VARYING +#endif in vec3 pos; void main() { GPU_INTEL_VERTEX_SHADER_WORKAROUND +#ifdef CONSERVATIVE_RASTER PASS_RESOURCE_ID +#endif vec3 world_pos = point_object_to_world(pos); gl_Position = point_world_to_ndc(world_pos); diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c index 6874947de55..a19af77124f 100644 --- a/source/blender/draw/engines/eevee/eevee_data.c +++ b/source/blender/draw/engines/eevee/eevee_data.c @@ -24,6 +24,8 @@ #include "DRW_render.h" +#include "BLI_memblock.h" + #include "eevee_lightcache.h" #include "eevee_private.h" @@ -54,8 +56,17 @@ void EEVEE_view_layer_data_free(void *storage) DRW_UBO_FREE_SAFE(sldata->grid_ubo); DRW_UBO_FREE_SAFE(sldata->planar_ubo); DRW_UBO_FREE_SAFE(sldata->common_ubo); - for (int i = 0; i < MAX_MATERIAL_RENDER_PASSES_UBO; i++) { - DRW_UBO_FREE_SAFE(sldata->renderpass_ubo[i]); + + DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.combined); + DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.diff_color); + DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.diff_light); + DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.spec_color); + DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.spec_light); + DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.emit); + + if (sldata->material_cache) { + BLI_memblock_destroy(sldata->material_cache, NULL); + sldata->material_cache = NULL; } } diff --git a/source/blender/draw/engines/eevee/eevee_depth_of_field.c b/source/blender/draw/engines/eevee/eevee_depth_of_field.c index ec6770e4549..4a3cc36ddef 100644 --- a/source/blender/draw/engines/eevee/eevee_depth_of_field.c +++ b/source/blender/draw/engines/eevee/eevee_depth_of_field.c @@ -31,6 +31,8 @@ #include "BKE_camera.h" +#include "BLI_string_utils.h" + #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" @@ -48,24 +50,28 @@ static struct { extern char datatoc_effect_dof_vert_glsl[]; extern char datatoc_effect_dof_frag_glsl[]; +extern char datatoc_common_view_lib_glsl[]; + static void eevee_create_shader_depth_of_field(const bool use_alpha) { + char *frag = BLI_string_joinN(datatoc_common_view_lib_glsl, datatoc_effect_dof_frag_glsl); e_data.dof_downsample_sh[use_alpha] = DRW_shader_create_fullscreen( - datatoc_effect_dof_frag_glsl, + frag, use_alpha ? "#define USE_ALPHA_DOF\n" "#define STEP_DOWNSAMPLE\n" : "#define STEP_DOWNSAMPLE\n"); e_data.dof_scatter_sh[use_alpha] = DRW_shader_create(datatoc_effect_dof_vert_glsl, NULL, - datatoc_effect_dof_frag_glsl, + frag, use_alpha ? "#define USE_ALPHA_DOF\n" "#define STEP_SCATTER\n" : "#define STEP_SCATTER\n"); - e_data.dof_resolve_sh[use_alpha] = DRW_shader_create_fullscreen(datatoc_effect_dof_frag_glsl, + e_data.dof_resolve_sh[use_alpha] = DRW_shader_create_fullscreen(frag, use_alpha ? "#define USE_ALPHA_DOF\n" "#define STEP_RESOLVE\n" : "#define STEP_RESOLVE\n"); + MEM_freeN(frag); } int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index 05b18da4374..ab846fe0f11 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -333,8 +333,7 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) grp = DRW_shgroup_create(EEVEE_shaders_velocity_resolve_sh_get(), psl->velocity_resolve); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_uniform_mat4(grp, "currPersinv", effects->velocity_curr_persinv); DRW_shgroup_uniform_mat4(grp, "pastPersmat", effects->velocity_past_persmat); DRW_shgroup_call(grp, quad, NULL); diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index a1112eb92df..b698574f9d7 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -88,7 +88,7 @@ static void eevee_engine_init(void *ved) * `EEVEE_effects_init` needs to go second for TAA. */ EEVEE_renderpasses_init(vedata); EEVEE_effects_init(sldata, vedata, camera, false); - EEVEE_materials_init(sldata, stl, fbl); + EEVEE_materials_init(sldata, vedata, stl, fbl); EEVEE_shadows_init(sldata); EEVEE_lightprobes_init(sldata, vedata); } @@ -230,7 +230,7 @@ static void eevee_draw_scene(void *vedata) BLI_halton_3d(primes, offset, samp, r); EEVEE_update_noise(psl, fbl, r); EEVEE_volumes_set_jitter(sldata, samp - 1); - EEVEE_materials_init(sldata, stl, fbl); + EEVEE_materials_init(sldata, vedata, stl, fbl); } /* Copy previous persmat to UBO data */ copy_m4_m4(sldata->common_data.prev_persmat, stl->effects->prev_persmat); @@ -274,8 +274,7 @@ static void eevee_draw_scene(void *vedata) /* Depth prepass */ DRW_stats_group_start("Prepass"); - DRW_draw_pass(psl->depth_pass); - DRW_draw_pass(psl->depth_pass_cull); + DRW_draw_pass(psl->depth_ps); DRW_stats_group_end(); /* Create minmax texture */ @@ -289,9 +288,9 @@ static void eevee_draw_scene(void *vedata) /* Shading pass */ DRW_stats_group_start("Shading"); if (DRW_state_draw_background()) { - DRW_draw_pass(psl->background_pass); + DRW_draw_pass(psl->background_ps); } - EEVEE_materials_draw_opaque(sldata, psl); + DRW_draw_pass(psl->material_ps); EEVEE_subsurface_data_render(sldata, vedata); DRW_stats_group_end(); @@ -306,9 +305,8 @@ static void eevee_draw_scene(void *vedata) /* Opaque refraction */ DRW_stats_group_start("Opaque Refraction"); - DRW_draw_pass(psl->refract_depth_pass); - DRW_draw_pass(psl->refract_depth_pass_cull); - DRW_draw_pass(psl->refract_pass); + DRW_draw_pass(psl->depth_refract_ps); + DRW_draw_pass(psl->material_refract_ps); DRW_stats_group_end(); /* Volumetrics Resolve Opaque */ diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c index 614c749b9aa..4cdd166f09c 100644 --- a/source/blender/draw/engines/eevee/eevee_lightcache.c +++ b/source/blender/draw/engines/eevee/eevee_lightcache.c @@ -379,9 +379,7 @@ static bool eevee_lightcache_static_load(LightCache *lcache) 0, false, NULL); - GPU_texture_bind(lcache->grid_tx.tex, 0); GPU_texture_filter_mode(lcache->grid_tx.tex, true); - GPU_texture_unbind(lcache->grid_tx.tex); } if (lcache->cube_tx.tex == NULL) { @@ -406,13 +404,11 @@ static bool eevee_lightcache_static_load(LightCache *lcache) NULL); } - GPU_texture_bind(lcache->cube_tx.tex, 0); - GPU_texture_mipmap_mode(lcache->cube_tx.tex, true, true); for (int mip = 0; mip < lcache->mips_len; mip++) { GPU_texture_add_mipmap( lcache->cube_tx.tex, GPU_DATA_10_11_11_REV, mip + 1, lcache->cube_mips[mip].data); } - GPU_texture_unbind(lcache->cube_tx.tex); + GPU_texture_mipmap_mode(lcache->cube_tx.tex, true, true); } return true; } @@ -822,7 +818,7 @@ static void eevee_lightbake_cache_create(EEVEE_Data *vedata, EEVEE_LightBake *lb DRW_render_viewport_size_set(viewport_size); EEVEE_effects_init(sldata, vedata, NULL, true); - EEVEE_materials_init(sldata, stl, fbl); + EEVEE_materials_init(sldata, vedata, stl, fbl); EEVEE_shadows_init(sldata); EEVEE_lightprobes_init(sldata, vedata); diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index 3350c512b17..83b2a9bb6d4 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -248,8 +248,7 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata, // DRW_shgroup_uniform_texture(grp, "texJitter", e_data.jitter); DRW_shgroup_uniform_texture(grp, "probeHdr", rt_color); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); DRW_shgroup_call_instances(grp, NULL, geom, 6); @@ -271,8 +270,7 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_float(grp, "intensityFac", &pinfo->intensity_fac, 1); DRW_shgroup_uniform_texture(grp, "probeHdr", rt_color); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); DRW_shgroup_call(grp, geom, NULL); @@ -293,8 +291,7 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley); DRW_shgroup_uniform_texture(grp, "probeDepth", rt_depth); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); DRW_shgroup_call(grp, geom, NULL); @@ -337,51 +334,29 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat Scene *scene = draw_ctx->scene; World *wo = scene->world; - const float *col = G_draw.block.colorBackground; - /* LookDev */ EEVEE_lookdev_cache_init(vedata, sldata, &grp, psl->probe_background, wo, pinfo); - /* END */ + if (!grp && wo) { - col = &wo->horr; - - if (wo->use_nodes && wo->nodetree) { - static float error_col[3] = {1.0f, 0.0f, 1.0f}; - static float queue_col[3] = {0.5f, 0.5f, 0.5f}; - struct GPUMaterial *gpumat = EEVEE_material_world_lightprobe_get(scene, wo); - - eGPUMaterialStatus status = GPU_material_status(gpumat); - - switch (status) { - case GPU_MAT_SUCCESS: - grp = DRW_shgroup_material_create(gpumat, psl->probe_background); - DRW_shgroup_uniform_float_copy(grp, "backgroundAlpha", 1.0f); - /* TODO (fclem): remove those (need to clean the GLSL files). */ - DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); - DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); - DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); - DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); - DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); - DRW_shgroup_call(grp, geom, NULL); - break; - case GPU_MAT_QUEUED: - stl->g_data->queued_shaders_count++; - col = queue_col; - break; - default: - col = error_col; - break; - } - } + struct GPUMaterial *gpumat = EEVEE_material_get(vedata, scene, NULL, wo, VAR_WORLD_PROBE); + + grp = DRW_shgroup_material_create(gpumat, psl->probe_background); + DRW_shgroup_uniform_float_copy(grp, "backgroundAlpha", 1.0f); + /* TODO (fclem): remove those (need to clean the GLSL files). */ + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); + DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); + DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); + DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); + DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); + DRW_shgroup_call(grp, geom, NULL); } /* Fallback if shader fails or if not using nodetree. */ if (grp == NULL) { grp = DRW_shgroup_create(EEVEE_shaders_probe_default_sh_get(), psl->probe_background); - DRW_shgroup_uniform_vec3(grp, "color", col, 1); + DRW_shgroup_uniform_vec3(grp, "color", G_draw.block.colorBackground, 1); DRW_shgroup_uniform_float_copy(grp, "backgroundAlpha", 1.0f); DRW_shgroup_call(grp, geom, NULL); } @@ -408,8 +383,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat /* TODO (fclem) get rid of those UBO. */ DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_call_procedural_triangles(grp, NULL, cube_len * 2); } @@ -436,8 +410,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat DRW_shgroup_uniform_block(shgrp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo); DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - shgrp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(shgrp, "renderpass_block", sldata->renderpass_ubo.combined); int tri_count = egrid->resolution[0] * egrid->resolution[1] * egrid->resolution[2] * 2; DRW_shgroup_call_procedural_triangles(shgrp, NULL, tri_count); } @@ -455,8 +428,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_probe_planar_display_sh_get(), psl->probe_display); DRW_shgroup_uniform_texture_ref(grp, "probePlanars", &txl->planar_pool); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); stl->g_data->planar_display_shgrp = DRW_shgroup_call_buffer_instance( grp, e_data.format_probe_display_planar, DRW_cache_quad_get()); @@ -923,12 +895,10 @@ static void lightbake_render_scene_face(int face, EEVEE_BakeRenderData *user_dat GPU_framebuffer_bind(face_fb[face]); GPU_framebuffer_clear_depth(face_fb[face], 1.0f); - DRW_draw_pass(psl->depth_pass); - DRW_draw_pass(psl->depth_pass_cull); + DRW_draw_pass(psl->depth_ps); DRW_draw_pass(psl->probe_background); - EEVEE_materials_draw_opaque(sldata, psl); - DRW_draw_pass(psl->sss_pass); /* Only output standard pass */ - DRW_draw_pass(psl->sss_pass_cull); + DRW_draw_pass(psl->material_ps); + DRW_draw_pass(psl->material_sss_ps); /* Only output standard pass */ DRW_draw_pass(psl->transparent_pass); } @@ -987,10 +957,8 @@ static void lightbake_render_scene_reflected(int layer, EEVEE_BakeRenderData *us /* Slight modification: we handle refraction as normal * shading and don't do SSRefraction. */ - DRW_draw_pass(psl->depth_pass_clip); - DRW_draw_pass(psl->depth_pass_clip_cull); - DRW_draw_pass(psl->refract_depth_pass_clip); - DRW_draw_pass(psl->refract_depth_pass_clip_cull); + DRW_draw_pass(psl->depth_ps); + DRW_draw_pass(psl->depth_refract_ps); DRW_draw_pass(psl->probe_background); EEVEE_create_minmax_buffer(vedata, tmp_planar_depth, layer); @@ -999,10 +967,9 @@ static void lightbake_render_scene_reflected(int layer, EEVEE_BakeRenderData *us GPU_framebuffer_bind(fbl->planarref_fb); /* Shading pass */ - EEVEE_materials_draw_opaque(sldata, psl); - DRW_draw_pass(psl->sss_pass); /* Only output standard pass */ - DRW_draw_pass(psl->sss_pass_cull); - DRW_draw_pass(psl->refract_pass); + DRW_draw_pass(psl->material_ps); + DRW_draw_pass(psl->material_sss_ps); /* Only output standard pass */ + DRW_draw_pass(psl->material_refract_ps); /* Transparent */ if (DRW_state_is_image_render()) { diff --git a/source/blender/draw/engines/eevee/eevee_lookdev.c b/source/blender/draw/engines/eevee/eevee_lookdev.c index b33be750d80..18365d69514 100644 --- a/source/blender/draw/engines/eevee/eevee_lookdev.c +++ b/source/blender/draw/engines/eevee/eevee_lookdev.c @@ -34,6 +34,8 @@ #include "ED_screen.h" +#include "GPU_material.h" + #include "UI_resources.h" #include "eevee_lightcache.h" @@ -56,6 +58,43 @@ static void eevee_lookdev_lightcache_delete(EEVEE_Data *vedata) g_data->studiolight_rot_z = 0.0f; } +static void eevee_lookdev_hdri_preview_init(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata) +{ + EEVEE_PassList *psl = vedata->psl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + DRWShadingGroup *grp; + + struct GPUBatch *sphere = DRW_cache_sphere_get(); + int mat_options = VAR_MAT_MESH | VAR_MAT_LOOKDEV; + + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS | + DRW_STATE_CULL_BACK; + + { + Material *ma = EEVEE_material_default_diffuse_get(); + GPUMaterial *gpumat = EEVEE_material_get(vedata, scene, ma, NULL, mat_options); + struct GPUShader *sh = GPU_material_get_shader(gpumat); + + DRW_PASS_CREATE(psl->lookdev_diffuse_pass, state); + grp = DRW_shgroup_create(sh, psl->lookdev_diffuse_pass); + EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, false); + DRW_shgroup_add_material_resources(grp, gpumat); + DRW_shgroup_call(grp, sphere, NULL); + } + { + Material *ma = EEVEE_material_default_glossy_get(); + GPUMaterial *gpumat = EEVEE_material_get(vedata, scene, ma, NULL, mat_options); + struct GPUShader *sh = GPU_material_get_shader(gpumat); + + DRW_PASS_CREATE(psl->lookdev_glossy_pass, state); + grp = DRW_shgroup_create(sh, psl->lookdev_glossy_pass); + EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, false); + DRW_shgroup_add_material_resources(grp, gpumat); + DRW_shgroup_call(grp, sphere, NULL); + } +} + void EEVEE_lookdev_cache_init(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, DRWShadingGroup **r_grp, @@ -106,6 +145,8 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata, effects->anchor[1] = rect->ymin; EEVEE_temporal_sampling_reset(vedata); } + + eevee_lookdev_hdri_preview_init(vedata, sldata); } if (LOOK_DEV_STUDIO_LIGHT_ENABLED(v3d)) { @@ -176,8 +217,7 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata, DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); } DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); diff --git a/source/blender/draw/engines/eevee/eevee_lut_gen.c b/source/blender/draw/engines/eevee/eevee_lut_gen.c new file mode 100644 index 00000000000..5f20d6fbfb8 --- /dev/null +++ b/source/blender/draw/engines/eevee/eevee_lut_gen.c @@ -0,0 +1,198 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2020, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + * + * EEVEE LUT generation: + * + * Routine to generate the LUT used by eevee stored in eevee_lut.h + * Theses functions are not to be used in the final executable. + */ + +#include "DRW_render.h" + +#include "BLI_alloca.h" +#include "BLI_rand.h" +#include "BLI_string_utils.h" + +extern char datatoc_bsdf_lut_frag_glsl[]; +extern char datatoc_btdf_lut_frag_glsl[]; +extern char datatoc_bsdf_common_lib_glsl[]; +extern char datatoc_bsdf_sampling_lib_glsl[]; +extern char datatoc_lightprobe_geom_glsl[]; +extern char datatoc_lightprobe_vert_glsl[]; + +static struct GPUTexture *create_ggx_lut_texture(int UNUSED(w), int UNUSED(h)) +{ + struct GPUTexture *tex; + struct GPUFrameBuffer *fb = NULL; + static float samples_len = 8192.0f; + static float inv_samples_len = 1.0f / 8192.0f; + + char *lib_str = BLI_string_joinN(datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl); + + struct GPUShader *sh = DRW_shader_create_with_lib(datatoc_lightprobe_vert_glsl, + datatoc_lightprobe_geom_glsl, + datatoc_bsdf_lut_frag_glsl, + lib_str, + "#define HAMMERSLEY_SIZE 8192\n" + "#define BRDF_LUT_SIZE 64\n" + "#define NOISE_SIZE 64\n"); + + DRWPass *pass = DRW_pass_create("LightProbe Filtering", DRW_STATE_WRITE_COLOR); + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_float(grp, "sampleCount", &samples_len, 1); + DRW_shgroup_uniform_float(grp, "invSampleCount", &inv_samples_len, 1); + DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley); + DRW_shgroup_uniform_texture(grp, "texJitter", e_data.jitter); + + struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); + DRW_shgroup_call(grp, geom, NULL); + + float *texels = MEM_mallocN(sizeof(float[2]) * w * h, "lut"); + + tex = DRW_texture_create_2d(w, h, GPU_RG16F, DRW_TEX_FILTER, (float *)texels); + + DRWFboTexture tex_filter = {&tex, GPU_RG16F, DRW_TEX_FILTER}; + GPU_framebuffer_init(&fb, &draw_engine_eevee_type, w, h, &tex_filter, 1); + + GPU_framebuffer_bind(fb); + DRW_draw_pass(pass); + + float *data = MEM_mallocN(sizeof(float[3]) * w * h, "lut"); + glReadBuffer(GL_COLOR_ATTACHMENT0); + glReadPixels(0, 0, w, h, GL_RGB, GL_FLOAT, data); + + printf("{"); + for (int i = 0; i < w * h * 3; i += 3) { + printf("%ff, %ff, ", data[i], data[i + 1]); + i += 3; + printf("%ff, %ff, ", data[i], data[i + 1]); + i += 3; + printf("%ff, %ff, ", data[i], data[i + 1]); + i += 3; + printf("%ff, %ff, \n", data[i], data[i + 1]); + } + printf("}"); + + MEM_freeN(texels); + MEM_freeN(data); + + return tex; +} + +static struct GPUTexture *create_ggx_refraction_lut_texture(int w, int h) +{ + struct GPUTexture *tex; + struct GPUTexture *hammersley = create_hammersley_sample_texture(8192); + struct GPUFrameBuffer *fb = NULL; + static float samples_len = 8192.0f; + static float a2 = 0.0f; + static float inv_samples_len = 1.0f / 8192.0f; + + char *frag_str = BLI_string_joinN( + datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl, datatoc_btdf_lut_frag_glsl); + + struct GPUShader *sh = DRW_shader_create_fullscreen(frag_str, + "#define HAMMERSLEY_SIZE 8192\n" + "#define BRDF_LUT_SIZE 64\n" + "#define NOISE_SIZE 64\n" + "#define LUT_SIZE 64\n"); + + MEM_freeN(frag_str); + + DRWPass *pass = DRW_pass_create("LightProbe Filtering", DRW_STATE_WRITE_COLOR); + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_float(grp, "a2", &a2, 1); + DRW_shgroup_uniform_float(grp, "sampleCount", &samples_len, 1); + DRW_shgroup_uniform_float(grp, "invSampleCount", &inv_samples_len, 1); + DRW_shgroup_uniform_texture(grp, "texHammersley", hammersley); + DRW_shgroup_uniform_texture(grp, "utilTex", e_data.util_tex); + + struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); + DRW_shgroup_call(grp, geom, NULL); + + float *texels = MEM_mallocN(sizeof(float[2]) * w * h, "lut"); + + tex = DRW_texture_create_2d(w, h, GPU_R16F, DRW_TEX_FILTER, (float *)texels); + + DRWFboTexture tex_filter = {&tex, GPU_R16F, DRW_TEX_FILTER}; + GPU_framebuffer_init(&fb, &draw_engine_eevee_type, w, h, &tex_filter, 1); + + GPU_framebuffer_bind(fb); + + float *data = MEM_mallocN(sizeof(float[3]) * w * h, "lut"); + + float inc = 1.0f / 31.0f; + float roughness = 1e-8f - inc; + FILE *f = BLI_fopen("btdf_split_sum_ggx.h", "w"); + fprintf(f, "static float btdf_split_sum_ggx[32][64 * 64] = {\n"); + do { + roughness += inc; + CLAMP(roughness, 1e-4f, 1.0f); + a2 = powf(roughness, 4.0f); + DRW_draw_pass(pass); + + GPU_framebuffer_read_data(0, 0, w, h, 3, 0, data); + +#if 1 + fprintf(f, "\t{\n\t\t"); + for (int i = 0; i < w * h * 3; i += 3) { + fprintf(f, "%ff,", data[i]); + if (((i / 3) + 1) % 12 == 0) { + fprintf(f, "\n\t\t"); + } + else { + fprintf(f, " "); + } + } + fprintf(f, "\n\t},\n"); +#else + for (int i = 0; i < w * h * 3; i += 3) { + if (data[i] < 0.01) { + printf(" "); + } + else if (data[i] < 0.3) { + printf("."); + } + else if (data[i] < 0.6) { + printf("+"); + } + else if (data[i] < 0.9) { + printf("%%"); + } + else { + printf("#"); + } + if ((i / 3 + 1) % 64 == 0) { + printf("\n"); + } + } +#endif + + } while (roughness < 1.0f); + fprintf(f, "\n};\n"); + + fclose(f); + + MEM_freeN(texels); + MEM_freeN(data); + + return tex; +}
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index 03cdb02a48a..0f10fb0ef53 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -23,10 +23,10 @@ #include "DRW_render.h" #include "BLI_alloca.h" -#include "BLI_dynstr.h" #include "BLI_ghash.h" #include "BLI_listbase.h" #include "BLI_math_bits.h" +#include "BLI_memblock.h" #include "BLI_rand.h" #include "BLI_string_utils.h" @@ -48,29 +48,11 @@ /* *********** STATIC *********** */ 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; - struct GPUShader *default_prepass_clip_sh; - struct GPUShader *default_hair_prepass_sh; - struct GPUShader *default_hair_prepass_clip_sh; - struct GPUShader *default_lit[VAR_MAT_MAX]; - struct GPUShader *default_background; - struct GPUShader *update_noise_sh; - /* 64*64 array texture containing all LUTs and other utilitarian arrays. * Packing enables us to same precious textures slots. */ struct GPUTexture *util_tex; struct GPUTexture *noise_tex; - uint sss_count; - float noise_offsets[3]; } e_data = {NULL}; /* Engine data */ @@ -82,8 +64,6 @@ extern char datatoc_prepass_vert_glsl[]; extern char datatoc_default_frag_glsl[]; extern char datatoc_default_world_frag_glsl[]; extern char datatoc_ltc_lib_glsl[]; -extern char datatoc_bsdf_lut_frag_glsl[]; -extern char datatoc_btdf_lut_frag_glsl[]; extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_bsdf_sampling_lib_glsl[]; extern char datatoc_common_uniforms_lib_glsl[]; @@ -107,320 +87,45 @@ extern char datatoc_volumetric_frag_glsl[]; extern char datatoc_volumetric_lib_glsl[]; extern char datatoc_gpu_shader_uniform_color_frag_glsl[]; -#define DEFAULT_RENDER_PASS_FLAG 0xefffffff - -/* Iterator for render passes. This iteration will only do the material based render passes. it - * will ignore `EEVEE_RENDER_PASS_ENVIRONMENT`. - * - * parameters: - * - `render_passes_` is a bitflag for render_passes that needs to be iterated over. - * - `render_pass_index_` is a parameter name where the index of the render_pass will be available - * during iteration. This index can be used to select the right pass in the `psl`. - * - `render_pass_` is the bitflag of the render_pass of the current iteration. - * - * The `render_pass_index_` parameter needs to be the same for the `RENDER_PASS_ITER_BEGIN` and - * `RENDER_PASS_ITER_END`. - */ -#define RENDER_PASS_ITER_BEGIN(render_passes_, render_pass_index_, render_pass_) \ - const eViewLayerEEVEEPassType __filtered_##render_pass_index_ = render_passes_ & \ - EEVEE_RENDERPASSES_MATERIAL & \ - ~EEVEE_RENDER_PASS_ENVIRONMENT; \ - if (__filtered_##render_pass_index_ != 0) { \ - int render_pass_index_ = 1; \ - for (int bit_##render_pass_ = 0; bit_##render_pass_ < EEVEE_RENDER_PASS_MAX_BIT; \ - bit_##render_pass_++) { \ - eViewLayerEEVEEPassType render_pass_ = (1 << bit_##render_pass_); \ - if ((__filtered_##render_pass_index_ & render_pass_) != 0) { -#define RENDER_PASS_ITER_END(render_pass_index_) \ - render_pass_index_ += 1; \ - } \ - } \ - } \ - ((void)0) +typedef struct EeveeMaterialCache { + struct DRWShadingGroup *depth_grp; + struct DRWShadingGroup *shading_grp; + struct DRWShadingGroup *shadow_grp; + struct GPUMaterial *shading_gpumat; + /* Meh, Used by hair to ensure draw order when calling DRW_shgroup_create_sub. + * Pointers to ghash values. */ + struct DRWShadingGroup **depth_grp_p; + struct DRWShadingGroup **shading_grp_p; + struct DRWShadingGroup **shadow_grp_p; +} EeveeMaterialCache; /* *********** FUNCTIONS *********** */ -#if 0 /* Used only to generate the LUT values */ -static struct GPUTexture *create_ggx_lut_texture(int UNUSED(w), int UNUSED(h)) -{ - struct GPUTexture *tex; - struct GPUFrameBuffer *fb = NULL; - static float samples_len = 8192.0f; - static float inv_samples_len = 1.0f / 8192.0f; - - char *lib_str = BLI_string_joinN(datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl); - - struct GPUShader *sh = DRW_shader_create_with_lib(datatoc_lightprobe_vert_glsl, - datatoc_lightprobe_geom_glsl, - datatoc_bsdf_lut_frag_glsl, - lib_str, - "#define HAMMERSLEY_SIZE 8192\n" - "#define BRDF_LUT_SIZE 64\n" - "#define NOISE_SIZE 64\n"); - - DRWPass *pass = DRW_pass_create("LightProbe Filtering", DRW_STATE_WRITE_COLOR); - DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); - DRW_shgroup_uniform_float(grp, "sampleCount", &samples_len, 1); - DRW_shgroup_uniform_float(grp, "invSampleCount", &inv_samples_len, 1); - DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley); - DRW_shgroup_uniform_texture(grp, "texJitter", e_data.jitter); - - struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); - DRW_shgroup_call(grp, geom, NULL); - - float *texels = MEM_mallocN(sizeof(float[2]) * w * h, "lut"); - - tex = DRW_texture_create_2d(w, h, GPU_RG16F, DRW_TEX_FILTER, (float *)texels); - - DRWFboTexture tex_filter = {&tex, GPU_RG16F, DRW_TEX_FILTER}; - GPU_framebuffer_init(&fb, &draw_engine_eevee_type, w, h, &tex_filter, 1); - - GPU_framebuffer_bind(fb); - DRW_draw_pass(pass); - - float *data = MEM_mallocN(sizeof(float[3]) * w * h, "lut"); - glReadBuffer(GL_COLOR_ATTACHMENT0); - glReadPixels(0, 0, w, h, GL_RGB, GL_FLOAT, data); - - printf("{"); - for (int i = 0; i < w * h * 3; i += 3) { - printf("%ff, %ff, ", data[i], data[i + 1]); - i += 3; - printf("%ff, %ff, ", data[i], data[i + 1]); - i += 3; - printf("%ff, %ff, ", data[i], data[i + 1]); - i += 3; - printf("%ff, %ff, \n", data[i], data[i + 1]); - } - printf("}"); - - MEM_freeN(texels); - MEM_freeN(data); - - return tex; -} - -static struct GPUTexture *create_ggx_refraction_lut_texture(int w, int h) -{ - struct GPUTexture *tex; - struct GPUTexture *hammersley = create_hammersley_sample_texture(8192); - struct GPUFrameBuffer *fb = NULL; - static float samples_len = 8192.0f; - static float a2 = 0.0f; - static float inv_samples_len = 1.0f / 8192.0f; - - char *frag_str = BLI_string_joinN( - datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl, datatoc_btdf_lut_frag_glsl); - - struct GPUShader *sh = DRW_shader_create_fullscreen(frag_str, - "#define HAMMERSLEY_SIZE 8192\n" - "#define BRDF_LUT_SIZE 64\n" - "#define NOISE_SIZE 64\n" - "#define LUT_SIZE 64\n"); - - MEM_freeN(frag_str); - - DRWPass *pass = DRW_pass_create("LightProbe Filtering", DRW_STATE_WRITE_COLOR); - DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); - DRW_shgroup_uniform_float(grp, "a2", &a2, 1); - DRW_shgroup_uniform_float(grp, "sampleCount", &samples_len, 1); - DRW_shgroup_uniform_float(grp, "invSampleCount", &inv_samples_len, 1); - DRW_shgroup_uniform_texture(grp, "texHammersley", hammersley); - DRW_shgroup_uniform_texture(grp, "utilTex", e_data.util_tex); - - struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); - DRW_shgroup_call(grp, geom, NULL); - - float *texels = MEM_mallocN(sizeof(float[2]) * w * h, "lut"); - - tex = DRW_texture_create_2d(w, h, GPU_R16F, DRW_TEX_FILTER, (float *)texels); - - DRWFboTexture tex_filter = {&tex, GPU_R16F, DRW_TEX_FILTER}; - GPU_framebuffer_init(&fb, &draw_engine_eevee_type, w, h, &tex_filter, 1); - - GPU_framebuffer_bind(fb); - - float *data = MEM_mallocN(sizeof(float[3]) * w * h, "lut"); - - float inc = 1.0f / 31.0f; - float roughness = 1e-8f - inc; - FILE *f = BLI_fopen("btdf_split_sum_ggx.h", "w"); - fprintf(f, "static float btdf_split_sum_ggx[32][64 * 64] = {\n"); - do { - roughness += inc; - CLAMP(roughness, 1e-4f, 1.0f); - a2 = powf(roughness, 4.0f); - DRW_draw_pass(pass); - - GPU_framebuffer_read_data(0, 0, w, h, 3, 0, data); - -# if 1 - fprintf(f, "\t{\n\t\t"); - for (int i = 0; i < w * h * 3; i += 3) { - fprintf(f, "%ff,", data[i]); - if (((i / 3) + 1) % 12 == 0) { - fprintf(f, "\n\t\t"); - } - else { - fprintf(f, " "); - } - } - fprintf(f, "\n\t},\n"); -# else - for (int i = 0; i < w * h * 3; i += 3) { - if (data[i] < 0.01) { - printf(" "); - } - else if (data[i] < 0.3) { - printf("."); - } - else if (data[i] < 0.6) { - printf("+"); - } - else if (data[i] < 0.9) { - printf("%%"); - } - else { - printf("#"); - } - if ((i / 3 + 1) % 64 == 0) { - printf("\n"); - } - } -# endif - - } while (roughness < 1.0f); - fprintf(f, "\n};\n"); - - fclose(f); - - MEM_freeN(texels); - MEM_freeN(data); - - return tex; -} -#endif /* XXX TODO define all shared resources in a shared place without duplication */ struct GPUTexture *EEVEE_materials_get_util_tex(void) { return e_data.util_tex; } -static char *eevee_get_defines(int options) -{ - char *str = NULL; - - DynStr *ds = BLI_dynstr_new(); - BLI_dynstr_append(ds, SHADER_DEFINES); - - if ((options & VAR_MAT_MESH) != 0) { - BLI_dynstr_append(ds, "#define MESH_SHADER\n"); - } - if ((options & VAR_MAT_HAIR) != 0) { - BLI_dynstr_append(ds, "#define HAIR_SHADER\n"); - } - if ((options & VAR_MAT_PROBE) != 0) { - BLI_dynstr_append(ds, "#define PROBE_CAPTURE\n"); - } - if ((options & VAR_MAT_CLIP) != 0) { - BLI_dynstr_append(ds, "#define USE_ALPHA_CLIP\n"); - } - if ((options & VAR_MAT_SHADOW) != 0) { - BLI_dynstr_append(ds, "#define SHADOW_SHADER\n"); - } - if ((options & VAR_MAT_HASH) != 0) { - BLI_dynstr_append(ds, "#define USE_ALPHA_HASH\n"); - } - if ((options & VAR_MAT_BLEND) != 0) { - BLI_dynstr_append(ds, "#define USE_ALPHA_BLEND\n"); - } - if ((options & VAR_MAT_MULT) != 0) { - BLI_dynstr_append(ds, "#define USE_MULTIPLY\n"); - } - if ((options & VAR_MAT_REFRACT) != 0) { - BLI_dynstr_append(ds, "#define USE_REFRACTION\n"); - } - if ((options & VAR_MAT_LOOKDEV) != 0) { - BLI_dynstr_append(ds, "#define LOOKDEV\n"); - } - if ((options & VAR_MAT_HOLDOUT) != 0) { - BLI_dynstr_append(ds, "#define HOLDOUT\n"); - } - - str = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - - return str; -} - -static char *eevee_get_volume_defines(int options) -{ - char *str = NULL; - - DynStr *ds = BLI_dynstr_new(); - BLI_dynstr_append(ds, SHADER_DEFINES); - BLI_dynstr_append(ds, "#define VOLUMETRICS\n"); - - if ((options & VAR_MAT_VOLUME) != 0) { - BLI_dynstr_append(ds, "#define MESH_SHADER\n"); - } - - str = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - - return str; -} - -/* Get the default render pass ubo. This is a ubo that enables all bsdf render passes. */ -struct GPUUniformBuffer *EEVEE_material_default_render_pass_ubo_get(EEVEE_ViewLayerData *sldata) -{ - return sldata->renderpass_ubo[0]; -} - -/* Get the render pass ubo for rendering the given render_pass. */ -static struct GPUUniformBuffer *get_render_pass_ubo(EEVEE_ViewLayerData *sldata, - eViewLayerEEVEEPassType render_pass) -{ - int index; - switch (render_pass) { - case EEVEE_RENDER_PASS_DIFFUSE_COLOR: - index = 1; - break; - case EEVEE_RENDER_PASS_DIFFUSE_LIGHT: - index = 2; - break; - case EEVEE_RENDER_PASS_SPECULAR_COLOR: - index = 3; - break; - case EEVEE_RENDER_PASS_SPECULAR_LIGHT: - index = 4; - break; - case EEVEE_RENDER_PASS_EMIT: - index = 5; - break; - default: - index = 0; - break; - } - return sldata->renderpass_ubo[index]; -} /** * ssr_id can be null to disable ssr contribution. */ -static void add_standard_uniforms(DRWShadingGroup *shgrp, - EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - int *ssr_id, - float *refract_depth, - bool use_diffuse, - bool use_glossy, - bool use_refract, - bool use_ssrefraction, - bool use_alpha_blend, - eViewLayerEEVEEPassType render_pass) +void EEVEE_material_bind_resources(DRWShadingGroup *shgrp, + GPUMaterial *gpumat, + EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata, + int *ssr_id, + float *refract_depth, + bool use_ssrefraction, + bool use_alpha_blend) { + bool use_diffuse = GPU_material_flag_get(gpumat, GPU_MATFLAG_DIFFUSE); + bool use_glossy = GPU_material_flag_get(gpumat, GPU_MATFLAG_GLOSSY); + bool use_refract = GPU_material_flag_get(gpumat, GPU_MATFLAG_REFRACT); + LightCache *lcache = vedata->stl->g_data->light_cache; EEVEE_EffectsInfo *effects = vedata->stl->effects; + EEVEE_PrivateData *pd = vedata->stl->g_data; DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo); DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo); @@ -428,11 +133,11 @@ static void add_standard_uniforms(DRWShadingGroup *shgrp, DRW_shgroup_uniform_block(shgrp, "light_block", sldata->light_ubo); DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo); DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block(shgrp, "renderpass_block", get_render_pass_ubo(sldata, render_pass)); + DRW_shgroup_uniform_block_ref(shgrp, "renderpass_block", &pd->renderpass_ubo); DRW_shgroup_uniform_int_copy(shgrp, "outputSssId", 1); + DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex); if (use_diffuse || use_glossy || use_refract) { - DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex); DRW_shgroup_uniform_texture_ref(shgrp, "shadowCubeTexture", &sldata->shadow_cube_pool); DRW_shgroup_uniform_texture_ref(shgrp, "shadowCascadeTexture", &sldata->shadow_cascade_pool); DRW_shgroup_uniform_texture_ref(shgrp, "maxzBuffer", &vedata->txl->maxzbuffer); @@ -463,36 +168,6 @@ static void add_standard_uniforms(DRWShadingGroup *shgrp, } } -/* Add the uniforms for the background shader to `shgrp`. */ -static void add_background_uniforms(DRWShadingGroup *shgrp, - EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata) -{ - EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; - DRW_shgroup_uniform_float(shgrp, "backgroundAlpha", &stl->g_data->background_alpha, 1); - /* TODO (fclem): remove those (need to clean the GLSL files). */ - DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo); - DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo); - DRW_shgroup_uniform_block(shgrp, "planar_block", sldata->planar_ubo); - DRW_shgroup_uniform_block(shgrp, "light_block", sldata->light_ubo); - DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo); - DRW_shgroup_uniform_block( - shgrp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); -} - -static void create_default_shader(int options) -{ - char *frag_str = BLI_string_joinN(e_data.frag_shader_lib, datatoc_default_frag_glsl); - - char *defines = eevee_get_defines(options); - - e_data.default_lit[options] = DRW_shader_create(e_data.vert_shader_str, NULL, frag_str, defines); - - MEM_freeN(defines); - MEM_freeN(frag_str); -} - static void eevee_init_noise_texture(void) { e_data.noise_tex = DRW_texture_create_2d(64, 64, GPU_RGBA16F, 0, (float *)blue_noise); @@ -559,8 +234,6 @@ void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, const d e_data.noise_offsets[1] = offsets[1]; e_data.noise_offsets[2] = offsets[2]; - /* Attach & detach because we don't currently support multiple FB per texture, - * and this would be the case for multiple viewport. */ GPU_framebuffer_bind(fbl->update_noise_fb); DRW_draw_pass(psl->update_noise_pass); } @@ -606,94 +279,15 @@ void EEVEE_update_viewvecs(float invproj[4][4], float winmat[4][4], float (*r_vi } void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata, EEVEE_StorageList *stl, EEVEE_FramebufferList *fbl) { const DRWContextState *draw_ctx = DRW_context_state_get(); EEVEE_PrivateData *g_data = stl->g_data; - if (!e_data.frag_shader_lib) { - /* Shaders */ - e_data.frag_shader_lib = BLI_string_joinN(datatoc_common_view_lib_glsl, - datatoc_common_uniforms_lib_glsl, - datatoc_bsdf_common_lib_glsl, - datatoc_bsdf_sampling_lib_glsl, - datatoc_ambient_occlusion_lib_glsl, - datatoc_raytrace_lib_glsl, - datatoc_ssr_lib_glsl, - datatoc_octahedron_lib_glsl, - datatoc_cubemap_lib_glsl, - datatoc_irradiance_lib_glsl, - datatoc_lightprobe_lib_glsl, - datatoc_ltc_lib_glsl, - datatoc_lights_lib_glsl, - /* Add one for each Closure */ - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_volumetric_lib_glsl); - - e_data.volume_shader_lib = BLI_string_joinN(datatoc_common_view_lib_glsl, - datatoc_common_uniforms_lib_glsl, - datatoc_bsdf_common_lib_glsl, - datatoc_ambient_occlusion_lib_glsl, - datatoc_octahedron_lib_glsl, - datatoc_cubemap_lib_glsl, - datatoc_irradiance_lib_glsl, - datatoc_lightprobe_lib_glsl, - datatoc_ltc_lib_glsl, - datatoc_lights_lib_glsl, - datatoc_volumetric_lib_glsl, - datatoc_volumetric_frag_glsl); - - e_data.vert_shader_str = BLI_string_joinN( - datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_lit_surface_vert_glsl); - - 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, - datatoc_common_view_lib_glsl, - NULL); - - char *vert_str = BLI_string_joinN( - datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_prepass_vert_glsl); - - e_data.default_prepass_sh = DRW_shader_create(vert_str, NULL, datatoc_prepass_frag_glsl, NULL); - - e_data.default_prepass_clip_sh = DRW_shader_create( - vert_str, NULL, datatoc_prepass_frag_glsl, "#define CLIP_PLANES\n"); - - e_data.default_hair_prepass_sh = DRW_shader_create( - vert_str, NULL, datatoc_prepass_frag_glsl, "#define HAIR_SHADER\n"); - - e_data.default_hair_prepass_clip_sh = DRW_shader_create(vert_str, - NULL, - datatoc_prepass_frag_glsl, - "#define HAIR_SHADER\n" - "#define CLIP_PLANES\n"); - MEM_freeN(vert_str); - - e_data.update_noise_sh = DRW_shader_create_fullscreen(datatoc_update_noise_frag_glsl, NULL); + if (!e_data.util_tex) { + EEVEE_shaders_material_shaders_init(); eevee_init_util_texture(); eevee_init_noise_texture(); @@ -728,33 +322,36 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, { /* Create RenderPass UBO */ - if (sldata->renderpass_ubo[0] == NULL) { - /* EEVEE_RENDER_PASS_COMBINED */ - sldata->renderpass_data[0] = (const EEVEE_RenderPassData){ - true, true, true, true, true, false}; - /* EEVEE_RENDER_PASS_DIFFUSE_COLOR */ - sldata->renderpass_data[1] = (const EEVEE_RenderPassData){ - true, false, false, false, false, true}; - /* EEVEE_RENDER_PASS_DIFFUSE_LIGHT */ - sldata->renderpass_data[2] = (const EEVEE_RenderPassData){ - true, true, false, false, false, false}; - /* EEVEE_RENDER_PASS_SPECULAR_COLOR */ - sldata->renderpass_data[3] = (const EEVEE_RenderPassData){ - false, false, true, false, false, false}; - /* EEVEE_RENDER_PASS_SPECULAR_LIGHT */ - sldata->renderpass_data[4] = (const EEVEE_RenderPassData){ - false, false, true, true, false, false}; - /* EEVEE_RENDER_PASS_EMIT */ - sldata->renderpass_data[5] = (const EEVEE_RenderPassData){ - false, false, false, false, true, false}; - - for (int i = 0; i < MAX_MATERIAL_RENDER_PASSES_UBO; i++) { - sldata->renderpass_ubo[i] = DRW_uniformbuffer_create(sizeof(EEVEE_RenderPassData), - &sldata->renderpass_data[i]); - } + if (sldata->renderpass_ubo.combined == NULL) { + sldata->renderpass_ubo.combined = DRW_uniformbuffer_create( + sizeof(EEVEE_RenderPassData), + &(const EEVEE_RenderPassData){true, true, true, true, true, false}); + + sldata->renderpass_ubo.diff_color = DRW_uniformbuffer_create( + sizeof(EEVEE_RenderPassData), + &(const EEVEE_RenderPassData){true, false, false, false, false, true}); + + sldata->renderpass_ubo.diff_light = DRW_uniformbuffer_create( + sizeof(EEVEE_RenderPassData), + &(const EEVEE_RenderPassData){true, true, false, false, false, false}); + + sldata->renderpass_ubo.spec_color = DRW_uniformbuffer_create( + sizeof(EEVEE_RenderPassData), + &(const EEVEE_RenderPassData){false, false, true, false, false, false}); + + sldata->renderpass_ubo.spec_light = DRW_uniformbuffer_create( + sizeof(EEVEE_RenderPassData), + &(const EEVEE_RenderPassData){false, false, true, true, false, false}); + + sldata->renderpass_ubo.emit = DRW_uniformbuffer_create( + sizeof(EEVEE_RenderPassData), + &(const EEVEE_RenderPassData){false, false, false, false, true, false}); } - /* HACK: EEVEE_material_world_background_get can create a new context. This can only be + /* Used combined pass by default. */ + g_data->renderpass_ubo = sldata->renderpass_ubo.combined; + + /* HACK: EEVEE_material_get can create a new context. This can only be * done when there is no active framebuffer. We do this here otherwise * `EEVEE_renderpasses_output_init` will fail. It cannot be done in * `EEVEE_renderpasses_init` as the `e_data.vertcode` can be uninitialized. @@ -763,414 +360,12 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, struct Scene *scene = draw_ctx->scene; struct World *wo = scene->world; if (wo && wo->use_nodes) { - EEVEE_material_world_background_get(scene, wo); + EEVEE_material_get(vedata, scene, NULL, wo, VAR_WORLD_BACKGROUND); } } } } -struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, World *wo) -{ - const void *engine = &DRW_engine_viewport_eevee_type; - const int options = VAR_WORLD_PROBE; - - GPUMaterial *mat = DRW_shader_find_from_world(wo, engine, options, false); - if (mat != NULL) { - return mat; - } - return DRW_shader_create_from_world(scene, - wo, - engine, - options, - false, - e_data.vert_background_shader_str, - NULL, - e_data.frag_shader_lib, - SHADER_DEFINES "#define PROBE_CAPTURE\n", - false); -} - -struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, World *wo) -{ - const void *engine = &DRW_engine_viewport_eevee_type; - int options = VAR_WORLD_BACKGROUND; - - GPUMaterial *mat = DRW_shader_find_from_world(wo, engine, options, true); - if (mat != NULL) { - return mat; - } - return DRW_shader_create_from_world(scene, - wo, - engine, - options, - false, - e_data.vert_background_shader_str, - NULL, - e_data.frag_shader_lib, - SHADER_DEFINES "#define WORLD_BACKGROUND\n", - true); -} - -struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, World *wo) -{ - const void *engine = &DRW_engine_viewport_eevee_type; - int options = VAR_WORLD_VOLUME; - - GPUMaterial *mat = DRW_shader_find_from_world(wo, engine, options, true); - if (mat != NULL) { - return mat; - } - - char *defines = eevee_get_volume_defines(options); - - mat = DRW_shader_create_from_world(scene, - wo, - engine, - options, - true, - e_data.vert_volume_shader_str, - e_data.geom_volume_shader_str, - e_data.volume_shader_lib, - defines, - true); - - MEM_freeN(defines); - - return mat; -} - -struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene, - Material *ma, - EEVEE_Data *UNUSED(vedata), - bool use_blend, - bool use_refract) -{ - const void *engine = &DRW_engine_viewport_eevee_type; - int options = VAR_MAT_MESH; - - SET_FLAG_FROM_TEST(options, use_blend, VAR_MAT_BLEND); - SET_FLAG_FROM_TEST(options, use_refract, VAR_MAT_REFRACT); - - GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true); - if (mat) { - return mat; - } - - char *defines = eevee_get_defines(options); - - mat = DRW_shader_create_from_material(scene, - ma, - engine, - options, - false, - e_data.vert_shader_str, - NULL, - e_data.frag_shader_lib, - defines, - true); - - MEM_freeN(defines); - - return mat; -} - -struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material *ma) -{ - const void *engine = &DRW_engine_viewport_eevee_type; - int options = VAR_MAT_VOLUME; - - GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true); - if (mat != NULL) { - return mat; - } - - char *defines = eevee_get_volume_defines(options); - - mat = DRW_shader_create_from_material(scene, - ma, - engine, - options, - true, - e_data.vert_volume_shader_str, - e_data.geom_volume_shader_str, - e_data.volume_shader_lib, - defines, - true); - - MEM_freeN(defines); - - return mat; -} - -struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene, - Material *ma, - bool use_hashed_alpha, - bool is_shadow) -{ - const void *engine = &DRW_engine_viewport_eevee_type; - int options = VAR_MAT_MESH; - - SET_FLAG_FROM_TEST(options, use_hashed_alpha, VAR_MAT_HASH); - SET_FLAG_FROM_TEST(options, !use_hashed_alpha, VAR_MAT_CLIP); - SET_FLAG_FROM_TEST(options, is_shadow, VAR_MAT_SHADOW); - - GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true); - if (mat) { - return mat; - } - - char *defines = eevee_get_defines(options); - - char *frag_str = BLI_string_joinN(e_data.frag_shader_lib, datatoc_prepass_frag_glsl); - - mat = DRW_shader_create_from_material(scene, - ma, - engine, - options, - false, - (is_shadow) ? e_data.vert_shadow_shader_str : - e_data.vert_shader_str, - NULL, - frag_str, - defines, - true); - - MEM_freeN(frag_str); - MEM_freeN(defines); - - return mat; -} - -static struct GPUMaterial *EEVEE_material_hair_depth_get(struct Scene *scene, - Material *ma, - bool use_hashed_alpha, - bool is_shadow) -{ - const void *engine = &DRW_engine_viewport_eevee_type; - int options = VAR_MAT_MESH | VAR_MAT_HAIR; - - SET_FLAG_FROM_TEST(options, use_hashed_alpha, VAR_MAT_HASH); - SET_FLAG_FROM_TEST(options, !use_hashed_alpha, VAR_MAT_CLIP); - SET_FLAG_FROM_TEST(options, is_shadow, VAR_MAT_SHADOW); - - GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true); - if (mat) { - return mat; - } - - char *defines = eevee_get_defines(options); - - char *frag_str = BLI_string_joinN(e_data.frag_shader_lib, datatoc_prepass_frag_glsl); - - mat = DRW_shader_create_from_material(scene, - ma, - engine, - options, - false, - (is_shadow) ? e_data.vert_shadow_shader_str : - e_data.vert_shader_str, - NULL, - frag_str, - defines, - false); - - MEM_freeN(frag_str); - MEM_freeN(defines); - - return mat; -} - -struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma) -{ - const void *engine = &DRW_engine_viewport_eevee_type; - int options = VAR_MAT_MESH | VAR_MAT_HAIR; - - GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true); - if (mat) { - return mat; - } - - char *defines = eevee_get_defines(options); - - mat = DRW_shader_create_from_material(scene, - ma, - engine, - options, - false, - e_data.vert_shader_str, - NULL, - e_data.frag_shader_lib, - defines, - true); - - MEM_freeN(defines); - - return mat; -} - -/** - * Create a default shading group inside the given pass. - */ -static struct DRWShadingGroup *EEVEE_default_shading_group_create(EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - DRWPass *pass, - bool is_hair, - bool use_blend, - bool use_ssr) -{ - static int ssr_id; - ssr_id = (use_ssr) ? 1 : -1; - int options = VAR_MAT_MESH; - - SET_FLAG_FROM_TEST(options, is_hair, VAR_MAT_HAIR); - SET_FLAG_FROM_TEST(options, use_blend, VAR_MAT_BLEND); - - if (e_data.default_lit[options] == NULL) { - create_default_shader(options); - } - - DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], pass); - add_standard_uniforms(shgrp, - sldata, - vedata, - &ssr_id, - NULL, - true, - true, - false, - false, - use_blend, - DEFAULT_RENDER_PASS_FLAG); - - return shgrp; -} - -/** - * Create a default shading group inside the default pass without standard uniforms. - */ -static struct DRWShadingGroup *EEVEE_default_shading_group_get(EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - Object *ob, - ParticleSystem *psys, - ModifierData *md, - bool is_hair, - bool holdout, - bool use_ssr) -{ - static int ssr_id; - ssr_id = (use_ssr) ? 1 : -1; - int options = VAR_MAT_MESH; - - EEVEE_PassList *psl = vedata->psl; - - BLI_assert(!is_hair || (ob && ((psys && md) || ob->type == OB_HAIR))); - - SET_FLAG_FROM_TEST(options, is_hair, VAR_MAT_HAIR); - SET_FLAG_FROM_TEST(options, holdout, VAR_MAT_HOLDOUT); - - if (e_data.default_lit[options] == NULL) { - create_default_shader(options); - } - - if (psl->default_pass[options] == NULL) { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES; - DRW_PASS_CREATE(psl->default_pass[options], state); - - /* XXX / WATCH: This creates non persistent binds for the ubos and textures. - * But it's currently OK because the following shgroups does not add any bind. - * EDIT: THIS IS NOT THE CASE FOR HAIRS !!! DUMMY!!! */ - if (!is_hair) { - DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], - psl->default_pass[options]); - add_standard_uniforms(shgrp, - sldata, - vedata, - &ssr_id, - NULL, - true, - true, - false, - false, - false, - DEFAULT_RENDER_PASS_FLAG); - } - } - - if (is_hair) { - DRWShadingGroup *shgrp = DRW_shgroup_hair_create( - ob, psys, md, vedata->psl->default_pass[options], e_data.default_lit[options]); - add_standard_uniforms(shgrp, - sldata, - vedata, - &ssr_id, - NULL, - true, - true, - false, - false, - false, - DEFAULT_RENDER_PASS_FLAG); - return shgrp; - } - else { - return DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]); - } -} - -static struct DRWShadingGroup *EEVEE_default_render_pass_shading_group_get( - EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - bool holdout, - bool use_ssr, - DRWPass *pass, - eViewLayerEEVEEPassType render_pass_flag) -{ - static int ssr_id; - ssr_id = (use_ssr) ? 1 : -1; - int options = VAR_MAT_MESH; - - SET_FLAG_FROM_TEST(options, holdout, VAR_MAT_HOLDOUT); - - if (e_data.default_lit[options] == NULL) { - create_default_shader(options); - } - - DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], pass); - add_standard_uniforms( - shgrp, sldata, vedata, &ssr_id, NULL, true, true, false, false, false, render_pass_flag); - return shgrp; -} - -static struct DRWShadingGroup *EEVEE_default_hair_render_pass_shading_group_get( - EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - Object *ob, - ParticleSystem *psys, - ModifierData *md, - bool holdout, - bool use_ssr, - DRWPass *pass, - eViewLayerEEVEEPassType render_pass_flag) -{ - static int ssr_id; - ssr_id = (use_ssr) ? 1 : -1; - int options = VAR_MAT_MESH | VAR_MAT_HAIR; - - BLI_assert((ob && psys && md)); - - SET_FLAG_FROM_TEST(options, holdout, VAR_MAT_HOLDOUT); - - if (e_data.default_lit[options] == NULL) { - create_default_shader(options); - } - - DRWShadingGroup *shgrp = DRW_shgroup_hair_create( - ob, psys, md, pass, e_data.default_lit[options]); - add_standard_uniforms( - shgrp, sldata, vedata, &ssr_id, NULL, true, true, false, false, false, render_pass_flag); - return shgrp; -} - void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; @@ -1180,10 +375,17 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) /* Create Material Ghash */ { stl->g_data->material_hash = BLI_ghash_ptr_new("Eevee_material ghash"); + + if (sldata->material_cache == NULL) { + sldata->material_cache = BLI_memblock_create(sizeof(EeveeMaterialCache)); + } + else { + BLI_memblock_clear(sldata->material_cache, NULL); + } } { - DRW_PASS_CREATE(psl->background_pass, DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL); + DRW_PASS_CREATE(psl->background_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL); struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); DRWShadingGroup *grp = NULL; @@ -1191,485 +393,297 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) Scene *scene = draw_ctx->scene; World *wo = scene->world; - const float *col = G_draw.block.colorBackground; - - EEVEE_lookdev_cache_init(vedata, sldata, &grp, psl->background_pass, wo, NULL); + EEVEE_lookdev_cache_init(vedata, sldata, &grp, psl->background_ps, wo, NULL); if (!grp && wo) { - col = &wo->horr; - - if (wo->use_nodes && wo->nodetree) { - static float error_col[3] = {1.0f, 0.0f, 1.0f}; - static float compile_col[3] = {0.5f, 0.5f, 0.5f}; - struct GPUMaterial *gpumat = EEVEE_material_world_background_get(scene, wo); - - switch (GPU_material_status(gpumat)) { - case GPU_MAT_SUCCESS: - grp = DRW_shgroup_material_create(gpumat, psl->background_pass); - add_background_uniforms(grp, sldata, vedata); - DRW_shgroup_call(grp, geom, NULL); - break; - case GPU_MAT_QUEUED: - /* TODO Bypass probe compilation. */ - stl->g_data->queued_shaders_count++; - col = compile_col; - break; - case GPU_MAT_FAILED: - default: - col = error_col; - break; - } - } + struct GPUMaterial *gpumat = EEVEE_material_get( + vedata, scene, NULL, wo, VAR_WORLD_BACKGROUND); + + grp = DRW_shgroup_material_create(gpumat, psl->background_ps); + DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1); + /* TODO (fclem): remove those (need to clean the GLSL files). */ + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); + DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); + DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); + DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); + DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); + DRW_shgroup_call(grp, geom, NULL); } /* Fallback if shader fails or if not using nodetree. */ if (grp == NULL) { - grp = DRW_shgroup_create(e_data.default_background, psl->background_pass); - DRW_shgroup_uniform_vec3(grp, "color", col, 1); + GPUShader *sh = EEVEE_shaders_default_background_sh_get(); + grp = DRW_shgroup_create(sh, psl->background_ps); + DRW_shgroup_uniform_vec3(grp, "color", G_draw.block.colorBackground, 1); DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1); DRW_shgroup_call(grp, geom, NULL); } } - { - DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; - DRW_PASS_CREATE(psl->depth_pass, state); - stl->g_data->depth_shgrp = DRW_shgroup_create(e_data.default_prepass_sh, psl->depth_pass); - - state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK; - DRW_PASS_CREATE(psl->depth_pass_cull, state); - stl->g_data->depth_shgrp_cull = DRW_shgroup_create(e_data.default_prepass_sh, - psl->depth_pass_cull); - - state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES; - DRW_PASS_CREATE(psl->depth_pass_clip, state); - stl->g_data->depth_shgrp_clip = DRW_shgroup_create(e_data.default_prepass_clip_sh, - psl->depth_pass_clip); - - state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES | - DRW_STATE_CULL_BACK; - DRW_PASS_CREATE(psl->depth_pass_clip_cull, state); - stl->g_data->depth_shgrp_clip_cull = DRW_shgroup_create(e_data.default_prepass_clip_sh, - psl->depth_pass_clip_cull); - } +#define EEVEE_PASS_CREATE(pass, state) \ + do { \ + DRW_PASS_CREATE(psl->pass##_ps, state); \ + DRW_PASS_CREATE(psl->pass##_cull_ps, state | DRW_STATE_CULL_BACK); \ + DRW_pass_link(psl->pass##_ps, psl->pass##_cull_ps); \ + } while (0) - { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES; - DRW_PASS_CREATE(psl->material_pass, state); - DRW_PASS_CREATE(psl->material_pass_cull, state | DRW_STATE_CULL_BACK); - } +#define EEVEE_CLIP_PASS_CREATE(pass, state) \ + do { \ + DRWState st = state | DRW_STATE_CLIP_PLANES; \ + DRW_PASS_INSTANCE_CREATE(psl->pass##_clip_ps, psl->pass##_ps, st); \ + DRW_PASS_INSTANCE_CREATE( \ + psl->pass##_clip_cull_ps, psl->pass##_cull_ps, st | DRW_STATE_CULL_BACK); \ + DRW_pass_link(psl->pass##_clip_ps, psl->pass##_clip_cull_ps); \ + } while (0) { - DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; - DRW_PASS_CREATE(psl->refract_depth_pass, state); - stl->g_data->refract_depth_shgrp = DRW_shgroup_create(e_data.default_prepass_sh, - psl->refract_depth_pass); - - state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK; - DRW_PASS_CREATE(psl->refract_depth_pass_cull, state); - stl->g_data->refract_depth_shgrp_cull = DRW_shgroup_create(e_data.default_prepass_sh, - psl->refract_depth_pass_cull); - - state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES; - DRW_PASS_CREATE(psl->refract_depth_pass_clip, state); - stl->g_data->refract_depth_shgrp_clip = DRW_shgroup_create(e_data.default_prepass_clip_sh, - psl->refract_depth_pass_clip); - - state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES | - DRW_STATE_CULL_BACK; - DRW_PASS_CREATE(psl->refract_depth_pass_clip_cull, state); - stl->g_data->refract_depth_shgrp_clip_cull = DRW_shgroup_create( - e_data.default_prepass_clip_sh, psl->refract_depth_pass_clip_cull); - } + DRWState state_depth = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; + DRWState state_shading = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES; + DRWState state_sss = DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS; - { - DRWState state = (DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES); - DRW_PASS_CREATE(psl->refract_pass, state); - } + EEVEE_PASS_CREATE(depth, state_depth); + EEVEE_CLIP_PASS_CREATE(depth, state_depth); - { - DRWState state = (DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES | - DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS); - DRW_PASS_CREATE(psl->sss_pass, state); - DRW_PASS_CREATE(psl->sss_pass_cull, state | DRW_STATE_CULL_BACK); - e_data.sss_count = 0; + EEVEE_PASS_CREATE(depth_refract, state_depth); + EEVEE_CLIP_PASS_CREATE(depth_refract, state_depth); + + EEVEE_PASS_CREATE(material, state_shading); + EEVEE_PASS_CREATE(material_refract, state_shading); + EEVEE_PASS_CREATE(material_sss, state_shading | state_sss); } + { + /* Renderpass accumulation. */ + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ADD_FULL; + /* Create an instance of each of theses passes and link them together. */ + DRWPass *passes[] = { + psl->material_ps, + psl->material_cull_ps, + psl->material_sss_ps, + psl->material_sss_cull_ps, + }; + DRWPass *first = NULL, *last = NULL; + for (int i = 0; i < ARRAY_SIZE(passes); i++) { + DRWPass *pass = DRW_pass_create_instance("Renderpass Accumulation", passes[i], state); + if (first == NULL) { + first = last = pass; + } + else { + DRW_pass_link(last, pass); + last = pass; + } + } + psl->material_accum_ps = first; + /* Same for background */ + DRW_PASS_INSTANCE_CREATE(psl->background_accum_ps, psl->background_ps, state); + } { DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES; DRW_PASS_CREATE(psl->transparent_pass, state); } - { DRW_PASS_CREATE(psl->update_noise_pass, DRW_STATE_WRITE_COLOR); - DRWShadingGroup *grp = DRW_shgroup_create(e_data.update_noise_sh, psl->update_noise_pass); + GPUShader *sh = EEVEE_shaders_update_noise_sh_get(); + DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->update_noise_pass); DRW_shgroup_uniform_texture(grp, "blueNoise", e_data.noise_tex); DRW_shgroup_uniform_vec3(grp, "offsets", e_data.noise_offsets, 1); DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } +} - if (eevee_hdri_preview_overlay_enabled(draw_ctx->v3d)) { - DRWShadingGroup *shgrp; - - struct GPUBatch *sphere = DRW_cache_sphere_get(); - static float color_chrome[3] = {1.0f, 1.0f, 1.0f}; - static float color_diffuse[3] = {0.8f, 0.8f, 0.8f}; - int options = VAR_MAT_MESH | VAR_MAT_LOOKDEV; +BLI_INLINE void material_shadow(EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata, + Material *ma, + bool is_hair, + EeveeMaterialCache *emc) +{ + EEVEE_PrivateData *pd = vedata->stl->g_data; + EEVEE_PassList *psl = vedata->psl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; - if (e_data.default_lit[options] == NULL) { - create_default_shader(options); + if (ma->blend_shadow != MA_BS_NONE) { + /* Shadow Pass */ + const bool use_shadow_shader = ma->use_nodes && ma->nodetree && + ELEM(ma->blend_shadow, MA_BS_CLIP, MA_BS_HASHED); + int mat_options = VAR_MAT_MESH | VAR_MAT_DEPTH; + SET_FLAG_FROM_TEST(mat_options, use_shadow_shader, VAR_MAT_HASH); + SET_FLAG_FROM_TEST(mat_options, is_hair, VAR_MAT_HAIR); + GPUMaterial *gpumat = (use_shadow_shader) ? + EEVEE_material_get(vedata, scene, ma, NULL, mat_options) : + EEVEE_material_default_get(scene, ma, mat_options); + + /* Avoid possible confusion with depth pre-pass options. */ + int option = KEY_SHADOW; + SET_FLAG_FROM_TEST(option, is_hair, KEY_HAIR); + + /* Search for the same shaders usage in the pass. */ + struct GPUShader *sh = GPU_material_get_shader(gpumat); + void *cache_key = (char *)sh + option; + DRWShadingGroup *grp, **grp_p; + + if (BLI_ghash_ensure_p(pd->material_hash, cache_key, (void ***)&grp_p)) { + /* This GPUShader has already been used by another material. + * Add new shading group just after to avoid shader switching cost. */ + grp = DRW_shgroup_create_sub(*grp_p); + } + else { + *grp_p = grp = DRW_shgroup_create(sh, psl->shadow_pass); + EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, false); } - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS | - DRW_STATE_CULL_BACK; - - DRW_PASS_CREATE(psl->lookdev_diffuse_pass, state); - shgrp = DRW_shgroup_create(e_data.default_lit[options], psl->lookdev_diffuse_pass); - add_standard_uniforms(shgrp, - sldata, - vedata, - NULL, - NULL, - true, - true, - false, - false, - false, - DEFAULT_RENDER_PASS_FLAG); - DRW_shgroup_uniform_vec3(shgrp, "basecol", color_diffuse, 1); - DRW_shgroup_uniform_float_copy(shgrp, "metallic", 0.0f); - DRW_shgroup_uniform_float_copy(shgrp, "specular", 0.5f); - DRW_shgroup_uniform_float_copy(shgrp, "roughness", 1.0f); - DRW_shgroup_call(shgrp, sphere, NULL); - - DRW_PASS_CREATE(psl->lookdev_glossy_pass, state); - shgrp = DRW_shgroup_create(e_data.default_lit[options], psl->lookdev_glossy_pass); - add_standard_uniforms(shgrp, - sldata, - vedata, - NULL, - NULL, - true, - true, - false, - false, - false, - DEFAULT_RENDER_PASS_FLAG); - DRW_shgroup_uniform_vec3(shgrp, "basecol", color_chrome, 1); - DRW_shgroup_uniform_float_copy(shgrp, "metallic", 1.0f); - DRW_shgroup_uniform_float_copy(shgrp, "roughness", 0.0f); - DRW_shgroup_call(shgrp, sphere, NULL); - } + DRW_shgroup_add_material_resources(grp, gpumat); - { - memset(psl->material_accum_pass, 0, sizeof(psl->material_accum_pass)); - for (int pass_index = 0; pass_index < stl->g_data->render_passes_material_count; - pass_index++) { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ADD_FULL; - DRW_PASS_CREATE(psl->material_accum_pass[pass_index], state); - } + emc->shadow_grp = grp; + emc->shadow_grp_p = grp_p; + } + else { + emc->shadow_grp = NULL; + emc->shadow_grp_p = NULL; } } -#define ADD_SHGROUP_CALL(shgrp, ob, geom, oedata) \ - do { \ - if (oedata) { \ - DRW_shgroup_call_with_callback(shgrp, geom, ob, oedata); \ - } \ - else { \ - DRW_shgroup_call(shgrp, geom, ob); \ - } \ - } while (0) - -#define ADD_SHGROUP_CALL_SAFE(shgrp, ob, geom, oedata) \ - do { \ - if (shgrp) { \ - ADD_SHGROUP_CALL(shgrp, ob, geom, oedata); \ - } \ - } while (0) - -typedef struct EeveeMaterialShadingGroups { - struct DRWShadingGroup *shading_grp; - struct DRWShadingGroup *depth_grp; - struct DRWShadingGroup *depth_clip_grp; - struct DRWShadingGroup *material_accum_grp[MAX_MATERIAL_RENDER_PASSES]; -} EeveeMaterialShadingGroups; - -static void material_opaque(Material *ma, - GHash *material_hash, - EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - struct GPUMaterial **gpumat, - struct GPUMaterial **gpumat_depth, - struct EeveeMaterialShadingGroups *shgrps, - bool holdout) +static EeveeMaterialCache material_opaque(EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata, + Material *ma, + const bool is_hair) { EEVEE_EffectsInfo *effects = vedata->stl->effects; + EEVEE_PrivateData *pd = vedata->stl->g_data; + EEVEE_PassList *psl = vedata->psl; const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; - EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; - EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; - bool use_diffuse, use_glossy, use_refract; - bool store_material = true; - float *color_p = &ma->r; - float *metal_p = &ma->metallic; - float *spec_p = &ma->spec; - float *rough_p = &ma->roughness; - const bool do_cull = (ma->blend_flag & MA_BL_CULL_BACKFACE) != 0; - const bool use_gpumat = (ma->use_nodes && ma->nodetree && !holdout); + const bool do_cull = !is_hair && (ma->blend_flag & MA_BL_CULL_BACKFACE) != 0; + const bool use_gpumat = (ma->use_nodes && ma->nodetree); const bool use_ssrefract = use_gpumat && ((ma->blend_flag & MA_BL_SS_REFRACTION) != 0) && ((effects->enabled_effects & EFFECT_REFRACT) != 0); - const bool use_translucency = ((ma->blend_flag & MA_BL_TRANSLUCENCY) != 0); + const bool use_depth_shader = use_gpumat && ELEM(ma->blend_method, MA_BM_CLIP, MA_BM_HASHED); - EeveeMaterialShadingGroups *emsg = BLI_ghash_lookup(material_hash, (const void *)ma); - - if (emsg) { - memcpy(shgrps, emsg, sizeof(EeveeMaterialShadingGroups)); - - /* This will have been created already, just perform a lookup. */ - *gpumat = (use_gpumat) ? EEVEE_material_mesh_get(scene, ma, vedata, false, use_ssrefract) : - NULL; - *gpumat_depth = (use_gpumat) ? EEVEE_material_mesh_depth_get( - scene, ma, (ma->blend_method == MA_BM_HASHED), false) : - NULL; - return; + /* HACK: Assume the struct will never be smaller than our variations. + * This allow us to only keep one ghash and avoid bigger keys comparissons/hashing. */ + void *key = (char *)ma + is_hair; + /* Search for other material instances (sharing the same Material datablock). */ + EeveeMaterialCache **emc_p, *emc; + if (BLI_ghash_ensure_p(pd->material_hash, key, (void ***)&emc_p)) { + return **emc_p; + } + else { + *emc_p = emc = BLI_memblock_alloc(sldata->material_cache); } - emsg = MEM_callocN(sizeof(EeveeMaterialShadingGroups), "EeveeMaterialShadingGroups"); - if (use_gpumat) { - static float error_col[3] = {1.0f, 0.0f, 1.0f}; - static float compile_col[3] = {0.5f, 0.5f, 0.5f}; - static float half = 0.5f; - - /* Shading */ - *gpumat = EEVEE_material_mesh_get(scene, ma, vedata, false, use_ssrefract); - - eGPUMaterialStatus status_mat_surface = GPU_material_status(*gpumat); - - /* Alpha CLipped : Discard pixel from depth pass, then - * fail the depth test for shading. */ - if (ELEM(ma->blend_method, MA_BM_CLIP, MA_BM_HASHED)) { - *gpumat_depth = EEVEE_material_mesh_depth_get( - scene, ma, (ma->blend_method == MA_BM_HASHED), false); + material_shadow(vedata, sldata, ma, is_hair, emc); - eGPUMaterialStatus status_mat_depth = GPU_material_status(*gpumat_depth); - if (status_mat_depth != GPU_MAT_SUCCESS) { - /* Mixing both flags. If depth shader fails, show it to the user by not using - * the surface shader. */ - status_mat_surface = status_mat_depth; - } - else if (use_ssrefract) { - emsg->depth_grp = DRW_shgroup_material_create( - *gpumat_depth, (do_cull) ? psl->refract_depth_pass_cull : psl->refract_depth_pass); - emsg->depth_clip_grp = DRW_shgroup_material_create( - *gpumat_depth, - (do_cull) ? psl->refract_depth_pass_clip_cull : psl->refract_depth_pass_clip); - } - else { - emsg->depth_grp = DRW_shgroup_material_create( - *gpumat_depth, (do_cull) ? psl->depth_pass_cull : psl->depth_pass); - emsg->depth_clip_grp = DRW_shgroup_material_create( - *gpumat_depth, (do_cull) ? psl->depth_pass_clip_cull : psl->depth_pass_clip); - } - - if (emsg->depth_grp != NULL) { - use_diffuse = GPU_material_flag_get(*gpumat_depth, GPU_MATFLAG_DIFFUSE); - use_glossy = GPU_material_flag_get(*gpumat_depth, GPU_MATFLAG_GLOSSY); - use_refract = GPU_material_flag_get(*gpumat_depth, GPU_MATFLAG_REFRACT); - - add_standard_uniforms(emsg->depth_grp, - sldata, - vedata, - NULL, - NULL, - use_diffuse, - use_glossy, - use_refract, - false, - false, - DEFAULT_RENDER_PASS_FLAG); - add_standard_uniforms(emsg->depth_clip_grp, - sldata, - vedata, - NULL, - NULL, - use_diffuse, - use_glossy, - use_refract, - false, - false, - DEFAULT_RENDER_PASS_FLAG); - - if (ma->blend_method == MA_BM_CLIP) { - DRW_shgroup_uniform_float(emsg->depth_grp, "alphaThreshold", &ma->alpha_threshold, 1); - DRW_shgroup_uniform_float( - emsg->depth_clip_grp, "alphaThreshold", &ma->alpha_threshold, 1); - } - } + { + /* Depth Pass */ + int mat_options = VAR_MAT_MESH | VAR_MAT_DEPTH; + SET_FLAG_FROM_TEST(mat_options, use_ssrefract, VAR_MAT_REFRACT); + SET_FLAG_FROM_TEST(mat_options, use_depth_shader, VAR_MAT_HASH); + SET_FLAG_FROM_TEST(mat_options, is_hair, VAR_MAT_HAIR); + GPUMaterial *gpumat = (use_depth_shader) ? + EEVEE_material_get(vedata, scene, ma, NULL, mat_options) : + EEVEE_material_default_get(scene, ma, mat_options); + + int option = 0; + SET_FLAG_FROM_TEST(option, do_cull, KEY_CULL); + SET_FLAG_FROM_TEST(option, use_ssrefract, KEY_REFRACT); + DRWPass *depth_ps = (DRWPass *[]){ + psl->depth_ps, + psl->depth_cull_ps, + psl->depth_refract_ps, + psl->depth_refract_cull_ps, + }[option]; + /* Hair are rendered inside the non-cull pass but needs to have a separate cache key. */ + SET_FLAG_FROM_TEST(option, is_hair, KEY_HAIR); + + /* Search for the same shaders usage in the pass. */ + struct GPUShader *sh = GPU_material_get_shader(gpumat); + void *cache_key = (char *)sh + option; + DRWShadingGroup *grp, **grp_p; + + if (BLI_ghash_ensure_p(pd->material_hash, cache_key, (void ***)&grp_p)) { + /* This GPUShader has already been used by another material. + * Add new shading group just after to avoid shader switching cost. */ + grp = DRW_shgroup_create_sub(*grp_p); } - - switch (status_mat_surface) { - case GPU_MAT_SUCCESS: { - static int no_ssr = 0; - static int first_ssr = 1; - int *ssr_id = (((effects->enabled_effects & EFFECT_SSR) != 0) && !use_ssrefract) ? - &first_ssr : - &no_ssr; - const bool use_sss = GPU_material_flag_get(*gpumat, GPU_MATFLAG_SSS); - use_diffuse = GPU_material_flag_get(*gpumat, GPU_MATFLAG_DIFFUSE); - use_glossy = GPU_material_flag_get(*gpumat, GPU_MATFLAG_GLOSSY); - use_refract = GPU_material_flag_get(*gpumat, GPU_MATFLAG_REFRACT); - - emsg->shading_grp = DRW_shgroup_material_create( - *gpumat, - (use_ssrefract) ? - psl->refract_pass : - (use_sss) ? ((do_cull) ? psl->sss_pass_cull : psl->sss_pass) : - ((do_cull) ? psl->material_pass_cull : psl->material_pass)); - - add_standard_uniforms(emsg->shading_grp, - sldata, - vedata, - ssr_id, - &ma->refract_depth, - use_diffuse, - use_glossy, - use_refract, - use_ssrefract, - false, - DEFAULT_RENDER_PASS_FLAG); - - if (use_sss) { - struct GPUTexture *sss_tex_profile = NULL; - struct GPUUniformBuffer *sss_profile = GPU_material_sss_profile_get( - *gpumat, stl->effects->sss_sample_count, &sss_tex_profile); - - if (sss_profile) { - /* Limit of 8 bit stencil buffer. ID 255 is refraction. */ - if (e_data.sss_count < 254) { - int sss_id = e_data.sss_count + 1; - DRW_shgroup_stencil_mask(emsg->shading_grp, sss_id); - EEVEE_subsurface_add_pass(sldata, vedata, sss_id, sss_profile); - if (use_translucency) { - EEVEE_subsurface_translucency_add_pass( - sldata, vedata, sss_id, sss_profile, sss_tex_profile); - } - e_data.sss_count++; - } - else { - /* TODO : display message. */ - printf("Error: Too many different Subsurface shader in the scene.\n"); - } - } - } - - RENDER_PASS_ITER_BEGIN (stl->g_data->render_passes, render_pass_index, render_pass_flag) { - emsg->material_accum_grp[render_pass_index] = DRW_shgroup_material_create( - *gpumat, psl->material_accum_pass[render_pass_index]); - add_standard_uniforms(emsg->material_accum_grp[render_pass_index], - sldata, - vedata, - ssr_id, - &ma->refract_depth, - use_diffuse, - use_glossy, - use_refract, - use_ssrefract, - false, - render_pass_flag); - } - RENDER_PASS_ITER_END(render_pass_index); - - break; - } - case GPU_MAT_QUEUED: { - stl->g_data->queued_shaders_count++; - color_p = compile_col; - metal_p = spec_p = rough_p = ½ - store_material = false; - break; - } - case GPU_MAT_FAILED: - default: - color_p = error_col; - metal_p = spec_p = rough_p = ½ - break; + else { + *grp_p = grp = DRW_shgroup_create(sh, depth_ps); + EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, false); } - } - /* Fallback to default shader */ - if (emsg->shading_grp == NULL) { - bool use_ssr = ((effects->enabled_effects & EFFECT_SSR) != 0); - emsg->shading_grp = EEVEE_default_shading_group_get( - sldata, vedata, NULL, NULL, NULL, false, holdout, use_ssr); - DRW_shgroup_uniform_vec3(emsg->shading_grp, "basecol", color_p, 1); - DRW_shgroup_uniform_float(emsg->shading_grp, "metallic", metal_p, 1); - DRW_shgroup_uniform_float(emsg->shading_grp, "specular", spec_p, 1); - DRW_shgroup_uniform_float(emsg->shading_grp, "roughness", rough_p, 1); - - RENDER_PASS_ITER_BEGIN (stl->g_data->render_passes, render_pass_index, render_pass_flag) { - DRWShadingGroup *shgrp = EEVEE_default_render_pass_shading_group_get( - sldata, - vedata, - holdout, - use_ssr, - psl->material_accum_pass[render_pass_index], - render_pass_flag); - - DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1); - DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1); - DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1); - DRW_shgroup_uniform_float(shgrp, "roughness", rough_p, 1); - emsg->material_accum_grp[render_pass_index] = shgrp; - } - RENDER_PASS_ITER_END(render_pass_index); - } + DRW_shgroup_add_material_resources(grp, gpumat); - /* Fallback default depth prepass */ - if (emsg->depth_grp == NULL) { - if (use_ssrefract) { - emsg->depth_grp = (do_cull) ? stl->g_data->refract_depth_shgrp_cull : - stl->g_data->refract_depth_shgrp; - emsg->depth_clip_grp = (do_cull) ? stl->g_data->refract_depth_shgrp_clip_cull : - stl->g_data->refract_depth_shgrp_clip; + emc->depth_grp = grp; + emc->depth_grp_p = grp_p; + } + { + /* Shading Pass */ + int mat_options = VAR_MAT_MESH; + SET_FLAG_FROM_TEST(mat_options, use_ssrefract, VAR_MAT_REFRACT); + SET_FLAG_FROM_TEST(mat_options, is_hair, VAR_MAT_HAIR); + GPUMaterial *gpumat = EEVEE_material_get(vedata, scene, ma, NULL, mat_options); + const bool use_sss = GPU_material_flag_get(gpumat, GPU_MATFLAG_SSS); + + int ssr_id = (((effects->enabled_effects & EFFECT_SSR) != 0) && !use_ssrefract) ? 1 : 0; + int option = (use_ssrefract ? 0 : (use_sss ? 1 : 2)) * 2 + do_cull; + DRWPass *shading_pass = (DRWPass *[]){ + psl->material_refract_ps, + psl->material_refract_cull_ps, + psl->material_sss_ps, + psl->material_sss_cull_ps, + psl->material_ps, + psl->material_cull_ps, + }[option]; + /* Hair are rendered inside the non-cull pass but needs to have a separate cache key */ + option = option * 2 + is_hair; + + /* Search for the same shaders usage in the pass. */ + /* HACK: Assume the struct will never be smaller than our variations. + * This allow us to only keep one ghash and avoid bigger keys comparissons/hashing. */ + BLI_assert(option <= 16); + struct GPUShader *sh = GPU_material_get_shader(gpumat); + void *cache_key = (char *)sh + option; + DRWShadingGroup *grp, **grp_p; + + if (BLI_ghash_ensure_p(pd->material_hash, cache_key, (void ***)&grp_p)) { + /* This GPUShader has already been used by another material. + * Add new shading group just after to avoid shader switching cost. */ + grp = DRW_shgroup_create_sub(*grp_p); } else { - emsg->depth_grp = (do_cull) ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp; - emsg->depth_clip_grp = (do_cull) ? stl->g_data->depth_shgrp_clip_cull : - stl->g_data->depth_shgrp_clip; + *grp_p = grp = DRW_shgroup_create(sh, shading_pass); + EEVEE_material_bind_resources( + grp, gpumat, sldata, vedata, &ssr_id, &ma->refract_depth, use_ssrefract, false); } - } + DRW_shgroup_add_material_resources(grp, gpumat); - memcpy(shgrps, emsg, sizeof(EeveeMaterialShadingGroups)); - if (store_material) { - BLI_ghash_insert(material_hash, ma, emsg); - } - else { - MEM_freeN(emsg); + if (use_sss) { + EEVEE_subsurface_add_pass(sldata, vedata, ma, grp, gpumat); + } + + emc->shading_grp = grp; + emc->shading_grp_p = grp_p; + emc->shading_gpumat = gpumat; } + return *emc; } -static void material_transparent(Material *ma, - EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - struct GPUMaterial **gpumat, - struct EeveeMaterialShadingGroups *shgrps) +static EeveeMaterialCache material_transparent(EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata, + Material *ma) { const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; - EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; - EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; + EEVEE_PassList *psl = vedata->psl; + EEVEE_EffectsInfo *effects = vedata->stl->effects; + EeveeMaterialCache emc = {0}; const bool do_cull = (ma->blend_flag & MA_BL_CULL_BACKFACE) != 0; const bool use_gpumat = ma->use_nodes && ma->nodetree; const bool use_ssrefract = use_gpumat && ((ma->blend_flag & MA_BL_SS_REFRACTION) != 0) && - ((stl->effects->enabled_effects & EFFECT_REFRACT) != 0); - const float *color_p = &ma->r; - const float *metal_p = &ma->metallic; - const float *spec_p = &ma->spec; - const float *rough_p = &ma->roughness; - + ((effects->enabled_effects & EFFECT_REFRACT) != 0); const bool use_prepass = ((ma->blend_flag & MA_BL_HIDE_BACKFACE) != 0); DRWState cur_state; @@ -1677,81 +691,53 @@ static void material_transparent(Material *ma, DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_CUSTOM); - /* Depth prepass */ + material_shadow(vedata, sldata, ma, false, &emc); + if (use_prepass) { - shgrps->depth_grp = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->transparent_pass); + /* Depth prepass */ + int mat_options = VAR_MAT_MESH | VAR_MAT_DEPTH; + GPUMaterial *gpumat = EEVEE_material_get(vedata, scene, ma, NULL, mat_options); + struct GPUShader *sh = GPU_material_get_shader(gpumat); + + DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->transparent_pass); + + EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, true); + DRW_shgroup_add_material_resources(grp, gpumat); cur_state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0; - DRW_shgroup_state_disable(shgrps->depth_grp, all_state); - DRW_shgroup_state_enable(shgrps->depth_grp, cur_state); + DRW_shgroup_state_disable(grp, all_state); + DRW_shgroup_state_enable(grp, cur_state); + + emc.depth_grp = grp; } + { + /* Shading */ + int ssr_id = -1; /* TODO transparent SSR */ + int mat_options = VAR_MAT_MESH | VAR_MAT_BLEND; + SET_FLAG_FROM_TEST(mat_options, use_ssrefract, VAR_MAT_REFRACT); + GPUMaterial *gpumat = EEVEE_material_get(vedata, scene, ma, NULL, mat_options); - if (use_gpumat) { - static float error_col[3] = {1.0f, 0.0f, 1.0f}; - static float compile_col[3] = {0.5f, 0.5f, 0.5f}; - static float half = 0.5f; + DRWShadingGroup *grp = DRW_shgroup_create(GPU_material_get_shader(gpumat), + psl->transparent_pass); - /* Shading */ - *gpumat = EEVEE_material_mesh_get(scene, ma, vedata, true, use_ssrefract); - - switch (GPU_material_status(*gpumat)) { - case GPU_MAT_SUCCESS: { - static int ssr_id = -1; /* TODO transparent SSR */ - - shgrps->shading_grp = DRW_shgroup_material_create(*gpumat, psl->transparent_pass); - - bool use_blend = true; - bool use_diffuse = GPU_material_flag_get(*gpumat, GPU_MATFLAG_DIFFUSE); - bool use_glossy = GPU_material_flag_get(*gpumat, GPU_MATFLAG_GLOSSY); - bool use_refract = GPU_material_flag_get(*gpumat, GPU_MATFLAG_REFRACT); - - add_standard_uniforms(shgrps->shading_grp, - sldata, - vedata, - &ssr_id, - &ma->refract_depth, - use_diffuse, - use_glossy, - use_refract, - use_ssrefract, - use_blend, - DEFAULT_RENDER_PASS_FLAG); - break; - } - case GPU_MAT_QUEUED: { - /* TODO Bypass probe compilation. */ - stl->g_data->queued_shaders_count++; - color_p = compile_col; - metal_p = spec_p = rough_p = ½ - break; - } - case GPU_MAT_FAILED: - default: - color_p = error_col; - metal_p = spec_p = rough_p = ½ - break; - } - } + EEVEE_material_bind_resources( + grp, gpumat, sldata, vedata, &ssr_id, &ma->refract_depth, use_ssrefract, true); + DRW_shgroup_add_material_resources(grp, gpumat); - /* Fallback to default shader */ - if (shgrps->shading_grp == NULL) { - shgrps->shading_grp = EEVEE_default_shading_group_create( - sldata, vedata, psl->transparent_pass, false, true, false); - DRW_shgroup_uniform_vec3(shgrps->shading_grp, "basecol", color_p, 1); - DRW_shgroup_uniform_float(shgrps->shading_grp, "metallic", metal_p, 1); - DRW_shgroup_uniform_float(shgrps->shading_grp, "specular", spec_p, 1); - DRW_shgroup_uniform_float(shgrps->shading_grp, "roughness", rough_p, 1); - } + 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; - 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(grp, all_state); + DRW_shgroup_state_enable(grp, cur_state); - /* Disable other blend modes and use the one we want. */ - DRW_shgroup_state_disable(shgrps->shading_grp, all_state); - DRW_shgroup_state_enable(shgrps->shading_grp, cur_state); + emc.shading_grp = grp; + emc.shading_gpumat = gpumat; + } + return emc; } /* Return correct material or empty default material if slot is empty. */ @@ -1766,12 +752,35 @@ BLI_INLINE Material *eevee_object_material_get(Object *ob, int slot, bool holdou ma = BKE_material_default_volume(); } else { - ma = BKE_material_default_empty(); + ma = BKE_material_default_surface(); } } return ma; } +BLI_INLINE EeveeMaterialCache eevee_material_cache_get( + EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob, int slot, bool is_hair) +{ + const bool holdout = (ob->base_flag & BASE_HOLDOUT) != 0; + EeveeMaterialCache matcache; + Material *ma = eevee_object_material_get(ob, slot, holdout); + switch (ma->blend_method) { + case MA_BM_BLEND: + if (!is_hair) { + matcache = material_transparent(vedata, sldata, ma); + break; + } + ATTR_FALLTHROUGH; + case MA_BM_SOLID: + case MA_BM_CLIP: + case MA_BM_HASHED: + default: + matcache = material_opaque(vedata, sldata, ma, is_hair); + break; + } + return matcache; +} + static void eevee_hair_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob, @@ -1780,240 +789,49 @@ static void eevee_hair_cache_populate(EEVEE_Data *vedata, int matnr, bool *cast_shadow) { - EEVEE_PassList *psl = vedata->psl; - EEVEE_StorageList *stl = vedata->stl; - const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; - const bool holdout = (ob->base_flag & BASE_HOLDOUT) != 0; - - DRWShadingGroup *shgrp = NULL; - Material *ma = eevee_object_material_get(ob, matnr - 1, holdout); - const bool use_gpumat = ma->use_nodes && ma->nodetree && !holdout; - const bool use_alpha_hash = (ma->blend_method == MA_BM_HASHED); - const bool use_alpha_clip = (ma->blend_method == MA_BM_CLIP); - const bool use_ssr = ((stl->effects->enabled_effects & EFFECT_SSR) != 0); + EeveeMaterialCache matcache = eevee_material_cache_get(vedata, sldata, ob, matnr - 1, true); - GPUMaterial *gpumat = use_gpumat ? EEVEE_material_hair_get(scene, ma) : NULL; - eGPUMaterialStatus status_mat_surface = gpumat ? GPU_material_status(gpumat) : GPU_MAT_SUCCESS; - - float *color_p = &ma->r; - float *metal_p = &ma->metallic; - float *spec_p = &ma->spec; - float *rough_p = &ma->roughness; - - /* Depth prepass. */ - if (use_gpumat && (use_alpha_clip || use_alpha_hash)) { - GPUMaterial *gpumat_depth = EEVEE_material_hair_depth_get(scene, ma, use_alpha_hash, false); - - eGPUMaterialStatus status_mat_depth = GPU_material_status(gpumat_depth); - - if (status_mat_depth != GPU_MAT_SUCCESS) { - /* Mixing both flags. If depth shader fails, show it to the user by not using - * the surface shader. */ - status_mat_surface = status_mat_depth; - } - else { - const bool use_diffuse = GPU_material_flag_get(gpumat_depth, GPU_MATFLAG_DIFFUSE); - const bool use_glossy = GPU_material_flag_get(gpumat_depth, GPU_MATFLAG_GLOSSY); - const bool use_refract = GPU_material_flag_get(gpumat_depth, GPU_MATFLAG_REFRACT); - - for (int i = 0; i < 2; i++) { - DRWPass *pass = (i == 0) ? psl->depth_pass : psl->depth_pass_clip; - - shgrp = DRW_shgroup_material_hair_create(ob, psys, md, pass, gpumat_depth); - - add_standard_uniforms(shgrp, - sldata, - vedata, - NULL, - NULL, - use_diffuse, - use_glossy, - use_refract, - false, - false, - DEFAULT_RENDER_PASS_FLAG); - - /* Unfortunately needed for correctness but not 99% of the time not needed. - * TODO detect when needed? */ - DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo); - DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo); - DRW_shgroup_uniform_block(shgrp, "planar_block", sldata->planar_ubo); - DRW_shgroup_uniform_block(shgrp, "light_block", sldata->light_ubo); - DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo); - DRW_shgroup_uniform_block( - shgrp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); - DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex); - - if (use_alpha_clip) { - DRW_shgroup_uniform_float(shgrp, "alphaThreshold", &ma->alpha_threshold, 1); - } - } - } + if (matcache.depth_grp) { + *matcache.depth_grp_p = DRW_shgroup_hair_create_sub(ob, psys, md, matcache.depth_grp); } - - /* Fallback to default shader */ - if (shgrp == NULL) { - for (int i = 0; i < 2; i++) { - DRWPass *depth_pass = (i == 0) ? psl->depth_pass : psl->depth_pass_clip; - struct GPUShader *depth_sh = (i == 0) ? e_data.default_hair_prepass_sh : - e_data.default_hair_prepass_clip_sh; - DRW_shgroup_hair_create(ob, psys, md, depth_pass, depth_sh); - } + if (matcache.shading_grp) { + *matcache.shading_grp_p = DRW_shgroup_hair_create_sub(ob, psys, md, matcache.shading_grp); } - - shgrp = NULL; - - if (gpumat) { - static int ssr_id; - ssr_id = (use_ssr) ? 1 : -1; - static float half = 0.5f; - static float error_col[3] = {1.0f, 0.0f, 1.0f}; - static float compile_col[3] = {0.5f, 0.5f, 0.5f}; - - switch (status_mat_surface) { - case GPU_MAT_SUCCESS: { - bool use_diffuse = GPU_material_flag_get(gpumat, GPU_MATFLAG_DIFFUSE); - bool use_glossy = GPU_material_flag_get(gpumat, GPU_MATFLAG_GLOSSY); - bool use_refract = GPU_material_flag_get(gpumat, GPU_MATFLAG_REFRACT); - - shgrp = DRW_shgroup_material_hair_create(ob, psys, md, psl->material_pass, gpumat); - - if (!use_diffuse && !use_glossy && !use_refract) { - /* HACK: Small hack to avoid issue when utilTex is needed for - * world_normals_get and none of the bsdfs are present. - * This binds utilTex even if not needed. */ - DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex); - } - - add_standard_uniforms(shgrp, - sldata, - vedata, - &ssr_id, - NULL, - use_diffuse, - use_glossy, - use_refract, - false, - false, - DEFAULT_RENDER_PASS_FLAG); - - /* Add the hair to all the render_passes that are enabled */ - RENDER_PASS_ITER_BEGIN (stl->g_data->render_passes, render_pass_index, render_pass_flag) { - shgrp = DRW_shgroup_material_hair_create( - ob, psys, md, psl->material_accum_pass[render_pass_index], gpumat); - if (!use_diffuse && !use_glossy && !use_refract) { - /* Small hack to avoid issue when utilTex is needed for - * world_normals_get and none of the bsdfs that need it are present. - * This binds `utilTex` even if not needed. */ - DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex); - } - - add_standard_uniforms(shgrp, - sldata, - vedata, - &ssr_id, - NULL, - use_diffuse, - use_glossy, - use_refract, - false, - false, - render_pass_flag); - } - RENDER_PASS_ITER_END(render_pass_index); - - break; - } - case GPU_MAT_QUEUED: { - stl->g_data->queued_shaders_count++; - color_p = compile_col; - metal_p = spec_p = rough_p = ½ - break; - } - case GPU_MAT_FAILED: - default: - color_p = error_col; - metal_p = spec_p = rough_p = ½ - break; - } + if (matcache.shadow_grp) { + *matcache.shadow_grp_p = DRW_shgroup_hair_create_sub(ob, psys, md, matcache.shadow_grp); + *cast_shadow = true; } +} - /* Fallback to default shader */ - if (shgrp == NULL) { - shgrp = EEVEE_default_shading_group_get(sldata, vedata, ob, psys, md, true, holdout, use_ssr); - DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1); - DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1); - DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1); - DRW_shgroup_uniform_float(shgrp, "roughness", rough_p, 1); - - RENDER_PASS_ITER_BEGIN (stl->g_data->render_passes, render_pass_index, render_pass_flag) { - shgrp = EEVEE_default_hair_render_pass_shading_group_get( - sldata, - vedata, - ob, - psys, - md, - holdout, - use_ssr, - psl->material_accum_pass[render_pass_index], - render_pass_flag); - - DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1); - DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1); - DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1); - DRW_shgroup_uniform_float(shgrp, "roughness", rough_p, 1); - } - RENDER_PASS_ITER_END(render_pass_index); - } +#define ADD_SHGROUP_CALL(shgrp, ob, geom, oedata) \ + do { \ + if (oedata) { \ + DRW_shgroup_call_with_callback(shgrp, geom, ob, oedata); \ + } \ + else { \ + DRW_shgroup_call(shgrp, geom, ob); \ + } \ + } while (0) - /* Shadows */ - char blend_shadow = use_gpumat ? ma->blend_shadow : MA_BS_SOLID; - const bool shadow_alpha_hash = (blend_shadow == MA_BS_HASHED); - switch (blend_shadow) { - case MA_BS_SOLID: - DRW_shgroup_hair_create(ob, psys, md, psl->shadow_pass, e_data.default_hair_prepass_sh); - *cast_shadow = true; - break; - case MA_BS_CLIP: - case MA_BS_HASHED: - gpumat = EEVEE_material_hair_depth_get(scene, ma, shadow_alpha_hash, true); - shgrp = DRW_shgroup_material_hair_create(ob, psys, md, psl->shadow_pass, gpumat); - /* Unfortunately needed for correctness but not 99% of the time not needed. - * TODO detect when needed? */ - DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo); - DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo); - DRW_shgroup_uniform_block(shgrp, "planar_block", sldata->planar_ubo); - DRW_shgroup_uniform_block(shgrp, "light_block", sldata->light_ubo); - DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo); - DRW_shgroup_uniform_block( - shgrp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); - DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex); - - if (!shadow_alpha_hash) { - DRW_shgroup_uniform_float(shgrp, "alphaThreshold", &ma->alpha_threshold, 1); - } - *cast_shadow = true; - break; - case MA_BS_NONE: - default: - break; +#define ADD_SHGROUP_CALL_SAFE(shgrp, ob, geom, oedata) \ + do { \ + if (shgrp) { \ + ADD_SHGROUP_CALL(shgrp, ob, geom, oedata); \ + } \ + } while (0) + +#define MATCACHE_AS_ARRAY(matcache, member, materials_len, output_array) \ + for (int i = 0; i < materials_len; i++) { \ + output_array[i] = matcache[i].member; \ } -} void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob, bool *cast_shadow) { - EEVEE_PassList *psl = vedata->psl; - EEVEE_StorageList *stl = vedata->stl; const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; - GHash *material_hash = stl->g_data->material_hash; - const bool holdout = (ob->base_flag & BASE_HOLDOUT) != 0; bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && !DRW_state_is_image_render(); @@ -2022,139 +840,64 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) { const int materials_len = DRW_cache_object_material_count_get(ob); - struct EeveeMaterialShadingGroups *shgrps_array = BLI_array_alloca(shgrps_array, - materials_len); - - struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); - struct GPUMaterial **gpumat_depth_array = BLI_array_alloca(gpumat_array, materials_len); - struct Material **ma_array = BLI_array_alloca(ma_array, materials_len); - + EeveeMaterialCache *matcache = BLI_array_alloca(matcache, materials_len); for (int i = 0; i < materials_len; i++) { - ma_array[i] = eevee_object_material_get(ob, i, holdout); - memset(&shgrps_array[i], 0, sizeof(EeveeMaterialShadingGroups)); - gpumat_array[i] = NULL; - gpumat_depth_array[i] = NULL; - - switch (ma_array[i]->blend_method) { - case MA_BM_SOLID: - case MA_BM_CLIP: - case MA_BM_HASHED: - material_opaque(ma_array[i], - material_hash, - sldata, - vedata, - &gpumat_array[i], - &gpumat_depth_array[i], - &shgrps_array[i], - holdout); - break; - case MA_BM_BLEND: - material_transparent(ma_array[i], sldata, vedata, &gpumat_array[i], &shgrps_array[i]); - break; - default: - BLI_assert(0); - break; - } + matcache[i] = eevee_material_cache_get(vedata, sldata, ob, i, false); } /* Only support single volume material for now. */ /* XXX We rely on the previously compiled surface shader * to know if the material has a "volume nodetree". */ - bool use_volume_material = (gpumat_array[0] && - GPU_material_has_volume_output(gpumat_array[0])); + bool use_volume_material = (matcache[0].shading_gpumat && + GPU_material_has_volume_output(matcache[0].shading_gpumat)); if ((ob->dt >= OB_SOLID) || DRW_state_is_image_render()) { - /* Get per-material split surface */ - struct GPUBatch **mat_geom = NULL; - - if (!use_sculpt_pbvh) { - mat_geom = DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len); - } - if (use_sculpt_pbvh) { - struct DRWShadingGroup **sculpt_shgrps_array = BLI_array_alloca(sculpt_shgrps_array, - materials_len); - for (int i = 0; i < materials_len; i++) { - sculpt_shgrps_array[i] = shgrps_array[i].shading_grp; - } - DRW_shgroup_call_sculpt_with_materials(sculpt_shgrps_array, materials_len, ob); + struct DRWShadingGroup **shgrps_array = BLI_array_alloca(shgrps_array, materials_len); - for (int i = 0; i < materials_len; i++) { - sculpt_shgrps_array[i] = shgrps_array[i].depth_grp; - } - DRW_shgroup_call_sculpt_with_materials(sculpt_shgrps_array, materials_len, ob); - for (int i = 0; i < materials_len; i++) { - sculpt_shgrps_array[i] = shgrps_array[i].depth_clip_grp; - } - DRW_shgroup_call_sculpt_with_materials(sculpt_shgrps_array, materials_len, ob); + MATCACHE_AS_ARRAY(matcache, shading_grp, materials_len, shgrps_array); + DRW_shgroup_call_sculpt_with_materials(shgrps_array, materials_len, ob); - for (int renderpass_index = 0; - renderpass_index < stl->g_data->render_passes_material_count; - renderpass_index++) { - for (int i = 0; i < materials_len; i++) { - sculpt_shgrps_array[i] = shgrps_array[i].material_accum_grp[renderpass_index]; - } - DRW_shgroup_call_sculpt_with_materials(sculpt_shgrps_array, materials_len, ob); - } + MATCACHE_AS_ARRAY(matcache, depth_grp, materials_len, shgrps_array); + DRW_shgroup_call_sculpt_with_materials(shgrps_array, materials_len, ob); - /* TODO(fclem): Support shadows in sculpt mode. */ + MATCACHE_AS_ARRAY(matcache, shadow_grp, materials_len, shgrps_array); + DRW_shgroup_call_sculpt_with_materials(shgrps_array, materials_len, ob); } - else if (mat_geom) { - for (int i = 0; i < materials_len; i++) { - if (mat_geom[i] == NULL) { - continue; - } + else { + struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); + MATCACHE_AS_ARRAY(matcache, shading_gpumat, materials_len, gpumat_array); + /* Get per-material split surface */ + struct GPUBatch **mat_geom = DRW_cache_object_surface_material_get( + ob, gpumat_array, materials_len); - /* Do not render surface if we are rendering a volume object - * and do not have a surface closure. */ - if (use_volume_material && - (gpumat_array[i] && !GPU_material_has_surface_output(gpumat_array[i]))) { - continue; - } + if (mat_geom) { + for (int i = 0; i < materials_len; i++) { + if (mat_geom[i] == NULL) { + continue; + } - /* XXX TODO rewrite this to include the dupli objects. - * This means we cannot exclude dupli objects from reflections!!! */ - EEVEE_ObjectEngineData *oedata = NULL; - if ((ob->base_flag & BASE_FROM_DUPLI) == 0) { - oedata = EEVEE_object_data_ensure(ob); - oedata->ob = ob; - oedata->test_data = &sldata->probes->vis_data; - } - EeveeMaterialShadingGroups *shgrps = &shgrps_array[i]; - ADD_SHGROUP_CALL(shgrps->shading_grp, ob, mat_geom[i], oedata); - ADD_SHGROUP_CALL_SAFE(shgrps->depth_grp, ob, mat_geom[i], oedata); - ADD_SHGROUP_CALL_SAFE(shgrps->depth_clip_grp, ob, mat_geom[i], oedata); - for (int renderpass_index = 0; - renderpass_index < stl->g_data->render_passes_material_count; - renderpass_index++) { - ADD_SHGROUP_CALL_SAFE( - shgrps->material_accum_grp[renderpass_index], ob, mat_geom[i], oedata); - } + /* Do not render surface if we are rendering a volume object + * and do not have a surface closure. */ + if (use_volume_material && + (gpumat_array[i] && !GPU_material_has_surface_output(gpumat_array[i]))) { + continue; + } + + /* XXX TODO rewrite this to include the dupli objects. + * This means we cannot exclude dupli objects from reflections!!! */ + EEVEE_ObjectEngineData *oedata = NULL; + if ((ob->base_flag & BASE_FROM_DUPLI) == 0) { + oedata = EEVEE_object_data_ensure(ob); + oedata->ob = ob; + oedata->test_data = &sldata->probes->vis_data; + } - /* Shadow Pass */ - struct GPUMaterial *gpumat; - const bool use_gpumat = (ma_array[i]->use_nodes && ma_array[i]->nodetree); - char blend_shadow = use_gpumat ? ma_array[i]->blend_shadow : MA_BS_SOLID; - switch (blend_shadow) { - case MA_BS_SOLID: - EEVEE_shadows_caster_add(sldata, stl, mat_geom[i], ob); - *cast_shadow = true; - break; - case MA_BS_CLIP: - gpumat = EEVEE_material_mesh_depth_get(scene, ma_array[i], false, true); - EEVEE_shadows_caster_material_add( - sldata, psl, gpumat, mat_geom[i], ob, &ma_array[i]->alpha_threshold); - *cast_shadow = true; - break; - case MA_BS_HASHED: - gpumat = EEVEE_material_mesh_depth_get(scene, ma_array[i], true, true); - EEVEE_shadows_caster_material_add(sldata, psl, gpumat, mat_geom[i], ob, NULL); - *cast_shadow = true; - break; - case MA_BS_NONE: - default: - break; + ADD_SHGROUP_CALL(matcache[i].shading_grp, ob, mat_geom[i], oedata); + ADD_SHGROUP_CALL_SAFE(matcache[i].depth_grp, ob, mat_geom[i], oedata); + ADD_SHGROUP_CALL_SAFE(matcache[i].shadow_grp, ob, mat_geom[i], oedata); + *cast_shadow = (matcache[i].shadow_grp != NULL); } } } @@ -2205,11 +948,12 @@ void EEVEE_object_hair_cache_populate(EEVEE_Data *vedata, void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { - EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; + EEVEE_PrivateData *pd = vedata->stl->g_data; + EEVEE_EffectsInfo *effects = vedata->stl->effects; - BLI_ghash_free(stl->g_data->material_hash, NULL, MEM_freeN); + BLI_ghash_free(pd->material_hash, NULL, NULL); - SET_FLAG_FROM_TEST(stl->effects->enabled_effects, e_data.sss_count > 0, EFFECT_SSS); + SET_FLAG_FROM_TEST(effects->enabled_effects, effects->sss_surface_count > 0, EFFECT_SSS); /* TODO(fclem) this is not really clean. Init should not be done in cache finish. */ EEVEE_subsurface_draw_init(sldata, vedata); @@ -2217,38 +961,10 @@ void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat void EEVEE_materials_free(void) { - for (int i = 0; i < VAR_MAT_MAX; i++) { - DRW_SHADER_FREE_SAFE(e_data.default_lit[i]); - } - 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); - DRW_SHADER_FREE_SAFE(e_data.default_prepass_sh); - DRW_SHADER_FREE_SAFE(e_data.default_prepass_clip_sh); - DRW_SHADER_FREE_SAFE(e_data.default_background); - DRW_SHADER_FREE_SAFE(e_data.update_noise_sh); DRW_TEXTURE_FREE_SAFE(e_data.util_tex); DRW_TEXTURE_FREE_SAFE(e_data.noise_tex); } -void EEVEE_materials_draw_opaque(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_PassList *psl) -{ - for (int i = 0; i < VAR_MAT_MAX; i++) { - if (psl->default_pass[i]) { - DRW_draw_pass(psl->default_pass[i]); - } - } - - DRW_draw_pass(psl->material_pass); - DRW_draw_pass(psl->material_pass_cull); -} - /* -------------------------------------------------------------------- */ /** \name Render Passes @@ -2256,172 +972,140 @@ void EEVEE_materials_draw_opaque(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Pass void EEVEE_material_renderpasses_init(EEVEE_Data *vedata) { - EEVEE_StorageList *stl = vedata->stl; - EEVEE_PrivateData *g_data = stl->g_data; + EEVEE_PrivateData *pd = vedata->stl->g_data; /* For diffuse and glossy we calculate the final light + color buffer where we extract the * light from by dividing by the color buffer. When one the light is requested we also tag * the color buffer to do the extraction. */ - if (g_data->render_passes & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) { - g_data->render_passes |= EEVEE_RENDER_PASS_DIFFUSE_COLOR; + if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) { + pd->render_passes |= EEVEE_RENDER_PASS_DIFFUSE_COLOR; } - if (g_data->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) { - g_data->render_passes |= EEVEE_RENDER_PASS_SPECULAR_COLOR; + if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) { + pd->render_passes |= EEVEE_RENDER_PASS_SPECULAR_COLOR; } +} - /* Calculate the number of material based render passes */ - uint num_render_passes = count_bits_i(stl->g_data->render_passes & EEVEE_RENDERPASSES_MATERIAL); - if ((num_render_passes != 0 && stl->g_data->render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) == - 0) { - num_render_passes += 1; +static void material_renderpass_init(EEVEE_FramebufferList *fbl, + GPUTexture **output_tx, + const eGPUTextureFormat format, + const bool do_clear) +{ + DRW_texture_ensure_fullscreen_2d(output_tx, format, 0); + /* Clear texture. */ + if (do_clear) { + float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + /* TODO(fclem) replace by GPU_texture_clear once it is fast. */ + GPU_framebuffer_texture_attach(fbl->material_accum_fb, *output_tx, 0, 0); + GPU_framebuffer_bind(fbl->material_accum_fb); + GPU_framebuffer_clear_color(fbl->material_accum_fb, clear); + GPU_framebuffer_bind(fbl->main_fb); + GPU_framebuffer_texture_detach(fbl->material_accum_fb, *output_tx); } - stl->g_data->render_passes_material_count = num_render_passes; } void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples) { - const DRWContextState *draw_ctx = DRW_context_state_get(); EEVEE_FramebufferList *fbl = vedata->fbl; DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); EEVEE_TextureList *txl = vedata->txl; EEVEE_StorageList *stl = vedata->stl; - EEVEE_PassList *psl = vedata->psl; EEVEE_EffectsInfo *effects = stl->effects; + EEVEE_PrivateData *pd = stl->g_data; - float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + /* Should be enough precision for many samples. */ + const eGPUTextureFormat texture_format = (tot_samples > 128) ? GPU_RGBA32F : GPU_RGBA16F; + const bool do_clear = DRW_state_is_image_render() || (effects->taa_current_sample == 1); /* Create FrameBuffer. */ + GPU_framebuffer_ensure_config(&fbl->material_accum_fb, + {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_LEAVE}); - /* Should be enough precision for many samples. */ - const eGPUTextureFormat texture_format_material_accum = (tot_samples > 128) ? GPU_RGBA32F : - GPU_RGBA16F; - const eViewLayerEEVEEPassType render_passes = stl->g_data->render_passes & - EEVEE_RENDERPASSES_MATERIAL; - if (render_passes != 0) { - GPU_framebuffer_ensure_config(&fbl->material_accum_fb, - {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_LEAVE}); - int render_pass_index = ((render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) != 0) ? 0 : 1; - for (int bit = 0; bit < 32; bit++) { - eViewLayerEEVEEPassType bitflag = (1 << bit); - if ((render_passes & bitflag) != 0) { - - DRW_texture_ensure_fullscreen_2d( - &txl->material_accum[render_pass_index], texture_format_material_accum, 0); - - /* Clear texture. */ - if (DRW_state_is_image_render() || effects->taa_current_sample == 1) { - GPU_framebuffer_texture_attach( - fbl->material_accum_fb, txl->material_accum[render_pass_index], 0, 0); - GPU_framebuffer_bind(fbl->material_accum_fb); - GPU_framebuffer_clear_color(fbl->material_accum_fb, clear); - GPU_framebuffer_bind(fbl->main_fb); - GPU_framebuffer_texture_detach(fbl->material_accum_fb, - txl->material_accum[render_pass_index]); - } - render_pass_index++; - } - } + if (pd->render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) { + material_renderpass_init(fbl, &txl->env_accum, texture_format, do_clear); + } + if (pd->render_passes & EEVEE_RENDER_PASS_EMIT) { + material_renderpass_init(fbl, &txl->emit_accum, texture_format, do_clear); + } + if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_COLOR) { + material_renderpass_init(fbl, &txl->diff_color_accum, texture_format, do_clear); + } + if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) { + material_renderpass_init(fbl, &txl->diff_light_accum, texture_format, do_clear); + } + if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_COLOR) { + material_renderpass_init(fbl, &txl->spec_color_accum, texture_format, do_clear); + } + if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) { + material_renderpass_init(fbl, &txl->spec_light_accum, texture_format, do_clear); - if ((render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) && - (effects->enabled_effects & EFFECT_SSR)) { + if (effects->enabled_effects & EFFECT_SSR) { EEVEE_reflection_output_init(sldata, vedata, tot_samples); } + } +} - if (render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) { - Scene *scene = draw_ctx->scene; - World *wo = scene->world; +static void material_renderpass_accumulate(EEVEE_FramebufferList *fbl, + DRWPass *renderpass, + EEVEE_PrivateData *pd, + GPUTexture *output_tx, + struct GPUUniformBuffer *renderpass_option_ubo) +{ + GPU_framebuffer_texture_attach(fbl->material_accum_fb, output_tx, 0, 0); + GPU_framebuffer_bind(fbl->material_accum_fb); - if (wo && wo->use_nodes && wo->nodetree) { - struct GPUMaterial *gpumat = EEVEE_material_world_background_get(scene, wo); - if (GPU_material_status(gpumat) == GPU_MAT_SUCCESS) { - DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, psl->material_accum_pass[0]); - add_background_uniforms(grp, sldata, vedata); - DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); - } - } - } - } + pd->renderpass_ubo = renderpass_option_ubo; + DRW_draw_pass(renderpass); + + GPU_framebuffer_texture_detach(fbl->material_accum_fb, output_tx); } void EEVEE_material_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_PassList *psl = vedata->psl; - EEVEE_StorageList *stl = vedata->stl; + EEVEE_PrivateData *pd = vedata->stl->g_data; + EEVEE_EffectsInfo *effects = vedata->stl->effects; EEVEE_TextureList *txl = vedata->txl; if (fbl->material_accum_fb != NULL) { - for (int renderpass_index = 0; renderpass_index < stl->g_data->render_passes_material_count; - renderpass_index++) { - if (txl->material_accum[renderpass_index] != NULL) { - GPU_framebuffer_texture_attach( - fbl->material_accum_fb, txl->material_accum[renderpass_index], 0, 0); - GPU_framebuffer_bind(fbl->material_accum_fb); - DRW_draw_pass(psl->material_accum_pass[renderpass_index]); - GPU_framebuffer_bind(fbl->main_fb); - GPU_framebuffer_texture_detach(fbl->material_accum_fb, - txl->material_accum[renderpass_index]); - } + DRWPass *material_accum_ps = psl->material_accum_ps; + if (pd->render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) { + material_renderpass_accumulate( + fbl, psl->background_accum_ps, pd, txl->env_accum, sldata->renderpass_ubo.combined); } - if ((stl->g_data->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) && - (stl->effects->enabled_effects & EFFECT_SSR)) { - EEVEE_reflection_output_accumulate(sldata, vedata); + if (pd->render_passes & EEVEE_RENDER_PASS_EMIT) { + material_renderpass_accumulate( + fbl, material_accum_ps, pd, txl->emit_accum, sldata->renderpass_ubo.emit); } - } -} - -int EEVEE_material_output_pass_index_get(EEVEE_ViewLayerData *UNUSED(sldata), - EEVEE_Data *vedata, - eViewLayerEEVEEPassType renderpass_type) -{ - EEVEE_StorageList *stl = vedata->stl; - - BLI_assert((stl->g_data->render_passes & EEVEE_RENDERPASSES_MATERIAL) != 0); - BLI_assert((stl->g_data->render_passes & EEVEE_RENDERPASSES_MATERIAL & renderpass_type) != 0); - - /* pass_index 0 is reserved for the environment pass. */ - if ((stl->g_data->render_passes & EEVEE_RENDER_PASS_ENVIRONMENT & renderpass_type) != 0) { - return 0; - } - - /* pass_index 0 is reserved for the environment pass. Other passes start from index 1 */ - int index = 1; - eViewLayerEEVEEPassType active_material_passes = stl->g_data->render_passes & - EEVEE_RENDERPASSES_MATERIAL & - ~EEVEE_RENDER_PASS_ENVIRONMENT; + if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_COLOR) { + material_renderpass_accumulate( + fbl, material_accum_ps, pd, txl->diff_color_accum, sldata->renderpass_ubo.diff_color); + } + if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) { + material_renderpass_accumulate( + fbl, material_accum_ps, pd, txl->diff_light_accum, sldata->renderpass_ubo.diff_light); - for (int bitshift = 0; bitshift < 32; bitshift++) { - eViewLayerEEVEEPassType pass_flag = (1 << bitshift); - if (pass_flag == renderpass_type) { - break; + if (effects->enabled_effects & EFFECT_SSS) { + EEVEE_subsurface_output_accumulate(sldata, vedata); + } } - if (active_material_passes & pass_flag) { - index++; + if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_COLOR) { + material_renderpass_accumulate( + fbl, material_accum_ps, pd, txl->spec_color_accum, sldata->renderpass_ubo.spec_color); } - } + if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) { + material_renderpass_accumulate( + fbl, material_accum_ps, pd, txl->spec_light_accum, sldata->renderpass_ubo.spec_light); - return index; -} + if (effects->enabled_effects & EFFECT_SSR) { + EEVEE_reflection_output_accumulate(sldata, vedata); + } + } -/* Get the pass index that contains the color pass for the given renderpass_type. */ -int EEVEE_material_output_color_pass_index_get(EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - eViewLayerEEVEEPassType renderpass_type) -{ - BLI_assert( - ELEM(renderpass_type, EEVEE_RENDER_PASS_DIFFUSE_LIGHT, EEVEE_RENDER_PASS_SPECULAR_LIGHT)); - eViewLayerEEVEEPassType color_pass_type; - switch (renderpass_type) { - case EEVEE_RENDER_PASS_DIFFUSE_LIGHT: - color_pass_type = EEVEE_RENDER_PASS_DIFFUSE_COLOR; - break; - case EEVEE_RENDER_PASS_SPECULAR_LIGHT: - color_pass_type = EEVEE_RENDER_PASS_SPECULAR_COLOR; - break; - default: - color_pass_type = 0; - BLI_assert(false); + /* Restore default. */ + pd->renderpass_ubo = sldata->renderpass_ubo.combined; + GPU_framebuffer_bind(fbl->main_fb); } - return EEVEE_material_output_pass_index_get(sldata, vedata, color_pass_type); } + /* \} */ diff --git a/source/blender/draw/engines/eevee/eevee_mist.c b/source/blender/draw/engines/eevee/eevee_mist.c index cdcfd64d995..7b942784ee9 100644 --- a/source/blender/draw/engines/eevee/eevee_mist.c +++ b/source/blender/draw/engines/eevee/eevee_mist.c @@ -114,8 +114,7 @@ void EEVEE_mist_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRWShadingGroup *grp = DRW_shgroup_create(e_data.mist_sh, psl->mist_accum_ps); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_uniform_vec3(grp, "mistSettings", &g_data->mist_start, 1); DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c index be4dfd07ce1..f5ebbe08dd1 100644 --- a/source/blender/draw/engines/eevee/eevee_occlusion.c +++ b/source/blender/draw/engines/eevee/eevee_occlusion.c @@ -170,8 +170,7 @@ void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input); DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } else { @@ -209,8 +208,7 @@ void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &effects->ao_src_depth); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_call(grp, quad, NULL); DRW_PASS_CREATE(psl->ao_horizon_search_layer, DRW_STATE_WRITE_COLOR); @@ -219,8 +217,7 @@ void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer); DRW_shgroup_uniform_texture_ref(grp, "depthBufferLayered", &effects->ao_src_depth); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_uniform_int(grp, "layer", &stl->effects->ao_depth_layer, 1); DRW_shgroup_call(grp, quad, NULL); @@ -233,8 +230,7 @@ void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input); DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_call(grp, quad, NULL); } } diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 264f301e52c..dbe2adef789 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -158,35 +158,34 @@ BLI_INLINE bool eevee_hdri_preview_overlay_enabled(const View3D *v3d) (EEVEE_RENDER_PASS_EMIT | EEVEE_RENDER_PASS_DIFFUSE_COLOR | EEVEE_RENDER_PASS_DIFFUSE_LIGHT | \ EEVEE_RENDER_PASS_SPECULAR_COLOR | EEVEE_RENDER_PASS_SPECULAR_LIGHT | \ EEVEE_RENDER_PASS_ENVIRONMENT) -#define MAX_MATERIAL_RENDER_PASSES 6 -#define MAX_MATERIAL_RENDER_PASSES_UBO 6 -/* World shader variations */ -enum { - VAR_WORLD_BACKGROUND = 0, - VAR_WORLD_PROBE = 1, - VAR_WORLD_VOLUME = 2, -}; /* Material shader variations */ enum { VAR_MAT_MESH = (1 << 0), - VAR_MAT_PROBE = (1 << 1), + VAR_MAT_VOLUME = (1 << 1), VAR_MAT_HAIR = (1 << 2), - VAR_MAT_BLEND = (1 << 3), - VAR_MAT_VOLUME = (1 << 4), + VAR_MAT_PROBE = (1 << 3), + VAR_MAT_BLEND = (1 << 4), VAR_MAT_LOOKDEV = (1 << 5), VAR_MAT_HOLDOUT = (1 << 6), - /* Max number of variation */ - /* IMPORTANT : Leave it last and set - * it's value accordingly. */ - VAR_MAT_MAX = (1 << 7), - /* These are options that are not counted in VAR_MAT_MAX - * because they are not cumulative with the others above. */ - VAR_MAT_CLIP = (1 << 9), - VAR_MAT_HASH = (1 << 10), - VAR_MAT_MULT = (1 << 11), - VAR_MAT_SHADOW = (1 << 12), - VAR_MAT_REFRACT = (1 << 13), + VAR_MAT_HASH = (1 << 7), + VAR_MAT_DEPTH = (1 << 8), + VAR_MAT_REFRACT = (1 << 9), + VAR_WORLD_BACKGROUND = (1 << 10), + VAR_WORLD_PROBE = (1 << 11), + VAR_WORLD_VOLUME = (1 << 12), + VAR_DEFAULT = (1 << 13), +}; + +/* Material shader cache keys */ +enum { + /* HACK: This assumes the struct GPUShader will never be smaller than our variations. + * This allow us to only keep one ghash and avoid bigger keys comparissons/hashing. + * We combine the GPUShader pointer with the key. */ + KEY_CULL = (1 << 0), + KEY_REFRACT = (1 << 1), + KEY_HAIR = (1 << 2), + KEY_SHADOW = (1 << 3), }; /* ************ PROBE UBO ************* */ @@ -272,23 +271,26 @@ typedef struct EEVEE_PassList { struct DRWPass *maxz_copydepth_ps; struct DRWPass *maxz_copydepth_layer_ps; - struct DRWPass *depth_pass; - struct DRWPass *depth_pass_cull; - struct DRWPass *depth_pass_clip; - struct DRWPass *depth_pass_clip_cull; - struct DRWPass *refract_depth_pass; - struct DRWPass *refract_depth_pass_cull; - struct DRWPass *refract_depth_pass_clip; - struct DRWPass *refract_depth_pass_clip_cull; - struct DRWPass *default_pass[VAR_MAT_MAX]; - struct DRWPass *sss_pass; - struct DRWPass *sss_pass_cull; - struct DRWPass *material_pass; - struct DRWPass *material_pass_cull; - struct DRWPass *material_accum_pass[MAX_MATERIAL_RENDER_PASSES]; - struct DRWPass *refract_pass; + /* Renderpass Accumulation. */ + struct DRWPass *material_accum_ps; + struct DRWPass *background_accum_ps; + + struct DRWPass *depth_ps; + struct DRWPass *depth_cull_ps; + struct DRWPass *depth_clip_ps; + struct DRWPass *depth_clip_cull_ps; + struct DRWPass *depth_refract_ps; + struct DRWPass *depth_refract_cull_ps; + struct DRWPass *depth_refract_clip_ps; + struct DRWPass *depth_refract_clip_cull_ps; + struct DRWPass *material_ps; + struct DRWPass *material_cull_ps; + struct DRWPass *material_refract_ps; + struct DRWPass *material_refract_cull_ps; + struct DRWPass *material_sss_ps; + struct DRWPass *material_sss_cull_ps; struct DRWPass *transparent_pass; - struct DRWPass *background_pass; + struct DRWPass *background_ps; struct DRWPass *update_noise_pass; struct DRWPass *lookdev_glossy_pass; struct DRWPass *lookdev_diffuse_pass; @@ -348,7 +350,12 @@ typedef struct EEVEE_TextureList { struct GPUTexture *mist_accum; struct GPUTexture *ao_accum; struct GPUTexture *sss_accum; - struct GPUTexture *material_accum[MAX_MATERIAL_RENDER_PASSES]; + struct GPUTexture *env_accum; + struct GPUTexture *diff_color_accum; + struct GPUTexture *diff_light_accum; + struct GPUTexture *spec_color_accum; + struct GPUTexture *spec_light_accum; + struct GPUTexture *emit_accum; struct GPUTexture *bloom_accum; struct GPUTexture *ssr_accum; struct GPUTexture *shadow_accum; @@ -574,6 +581,7 @@ typedef struct EEVEE_EffectsInfo { bool swap_double_buffer; /* SSSS */ int sss_sample_count; + int sss_surface_count; struct GPUTexture *sss_irradiance; /* Textures from pool */ struct GPUTexture *sss_radius; struct GPUTexture *sss_albedo; @@ -754,14 +762,22 @@ typedef struct EEVEE_ViewLayerData { struct GPUUniformBuffer *planar_ubo; /* Material Render passes */ - struct EEVEE_RenderPassData renderpass_data[MAX_MATERIAL_RENDER_PASSES_UBO]; - struct GPUUniformBuffer *renderpass_ubo[MAX_MATERIAL_RENDER_PASSES_UBO]; + struct { + struct GPUUniformBuffer *combined; + struct GPUUniformBuffer *diff_color; + struct GPUUniformBuffer *diff_light; + struct GPUUniformBuffer *spec_color; + struct GPUUniformBuffer *spec_light; + struct GPUUniformBuffer *emit; + } renderpass_ubo; /* Common Uniform Buffer */ struct EEVEE_CommonUniformBuffer common_data; struct GPUUniformBuffer *common_ubo; struct LightCache *fallback_lightcache; + + struct BLI_memblock *material_cache; } EEVEE_ViewLayerData; /* ************ OBJECT DATA ************ */ @@ -809,14 +825,6 @@ typedef struct EEVEE_Data { typedef struct EEVEE_PrivateData { struct DRWShadingGroup *shadow_shgrp; struct DRWShadingGroup *shadow_accum_shgrp; - struct DRWShadingGroup *depth_shgrp; - struct DRWShadingGroup *depth_shgrp_cull; - struct DRWShadingGroup *depth_shgrp_clip; - struct DRWShadingGroup *depth_shgrp_clip_cull; - struct DRWShadingGroup *refract_depth_shgrp; - struct DRWShadingGroup *refract_depth_shgrp_cull; - struct DRWShadingGroup *refract_depth_shgrp_clip; - struct DRWShadingGroup *refract_depth_shgrp_clip_cull; struct DRWCallBuffer *planar_display_shgrp; struct GHash *material_hash; float background_alpha; /* TODO find a better place for this. */ @@ -862,9 +870,8 @@ typedef struct EEVEE_PrivateData { GPUTexture *renderpass_input; GPUTexture *renderpass_col_input; GPUTexture *renderpass_light_input; - /* The number of active material based render passes */ - uint render_passes_material_count; - + /* Renderpass ubo reference used by material pass. */ + struct GPUUniformBuffer *renderpass_ubo; /** For rendering shadows. */ struct DRWView *cube_views[6]; /** For rendering probes. */ @@ -892,6 +899,7 @@ EEVEE_WorldEngineData *EEVEE_world_data_ensure(World *wo); /* eevee_materials.c */ struct GPUTexture *EEVEE_materials_get_util_tex(void); /* XXX */ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata, EEVEE_StorageList *stl, EEVEE_FramebufferList *fbl); void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); @@ -908,31 +916,20 @@ void EEVEE_object_hair_cache_populate(EEVEE_Data *vedata, Object *ob, bool *cast_shadow); void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); -struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, struct World *wo); -struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, struct World *wo); -struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, struct World *wo); -struct GPUMaterial *EEVEE_material_mesh_get( - struct Scene *scene, Material *ma, EEVEE_Data *vedata, bool use_blend, bool use_refract); -struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material *ma); -struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene, - Material *ma, - bool use_hashed_alpha, - bool is_shadow); -struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma); -struct GPUUniformBuffer *EEVEE_material_default_render_pass_ubo_get(EEVEE_ViewLayerData *sldata); void EEVEE_materials_free(void); -void EEVEE_materials_draw_opaque(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl); void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, const double offsets[3]); void EEVEE_update_viewvecs(float invproj[4][4], float winmat[4][4], float (*r_viewvecs)[4]); void EEVEE_material_renderpasses_init(EEVEE_Data *vedata); void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples); void EEVEE_material_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); -int EEVEE_material_output_pass_index_get(EEVEE_ViewLayerData *UNUSED(sldata), - EEVEE_Data *vedata, - eViewLayerEEVEEPassType renderpass_type); -int EEVEE_material_output_color_pass_index_get(EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - eViewLayerEEVEEPassType renderpass_type); +void EEVEE_material_bind_resources(DRWShadingGroup *shgrp, + struct GPUMaterial *gpumat, + EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata, + int *ssr_id, + float *refract_depth, + bool use_ssrefraction, + bool use_alpha_blend); /* eevee_lights.c */ void eevee_light_matrix_get(const EEVEE_Light *evli, float r_mat[4][4]); void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); @@ -943,16 +940,6 @@ void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void eevee_contact_shadow_setup(const Light *la, EEVEE_Shadow *evsh); void EEVEE_shadows_init(EEVEE_ViewLayerData *sldata); void EEVEE_shadows_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); -void EEVEE_shadows_caster_add(EEVEE_ViewLayerData *sldata, - EEVEE_StorageList *stl, - struct GPUBatch *geom, - Object *ob); -void EEVEE_shadows_caster_material_add(EEVEE_ViewLayerData *sldata, - EEVEE_PassList *psl, - struct GPUMaterial *gpumat, - struct GPUBatch *geom, - struct Object *ob, - const float *alpha_threshold); void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, struct Object *ob); void EEVEE_shadows_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_shadows_cube_add(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, struct Object *ob); @@ -986,6 +973,7 @@ void EEVEE_random_rotation_m4(int sample_ofs, float scale, float r_mat[4][4]); /* eevee_shaders.c */ void EEVEE_shaders_lightprobe_shaders_init(void); +void EEVEE_shaders_material_shaders_init(void); struct GPUShader *EEVEE_shaders_probe_filter_glossy_sh_get(void); struct GPUShader *EEVEE_shaders_probe_default_sh_get(void); struct GPUShader *EEVEE_shaders_probe_filter_diffuse_sh_get(void); @@ -993,12 +981,22 @@ struct GPUShader *EEVEE_shaders_probe_filter_visibility_sh_get(void); struct GPUShader *EEVEE_shaders_probe_grid_fill_sh_get(void); struct GPUShader *EEVEE_shaders_probe_planar_downsample_sh_get(void); struct GPUShader *EEVEE_shaders_default_studiolight_sh_get(void); +struct GPUShader *EEVEE_shaders_default_background_sh_get(void); struct GPUShader *EEVEE_shaders_background_studiolight_sh_get(void); struct GPUShader *EEVEE_shaders_probe_cube_display_sh_get(void); struct GPUShader *EEVEE_shaders_probe_grid_display_sh_get(void); struct GPUShader *EEVEE_shaders_probe_planar_display_sh_get(void); +struct GPUShader *EEVEE_shaders_update_noise_sh_get(void); struct GPUShader *EEVEE_shaders_velocity_resolve_sh_get(void); struct GPUShader *EEVEE_shaders_taa_resolve_sh_get(EEVEE_EffectsFlag enabled_effects); +struct bNodeTree *EEVEE_shader_default_surface_nodetree(Material *ma); +struct bNodeTree *EEVEE_shader_default_world_nodetree(World *wo); +Material *EEVEE_material_default_diffuse_get(void); +Material *EEVEE_material_default_glossy_get(void); +Material *EEVEE_material_default_error_get(void); +struct GPUMaterial *EEVEE_material_default_get(struct Scene *scene, Material *ma, int options); +struct GPUMaterial *EEVEE_material_get( + EEVEE_Data *vedata, struct Scene *scene, Material *ma, World *wo, int options); void EEVEE_shaders_free(void); /* eevee_lightprobes.c */ @@ -1105,13 +1103,9 @@ void EEVEE_subsurface_output_init(EEVEE_ViewLayerData *sldata, uint tot_samples); void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, - uint sss_id, - struct GPUUniformBuffer *sss_profile); -void EEVEE_subsurface_translucency_add_pass(EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - uint sss_id, - struct GPUUniformBuffer *sss_profile, - struct GPUTexture *sss_tex_profile); + Material *ma, + DRWShadingGroup *shgrp, + struct GPUMaterial *gpumat); void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_subsurface_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_subsurface_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c index 076738dcbdf..89a5ad2198a 100644 --- a/source/blender/draw/engines/eevee/eevee_render.c +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -151,7 +151,7 @@ bool EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph * * `EEVEE_effects_init` needs to go second for TAA. */ EEVEE_renderpasses_init(vedata); EEVEE_effects_init(sldata, vedata, ob_camera_eval, false); - EEVEE_materials_init(sldata, stl, fbl); + EEVEE_materials_init(sldata, vedata, stl, fbl); EEVEE_shadows_init(sldata); EEVEE_lightprobes_init(sldata, vedata); @@ -463,7 +463,7 @@ static void eevee_render_draw_background(EEVEE_Data *vedata) GPU_ATTACHMENT_NONE}); GPU_framebuffer_bind(fbl->main_fb); - DRW_draw_pass(psl->background_pass); + DRW_draw_pass(psl->background_ps); GPU_framebuffer_ensure_config(&fbl->main_fb, {GPU_ATTACHMENT_LEAVE, @@ -556,7 +556,7 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl EEVEE_update_noise(psl, fbl, r); EEVEE_temporal_sampling_matrices_calc(stl->effects, r); EEVEE_volumes_set_jitter(sldata, stl->effects->taa_current_sample - 1); - EEVEE_materials_init(sldata, stl, fbl); + EEVEE_materials_init(sldata, vedata, stl, fbl); /* Refresh Probes * Shadows needs to be updated for correct probes */ @@ -578,8 +578,7 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl GPU_framebuffer_bind(fbl->main_fb); GPU_framebuffer_clear_color_depth_stencil(fbl->main_fb, clear_col, clear_depth, clear_stencil); /* Depth prepass */ - DRW_draw_pass(psl->depth_pass); - DRW_draw_pass(psl->depth_pass_cull); + DRW_draw_pass(psl->depth_ps); /* Create minmax texture */ EEVEE_create_minmax_buffer(vedata, dtxl->depth, -1); EEVEE_occlusion_compute(sldata, vedata, dtxl->depth, -1); @@ -587,16 +586,15 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl /* Shading pass */ eevee_render_draw_background(vedata); GPU_framebuffer_bind(fbl->main_fb); - EEVEE_materials_draw_opaque(sldata, psl); + DRW_draw_pass(psl->material_ps); EEVEE_subsurface_data_render(sldata, vedata); /* Effects pre-transparency */ EEVEE_subsurface_compute(sldata, vedata); EEVEE_reflection_compute(sldata, vedata); EEVEE_refraction_compute(sldata, vedata); /* Opaque refraction */ - DRW_draw_pass(psl->refract_depth_pass); - DRW_draw_pass(psl->refract_depth_pass_cull); - DRW_draw_pass(psl->refract_pass); + DRW_draw_pass(psl->depth_refract_ps); + DRW_draw_pass(psl->material_refract_ps); /* Result NORMAL */ eevee_render_result_normal(rl, viewname, rect, vedata, sldata); /* Volumetrics Resolve Opaque */ diff --git a/source/blender/draw/engines/eevee/eevee_renderpasses.c b/source/blender/draw/engines/eevee/eevee_renderpasses.c index 9112e14dcf5..4a1880caf7d 100644 --- a/source/blender/draw/engines/eevee/eevee_renderpasses.c +++ b/source/blender/draw/engines/eevee/eevee_renderpasses.c @@ -201,8 +201,7 @@ void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata, grp, "inputSecondLightBuffer", &g_data->renderpass_light_input); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_uniform_int(grp, "currentSample", &g_data->renderpass_current_sample, 1); DRW_shgroup_uniform_int(grp, "renderpassType", &g_data->renderpass_type, 1); DRW_shgroup_uniform_int(grp, "postProcessType", &g_data->renderpass_postprocess, 1); @@ -225,7 +224,7 @@ void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata, * Only invoke this function for passes that need post-processing. * * After invoking this function the active framebuffer is set to `vedata->fbl->renderpass_fb`. */ -void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *sldata, +void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata, eViewLayerEEVEEPassType renderpass_type) { @@ -276,22 +275,30 @@ void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *sldata, g_data->renderpass_input = txl->shadow_accum; break; } - case EEVEE_RENDER_PASS_DIFFUSE_COLOR: - case EEVEE_RENDER_PASS_SPECULAR_COLOR: - case EEVEE_RENDER_PASS_ENVIRONMENT: + case EEVEE_RENDER_PASS_DIFFUSE_COLOR: { + g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR; + g_data->renderpass_input = txl->diff_color_accum; + break; + } + case EEVEE_RENDER_PASS_SPECULAR_COLOR: { + g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR; + g_data->renderpass_input = txl->spec_color_accum; + break; + } + case EEVEE_RENDER_PASS_ENVIRONMENT: { + g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR; + g_data->renderpass_input = txl->env_accum; + break; + } case EEVEE_RENDER_PASS_EMIT: { g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR; - int renderpass_index = EEVEE_material_output_pass_index_get(sldata, vedata, renderpass_type); - g_data->renderpass_input = txl->material_accum[renderpass_index]; + g_data->renderpass_input = txl->emit_accum; break; } case EEVEE_RENDER_PASS_SPECULAR_LIGHT: { g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_LIGHT; - int renderpass_index = EEVEE_material_output_pass_index_get(sldata, vedata, renderpass_type); - int renderpass_index_color = EEVEE_material_output_color_pass_index_get( - sldata, vedata, renderpass_type); - g_data->renderpass_input = txl->material_accum[renderpass_index]; - g_data->renderpass_col_input = txl->material_accum[renderpass_index_color]; + g_data->renderpass_input = txl->spec_light_accum; + g_data->renderpass_col_input = txl->spec_color_accum; if ((stl->effects->enabled_effects & EFFECT_SSR) != 0) { g_data->renderpass_postprocess = PASS_POST_TWO_LIGHT_BUFFERS; g_data->renderpass_light_input = txl->ssr_accum; @@ -303,11 +310,8 @@ void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *sldata, } case EEVEE_RENDER_PASS_DIFFUSE_LIGHT: { g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_LIGHT; - int renderpass_index = EEVEE_material_output_pass_index_get(sldata, vedata, renderpass_type); - int renderpass_index_color = EEVEE_material_output_color_pass_index_get( - sldata, vedata, renderpass_type); - g_data->renderpass_input = txl->material_accum[renderpass_index]; - g_data->renderpass_col_input = txl->material_accum[renderpass_index_color]; + g_data->renderpass_input = txl->diff_light_accum; + g_data->renderpass_col_input = txl->diff_color_accum; if ((stl->effects->enabled_effects & EFFECT_SSS) != 0) { g_data->renderpass_postprocess = PASS_POST_TWO_LIGHT_BUFFERS; g_data->renderpass_light_input = txl->sss_accum; @@ -343,10 +347,6 @@ void EEVEE_renderpasses_output_accumulate(EEVEE_ViewLayerData *sldata, if ((render_pass & EEVEE_RENDER_PASS_MIST) != 0) { EEVEE_mist_output_accumulate(sldata, vedata); } - if ((render_pass & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) != 0 && - (effects->enabled_effects & EFFECT_SSS) != 0) { - EEVEE_subsurface_output_accumulate(sldata, vedata); - } if ((render_pass & EEVEE_RENDER_PASS_AO) != 0) { EEVEE_occlusion_output_accumulate(sldata, vedata); } diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c index 2e467fe8535..cece67334c5 100644 --- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c +++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c @@ -237,8 +237,7 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); if (!effects->reflection_trace_full) { DRW_shgroup_uniform_ivec2(grp, "halfresOffset", effects->ssr_halfres_ofs, 1); } @@ -259,8 +258,7 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_uniform_int(grp, "neighborOffset", &effects->ssr_neighbor_ofs, 1); if ((effects->enabled_effects & EFFECT_GTAO) != 0) { DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c index 50b7c5c5f97..4d25f62a317 100644 --- a/source/blender/draw/engines/eevee/eevee_shaders.c +++ b/source/blender/draw/engines/eevee/eevee_shaders.c @@ -22,12 +22,20 @@ #include "DRW_render.h" +#include "BKE_lib_id.h" +#include "BKE_node.h" + +#include "BLI_dynstr.h" #include "BLI_string_utils.h" #include "MEM_guardedalloc.h" +#include "GPU_material.h" #include "GPU_shader.h" +#include "NOD_shader.h" + +#include "eevee_engine.h" #include "eevee_private.h" static const char *filter_defines = "#define HAMMERSLEY_SIZE " STRINGIFY(HAMMERSLEY_SIZE) "\n" @@ -61,6 +69,38 @@ static struct { struct GPUShader *taa_resolve_sh; struct GPUShader *taa_resolve_reproject_sh; + /* General purpose Shaders. */ + struct GPUShader *default_background; + struct GPUShader *update_noise_sh; + + /* Shader strings */ + 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; + + /* LookDev Materials */ + Material *glossy_mat; + Material *diffuse_mat; + + Material *error_mat; + + /* Default Material */ + struct { + bNodeTree *ntree; + bNodeSocketValueRGBA *color_socket; + bNodeSocketValueFloat *metallic_socket; + bNodeSocketValueFloat *roughness_socket; + bNodeSocketValueFloat *specular_socket; + } surface; + + struct { + bNodeTree *ntree; + bNodeSocketValueRGBA *color_socket; + } world; } e_data = {NULL}; /* Engine data */ extern char datatoc_bsdf_common_lib_glsl[]; @@ -68,27 +108,42 @@ extern char datatoc_bsdf_sampling_lib_glsl[]; extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_common_view_lib_glsl[]; +extern char datatoc_ambient_occlusion_lib_glsl[]; extern char datatoc_background_vert_glsl[]; +extern char datatoc_common_hair_lib_glsl[]; +extern char datatoc_cubemap_lib_glsl[]; extern char datatoc_default_world_frag_glsl[]; -extern char datatoc_lightprobe_geom_glsl[]; -extern char datatoc_lightprobe_vert_glsl[]; +extern char datatoc_irradiance_lib_glsl[]; extern char datatoc_lightprobe_cube_display_frag_glsl[]; extern char datatoc_lightprobe_cube_display_vert_glsl[]; extern char datatoc_lightprobe_filter_diffuse_frag_glsl[]; extern char datatoc_lightprobe_filter_glossy_frag_glsl[]; extern char datatoc_lightprobe_filter_visibility_frag_glsl[]; +extern char datatoc_lightprobe_geom_glsl[]; extern char datatoc_lightprobe_grid_display_frag_glsl[]; extern char datatoc_lightprobe_grid_display_vert_glsl[]; extern char datatoc_lightprobe_grid_fill_frag_glsl[]; +extern char datatoc_lightprobe_lib_glsl[]; extern char datatoc_lightprobe_planar_display_frag_glsl[]; extern char datatoc_lightprobe_planar_display_vert_glsl[]; extern char datatoc_lightprobe_planar_downsample_frag_glsl[]; extern char datatoc_lightprobe_planar_downsample_geom_glsl[]; extern char datatoc_lightprobe_planar_downsample_vert_glsl[]; -extern char datatoc_irradiance_lib_glsl[]; -extern char datatoc_lightprobe_lib_glsl[]; +extern char datatoc_lightprobe_vert_glsl[]; +extern char datatoc_lights_lib_glsl[]; +extern char datatoc_lit_surface_frag_glsl[]; +extern char datatoc_lit_surface_vert_glsl[]; +extern char datatoc_ltc_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; -extern char datatoc_cubemap_lib_glsl[]; +extern char datatoc_prepass_frag_glsl[]; +extern char datatoc_raytrace_lib_glsl[]; +extern char datatoc_shadow_vert_glsl[]; +extern char datatoc_ssr_lib_glsl[]; +extern char datatoc_update_noise_frag_glsl[]; +extern char datatoc_volumetric_frag_glsl[]; +extern char datatoc_volumetric_geom_glsl[]; +extern char datatoc_volumetric_lib_glsl[]; +extern char datatoc_volumetric_vert_glsl[]; /* Velocity Resolve */ extern char datatoc_effect_velocity_resolve_frag_glsl[]; @@ -150,6 +205,64 @@ void EEVEE_shaders_lightprobe_shaders_init(void) NULL); } +void EEVEE_shaders_material_shaders_init(void) +{ + e_data.frag_shader_lib = BLI_string_joinN(datatoc_common_view_lib_glsl, + datatoc_common_uniforms_lib_glsl, + datatoc_bsdf_common_lib_glsl, + datatoc_bsdf_sampling_lib_glsl, + datatoc_ambient_occlusion_lib_glsl, + datatoc_raytrace_lib_glsl, + datatoc_ssr_lib_glsl, + datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, + datatoc_irradiance_lib_glsl, + datatoc_lightprobe_lib_glsl, + datatoc_ltc_lib_glsl, + datatoc_lights_lib_glsl, + /* Add one for each Closure */ + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_volumetric_lib_glsl); + + e_data.volume_shader_lib = BLI_string_joinN(datatoc_common_view_lib_glsl, + datatoc_common_uniforms_lib_glsl, + datatoc_bsdf_common_lib_glsl, + datatoc_ambient_occlusion_lib_glsl, + datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, + datatoc_irradiance_lib_glsl, + datatoc_lightprobe_lib_glsl, + datatoc_ltc_lib_glsl, + datatoc_lights_lib_glsl, + datatoc_volumetric_lib_glsl, + datatoc_volumetric_frag_glsl); + + e_data.vert_shader_str = BLI_string_joinN( + datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_lit_surface_vert_glsl); + + 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); +} + GPUShader *EEVEE_shaders_probe_filter_glossy_sh_get(void) { return e_data.probe_filter_glossy_sh; @@ -292,6 +405,26 @@ GPUShader *EEVEE_shaders_velocity_resolve_sh_get(void) return e_data.velocity_resolve_sh; } +GPUShader *EEVEE_shaders_default_background_sh_get(void) +{ + if (e_data.default_background == NULL) { + e_data.default_background = DRW_shader_create_with_lib(datatoc_background_vert_glsl, + NULL, + datatoc_default_world_frag_glsl, + datatoc_common_view_lib_glsl, + NULL); + } + return e_data.default_background; +} + +GPUShader *EEVEE_shaders_update_noise_sh_get(void) +{ + if (e_data.update_noise_sh == NULL) { + e_data.update_noise_sh = DRW_shader_create_fullscreen(datatoc_update_noise_frag_glsl, NULL); + } + return e_data.update_noise_sh; +} + GPUShader *EEVEE_shaders_taa_resolve_sh_get(EEVEE_EffectsFlag enabled_effects) { GPUShader **sh; @@ -316,8 +449,330 @@ GPUShader *EEVEE_shaders_taa_resolve_sh_get(EEVEE_EffectsFlag enabled_effects) return *sh; } +Material *EEVEE_material_default_diffuse_get(void) +{ + if (!e_data.diffuse_mat) { + Material *ma = BKE_id_new_nomain(ID_MA, "EEVEEE default diffuse"); + + bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname); + ma->nodetree = ntree; + ma->use_nodes = true; + + bNode *bsdf = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_DIFFUSE); + bNodeSocket *base_color = nodeFindSocket(bsdf, SOCK_IN, "Color"); + copy_v3_fl(((bNodeSocketValueRGBA *)base_color->default_value)->value, 0.8f); + + bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_MATERIAL); + + nodeAddLink(ntree, + bsdf, + nodeFindSocket(bsdf, SOCK_OUT, "BSDF"), + output, + nodeFindSocket(output, SOCK_IN, "Surface")); + + nodeSetActive(ntree, output); + e_data.diffuse_mat = ma; + } + return e_data.diffuse_mat; +} + +Material *EEVEE_material_default_glossy_get(void) +{ + if (!e_data.glossy_mat) { + Material *ma = BKE_id_new_nomain(ID_MA, "EEVEEE default metal"); + + bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname); + ma->nodetree = ntree; + ma->use_nodes = true; + + bNode *bsdf = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_GLOSSY); + bNodeSocket *base_color = nodeFindSocket(bsdf, SOCK_IN, "Color"); + copy_v3_fl(((bNodeSocketValueRGBA *)base_color->default_value)->value, 1.0f); + bNodeSocket *roughness = nodeFindSocket(bsdf, SOCK_IN, "Roughness"); + ((bNodeSocketValueFloat *)roughness->default_value)->value = 0.0f; + + bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_MATERIAL); + + nodeAddLink(ntree, + bsdf, + nodeFindSocket(bsdf, SOCK_OUT, "BSDF"), + output, + nodeFindSocket(output, SOCK_IN, "Surface")); + + nodeSetActive(ntree, output); + e_data.glossy_mat = ma; + } + return e_data.glossy_mat; +} + +Material *EEVEE_material_default_error_get(void) +{ + if (!e_data.error_mat) { + Material *ma = BKE_id_new_nomain(ID_MA, "EEVEEE default metal"); + + bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname); + ma->nodetree = ntree; + ma->use_nodes = true; + + /* Use emission and output material to be compatible with both World and Material. */ + bNode *bsdf = nodeAddStaticNode(NULL, ntree, SH_NODE_EMISSION); + bNodeSocket *color = nodeFindSocket(bsdf, SOCK_IN, "Color"); + copy_v3_fl3(((bNodeSocketValueRGBA *)color->default_value)->value, 1.0f, 0.0f, 1.0f); + + bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_MATERIAL); + + nodeAddLink(ntree, + bsdf, + nodeFindSocket(bsdf, SOCK_OUT, "Emission"), + output, + nodeFindSocket(output, SOCK_IN, "Surface")); + + nodeSetActive(ntree, output); + e_data.error_mat = ma; + } + return e_data.error_mat; +} + +/* Configure a default nodetree with the given material. */ +struct bNodeTree *EEVEE_shader_default_surface_nodetree(Material *ma) +{ + /* WARNING: This function is not threadsafe. Which is not a problem for the moment. */ + if (!e_data.surface.ntree) { + bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname); + bNode *bsdf = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_PRINCIPLED); + bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_MATERIAL); + bNodeSocket *bsdf_out = nodeFindSocket(bsdf, SOCK_OUT, "BSDF"); + bNodeSocket *output_in = nodeFindSocket(output, SOCK_IN, "Surface"); + nodeAddLink(ntree, bsdf, bsdf_out, output, output_in); + nodeSetActive(ntree, output); + + e_data.surface.color_socket = nodeFindSocket(bsdf, SOCK_IN, "Base Color")->default_value; + e_data.surface.metallic_socket = nodeFindSocket(bsdf, SOCK_IN, "Metallic")->default_value; + e_data.surface.roughness_socket = nodeFindSocket(bsdf, SOCK_IN, "Roughness")->default_value; + e_data.surface.specular_socket = nodeFindSocket(bsdf, SOCK_IN, "Specular")->default_value; + e_data.surface.ntree = ntree; + } + /* Update */ + copy_v3_fl3(e_data.surface.color_socket->value, ma->r, ma->g, ma->b); + e_data.surface.metallic_socket->value = ma->metallic; + e_data.surface.roughness_socket->value = ma->roughness; + e_data.surface.specular_socket->value = ma->spec; + + return e_data.surface.ntree; +} + +/* Configure a default nodetree with the given world. */ +struct bNodeTree *EEVEE_shader_default_world_nodetree(World *wo) +{ + /* WARNING: This function is not threadsafe. Which is not a problem for the moment. */ + if (!e_data.world.ntree) { + bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname); + bNode *bg = nodeAddStaticNode(NULL, ntree, SH_NODE_BACKGROUND); + bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_WORLD); + bNodeSocket *bg_out = nodeFindSocket(bg, SOCK_OUT, "Background"); + bNodeSocket *output_in = nodeFindSocket(output, SOCK_IN, "Surface"); + nodeAddLink(ntree, bg, bg_out, output, output_in); + nodeSetActive(ntree, output); + + e_data.world.color_socket = nodeFindSocket(bg, SOCK_IN, "Color")->default_value; + e_data.world.ntree = ntree; + } + + copy_v3_fl3(e_data.world.color_socket->value, wo->horr, wo->horg, wo->horb); + + return e_data.world.ntree; +} + +static char *eevee_get_defines(int options) +{ + char *str = NULL; + + DynStr *ds = BLI_dynstr_new(); + BLI_dynstr_append(ds, SHADER_DEFINES); + + if ((options & VAR_WORLD_BACKGROUND) != 0) { + BLI_dynstr_append(ds, "#define WORLD_BACKGROUND\n"); + } + if ((options & VAR_MAT_VOLUME) != 0) { + BLI_dynstr_append(ds, "#define VOLUMETRICS\n"); + } + if ((options & VAR_MAT_MESH) != 0) { + BLI_dynstr_append(ds, "#define MESH_SHADER\n"); + } + if ((options & VAR_MAT_DEPTH) != 0) { + BLI_dynstr_append(ds, "#define DEPTH_SHADER\n"); + } + if ((options & VAR_MAT_HAIR) != 0) { + BLI_dynstr_append(ds, "#define HAIR_SHADER\n"); + } + if ((options & (VAR_MAT_PROBE | VAR_WORLD_PROBE)) != 0) { + BLI_dynstr_append(ds, "#define PROBE_CAPTURE\n"); + } + if ((options & VAR_MAT_HASH) != 0) { + BLI_dynstr_append(ds, "#define USE_ALPHA_HASH\n"); + } + if ((options & VAR_MAT_BLEND) != 0) { + BLI_dynstr_append(ds, "#define USE_ALPHA_BLEND\n"); + } + if ((options & VAR_MAT_REFRACT) != 0) { + BLI_dynstr_append(ds, "#define USE_REFRACTION\n"); + } + if ((options & VAR_MAT_LOOKDEV) != 0) { + BLI_dynstr_append(ds, "#define LOOKDEV\n"); + } + if ((options & VAR_MAT_HOLDOUT) != 0) { + BLI_dynstr_append(ds, "#define HOLDOUT\n"); + } + + str = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + + return str; +} + +static char *eevee_get_vert(int options) +{ + char *str = NULL; + + if ((options & VAR_MAT_VOLUME) != 0) { + str = BLI_strdup(e_data.vert_volume_shader_str); + } + else if ((options & (VAR_WORLD_PROBE | VAR_WORLD_BACKGROUND)) != 0) { + str = BLI_strdup(e_data.vert_background_shader_str); + } + else { + str = BLI_strdup(e_data.vert_shader_str); + } + + return str; +} + +static char *eevee_get_geom(int options) +{ + char *str = NULL; + + if ((options & VAR_MAT_VOLUME) != 0) { + str = BLI_strdup(e_data.geom_volume_shader_str); + } + + return str; +} + +static char *eevee_get_frag(int options) +{ + char *str = NULL; + + if ((options & VAR_MAT_VOLUME) != 0) { + str = BLI_strdup(e_data.volume_shader_lib); + } + else if ((options & VAR_MAT_DEPTH) != 0) { + str = BLI_string_joinN(e_data.frag_shader_lib, datatoc_prepass_frag_glsl); + } + else { + str = BLI_strdup(e_data.frag_shader_lib); + } + + return str; +} + +static struct GPUMaterial *eevee_material_get_ex( + struct Scene *scene, Material *ma, World *wo, int options, bool deferred) +{ + BLI_assert(ma || wo); + const bool is_volume = (options & VAR_MAT_VOLUME) != 0; + const bool is_default = (options & VAR_DEFAULT) != 0; + const void *engine = &DRW_engine_viewport_eevee_type; + + GPUMaterial *mat = NULL; + + if (ma) { + mat = DRW_shader_find_from_material(ma, engine, options, deferred); + } + else { + mat = DRW_shader_find_from_world(wo, engine, options, deferred); + } + + if (mat) { + return mat; + } + + char *defines = eevee_get_defines(options); + char *vert = eevee_get_vert(options); + char *geom = eevee_get_geom(options); + char *frag = eevee_get_frag(options); + + if (ma) { + bNodeTree *ntree = !is_default ? ma->nodetree : EEVEE_shader_default_surface_nodetree(ma); + mat = DRW_shader_create_from_material( + scene, ma, ntree, engine, options, is_volume, vert, geom, frag, defines, deferred); + } + else { + bNodeTree *ntree = !is_default ? wo->nodetree : EEVEE_shader_default_world_nodetree(wo); + mat = DRW_shader_create_from_world( + scene, wo, ntree, engine, options, is_volume, vert, geom, frag, defines, deferred); + } + + MEM_SAFE_FREE(defines); + MEM_SAFE_FREE(vert); + MEM_SAFE_FREE(geom); + MEM_SAFE_FREE(frag); + + return mat; +} + +/* Note: Compilation is not deferred. */ +struct GPUMaterial *EEVEE_material_default_get(struct Scene *scene, Material *ma, int options) +{ + Material *def_ma = (ma && (options & VAR_MAT_VOLUME)) ? BKE_material_default_volume() : + BKE_material_default_surface(); + BLI_assert(def_ma->use_nodes && def_ma->nodetree); + + return eevee_material_get_ex(scene, def_ma, NULL, options, false); +} + +struct GPUMaterial *EEVEE_material_get( + EEVEE_Data *vedata, struct Scene *scene, Material *ma, World *wo, int options) +{ + if ((ma && (!ma->use_nodes || !ma->nodetree)) || (wo && (!wo->use_nodes || !wo->nodetree))) { + options |= VAR_DEFAULT; + } + + /* Meh, implicit option. World probe cannot be deferred because they need + * to be rendered immediatly. */ + const bool deferred = (options & VAR_WORLD_PROBE) == 0; + + GPUMaterial *mat = eevee_material_get_ex(scene, ma, wo, options, deferred); + + int status = GPU_material_status(mat); + switch (status) { + case GPU_MAT_SUCCESS: + break; + case GPU_MAT_QUEUED: + vedata->stl->g_data->queued_shaders_count++; + mat = EEVEE_material_default_get(scene, ma, options); + break; + case GPU_MAT_FAILED: + default: + ma = EEVEE_material_default_error_get(); + mat = eevee_material_get_ex(scene, ma, NULL, options, false); + break; + } + /* Returned material should be ready to be drawn. */ + BLI_assert(GPU_material_status(mat) == GPU_MAT_SUCCESS); + return mat; +} + void EEVEE_shaders_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_background); + DRW_SHADER_FREE_SAFE(e_data.update_noise_sh); DRW_SHADER_FREE_SAFE(e_data.probe_default_sh); DRW_SHADER_FREE_SAFE(e_data.probe_filter_glossy_sh); DRW_SHADER_FREE_SAFE(e_data.probe_filter_diffuse_sh); @@ -332,4 +787,27 @@ void EEVEE_shaders_free(void) DRW_SHADER_FREE_SAFE(e_data.velocity_resolve_sh); DRW_SHADER_FREE_SAFE(e_data.taa_resolve_sh); DRW_SHADER_FREE_SAFE(e_data.taa_resolve_reproject_sh); + + if (e_data.glossy_mat) { + BKE_id_free(NULL, e_data.glossy_mat); + e_data.glossy_mat = NULL; + } + if (e_data.diffuse_mat) { + BKE_id_free(NULL, e_data.diffuse_mat); + e_data.diffuse_mat = NULL; + } + if (e_data.error_mat) { + BKE_id_free(NULL, e_data.error_mat); + e_data.error_mat = NULL; + } + if (e_data.surface.ntree) { + ntreeFreeEmbeddedTree(e_data.surface.ntree); + MEM_freeN(e_data.surface.ntree); + e_data.surface.ntree = NULL; + } + if (e_data.world.ntree) { + ntreeFreeEmbeddedTree(e_data.world.ntree); + MEM_freeN(e_data.world.ntree); + e_data.world.ntree = NULL; + } } diff --git a/source/blender/draw/engines/eevee/eevee_shadows.c b/source/blender/draw/engines/eevee/eevee_shadows.c index fb338d85fde..84c50a22ae6 100644 --- a/source/blender/draw/engines/eevee/eevee_shadows.c +++ b/source/blender/draw/engines/eevee/eevee_shadows.c @@ -159,47 +159,6 @@ void EEVEE_shadows_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) } } -/* Add a shadow caster to the shadowpasses */ -void EEVEE_shadows_caster_add(EEVEE_ViewLayerData *UNUSED(sldata), - EEVEE_StorageList *stl, - struct GPUBatch *geom, - Object *ob) -{ - DRW_shgroup_call(stl->g_data->shadow_shgrp, geom, ob); -} - -void EEVEE_shadows_caster_material_add(EEVEE_ViewLayerData *sldata, - EEVEE_PassList *psl, - struct GPUMaterial *gpumat, - struct GPUBatch *geom, - struct Object *ob, - const float *alpha_threshold) -{ - /* TODO / PERF : reuse the same shading group for objects with the same material */ - DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, psl->shadow_pass); - - if (grp == NULL) { - return; - } - - /* Unfortunately needed for correctness but not 99% of the time not needed. - * TODO detect when needed? */ - DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); - DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); - DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); - DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); - DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); - DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - - if (alpha_threshold != NULL) { - DRW_shgroup_uniform_float(grp, "alphaThreshold", alpha_threshold, 1); - } - - DRW_shgroup_call(grp, geom, ob); -} - /* Make that object update shadow casting lights inside its influence bounding box. */ void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, Object *ob) { @@ -470,8 +429,7 @@ void EEVEE_shadow_output_init(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool); DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeTexture", &sldata->shadow_cascade_pool); diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c index 4f334812a8e..7674148f76a 100644 --- a/source/blender/draw/engines/eevee/eevee_subsurface.c +++ b/source/blender/draw/engines/eevee/eevee_subsurface.c @@ -29,7 +29,9 @@ #include "DEG_depsgraph_query.h" #include "GPU_extensions.h" +#include "GPU_material.h" #include "GPU_texture.h" + #include "eevee_private.h" static struct { @@ -83,6 +85,7 @@ void EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); effects->sss_sample_count = 1 + scene_eval->eevee.sss_samples * 2; + effects->sss_surface_count = 0; common_data->sss_jitter_threshold = scene_eval->eevee.sss_jitter_threshold; } @@ -221,70 +224,77 @@ void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, - uint sss_id, - struct GPUUniformBuffer *sss_profile) + Material *ma, + DRWShadingGroup *shgrp, + struct GPUMaterial *gpumat) { - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; - struct GPUBatch *quad = DRW_cache_fullscreen_quad_get(); + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); GPUTexture **depth_src = GPU_depth_blitting_workaround() ? &effects->sss_stencil : &dtxl->depth; - DRWShadingGroup *grp = DRW_shgroup_create(e_data.sss_sh[0], psl->sss_blur_ps); - DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src); - DRW_shgroup_uniform_texture_ref(grp, "sssIrradiance", &effects->sss_irradiance); - DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius); - DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); - DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); - DRW_shgroup_stencil_mask(grp, sss_id); - DRW_shgroup_call(grp, quad, NULL); - - grp = DRW_shgroup_create(e_data.sss_sh[1], psl->sss_resolve_ps); - DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src); - DRW_shgroup_uniform_texture_ref(grp, "sssIrradiance", &effects->sss_blur); - DRW_shgroup_uniform_texture_ref(grp, "sssAlbedo", &effects->sss_albedo); - DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius); - DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); - DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); - DRW_shgroup_stencil_mask(grp, sss_id); - DRW_shgroup_call(grp, quad, NULL); -} + struct GPUTexture *sss_tex_profile = NULL; + struct GPUUniformBuffer *sss_profile = GPU_material_sss_profile_get( + gpumat, stl->effects->sss_sample_count, &sss_tex_profile); -void EEVEE_subsurface_translucency_add_pass(EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - uint sss_id, - struct GPUUniformBuffer *sss_profile, - GPUTexture *sss_tex_profile) -{ - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - EEVEE_PassList *psl = vedata->psl; - EEVEE_StorageList *stl = vedata->stl; - EEVEE_EffectsInfo *effects = stl->effects; - struct GPUBatch *quad = DRW_cache_fullscreen_quad_get(); - GPUTexture **depth_src = GPU_depth_blitting_workaround() ? &effects->sss_stencil : &dtxl->depth; + if (!sss_profile) { + BLI_assert(0 && "SSS pass requested but no SSS data was found"); + return; + } + + /* Limit of 8 bit stencil buffer. ID 255 is refraction. */ + if (effects->sss_surface_count >= 254) { + /* TODO : display message. */ + printf("Error: Too many different Subsurface shader in the scene.\n"); + return; + } + + int sss_id = ++(effects->sss_surface_count); + /* Make main pass output stencil mask. */ + DRW_shgroup_stencil_mask(shgrp, sss_id); + + { + DRWShadingGroup *grp = DRW_shgroup_create(e_data.sss_sh[0], psl->sss_blur_ps); + DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src); + DRW_shgroup_uniform_texture_ref(grp, "sssIrradiance", &effects->sss_irradiance); + DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius); + DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); + DRW_shgroup_stencil_mask(grp, sss_id); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + + grp = DRW_shgroup_create(e_data.sss_sh[1], psl->sss_resolve_ps); + DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src); + DRW_shgroup_uniform_texture_ref(grp, "sssIrradiance", &effects->sss_blur); + DRW_shgroup_uniform_texture_ref(grp, "sssAlbedo", &effects->sss_albedo); + DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius); + DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); + DRW_shgroup_stencil_mask(grp, sss_id); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } - DRWShadingGroup *grp = DRW_shgroup_create(e_data.sss_sh[2], psl->sss_translucency_ps); - DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); - DRW_shgroup_uniform_texture(grp, "sssTexProfile", sss_tex_profile); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src); - DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius); - DRW_shgroup_uniform_texture_ref(grp, "sssShadowCubes", &sldata->shadow_cube_pool); - DRW_shgroup_uniform_texture_ref(grp, "sssShadowCascades", &sldata->shadow_cascade_pool); - DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); - DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); - DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); - DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); - DRW_shgroup_stencil_mask(grp, sss_id); - DRW_shgroup_call(grp, quad, NULL); + if (ma->blend_flag & MA_BL_TRANSLUCENCY) { + DRWShadingGroup *grp = DRW_shgroup_create(e_data.sss_sh[2], psl->sss_translucency_ps); + DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); + DRW_shgroup_uniform_texture(grp, "sssTexProfile", sss_tex_profile); + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src); + DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius); + DRW_shgroup_uniform_texture_ref(grp, "sssShadowCubes", &sldata->shadow_cube_pool); + DRW_shgroup_uniform_texture_ref(grp, "sssShadowCascades", &sldata->shadow_cascade_pool); + DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); + DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); + DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); + DRW_shgroup_stencil_mask(grp, sss_id); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } } void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) @@ -310,8 +320,7 @@ void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat GPU_ATTACHMENT_TEXTURE(effects->sss_albedo)}); GPU_framebuffer_bind(fbl->main_fb); - DRW_draw_pass(psl->sss_pass); - DRW_draw_pass(psl->sss_pass_cull); + DRW_draw_pass(psl->material_sss_ps); /* Restore */ GPU_framebuffer_ensure_config(&fbl->main_fb, @@ -350,23 +359,15 @@ void EEVEE_subsurface_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) if (!DRW_pass_is_empty(psl->sss_translucency_ps)) { /* We sample the shadow-maps using normal sampler. We need to disable Comparison mode. * TODO(fclem) avoid this by using sampler objects.*/ - GPU_texture_bind(sldata->shadow_cube_pool, 0); GPU_texture_compare_mode(sldata->shadow_cube_pool, false); - GPU_texture_unbind(sldata->shadow_cube_pool); - GPU_texture_bind(sldata->shadow_cascade_pool, 0); GPU_texture_compare_mode(sldata->shadow_cascade_pool, false); - GPU_texture_unbind(sldata->shadow_cascade_pool); GPU_framebuffer_bind(fbl->sss_translucency_fb); DRW_draw_pass(psl->sss_translucency_ps); /* Reset original state. */ - GPU_texture_bind(sldata->shadow_cube_pool, 0); GPU_texture_compare_mode(sldata->shadow_cube_pool, true); - GPU_texture_unbind(sldata->shadow_cube_pool); - GPU_texture_bind(sldata->shadow_cascade_pool, 0); GPU_texture_compare_mode(sldata->shadow_cascade_pool, true); - GPU_texture_unbind(sldata->shadow_cascade_pool); } /* 1. horizontal pass */ diff --git a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c index b70d872c4af..d57048f2c4e 100644 --- a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c +++ b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c @@ -292,8 +292,7 @@ void EEVEE_temporal_sampling_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data DRW_shgroup_uniform_texture_ref(grp, "colorHistoryBuffer", &txl->taa_history); DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &effects->source_buffer); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); if (effects->enabled_effects & EFFECT_TAA_REPROJECT) { // DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index 83bd4fcf8d2..90860e94270 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -355,7 +355,7 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) struct World *wo = scene->world; if (wo != NULL && wo->use_nodes && wo->nodetree && !LOOK_DEV_STUDIO_LIGHT_ENABLED(draw_ctx->v3d)) { - struct GPUMaterial *mat = EEVEE_material_world_volume_get(scene, wo); + struct GPUMaterial *mat = EEVEE_material_get(vedata, scene, NULL, wo, VAR_MAT_VOLUME); if (GPU_material_has_volume_output(mat)) { grp = DRW_shgroup_material_create(mat, psl->volumetric_world_ps); @@ -369,8 +369,7 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); /* Fix principle volumetric not working with world materials. */ ListBase gpu_grids = GPU_material_volume_grids(mat); @@ -388,8 +387,7 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) /* If no world or volume material is present just clear the buffer with this drawcall */ grp = DRW_shgroup_create(e_data.volumetric_clear_sh, psl->volumetric_world_ps); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_call_procedural_triangles(grp, NULL, common_data->vol_tex_size[2]); } @@ -590,12 +588,10 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, return; } - struct GPUMaterial *mat = EEVEE_material_mesh_volume_get(scene, ma); + int mat_options = VAR_MAT_VOLUME | VAR_MAT_MESH; + struct GPUMaterial *mat = EEVEE_material_get(vedata, scene, ma, NULL, mat_options); eGPUMaterialStatus status = GPU_material_status(mat); - if (status == GPU_MAT_QUEUED) { - vedata->stl->g_data->queued_shaders_count++; - } /* If shader failed to compile or is currently compiling. */ if (status != GPU_MAT_SUCCESS) { return; @@ -609,8 +605,7 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); @@ -661,8 +656,7 @@ void EEVEE_volumes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_call_procedural_triangles(grp, NULL, common_data->vol_tex_size[2]); @@ -671,8 +665,7 @@ void EEVEE_volumes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_texture_ref(grp, "volumeScattering", &txl->volume_scatter); DRW_shgroup_uniform_texture_ref(grp, "volumeExtinction", &txl->volume_transmit); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_call_procedural_triangles( grp, NULL, USE_VOLUME_OPTI ? 1 : common_data->vol_tex_size[2]); @@ -683,8 +676,7 @@ void EEVEE_volumes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_texture_ref(grp, "inTransmittance", &txl->volume_transmit); DRW_shgroup_uniform_texture_ref(grp, "inSceneDepth", &e_data.depth_src); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } @@ -775,12 +767,8 @@ void EEVEE_volumes_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) /* We sample the shadow-maps using shadow sampler. We need to enable Comparison mode. * TODO(fclem) avoid this by using sampler objects.*/ - GPU_texture_bind(sldata->shadow_cube_pool, 0); GPU_texture_compare_mode(sldata->shadow_cube_pool, true); - GPU_texture_unbind(sldata->shadow_cube_pool); - GPU_texture_bind(sldata->shadow_cascade_pool, 0); GPU_texture_compare_mode(sldata->shadow_cascade_pool, true); - GPU_texture_unbind(sldata->shadow_cascade_pool); GPU_framebuffer_bind(fbl->volumetric_fb); DRW_draw_pass(psl->volumetric_world_ps); @@ -920,8 +908,7 @@ void EEVEE_volumes_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, DRW_shgroup_uniform_texture_ref(grp, "inTransmittance", &txl->volume_transmit); DRW_shgroup_uniform_texture_ref(grp, "inSceneDepth", &e_data.depth_src); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block( - grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); } else { /* There is no volumetrics in the scene. Use a shader to fill the accum textures with a default diff --git a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl index 8662c0ecb6a..57b16418696 100644 --- a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl @@ -6,13 +6,9 @@ #if defined(MESH_SHADER) # if !defined(USE_ALPHA_HASH) -# if !defined(USE_ALPHA_CLIP) -# if !defined(SHADOW_SHADER) -# if !defined(USE_MULTIPLY) -# if !defined(USE_ALPHA_BLEND) -# define ENABLE_DEFERED_AO -# endif -# endif +# if !defined(DEPTH_SHADER) +# if !defined(USE_ALPHA_BLEND) +# define ENABLE_DEFERED_AO # endif # endif # endif diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index c3518198805..402d306df45 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -928,7 +928,7 @@ Closure closure_emission(vec3 rgb) /* Breaking this across multiple lines causes issues for some older GLSL compilers. */ /* clang-format off */ -# if defined(MESH_SHADER) && !defined(USE_ALPHA_HASH) && !defined(USE_ALPHA_CLIP) && !defined(SHADOW_SHADER) +# if defined(MESH_SHADER) && !defined(DEPTH_SHADER) /* clang-format on */ # ifndef USE_ALPHA_BLEND layout(location = 0) out vec4 outRadiance; @@ -1001,6 +1001,10 @@ void main() outRadiance.rgb += cl.sss_irradiance.rgb * cl.sss_albedo.rgb * fac; # endif +# ifdef LOOKDEV + gl_FragDepth = 0.0; +# endif + # ifndef USE_ALPHA_BLEND float alpha_div = 1.0 / max(1e-8, alpha); outRadiance.rgb *= alpha_div; @@ -1011,6 +1015,6 @@ void main() # endif } -# endif /* MESH_SHADER && !SHADOW_SHADER */ +# endif /* MESH_SHADER */ #endif /* VOLUMETRICS */ diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl index 5277bfa32bb..d56890769a7 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl @@ -1,6 +1,4 @@ -uniform mat4 ProjectionMatrix; - uniform sampler2D colorBuffer; uniform sampler2D depthBuffer; diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl index 8c2619650b9..bc7879763c3 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl @@ -177,7 +177,7 @@ void CLOSURE_NAME(vec3 N out_refr = vec3(0.0); #endif -#if defined(SHADOW_SHADER) || defined(WORLD_BACKGROUND) +#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND) /* This makes shader resources become unused and avoid issues with samplers. (see T59747) */ return; #else diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl index cf20b3ff5b9..1b94fc2bee1 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl @@ -4,11 +4,12 @@ in vec3 pos; in vec3 nor; #endif +#ifdef MESH_SHADER out vec3 worldPosition; out vec3 viewPosition; - out vec3 worldNormal; out vec3 viewNormal; +#endif #ifdef HAIR_SHADER out vec3 hairTangent; @@ -41,22 +42,28 @@ void main() hairThickness, hairThickTime); worldNormal = cross(hairTangent, binor); - worldPosition = pos; + vec3 world_pos = pos; #else - worldPosition = point_object_to_world(pos); - worldNormal = normalize(normal_object_to_world(nor)); + vec3 world_pos = point_object_to_world(pos); #endif - /* No need to normalize since this is just a rotation. */ - viewNormal = normal_world_to_view(worldNormal); + gl_Position = point_world_to_ndc(world_pos); + /* Used for planar reflections */ + gl_ClipDistance[0] = dot(vec4(world_pos, 1.0), clipPlanes[0]); + +#ifdef MESH_SHADER + worldPosition = world_pos; viewPosition = point_world_to_view(worldPosition); - gl_Position = point_world_to_ndc(worldPosition); - /* Used for planar reflections */ - gl_ClipDistance[0] = dot(vec4(worldPosition, 1.0), clipPlanes[0]); +# ifndef HAIR_SHADER + worldNormal = normalize(normal_object_to_world(nor)); +# endif -#ifdef USE_ATTR + /* No need to normalize since this is just a rotation. */ + viewNormal = normal_world_to_view(worldNormal); +# ifdef USE_ATTR pass_attr(pos); +# endif #endif } diff --git a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl index b49dbfceba2..9acd8f998f6 100644 --- a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl @@ -45,26 +45,22 @@ float hashed_alpha_threshold(vec3 co) /* Find our final, uniformly distributed alpha threshold. */ float threshold = (x < one_a) ? ((x < a) ? cases.x : cases.y) : cases.z; + /* Jitter the threshold for TAA accumulation. */ + threshold = fract(threshold + alphaHashOffset); + /* Avoids threshold == 0. */ threshold = clamp(threshold, 1.0e-6, 1.0); - /* Jitter the threshold for TAA accumulation. */ - return fract(threshold + alphaHashOffset); + return threshold; } #endif -#ifdef USE_ALPHA_CLIP -uniform float alphaThreshold; -#endif +#define NODETREE_EXEC void main() { - /* For now do nothing. - * In the future, output object motion blur. */ - -#if defined(USE_ALPHA_HASH) || defined(USE_ALPHA_CLIP) -# define NODETREE_EXEC +#if defined(USE_ALPHA_HASH) Closure cl = nodetree_exec(); @@ -75,11 +71,6 @@ void main() if (opacity < hashed_alpha_threshold(worldPosition)) { discard; } -# elif defined(USE_ALPHA_CLIP) - /* Alpha clip */ - if (opacity <= alphaThreshold) { - discard; - } # endif #endif } diff --git a/source/blender/draw/engines/external/external_engine.c b/source/blender/draw/engines/external/external_engine.c index 6e636e4dc93..2f448b784ed 100644 --- a/source/blender/draw/engines/external/external_engine.c +++ b/source/blender/draw/engines/external/external_engine.c @@ -44,6 +44,11 @@ #define EXTERNAL_ENGINE "BLENDER_EXTERNAL" +extern char datatoc_depth_frag_glsl[]; +extern char datatoc_depth_vert_glsl[]; + +extern char datatoc_common_view_lib_glsl[]; + /* *********** LISTS *********** */ /* GPUViewport.storage @@ -106,7 +111,16 @@ static void external_engine_init(void *vedata) /* Depth prepass */ if (!e_data.depth_sh) { - e_data.depth_sh = DRW_shader_create_3d_depth_only(GPU_SHADER_CFG_DEFAULT); + const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[GPU_SHADER_CFG_DEFAULT]; + + e_data.depth_sh = GPU_shader_create_from_arrays({ + .vert = (const char *[]){sh_cfg->lib, + datatoc_common_view_lib_glsl, + datatoc_depth_vert_glsl, + NULL}, + .frag = (const char *[]){datatoc_depth_frag_glsl, NULL}, + .defs = (const char *[]){sh_cfg->def, NULL}, + }); } if (!stl->g_data) { @@ -277,7 +291,7 @@ static void external_draw_scene(void *vedata) static void external_engine_free(void) { - /* All shaders are builtin. */ + DRW_SHADER_FREE_SAFE(e_data.depth_sh); } static const DrawEngineDataSize external_data_size = DRW_VIEWPORT_DATA_SIZE(EXTERNAL_Data); diff --git a/source/blender/draw/engines/gpencil/gpencil_antialiasing.c b/source/blender/draw/engines/gpencil/gpencil_antialiasing.c index 4dd5e3b2da1..8955240c549 100644 --- a/source/blender/draw/engines/gpencil/gpencil_antialiasing.c +++ b/source/blender/draw/engines/gpencil/gpencil_antialiasing.c @@ -78,13 +78,8 @@ void GPENCIL_antialiasing_init(struct GPENCIL_Data *vedata) false, NULL); - GPU_texture_bind(txl->smaa_search_tx, 0); GPU_texture_filter_mode(txl->smaa_search_tx, true); - GPU_texture_unbind(txl->smaa_search_tx); - - GPU_texture_bind(txl->smaa_area_tx, 0); GPU_texture_filter_mode(txl->smaa_area_tx, true); - GPU_texture_unbind(txl->smaa_area_tx); } { diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c index 1344b649dff..2b811f1d52e 100644 --- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c @@ -381,7 +381,7 @@ GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd, struct GPUShader *sh = GPENCIL_shader_geometry_get(); DRWShadingGroup *grp = tgp_layer->base_shgrp = DRW_shgroup_create(sh, tgp_layer->geom_ps); - DRW_shgroup_uniform_texture_persistent(grp, "gpSceneDepthTexture", depth_tex); + DRW_shgroup_uniform_texture(grp, "gpSceneDepthTexture", depth_tex); DRW_shgroup_uniform_texture_ref(grp, "gpMaskTexture", mask_tex); DRW_shgroup_uniform_vec3_copy(grp, "gpNormal", tgp_ob->plane_normal); DRW_shgroup_uniform_bool_copy(grp, "strokeOrder3d", tgp_ob->is_drawmode3d); diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c index 4f586a1e9f3..495de7ef10b 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.c +++ b/source/blender/draw/engines/gpencil/gpencil_engine.c @@ -91,6 +91,7 @@ void GPENCIL_engine_init(void *ved) stl->pd->gp_object_pool = vldata->gp_object_pool; stl->pd->gp_layer_pool = vldata->gp_layer_pool; stl->pd->gp_vfx_pool = vldata->gp_vfx_pool; + stl->pd->view_layer = ctx->view_layer; stl->pd->scene = ctx->scene; stl->pd->v3d = ctx->v3d; stl->pd->last_light_pool = NULL; @@ -468,7 +469,7 @@ static void gpencil_layer_cache_populate(bGPDlayer *gpl, /* Iterator dependent uniforms. */ DRWShadingGroup *grp = iter->grp = tgp_layer->base_shgrp; - DRW_shgroup_uniform_block_persistent(grp, "gpLightBlock", iter->ubo_lights); + DRW_shgroup_uniform_block(grp, "gpLightBlock", iter->ubo_lights); DRW_shgroup_uniform_block(grp, "gpMaterialBlock", iter->ubo_mat); DRW_shgroup_uniform_texture(grp, "gpFillTexture", iter->tex_fill); DRW_shgroup_uniform_texture(grp, "gpStrokeTexture", iter->tex_stroke); @@ -598,6 +599,7 @@ void GPENCIL_cache_populate(void *ved, Object *ob) GPENCIL_Data *vedata = (GPENCIL_Data *)ved; GPENCIL_PrivateData *pd = vedata->stl->pd; GPENCIL_TextureList *txl = vedata->txl; + const bool is_final_render = DRW_state_is_image_render(); /* object must be visible */ if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) { @@ -617,7 +619,8 @@ void GPENCIL_cache_populate(void *ved, Object *ob) bGPdata *gpd = (bGPdata *)ob->data; bool do_onion = (!pd->is_render) ? pd->do_onion : (gpd->onion_flag & GP_ONION_GHOST_ALWAYS); - BKE_gpencil_visible_stroke_iter(ob, + BKE_gpencil_visible_stroke_iter(is_final_render ? pd->view_layer : NULL, + ob, gpencil_layer_cache_populate, gpencil_stroke_cache_populate, &iter, diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h index f765dcf73de..cedd75af813 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.h +++ b/source/blender/draw/engines/gpencil/gpencil_engine.h @@ -307,6 +307,8 @@ typedef struct GPENCIL_PrivateData { float dof_params[2]; /* Used for DoF Setup. */ Object *camera; + /* Copy of draw_ctx->view_layer for convenience. */ + struct ViewLayer *view_layer; /* Copy of draw_ctx->scene for convenience. */ struct Scene *scene; /* Copy of draw_ctx->vie3d for convenience. */ diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c index a538b7ffd5f..95fd918f8c1 100644 --- a/source/blender/draw/engines/overlay/overlay_armature.c +++ b/source/blender/draw/engines/overlay/overlay_armature.c @@ -184,7 +184,7 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_armature_sphere(false); grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); cb->point_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_point_get()); @@ -196,7 +196,7 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_armature_shape(false); grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); cb->custom_solid = grp; cb->box_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_box_get()); @@ -212,29 +212,29 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_armature_sphere(true); grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); cb->point_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_point_wire_outline_get()); sh = OVERLAY_shader_armature_shape(true); cb->custom_outline = grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); cb->box_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_box_wire_get()); cb->octa_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_wire_get()); sh = OVERLAY_shader_armature_shape_wire(); cb->custom_wire = grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); } { format = formats->instance_extra; sh = OVERLAY_shader_armature_degrees_of_freedom(); grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); cb->dof_lines = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_lines_get()); grp = DRW_shgroup_create(sh, armature_transp_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); cb->dof_sphere = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_sphere_get()); } { @@ -242,7 +242,7 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_armature_stick(); grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); cb->stick = BUF_INSTANCE(grp, format, DRW_cache_bone_stick_get()); } { @@ -251,7 +251,7 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_armature_envelope(false); grp = DRW_shgroup_create(sh, armature_ps); DRW_shgroup_state_enable(grp, DRW_STATE_CULL_BACK); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_bool_copy(grp, "isDistance", false); DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); cb->envelope_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get()); @@ -266,14 +266,14 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_armature_envelope(true); grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); cb->envelope_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_outline_get()); format = formats->instance_bone_envelope_distance; sh = OVERLAY_shader_armature_envelope(false); grp = DRW_shgroup_create(sh, armature_transp_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_bool_copy(grp, "isDistance", true); DRW_shgroup_state_enable(grp, DRW_STATE_CULL_FRONT); cb->envelope_distance = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get()); @@ -283,7 +283,7 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_armature_wire(); grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); cb->wire = BUF_LINE(grp, format); } } diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c index 71efc6b8d03..859f3f93b1d 100644 --- a/source/blender/draw/engines/overlay/overlay_extra.c +++ b/source/blender/draw/engines/overlay/overlay_extra.c @@ -81,8 +81,8 @@ void OVERLAY_extra_cache_init(OVERLAY_Data *vedata) struct GPUTexture *tex = DRW_state_is_fbo() ? dtxl->depth : txl->dummy_depth_tx; pd->extra_grid_grp = grp = DRW_shgroup_create(sh, psl->extra_grid_ps); - DRW_shgroup_uniform_texture_persistent(grp, "depthBuffer", tex); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_texture(grp, "depthBuffer", tex); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0); } @@ -112,7 +112,7 @@ void OVERLAY_extra_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_extra(is_select); grp = DRW_shgroup_create(sh, extra_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); grp_sub = DRW_shgroup_create_sub(grp); cb->camera_distances = BUF_INSTANCE(grp_sub, format, DRW_cache_camera_distances_get()); @@ -157,7 +157,7 @@ void OVERLAY_extra_cache_init(OVERLAY_Data *vedata) { format = formats->instance_extra; grp = DRW_shgroup_create(sh, psl->extra_blend_ps); /* NOTE: not the same pass! */ - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); grp_sub = DRW_shgroup_create_sub(grp); DRW_shgroup_state_enable(grp_sub, DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK); @@ -174,7 +174,7 @@ void OVERLAY_extra_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_extra_groundline(); grp = DRW_shgroup_create(sh, extra_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA); cb->groundline = BUF_INSTANCE(grp, format, DRW_cache_groundline_get()); @@ -183,7 +183,7 @@ void OVERLAY_extra_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_extra_wire(false, is_select); grp = DRW_shgroup_create(sh, extra_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); cb->extra_dashed_lines = BUF_LINE(grp, formats->pos_color); cb->extra_lines = BUF_LINE(grp, formats->wire_extra); @@ -192,20 +192,20 @@ void OVERLAY_extra_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_extra_wire(true, is_select); cb->extra_wire = grp = DRW_shgroup_create(sh, extra_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); } { sh = OVERLAY_shader_extra_loose_point(); cb->extra_loose_points = grp = DRW_shgroup_create(sh, extra_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); } { format = formats->pos; sh = OVERLAY_shader_extra_point(); grp = DRW_shgroup_create(sh, psl->extra_centers_ps); /* NOTE: not the same pass! */ - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); grp_sub = DRW_shgroup_create_sub(grp); DRW_shgroup_uniform_vec4_copy(grp_sub, "color", G_draw.block.colorActive); @@ -1371,9 +1371,9 @@ static void OVERLAY_volume_extra(OVERLAY_ExtraCallBuffers *cb, madd_v3fl_v3fl_v3fl_v3i(min, mds->p0, mds->cell_size, mds->res_min); float voxel_cubemat[4][4] = {{0.0f}}; /* scale small cube to voxel size */ - voxel_cubemat[0][0] = 1.0f / (float)mds->base_res[0]; - voxel_cubemat[1][1] = 1.0f / (float)mds->base_res[1]; - voxel_cubemat[2][2] = 1.0f / (float)mds->base_res[2]; + voxel_cubemat[0][0] = mds->cell_size[0] / 2.0f; + voxel_cubemat[1][1] = mds->cell_size[1] / 2.0f; + voxel_cubemat[2][2] = mds->cell_size[2] / 2.0f; voxel_cubemat[3][3] = 1.0f; /* translate small cube to corner */ copy_v3_v3(voxel_cubemat[3], min); diff --git a/source/blender/draw/engines/overlay/overlay_facing.c b/source/blender/draw/engines/overlay/overlay_facing.c index 9216ae61b3e..4eb4b8ae85b 100644 --- a/source/blender/draw/engines/overlay/overlay_facing.c +++ b/source/blender/draw/engines/overlay/overlay_facing.c @@ -41,7 +41,7 @@ void OVERLAY_facing_cache_init(OVERLAY_Data *vedata) GPUShader *sh = OVERLAY_shader_facing(); pd->facing_grp[i] = DRW_shgroup_create(sh, psl->facing_ps[i]); - DRW_shgroup_uniform_block_persistent(pd->facing_grp[i], "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(pd->facing_grp[i], "globalsBlock", G_draw.block_ubo); } if (!pd->use_in_front) { diff --git a/source/blender/draw/engines/overlay/overlay_gpencil.c b/source/blender/draw/engines/overlay/overlay_gpencil.c index 1397ef7b4b2..ccc914e0422 100644 --- a/source/blender/draw/engines/overlay/overlay_gpencil.c +++ b/source/blender/draw/engines/overlay/overlay_gpencil.c @@ -361,7 +361,7 @@ static void OVERLAY_gpencil_color_names(Object *ob) int cfra = DEG_get_ctime(draw_ctx->depsgraph); BKE_gpencil_visible_stroke_iter( - ob, NULL, overlay_gpencil_draw_stroke_color_name, ob, false, cfra); + NULL, ob, NULL, overlay_gpencil_draw_stroke_color_name, ob, false, cfra); } void OVERLAY_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob) diff --git a/source/blender/draw/engines/overlay/overlay_motion_path.c b/source/blender/draw/engines/overlay/overlay_motion_path.c index 531e1faf715..168f6f8a17f 100644 --- a/source/blender/draw/engines/overlay/overlay_motion_path.c +++ b/source/blender/draw/engines/overlay/overlay_motion_path.c @@ -49,11 +49,11 @@ void OVERLAY_motion_path_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_motion_path_line(); pd->motion_path_lines_grp = grp = DRW_shgroup_create(sh, psl->motion_paths_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); sh = OVERLAY_shader_motion_path_vert(); pd->motion_path_points_grp = grp = DRW_shgroup_create(sh, psl->motion_paths_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); } /* Just convert the CPU cache to GPU cache. */ diff --git a/source/blender/draw/engines/overlay/overlay_outline.c b/source/blender/draw/engines/overlay/overlay_outline.c index 142421f58d8..99d22fc380f 100644 --- a/source/blender/draw/engines/overlay/overlay_outline.c +++ b/source/blender/draw/engines/overlay/overlay_outline.c @@ -259,7 +259,7 @@ static void OVERLAY_outline_gpencil(OVERLAY_PrivateData *pd, Object *ob) } BKE_gpencil_visible_stroke_iter( - ob, gp_layer_cache_populate, gp_stroke_cache_populate, &iter, false, pd->cfra); + NULL, ob, gp_layer_cache_populate, gp_stroke_cache_populate, &iter, false, pd->cfra); } void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata, diff --git a/source/blender/draw/engines/overlay/overlay_particle.c b/source/blender/draw/engines/overlay/overlay_particle.c index 98bc62ae66a..b891bb4ce4c 100644 --- a/source/blender/draw/engines/overlay/overlay_particle.c +++ b/source/blender/draw/engines/overlay/overlay_particle.c @@ -152,13 +152,13 @@ void OVERLAY_particle_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_particle_dot(); pd->particle_dots_grp = grp = DRW_shgroup_create(sh, psl->particle_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_texture_persistent(grp, "weightTex", G_draw.ramp); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.ramp); sh = OVERLAY_shader_particle_shape(); pd->particle_shapes_grp = grp = DRW_shgroup_create(sh, psl->particle_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_texture_persistent(grp, "weightTex", G_draw.ramp); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.ramp); } void OVERLAY_particle_cache_populate(OVERLAY_Data *vedata, Object *ob) diff --git a/source/blender/draw/engines/overlay/overlay_pointcloud.c b/source/blender/draw/engines/overlay/overlay_pointcloud.c index a0de7aac1f1..b2a2d44bf73 100644 --- a/source/blender/draw/engines/overlay/overlay_pointcloud.c +++ b/source/blender/draw/engines/overlay/overlay_pointcloud.c @@ -46,7 +46,7 @@ void OVERLAY_pointcloud_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_pointcloud_dot(); pd->pointcloud_dots_grp = grp = DRW_shgroup_create(sh, psl->pointcloud_ps); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); } void OVERLAY_pointcloud_cache_populate(OVERLAY_Data *vedata, Object *ob) diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.c b/source/blender/draw/engines/overlay/overlay_wireframe.c index cb36f0ed326..eebfc88fdce 100644 --- a/source/blender/draw/engines/overlay/overlay_wireframe.c +++ b/source/blender/draw/engines/overlay/overlay_wireframe.c @@ -91,7 +91,7 @@ void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata) for (int use_coloring = 0; use_coloring < 2; use_coloring++) { pd->wires_grp[xray][use_coloring] = grp = DRW_shgroup_create(wires_sh, pass); - DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tx); DRW_shgroup_uniform_float_copy(grp, "wireStepParam", pd->shdata.wire_step_param); DRW_shgroup_uniform_bool_copy(grp, "useColoring", use_coloring); @@ -197,13 +197,15 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata, struct GPUBatch *geom = NULL; switch (ob->type) { case OB_CURVE: - if (ob->runtime.curve_cache && BKE_displist_has_faces(&ob->runtime.curve_cache->disp)) { + if (!pd->wireframe_mode && !use_wire && ob->runtime.curve_cache && + BKE_displist_has_faces(&ob->runtime.curve_cache->disp)) { break; } geom = DRW_cache_curve_edge_wire_get(ob); break; case OB_FONT: - if (ob->runtime.curve_cache && BKE_displist_has_faces(&ob->runtime.curve_cache->disp)) { + if (!pd->wireframe_mode && !use_wire && ob->runtime.curve_cache && + BKE_displist_has_faces(&ob->runtime.curve_cache->disp)) { break; } geom = DRW_cache_text_loose_edges_get(ob); diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl index 0efcfb35929..51007a9f246 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl @@ -4,7 +4,6 @@ * Converted and adapted from HLSL to GLSL by Clément Foucault */ -uniform mat4 ProjectionMatrix; uniform vec2 invertedViewportSize; uniform vec2 nearFar; uniform vec3 dofParams; diff --git a/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c index cb8eb7d1e92..0e896c4b7bb 100644 --- a/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c +++ b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c @@ -266,13 +266,8 @@ void workbench_antialiasing_engine_init(WORKBENCH_Data *vedata) false, NULL); - GPU_texture_bind(txl->smaa_search_tx, 0); GPU_texture_filter_mode(txl->smaa_search_tx, true); - GPU_texture_unbind(txl->smaa_search_tx); - - GPU_texture_bind(txl->smaa_area_tx, 0); GPU_texture_filter_mode(txl->smaa_area_tx, true); - GPU_texture_unbind(txl->smaa_area_tx); } } else { diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c index 0b7d313342b..b36a4a3a494 100644 --- a/source/blender/draw/engines/workbench/workbench_materials.c +++ b/source/blender/draw/engines/workbench/workbench_materials.c @@ -284,11 +284,11 @@ DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd, *grp_tex = grp = DRW_shgroup_create_sub(grp); if (tex_tile_data) { - DRW_shgroup_uniform_texture_persistent(grp, "imageTileArray", tex); - DRW_shgroup_uniform_texture_persistent(grp, "imageTileData", tex_tile_data); + DRW_shgroup_uniform_texture(grp, "imageTileArray", tex); + DRW_shgroup_uniform_texture(grp, "imageTileData", tex_tile_data); } else { - DRW_shgroup_uniform_texture_persistent(grp, "imageTexture", tex); + DRW_shgroup_uniform_texture(grp, "imageTexture", tex); } DRW_shgroup_uniform_bool_copy(grp, "imagePremult", (ima && ima->alpha_mode == IMA_ALPHA_PREMUL)); DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST)); diff --git a/source/blender/draw/engines/workbench/workbench_opaque.c b/source/blender/draw/engines/workbench/workbench_opaque.c index c9c43e785ca..27d5b71f35c 100644 --- a/source/blender/draw/engines/workbench/workbench_opaque.c +++ b/source/blender/draw/engines/workbench/workbench_opaque.c @@ -95,21 +95,21 @@ void workbench_opaque_cache_init(WORKBENCH_Data *data) DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap); wpd->prepass[opaque][infront][hair].vcol_shgrp = grp = DRW_shgroup_create(sh, pass); - DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr); DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. (uses vcol) */ DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap); sh = workbench_shader_opaque_image_get(wpd, hair, false); wpd->prepass[opaque][infront][hair].image_shgrp = grp = DRW_shgroup_create(sh, pass); - DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr); DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */ DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap); sh = workbench_shader_opaque_image_get(wpd, hair, true); wpd->prepass[opaque][infront][hair].image_tiled_shgrp = grp = DRW_shgroup_create(sh, pass); - DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr); DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */ DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap); } @@ -123,9 +123,9 @@ void workbench_opaque_cache_init(WORKBENCH_Data *data) sh = workbench_shader_composite_get(wpd); grp = DRW_shgroup_create(sh, psl->composite_ps); - DRW_shgroup_uniform_block_persistent(grp, "world_block", wpd->world_ubo); - DRW_shgroup_uniform_texture_persistent(grp, "materialBuffer", wpd->material_buffer_tx); - DRW_shgroup_uniform_texture_persistent(grp, "normalBuffer", wpd->normal_buffer_tx); + DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); + DRW_shgroup_uniform_texture(grp, "materialBuffer", wpd->material_buffer_tx); + DRW_shgroup_uniform_texture(grp, "normalBuffer", wpd->normal_buffer_tx); DRW_shgroup_uniform_bool_copy(grp, "forceShadowing", false); DRW_shgroup_stencil_mask(grp, 0x00); @@ -137,8 +137,8 @@ void workbench_opaque_cache_init(WORKBENCH_Data *data) struct GPUTexture *spec_tx = wpd->studio_light->matcap_specular.gputexture; const bool use_spec = workbench_is_specular_highlight_enabled(wpd); spec_tx = (use_spec && spec_tx) ? spec_tx : diff_tx; - DRW_shgroup_uniform_texture_persistent(grp, "matcapDiffuseImage", diff_tx); - DRW_shgroup_uniform_texture_persistent(grp, "matcapSpecularImage", spec_tx); + DRW_shgroup_uniform_texture(grp, "matcapDiffuseImage", diff_tx); + DRW_shgroup_uniform_texture(grp, "matcapSpecularImage", spec_tx); } DRW_shgroup_call_procedural_triangles(grp, NULL, 1); diff --git a/source/blender/draw/engines/workbench/workbench_shader.c b/source/blender/draw/engines/workbench/workbench_shader.c index 2e796056029..99366779b22 100644 --- a/source/blender/draw/engines/workbench/workbench_shader.c +++ b/source/blender/draw/engines/workbench/workbench_shader.c @@ -23,6 +23,7 @@ #include "DRW_render.h" #include "BLI_dynstr.h" +#include "BLI_string_utils.h" #include "workbench_engine.h" #include "workbench_private.h" @@ -359,32 +360,24 @@ void workbench_shader_depth_of_field_get(GPUShader **prepare_sh, GPUShader **resolve_sh) { if (e_data.dof_prepare_sh == NULL) { - e_data.dof_prepare_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, - "#define PREPARE\n"); - - e_data.dof_downsample_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, - "#define DOWNSAMPLE\n"); + char *frag = BLI_string_joinN(datatoc_common_view_lib_glsl, + datatoc_workbench_effect_dof_frag_glsl); + e_data.dof_prepare_sh = DRW_shader_create_fullscreen(frag, "#define PREPARE\n"); + e_data.dof_downsample_sh = DRW_shader_create_fullscreen(frag, "#define DOWNSAMPLE\n"); #if 0 /* TODO(fclem) finish COC min_max optimization */ - e_data.dof_flatten_v_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, + e_data.dof_flatten_v_sh = DRW_shader_create_fullscreen(frag, "#define FLATTEN_VERTICAL\n"); - - e_data.dof_flatten_h_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, + e_data.dof_flatten_h_sh = DRW_shader_create_fullscreen(frag, "#define FLATTEN_HORIZONTAL\n"); - - e_data.dof_dilate_v_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, + e_data.dof_dilate_v_sh = DRW_shader_create_fullscreen(frag, "#define DILATE_VERTICAL\n"); - - e_data.dof_dilate_h_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, + e_data.dof_dilate_h_sh = DRW_shader_create_fullscreen(frag, "#define DILATE_HORIZONTAL\n"); #endif - e_data.dof_blur1_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, - "#define BLUR1\n"); - - e_data.dof_blur2_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, - "#define BLUR2\n"); - - e_data.dof_resolve_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, - "#define RESOLVE\n"); + e_data.dof_blur1_sh = DRW_shader_create_fullscreen(frag, "#define BLUR1\n"); + e_data.dof_blur2_sh = DRW_shader_create_fullscreen(frag, "#define BLUR2\n"); + e_data.dof_resolve_sh = DRW_shader_create_fullscreen(frag, "#define RESOLVE\n"); + MEM_freeN(frag); } *prepare_sh = e_data.dof_prepare_sh; diff --git a/source/blender/draw/engines/workbench/workbench_transparent.c b/source/blender/draw/engines/workbench/workbench_transparent.c index 39aa721a41c..5fd8229304a 100644 --- a/source/blender/draw/engines/workbench/workbench_transparent.c +++ b/source/blender/draw/engines/workbench/workbench_transparent.c @@ -67,7 +67,7 @@ void workbench_transparent_engine_init(WORKBENCH_Data *data) static void workbench_transparent_lighting_uniforms(WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp) { - DRW_shgroup_uniform_block_persistent(grp, "world_block", wpd->world_ubo); + DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); DRW_shgroup_uniform_bool_copy(grp, "forceShadowing", false); if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) { @@ -78,8 +78,8 @@ static void workbench_transparent_lighting_uniforms(WORKBENCH_PrivateData *wpd, struct GPUTexture *spec_tx = wpd->studio_light->matcap_specular.gputexture; const bool use_spec = workbench_is_specular_highlight_enabled(wpd); spec_tx = (use_spec && spec_tx) ? spec_tx : diff_tx; - DRW_shgroup_uniform_texture_persistent(grp, "matcapDiffuseImage", diff_tx); - DRW_shgroup_uniform_texture_persistent(grp, "matcapSpecularImage", spec_tx); + DRW_shgroup_uniform_texture(grp, "matcapDiffuseImage", diff_tx); + DRW_shgroup_uniform_texture(grp, "matcapSpecularImage", spec_tx); } } @@ -116,20 +116,20 @@ void workbench_transparent_cache_init(WORKBENCH_Data *data) workbench_transparent_lighting_uniforms(wpd, grp); wpd->prepass[transp][infront][hair].vcol_shgrp = grp = DRW_shgroup_create(sh, pass); - DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr); DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. (uses vcol) */ sh = workbench_shader_transparent_image_get(wpd, hair, false); wpd->prepass[transp][infront][hair].image_shgrp = grp = DRW_shgroup_create(sh, pass); - DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr); DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */ workbench_transparent_lighting_uniforms(wpd, grp); sh = workbench_shader_transparent_image_get(wpd, hair, true); wpd->prepass[transp][infront][hair].image_tiled_shgrp = grp = DRW_shgroup_create(sh, pass); - DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr); DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */ workbench_transparent_lighting_uniforms(wpd, grp); } diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index d3585b02b7d..b002f68e4d2 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -221,10 +221,7 @@ struct GPUShader *DRW_shader_create_with_transform_feedback(const char *vert, const eGPUShaderTFBType prim_type, const char **varying_names, const int varying_count); -struct GPUShader *DRW_shader_create_2d(const char *frag, const char *defines); -struct GPUShader *DRW_shader_create_3d(const char *frag, const char *defines); struct GPUShader *DRW_shader_create_fullscreen(const char *frag, const char *defines); -struct GPUShader *DRW_shader_create_3d_depth_only(eGPUShaderConfig slot); struct GPUMaterial *DRW_shader_find_from_world(struct World *wo, const void *engine_type, const int options, @@ -235,6 +232,7 @@ struct GPUMaterial *DRW_shader_find_from_material(struct Material *ma, bool deferred); struct GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, struct World *wo, + struct bNodeTree *ntree, const void *engine_type, const int options, const bool is_volume_shader, @@ -245,6 +243,7 @@ struct GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, bool deferred); struct GPUMaterial *DRW_shader_create_from_material(struct Scene *scene, struct Material *ma, + struct bNodeTree *ntree, const void *engine_type, const int options, const bool is_volume_shader, @@ -376,6 +375,8 @@ DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader, DRWPass *pass, struct GPUVertBuf *tf_target); +void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, struct GPUMaterial *material); + /* return final visibility */ typedef bool(DRWCallVisibilityFn)(bool vis_in, void *user_data); @@ -471,18 +472,15 @@ void DRW_shgroup_clear_framebuffer(DRWShadingGroup *shgroup, void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const struct GPUTexture *tex); -void DRW_shgroup_uniform_texture_persistent(DRWShadingGroup *shgroup, - const char *name, - const struct GPUTexture *tex); -void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, - const char *name, - const struct GPUUniformBuffer *ubo); -void DRW_shgroup_uniform_block_persistent(DRWShadingGroup *shgroup, - const char *name, - const struct GPUUniformBuffer *ubo); void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup, const char *name, struct GPUTexture **tex); +void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, + const char *name, + const struct GPUUniformBuffer *ubo); +void DRW_shgroup_uniform_block_ref(DRWShadingGroup *shgroup, + const char *name, + struct GPUUniformBuffer **ubo); void DRW_shgroup_uniform_float(DRWShadingGroup *shgroup, const char *name, const float *value, @@ -541,6 +539,8 @@ bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup); /* Passes */ DRWPass *DRW_pass_create(const char *name, DRWState state); +DRWPass *DRW_pass_create_instance(const char *name, DRWPass *original, DRWState state); +void DRW_pass_link(DRWPass *first, DRWPass *second); /* TODO Replace with passes inheritance. */ void DRW_pass_state_set(DRWPass *pass, DRWState state); void DRW_pass_state_add(DRWPass *pass, DRWState state); @@ -554,6 +554,8 @@ void DRW_pass_sort_shgroup_reverse(DRWPass *pass); bool DRW_pass_is_empty(DRWPass *pass); #define DRW_PASS_CREATE(pass, state) (pass = DRW_pass_create(#pass, state)) +#define DRW_PASS_INSTANCE_CREATE(pass, original, state) \ + (pass = DRW_pass_create_instance(#pass, (original), state)) /* Views */ DRWView *DRW_view_create(const float viewmat[4][4], @@ -707,6 +709,8 @@ typedef struct DRWContextState { struct Depsgraph *depsgraph; + struct TaskGraph *task_graph; + eObjectMode object_mode; eGPUShaderConfig sh_cfg; diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 23d0d74534d..c23ea3d7c82 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -3534,13 +3534,15 @@ void drw_batch_cache_generate_requested(Object *ob) struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); switch (ob->type) { case OB_MESH: - DRW_mesh_batch_cache_create_requested(ob, (Mesh *)ob->data, scene, is_paint_mode, use_hide); + DRW_mesh_batch_cache_create_requested( + DST.task_graph, ob, (Mesh *)ob->data, scene, is_paint_mode, use_hide); break; case OB_CURVE: case OB_FONT: case OB_SURF: if (mesh_eval) { - DRW_mesh_batch_cache_create_requested(ob, mesh_eval, scene, is_paint_mode, use_hide); + DRW_mesh_batch_cache_create_requested( + DST.task_graph, ob, mesh_eval, scene, is_paint_mode, use_hide); } DRW_curve_batch_cache_create_requested(ob); break; diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h index b2fea957227..f203c2ff1ea 100644 --- a/source/blender/draw/intern/draw_cache_extract.h +++ b/source/blender/draw/intern/draw_cache_extract.h @@ -23,6 +23,8 @@ #ifndef __DRAW_CACHE_EXTRACT_H__ #define __DRAW_CACHE_EXTRACT_H__ +struct TaskGraph; + /* Vertex Group Selection and display options */ typedef struct DRW_MeshWeightState { int defgroup_active; @@ -249,7 +251,8 @@ typedef struct MeshBatchCache { bool no_loose_wire; } MeshBatchCache; -void mesh_buffer_cache_create_requested(MeshBatchCache *cache, +void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, + MeshBatchCache *cache, MeshBufferCache mbc, Mesh *me, const bool is_editmode, diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh.c index cbb5f5f06ff..0fd6bf54856 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh.c +++ b/source/blender/draw/intern/draw_cache_extract_mesh.c @@ -134,15 +134,12 @@ typedef struct MeshRenderData { float (*poly_normals)[3]; int *lverts, *ledges; } MeshRenderData; - static MeshRenderData *mesh_render_data_create(Mesh *me, const bool is_editmode, const bool is_paint_mode, const float obmat[4][4], const bool do_final, const bool do_uvedit, - const eMRIterType iter_type, - const eMRDataType data_flag, const DRW_MeshCDMask *UNUSED(cd_used), const ToolSettings *ts) { @@ -152,9 +149,6 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, copy_m4_m4(mr->obmat, obmat); - const bool is_auto_smooth = (me->flag & ME_AUTOSMOOTH) != 0; - const float split_angle = is_auto_smooth ? me->smoothresh : (float)M_PI; - if (is_editmode) { BLI_assert(me->edit_mesh->mesh_eval_cage && me->edit_mesh->mesh_eval_final); mr->bm = me->edit_mesh->bm; @@ -244,7 +238,32 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX); mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX); mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX); + } + else { + /* BMesh */ + BMesh *bm = mr->bm; + + mr->vert_len = bm->totvert; + mr->edge_len = bm->totedge; + mr->loop_len = bm->totloop; + mr->poly_len = bm->totface; + mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len); + } + return mr; +} + +/* Part of the creation of the MeshRenderData that happens in a thread. */ +static void mesh_render_data_update(MeshRenderData *mr, + const eMRIterType iter_type, + const eMRDataType data_flag) +{ + Mesh *me = mr->me; + const bool is_auto_smooth = (me->flag & ME_AUTOSMOOTH) != 0; + const float split_angle = is_auto_smooth ? me->smoothresh : (float)M_PI; + + if (mr->extract_type != MR_EXTRACT_BMESH) { + /* Mesh */ if (data_flag & (MR_DATA_POLY_NOR | MR_DATA_LOOP_NOR | MR_DATA_TAN_LOOP_NOR)) { mr->poly_normals = MEM_mallocN(sizeof(*mr->poly_normals) * mr->poly_len, __func__); BKE_mesh_calc_normals_poly((MVert *)mr->mvert, @@ -323,13 +342,6 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, else { /* BMesh */ BMesh *bm = mr->bm; - - mr->vert_len = bm->totvert; - mr->edge_len = bm->totedge; - mr->loop_len = bm->totloop; - mr->poly_len = bm->totface; - mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len); - if (data_flag & MR_DATA_POLY_NOR) { /* Use bmface->no instead. */ } @@ -394,7 +406,6 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, mr->loop_loose_len = mr->vert_loose_len + mr->edge_loose_len * 2; } } - return mr; } static void mesh_render_data_free(MeshRenderData *mr) @@ -742,46 +753,15 @@ static const MeshExtract extract_lines = { 0, false, }; - /** \} */ /* ---------------------------------------------------------------------- */ -/** \name Extract Loose Edges Indices +/** \name Extract Loose Edges Sub Buffer * \{ */ -static void *extract_lines_loose_init(const MeshRenderData *UNUSED(mr), void *UNUSED(buf)) -{ - return NULL; -} - -static void extract_lines_loose_ledge_mesh(const MeshRenderData *UNUSED(mr), - int UNUSED(e), - const MEdge *UNUSED(medge), - void *UNUSED(elb)) -{ - /* This function is intentionally empty. The existence of this functions ensures that - * `iter_type` `MR_ITER_LVERT` is set when initializing the `MeshRenderData` (See - * `mesh_extract_iter_type`). This flag ensures that `mr->edge_loose_len` field is filled. This - * field we use in the `extract_lines_loose_finish` function to create a subrange from the - * `ibo.lines`. */ -} - -static void extract_lines_loose_ledge_bmesh(const MeshRenderData *UNUSED(mr), - int UNUSED(e), - BMEdge *UNUSED(eed), - void *UNUSED(elb)) -{ - /* This function is intentionally empty. The existence of this functions ensures that - * `iter_type` `MR_ITER_LVERT` is set when initializing the `MeshRenderData` (See - * `mesh_extract_iter_type`). This flag ensures that `mr->edge_loose_len` field is filled. This - * field we use in the `extract_lines_loose_finish` function to create a subrange from the - * `ibo.lines`. */ -} - -static void extract_lines_loose_finish(const MeshRenderData *mr, - void *UNUSED(ibo), - void *UNUSED(elb)) +static void extract_lines_loose_subbuffer(const MeshRenderData *mr) { + BLI_assert(mr->cache->final.ibo.lines); /* Multiply by 2 because these are edges indices. */ const int start = mr->edge_len * 2; const int len = mr->edge_loose_len * 2; @@ -790,17 +770,24 @@ static void extract_lines_loose_finish(const MeshRenderData *mr, mr->cache->no_loose_wire = (len == 0); } -static const MeshExtract extract_lines_loose = { - extract_lines_loose_init, - NULL, - NULL, +static void extract_lines_with_lines_loose_finish(const MeshRenderData *mr, void *ibo, void *elb) +{ + GPU_indexbuf_build_in_place(elb, ibo); + extract_lines_loose_subbuffer(mr); + MEM_freeN(elb); +} + +static const MeshExtract extract_lines_with_lines_loose = { + extract_lines_init, NULL, NULL, - extract_lines_loose_ledge_bmesh, - extract_lines_loose_ledge_mesh, + extract_lines_loop_bmesh, + extract_lines_loop_mesh, + extract_lines_ledge_bmesh, + extract_lines_ledge_mesh, NULL, NULL, - extract_lines_loose_finish, + extract_lines_with_lines_loose_finish, 0, false, }; @@ -1716,8 +1703,8 @@ static void extract_lnor_hq_loop_mesh( } /* Flag for paint mode overlay. - * Only use MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals. In paint - * mode it will use the unmapped data to draw the wireframe. */ + * Only use MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals. In + * paint mode it will use the unmapped data to draw the wireframe. */ if (mpoly->flag & ME_HIDE || (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) && mr->v_origindex[mloop->v] == ORIGINDEX_NONE)) { @@ -1795,8 +1782,8 @@ static void extract_lnor_loop_mesh( } /* Flag for paint mode overlay. - * Only use MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals. In paint - * mode it will use the unmapped data to draw the wireframe. */ + * Only use MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals. In + * paint mode it will use the unmapped data to draw the wireframe. */ if (mpoly->flag & ME_HIDE || (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) && mr->v_origindex[mloop->v] == ORIGINDEX_NONE)) { @@ -2162,10 +2149,10 @@ static void *extract_vcol_init(const MeshRenderData *mr, void *buf) GPUVertFormat format = {0}; GPU_vertformat_deinterleave(&format); - CustomData *cd_ldata = &mr->me->ldata; + CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; uint32_t vcol_layers = mr->cache->cd_used.vcol; - for (int i = 0; i < 8; i++) { + for (int i = 0; i < MAX_MCOL; i++) { if (vcol_layers & (1 << i)) { char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPCOL, i); @@ -2197,14 +2184,32 @@ static void *extract_vcol_init(const MeshRenderData *mr, void *buf) } gpuMeshVcol; gpuMeshVcol *vcol_data = (gpuMeshVcol *)vbo->data; - for (int i = 0; i < 8; i++) { + for (int i = 0; i < MAX_MCOL; i++) { if (vcol_layers & (1 << i)) { - MLoopCol *mcol = (MLoopCol *)CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i); - for (int l = 0; l < mr->loop_len; l++, mcol++, vcol_data++) { - vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->r]); - vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->g]); - vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->b]); - vcol_data->a = unit_float_to_ushort_clamp(mcol->a * (1.0f / 255.0f)); + if (mr->extract_type == MR_EXTRACT_BMESH) { + int cd_ofs = CustomData_get_n_offset(cd_ldata, CD_MLOOPCOL, i); + BMIter f_iter, l_iter; + BMFace *efa; + BMLoop *loop; + BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (loop, &l_iter, efa, BM_LOOPS_OF_FACE) { + const MLoopCol *mloopcol = BM_ELEM_CD_GET_VOID_P(loop, cd_ofs); + vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]); + vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]); + vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]); + vcol_data->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f)); + vcol_data++; + } + } + } + else { + const MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i); + for (int l = 0; l < mr->loop_len; l++, mloopcol++, vcol_data++) { + vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]); + vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]); + vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]); + vcol_data->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f)); + } } } } @@ -4522,10 +4527,14 @@ static const MeshExtract extract_fdot_idx = { /** \} */ /* ---------------------------------------------------------------------- */ -/** \name Extract Loop +/** \name ExtractTaskData * \{ */ +typedef struct ExtractUserData { + void *user_data; +} ExtractUserData; typedef struct ExtractTaskData { + void *next, *prev; const MeshRenderData *mr; const MeshExtract *extract; eMRIterType iter_type; @@ -4533,9 +4542,16 @@ typedef struct ExtractTaskData { /** Decremented each time a task is finished. */ int32_t *task_counter; void *buf; - void *user_data; + ExtractUserData *user_data; } ExtractTaskData; +static void extract_task_data_free(void *data) +{ + ExtractTaskData *task_data = data; + MEM_SAFE_FREE(task_data->user_data); + MEM_freeN(task_data); +} + BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr, const eMRIterType iter_type, int start, @@ -4612,31 +4628,184 @@ BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr, } } -static void extract_run(TaskPool *__restrict UNUSED(pool), void *taskdata) +static void extract_init(ExtractTaskData *data) { - ExtractTaskData *data = taskdata; - mesh_extract_iter( - data->mr, data->iter_type, data->start, data->end, data->extract, data->user_data); + data->user_data->user_data = data->extract->init(data->mr, data->buf); +} + +static void extract_run(void *__restrict taskdata) +{ + ExtractTaskData *data = (ExtractTaskData *)taskdata; + mesh_extract_iter(data->mr, + data->iter_type, + data->start, + data->end, + data->extract, + data->user_data->user_data); /* If this is the last task, we do the finish function. */ int remainin_tasks = atomic_sub_and_fetch_int32(data->task_counter, 1); if (remainin_tasks == 0 && data->extract->finish != NULL) { - data->extract->finish(data->mr, data->buf, data->user_data); + data->extract->finish(data->mr, data->buf, data->user_data->user_data); + } +} + +static void extract_init_and_run(void *__restrict taskdata) +{ + extract_init((ExtractTaskData *)taskdata); + extract_run(taskdata); +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Task Node - Update Mesh Render Data + * \{ */ +typedef struct MeshRenderDataUpdateTaskData { + MeshRenderData *mr; + eMRIterType iter_type; + eMRDataType data_flag; +} MeshRenderDataUpdateTaskData; + +static void mesh_render_data_update_task_data_free(MeshRenderDataUpdateTaskData *taskdata) +{ + BLI_assert(taskdata); + mesh_render_data_free(taskdata->mr); + MEM_freeN(taskdata); +} + +static void mesh_extract_render_data_node_exec(void *__restrict task_data) +{ + MeshRenderDataUpdateTaskData *update_task_data = task_data; + mesh_render_data_update( + update_task_data->mr, update_task_data->iter_type, update_task_data->data_flag); +} + +static struct TaskNode *mesh_extract_render_data_node_create(struct TaskGraph *task_graph, + MeshRenderData *mr, + const eMRIterType iter_type, + const eMRDataType data_flag) +{ + MeshRenderDataUpdateTaskData *task_data = MEM_mallocN(sizeof(MeshRenderDataUpdateTaskData), + __func__); + task_data->mr = mr; + task_data->iter_type = iter_type; + task_data->data_flag = data_flag; + + struct TaskNode *task_node = BLI_task_graph_node_create( + task_graph, + mesh_extract_render_data_node_exec, + task_data, + (TaskGraphNodeFreeFunction)mesh_render_data_update_task_data_free); + return task_node; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Task Node - Extract Single Threaded + * \{ */ +typedef struct ExtractSingleThreadedTaskData { + ListBase task_datas; +} ExtractSingleThreadedTaskData; + +static void extract_single_threaded_task_data_free(ExtractSingleThreadedTaskData *taskdata) +{ + BLI_assert(taskdata); + LISTBASE_FOREACH_MUTABLE (ExtractTaskData *, td, &taskdata->task_datas) { + extract_task_data_free(td); + } + BLI_listbase_clear(&taskdata->task_datas); + MEM_freeN(taskdata); +} + +static void extract_single_threaded_task_node_exec(void *__restrict task_data) +{ + ExtractSingleThreadedTaskData *extract_task_data = task_data; + LISTBASE_FOREACH (ExtractTaskData *, td, &extract_task_data->task_datas) { + extract_init_and_run(td); + } +} + +static struct TaskNode *extract_single_threaded_task_node_create( + struct TaskGraph *task_graph, ExtractSingleThreadedTaskData *task_data) +{ + struct TaskNode *task_node = BLI_task_graph_node_create( + task_graph, + extract_single_threaded_task_node_exec, + task_data, + (TaskGraphNodeFreeFunction)extract_single_threaded_task_data_free); + return task_node; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Task Node - UserData Initializer + * \{ */ +typedef struct UserDataInitTaskData { + ListBase task_datas; + int32_t *task_counters; + +} UserDataInitTaskData; + +static void user_data_init_task_data_free(UserDataInitTaskData *taskdata) +{ + BLI_assert(taskdata); + LISTBASE_FOREACH_MUTABLE (ExtractTaskData *, td, &taskdata->task_datas) { + extract_task_data_free(td); + } + BLI_listbase_clear(&taskdata->task_datas); + MEM_SAFE_FREE(taskdata->task_counters); + MEM_freeN(taskdata); +} + +static void user_data_init_task_data_exec(void *__restrict task_data) +{ + UserDataInitTaskData *extract_task_data = task_data; + LISTBASE_FOREACH (ExtractTaskData *, td, &extract_task_data->task_datas) { + extract_init(td); } } -static void extract_range_task_create( - TaskPool *task_pool, ExtractTaskData *taskdata, const eMRIterType type, int start, int length) +static struct TaskNode *user_data_init_task_node_create(struct TaskGraph *task_graph, + UserDataInitTaskData *task_data) +{ + struct TaskNode *task_node = BLI_task_graph_node_create( + task_graph, + user_data_init_task_data_exec, + task_data, + (TaskGraphNodeFreeFunction)user_data_init_task_data_free); + return task_node; +} + +/** \} */ +/* ---------------------------------------------------------------------- */ +/** \name Extract Loop + * \{ */ + +static void extract_range_task_create(struct TaskGraph *task_graph, + struct TaskNode *task_node_user_data_init, + ExtractTaskData *taskdata, + const eMRIterType type, + int start, + int length) { taskdata = MEM_dupallocN(taskdata); atomic_add_and_fetch_int32(taskdata->task_counter, 1); taskdata->iter_type = type; taskdata->start = start; taskdata->end = start + length; - BLI_task_pool_push(task_pool, extract_run, taskdata, true, NULL); + struct TaskNode *task_node = BLI_task_graph_node_create( + task_graph, extract_run, taskdata, MEM_freeN); + BLI_task_graph_edge_create(task_node_user_data_init, task_node); } -static void extract_task_create(TaskPool *task_pool, +static void extract_task_create(struct TaskGraph *task_graph, + struct TaskNode *task_node_mesh_render_data, + struct TaskNode *task_node_user_data_init, + ListBase *single_threaded_task_datas, + ListBase *user_data_init_task_datas, const Scene *scene, const MeshRenderData *mr, const MeshExtract *extract, @@ -4654,58 +4823,75 @@ static void extract_task_create(TaskPool *task_pool, /* Divide extraction of the VBO/IBO into sensible chunks of works. */ ExtractTaskData *taskdata = MEM_mallocN(sizeof(*taskdata), "ExtractTaskData"); + taskdata->next = NULL; + taskdata->prev = NULL; taskdata->mr = mr; taskdata->extract = extract; taskdata->buf = buf; - taskdata->user_data = extract->init(mr, buf); + + /* ExtractUserData is shared between the iterations as it holds counters to detect if the + * extraction is finished. To make sure the duplication of the userdata does not create a new + * instance of the counters we allocate the userdata in its own container. + * + * This structure makes sure that when extract_init is called, that the user data of all + * iterations are updated. */ + taskdata->user_data = MEM_callocN(sizeof(ExtractUserData), __func__); taskdata->iter_type = mesh_extract_iter_type(extract); taskdata->task_counter = task_counter; taskdata->start = 0; taskdata->end = INT_MAX; /* Simple heuristic. */ - const bool use_thread = (mr->loop_len + mr->loop_loose_len) > 8192; + const int chunk_size = 8192; + const bool use_thread = (mr->loop_len + mr->loop_loose_len) > chunk_size; if (use_thread && extract->use_threading) { + /* Divide task into sensible chunks. */ - const int chunk_size = 8192; if (taskdata->iter_type & MR_ITER_LOOPTRI) { for (int i = 0; i < mr->tri_len; i += chunk_size) { - extract_range_task_create(task_pool, taskdata, MR_ITER_LOOPTRI, i, chunk_size); + extract_range_task_create( + task_graph, task_node_user_data_init, taskdata, MR_ITER_LOOPTRI, i, chunk_size); } } if (taskdata->iter_type & MR_ITER_LOOP) { for (int i = 0; i < mr->poly_len; i += chunk_size) { - extract_range_task_create(task_pool, taskdata, MR_ITER_LOOP, i, chunk_size); + extract_range_task_create( + task_graph, task_node_user_data_init, taskdata, MR_ITER_LOOP, i, chunk_size); } } if (taskdata->iter_type & MR_ITER_LEDGE) { for (int i = 0; i < mr->edge_loose_len; i += chunk_size) { - extract_range_task_create(task_pool, taskdata, MR_ITER_LEDGE, i, chunk_size); + extract_range_task_create( + task_graph, task_node_user_data_init, taskdata, MR_ITER_LEDGE, i, chunk_size); } } if (taskdata->iter_type & MR_ITER_LVERT) { for (int i = 0; i < mr->vert_loose_len; i += chunk_size) { - extract_range_task_create(task_pool, taskdata, MR_ITER_LVERT, i, chunk_size); + extract_range_task_create( + task_graph, task_node_user_data_init, taskdata, MR_ITER_LVERT, i, chunk_size); } } - MEM_freeN(taskdata); + BLI_addtail(user_data_init_task_datas, taskdata); } else if (use_thread) { /* One task for the whole VBO. */ (*task_counter)++; - BLI_task_pool_push(task_pool, extract_run, taskdata, true, NULL); + struct TaskNode *one_task = BLI_task_graph_node_create( + task_graph, extract_init_and_run, taskdata, extract_task_data_free); + BLI_task_graph_edge_create(task_node_mesh_render_data, one_task); } else { /* Single threaded extraction. */ (*task_counter)++; - extract_run(NULL, taskdata); - MEM_freeN(taskdata); + BLI_addtail(single_threaded_task_datas, taskdata); } } -void mesh_buffer_cache_create_requested(MeshBatchCache *cache, +void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, + MeshBatchCache *cache, MeshBufferCache mbc, Mesh *me, + const bool is_editmode, const bool is_paint_mode, const float obmat[4][4], @@ -4717,9 +4903,41 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache, const ToolSettings *ts, const bool use_hide) { + /* For each mesh where batches needs to be updated a sub-graph will be added to the task_graph. + * This sub-graph starts with an extract_render_data_node. This fills/converts the required data + * from Mesh. + * + * Small extractions and extractions that can't be multi-threaded are grouped in a single + * `extract_single_threaded_task_node`. + * + * Other extractions will create a node for each loop exceeding 8192 items. these nodes are + * linked to the `user_data_init_task_node`. the `user_data_init_task_node` prepares the userdata + * needed for the extraction based on the data extracted from the mesh. counters are used to + * check if the finalize of a task has to be called. + * + * Mesh extraction sub graph + * + * +----------------------+ + * +-----> | extract_task1_loop_1 | + * | +----------------------+ + * +------------------+ +----------------------+ +----------------------+ + * | mesh_render_data | --> | | --> | extract_task1_loop_2 | + * +------------------+ | | +----------------------+ + * | | | +----------------------+ + * | | user_data_init | --> | extract_task2_loop_1 | + * v | | +----------------------+ + * +------------------+ | | +----------------------+ + * | single_threaded | | | --> | extract_task2_loop_2 | + * +------------------+ +----------------------+ +----------------------+ + * | +----------------------+ + * +-----> | extract_task2_loop_3 | + * +----------------------+ + */ eMRIterType iter_flag = 0; eMRDataType data_flag = 0; + const bool do_lines_loose_subbuffer = mbc.ibo.lines_loose != NULL; + #define TEST_ASSIGN(type, type_lowercase, name) \ do { \ if (DRW_TEST_ASSIGN_##type(mbc.type_lowercase.name)) { \ @@ -4757,7 +4975,6 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache, TEST_ASSIGN(IBO, ibo, fdots); TEST_ASSIGN(IBO, ibo, lines_paint_mask); TEST_ASSIGN(IBO, ibo, lines_adjacency); - TEST_ASSIGN(IBO, ibo, lines_loose); TEST_ASSIGN(IBO, ibo, edituv_tris); TEST_ASSIGN(IBO, ibo, edituv_lines); TEST_ASSIGN(IBO, ibo, edituv_points); @@ -4769,16 +4986,8 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache, double rdata_start = PIL_check_seconds_timer(); #endif - MeshRenderData *mr = mesh_render_data_create(me, - is_editmode, - is_paint_mode, - obmat, - do_final, - do_uvedit, - iter_flag, - data_flag, - cd_layer_used, - ts); + MeshRenderData *mr = mesh_render_data_create( + me, is_editmode, is_paint_mode, obmat, do_final, do_uvedit, cd_layer_used, ts); mr->cache = cache; /* HACK */ mr->use_hide = use_hide; mr->use_subsurf_fdots = use_subsurf_fdots; @@ -4788,20 +4997,32 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache, double rdata_end = PIL_check_seconds_timer(); #endif - TaskPool *task_pool; - - /* Create a suspended pool as the finalize method could be called too early. - * See `extract_run`. */ - task_pool = BLI_task_pool_create_suspended(NULL, TASK_PRIORITY_HIGH); - size_t counters_size = (sizeof(mbc) / sizeof(void *)) * sizeof(int32_t); int32_t *task_counters = MEM_callocN(counters_size, __func__); int counter_used = 0; + struct TaskNode *task_node_mesh_render_data = mesh_extract_render_data_node_create( + task_graph, mr, iter_flag, data_flag); + ExtractSingleThreadedTaskData *single_threaded_task_data = MEM_callocN( + sizeof(ExtractSingleThreadedTaskData), __func__); + UserDataInitTaskData *user_data_init_task_data = MEM_callocN(sizeof(UserDataInitTaskData), + __func__); + user_data_init_task_data->task_counters = task_counters; + struct TaskNode *task_node_user_data_init = user_data_init_task_node_create( + task_graph, user_data_init_task_data); + #define EXTRACT(buf, name) \ if (mbc.buf.name) { \ - extract_task_create( \ - task_pool, scene, mr, &extract_##name, mbc.buf.name, &task_counters[counter_used++]); \ + extract_task_create(task_graph, \ + task_node_mesh_render_data, \ + task_node_user_data_init, \ + &single_threaded_task_data->task_datas, \ + &user_data_init_task_data->task_datas, \ + scene, \ + mr, \ + &extract_##name, \ + mbc.buf.name, \ + &task_counters[counter_used++]); \ } \ ((void)0) @@ -4829,7 +5050,33 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache, EXTRACT(vbo, skin_roots); EXTRACT(ibo, tris); - EXTRACT(ibo, lines); + if (mbc.ibo.lines) { + /* When `lines` and `lines_loose` are requested, schedule lines extraction that also creates + * the `lines_loose` sub-buffer. */ + const MeshExtract *lines_extractor = do_lines_loose_subbuffer ? + &extract_lines_with_lines_loose : + &extract_lines; + extract_task_create(task_graph, + task_node_mesh_render_data, + task_node_user_data_init, + &single_threaded_task_data->task_datas, + &user_data_init_task_data->task_datas, + scene, + mr, + lines_extractor, + mbc.ibo.lines, + &task_counters[counter_used++]); + } + else { + if (do_lines_loose_subbuffer) { + /* When `lines_loose` is requested without `lines` we can create the sub-buffer on the fly as + * the `lines` buffer should then already be up-to-date. + * (see `DRW_batch_requested(cache->batch.loose_edges, GPU_PRIM_LINES)` in + * `DRW_mesh_batch_cache_create_requested`). + */ + extract_lines_loose_subbuffer(mr); + } + } EXTRACT(ibo, points); EXTRACT(ibo, fdots); EXTRACT(ibo, lines_paint_mask); @@ -4839,27 +5086,29 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache, EXTRACT(ibo, edituv_points); EXTRACT(ibo, edituv_fdots); - /* TODO(fclem) Ideally, we should have one global pool for all - * objects and wait for finish only before drawing when buffers - * need to be ready. */ - BLI_task_pool_work_and_wait(task_pool); - - /* The next task(s) rely on the result of the tasks above. */ + /* Only create the edge when there are user datas that needs to be inited. + * The task is still part of the graph so the task_data will be freed when the graph is freed. + */ + if (!BLI_listbase_is_empty(&user_data_init_task_data->task_datas)) { + BLI_task_graph_edge_create(task_node_mesh_render_data, task_node_user_data_init); + } - /* The `lines_loose` is a sub buffer from `ibo.lines`. - * We schedule it here due to potential synchronization issues.*/ - EXTRACT(ibo, lines_loose); + if (!BLI_listbase_is_empty(&single_threaded_task_data->task_datas)) { + struct TaskNode *task_node = extract_single_threaded_task_node_create( + task_graph, single_threaded_task_data); + BLI_task_graph_edge_create(task_node_mesh_render_data, task_node); + } + else { + extract_single_threaded_task_data_free(single_threaded_task_data); + } - BLI_task_pool_work_and_wait(task_pool); + /* Trigger the sub-graph for this mesh. */ + BLI_task_graph_node_push_work(task_node_mesh_render_data); #undef EXTRACT - BLI_task_pool_free(task_pool); - MEM_freeN(task_counters); - - mesh_render_data_free(mr); - #ifdef DEBUG_TIME + BLI_task_graph_work_and_wait(task_graph); double end = PIL_check_seconds_timer(); static double avg = 0; diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index daa46252331..80649143537 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -31,6 +31,7 @@ struct ListBase; struct ModifierData; struct PTCacheEdit; struct ParticleSystem; +struct TaskGraph; struct Curve; struct Hair; @@ -150,7 +151,8 @@ int DRW_volume_material_count_get(struct Volume *volume); struct GPUBatch *DRW_volume_batch_cache_get_wireframes_face(struct Volume *volume); /* Mesh */ -void DRW_mesh_batch_cache_create_requested(struct Object *ob, +void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, + struct Object *ob, struct Mesh *me, const struct Scene *scene, const bool is_paint_mode, diff --git a/source/blender/draw/intern/draw_cache_impl_gpencil.c b/source/blender/draw/intern/draw_cache_impl_gpencil.c index ee148e0934d..b4974330043 100644 --- a/source/blender/draw/intern/draw_cache_impl_gpencil.c +++ b/source/blender/draw/intern/draw_cache_impl_gpencil.c @@ -102,6 +102,7 @@ static GpencilBatchCache *gpencil_batch_cache_init(Object *ob, int cfra) cache->is_dirty = true; cache->cache_frame = cfra; + return cache; } @@ -385,7 +386,8 @@ static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfr .vert_len = 1, /* Start at 1 for the gl_InstanceID trick to work (see vert shader). */ .tri_len = 0, }; - BKE_gpencil_visible_stroke_iter(ob, NULL, gp_object_verts_count_cb, &iter, do_onion, cfra); + BKE_gpencil_visible_stroke_iter( + NULL, ob, NULL, gp_object_verts_count_cb, &iter, do_onion, cfra); /* Create VBOs. */ GPUVertFormat *format = gpencil_stroke_format(); @@ -401,7 +403,7 @@ static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfr GPU_indexbuf_init(&iter.ibo, GPU_PRIM_TRIS, iter.tri_len, iter.vert_len); /* Fill buffers with data. */ - BKE_gpencil_visible_stroke_iter(ob, NULL, gpencil_stroke_iter_cb, &iter, do_onion, cfra); + BKE_gpencil_visible_stroke_iter(NULL, ob, NULL, gpencil_stroke_iter_cb, &iter, do_onion, cfra); /* Mark last 2 verts as invalid. */ for (int i = 0; i < 2; i++) { @@ -475,7 +477,7 @@ GPUBatch *DRW_cache_gpencil_face_wireframe_get(Object *ob) /* IMPORTANT: Keep in sync with gpencil_edit_batches_ensure() */ bool do_onion = true; - BKE_gpencil_visible_stroke_iter(ob, NULL, gp_lines_indices_cb, &iter, do_onion, cfra); + BKE_gpencil_visible_stroke_iter(NULL, ob, NULL, gp_lines_indices_cb, &iter, do_onion, cfra); GPUIndexBuf *ibo = GPU_indexbuf_build(&iter.ibo); @@ -724,7 +726,8 @@ static void gpencil_edit_batches_ensure(Object *ob, GpencilBatchCache *cache, in iter.verts = (gpEditVert *)cache->edit_vbo->data; /* Fill buffers with data. */ - BKE_gpencil_visible_stroke_iter(ob, NULL, gpencil_edit_stroke_iter_cb, &iter, do_onion, cfra); + BKE_gpencil_visible_stroke_iter( + NULL, ob, NULL, gpencil_edit_stroke_iter_cb, &iter, do_onion, cfra); /* Create the batches */ cache->edit_points_batch = GPU_batch_create(GPU_PRIM_POINTS, cache->vbo, NULL); diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index 237c7bddfad..99e285a18f1 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -33,6 +33,7 @@ #include "BLI_math_bits.h" #include "BLI_math_vector.h" #include "BLI_string.h" +#include "BLI_task.h" #include "BLI_utildefines.h" #include "DNA_mesh_types.h" @@ -1019,9 +1020,14 @@ void DRW_mesh_batch_cache_free_old(Mesh *me, int ctime) } /* Can be called for any surface type. Mesh *me is the final mesh. */ -void DRW_mesh_batch_cache_create_requested( - Object *ob, Mesh *me, const Scene *scene, const bool is_paint_mode, const bool use_hide) -{ +void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, + Object *ob, + Mesh *me, + const Scene *scene, + const bool is_paint_mode, + const bool use_hide) +{ + BLI_assert(task_graph); GPUIndexBuf **saved_elem_ranges = NULL; const ToolSettings *ts = NULL; if (scene) { @@ -1378,7 +1384,8 @@ void DRW_mesh_batch_cache_create_requested( false; if (do_uvcage) { - mesh_buffer_cache_create_requested(cache, + mesh_buffer_cache_create_requested(task_graph, + cache, cache->uv_cage, me, is_editmode, @@ -1394,7 +1401,8 @@ void DRW_mesh_batch_cache_create_requested( } if (do_cage) { - mesh_buffer_cache_create_requested(cache, + mesh_buffer_cache_create_requested(task_graph, + cache, cache->cage, me, is_editmode, @@ -1409,7 +1417,8 @@ void DRW_mesh_batch_cache_create_requested( true); } - mesh_buffer_cache_create_requested(cache, + mesh_buffer_cache_create_requested(task_graph, + cache, cache->final, me, is_editmode, @@ -1422,10 +1431,12 @@ void DRW_mesh_batch_cache_create_requested( scene, ts, use_hide); - #ifdef DEBUG check: /* Make sure all requested batches have been setup. */ + /* TODO(jbakker): we should move this to the draw_manager but that needs refactoring and + * additional looping.*/ + BLI_task_graph_work_and_wait(task_graph); for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); i++) { BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], 0)); } diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h index f14cdc0dbde..656d72b2808 100644 --- a/source/blender/draw/intern/draw_common.h +++ b/source/blender/draw/intern/draw_common.h @@ -172,23 +172,11 @@ bool DRW_object_axis_orthogonal_to_view(Object *ob, int axis); /* This creates a shading group with display hairs. * The draw call is already added by this function, just add additional uniforms. */ -struct DRWShadingGroup *DRW_shgroup_hair_create(struct Object *object, - struct ParticleSystem *psys, - struct ModifierData *md, - struct DRWPass *hair_pass, - struct GPUShader *shader); - struct DRWShadingGroup *DRW_shgroup_hair_create_sub(struct Object *object, struct ParticleSystem *psys, struct ModifierData *md, struct DRWShadingGroup *shgrp); -struct DRWShadingGroup *DRW_shgroup_material_hair_create(struct Object *object, - struct ParticleSystem *psys, - struct ModifierData *md, - struct DRWPass *hair_pass, - struct GPUMaterial *material); - void DRW_hair_init(void); void DRW_hair_update(void); void DRW_hair_free(void); diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c index 27de7cc1c7c..2fdaf0d5345 100644 --- a/source/blender/draw/intern/draw_hair.c +++ b/source/blender/draw/intern/draw_hair.c @@ -124,13 +124,10 @@ void DRW_hair_init(void) } } -static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object, - ParticleSystem *psys, - ModifierData *md, - DRWPass *hair_pass, - DRWShadingGroup *shgrp_parent, - struct GPUMaterial *gpu_mat, - GPUShader *gpu_shader) +DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, + ParticleSystem *psys, + ModifierData *md, + DRWShadingGroup *shgrp_parent) { /* TODO(fclem): Pass the scene as parameter */ const DRWContextState *draw_ctx = DRW_context_state_get(); @@ -154,24 +151,7 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object, need_ft_update = hair_ensure_procedural_data(object, &hair_cache, subdiv, thickness_res); } - DRWShadingGroup *shgrp; - if (shgrp_parent) { - shgrp = DRW_shgroup_create_sub(shgrp_parent); - } - else if (gpu_mat) { - shgrp = DRW_shgroup_material_create(gpu_mat, hair_pass); - } - else if (gpu_shader) { - shgrp = DRW_shgroup_create(gpu_shader, hair_pass); - } - else { - shgrp = NULL; - BLI_assert(0); - } - - if (shgrp == NULL) { - return NULL; - } + DRWShadingGroup *shgrp = DRW_shgroup_create_sub(shgrp_parent); /* TODO optimize this. Only bind the ones GPUMaterial needs. */ for (int i = 0; i < hair_cache->num_uv_layers; i++) { @@ -284,29 +264,6 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object, return shgrp; } -DRWShadingGroup *DRW_shgroup_hair_create( - Object *object, ParticleSystem *psys, ModifierData *md, DRWPass *hair_pass, GPUShader *shader) -{ - return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, NULL, NULL, shader); -} - -DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, - ParticleSystem *psys, - ModifierData *md, - DRWShadingGroup *shgrp) -{ - return drw_shgroup_create_hair_procedural_ex(object, psys, md, NULL, shgrp, NULL, NULL); -} - -DRWShadingGroup *DRW_shgroup_material_hair_create(Object *object, - ParticleSystem *psys, - ModifierData *md, - DRWPass *hair_pass, - struct GPUMaterial *material) -{ - return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, NULL, material, NULL); -} - void DRW_hair_update(void) { #ifndef USE_TRANSFORM_FEEDBACK diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index bdef6d50db8..08c6a0e8da8 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -27,6 +27,7 @@ #include "BLI_memblock.h" #include "BLI_rect.h" #include "BLI_string.h" +#include "BLI_task.h" #include "BLI_threads.h" #include "BLF_api.h" @@ -115,17 +116,6 @@ static ListBase DRW_engines = {NULL, NULL}; static void drw_state_prepare_clean_for_draw(DRWManager *dst) { memset(dst, 0x0, offsetof(DRWManager, gl_context)); - - /* Maybe not the best place for this. */ - if (!DST.uniform_names.buffer) { - DST.uniform_names.buffer = MEM_callocN(DRW_UNIFORM_BUFFER_NAME, "Name Buffer"); - DST.uniform_names.buffer_len = DRW_UNIFORM_BUFFER_NAME; - } - else if (DST.uniform_names.buffer_len > DRW_UNIFORM_BUFFER_NAME) { - DST.uniform_names.buffer = MEM_reallocN(DST.uniform_names.buffer, DRW_UNIFORM_BUFFER_NAME); - DST.uniform_names.buffer_len = DRW_UNIFORM_BUFFER_NAME; - } - DST.uniform_names.buffer_ofs = 0; } /* This function is used to reset draw manager to a state @@ -140,6 +130,23 @@ static void drw_state_ensure_not_reused(DRWManager *dst) #endif /* -------------------------------------------------------------------- */ +/** \name Threading + * \{ */ +static void drw_task_graph_init(void) +{ + BLI_assert(DST.task_graph == NULL); + DST.task_graph = BLI_task_graph_create(); +} + +static void drw_task_graph_deinit(void) +{ + BLI_task_graph_work_and_wait(DST.task_graph); + BLI_task_graph_free(DST.task_graph); + DST.task_graph = NULL; +} +/* \} */ + +/* -------------------------------------------------------------------- */ /** \name Settings * \{ */ @@ -588,9 +595,6 @@ static void drw_viewport_var_init(void) ED_view3d_init_mats_rv3d(DST.draw_ctx.object_edit, rv3d); } - /* Alloc array of texture reference. */ - memset(&DST.RST, 0x0, sizeof(DST.RST)); - if (G_draw.view_ubo == NULL) { G_draw.view_ubo = DRW_uniformbuffer_create(sizeof(DRWViewUboStorage), NULL); } @@ -1428,6 +1432,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, /* reuse if caller sets */ .evil_C = DST.draw_ctx.evil_C, }; + drw_task_graph_init(); drw_context_state_init(); drw_viewport_var_init(); @@ -1492,6 +1497,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, #endif } + drw_task_graph_deinit(); DRW_stats_begin(); GPU_framebuffer_bind(DST.default_framebuffer); @@ -1772,7 +1778,6 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph) DST.options.is_image_render = true; DST.options.is_scene_render = true; DST.options.draw_background = scene->r.alphamode == R_ADDSKY; - DST.draw_ctx = (DRWContextState){ .scene = scene, .view_layer = view_layer, @@ -1857,9 +1862,9 @@ void DRW_render_object_iter( void (*callback)(void *vedata, Object *ob, RenderEngine *engine, struct Depsgraph *depsgraph)) { const DRWContextState *draw_ctx = DRW_context_state_get(); - DRW_hair_init(); + drw_task_graph_init(); const int object_type_exclude_viewport = draw_ctx->v3d ? draw_ctx->v3d->object_type_exclude_viewport : 0; @@ -1882,6 +1887,7 @@ void DRW_render_object_iter( DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END; drw_duplidata_free(); + drw_task_graph_deinit(); } /* Assume a valid gl context is bound (and that the gl_context_mutex has been acquired). @@ -2053,7 +2059,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, DST.viewport = viewport; DST.options.is_select = true; - + drw_task_graph_init(); /* Get list of enabled engines */ if (use_obedit) { drw_engines_enable_overlays(); @@ -2163,6 +2169,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, } drw_duplidata_free(); + drw_task_graph_deinit(); drw_engines_cache_finish(); DRW_render_instance_buffer_finish(); @@ -2243,7 +2250,7 @@ static void drw_draw_depth_loop_imp(struct Depsgraph *depsgraph, .engine_type = engine_type, .depsgraph = depsgraph, }; - + drw_task_graph_init(); drw_engines_data_validate(); /* Setup framebuffer */ @@ -2287,6 +2294,7 @@ static void drw_draw_depth_loop_imp(struct Depsgraph *depsgraph, DRW_render_instance_buffer_finish(); } + drw_task_graph_deinit(); /* Start Drawing */ DRW_state_reset(); @@ -2376,7 +2384,7 @@ void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *region, View3D *v3d, cons .obact = OBACT(view_layer), .depsgraph = depsgraph, }; - + drw_task_graph_init(); drw_context_state_init(); /* Setup viewport */ @@ -2411,6 +2419,7 @@ void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *region, View3D *v3d, cons drw_resource_buffer_finish(DST.vmempool); #endif } + drw_task_graph_deinit(); /* Start Drawing */ DRW_state_reset(); @@ -2474,8 +2483,10 @@ void DRW_draw_depth_object( else { batch = DRW_mesh_batch_cache_get_surface(me); } - - DRW_mesh_batch_cache_create_requested(object, me, scene, false, true); + struct TaskGraph *task_graph = BLI_task_graph_create(); + DRW_mesh_batch_cache_create_requested(task_graph, object, me, scene, false, true); + BLI_task_graph_work_and_wait(task_graph); + BLI_task_graph_free(task_graph); const eGPUShaderConfig sh_cfg = world_clip_planes ? GPU_SHADER_CFG_CLIPPED : GPU_SHADER_CFG_DEFAULT; @@ -2721,8 +2732,6 @@ void DRW_engines_free(void) DRW_TEXTURE_FREE_SAFE(G_draw.ramp); DRW_TEXTURE_FREE_SAFE(G_draw.weight_ramp); - MEM_SAFE_FREE(DST.uniform_names.buffer); - if (DST.draw_list) { GPU_draw_list_discard(DST.draw_list); } diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h index f6d8179b193..733711a06da 100644 --- a/source/blender/draw/intern/draw_manager.h +++ b/source/blender/draw/intern/draw_manager.h @@ -31,6 +31,7 @@ #include "BLI_assert.h" #include "BLI_linklist.h" #include "BLI_memblock.h" +#include "BLI_task.h" #include "BLI_threads.h" #include "GPU_batch.h" @@ -276,10 +277,9 @@ typedef enum { DRW_UNIFORM_FLOAT, DRW_UNIFORM_FLOAT_COPY, DRW_UNIFORM_TEXTURE, - DRW_UNIFORM_TEXTURE_PERSIST, DRW_UNIFORM_TEXTURE_REF, DRW_UNIFORM_BLOCK, - DRW_UNIFORM_BLOCK_PERSIST, + DRW_UNIFORM_BLOCK_REF, DRW_UNIFORM_TFEEDBACK_TARGET, /** Per drawcall uniforms/UBO */ DRW_UNIFORM_BLOCK_OBMATS, @@ -290,7 +290,6 @@ typedef enum { 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; @@ -299,15 +298,28 @@ struct DRWUniform { union { /* For reference or array/vector types. */ const void *pvalue; - /* Single values. */ + /* DRW_UNIFORM_TEXTURE */ + struct { + union { + GPUTexture *texture; + GPUTexture **texture_ref; + }; + eGPUSamplerState sampler_state; + }; + /* DRW_UNIFORM_BLOCK */ + union { + GPUUniformBuffer *block; + GPUUniformBuffer **block_ref; + }; + /* DRW_UNIFORM_FLOAT_COPY */ float fvalue[4]; + /* DRW_UNIFORM_INT_COPY */ int ivalue[4]; }; - int location; + int location; /* Use as binding point for textures and ubos. */ 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 { @@ -342,6 +354,13 @@ struct DRWPass { DRWShadingGroup *last; } shgroups; + /* Draw the shgroups of this pass instead. + * This avoid duplicating drawcalls/shgroups + * for similar passes. */ + DRWPass *original; + /* Link list of additional passes to render. */ + DRWPass *next; + DRWResourceHandle handle; DRWState state; char name[MAX_PASS_NAME]; @@ -525,6 +544,8 @@ typedef struct DRWManager { uint select_id; #endif + struct TaskGraph *task_graph; + /* ---------- Nothing after this point is cleared after use ----------- */ /* gl_context serves as the offset for clearing only @@ -537,31 +558,11 @@ typedef struct DRWManager { GPUDrawList *draw_list; - /** GPU Resource State: Memory storage between drawing. */ - struct { - /* High end GPUs supports up to 32 binds per shader stage. - * We only use textures during the vertex and fragment stage, - * so 2 * 32 slots is a nice limit. */ - GPUTexture *bound_texs[DST_MAX_SLOTS]; - uint64_t bound_tex_slots; - uint64_t bound_tex_slots_persist; - - GPUUniformBuffer *bound_ubos[DST_MAX_SLOTS]; - uint64_t bound_ubo_slots; - uint64_t bound_ubo_slots_persist; - } RST; - struct { /* TODO(fclem) optimize: use chunks. */ DRWDebugLine *lines; DRWDebugSphere *spheres; } debug; - - struct { - char *buffer; - uint buffer_len; - uint buffer_ofs; - } uniform_names; } DRWManager; extern DRWManager DST; /* TODO: get rid of this and allow multi-threaded rendering. */ diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index aa401bcffa5..376bc69b392 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -170,13 +170,20 @@ void drw_resource_buffer_finish(ViewportMemoryPool *vmempool) /** \name Uniforms (DRW_shgroup_uniform) * \{ */ -static DRWUniform *drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup, - int loc, - DRWUniformType type, - const void *value, - int length, - int arraysize) -{ +static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup, + int loc, + DRWUniformType type, + const void *value, + eGPUSamplerState sampler_state, + int length, + int arraysize) +{ + if (loc == -1) { + /* Nice to enable eventually, for now eevee uses uniforms that might not exist. */ + // BLI_assert(0); + return; + } + DRWUniformChunk *unichunk = shgroup->uniforms; /* Happens on first uniform or if chunk is full. */ if (!unichunk || unichunk->uniform_used == unichunk->uniform_len) { @@ -202,22 +209,24 @@ static DRWUniform *drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup, BLI_assert(length <= 4); memcpy(uni->fvalue, value, sizeof(float) * length); break; + case DRW_UNIFORM_BLOCK: + uni->block = (GPUUniformBuffer *)value; + break; + case DRW_UNIFORM_BLOCK_REF: + uni->block_ref = (GPUUniformBuffer **)value; + break; + case DRW_UNIFORM_TEXTURE: + uni->texture = (GPUTexture *)value; + uni->sampler_state = sampler_state; + break; + case DRW_UNIFORM_TEXTURE_REF: + uni->texture_ref = (GPUTexture **)value; + uni->sampler_state = sampler_state; + break; default: uni->pvalue = (const float *)value; break; } - - return uni; -} - -static void drw_shgroup_builtin_uniform( - DRWShadingGroup *shgroup, int builtin, const void *value, int length, int arraysize) -{ - int loc = GPU_shader_get_builtin_uniform(shgroup->shader, builtin); - - if (loc != -1) { - drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_FLOAT, value, length, arraysize); - } } static void drw_shgroup_uniform(DRWShadingGroup *shgroup, @@ -227,61 +236,29 @@ static void drw_shgroup_uniform(DRWShadingGroup *shgroup, int length, int arraysize) { - int location; - if (ELEM(type, DRW_UNIFORM_BLOCK, DRW_UNIFORM_BLOCK_PERSIST)) { - location = GPU_shader_get_uniform_block(shgroup->shader, name); - } - else { - location = GPU_shader_get_uniform(shgroup->shader, name); - } - - if (location == -1) { - /* Nice to enable eventually, for now eevee uses uniforms that might not exist. */ - // BLI_assert(0); - return; - } - BLI_assert(arraysize > 0 && arraysize <= 16); BLI_assert(length >= 0 && length <= 16); - - 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. */ - if (location == -2 || DRW_DEBUG_USE_UNIFORM_NAME) { - int ofs = DST.uniform_names.buffer_ofs; - int max_len = DST.uniform_names.buffer_len - ofs; - size_t len = strlen(name) + 1; - - if (len >= max_len) { - DST.uniform_names.buffer_len += MAX2(DST.uniform_names.buffer_len, len); - DST.uniform_names.buffer = MEM_reallocN(DST.uniform_names.buffer, - DST.uniform_names.buffer_len); - } - - char *dst = DST.uniform_names.buffer + ofs; - memcpy(dst, name, len); /* Copies NULL terminator. */ - - DST.uniform_names.buffer_ofs += len; - uni->name_ofs = ofs; - } + BLI_assert(!ELEM(type, + DRW_UNIFORM_BLOCK, + DRW_UNIFORM_BLOCK_REF, + DRW_UNIFORM_TEXTURE, + DRW_UNIFORM_TEXTURE_REF)); + int location = GPU_shader_get_uniform(shgroup->shader, name); + drw_shgroup_uniform_create_ex(shgroup, location, type, value, 0, length, arraysize); } void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex) { BLI_assert(tex != NULL); - drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_TEXTURE, tex, 0, 1); + int loc = GPU_shader_get_texture_binding(shgroup->shader, name); + drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_TEXTURE, tex, GPU_SAMPLER_MAX, 0, 1); } -/* Same as DRW_shgroup_uniform_texture but is guaranteed to be bound if shader does not change - * between shgrp. */ -void DRW_shgroup_uniform_texture_persistent(DRWShadingGroup *shgroup, - const char *name, - const GPUTexture *tex) +void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex) { BLI_assert(tex != NULL); - drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_TEXTURE_PERSIST, tex, 0, 1); + int loc = GPU_shader_get_texture_binding(shgroup->shader, name); + drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_TEXTURE_REF, tex, GPU_SAMPLER_MAX, 0, 1); } void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, @@ -289,22 +266,17 @@ void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const GPUUniformBuffer *ubo) { BLI_assert(ubo != NULL); - drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_BLOCK, ubo, 0, 1); + int loc = GPU_shader_get_uniform_block_binding(shgroup->shader, name); + drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_BLOCK, ubo, 0, 0, 1); } -/* Same as DRW_shgroup_uniform_block but is guaranteed to be bound if shader does not change - * between shgrp. */ -void DRW_shgroup_uniform_block_persistent(DRWShadingGroup *shgroup, - const char *name, - const GPUUniformBuffer *ubo) +void DRW_shgroup_uniform_block_ref(DRWShadingGroup *shgroup, + const char *name, + GPUUniformBuffer **ubo) { BLI_assert(ubo != NULL); - drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_BLOCK_PERSIST, ubo, 0, 1); -} - -void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex) -{ - drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_TEXTURE_REF, tex, 0, 1); + int loc = GPU_shader_get_uniform_block_binding(shgroup->shader, name); + drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_BLOCK_REF, ubo, 0, 0, 1); } void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, @@ -441,7 +413,7 @@ void DRW_shgroup_uniform_vec4_array_copy(DRWShadingGroup *shgroup, const float (*value)[4], int arraysize) { - int location = GPU_shader_get_uniform_ensure(shgroup->shader, name); + int location = GPU_shader_get_uniform(shgroup->shader, name); if (location == -1) { /* Nice to enable eventually, for now eevee uses uniforms that might not exist. */ @@ -450,7 +422,8 @@ void DRW_shgroup_uniform_vec4_array_copy(DRWShadingGroup *shgroup, } for (int i = 0; i < arraysize; i++) { - drw_shgroup_uniform_create_ex(shgroup, location + i, DRW_UNIFORM_FLOAT_COPY, &value[i], 4, 1); + drw_shgroup_uniform_create_ex( + shgroup, location + i, DRW_UNIFORM_FLOAT_COPY, &value[i], 0, 4, 1); } } @@ -1196,52 +1169,49 @@ 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 view_ubo_location = GPU_shader_get_uniform_block_binding(shader, "viewBlock"); + int model_ubo_location = GPU_shader_get_uniform_block_binding(shader, "modelBlock"); + int info_ubo_location = GPU_shader_get_uniform_block_binding(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); int resourceid_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_RESOURCE_ID); if (chunkid_location != -1) { drw_shgroup_uniform_create_ex( - shgroup, chunkid_location, DRW_UNIFORM_RESOURCE_CHUNK, NULL, 0, 1); + shgroup, chunkid_location, DRW_UNIFORM_RESOURCE_CHUNK, NULL, 0, 0, 1); } if (resourceid_location != -1) { drw_shgroup_uniform_create_ex( - shgroup, resourceid_location, DRW_UNIFORM_RESOURCE_ID, NULL, 0, 1); + shgroup, resourceid_location, DRW_UNIFORM_RESOURCE_ID, NULL, 0, 0, 1); } if (baseinst_location != -1) { drw_shgroup_uniform_create_ex( - shgroup, baseinst_location, DRW_UNIFORM_BASE_INSTANCE, NULL, 0, 1); + shgroup, baseinst_location, DRW_UNIFORM_BASE_INSTANCE, NULL, 0, 0, 1); } if (model_ubo_location != -1) { drw_shgroup_uniform_create_ex( - shgroup, model_ubo_location, DRW_UNIFORM_BLOCK_OBMATS, NULL, 0, 1); + shgroup, model_ubo_location, DRW_UNIFORM_BLOCK_OBMATS, NULL, 0, 0, 1); } else { + /* Note: This is only here to support old hardware fallback where uniform buffer is still + * too slow or buggy. */ 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); + drw_shgroup_uniform_create_ex(shgroup, model, DRW_UNIFORM_MODEL_MATRIX, NULL, 0, 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); + shgroup, modelinverse, DRW_UNIFORM_MODEL_MATRIX_INVERSE, NULL, 0, 0, 1); } } if (info_ubo_location != -1) { drw_shgroup_uniform_create_ex( - shgroup, info_ubo_location, DRW_UNIFORM_BLOCK_OBINFOS, NULL, 0, 1); + shgroup, info_ubo_location, DRW_UNIFORM_BLOCK_OBINFOS, NULL, 0, 0, 1); /* Abusing this loc to tell shgroup we need the obinfos. */ shgroup->objectinfo = 1; @@ -1252,25 +1222,21 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader) if (view_ubo_location != -1) { drw_shgroup_uniform_create_ex( - shgroup, view_ubo_location, DRW_UNIFORM_BLOCK_PERSIST, G_draw.view_ubo, 0, 1); - } - else { - /* Only here to support builtin shaders. This should not be used by engines. */ - /* TODO remove. */ - DRWViewUboStorage *storage = &DST.view_storage_cpy; - drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEW, storage->viewmat, 16, 1); - drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEW_INV, storage->viewinv, 16, 1); - drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEWPROJECTION, storage->persmat, 16, 1); - drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEWPROJECTION_INV, storage->persinv, 16, 1); - drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_PROJECTION, storage->winmat, 16, 1); - drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_PROJECTION_INV, storage->wininv, 16, 1); - drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_CLIPPLANES, storage->clipplanes, 4, 6); + shgroup, view_ubo_location, DRW_UNIFORM_BLOCK, G_draw.view_ubo, 0, 0, 1); } /* Not supported. */ 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); + BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_VIEW) == -1); + BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_VIEW_INV) == -1); + BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_VIEWPROJECTION) == -1); + BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_VIEWPROJECTION_INV) == -1); + BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_PROJECTION) == -1); + BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_PROJECTION_INV) == -1); + BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_CLIPPLANES) == -1); + BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MVP) == -1); } static DRWShadingGroup *drw_shgroup_create_ex(struct GPUShader *shader, DRWPass *pass) @@ -1308,18 +1274,20 @@ static DRWShadingGroup *drw_shgroup_material_create_ex(GPUPass *gpupass, DRWPass static void drw_shgroup_material_texture(DRWShadingGroup *grp, GPUMaterialTexture *tex, const char *name, + eGPUSamplerState state, int textarget) { GPUTexture *gputex = GPU_texture_from_blender(tex->ima, tex->iuser, NULL, textarget); - DRW_shgroup_uniform_texture(grp, name, gputex); + + int loc = GPU_shader_get_texture_binding(grp->shader, name); + drw_shgroup_uniform_create_ex(grp, loc, DRW_UNIFORM_TEXTURE, gputex, state, 0, 1); GPUTexture **gputex_ref = BLI_memblock_alloc(DST.vmempool->images); *gputex_ref = gputex; GPU_texture_ref(gputex); } -static DRWShadingGroup *drw_shgroup_material_inputs(DRWShadingGroup *grp, - struct GPUMaterial *material) +void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, struct GPUMaterial *material) { ListBase textures = GPU_material_textures(material); @@ -1328,11 +1296,14 @@ static DRWShadingGroup *drw_shgroup_material_inputs(DRWShadingGroup *grp, if (tex->ima) { /* Image */ if (tex->tiled_mapping_name[0]) { - drw_shgroup_material_texture(grp, tex, tex->sampler_name, GL_TEXTURE_2D_ARRAY); - drw_shgroup_material_texture(grp, tex, tex->tiled_mapping_name, GL_TEXTURE_1D_ARRAY); + drw_shgroup_material_texture( + grp, tex, tex->sampler_name, tex->sampler_state, GL_TEXTURE_2D_ARRAY); + drw_shgroup_material_texture( + grp, tex, tex->tiled_mapping_name, tex->sampler_state, GL_TEXTURE_1D_ARRAY); } else { - drw_shgroup_material_texture(grp, tex, tex->sampler_name, GL_TEXTURE_2D); + drw_shgroup_material_texture( + grp, tex, tex->sampler_name, tex->sampler_state, GL_TEXTURE_2D); } } else if (tex->colorband) { @@ -1345,8 +1316,6 @@ static DRWShadingGroup *drw_shgroup_material_inputs(DRWShadingGroup *grp, if (ubo != NULL) { DRW_shgroup_uniform_block(grp, GPU_UBO_BLOCK_NAME, ubo); } - - return grp; } GPUVertFormat *DRW_shgroup_instance_format_array(const DRWInstanceAttrFormat attrs[], @@ -1371,7 +1340,7 @@ DRWShadingGroup *DRW_shgroup_material_create(struct GPUMaterial *material, DRWPa if (shgroup) { drw_shgroup_init(shgroup, GPU_pass_shader_get(gpupass)); - drw_shgroup_material_inputs(shgroup, material); + DRW_shgroup_add_material_resources(shgroup, material); } return shgroup; } @@ -1390,7 +1359,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); - drw_shgroup_uniform_create_ex(shgroup, 0, DRW_UNIFORM_TFEEDBACK_TARGET, tf_target, 0, 1); + drw_shgroup_uniform_create_ex(shgroup, 0, DRW_UNIFORM_TFEEDBACK_TARGET, tf_target, 0, 0, 1); return shgroup; } @@ -1922,9 +1891,28 @@ DRWPass *DRW_pass_create(const char *name, DRWState state) pass->handle = DST.pass_handle; DRW_handle_increment(&DST.pass_handle); + pass->original = NULL; + pass->next = NULL; + + return pass; +} + +DRWPass *DRW_pass_create_instance(const char *name, DRWPass *original, DRWState state) +{ + DRWPass *pass = DRW_pass_create(name, state); + pass->original = original; + return pass; } +/* Link two passes so that they are both rendered if the first one is being drawn. */ +void DRW_pass_link(DRWPass *first, DRWPass *second) +{ + BLI_assert(first != second); + BLI_assert(first->next == NULL); + first->next = second; +} + bool DRW_pass_is_empty(DRWPass *pass) { LISTBASE_FOREACH (DRWShadingGroup *, shgroup, &pass->shgroups) { diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c index 6c62d4d2405..144ce573460 100644 --- a/source/blender/draw/intern/draw_manager_exec.c +++ b/source/blender/draw/intern/draw_manager_exec.c @@ -22,6 +22,7 @@ #include "draw_manager.h" +#include "BLI_alloca.h" #include "BLI_math.h" #include "BLI_math_bits.h" #include "BLI_memblock.h" @@ -65,7 +66,6 @@ typedef struct DRWCommandsState { /* Legacy matrix support. */ int obmat_loc; int obinv_loc; - int mvp_loc; /* Selection ID state. */ GPUVertBuf *select_buf; uint select_id; @@ -655,8 +655,7 @@ static void draw_compute_culling(DRWView *view) BLI_INLINE void draw_legacy_matrix_update(DRWShadingGroup *shgroup, DRWResourceHandle *handle, float obmat_loc, - float obinv_loc, - float mvp_loc) + float obinv_loc) { /* Still supported for compatibility with gpu_shader_* but should be forbidden. */ DRWObjectMatrix *ob_mats = DRW_memblock_elem_from_handle(DST.vmempool->obmats, handle); @@ -666,13 +665,6 @@ BLI_INLINE void draw_legacy_matrix_update(DRWShadingGroup *shgroup, 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 (mvp_loc != -1) { - float mvp[4][4]; - 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) @@ -744,107 +736,6 @@ BLI_INLINE void draw_indirect_call(DRWShadingGroup *shgroup, DRWCommandsState *s } } -enum { - BIND_NONE = 0, - BIND_TEMP = 1, /* Release slot after this shading group. */ - BIND_PERSIST = 2, /* Release slot only after the next shader change. */ -}; - -static void set_bound_flags(uint64_t *slots, uint64_t *persist_slots, int slot_idx, char bind_type) -{ - uint64_t slot = 1llu << (unsigned long)slot_idx; - *slots |= slot; - if (bind_type == BIND_PERSIST) { - *persist_slots |= slot; - } -} - -static int get_empty_slot_index(uint64_t slots) -{ - uint64_t empty_slots = ~slots; - /* Find first empty slot using bitscan. */ - if (empty_slots != 0) { - if ((empty_slots & 0xFFFFFFFFlu) != 0) { - return (int)bitscan_forward_uint(empty_slots); - } - else { - return (int)bitscan_forward_uint(empty_slots >> 32) + 32; - } - } - else { - /* Greater than GPU_max_textures() */ - return 99999; - } -} - -static void bind_texture(GPUTexture *tex, char bind_type) -{ - int idx = GPU_texture_bound_number(tex); - if (idx == -1) { - /* Texture isn't bound yet. Find an empty slot and bind it. */ - idx = get_empty_slot_index(DST.RST.bound_tex_slots); - - if (idx < GPU_max_textures()) { - GPUTexture **gpu_tex_slot = &DST.RST.bound_texs[idx]; - /* Unbind any previous texture. */ - if (*gpu_tex_slot != NULL) { - GPU_texture_unbind(*gpu_tex_slot); - } - GPU_texture_bind(tex, idx); - *gpu_tex_slot = tex; - } - else { - printf("Not enough texture slots! Reduce number of textures used by your shader.\n"); - return; - } - } - else { - /* This texture slot was released but the tex - * is still bound. Just flag the slot again. */ - BLI_assert(DST.RST.bound_texs[idx] == tex); - } - set_bound_flags(&DST.RST.bound_tex_slots, &DST.RST.bound_tex_slots_persist, idx, bind_type); -} - -static void bind_ubo(GPUUniformBuffer *ubo, char bind_type) -{ - int idx = GPU_uniformbuffer_bindpoint(ubo); - if (idx == -1) { - /* 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. */ - if (*gpu_ubo_slot != NULL) { - GPU_uniformbuffer_unbind(*gpu_ubo_slot); - } - GPU_uniformbuffer_bind(ubo, idx); - *gpu_ubo_slot = ubo; - } - else { - /* printf so user can report bad behavior */ - printf("Not enough ubo slots! This should not happen!\n"); - /* This is not depending on user input. - * It is our responsibility to make sure there is enough slots. */ - BLI_assert(0); - return; - } - } - 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); -} - #ifndef NDEBUG /** * Opengl specification is strict on buffer binding. @@ -900,28 +791,6 @@ static bool ubo_bindings_validate(DRWShadingGroup *shgroup) } #endif -static void release_texture_slots(bool with_persist) -{ - if (with_persist) { - DST.RST.bound_tex_slots = 0; - DST.RST.bound_tex_slots_persist = 0; - } - else { - DST.RST.bound_tex_slots &= DST.RST.bound_tex_slots_persist; - } -} - -static void release_ubo_slots(bool with_persist) -{ - if (with_persist) { - DST.RST.bound_ubo_slots = 0; - DST.RST.bound_ubo_slots_persist = 0; - } - else { - DST.RST.bound_ubo_slots &= DST.RST.bound_ubo_slots_persist; - } -} - static void draw_update_uniforms(DRWShadingGroup *shgroup, DRWCommandsState *state, bool *use_tfeedback) @@ -929,69 +798,42 @@ static void draw_update_uniforms(DRWShadingGroup *shgroup, 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: + GPU_shader_uniform_vector_int( + shgroup->shader, uni->location, uni->length, uni->arraysize, uni->ivalue); + break; case DRW_UNIFORM_INT: GPU_shader_uniform_vector_int( - shgroup->shader, uni->location, uni->length, uni->arraysize, data); + shgroup->shader, uni->location, uni->length, uni->arraysize, uni->pvalue); break; case DRW_UNIFORM_FLOAT_COPY: + GPU_shader_uniform_vector( + shgroup->shader, uni->location, uni->length, uni->arraysize, uni->fvalue); + break; case DRW_UNIFORM_FLOAT: GPU_shader_uniform_vector( - shgroup->shader, uni->location, uni->length, uni->arraysize, data); + shgroup->shader, uni->location, uni->length, uni->arraysize, uni->pvalue); 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); + GPU_texture_bind_ex(uni->texture, uni->sampler_state, uni->location, false); 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); + GPU_texture_bind_ex(*uni->texture_ref, uni->sampler_state, uni->location, false); break; case DRW_UNIFORM_BLOCK: - ubo = (GPUUniformBuffer *)uni->pvalue; - bind_ubo(ubo, BIND_TEMP); - GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo); + GPU_uniformbuffer_bind(uni->block, uni->location); break; - case DRW_UNIFORM_BLOCK_PERSIST: - ubo = (GPUUniformBuffer *)uni->pvalue; - bind_ubo(ubo, BIND_PERSIST); - GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo); + case DRW_UNIFORM_BLOCK_REF: + GPU_uniformbuffer_bind(*uni->block_ref, uni->location); 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); + GPU_uniformbuffer_bind(DST.vmempool->matrices_ubo[0], uni->location); 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); + GPU_uniformbuffer_bind(DST.vmempool->obinfos_ubo[0], uni->location); break; case DRW_UNIFORM_RESOURCE_CHUNK: state->chunkid_loc = uni->location; @@ -1001,9 +843,9 @@ static void draw_update_uniforms(DRWShadingGroup *shgroup, state->resourceid_loc = uni->location; 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); + BLI_assert(uni->pvalue && (*use_tfeedback == false)); + *use_tfeedback = GPU_shader_transform_feedback_enable( + shgroup->shader, ((GPUVertBuf *)uni->pvalue)->vbo_id); break; /* Legacy/Fallback support. */ case DRW_UNIFORM_BASE_INSTANCE: @@ -1015,9 +857,6 @@ static void draw_update_uniforms(DRWShadingGroup *shgroup, case DRW_UNIFORM_MODEL_MATRIX_INVERSE: state->obinv_loc = uni->location; break; - case DRW_UNIFORM_MODELVIEWPROJECTION_MATRIX: - state->mvp_loc = uni->location; - break; } } } @@ -1110,7 +949,7 @@ static void draw_call_resource_bind(DRWCommandsState *state, const DRWResourceHa } if (state->obmats_loc != -1) { GPU_uniformbuffer_unbind(DST.vmempool->matrices_ubo[state->resource_chunk]); - GPU_uniformbuffer_bind(DST.vmempool->matrices_ubo[chunk], 0); + GPU_uniformbuffer_bind(DST.vmempool->matrices_ubo[chunk], state->obmats_loc); } if (state->obinfos_loc != -1) { GPU_uniformbuffer_unbind(DST.vmempool->obinfos_ubo[state->resource_chunk]); @@ -1153,10 +992,8 @@ static void draw_call_single_do(DRWShadingGroup *shgroup, 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 (state->obmats_loc == -1 && (state->obmat_loc != -1 || state->obinv_loc != -1)) { + draw_legacy_matrix_update(shgroup, &handle, state->obmat_loc, state->obinv_loc); } if (G.f & G_FLAG_PICKSEL) { @@ -1262,7 +1099,6 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) .resourceid_loc = -1, .obmat_loc = -1, .obinv_loc = -1, - .mvp_loc = -1, .drw_state_enabled = 0, .drw_state_disabled = 0, }; @@ -1273,6 +1109,11 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) if (shader_changed) { if (DST.shader) { GPU_shader_unbind(); + + /* Unbinding can be costly. Skip in normal condition. */ + if (G.debug & G_DEBUG_GPU) { + GPU_texture_unbind_all(); + } } GPU_shader_bind(shgroup->shader); DST.shader = shgroup->shader; @@ -1283,9 +1124,6 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) DST.batch = NULL; } - release_ubo_slots(shader_changed); - release_texture_slots(shader_changed); - draw_update_uniforms(shgroup, &state, &use_tfeedback); drw_state_set(pass_state); @@ -1426,6 +1264,11 @@ static void drw_draw_pass_ex(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group) { + if (pass->original) { + start_group = pass->original->shgroups.first; + end_group = pass->original->shgroups.last; + } + if (start_group == NULL) { return; } @@ -1462,24 +1305,9 @@ static void drw_draw_pass_ex(DRWPass *pass, } } - /* Clear Bound textures */ - for (int i = 0; i < DST_MAX_SLOTS; i++) { - if (DST.RST.bound_texs[i] != NULL) { - GPU_texture_unbind(DST.RST.bound_texs[i]); - DST.RST.bound_texs[i] = NULL; - } - } - - /* Clear Bound Ubos */ - for (int i = 0; i < DST_MAX_SLOTS; i++) { - if (DST.RST.bound_ubos[i] != NULL) { - GPU_uniformbuffer_unbind(DST.RST.bound_ubos[i]); - DST.RST.bound_ubos[i] = NULL; - } - } - if (DST.shader) { GPU_shader_unbind(); + GPU_texture_unbind_all(); DST.shader = NULL; } @@ -1511,7 +1339,9 @@ static void drw_draw_pass_ex(DRWPass *pass, void DRW_draw_pass(DRWPass *pass) { - drw_draw_pass_ex(pass, pass->shgroups.first, pass->shgroups.last); + for (; pass; pass = pass->next) { + drw_draw_pass_ex(pass, pass->shgroups.first, pass->shgroups.last); + } } /* Draw only a subset of shgroups. Used in special situations as grease pencil strokes */ diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c index 0d6527421d0..6304b707cb9 100644 --- a/source/blender/draw/intern/draw_manager_shader.c +++ b/source/blender/draw/intern/draw_manager_shader.c @@ -343,27 +343,12 @@ GPUShader *DRW_shader_create_with_transform_feedback(const char *vert, __func__); } -GPUShader *DRW_shader_create_2d(const char *frag, const char *defines) -{ - return GPU_shader_create(datatoc_gpu_shader_2D_vert_glsl, frag, NULL, NULL, defines, __func__); -} - -GPUShader *DRW_shader_create_3d(const char *frag, const char *defines) -{ - return GPU_shader_create(datatoc_gpu_shader_3D_vert_glsl, frag, NULL, NULL, defines, __func__); -} - GPUShader *DRW_shader_create_fullscreen(const char *frag, const char *defines) { return GPU_shader_create( datatoc_common_fullscreen_vert_glsl, frag, NULL, NULL, defines, __func__); } -GPUShader *DRW_shader_create_3d_depth_only(eGPUShaderConfig sh_cfg) -{ - return GPU_shader_get_builtin_shader_with_config(GPU_SHADER_3D_DEPTH_ONLY, sh_cfg); -} - GPUMaterial *DRW_shader_find_from_world(World *wo, const void *engine_type, const int options, @@ -398,6 +383,7 @@ GPUMaterial *DRW_shader_find_from_material(Material *ma, GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, World *wo, + struct bNodeTree *ntree, const void *engine_type, const int options, const bool is_volume_shader, @@ -408,7 +394,7 @@ GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, bool deferred) { GPUMaterial *mat = NULL; - if (DRW_state_is_image_render()) { + if (DRW_state_is_image_render() || !deferred) { mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine_type, options); } @@ -416,7 +402,7 @@ GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, scene = (Scene *)DEG_get_original_id(&DST.draw_ctx.scene->id); mat = GPU_material_from_nodetree(scene, NULL, - wo->nodetree, + ntree, &wo->gpumaterial, engine_type, options, @@ -437,6 +423,7 @@ GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, GPUMaterial *DRW_shader_create_from_material(struct Scene *scene, Material *ma, + struct bNodeTree *ntree, const void *engine_type, const int options, const bool is_volume_shader, @@ -447,7 +434,7 @@ GPUMaterial *DRW_shader_create_from_material(struct Scene *scene, bool deferred) { GPUMaterial *mat = NULL; - if (DRW_state_is_image_render()) { + if (DRW_state_is_image_render() || !deferred) { mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine_type, options); } @@ -455,7 +442,7 @@ GPUMaterial *DRW_shader_create_from_material(struct Scene *scene, scene = (Scene *)DEG_get_original_id(&DST.draw_ctx.scene->id); mat = GPU_material_from_nodetree(scene, ma, - ma->nodetree, + ntree, &ma->gpumaterial, engine_type, options, diff --git a/source/blender/draw/intern/draw_manager_texture.c b/source/blender/draw/intern/draw_manager_texture.c index 6abab38e1e6..0cb6535b1c1 100644 --- a/source/blender/draw/intern/draw_manager_texture.c +++ b/source/blender/draw/intern/draw_manager_texture.c @@ -61,17 +61,17 @@ static bool drw_texture_format_supports_framebuffer(eGPUTextureFormat format) void drw_texture_set_parameters(GPUTexture *tex, DRWTextureFlag flags) { - GPU_texture_bind(tex, 0); if (flags & DRW_TEX_MIPMAP) { GPU_texture_mipmap_mode(tex, true, flags & DRW_TEX_FILTER); + GPU_texture_bind(tex, 0); GPU_texture_generate_mipmap(tex); + GPU_texture_unbind(tex); } else { GPU_texture_filter_mode(tex, flags & DRW_TEX_FILTER); } GPU_texture_wrap_mode(tex, flags & DRW_TEX_WRAP, true); GPU_texture_compare_mode(tex, flags & DRW_TEX_COMPARE); - GPU_texture_unbind(tex); } GPUTexture *DRW_texture_create_1d(int w, |