From 20deb0917d466ca9dd1bf435dfb326c72f73e3c0 Mon Sep 17 00:00:00 2001 From: Je06jm Date: Tue, 23 Nov 2021 14:16:03 -0700 Subject: Implemented AMD's FSR as a computer shader for upscaling 3D scenes --- servers/rendering/rasterizer_dummy.h | 2 +- servers/rendering/renderer_compositor.h | 3 +- servers/rendering/renderer_rd/effects_rd.cpp | 59 +++++++ servers/rendering/renderer_rd/effects_rd.h | 24 +++ .../forward_clustered/render_forward_clustered.cpp | 48 +++--- .../forward_clustered/render_forward_clustered.h | 6 + .../renderer_rd/renderer_compositor_rd.cpp | 6 +- .../rendering/renderer_rd/renderer_compositor_rd.h | 2 - .../rendering/renderer_rd/renderer_scene_gi_rd.cpp | 16 +- .../renderer_rd/renderer_scene_render_rd.cpp | 158 +++++++++++++------ .../renderer_rd/renderer_scene_render_rd.h | 15 +- .../rendering/renderer_rd/renderer_storage_rd.cpp | 106 +++++++++++++ .../rendering/renderer_rd/renderer_storage_rd.h | 8 + .../rendering/renderer_rd/shaders/fsr_upscale.glsl | 173 +++++++++++++++++++++ servers/rendering/renderer_scene.h | 2 +- servers/rendering/renderer_scene_cull.h | 2 +- servers/rendering/renderer_scene_render.h | 2 +- servers/rendering/renderer_viewport.cpp | 110 +++++++++++-- servers/rendering/renderer_viewport.h | 15 +- servers/rendering/rendering_device.h | 1 + servers/rendering/rendering_server_default.h | 6 +- 21 files changed, 649 insertions(+), 115 deletions(-) create mode 100644 servers/rendering/renderer_rd/shaders/fsr_upscale.glsl (limited to 'servers/rendering') diff --git a/servers/rendering/rasterizer_dummy.h b/servers/rendering/rasterizer_dummy.h index cecb009aa0..3451ea2d39 100644 --- a/servers/rendering/rasterizer_dummy.h +++ b/servers/rendering/rasterizer_dummy.h @@ -195,7 +195,7 @@ public: void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) override {} RID render_buffers_create() override { return RID(); } - void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) override {} + void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) override {} void gi_set_use_half_resolution(bool p_enable) override {} void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_curve) override {} diff --git a/servers/rendering/renderer_compositor.h b/servers/rendering/renderer_compositor.h index 1971c3e781..4526354d17 100644 --- a/servers/rendering/renderer_compositor.h +++ b/servers/rendering/renderer_compositor.h @@ -67,6 +67,7 @@ private: protected: static RendererCompositor *(*_create_func)(); + bool back_end = false; public: static RendererCompositor *create(); @@ -88,7 +89,7 @@ public: virtual uint64_t get_frame_number() const = 0; virtual double get_frame_delta_time() const = 0; - virtual bool is_low_end() const = 0; + _FORCE_INLINE_ virtual bool is_low_end() const { return back_end; }; virtual bool is_xr_enabled() const; RendererCompositor(); diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp index fdd6939a8b..cf943901d4 100644 --- a/servers/rendering/renderer_rd/effects_rd.cpp +++ b/servers/rendering/renderer_rd/effects_rd.cpp @@ -237,6 +237,43 @@ RID EffectsRD::_get_compute_uniform_set_from_image_pair(RID p_texture1, RID p_te return uniform_set; } +void EffectsRD::fsr_upscale(RID p_source_rd_texture, RID p_secondary_texture, RID p_destination_texture, const Size2i &p_internal_size, const Size2i &p_size, float p_fsr_upscale_sharpness) { + memset(&FSR_upscale.push_constant, 0, sizeof(FSRUpscalePushConstant)); + + int dispatch_x = (p_size.x + 15) / 16; + int dispatch_y = (p_size.y + 15) / 16; + + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, FSR_upscale.pipeline); + + FSR_upscale.push_constant.resolution_width = p_internal_size.width; + FSR_upscale.push_constant.resolution_height = p_internal_size.height; + FSR_upscale.push_constant.upscaled_width = p_size.width; + FSR_upscale.push_constant.upscaled_height = p_size.height; + FSR_upscale.push_constant.sharpness = p_fsr_upscale_sharpness; + + //FSR Easc + FSR_upscale.push_constant.pass = FSR_UPSCALE_PASS_EASU; + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_secondary_texture), 1); + + RD::get_singleton()->compute_list_set_push_constant(compute_list, &FSR_upscale.push_constant, sizeof(FSRUpscalePushConstant)); + + RD::get_singleton()->compute_list_dispatch(compute_list, dispatch_x, dispatch_y, 1); + RD::get_singleton()->compute_list_add_barrier(compute_list); + + //FSR Rcas + FSR_upscale.push_constant.pass = FSR_UPSCALE_PASS_RCAS; + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_secondary_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_destination_texture), 1); + + RD::get_singleton()->compute_list_set_push_constant(compute_list, &FSR_upscale.push_constant, sizeof(FSRUpscalePushConstant)); + + RD::get_singleton()->compute_list_dispatch(compute_list, dispatch_x, dispatch_y, 1); + + RD::get_singleton()->compute_list_end(compute_list); +} + void EffectsRD::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y, bool p_panorama) { memset(©_to_fb.push_constant, 0, sizeof(CopyToFbPushConstant)); @@ -1888,6 +1925,27 @@ void EffectsRD::sort_buffer(RID p_uniform_set, int p_size) { } EffectsRD::EffectsRD(bool p_prefer_raster_effects) { + { + Vector FSR_upscale_modes; + +#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) + // MoltenVK does not support some of the operations used by the normal mode of FSR. Fallback works just fine though. + FSR_upscale_modes.push_back("\n#define MODE_FSR_UPSCALE_FALLBACK\n"); +#else + // Everyone else can use normal mode when available. + if (RD::get_singleton()->get_device_capabilities()->supports_fsr_half_float) { + FSR_upscale_modes.push_back("\n#define MODE_FSR_UPSCALE_NORMAL\n"); + } else { + FSR_upscale_modes.push_back("\n#define MODE_FSR_UPSCALE_FALLBACK\n"); + } +#endif + + FSR_upscale.shader.initialize(FSR_upscale_modes); + + FSR_upscale.shader_version = FSR_upscale.shader.version_create(); + FSR_upscale.pipeline = RD::get_singleton()->compute_pipeline_create(FSR_upscale.shader.version_get_shader(FSR_upscale.shader_version, 0)); + } + prefer_raster_effects = p_prefer_raster_effects; if (prefer_raster_effects) { @@ -2523,6 +2581,7 @@ EffectsRD::~EffectsRD() { RD::get_singleton()->free(index_buffer); //array gets freed as dependency RD::get_singleton()->free(filter.coefficient_buffer); + FSR_upscale.shader.version_free(FSR_upscale.shader_version); if (prefer_raster_effects) { blur_raster.shader.version_free(blur_raster.shader_version); bokeh.raster_shader.version_free(blur_raster.shader_version); diff --git a/servers/rendering/renderer_rd/effects_rd.h b/servers/rendering/renderer_rd/effects_rd.h index 551e50ed25..6037127e82 100644 --- a/servers/rendering/renderer_rd/effects_rd.h +++ b/servers/rendering/renderer_rd/effects_rd.h @@ -45,6 +45,7 @@ #include "servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/fsr_upscale.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/luminance_reduce.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/resolve.glsl.gen.h" @@ -69,6 +70,28 @@ class EffectsRD { private: bool prefer_raster_effects; + enum FSRUpscalePass { + FSR_UPSCALE_PASS_EASU = 0, + FSR_UPSCALE_PASS_RCAS = 1 + }; + + struct FSRUpscalePushConstant { + float resolution_width; + float resolution_height; + float upscaled_width; + float upscaled_height; + float sharpness; + int pass; + int _unused0, _unused1; + }; + + struct FSRUpscale { + FSRUpscalePushConstant push_constant; + FsrUpscaleShaderRD shader; + RID shader_version; + RID pipeline; + } FSR_upscale; + enum BlurRasterMode { BLUR_MIPMAP, @@ -754,6 +777,7 @@ private: public: bool get_prefer_raster_effects(); + void fsr_upscale(RID p_source_rd_texture, RID p_secondary_texture, RID p_destination_texture, const Size2i &p_internal_size, const Size2i &p_size, float p_fsr_upscale_sharpness); void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false, bool p_srgb = false, RID p_secondary = RID()); void copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_all_source = false, bool p_8_bit_dst = false, bool p_alpha_to_one = false); void copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array); 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 6d85c1f4c1..03ce2690bf 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -1954,7 +1954,9 @@ void RenderForwardClustered::_base_uniforms_changed() { } void RenderForwardClustered::_update_render_base_uniform_set() { - if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != storage->lightmap_array_get_version())) { + if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != storage->lightmap_array_get_version()) || base_uniform_set_updated) { + base_uniform_set_updated = false; + if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) { RD::get_singleton()->free(render_base_uniform_set); } @@ -1969,18 +1971,18 @@ void RenderForwardClustered::_update_render_base_uniform_set() { u.binding = 1; u.ids.resize(12); RID *ids_ptr = u.ids.ptrw(); - ids_ptr[0] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[1] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[2] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[3] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[4] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[5] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[6] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - ids_ptr[7] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - ids_ptr[8] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - ids_ptr[9] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - ids_ptr[10] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - ids_ptr[11] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[0] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[1] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[2] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[3] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[4] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[5] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[6] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[7] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[8] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[9] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[10] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[11] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); uniforms.push_back(u); } @@ -1999,19 +2001,19 @@ void RenderForwardClustered::_update_render_base_uniform_set() { RID sampler; switch (decals_get_filter()) { case RS::DECAL_FILTER_NEAREST: { - sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); } break; case RS::DECAL_FILTER_NEAREST_MIPMAPS: { - sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); } break; case RS::DECAL_FILTER_LINEAR: { - sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); } break; case RS::DECAL_FILTER_LINEAR_MIPMAPS: { - sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); } break; case RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: { - sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); } break; } @@ -2026,19 +2028,19 @@ void RenderForwardClustered::_update_render_base_uniform_set() { RID sampler; switch (light_projectors_get_filter()) { case RS::LIGHT_PROJECTOR_FILTER_NEAREST: { - sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); } break; case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS: { - sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); } break; case RS::LIGHT_PROJECTOR_FILTER_LINEAR: { - sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); } break; case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS: { - sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); } break; case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: { - sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); } break; } 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 7707d77296..d6ab4d1db2 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -129,6 +129,7 @@ class RenderForwardClustered : public RendererSceneRenderRD { virtual void _base_uniforms_changed() override; virtual RID _render_buffers_get_normal_texture(RID p_render_buffers) override; + bool base_uniform_set_updated = false; void _update_render_base_uniform_set(); RID _setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture); RID _setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas = false, int p_index = 0); @@ -603,6 +604,11 @@ protected: virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray &p_instances) override; public: + _FORCE_INLINE_ virtual void update_uniform_sets() override { + base_uniform_set_updated = true; + _update_render_base_uniform_set(); + } + virtual GeometryInstance *geometry_instance_create(RID p_base) override; virtual void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) override; virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) override; diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index 559e6d5ad7..522a8e8112 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -281,12 +281,12 @@ RendererCompositorRD::RendererCompositorRD() { storage = memnew(RendererStorageRD); canvas = memnew(RendererCanvasRenderRD(storage)); - uint32_t back_end = GLOBAL_GET("rendering/vulkan/rendering/back_end"); + back_end = (bool)(int)GLOBAL_GET("rendering/vulkan/rendering/back_end"); uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE); - if (back_end == 1 || textures_per_stage < 48) { + if (back_end || textures_per_stage < 48) { scene = memnew(RendererSceneRenderImplementation::RenderForwardMobile(storage)); - } else { // back_end == 0 + } else { // back_end == false // default to our high end renderer scene = memnew(RendererSceneRenderImplementation::RenderForwardClustered(storage)); } diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h index 0230c46800..f69e40e0ff 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.h +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h @@ -116,8 +116,6 @@ public: _create_func = _create_current; } - virtual bool is_low_end() const { return false; } - static RendererCompositorRD *singleton; RendererCompositorRD(); ~RendererCompositorRD(); diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp index 807af00c8e..b6b5c90b39 100644 --- a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp @@ -3132,8 +3132,8 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_ RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; - tf.width = rb->width; - tf.height = rb->height; + tf.width = rb->internal_width; + tf.height = rb->internal_height; if (half_resolution) { tf.width >>= 1; tf.height >>= 1; @@ -3146,13 +3146,13 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_ PushConstant push_constant; - push_constant.screen_size[0] = rb->width; - push_constant.screen_size[1] = rb->height; + push_constant.screen_size[0] = rb->internal_width; + push_constant.screen_size[1] = rb->internal_height; push_constant.z_near = p_projection.get_z_near(); push_constant.z_far = p_projection.get_z_far(); push_constant.orthogonal = p_projection.is_orthogonal(); - push_constant.proj_info[0] = -2.0f / (rb->width * p_projection.matrix[0][0]); - push_constant.proj_info[1] = -2.0f / (rb->height * p_projection.matrix[1][1]); + push_constant.proj_info[0] = -2.0f / (rb->internal_width * p_projection.matrix[0][0]); + push_constant.proj_info[1] = -2.0f / (rb->internal_height * p_projection.matrix[1][1]); push_constant.proj_info[2] = (1.0f - p_projection.matrix[0][2]) / p_projection.matrix[0][0]; push_constant.proj_info[3] = (1.0f + p_projection.matrix[1][2]) / p_projection.matrix[1][1]; push_constant.max_voxel_gi_instances = MIN((uint64_t)MAX_VOXEL_GI_INSTANCES, p_voxel_gi_instances.size()); @@ -3344,9 +3344,9 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(PushConstant)); if (rb->gi.using_half_size_gi) { - RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width >> 1, rb->height >> 1, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->internal_width >> 1, rb->internal_height >> 1, 1); } else { - RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width, rb->height, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->internal_width, rb->internal_height, 1); } //do barrier later to allow oeverlap //RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //no barriers, let other compute, raster and transfer happen at the same time diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index b8e9f40bc4..ca77198629 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -1503,8 +1503,8 @@ void RendererSceneRenderRD::_allocate_blur_textures(RenderBuffers *rb) { RD::TextureFormat tf; tf.format = _render_buffers_get_color_format(); // RD::DATA_FORMAT_R16G16B16A16_SFLOAT; - tf.width = rb->width; - tf.height = rb->height; + tf.width = rb->internal_width; + tf.height = rb->internal_height; tf.texture_type = rb->view_count > 1 ? RD::TEXTURE_TYPE_2D_ARRAY : RD::TEXTURE_TYPE_2D; tf.array_layers = rb->view_count; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; @@ -1515,6 +1515,10 @@ void RendererSceneRenderRD::_allocate_blur_textures(RenderBuffers *rb) { } tf.mipmaps = mipmaps_required; + rb->sss_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + tf.width = rb->internal_width; + tf.height = rb->internal_height; rb->blur[0].texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); //the second one is smaller (only used for separatable part of blur) tf.width >>= 1; @@ -1522,8 +1526,8 @@ void RendererSceneRenderRD::_allocate_blur_textures(RenderBuffers *rb) { tf.mipmaps--; rb->blur[1].texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); - int base_width = rb->width; - int base_height = rb->height; + int base_width = rb->internal_width; + int base_height = rb->internal_height; for (uint32_t i = 0; i < mipmaps_required; i++) { RenderBuffers::Blur::Mipmap mm; @@ -1577,8 +1581,8 @@ void RendererSceneRenderRD::_allocate_blur_textures(RenderBuffers *rb) { // create 4 weight textures, 2 full size, 2 half size tf.format = RD::DATA_FORMAT_R16_SFLOAT; // We could probably use DATA_FORMAT_R8_SNORM if we don't pre-multiply by blur_size but that depends on whether we can remove DEPTH_GAP - tf.width = rb->width; - tf.height = rb->height; + tf.width = rb->internal_width; + tf.height = rb->internal_height; tf.texture_type = rb->view_count > 1 ? RD::TEXTURE_TYPE_2D_ARRAY : RD::TEXTURE_TYPE_2D; tf.array_layers = rb->view_count; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; @@ -1656,8 +1660,8 @@ void RendererSceneRenderRD::_allocate_depth_backbuffer_textures(RenderBuffers *r void RendererSceneRenderRD::_allocate_luminance_textures(RenderBuffers *rb) { ERR_FAIL_COND(!rb->luminance.current.is_null()); - int w = rb->width; - int h = rb->height; + int w = rb->internal_width; + int h = rb->internal_height; while (true) { w = MAX(w / 8, 1); @@ -1709,9 +1713,26 @@ void RendererSceneRenderRD::_free_render_buffer_data(RenderBuffers *rb) { rb->texture_fb = RID(); } - if (rb->texture.is_valid()) { - RD::get_singleton()->free(rb->texture); + if (rb->internal_texture == rb->texture && rb->internal_texture.is_valid()) { + RD::get_singleton()->free(rb->internal_texture); rb->texture = RID(); + rb->internal_texture = RID(); + rb->upscale_texture = RID(); + } else { + if (rb->texture.is_valid()) { + RD::get_singleton()->free(rb->texture); + rb->texture = RID(); + } + + if (rb->internal_texture.is_valid()) { + RD::get_singleton()->free(rb->internal_texture); + rb->internal_texture = RID(); + } + + if (rb->upscale_texture.is_valid()) { + RD::get_singleton()->free(rb->upscale_texture); + rb->upscale_texture = RID(); + } } if (rb->depth_texture.is_valid()) { @@ -1729,6 +1750,11 @@ void RendererSceneRenderRD::_free_render_buffer_data(RenderBuffers *rb) { rb->depth_back_texture = RID(); } + if (rb->sss_texture.is_valid()) { + RD::get_singleton()->free(rb->sss_texture); + rb->sss_texture = RID(); + } + for (int i = 0; i < 2; i++) { for (int m = 0; m < rb->blur[i].mipmaps.size(); m++) { // do we free the texture slice here? or is it enough to free the main texture? @@ -1818,7 +1844,7 @@ void RendererSceneRenderRD::_process_sss(RID p_render_buffers, const CameraMatri RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND(!rb); - bool can_use_effects = rb->width >= 8 && rb->height >= 8; + bool can_use_effects = rb->internal_width >= 8 && rb->internal_height >= 8; if (!can_use_effects) { //just copy @@ -1829,18 +1855,18 @@ void RendererSceneRenderRD::_process_sss(RID p_render_buffers, const CameraMatri _allocate_blur_textures(rb); } - storage->get_effects()->sub_surface_scattering(rb->texture, rb->blur[0].mipmaps[0].texture, rb->depth_texture, p_camera, Size2i(rb->width, rb->height), sss_scale, sss_depth_scale, sss_quality); + storage->get_effects()->sub_surface_scattering(rb->internal_texture, rb->sss_texture, rb->depth_texture, p_camera, Size2i(rb->internal_width, rb->internal_height), sss_scale, sss_depth_scale, sss_quality); } void RendererSceneRenderRD::_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) { RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND(!rb); - bool can_use_effects = rb->width >= 8 && rb->height >= 8; + bool can_use_effects = rb->internal_width >= 8 && rb->internal_height >= 8; if (!can_use_effects) { //just copy - storage->get_effects()->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->texture, RID()); + storage->get_effects()->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->internal_texture, RID()); return; } @@ -1852,8 +1878,8 @@ void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_frameb if (rb->ssr.depth_scaled.is_null()) { RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R32_SFLOAT; - tf.width = rb->width / 2; - tf.height = rb->height / 2; + tf.width = rb->internal_width / 2; + tf.height = rb->internal_height / 2; tf.texture_type = RD::TEXTURE_TYPE_2D; tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT; @@ -1867,8 +1893,8 @@ void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_frameb if (ssr_roughness_quality != RS::ENV_SSR_ROUGNESS_QUALITY_DISABLED && !rb->ssr.blur_radius[0].is_valid()) { RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R8_UNORM; - tf.width = rb->width / 2; - tf.height = rb->height / 2; + tf.width = rb->internal_width / 2; + tf.height = rb->internal_height / 2; tf.texture_type = RD::TEXTURE_TYPE_2D; tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; @@ -1880,8 +1906,8 @@ void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_frameb _allocate_blur_textures(rb); } - storage->get_effects()->screen_space_reflection(rb->texture, p_normal_buffer, ssr_roughness_quality, rb->ssr.blur_radius[0], rb->ssr.blur_radius[1], p_metallic, p_metallic_mask, rb->depth_texture, rb->ssr.depth_scaled, rb->ssr.normal_scaled, rb->blur[0].mipmaps[1].texture, rb->blur[1].mipmaps[0].texture, Size2i(rb->width / 2, rb->height / 2), env->ssr_max_steps, env->ssr_fade_in, env->ssr_fade_out, env->ssr_depth_tolerance, p_projection); - storage->get_effects()->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->texture, rb->blur[0].mipmaps[1].texture); + storage->get_effects()->screen_space_reflection(rb->internal_texture, p_normal_buffer, ssr_roughness_quality, rb->ssr.blur_radius[0], rb->ssr.blur_radius[1], p_metallic, p_metallic_mask, rb->depth_texture, rb->ssr.depth_scaled, rb->ssr.normal_scaled, rb->blur[0].mipmaps[1].texture, rb->blur[1].mipmaps[0].texture, Size2i(rb->internal_width / 2, rb->internal_height / 2), env->ssr_max_steps, env->ssr_fade_in, env->ssr_fade_out, env->ssr_depth_tolerance, p_projection); + storage->get_effects()->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->internal_texture, rb->blur[0].mipmaps[1].texture); } void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection) { @@ -1918,15 +1944,15 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen int half_width; int half_height; if (ssao_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; + buffer_width = (rb->internal_width + 3) / 4; + buffer_height = (rb->internal_height + 3) / 4; + half_width = (rb->internal_width + 7) / 8; + half_height = (rb->internal_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; + buffer_width = (rb->internal_width + 1) / 2; + buffer_height = (rb->internal_height + 1) / 2; + half_width = (rb->internal_width + 3) / 4; + half_height = (rb->internal_height + 3) / 4; } bool uniform_sets_are_invalid = false; if (rb->ssao.depth.is_null()) { @@ -1998,8 +2024,8 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen { RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R8_UNORM; - tf.width = rb->width; - tf.height = rb->height; + 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"); @@ -2022,7 +2048,7 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen settings.blur_passes = ssao_blur_passes; settings.fadeout_from = ssao_fadeout_from; settings.fadeout_to = ssao_fadeout_to; - settings.full_screen_size = Size2i(rb->width, rb->height); + settings.full_screen_size = Size2i(rb->internal_width, rb->internal_height); settings.half_screen_size = Size2i(buffer_width, buffer_height); settings.quarter_screen_size = Size2i(half_width, half_height); @@ -2102,9 +2128,9 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende EffectsRD::BokehBuffers buffers; - // Textures we use. - buffers.base_texture_size = Size2i(rb->width, rb->height); - buffers.base_texture = rb->texture; + // Textures we use + buffers.base_texture_size = Size2i(rb->internal_width, rb->internal_height); + buffers.base_texture = rb->internal_texture; buffers.depth_texture = rb->depth_texture; buffers.secondary_texture = rb->blur[0].mipmaps[0].texture; buffers.half_texture[0] = rb->blur[1].mipmaps[0].texture; @@ -2143,9 +2169,9 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende double step = env->auto_exp_speed * time_step; if (can_use_storage) { - storage->get_effects()->luminance_reduction(rb->texture, Size2i(rb->width, rb->height), rb->luminance.reduce, rb->luminance.current, env->min_luminance, env->max_luminance, step, set_immediate); + storage->get_effects()->luminance_reduction(rb->internal_texture, Size2i(rb->internal_width, rb->internal_height), rb->luminance.reduce, rb->luminance.current, env->min_luminance, env->max_luminance, step, set_immediate); } else { - storage->get_effects()->luminance_reduction_raster(rb->texture, Size2i(rb->width, rb->height), rb->luminance.reduce, rb->luminance.fb, rb->luminance.current, env->min_luminance, env->max_luminance, step, set_immediate); + storage->get_effects()->luminance_reduction_raster(rb->internal_texture, Size2i(rb->internal_width, rb->internal_height), rb->luminance.reduce, rb->luminance.fb, rb->luminance.current, env->min_luminance, env->max_luminance, step, set_immediate); } // Swap final reduce with prev luminance. SWAP(rb->luminance.current, rb->luminance.reduce.write[rb->luminance.reduce.size() - 1]); @@ -2188,9 +2214,9 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende luminance_texture = rb->luminance.current; } if (can_use_storage) { - storage->get_effects()->gaussian_glow(rb->texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale); + storage->get_effects()->gaussian_glow(rb->internal_texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale); } else { - storage->get_effects()->gaussian_glow_raster(rb->texture, rb->blur[1].mipmaps[i].half_fb, rb->blur[1].mipmaps[i].half_texture, rb->blur[1].mipmaps[i].fb, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale); + storage->get_effects()->gaussian_glow_raster(rb->internal_texture, rb->blur[1].mipmaps[i].half_fb, rb->blur[1].mipmaps[i].half_texture, rb->blur[1].mipmaps[i].fb, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale); } } else { if (can_use_storage) { @@ -2237,7 +2263,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende } tonemap.use_debanding = rb->use_debanding; - tonemap.texture_size = Vector2i(rb->width, rb->height); + tonemap.texture_size = Vector2i(rb->internal_width, rb->internal_height); if (env) { tonemap.tonemap_mode = env->tone_mapper; @@ -2268,7 +2294,15 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende tonemap.luminance_multiplier = _render_buffers_get_luminance_multiplier(); tonemap.view_count = p_render_data->view_count; - storage->get_effects()->tonemapper(rb->texture, storage->render_target_get_rd_framebuffer(rb->render_target), tonemap); + storage->get_effects()->tonemapper(rb->internal_texture, storage->render_target_get_rd_framebuffer(rb->render_target), tonemap); + + RD::get_singleton()->draw_command_end_label(); + } + + if (can_use_effects && can_use_storage && (rb->internal_width != rb->width || rb->internal_height != rb->height)) { + RD::get_singleton()->draw_command_begin_label("FSR Upscale"); + + storage->get_effects()->fsr_upscale(rb->internal_texture, rb->upscale_texture, rb->texture, Size2i(rb->internal_width, rb->internal_height), Size2i(rb->width, rb->height), rb->fsr_sharpness); RD::get_singleton()->draw_command_end_label(); } @@ -2628,14 +2662,28 @@ bool RendererSceneRenderRD::_render_buffers_can_be_storage() { return true; } -void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) { +void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) { ERR_FAIL_COND_MSG(p_view_count == 0, "Must have at least 1 view"); + if (!_render_buffers_can_be_storage()) { + p_internal_height = p_height; + p_internal_width = p_width; + } + + if (p_width != p_internal_width) { + float fsr_mipmap_bias = -log2f(p_width / p_internal_width) + p_fsr_mipmap_bias; + storage->sampler_rd_configure_custom(fsr_mipmap_bias); + update_uniform_sets(); + } + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); // Should we add an overrule per viewport? + rb->internal_width = p_internal_width; + rb->internal_height = p_internal_height; rb->width = p_width; rb->height = p_height; + rb->fsr_sharpness = p_fsr_sharpness; rb->render_target = p_render_target; rb->msaa = p_msaa; rb->screen_space_aa = p_screen_space_aa; @@ -2657,8 +2705,8 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; } tf.format = _render_buffers_get_color_format(); - tf.width = rb->width; - tf.height = rb->height; + tf.width = rb->internal_width; // If set to rb->width, msaa won't crash + tf.height = rb->internal_height; // If set to rb->width, msaa won't crash tf.array_layers = rb->view_count; // create a layer for every view tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | (_render_buffers_can_be_storage() ? RD::TEXTURE_USAGE_STORAGE_BIT : 0) | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) { @@ -2666,7 +2714,17 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p } tf.usage_bits |= RD::TEXTURE_USAGE_INPUT_ATTACHMENT_BIT; // only needed when using subpasses in the mobile renderer - rb->texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); + rb->internal_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + if ((p_internal_width != p_width || p_internal_height != p_height)) { + tf.width = rb->width; + tf.height = rb->height; + rb->texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); + rb->upscale_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); + } else { + rb->texture = rb->internal_texture; + rb->upscale_texture = rb->internal_texture; + } } { @@ -2680,8 +2738,8 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p tf.format = RD::DATA_FORMAT_R32_SFLOAT; } - tf.width = rb->width; - tf.height = rb->height; + tf.width = rb->internal_width; + tf.height = rb->internal_height; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT; tf.array_layers = rb->view_count; // create a layer for every view @@ -2697,16 +2755,16 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p if (!_render_buffers_can_be_storage()) { // ONLY USED ON MOBILE RENDERER, ONLY USED FOR POST EFFECTS! Vector fb; - fb.push_back(rb->texture); + fb.push_back(rb->internal_texture); rb->texture_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, rb->view_count); } RID target_texture = storage->render_target_get_rd_texture(rb->render_target); - rb->data->configure(rb->texture, rb->depth_texture, target_texture, rb->width, rb->height, p_msaa, p_view_count); + rb->data->configure(rb->internal_texture, rb->depth_texture, target_texture, p_internal_width, p_internal_height, p_msaa, p_view_count); if (is_clustered_enabled()) { - rb->cluster_builder->setup(Size2i(rb->width, rb->height), max_cluster_elements, rb->depth_texture, storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED), rb->texture); + rb->cluster_builder->setup(Size2i(p_internal_width, p_internal_height), max_cluster_elements, rb->depth_texture, storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED), rb->internal_texture); } } @@ -4704,9 +4762,7 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData if (p_render_buffers.is_valid()) { /* _debug_draw_cluster(p_render_buffers); - RENDER_TIMESTAMP("Tonemap"); - _render_buffers_post_process_and_tonemap(&render_data); */ diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 740e0e75ce..98ab1a2c3c 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -456,7 +456,11 @@ private: struct RenderBuffers { RenderBufferData *data = nullptr; - int width = 0, height = 0; + int internal_width = 0; + int internal_height = 0; + int width = 0; + int height = 0; + float fsr_sharpness = 0.2f; RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED; RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED; bool use_debanding = false; @@ -466,9 +470,12 @@ private: uint64_t auto_exposure_version = 1; - RID texture; //main texture for rendering to, must be filled after done rendering + RID sss_texture; //texture for sss. This needs to be a different resolution than blur[0] + RID internal_texture; //main texture for rendering to, must be filled after done rendering + RID texture; //upscaled version of main texture (This uses the same resource as internal_texture if there is no upscaling) RID depth_texture; //main depth texture RID texture_fb; // framebuffer for the main texture, ONLY USED FOR MOBILE RENDERER POST EFFECTS, DO NOT USE FOR RENDERING 3D!!! + RID upscale_texture; //used when upscaling internal_texture (This uses the same resource as internal_texture if there is no upscaling) RendererSceneGIRD::SDFGI *sdfgi = nullptr; VolumetricFog *volumetric_fog = nullptr; @@ -1332,7 +1339,7 @@ public: virtual RD::DataFormat _render_buffers_get_color_format(); virtual bool _render_buffers_can_be_storage(); virtual RID render_buffers_create() override; - virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) override; + virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) override; virtual void gi_set_use_half_resolution(bool p_enable) override; RID render_buffers_get_depth_texture(RID p_render_buffers); @@ -1363,6 +1370,8 @@ public: float render_buffers_get_volumetric_fog_end(RID p_render_buffers); float render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers); + virtual void update_uniform_sets(){}; + virtual void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray &p_instances, const PagedArray &p_lights, const PagedArray &p_reflection_probes, const PagedArray &p_voxel_gi_instances, const PagedArray &p_decals, const PagedArray &p_lightmaps, const PagedArray &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) override; virtual void render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray &p_instances, RID p_framebuffer, const Rect2i &p_region) override; diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index 04753d7a9b..04acc871b4 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp @@ -1227,6 +1227,100 @@ RendererStorageRD::CanvasTexture::~CanvasTexture() { clear_sets(); } +void RendererStorageRD::sampler_rd_configure_custom(float p_mipmap_bias) { + for (int i = 1; i < RS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) { + for (int j = 1; j < RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) { + RD::SamplerState sampler_state; + switch (i) { + case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST: { + sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST; + sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST; + sampler_state.max_lod = 0; + } break; + case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR: { + sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR; + sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR; + sampler_state.max_lod = 0; + } break; + case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: { + sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST; + sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST; + if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) { + sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST; + } else { + sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR; + } + sampler_state.lod_bias = p_mipmap_bias; + } break; + case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: { + sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR; + sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR; + if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) { + sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST; + } else { + sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR; + } + sampler_state.lod_bias = p_mipmap_bias; + + } break; + case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC: { + sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST; + sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST; + if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) { + sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST; + } else { + sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR; + } + sampler_state.lod_bias = p_mipmap_bias; + sampler_state.use_anisotropy = true; + sampler_state.anisotropy_max = 1 << int(GLOBAL_GET("rendering/textures/default_filters/anisotropic_filtering_level")); + } break; + case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC: { + sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR; + sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR; + if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) { + sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST; + } else { + sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR; + } + sampler_state.lod_bias = p_mipmap_bias; + sampler_state.use_anisotropy = true; + sampler_state.anisotropy_max = 1 << int(GLOBAL_GET("rendering/textures/default_filters/anisotropic_filtering_level")); + + } break; + default: { + } + } + switch (j) { + case RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED: { + sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE; + sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE; + sampler_state.repeat_w = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE; + + } break; + case RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: { + sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_REPEAT; + sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_REPEAT; + sampler_state.repeat_w = RD::SAMPLER_REPEAT_MODE_REPEAT; + } break; + case RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: { + sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; + sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; + sampler_state.repeat_w = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; + } break; + default: { + } + } + + if (custom_rd_samplers[i][j].is_valid()) { + RD::get_singleton()->free(custom_rd_samplers[i][j]); + } + + custom_rd_samplers[i][j] = RD::get_singleton()->sampler_create(sampler_state); + } + } +} + RID RendererStorageRD::canvas_texture_allocate() { return canvas_texture_owner.allocate_rid(); } @@ -9774,6 +9868,9 @@ RendererStorageRD::RendererStorageRD() { } } + //custom sampler + sampler_rd_configure_custom(0.0f); + //default rd buffers { Vector buffer; @@ -10104,6 +10201,15 @@ RendererStorageRD::~RendererStorageRD() { } } + //custom samplers + for (int i = 1; i < RS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) { + for (int j = 0; j < RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) { + if (custom_rd_samplers[i][j].is_valid()) { + RD::get_singleton()->free(custom_rd_samplers[i][j]); + } + } + } + //def buffers for (int i = 0; i < DEFAULT_RD_BUFFER_MAX; i++) { RD::get_singleton()->free(mesh_default_rd_buffers[i]); diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h index 2cd3a01c66..9a64480c3e 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.h +++ b/servers/rendering/renderer_rd/renderer_storage_rd.h @@ -320,6 +320,7 @@ private: RID default_rd_textures[DEFAULT_RD_TEXTURE_MAX]; RID default_rd_samplers[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX]; + RID custom_rd_samplers[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX]; RID default_rd_storage_buffer; /* DECAL ATLAS */ @@ -1391,6 +1392,13 @@ public: _FORCE_INLINE_ RID sampler_rd_get_default(RS::CanvasItemTextureFilter p_filter, RS::CanvasItemTextureRepeat p_repeat) { return default_rd_samplers[p_filter][p_repeat]; } + _FORCE_INLINE_ RID sampler_rd_get_custom(RS::CanvasItemTextureFilter p_filter, RS::CanvasItemTextureRepeat p_repeat) { + return custom_rd_samplers[p_filter][p_repeat]; + } + + void sampler_rd_configure_custom(float mipmap_bias); + + void sampler_rd_set_default(float p_mipmap_bias); /* CANVAS TEXTURE API */ diff --git a/servers/rendering/renderer_rd/shaders/fsr_upscale.glsl b/servers/rendering/renderer_rd/shaders/fsr_upscale.glsl new file mode 100644 index 0000000000..4e2ba84033 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/fsr_upscale.glsl @@ -0,0 +1,173 @@ +/*************************************************************************/ +/* fsr_upscale.glsl */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ +/* "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. */ +/*************************************************************************/ + +#[compute] + +#version 450 + +#VERSION_DEFINES + +#define A_GPU +#define A_GLSL + +#ifdef MODE_FSR_UPSCALE_NORMAL + +#define A_HALF + +#endif + +#include "thirdparty/amd-fsr/ffx_a.h" + +layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; + +layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly image2D fsr_image; +layout(set = 0, binding = 0) uniform sampler2D source_image; + +#define FSR_UPSCALE_PASS_TYPE_EASU 0 +#define FSR_UPSCALE_PASS_TYPE_RCAS 1 + +layout(push_constant, binding = 1, std430) uniform Params { + float resolution_width; + float resolution_height; + float upscaled_width; + float upscaled_height; + float sharpness; + int pass; +} +params; + +AU4 Const0, Const1, Const2, Const3; + +#ifdef MODE_FSR_UPSCALE_FALLBACK + +#define FSR_EASU_F +AF4 FsrEasuRF(AF2 p) { + AF4 res = textureGather(source_image, p, 0); + return res; +} +AF4 FsrEasuGF(AF2 p) { + AF4 res = textureGather(source_image, p, 1); + return res; +} +AF4 FsrEasuBF(AF2 p) { + AF4 res = textureGather(source_image, p, 2); + return res; +} + +#define FSR_RCAS_F +AF4 FsrRcasLoadF(ASU2 p) { + return AF4(texelFetch(source_image, ASU2(p), 0)); +} +void FsrRcasInputF(inout AF1 r, inout AF1 g, inout AF1 b) {} + +#else + +#define FSR_EASU_H +AH4 FsrEasuRH(AF2 p) { + AH4 res = AH4(textureGather(source_image, p, 0)); + return res; +} +AH4 FsrEasuGH(AF2 p) { + AH4 res = AH4(textureGather(source_image, p, 1)); + return res; +} +AH4 FsrEasuBH(AF2 p) { + AH4 res = AH4(textureGather(source_image, p, 2)); + return res; +} + +#define FSR_RCAS_H +AH4 FsrRcasLoadH(ASW2 p) { + return AH4(texelFetch(source_image, ASU2(p), 0)); +} +void FsrRcasInputH(inout AH1 r, inout AH1 g, inout AH1 b) {} + +#endif + +#include "thirdparty/amd-fsr/ffx_fsr1.h" + +void fsr_easu_pass(AU2 pos) { +#ifdef MODE_FSR_UPSCALE_NORMAL + + AH3 Gamma2Color = AH3(0, 0, 0); + FsrEasuH(Gamma2Color, pos, Const0, Const1, Const2, Const3); + imageStore(fsr_image, ASU2(pos), AH4(Gamma2Color, 1)); + +#else + + AF3 Gamma2Color = AF3(0, 0, 0); + FsrEasuF(Gamma2Color, pos, Const0, Const1, Const2, Const3); + imageStore(fsr_image, ASU2(pos), AF4(Gamma2Color, 1)); + +#endif +} + +void fsr_rcas_pass(AU2 pos) { +#ifdef MODE_FSR_UPSCALE_NORMAL + + AH3 Gamma2Color = AH3(0, 0, 0); + FsrRcasH(Gamma2Color.r, Gamma2Color.g, Gamma2Color.b, pos, Const0); + imageStore(fsr_image, ASU2(pos), AH4(Gamma2Color, 1)); + +#else + + AF3 Gamma2Color = AF3(0, 0, 0); + FsrRcasF(Gamma2Color.r, Gamma2Color.g, Gamma2Color.b, pos, Const0); + imageStore(fsr_image, ASU2(pos), AF4(Gamma2Color, 1)); + +#endif +} + +void fsr_pass(AU2 pos) { + if (params.pass == FSR_UPSCALE_PASS_TYPE_EASU) { + fsr_easu_pass(pos); + } else if (params.pass == FSR_UPSCALE_PASS_TYPE_RCAS) { + fsr_rcas_pass(pos); + } +} + +void main() { + // Clang does not like unused functions. If ffx_a.h is included in the binary, clang will throw a fit and not compile so we must configure FSR in this shader + if (params.pass == FSR_UPSCALE_PASS_TYPE_EASU) { + FsrEasuCon(Const0, Const1, Const2, Const3, params.resolution_width, params.resolution_height, params.resolution_width, params.resolution_height, params.upscaled_width, params.upscaled_height); + } else if (params.pass == FSR_UPSCALE_PASS_TYPE_RCAS) { + FsrRcasCon(Const0, params.sharpness); + } + + AU2 gxy = ARmp8x8(gl_LocalInvocationID.x) + AU2(gl_WorkGroupID.x << 4u, gl_WorkGroupID.y << 4u); + + fsr_pass(gxy); + gxy.x += 8u; + fsr_pass(gxy); + gxy.y += 8u; + fsr_pass(gxy); + gxy.x -= 8u; + fsr_pass(gxy); +} diff --git a/servers/rendering/renderer_scene.h b/servers/rendering/renderer_scene.h index b6e99e4be5..02c845581c 100644 --- a/servers/rendering/renderer_scene.h +++ b/servers/rendering/renderer_scene.h @@ -191,7 +191,7 @@ public: virtual RID render_buffers_create() = 0; - virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) = 0; + virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) = 0; virtual void gi_set_use_half_resolution(bool p_enable) = 0; diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index 2bfcfd462c..e51a1fc02e 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -1155,7 +1155,7 @@ public: /* Render Buffers */ PASS0R(RID, render_buffers_create) - PASS8(render_buffers_configure, RID, RID, int, int, RS::ViewportMSAA, RS::ViewportScreenSpaceAA, bool, uint32_t) + PASS12(render_buffers_configure, RID, RID, int, int, int, int, float, float, RS::ViewportMSAA, RS::ViewportScreenSpaceAA, bool, uint32_t) PASS1(gi_set_use_half_resolution, bool) /* Shadow Atlas */ diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h index 200ddc55d4..0d71ea22da 100644 --- a/servers/rendering/renderer_scene_render.h +++ b/servers/rendering/renderer_scene_render.h @@ -256,7 +256,7 @@ public: virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) = 0; virtual RID render_buffers_create() = 0; - virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) = 0; + virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) = 0; virtual void gi_set_use_half_resolution(bool p_enable) = 0; virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_limit) = 0; diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index c3d57a13ad..8a14834569 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -77,18 +77,69 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) { RSG::scene->free(p_viewport->render_buffers); p_viewport->render_buffers = RID(); } else { - float scale_3d = p_viewport->scale_3d; - if (Engine::get_singleton()->is_editor_hint()) { - // Ignore the 3D viewport render scaling inside of the editor. - // The Half Resolution 3D editor viewport option should be used instead. - scale_3d = 1.0; + float scaling_3d_scale = p_viewport->scaling_3d_scale; + + RS::ViewportScaling3DMode scaling_3d_mode = p_viewport->scaling_3d_mode; + bool scaling_enabled = true; + + if ((scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR) && (scaling_3d_scale > 1.0)) { + // FSR is not design for downsampling. + // Throw a warning and fallback to VIEWPORT_SCALING_3D_MODE_BILINEAR + print_error("FSR does not support supersampling. Falling back to bilinear mode."); + scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_BILINEAR; } - // Clamp 3D rendering resolution to reasonable values supported on most hardware. - // This prevents freezing the engine or outright crashing on lower-end GPUs. - const int width = CLAMP(p_viewport->size.width * scale_3d, 1, 16384); - const int height = CLAMP(p_viewport->size.height * scale_3d, 1, 16384); - RSG::scene->render_buffers_configure(p_viewport->render_buffers, p_viewport->render_target, width, height, p_viewport->msaa, p_viewport->screen_space_aa, p_viewport->use_debanding, p_viewport->get_view_count()); + if ((scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR) && !p_viewport->fsr_enabled) { + // FSR is not actually available. + // Throw a warning and fallback to disable scaling + print_error("FSR is not available. Disabled FSR scaling 3D. Try bilinear mode."); + scaling_enabled = false; + } + + if (scaling_3d_scale == 1.0) { + scaling_enabled = false; + } + + int width; + int height; + int render_width; + int render_height; + + if (scaling_enabled) { + switch (scaling_3d_mode) { + case RS::VIEWPORT_SCALING_3D_MODE_BILINEAR: + // Clamp 3D rendering resolution to reasonable values supported on most hardware. + // This prevents freezing the engine or outright crashing on lower-end GPUs. + width = CLAMP(p_viewport->size.width * scaling_3d_scale, 1, 16384); + height = CLAMP(p_viewport->size.height * scaling_3d_scale, 1, 16384); + render_width = width; + render_height = height; + break; + case RS::VIEWPORT_SCALING_3D_MODE_FSR: + width = p_viewport->size.width; + height = p_viewport->size.height; + render_width = MAX(width * scaling_3d_scale, 1.0); // width / (width * scaling) + render_height = MAX(height * scaling_3d_scale, 1.0); + break; + default: + // This is an unknown mode. + print_error(vformat("Unknown scaling mode: %d, disabling scaling 3D", scaling_3d_mode)); + width = p_viewport->size.width; + height = p_viewport->size.height; + render_width = width; + render_height = height; + break; + } + } else { + width = p_viewport->size.width; + height = p_viewport->size.height; + render_width = width; + render_height = height; + } + + p_viewport->internal_size = Size2(render_width, render_height); + + RSG::scene->render_buffers_configure(p_viewport->render_buffers, p_viewport->render_target, render_width, render_height, width, height, p_viewport->fsr_sharpness, p_viewport->fsr_mipmap_bias, p_viewport->msaa, p_viewport->screen_space_aa, p_viewport->use_debanding, p_viewport->get_view_count()); } } } @@ -117,7 +168,7 @@ void RendererViewport::_draw_3d(Viewport *p_viewport) { } float screen_lod_threshold = p_viewport->lod_threshold / float(p_viewport->size.width); - RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->self, p_viewport->size, screen_lod_threshold, p_viewport->shadow_atlas, xr_interface, &p_viewport->render_info); + RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->self, p_viewport->internal_size, screen_lod_threshold, p_viewport->shadow_atlas, xr_interface, &p_viewport->render_info); RENDER_TIMESTAMP("size = xr_interface->get_render_target_size(); uint32_t view_count = xr_interface->get_view_count(); - RSG::storage->render_target_set_size(vp->render_target, vp->size.x, vp->size.y, view_count); + RSG::storage->render_target_set_size(vp->render_target, vp->internal_size.x, vp->internal_size.y, view_count); // check for an external texture destination (disabled for now, not yet supported) // RSG::storage->render_target_set_external_texture(vp->render_target, xr_interface->get_external_texture_for_eye(leftOrMono)); @@ -662,6 +713,8 @@ void RendererViewport::viewport_initialize(RID p_rid) { viewport->render_target = RSG::storage->render_target_create(); viewport->shadow_atlas = RSG::scene->shadow_atlas_create(); viewport->viewport_render_direct_to_screen = false; + + viewport->fsr_enabled = !RSG::rasterizer->is_low_end() && !viewport->disable_3d; } void RendererViewport::viewport_set_use_xr(RID p_viewport, bool p_use_xr) { @@ -676,18 +729,42 @@ void RendererViewport::viewport_set_use_xr(RID p_viewport, bool p_use_xr) { _configure_3d_render_buffers(viewport); } -void RendererViewport::viewport_set_scale_3d(RID p_viewport, float p_scale_3d) { +void RendererViewport::viewport_set_scaling_3d_mode(RID p_viewport, RS::ViewportScaling3DMode p_mode) { + Viewport *viewport = viewport_owner.get_or_null(p_viewport); + ERR_FAIL_COND(!viewport); + + viewport->scaling_3d_mode = p_mode; + _configure_3d_render_buffers(viewport); +} + +void RendererViewport::viewport_set_fsr_sharpness(RID p_viewport, float p_sharpness) { + Viewport *viewport = viewport_owner.get_or_null(p_viewport); + ERR_FAIL_COND(!viewport); + + viewport->fsr_sharpness = p_sharpness; + _configure_3d_render_buffers(viewport); +} + +void RendererViewport::viewport_set_fsr_mipmap_bias(RID p_viewport, float p_mipmap_bias) { + Viewport *viewport = viewport_owner.get_or_null(p_viewport); + ERR_FAIL_COND(!viewport); + + viewport->fsr_mipmap_bias = p_mipmap_bias; + _configure_3d_render_buffers(viewport); +} + +void RendererViewport::viewport_set_scaling_3d_scale(RID p_viewport, float p_scaling_3d_scale) { Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); // Clamp to reasonable values that are actually useful. // Values above 2.0 don't serve a practical purpose since the viewport // isn't displayed with mipmaps. - if (viewport->scale_3d == CLAMP(p_scale_3d, 0.1, 2.0)) { + if (viewport->scaling_3d_scale == CLAMP(p_scaling_3d_scale, 0.1, 2.0)) { return; } - viewport->scale_3d = CLAMP(p_scale_3d, 0.1, 2.0); + viewport->scaling_3d_scale = CLAMP(p_scaling_3d_scale, 0.1, 2.0); _configure_3d_render_buffers(viewport); } @@ -713,6 +790,7 @@ void RendererViewport::viewport_set_size(RID p_viewport, int p_width, int p_heig ERR_FAIL_COND(!viewport); viewport->size = Size2(p_width, p_height); + uint32_t view_count = viewport->get_view_count(); RSG::storage->render_target_set_size(viewport->render_target, p_width, p_height, view_count); _configure_3d_render_buffers(viewport); @@ -765,7 +843,7 @@ void RendererViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_ // if render_direct_to_screen was used, reset size and position if (RSG::rasterizer->is_low_end() && viewport->viewport_render_direct_to_screen) { RSG::storage->render_target_set_position(viewport->render_target, 0, 0); - RSG::storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->get_view_count()); + RSG::storage->render_target_set_size(viewport->render_target, viewport->internal_size.x, viewport->internal_size.y, viewport->get_view_count()); } viewport->viewport_to_screen_rect = Rect2(); diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h index f6e6cc8e84..5bb4dbbc6f 100644 --- a/servers/rendering/renderer_viewport.h +++ b/servers/rendering/renderer_viewport.h @@ -49,12 +49,16 @@ public: bool use_xr; /* use xr interface to override camera positioning and projection matrices and control output */ - float scale_3d = 1.0; - + Size2i internal_size; Size2i size; RID camera; RID scenario; + RS::ViewportScaling3DMode scaling_3d_mode; + float scaling_3d_scale = 1.0; + float fsr_sharpness = 0.2f; + float fsr_mipmap_bias = 0.0f; + bool fsr_enabled; RS::ViewportUpdateMode update_mode; RID render_target; RID render_target_texture; @@ -207,7 +211,6 @@ public: void viewport_initialize(RID p_rid); void viewport_set_use_xr(RID p_viewport, bool p_use_xr); - void viewport_set_scale_3d(RID p_viewport, float p_scale_3d); void viewport_set_size(RID p_viewport, int p_width, int p_height); @@ -216,6 +219,12 @@ public: void viewport_set_active(RID p_viewport, bool p_active); void viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport); + + void viewport_set_scaling_3d_mode(RID p_viewport, RS::ViewportScaling3DMode p_mode); + void viewport_set_scaling_3d_scale(RID p_viewport, float p_scaling_3d_scale); + void viewport_set_fsr_sharpness(RID p_viewport, float p_sharpness); + void viewport_set_fsr_mipmap_bias(RID p_viewport, float p_mipmap_bias); + void viewport_set_update_mode(RID p_viewport, RS::ViewportUpdateMode p_mode); void viewport_set_vflip(RID p_viewport, bool p_enable); diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index 5eb8f1cead..563a80c12c 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -120,6 +120,7 @@ public: // features bool supports_multiview = false; // If true this device supports multiview options + bool supports_fsr_half_float = false; // If true this device supports FSR scaling 3D in half float mode, otherwise use the fallback mode }; typedef String (*ShaderSPIRVGetCacheKeyFunction)(const Capabilities *p_capabilities); diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index f75bca600e..b50631bb21 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -528,7 +528,6 @@ public: FUNCRIDSPLIT(viewport) FUNC2(viewport_set_use_xr, RID, bool) - FUNC2(viewport_set_scale_3d, RID, float) FUNC3(viewport_set_size, RID, int, int) FUNC2(viewport_set_active, RID, bool) @@ -539,6 +538,11 @@ public: FUNC3(viewport_attach_to_screen, RID, const Rect2 &, int) FUNC2(viewport_set_render_direct_to_screen, RID, bool) + FUNC2(viewport_set_scaling_3d_mode, RID, ViewportScaling3DMode) + FUNC2(viewport_set_scaling_3d_scale, RID, float) + FUNC2(viewport_set_fsr_sharpness, RID, float) + FUNC2(viewport_set_fsr_mipmap_bias, RID, float) + FUNC2(viewport_set_update_mode, RID, ViewportUpdateMode) FUNC1RC(RID, viewport_get_texture, RID) -- cgit v1.2.3