diff options
Diffstat (limited to 'servers')
30 files changed, 940 insertions, 251 deletions
diff --git a/servers/rendering/dummy/storage/texture_storage.h b/servers/rendering/dummy/storage/texture_storage.h index fe10f6489c..195d378a41 100644 --- a/servers/rendering/dummy/storage/texture_storage.h +++ b/servers/rendering/dummy/storage/texture_storage.h @@ -169,6 +169,9 @@ public: virtual void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) override {} virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const override { return Rect2i(); } virtual void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) override {} + + virtual void render_target_set_vrs_mode(RID p_render_target, RS::ViewportVRSMode p_mode) override{}; + virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) override{}; }; } // namespace RendererDummy diff --git a/servers/rendering/renderer_rd/effects/copy_effects.cpp b/servers/rendering/renderer_rd/effects/copy_effects.cpp index c30e8ed58f..cbf7046887 100644 --- a/servers/rendering/renderer_rd/effects/copy_effects.cpp +++ b/servers/rendering/renderer_rd/effects/copy_effects.cpp @@ -100,11 +100,11 @@ CopyEffects::CopyEffects(bool p_prefer_raster_effects) { { Vector<String> copy_modes; - copy_modes.push_back("\n"); - copy_modes.push_back("\n#define MODE_PANORAMA_TO_DP\n"); - copy_modes.push_back("\n#define MODE_TWO_SOURCES\n"); - copy_modes.push_back("\n#define MULTIVIEW\n"); - copy_modes.push_back("\n#define MULTIVIEW\n#define MODE_TWO_SOURCES\n"); + copy_modes.push_back("\n"); // COPY_TO_FB_COPY + copy_modes.push_back("\n#define MODE_PANORAMA_TO_DP\n"); // COPY_TO_FB_COPY_PANORAMA_TO_DP + copy_modes.push_back("\n#define MODE_TWO_SOURCES\n"); // COPY_TO_FB_COPY2 + copy_modes.push_back("\n#define MULTIVIEW\n"); // COPY_TO_FB_MULTIVIEW + copy_modes.push_back("\n#define MULTIVIEW\n#define MODE_TWO_SOURCES\n"); // COPY_TO_FB_MULTIVIEW_WITH_DEPTH copy_to_fb.shader.initialize(copy_modes); diff --git a/servers/rendering/renderer_rd/effects/vrs.cpp b/servers/rendering/renderer_rd/effects/vrs.cpp new file mode 100644 index 0000000000..505a35a269 --- /dev/null +++ b/servers/rendering/renderer_rd/effects/vrs.cpp @@ -0,0 +1,171 @@ +/*************************************************************************/ +/* vrs.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* 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 */ +/* "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. */ +/*************************************************************************/ + +#include "vrs.h" +#include "../renderer_compositor_rd.h" +#include "../storage_rd/texture_storage.h" +#include "../uniform_set_cache_rd.h" +#include "servers/xr_server.h" + +using namespace RendererRD; + +VRS::VRS() { + { + Vector<String> vrs_modes; + vrs_modes.push_back("\n"); // VRS_DEFAULT + vrs_modes.push_back("\n#define MULTIVIEW\n"); // VRS_MULTIVIEW + + vrs_shader.shader.initialize(vrs_modes); + + if (!RendererCompositorRD::singleton->is_xr_enabled()) { + vrs_shader.shader.set_variant_enabled(VRS_MULTIVIEW, false); + } + + vrs_shader.shader_version = vrs_shader.shader.version_create(); + + //use additive + + for (int i = 0; i < VRS_MAX; i++) { + if (vrs_shader.shader.is_variant_enabled(i)) { + vrs_shader.pipelines[i].setup(vrs_shader.shader.version_get_shader(vrs_shader.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); + } else { + vrs_shader.pipelines[i].clear(); + } + } + } +} + +VRS::~VRS() { + vrs_shader.shader.version_free(vrs_shader.shader_version); +} + +void VRS::copy_vrs(RID p_source_rd_texture, RID p_dest_framebuffer, bool p_multiview) { + UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); + ERR_FAIL_NULL(uniform_set_cache); + MaterialStorage *material_storage = MaterialStorage::get_singleton(); + ERR_FAIL_NULL(material_storage); + + // setup our uniforms + RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + + RD::Uniform u_source_rd_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_rd_texture })); + + VRSMode mode = p_multiview ? VRS_MULTIVIEW : VRS_DEFAULT; + + RID shader = vrs_shader.shader.version_get_shader(vrs_shader.shader_version, mode); + ERR_FAIL_COND(shader.is_null()); + + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>()); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, vrs_shader.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0); + RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array()); + // RD::get_singleton()->draw_list_set_push_constant(draw_list, &vrs_shader.push_constant, sizeof(VRSPushConstant)); + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); +} + +void VRS::create_vrs_texture(const int p_base_width, const int p_base_height, const uint32_t p_view_count, RID &p_vrs_texture, RID &p_vrs_fb) { + // TODO find a way to skip this if VRS is not supported, but we don't have access to VulkanContext here, even though we're in vulkan.. hmmm + + // TODO we should find some way to store this properly, we're assuming 16x16 as this seems to be the standard but in our vrs_capacities we + // obtain a minimum and maximum size, and we should choose something within this range and then make sure that is consistantly set when creating + // our frame buffer. Also it is important that we make the resulting size we calculate down below available to the end user so they know the size + // of the VRS buffer to supply. + Size2i texel_size = Size2i(16, 16); + + RD::TextureFormat tf; + if (p_view_count > 1) { + tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; + } else { + tf.texture_type = RD::TEXTURE_TYPE_2D; + } + tf.format = RD::DATA_FORMAT_R8_UINT; + tf.width = p_base_width / texel_size.x; + if (p_base_width % texel_size.x != 0) { + tf.width++; + } + tf.height = p_base_height / texel_size.y; + if (p_base_height % texel_size.y != 0) { + tf.height++; + } + tf.array_layers = p_view_count; // create a layer for every view + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_VRS_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + tf.samples = RD::TEXTURE_SAMPLES_1; + + p_vrs_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + // by default VRS is assumed to be our VRS attachment, but if we need to write into it, we need a bit more control + Vector<RID> fb; + fb.push_back(p_vrs_texture); + + RD::FramebufferPass pass; + pass.color_attachments.push_back(0); + + Vector<RD::FramebufferPass> passes; + passes.push_back(pass); + + p_vrs_fb = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, p_view_count); +} + +void VRS::update_vrs_texture(RID p_vrs_fb, RID p_render_target) { + TextureStorage *texture_storage = TextureStorage::get_singleton(); + RS::ViewportVRSMode vrs_mode = texture_storage->render_target_get_vrs_mode(p_render_target); + + if (vrs_mode != RS::VIEWPORT_VRS_DISABLED) { + RD::get_singleton()->draw_command_begin_label("VRS Setup"); + + // TODO figure out if image has changed since it was last copied so we can save some resources.. + + if (vrs_mode == RS::VIEWPORT_VRS_TEXTURE) { + RID vrs_texture = texture_storage->render_target_get_vrs_texture(p_render_target); + if (vrs_texture.is_valid()) { + Texture *texture = texture_storage->get_texture(vrs_texture); + if (texture) { + // Copy into our density buffer + copy_vrs(texture->rd_texture, p_vrs_fb, texture->layers > 1); + } + } + } else if (vrs_mode == RS::VIEWPORT_VRS_XR) { + Ref<XRInterface> interface = XRServer::get_singleton()->get_primary_interface(); + if (interface.is_valid()) { + RID vrs_texture = interface->get_vrs_texture(); + if (vrs_texture.is_valid()) { + Texture *texture = texture_storage->get_texture(vrs_texture); + if (texture) { + // Copy into our density buffer + copy_vrs(texture->rd_texture, p_vrs_fb, texture->layers > 1); + } + } + } + } + + RD::get_singleton()->draw_command_end_label(); + } +} diff --git a/servers/rendering/renderer_rd/effects/vrs.h b/servers/rendering/renderer_rd/effects/vrs.h new file mode 100644 index 0000000000..0f2bdd31b6 --- /dev/null +++ b/servers/rendering/renderer_rd/effects/vrs.h @@ -0,0 +1,75 @@ +/*************************************************************************/ +/* vrs.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* 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 */ +/* "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. */ +/*************************************************************************/ + +#ifndef VRS_RD_H +#define VRS_RD_H + +#include "servers/rendering/renderer_rd/pipeline_cache_rd.h" +#include "servers/rendering/renderer_rd/shaders/effects/vrs.glsl.gen.h" +#include "servers/rendering/renderer_scene_render.h" + +#include "servers/rendering_server.h" + +namespace RendererRD { + +class VRS { +private: + enum VRSMode { + VRS_DEFAULT, + VRS_MULTIVIEW, + VRS_MAX, + }; + + /* we have no push constant here (yet) + struct VRSPushConstant { + + }; + */ + + struct VRSShader { + // VRSPushConstant push_constant; + VrsShaderRD shader; + RID shader_version; + PipelineCacheRD pipelines[VRS_MAX]; + } vrs_shader; + +public: + VRS(); + ~VRS(); + + void copy_vrs(RID p_source_rd_texture, RID p_dest_framebuffer, bool p_multiview = false); + + void create_vrs_texture(const int p_base_width, const int p_base_height, const uint32_t p_view_count, RID &p_vrs_texture, RID &p_vrs_fb); + void update_vrs_texture(RID p_vrs_fb, RID p_render_target); +}; + +} // namespace RendererRD + +#endif // !VRS_RD_H diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp index d45ddbc392..f731a0007a 100644 --- a/servers/rendering/renderer_rd/effects_rd.cpp +++ b/servers/rendering/renderer_rd/effects_rd.cpp @@ -1309,7 +1309,7 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) { 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) { + if (RD::get_singleton()->has_feature(RD::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"); diff --git a/servers/rendering/renderer_rd/environment/gi.cpp b/servers/rendering/renderer_rd/environment/gi.cpp index a749e7d5bc..f17d5172b7 100644 --- a/servers/rendering/renderer_rd/environment/gi.cpp +++ b/servers/rendering/renderer_rd/environment/gi.cpp @@ -109,6 +109,7 @@ void GI::voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &p_to_cell_xfo Vector<Vector<uint8_t>> s; s.push_back(p_distance_field); voxel_gi->sdf_texture = RD::get_singleton()->texture_create(tf, RD::TextureView(), s); + RD::get_singleton()->set_resource_name(voxel_gi->sdf_texture, "VoxelGI SDF Texture"); } #if 0 { @@ -122,6 +123,7 @@ void GI::voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &p_to_cell_xfo tf.shareable_formats.push_back(RD::DATA_FORMAT_R8_UNORM); tf.shareable_formats.push_back(RD::DATA_FORMAT_R8_UINT); voxel_gi->sdf_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(voxel_gi->sdf_texture, "VoxelGI SDF Texture"); } RID shared_tex; { @@ -402,29 +404,38 @@ void GI::SDFGI::create(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world RD::TextureFormat tf_render = tf_sdf; tf_render.format = RD::DATA_FORMAT_R16_UINT; render_albedo = RD::get_singleton()->texture_create(tf_render, RD::TextureView()); + RD::get_singleton()->set_resource_name(render_albedo, "VoxelGI Render Albedo"); tf_render.format = RD::DATA_FORMAT_R32_UINT; render_emission = RD::get_singleton()->texture_create(tf_render, RD::TextureView()); + RD::get_singleton()->set_resource_name(render_emission, "VoxelGI Render Emission"); render_emission_aniso = RD::get_singleton()->texture_create(tf_render, RD::TextureView()); + RD::get_singleton()->set_resource_name(render_emission_aniso, "VoxelGI Render Emission Aniso"); tf_render.format = RD::DATA_FORMAT_R8_UNORM; //at least its easy to visualize for (int i = 0; i < 8; i++) { render_occlusion[i] = RD::get_singleton()->texture_create(tf_render, RD::TextureView()); + RD::get_singleton()->set_resource_name(render_occlusion[i], String("VoxelGI Render Occlusion ") + itos(i)); } tf_render.format = RD::DATA_FORMAT_R32_UINT; render_geom_facing = RD::get_singleton()->texture_create(tf_render, RD::TextureView()); + RD::get_singleton()->set_resource_name(render_geom_facing, "VoxelGI Render Geometry Facing"); tf_render.format = RD::DATA_FORMAT_R8G8B8A8_UINT; render_sdf[0] = RD::get_singleton()->texture_create(tf_render, RD::TextureView()); + RD::get_singleton()->set_resource_name(render_sdf[0], "VoxelGI Render SDF 0"); render_sdf[1] = RD::get_singleton()->texture_create(tf_render, RD::TextureView()); + RD::get_singleton()->set_resource_name(render_sdf[1], "VoxelGI Render SDF 1"); tf_render.width /= 2; tf_render.height /= 2; tf_render.depth /= 2; render_sdf_half[0] = RD::get_singleton()->texture_create(tf_render, RD::TextureView()); + RD::get_singleton()->set_resource_name(render_sdf_half[0], "VoxelGI Render SDF Half 0"); render_sdf_half[1] = RD::get_singleton()->texture_create(tf_render, RD::TextureView()); + RD::get_singleton()->set_resource_name(render_sdf_half[1], "VoxelGI Render SDF Half 1"); } RD::TextureFormat tf_occlusion = tf_sdf; @@ -465,7 +476,9 @@ void GI::SDFGI::create(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world tf_probe_average.texture_type = RD::TEXTURE_TYPE_2D; lightprobe_history_scroll = RD::get_singleton()->texture_create(tf_probe_history, RD::TextureView()); + RD::get_singleton()->set_resource_name(lightprobe_history_scroll, "VoxelGI LightProbe History Scroll"); lightprobe_average_scroll = RD::get_singleton()->texture_create(tf_probe_average, RD::TextureView()); + RD::get_singleton()->set_resource_name(lightprobe_average_scroll, "VoxelGI LightProbe Average Scroll"); { //octahedral lightprobes @@ -479,6 +492,7 @@ void GI::SDFGI::create(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world //lightprobe texture is an octahedral texture lightprobe_data = RD::get_singleton()->texture_create(tf_octprobes, RD::TextureView()); + RD::get_singleton()->set_resource_name(lightprobe_data, "VoxelGI LightProbe Data"); RD::TextureView tv; tv.format_override = RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32; lightprobe_texture = RD::get_singleton()->texture_create_shared(tv, lightprobe_data); @@ -492,11 +506,13 @@ void GI::SDFGI::create(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world tf_ambient.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; //lightprobe texture is an octahedral texture ambient_texture = RD::get_singleton()->texture_create(tf_ambient, RD::TextureView()); + RD::get_singleton()->set_resource_name(ambient_texture, "VoxelGI Ambient Texture"); } cascades_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES); occlusion_data = RD::get_singleton()->texture_create(tf_occlusion, RD::TextureView()); + RD::get_singleton()->set_resource_name(occlusion_data, "VoxelGI Occlusion Data"); { RD::TextureView tv; tv.format_override = RD::DATA_FORMAT_R4G4B4A4_UNORM_PACK16; @@ -509,11 +525,15 @@ void GI::SDFGI::create(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world /* 3D Textures */ cascade.sdf_tex = RD::get_singleton()->texture_create(tf_sdf, RD::TextureView()); + RD::get_singleton()->set_resource_name(cascade.sdf_tex, "VoxelGI Cascade SDF Texture"); cascade.light_data = RD::get_singleton()->texture_create(tf_light, RD::TextureView()); + RD::get_singleton()->set_resource_name(cascade.light_data, "VoxelGI Cascade Light Data"); cascade.light_aniso_0_tex = RD::get_singleton()->texture_create(tf_aniso0, RD::TextureView()); + RD::get_singleton()->set_resource_name(cascade.light_aniso_0_tex, "VoxelGI Cascade Light Aniso 0 Texture"); cascade.light_aniso_1_tex = RD::get_singleton()->texture_create(tf_aniso1, RD::TextureView()); + RD::get_singleton()->set_resource_name(cascade.light_aniso_1_tex, "VoxelGI Cascade Light Aniso 1 Texture"); { RD::TextureView tv; @@ -540,9 +560,11 @@ void GI::SDFGI::create(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world /* Probe History */ cascade.lightprobe_history_tex = RD::get_singleton()->texture_create(tf_probe_history, RD::TextureView()); + RD::get_singleton()->set_resource_name(cascade.lightprobe_history_tex, "VoxelGI Cascade LightProbe History Texture"); RD::get_singleton()->texture_clear(cascade.lightprobe_history_tex, Color(0, 0, 0, 0), 0, 1, 0, tf_probe_history.array_layers); //needs to be cleared for average to work cascade.lightprobe_average_tex = RD::get_singleton()->texture_create(tf_probe_average, RD::TextureView()); + RD::get_singleton()->set_resource_name(cascade.lightprobe_average_tex, "VoxelGI Cascade LightProbe Average Texture"); RD::get_singleton()->texture_clear(cascade.lightprobe_average_tex, Color(0, 0, 0, 0), 0, 1, 0, 1); //needs to be cleared for average to work /* Buffers */ @@ -2444,6 +2466,7 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(texture, "VoxelGI Instance Texture"); RD::get_singleton()->texture_clear(texture, Color(0, 0, 0, 0), 0, levels.size(), 0, 1); @@ -2573,6 +2596,7 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID dtf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; } dmap.texture = RD::get_singleton()->texture_create(dtf, RD::TextureView()); + RD::get_singleton()->set_resource_name(dmap.texture, "VoxelGI Instance DMap Texture"); if (dynamic_maps.size() == 0) { // Render depth for first one. @@ -2580,6 +2604,7 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID 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()); + RD::get_singleton()->set_resource_name(dmap.fb_depth, "VoxelGI Instance DMap FB Depth"); } //just use depth as-is @@ -2587,13 +2612,17 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; dmap.depth = RD::get_singleton()->texture_create(dtf, RD::TextureView()); + RD::get_singleton()->set_resource_name(dmap.depth, "VoxelGI Instance DMap Depth"); if (dynamic_maps.size() == 0) { dtf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; dmap.albedo = RD::get_singleton()->texture_create(dtf, RD::TextureView()); + RD::get_singleton()->set_resource_name(dmap.albedo, "VoxelGI Instance DMap Albedo"); dmap.normal = RD::get_singleton()->texture_create(dtf, RD::TextureView()); + RD::get_singleton()->set_resource_name(dmap.normal, "VoxelGI Instance DMap Normal"); dmap.orm = RD::get_singleton()->texture_create(dtf, RD::TextureView()); + RD::get_singleton()->set_resource_name(dmap.orm, "VoxelGI Instance DMap ORM"); Vector<RID> fb; fb.push_back(dmap.albedo); @@ -3342,37 +3371,40 @@ void GI::init(RendererSceneSkyRD *p_sky) { //calculate tables String defines = "\n#define SDFGI_OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; Vector<String> gi_modes; + gi_modes.push_back("\n#define USE_VOXEL_GI_INSTANCES\n"); // MODE_VOXEL_GI gi_modes.push_back("\n#define USE_SDFGI\n"); // MODE_SDFGI gi_modes.push_back("\n#define USE_SDFGI\n\n#define USE_VOXEL_GI_INSTANCES\n"); // MODE_COMBINED - gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_VOXEL_GI_INSTANCES\n"); // MODE_HALF_RES_VOXEL_GI - gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n"); // MODE_HALF_RES_SDFGI - gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n\n#define USE_VOXEL_GI_INSTANCES\n"); // MODE_HALF_RES_COMBINED - - gi_modes.push_back("\n#define USE_VOXEL_GI_INSTANCES\n#define USE_MULTIVIEW\n"); // MODE_VOXEL_GI_MULTIVIEW - gi_modes.push_back("\n#define USE_SDFGI\n#define USE_MULTIVIEW\n"); // MODE_SDFGI_MULTIVIEW - gi_modes.push_back("\n#define USE_SDFGI\n\n#define USE_VOXEL_GI_INSTANCES\n#define USE_MULTIVIEW\n"); // MODE_COMBINED_MULTIVIEW - gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_VOXEL_GI_INSTANCES\n#define USE_MULTIVIEW\n"); // MODE_HALF_RES_VOXEL_GI_MULTIVIEW - gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n#define USE_MULTIVIEW\n"); // MODE_HALF_RES_SDFGI_MULTIVIEW - gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n\n#define USE_VOXEL_GI_INSTANCES\n#define USE_MULTIVIEW\n"); // MODE_HALF_RES_COMBINED_MULTIVIEW shader.initialize(gi_modes, defines); + shader_version = shader.version_create(); + + Vector<RD::PipelineSpecializationConstant> specialization_constants; + + { + RD::PipelineSpecializationConstant sc; + sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL; + sc.constant_id = 0; // SHADER_SPECIALIZATION_HALF_RES + sc.bool_value = false; + specialization_constants.push_back(sc); - if (!RendererCompositorRD::singleton->is_xr_enabled()) { - shader.set_variant_enabled(MODE_VOXEL_GI_MULTIVIEW, false); - shader.set_variant_enabled(MODE_SDFGI_MULTIVIEW, false); - shader.set_variant_enabled(MODE_COMBINED_MULTIVIEW, false); - shader.set_variant_enabled(MODE_HALF_RES_VOXEL_GI_MULTIVIEW, false); - shader.set_variant_enabled(MODE_HALF_RES_SDFGI_MULTIVIEW, false); - shader.set_variant_enabled(MODE_HALF_RES_COMBINED_MULTIVIEW, false); + sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL; + sc.constant_id = 1; // SHADER_SPECIALIZATION_USE_FULL_PROJECTION_MATRIX + sc.bool_value = false; + specialization_constants.push_back(sc); + + sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL; + sc.constant_id = 2; // SHADER_SPECIALIZATION_USE_VRS + sc.bool_value = false; + specialization_constants.push_back(sc); } - shader_version = shader.version_create(); - for (int i = 0; i < MODE_MAX; i++) { - if (shader.is_variant_enabled(i)) { - pipelines[i] = RD::get_singleton()->compute_pipeline_create(shader.version_get_shader(shader_version, i)); - } else { - pipelines[i] = RID(); + for (int v = 0; v < SHADER_SPECIALIZATION_VARIATIONS; v++) { + specialization_constants.ptrw()[0].bool_value = (v & SHADER_SPECIALIZATION_HALF_RES) ? true : false; + specialization_constants.ptrw()[1].bool_value = (v & SHADER_SPECIALIZATION_USE_FULL_PROJECTION_MATRIX) ? true : false; + specialization_constants.ptrw()[2].bool_value = (v & SHADER_SPECIALIZATION_USE_VRS) ? true : false; + for (int i = 0; i < MODE_MAX; i++) { + pipelines[v][i] = RD::get_singleton()->compute_pipeline_create(shader.version_get_shader(shader_version, i), specialization_constants); } } @@ -3564,25 +3596,17 @@ void GI::RenderBuffersGI::free() { } if (ambient_buffer.is_valid()) { - if (view_count == 1) { - // Only one view? then these are copies of our main buffers. - ambient_view[0] = RID(); - reflection_view[0] = RID(); - } else { - // Multiple views? free our slices. - for (uint32_t v = 0; v < view_count; v++) { - RD::get_singleton()->free(ambient_view[v]); - RD::get_singleton()->free(reflection_view[v]); - ambient_view[v] = RID(); - reflection_view[v] = RID(); - } - } - - // Now we can free our buffers. RD::get_singleton()->free(ambient_buffer); RD::get_singleton()->free(reflection_buffer); ambient_buffer = RID(); reflection_buffer = RID(); + + // these are automatically freed when we free the textures, so just reset.. + for (uint32_t v = 0; v < RendererSceneRender::MAX_RENDER_VIEWS; v++) { + ambient_slice[v] = RID(); + reflection_slice[v] = RID(); + } + view_count = 0; } @@ -3592,7 +3616,7 @@ void GI::RenderBuffersGI::free() { } } -void GI::process_gi(RID p_render_buffers, RID *p_normal_roughness_views, RID p_voxel_gi_buffer, RID p_environment, uint32_t p_view_count, const CameraMatrix *p_projections, const Vector3 *p_eye_offsets, const Transform3D &p_cam_transform, const PagedArray<RID> &p_voxel_gi_instances, RendererSceneRenderRD *p_scene_render) { +void GI::process_gi(RID p_render_buffers, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer, const RID *p_vrs_slices, RID p_environment, uint32_t p_view_count, const CameraMatrix *p_projections, const Vector3 *p_eye_offsets, const Transform3D &p_cam_transform, const PagedArray<RID> &p_voxel_gi_instances, RendererSceneRenderRD *p_scene_render) { RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); @@ -3606,14 +3630,13 @@ void GI::process_gi(RID p_render_buffers, RID *p_normal_roughness_views, RID p_v if (rb->rbgi.ambient_buffer.is_null() || rb->rbgi.using_half_size_gi != half_resolution || rb->rbgi.view_count != p_view_count) { // Free our old buffer if applicable if (rb->rbgi.ambient_buffer.is_valid()) { - if (rb->rbgi.view_count > 1) { - for (uint32_t v = 0; v < rb->rbgi.view_count; v++) { - RD::get_singleton()->free(rb->rbgi.ambient_view[v]); - RD::get_singleton()->free(rb->rbgi.reflection_view[v]); - } - } RD::get_singleton()->free(rb->rbgi.ambient_buffer); RD::get_singleton()->free(rb->rbgi.reflection_buffer); + + for (uint32_t v = 0; v < RendererSceneRender::MAX_RENDER_VIEWS; v++) { + rb->rbgi.ambient_slice[v] = RID(); + rb->rbgi.reflection_slice[v] = RID(); + } } // Remember the view count we're using @@ -3637,18 +3660,19 @@ void GI::process_gi(RID p_render_buffers, RID *p_normal_roughness_views, RID p_v } tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; rb->rbgi.ambient_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->rbgi.ambient_buffer, "GI Ambient Buffer"); rb->rbgi.reflection_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->rbgi.reflection_buffer, "GI Reflection Buffer"); rb->rbgi.using_half_size_gi = half_resolution; if (p_view_count == 1) { - // Just one view? Copy our buffers - rb->rbgi.ambient_view[0] = rb->rbgi.ambient_buffer; - rb->rbgi.reflection_view[0] = rb->rbgi.reflection_buffer; + // Just copy, we don't need to create slices + rb->rbgi.ambient_slice[0] = rb->rbgi.ambient_buffer; + rb->rbgi.reflection_slice[0] = rb->rbgi.reflection_buffer; } else { - // More then one view? Create slices for each view for (uint32_t v = 0; v < p_view_count; v++) { - rb->rbgi.ambient_view[v] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->rbgi.ambient_buffer, v, 0); - rb->rbgi.reflection_view[v] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->rbgi.reflection_buffer, v, 0); + rb->rbgi.ambient_slice[v] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->rbgi.ambient_buffer, v, 0); + rb->rbgi.reflection_slice[v] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->rbgi.reflection_buffer, v, 0); } } } @@ -3681,29 +3705,45 @@ void GI::process_gi(RID p_render_buffers, RID *p_normal_roughness_views, RID p_v // Now compute the contents of our buffers. RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(true); - for (uint32_t v = 0; v < p_view_count; v++) { - // Render each eye seperately. - // We need to look into whether we can make our compute shader use Multiview but not sure that works or makes a difference.. + // Render each eye seperately. + // We need to look into whether we can make our compute shader use Multiview but not sure that works or makes a difference.. - // setup our push constant + // setup our push constant - PushConstant push_constant; + PushConstant push_constant; - push_constant.view_index = v; - push_constant.orthogonal = p_projections[v].is_orthogonal(); - push_constant.max_voxel_gi_instances = MIN((uint64_t)MAX_VOXEL_GI_INSTANCES, p_voxel_gi_instances.size()); - push_constant.high_quality_vct = voxel_gi_quality == RS::VOXEL_GI_QUALITY_HIGH; + push_constant.max_voxel_gi_instances = MIN((uint64_t)MAX_VOXEL_GI_INSTANCES, p_voxel_gi_instances.size()); + push_constant.high_quality_vct = voxel_gi_quality == RS::VOXEL_GI_QUALITY_HIGH; - push_constant.z_near = p_projections[v].get_z_near(); - push_constant.z_far = p_projections[v].get_z_far(); + // these should be the same for all views + push_constant.orthogonal = p_projections[0].is_orthogonal(); + push_constant.z_near = p_projections[0].get_z_near(); + push_constant.z_far = p_projections[0].get_z_far(); - push_constant.proj_info[0] = -2.0f / (rb->internal_width * p_projections[v].matrix[0][0]); - push_constant.proj_info[1] = -2.0f / (rb->internal_height * p_projections[v].matrix[1][1]); - push_constant.proj_info[2] = (1.0f - p_projections[v].matrix[0][2]) / p_projections[v].matrix[0][0]; - push_constant.proj_info[3] = (1.0f + p_projections[v].matrix[1][2]) / p_projections[v].matrix[1][1]; + // these are only used if we have 1 view, else we use the projections in our scene data + push_constant.proj_info[0] = -2.0f / (rb->internal_width * p_projections[0].matrix[0][0]); + push_constant.proj_info[1] = -2.0f / (rb->internal_height * p_projections[0].matrix[1][1]); + push_constant.proj_info[2] = (1.0f - p_projections[0].matrix[0][2]) / p_projections[0].matrix[0][0]; + push_constant.proj_info[3] = (1.0f + p_projections[0].matrix[1][2]) / p_projections[0].matrix[1][1]; - bool use_sdfgi = rb->sdfgi != nullptr; - bool use_voxel_gi_instances = push_constant.max_voxel_gi_instances > 0; + bool use_sdfgi = rb->sdfgi != nullptr; + bool use_voxel_gi_instances = push_constant.max_voxel_gi_instances > 0; + + uint32_t pipeline_specialization = 0; + if (rb->rbgi.using_half_size_gi) { + pipeline_specialization |= SHADER_SPECIALIZATION_HALF_RES; + } + if (p_view_count > 1) { + pipeline_specialization |= SHADER_SPECIALIZATION_USE_FULL_PROJECTION_MATRIX; + } + if (p_vrs_slices[0].is_valid()) { + pipeline_specialization |= SHADER_SPECIALIZATION_USE_VRS; + } + + Mode mode = (use_sdfgi && use_voxel_gi_instances) ? MODE_COMBINED : (use_sdfgi ? MODE_SDFGI : MODE_VOXEL_GI); + + for (uint32_t v = 0; v < p_view_count; v++) { + push_constant.view_index = v; // setup our uniform set if (rb->rbgi.uniform_set[v].is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->rbgi.uniform_set[v])) { @@ -3790,7 +3830,7 @@ void GI::process_gi(RID p_render_buffers, RID *p_normal_roughness_views, RID p_v RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 9; - u.append_id(rb->rbgi.ambient_view[v]); + u.append_id(rb->rbgi.ambient_slice[v]); uniforms.push_back(u); } @@ -3798,7 +3838,7 @@ void GI::process_gi(RID p_render_buffers, RID *p_normal_roughness_views, RID p_v RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 10; - u.append_id(rb->rbgi.reflection_view[v]); + u.append_id(rb->rbgi.reflection_slice[v]); uniforms.push_back(u); } @@ -3824,7 +3864,7 @@ void GI::process_gi(RID p_render_buffers, RID *p_normal_roughness_views, RID p_v RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 13; - u.append_id(p_normal_roughness_views[v]); + u.append_id(p_normal_roughness_slices[v]); uniforms.push_back(u); } { @@ -3865,27 +3905,19 @@ void GI::process_gi(RID p_render_buffers, RID *p_normal_roughness_views, RID p_v u.append_id(rb->rbgi.scene_data_ubo); uniforms.push_back(u); } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 19; + RID buffer = p_vrs_slices[v].is_valid() ? p_vrs_slices[v] : texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_VRS); + u.append_id(buffer); + uniforms.push_back(u); + } rb->rbgi.uniform_set[v] = RD::get_singleton()->uniform_set_create(uniforms, shader.version_get_shader(shader_version, 0), 0); } - Mode mode; - - if (p_view_count > 1) { - if (rb->rbgi.using_half_size_gi) { - mode = (use_sdfgi && use_voxel_gi_instances) ? MODE_HALF_RES_COMBINED_MULTIVIEW : (use_sdfgi ? MODE_HALF_RES_SDFGI_MULTIVIEW : MODE_HALF_RES_VOXEL_GI_MULTIVIEW); - } else { - mode = (use_sdfgi && use_voxel_gi_instances) ? MODE_COMBINED_MULTIVIEW : (use_sdfgi ? MODE_SDFGI_MULTIVIEW : MODE_VOXEL_GI_MULTIVIEW); - } - } else { - if (rb->rbgi.using_half_size_gi) { - mode = (use_sdfgi && use_voxel_gi_instances) ? MODE_HALF_RES_COMBINED : (use_sdfgi ? MODE_HALF_RES_SDFGI : MODE_HALF_RES_VOXEL_GI); - } else { - mode = (use_sdfgi && use_voxel_gi_instances) ? MODE_COMBINED : (use_sdfgi ? MODE_SDFGI : MODE_VOXEL_GI); - } - } - - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipelines[mode]); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipelines[pipeline_specialization][mode]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->rbgi.uniform_set[v], 0); RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(PushConstant)); diff --git a/servers/rendering/renderer_rd/environment/gi.h b/servers/rendering/renderer_rd/environment/gi.h index 294b8d3cfd..d950ff9e86 100644 --- a/servers/rendering/renderer_rd/environment/gi.h +++ b/servers/rendering/renderer_rd/environment/gi.h @@ -660,13 +660,13 @@ public: /* GI buffers */ RID ambient_buffer; + RID ambient_slice[RendererSceneRender::MAX_RENDER_VIEWS]; RID reflection_buffer; - RID ambient_view[RendererSceneRender::MAX_RENDER_VIEWS]; - RID reflection_view[RendererSceneRender::MAX_RENDER_VIEWS]; - RID uniform_set[RendererSceneRender::MAX_RENDER_VIEWS]; + RID reflection_slice[RendererSceneRender::MAX_RENDER_VIEWS]; bool using_half_size_gi = false; uint32_t view_count = 1; + RID uniform_set[RendererSceneRender::MAX_RENDER_VIEWS]; RID scene_data_ubo; void free(); @@ -729,44 +729,41 @@ public: }; struct PushConstant { - uint32_t view_index; uint32_t max_voxel_gi_instances; uint32_t high_quality_vct; uint32_t orthogonal; + uint32_t view_index; float proj_info[4]; float z_near; float z_far; - float pad1; float pad2; + float pad3; }; RID sdfgi_ubo; + enum Mode { MODE_VOXEL_GI, MODE_SDFGI, MODE_COMBINED, - MODE_HALF_RES_VOXEL_GI, - MODE_HALF_RES_SDFGI, - MODE_HALF_RES_COMBINED, - - MODE_VOXEL_GI_MULTIVIEW, - MODE_SDFGI_MULTIVIEW, - MODE_COMBINED_MULTIVIEW, - MODE_HALF_RES_VOXEL_GI_MULTIVIEW, - MODE_HALF_RES_SDFGI_MULTIVIEW, - MODE_HALF_RES_COMBINED_MULTIVIEW, - MODE_MAX }; + enum ShaderSpecializations { + SHADER_SPECIALIZATION_HALF_RES = 1 << 0, + SHADER_SPECIALIZATION_USE_FULL_PROJECTION_MATRIX = 1 << 1, + SHADER_SPECIALIZATION_USE_VRS = 1 << 2, + SHADER_SPECIALIZATION_VARIATIONS = 0x07, + }; + RID default_voxel_gi_buffer; bool half_resolution = false; GiShaderRD shader; RID shader_version; - RID pipelines[MODE_MAX]; + RID pipelines[SHADER_SPECIALIZATION_VARIATIONS][MODE_MAX]; GI(); ~GI(); @@ -777,7 +774,7 @@ public: SDFGI *create_sdfgi(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size); void setup_voxel_gi_instances(RID p_render_buffers, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, uint32_t &r_voxel_gi_instances_used, RendererSceneRenderRD *p_scene_render); - void process_gi(RID p_render_buffers, RID *p_normal_roughness_views, RID p_voxel_gi_buffer, RID p_environment, uint32_t p_view_count, const CameraMatrix *p_projections, const Vector3 *p_eye_offsets, const Transform3D &p_cam_transform, const PagedArray<RID> &p_voxel_gi_instances, RendererSceneRenderRD *p_scene_render); + void process_gi(RID p_render_buffers, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer, const RID *p_vrs_slices, RID p_environment, uint32_t p_view_count, const CameraMatrix *p_projections, const Vector3 *p_eye_offsets, const Transform3D &p_cam_transform, const PagedArray<RID> &p_voxel_gi_instances, RendererSceneRenderRD *p_scene_render); RID voxel_gi_instance_create(RID p_base); void voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform); 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 f759fa3aa5..85652a041d 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -171,29 +171,24 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_voxelgi() } void RenderForwardClustered::RenderBufferDataForwardClustered::clear() { + // note, slices are freed automatically when the parent texture is freed so we just clear them. + for (uint32_t v = 0; v < RendererSceneRender::MAX_RENDER_VIEWS; v++) { + color_views[v] = RID(); + depth_views[v] = RID(); + color_msaa_views[v] = RID(); + depth_msaa_views[v] = RID(); + normal_roughness_views[v] = RID(); + normal_roughness_msaa_views[v] = RID(); + voxelgi_views[v] = RID(); + voxelgi_msaa_views[v] = RID(); + vrs_views[v] = RID(); + } + if (voxelgi_buffer != RID()) { RD::get_singleton()->free(voxelgi_buffer); voxelgi_buffer = RID(); - if (view_count == 1) { - voxelgi_views[0] = RID(); - } else { - for (uint32_t v = 0; v < view_count; v++) { - RD::get_singleton()->free(voxelgi_views[v]); - voxelgi_views[v] = RID(); - } - } - if (voxelgi_buffer_msaa.is_valid()) { - if (view_count == 1) { - voxelgi_msaa_views[0] = RID(); - } else { - for (uint32_t v = 0; v < view_count; v++) { - RD::get_singleton()->free(voxelgi_msaa_views[v]); - voxelgi_msaa_views[v] = RID(); - } - } - RD::get_singleton()->free(voxelgi_buffer_msaa); voxelgi_buffer_msaa = RID(); } @@ -202,35 +197,11 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::clear() { } if (color_msaa.is_valid()) { - if (view_count == 1) { - color_views[0] = RID(); - color_msaa_views[0] = RID(); - } else { - for (uint32_t v = 0; v < view_count; v++) { - RD::get_singleton()->free(color_views[v]); - RD::get_singleton()->free(color_msaa_views[v]); - color_views[v] = RID(); - color_msaa_views[v] = RID(); - } - } - RD::get_singleton()->free(color_msaa); color_msaa = RID(); } if (depth_msaa.is_valid()) { - if (view_count == 1) { - depth_views[0] = RID(); - depth_msaa_views[0] = RID(); - } else { - for (uint32_t v = 0; v < view_count; v++) { - RD::get_singleton()->free(depth_views[v]); - RD::get_singleton()->free(depth_msaa_views[v]); - depth_views[v] = RID(); - depth_msaa_views[v] = RID(); - } - } - RD::get_singleton()->free(depth_msaa); depth_msaa = RID(); } @@ -245,33 +216,17 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::clear() { } color = RID(); + color_only_fb = RID(); depth = RID(); depth_fb = RID(); color_framebuffers.clear(); // Color pass framebuffers are freed automatically by their dependency relations if (normal_roughness_buffer.is_valid()) { - if (view_count == 1) { - normal_roughness_views[0] = RID(); - } else { - for (uint32_t v = 0; v < view_count; v++) { - RD::get_singleton()->free(normal_roughness_views[v]); - normal_roughness_views[v] = RID(); - } - } - RD::get_singleton()->free(normal_roughness_buffer); normal_roughness_buffer = RID(); if (normal_roughness_buffer_msaa.is_valid()) { - if (view_count == 1) { - normal_roughness_msaa_views[0] = RID(); - } else { - for (uint32_t v = 0; v < view_count; v++) { - RD::get_singleton()->free(normal_roughness_msaa_views[v]); - normal_roughness_msaa_views[v] = RID(); - } - } RD::get_singleton()->free(normal_roughness_buffer_msaa); normal_roughness_buffer_msaa = RID(); } @@ -294,11 +249,12 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::clear() { } } -void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, bool p_use_taa, uint32_t p_view_count) { +void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, bool p_use_taa, uint32_t p_view_count, RID p_vrs_texture) { clear(); msaa = p_msaa; use_taa = p_use_taa; + vrs = p_vrs_texture; width = p_width; height = p_height; @@ -307,11 +263,26 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_c color = p_color_buffer; depth = p_depth_buffer; + if (vrs.is_valid()) { + if (view_count == 1) { + // just reuse + vrs_views[0] = vrs; + } else { + // create slices + for (uint32_t v = 0; v < view_count; v++) { + vrs_views[v] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), vrs, v, 0); + } + } + } + if (p_msaa == RS::VIEWPORT_MSAA_DISABLED) { { Vector<RID> fb; fb.push_back(p_color_buffer); fb.push_back(depth); + if (vrs.is_valid()) { + fb.push_back(vrs); + } color_only_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, view_count); } @@ -371,6 +342,9 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_c Vector<RID> fb; fb.push_back(color_msaa); fb.push_back(depth_msaa); + if (vrs.is_valid()) { + fb.push_back(vrs); + } color_only_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, view_count); } @@ -409,6 +383,10 @@ RID RenderForwardClustered::RenderBufferDataForwardClustered::get_color_pass_fb( fb.push_back(use_msaa ? depth_msaa : depth); + if (vrs.is_valid()) { + fb.push_back(vrs); + } + int v_count = (p_color_pass_flags & COLOR_PASS_FLAG_MULTIVIEW) ? view_count : 1; RID framebuffer = RD::get_singleton()->framebuffer_create(fb, RD::INVALID_ID, v_count); color_framebuffers[p_color_pass_flags] = framebuffer; @@ -1673,8 +1651,8 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co continue_depth = !finish_depth; } - RID null_rids[2]; - _pre_opaque_render(p_render_data, using_ssao, using_ssil, using_sdfgi || using_voxelgi, render_buffer ? render_buffer->normal_roughness_views : null_rids, render_buffer ? render_buffer->voxelgi_buffer : RID()); + RID nullrids[RendererSceneRender::MAX_RENDER_VIEWS]; + _pre_opaque_render(p_render_data, using_ssao, using_ssil, using_sdfgi || using_voxelgi, render_buffer ? render_buffer->normal_roughness_views : nullrids, render_buffer ? render_buffer->voxelgi_buffer : RID(), render_buffer ? render_buffer->vrs_views : nullrids); RD::get_singleton()->draw_command_begin_label("Render Opaque Pass"); 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 9e1f1b9954..ff712a20a1 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -107,11 +107,14 @@ class RenderForwardClustered : public RendererSceneRenderRD { RID depth_normal_roughness_voxelgi_fb; RID color_only_fb; RID specular_only_fb; + + RID vrs; + int width, height; HashMap<uint32_t, RID> color_framebuffers; // for multiview - uint32_t view_count; + uint32_t view_count = 1; RID color_views[RendererSceneRender::MAX_RENDER_VIEWS]; // we should rewrite this so we get access to the existing views in our renderer, something we can address when we reorg this RID depth_views[RendererSceneRender::MAX_RENDER_VIEWS]; // we should rewrite this so we get access to the existing views in our renderer, something we can address when we reorg this RID color_msaa_views[RendererSceneRender::MAX_RENDER_VIEWS]; @@ -120,13 +123,14 @@ class RenderForwardClustered : public RendererSceneRenderRD { RID normal_roughness_msaa_views[RendererSceneRender::MAX_RENDER_VIEWS]; RID voxelgi_views[RendererSceneRender::MAX_RENDER_VIEWS]; RID voxelgi_msaa_views[RendererSceneRender::MAX_RENDER_VIEWS]; + RID vrs_views[RendererSceneRender::MAX_RENDER_VIEWS]; RID render_sdfgi_uniform_set; void ensure_specular(); void ensure_voxelgi(); void ensure_velocity(); void clear(); - virtual void configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, bool p_use_taa, uint32_t p_view_count); + virtual void configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, bool p_use_taa, uint32_t p_view_count, RID p_vrs_texture); RID get_color_pass_fb(uint32_t p_color_pass_flags); ~RenderBufferDataForwardClustered(); 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 e1855ddb36..966621c93e 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -87,10 +87,11 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::clear() { } } -void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, bool p_use_taa, uint32_t p_view_count) { +void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, bool p_use_taa, uint32_t p_view_count, RID p_vrs_texture) { clear(); msaa = p_msaa; + vrs = p_vrs_texture; Size2i target_size = RD::get_singleton()->texture_size(p_target_buffer); @@ -108,6 +109,9 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_b Vector<RID> fb; fb.push_back(p_color_buffer); // 0 - color buffer fb.push_back(depth); // 1 - depth buffer + if (vrs.is_valid()) { + fb.push_back(vrs); // 2 - vrs texture + } // Now define our subpasses Vector<RD::FramebufferPass> passes; @@ -116,6 +120,9 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_b // re-using the same attachments pass.color_attachments.push_back(0); pass.depth_attachment = 1; + if (vrs.is_valid()) { + pass.vrs_attachment = 2; + } // - opaque pass passes.push_back(pass); @@ -131,12 +138,13 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_b if (!is_scaled) { // - add blit to 2D pass - fb.push_back(p_target_buffer); // 2 - target buffer + int target_buffer_id = fb.size(); + fb.push_back(p_target_buffer); // 2/3 - target buffer RD::FramebufferPass blit_pass; - blit_pass.color_attachments.push_back(2); + blit_pass.color_attachments.push_back(target_buffer_id); blit_pass.input_attachments.push_back(0); - passes.push_back(blit_pass); + passes.push_back(blit_pass); // this doesn't need VRS color_fbs[FB_CONFIG_FOUR_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count); } else { @@ -179,6 +187,9 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_b Vector<RID> fb; fb.push_back(color_msaa); // 0 - msaa color buffer fb.push_back(depth_msaa); // 1 - msaa depth buffer + if (vrs.is_valid()) { + fb.push_back(vrs); // 2 - vrs texture + } // Now define our subpasses Vector<RD::FramebufferPass> passes; @@ -187,18 +198,22 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_b // re-using the same attachments pass.color_attachments.push_back(0); pass.depth_attachment = 1; + if (vrs.is_valid()) { + pass.vrs_attachment = 2; + } // - opaque pass passes.push_back(pass); // - add sky pass - fb.push_back(color); // 2 - color buffer + int color_buffer_id = fb.size(); + fb.push_back(color); // color buffer passes.push_back(pass); // without resolve for our 3 + 4 subpass config { // but with resolve for our 2 subpass config Vector<RD::FramebufferPass> two_passes; two_passes.push_back(pass); // opaque subpass without resolve - pass.resolve_attachments.push_back(2); + pass.resolve_attachments.push_back(color_buffer_id); two_passes.push_back(pass); // sky subpass with resolve color_fbs[FB_CONFIG_TWO_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, two_passes, RenderingDevice::INVALID_ID, view_count); @@ -217,10 +232,11 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_b if (!is_scaled) { // - add blit to 2D pass - fb.push_back(p_target_buffer); // 3 - target buffer + int target_buffer_id = fb.size(); + fb.push_back(p_target_buffer); // target buffer RD::FramebufferPass blit_pass; - blit_pass.color_attachments.push_back(3); - blit_pass.input_attachments.push_back(2); + blit_pass.color_attachments.push_back(target_buffer_id); + blit_pass.input_attachments.push_back(color_buffer_id); passes.push_back(blit_pass); color_fbs[FB_CONFIG_FOUR_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count); @@ -675,8 +691,8 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color RD::get_singleton()->draw_command_end_label(); // Setup Sky resolution buffers } - RID null_rids[2]; - _pre_opaque_render(p_render_data, false, false, false, null_rids, RID()); + RID nullrids[RendererSceneRender::MAX_RENDER_VIEWS]; + _pre_opaque_render(p_render_data, false, false, false, nullrids, RID(), nullrids); 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 473a58045c..bf4a52d466 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -131,12 +131,14 @@ protected: RID depth_msaa; // RID normal_roughness_buffer_msaa; + RID vrs; + RID color_fbs[FB_CONFIG_MAX]; int width, height; uint32_t view_count; void clear(); - virtual void configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, bool p_use_taa, uint32_t p_view_count); + virtual void configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, bool p_use_taa, uint32_t p_view_count, RID p_vrs_texture); ~RenderBufferDataForwardMobile(); }; diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 120bd9ece3..a2a0538e04 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -1827,6 +1827,16 @@ void RendererSceneRenderRD::_free_render_buffer_data(RenderBuffers *rb) { rb->sss_texture = RID(); } + if (rb->vrs_fb.is_valid()) { + RD::get_singleton()->free(rb->vrs_fb); + rb->vrs_fb = RID(); + } + + if (rb->vrs_texture.is_valid()) { + RD::get_singleton()->free(rb->vrs_texture); + rb->vrs_texture = RID(); + } + for (int i = 0; i < 2; i++) { for (int l = 0; l < rb->blur[i].layers.size(); l++) { for (int m = 0; m < rb->blur[i].layers[l].mipmaps.size(); m++) { @@ -3151,8 +3161,13 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p } } + RS::ViewportVRSMode vrs_mode = texture_storage->render_target_get_vrs_mode(rb->render_target); + if (is_vrs_supported() && vrs_mode != RS::VIEWPORT_VRS_DISABLED) { + vrs->create_vrs_texture(p_internal_width, p_internal_height, p_view_count, rb->vrs_texture, rb->vrs_fb); + } + RID target_texture = texture_storage->render_target_get_rd_texture(rb->render_target); - rb->data->configure(rb->internal_texture, rb->depth_texture, target_texture, p_internal_width, p_internal_height, p_msaa, p_use_taa, p_view_count); + rb->data->configure(rb->internal_texture, rb->depth_texture, target_texture, p_internal_width, p_internal_height, p_msaa, p_use_taa, p_view_count, rb->vrs_texture); if (is_clustered_enabled()) { rb->cluster_builder->setup(Size2i(p_internal_width, p_internal_height), max_cluster_elements, rb->depth_texture, RendererRD::MaterialStorage::get_singleton()->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED), rb->internal_texture); @@ -4929,7 +4944,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_ssil, bool p_use_gi, RID *p_normal_roughness_views, 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, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer, const RID *p_vrs_slices) { // Render shadows while GI is rendering, due to how barriers are handled, this should happen at the same time RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); @@ -5004,7 +5019,7 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool //start GI if (render_gi) { - gi.process_gi(p_render_data->render_buffers, p_normal_roughness_views, p_voxel_gi_buffer, p_render_data->environment, p_render_data->view_count, p_render_data->view_projection, p_render_data->view_eye_offset, p_render_data->cam_transform, *p_render_data->voxel_gi_instances, this); + gi.process_gi(p_render_data->render_buffers, p_normal_roughness_slices, p_voxel_gi_buffer, p_vrs_slices, p_render_data->environment, p_render_data->view_count, p_render_data->view_projection, p_render_data->view_eye_offset, p_render_data->cam_transform, *p_render_data->voxel_gi_instances, this); } //Do shadow rendering (in parallel with GI) @@ -5045,13 +5060,13 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool } if (p_use_ssao) { - // TODO make these proper stereo and thus use p_normal_roughness_views correctly - _process_ssao(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_views[0], p_render_data->cam_projection); + // TODO make these proper stereo + _process_ssao(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_slices[0], p_render_data->cam_projection); } if (p_use_ssil) { - // TODO make these proper stereo and thus use p_normal_roughness_views correctly - _process_ssil(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_views[0], p_render_data->cam_projection, p_render_data->cam_transform); + // TODO make these proper stereo + _process_ssil(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_slices[0], p_render_data->cam_projection, p_render_data->cam_transform); } } @@ -5240,6 +5255,11 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData render_data.cluster_max_elements = current_cluster_builder->get_max_cluster_elements(); } + if (rb != nullptr && rb->vrs_fb.is_valid()) { + // vrs_fb will only be valid if vrs is enabled + vrs->update_vrs_texture(rb->vrs_fb, rb->render_target); + } + _render_scene(&render_data, clear_color); if (p_render_buffers.is_valid()) { @@ -5736,6 +5756,10 @@ int RendererSceneRenderRD::get_max_directional_lights() const { return cluster.max_directional_lights; } +bool RendererSceneRenderRD::is_vrs_supported() const { + return RD::get_singleton()->has_feature(RD::SUPPORTS_ATTACHMENT_VRS); +} + bool RendererSceneRenderRD::is_dynamic_gi_supported() const { // usable by default (unless low end = true) return true; @@ -5975,6 +5999,7 @@ void fog() { bokeh_dof = memnew(RendererRD::BokehDOF(!can_use_storage)); copy_effects = memnew(RendererRD::CopyEffects(!can_use_storage)); tone_mapper = memnew(RendererRD::ToneMapper); + vrs = memnew(RendererRD::VRS); } RendererSceneRenderRD::~RendererSceneRenderRD() { @@ -5989,6 +6014,9 @@ RendererSceneRenderRD::~RendererSceneRenderRD() { if (tone_mapper) { memdelete(tone_mapper); } + if (vrs) { + memdelete(vrs); + } for (const KeyValue<int, ShadowCubemap> &E : shadow_cubemaps) { RD::get_singleton()->free(E.value.cubemap); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 4249e7dbe4..d11bbd183e 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -38,6 +38,7 @@ #include "servers/rendering/renderer_rd/effects/bokeh_dof.h" #include "servers/rendering/renderer_rd/effects/copy_effects.h" #include "servers/rendering/renderer_rd/effects/tone_mapper.h" +#include "servers/rendering/renderer_rd/effects/vrs.h" #include "servers/rendering/renderer_rd/environment/gi.h" #include "servers/rendering/renderer_rd/renderer_scene_environment_rd.h" #include "servers/rendering/renderer_rd/renderer_scene_sky_rd.h" @@ -104,11 +105,12 @@ protected: RendererRD::BokehDOF *bokeh_dof = nullptr; RendererRD::CopyEffects *copy_effects = nullptr; RendererRD::ToneMapper *tone_mapper = nullptr; + RendererRD::VRS *vrs = nullptr; double time = 0.0; double time_step = 0.0; struct RenderBufferData { - virtual void configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, bool p_use_taa, uint32_t p_view_count) = 0; + virtual void configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, bool p_use_taa, uint32_t p_view_count, RID p_vrs_texture) = 0; virtual ~RenderBufferData() {} }; virtual RenderBufferData *_create_render_buffer_data() = 0; @@ -149,7 +151,7 @@ protected: 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_ssil, bool p_use_gi, RID *p_normal_roughness_views, 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, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer, const RID *p_vrs_slices); void _render_buffers_copy_screen_texture(const RenderDataRD *p_render_data); void _render_buffers_copy_depth_texture(const RenderDataRD *p_render_data); @@ -492,6 +494,8 @@ private: 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) + RID vrs_texture; // texture for vrs. + RID vrs_fb; // framebuffer to write to our vrs texture // Access to the layers for each of our views (specifically needed for applying post effects on stereoscopic images) struct View { @@ -1503,6 +1507,7 @@ public: virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) override; + virtual bool is_vrs_supported() const; virtual bool is_dynamic_gi_supported() const; virtual bool is_clustered_enabled() const; virtual bool is_volumetric_supported() const; diff --git a/servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl b/servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl index 9787c9879d..1c17eabb56 100644 --- a/servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl @@ -88,7 +88,7 @@ layout(set = 0, binding = 0) uniform sampler2DArray source_color; layout(set = 1, binding = 0) uniform sampler2DArray source_depth; layout(location = 1) out float depth; #endif /* MODE_TWO_SOURCES */ -#else +#else /* MULTIVIEW */ layout(set = 0, binding = 0) uniform sampler2D source_color; #ifdef MODE_TWO_SOURCES layout(set = 1, binding = 0) uniform sampler2D source_color2; @@ -139,7 +139,7 @@ void main() { //uv.y = 1.0 - uv.y; uv = 1.0 - uv; } -#endif +#endif /* MODE_PANORAMA_TO_DP */ #ifdef MULTIVIEW vec4 color = textureLod(source_color, uv, 0.0); @@ -148,12 +148,13 @@ void main() { depth = textureLod(source_depth, uv, 0.0).r; #endif /* MODE_TWO_SOURCES */ -#else +#else /* MULTIVIEW */ vec4 color = textureLod(source_color, uv, 0.0); #ifdef MODE_TWO_SOURCES color += textureLod(source_color2, uv, 0.0); #endif /* MODE_TWO_SOURCES */ #endif /* MULTIVIEW */ + if (params.force_luminance) { color.rgb = vec3(max(max(color.r, color.g), color.b)); } @@ -163,5 +164,6 @@ void main() { if (params.srgb) { color.rgb = linear_to_srgb(color.rgb); } + frag_color = color; } diff --git a/servers/rendering/renderer_rd/shaders/effects/vrs.glsl b/servers/rendering/renderer_rd/shaders/effects/vrs.glsl new file mode 100644 index 0000000000..5ef83c0b44 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/effects/vrs.glsl @@ -0,0 +1,72 @@ +#[vertex] + +#version 450 + +#VERSION_DEFINES + +#ifdef MULTIVIEW +#ifdef has_VK_KHR_multiview +#extension GL_EXT_multiview : enable +#define ViewIndex gl_ViewIndex +#else // has_VK_KHR_multiview +#define ViewIndex 0 +#endif // has_VK_KHR_multiview +#endif //MULTIVIEW + +#ifdef MULTIVIEW +layout(location = 0) out vec3 uv_interp; +#else +layout(location = 0) out vec2 uv_interp; +#endif + +void main() { + vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)); + uv_interp.xy = base_arr[gl_VertexIndex]; +#ifdef MULTIVIEW + uv_interp.z = ViewIndex; +#endif + + gl_Position = vec4(uv_interp.xy * 2.0 - 1.0, 0.0, 1.0); +} + +#[fragment] + +#version 450 + +#VERSION_DEFINES + +#ifdef MULTIVIEW +#ifdef has_VK_KHR_multiview +#extension GL_EXT_multiview : enable +#define ViewIndex gl_ViewIndex +#else // has_VK_KHR_multiview +#define ViewIndex 0 +#endif // has_VK_KHR_multiview +#endif //MULTIVIEW + +#ifdef MULTIVIEW +layout(location = 0) in vec3 uv_interp; +layout(set = 0, binding = 0) uniform sampler2DArray source_color; +#else /* MULTIVIEW */ +layout(location = 0) in vec2 uv_interp; +layout(set = 0, binding = 0) uniform sampler2D source_color; +#endif /* MULTIVIEW */ + +layout(location = 0) out uint frag_color; + +void main() { +#ifdef MULTIVIEW + vec3 uv = uv_interp; +#else + vec2 uv = uv_interp; +#endif + +#ifdef MULTIVIEW + vec4 color = textureLod(source_color, uv, 0.0); +#else /* MULTIVIEW */ + vec4 color = textureLod(source_color, uv, 0.0); +#endif /* MULTIVIEW */ + + // See if we can change the sampler to one that returns int... + frag_color = uint(color.r * 256.0); +} diff --git a/servers/rendering/renderer_rd/shaders/environment/gi.glsl b/servers/rendering/renderer_rd/shaders/environment/gi.glsl index f687d50a2d..5f34e7112d 100644 --- a/servers/rendering/renderer_rd/shaders/environment/gi.glsl +++ b/servers/rendering/renderer_rd/shaders/environment/gi.glsl @@ -8,6 +8,12 @@ layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; #define M_PI 3.141592 +/* Specialization Constants (Toggles) */ + +layout(constant_id = 0) const bool sc_half_res = false; +layout(constant_id = 1) const bool sc_use_full_projection_matrix = false; +layout(constant_id = 2) const bool sc_use_vrs = false; + #define SDFGI_MAX_CASCADES 8 //set 0 for SDFGI and render buffers @@ -97,18 +103,20 @@ layout(set = 0, binding = 18, std140) uniform SceneData { } scene_data; +layout(r8ui, set = 0, binding = 19) uniform restrict readonly uimage2D vrs_buffer; + layout(push_constant, std430) uniform Params { - uint view_index; uint max_voxel_gi_instances; bool high_quality_vct; bool orthogonal; + uint view_index; vec4 proj_info; float z_near; float z_far; - float pad1; float pad2; + float pad3; } params; @@ -140,34 +148,34 @@ vec4 blend_color(vec4 src, vec4 dst) { } vec3 reconstruct_position(ivec2 screen_pos) { -#ifdef USE_MULTIVIEW - vec4 pos; - pos.xy = (2.0 * vec2(screen_pos) / vec2(scene_data.screen_size)) - 1.0; - pos.z = texelFetch(sampler2D(depth_buffer, linear_sampler), screen_pos, 0).r * 2.0 - 1.0; - pos.w = 1.0; + if (sc_use_full_projection_matrix) { + vec4 pos; + pos.xy = (2.0 * vec2(screen_pos) / vec2(scene_data.screen_size)) - 1.0; + pos.z = texelFetch(sampler2D(depth_buffer, linear_sampler), screen_pos, 0).r * 2.0 - 1.0; + pos.w = 1.0; - pos = scene_data.inv_projection[params.view_index] * pos; + pos = scene_data.inv_projection[params.view_index] * pos; - return pos.xyz / pos.w; -#else - vec3 pos; - pos.z = texelFetch(sampler2D(depth_buffer, linear_sampler), screen_pos, 0).r; - - pos.z = pos.z * 2.0 - 1.0; - if (params.orthogonal) { - pos.z = ((pos.z + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; + return pos.xyz / pos.w; } else { - pos.z = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - pos.z * (params.z_far - params.z_near)); - } - pos.z = -pos.z; + vec3 pos; + pos.z = texelFetch(sampler2D(depth_buffer, linear_sampler), screen_pos, 0).r; + + pos.z = pos.z * 2.0 - 1.0; + if (params.orthogonal) { + pos.z = ((pos.z + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; + } else { + pos.z = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - pos.z * (params.z_far - params.z_near)); + } + pos.z = -pos.z; - pos.xy = vec2(screen_pos) * params.proj_info.xy + params.proj_info.zw; - if (!params.orthogonal) { - pos.xy *= pos.z; - } + pos.xy = vec2(screen_pos) * params.proj_info.xy + params.proj_info.zw; + if (!params.orthogonal) { + pos.xy *= pos.z; + } - return pos; -#endif + return pos; + } } void sdfvoxel_gi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal, vec3 cam_specular_normal, float roughness, out vec3 diffuse_light, out vec3 specular_light) { @@ -587,7 +595,6 @@ void voxel_gi_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 vec4 fetch_normal_and_roughness(ivec2 pos) { vec4 normal_roughness = texelFetch(sampler2D(normal_roughness_buffer, linear_sampler), pos, 0); - normal_roughness.xyz = normalize(normal_roughness.xyz * 2.0 - 1.0); return normal_roughness; } @@ -600,7 +607,7 @@ void process_gi(ivec2 pos, vec3 vertex, inout vec4 ambient_light, inout vec4 ref if (normal.length() > 0.5) { //valid normal, can do GI float roughness = normal_roughness.w; - vec3 view = -normalize(mat3(scene_data.cam_transform) * (vertex - scene_data.eye_offset[params.view_index].xyz)); + vec3 view = -normalize(mat3(scene_data.cam_transform) * (vertex - scene_data.eye_offset[gl_GlobalInvocationID.z].xyz)); vertex = mat3(scene_data.cam_transform) * vertex; normal = normalize(mat3(scene_data.cam_transform) * normal); vec3 reflection = normalize(reflect(-view, normal)); @@ -648,9 +655,35 @@ void process_gi(ivec2 pos, vec3 vertex, inout vec4 ambient_light, inout vec4 ref void main() { ivec2 pos = ivec2(gl_GlobalInvocationID.xy); -#ifdef MODE_HALF_RES - pos <<= 1; -#endif + uint vrs_x, vrs_y; + if (sc_use_vrs) { + ivec2 vrs_pos; + + // Currenty we use a 16x16 texel, possibly some day make this configurable. + if (sc_half_res) { + vrs_pos = pos >> 3; + } else { + vrs_pos = pos >> 4; + } + + uint vrs_texel = imageLoad(vrs_buffer, vrs_pos).r; + // note, valid values for vrs_x and vrs_y are 1, 2 and 4. + vrs_x = 1 << ((vrs_texel >> 2) & 3); + vrs_y = 1 << (vrs_texel & 3); + + if (mod(pos.x, vrs_x) != 0) { + return; + } + + if (mod(pos.y, vrs_y) != 0) { + return; + } + } + + if (sc_half_res) { + pos <<= 1; + } + if (any(greaterThanEqual(pos, scene_data.screen_size))) { //too large, do nothing return; } @@ -663,10 +696,69 @@ void main() { process_gi(pos, vertex, ambient_light, reflection_light); -#ifdef MODE_HALF_RES - pos >>= 1; -#endif + if (sc_half_res) { + pos >>= 1; + } imageStore(ambient_buffer, pos, ambient_light); imageStore(reflection_buffer, pos, reflection_light); + + if (sc_use_vrs) { + if (vrs_x > 1) { + imageStore(ambient_buffer, pos + ivec2(1, 0), ambient_light); + imageStore(reflection_buffer, pos + ivec2(1, 0), reflection_light); + } + + if (vrs_x > 2) { + imageStore(ambient_buffer, pos + ivec2(2, 0), ambient_light); + imageStore(reflection_buffer, pos + ivec2(2, 0), reflection_light); + + imageStore(ambient_buffer, pos + ivec2(3, 0), ambient_light); + imageStore(reflection_buffer, pos + ivec2(3, 0), reflection_light); + } + + if (vrs_y > 1) { + imageStore(ambient_buffer, pos + ivec2(0, 1), ambient_light); + imageStore(reflection_buffer, pos + ivec2(0, 1), reflection_light); + } + + if (vrs_y > 1 && vrs_x > 1) { + imageStore(ambient_buffer, pos + ivec2(1, 1), ambient_light); + imageStore(reflection_buffer, pos + ivec2(1, 1), reflection_light); + } + + if (vrs_y > 1 && vrs_x > 2) { + imageStore(ambient_buffer, pos + ivec2(2, 1), ambient_light); + imageStore(reflection_buffer, pos + ivec2(2, 1), reflection_light); + + imageStore(ambient_buffer, pos + ivec2(3, 1), ambient_light); + imageStore(reflection_buffer, pos + ivec2(3, 1), reflection_light); + } + + if (vrs_y > 2) { + imageStore(ambient_buffer, pos + ivec2(0, 2), ambient_light); + imageStore(reflection_buffer, pos + ivec2(0, 2), reflection_light); + imageStore(ambient_buffer, pos + ivec2(0, 3), ambient_light); + imageStore(reflection_buffer, pos + ivec2(0, 3), reflection_light); + } + + if (vrs_y > 2 && vrs_x > 1) { + imageStore(ambient_buffer, pos + ivec2(1, 2), ambient_light); + imageStore(reflection_buffer, pos + ivec2(1, 2), reflection_light); + imageStore(ambient_buffer, pos + ivec2(1, 3), ambient_light); + imageStore(reflection_buffer, pos + ivec2(1, 3), reflection_light); + } + + if (vrs_y > 2 && vrs_x > 2) { + imageStore(ambient_buffer, pos + ivec2(2, 2), ambient_light); + imageStore(reflection_buffer, pos + ivec2(2, 2), reflection_light); + imageStore(ambient_buffer, pos + ivec2(2, 3), ambient_light); + imageStore(reflection_buffer, pos + ivec2(2, 3), reflection_light); + + imageStore(ambient_buffer, pos + ivec2(3, 2), ambient_light); + imageStore(reflection_buffer, pos + ivec2(3, 2), reflection_light); + imageStore(ambient_buffer, pos + ivec2(3, 3), ambient_light); + imageStore(reflection_buffer, pos + ivec2(3, 3), reflection_light); + } + } } diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index 1109357a74..762ad685e8 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -349,7 +349,6 @@ TextureStorage::TextureStorage() { Vector<uint8_t> pv; pv.resize(16 * 4); - for (int i = 0; i < 16; i++) { pv.set(i * 4 + 0, 0); pv.set(i * 4 + 1, 0); @@ -358,7 +357,6 @@ TextureStorage::TextureStorage() { } { - //take the chance and initialize decal atlas to something Vector<Vector<uint8_t>> vpv; vpv.push_back(pv); decal_atlas.texture = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv); @@ -366,6 +364,29 @@ TextureStorage::TextureStorage() { } } + { //create default VRS + + RD::TextureFormat tformat; + tformat.format = RD::DATA_FORMAT_R8_UINT; + tformat.width = 4; + tformat.height = 4; + tformat.array_layers = 1; + tformat.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_VRS_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; + tformat.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; + + Vector<uint8_t> pv; + pv.resize(4 * 4); + for (int i = 0; i < 4 * 4; i++) { + pv.set(i, 0); + } + + { + Vector<Vector<uint8_t>> vpv; + vpv.push_back(pv); + default_rd_textures[DEFAULT_RD_TEXTURE_VRS] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv); + } + } + { Vector<String> sdf_modes; sdf_modes.push_back("\n#define MODE_LOAD\n"); @@ -2751,3 +2772,31 @@ void TextureStorage::render_target_set_backbuffer_uniform_set(RID p_render_targe ERR_FAIL_COND(!rt); rt->backbuffer_uniform_set = p_uniform_set; } + +void TextureStorage::render_target_set_vrs_mode(RID p_render_target, RS::ViewportVRSMode p_mode) { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND(!rt); + + rt->vrs_mode = p_mode; +} + +void TextureStorage::render_target_set_vrs_texture(RID p_render_target, RID p_texture) { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND(!rt); + + rt->vrs_texture = p_texture; +} + +RS::ViewportVRSMode TextureStorage::render_target_get_vrs_mode(RID p_render_target) const { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND_V(!rt, RS::VIEWPORT_VRS_DISABLED); + + return rt->vrs_mode; +} + +RID TextureStorage::render_target_get_vrs_texture(RID p_render_target) const { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND_V(!rt, RID()); + + return rt->vrs_texture; +} diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h index 7a96e6c6ed..ac95e13604 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h @@ -52,6 +52,7 @@ enum DefaultRDTexture { DEFAULT_RD_TEXTURE_3D_BLACK, DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE, DEFAULT_RD_TEXTURE_2D_UINT, + DEFAULT_RD_TEXTURE_VRS, DEFAULT_RD_TEXTURE_MAX }; @@ -229,6 +230,10 @@ struct RenderTarget { RS::ViewportSDFScale sdf_scale = RS::VIEWPORT_SDF_SCALE_50_PERCENT; Size2i process_size; + // VRS + RS::ViewportVRSMode vrs_mode = RS::VIEWPORT_VRS_DISABLED; + RID vrs_texture; + //texture generated for this owner (nor RD). RID texture; bool was_used; @@ -549,6 +554,12 @@ public: virtual void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) override; bool render_target_is_sdf_enabled(RID p_render_target) const; + virtual void render_target_set_vrs_mode(RID p_render_target, RS::ViewportVRSMode p_mode) override; + virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) override; + + RS::ViewportVRSMode render_target_get_vrs_mode(RID p_render_target) const; + RID render_target_get_vrs_texture(RID p_render_target) const; + Size2 render_target_get_size(RID p_render_target); RID render_target_get_rd_framebuffer(RID p_render_target); RID render_target_get_rd_texture(RID p_render_target); diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index 303efe50f7..7c9b2567d6 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -1207,6 +1207,22 @@ RID RendererViewport::viewport_find_from_screen_attachment(DisplayServer::Window return RID(); } +void RendererViewport::viewport_set_vrs_mode(RID p_viewport, RS::ViewportVRSMode p_mode) { + Viewport *viewport = viewport_owner.get_or_null(p_viewport); + ERR_FAIL_COND(!viewport); + + RSG::texture_storage->render_target_set_vrs_mode(viewport->render_target, p_mode); + _configure_3d_render_buffers(viewport); +} + +void RendererViewport::viewport_set_vrs_texture(RID p_viewport, RID p_texture) { + Viewport *viewport = viewport_owner.get_or_null(p_viewport); + ERR_FAIL_COND(!viewport); + + RSG::texture_storage->render_target_set_vrs_texture(viewport->render_target, p_texture); + _configure_3d_render_buffers(viewport); +} + bool RendererViewport::free(RID p_rid) { if (viewport_owner.owns(p_rid)) { Viewport *viewport = viewport_owner.get_or_null(p_rid); diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h index 49ee9a6224..027f2dfad6 100644 --- a/servers/rendering/renderer_viewport.h +++ b/servers/rendering/renderer_viewport.h @@ -284,6 +284,9 @@ public: virtual RID viewport_find_from_screen_attachment(DisplayServer::WindowID p_id = DisplayServer::MAIN_WINDOW_ID) const; + void viewport_set_vrs_mode(RID p_viewport, RS::ViewportVRSMode p_mode); + void viewport_set_vrs_texture(RID p_viewport, RID p_texture); + void handle_timestamp(String p_timestamp, uint64_t p_cpu_time, uint64_t p_gpu_time); void set_default_clear_color(const Color &p_color); diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 6fc5d0b3e8..0b76bb3051 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -64,12 +64,12 @@ Vector<uint8_t> RenderingDevice::shader_compile_spirv_from_source(ShaderStage p_ ERR_FAIL_COND_V(!compile_to_spirv_function, Vector<uint8_t>()); - return compile_to_spirv_function(p_stage, p_source_code, p_language, r_error, &device_capabilities); + return compile_to_spirv_function(p_stage, p_source_code, p_language, r_error, this); } String RenderingDevice::shader_get_spirv_cache_key() const { if (get_spirv_cache_key_function) { - return get_spirv_cache_key_function(&device_capabilities); + return get_spirv_cache_key_function(this); } return String(); } @@ -279,6 +279,7 @@ static Vector<RenderingDevice::PipelineSpecializationConstant> _get_spec_constan } return ret; } + RID RenderingDevice::_render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, int p_dynamic_state_flags, uint32_t p_for_render_pass, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants) { PipelineRasterizationState rasterization_state; if (p_rasterization_state.is_valid()) { diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index 0973e29974..03aa6f7644 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -123,19 +123,10 @@ public: DeviceFamily device_family = DEVICE_UNKNOWN; uint32_t version_major = 1.0; uint32_t version_minor = 0.0; - - // subgroup capabilities - uint32_t subgroup_size = 0; - uint32_t subgroup_in_shaders = 0; // Set flags using SHADER_STAGE_VERTEX_BIT, SHADER_STAGE_FRAGMENT_BIT, etc. - uint32_t subgroup_operations = 0; // Set flags, using SubgroupOperations - - // 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); - typedef Vector<uint8_t> (*ShaderCompileToSPIRVFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, const Capabilities *p_capabilities); + typedef String (*ShaderSPIRVGetCacheKeyFunction)(const RenderingDevice *p_render_device); + typedef Vector<uint8_t> (*ShaderCompileToSPIRVFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, const RenderingDevice *p_render_device); typedef Vector<uint8_t> (*ShaderCacheFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language); private: @@ -444,6 +435,7 @@ public: TEXTURE_USAGE_CAN_COPY_FROM_BIT = (1 << 7), TEXTURE_USAGE_CAN_COPY_TO_BIT = (1 << 8), TEXTURE_USAGE_INPUT_ATTACHMENT_BIT = (1 << 9), + TEXTURE_USAGE_VRS_ATTACHMENT_BIT = (1 << 10), }; enum TextureSwizzle { @@ -552,6 +544,7 @@ public: Vector<int32_t> resolve_attachments; Vector<int32_t> preserve_attachments; int32_t depth_attachment = ATTACHMENT_UNUSED; + int32_t vrs_attachment = ATTACHMENT_UNUSED; // density map for VRS, only used if supported }; virtual FramebufferFormatID framebuffer_format_create_multipass(const Vector<AttachmentFormat> &p_attachments, Vector<FramebufferPass> &p_passes, uint32_t p_view_count = 1) = 0; @@ -675,6 +668,13 @@ public: const Capabilities *get_device_capabilities() const { return &device_capabilities; }; + enum Features { + SUPPORTS_MULTIVIEW, + SUPPORTS_FSR_HALF_FLOAT, + SUPPORTS_ATTACHMENT_VRS, + }; + virtual bool has_feature(const Features p_feature) const = 0; + virtual Vector<uint8_t> shader_compile_spirv_from_source(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language = SHADER_LANGUAGE_GLSL, String *r_error = nullptr, bool p_allow_cache = true); virtual String shader_get_spirv_cache_key() const; @@ -1221,9 +1221,12 @@ public: LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_X, LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Y, LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z, + LIMIT_SUBGROUP_SIZE, + LIMIT_SUBGROUP_IN_SHADERS, // Set flags using SHADER_STAGE_VERTEX_BIT, SHADER_STAGE_FRAGMENT_BIT, etc. + LIMIT_SUBGROUP_OPERATIONS, }; - virtual uint64_t limit_get(Limit p_limit) = 0; + virtual uint64_t limit_get(Limit p_limit) const = 0; //methods below not exposed, used by RenderingDeviceRD virtual void prepare_screen_for_drawing() = 0; @@ -1324,6 +1327,7 @@ VARIANT_ENUM_CAST(RenderingDevice::InitialAction) VARIANT_ENUM_CAST(RenderingDevice::FinalAction) VARIANT_ENUM_CAST(RenderingDevice::Limit) VARIANT_ENUM_CAST(RenderingDevice::MemoryType) +VARIANT_ENUM_CAST(RenderingDevice::Features) typedef RenderingDevice RD; diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index 9dfd8ffb94..429b8a06e2 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -637,6 +637,9 @@ public: FUNC2(call_set_vsync_mode, DisplayServer::VSyncMode, DisplayServer::WindowID) + FUNC2(viewport_set_vrs_mode, RID, ViewportVRSMode) + FUNC2(viewport_set_vrs_texture, RID, RID) + /* ENVIRONMENT API */ #undef server_name diff --git a/servers/rendering/storage/texture_storage.h b/servers/rendering/storage/texture_storage.h index e90a028713..92238c19ee 100644 --- a/servers/rendering/storage/texture_storage.h +++ b/servers/rendering/storage/texture_storage.h @@ -143,6 +143,9 @@ public: virtual void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) = 0; virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const = 0; virtual void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) = 0; + + virtual void render_target_set_vrs_mode(RID p_render_target, RS::ViewportVRSMode p_mode) = 0; + virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) = 0; }; #endif // !TEXTURE_STORAGE_H diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 354cada5ce..5ee12d04d9 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2225,6 +2225,9 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("viewport_get_measured_render_time_gpu", "viewport"), &RenderingServer::viewport_get_measured_render_time_gpu); + ClassDB::bind_method(D_METHOD("viewport_set_vrs_mode", "viewport", "mode"), &RenderingServer::viewport_set_vrs_mode); + ClassDB::bind_method(D_METHOD("viewport_set_vrs_texture", "viewport", "texture"), &RenderingServer::viewport_set_vrs_texture); + BIND_ENUM_CONSTANT(VIEWPORT_SCALING_3D_MODE_BILINEAR); BIND_ENUM_CONSTANT(VIEWPORT_SCALING_3D_MODE_FSR); BIND_ENUM_CONSTANT(VIEWPORT_SCALING_3D_MODE_MAX); @@ -2300,6 +2303,11 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_OCCLUDERS); BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_MOTION_VECTORS); + BIND_ENUM_CONSTANT(VIEWPORT_VRS_DISABLED); + BIND_ENUM_CONSTANT(VIEWPORT_VRS_TEXTURE); + BIND_ENUM_CONSTANT(VIEWPORT_VRS_XR); + BIND_ENUM_CONSTANT(VIEWPORT_VRS_MAX); + /* SKY API */ ClassDB::bind_method(D_METHOD("sky_create"), &RenderingServer::sky_create); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index ff6d27a4a8..8d224f2832 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -946,6 +946,16 @@ public: virtual RID viewport_find_from_screen_attachment(DisplayServer::WindowID p_id = DisplayServer::MAIN_WINDOW_ID) const = 0; + enum ViewportVRSMode { + VIEWPORT_VRS_DISABLED, + VIEWPORT_VRS_TEXTURE, + VIEWPORT_VRS_XR, + VIEWPORT_VRS_MAX, + }; + + virtual void viewport_set_vrs_mode(RID p_viewport, ViewportVRSMode p_mode) = 0; + virtual void viewport_set_vrs_texture(RID p_viewport, RID p_texture) = 0; + /* SKY API */ enum SkyMode { @@ -1609,6 +1619,7 @@ VARIANT_ENUM_CAST(RenderingServer::ViewportDebugDraw); VARIANT_ENUM_CAST(RenderingServer::ViewportOcclusionCullingBuildQuality); VARIANT_ENUM_CAST(RenderingServer::ViewportSDFOversize); VARIANT_ENUM_CAST(RenderingServer::ViewportSDFScale); +VARIANT_ENUM_CAST(RenderingServer::ViewportVRSMode); VARIANT_ENUM_CAST(RenderingServer::SkyMode); VARIANT_ENUM_CAST(RenderingServer::EnvironmentBG); VARIANT_ENUM_CAST(RenderingServer::EnvironmentAmbientSource); diff --git a/servers/xr/xr_interface.cpp b/servers/xr/xr_interface.cpp index 7ae111b5e7..0808b1fd7b 100644 --- a/servers/xr/xr_interface.cpp +++ b/servers/xr/xr_interface.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "xr_interface.h" -// #include "servers/rendering/renderer_compositor.h" +#include "servers/rendering/renderer_compositor.h" void XRInterface::_bind_methods() { ADD_SIGNAL(MethodInfo("play_area_changed", PropertyInfo(Variant::INT, "mode"))); @@ -114,7 +114,12 @@ void XRInterface::set_primary(bool p_primary) { XRInterface::XRInterface() {} -XRInterface::~XRInterface() {} +XRInterface::~XRInterface() { + if (vrs.vrs_texture.is_valid()) { + RS::get_singleton()->free(vrs.vrs_texture); + vrs.vrs_texture = RID(); + } +} // query if this interface supports this play area mode bool XRInterface::supports_play_area_mode(XRInterface::PlayAreaMode p_mode) { @@ -151,6 +156,85 @@ int XRInterface::get_camera_feed_id() { return 0; } +RID XRInterface::get_vrs_texture() { + // Default logic will return a standard VRS image based on our target size and default projections. + // Note that this only gets called if VRS is supported on the hardware. + + Size2 texel_size = Size2(16.0, 16.0); // For now we assume we always use 16x16 texels, seems to be the standard. + int view_count = get_view_count(); + Size2 target_size = get_render_target_size(); + real_t aspect = target_size.x / target_size.y; // is this y/x ? + Size2 vrs_size = Size2(round(0.5 + target_size.x / texel_size.x), round(0.5 + target_size.y / texel_size.y)); + real_t radius = vrs_size.length() * 0.5; + Size2 vrs_sizei = vrs_size; + + if (vrs.size != vrs_sizei) { + const uint8_t densities[] = { + 0, // 1x1 + 1, // 1x2 + // 4, // 2x1 + 5, // 2x2 + 6, // 2x4 + // 9, // 4x2 + 10, // 4x4 + }; + + // out with the old + if (vrs.vrs_texture.is_valid()) { + RS::get_singleton()->free(vrs.vrs_texture); + vrs.vrs_texture = RID(); + } + + // in with the new + Vector<Ref<Image>> images; + vrs.size = vrs_sizei; + + for (int i = 0; i < view_count && i < 2; i++) { + PackedByteArray data; + data.resize(vrs_sizei.x * vrs_sizei.y); + uint8_t *data_ptr = data.ptrw(); + + // Our near and far don't matter much for what we're doing here, but there are some interfaces that will remember this as the near and far and may fail as a result... + CameraMatrix cm = get_projection_for_view(i, aspect, 0.1, 1000.0); + Vector3 center = cm.xform(Vector3(0.0, 0.0, 999.0)); + + Vector2i view_center; + view_center.x = int(vrs_size.x * (center.x + 1.0) * 0.5); + view_center.y = int(vrs_size.y * (center.y + 1.0) * 0.5); + + int d = 0; + for (int y = 0; y < vrs_sizei.y; y++) { + for (int x = 0; x < vrs_sizei.x; x++) { + Vector2 offset = Vector2(x - view_center.x, y - view_center.y); + offset.y *= aspect; + real_t distance = offset.length(); + int idx = round(5.0 * distance / radius); + if (idx > 4) { + idx = 4; + } + uint8_t density = densities[idx]; + + data_ptr[d++] = density; + } + } + + Ref<Image> image; + image.instantiate(); + image->create_from_data(vrs_sizei.x, vrs_sizei.y, false, Image::FORMAT_R8, data); + + images.push_back(image); + } + + if (images.size() == 1) { + vrs.vrs_texture = RS::get_singleton()->texture_2d_create(images[0]); + } else { + vrs.vrs_texture = RS::get_singleton()->texture_2d_layered_create(images, RS::TEXTURE_LAYERED_2D_ARRAY); + } + } + + return vrs.vrs_texture; +} + /** these are optional, so we want dummies **/ PackedStringArray XRInterface::get_suggested_tracker_names() const { PackedStringArray arr; diff --git a/servers/xr/xr_interface.h b/servers/xr/xr_interface.h index 62eba2f00b..b4eb4694f6 100644 --- a/servers/xr/xr_interface.h +++ b/servers/xr/xr_interface.h @@ -120,6 +120,7 @@ public: virtual Transform3D get_camera_transform() = 0; /* returns the position of our camera for updating our camera node. For monoscopic this is equal to the views transform, for stereoscopic this should be an average */ virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) = 0; /* get each views transform */ virtual CameraMatrix get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) = 0; /* get each view projection matrix */ + virtual RID get_vrs_texture(); /* obtain VRS texture */ // note, external color/depth/vrs texture support will be added here soon. @@ -133,6 +134,12 @@ public: XRInterface(); ~XRInterface(); + +private: + struct VRSData { + RID vrs_texture; + Size2i size; + } vrs; }; VARIANT_ENUM_CAST(XRInterface::Capabilities); diff --git a/servers/xr/xr_interface_extension.cpp b/servers/xr/xr_interface_extension.cpp index 1f3d07c357..94953c69a9 100644 --- a/servers/xr/xr_interface_extension.cpp +++ b/servers/xr/xr_interface_extension.cpp @@ -50,6 +50,7 @@ void XRInterfaceExtension::_bind_methods() { GDVIRTUAL_BIND(_get_camera_transform); GDVIRTUAL_BIND(_get_transform_for_view, "view", "cam_transform"); GDVIRTUAL_BIND(_get_projection_for_view, "view", "aspect", "z_near", "z_far"); + GDVIRTUAL_BIND(_get_vrs_texture); GDVIRTUAL_BIND(_process); GDVIRTUAL_BIND(_pre_render); @@ -273,6 +274,15 @@ CameraMatrix XRInterfaceExtension::get_projection_for_view(uint32_t p_view, doub return CameraMatrix(); } +RID XRInterfaceExtension::get_vrs_texture() { + RID vrs_texture; + if (GDVIRTUAL_CALL(_get_vrs_texture, vrs_texture)) { + return vrs_texture; + } else { + return XRInterface::get_vrs_texture(); + } +} + void XRInterfaceExtension::add_blit(RID p_render_target, Rect2 p_src_rect, Rect2i p_dst_rect, bool p_use_layer, uint32_t p_layer, bool p_apply_lens_distortion, Vector2 p_eye_center, double p_k1, double p_k2, double p_upscale, double p_aspect_ratio) { BlitToScreen blit; diff --git a/servers/xr/xr_interface_extension.h b/servers/xr/xr_interface_extension.h index 5a436b9fd0..7174b412c5 100644 --- a/servers/xr/xr_interface_extension.h +++ b/servers/xr/xr_interface_extension.h @@ -101,12 +101,14 @@ public: virtual Transform3D get_camera_transform() override; virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) override; virtual CameraMatrix get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) override; + virtual RID get_vrs_texture() override; GDVIRTUAL0R(Size2, _get_render_target_size); GDVIRTUAL0R(uint32_t, _get_view_count); GDVIRTUAL0R(Transform3D, _get_camera_transform); GDVIRTUAL2R(Transform3D, _get_transform_for_view, uint32_t, const Transform3D &); GDVIRTUAL4R(PackedFloat64Array, _get_projection_for_view, uint32_t, double, double, double); + GDVIRTUAL0R(RID, _get_vrs_texture); void add_blit(RID p_render_target, Rect2 p_src_rect, Rect2i p_dst_rect, bool p_use_layer = false, uint32_t p_layer = 0, bool p_apply_lens_distortion = false, Vector2 p_eye_center = Vector2(), double p_k1 = 0.0, double p_k2 = 0.0, double p_upscale = 1.0, double p_aspect_ratio = 1.0); |