diff options
Diffstat (limited to 'servers/rendering')
86 files changed, 3156 insertions, 1158 deletions
diff --git a/servers/rendering/rasterizer_dummy.h b/servers/rendering/rasterizer_dummy.h index 3451ea2d39..67ad277c84 100644 --- a/servers/rendering/rasterizer_dummy.h +++ b/servers/rendering/rasterizer_dummy.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -116,6 +116,8 @@ public: void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override {} void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) override {} void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override {} + void environment_set_ssil(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_sharpness, float p_normal_rejection) override {} + void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override {} void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) override {} @@ -692,7 +694,9 @@ public: virtual void update_memory_info() override {} virtual uint64_t get_rendering_info(RS::RenderingInfo p_info) override { return 0; } - bool has_os_feature(const String &p_feature) const override { return false; } + bool has_os_feature(const String &p_feature) const override { + return p_feature == "rgtc" || p_feature == "bptc" || p_feature == "s3tc" || p_feature == "etc" || p_feature == "etc2"; + } void update_dirty_resources() override {} diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index 7b70483571..02af3c6eb9 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -786,7 +786,7 @@ void RendererCanvasCull::canvas_item_add_texture_rect(RID p_item, const Rect2 &p if (p_tile) { rect->flags |= RendererCanvasRender::CANVAS_RECT_TILE; rect->flags |= RendererCanvasRender::CANVAS_RECT_REGION; - rect->source = Rect2(0, 0, fabsf(p_rect.size.width), fabsf(p_rect.size.height)); + rect->source = Rect2(0, 0, ABS(p_rect.size.width), ABS(p_rect.size.height)); } if (p_rect.size.x < 0) { diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h index bdd61123df..fc53ce2327 100644 --- a/servers/rendering/renderer_canvas_cull.h +++ b/servers/rendering/renderer_canvas_cull.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_canvas_render.cpp b/servers/rendering/renderer_canvas_render.cpp index 1945435586..3b68cd74fd 100644 --- a/servers/rendering/renderer_canvas_render.cpp +++ b/servers/rendering/renderer_canvas_render.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_canvas_render.h b/servers/rendering/renderer_canvas_render.h index 04ddae4089..1840925f78 100644 --- a/servers/rendering/renderer_canvas_render.h +++ b/servers/rendering/renderer_canvas_render.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_compositor.cpp b/servers/rendering/renderer_compositor.cpp index 80c4625261..82e8bd6ef9 100644 --- a/servers/rendering/renderer_compositor.cpp +++ b/servers/rendering/renderer_compositor.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_compositor.h b/servers/rendering/renderer_compositor.h index 4526354d17..f245af9a4a 100644 --- a/servers/rendering/renderer_compositor.h +++ b/servers/rendering/renderer_compositor.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/cluster_builder_rd.cpp b/servers/rendering/renderer_rd/cluster_builder_rd.cpp index 4a98cf0831..6ad3556969 100644 --- a/servers/rendering/renderer_rd/cluster_builder_rd.cpp +++ b/servers/rendering/renderer_rd/cluster_builder_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/cluster_builder_rd.h b/servers/rendering/renderer_rd/cluster_builder_rd.h index feafd4c2db..7f6750fa7e 100644 --- a/servers/rendering/renderer_rd/cluster_builder_rd.h +++ b/servers/rendering/renderer_rd/cluster_builder_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp index cf943901d4..4a19519995 100644 --- a/servers/rendering/renderer_rd/effects_rd.cpp +++ b/servers/rendering/renderer_rd/effects_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -1315,6 +1315,111 @@ void EffectsRD::bokeh_dof_raster(const BokehBuffers &p_buffers, bool p_dof_far, } } +void EffectsRD::downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_mipmaps, RS::EnvironmentSSAOQuality p_ssao_quality, RS::EnvironmentSSILQuality p_ssil_quality, bool p_invalidate_uniform_set, bool p_ssao_half_size, bool p_ssil_half_size, Size2i p_full_screen_size, const CameraMatrix &p_projection) { + // Downsample and deinterleave the depth buffer for SSAO and SSIL + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + + int downsample_pipeline = SS_EFFECTS_DOWNSAMPLE; + bool use_mips = p_ssao_quality > RS::ENV_SSAO_QUALITY_MEDIUM || p_ssil_quality > RS::ENV_SSIL_QUALITY_MEDIUM; + + if (p_ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW && p_ssil_quality == RS::ENV_SSIL_QUALITY_VERY_LOW) { + downsample_pipeline = SS_EFFECTS_DOWNSAMPLE_HALF; + } else if (use_mips) { + downsample_pipeline = SS_EFFECTS_DOWNSAMPLE_MIPMAP; + } + + bool use_half_size = false; + bool use_full_mips = false; + + if (p_ssao_half_size && p_ssil_half_size) { + downsample_pipeline++; + use_half_size = true; + } else if (p_ssao_half_size != p_ssil_half_size) { + if (use_mips) { + downsample_pipeline = SS_EFFECTS_DOWNSAMPLE_FULL_MIPS; + use_full_mips = true; + } else { + // Only need the first two mipmaps, but the cost to generate the next two is trivial + // TODO investigate the benefit of a shader version to generate only 2 mips + downsample_pipeline = SS_EFFECTS_DOWNSAMPLE_MIPMAP; + use_mips = true; + } + } + + int depth_index = use_half_size ? 1 : 0; + + RD::get_singleton()->draw_command_begin_label("Downsample Depth"); + if (p_invalidate_uniform_set || use_full_mips != ss_effects.used_full_mips_last_frame || use_half_size != ss_effects.used_half_size_last_frame || use_mips != ss_effects.used_mips_last_frame) { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 0; + u.ids.push_back(p_depth_mipmaps[depth_index + 1]); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 1; + u.ids.push_back(p_depth_mipmaps[depth_index + 2]); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 2; + u.ids.push_back(p_depth_mipmaps[depth_index + 3]); + uniforms.push_back(u); + } + if (use_full_mips) { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 3; + u.ids.push_back(p_depth_mipmaps[4]); + uniforms.push_back(u); + } + ss_effects.downsample_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ss_effects.downsample_shader.version_get_shader(ss_effects.downsample_shader_version, use_full_mips ? 6 : 2), 2); + } + + float depth_linearize_mul = -p_projection.matrix[3][2]; + float depth_linearize_add = p_projection.matrix[2][2]; + if (depth_linearize_mul * depth_linearize_add < 0) { + depth_linearize_add = -depth_linearize_add; + } + + ss_effects.downsample_push_constant.orthogonal = p_projection.is_orthogonal(); + ss_effects.downsample_push_constant.z_near = depth_linearize_mul; + ss_effects.downsample_push_constant.z_far = depth_linearize_add; + if (ss_effects.downsample_push_constant.orthogonal) { + ss_effects.downsample_push_constant.z_near = p_projection.get_z_near(); + ss_effects.downsample_push_constant.z_far = p_projection.get_z_far(); + } + ss_effects.downsample_push_constant.pixel_size[0] = 1.0 / p_full_screen_size.x; + ss_effects.downsample_push_constant.pixel_size[1] = 1.0 / p_full_screen_size.y; + ss_effects.downsample_push_constant.radius_sq = 1.0; + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ss_effects.pipelines[downsample_pipeline]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_buffer), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_depth_mipmaps[depth_index + 0]), 1); + if (use_mips) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, ss_effects.downsample_uniform_set, 2); + } + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ss_effects.downsample_push_constant, sizeof(SSEffectsDownsamplePushConstant)); + + Size2i size(MAX(1, p_full_screen_size.x >> (use_half_size ? 2 : 1)), MAX(1, p_full_screen_size.y >> (use_half_size ? 2 : 1))); + + RD::get_singleton()->compute_list_dispatch_threads(compute_list, size.x, size.y, 1); + RD::get_singleton()->compute_list_add_barrier(compute_list); + RD::get_singleton()->draw_command_end_label(); + + RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_COMPUTE); + + ss_effects.used_full_mips_last_frame = use_mips; + ss_effects.used_full_mips_last_frame = use_full_mips; + ss_effects.used_half_size_last_frame = use_half_size; +} + void EffectsRD::gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set) { RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_gather_uniform_set, 0); if ((p_settings.quality == RS::ENV_SSAO_QUALITY_ULTRA) && !p_adaptive_base_pass) { @@ -1341,82 +1446,12 @@ void EffectsRD::gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> RD::get_singleton()->compute_list_add_barrier(p_compute_list); } -void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_depth_mipmaps_texture, const Vector<RID> &p_depth_mipmaps, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets, RID &r_downsample_uniform_set, RID &r_gather_uniform_set, RID &r_importance_map_uniform_set) { +void EffectsRD::generate_ssao(RID p_normal_buffer, RID p_depth_mipmaps_texture, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets, RID &r_gather_uniform_set, RID &r_importance_map_uniform_set) { RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - RD::get_singleton()->draw_command_begin_label("SSAO"); + memset(&ssao.gather_push_constant, 0, sizeof(SSAOGatherPushConstant)); /* FIRST PASS */ - // Downsample and deinterleave the depth buffer. - { - RD::get_singleton()->draw_command_begin_label("Downsample Depth"); - if (p_invalidate_uniform_sets) { - Vector<RD::Uniform> uniforms; - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 0; - u.ids.push_back(p_depth_mipmaps[1]); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 1; - u.ids.push_back(p_depth_mipmaps[2]); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 2; - u.ids.push_back(p_depth_mipmaps[3]); - uniforms.push_back(u); - } - r_downsample_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.downsample_shader.version_get_shader(ssao.downsample_shader_version, 2), 2); - } - - float depth_linearize_mul = -p_projection.matrix[3][2]; - float depth_linearize_add = p_projection.matrix[2][2]; - if (depth_linearize_mul * depth_linearize_add < 0) { - depth_linearize_add = -depth_linearize_add; - } - - ssao.downsample_push_constant.orthogonal = p_projection.is_orthogonal(); - ssao.downsample_push_constant.z_near = depth_linearize_mul; - ssao.downsample_push_constant.z_far = depth_linearize_add; - if (ssao.downsample_push_constant.orthogonal) { - ssao.downsample_push_constant.z_near = p_projection.get_z_near(); - ssao.downsample_push_constant.z_far = p_projection.get_z_far(); - } - ssao.downsample_push_constant.pixel_size[0] = 1.0 / p_settings.full_screen_size.x; - ssao.downsample_push_constant.pixel_size[1] = 1.0 / p_settings.full_screen_size.y; - ssao.downsample_push_constant.radius_sq = p_settings.radius * p_settings.radius; - - int downsample_pipeline = SSAO_DOWNSAMPLE; - if (p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) { - downsample_pipeline = SSAO_DOWNSAMPLE_HALF; - } else if (p_settings.quality > RS::ENV_SSAO_QUALITY_MEDIUM) { - downsample_pipeline = SSAO_DOWNSAMPLE_MIPMAP; - } - - if (p_settings.half_size) { - downsample_pipeline++; - } - - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[downsample_pipeline]); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_buffer), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_depth_mipmaps[0]), 1); - if (p_settings.quality > RS::ENV_SSAO_QUALITY_MEDIUM) { - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, r_downsample_uniform_set, 2); - } - RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.downsample_push_constant, sizeof(SSAODownsamplePushConstant)); - - Size2i size(MAX(1, p_settings.full_screen_size.x >> (p_settings.half_size ? 2 : 1)), MAX(1, p_settings.full_screen_size.y >> (p_settings.half_size ? 2 : 1))); - - RD::get_singleton()->compute_list_dispatch_threads(compute_list, size.x, size.y, 1); - RD::get_singleton()->compute_list_add_barrier(compute_list); - RD::get_singleton()->draw_command_end_label(); // Downsample SSAO - } + RD::get_singleton()->draw_command_begin_label("Process Screen Space Ambient Occlusion"); /* SECOND PASS */ // Sample SSAO { @@ -1469,7 +1504,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; u.binding = 0; - u.ids.push_back(ssao.mirror_sampler); + u.ids.push_back(default_sampler); u.ids.push_back(p_depth_mipmaps_texture); uniforms.push_back(u); } @@ -1484,7 +1519,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 2; - u.ids.push_back(ssao.gather_constants_buffer); + u.ids.push_back(ss_effects.gather_constants_buffer); uniforms.push_back(u); } r_gather_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.gather_shader.version_get_shader(ssao.gather_shader_version, 0), 0); @@ -1574,6 +1609,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep for (int pass = 0; pass < blur_passes; pass++) { int blur_pipeline = SSAO_BLUR_PASS; if (p_settings.quality > RS::ENV_SSAO_QUALITY_VERY_LOW) { + blur_pipeline = SSAO_BLUR_PASS_SMART; if (pass < blur_passes - 2) { blur_pipeline = SSAO_BLUR_PASS_WIDE; } else { @@ -1591,7 +1627,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep if (p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) { RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ao_slices[i]), 0); } else { - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture_and_sampler(p_ao_slices[i], ssao.mirror_sampler), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture_and_sampler(p_ao_slices[i], ss_effects.mirror_sampler), 0); } RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_ao_pong_slices[i]), 1); @@ -1599,7 +1635,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep if (p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) { RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ao_pong_slices[i]), 0); } else { - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture_and_sampler(p_ao_pong_slices[i], ssao.mirror_sampler), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture_and_sampler(p_ao_pong_slices[i], ss_effects.mirror_sampler), 0); } RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_ao_slices[i]), 1); } @@ -1649,12 +1685,305 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep RD::get_singleton()->draw_command_end_label(); // Interleave } RD::get_singleton()->draw_command_end_label(); //SSAO - RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_TRANSFER); //wait for upcoming transfer + RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //wait for upcoming transfer int zero[1] = { 0 }; RD::get_singleton()->buffer_update(ssao.importance_map_load_counter, 0, sizeof(uint32_t), &zero, 0); //no barrier } +void EffectsRD::gather_ssil(RD::ComputeListID p_compute_list, const Vector<RID> p_ssil_slices, const Vector<RID> p_edges_slices, const SSILSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set, RID p_projection_uniform_set) { + RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_gather_uniform_set, 0); + if ((p_settings.quality == RS::ENV_SSIL_QUALITY_ULTRA) && !p_adaptive_base_pass) { + RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_importance_map_uniform_set, 1); + } + RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_projection_uniform_set, 3); + + for (int i = 0; i < 4; i++) { + if ((p_settings.quality == RS::ENV_SSIL_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) { + continue; + } + + ssil.gather_push_constant.pass_coord_offset[0] = i % 2; + ssil.gather_push_constant.pass_coord_offset[1] = i / 2; + ssil.gather_push_constant.pass_uv_offset[0] = ((i % 2) - 0.0) / p_settings.full_screen_size.x; + ssil.gather_push_constant.pass_uv_offset[1] = ((i / 2) - 0.0) / p_settings.full_screen_size.y; + ssil.gather_push_constant.pass = i; + RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, _get_compute_uniform_set_from_image_pair(p_ssil_slices[i], p_edges_slices[i]), 2); + RD::get_singleton()->compute_list_set_push_constant(p_compute_list, &ssil.gather_push_constant, sizeof(SSILGatherPushConstant)); + + Size2i size = Size2i(p_settings.full_screen_size.x >> (p_settings.half_size ? 2 : 1), p_settings.full_screen_size.y >> (p_settings.half_size ? 2 : 1)); + + RD::get_singleton()->compute_list_dispatch_threads(p_compute_list, size.x, size.y, 1); + } + RD::get_singleton()->compute_list_add_barrier(p_compute_list); +} + +void EffectsRD::screen_space_indirect_lighting(RID p_diffuse, RID p_destination, RID p_normal_buffer, RID p_depth_mipmaps_texture, RID p_ssil, const Vector<RID> p_ssil_slices, RID p_ssil_pong, const Vector<RID> p_ssil_pong_slices, RID p_importance_map, RID p_importance_map_pong, RID p_edges, const Vector<RID> p_edges_slices, const CameraMatrix &p_projection, const CameraMatrix &p_last_projection, const SSILSettings &p_settings, bool p_invalidate_uniform_sets, RID &r_gather_uniform_set, RID &r_importance_map_uniform_set, RID &r_projection_uniform_set) { + RD::get_singleton()->draw_command_begin_label("Process Screen Space Indirect Lighting"); + //Store projection info before starting the compute list + SSILProjectionUniforms projection_uniforms; + store_camera(p_last_projection, projection_uniforms.inv_last_frame_projection_matrix); + + RD::get_singleton()->buffer_update(ssil.projection_uniform_buffer, 0, sizeof(SSILProjectionUniforms), &projection_uniforms); + + memset(&ssil.gather_push_constant, 0, sizeof(SSILGatherPushConstant)); + + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + { + RD::get_singleton()->draw_command_begin_label("Gather Samples"); + ssil.gather_push_constant.screen_size[0] = p_settings.full_screen_size.x; + ssil.gather_push_constant.screen_size[1] = p_settings.full_screen_size.y; + + ssil.gather_push_constant.half_screen_pixel_size[0] = 1.0 / p_settings.half_screen_size.x; + ssil.gather_push_constant.half_screen_pixel_size[1] = 1.0 / p_settings.half_screen_size.y; + float tan_half_fov_x = 1.0 / p_projection.matrix[0][0]; + float tan_half_fov_y = 1.0 / p_projection.matrix[1][1]; + ssil.gather_push_constant.NDC_to_view_mul[0] = tan_half_fov_x * 2.0; + ssil.gather_push_constant.NDC_to_view_mul[1] = tan_half_fov_y * -2.0; + ssil.gather_push_constant.NDC_to_view_add[0] = tan_half_fov_x * -1.0; + ssil.gather_push_constant.NDC_to_view_add[1] = tan_half_fov_y; + ssil.gather_push_constant.z_near = p_projection.get_z_near(); + ssil.gather_push_constant.z_far = p_projection.get_z_far(); + ssil.gather_push_constant.is_orthogonal = p_projection.is_orthogonal(); + + ssil.gather_push_constant.half_screen_pixel_size_x025[0] = ssil.gather_push_constant.half_screen_pixel_size[0] * 0.25; + ssil.gather_push_constant.half_screen_pixel_size_x025[1] = ssil.gather_push_constant.half_screen_pixel_size[1] * 0.25; + + ssil.gather_push_constant.radius = p_settings.radius; + float radius_near_limit = (p_settings.radius * 1.2f); + if (p_settings.quality <= RS::ENV_SSIL_QUALITY_LOW) { + radius_near_limit *= 1.50f; + + if (p_settings.quality == RS::ENV_SSIL_QUALITY_VERY_LOW) { + ssil.gather_push_constant.radius *= 0.8f; + } + } + radius_near_limit /= tan_half_fov_y; + ssil.gather_push_constant.intensity = p_settings.intensity * Math_PI; + ssil.gather_push_constant.fade_out_mul = -1.0 / (p_settings.fadeout_to - p_settings.fadeout_from); + ssil.gather_push_constant.fade_out_add = p_settings.fadeout_from / (p_settings.fadeout_to - p_settings.fadeout_from) + 1.0; + ssil.gather_push_constant.inv_radius_near_limit = 1.0f / radius_near_limit; + ssil.gather_push_constant.neg_inv_radius = -1.0 / ssil.gather_push_constant.radius; + ssil.gather_push_constant.normal_rejection_amount = p_settings.normal_rejection; + + ssil.gather_push_constant.load_counter_avg_div = 9.0 / float((p_settings.quarter_screen_size.x) * (p_settings.quarter_screen_size.y) * 255); + ssil.gather_push_constant.adaptive_sample_limit = p_settings.adaptive_target; + + ssil.gather_push_constant.quality = MAX(0, p_settings.quality - 1); + ssil.gather_push_constant.size_multiplier = p_settings.half_size ? 2 : 1; + + if (p_invalidate_uniform_sets) { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.binding = 0; + u.ids.push_back(default_mipmap_sampler); + u.ids.push_back(p_diffuse); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 1; + u.ids.push_back(ssil.projection_uniform_buffer); + uniforms.push_back(u); + } + r_projection_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssil.gather_shader.version_get_shader(ssil.gather_shader_version, 0), 3); + } + + if (p_invalidate_uniform_sets) { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.binding = 0; + u.ids.push_back(default_sampler); + u.ids.push_back(p_depth_mipmaps_texture); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 1; + u.ids.push_back(p_normal_buffer); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 2; + u.ids.push_back(ss_effects.gather_constants_buffer); + uniforms.push_back(u); + } + r_gather_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssil.gather_shader.version_get_shader(ssil.gather_shader_version, 0), 0); + } + + if (p_invalidate_uniform_sets) { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 0; + u.ids.push_back(p_ssil_pong); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.binding = 1; + u.ids.push_back(default_sampler); + u.ids.push_back(p_importance_map); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 2; + u.ids.push_back(ssil.importance_map_load_counter); + uniforms.push_back(u); + } + r_importance_map_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssil.gather_shader.version_get_shader(ssil.gather_shader_version, 2), 1); + } + + if (p_settings.quality == RS::ENV_SSIL_QUALITY_ULTRA) { + RD::get_singleton()->draw_command_begin_label("Generate Importance Map"); + ssil.importance_map_push_constant.half_screen_pixel_size[0] = 1.0 / p_settings.half_screen_size.x; + ssil.importance_map_push_constant.half_screen_pixel_size[1] = 1.0 / p_settings.half_screen_size.y; + ssil.importance_map_push_constant.intensity = p_settings.intensity * Math_PI; + //base pass + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_GATHER_BASE]); + gather_ssil(compute_list, p_ssil_pong_slices, p_edges_slices, p_settings, true, r_gather_uniform_set, r_importance_map_uniform_set, r_projection_uniform_set); + //generate importance map + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_GENERATE_IMPORTANCE_MAP]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ssil_pong), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_importance_map), 1); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssil.importance_map_push_constant, sizeof(SSILImportanceMapPushConstant)); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_settings.quarter_screen_size.x, p_settings.quarter_screen_size.y, 1); + RD::get_singleton()->compute_list_add_barrier(compute_list); + // process Importance Map A + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_PROCESS_IMPORTANCE_MAPA]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_importance_map), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_importance_map_pong), 1); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssil.importance_map_push_constant, sizeof(SSILImportanceMapPushConstant)); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_settings.quarter_screen_size.x, p_settings.quarter_screen_size.y, 1); + RD::get_singleton()->compute_list_add_barrier(compute_list); + // process Importance Map B + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_PROCESS_IMPORTANCE_MAPB]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_importance_map_pong), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_importance_map), 1); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, ssil.counter_uniform_set, 2); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssil.importance_map_push_constant, sizeof(SSILImportanceMapPushConstant)); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_settings.quarter_screen_size.x, p_settings.quarter_screen_size.y, 1); + RD::get_singleton()->compute_list_add_barrier(compute_list); + + RD::get_singleton()->draw_command_end_label(); // Importance Map + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_GATHER_ADAPTIVE]); + } else { + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_GATHER]); + } + + gather_ssil(compute_list, p_ssil_slices, p_edges_slices, p_settings, false, r_gather_uniform_set, r_importance_map_uniform_set, r_projection_uniform_set); + RD::get_singleton()->draw_command_end_label(); //Gather + } + + { + RD::get_singleton()->draw_command_begin_label("Edge Aware Blur"); + ssil.blur_push_constant.edge_sharpness = 1.0 - p_settings.sharpness; + ssil.blur_push_constant.half_screen_pixel_size[0] = 1.0 / p_settings.half_screen_size.x; + ssil.blur_push_constant.half_screen_pixel_size[1] = 1.0 / p_settings.half_screen_size.y; + + int blur_passes = p_settings.quality > RS::ENV_SSIL_QUALITY_VERY_LOW ? p_settings.blur_passes : 1; + + for (int pass = 0; pass < blur_passes; pass++) { + int blur_pipeline = SSIL_BLUR_PASS; + if (p_settings.quality > RS::ENV_SSIL_QUALITY_VERY_LOW) { + blur_pipeline = SSIL_BLUR_PASS_SMART; + if (pass < blur_passes - 2) { + blur_pipeline = SSIL_BLUR_PASS_WIDE; + } + } + + for (int i = 0; i < 4; i++) { + if ((p_settings.quality == RS::ENV_SSIL_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) { + continue; + } + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[blur_pipeline]); + if (pass % 2 == 0) { + if (p_settings.quality == RS::ENV_SSIL_QUALITY_VERY_LOW) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ssil_slices[i]), 0); + } else { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture_and_sampler(p_ssil_slices[i], ss_effects.mirror_sampler), 0); + } + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_ssil_pong_slices[i]), 1); + } else { + if (p_settings.quality == RS::ENV_SSIL_QUALITY_VERY_LOW) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ssil_pong_slices[i]), 0); + } else { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture_and_sampler(p_ssil_pong_slices[i], ss_effects.mirror_sampler), 0); + } + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_ssil_slices[i]), 1); + } + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_edges_slices[i]), 2); + + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssil.blur_push_constant, sizeof(SSILBlurPushConstant)); + + int x_groups = (p_settings.full_screen_size.x >> (p_settings.half_size ? 2 : 1)); + int y_groups = (p_settings.full_screen_size.y >> (p_settings.half_size ? 2 : 1)); + + RD::get_singleton()->compute_list_dispatch_threads(compute_list, x_groups, y_groups, 1); + if (p_settings.quality > RS::ENV_SSIL_QUALITY_VERY_LOW) { + RD::get_singleton()->compute_list_add_barrier(compute_list); + } + } + } + + RD::get_singleton()->draw_command_end_label(); // Blur + } + + { + RD::get_singleton()->draw_command_begin_label("Interleave Buffers"); + ssil.interleave_push_constant.inv_sharpness = 1.0 - p_settings.sharpness; + ssil.interleave_push_constant.pixel_size[0] = 1.0 / p_settings.full_screen_size.x; + ssil.interleave_push_constant.pixel_size[1] = 1.0 / p_settings.full_screen_size.y; + ssil.interleave_push_constant.size_modifier = uint32_t(p_settings.half_size ? 4 : 2); + + int interleave_pipeline = SSIL_INTERLEAVE_HALF; + if (p_settings.quality == RS::ENV_SSIL_QUALITY_LOW) { + interleave_pipeline = SSIL_INTERLEAVE; + } else if (p_settings.quality >= RS::ENV_SSIL_QUALITY_MEDIUM) { + interleave_pipeline = SSIL_INTERLEAVE_SMART; + } + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[interleave_pipeline]); + + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_destination), 0); + + if (p_settings.quality > RS::ENV_SSIL_QUALITY_VERY_LOW && p_settings.blur_passes % 2 == 0) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ssil), 1); + } else { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ssil_pong), 1); + } + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_edges), 2); + + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssil.interleave_push_constant, sizeof(SSILInterleavePushConstant)); + + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_settings.full_screen_size.x, p_settings.full_screen_size.y, 1); + RD::get_singleton()->compute_list_add_barrier(compute_list); + RD::get_singleton()->draw_command_end_label(); // Interleave + } + + RD::get_singleton()->draw_command_end_label(); // SSIL + + RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); + + int zero[1] = { 0 }; + RD::get_singleton()->buffer_update(ssil.importance_map_load_counter, 0, sizeof(uint32_t), &zero, 0); //no barrier +} + void EffectsRD::roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve) { roughness_limiter.push_constant.screen_size[0] = p_size.x; roughness_limiter.push_constant.screen_size[1] = p_size.y; @@ -2173,63 +2502,36 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) { } if (!prefer_raster_effects) { - // Initialize ssao - - RD::SamplerState sampler; - sampler.mag_filter = RD::SAMPLER_FILTER_NEAREST; - sampler.min_filter = RD::SAMPLER_FILTER_NEAREST; - sampler.mip_filter = RD::SAMPLER_FILTER_NEAREST; - sampler.repeat_u = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; - sampler.repeat_v = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; - sampler.repeat_w = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; - sampler.max_lod = 4; - - ssao.mirror_sampler = RD::get_singleton()->sampler_create(sampler); - - uint32_t pipeline = 0; - { - Vector<String> ssao_modes; - ssao_modes.push_back("\n"); - ssao_modes.push_back("\n#define USE_HALF_SIZE\n"); - ssao_modes.push_back("\n#define GENERATE_MIPS\n"); - ssao_modes.push_back("\n#define GENERATE_MIPS\n#define USE_HALF_SIZE"); - ssao_modes.push_back("\n#define USE_HALF_BUFFERS\n"); - ssao_modes.push_back("\n#define USE_HALF_BUFFERS\n#define USE_HALF_SIZE"); - - ssao.downsample_shader.initialize(ssao_modes); - - ssao.downsample_shader_version = ssao.downsample_shader.version_create(); - - for (int i = 0; i <= SSAO_DOWNSAMPLE_HALF_RES_HALF; i++) { - ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.downsample_shader.version_get_shader(ssao.downsample_shader_version, i)); - pipeline++; - } - } { - Vector<String> ssao_modes; - - ssao_modes.push_back("\n"); - ssao_modes.push_back("\n#define SSAO_BASE\n"); - ssao_modes.push_back("\n#define ADAPTIVE\n"); - - ssao.gather_shader.initialize(ssao_modes); - - ssao.gather_shader_version = ssao.gather_shader.version_create(); - - for (int i = SSAO_GATHER; i <= SSAO_GATHER_ADAPTIVE; i++) { - ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.gather_shader.version_get_shader(ssao.gather_shader_version, i - SSAO_GATHER)); - pipeline++; + // Initialize depth buffer for screen space effects + Vector<String> downsampler_modes; + downsampler_modes.push_back("\n"); + downsampler_modes.push_back("\n#define USE_HALF_SIZE\n"); + downsampler_modes.push_back("\n#define GENERATE_MIPS\n"); + downsampler_modes.push_back("\n#define GENERATE_MIPS\n#define USE_HALF_SIZE\n"); + downsampler_modes.push_back("\n#define USE_HALF_BUFFERS\n"); + downsampler_modes.push_back("\n#define USE_HALF_BUFFERS\n#define USE_HALF_SIZE\n"); + downsampler_modes.push_back("\n#define GENERATE_MIPS\n#define GENERATE_FULL_MIPS"); + + ss_effects.downsample_shader.initialize(downsampler_modes); + + ss_effects.downsample_shader_version = ss_effects.downsample_shader.version_create(); + + for (int i = 0; i < SS_EFFECTS_MAX; i++) { + ss_effects.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ss_effects.downsample_shader.version_get_shader(ss_effects.downsample_shader_version, i)); } - ssao.gather_constants_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SSAOGatherConstants)); - SSAOGatherConstants gather_constants; + ss_effects.gather_constants_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SSEffectsGatherConstants)); + SSEffectsGatherConstants gather_constants; const int sub_pass_count = 5; for (int pass = 0; pass < 4; pass++) { for (int subPass = 0; subPass < sub_pass_count; subPass++) { int a = pass; + int b = subPass; + int spmap[5]{ 0, 1, 4, 3, 2 }; - int b = spmap[subPass]; + b = spmap[subPass]; float ca, sa; float angle0 = (float(a) + float(b) / float(sub_pass_count)) * Math_PI * 0.5f; @@ -2246,72 +2548,105 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) { } } - RD::get_singleton()->buffer_update(ssao.gather_constants_buffer, 0, sizeof(SSAOGatherConstants), &gather_constants); + RD::get_singleton()->buffer_update(ss_effects.gather_constants_buffer, 0, sizeof(SSEffectsGatherConstants), &gather_constants); } + { - Vector<String> ssao_modes; - ssao_modes.push_back("\n#define GENERATE_MAP\n"); - ssao_modes.push_back("\n#define PROCESS_MAPA\n"); - ssao_modes.push_back("\n#define PROCESS_MAPB\n"); + // Initialize ssao - ssao.importance_map_shader.initialize(ssao_modes); + RD::SamplerState sampler; + sampler.mag_filter = RD::SAMPLER_FILTER_NEAREST; + sampler.min_filter = RD::SAMPLER_FILTER_NEAREST; + sampler.mip_filter = RD::SAMPLER_FILTER_NEAREST; + sampler.repeat_u = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; + sampler.repeat_v = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; + sampler.repeat_w = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; + sampler.max_lod = 4; - ssao.importance_map_shader_version = ssao.importance_map_shader.version_create(); + ss_effects.mirror_sampler = RD::get_singleton()->sampler_create(sampler); - for (int i = SSAO_GENERATE_IMPORTANCE_MAP; i <= SSAO_PROCESS_IMPORTANCE_MAPB; i++) { - ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.importance_map_shader.version_get_shader(ssao.importance_map_shader_version, i - SSAO_GENERATE_IMPORTANCE_MAP)); + uint32_t pipeline = 0; + { + Vector<String> ssao_modes; - pipeline++; - } - ssao.importance_map_load_counter = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t)); - int zero[1] = { 0 }; - RD::get_singleton()->buffer_update(ssao.importance_map_load_counter, 0, sizeof(uint32_t), &zero); - RD::get_singleton()->set_resource_name(ssao.importance_map_load_counter, "Importance Map Load Counter"); + ssao_modes.push_back("\n"); + ssao_modes.push_back("\n#define SSAO_BASE\n"); + ssao_modes.push_back("\n#define ADAPTIVE\n"); - Vector<RD::Uniform> uniforms; + ssao.gather_shader.initialize(ssao_modes); + + ssao.gather_shader_version = ssao.gather_shader.version_create(); + + for (int i = 0; i <= SSAO_GATHER_ADAPTIVE; i++) { + ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.gather_shader.version_get_shader(ssao.gather_shader_version, i)); + pipeline++; + } + } { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.binding = 0; - u.ids.push_back(ssao.importance_map_load_counter); - uniforms.push_back(u); + Vector<String> ssao_modes; + ssao_modes.push_back("\n#define GENERATE_MAP\n"); + ssao_modes.push_back("\n#define PROCESS_MAPA\n"); + ssao_modes.push_back("\n#define PROCESS_MAPB\n"); + + ssao.importance_map_shader.initialize(ssao_modes); + + ssao.importance_map_shader_version = ssao.importance_map_shader.version_create(); + + for (int i = SSAO_GENERATE_IMPORTANCE_MAP; i <= SSAO_PROCESS_IMPORTANCE_MAPB; i++) { + ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.importance_map_shader.version_get_shader(ssao.importance_map_shader_version, i - SSAO_GENERATE_IMPORTANCE_MAP)); + + pipeline++; + } + ssao.importance_map_load_counter = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t)); + int zero[1] = { 0 }; + RD::get_singleton()->buffer_update(ssao.importance_map_load_counter, 0, sizeof(uint32_t), &zero); + RD::get_singleton()->set_resource_name(ssao.importance_map_load_counter, "Importance Map Load Counter"); + + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 0; + u.ids.push_back(ssao.importance_map_load_counter); + uniforms.push_back(u); + } + ssao.counter_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.importance_map_shader.version_get_shader(ssao.importance_map_shader_version, 2), 2); + RD::get_singleton()->set_resource_name(ssao.counter_uniform_set, "Load Counter Uniform Set"); } - ssao.counter_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.importance_map_shader.version_get_shader(ssao.importance_map_shader_version, 2), 2); - RD::get_singleton()->set_resource_name(ssao.counter_uniform_set, "Load Counter Uniform Set"); - } - { - Vector<String> ssao_modes; - ssao_modes.push_back("\n#define MODE_NON_SMART\n"); - ssao_modes.push_back("\n#define MODE_SMART\n"); - ssao_modes.push_back("\n#define MODE_WIDE\n"); + { + Vector<String> ssao_modes; + ssao_modes.push_back("\n#define MODE_NON_SMART\n"); + ssao_modes.push_back("\n#define MODE_SMART\n"); + ssao_modes.push_back("\n#define MODE_WIDE\n"); - ssao.blur_shader.initialize(ssao_modes); + ssao.blur_shader.initialize(ssao_modes); - ssao.blur_shader_version = ssao.blur_shader.version_create(); + ssao.blur_shader_version = ssao.blur_shader.version_create(); - for (int i = SSAO_BLUR_PASS; i <= SSAO_BLUR_PASS_WIDE; i++) { - ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.blur_shader.version_get_shader(ssao.blur_shader_version, i - SSAO_BLUR_PASS)); + for (int i = SSAO_BLUR_PASS; i <= SSAO_BLUR_PASS_WIDE; i++) { + ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.blur_shader.version_get_shader(ssao.blur_shader_version, i - SSAO_BLUR_PASS)); - pipeline++; + pipeline++; + } } - } - { - Vector<String> ssao_modes; - ssao_modes.push_back("\n#define MODE_NON_SMART\n"); - ssao_modes.push_back("\n#define MODE_SMART\n"); - ssao_modes.push_back("\n#define MODE_HALF\n"); - - ssao.interleave_shader.initialize(ssao_modes); - - ssao.interleave_shader_version = ssao.interleave_shader.version_create(); - for (int i = SSAO_INTERLEAVE; i <= SSAO_INTERLEAVE_HALF; i++) { - ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.interleave_shader.version_get_shader(ssao.interleave_shader_version, i - SSAO_INTERLEAVE)); - RD::get_singleton()->set_resource_name(ssao.pipelines[pipeline], "Interleave Pipeline " + itos(i)); - pipeline++; + { + Vector<String> ssao_modes; + ssao_modes.push_back("\n#define MODE_NON_SMART\n"); + ssao_modes.push_back("\n#define MODE_SMART\n"); + ssao_modes.push_back("\n#define MODE_HALF\n"); + + ssao.interleave_shader.initialize(ssao_modes); + + ssao.interleave_shader_version = ssao.interleave_shader.version_create(); + for (int i = SSAO_INTERLEAVE; i <= SSAO_INTERLEAVE_HALF; i++) { + ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.interleave_shader.version_get_shader(ssao.interleave_shader_version, i - SSAO_INTERLEAVE)); + RD::get_singleton()->set_resource_name(ssao.pipelines[pipeline], "Interleave Pipeline " + itos(i)); + pipeline++; + } } - } - ERR_FAIL_COND(pipeline != SSAO_MAX); + ERR_FAIL_COND(pipeline != SSAO_MAX); + } } if (!prefer_raster_effects) { @@ -2504,6 +2839,79 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) { } { + Vector<String> ssil_modes; + ssil_modes.push_back("\n"); + ssil_modes.push_back("\n#define SSIL_BASE\n"); + ssil_modes.push_back("\n#define ADAPTIVE\n"); + + ssil.gather_shader.initialize(ssil_modes); + + ssil.gather_shader_version = ssil.gather_shader.version_create(); + + for (int i = SSIL_GATHER; i <= SSIL_GATHER_ADAPTIVE; i++) { + ssil.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssil.gather_shader.version_get_shader(ssil.gather_shader_version, i)); + } + ssil.projection_uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SSILProjectionUniforms)); + } + + { + Vector<String> ssil_modes; + ssil_modes.push_back("\n#define GENERATE_MAP\n"); + ssil_modes.push_back("\n#define PROCESS_MAPA\n"); + ssil_modes.push_back("\n#define PROCESS_MAPB\n"); + + ssil.importance_map_shader.initialize(ssil_modes); + + ssil.importance_map_shader_version = ssil.importance_map_shader.version_create(); + + for (int i = SSIL_GENERATE_IMPORTANCE_MAP; i <= SSIL_PROCESS_IMPORTANCE_MAPB; i++) { + ssil.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssil.importance_map_shader.version_get_shader(ssil.importance_map_shader_version, i - SSIL_GENERATE_IMPORTANCE_MAP)); + } + ssil.importance_map_load_counter = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t)); + int zero[1] = { 0 }; + RD::get_singleton()->buffer_update(ssil.importance_map_load_counter, 0, sizeof(uint32_t), &zero); + RD::get_singleton()->set_resource_name(ssil.importance_map_load_counter, "Importance Map Load Counter"); + + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 0; + u.ids.push_back(ssil.importance_map_load_counter); + uniforms.push_back(u); + } + ssil.counter_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssil.importance_map_shader.version_get_shader(ssil.importance_map_shader_version, 2), 2); + RD::get_singleton()->set_resource_name(ssil.counter_uniform_set, "Load Counter Uniform Set"); + } + { + Vector<String> ssil_modes; + ssil_modes.push_back("\n#define MODE_NON_SMART\n"); + ssil_modes.push_back("\n#define MODE_SMART\n"); + ssil_modes.push_back("\n#define MODE_WIDE\n"); + + ssil.blur_shader.initialize(ssil_modes); + + ssil.blur_shader_version = ssil.blur_shader.version_create(); + for (int i = SSIL_BLUR_PASS; i <= SSIL_BLUR_PASS_WIDE; i++) { + ssil.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssil.blur_shader.version_get_shader(ssil.blur_shader_version, i - SSIL_BLUR_PASS)); + } + } + + { + Vector<String> ssil_modes; + ssil_modes.push_back("\n#define MODE_NON_SMART\n"); + ssil_modes.push_back("\n#define MODE_SMART\n"); + ssil_modes.push_back("\n#define MODE_HALF\n"); + + ssil.interleave_shader.initialize(ssil_modes); + + ssil.interleave_shader_version = ssil.interleave_shader.version_create(); + for (int i = SSIL_INTERLEAVE; i <= SSIL_INTERLEAVE_HALF; i++) { + ssil.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssil.interleave_shader.version_get_shader(ssil.interleave_shader_version, i - SSIL_INTERLEAVE)); + } + } + + { Vector<String> resolve_modes; resolve_modes.push_back("\n#define MODE_RESOLVE_GI\n"); resolve_modes.push_back("\n#define MODE_RESOLVE_GI\n#define VOXEL_GI_RESOLVE\n"); @@ -2600,20 +3008,26 @@ EffectsRD::~EffectsRD() { copy.shader.version_free(copy.shader_version); resolve.shader.version_free(resolve.shader_version); specular_merge.shader.version_free(specular_merge.shader_version); + ss_effects.downsample_shader.version_free(ss_effects.downsample_shader_version); ssao.blur_shader.version_free(ssao.blur_shader_version); ssao.gather_shader.version_free(ssao.gather_shader_version); - ssao.downsample_shader.version_free(ssao.downsample_shader_version); ssao.interleave_shader.version_free(ssao.interleave_shader_version); ssao.importance_map_shader.version_free(ssao.importance_map_shader_version); + ssil.blur_shader.version_free(ssil.blur_shader_version); + ssil.gather_shader.version_free(ssil.gather_shader_version); + ssil.interleave_shader.version_free(ssil.interleave_shader_version); + ssil.importance_map_shader.version_free(ssil.importance_map_shader_version); roughness_limiter.shader.version_free(roughness_limiter.shader_version); ssr.shader.version_free(ssr.shader_version); ssr_filter.shader.version_free(ssr_filter.shader_version); ssr_scale.shader.version_free(ssr_scale.shader_version); sss.shader.version_free(sss.shader_version); - RD::get_singleton()->free(ssao.mirror_sampler); - RD::get_singleton()->free(ssao.gather_constants_buffer); + RD::get_singleton()->free(ss_effects.mirror_sampler); + RD::get_singleton()->free(ss_effects.gather_constants_buffer); RD::get_singleton()->free(ssao.importance_map_load_counter); + RD::get_singleton()->free(ssil.importance_map_load_counter); + RD::get_singleton()->free(ssil.projection_uniform_buffer); } copy_to_fb.shader.version_free(copy_to_fb.shader_version); cube_to_dp.shader.version_free(cube_to_dp.shader_version); diff --git a/servers/rendering/renderer_rd/effects_rd.h b/servers/rendering/renderer_rd/effects_rd.h index 6037127e82..747f2c8941 100644 --- a/servers/rendering/renderer_rd/effects_rd.h +++ b/servers/rendering/renderer_rd/effects_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -55,11 +55,15 @@ #include "servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/sort.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/specular_merge.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/ss_effects_downsample.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/ssao.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/ssao_blur.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/ssao_downsample.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/ssao_interleave.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/ssil.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/ssil_blur.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/ssil_importance_map.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/ssil_interleave.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/tonemap.glsl.gen.h" #include "servers/rendering/renderer_scene_render.h" @@ -399,13 +403,47 @@ private: PipelineCacheRD raster_pipelines[BOKEH_MAX]; } bokeh; + struct SSEffectsDownsamplePushConstant { + float pixel_size[2]; + float z_far; + float z_near; + uint32_t orthogonal; + float radius_sq; + uint32_t pad[2]; + }; + + enum SSEffectsMode { + SS_EFFECTS_DOWNSAMPLE, + SS_EFFECTS_DOWNSAMPLE_HALF_RES, + SS_EFFECTS_DOWNSAMPLE_MIPMAP, + SS_EFFECTS_DOWNSAMPLE_MIPMAP_HALF_RES, + SS_EFFECTS_DOWNSAMPLE_HALF, + SS_EFFECTS_DOWNSAMPLE_HALF_RES_HALF, + SS_EFFECTS_DOWNSAMPLE_FULL_MIPS, + SS_EFFECTS_MAX + }; + + struct SSEffectsGatherConstants { + float rotation_matrices[80]; //5 vec4s * 4 + }; + + struct SSEffects { + SSEffectsDownsamplePushConstant downsample_push_constant; + SsEffectsDownsampleShaderRD downsample_shader; + RID downsample_shader_version; + RID downsample_uniform_set; + bool used_half_size_last_frame = false; + bool used_mips_last_frame = false; + bool used_full_mips_last_frame = false; + + RID gather_constants_buffer; + + RID mirror_sampler; + + RID pipelines[SS_EFFECTS_MAX]; + } ss_effects; + enum SSAOMode { - SSAO_DOWNSAMPLE, - SSAO_DOWNSAMPLE_HALF_RES, - SSAO_DOWNSAMPLE_MIPMAP, - SSAO_DOWNSAMPLE_MIPMAP_HALF_RES, - SSAO_DOWNSAMPLE_HALF, - SSAO_DOWNSAMPLE_HALF_RES_HALF, SSAO_GATHER, SSAO_GATHER_BASE, SSAO_GATHER_ADAPTIVE, @@ -421,15 +459,6 @@ private: SSAO_MAX }; - struct SSAODownsamplePushConstant { - float pixel_size[2]; - float z_far; - float z_near; - uint32_t orthogonal; - float radius_sq; - uint32_t pad[2]; - }; - struct SSAOGatherPushConstant { int32_t screen_size[2]; int pass; @@ -455,7 +484,7 @@ private: float horizon_angle_threshold; float inv_radius_near_limit; - bool is_orthogonal; + uint32_t is_orthogonal; float neg_inv_radius; float load_counter_avg_div; float adaptive_sample_limit; @@ -464,10 +493,6 @@ private: float pass_uv_offset[2]; }; - struct SSAOGatherConstants { - float rotation_matrices[80]; //5 vec4s * 4 - }; - struct SSAOImportanceMapPushConstant { float half_screen_pixel_size[2]; float intensity; @@ -487,15 +512,9 @@ private: }; struct SSAO { - SSAODownsamplePushConstant downsample_push_constant; - SsaoDownsampleShaderRD downsample_shader; - RID downsample_shader_version; - SSAOGatherPushConstant gather_push_constant; SsaoShaderRD gather_shader; RID gather_shader_version; - RID gather_constants_buffer; - bool gather_initialized = false; SSAOImportanceMapPushConstant importance_map_push_constant; SsaoImportanceMapShaderRD importance_map_shader; @@ -511,10 +530,104 @@ private: SsaoInterleaveShaderRD interleave_shader; RID interleave_shader_version; - RID mirror_sampler; RID pipelines[SSAO_MAX]; } ssao; + enum SSILMode { + SSIL_GATHER, + SSIL_GATHER_BASE, + SSIL_GATHER_ADAPTIVE, + SSIL_GENERATE_IMPORTANCE_MAP, + SSIL_PROCESS_IMPORTANCE_MAPA, + SSIL_PROCESS_IMPORTANCE_MAPB, + SSIL_BLUR_PASS, + SSIL_BLUR_PASS_SMART, + SSIL_BLUR_PASS_WIDE, + SSIL_INTERLEAVE, + SSIL_INTERLEAVE_SMART, + SSIL_INTERLEAVE_HALF, + SSIL_MAX + }; + + struct SSILGatherPushConstant { + int32_t screen_size[2]; + int pass; + int quality; + + float half_screen_pixel_size[2]; + float half_screen_pixel_size_x025[2]; + + float NDC_to_view_mul[2]; + float NDC_to_view_add[2]; + + float pad2[2]; + float z_near; + float z_far; + + float radius; + float intensity; + int size_multiplier; + int pad; + + float fade_out_mul; + float fade_out_add; + float normal_rejection_amount; + float inv_radius_near_limit; + + uint32_t is_orthogonal; + float neg_inv_radius; + float load_counter_avg_div; + float adaptive_sample_limit; + + int32_t pass_coord_offset[2]; + float pass_uv_offset[2]; + }; + + struct SSILImportanceMapPushConstant { + float half_screen_pixel_size[2]; + float intensity; + float pad; + }; + + struct SSILBlurPushConstant { + float edge_sharpness; + float pad; + float half_screen_pixel_size[2]; + }; + + struct SSILInterleavePushConstant { + float inv_sharpness; + uint32_t size_modifier; + float pixel_size[2]; + }; + + struct SSILProjectionUniforms { + float inv_last_frame_projection_matrix[16]; + }; + + struct SSIL { + SSILGatherPushConstant gather_push_constant; + SsilShaderRD gather_shader; + RID gather_shader_version; + RID projection_uniform_buffer; + + SSILImportanceMapPushConstant importance_map_push_constant; + SsilImportanceMapShaderRD importance_map_shader; + RID importance_map_shader_version; + RID importance_map_load_counter; + RID counter_uniform_set; + + SSILBlurPushConstant blur_push_constant; + SsilBlurShaderRD blur_shader; + RID blur_shader_version; + + SSILInterleavePushConstant interleave_push_constant; + SsilInterleaveShaderRD interleave_shader; + RID interleave_shader_version; + + RID pipelines[SSIL_MAX]; + } ssil; + struct RoughnessLimiterPushConstant { int32_t screen_size[2]; float curve; @@ -615,6 +728,7 @@ private: uint8_t metallic_mask[4]; float projection[16]; + float prev_projection[16]; }; struct ScreenSpaceReflection { @@ -879,11 +993,34 @@ public: Size2i quarter_screen_size = Size2i(); }; + struct SSILSettings { + float radius = 1.0; + float intensity = 2.0; + float sharpness = 0.98; + float normal_rejection = 1.0; + + RS::EnvironmentSSILQuality quality = RS::ENV_SSIL_QUALITY_MEDIUM; + bool half_size = true; + float adaptive_target = 0.5; + int blur_passes = 4; + float fadeout_from = 50.0; + float fadeout_to = 300.0; + + Size2i full_screen_size = Size2i(); + Size2i half_screen_size = Size2i(); + Size2i quarter_screen_size = Size2i(); + }; + void tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings); void tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_color, RD::FramebufferFormatID p_dst_format_id, const TonemapSettings &p_settings); + void downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_mipmaps, RS::EnvironmentSSAOQuality p_ssao_quality, RS::EnvironmentSSILQuality p_ssil_quality, bool p_invalidate_uniform_set, bool p_ssao_half_size, bool p_ssil_half_size, Size2i p_full_screen_size, const CameraMatrix &p_projection); + void gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set); - void generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_depth_mipmaps_texture, const Vector<RID> &depth_mipmaps, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets, RID &r_downsample_uniform_set, RID &r_gather_uniform_set, RID &r_importance_map_uniform_set); + void generate_ssao(RID p_normal_buffer, RID p_depth_mipmaps_texture, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets, RID &r_gather_uniform_set, RID &r_importance_map_uniform_set); + + void gather_ssil(RD::ComputeListID p_compute_list, const Vector<RID> p_ssil_slices, const Vector<RID> p_edges_slices, const SSILSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set, RID p_projection_uniform_set); + void screen_space_indirect_lighting(RID p_diffuse, RID p_destination, RID p_normal_buffer, RID p_depth_mipmaps_texture, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_importance_map, RID p_importance_map_pong, RID p_edges, const Vector<RID> p_edges_slices, const CameraMatrix &p_projection, const CameraMatrix &p_last_projection, const SSILSettings &p_settings, bool p_invalidate_uniform_sets, RID &r_gather_uniform_set, RID &r_importance_map_uniform_set, RID &r_projection_uniform_set); void roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve); void cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size); diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index 8fb276b8fb..1771ade012 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -730,7 +730,7 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat scene_state.ubo.ambient_light_color_energy[3] = 1.0; scene_state.ubo.use_ambient_cubemap = false; scene_state.ubo.use_reflection_cubemap = false; - scene_state.ubo.ssao_enabled = false; + scene_state.ubo.ss_effects_flags = 0; } else if (is_environment(p_render_data->environment)) { RS::EnvironmentBG env_bg = environment_get_background(p_render_data->environment); @@ -775,9 +775,14 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat scene_state.ubo.use_reflection_cubemap = false; } - scene_state.ubo.ssao_enabled = p_opaque_render_buffers && environment_is_ssao_enabled(p_render_data->environment); scene_state.ubo.ssao_ao_affect = environment_get_ssao_ao_affect(p_render_data->environment); scene_state.ubo.ssao_light_affect = environment_get_ssao_light_affect(p_render_data->environment); + uint32_t ss_flags = 0; + if (p_opaque_render_buffers) { + ss_flags |= environment_is_ssao_enabled(p_render_data->environment) ? 1 : 0; + ss_flags |= environment_is_ssil_enabled(p_render_data->environment) ? 2 : 0; + } + scene_state.ubo.ss_effects_flags = ss_flags; scene_state.ubo.fog_enabled = environment_is_fog_enabled(p_render_data->environment); scene_state.ubo.fog_density = environment_get_fog_density(p_render_data->environment); @@ -809,7 +814,7 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat scene_state.ubo.use_ambient_cubemap = false; scene_state.ubo.use_reflection_cubemap = false; - scene_state.ubo.ssao_enabled = false; + scene_state.ubo.ss_effects_flags = 0; } scene_state.ubo.roughness_limiter_enabled = p_opaque_render_buffers && screen_space_roughness_limiter_is_active(); @@ -1225,6 +1230,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co bool using_sdfgi = false; bool using_voxelgi = false; bool reverse_cull = false; + bool using_ssil = p_render_data->environment.is_valid() && environment_is_ssil_enabled(p_render_data->environment); if (render_buffer) { screen_size.x = render_buffer->width; @@ -1254,7 +1260,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co opaque_specular_framebuffer = render_buffer->color_specular_fb; } - } else if (p_render_data->environment.is_valid() && (environment_is_ssao_enabled(p_render_data->environment) || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER)) { + } else if (p_render_data->environment.is_valid() && (environment_is_ssao_enabled(p_render_data->environment) || using_ssil || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER)) { depth_pass_mode = PASS_MODE_DEPTH_NORMAL_ROUGHNESS; } @@ -1449,7 +1455,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co continue_depth = !finish_depth; } - _pre_opaque_render(p_render_data, using_ssao, using_sdfgi || using_voxelgi, render_buffer ? render_buffer->normal_roughness_buffer : RID(), render_buffer ? render_buffer->voxelgi_buffer : RID()); + _pre_opaque_render(p_render_data, using_ssao, using_ssil, using_sdfgi || using_voxelgi, render_buffer ? render_buffer->normal_roughness_buffer : RID(), render_buffer ? render_buffer->voxelgi_buffer : RID()); RD::get_singleton()->draw_command_begin_label("Render Opaque Pass"); @@ -1594,6 +1600,8 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co RD::get_singleton()->draw_command_end_label(); + RENDER_TIMESTAMP("Resolve"); + RD::get_singleton()->draw_command_begin_label("Resolve"); if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { @@ -1602,6 +1610,13 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co RD::get_singleton()->draw_command_end_label(); + RD::get_singleton()->draw_command_begin_label("Copy framebuffer for SSIL"); + if (using_ssil) { + RENDER_TIMESTAMP("Copy Final Framebuffer"); + _copy_framebuffer_to_ssil(p_render_data->render_buffers); + } + RD::get_singleton()->draw_command_end_label(); + if (p_render_data->render_buffers.is_valid()) { _debug_draw_cluster(p_render_data->render_buffers); @@ -2372,6 +2387,15 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend u.ids.push_back(vfog); uniforms.push_back(u); } + { + RD::Uniform u; + u.binding = 19; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID ssil = rb ? render_buffers_get_ssil_texture(p_render_data->render_buffers) : RID(); + RID texture = ssil.is_valid() ? ssil : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); + u.ids.push_back(texture); + uniforms.push_back(u); + } } if (p_index >= (int)render_pass_uniform_sets.size()) { diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h index d6ab4d1db2..b2309996a7 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -251,7 +251,7 @@ class RenderForwardClustered : public RendererSceneRenderRD { float z_far; float z_near; - uint32_t ssao_enabled; + uint32_t ss_effects_flags; float ssao_light_affect; float ssao_ao_affect; uint32_t roughness_limiter_enabled; diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp index 768bd1de9d..0cdcbc952d 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -44,7 +44,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { uniforms.clear(); uses_screen_texture = false; - if (code == String()) { + if (code.is_empty()) { return; //just invalid, but no error } diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h index f2a55939f4..98448ce846 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 445623fb86..fc2bc1cadf 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -669,7 +669,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color RD::get_singleton()->draw_command_end_label(); // Setup Sky resolution buffers } - _pre_opaque_render(p_render_data, false, false, RID(), RID()); + _pre_opaque_render(p_render_data, false, false, false, RID(), RID()); uint32_t spec_constant_base_flags = 0; diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h index 485d08b589..0ef1fe6ceb 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp index e6d9a60f94..9b96cc18bc 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -47,7 +47,7 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { uniforms.clear(); uses_screen_texture = false; - if (code == String()) { + if (code.is_empty()) { return; //just invalid, but no error } diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h index 392fac1e3e..770f9bde3b 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/pipeline_cache_rd.cpp b/servers/rendering/renderer_rd/pipeline_cache_rd.cpp index 0d60052666..e812a48d3d 100644 --- a/servers/rendering/renderer_rd/pipeline_cache_rd.cpp +++ b/servers/rendering/renderer_rd/pipeline_cache_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/pipeline_cache_rd.h b/servers/rendering/renderer_rd/pipeline_cache_rd.h index e52f47fa47..8d82480b38 100644 --- a/servers/rendering/renderer_rd/pipeline_cache_rd.h +++ b/servers/rendering/renderer_rd/pipeline_cache_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index d013099cce..704a164a3a 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -1953,7 +1953,7 @@ void RendererCanvasRenderRD::ShaderData::set_code(const String &p_code) { uses_sdf = false; uses_time = false; - if (code == String()) { + if (code.is_empty()) { return; //just invalid, but no error } diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h index 26ccbd3bf5..c9544a5239 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index 522a8e8112..2f8ef696cd 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -240,7 +240,7 @@ RendererCompositorRD *RendererCompositorRD::singleton = nullptr; RendererCompositorRD::RendererCompositorRD() { { String shader_cache_dir = Engine::get_singleton()->get_shader_cache_path(); - if (shader_cache_dir == String()) { + if (shader_cache_dir.is_empty()) { shader_cache_dir = "user://"; } DirAccessRef da = DirAccess::open(shader_cache_dir); @@ -261,7 +261,7 @@ RendererCompositorRD::RendererCompositorRD() { shader_cache_dir = String(); //disable only if not editor } - if (shader_cache_dir != String()) { + if (!shader_cache_dir.is_empty()) { bool compress = GLOBAL_GET("rendering/shader_compiler/shader_cache/compress"); bool use_zstd = GLOBAL_GET("rendering/shader_compiler/shader_cache/use_zstd_compression"); bool strip_debug = GLOBAL_GET("rendering/shader_compiler/shader_cache/strip_debug"); diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h index f69e40e0ff..9a992d5819 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.h +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp index 550e59ba98..7ea117ef33 100644 --- a/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/renderer_scene_environment_rd.h b/servers/rendering/renderer_rd/renderer_scene_environment_rd.h index ec9cb4a798..9e36a61870 100644 --- a/servers/rendering/renderer_rd/renderer_scene_environment_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_environment_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -123,6 +123,14 @@ public: float ssr_fade_out = 2.0; float ssr_depth_tolerance = 0.2; + /// SSIL + /// + bool ssil_enabled = false; + float ssil_radius = 5.0; + float ssil_intensity = 1.0; + float ssil_sharpness = 0.98; + float ssil_normal_rejection = 1.0; + /// SDFGI bool sdfgi_enabled = false; RS::EnvironmentSDFGICascades sdfgi_cascades; diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp index b6b5c90b39..73cb088f6a 100644 --- a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -1305,7 +1305,6 @@ void RendererSceneGIRD::SDFGI::debug_probes(RD::DrawListID p_draw_list, RID p_fr RD::get_singleton()->draw_list_draw(p_draw_list, false, total_probes, total_points); if (gi->sdfgi_debug_probe_dir != Vector3()) { - print_line("CLICK DEBUG ME?"); uint32_t cascade = 0; Vector3 offset = Vector3((Vector3i(1, 1, 1) * -int32_t(cascade_size >> 1) + cascades[cascade].position)) * cascades[cascade].cell_size * Vector3(1.0, 1.0 / y_mult, 1.0); Vector3 probe_size = cascades[cascade].cell_size * (cascade_size / SDFGI::PROBE_DIVISOR) * Vector3(1.0, 1.0 / y_mult, 1.0); @@ -1333,11 +1332,6 @@ void RendererSceneGIRD::SDFGI::debug_probes(RD::DrawListID p_draw_list, RID p_fr } } - if (gi->sdfgi_debug_probe_enabled) { - print_line("found: " + gi->sdfgi_debug_probe_index); - } else { - print_line("no found"); - } gi->sdfgi_debug_probe_dir = Vector3(); } @@ -1864,7 +1858,7 @@ void RendererSceneGIRD::SDFGI::render_region(RID p_render_buffers, int p_region, Ref<Image> img; img.instantiate(); for (uint32_t i = 0; i < cascade_size; i++) { - Vector<uint8_t> subarr = data.subarray(128 * 128 * i, 128 * 128 * (i + 1) - 1); + Vector<uint8_t> subarr = data.slice(128 * 128 * i, 128 * 128 * (i + 1)); img->create(cascade_size, cascade_size, false, Image::FORMAT_L8, subarr); img->save_png("res://cascade_sdf_" + itos(cascade) + "_" + itos(i) + ".png"); } @@ -1877,7 +1871,7 @@ void RendererSceneGIRD::SDFGI::render_region(RID p_render_buffers, int p_region, Ref<Image> img; img.instantiate(); for (uint32_t i = 0; i < cascade_size; i++) { - Vector<uint8_t> subarr = data.subarray(128 * 128 * i * 2, 128 * 128 * (i + 1) * 2 - 1); + Vector<uint8_t> subarr = data.slice(128 * 128 * i * 2, 128 * 128 * (i + 1) * 2); img->createcascade_size, cascade_size, false, Image::FORMAT_RGB565, subarr); img->convert(Image::FORMAT_RGBA8); img->save_png("res://cascade_" + itos(cascade) + "_" + itos(i) + ".png"); @@ -2065,7 +2059,7 @@ void RendererSceneGIRD::VoxelGIInstance::update(bool p_update_light_instances, c for (int i = 0; i < levels.size(); i++) { VoxelGIInstance::Mipmap mipmap; - mipmap.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), texture, 0, i, RD::TEXTURE_SLICE_3D); + mipmap.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), texture, 0, i, 1, RD::TEXTURE_SLICE_3D); mipmap.level = levels.size() - i - 1; mipmap.cell_offset = 0; for (uint32_t j = 0; j < mipmap.level; j++) { @@ -2182,8 +2176,9 @@ void RendererSceneGIRD::VoxelGIInstance::update(bool p_update_light_instances, c dmap.texture = RD::get_singleton()->texture_create(dtf, RD::TextureView()); if (dynamic_maps.size() == 0) { - //render depth for first one - dtf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32; + // Render depth for first one. + // Use 16-bit depth when supported to improve performance. + dtf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D16_UNORM, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D16_UNORM : RD::DATA_FORMAT_X8_D24_UNORM_PACK32; dtf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; dmap.fb_depth = RD::get_singleton()->texture_create(dtf, RD::TextureView()); } diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.h b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h index 9f6fc8a9b7..a407199d0a 100644 --- a/servers/rendering/renderer_rd/renderer_scene_gi_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -602,19 +602,15 @@ public: }; struct VoxelGIData { - float xform[16]; - float bounds[3]; - float dynamic_range; + float xform[16]; // 64 - 64 - float bias; - float normal_bias; - uint32_t blend_ambient; - uint32_t texture_slot; + float bounds[3]; // 12 - 76 + float dynamic_range; // 4 - 80 - uint32_t pad0; - uint32_t pad1; - uint32_t pad2; - uint32_t mipmaps; + float bias; // 4 - 84 + float normal_bias; // 4 - 88 + uint32_t blend_ambient; // 4 - 92 + uint32_t mipmaps; // 4 - 96 }; struct PushConstant { diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index ae8d91a73b..1297f49724 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -427,6 +427,26 @@ void RendererSceneRenderRD::environment_set_ssao_quality(RS::EnvironmentSSAOQual ssao_fadeout_to = p_fadeout_to; } +void RendererSceneRenderRD::environment_set_ssil(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_sharpness, float p_normal_rejection) { + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); + ERR_FAIL_COND(!env); + + env->ssil_enabled = p_enable; + env->ssil_radius = p_radius; + env->ssil_intensity = p_intensity; + env->ssil_sharpness = p_sharpness; + env->ssil_normal_rejection = p_normal_rejection; +} + +void RendererSceneRenderRD::environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) { + ssil_quality = p_quality; + ssil_half_size = p_half_size; + ssil_adaptive_target = p_adaptive_target; + ssil_blur_passes = p_blur_passes; + ssil_fadeout_from = p_fadeout_from; + ssil_fadeout_to = p_fadeout_to; +} + bool RendererSceneRenderRD::environment_is_ssao_enabled(RID p_env) const { RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, false); @@ -445,6 +465,12 @@ float RendererSceneRenderRD::environment_get_ssao_light_affect(RID p_env) const return env->ssao_direct_light_affect; } +bool RendererSceneRenderRD::environment_is_ssil_enabled(RID p_env) const { + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); + ERR_FAIL_COND_V(!env, false); + return env->ssil_enabled; +} + bool RendererSceneRenderRD::environment_is_ssr_enabled(RID p_env) const { RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, false); @@ -1798,24 +1824,51 @@ void RendererSceneRenderRD::_free_render_buffer_data(RenderBuffers *rb) { rb->luminance.current = RID(); } - if (rb->ssao.depth.is_valid()) { - RD::get_singleton()->free(rb->ssao.depth); - RD::get_singleton()->free(rb->ssao.ao_deinterleaved); - RD::get_singleton()->free(rb->ssao.ao_pong); - RD::get_singleton()->free(rb->ssao.ao_final); + if (rb->ss_effects.linear_depth.is_valid()) { + RD::get_singleton()->free(rb->ss_effects.linear_depth); + rb->ss_effects.linear_depth = RID(); + rb->ss_effects.linear_depth_slices.clear(); + } + + if (rb->ss_effects.ssao.ao_final.is_valid()) { + RD::get_singleton()->free(rb->ss_effects.ssao.ao_deinterleaved); + RD::get_singleton()->free(rb->ss_effects.ssao.ao_pong); + RD::get_singleton()->free(rb->ss_effects.ssao.ao_final); + + RD::get_singleton()->free(rb->ss_effects.ssao.importance_map[0]); + RD::get_singleton()->free(rb->ss_effects.ssao.importance_map[1]); + + rb->ss_effects.ssao.ao_deinterleaved = RID(); + rb->ss_effects.ssao.ao_pong = RID(); + rb->ss_effects.ssao.ao_final = RID(); + rb->ss_effects.ssao.importance_map[0] = RID(); + rb->ss_effects.ssao.importance_map[1] = RID(); + + rb->ss_effects.ssao.ao_deinterleaved_slices.clear(); + rb->ss_effects.ssao.ao_pong_slices.clear(); + } + + if (rb->ss_effects.ssil.ssil_final.is_valid()) { + RD::get_singleton()->free(rb->ss_effects.ssil.ssil_final); + RD::get_singleton()->free(rb->ss_effects.ssil.deinterleaved); + RD::get_singleton()->free(rb->ss_effects.ssil.pong); + RD::get_singleton()->free(rb->ss_effects.ssil.edges); + RD::get_singleton()->free(rb->ss_effects.ssil.importance_map[0]); + RD::get_singleton()->free(rb->ss_effects.ssil.importance_map[1]); - RD::get_singleton()->free(rb->ssao.importance_map[0]); - RD::get_singleton()->free(rb->ssao.importance_map[1]); + rb->ss_effects.ssil.ssil_final = RID(); + rb->ss_effects.ssil.deinterleaved = RID(); + rb->ss_effects.ssil.pong = RID(); + rb->ss_effects.ssil.edges = RID(); + rb->ss_effects.ssil.deinterleaved_slices.clear(); + rb->ss_effects.ssil.pong_slices.clear(); + rb->ss_effects.ssil.edges_slices.clear(); + rb->ss_effects.ssil.importance_map[0] = RID(); + rb->ss_effects.ssil.importance_map[1] = RID(); - rb->ssao.depth = RID(); - rb->ssao.ao_deinterleaved = RID(); - rb->ssao.ao_pong = RID(); - rb->ssao.ao_final = RID(); - rb->ssao.importance_map[0] = RID(); - rb->ssao.importance_map[1] = RID(); - rb->ssao.depth_slices.clear(); - rb->ssao.ao_deinterleaved_slices.clear(); - rb->ssao.ao_pong_slices.clear(); + RD::get_singleton()->free(rb->ss_effects.last_frame); + rb->ss_effects.last_frame = RID(); + rb->ss_effects.last_frame_slices.clear(); } if (rb->ssr.blur_radius[0].is_valid()) { @@ -1919,24 +1972,21 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen RENDER_TIMESTAMP("Process SSAO"); - if (rb->ssao.ao_final.is_valid() && ssao_using_half_size != ssao_half_size) { - RD::get_singleton()->free(rb->ssao.depth); - RD::get_singleton()->free(rb->ssao.ao_deinterleaved); - RD::get_singleton()->free(rb->ssao.ao_pong); - RD::get_singleton()->free(rb->ssao.ao_final); + if (rb->ss_effects.ssao.ao_final.is_valid() && ssao_using_half_size != ssao_half_size) { + RD::get_singleton()->free(rb->ss_effects.ssao.ao_deinterleaved); + RD::get_singleton()->free(rb->ss_effects.ssao.ao_pong); + RD::get_singleton()->free(rb->ss_effects.ssao.ao_final); - RD::get_singleton()->free(rb->ssao.importance_map[0]); - RD::get_singleton()->free(rb->ssao.importance_map[1]); + RD::get_singleton()->free(rb->ss_effects.ssao.importance_map[0]); + RD::get_singleton()->free(rb->ss_effects.ssao.importance_map[1]); - rb->ssao.depth = RID(); - rb->ssao.ao_deinterleaved = RID(); - rb->ssao.ao_pong = RID(); - rb->ssao.ao_final = RID(); - rb->ssao.importance_map[0] = RID(); - rb->ssao.importance_map[1] = RID(); - rb->ssao.depth_slices.clear(); - rb->ssao.ao_deinterleaved_slices.clear(); - rb->ssao.ao_pong_slices.clear(); + rb->ss_effects.ssao.ao_deinterleaved = RID(); + rb->ss_effects.ssao.ao_pong = RID(); + rb->ss_effects.ssao.ao_final = RID(); + rb->ss_effects.ssao.importance_map[0] = RID(); + rb->ss_effects.ssao.importance_map[1] = RID(); + rb->ss_effects.ssao.ao_deinterleaved_slices.clear(); + rb->ss_effects.ssao.ao_pong_slices.clear(); } int buffer_width; @@ -1955,27 +2005,10 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen half_height = (rb->internal_height + 3) / 4; } bool uniform_sets_are_invalid = false; - if (rb->ssao.depth.is_null()) { - //allocate depth slices - + if (rb->ss_effects.ssao.ao_deinterleaved.is_null()) { { - RD::TextureFormat tf; - tf.format = RD::DATA_FORMAT_R16_SFLOAT; - tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; - tf.width = buffer_width; - tf.height = buffer_height; - tf.mipmaps = 4; - tf.array_layers = 4; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - rb->ssao.depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); - RD::get_singleton()->set_resource_name(rb->ssao.depth, "SSAO Depth"); - for (uint32_t i = 0; i < tf.mipmaps; i++) { - RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ssao.depth, 0, i, RD::TEXTURE_SLICE_2D_ARRAY); - rb->ssao.depth_slices.push_back(slice); - RD::get_singleton()->set_resource_name(rb->ssao.depth_slices[i], "SSAO Depth Mip " + itos(i) + " "); - } + rb->ss_effects.ssao.depth_texture_view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.linear_depth, 0, ssao_half_size ? 1 : 0, 4, RD::TEXTURE_SLICE_2D_ARRAY); } - { RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R8G8_UNORM; @@ -1984,12 +2017,12 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen tf.height = buffer_height; tf.array_layers = 4; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - rb->ssao.ao_deinterleaved = RD::get_singleton()->texture_create(tf, RD::TextureView()); - RD::get_singleton()->set_resource_name(rb->ssao.ao_deinterleaved, "SSAO De-interleaved Array"); + rb->ss_effects.ssao.ao_deinterleaved = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ss_effects.ssao.ao_deinterleaved, "SSAO De-interleaved Array"); for (uint32_t i = 0; i < 4; i++) { - RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ssao.ao_deinterleaved, i, 0); - rb->ssao.ao_deinterleaved_slices.push_back(slice); - RD::get_singleton()->set_resource_name(rb->ssao.ao_deinterleaved_slices[i], "SSAO De-interleaved Array Layer " + itos(i) + " "); + RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.ssao.ao_deinterleaved, i, 0); + rb->ss_effects.ssao.ao_deinterleaved_slices.push_back(slice); + RD::get_singleton()->set_resource_name(slice, "SSAO De-interleaved Array Layer " + itos(i) + " "); } } @@ -2001,12 +2034,12 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen tf.height = buffer_height; tf.array_layers = 4; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - rb->ssao.ao_pong = RD::get_singleton()->texture_create(tf, RD::TextureView()); - RD::get_singleton()->set_resource_name(rb->ssao.ao_pong, "SSAO De-interleaved Array Pong"); + rb->ss_effects.ssao.ao_pong = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ss_effects.ssao.ao_pong, "SSAO De-interleaved Array Pong"); for (uint32_t i = 0; i < 4; i++) { - RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ssao.ao_pong, i, 0); - rb->ssao.ao_pong_slices.push_back(slice); - RD::get_singleton()->set_resource_name(rb->ssao.ao_deinterleaved_slices[i], "SSAO De-interleaved Array Layer " + itos(i) + " Pong"); + RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.ssao.ao_pong, i, 0); + rb->ss_effects.ssao.ao_pong_slices.push_back(slice); + RD::get_singleton()->set_resource_name(slice, "SSAO De-interleaved Array Layer " + itos(i) + " Pong"); } } @@ -2016,10 +2049,10 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen tf.width = half_width; tf.height = half_height; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - rb->ssao.importance_map[0] = RD::get_singleton()->texture_create(tf, RD::TextureView()); - RD::get_singleton()->set_resource_name(rb->ssao.importance_map[0], "SSAO Importance Map"); - rb->ssao.importance_map[1] = RD::get_singleton()->texture_create(tf, RD::TextureView()); - RD::get_singleton()->set_resource_name(rb->ssao.importance_map[1], "SSAO Importance Map Pong"); + rb->ss_effects.ssao.importance_map[0] = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ss_effects.ssao.importance_map[0], "SSAO Importance Map"); + rb->ss_effects.ssao.importance_map[1] = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ss_effects.ssao.importance_map[1], "SSAO Importance Map Pong"); } { RD::TextureFormat tf; @@ -2027,8 +2060,8 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen tf.width = rb->internal_width; tf.height = rb->internal_height; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - rb->ssao.ao_final = RD::get_singleton()->texture_create(tf, RD::TextureView()); - RD::get_singleton()->set_resource_name(rb->ssao.ao_final, "SSAO Final"); + rb->ss_effects.ssao.ao_final = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ss_effects.ssao.ao_final, "SSAO Final"); } ssao_using_half_size = ssao_half_size; uniform_sets_are_invalid = true; @@ -2052,7 +2085,187 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen settings.half_screen_size = Size2i(buffer_width, buffer_height); settings.quarter_screen_size = Size2i(half_width, half_height); - storage->get_effects()->generate_ssao(rb->depth_texture, p_normal_buffer, rb->ssao.depth, rb->ssao.depth_slices, rb->ssao.ao_deinterleaved, rb->ssao.ao_deinterleaved_slices, rb->ssao.ao_pong, rb->ssao.ao_pong_slices, rb->ssao.ao_final, rb->ssao.importance_map[0], rb->ssao.importance_map[1], p_projection, settings, uniform_sets_are_invalid, rb->ssao.downsample_uniform_set, rb->ssao.gather_uniform_set, rb->ssao.importance_map_uniform_set); + storage->get_effects()->generate_ssao(p_normal_buffer, rb->ss_effects.ssao.depth_texture_view, rb->ss_effects.ssao.ao_deinterleaved, rb->ss_effects.ssao.ao_deinterleaved_slices, rb->ss_effects.ssao.ao_pong, rb->ss_effects.ssao.ao_pong_slices, rb->ss_effects.ssao.ao_final, rb->ss_effects.ssao.importance_map[0], rb->ss_effects.ssao.importance_map[1], p_projection, settings, uniform_sets_are_invalid, rb->ss_effects.ssao.gather_uniform_set, rb->ss_effects.ssao.importance_map_uniform_set); +} + +void RendererSceneRenderRD::_process_ssil(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection, const Transform3D &p_transform) { + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); + ERR_FAIL_COND(!rb); + + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_environment); + ERR_FAIL_COND(!env); + + RENDER_TIMESTAMP("Process SSIL"); + + if (rb->ss_effects.ssil.ssil_final.is_valid() && ssil_using_half_size != ssil_half_size) { + RD::get_singleton()->free(rb->ss_effects.ssil.ssil_final); + RD::get_singleton()->free(rb->ss_effects.ssil.deinterleaved); + RD::get_singleton()->free(rb->ss_effects.ssil.pong); + RD::get_singleton()->free(rb->ss_effects.ssil.edges); + RD::get_singleton()->free(rb->ss_effects.ssil.importance_map[0]); + RD::get_singleton()->free(rb->ss_effects.ssil.importance_map[1]); + + rb->ss_effects.ssil.ssil_final = RID(); + rb->ss_effects.ssil.deinterleaved = RID(); + rb->ss_effects.ssil.pong = RID(); + rb->ss_effects.ssil.edges = RID(); + rb->ss_effects.ssil.deinterleaved_slices.clear(); + rb->ss_effects.ssil.pong_slices.clear(); + rb->ss_effects.ssil.edges_slices.clear(); + rb->ss_effects.ssil.importance_map[0] = RID(); + rb->ss_effects.ssil.importance_map[1] = RID(); + } + + int buffer_width; + int buffer_height; + int half_width; + int half_height; + if (ssil_half_size) { + buffer_width = (rb->width + 3) / 4; + buffer_height = (rb->height + 3) / 4; + half_width = (rb->width + 7) / 8; + half_height = (rb->height + 7) / 8; + } else { + buffer_width = (rb->width + 1) / 2; + buffer_height = (rb->height + 1) / 2; + half_width = (rb->width + 3) / 4; + half_height = (rb->height + 3) / 4; + } + bool uniform_sets_are_invalid = false; + if (rb->ss_effects.ssil.ssil_final.is_null()) { + { + rb->ss_effects.ssil.depth_texture_view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.linear_depth, 0, ssil_half_size ? 1 : 0, 4, RD::TEXTURE_SLICE_2D_ARRAY); + } + { + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tf.width = rb->width; + tf.height = rb->height; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + rb->ss_effects.ssil.ssil_final = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ss_effects.ssil.ssil_final, "SSIL texture"); + RD::get_singleton()->texture_clear(rb->ss_effects.ssil.ssil_final, Color(0, 0, 0, 0), 0, 1, 0, 1); + if (rb->ss_effects.last_frame.is_null()) { + tf.mipmaps = 6; + rb->ss_effects.last_frame = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ss_effects.last_frame, "Last Frame Radiance"); + RD::get_singleton()->texture_clear(rb->ss_effects.last_frame, Color(0, 0, 0, 0), 0, tf.mipmaps, 0, 1); + for (uint32_t i = 0; i < 6; i++) { + RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.last_frame, 0, i); + rb->ss_effects.last_frame_slices.push_back(slice); + RD::get_singleton()->set_resource_name(slice, "Last Frame Radiance Mip " + itos(i) + " "); + } + } + } + { + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; + tf.width = buffer_width; + tf.height = buffer_height; + tf.array_layers = 4; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + rb->ss_effects.ssil.deinterleaved = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ss_effects.ssil.deinterleaved, "SSIL deinterleaved buffer"); + for (uint32_t i = 0; i < 4; i++) { + RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.ssil.deinterleaved, i, 0); + rb->ss_effects.ssil.deinterleaved_slices.push_back(slice); + RD::get_singleton()->set_resource_name(slice, "SSIL deinterleaved buffer array " + itos(i) + " "); + } + } + + { + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; + tf.width = buffer_width; + tf.height = buffer_height; + tf.array_layers = 4; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + rb->ss_effects.ssil.pong = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ss_effects.ssil.pong, "SSIL deinterleaved pong buffer"); + for (uint32_t i = 0; i < 4; i++) { + RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.ssil.pong, i, 0); + rb->ss_effects.ssil.pong_slices.push_back(slice); + RD::get_singleton()->set_resource_name(slice, "SSIL deinterleaved buffer pong array " + itos(i) + " "); + } + } + + { + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R8_UNORM; + tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; + tf.width = buffer_width; + tf.height = buffer_height; + tf.array_layers = 4; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + rb->ss_effects.ssil.edges = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ss_effects.ssil.edges, "SSIL edges buffer"); + for (uint32_t i = 0; i < 4; i++) { + RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.ssil.edges, i, 0); + rb->ss_effects.ssil.edges_slices.push_back(slice); + RD::get_singleton()->set_resource_name(slice, "SSIL edges buffer slice " + itos(i) + " "); + } + } + + { + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R8_UNORM; + tf.width = half_width; + tf.height = half_height; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + rb->ss_effects.ssil.importance_map[0] = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ss_effects.ssil.importance_map[0], "SSIL Importance Map"); + rb->ss_effects.ssil.importance_map[1] = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ss_effects.ssil.importance_map[1], "SSIL Importance Map Pong"); + } + uniform_sets_are_invalid = true; + ssil_using_half_size = ssil_half_size; + } + + EffectsRD::SSILSettings settings; + settings.radius = env->ssil_radius; + settings.intensity = env->ssil_intensity; + settings.sharpness = env->ssil_sharpness; + settings.normal_rejection = env->ssil_normal_rejection; + + settings.quality = ssil_quality; + settings.half_size = ssil_half_size; + settings.adaptive_target = ssil_adaptive_target; + settings.blur_passes = ssil_blur_passes; + settings.fadeout_from = ssil_fadeout_from; + settings.fadeout_to = ssil_fadeout_to; + settings.full_screen_size = Size2i(rb->width, rb->height); + settings.half_screen_size = Size2i(buffer_width, buffer_height); + settings.quarter_screen_size = Size2i(half_width, half_height); + + CameraMatrix correction; + correction.set_depth_correction(true); + CameraMatrix projection = correction * p_projection; + Transform3D transform = p_transform; + transform.set_origin(Vector3(0.0, 0.0, 0.0)); + CameraMatrix last_frame_projection = rb->ss_effects.last_frame_projection * CameraMatrix(rb->ss_effects.last_frame_transform.affine_inverse()) * CameraMatrix(transform) * projection.inverse(); + + storage->get_effects()->screen_space_indirect_lighting(rb->ss_effects.last_frame, rb->ss_effects.ssil.ssil_final, p_normal_buffer, rb->ss_effects.ssil.depth_texture_view, rb->ss_effects.ssil.deinterleaved, rb->ss_effects.ssil.deinterleaved_slices, rb->ss_effects.ssil.pong, rb->ss_effects.ssil.pong_slices, rb->ss_effects.ssil.importance_map[0], rb->ss_effects.ssil.importance_map[1], rb->ss_effects.ssil.edges, rb->ss_effects.ssil.edges_slices, p_projection, last_frame_projection, settings, uniform_sets_are_invalid, rb->ss_effects.ssil.gather_uniform_set, rb->ss_effects.ssil.importance_map_uniform_set, rb->ss_effects.ssil.projection_uniform_set); + rb->ss_effects.last_frame_projection = projection; + rb->ss_effects.last_frame_transform = transform; +} + +void RendererSceneRenderRD::_copy_framebuffer_to_ssil(RID p_render_buffers) { + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); + ERR_FAIL_COND(!rb); + + if (rb->ss_effects.last_frame.is_valid()) { + storage->get_effects()->copy_to_rect(rb->texture, rb->ss_effects.last_frame, Rect2i(0, 0, rb->width, rb->height)); + + int width = rb->width; + int height = rb->height; + for (int i = 0; i < rb->ss_effects.last_frame_slices.size() - 1; i++) { + width = MAX(1, width >> 1); + height = MAX(1, height >> 1); + storage->get_effects()->make_mipmap(rb->ss_effects.last_frame_slices[i], rb->ss_effects.last_frame_slices[i + 1], Size2i(width, height)); + } + } } void RendererSceneRenderRD::_render_buffers_copy_screen_texture(const RenderDataRD *p_render_data) { @@ -2427,10 +2640,14 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID } } - if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SSAO && rb->ssao.ao_final.is_valid()) { + if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SSAO && rb->ss_effects.ssao.ao_final.is_valid()) { + Size2 rtsize = storage->render_target_get_size(rb->render_target); + effects->copy_to_fb_rect(rb->ss_effects.ssao.ao_final, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, true); + } + + if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SSIL && rb->ss_effects.ssil.ssil_final.is_valid()) { Size2 rtsize = storage->render_target_get_size(rb->render_target); - RID ao_buf = rb->ssao.ao_final; - effects->copy_to_fb_rect(ao_buf, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, true); + effects->copy_to_fb_rect(rb->ss_effects.ssil.ssil_final, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, false); } if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER && _render_buffers_get_normal_texture(p_render_buffers).is_valid()) { @@ -2494,7 +2711,13 @@ RID RendererSceneRenderRD::render_buffers_get_ao_texture(RID p_render_buffers) { RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(!rb, RID()); - return rb->ssao.ao_final; + return rb->ss_effects.ssao.ao_final; +} +RID RendererSceneRenderRD::render_buffers_get_ssil_texture(RID p_render_buffers) { + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); + ERR_FAIL_COND_V(!rb, RID()); + + return rb->ss_effects.ssil.ssil_final; } RID RendererSceneRenderRD::render_buffers_get_voxel_gi_buffer(RID p_render_buffers) { @@ -3581,7 +3804,7 @@ void RendererSceneRenderRD::FogShaderData::set_code(const String &p_code) { ubo_size = 0; uniforms.clear(); - if (code == String()) { + if (code.is_empty()) { return; //just invalid, but no error } @@ -4417,9 +4640,9 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e uint32_t cluster_screen_width = (rb->width - 1) / cluster_size + 1; uint32_t cluster_screen_height = (rb->height - 1) / cluster_size + 1; - params.cluster_type_size = cluster_screen_width * cluster_screen_height * (32 + 32); - params.cluster_width = cluster_screen_width; params.max_cluster_element_count_div_32 = max_cluster_elements / 32; + params.cluster_type_size = cluster_screen_width * cluster_screen_height * (params.max_cluster_element_count_div_32 + 32); + params.cluster_width = cluster_screen_width; params.screen_size[0] = rb->width; params.screen_size[1] = rb->height; @@ -4528,7 +4751,7 @@ void RendererSceneRenderRD::_pre_resolve_render(RenderDataRD *p_render_data, boo } } -void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_gi, RID p_normal_roughness_buffer, RID p_voxel_gi_buffer) { +void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_gi, RID p_normal_roughness_buffer, RID p_voxel_gi_buffer) { // Render shadows while GI is rendering, due to how barriers are handled, this should happen at the same time if (p_render_data->render_buffers.is_valid() && p_use_gi) { @@ -4615,9 +4838,40 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool } if (p_render_data->render_buffers.is_valid()) { + if (p_use_ssao || p_use_ssil) { + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers); + ERR_FAIL_COND(!rb); + + bool invalidate_uniform_set = false; + if (rb->ss_effects.linear_depth.is_null()) { + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R16_SFLOAT; + tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; + tf.width = (rb->width + 1) / 2; + tf.height = (rb->height + 1) / 2; + tf.mipmaps = 5; + tf.array_layers = 4; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + rb->ss_effects.linear_depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ss_effects.linear_depth, "SS Effects Depth"); + for (uint32_t i = 0; i < tf.mipmaps; i++) { + RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.linear_depth, 0, i, 1, RD::TEXTURE_SLICE_2D_ARRAY); + rb->ss_effects.linear_depth_slices.push_back(slice); + RD::get_singleton()->set_resource_name(slice, "SS Effects Depth Mip " + itos(i) + " "); + } + invalidate_uniform_set = true; + } + + storage->get_effects()->downsample_depth(rb->depth_texture, rb->ss_effects.linear_depth_slices, ssao_quality, ssil_quality, invalidate_uniform_set, ssao_half_size, ssil_half_size, Size2i(rb->width, rb->height), p_render_data->cam_projection); + } + if (p_use_ssao) { _process_ssao(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_buffer, p_render_data->cam_projection); } + + if (p_use_ssil) { + _process_ssil(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_buffer, p_render_data->cam_projection, p_render_data->cam_transform); + } } //full barrier here, we need raster, transfer and compute and it depends from the previous work @@ -5499,6 +5753,9 @@ void fog() { sss_quality = RS::SubSurfaceScatteringQuality(int(GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_quality"))); sss_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_scale"); sss_depth_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_depth_scale"); + + environment_set_ssil_quality(RS::EnvironmentSSILQuality(int(GLOBAL_GET("rendering/environment/ssil/quality"))), GLOBAL_GET("rendering/environment/ssil/half_size"), GLOBAL_GET("rendering/environment/ssil/adaptive_target"), GLOBAL_GET("rendering/environment/ssil/blur_passes"), GLOBAL_GET("rendering/environment/ssil/fadeout_from"), GLOBAL_GET("rendering/environment/ssil/fadeout_to")); + directional_penumbra_shadow_kernel = memnew_arr(float, 128); directional_soft_shadow_kernel = memnew_arr(float, 128); penumbra_shadow_kernel = memnew_arr(float, 128); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 98ab1a2c3c..55891bc2a9 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -129,12 +129,15 @@ protected: void _process_ssao(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection); void _process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive); void _process_sss(RID p_render_buffers, const CameraMatrix &p_camera); + void _process_ssil(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection, const Transform3D &p_transform); + void _copy_framebuffer_to_ssil(RID p_render_buffers); + void _ensure_ss_effects(RID p_render_buffers, bool p_using_ssil); bool _needs_post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi); void _post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi); void _pre_resolve_render(RenderDataRD *p_render_data, bool p_use_gi); - void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_gi, RID p_normal_roughness_buffer, RID p_voxel_gi_buffer); + void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_gi, RID p_normal_roughness_buffer, RID p_voxel_gi_buffer); void _render_buffers_copy_screen_texture(const RenderDataRD *p_render_data); void _render_buffers_copy_depth_texture(const RenderDataRD *p_render_data); @@ -415,6 +418,14 @@ private: float ssao_fadeout_from = 50.0; float ssao_fadeout_to = 300.0; + RS::EnvironmentSSILQuality ssil_quality = RS::ENV_SSIL_QUALITY_MEDIUM; + bool ssil_half_size = false; + bool ssil_using_half_size = false; + float ssil_adaptive_target = 0.5; + int ssil_blur_passes = 4; + float ssil_fadeout_from = 50.0; + float ssil_fadeout_to = 300.0; + bool glow_bicubic_upscale = false; bool glow_high_quality = false; RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::ENV_SSR_ROUGNESS_QUALITY_LOW; @@ -524,20 +535,47 @@ private: RID current_fb; } luminance; - struct SSAO { - RID depth; - Vector<RID> depth_slices; - RID ao_deinterleaved; - Vector<RID> ao_deinterleaved_slices; - RID ao_pong; - Vector<RID> ao_pong_slices; - RID ao_final; - RID importance_map[2]; + struct SSEffects { + RID linear_depth; + Vector<RID> linear_depth_slices; RID downsample_uniform_set; - RID gather_uniform_set; - RID importance_map_uniform_set; - } ssao; + + RID last_frame; + Vector<RID> last_frame_slices; + + CameraMatrix last_frame_projection; + Transform3D last_frame_transform; + + struct SSAO { + RID ao_deinterleaved; + Vector<RID> ao_deinterleaved_slices; + RID ao_pong; + Vector<RID> ao_pong_slices; + RID ao_final; + RID importance_map[2]; + RID depth_texture_view; + + RID gather_uniform_set; + RID importance_map_uniform_set; + } ssao; + + struct SSIL { + RID ssil_final; + RID deinterleaved; + Vector<RID> deinterleaved_slices; + RID pong; + Vector<RID> pong_slices; + RID edges; + Vector<RID> edges_slices; + RID importance_map[2]; + RID depth_texture_view; + + RID gather_uniform_set; + RID importance_map_uniform_set; + RID projection_uniform_set; + } ssil; + } ss_effects; struct SSR { RID normal_scaled; @@ -1046,9 +1084,12 @@ public: virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) override; virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) override; virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override; + virtual void environment_set_ssil(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_sharpness, float p_normal_rejection) override; + virtual void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override; bool environment_is_ssao_enabled(RID p_env) const; float environment_get_ssao_ao_affect(RID p_env) const; float environment_get_ssao_light_affect(RID p_env) const; + bool environment_is_ssil_enabled(RID p_env) const; bool environment_is_ssr_enabled(RID p_env) const; bool environment_is_sdfgi_enabled(RID p_env) const; @@ -1344,6 +1385,7 @@ public: RID render_buffers_get_depth_texture(RID p_render_buffers); RID render_buffers_get_ao_texture(RID p_render_buffers); + RID render_buffers_get_ssil_texture(RID p_render_buffers); RID render_buffers_get_back_buffer_texture(RID p_render_buffers); RID render_buffers_get_back_depth_texture(RID p_render_buffers); RID render_buffers_get_voxel_gi_buffer(RID p_render_buffers); diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp index a9c39fb937..8fb3c607fa 100644 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -46,7 +46,7 @@ void RendererSceneSkyRD::SkyShaderData::set_code(const String &p_code) { ubo_size = 0; uniforms.clear(); - if (code == String()) { + if (code.is_empty()) { return; //just invalid, but no error } @@ -360,7 +360,7 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_data(RendererStorageR mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex); } - layer.views.write[j] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + i * 6, j, RD::TEXTURE_SLICE_CUBEMAP); + layer.views.write[j] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + i * 6, j, 1, RD::TEXTURE_SLICE_CUBEMAP); mmw = MAX(1, mmw >> 1); mmh = MAX(1, mmh >> 1); @@ -388,7 +388,7 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_data(RendererStorageR mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex); } - layer.views.write[j] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, j, RD::TEXTURE_SLICE_CUBEMAP); + layer.views.write[j] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, j, 1, RD::TEXTURE_SLICE_CUBEMAP); mmw = MAX(1, mmw >> 1); mmh = MAX(1, mmh >> 1); @@ -397,7 +397,7 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_data(RendererStorageR layers.push_back(layer); } - radiance_base_cubemap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, 0, RD::TEXTURE_SLICE_CUBEMAP); + radiance_base_cubemap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, 0, 1, RD::TEXTURE_SLICE_CUBEMAP); RD::get_singleton()->set_resource_name(radiance_base_cubemap, "radiance base cubemap"); RD::TextureFormat tf; tf.format = p_texture_format; @@ -418,7 +418,7 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_data(RendererStorageR ReflectionData::DownsampleLayer::Mipmap &mm = downsampled_layer.mipmaps.write[j]; mm.size.width = mmw; mm.size.height = mmh; - mm.view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), downsampled_radiance_cubemap, 0, j, RD::TEXTURE_SLICE_CUBEMAP); + mm.view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), downsampled_radiance_cubemap, 0, j, 1, RD::TEXTURE_SLICE_CUBEMAP); RD::get_singleton()->set_resource_name(mm.view, "Downsampled Radiance Cubemap Mip " + itos(j) + " "); if (prefer_raster_effects) { // we need a framebuffer for each side of our cubemap diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h index 8689395bea..1359cdec67 100644 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index 29e4a63cbb..496dde123d 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -1089,7 +1089,7 @@ Vector<Ref<Image>> RendererStorageRD::texture_3d_get(RID p_texture) const { const Texture::BufferSlice3D &bs = tex->buffer_slices_3d[i]; ERR_FAIL_COND_V(bs.offset >= (uint32_t)all_data.size(), Vector<Ref<Image>>()); ERR_FAIL_COND_V(bs.offset + bs.buffer_size > (uint32_t)all_data.size(), Vector<Ref<Image>>()); - Vector<uint8_t> sub_region = all_data.subarray(bs.offset, bs.offset + bs.buffer_size - 1); + Vector<uint8_t> sub_region = all_data.slice(bs.offset, bs.offset + bs.buffer_size); Ref<Image> img; img.instantiate(); @@ -2655,13 +2655,13 @@ void RendererStorageRD::MaterialData::update_uniform_buffer(const Map<StringName uint32_t size = 0U; // The following code enforces a 16-byte alignment of uniform arrays. if (E.value.array_size > 0) { - size = ShaderLanguage::get_type_size(E.value.type) * E.value.array_size; + size = ShaderLanguage::get_datatype_size(E.value.type) * E.value.array_size; int m = (16 * E.value.array_size); if ((size % m) != 0U) { size += m - (size % m); } } else { - size = ShaderLanguage::get_type_size(E.value.type); + size = ShaderLanguage::get_datatype_size(E.value.type); } ERR_CONTINUE(offset + size > p_buffer_size); #endif @@ -2818,11 +2818,14 @@ void RendererStorageRD::MaterialData::update_textures(const Map<StringName, Vari case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO: { rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_BLACK); } break; - case ShaderLanguage::ShaderNode::Uniform::HINT_NONE: { + case ShaderLanguage::ShaderNode::Uniform::HINT_ANISOTROPY: { + rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_ANISO); + } break; + case ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL: { rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL); } break; - case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: { - rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_ANISO); + case ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL: { + rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL); } break; default: { rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE); @@ -2861,7 +2864,7 @@ void RendererStorageRD::MaterialData::update_textures(const Map<StringName, Vari } } #ifdef TOOLS_ENABLED - if (roughness_detect_texture && normal_detect_texture && normal_detect_texture->path != String()) { + if (roughness_detect_texture && normal_detect_texture && !normal_detect_texture->path.is_empty()) { roughness_detect_texture->detect_roughness_callback(roughness_detect_texture->detect_roughness_callback_ud, normal_detect_texture->path, roughness_channel); } #endif @@ -2901,7 +2904,7 @@ void RendererStorageRD::MaterialData::update_textures(const Map<StringName, Vari rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE); } #ifdef TOOLS_ENABLED - if (roughness_detect_texture && normal_detect_texture && normal_detect_texture->path != String()) { + if (roughness_detect_texture && normal_detect_texture && !normal_detect_texture->path.is_empty()) { roughness_detect_texture->detect_roughness_callback(roughness_detect_texture->detect_roughness_callback_ud, normal_detect_texture->path, roughness_channel); } #endif @@ -5820,7 +5823,7 @@ void RendererStorageRD::ParticlesShaderData::set_code(const String &p_code) { uniforms.clear(); uses_collision = false; - if (code == String()) { + if (code.is_empty()) { return; //just invalid, but no error } @@ -9234,7 +9237,7 @@ void RendererStorageRD::_update_global_variables() { for (uint32_t i = 0; i < total_regions; i++) { if (global_variables.buffer_dirty_regions[i]) { - RD::get_singleton()->buffer_update(global_variables.buffer, i * region_byte_size, region_byte_size, global_variables.buffer_values); + RD::get_singleton()->buffer_update(global_variables.buffer, i * region_byte_size, region_byte_size, &global_variables.buffer_values[i * GlobalVariables::BUFFER_DIRTY_REGION_SIZE]); global_variables.buffer_dirty_regions[i] = false; } @@ -9265,7 +9268,6 @@ void RendererStorageRD::_update_global_variables() { ERR_CONTINUE(!material); //wtf _material_queue_update(material, false, true); - print_line("update material texture?"); } global_variables.must_update_texture_materials = false; diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h index 9a64480c3e..8f044dbe75 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.h +++ b/servers/rendering/renderer_rd/renderer_storage_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/shader_compiler_rd.cpp b/servers/rendering/renderer_rd/shader_compiler_rd.cpp index 77d3a2e766..38ac00176f 100644 --- a/servers/rendering/renderer_rd/shader_compiler_rd.cpp +++ b/servers/rendering/renderer_rd/shader_compiler_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -54,81 +54,6 @@ static String _typestr(SL::DataType p_type) { return type; } -static int _get_datatype_size(SL::DataType p_type) { - switch (p_type) { - case SL::TYPE_VOID: - return 0; - case SL::TYPE_BOOL: - return 4; - case SL::TYPE_BVEC2: - return 8; - case SL::TYPE_BVEC3: - return 12; - case SL::TYPE_BVEC4: - return 16; - case SL::TYPE_INT: - return 4; - case SL::TYPE_IVEC2: - return 8; - case SL::TYPE_IVEC3: - return 12; - case SL::TYPE_IVEC4: - return 16; - case SL::TYPE_UINT: - return 4; - case SL::TYPE_UVEC2: - return 8; - case SL::TYPE_UVEC3: - return 12; - case SL::TYPE_UVEC4: - return 16; - case SL::TYPE_FLOAT: - return 4; - case SL::TYPE_VEC2: - return 8; - case SL::TYPE_VEC3: - return 12; - case SL::TYPE_VEC4: - return 16; - case SL::TYPE_MAT2: - return 32; // 4 * 4 + 4 * 4 - case SL::TYPE_MAT3: - return 48; // 4 * 4 + 4 * 4 + 4 * 4 - case SL::TYPE_MAT4: - return 64; - case SL::TYPE_SAMPLER2D: - return 16; - case SL::TYPE_ISAMPLER2D: - return 16; - case SL::TYPE_USAMPLER2D: - return 16; - case SL::TYPE_SAMPLER2DARRAY: - return 16; - case SL::TYPE_ISAMPLER2DARRAY: - return 16; - case SL::TYPE_USAMPLER2DARRAY: - return 16; - case SL::TYPE_SAMPLER3D: - return 16; - case SL::TYPE_ISAMPLER3D: - return 16; - case SL::TYPE_USAMPLER3D: - return 16; - case SL::TYPE_SAMPLERCUBE: - return 16; - case SL::TYPE_SAMPLERCUBEARRAY: - return 16; - case SL::TYPE_STRUCT: - return 0; - - case SL::TYPE_MAX: { - ERR_FAIL_V(0); - }; - } - - ERR_FAIL_V(0); -} - static int _get_datatype_alignment(SL::DataType p_type) { switch (p_type) { case SL::TYPE_VOID: @@ -658,12 +583,12 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge uniform_defines.write[uniform.order] = ucode; if (is_buffer_global) { //globals are indices into the global table - uniform_sizes.write[uniform.order] = _get_datatype_size(ShaderLanguage::TYPE_UINT); + uniform_sizes.write[uniform.order] = ShaderLanguage::get_datatype_size(ShaderLanguage::TYPE_UINT); uniform_alignments.write[uniform.order] = _get_datatype_alignment(ShaderLanguage::TYPE_UINT); } else { // The following code enforces a 16-byte alignment of uniform arrays. if (uniform.array_size > 0) { - int size = _get_datatype_size(uniform.type) * uniform.array_size; + int size = ShaderLanguage::get_datatype_size(uniform.type) * uniform.array_size; int m = (16 * uniform.array_size); if ((size % m) != 0) { size += m - (size % m); @@ -671,7 +596,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge uniform_sizes.write[uniform.order] = size; uniform_alignments.write[uniform.order] = 16; } else { - uniform_sizes.write[uniform.order] = _get_datatype_size(uniform.type); + uniform_sizes.write[uniform.order] = ShaderLanguage::get_datatype_size(uniform.type); uniform_alignments.write[uniform.order] = _get_datatype_alignment(uniform.type); } } @@ -1318,6 +1243,9 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge code += ")"; } break; + case SL::OP_EMPTY: { + // Semicolon (or empty statement) - ignored. + } break; default: { if (p_use_scope) { @@ -1410,7 +1338,13 @@ ShaderLanguage::DataType ShaderCompilerRD::_get_variable_type(const StringName & } Error ShaderCompilerRD::compile(RS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code) { - Error err = parser.compile(p_code, ShaderTypes::get_singleton()->get_functions(p_mode), ShaderTypes::get_singleton()->get_modes(p_mode), ShaderLanguage::VaryingFunctionNames(), ShaderTypes::get_singleton()->get_types(), _get_variable_type); + SL::ShaderCompileInfo info; + info.functions = ShaderTypes::get_singleton()->get_functions(p_mode); + info.render_modes = ShaderTypes::get_singleton()->get_modes(p_mode); + info.shader_types = ShaderTypes::get_singleton()->get_types(); + info.global_variable_type_func = _get_variable_type; + + Error err = parser.compile(p_code, info); if (err != OK) { Vector<String> shader = p_code.split("\n"); diff --git a/servers/rendering/renderer_rd/shader_compiler_rd.h b/servers/rendering/renderer_rd/shader_compiler_rd.h index 2ab689c27c..5670d881f6 100644 --- a/servers/rendering/renderer_rd/shader_compiler_rd.h +++ b/servers/rendering/renderer_rd/shader_compiler_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp index 2568090918..73766d14d8 100644 --- a/servers/rendering/renderer_rd/shader_rd.cpp +++ b/servers/rendering/renderer_rd/shader_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -79,7 +79,7 @@ void ShaderRD::_add_stage(const char *p_code, StageType p_stage_type) { } if (push_chunk) { - if (text != String()) { + if (!text.is_empty()) { StageTemplate::Chunk text_chunk; text_chunk.type = StageTemplate::Chunk::TYPE_TEXT; text_chunk.text = text.utf8(); @@ -90,7 +90,7 @@ void ShaderRD::_add_stage(const char *p_code, StageType p_stage_type) { } } - if (text != String()) { + if (!text.is_empty()) { StageTemplate::Chunk text_chunk; text_chunk.type = StageTemplate::Chunk::TYPE_TEXT; text_chunk.text = text.utf8(); @@ -638,7 +638,7 @@ void ShaderRD::initialize(const Vector<String> &p_variant_defines, const String variants_enabled.push_back(true); } - if (shader_cache_dir != String()) { + if (!shader_cache_dir.is_empty()) { StringBuilder hash_build; hash_build.append("[base_hash]"); diff --git a/servers/rendering/renderer_rd/shader_rd.h b/servers/rendering/renderer_rd/shader_rd.h index 984b168659..06f78ab193 100644 --- a/servers/rendering/renderer_rd/shader_rd.h +++ b/servers/rendering/renderer_rd/shader_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/shaders/copy.glsl b/servers/rendering/renderer_rd/shaders/copy.glsl index 4110a95ddb..a89f83b5c4 100644 --- a/servers/rendering/renderer_rd/shaders/copy.glsl +++ b/servers/rendering/renderer_rd/shaders/copy.glsl @@ -84,6 +84,8 @@ void main() { color += texelFetch(source_color, base_pos + ivec2(1, 0), 0); color += texelFetch(source_color, base_pos + ivec2(1, 1), 0); color /= 4.0; + color = mix(color, vec4(100.0, 100.0, 100.0, 1.0), isinf(color)); + color = mix(color, vec4(100.0, 100.0, 100.0, 1.0), isnan(color)); imageStore(dest_buffer, pos + params.target, color); #endif @@ -132,6 +134,13 @@ void main() { local_cache[dest_index + 16] = textureLod(source_color, quad_center_uv + vec2(0.0, 1.0 / params.section.w), 0); local_cache[dest_index + 16 + 1] = textureLod(source_color, quad_center_uv + vec2(1.0 / params.section.zw), 0); } + if (bool(params.flags & FLAG_GLOW_FIRST_PASS)) { + // Tonemap initial samples to reduce weight of fireflies: https://graphicrants.blogspot.com/2013/12/tone-mapping.html + local_cache[dest_index] /= 1.0 + dot(local_cache[dest_index].rgb, vec3(0.299, 0.587, 0.114)); + local_cache[dest_index + 1] /= 1.0 + dot(local_cache[dest_index + 1].rgb, vec3(0.299, 0.587, 0.114)); + local_cache[dest_index + 16] /= 1.0 + dot(local_cache[dest_index + 16].rgb, vec3(0.299, 0.587, 0.114)); + local_cache[dest_index + 16 + 1] /= 1.0 + dot(local_cache[dest_index + 16 + 1].rgb, vec3(0.299, 0.587, 0.114)); + } memoryBarrierShared(); barrier(); @@ -177,6 +186,11 @@ void main() { color += temp_cache[index - 2] * 0.140367; color += temp_cache[index - 3] * 0.106595; + if (bool(params.flags & FLAG_GLOW_FIRST_PASS)) { + // Undo tonemap to restore range: https://graphicrants.blogspot.com/2013/12/tone-mapping.html + color /= 1.0 - dot(color.rgb, vec3(0.299, 0.587, 0.114)); + } + color *= params.glow_strength; if (bool(params.flags & FLAG_GLOW_FIRST_PASS)) { @@ -186,7 +200,7 @@ void main() { #endif color *= params.glow_exposure; - float luminance = max(color.r, max(color.g, color.b)); + float luminance = dot(color.rgb, vec3(0.299, 0.587, 0.114)); float feedback = max(smoothstep(params.glow_hdr_threshold, params.glow_hdr_threshold + params.glow_hdr_scale, luminance), params.glow_bloom); color = min(color * feedback, vec4(params.glow_luminance_cap)); diff --git a/servers/rendering/renderer_rd/shaders/fsr_upscale.glsl b/servers/rendering/renderer_rd/shaders/fsr_upscale.glsl index 4e2ba84033..54a7790f77 100644 --- a/servers/rendering/renderer_rd/shaders/fsr_upscale.glsl +++ b/servers/rendering/renderer_rd/shaders/fsr_upscale.glsl @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/shaders/gi.glsl b/servers/rendering/renderer_rd/shaders/gi.glsl index 5528ea3659..9854f124d7 100644 --- a/servers/rendering/renderer_rd/shaders/gi.glsl +++ b/servers/rendering/renderer_rd/shaders/gi.glsl @@ -68,19 +68,15 @@ sdfgi; #define MAX_VOXEL_GI_INSTANCES 8 struct VoxelGIData { - mat4 xform; - vec3 bounds; - float dynamic_range; + mat4 xform; // 64 - 64 - float bias; - float normal_bias; - bool blend_ambient; - uint texture_slot; + vec3 bounds; // 12 - 76 + float dynamic_range; // 4 - 80 - uint pad0; - uint pad1; - uint pad2; - uint mipmaps; + float bias; // 4 - 84 + float normal_bias; // 4 - 88 + bool blend_ambient; // 4 - 92 + uint mipmaps; // 4 - 96 }; layout(set = 0, binding = 16, std140) uniform VoxelGIs { diff --git a/servers/rendering/renderer_rd/shaders/giprobe_write.glsl b/servers/rendering/renderer_rd/shaders/giprobe_write.glsl index 25d87ca45d..a6d65bffeb 100644 --- a/servers/rendering/renderer_rd/shaders/giprobe_write.glsl +++ b/servers/rendering/renderer_rd/shaders/giprobe_write.glsl @@ -7,7 +7,6 @@ layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; #define NO_CHILDREN 0xFFFFFFFF -#define GREY_VEC vec3(0.33333, 0.33333, 0.33333) struct CellChildren { uint children[8]; diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl index e4628b2d5a..9b72ccc87d 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl @@ -1153,7 +1153,7 @@ void main() { } #endif // !USE_LIGHTMAP - if (scene_data.ssao_enabled) { + if (bool(scene_data.ss_effects_flags & SCREEN_SPACE_EFFECTS_FLAGS_USE_SSAO)) { float ssao = texture(sampler2D(ao_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv).r; ao = min(ao, ssao); ao_light_affect = mix(ao_light_affect, max(ao_light_affect, scene_data.ssao_light_affect), scene_data.ssao_ao_affect); @@ -1223,6 +1223,12 @@ void main() { // convert ao to direct light ao ao = mix(1.0, ao, ao_light_affect); + if (bool(scene_data.ss_effects_flags & SCREEN_SPACE_EFFECTS_FLAGS_USE_SSIL)) { + vec4 ssil = textureLod(sampler2D(ssil_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv, 0.0); + ambient_light *= 1.0 - ssil.a; + ambient_light += ssil.rgb * albedo.rgb; + } + //this saves some VGPRs vec3 f0 = F0(metallic, specular, albedo); diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl index be29cf4f58..0f7cd18534 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl @@ -72,6 +72,9 @@ layout(set = 0, binding = 4) uniform sampler light_projector_sampler; //3 bits of stride #define INSTANCE_FLAGS_PARTICLE_TRAIL_MASK 0xFF +#define SCREEN_SPACE_EFFECTS_FLAGS_USE_SSAO 1 +#define SCREEN_SPACE_EFFECTS_FLAGS_USE_SSIL 2 + layout(set = 0, binding = 5, std430) restrict readonly buffer OmniLights { LightData data[]; } @@ -201,7 +204,7 @@ layout(set = 1, binding = 0, std140) uniform SceneData { float z_far; float z_near; - bool ssao_enabled; + uint ss_effects_flags; float ssao_light_affect; float ssao_ao_affect; bool roughness_limiter_enabled; @@ -305,19 +308,15 @@ layout(set = 1, binding = 15) uniform texture2DArray sdfgi_lightprobe_texture; layout(set = 1, binding = 16) uniform texture3D sdfgi_occlusion_cascades; struct VoxelGIData { - mat4 xform; - vec3 bounds; - float dynamic_range; + mat4 xform; // 64 - 64 - float bias; - float normal_bias; - bool blend_ambient; - uint texture_slot; + vec3 bounds; // 12 - 76 + float dynamic_range; // 4 - 80 - float anisotropy_strength; - float ambient_occlusion; - float ambient_occlusion_size; - uint mipmaps; + float bias; // 4 - 84 + float normal_bias; // 4 - 88 + bool blend_ambient; // 4 - 92 + uint mipmaps; // 4 - 96 }; layout(set = 1, binding = 17, std140) uniform VoxelGIs { @@ -327,6 +326,8 @@ voxel_gi_instances; layout(set = 1, binding = 18) uniform texture3D volumetric_fog_texture; +layout(set = 1, binding = 19) uniform texture2D ssil_buffer; + #endif /* Set 2 Skeleton & Instancing (can change per item) */ diff --git a/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl b/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl index 78e0a85341..fde5688301 100644 --- a/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl +++ b/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl @@ -223,7 +223,6 @@ void main() { blur_radius = (a * (sqrt(a2 + fh2) - a)) / (4.0f * h); } } - final_color = imageLoad(source_diffuse, ivec2((final_pos - 0.5) * pixel_size)); imageStore(blur_radius_image, ssC, vec4(blur_radius / 255.0)); //stored in r8 diff --git a/servers/rendering/renderer_rd/shaders/ssao_downsample.glsl b/servers/rendering/renderer_rd/shaders/ss_effects_downsample.glsl index ee0db6a6f0..bdabc146d8 100644 --- a/servers/rendering/renderer_rd/shaders/ssao_downsample.glsl +++ b/servers/rendering/renderer_rd/shaders/ss_effects_downsample.glsl @@ -42,6 +42,9 @@ layout(r16f, set = 1, binding = 0) uniform restrict writeonly image2DArray dest_ layout(r16f, set = 2, binding = 0) uniform restrict writeonly image2DArray dest_image1; layout(r16f, set = 2, binding = 1) uniform restrict writeonly image2DArray dest_image2; layout(r16f, set = 2, binding = 2) uniform restrict writeonly image2DArray dest_image3; +#ifdef GENERATE_FULL_MIPS +layout(r16f, set = 2, binding = 3) uniform restrict writeonly image2DArray dest_image4; +#endif #endif vec4 screen_space_to_view_space_depth(vec4 p_depth) { @@ -150,7 +153,27 @@ void prepare_depths_and_mips(vec4 p_samples, uvec2 p_output_coord, uvec2 p_gtid) float avg = mip_smart_average(vec4(sample_00, sample_01, sample_10, sample_11)); imageStore(dest_image3, ivec3(p_output_coord.x, p_output_coord.y, depth_array_index), vec4(avg)); +#ifndef GENERATE_FULL_MIPS + } +#else + depth_buffer[depth_array_index][buffer_coord.x][buffer_coord.y] = avg; } + still_alive = p_gtid.x % 16 == depth_array_offset.x && depth_array_offset.y % 16 == depth_array_offset.y; + + p_output_coord /= 2; + groupMemoryBarrier(); + barrier(); + + if (still_alive) { + float sample_00 = depth_buffer[depth_array_index][buffer_coord.x + 0][buffer_coord.y + 0]; + float sample_01 = depth_buffer[depth_array_index][buffer_coord.x + 0][buffer_coord.y + 8]; + float sample_10 = depth_buffer[depth_array_index][buffer_coord.x + 8][buffer_coord.y + 0]; + float sample_11 = depth_buffer[depth_array_index][buffer_coord.x + 8][buffer_coord.y + 8]; + + float avg = mip_smart_average(vec4(sample_00, sample_01, sample_10, sample_11)); + imageStore(dest_image4, ivec3(p_output_coord.x, p_output_coord.y, depth_array_index), vec4(avg)); + } +#endif } #else #ifndef USE_HALF_BUFFERS diff --git a/servers/rendering/renderer_rd/shaders/ssao.glsl b/servers/rendering/renderer_rd/shaders/ssao.glsl index 6e945edfcd..18cab75c3b 100644 --- a/servers/rendering/renderer_rd/shaders/ssao.glsl +++ b/servers/rendering/renderer_rd/shaders/ssao.glsl @@ -23,8 +23,6 @@ #VERSION_DEFINES -#define SSAO_ADAPTIVE_TAP_BASE_COUNT 5 - #define INTELSSAO_MAIN_DISK_SAMPLE_COUNT (32) const vec4 sample_pattern[INTELSSAO_MAIN_DISK_SAMPLE_COUNT] = { vec4(0.78488064, 0.56661671, 1.500000, -0.126083), vec4(0.26022232, -0.29575172, 1.500000, -1.064030), vec4(0.10459357, 0.08372527, 1.110000, -2.730563), vec4(-0.68286800, 0.04963045, 1.090000, -0.498827), @@ -62,7 +60,6 @@ const int num_taps[5] = { 3, 5, 12, 0, 0 }; #define SSAO_REDUCE_RADIUS_NEAR_SCREEN_BORDER_ENABLE_AT_QUALITY_PRESET (1) #define SSAO_MAX_TAPS 32 -#define SSAO_MAX_REF_TAPS 512 #define SSAO_ADAPTIVE_TAP_BASE_COUNT 5 #define SSAO_ADAPTIVE_TAP_FLEXIBLE_COUNT (SSAO_MAX_TAPS - SSAO_ADAPTIVE_TAP_BASE_COUNT) #define SSAO_DEPTH_MIP_LEVELS 4 diff --git a/servers/rendering/renderer_rd/shaders/ssao_blur.glsl b/servers/rendering/renderer_rd/shaders/ssao_blur.glsl index d9cd2b4e85..b154f5e527 100644 --- a/servers/rendering/renderer_rd/shaders/ssao_blur.glsl +++ b/servers/rendering/renderer_rd/shaders/ssao_blur.glsl @@ -128,19 +128,19 @@ void main() { #ifdef MODE_NON_SMART - vec2 halfPixel = params.half_screen_pixel_size * 0.5f; + vec2 half_pixel = params.half_screen_pixel_size * 0.5; vec2 uv = (vec2(gl_GlobalInvocationID.xy) + vec2(0.5, 0.5)) * params.half_screen_pixel_size; - vec2 centre = textureLod(source_ssao, vec2(uv), 0.0).xy; + vec2 center = textureLod(source_ssao, vec2(uv), 0.0).xy; vec4 vals; - vals.x = textureLod(source_ssao, vec2(uv + vec2(-halfPixel.x * 3, -halfPixel.y)), 0.0).x; - vals.y = textureLod(source_ssao, vec2(uv + vec2(+halfPixel.x, -halfPixel.y * 3)), 0.0).x; - vals.z = textureLod(source_ssao, vec2(uv + vec2(-halfPixel.x, +halfPixel.y * 3)), 0.0).x; - vals.w = textureLod(source_ssao, vec2(uv + vec2(+halfPixel.x * 3, +halfPixel.y)), 0.0).x; + vals.x = textureLod(source_ssao, vec2(uv + vec2(-half_pixel.x * 3, -half_pixel.y)), 0.0).x; + vals.y = textureLod(source_ssao, vec2(uv + vec2(+half_pixel.x, -half_pixel.y * 3)), 0.0).x; + vals.z = textureLod(source_ssao, vec2(uv + vec2(-half_pixel.x, +half_pixel.y * 3)), 0.0).x; + vals.w = textureLod(source_ssao, vec2(uv + vec2(+half_pixel.x * 3, +half_pixel.y)), 0.0).x; - vec2 sampled = vec2(dot(vals, vec4(0.2)) + centre.x * 0.2, centre.y); + vec2 sampled = vec2(dot(vals, vec4(0.2)) + center.x * 0.2, center.y); #else #ifdef MODE_SMART diff --git a/servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl b/servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl index 687fe1e6e2..23eba34d63 100644 --- a/servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl +++ b/servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl @@ -26,7 +26,7 @@ layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; #ifdef GENERATE_MAP -layout(set = 0, binding = 0) uniform sampler2DArray source_ssao; +layout(set = 0, binding = 0) uniform sampler2DArray source_texture; #else layout(set = 0, binding = 0) uniform sampler2D source_importance; #endif @@ -56,11 +56,10 @@ void main() { vec2 base_uv = (vec2(base_position) + vec2(0.5f, 0.5f)) * params.half_screen_pixel_size; - float avg = 0.0; float minV = 1.0; float maxV = 0.0; for (int i = 0; i < 4; i++) { - vec4 vals = textureGather(source_ssao, vec3(base_uv, i)); + vec4 vals = textureGather(source_texture, vec3(base_uv, i)); // apply the same modifications that would have been applied in the main shader vals = params.intensity * vals; @@ -69,8 +68,6 @@ void main() { vals = pow(clamp(vals, 0.0, 1.0), vec4(params.power)); - avg += dot(vec4(vals.x, vals.y, vals.z, vals.w), vec4(1.0 / 16.0, 1.0 / 16.0, 1.0 / 16.0, 1.0 / 16.0)); - maxV = max(maxV, max(max(vals.x, vals.y), max(vals.z, vals.w))); minV = min(minV, min(min(vals.x, vals.y), min(vals.z, vals.w))); } diff --git a/servers/rendering/renderer_rd/shaders/ssil.glsl b/servers/rendering/renderer_rd/shaders/ssil.glsl new file mode 100644 index 0000000000..d1f8f42790 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/ssil.glsl @@ -0,0 +1,444 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2016, Intel Corporation +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to the following conditions: +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of +// the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// File changes (yyyy-mm-dd) +// 2016-09-07: filip.strugar@intel.com: first commit +// 2020-12-05: clayjohn: convert to Vulkan and Godot +// 2021-05-27: clayjohn: convert SSAO to SSIL +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#[compute] + +#version 450 + +#VERSION_DEFINES + +#define SSIL_MAIN_DISK_SAMPLE_COUNT (32) +const vec4 sample_pattern[SSIL_MAIN_DISK_SAMPLE_COUNT] = { + vec4(0.78488064, 0.56661671, 1.500000, -0.126083), vec4(0.26022232, -0.29575172, 1.500000, -1.064030), vec4(0.10459357, 0.08372527, 1.110000, -2.730563), vec4(-0.68286800, 0.04963045, 1.090000, -0.498827), + vec4(-0.13570161, -0.64190155, 1.250000, -0.532765), vec4(-0.26193795, -0.08205118, 0.670000, -1.783245), vec4(-0.61177456, 0.66664219, 0.710000, -0.044234), vec4(0.43675563, 0.25119025, 0.610000, -1.167283), + vec4(0.07884444, 0.86618668, 0.640000, -0.459002), vec4(-0.12790935, -0.29869005, 0.600000, -1.729424), vec4(-0.04031125, 0.02413622, 0.600000, -4.792042), vec4(0.16201244, -0.52851415, 0.790000, -1.067055), + vec4(-0.70991218, 0.47301072, 0.640000, -0.335236), vec4(0.03277707, -0.22349690, 0.600000, -1.982384), vec4(0.68921727, 0.36800742, 0.630000, -0.266718), vec4(0.29251814, 0.37775412, 0.610000, -1.422520), + vec4(-0.12224089, 0.96582592, 0.600000, -0.426142), vec4(0.11071457, -0.16131058, 0.600000, -2.165947), vec4(0.46562141, -0.59747696, 0.600000, -0.189760), vec4(-0.51548797, 0.11804193, 0.600000, -1.246800), + vec4(0.89141309, -0.42090443, 0.600000, 0.028192), vec4(-0.32402530, -0.01591529, 0.600000, -1.543018), vec4(0.60771245, 0.41635221, 0.600000, -0.605411), vec4(0.02379565, -0.08239821, 0.600000, -3.809046), + vec4(0.48951152, -0.23657045, 0.600000, -1.189011), vec4(-0.17611565, -0.81696892, 0.600000, -0.513724), vec4(-0.33930185, -0.20732205, 0.600000, -1.698047), vec4(-0.91974425, 0.05403209, 0.600000, 0.062246), + vec4(-0.15064627, -0.14949332, 0.600000, -1.896062), vec4(0.53180975, -0.35210401, 0.600000, -0.758838), vec4(0.41487166, 0.81442589, 0.600000, -0.505648), vec4(-0.24106961, -0.32721516, 0.600000, -1.665244) +}; + +// these values can be changed (up to SSIL_MAX_TAPS) with no changes required elsewhere; values for 4th and 5th preset are ignored but array needed to avoid compilation errors +// the actual number of texture samples is two times this value (each "tap" has two symmetrical depth texture samples) +const int num_taps[5] = { 3, 5, 12, 0, 0 }; + +#define SSIL_TILT_SAMPLES_ENABLE_AT_QUALITY_PRESET (99) // to disable simply set to 99 or similar +#define SSIL_TILT_SAMPLES_AMOUNT (0.4) +// +#define SSIL_HALOING_REDUCTION_ENABLE_AT_QUALITY_PRESET (1) // to disable simply set to 99 or similar +#define SSIL_HALOING_REDUCTION_AMOUNT (0.8) // values from 0.0 - 1.0, 1.0 means max weighting (will cause artifacts, 0.8 is more reasonable) +// +#define SSIL_DEPTH_MIPS_ENABLE_AT_QUALITY_PRESET (2) +#define SSIL_DEPTH_MIPS_GLOBAL_OFFSET (-4.3) // best noise/quality/performance tradeoff, found empirically +// +// !!warning!! the edge handling is hard-coded to 'disabled' on quality level 0, and enabled above, on the C++ side; while toggling it here will work for +// testing purposes, it will not yield performance gains (or correct results) +#define SSIL_DEPTH_BASED_EDGES_ENABLE_AT_QUALITY_PRESET (1) +// +#define SSIL_REDUCE_RADIUS_NEAR_SCREEN_BORDER_ENABLE_AT_QUALITY_PRESET (1) + +#define SSIL_MAX_TAPS 32 +#define SSIL_ADAPTIVE_TAP_BASE_COUNT 5 +#define SSIL_ADAPTIVE_TAP_FLEXIBLE_COUNT (SSIL_MAX_TAPS - SSIL_ADAPTIVE_TAP_BASE_COUNT) +#define SSIL_DEPTH_MIP_LEVELS 4 + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +layout(set = 0, binding = 0) uniform sampler2DArray source_depth_mipmaps; +layout(rgba8, set = 0, binding = 1) uniform restrict readonly image2D source_normal; +layout(set = 0, binding = 2) uniform Constants { //get into a lower set + vec4 rotation_matrices[20]; +} +constants; + +#ifdef ADAPTIVE +layout(rgba16, set = 1, binding = 0) uniform restrict readonly image2DArray source_ssil; +layout(set = 1, binding = 1) uniform sampler2D source_importance; +layout(set = 1, binding = 2, std430) buffer Counter { + uint sum; +} +counter; +#endif + +layout(rgba16, set = 2, binding = 0) uniform restrict writeonly image2D dest_image; +layout(r8, set = 2, binding = 1) uniform image2D edges_weights_image; + +layout(set = 3, binding = 0) uniform sampler2D last_frame; +layout(set = 3, binding = 1) uniform ProjectionConstants { + mat4 reprojection; +} +projection_constants; + +layout(push_constant, binding = 3, std430) uniform Params { + ivec2 screen_size; + int pass; + int quality; + + vec2 half_screen_pixel_size; + vec2 half_screen_pixel_size_x025; + + vec2 NDC_to_view_mul; + vec2 NDC_to_view_add; + + vec2 pad2; + float z_near; + float z_far; + + float radius; + float intensity; + int size_multiplier; + int pad; + + float fade_out_mul; + float fade_out_add; + float normal_rejection_amount; + float inv_radius_near_limit; + + bool is_orthogonal; + float neg_inv_radius; + float load_counter_avg_div; + float adaptive_sample_limit; + + ivec2 pass_coord_offset; + vec2 pass_uv_offset; +} +params; + +float pack_edges(vec4 p_edgesLRTB) { + p_edgesLRTB = round(clamp(p_edgesLRTB, 0.0, 1.0) * 3.05); + return dot(p_edgesLRTB, vec4(64.0 / 255.0, 16.0 / 255.0, 4.0 / 255.0, 1.0 / 255.0)); +} + +vec3 NDC_to_view_space(vec2 p_pos, float p_viewspace_depth) { + if (params.is_orthogonal) { + return vec3((params.NDC_to_view_mul * p_pos.xy + params.NDC_to_view_add), p_viewspace_depth); + } else { + return vec3((params.NDC_to_view_mul * p_pos.xy + params.NDC_to_view_add) * p_viewspace_depth, p_viewspace_depth); + } +} + +// calculate effect radius and fit our screen sampling pattern inside it +void calculate_radius_parameters(const float p_pix_center_length, const vec2 p_pixel_size_at_center, out float r_lookup_radius, out float r_radius, out float r_fallof_sq) { + r_radius = params.radius; + + // when too close, on-screen sampling disk will grow beyond screen size; limit this to avoid closeup temporal artifacts + const float too_close_limit = clamp(p_pix_center_length * params.inv_radius_near_limit, 0.0, 1.0) * 0.8 + 0.2; + + r_radius *= too_close_limit; + + // 0.85 is to reduce the radius to allow for more samples on a slope to still stay within influence + r_lookup_radius = (0.85 * r_radius) / p_pixel_size_at_center.x; + + // used to calculate falloff (both for AO samples and per-sample weights) + r_fallof_sq = -1.0 / (r_radius * r_radius); +} + +vec4 calculate_edges(const float p_center_z, const float p_left_z, const float p_right_z, const float p_top_z, const float p_bottom_z) { + // slope-sensitive depth-based edge detection + vec4 edgesLRTB = vec4(p_left_z, p_right_z, p_top_z, p_bottom_z) - p_center_z; + vec4 edgesLRTB_slope_adjusted = edgesLRTB + edgesLRTB.yxwz; + edgesLRTB = min(abs(edgesLRTB), abs(edgesLRTB_slope_adjusted)); + return clamp((1.3 - edgesLRTB / (p_center_z * 0.040)), 0.0, 1.0); +} + +vec3 decode_normal(vec3 p_encoded_normal) { + vec3 normal = p_encoded_normal * 2.0 - 1.0; + return normal; +} + +vec3 load_normal(ivec2 p_pos) { + vec3 encoded_normal = imageLoad(source_normal, p_pos).xyz; + encoded_normal.z = 1.0 - encoded_normal.z; + return decode_normal(encoded_normal); +} + +vec3 load_normal(ivec2 p_pos, ivec2 p_offset) { + vec3 encoded_normal = imageLoad(source_normal, p_pos + p_offset).xyz; + encoded_normal.z = 1.0 - encoded_normal.z; + return decode_normal(encoded_normal); +} + +// all vectors in viewspace +float calculate_pixel_obscurance(vec3 p_pixel_normal, vec3 p_hit_delta, float p_fallof_sq) { + float length_sq = dot(p_hit_delta, p_hit_delta); + float NdotD = dot(p_pixel_normal, p_hit_delta) / sqrt(length_sq); + + float falloff_mult = max(0.0, length_sq * p_fallof_sq + 1.0); + + return max(0, NdotD - 0.05) * falloff_mult; +} + +void SSIL_tap_inner(const int p_quality_level, inout vec3 r_color_sum, inout float r_obscurance_sum, inout float r_weight_sum, const vec2 p_sampling_uv, const float p_mip_level, const vec3 p_pix_center_pos, vec3 p_pixel_normal, const float p_fallof_sq, const float p_weight_mod) { + // get depth at sample + float viewspace_sample_z = textureLod(source_depth_mipmaps, vec3(p_sampling_uv, params.pass), p_mip_level).x; + vec3 sample_normal = load_normal(ivec2(p_sampling_uv * vec2(params.screen_size))); + + // convert to viewspace + vec3 hit_pos = NDC_to_view_space(p_sampling_uv.xy, viewspace_sample_z); + vec3 hit_delta = hit_pos - p_pix_center_pos; + + float obscurance = calculate_pixel_obscurance(p_pixel_normal, hit_delta, p_fallof_sq); + float weight = 1.0; + + if (p_quality_level >= SSIL_HALOING_REDUCTION_ENABLE_AT_QUALITY_PRESET) { + float reduct = max(0, -hit_delta.z); + reduct = clamp(reduct * params.neg_inv_radius + 2.0, 0.0, 1.0); + weight = SSIL_HALOING_REDUCTION_AMOUNT * reduct + (1.0 - SSIL_HALOING_REDUCTION_AMOUNT); + } + + // Translate sampling_uv to last screen's coordinates + const vec4 sample_pos = projection_constants.reprojection * vec4(p_sampling_uv * 2.0 - 1.0, (viewspace_sample_z - params.z_near) / (params.z_far - params.z_near) * 2.0 - 1.0, 1.0); + vec2 reprojected_sampling_uv = (sample_pos.xy / sample_pos.w) * 0.5 + 0.5; + + weight *= p_weight_mod; + + r_obscurance_sum += obscurance * weight; + + vec3 sample_color = textureLod(last_frame, reprojected_sampling_uv, 5.0).rgb; + // Reduce impact of fireflies by tonemapping before averaging: http://graphicrants.blogspot.com/2013/12/tone-mapping.html + sample_color /= (1.0 + dot(sample_color, vec3(0.299, 0.587, 0.114))); + r_color_sum += sample_color * obscurance * weight * mix(1.0, smoothstep(0.0, 0.1, -dot(sample_normal, normalize(hit_delta))), params.normal_rejection_amount); + r_weight_sum += weight; +} + +void SSILTap(const int p_quality_level, inout vec3 r_color_sum, inout float r_obscurance_sum, inout float r_weight_sum, const int p_tap_index, const mat2 p_rot_scale, const vec3 p_pix_center_pos, vec3 p_pixel_normal, const vec2 p_normalized_screen_pos, const float p_mip_offset, const float p_fallof_sq, float p_weight_mod, vec2 p_norm_xy, float p_norm_xy_length) { + vec2 sample_offset; + float sample_pow_2_len; + + // patterns + { + vec4 new_sample = sample_pattern[p_tap_index]; + sample_offset = new_sample.xy * p_rot_scale; + sample_pow_2_len = new_sample.w; // precalculated, same as: sample_pow_2_len = log2( length( new_sample.xy ) ); + p_weight_mod *= new_sample.z; + } + + // snap to pixel center (more correct obscurance math, avoids artifacts) + sample_offset = round(sample_offset); + + // calculate MIP based on the sample distance from the centre, similar to as described + // in http://graphics.cs.williams.edu/papers/SAOHPG12/. + float mip_level = (p_quality_level < SSIL_DEPTH_MIPS_ENABLE_AT_QUALITY_PRESET) ? (0) : (sample_pow_2_len + p_mip_offset); + + vec2 sampling_uv = sample_offset * params.half_screen_pixel_size + p_normalized_screen_pos; + + SSIL_tap_inner(p_quality_level, r_color_sum, r_obscurance_sum, r_weight_sum, sampling_uv, mip_level, p_pix_center_pos, p_pixel_normal, p_fallof_sq, p_weight_mod); + + // for the second tap, just use the mirrored offset + vec2 sample_offset_mirrored_uv = -sample_offset; + + // tilt the second set of samples so that the disk is effectively rotated by the normal + // effective at removing one set of artifacts, but too expensive for lower quality settings + if (p_quality_level >= SSIL_TILT_SAMPLES_ENABLE_AT_QUALITY_PRESET) { + float dot_norm = dot(sample_offset_mirrored_uv, p_norm_xy); + sample_offset_mirrored_uv -= dot_norm * p_norm_xy_length * p_norm_xy; + sample_offset_mirrored_uv = round(sample_offset_mirrored_uv); + } + + // snap to pixel center (more correct obscurance math, avoids artifacts) + vec2 sampling_mirrored_uv = sample_offset_mirrored_uv * params.half_screen_pixel_size + p_normalized_screen_pos; + + SSIL_tap_inner(p_quality_level, r_color_sum, r_obscurance_sum, r_weight_sum, sampling_mirrored_uv, mip_level, p_pix_center_pos, p_pixel_normal, p_fallof_sq, p_weight_mod); +} + +void generate_SSIL(out vec3 r_color, out vec4 r_edges, out float r_obscurance, out float r_weight, const vec2 p_pos, int p_quality_level, bool p_adaptive_base) { + vec2 pos_rounded = trunc(p_pos); + uvec2 upos = uvec2(pos_rounded); + + const int number_of_taps = (p_adaptive_base) ? (SSIL_ADAPTIVE_TAP_BASE_COUNT) : (num_taps[p_quality_level]); + float pix_z, pix_left_z, pix_top_z, pix_right_z, pix_bottom_z; + + vec4 valuesUL = textureGather(source_depth_mipmaps, vec3(pos_rounded * params.half_screen_pixel_size, params.pass)); + vec4 valuesBR = textureGather(source_depth_mipmaps, vec3((pos_rounded + vec2(1.0)) * params.half_screen_pixel_size, params.pass)); + + // get this pixel's viewspace depth + pix_z = valuesUL.y; + + // get left right top bottom neighbouring pixels for edge detection (gets compiled out on quality_level == 0) + pix_left_z = valuesUL.x; + pix_top_z = valuesUL.z; + pix_right_z = valuesBR.z; + pix_bottom_z = valuesBR.x; + + vec2 normalized_screen_pos = pos_rounded * params.half_screen_pixel_size + params.half_screen_pixel_size_x025; + vec3 pix_center_pos = NDC_to_view_space(normalized_screen_pos, pix_z); + + // Load this pixel's viewspace normal + uvec2 full_res_coord = upos * 2 * params.size_multiplier + params.pass_coord_offset.xy; + vec3 pixel_normal = load_normal(ivec2(full_res_coord)); + + const vec2 pixel_size_at_center = NDC_to_view_space(normalized_screen_pos.xy + params.half_screen_pixel_size, pix_center_pos.z).xy - pix_center_pos.xy; + + float pixel_lookup_radius; + float fallof_sq; + + // calculate effect radius and fit our screen sampling pattern inside it + float viewspace_radius; + calculate_radius_parameters(length(pix_center_pos), pixel_size_at_center, pixel_lookup_radius, viewspace_radius, fallof_sq); + + // calculate samples rotation/scaling + mat2 rot_scale_matrix; + uint pseudo_random_index; + + { + vec4 rotation_scale; + // reduce effect radius near the screen edges slightly; ideally, one would render a larger depth buffer (5% on each side) instead + if (!p_adaptive_base && (p_quality_level >= SSIL_REDUCE_RADIUS_NEAR_SCREEN_BORDER_ENABLE_AT_QUALITY_PRESET)) { + float near_screen_border = min(min(normalized_screen_pos.x, 1.0 - normalized_screen_pos.x), min(normalized_screen_pos.y, 1.0 - normalized_screen_pos.y)); + near_screen_border = clamp(10.0 * near_screen_border + 0.6, 0.0, 1.0); + pixel_lookup_radius *= near_screen_border; + } + + // load & update pseudo-random rotation matrix + pseudo_random_index = uint(pos_rounded.y * 2 + pos_rounded.x) % 5; + rotation_scale = constants.rotation_matrices[params.pass * 5 + pseudo_random_index]; + rot_scale_matrix = mat2(rotation_scale.x * pixel_lookup_radius, rotation_scale.y * pixel_lookup_radius, rotation_scale.z * pixel_lookup_radius, rotation_scale.w * pixel_lookup_radius); + } + + // the main obscurance & sample weight storage + vec3 color_sum = vec3(0.0); + float obscurance_sum = 0.0; + float weight_sum = 0.0; + + // edge mask for between this and left/right/top/bottom neighbour pixels - not used in quality level 0 so initialize to "no edge" (1 is no edge, 0 is edge) + vec4 edgesLRTB = vec4(1.0, 1.0, 1.0, 1.0); + + // Move center pixel slightly towards camera to avoid imprecision artifacts due to using of 16bit depth buffer; a lot smaller offsets needed when using 32bit floats + pix_center_pos *= 0.9992; + + if (!p_adaptive_base && (p_quality_level >= SSIL_DEPTH_BASED_EDGES_ENABLE_AT_QUALITY_PRESET)) { + edgesLRTB = calculate_edges(pix_z, pix_left_z, pix_right_z, pix_top_z, pix_bottom_z); + } + + const float global_mip_offset = SSIL_DEPTH_MIPS_GLOBAL_OFFSET; + float mip_offset = (p_quality_level < SSIL_DEPTH_MIPS_ENABLE_AT_QUALITY_PRESET) ? (0) : (log2(pixel_lookup_radius) + global_mip_offset); + + // Used to tilt the second set of samples so that the disk is effectively rotated by the normal + // effective at removing one set of artifacts, but too expensive for lower quality settings + vec2 norm_xy = vec2(pixel_normal.x, pixel_normal.y); + float norm_xy_length = length(norm_xy); + norm_xy /= vec2(norm_xy_length, -norm_xy_length); + norm_xy_length *= SSIL_TILT_SAMPLES_AMOUNT; + + // standard, non-adaptive approach + if ((p_quality_level != 3) || p_adaptive_base) { + for (int i = 0; i < number_of_taps; i++) { + SSILTap(p_quality_level, color_sum, obscurance_sum, weight_sum, i, rot_scale_matrix, pix_center_pos, pixel_normal, normalized_screen_pos, mip_offset, fallof_sq, 1.0, norm_xy, norm_xy_length); + } + } +#ifdef ADAPTIVE + else { + // add new ones if needed + vec2 full_res_uv = normalized_screen_pos + params.pass_uv_offset.xy; + float importance = textureLod(source_importance, full_res_uv, 0.0).x; + + //Need to store obscurance from base pass + // load existing base values + vec4 base_values = imageLoad(source_ssil, ivec3(upos, params.pass)); + weight_sum += imageLoad(edges_weights_image, ivec2(upos)).r * float(SSIL_ADAPTIVE_TAP_BASE_COUNT * 4.0); + color_sum += (base_values.rgb) * weight_sum; + obscurance_sum += (base_values.a) * weight_sum; + + // increase importance around edges + float edge_count = dot(1.0 - edgesLRTB, vec4(1.0, 1.0, 1.0, 1.0)); + + float avg_total_importance = float(counter.sum) * params.load_counter_avg_div; + + float importance_limiter = clamp(params.adaptive_sample_limit / avg_total_importance, 0.0, 1.0); + importance *= importance_limiter; + + float additional_sample_count = SSIL_ADAPTIVE_TAP_FLEXIBLE_COUNT * importance; + + const float blend_range = 3.0; + const float blend_range_inv = 1.0 / blend_range; + + additional_sample_count += 0.5; + uint additional_samples = uint(additional_sample_count); + uint additional_samples_to = min(SSIL_MAX_TAPS, additional_samples + SSIL_ADAPTIVE_TAP_BASE_COUNT); + + for (uint i = SSIL_ADAPTIVE_TAP_BASE_COUNT; i < additional_samples_to; i++) { + additional_sample_count -= 1.0f; + float weight_mod = clamp(additional_sample_count * blend_range_inv, 0.0, 1.0); + SSILTap(p_quality_level, color_sum, obscurance_sum, weight_sum, int(i), rot_scale_matrix, pix_center_pos, pixel_normal, normalized_screen_pos, mip_offset, fallof_sq, weight_mod, norm_xy, norm_xy_length); + } + } +#endif + + // Early out for adaptive base + if (p_adaptive_base) { + vec3 color = color_sum / weight_sum; + + r_color = color; + r_edges = vec4(0.0); + r_obscurance = obscurance_sum / weight_sum; + r_weight = weight_sum; + return; + } + + // Calculate weighted average + vec3 color = color_sum / weight_sum; + color /= 1.0 - dot(color, vec3(0.299, 0.587, 0.114)); + + // Calculate fadeout (1 close, gradient, 0 far) + float fade_out = clamp(pix_center_pos.z * params.fade_out_mul + params.fade_out_add, 0.0, 1.0); + + // Reduce the SSIL if we're on the edge to remove artifacts on edges (we don't care for the lower quality one) + if (!p_adaptive_base && (p_quality_level >= SSIL_DEPTH_BASED_EDGES_ENABLE_AT_QUALITY_PRESET)) { + // when there's more than 2 opposite edges, start fading out the occlusion to reduce aliasing artifacts + float edge_fadeout_factor = clamp((1.0 - edgesLRTB.x - edgesLRTB.y) * 0.35, 0.0, 1.0) + clamp((1.0 - edgesLRTB.z - edgesLRTB.w) * 0.35, 0.0, 1.0); + + fade_out *= clamp(1.0 - edge_fadeout_factor, 0.0, 1.0); + } + + color = params.intensity * color; + + color *= fade_out; + + // outputs! + r_color = color; + r_edges = edgesLRTB; // These are used to prevent blurring across edges, 1 means no edge, 0 means edge, 0.5 means half way there, etc. + r_obscurance = clamp((obscurance_sum / weight_sum) * params.intensity, 0.0, 1.0); + r_weight = weight_sum; +} + +void main() { + vec3 out_color; + float out_obscurance; + float out_weight; + vec4 out_edges; + ivec2 ssC = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThanEqual(ssC, params.screen_size))) { //too large, do nothing + return; + } + + vec2 uv = vec2(gl_GlobalInvocationID) + vec2(0.5); +#ifdef SSIL_BASE + generate_SSIL(out_color, out_edges, out_obscurance, out_weight, uv, params.quality, true); + + imageStore(dest_image, ssC, vec4(out_color, out_obscurance)); + imageStore(edges_weights_image, ssC, vec4(out_weight / (float(SSIL_ADAPTIVE_TAP_BASE_COUNT) * 4.0))); +#else + generate_SSIL(out_color, out_edges, out_obscurance, out_weight, uv, params.quality, false); // pass in quality levels + + imageStore(dest_image, ssC, vec4(out_color, out_obscurance)); + imageStore(edges_weights_image, ssC, vec4(pack_edges(out_edges))); +#endif +} diff --git a/servers/rendering/renderer_rd/shaders/ssil_blur.glsl b/servers/rendering/renderer_rd/shaders/ssil_blur.glsl new file mode 100644 index 0000000000..11861e261f --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/ssil_blur.glsl @@ -0,0 +1,124 @@ +#[compute] + +#version 450 + +#VERSION_DEFINES + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +layout(set = 0, binding = 0) uniform sampler2D source_ssil; + +layout(rgba16, set = 1, binding = 0) uniform restrict writeonly image2D dest_image; + +layout(r8, set = 2, binding = 0) uniform restrict readonly image2D source_edges; + +layout(push_constant, binding = 1, std430) uniform Params { + float edge_sharpness; + float pad; + vec2 half_screen_pixel_size; +} +params; + +vec4 unpack_edges(float p_packed_val) { + uint packed_val = uint(p_packed_val * 255.5); + vec4 edgesLRTB; + edgesLRTB.x = float((packed_val >> 6) & 0x03) / 3.0; + edgesLRTB.y = float((packed_val >> 4) & 0x03) / 3.0; + edgesLRTB.z = float((packed_val >> 2) & 0x03) / 3.0; + edgesLRTB.w = float((packed_val >> 0) & 0x03) / 3.0; + + return clamp(edgesLRTB + params.edge_sharpness, 0.0, 1.0); +} + +void add_sample(vec4 p_ssil_value, float p_edge_value, inout vec4 r_sum, inout float r_sum_weight) { + float weight = p_edge_value; + + r_sum += (weight * p_ssil_value); + r_sum_weight += weight; +} + +#ifdef MODE_WIDE +vec4 sample_blurred_wide(ivec2 p_pos, vec2 p_coord) { + vec4 ssil_value = textureLodOffset(source_ssil, vec2(p_coord), 0.0, ivec2(0, 0)); + vec4 ssil_valueL = textureLodOffset(source_ssil, vec2(p_coord), 0.0, ivec2(-2, 0)); + vec4 ssil_valueT = textureLodOffset(source_ssil, vec2(p_coord), 0.0, ivec2(0, -2)); + vec4 ssil_valueR = textureLodOffset(source_ssil, vec2(p_coord), 0.0, ivec2(2, 0)); + vec4 ssil_valueB = textureLodOffset(source_ssil, vec2(p_coord), 0.0, ivec2(0, 2)); + + vec4 edgesLRTB = unpack_edges(imageLoad(source_edges, p_pos).r); + edgesLRTB.x *= unpack_edges(imageLoad(source_edges, p_pos + ivec2(-2, 0)).r).y; + edgesLRTB.z *= unpack_edges(imageLoad(source_edges, p_pos + ivec2(0, -2)).r).w; + edgesLRTB.y *= unpack_edges(imageLoad(source_edges, p_pos + ivec2(2, 0)).r).x; + edgesLRTB.w *= unpack_edges(imageLoad(source_edges, p_pos + ivec2(0, 2)).r).z; + + float sum_weight = 0.8; + vec4 sum = ssil_value * sum_weight; + + add_sample(ssil_valueL, edgesLRTB.x, sum, sum_weight); + add_sample(ssil_valueR, edgesLRTB.y, sum, sum_weight); + add_sample(ssil_valueT, edgesLRTB.z, sum, sum_weight); + add_sample(ssil_valueB, edgesLRTB.w, sum, sum_weight); + + vec4 ssil_avg = sum / sum_weight; + + ssil_value = ssil_avg; + + return ssil_value; +} +#endif + +#ifdef MODE_SMART +vec4 sample_blurred(ivec2 p_pos, vec2 p_coord) { + vec4 vC = textureLodOffset(source_ssil, vec2(p_coord), 0.0, ivec2(0, 0)); + vec4 vL = textureLodOffset(source_ssil, vec2(p_coord), 0.0, ivec2(-1, 0)); + vec4 vT = textureLodOffset(source_ssil, vec2(p_coord), 0.0, ivec2(0, -1)); + vec4 vR = textureLodOffset(source_ssil, vec2(p_coord), 0.0, ivec2(1, 0)); + vec4 vB = textureLodOffset(source_ssil, vec2(p_coord), 0.0, ivec2(0, 1)); + + float packed_edges = imageLoad(source_edges, p_pos).r; + vec4 edgesLRTB = unpack_edges(packed_edges); + + float sum_weight = 0.5; + vec4 sum = vC * sum_weight; + + add_sample(vL, edgesLRTB.x, sum, sum_weight); + add_sample(vR, edgesLRTB.y, sum, sum_weight); + add_sample(vT, edgesLRTB.z, sum, sum_weight); + add_sample(vB, edgesLRTB.w, sum, sum_weight); + + vec4 ssil_avg = sum / sum_weight; + + vec4 ssil_value = ssil_avg; + + return ssil_value; +} +#endif + +void main() { + // Pixel being shaded + ivec2 ssC = ivec2(gl_GlobalInvocationID.xy); + +#ifdef MODE_NON_SMART + + vec2 half_pixel = params.half_screen_pixel_size * 0.5; + + vec2 uv = (vec2(gl_GlobalInvocationID.xy) + vec2(0.5, 0.5)) * params.half_screen_pixel_size; + + vec4 centre = textureLod(source_ssil, uv, 0.0); + + vec4 value = textureLod(source_ssil, vec2(uv + vec2(-half_pixel.x * 3, -half_pixel.y)), 0.0) * 0.2; + value += textureLod(source_ssil, vec2(uv + vec2(+half_pixel.x, -half_pixel.y * 3)), 0.0) * 0.2; + value += textureLod(source_ssil, vec2(uv + vec2(-half_pixel.x, +half_pixel.y * 3)), 0.0) * 0.2; + value += textureLod(source_ssil, vec2(uv + vec2(+half_pixel.x * 3, +half_pixel.y)), 0.0) * 0.2; + + vec4 sampled = value + centre * 0.2; + +#else +#ifdef MODE_SMART + vec4 sampled = sample_blurred(ssC, (vec2(gl_GlobalInvocationID.xy) + vec2(0.5, 0.5)) * params.half_screen_pixel_size); +#else // MODE_WIDE + vec4 sampled = sample_blurred_wide(ssC, (vec2(gl_GlobalInvocationID.xy) + vec2(0.5, 0.5)) * params.half_screen_pixel_size); +#endif +#endif // MODE_NON_SMART + imageStore(dest_image, ssC, sampled); +} diff --git a/servers/rendering/renderer_rd/shaders/ssil_importance_map.glsl b/servers/rendering/renderer_rd/shaders/ssil_importance_map.glsl new file mode 100644 index 0000000000..815aa55fd4 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/ssil_importance_map.glsl @@ -0,0 +1,124 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2016, Intel Corporation +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to the following conditions: +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of +// the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// File changes (yyyy-mm-dd) +// 2016-09-07: filip.strugar@intel.com: first commit +// 2020-12-05: clayjohn: convert to Vulkan and Godot +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#[compute] + +#version 450 + +#VERSION_DEFINES + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +#ifdef GENERATE_MAP +layout(set = 0, binding = 0) uniform sampler2DArray source_texture; +#else +layout(set = 0, binding = 0) uniform sampler2D source_importance; +#endif +layout(r8, set = 1, binding = 0) uniform restrict writeonly image2D dest_image; + +#ifdef PROCESS_MAPB +layout(set = 2, binding = 0, std430) buffer Counter { + uint sum; +} +counter; +#endif + +layout(push_constant, binding = 1, std430) uniform Params { + vec2 half_screen_pixel_size; + float intensity; + float pad; +} +params; + +void main() { + // Pixel being shaded + ivec2 ssC = ivec2(gl_GlobalInvocationID.xy); + +#ifdef GENERATE_MAP + // importance map stuff + uvec2 base_position = ssC * 2; + + float avg = 0.0; + float minV = 1.0; + float maxV = 0.0; + for (int i = 0; i < 4; i++) { + vec3 value_a = texelFetch(source_texture, ivec3(base_position, i), 0).rgb * params.intensity; + vec3 value_b = texelFetch(source_texture, ivec3(base_position, i) + ivec3(0, 1, 0), 0).rgb * params.intensity; + vec3 value_c = texelFetch(source_texture, ivec3(base_position, i) + ivec3(1, 0, 0), 0).rgb * params.intensity; + vec3 value_d = texelFetch(source_texture, ivec3(base_position, i) + ivec3(1, 1, 0), 0).rgb * params.intensity; + + // Calculate luminance (black and white value) + float a = dot(value_a, vec3(0.2125, 0.7154, 0.0721)); + float b = dot(value_b, vec3(0.2125, 0.7154, 0.0721)); + float c = dot(value_c, vec3(0.2125, 0.7154, 0.0721)); + float d = dot(value_d, vec3(0.2125, 0.7154, 0.0721)); + + maxV = max(maxV, max(max(a, b), max(c, d))); + minV = min(minV, min(min(a, b), min(c, d))); + } + + float min_max_diff = maxV - minV; + + imageStore(dest_image, ssC, vec4(pow(clamp(min_max_diff * 2.0, 0.0, 1.0), 0.6))); +#endif + +#ifdef PROCESS_MAPA + vec2 uv = (vec2(ssC) + 0.5) * params.half_screen_pixel_size * 2.0; + + float centre = textureLod(source_importance, uv, 0.0).x; + + vec2 half_pixel = params.half_screen_pixel_size; + + vec4 vals; + vals.x = textureLod(source_importance, uv + vec2(-half_pixel.x * 3, -half_pixel.y), 0.0).x; + vals.y = textureLod(source_importance, uv + vec2(+half_pixel.x, -half_pixel.y * 3), 0.0).x; + vals.z = textureLod(source_importance, uv + vec2(+half_pixel.x * 3, +half_pixel.y), 0.0).x; + vals.w = textureLod(source_importance, uv + vec2(-half_pixel.x, +half_pixel.y * 3), 0.0).x; + + float avg = dot(vals, vec4(0.25, 0.25, 0.25, 0.25)); + + imageStore(dest_image, ssC, vec4(avg)); +#endif + +#ifdef PROCESS_MAPB + vec2 uv = (vec2(ssC) + 0.5f) * params.half_screen_pixel_size * 2.0; + + float centre = textureLod(source_importance, uv, 0.0).x; + + vec2 half_pixel = params.half_screen_pixel_size; + + vec4 vals; + vals.x = textureLod(source_importance, uv + vec2(-half_pixel.x, -half_pixel.y * 3), 0.0).x; + vals.y = textureLod(source_importance, uv + vec2(+half_pixel.x * 3, -half_pixel.y), 0.0).x; + vals.z = textureLod(source_importance, uv + vec2(+half_pixel.x, +half_pixel.y * 3), 0.0).x; + vals.w = textureLod(source_importance, uv + vec2(-half_pixel.x * 3, +half_pixel.y), 0.0).x; + + float avg = dot(vals, vec4(0.25, 0.25, 0.25, 0.25)); + + imageStore(dest_image, ssC, vec4(avg)); + + // sum the average; to avoid overflowing we assume max AO resolution is not bigger than 16384x16384; so quarter res (used here) will be 4096x4096, which leaves us with 8 bits per pixel + uint sum = uint(clamp(avg, 0.0, 1.0) * 255.0 + 0.5); + + // save every 9th to avoid InterlockedAdd congestion - since we're blurring, this is good enough; compensated by multiplying load_counter_avg_div by 9 + if (((ssC.x % 3) + (ssC.y % 3)) == 0) { + atomicAdd(counter.sum, sum); + } +#endif +} diff --git a/servers/rendering/renderer_rd/shaders/ssil_interleave.glsl b/servers/rendering/renderer_rd/shaders/ssil_interleave.glsl new file mode 100644 index 0000000000..8a7a5ae4fd --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/ssil_interleave.glsl @@ -0,0 +1,102 @@ +#[compute] + +#version 450 + +#VERSION_DEFINES + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +layout(rgba16, set = 0, binding = 0) uniform restrict writeonly image2D dest_image; +layout(set = 1, binding = 0) uniform sampler2DArray source_texture; +layout(r8, set = 2, binding = 0) uniform restrict readonly image2DArray source_edges; + +layout(push_constant, binding = 1, std430) uniform Params { + float inv_sharpness; + uint size_modifier; + vec2 pixel_size; +} +params; + +vec4 unpack_edges(float p_packed_val) { + uint packed_val = uint(p_packed_val * 255.5); + vec4 edgesLRTB; + edgesLRTB.x = float((packed_val >> 6) & 0x03) / 3.0; + edgesLRTB.y = float((packed_val >> 4) & 0x03) / 3.0; + edgesLRTB.z = float((packed_val >> 2) & 0x03) / 3.0; + edgesLRTB.w = float((packed_val >> 0) & 0x03) / 3.0; + + return clamp(edgesLRTB + params.inv_sharpness, 0.0, 1.0); +} + +void main() { + ivec2 ssC = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThanEqual(ssC, ivec2(1.0 / params.pixel_size)))) { //too large, do nothing + return; + } + +#ifdef MODE_SMART + uvec2 pix_pos = uvec2(gl_GlobalInvocationID.xy); + vec2 uv = (gl_GlobalInvocationID.xy + vec2(0.5)) * params.pixel_size; + + // calculate index in the four deinterleaved source array texture + int mx = int(pix_pos.x % 2); + int my = int(pix_pos.y % 2); + int index_center = mx + my * 2; // center index + int index_horizontal = (1 - mx) + my * 2; // neighbouring, horizontal + int index_vertical = mx + (1 - my) * 2; // neighbouring, vertical + int index_diagonal = (1 - mx) + (1 - my) * 2; // diagonal + + vec4 color = texelFetch(source_texture, ivec3(pix_pos / uvec2(params.size_modifier), index_center), 0); + + vec4 edgesLRTB = unpack_edges(imageLoad(source_edges, ivec3(pix_pos / uvec2(params.size_modifier), index_center)).r); + + // convert index shifts to sampling offsets + float fmx = float(mx); + float fmy = float(my); + + // in case of an edge, push sampling offsets away from the edge (towards pixel center) + float fmxe = (edgesLRTB.y - edgesLRTB.x); + float fmye = (edgesLRTB.w - edgesLRTB.z); + + // calculate final sampling offsets and sample using bilinear filter + vec2 uv_horizontal = (gl_GlobalInvocationID.xy + vec2(0.5) + vec2(fmx + fmxe - 0.5, 0.5 - fmy)) * params.pixel_size; + vec4 color_horizontal = textureLod(source_texture, vec3(uv_horizontal, index_horizontal), 0.0); + vec2 uv_vertical = (gl_GlobalInvocationID.xy + vec2(0.5) + vec2(0.5 - fmx, fmy - 0.5 + fmye)) * params.pixel_size; + vec4 color_vertical = textureLod(source_texture, vec3(uv_vertical, index_vertical), 0.0); + vec2 uv_diagonal = (gl_GlobalInvocationID.xy + vec2(0.5) + vec2(fmx - 0.5 + fmxe, fmy - 0.5 + fmye)) * params.pixel_size; + vec4 color_diagonal = textureLod(source_texture, vec3(uv_diagonal, index_diagonal), 0.0); + + // reduce weight for samples near edge - if the edge is on both sides, weight goes to 0 + vec4 blendWeights; + blendWeights.x = 1.0; + blendWeights.y = (edgesLRTB.x + edgesLRTB.y) * 0.5; + blendWeights.z = (edgesLRTB.z + edgesLRTB.w) * 0.5; + blendWeights.w = (blendWeights.y + blendWeights.z) * 0.5; + + // calculate weighted average + float blendWeightsSum = dot(blendWeights, vec4(1.0, 1.0, 1.0, 1.0)); + color += color_horizontal * blendWeights.y; + color += color_vertical * blendWeights.z; + color += color_diagonal * blendWeights.w; + color /= blendWeightsSum; + + imageStore(dest_image, ivec2(gl_GlobalInvocationID.xy), color); +#else // !MODE_SMART + + vec2 uv = (gl_GlobalInvocationID.xy + vec2(0.5)) * params.pixel_size; +#ifdef MODE_HALF + vec4 a = textureLod(source_texture, vec3(uv, 0), 0.0); + vec4 d = textureLod(source_texture, vec3(uv, 3), 0.0); + vec4 avg = (a + d) * 0.5; + +#else + vec4 a = textureLod(source_texture, vec3(uv, 0), 0.0); + vec4 b = textureLod(source_texture, vec3(uv, 1), 0.0); + vec4 c = textureLod(source_texture, vec3(uv, 2), 0.0); + vec4 d = textureLod(source_texture, vec3(uv, 3), 0.0); + vec4 avg = (a + b + c + d) * 0.25; + +#endif + imageStore(dest_image, ivec2(gl_GlobalInvocationID.xy), avg); +#endif +} diff --git a/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl b/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl index 747f88960c..7c8d4f7f99 100644 --- a/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl +++ b/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl @@ -76,19 +76,15 @@ layout(set = 0, binding = 10) uniform sampler shadow_sampler; #define MAX_VOXEL_GI_INSTANCES 8 struct VoxelGIData { - mat4 xform; - vec3 bounds; - float dynamic_range; + mat4 xform; // 64 - 64 - float bias; - float normal_bias; - bool blend_ambient; - uint texture_slot; + vec3 bounds; // 12 - 76 + float dynamic_range; // 4 - 80 - float anisotropy_strength; - float ambient_occlusion; - float ambient_occlusion_size; - uint mipmaps; + float bias; // 4 - 84 + float normal_bias; // 4 - 88 + bool blend_ambient; // 4 - 92 + uint mipmaps; // 4 - 96 }; layout(set = 0, binding = 11, std140) uniform VoxelGIs { @@ -581,16 +577,29 @@ void main() { if (spot_lights.data[light_index].shadow_enabled) { //has shadow - vec4 v = vec4(view_pos, 1.0); + vec4 uv_rect = spot_lights.data[light_index].atlas_rect; + vec2 flip_offset = spot_lights.data[light_index].direction.xy; - vec4 splane = (spot_lights.data[light_index].shadow_matrix * v); - splane /= splane.w; + vec3 local_vert = (spot_lights.data[light_index].shadow_matrix * vec4(view_pos, 1.0)).xyz; - float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r; + float shadow_len = length(local_vert); //need to remember shadow len from here + vec3 shadow_sample = normalize(local_vert); - shadow_attenuation = exp(min(0.0, (depth - splane.z)) / spot_lights.data[light_index].inv_radius * spot_lights.data[light_index].shadow_volumetric_fog_fade); - } + if (shadow_sample.z >= 0.0) { + uv_rect.xy += flip_offset; + } + shadow_sample.z = 1.0 + abs(shadow_sample.z); + vec3 pos = vec3(shadow_sample.xy / shadow_sample.z, shadow_len - spot_lights.data[light_index].shadow_bias); + pos.z *= spot_lights.data[light_index].inv_radius; + + pos.xy = pos.xy * 0.5 + 0.5; + pos.xy = uv_rect.xy + pos.xy * uv_rect.zw; + + float depth = texture(sampler2D(shadow_atlas, linear_sampler), pos.xy).r; + + shadow_attenuation = exp(min(0.0, (depth - pos.z)) / spot_lights.data[light_index].inv_radius * spot_lights.data[light_index].shadow_volumetric_fog_fade); + } total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot(normalize(light_rel_vec), normalize(view_pos)), params.phase_g); } } diff --git a/servers/rendering/renderer_rd/shaders/voxel_gi.glsl b/servers/rendering/renderer_rd/shaders/voxel_gi.glsl index 779f04ed35..73a97d9df1 100644 --- a/servers/rendering/renderer_rd/shaders/voxel_gi.glsl +++ b/servers/rendering/renderer_rd/shaders/voxel_gi.glsl @@ -13,7 +13,6 @@ layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; #ifndef MODE_DYNAMIC #define NO_CHILDREN 0xFFFFFFFF -#define GREY_VEC vec3(0.33333, 0.33333, 0.33333) struct CellChildren { uint children[8]; diff --git a/servers/rendering/renderer_rd/shaders/voxel_gi_debug.glsl b/servers/rendering/renderer_rd/shaders/voxel_gi_debug.glsl index 281c496df3..3f3437f527 100644 --- a/servers/rendering/renderer_rd/shaders/voxel_gi_debug.glsl +++ b/servers/rendering/renderer_rd/shaders/voxel_gi_debug.glsl @@ -90,66 +90,10 @@ void main() { #endif #ifdef MODE_DEBUG_LIGHT - -#ifdef USE_ANISOTROPY - -#define POS_X 0 -#define POS_Y 1 -#define POS_Z 2 -#define NEG_X 3 -#define NEG_Y 4 -#define NEG_Z 5 - - const uint triangle_aniso[12] = uint[]( - NEG_X, - NEG_Z, - NEG_Y, - NEG_Z, - NEG_X, - NEG_Y, - POS_Z, - POS_X, - POS_X, - POS_Y, - POS_Y, - POS_Z); - - color_interp.xyz = texelFetch(sampler3D(color_tex, tex_sampler), ivec3(posu), int(params.level)).xyz * params.dynamic_range; - vec3 aniso_pos = texelFetch(sampler3D(aniso_pos_tex, tex_sampler), ivec3(posu), int(params.level)).xyz; - vec3 aniso_neg = texelFetch(sampler3D(aniso_neg_tex, tex_sampler), ivec3(posu), int(params.level)).xyz; - uint side = triangle_aniso[gl_VertexIndex / 3]; - - float strength = 0.0; - switch (side) { - case POS_X: - strength = aniso_pos.x; - break; - case POS_Y: - strength = aniso_pos.y; - break; - case POS_Z: - strength = aniso_pos.z; - break; - case NEG_X: - strength = aniso_neg.x; - break; - case NEG_Y: - strength = aniso_neg.y; - break; - case NEG_Z: - strength = aniso_neg.z; - break; - } - - color_interp.xyz *= strength; - -#else color_interp = texelFetch(sampler3D(color_tex, tex_sampler), ivec3(posu), int(params.level)); color_interp.xyz *params.dynamic_range; - #endif -#endif float scale = (1 << params.level); gl_Position = params.projection * vec4((vec3(posu) + vertex) * scale, 1.0); diff --git a/servers/rendering/renderer_rd/shaders/voxel_gi_sdf.glsl b/servers/rendering/renderer_rd/shaders/voxel_gi_sdf.glsl index e20b3f680d..3bb4421646 100644 --- a/servers/rendering/renderer_rd/shaders/voxel_gi_sdf.glsl +++ b/servers/rendering/renderer_rd/shaders/voxel_gi_sdf.glsl @@ -6,10 +6,9 @@ layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in; -#define MAX_DISTANCE 100000 +#define MAX_DISTANCE 100000.0 #define NO_CHILDREN 0xFFFFFFFF -#define GREY_VEC vec3(0.33333, 0.33333, 0.33333) struct CellChildren { uint children[8]; @@ -44,7 +43,7 @@ params; void main() { vec3 pos = vec3(gl_GlobalInvocationID); - float closest_dist = 100000.0; + float closest_dist = MAX_DISTANCE; for (uint i = params.offset; i < params.end; i++) { vec3 posu = vec3(uvec3(cell_data.data[i].position & 0x7FF, (cell_data.data[i].position >> 11) & 0x3FF, cell_data.data[i].position >> 21)); diff --git a/servers/rendering/renderer_scene.cpp b/servers/rendering/renderer_scene.cpp index dd544d4f3f..b3fdd88626 100644 --- a/servers/rendering/renderer_scene.cpp +++ b/servers/rendering/renderer_scene.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_scene.h b/servers/rendering/renderer_scene.h index 02c845581c..f4aca8dce2 100644 --- a/servers/rendering/renderer_scene.h +++ b/servers/rendering/renderer_scene.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -143,9 +143,11 @@ public: virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) = 0; virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) = 0; - virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) = 0; + virtual void environment_set_ssil(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_sharpness, float p_normal_rejection) = 0; + virtual void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) = 0; + virtual void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) = 0; virtual void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) = 0; diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 5b834db178..1f72b23f8a 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index e51a1fc02e..6d5b714782 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -1108,6 +1108,9 @@ public: PASS10(environment_set_ssao, RID, bool, float, float, float, float, float, float, float, float) PASS6(environment_set_ssao_quality, RS::EnvironmentSSAOQuality, bool, float, int, float, float) + PASS6(environment_set_ssil, RID, bool, float, float, float, float) + PASS6(environment_set_ssil_quality, RS::EnvironmentSSILQuality, bool, float, int, float, float) + PASS11(environment_set_glow, RID, bool, Vector<float>, float, float, float, float, RS::EnvironmentGlowBlendMode, float, float, float) PASS1(environment_glow_set_use_bicubic_upscale, bool) PASS1(environment_glow_set_use_high_quality, bool) diff --git a/servers/rendering/renderer_scene_occlusion_cull.cpp b/servers/rendering/renderer_scene_occlusion_cull.cpp index 1b8aea36d7..bda0950097 100644 --- a/servers/rendering/renderer_scene_occlusion_cull.cpp +++ b/servers/rendering/renderer_scene_occlusion_cull.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_scene_occlusion_cull.h b/servers/rendering/renderer_scene_occlusion_cull.h index 4e4b1b94db..48412dab68 100644 --- a/servers/rendering/renderer_scene_occlusion_cull.h +++ b/servers/rendering/renderer_scene_occlusion_cull.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_scene_render.cpp b/servers/rendering/renderer_scene_render.cpp index 38d1218dee..c802f72fdf 100644 --- a/servers/rendering/renderer_scene_render.cpp +++ b/servers/rendering/renderer_scene_render.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h index 0d71ea22da..3c4582eab8 100644 --- a/servers/rendering/renderer_scene_render.h +++ b/servers/rendering/renderer_scene_render.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -134,9 +134,11 @@ public: virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) = 0; virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) = 0; - virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) = 0; + virtual void environment_set_ssil(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_sharpness, float p_normal_rejection) = 0; + virtual void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) = 0; + virtual void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) = 0; virtual void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) = 0; diff --git a/servers/rendering/renderer_storage.cpp b/servers/rendering/renderer_storage.cpp index aa005fac0a..56409ae187 100644 --- a/servers/rendering/renderer_storage.cpp +++ b/servers/rendering/renderer_storage.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_storage.h b/servers/rendering/renderer_storage.h index 8926bf24aa..056fecd020 100644 --- a/servers/rendering/renderer_storage.h +++ b/servers/rendering/renderer_storage.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_thread_pool.cpp b/servers/rendering/renderer_thread_pool.cpp index 98050dd508..ddf1d1bd00 100644 --- a/servers/rendering/renderer_thread_pool.cpp +++ b/servers/rendering/renderer_thread_pool.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_thread_pool.h b/servers/rendering/renderer_thread_pool.h index ae25415a0d..4626490d32 100644 --- a/servers/rendering/renderer_thread_pool.h +++ b/servers/rendering/renderer_thread_pool.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index eddf5bf53d..395e8d9583 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h index 5bb4dbbc6f..0db8b76dd9 100644 --- a/servers/rendering/renderer_viewport.h +++ b/servers/rendering/renderer_viewport.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index dcbc5f5c8e..cc2856f159 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -98,10 +98,10 @@ RID RenderingDevice::_texture_create_shared(const Ref<RDTextureView> &p_view, RI return texture_create_shared(p_view->base, p_with_texture); } -RID RenderingDevice::_texture_create_shared_from_slice(const Ref<RDTextureView> &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, TextureSliceType p_slice_type) { +RID RenderingDevice::_texture_create_shared_from_slice(const Ref<RDTextureView> &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, uint32_t p_mipmaps, TextureSliceType p_slice_type) { ERR_FAIL_COND_V(p_view.is_null(), RID()); - return texture_create_shared_from_slice(p_view->base, p_with_texture, p_layer, p_mipmap, p_slice_type); + return texture_create_shared_from_slice(p_view->base, p_with_texture, p_layer, p_mipmap, p_mipmaps, p_slice_type); } RenderingDevice::FramebufferFormatID RenderingDevice::_framebuffer_format_create(const TypedArray<RDAttachmentFormat> &p_attachments, uint32_t p_view_count) { @@ -185,9 +185,13 @@ Ref<RDShaderSPIRV> RenderingDevice::_shader_compile_spirv_from_source(const Ref< String error; ShaderStage stage = ShaderStage(i); - Vector<uint8_t> spirv = shader_compile_spirv_from_source(stage, p_source->get_stage_source(stage), p_source->get_language(), &error, p_allow_cache); - bytecode->set_stage_bytecode(stage, spirv); - bytecode->set_stage_compile_error(stage, error); + String source = p_source->get_stage_source(stage); + + if (!source.is_empty()) { + Vector<uint8_t> spirv = shader_compile_spirv_from_source(stage, source, p_source->get_language(), &error, p_allow_cache); + bytecode->set_stage_bytecode(stage, spirv); + bytecode->set_stage_compile_error(stage, error); + } } return bytecode; } @@ -201,7 +205,7 @@ Vector<uint8_t> RenderingDevice::_shader_compile_binary_from_spirv(const Ref<RDS ShaderStageSPIRVData sd; sd.shader_stage = stage; String error = p_spirv->get_stage_compile_error(stage); - ERR_FAIL_COND_V_MSG(error != String(), Vector<uint8_t>(), "Can't create a shader from an errored bytecode. Check errors in source bytecode."); + ERR_FAIL_COND_V_MSG(!error.is_empty(), Vector<uint8_t>(), "Can't create a shader from an errored bytecode. Check errors in source bytecode."); sd.spir_v = p_spirv->get_stage_bytecode(stage); if (sd.spir_v.is_empty()) { continue; @@ -221,7 +225,7 @@ RID RenderingDevice::_shader_create_from_spirv(const Ref<RDShaderSPIRV> &p_spirv ShaderStageSPIRVData sd; sd.shader_stage = stage; String error = p_spirv->get_stage_compile_error(stage); - ERR_FAIL_COND_V_MSG(error != String(), RID(), "Can't create a shader from an errored bytecode. Check errors in source bytecode."); + ERR_FAIL_COND_V_MSG(!error.is_empty(), RID(), "Can't create a shader from an errored bytecode. Check errors in source bytecode."); sd.spir_v = p_spirv->get_stage_bytecode(stage); if (sd.spir_v.is_empty()) { continue; @@ -360,7 +364,7 @@ void RenderingDevice::_compute_list_set_push_constant(ComputeListID p_list, cons void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("texture_create", "format", "view", "data"), &RenderingDevice::_texture_create, DEFVAL(Array())); ClassDB::bind_method(D_METHOD("texture_create_shared", "view", "with_texture"), &RenderingDevice::_texture_create_shared); - ClassDB::bind_method(D_METHOD("texture_create_shared_from_slice", "view", "with_texture", "layer", "mipmap", "slice_type"), &RenderingDevice::_texture_create_shared_from_slice, DEFVAL(TEXTURE_SLICE_2D)); + ClassDB::bind_method(D_METHOD("texture_create_shared_from_slice", "view", "with_texture", "layer", "mipmap", "mipmaps", "slice_type"), &RenderingDevice::_texture_create_shared_from_slice, DEFVAL(1), DEFVAL(TEXTURE_SLICE_2D)); ClassDB::bind_method(D_METHOD("texture_update", "texture", "layer", "data", "post_barrier"), &RenderingDevice::texture_update, DEFVAL(BARRIER_MASK_ALL)); ClassDB::bind_method(D_METHOD("texture_get_data", "texture", "layer"), &RenderingDevice::texture_get_data); diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index 563a80c12c..737c782776 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -505,7 +505,7 @@ public: TEXTURE_SLICE_2D_ARRAY, }; - virtual RID texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, TextureSliceType p_slice_type = TEXTURE_SLICE_2D) = 0; + virtual RID texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, uint32_t p_mipmaps = 1, TextureSliceType p_slice_type = TEXTURE_SLICE_2D) = 0; virtual Error texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; virtual Vector<uint8_t> texture_get_data(RID p_texture, uint32_t p_layer) = 0; // CPU textures will return immediately, while GPU textures will most likely force a flush @@ -1210,7 +1210,7 @@ protected: //binders to script API RID _texture_create(const Ref<RDTextureFormat> &p_format, const Ref<RDTextureView> &p_view, const TypedArray<PackedByteArray> &p_data = Array()); RID _texture_create_shared(const Ref<RDTextureView> &p_view, RID p_with_texture); - RID _texture_create_shared_from_slice(const Ref<RDTextureView> &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, TextureSliceType p_slice_type = TEXTURE_SLICE_2D); + RID _texture_create_shared_from_slice(const Ref<RDTextureView> &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, uint32_t p_mipmaps = 1, TextureSliceType p_slice_type = TEXTURE_SLICE_2D); FramebufferFormatID _framebuffer_format_create(const TypedArray<RDAttachmentFormat> &p_attachments, uint32_t p_view_count); FramebufferFormatID _framebuffer_format_create_multipass(const TypedArray<RDAttachmentFormat> &p_attachments, const TypedArray<RDFramebufferPass> &p_passes, uint32_t p_view_count); diff --git a/servers/rendering/rendering_device_binds.cpp b/servers/rendering/rendering_device_binds.cpp index a21f28989b..19cde610ba 100644 --- a/servers/rendering/rendering_device_binds.cpp +++ b/servers/rendering/rendering_device_binds.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -80,7 +80,7 @@ Error RDShaderFile::parse_versions_from_text(const String &p_text, const String } } - if (base_error != String()) { + if (!base_error.is_empty()) { break; } } @@ -89,7 +89,7 @@ Error RDShaderFile::parse_versions_from_text(const String &p_text, const String } } - if (stage == RD::SHADER_STAGE_MAX && line.strip_edges() != "") { + if (stage == RD::SHADER_STAGE_MAX && !line.strip_edges().is_empty()) { line = line.strip_edges(); if (line.begins_with("//") || line.begins_with("/*")) { continue; //assuming comment (single line) @@ -98,7 +98,7 @@ Error RDShaderFile::parse_versions_from_text(const String &p_text, const String if (reading_versions) { String l = line.strip_edges(); - if (l != "") { + if (!l.is_empty()) { if (l.find("=") == -1) { base_error = "Missing `=` in '" + l + "'. Version syntax is `version = \"<defines with C escaping>\";`."; break; @@ -124,7 +124,7 @@ Error RDShaderFile::parse_versions_from_text(const String &p_text, const String version_texts[version] = define + "\n" + p_defines; } } else { - if (stage == RD::SHADER_STAGE_MAX && line.strip_edges() != "") { + if (stage == RD::SHADER_STAGE_MAX && !line.strip_edges().is_empty()) { base_error = "Text was found that does not belong to a valid section: " + line; break; } @@ -140,7 +140,7 @@ Error RDShaderFile::parse_versions_from_text(const String &p_text, const String } include = include.substr(1, include.length() - 2).strip_edges(); String include_text = p_include_func(include, p_include_func_userdata); - if (include_text != String()) { + if (!include_text.is_empty()) { stage_code[stage] += "\n" + include_text + "\n"; } else { base_error = "#include failed for file '" + include + "'"; @@ -158,7 +158,7 @@ Error RDShaderFile::parse_versions_from_text(const String &p_text, const String Ref<RDShaderFile> shader_file; shader_file.instantiate(); - if (base_error == "") { + if (base_error.is_empty()) { if (stage_found[RD::SHADER_STAGE_COMPUTE] && stages_found > 1) { ERR_FAIL_V_MSG(ERR_PARSE_ERROR, "When writing compute shaders, [compute] mustbe the only stage present."); } @@ -177,14 +177,14 @@ Error RDShaderFile::parse_versions_from_text(const String &p_text, const String for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) { String code = stage_code[i]; - if (code == String()) { + if (code.is_empty()) { continue; } code = code.replace("VERSION_DEFINES", E.value); String error; Vector<uint8_t> spirv = RenderingDevice::get_singleton()->shader_compile_spirv_from_source(RD::ShaderStage(i), code, RD::SHADER_LANGUAGE_GLSL, &error, false); bytecode->set_stage_bytecode(RD::ShaderStage(i), spirv); - if (error != "") { + if (!error.is_empty()) { error += String() + "\n\nStage '" + stage_str[i] + "' source code: \n\n"; Vector<String> sclines = code.split("\n"); for (int j = 0; j < sclines.size(); j++) { diff --git a/servers/rendering/rendering_device_binds.h b/servers/rendering/rendering_device_binds.h index 2cf7821668..b07857364b 100644 --- a/servers/rendering/rendering_device_binds.h +++ b/servers/rendering/rendering_device_binds.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -368,13 +368,13 @@ public: } void print_errors(const String &p_file) { - if (base_error != "") { + if (!base_error.is_empty()) { ERR_PRINT("Error parsing shader '" + p_file + "':\n\n" + base_error); } else { for (KeyValue<StringName, Ref<RDShaderSPIRV>> &E : versions) { for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) { String error = E.value->get_stage_compile_error(RD::ShaderStage(i)); - if (error != String()) { + if (!error.is_empty()) { static const char *stage_str[RD::SHADER_STAGE_MAX] = { "vertex", "fragment", diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp index 2ce9a20b6b..e60e507f87 100644 --- a/servers/rendering/rendering_server_default.cpp +++ b/servers/rendering/rendering_server_default.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index b50631bb21..c4a6494da9 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -626,6 +626,9 @@ public: FUNC10(environment_set_ssao, RID, bool, float, float, float, float, float, float, float, float) FUNC6(environment_set_ssao_quality, EnvironmentSSAOQuality, bool, float, int, float, float) + FUNC6(environment_set_ssil, RID, bool, float, float, float, float) + FUNC6(environment_set_ssil_quality, EnvironmentSSILQuality, bool, float, int, float, float) + FUNC11(environment_set_glow, RID, bool, Vector<float>, float, float, float, float, EnvironmentGlowBlendMode, float, float, float) FUNC1(environment_glow_set_use_bicubic_upscale, bool) FUNC1(environment_glow_set_use_high_quality, bool) diff --git a/servers/rendering/rendering_server_globals.cpp b/servers/rendering/rendering_server_globals.cpp index 2dda506bac..b8b06b5eea 100644 --- a/servers/rendering/rendering_server_globals.cpp +++ b/servers/rendering/rendering_server_globals.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/rendering_server_globals.h b/servers/rendering/rendering_server_globals.h index 63755e6125..4351830a5f 100644 --- a/servers/rendering/rendering_server_globals.h +++ b/servers/rendering/rendering_server_globals.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 50719ecfc3..5d420ba48d 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -88,7 +88,8 @@ String ShaderLanguage::get_operator_text(Operator p_op) { "--", "()", "construct", - "index" }; + "index", + "empty" }; return op_names[p_op]; } @@ -203,7 +204,7 @@ const char *ShaderLanguage::token_names[TK_MAX] = { "HINT_WHITE_TEXTURE", "HINT_BLACK_TEXTURE", "HINT_NORMAL_TEXTURE", - "HINT_ANISO_TEXTURE", + "HINT_ANISOTROPY_TEXTURE", "HINT_ALBEDO_TEXTURE", "HINT_BLACK_ALBEDO_TEXTURE", "HINT_COLOR", @@ -213,8 +214,8 @@ const char *ShaderLanguage::token_names[TK_MAX] = { "FILTER_LINEAR", "FILTER_NEAREST_MIPMAP", "FILTER_LINEAR_MIPMAP", - "FILTER_NEAREST_MIPMAP_ANISO", - "FILTER_LINEAR_MIPMAP_ANISO", + "FILTER_NEAREST_MIPMAP_ANISOTROPIC", + "FILTER_LINEAR_MIPMAP_ANISOTROPIC", "REPEAT_ENABLE", "REPEAT_DISABLE", "SHADER_TYPE", @@ -225,7 +226,7 @@ const char *ShaderLanguage::token_names[TK_MAX] = { String ShaderLanguage::get_token_text(Token p_token) { String name = token_names[p_token.type]; - if (p_token.type == TK_INT_CONSTANT || p_token.type == TK_FLOAT_CONSTANT) { + if (p_token.is_integer_constant() || p_token.type == TK_FLOAT_CONSTANT) { name += "(" + rtos(p_token.constant) + ")"; } else if (p_token.type == TK_IDENTIFIER) { name += "(" + String(p_token.text) + ")"; @@ -317,7 +318,7 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = { { TK_HINT_ROUGHNESS_B, "hint_roughness_b" }, { TK_HINT_ROUGHNESS_A, "hint_roughness_a" }, { TK_HINT_ROUGHNESS_GRAY, "hint_roughness_gray" }, - { TK_HINT_ANISO_TEXTURE, "hint_aniso" }, + { TK_HINT_ANISOTROPY_TEXTURE, "hint_anisotropy" }, { TK_HINT_ALBEDO_TEXTURE, "hint_albedo" }, { TK_HINT_BLACK_ALBEDO_TEXTURE, "hint_black_albedo" }, { TK_HINT_COLOR, "hint_color" }, @@ -327,8 +328,8 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = { { TK_FILTER_LINEAR, "filter_linear" }, { TK_FILTER_NEAREST_MIPMAP, "filter_nearest_mipmap" }, { TK_FILTER_LINEAR_MIPMAP, "filter_linear_mipmap" }, - { TK_FILTER_NEAREST_MIPMAP_ANISO, "filter_nearest_mipmap_aniso" }, - { TK_FILTER_LINEAR_MIPMAP_ANISO, "filter_linear_mipmap_aniso" }, + { TK_FILTER_NEAREST_MIPMAP_ANISOTROPIC, "filter_nearest_mipmap_anisotropic" }, + { TK_FILTER_LINEAR_MIPMAP_ANISOTROPIC, "filter_linear_mipmap_anisotropic" }, { TK_REPEAT_ENABLE, "repeat_enable" }, { TK_REPEAT_DISABLE, "repeat_disable" }, { TK_SHADER_TYPE, "shader_type" }, @@ -474,6 +475,10 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { case ':': return _make_token(TK_COLON); case '^': + if (GETCHAR(0) == '=') { + char_idx++; + return _make_token(TK_OP_ASSIGN_BIT_XOR); + } return _make_token(TK_OP_BIT_XOR); case '~': return _make_token(TK_OP_BIT_INVERT); @@ -540,63 +545,113 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { if (_is_number(GETCHAR(0)) || (GETCHAR(0) == '.' && _is_number(GETCHAR(1)))) { // parse number + bool hexa_found = false; bool period_found = false; bool exponent_found = false; - bool hexa_found = false; - bool sign_found = false; bool float_suffix_found = false; + bool uint_suffix_found = false; + bool end_suffix_found = false; + + enum { + CASE_ALL, + CASE_HEXA_PERIOD, + CASE_EXPONENT, + CASE_SIGN_AFTER_EXPONENT, + CASE_NONE, + CASE_MAX, + } lut_case = CASE_ALL; + + static bool suffix_lut[CASE_MAX][127]; + + if (!is_const_suffix_lut_initialized) { + is_const_suffix_lut_initialized = true; + + for (int i = 0; i < 127; i++) { + char t = char(i); + + suffix_lut[CASE_ALL][i] = t == '.' || t == 'x' || t == 'e' || t == 'f' || t == 'u' || t == '-' || t == '+'; + suffix_lut[CASE_HEXA_PERIOD][i] = t == 'e' || t == 'f'; + suffix_lut[CASE_EXPONENT][i] = t == 'f' || t == '-' || t == '+'; + suffix_lut[CASE_SIGN_AFTER_EXPONENT][i] = t == 'f'; + suffix_lut[CASE_NONE][i] = false; + } + } String str; int i = 0; while (true) { - if (GETCHAR(i) == '.') { - if (period_found || exponent_found || hexa_found || float_suffix_found) { - return _make_token(TK_ERROR, "Invalid numeric constant"); - } - period_found = true; - } else if (GETCHAR(i) == 'x') { - if (hexa_found || str.length() != 1 || str[0] != '0') { - return _make_token(TK_ERROR, "Invalid numeric constant"); + const char32_t symbol = String::char_lowercase(GETCHAR(i)); + bool error = false; + + if (_is_number(symbol)) { + if (end_suffix_found) { + error = true; } - hexa_found = true; - } else if (GETCHAR(i) == 'e' && !hexa_found) { - if (exponent_found || float_suffix_found) { - return _make_token(TK_ERROR, "Invalid numeric constant"); + } else { + if (symbol < 0x7F && suffix_lut[lut_case][symbol]) { + if (symbol == 'x') { + hexa_found = true; + lut_case = CASE_HEXA_PERIOD; + } else if (symbol == '.') { + period_found = true; + lut_case = CASE_HEXA_PERIOD; + } else if (symbol == 'e' && !hexa_found) { + exponent_found = true; + lut_case = CASE_EXPONENT; + } else if (symbol == 'f' && !hexa_found) { + if (!period_found && !exponent_found) { + error = true; + } + float_suffix_found = true; + end_suffix_found = true; + lut_case = CASE_NONE; + } else if (symbol == 'u') { + uint_suffix_found = true; + end_suffix_found = true; + lut_case = CASE_NONE; + } else if (symbol == '-' || symbol == '+') { + if (exponent_found) { + lut_case = CASE_SIGN_AFTER_EXPONENT; + } else { + break; + } + } + } else if (!hexa_found || !_is_hex(symbol)) { + if (_is_text_char(symbol)) { + error = true; + } else { + break; + } } - exponent_found = true; - } else if (GETCHAR(i) == 'f' && !hexa_found) { - if (exponent_found) { - return _make_token(TK_ERROR, "Invalid numeric constant"); + } + + if (error) { + if (hexa_found) { + return _make_token(TK_ERROR, "Invalid (hexadecimal) numeric constant"); } - float_suffix_found = true; - } else if (_is_number(GETCHAR(i))) { - if (float_suffix_found) { - return _make_token(TK_ERROR, "Invalid numeric constant"); + if (period_found || exponent_found || float_suffix_found) { + return _make_token(TK_ERROR, "Invalid (float) numeric constant"); } - } else if (hexa_found && _is_hex(GETCHAR(i))) { - } else if ((GETCHAR(i) == '-' || GETCHAR(i) == '+') && exponent_found) { - if (sign_found) { - return _make_token(TK_ERROR, "Invalid numeric constant"); + if (uint_suffix_found) { + return _make_token(TK_ERROR, "Invalid (unsigned integer) numeric constant"); } - sign_found = true; - } else { - break; + return _make_token(TK_ERROR, "Invalid (integer) numeric constant"); } - - str += char32_t(GETCHAR(i)); + str += symbol; i++; } char32_t last_char = str[str.length() - 1]; - if (hexa_found) { - //integer(hex) + if (hexa_found) { // Integer(hex) if (str.size() > 11 || !str.is_valid_hex_number(true)) { // > 0xFFFFFFFF return _make_token(TK_ERROR, "Invalid (hexadecimal) numeric constant"); } - } else if (period_found || exponent_found || float_suffix_found) { - //floats + } else if (period_found || exponent_found || float_suffix_found) { // Float + if (exponent_found && (!_is_number(last_char) && last_char != 'f')) { // checks for eg: "2E", "2E-", "2E+" + return _make_token(TK_ERROR, "Invalid (float) numeric constant"); + } if (period_found) { if (float_suffix_found) { //checks for eg "1.f" or "1.99f" notations @@ -617,22 +672,28 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { } if (float_suffix_found) { - //strip the suffix + // Strip the suffix. str = str.left(str.length() - 1); - //compensate reading cursor position + // Compensate reading cursor position. char_idx += 1; } if (!str.is_valid_float()) { return _make_token(TK_ERROR, "Invalid (float) numeric constant"); } - } else { - //integers - if (!_is_number(last_char)) { - return _make_token(TK_ERROR, "Invalid (integer) numeric constant"); + } else { // Integer + if (uint_suffix_found) { + // Strip the suffix. + str = str.left(str.length() - 1); + // Compensate reading cursor position. + char_idx += 1; } if (!str.is_valid_int()) { - return _make_token(TK_ERROR, "Invalid numeric constant"); + if (uint_suffix_found) { + return _make_token(TK_ERROR, "Invalid (unsigned integer) numeric constant"); + } else { + return _make_token(TK_ERROR, "Invalid (integer) numeric constant"); + } } } @@ -640,6 +701,8 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { Token tk; if (period_found || exponent_found || float_suffix_found) { tk.type = TK_FLOAT_CONSTANT; + } else if (uint_suffix_found) { + tk.type = TK_UINT_CONSTANT; } else { tk.type = TK_INT_CONSTANT; } @@ -909,10 +972,10 @@ void ShaderLanguage::clear() { completion_type = COMPLETION_NONE; completion_block = nullptr; completion_function = StringName(); - completion_class = SubClassTag::TAG_GLOBAL; + completion_class = TAG_GLOBAL; completion_struct = StringName(); - - unknown_varying_usages.clear(); + completion_base = TYPE_VOID; + completion_base_array = false; #ifdef DEBUG_ENABLED used_constants.clear(); @@ -2654,6 +2717,8 @@ const ShaderLanguage::BuiltinFuncConstArgs ShaderLanguage::builtin_func_const_ar { nullptr, 0, 0, 0 } }; +bool ShaderLanguage::is_const_suffix_lut_initialized = false; + bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str) { ERR_FAIL_COND_V(p_func->op != OP_CALL && p_func->op != OP_CONSTRUCT, false); @@ -2994,7 +3059,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI } FunctionNode *pfunc = shader->functions[i].function; - if (arg_list == "") { + if (arg_list.is_empty()) { for (int j = 0; j < pfunc->arguments.size(); j++) { if (j > 0) { arg_list += ", "; @@ -3230,6 +3295,10 @@ bool ShaderLanguage::is_token_operator_assign(TokenType p_type) { p_type == TK_OP_ASSIGN_BIT_XOR); } +bool ShaderLanguage::is_token_hint(TokenType p_type) { + return int(p_type) > int(TK_RENDER_MODE) && int(p_type) < int(TK_SHADER_TYPE); +} + bool ShaderLanguage::convert_constant(ConstantNode *p_constant, DataType p_to_type, ConstantNode::Value *p_value) { if (p_constant->datatype == p_to_type) { if (p_value) { @@ -3797,55 +3866,77 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform return pi; } -uint32_t ShaderLanguage::get_type_size(DataType p_type) { +uint32_t ShaderLanguage::get_datatype_size(ShaderLanguage::DataType p_type) { switch (p_type) { case TYPE_VOID: return 0; case TYPE_BOOL: - case TYPE_INT: - case TYPE_UINT: - case TYPE_FLOAT: return 4; case TYPE_BVEC2: - case TYPE_IVEC2: - case TYPE_UVEC2: - case TYPE_VEC2: return 8; case TYPE_BVEC3: - case TYPE_IVEC3: - case TYPE_UVEC3: - case TYPE_VEC3: return 12; case TYPE_BVEC4: + return 16; + case TYPE_INT: + return 4; + case TYPE_IVEC2: + return 8; + case TYPE_IVEC3: + return 12; case TYPE_IVEC4: + return 16; + case TYPE_UINT: + return 4; + case TYPE_UVEC2: + return 8; + case TYPE_UVEC3: + return 12; case TYPE_UVEC4: + return 16; + case TYPE_FLOAT: + return 4; + case TYPE_VEC2: + return 8; + case TYPE_VEC3: + return 12; case TYPE_VEC4: return 16; case TYPE_MAT2: - return 8; + return 32; // 4 * 4 + 4 * 4 case TYPE_MAT3: - return 12; + return 48; // 4 * 4 + 4 * 4 + 4 * 4 case TYPE_MAT4: - return 16; + return 64; case TYPE_SAMPLER2D: + return 16; case TYPE_ISAMPLER2D: + return 16; case TYPE_USAMPLER2D: + return 16; case TYPE_SAMPLER2DARRAY: + return 16; case TYPE_ISAMPLER2DARRAY: + return 16; case TYPE_USAMPLER2DARRAY: + return 16; case TYPE_SAMPLER3D: + return 16; case TYPE_ISAMPLER3D: + return 16; case TYPE_USAMPLER3D: + return 16; case TYPE_SAMPLERCUBE: + return 16; case TYPE_SAMPLERCUBEARRAY: - return 4; //not really, but useful for indices + return 16; case TYPE_STRUCT: - // FIXME: Implement. - return 0; - case ShaderLanguage::TYPE_MAX: return 0; + case TYPE_MAX: { + ERR_FAIL_V(0); + }; } - return 0; + ERR_FAIL_V(0); } void ShaderLanguage::get_keyword_list(List<String> *r_keywords) { @@ -4051,43 +4142,6 @@ bool ShaderLanguage::_validate_varying_assign(ShaderNode::Varying &p_varying, St return true; } -bool ShaderLanguage::_validate_varying_using(ShaderNode::Varying &p_varying, String *r_message) { - switch (p_varying.stage) { - case ShaderNode::Varying::STAGE_UNKNOWN: - VaryingUsage usage; - usage.var = &p_varying; - usage.line = tk_line; - unknown_varying_usages.push_back(usage); - break; - case ShaderNode::Varying::STAGE_VERTEX: - if (current_function == varying_function_names.fragment || current_function == varying_function_names.light) { - p_varying.stage = ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT_LIGHT; - } - break; - case ShaderNode::Varying::STAGE_FRAGMENT: - if (current_function == varying_function_names.light) { - p_varying.stage = ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT; - } - break; - default: - break; - } - return true; -} - -bool ShaderLanguage::_check_varying_usages(int *r_error_line, String *r_error_message) const { - for (const List<ShaderLanguage::VaryingUsage>::Element *E = unknown_varying_usages.front(); E; E = E->next()) { - ShaderNode::Varying::Stage stage = E->get().var->stage; - if (stage != ShaderNode::Varying::STAGE_UNKNOWN && stage != ShaderNode::Varying::STAGE_VERTEX && stage != ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT_LIGHT) { - *r_error_line = E->get().line; - *r_error_message = RTR("Fragment-stage varying could not been accessed in custom function!"); - return false; - } - } - - return true; -} - bool ShaderLanguage::_check_node_constness(const Node *p_node) const { switch (p_node->type) { case Node::TYPE_OPERATOR: { @@ -4293,7 +4347,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_array_size(BlockNode *p_block, cons return n; } -Error ShaderLanguage::_parse_global_array_size(int &r_array_size) { +Error ShaderLanguage::_parse_global_array_size(int &r_array_size, const FunctionInfo &p_function_info) { if (r_array_size > 0) { _set_error("Array size is already defined!"); return ERR_PARSE_ERROR; @@ -4303,9 +4357,9 @@ Error ShaderLanguage::_parse_global_array_size(int &r_array_size) { int array_size = 0; - if (tk.type != TK_INT_CONSTANT || ((int)tk.constant) <= 0) { + if (!tk.is_integer_constant() || ((int)tk.constant) <= 0) { _set_tkpos(pos); - Node *n = _parse_array_size(nullptr, FunctionInfo(), array_size); + Node *n = _parse_array_size(nullptr, p_function_info, array_size); if (!n) { return ERR_PARSE_ERROR; } @@ -4328,27 +4382,28 @@ Error ShaderLanguage::_parse_global_array_size(int &r_array_size) { return OK; } -Error ShaderLanguage::_parse_local_array_size(BlockNode *p_block, const FunctionInfo &p_function_info, ArrayDeclarationNode *p_node, ArrayDeclarationNode::Declaration *p_decl, int &r_array_size, bool &r_is_unknown_size) { +Error ShaderLanguage::_parse_local_array_size(BlockNode *p_block, const FunctionInfo &p_function_info, Node *&r_size_expression, int &r_array_size, bool &r_is_unknown_size) { TkPos pos = _get_tkpos(); Token tk = _get_token(); if (tk.type == TK_BRACKET_CLOSE) { r_is_unknown_size = true; } else { - if (tk.type != TK_INT_CONSTANT || ((int)tk.constant) <= 0) { + int size = 0; + if (!tk.is_integer_constant() || ((int)tk.constant) <= 0) { _set_tkpos(pos); int array_size = 0; Node *n = _parse_array_size(p_block, p_function_info, array_size); if (!n) { return ERR_PARSE_ERROR; } - p_decl->size = array_size; - p_node->size_expression = n; + size = array_size; + r_size_expression = n; } else if (((int)tk.constant) > 0) { - p_decl->size = (uint32_t)tk.constant; + size = (uint32_t)tk.constant; } - if (p_decl->size <= 0) { + if (size <= 0) { _set_error("Expected single integer constant > 0"); return ERR_PARSE_ERROR; } @@ -4359,7 +4414,7 @@ Error ShaderLanguage::_parse_local_array_size(BlockNode *p_block, const Function return ERR_PARSE_ERROR; } - r_array_size = p_decl->size; + r_array_size = size; } return OK; @@ -4669,6 +4724,14 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons constant->datatype = TYPE_INT; expr = constant; + } else if (tk.type == TK_UINT_CONSTANT) { + ConstantNode *constant = alloc_node<ConstantNode>(); + ConstantNode::Value v; + v.uint = tk.constant; + constant->values.push_back(v); + constant->datatype = TYPE_UINT; + expr = constant; + } else if (tk.type == TK_TRUE) { //handle true constant ConstantNode *constant = alloc_node<ConstantNode>(); @@ -4770,11 +4833,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (shader->structs.has(identifier)) { pstruct = shader->structs[identifier].shader_struct; -#ifdef DEBUG_ENABLED - if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_STRUCT_FLAG) && used_structs.has(identifier)) { - used_structs[identifier].used = true; - } -#endif // DEBUG_ENABLED struct_init = true; } @@ -4916,55 +4974,104 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons for (int i = 0; i < call_function->arguments.size(); i++) { int argidx = i + 1; if (argidx < func->arguments.size()) { - if (call_function->arguments[i].is_const || call_function->arguments[i].qualifier == ArgumentQualifier::ARGUMENT_QUALIFIER_OUT || call_function->arguments[i].qualifier == ArgumentQualifier::ARGUMENT_QUALIFIER_INOUT) { - bool error = false; - Node *n = func->arguments[argidx]; - if (n->type == Node::TYPE_CONSTANT || n->type == Node::TYPE_OPERATOR) { - if (!call_function->arguments[i].is_const) { + bool error = false; + Node *n = func->arguments[argidx]; + ArgumentQualifier arg_qual = call_function->arguments[i].qualifier; + bool is_out_arg = arg_qual != ArgumentQualifier::ARGUMENT_QUALIFIER_IN; + + if (n->type == Node::TYPE_VARIABLE || n->type == Node::TYPE_ARRAY) { + StringName varname; + + if (n->type == Node::TYPE_VARIABLE) { + VariableNode *vn = static_cast<VariableNode *>(n); + varname = vn->name; + } else { // TYPE_ARRAY + ArrayNode *an = static_cast<ArrayNode *>(n); + varname = an->name; + } + + if (shader->varyings.has(varname)) { + switch (shader->varyings[varname].stage) { + case ShaderNode::Varying::STAGE_UNKNOWN: { + _set_error(vformat("Varying '%s' must be assigned in the vertex or fragment function first!", varname)); + return nullptr; + } + case ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT_LIGHT: + [[fallthrough]]; + case ShaderNode::Varying::STAGE_VERTEX: + if (is_out_arg && current_function != varying_function_names.vertex) { // inout/out + error = true; + } + break; + case ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT: + [[fallthrough]]; + case ShaderNode::Varying::STAGE_FRAGMENT: + if (!is_out_arg) { + if (current_function != varying_function_names.fragment && current_function != varying_function_names.light) { + error = true; + } + } else if (current_function != varying_function_names.fragment) { // inout/out + error = true; + } + break; + default: + break; + } + + if (error) { + _set_error(vformat("Varying '%s' cannot be passed for the '%s' parameter in that context!", varname, _get_qualifier_str(arg_qual))); + return nullptr; + } + } + } + + bool is_const_arg = call_function->arguments[i].is_const; + + if (is_const_arg || is_out_arg) { + StringName varname; + + if (n->type == Node::TYPE_CONSTANT || n->type == Node::TYPE_OPERATOR || n->type == Node::TYPE_ARRAY_CONSTRUCT) { + if (!is_const_arg) { error = true; } } else if (n->type == Node::TYPE_ARRAY) { ArrayNode *an = static_cast<ArrayNode *>(n); - if (an->call_expression != nullptr || an->is_const) { + if (!is_const_arg && (an->call_expression != nullptr || an->is_const)) { error = true; } + varname = an->name; } else if (n->type == Node::TYPE_VARIABLE) { VariableNode *vn = static_cast<VariableNode *>(n); - if (vn->is_const) { + if (vn->is_const && !is_const_arg) { error = true; - } else { - StringName varname = vn->name; - if (shader->constants.has(varname)) { - error = true; - } else if (shader->uniforms.has(varname)) { - error = true; - } else { - if (shader->varyings.has(varname)) { - _set_error(vformat("Varyings cannot be passed for '%s' parameter!", _get_qualifier_str(call_function->arguments[i].qualifier))); - return nullptr; - } - if (p_function_info.built_ins.has(varname)) { - BuiltInInfo info = p_function_info.built_ins[varname]; - if (info.constant) { - error = true; - } - } - } } + varname = vn->name; } else if (n->type == Node::TYPE_MEMBER) { MemberNode *mn = static_cast<MemberNode *>(n); - if (mn->basetype_const) { + if (mn->basetype_const && is_out_arg) { + error = true; + } + } + if (!error && varname != StringName()) { + if (shader->constants.has(varname)) { + error = true; + } else if (shader->uniforms.has(varname)) { error = true; + } else if (p_function_info.built_ins.has(varname)) { + BuiltInInfo info = p_function_info.built_ins[varname]; + if (info.constant) { + error = true; + } } } + if (error) { - _set_error(vformat("Constant value cannot be passed for '%s' parameter!", _get_qualifier_str(call_function->arguments[i].qualifier))); + _set_error(vformat("Constant value cannot be passed for '%s' parameter!", _get_qualifier_str(arg_qual))); return nullptr; } } if (is_sampler_type(call_function->arguments[i].type)) { //let's see where our argument comes from - Node *n = func->arguments[argidx]; ERR_CONTINUE(n->type != Node::TYPE_VARIABLE); //bug? this should always be a variable VariableNode *vn = static_cast<VariableNode *>(n); StringName varname = vn->name; @@ -5068,9 +5175,21 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons return nullptr; } } else { - if (!_validate_varying_using(shader->varyings[identifier], &error)) { - _set_error(error); - return nullptr; + ShaderNode::Varying &var = shader->varyings[identifier]; + + switch (var.stage) { + case ShaderNode::Varying::STAGE_VERTEX: + if (current_function == varying_function_names.fragment || current_function == varying_function_names.light) { + var.stage = ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT_LIGHT; + } + break; + case ShaderNode::Varying::STAGE_FRAGMENT: + if (current_function == varying_function_names.light) { + var.stage = ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT; + } + break; + default: + break; } } } @@ -5208,9 +5327,21 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons expression.push_back(e); continue; } else { - _set_error("Expected expression, found: " + get_token_text(tk)); - return nullptr; - //nothing + if (tk.type != TK_SEMICOLON) { + _set_error("Expected expression, found: " + get_token_text(tk)); + return nullptr; + } else { +#ifdef DEBUG_ENABLED + if (check_warnings && HAS_WARNING(ShaderWarning::FORMATTING_ERROR_FLAG)) { + _add_line_warning(ShaderWarning::FORMATTING_ERROR, "Empty statement. Remove ';' to fix this warning."); + } +#endif // DEBUG_ENABLED + _set_tkpos(prepos); + + OperatorNode *func = alloc_node<OperatorNode>(); + func->op = OP_EMPTY; + expr = func; + } } ERR_FAIL_COND_V(!expr, nullptr); @@ -5223,7 +5354,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (tk.type == TK_CURSOR) { //do nothing - } else if (tk.type == TK_IDENTIFIER) { } else if (tk.type == TK_PERIOD) { DataType dt = expr->get_datatype(); String st = expr->get_datatype_name(); @@ -6012,7 +6142,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons ERR_FAIL_V(nullptr); //unexpected operator } -#if DEBUG_ENABLED +#ifdef DEBUG_ENABLED if (check_warnings && HAS_WARNING(ShaderWarning::FLOAT_COMPARISON_FLAG) && (op == OP_EQUAL || op == OP_NOT_EQUAL) && (!expression[i - 1].is_op && !expression[i + 1].is_op) && (expression[i - 1].node->get_datatype() == TYPE_FLOAT && expression[i + 1].node->get_datatype() == TYPE_FLOAT)) { @@ -6329,6 +6459,11 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun String struct_name = ""; if (is_struct) { struct_name = tk.text; +#ifdef DEBUG_ENABLED + if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_STRUCT_FLAG) && used_structs.has(struct_name)) { + used_structs[struct_name].used = true; + } +#endif // DEBUG_ENABLED } bool is_const = false; @@ -6374,49 +6509,44 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun return ERR_PARSE_ERROR; } - tk = _get_token(); - Node *vardecl = nullptr; + int array_size = 0; + bool fixed_array_size = false; + bool first = true; - while (true) { + do { bool unknown_size = false; - int array_size = 0; + Node *size_expr = nullptr; ArrayDeclarationNode *anode = nullptr; ArrayDeclarationNode::Declaration adecl; - if (tk.type != TK_IDENTIFIER && tk.type != TK_BRACKET_OPEN) { - _set_error("Expected identifier or '[' after type."); - return ERR_PARSE_ERROR; - } + tk = _get_token(); - if (tk.type == TK_BRACKET_OPEN) { - anode = alloc_node<ArrayDeclarationNode>(); + if (first) { + first = false; - if (is_struct) { - anode->struct_name = struct_name; - anode->datatype = TYPE_STRUCT; - } else { - anode->datatype = type; + if (tk.type != TK_IDENTIFIER && tk.type != TK_BRACKET_OPEN) { + _set_error("Expected identifier or '[' after datatype."); + return ERR_PARSE_ERROR; } - anode->precision = precision; - anode->is_const = is_const; - vardecl = (Node *)anode; - - adecl.size = 0U; - adecl.single_expression = false; + if (tk.type == TK_BRACKET_OPEN) { + Error error = _parse_local_array_size(p_block, p_function_info, size_expr, array_size, unknown_size); + if (error != OK) { + return error; + } + adecl.single_expression = false; + adecl.size = array_size; - Error error = _parse_local_array_size(p_block, p_function_info, anode, &adecl, array_size, unknown_size); - if (error != OK) { - return error; + fixed_array_size = true; + tk = _get_token(); } - tk = _get_token(); + } - if (tk.type != TK_IDENTIFIER) { - _set_error("Expected identifier!"); - return ERR_PARSE_ERROR; - } + if (tk.type != TK_IDENTIFIER) { + _set_error("Expected identifier!"); + return ERR_PARSE_ERROR; } StringName name = tk.text; @@ -6454,8 +6584,10 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun tk = _get_token(); + bool is_array_decl = var.array_size > 0 || unknown_size; + if (tk.type == TK_BRACKET_OPEN) { - if (var.array_size > 0 || unknown_size) { + if (is_array_decl) { _set_error("Array size is already defined!"); return ERR_PARSE_ERROR; } @@ -6465,28 +6597,37 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun return ERR_PARSE_ERROR; } - anode = alloc_node<ArrayDeclarationNode>(); - if (is_struct) { - anode->struct_name = struct_name; - anode->datatype = TYPE_STRUCT; - } else { - anode->datatype = type; + Error error = _parse_local_array_size(p_block, p_function_info, size_expr, var.array_size, unknown_size); + if (error != OK) { + return error; } - anode->precision = precision; - anode->is_const = is_const; - vardecl = (Node *)anode; - adecl.size = 0U; adecl.single_expression = false; + adecl.size = var.array_size; + array_size = var.array_size; - Error error = _parse_local_array_size(p_block, p_function_info, anode, &adecl, var.array_size, unknown_size); - if (error != OK) { - return error; - } + is_array_decl = true; tk = _get_token(); } - if (var.array_size > 0 || unknown_size) { + if (is_array_decl) { + { + anode = alloc_node<ArrayDeclarationNode>(); + + if (is_struct) { + anode->struct_name = struct_name; + anode->datatype = TYPE_STRUCT; + } else { + anode->datatype = type; + } + + anode->precision = precision; + anode->is_const = is_const; + anode->size_expression = size_expr; + + vardecl = (Node *)anode; + } + bool full_def = false; if (tk.type == TK_OP_ASSIGN) { @@ -6704,6 +6845,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun } } + array_size = var.array_size; anode->declarations.push_back(adecl); } else if (tk.type == TK_OP_ASSIGN) { VariableDeclarationNode *node = alloc_node<VariableDeclarationNode>(); @@ -6772,22 +6914,24 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun } p_block->statements.push_back(vardecl); - p_block->variables[name] = var; + + if (!fixed_array_size) { + array_size = 0; + } + if (tk.type == TK_COMMA) { if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR) { _set_error("Multiple declarations in 'for' loop are not implemented yet."); return ERR_PARSE_ERROR; } - tk = _get_token(); - //another variable } else if (tk.type == TK_SEMICOLON) { break; } else { _set_error("Expected ',' or ';' after variable"); return ERR_PARSE_ERROR; } - } + } while (tk.type == TK_COMMA); //another variable } else if (tk.type == TK_CURLY_BRACKET_OPEN) { //a sub block, just because.. BlockNode *block = alloc_node<BlockNode>(); @@ -6840,7 +6984,9 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun block->parent_block = p_block; cf->blocks.push_back(block); err = _parse_block(block, p_function_info, true, p_can_break, p_can_continue); - + if (err) { + return err; + } } else { _set_tkpos(pos); //rollback } @@ -6970,7 +7116,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun Node *n = nullptr; - if (tk.type != TK_INT_CONSTANT) { + if (!tk.is_integer_constant()) { bool correct_constant_expression = false; DataType data_type; @@ -6993,11 +7139,15 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun n = vn; } else { ConstantNode::Value v; - v.sint = (int)tk.constant * sign; + if (tk.type == TK_UINT_CONSTANT) { + v.uint = (uint32_t)tk.constant; + } else { + v.sint = (int)tk.constant * sign; + } ConstantNode *cn = alloc_node<ConstantNode>(); cn->values.push_back(v); - cn->datatype = TYPE_INT; + cn->datatype = (tk.type == TK_UINT_CONSTANT ? TYPE_UINT : TYPE_INT); n = cn; } @@ -7219,7 +7369,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun if (tk.type == TK_SEMICOLON) { //all is good if (b->parent_function->return_type != TYPE_VOID) { - _set_error("Expected return with an expression of type '" + (return_struct_name != "" ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + array_size_string + "'"); + _set_error("Expected return with an expression of type '" + (!return_struct_name.is_empty() ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + array_size_string + "'"); return ERR_PARSE_ERROR; } } else { @@ -7231,7 +7381,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun } if (b->parent_function->return_type != expr->get_datatype() || b->parent_function->return_array_size != expr->get_array_size() || return_struct_name != expr->get_datatype_name()) { - _set_error("Expected return with an expression of type '" + (return_struct_name != "" ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + array_size_string + "'"); + _set_error("Expected return with an expression of type '" + (!return_struct_name.is_empty() ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + array_size_string + "'"); return ERR_PARSE_ERROR; } @@ -7353,7 +7503,7 @@ String ShaderLanguage::_get_shader_type_list(const Set<String> &p_shader_types) // Return a list of shader types as an human-readable string String valid_types; for (const Set<String>::Element *E = p_shader_types.front(); E; E = E->next()) { - if (valid_types != String()) { + if (!valid_types.is_empty()) { valid_types += ", "; } @@ -7404,7 +7554,7 @@ Error ShaderLanguage::_validate_datatype(DataType p_type) { return OK; } -Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const Set<String> &p_shader_types) { +Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_functions, const Vector<ModeInfo> &p_render_modes, const Set<String> &p_shader_types) { Token tk = _get_token(); TkPos prev_pos; @@ -7443,9 +7593,19 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct int texture_binding = 0; int uniforms = 0; int instance_index = 0; +#ifdef DEBUG_ENABLED + int uniform_buffer_size = 0; + int max_uniform_buffer_size = 0; + if (RenderingDevice::get_singleton()) { + max_uniform_buffer_size = RenderingDevice::get_singleton()->limit_get(RenderingDevice::LIMIT_MAX_UNIFORM_BUFFER_SIZE); + } +#endif // DEBUG_ENABLED ShaderNode::Uniform::Scope uniform_scope = ShaderNode::Uniform::SCOPE_LOCAL; stages = &p_functions; + const FunctionInfo &constants = p_functions.has("constants") ? p_functions["constants"] : FunctionInfo(); + + Map<String, String> defined_modes; while (tk.type != TK_EOF) { switch (tk.type) { @@ -7459,13 +7619,40 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct return ERR_PARSE_ERROR; } - if (p_render_modes.find(mode) == -1) { - _set_error("Invalid render mode: '" + String(mode) + "'"); + const String smode = String(mode); + + if (shader->render_modes.find(mode) != -1) { + _set_error(vformat("Duplicated render mode: '%s'.", smode)); return ERR_PARSE_ERROR; } - if (shader->render_modes.find(mode) != -1) { - _set_error("Duplicate render mode: '" + String(mode) + "'"); + bool found = false; + + for (int i = 0; i < p_render_modes.size(); i++) { + const ModeInfo &info = p_render_modes[i]; + const String name = String(info.name); + + if (smode.begins_with(name)) { + if (!info.options.is_empty()) { + if (info.options.find(smode.substr(name.length() + 1)) != -1) { + found = true; + + if (defined_modes.has(name)) { + _set_error(vformat("Redefinition of render mode: '%s'. The %s mode has already been set to '%s'.", smode, name, defined_modes[name])); + return ERR_PARSE_ERROR; + } + defined_modes.insert(name, smode); + break; + } + } else { + found = true; + break; + } + } + } + + if (!found) { + _set_error(vformat("Invalid render mode: '%s'.", smode)); return ERR_PARSE_ERROR; } @@ -7489,7 +7676,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); if (tk.type == TK_IDENTIFIER) { st.name = tk.text; - if (shader->structs.has(st.name)) { + if (shader->constants.has(st.name) || shader->structs.has(st.name)) { _set_error("Redefinition of '" + String(st.name) + "'"); return ERR_PARSE_ERROR; } @@ -7531,6 +7718,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (shader->structs.has(tk.text)) { struct_name = tk.text; +#ifdef DEBUG_ENABLED + if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_STRUCT_FLAG) && used_structs.has(struct_name)) { + used_structs[struct_name].used = true; + } +#endif // DEBUG_ENABLED struct_dt = true; if (use_precision) { _set_error("Precision modifier cannot be used on structs."); @@ -7551,57 +7743,71 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct _set_error("void datatype not allowed here"); return ERR_PARSE_ERROR; } - tk = _get_token(); - - if (tk.type != TK_IDENTIFIER && tk.type != TK_BRACKET_OPEN) { - _set_error("Expected identifier or '['."); - return ERR_PARSE_ERROR; - } + bool first = true; + bool fixed_array_size = false; int array_size = 0; - if (tk.type == TK_BRACKET_OPEN) { - Error error = _parse_global_array_size(array_size); - if (error != OK) { - return error; - } + do { tk = _get_token(); - } - if (tk.type != TK_IDENTIFIER) { - _set_error("Expected identifier!"); - return ERR_PARSE_ERROR; - } + if (first) { + first = false; - MemberNode *member = alloc_node<MemberNode>(); - member->precision = precision; - member->datatype = type; - member->struct_name = struct_name; - member->name = tk.text; - member->array_size = array_size; + if (tk.type != TK_IDENTIFIER && tk.type != TK_BRACKET_OPEN) { + _set_error("Expected identifier or '['."); + return ERR_PARSE_ERROR; + } - if (member_names.has(member->name)) { - _set_error("Redefinition of '" + String(member->name) + "'"); - return ERR_PARSE_ERROR; - } - member_names.insert(member->name); - tk = _get_token(); + if (tk.type == TK_BRACKET_OPEN) { + Error error = _parse_global_array_size(array_size, constants); + if (error != OK) { + return error; + } + fixed_array_size = true; + tk = _get_token(); + } + } - if (tk.type == TK_BRACKET_OPEN) { - Error error = _parse_global_array_size(member->array_size); - if (error != OK) { - return error; + if (tk.type != TK_IDENTIFIER) { + _set_error("Expected identifier!"); + return ERR_PARSE_ERROR; } + + MemberNode *member = alloc_node<MemberNode>(); + member->precision = precision; + member->datatype = type; + member->struct_name = struct_name; + member->name = tk.text; + member->array_size = array_size; + + if (member_names.has(member->name)) { + _set_error("Redefinition of '" + String(member->name) + "'"); + return ERR_PARSE_ERROR; + } + member_names.insert(member->name); tk = _get_token(); - } - if (tk.type != TK_SEMICOLON) { - _set_error("Expected ';'"); - return ERR_PARSE_ERROR; - } + if (tk.type == TK_BRACKET_OPEN) { + Error error = _parse_global_array_size(member->array_size, constants); + if (error != OK) { + return error; + } + tk = _get_token(); + } + + if (!fixed_array_size) { + array_size = 0; + } - st_node->members.push_back(member); - member_count++; + if (tk.type != TK_SEMICOLON && tk.type != TK_COMMA) { + _set_error("Expected ',' or ';' after struct member."); + return ERR_PARSE_ERROR; + } + + st_node->members.push_back(member); + member_count++; + } while (tk.type == TK_COMMA); // another member } } if (member_count == 0) { @@ -7715,7 +7921,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } if (tk.type == TK_BRACKET_OPEN) { - Error error = _parse_global_array_size(array_size); + Error error = _parse_global_array_size(array_size, constants); if (error != OK) { return error; } @@ -7730,7 +7936,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct prev_pos = _get_tkpos(); name = tk.text; - if (_find_identifier(nullptr, false, FunctionInfo(), name)) { + if (_find_identifier(nullptr, false, constants, name)) { _set_error("Redefinition of '" + String(name) + "'"); return ERR_PARSE_ERROR; } @@ -7763,7 +7969,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); if (tk.type == TK_BRACKET_OPEN) { - Error error = _parse_global_array_size(uniform2.array_size); + Error error = _parse_global_array_size(uniform2.array_size, constants); if (error != OK) { return error; } @@ -7794,6 +8000,18 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct uniform2.texture_order = -1; if (uniform_scope != ShaderNode::Uniform::SCOPE_INSTANCE) { uniform2.order = uniforms++; +#ifdef DEBUG_ENABLED + if (uniform2.array_size > 0) { + int size = get_datatype_size(uniform2.type) * uniform2.array_size; + int m = (16 * uniform2.array_size); + if ((size % m) != 0U) { + size += m - (size % m); + } + uniform_buffer_size += size; + } else { + uniform_buffer_size += get_datatype_size(uniform2.type); + } +#endif // DEBUG_ENABLED } } @@ -7811,9 +8029,19 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct int custom_instance_index = -1; if (tk.type == TK_COLON) { + completion_type = COMPLETION_HINT; + completion_base = type; + completion_base_array = uniform2.array_size > 0; + //hint do { tk = _get_token(); + completion_line = tk.line; + + if (!is_token_hint(tk.type)) { + _set_error("Expected valid type hint after ':'."); + return ERR_PARSE_ERROR; + } if (uniform2.array_size > 0) { if (tk.type != TK_HINT_COLOR) { @@ -7840,8 +8068,8 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct uniform2.hint = ShaderNode::Uniform::HINT_ROUGHNESS_A; } else if (tk.type == TK_HINT_ROUGHNESS_GRAY) { uniform2.hint = ShaderNode::Uniform::HINT_ROUGHNESS_GRAY; - } else if (tk.type == TK_HINT_ANISO_TEXTURE) { - uniform2.hint = ShaderNode::Uniform::HINT_ANISO; + } else if (tk.type == TK_HINT_ANISOTROPY_TEXTURE) { + uniform2.hint = ShaderNode::Uniform::HINT_ANISOTROPY; } else if (tk.type == TK_HINT_ALBEDO_TEXTURE) { uniform2.hint = ShaderNode::Uniform::HINT_ALBEDO; } else if (tk.type == TK_HINT_BLACK_ALBEDO_TEXTURE) { @@ -7874,7 +8102,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); } - if (tk.type != TK_FLOAT_CONSTANT && tk.type != TK_INT_CONSTANT) { + if (tk.type != TK_FLOAT_CONSTANT && !tk.is_integer_constant()) { _set_error("Expected integer constant"); return ERR_PARSE_ERROR; } @@ -7898,7 +8126,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); } - if (tk.type != TK_FLOAT_CONSTANT && tk.type != TK_INT_CONSTANT) { + if (tk.type != TK_FLOAT_CONSTANT && !tk.is_integer_constant()) { _set_error("Expected integer constant after ','"); return ERR_PARSE_ERROR; } @@ -7911,7 +8139,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (tk.type == TK_COMMA) { tk = _get_token(); - if (tk.type != TK_FLOAT_CONSTANT && tk.type != TK_INT_CONSTANT) { + if (tk.type != TK_FLOAT_CONSTANT && !tk.is_integer_constant()) { _set_error("Expected integer constant after ','"); return ERR_PARSE_ERROR; } @@ -7949,7 +8177,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct return ERR_PARSE_ERROR; } - if (tk.type != TK_INT_CONSTANT) { + if (!tk.is_integer_constant()) { _set_error("Expected integer constant"); return ERR_PARSE_ERROR; } @@ -7975,16 +8203,14 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct uniform2.filter = FILTER_NEAREST_MIPMAP; } else if (tk.type == TK_FILTER_LINEAR_MIPMAP) { uniform2.filter = FILTER_LINEAR_MIPMAP; - } else if (tk.type == TK_FILTER_NEAREST_MIPMAP_ANISO) { - uniform2.filter = FILTER_NEAREST_MIPMAP_ANISO; - } else if (tk.type == TK_FILTER_LINEAR_MIPMAP_ANISO) { - uniform2.filter = FILTER_LINEAR_MIPMAP_ANISO; + } else if (tk.type == TK_FILTER_NEAREST_MIPMAP_ANISOTROPIC) { + uniform2.filter = FILTER_NEAREST_MIPMAP_ANISOTROPIC; + } else if (tk.type == TK_FILTER_LINEAR_MIPMAP_ANISOTROPIC) { + uniform2.filter = FILTER_LINEAR_MIPMAP_ANISOTROPIC; } else if (tk.type == TK_REPEAT_DISABLE) { uniform2.repeat = REPEAT_DISABLE; } else if (tk.type == TK_REPEAT_ENABLE) { uniform2.repeat = REPEAT_ENABLE; - } else { - _set_error("Expected valid type hint after ':'."); } if (uniform2.hint != ShaderNode::Uniform::HINT_RANGE && uniform2.hint != ShaderNode::Uniform::HINT_NONE && uniform2.hint != ShaderNode::Uniform::HINT_COLOR && type <= TYPE_MAT4) { @@ -8017,7 +8243,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct return ERR_PARSE_ERROR; } - Node *expr = _parse_and_reduce_expression(nullptr, FunctionInfo()); + Node *expr = _parse_and_reduce_expression(nullptr, constants); if (!expr) { return ERR_PARSE_ERROR; } @@ -8051,6 +8277,8 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct _set_error("Expected ';'"); return ERR_PARSE_ERROR; } + + completion_type = COMPLETION_NONE; } else { // varying ShaderNode::Varying varying; varying.type = type; @@ -8075,7 +8303,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct return ERR_PARSE_ERROR; } tk = _get_token(); - if (tk.type == TK_INT_CONSTANT && tk.constant > 0) { + if (tk.is_integer_constant() && tk.constant > 0) { varying.array_size = (int)tk.constant; tk = _get_token(); @@ -8113,7 +8341,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct DataPrecision precision = PRECISION_DEFAULT; DataType type; StringName name; - int return_array_size = 0; + int array_size = 0; if (tk.type == TK_CONST) { is_constant = true; @@ -8152,13 +8380,19 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct prev_pos = _get_tkpos(); tk = _get_token(); + bool unknown_size = false; + if (tk.type == TK_BRACKET_OPEN) { + if (is_constant && RenderingServer::get_singleton()->is_low_end()) { + _set_error("Global const arrays are only supported on high-end platform!"); + return ERR_PARSE_ERROR; + } bool error = false; tk = _get_token(); - if (tk.type == TK_INT_CONSTANT) { - return_array_size = (int)tk.constant; - if (return_array_size > 0) { + if (tk.is_integer_constant()) { + array_size = (int)tk.constant; + if (array_size > 0) { tk = _get_token(); if (tk.type != TK_BRACKET_CLOSE) { _set_error("Expected ']'"); @@ -8167,11 +8401,13 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } else { error = true; } + } else if (tk.type == TK_BRACKET_CLOSE) { + unknown_size = true; } else { error = true; } if (error) { - _set_error("Expected integer constant > 0"); + _set_error("Expected integer constant > 0 or ']'"); return ERR_PARSE_ERROR; } @@ -8183,16 +8419,15 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct _get_completable_identifier(nullptr, COMPLETION_MAIN_FUNCTION, name); if (name == StringName()) { - _set_error("Expected function name after datatype"); - return ERR_PARSE_ERROR; - } - - if (_find_identifier(nullptr, false, FunctionInfo(), name)) { - _set_error("Redefinition of '" + String(name) + "'"); + if (is_constant) { + _set_error("Expected identifier or '[' after datatype."); + } else { + _set_error("Expected function name after datatype."); + } return ERR_PARSE_ERROR; } - if (has_builtin(p_functions, name)) { + if (shader->structs.has(name) || _find_identifier(nullptr, false, constants, name) || has_builtin(p_functions, name)) { _set_error("Redefinition of '" + String(name) + "'"); return ERR_PARSE_ERROR; } @@ -8205,7 +8440,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } //variable - + bool first = true; while (true) { ShaderNode::Constant constant; constant.name = name; @@ -8213,21 +8448,23 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct constant.type_str = struct_name; constant.precision = precision; constant.initializer = nullptr; - constant.array_size = 0; - - bool unknown_size = false; + constant.array_size = (first ? array_size : 0); + first = false; if (tk.type == TK_BRACKET_OPEN) { if (RenderingServer::get_singleton()->is_low_end()) { - _set_error("Global const arrays are supported only on high-end platform!"); + _set_error("Global const arrays are only supported on high-end platform!"); + return ERR_PARSE_ERROR; + } + if (constant.array_size > 0 || unknown_size) { + _set_error("Array size is already defined!"); return ERR_PARSE_ERROR; } - tk = _get_token(); if (tk.type == TK_BRACKET_CLOSE) { unknown_size = true; tk = _get_token(); - } else if (tk.type == TK_INT_CONSTANT && ((int)tk.constant) > 0) { + } else if (tk.is_integer_constant() && ((int)tk.constant) > 0) { constant.array_size = (int)tk.constant; tk = _get_token(); if (tk.type != TK_BRACKET_CLOSE) { @@ -8300,7 +8537,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } else { _set_tkpos(prev_pos); - Node *n = _parse_and_reduce_expression(nullptr, FunctionInfo()); + Node *n = _parse_and_reduce_expression(nullptr, constants); if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) { _set_error("Expected single integer constant > 0"); return ERR_PARSE_ERROR; @@ -8381,7 +8618,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (tk.type == TK_PARENTHESIS_OPEN || curly) { // initialization while (true) { - Node *n = _parse_and_reduce_expression(nullptr, FunctionInfo()); + Node *n = _parse_and_reduce_expression(nullptr, constants); if (!n) { return ERR_PARSE_ERROR; } @@ -8436,7 +8673,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct constant.initializer = static_cast<ConstantNode *>(expr); } else { //variable created with assignment! must parse an expression - Node *expr = _parse_and_reduce_expression(nullptr, FunctionInfo()); + Node *expr = _parse_and_reduce_expression(nullptr, constants); if (!expr) { return ERR_PARSE_ERROR; } @@ -8452,7 +8689,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct constant.initializer = static_cast<ConstantNode *>(expr); - if (!_compare_datatypes(type, struct_name, 0, expr->get_datatype(), expr->get_datatype_name(), 0)) { + if (!_compare_datatypes(type, struct_name, 0, expr->get_datatype(), expr->get_datatype_name(), expr->get_array_size())) { return ERR_PARSE_ERROR; } } @@ -8483,7 +8720,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } name = tk.text; - if (_find_identifier(nullptr, false, FunctionInfo(), name)) { + if (_find_identifier(nullptr, false, constants, name)) { _set_error("Redefinition of '" + String(name) + "'"); return ERR_PARSE_ERROR; } @@ -8517,6 +8754,12 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } } + if (p_functions.has("constants")) { // Adds global constants: 'PI', 'TAU', 'E' + for (const KeyValue<StringName, BuiltInInfo> &E : p_functions["constants"].built_ins) { + builtins.built_ins.insert(E.key, E.value); + } + } + ShaderNode::Function function; function.callable = !p_functions.has(name); @@ -8532,7 +8775,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct func_node->return_type = type; func_node->return_struct_name = struct_name; func_node->return_precision = precision; - func_node->return_array_size = return_array_size; + func_node->return_array_size = array_size; if (p_functions.has(name)) { func_node->can_discard = p_functions[name].can_discard; @@ -8586,7 +8829,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct StringName param_struct_name; DataPrecision pprecision = PRECISION_DEFAULT; bool use_precision = false; - int array_size = 0; + int arg_array_size = 0; if (is_token_precision(tk.type)) { pprecision = get_token_precision(tk.type); @@ -8599,6 +8842,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (shader->structs.has(tk.text)) { is_struct = true; param_struct_name = tk.text; +#ifdef DEBUG_ENABLED + if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_STRUCT_FLAG) && used_structs.has(param_struct_name)) { + used_structs[param_struct_name].used = true; + } +#endif // DEBUG_ENABLED if (use_precision) { _set_error("Precision modifier cannot be used on structs."); return ERR_PARSE_ERROR; @@ -8636,10 +8884,10 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct bool error = false; tk = _get_token(); - if (tk.type == TK_INT_CONSTANT) { - array_size = (int)tk.constant; + if (tk.is_integer_constant()) { + arg_array_size = (int)tk.constant; - if (array_size > 0) { + if (arg_array_size > 0) { tk = _get_token(); if (tk.type != TK_BRACKET_CLOSE) { _set_error("Expected ']'"); @@ -8691,17 +8939,17 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); if (tk.type == TK_BRACKET_OPEN) { - if (array_size > 0) { + if (arg_array_size > 0) { _set_error("Array size is already defined!"); return ERR_PARSE_ERROR; } bool error = false; tk = _get_token(); - if (tk.type == TK_INT_CONSTANT) { - array_size = (int)tk.constant; + if (tk.is_integer_constant()) { + arg_array_size = (int)tk.constant; - if (array_size > 0) { + if (arg_array_size > 0) { tk = _get_token(); if (tk.type != TK_BRACKET_CLOSE) { _set_error("Expected ']'"); @@ -8721,7 +8969,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); } - arg.array_size = array_size; + arg.array_size = arg_array_size; func_node->arguments.push_back(arg); if (tk.type == TK_COMMA) { @@ -8773,14 +9021,14 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); } - int error_line; - String error_message; - if (!_check_varying_usages(&error_line, &error_message)) { - _set_tkpos({ 0, error_line }); - _set_error(error_message); - return ERR_PARSE_ERROR; +#ifdef DEBUG_ENABLED + if (HAS_WARNING(ShaderWarning::DEVICE_LIMIT_EXCEEDED) && (uniform_buffer_size > max_uniform_buffer_size)) { + Vector<Variant> args; + args.push_back(uniform_buffer_size); + args.push_back(max_uniform_buffer_size); + _add_global_warning(ShaderWarning::DEVICE_LIMIT_EXCEEDED, "uniform buffer", args); } - +#endif // DEBUG_ENABLED return OK; } @@ -8900,7 +9148,7 @@ String ShaderLanguage::get_shader_type(const String &p_code) { break; } else if (p_code[i] <= 32) { - if (cur_identifier != String()) { + if (!cur_identifier.is_empty()) { if (!reading_type) { if (cur_identifier != "shader_type") { return String(); @@ -8960,17 +9208,17 @@ uint32_t ShaderLanguage::get_warning_flags() const { } #endif // DEBUG_ENABLED -Error ShaderLanguage::compile(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const VaryingFunctionNames &p_varying_function_names, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func) { +Error ShaderLanguage::compile(const String &p_code, const ShaderCompileInfo &p_info) { clear(); code = p_code; - global_var_get_type_func = p_global_variable_type_func; - varying_function_names = p_varying_function_names; + global_var_get_type_func = p_info.global_variable_type_func; + varying_function_names = p_info.varying_function_names; nodes = nullptr; shader = alloc_node<ShaderNode>(); - Error err = _parse_shader(p_functions, p_render_modes, p_shader_types); + Error err = _parse_shader(p_info.functions, p_info.render_modes, p_info.shader_types); #ifdef DEBUG_ENABLED if (check_warnings) { @@ -8984,17 +9232,17 @@ Error ShaderLanguage::compile(const String &p_code, const Map<StringName, Functi return OK; } -Error ShaderLanguage::complete(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const VaryingFunctionNames &p_varying_function_names, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func, List<ScriptCodeCompletionOption> *r_options, String &r_call_hint) { +Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_info, List<ScriptCodeCompletionOption> *r_options, String &r_call_hint) { clear(); code = p_code; - varying_function_names = p_varying_function_names; + varying_function_names = p_info.varying_function_names; nodes = nullptr; - global_var_get_type_func = p_global_variable_type_func; + global_var_get_type_func = p_info.global_variable_type_func; shader = alloc_node<ShaderNode>(); - _parse_shader(p_functions, p_render_modes, p_shader_types); + _parse_shader(p_info.functions, p_info.render_modes, p_info.shader_types); switch (completion_type) { case COMPLETION_NONE: { @@ -9002,9 +9250,32 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct return OK; } break; case COMPLETION_RENDER_MODE: { - for (int i = 0; i < p_render_modes.size(); i++) { - ScriptCodeCompletionOption option(p_render_modes[i], ScriptCodeCompletionOption::KIND_ENUM); - r_options->push_back(option); + for (int i = 0; i < p_info.render_modes.size(); i++) { + const ModeInfo &info = p_info.render_modes[i]; + + if (!info.options.is_empty()) { + bool found = false; + + for (int j = 0; j < info.options.size(); j++) { + if (shader->render_modes.has(String(info.name) + "_" + String(info.options[j]))) { + found = true; + } + } + + if (!found) { + for (int j = 0; j < info.options.size(); j++) { + ScriptCodeCompletionOption option(String(info.name) + "_" + String(info.options[j]), ScriptCodeCompletionOption::KIND_ENUM); + r_options->push_back(option); + } + } + } else { + const String name = String(info.name); + + if (!shader->render_modes.has(name)) { + ScriptCodeCompletionOption option(name, ScriptCodeCompletionOption::KIND_ENUM); + r_options->push_back(option); + } + } } return OK; @@ -9021,7 +9292,7 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct return OK; } break; case COMPLETION_MAIN_FUNCTION: { - for (const KeyValue<StringName, FunctionInfo> &E : p_functions) { + for (const KeyValue<StringName, FunctionInfo> &E : p_info.functions) { ScriptCodeCompletionOption option(E.key, ScriptCodeCompletionOption::KIND_FUNCTION); r_options->push_back(option); } @@ -9057,8 +9328,18 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct } if (comp_ident) { - if (p_functions.has("global")) { - for (const KeyValue<StringName, BuiltInInfo> &E : p_functions["global"].built_ins) { + if (p_info.functions.has("global")) { + for (const KeyValue<StringName, BuiltInInfo> &E : p_info.functions["global"].built_ins) { + ScriptCodeCompletionOption::Kind kind = ScriptCodeCompletionOption::KIND_MEMBER; + if (E.value.constant) { + kind = ScriptCodeCompletionOption::KIND_CONSTANT; + } + matches.insert(E.key, kind); + } + } + + if (p_info.functions.has("constants")) { + for (const KeyValue<StringName, BuiltInInfo> &E : p_info.functions["constants"].built_ins) { ScriptCodeCompletionOption::Kind kind = ScriptCodeCompletionOption::KIND_MEMBER; if (E.value.constant) { kind = ScriptCodeCompletionOption::KIND_CONSTANT; @@ -9067,8 +9348,8 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct } } - if (skip_function != StringName() && p_functions.has(skip_function)) { - for (const KeyValue<StringName, BuiltInInfo> &E : p_functions[skip_function].built_ins) { + if (skip_function != StringName() && p_info.functions.has(skip_function)) { + for (const KeyValue<StringName, BuiltInInfo> &E : p_info.functions[skip_function].built_ins) { ScriptCodeCompletionOption::Kind kind = ScriptCodeCompletionOption::KIND_MEMBER; if (E.value.constant) { kind = ScriptCodeCompletionOption::KIND_CONSTANT; @@ -9383,6 +9664,57 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct } } break; + case COMPLETION_HINT: { + if (completion_base == DataType::TYPE_VEC4) { + ScriptCodeCompletionOption option("hint_color", ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + r_options->push_back(option); + } else if ((completion_base == DataType::TYPE_INT || completion_base == DataType::TYPE_FLOAT) && !completion_base_array) { + ScriptCodeCompletionOption option("hint_range", ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + + if (completion_base == DataType::TYPE_INT) { + option.insert_text = "hint_range(0, 100, 1)"; + } else { + option.insert_text = "hint_range(0.0, 1.0, 0.1)"; + } + + r_options->push_back(option); + } else if ((int(completion_base) > int(TYPE_MAT4) && int(completion_base) < int(TYPE_STRUCT)) && !completion_base_array) { + static Vector<String> options; + + if (options.is_empty()) { + options.push_back("filter_linear"); + options.push_back("filter_linear_mipmap"); + options.push_back("filter_linear_mipmap_anisotropic"); + options.push_back("filter_nearest"); + options.push_back("filter_nearest_mipmap"); + options.push_back("filter_nearest_mipmap_anisotropic"); + options.push_back("hint_albedo"); + options.push_back("hint_anisotropy"); + options.push_back("hint_black"); + options.push_back("hint_black_albedo"); + options.push_back("hint_normal"); + options.push_back("hint_roughness_a"); + options.push_back("hint_roughness_b"); + options.push_back("hint_roughness_g"); + options.push_back("hint_roughness_gray"); + options.push_back("hint_roughness_normal"); + options.push_back("hint_roughness_r"); + options.push_back("hint_white"); + options.push_back("repeat_enable"); + options.push_back("repeat_disable"); + } + + for (int i = 0; i < options.size(); i++) { + ScriptCodeCompletionOption option(options[i], ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + r_options->push_back(option); + } + } + if (!completion_base_array) { + ScriptCodeCompletionOption option("instance_index", ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + option.insert_text = "instance_index(0)"; + r_options->push_back(option); + } + } break; } return ERR_PARSE_ERROR; @@ -9404,7 +9736,7 @@ ShaderLanguage::ShaderLanguage() { nodes = nullptr; completion_class = TAG_GLOBAL; -#if DEBUG_ENABLED +#ifdef DEBUG_ENABLED warnings_check_map.insert(ShaderWarning::UNUSED_CONSTANT, &used_constants); warnings_check_map.insert(ShaderWarning::UNUSED_FUNCTION, &used_functions); warnings_check_map.insert(ShaderWarning::UNUSED_STRUCT, &used_structs); diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index c82f71d10d..b9c2d4b33c 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -57,6 +57,7 @@ public: TK_FALSE, TK_FLOAT_CONSTANT, TK_INT_CONSTANT, + TK_UINT_CONSTANT, TK_TYPE_VOID, TK_TYPE_BOOL, TK_TYPE_BVEC2, @@ -168,7 +169,7 @@ public: TK_HINT_ROUGHNESS_B, TK_HINT_ROUGHNESS_A, TK_HINT_ROUGHNESS_GRAY, - TK_HINT_ANISO_TEXTURE, + TK_HINT_ANISOTROPY_TEXTURE, TK_HINT_ALBEDO_TEXTURE, TK_HINT_BLACK_ALBEDO_TEXTURE, TK_HINT_COLOR, @@ -178,8 +179,8 @@ public: TK_FILTER_LINEAR, TK_FILTER_NEAREST_MIPMAP, TK_FILTER_LINEAR_MIPMAP, - TK_FILTER_NEAREST_MIPMAP_ANISO, - TK_FILTER_LINEAR_MIPMAP_ANISO, + TK_FILTER_NEAREST_MIPMAP_ANISOTROPIC, + TK_FILTER_LINEAR_MIPMAP_ANISOTROPIC, TK_REPEAT_ENABLE, TK_REPEAT_DISABLE, TK_SHADER_TYPE, @@ -287,6 +288,7 @@ public: OP_CONSTRUCT, OP_STRUCT, OP_INDEX, + OP_EMPTY, OP_MAX }; @@ -320,8 +322,8 @@ public: FILTER_LINEAR, FILTER_NEAREST_MIPMAP, FILTER_LINEAR_MIPMAP, - FILTER_NEAREST_MIPMAP_ANISO, - FILTER_LINEAR_MIPMAP_ANISO, + FILTER_NEAREST_MIPMAP_ANISOTROPIC, + FILTER_LINEAR_MIPMAP_ANISOTROPIC, FILTER_DEFAULT, }; @@ -574,7 +576,7 @@ public: virtual DataType get_datatype() const override { return datatype; } virtual String get_datatype_name() const override { return String(struct_name); } - virtual int get_array_size() const override { return array_size; } + virtual int get_array_size() const override { return (index_expression || call_expression) ? 0 : array_size; } virtual bool is_indexed() const override { return index_expression != nullptr || call_expression != nullptr; } MemberNode() : @@ -680,7 +682,7 @@ public: HINT_ROUGHNESS_GRAY, HINT_BLACK, HINT_WHITE, - HINT_ANISO, + HINT_ANISOTROPY, HINT_MAX }; @@ -747,6 +749,7 @@ public: COMPLETION_CALL_ARGUMENTS, COMPLETION_INDEX, COMPLETION_STRUCT, + COMPLETION_HINT, }; struct Token { @@ -754,6 +757,9 @@ public: StringName text; double constant; uint16_t line; + bool is_integer_constant() const { + return type == TK_INT_CONSTANT || type == TK_UINT_CONSTANT; + } }; static String get_operator_text(Operator p_op); @@ -771,6 +777,7 @@ public: static bool is_token_nonvoid_datatype(TokenType p_type); static bool is_token_operator(TokenType p_type); static bool is_token_operator_assign(TokenType p_type); + static bool is_token_hint(TokenType p_type); static bool convert_constant(ConstantNode *p_constant, DataType p_to_type, ConstantNode::Value *p_value = nullptr); static DataType get_scalar_type(DataType p_type); @@ -780,7 +787,7 @@ public: static bool is_sampler_type(DataType p_type); static Variant constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, int p_array_size, ShaderLanguage::ShaderNode::Uniform::Hint p_hint = ShaderLanguage::ShaderNode::Uniform::HINT_NONE); static PropertyInfo uniform_to_property_info(const ShaderNode::Uniform &p_uniform); - static uint32_t get_type_size(DataType p_type); + static uint32_t get_datatype_size(DataType p_type); static void get_keyword_list(List<String> *r_keywords); static bool is_control_flow_keyword(String p_keyword); @@ -812,6 +819,57 @@ public: DataType return_type = TYPE_VOID; }; + struct ModeInfo { + StringName name; + Vector<StringName> options; + + ModeInfo() {} + + ModeInfo(const StringName &p_name) : + name(p_name) { + } + + ModeInfo(const StringName &p_name, const StringName &p_arg1, const StringName &p_arg2) : + name(p_name) { + options.push_back(p_arg1); + options.push_back(p_arg2); + } + + ModeInfo(const StringName &p_name, const StringName &p_arg1, const StringName &p_arg2, const StringName &p_arg3) : + name(p_name) { + options.push_back(p_arg1); + options.push_back(p_arg2); + options.push_back(p_arg3); + } + + ModeInfo(const StringName &p_name, const StringName &p_arg1, const StringName &p_arg2, const StringName &p_arg3, const StringName &p_arg4) : + name(p_name) { + options.push_back(p_arg1); + options.push_back(p_arg2); + options.push_back(p_arg3); + options.push_back(p_arg4); + } + + ModeInfo(const StringName &p_name, const StringName &p_arg1, const StringName &p_arg2, const StringName &p_arg3, const StringName &p_arg4, const StringName &p_arg5) : + name(p_name) { + options.push_back(p_arg1); + options.push_back(p_arg2); + options.push_back(p_arg3); + options.push_back(p_arg4); + options.push_back(p_arg5); + } + + ModeInfo(const StringName &p_name, const StringName &p_arg1, const StringName &p_arg2, const StringName &p_arg3, const StringName &p_arg4, const StringName &p_arg5, const StringName &p_arg6) : + name(p_name) { + options.push_back(p_arg1); + options.push_back(p_arg2); + options.push_back(p_arg3); + options.push_back(p_arg4); + options.push_back(p_arg5); + options.push_back(p_arg6); + } + }; + struct FunctionInfo { Map<StringName, BuiltInInfo> built_ins; Map<StringName, StageFunctionInfo> stage_functions; @@ -861,11 +919,14 @@ private: bool check_warnings = false; uint32_t warning_flags; - void _add_line_warning(ShaderWarning::Code p_code, const StringName &p_subject = "") { - warnings.push_back(ShaderWarning(p_code, tk_line, p_subject)); + void _add_line_warning(ShaderWarning::Code p_code, const StringName &p_subject = "", const Vector<Variant> &p_extra_args = Vector<Variant>()) { + warnings.push_back(ShaderWarning(p_code, tk_line, p_subject, p_extra_args)); + } + void _add_global_warning(ShaderWarning::Code p_code, const StringName &p_subject = "", const Vector<Variant> &p_extra_args = Vector<Variant>()) { + warnings.push_back(ShaderWarning(p_code, -1, p_subject, p_extra_args)); } - void _add_warning(ShaderWarning::Code p_code, int p_line, const StringName &p_subject = "") { - warnings.push_back(ShaderWarning(p_code, p_line, p_subject)); + void _add_warning(ShaderWarning::Code p_code, int p_line, const StringName &p_subject = "", const Vector<Variant> &p_extra_args = Vector<Variant>()) { + warnings.push_back(ShaderWarning(p_code, p_line, p_subject, p_extra_args)); } void _check_warning_accums(); #endif // DEBUG_ENABLED @@ -880,14 +941,6 @@ private: VaryingFunctionNames varying_function_names; - struct VaryingUsage { - ShaderNode::Varying *var; - int line; - }; - List<VaryingUsage> unknown_varying_usages; - - bool _check_varying_usages(int *r_error_line, String *r_error_message) const; - TkPos _get_tkpos() { TkPos tkp; tkp.char_idx = char_idx; @@ -965,10 +1018,12 @@ private: int completion_line; BlockNode *completion_block; DataType completion_base; + bool completion_base_array; SubClassTag completion_class; StringName completion_function; StringName completion_struct; int completion_argument; + const Map<StringName, FunctionInfo> *stages = nullptr; bool _get_completable_identifier(BlockNode *p_block, CompletionType p_type, StringName &identifier); @@ -976,6 +1031,8 @@ private: static const BuiltinFuncOutArgs builtin_func_out_args[]; static const BuiltinFuncConstArgs builtin_func_const_args[]; + static bool is_const_suffix_lut_initialized; + Error _validate_datatype(DataType p_type); bool _compare_datatypes(DataType p_datatype_a, String p_datatype_name_a, int p_array_size_a, DataType p_datatype_b, String p_datatype_name_b, int p_array_size_b); bool _compare_datatypes_in_nodes(Node *a, Node *b); @@ -985,12 +1042,11 @@ private: bool _propagate_function_call_sampler_uniform_settings(StringName p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat); bool _propagate_function_call_sampler_builtin_reference(StringName p_name, int p_argument, const StringName &p_builtin); bool _validate_varying_assign(ShaderNode::Varying &p_varying, String *r_message); - bool _validate_varying_using(ShaderNode::Varying &p_varying, String *r_message); bool _check_node_constness(const Node *p_node) const; Node *_parse_array_size(BlockNode *p_block, const FunctionInfo &p_function_info, int &r_array_size); - Error _parse_global_array_size(int &r_array_size); - Error _parse_local_array_size(BlockNode *p_block, const FunctionInfo &p_function_info, ArrayDeclarationNode *p_node, ArrayDeclarationNode::Declaration *p_decl, int &r_array_size, bool &r_is_unknown_size); + Error _parse_global_array_size(int &r_array_size, const FunctionInfo &p_function_info); + Error _parse_local_array_size(BlockNode *p_block, const FunctionInfo &p_function_info, Node *&r_size_expression, int &r_array_size, bool &r_is_unknown_size); Node *_parse_expression(BlockNode *p_block, const FunctionInfo &p_function_info); Node *_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info); @@ -1002,7 +1058,7 @@ private: String _get_shader_type_list(const Set<String> &p_shader_types) const; String _get_qualifier_str(ArgumentQualifier p_qualifier) const; - Error _parse_shader(const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const Set<String> &p_shader_types); + Error _parse_shader(const Map<StringName, FunctionInfo> &p_functions, const Vector<ModeInfo> &p_render_modes, const Set<String> &p_shader_types); Error _find_last_flow_op_in_block(BlockNode *p_block, FlowOperation p_op); Error _find_last_flow_op_in_op(ControlFlowNode *p_flow, FlowOperation p_op); @@ -1023,8 +1079,17 @@ public: void clear(); static String get_shader_type(const String &p_code); - Error compile(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const VaryingFunctionNames &p_varying_function_names, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func); - Error complete(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const VaryingFunctionNames &p_varying_function_names, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func, List<ScriptCodeCompletionOption> *r_options, String &r_call_hint); + + struct ShaderCompileInfo { + Map<StringName, FunctionInfo> functions; + Vector<ModeInfo> render_modes; + VaryingFunctionNames varying_function_names = VaryingFunctionNames(); + Set<String> shader_types; + GlobalVariableGetTypeFunc global_variable_type_func = nullptr; + }; + + Error compile(const String &p_code, const ShaderCompileInfo &p_info); + Error complete(const String &p_code, const ShaderCompileInfo &p_info, List<ScriptCodeCompletionOption> *r_options, String &r_call_hint); String get_error_text(); int get_error_line(); diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp index eb5c9e66e8..667f8b515f 100644 --- a/servers/rendering/shader_types.cpp +++ b/servers/rendering/shader_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -35,7 +35,7 @@ const Map<StringName, ShaderLanguage::FunctionInfo> &ShaderTypes::get_functions( return shader_modes[p_mode].functions; } -const Vector<StringName> &ShaderTypes::get_modes(RS::ShaderMode p_mode) const { +const Vector<ShaderLanguage::ModeInfo> &ShaderTypes::get_modes(RS::ShaderMode p_mode) const { return shader_modes[p_mode].modes; } @@ -59,9 +59,9 @@ ShaderTypes::ShaderTypes() { /*************** SPATIAL ***********************/ shader_modes[RS::SHADER_SPATIAL].functions["global"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT); - shader_modes[RS::SHADER_SPATIAL].functions["global"].built_ins["PI"] = constt(ShaderLanguage::TYPE_FLOAT); - shader_modes[RS::SHADER_SPATIAL].functions["global"].built_ins["TAU"] = constt(ShaderLanguage::TYPE_FLOAT); - shader_modes[RS::SHADER_SPATIAL].functions["global"].built_ins["E"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[RS::SHADER_SPATIAL].functions["constants"].built_ins["PI"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[RS::SHADER_SPATIAL].functions["constants"].built_ins["TAU"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[RS::SHADER_SPATIAL].functions["constants"].built_ins["E"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VERTEX"] = ShaderLanguage::TYPE_VEC3; shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["NORMAL"] = ShaderLanguage::TYPE_VEC3; @@ -190,60 +190,36 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].functions["light"].can_discard = true; shader_modes[RS::SHADER_SPATIAL].functions["light"].main_function = true; - //order used puts first enum mode (default) first - shader_modes[RS::SHADER_SPATIAL].modes.push_back("blend_mix"); - shader_modes[RS::SHADER_SPATIAL].modes.push_back("blend_add"); - shader_modes[RS::SHADER_SPATIAL].modes.push_back("blend_sub"); - shader_modes[RS::SHADER_SPATIAL].modes.push_back("blend_mul"); - - shader_modes[RS::SHADER_SPATIAL].modes.push_back("depth_draw_opaque"); - shader_modes[RS::SHADER_SPATIAL].modes.push_back("depth_draw_always"); - shader_modes[RS::SHADER_SPATIAL].modes.push_back("depth_draw_never"); - - shader_modes[RS::SHADER_SPATIAL].modes.push_back("depth_prepass_alpha"); - - shader_modes[RS::SHADER_SPATIAL].modes.push_back("depth_test_disabled"); - - shader_modes[RS::SHADER_SPATIAL].modes.push_back("sss_mode_skin"); - - shader_modes[RS::SHADER_SPATIAL].modes.push_back("cull_back"); - shader_modes[RS::SHADER_SPATIAL].modes.push_back("cull_front"); - shader_modes[RS::SHADER_SPATIAL].modes.push_back("cull_disabled"); - - shader_modes[RS::SHADER_SPATIAL].modes.push_back("unshaded"); - shader_modes[RS::SHADER_SPATIAL].modes.push_back("wireframe"); - - shader_modes[RS::SHADER_SPATIAL].modes.push_back("diffuse_lambert"); - shader_modes[RS::SHADER_SPATIAL].modes.push_back("diffuse_lambert_wrap"); - shader_modes[RS::SHADER_SPATIAL].modes.push_back("diffuse_burley"); - shader_modes[RS::SHADER_SPATIAL].modes.push_back("diffuse_toon"); - - shader_modes[RS::SHADER_SPATIAL].modes.push_back("specular_schlick_ggx"); - shader_modes[RS::SHADER_SPATIAL].modes.push_back("specular_blinn"); - shader_modes[RS::SHADER_SPATIAL].modes.push_back("specular_phong"); - shader_modes[RS::SHADER_SPATIAL].modes.push_back("specular_toon"); - shader_modes[RS::SHADER_SPATIAL].modes.push_back("specular_disabled"); - - shader_modes[RS::SHADER_SPATIAL].modes.push_back("skip_vertex_transform"); - shader_modes[RS::SHADER_SPATIAL].modes.push_back("world_vertex_coords"); - shader_modes[RS::SHADER_SPATIAL].modes.push_back("ensure_correct_normals"); - - shader_modes[RS::SHADER_SPATIAL].modes.push_back("shadows_disabled"); - shader_modes[RS::SHADER_SPATIAL].modes.push_back("ambient_light_disabled"); - shader_modes[RS::SHADER_SPATIAL].modes.push_back("shadow_to_opacity"); - - shader_modes[RS::SHADER_SPATIAL].modes.push_back("vertex_lighting"); - shader_modes[RS::SHADER_SPATIAL].modes.push_back("particle_trails"); - - shader_modes[RS::SHADER_SPATIAL].modes.push_back("alpha_to_coverage"); - shader_modes[RS::SHADER_SPATIAL].modes.push_back("alpha_to_coverage_and_one"); + // spatial render modes + { + shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "blend", "mix", "add", "sub", "mul" }); + shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "depth_draw", "opaque", "always", "never" }); + shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "depth_prepass_alpha" }); + shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "depth_test_disabled" }); + shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "sss_mode_skin" }); + shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "cull", "back", "front", "disabled" }); + shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "unshaded" }); + shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "wireframe" }); + shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "diffuse", "lambert", "lambert_wrap", "burley", "toon" }); + shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "specular", "schlick_ggx", "blinn", "phong", "toon", "disabled" }); + shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "skip_vertex_transform" }); + shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "world_vertex_coords" }); + shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "ensure_correct_normals" }); + shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "shadows_disabled" }); + shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "ambient_light_disabled" }); + shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "shadow_to_opacity" }); + shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "vertex_lighting" }); + shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "particle_trails" }); + shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "alpha_to_coverage" }); + shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "alpha_to_coverage_and_one" }); + } /************ CANVAS ITEM **************************/ shader_modes[RS::SHADER_CANVAS_ITEM].functions["global"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT); - shader_modes[RS::SHADER_CANVAS_ITEM].functions["global"].built_ins["PI"] = constt(ShaderLanguage::TYPE_FLOAT); - shader_modes[RS::SHADER_CANVAS_ITEM].functions["global"].built_ins["TAU"] = constt(ShaderLanguage::TYPE_FLOAT); - shader_modes[RS::SHADER_CANVAS_ITEM].functions["global"].built_ins["E"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[RS::SHADER_CANVAS_ITEM].functions["constants"].built_ins["PI"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[RS::SHADER_CANVAS_ITEM].functions["constants"].built_ins["TAU"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[RS::SHADER_CANVAS_ITEM].functions["constants"].built_ins["E"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[RS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["VERTEX"] = ShaderLanguage::TYPE_VEC2; shader_modes[RS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["UV"] = ShaderLanguage::TYPE_VEC2; @@ -319,24 +295,20 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].can_discard = true; shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].main_function = true; - shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("skip_vertex_transform"); - - shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("blend_mix"); - shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("blend_add"); - shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("blend_sub"); - shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("blend_mul"); - shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("blend_premul_alpha"); - shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("blend_disabled"); - - shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("unshaded"); - shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("light_only"); + // canvasitem render modes + { + shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back({ "skip_vertex_transform" }); + shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back({ "blend", "mix", "add", "sub", "mul", "premul_alpha", "disabled" }); + shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back({ "unshaded" }); + shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back({ "light_only" }); + } /************ PARTICLES **************************/ shader_modes[RS::SHADER_PARTICLES].functions["global"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT); - shader_modes[RS::SHADER_PARTICLES].functions["global"].built_ins["PI"] = constt(ShaderLanguage::TYPE_FLOAT); - shader_modes[RS::SHADER_PARTICLES].functions["global"].built_ins["TAU"] = constt(ShaderLanguage::TYPE_FLOAT); - shader_modes[RS::SHADER_PARTICLES].functions["global"].built_ins["E"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[RS::SHADER_PARTICLES].functions["constants"].built_ins["PI"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[RS::SHADER_PARTICLES].functions["constants"].built_ins["TAU"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[RS::SHADER_PARTICLES].functions["constants"].built_ins["E"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4; shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["VELOCITY"] = ShaderLanguage::TYPE_VEC3; @@ -367,7 +339,7 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["LIFETIME"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["DELTA"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["NUMBER"] = constt(ShaderLanguage::TYPE_UINT); - shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_INT); + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_UINT); shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4); shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT); shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["FLAG_EMIT_POSITION"] = constt(ShaderLanguage::TYPE_UINT); @@ -392,17 +364,20 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_PARTICLES].functions["process"].stage_functions["emit_subparticle"] = emit_vertex_func; } - shader_modes[RS::SHADER_PARTICLES].modes.push_back("collision_use_scale"); - shader_modes[RS::SHADER_PARTICLES].modes.push_back("disable_force"); - shader_modes[RS::SHADER_PARTICLES].modes.push_back("disable_velocity"); - shader_modes[RS::SHADER_PARTICLES].modes.push_back("keep_data"); + // particles render modes + { + shader_modes[RS::SHADER_PARTICLES].modes.push_back({ "collision_use_scale" }); + shader_modes[RS::SHADER_PARTICLES].modes.push_back({ "disable_force" }); + shader_modes[RS::SHADER_PARTICLES].modes.push_back({ "disable_velocity" }); + shader_modes[RS::SHADER_PARTICLES].modes.push_back({ "keep_data" }); + } /************ SKY **************************/ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT); - shader_modes[RS::SHADER_SKY].functions["global"].built_ins["PI"] = constt(ShaderLanguage::TYPE_FLOAT); - shader_modes[RS::SHADER_SKY].functions["global"].built_ins["TAU"] = constt(ShaderLanguage::TYPE_FLOAT); - shader_modes[RS::SHADER_SKY].functions["global"].built_ins["E"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[RS::SHADER_SKY].functions["constants"].built_ins["PI"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[RS::SHADER_SKY].functions["constants"].built_ins["TAU"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[RS::SHADER_SKY].functions["constants"].built_ins["E"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[RS::SHADER_SKY].functions["global"].built_ins["POSITION"] = constt(ShaderLanguage::TYPE_VEC3); shader_modes[RS::SHADER_SKY].functions["global"].built_ins["RADIANCE"] = constt(ShaderLanguage::TYPE_SAMPLERCUBE); shader_modes[RS::SHADER_SKY].functions["global"].built_ins["AT_HALF_RES_PASS"] = constt(ShaderLanguage::TYPE_BOOL); @@ -439,16 +414,19 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["FOG"] = ShaderLanguage::TYPE_VEC4; shader_modes[RS::SHADER_SKY].functions["sky"].main_function = true; - shader_modes[RS::SHADER_SKY].modes.push_back("use_half_res_pass"); - shader_modes[RS::SHADER_SKY].modes.push_back("use_quarter_res_pass"); - shader_modes[RS::SHADER_SKY].modes.push_back("disable_fog"); + // sky render modes + { + shader_modes[RS::SHADER_SKY].modes.push_back({ "use_half_res_pass" }); + shader_modes[RS::SHADER_SKY].modes.push_back({ "use_quarter_res_pass" }); + shader_modes[RS::SHADER_SKY].modes.push_back({ "disable_fog" }); + } /************ FOG **************************/ shader_modes[RS::SHADER_FOG].functions["global"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT); - shader_modes[RS::SHADER_FOG].functions["global"].built_ins["PI"] = constt(ShaderLanguage::TYPE_FLOAT); - shader_modes[RS::SHADER_FOG].functions["global"].built_ins["TAU"] = constt(ShaderLanguage::TYPE_FLOAT); - shader_modes[RS::SHADER_FOG].functions["global"].built_ins["E"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[RS::SHADER_FOG].functions["constants"].built_ins["PI"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[RS::SHADER_FOG].functions["constants"].built_ins["TAU"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[RS::SHADER_FOG].functions["constants"].built_ins["E"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["WORLD_POSITION"] = constt(ShaderLanguage::TYPE_VEC3); shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["OBJECT_POSITION"] = constt(ShaderLanguage::TYPE_VEC3); diff --git a/servers/rendering/shader_types.h b/servers/rendering/shader_types.h index 75a310a1b1..385083b670 100644 --- a/servers/rendering/shader_types.h +++ b/servers/rendering/shader_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -38,7 +38,7 @@ class ShaderTypes { struct Type { Map<StringName, ShaderLanguage::FunctionInfo> functions; - Vector<StringName> modes; + Vector<ShaderLanguage::ModeInfo> modes; }; Map<RS::ShaderMode, Type> shader_modes; @@ -52,7 +52,7 @@ public: static ShaderTypes *get_singleton() { return singleton; } const Map<StringName, ShaderLanguage::FunctionInfo> &get_functions(RS::ShaderMode p_mode) const; - const Vector<StringName> &get_modes(RS::ShaderMode p_mode) const; + const Vector<ShaderLanguage::ModeInfo> &get_modes(RS::ShaderMode p_mode) const; const Set<String> &get_types() const; const List<String> &get_types_list() const; diff --git a/servers/rendering/shader_warnings.cpp b/servers/rendering/shader_warnings.cpp index 0b8476478c..f2e74c4d78 100644 --- a/servers/rendering/shader_warnings.cpp +++ b/servers/rendering/shader_warnings.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -61,6 +61,10 @@ String ShaderWarning::get_message() const { return vformat("The varying '%s' is declared but never used.", subject); case UNUSED_LOCAL_VARIABLE: return vformat("The local variable '%s' is declared but never used.", subject); + case FORMATTING_ERROR: + return subject; + case DEVICE_LIMIT_EXCEEDED: + return vformat("The total size of the %s for this shader on this device has been exceeded (%s/%s). The shader may not work correctly.", subject, (int)extra_args[0], (int)extra_args[1]); default: break; } @@ -71,6 +75,10 @@ String ShaderWarning::get_name() const { return get_name_from_code(code); } +Vector<Variant> ShaderWarning::get_extra_args() const { + return extra_args; +} + String ShaderWarning::get_name_from_code(Code p_code) { ERR_FAIL_INDEX_V(p_code, WARNING_MAX, String()); @@ -82,6 +90,8 @@ String ShaderWarning::get_name_from_code(Code p_code) { "UNUSED_UNIFORM", "UNUSED_VARYING", "UNUSED_LOCAL_VARIABLE", + "FORMATTING_ERROR", + "DEVICE_LIMIT_EXCEEDED", }; static_assert((sizeof(names) / sizeof(*names)) == WARNING_MAX, "Amount of warning types don't match the amount of warning names."); @@ -110,6 +120,8 @@ static void init_code_to_flags_map() { code_to_flags_map->insert(ShaderWarning::UNUSED_UNIFORM, ShaderWarning::UNUSED_UNIFORM_FLAG); code_to_flags_map->insert(ShaderWarning::UNUSED_VARYING, ShaderWarning::UNUSED_VARYING_FLAG); code_to_flags_map->insert(ShaderWarning::UNUSED_LOCAL_VARIABLE, ShaderWarning::UNUSED_LOCAL_VARIABLE_FLAG); + code_to_flags_map->insert(ShaderWarning::FORMATTING_ERROR, ShaderWarning::FORMATTING_ERROR_FLAG); + code_to_flags_map->insert(ShaderWarning::DEVICE_LIMIT_EXCEEDED, ShaderWarning::DEVICE_LIMIT_EXCEEDED_FLAG); } ShaderWarning::CodeFlags ShaderWarning::get_flags_from_codemap(const Map<Code, bool> &p_map) { @@ -128,8 +140,8 @@ ShaderWarning::CodeFlags ShaderWarning::get_flags_from_codemap(const Map<Code, b return (CodeFlags)result; } -ShaderWarning::ShaderWarning(Code p_code, int p_line, const StringName &p_subject) : - code(p_code), line(p_line), subject(p_subject) { +ShaderWarning::ShaderWarning(Code p_code, int p_line, const StringName &p_subject, const Vector<Variant> &p_extra_args) : + code(p_code), line(p_line), subject(p_subject), extra_args(p_extra_args) { } #endif // DEBUG_ENABLED diff --git a/servers/rendering/shader_warnings.h b/servers/rendering/shader_warnings.h index db872d8fb1..e309907181 100644 --- a/servers/rendering/shader_warnings.h +++ b/servers/rendering/shader_warnings.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -36,6 +36,7 @@ #include "core/string/string_name.h" #include "core/templates/list.h" #include "core/templates/map.h" +#include "core/variant/variant.h" class ShaderWarning { public: @@ -47,6 +48,8 @@ public: UNUSED_UNIFORM, UNUSED_VARYING, UNUSED_LOCAL_VARIABLE, + FORMATTING_ERROR, + DEVICE_LIMIT_EXCEEDED, WARNING_MAX, }; @@ -59,12 +62,15 @@ public: UNUSED_UNIFORM_FLAG = 16U, UNUSED_VARYING_FLAG = 32U, UNUSED_LOCAL_VARIABLE_FLAG = 64U, + FORMATTING_ERROR_FLAG = 128U, + DEVICE_LIMIT_EXCEEDED_FLAG = 256U, }; private: Code code; int line; StringName subject; + Vector<Variant> extra_args; public: Code get_code() const; @@ -72,12 +78,13 @@ public: const StringName &get_subject() const; String get_message() const; String get_name() const; + Vector<Variant> get_extra_args() const; static String get_name_from_code(Code p_code); static Code get_code_from_name(const String &p_name); static CodeFlags get_flags_from_codemap(const Map<Code, bool> &p_map); - ShaderWarning(Code p_code = WARNING_MAX, int p_line = -1, const StringName &p_subject = ""); + ShaderWarning(Code p_code = WARNING_MAX, int p_line = -1, const StringName &p_subject = "", const Vector<Variant> &p_extra_args = Vector<Variant>()); }; #endif // DEBUG_ENABLED |