summaryrefslogtreecommitdiffstats
path: root/servers/rendering/renderer_rd
diff options
context:
space:
mode:
Diffstat (limited to 'servers/rendering/renderer_rd')
-rw-r--r--servers/rendering/renderer_rd/cluster_builder_rd.cpp21
-rw-r--r--servers/rendering/renderer_rd/effects/SCsub31
-rw-r--r--servers/rendering/renderer_rd/effects/bokeh_dof.cpp18
-rw-r--r--servers/rendering/renderer_rd/effects/copy_effects.cpp26
-rw-r--r--servers/rendering/renderer_rd/effects/debug_effects.cpp69
-rw-r--r--servers/rendering/renderer_rd/effects/debug_effects.h16
-rw-r--r--servers/rendering/renderer_rd/effects/fsr2.cpp891
-rw-r--r--servers/rendering/renderer_rd/effects/fsr2.h199
-rw-r--r--servers/rendering/renderer_rd/effects/luminance.cpp3
-rw-r--r--servers/rendering/renderer_rd/effects/ss_effects.cpp2
-rw-r--r--servers/rendering/renderer_rd/effects/taa.cpp14
-rw-r--r--servers/rendering/renderer_rd/effects/taa.h1
-rw-r--r--servers/rendering/renderer_rd/effects/tone_mapper.cpp32
-rw-r--r--servers/rendering/renderer_rd/effects/tone_mapper.h25
-rw-r--r--servers/rendering/renderer_rd/effects/vrs.cpp3
-rw-r--r--servers/rendering/renderer_rd/environment/fog.cpp32
-rw-r--r--servers/rendering/renderer_rd/environment/fog.h8
-rw-r--r--servers/rendering/renderer_rd/environment/gi.cpp147
-rw-r--r--servers/rendering/renderer_rd/environment/gi.h2
-rw-r--r--servers/rendering/renderer_rd/environment/sky.cpp78
-rw-r--r--servers/rendering/renderer_rd/environment/sky.h5
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp333
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h26
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp6
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h2
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp315
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h54
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp8
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h2
-rw-r--r--servers/rendering/renderer_rd/pipeline_cache_rd.h2
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp170
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.h11
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.cpp27
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.h2
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp48
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.h1
-rw-r--r--servers/rendering/renderer_rd/shader_rd.cpp8
-rw-r--r--servers/rendering/renderer_rd/shader_rd.h2
-rw-r--r--servers/rendering/renderer_rd/shaders/blit.glsl13
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas.glsl21
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/SCsub2
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/blur_raster.glsl7
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl7
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/copy.glsl27
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_raster.glsl6
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/cubemap_filter_raster.glsl6
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/cubemap_roughness_raster.glsl6
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/fsr2/SCsub17
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_accumulate_pass.glsl8
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_autogen_reactive_pass.glsl8
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_compute_luminance_pyramid_pass.glsl7
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_depth_clip_pass.glsl8
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_lock_pass.glsl7
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_rcas_pass.glsl7
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_reconstruct_previous_depth_pass.glsl8
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_tcr_autogen_pass.glsl8
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/luminance_reduce_raster.glsl7
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/motion_vector_inc.glsl6
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/motion_vectors.glsl97
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl47
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/specular_merge.glsl15
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/taa_resolve.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/tonemap.glsl54
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/vrs.glsl7
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/sky.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl5
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl224
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl7
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl145
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl40
-rw-r--r--servers/rendering/renderer_rd/shaders/particles.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/particles_copy.glsl25
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_data_inc.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/skeleton.glsl28
-rw-r--r--servers/rendering/renderer_rd/storage_rd/light_storage.cpp188
-rw-r--r--servers/rendering/renderer_rd/storage_rd/light_storage.h67
-rw-r--r--servers/rendering/renderer_rd/storage_rd/material_storage.cpp416
-rw-r--r--servers/rendering/renderer_rd/storage_rd/material_storage.h38
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp498
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.h83
-rw-r--r--servers/rendering/renderer_rd/storage_rd/particles_storage.cpp249
-rw-r--r--servers/rendering/renderer_rd/storage_rd/particles_storage.h45
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp108
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h48
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp9
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h4
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.cpp251
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.h7
-rw-r--r--servers/rendering/renderer_rd/storage_rd/utilities.cpp16
92 files changed, 3947 insertions, 1618 deletions
diff --git a/servers/rendering/renderer_rd/cluster_builder_rd.cpp b/servers/rendering/renderer_rd/cluster_builder_rd.cpp
index d2a1a5ab9c..7554e478bb 100644
--- a/servers/rendering/renderer_rd/cluster_builder_rd.cpp
+++ b/servers/rendering/renderer_rd/cluster_builder_rd.cpp
@@ -58,6 +58,7 @@ ClusterBuilderSharedDataRD::ClusterBuilderSharedDataRD() {
afs.push_back(RD::AttachmentFormat());
afs.write[0].usage_flags = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
fb_format = RD::get_singleton()->framebuffer_format_create(afs);
+ blend_state = RD::PipelineColorBlendState::create_blend();
defines = "\n#define USE_ATTACHMENT\n";
}
@@ -94,7 +95,7 @@ ClusterBuilderSharedDataRD::ClusterBuilderSharedDataRD() {
0, 0, -1, 0.7236073, -0.5257253, -0.4472195, -0.276388, -0.8506492, -0.4472199, -0.8944262, 0, -0.4472156, -0.276388, 0.8506492, -0.4472199, 0.7236073, 0.5257253, -0.4472195, 0.276388, -0.8506492, 0.4472199, -0.7236073, -0.5257253, 0.4472195, -0.7236073, 0.5257253, 0.4472195, 0.276388, 0.8506492, 0.4472199, 0.8944262, 0, 0.4472156, 0, 0, 1, -0.1624555, -0.4999952, -0.8506544, 0.4253227, -0.3090114, -0.8506542, 0.2628688, -0.8090116, -0.5257377, 0.8506479, 0, -0.5257359, 0.4253227, 0.3090114, -0.8506542, -0.5257298, 0, -0.8506517, -0.6881894, -0.4999969, -0.5257362, -0.1624555, 0.4999952, -0.8506544, -0.6881894, 0.4999969, -0.5257362, 0.2628688, 0.8090116, -0.5257377, 0.9510579, -0.3090126, 0, 0.9510579, 0.3090126, 0, 0, -1, 0, 0.5877856, -0.8090167, 0, -0.9510579, -0.3090126, 0, -0.5877856, -0.8090167, 0, -0.5877856, 0.8090167, 0, -0.9510579, 0.3090126, 0, 0.5877856, 0.8090167, 0, 0, 1, 0, 0.6881894, -0.4999969, 0.5257362, -0.2628688, -0.8090116, 0.5257377, -0.8506479, 0, 0.5257359, -0.2628688, 0.8090116, 0.5257377, 0.6881894, 0.4999969, 0.5257362, 0.1624555, -0.4999952, 0.8506544, 0.5257298, 0, 0.8506517, -0.4253227, -0.3090114, 0.8506542, -0.4253227, 0.3090114, 0.8506542, 0.1624555, 0.4999952, 0.8506544
};
static const uint32_t icosphere_triangle_count = 80;
- static const uint32_t icosphere_triangle_indices[icosphere_triangle_count * 3] = {
+ static const uint16_t icosphere_triangle_indices[icosphere_triangle_count * 3] = {
0, 13, 12, 1, 13, 15, 0, 12, 17, 0, 17, 19, 0, 19, 16, 1, 15, 22, 2, 14, 24, 3, 18, 26, 4, 20, 28, 5, 21, 30, 1, 22, 25, 2, 24, 27, 3, 26, 29, 4, 28, 31, 5, 30, 23, 6, 32, 37, 7, 33, 39, 8, 34, 40, 9, 35, 41, 10, 36, 38, 38, 41, 11, 38, 36, 41, 36, 9, 41, 41, 40, 11, 41, 35, 40, 35, 8, 40, 40, 39, 11, 40, 34, 39, 34, 7, 39, 39, 37, 11, 39, 33, 37, 33, 6, 37, 37, 38, 11, 37, 32, 38, 32, 10, 38, 23, 36, 10, 23, 30, 36, 30, 9, 36, 31, 35, 9, 31, 28, 35, 28, 8, 35, 29, 34, 8, 29, 26, 34, 26, 7, 34, 27, 33, 7, 27, 24, 33, 24, 6, 33, 25, 32, 6, 25, 22, 32, 22, 10, 32, 30, 31, 9, 30, 21, 31, 21, 4, 31, 28, 29, 8, 28, 20, 29, 20, 3, 29, 26, 27, 7, 26, 18, 27, 18, 2, 27, 24, 25, 6, 24, 14, 25, 14, 1, 25, 22, 23, 10, 22, 15, 23, 15, 5, 23, 16, 21, 5, 16, 19, 21, 19, 4, 21, 19, 20, 4, 19, 17, 20, 17, 3, 20, 17, 18, 3, 17, 12, 18, 12, 2, 18, 15, 16, 5, 15, 13, 16, 13, 0, 16, 12, 14, 2, 12, 13, 14, 13, 1, 14
};
@@ -105,10 +106,10 @@ ClusterBuilderSharedDataRD::ClusterBuilderSharedDataRD() {
sphere_vertex_buffer = RD::get_singleton()->vertex_buffer_create(vertex_data.size(), vertex_data);
Vector<uint8_t> index_data;
- index_data.resize(sizeof(uint32_t) * icosphere_triangle_count * 3);
+ index_data.resize(sizeof(uint16_t) * icosphere_triangle_count * 3);
memcpy(index_data.ptrw(), icosphere_triangle_indices, index_data.size());
- sphere_index_buffer = RD::get_singleton()->index_buffer_create(icosphere_triangle_count * 3, RD::INDEX_BUFFER_FORMAT_UINT32, index_data);
+ sphere_index_buffer = RD::get_singleton()->index_buffer_create(icosphere_triangle_count * 3, RD::INDEX_BUFFER_FORMAT_UINT16, index_data);
Vector<RID> buffers;
buffers.push_back(sphere_vertex_buffer);
@@ -138,7 +139,7 @@ ClusterBuilderSharedDataRD::ClusterBuilderSharedDataRD() {
0, 1, -1, 0.1950903, 0.9807853, -1, 0.3826835, 0.9238795, -1, 0.5555703, 0.8314696, -1, 0.7071068, 0.7071068, -1, 0.8314697, 0.5555702, -1, 0.9238795, 0.3826834, -1, 0.9807853, 0.1950903, -1, 1, 0, -1, 0.9807853, -0.1950902, -1, 0.9238796, -0.3826833, -1, 0.8314697, -0.5555702, -1, 0.7071068, -0.7071068, -1, 0.5555702, -0.8314697, -1, 0.3826833, -0.9238796, -1, 0.1950901, -0.9807853, -1, -3.25841e-7, -1, -1, -0.1950907, -0.9807852, -1, -0.3826839, -0.9238793, -1, -0.5555707, -0.8314693, -1, -0.7071073, -0.7071063, -1, -0.83147, -0.5555697, -1, -0.9238799, -0.3826827, -1, 0, 0, 0, -0.9807854, -0.1950894, -1, -1, 9.65599e-7, -1, -0.9807851, 0.1950913, -1, -0.9238791, 0.3826845, -1, -0.8314689, 0.5555713, -1, -0.7071059, 0.7071077, -1, -0.5555691, 0.8314704, -1, -0.3826821, 0.9238801, -1, -0.1950888, 0.9807856, -1
};
static const uint32_t cone_triangle_count = 62;
- static const uint32_t cone_triangle_indices[cone_triangle_count * 3] = {
+ static const uint16_t cone_triangle_indices[cone_triangle_count * 3] = {
0, 23, 1, 1, 23, 2, 2, 23, 3, 3, 23, 4, 4, 23, 5, 5, 23, 6, 6, 23, 7, 7, 23, 8, 8, 23, 9, 9, 23, 10, 10, 23, 11, 11, 23, 12, 12, 23, 13, 13, 23, 14, 14, 23, 15, 15, 23, 16, 16, 23, 17, 17, 23, 18, 18, 23, 19, 19, 23, 20, 20, 23, 21, 21, 23, 22, 22, 23, 24, 24, 23, 25, 25, 23, 26, 26, 23, 27, 27, 23, 28, 28, 23, 29, 29, 23, 30, 30, 23, 31, 31, 23, 32, 32, 23, 0, 7, 15, 24, 32, 0, 1, 1, 2, 3, 3, 4, 5, 5, 6, 3, 6, 7, 3, 7, 8, 9, 9, 10, 7, 10, 11, 7, 11, 12, 15, 12, 13, 15, 13, 14, 15, 15, 16, 17, 17, 18, 19, 19, 20, 24, 20, 21, 24, 21, 22, 24, 24, 25, 26, 26, 27, 28, 28, 29, 30, 30, 31, 32, 32, 1, 3, 15, 17, 24, 17, 19, 24, 24, 26, 32, 26, 28, 32, 28, 30, 32, 32, 3, 7, 7, 11, 15, 32, 7, 24
};
@@ -149,10 +150,10 @@ ClusterBuilderSharedDataRD::ClusterBuilderSharedDataRD() {
cone_vertex_buffer = RD::get_singleton()->vertex_buffer_create(vertex_data.size(), vertex_data);
Vector<uint8_t> index_data;
- index_data.resize(sizeof(uint32_t) * cone_triangle_count * 3);
+ index_data.resize(sizeof(uint16_t) * cone_triangle_count * 3);
memcpy(index_data.ptrw(), cone_triangle_indices, index_data.size());
- cone_index_buffer = RD::get_singleton()->index_buffer_create(cone_triangle_count * 3, RD::INDEX_BUFFER_FORMAT_UINT32, index_data);
+ cone_index_buffer = RD::get_singleton()->index_buffer_create(cone_triangle_count * 3, RD::INDEX_BUFFER_FORMAT_UINT16, index_data);
Vector<RID> buffers;
buffers.push_back(cone_vertex_buffer);
@@ -192,7 +193,7 @@ ClusterBuilderSharedDataRD::ClusterBuilderSharedDataRD() {
-1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1
};
static const uint32_t box_triangle_count = 12;
- static const uint32_t box_triangle_indices[box_triangle_count * 3] = {
+ static const uint16_t box_triangle_indices[box_triangle_count * 3] = {
1, 2, 0, 3, 6, 2, 7, 4, 6, 5, 0, 4, 6, 0, 2, 3, 5, 7, 1, 3, 2, 3, 7, 6, 7, 5, 4, 5, 1, 0, 6, 4, 0, 3, 1, 5
};
@@ -203,10 +204,10 @@ ClusterBuilderSharedDataRD::ClusterBuilderSharedDataRD() {
box_vertex_buffer = RD::get_singleton()->vertex_buffer_create(vertex_data.size(), vertex_data);
Vector<uint8_t> index_data;
- index_data.resize(sizeof(uint32_t) * box_triangle_count * 3);
+ index_data.resize(sizeof(uint16_t) * box_triangle_count * 3);
memcpy(index_data.ptrw(), box_triangle_indices, index_data.size());
- box_index_buffer = RD::get_singleton()->index_buffer_create(box_triangle_count * 3, RD::INDEX_BUFFER_FORMAT_UINT32, index_data);
+ box_index_buffer = RD::get_singleton()->index_buffer_create(box_triangle_count * 3, RD::INDEX_BUFFER_FORMAT_UINT16, index_data);
Vector<RID> buffers;
buffers.push_back(box_vertex_buffer);
@@ -285,7 +286,7 @@ void ClusterBuilderRD::setup(Size2i p_screen_size, uint32_t p_max_elements, RID
cluster_render_buffer = RD::get_singleton()->storage_buffer_create(cluster_render_buffer_size);
cluster_buffer = RD::get_singleton()->storage_buffer_create(cluster_buffer_size);
- render_elements = static_cast<RenderElementData *>(memalloc(sizeof(RenderElementData *) * render_element_max));
+ render_elements = static_cast<RenderElementData *>(memalloc(sizeof(RenderElementData) * render_element_max));
render_element_count = 0;
element_buffer = RD::get_singleton()->storage_buffer_create(sizeof(RenderElementData) * render_element_max);
diff --git a/servers/rendering/renderer_rd/effects/SCsub b/servers/rendering/renderer_rd/effects/SCsub
index 86681f9c74..8e13715447 100644
--- a/servers/rendering/renderer_rd/effects/SCsub
+++ b/servers/rendering/renderer_rd/effects/SCsub
@@ -2,4 +2,33 @@
Import("env")
-env.add_source_files(env.servers_sources, "*.cpp")
+env_effects = env.Clone()
+
+# Thirdparty source files
+
+thirdparty_obj = []
+
+thirdparty_dir = "#thirdparty/amd-fsr2/"
+thirdparty_sources = ["ffx_assert.cpp", "ffx_fsr2.cpp"]
+thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
+
+env_effects.Prepend(CPPPATH=[thirdparty_dir])
+
+# This flag doesn't actually control anything GCC specific in FSR2. It determines
+# if symbols should be exported, which is not required for Godot.
+env_effects.Append(CPPDEFINES=["FFX_GCC"])
+
+env_thirdparty = env_effects.Clone()
+env_thirdparty.disable_warnings()
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.servers_sources += thirdparty_obj
+
+# Godot source files
+
+module_obj = []
+
+env_effects.add_source_files(module_obj, "*.cpp")
+env.servers_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/servers/rendering/renderer_rd/effects/bokeh_dof.cpp b/servers/rendering/renderer_rd/effects/bokeh_dof.cpp
index 971f8b7f6f..cc5031823e 100644
--- a/servers/rendering/renderer_rd/effects/bokeh_dof.cpp
+++ b/servers/rendering/renderer_rd/effects/bokeh_dof.cpp
@@ -359,11 +359,10 @@ void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, RID p_camera_attr
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[BOKEH_GEN_BLUR_SIZE].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_depth_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, &bokeh.push_constant, sizeof(BokehPushConstant));
- RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
}
@@ -393,11 +392,10 @@ void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, RID p_camera_attr
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_base_texture), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_weight_texture0), 1);
- 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, &bokeh.push_constant, sizeof(BokehPushConstant));
- RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
// Pass 2
@@ -418,11 +416,10 @@ void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, RID p_camera_attr
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, texture), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, weight), 1);
- 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, &bokeh.push_constant, sizeof(BokehPushConstant));
- RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
if (bokeh.push_constant.half_size) {
@@ -438,11 +435,10 @@ void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, RID p_camera_attr
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_half_texture1), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_weight_texture3), 1);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 2, u_weight_texture0), 2);
- 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, &bokeh.push_constant, sizeof(BokehPushConstant));
- RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
}
@@ -471,11 +467,10 @@ void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, RID p_camera_attr
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_base_texture), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_weight_texture0), 1);
- 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, &bokeh.push_constant, sizeof(BokehPushConstant));
- RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
if (bokeh.push_constant.half_size) {
@@ -491,11 +486,10 @@ void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, RID p_camera_attr
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_half_texture0), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_weight_texture2), 1);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 2, u_weight_texture0), 2);
- 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, &bokeh.push_constant, sizeof(BokehPushConstant));
- RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
} else {
CopyEffects::get_singleton()->copy_raster(p_buffers.secondary_texture, p_buffers.base_fb);
diff --git a/servers/rendering/renderer_rd/effects/copy_effects.cpp b/servers/rendering/renderer_rd/effects/copy_effects.cpp
index eba1c145e3..aa1a87cdd7 100644
--- a/servers/rendering/renderer_rd/effects/copy_effects.cpp
+++ b/servers/rendering/renderer_rd/effects/copy_effects.cpp
@@ -281,8 +281,8 @@ CopyEffects::CopyEffects(bool p_prefer_raster_effects) {
ba.enable_blend = true;
ba.src_color_blend_factor = RD::BLEND_FACTOR_ONE;
ba.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
- ba.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
- ba.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+ ba.src_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
+ ba.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
ba.color_blend_op = RD::BLEND_OP_ADD;
ba.alpha_blend_op = RD::BLEND_OP_ADD;
@@ -696,11 +696,9 @@ void CopyEffects::gaussian_blur_raster(RID p_source_rd_texture, RID p_dest_textu
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(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, &blur_raster.push_constant, sizeof(BlurRasterPushConstant));
- RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
}
@@ -803,12 +801,11 @@ void CopyEffects::gaussian_glow_raster(RID p_source_rd_texture, RID p_half_textu
RD::Uniform u_auto_exposure(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_auto_exposure }));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_auto_exposure), 1);
}
- RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array());
blur_raster.push_constant.flags = base_flags | BLUR_FLAG_HORIZONTAL | (p_first_pass ? BLUR_FLAG_GLOW_FIRST_PASS : 0);
RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur_raster.push_constant, sizeof(BlurRasterPushConstant));
- RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
blur_mode = BLUR_MODE_GAUSSIAN_GLOW;
@@ -820,12 +817,11 @@ void CopyEffects::gaussian_glow_raster(RID p_source_rd_texture, RID p_half_textu
draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(dest_framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_half_texture), 0);
- RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array());
blur_raster.push_constant.flags = base_flags;
RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur_raster.push_constant, sizeof(BlurRasterPushConstant));
- RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
}
@@ -1055,11 +1051,10 @@ void CopyEffects::cubemap_downsample_raster(RID p_source_cubemap, RID p_dest_fra
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);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, cubemap_downsampler.raster_pipeline.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_cubemap), 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, &cubemap_downsampler.push_constant, sizeof(CubemapDownsamplerPushConstant));
- RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
}
@@ -1136,11 +1131,10 @@ void CopyEffects::cubemap_filter_raster(RID p_source_cubemap, RID p_dest_framebu
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, filter.raster_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_cubemap), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, filter.uniform_set, 1);
- 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, &push_constant, sizeof(CubemapFilterRasterPushConstant));
- RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
}
@@ -1214,11 +1208,10 @@ void CopyEffects::cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_f
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);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, roughness.raster_pipeline.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, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant));
- RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
}
@@ -1269,8 +1262,7 @@ void CopyEffects::merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_b
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_reflection), 1);
}
- RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array());
- RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
RD::get_singleton()->draw_command_end_label();
diff --git a/servers/rendering/renderer_rd/effects/debug_effects.cpp b/servers/rendering/renderer_rd/effects/debug_effects.cpp
index 8cd3c22483..abcd9bbfae 100644
--- a/servers/rendering/renderer_rd/effects/debug_effects.cpp
+++ b/servers/rendering/renderer_rd/effects/debug_effects.cpp
@@ -51,6 +51,17 @@ DebugEffects::DebugEffects() {
raster_state.wireframe = true;
shadow_frustum.pipelines[SFP_WIREFRAME].setup(shadow_frustum.shader.version_get_shader(shadow_frustum.shader_version, 0), RD::RENDER_PRIMITIVE_LINES, raster_state, RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
}
+
+ {
+ // Motion Vectors debug shader.
+ Vector<String> modes;
+ modes.push_back("");
+
+ motion_vectors.shader.initialize(modes);
+ motion_vectors.shader_version = motion_vectors.shader.version_create();
+
+ motion_vectors.pipeline.setup(motion_vectors.shader.version_get_shader(motion_vectors.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_blend(), 0);
+ }
}
void DebugEffects::_create_frustum_arrays() {
@@ -74,7 +85,7 @@ void DebugEffects::_create_frustum_arrays() {
}
if (frustum.index_buffer.is_null()) {
- uint32_t indices[6 * 2 * 3] = {
+ uint16_t indices[6 * 2 * 3] = {
// Far
0, 1, 2, // FLT, FLB, FRT
1, 3, 2, // FLB, FRB, FRT
@@ -100,19 +111,19 @@ void DebugEffects::_create_frustum_arrays() {
data.resize(6 * 2 * 3 * 4);
{
uint8_t *w = data.ptrw();
- int *p32 = (int *)w;
+ uint16_t *p16 = (uint16_t *)w;
for (int i = 0; i < 6 * 2 * 3; i++) {
- *p32 = indices[i];
- p32++;
+ *p16 = indices[i];
+ p16++;
}
}
- frustum.index_buffer = RD::get_singleton()->index_buffer_create(6 * 2 * 3, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, data);
+ frustum.index_buffer = RD::get_singleton()->index_buffer_create(6 * 2 * 3, RenderingDevice::INDEX_BUFFER_FORMAT_UINT16, data);
frustum.index_array = RD::get_singleton()->index_array_create(frustum.index_buffer, 0, 6 * 2 * 3);
}
if (frustum.lines_buffer.is_null()) {
- uint32_t indices[12 * 2] = {
+ uint16_t indices[12 * 2] = {
0, 1, // FLT - FLB
1, 3, // FLB - FRB
3, 2, // FRB - FRT
@@ -134,14 +145,14 @@ void DebugEffects::_create_frustum_arrays() {
data.resize(12 * 2 * 4);
{
uint8_t *w = data.ptrw();
- int *p32 = (int *)w;
+ uint16_t *p16 = (uint16_t *)w;
for (int i = 0; i < 12 * 2; i++) {
- *p32 = indices[i];
- p32++;
+ *p16 = indices[i];
+ p16++;
}
}
- frustum.lines_buffer = RD::get_singleton()->index_buffer_create(12 * 2, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, data);
+ frustum.lines_buffer = RD::get_singleton()->index_buffer_create(12 * 2, RenderingDevice::INDEX_BUFFER_FORMAT_UINT16, data);
frustum.lines_array = RD::get_singleton()->index_array_create(frustum.lines_buffer, 0, 12 * 2);
}
}
@@ -163,6 +174,8 @@ DebugEffects::~DebugEffects() {
if (frustum.lines_buffer.is_valid()) {
RD::get_singleton()->free(frustum.lines_buffer); // Array gets freed as dependency.
}
+
+ motion_vectors.shader.version_free(motion_vectors.shader_version);
}
void DebugEffects::draw_shadow_frustum(RID p_light, const Projection &p_cam_projection, const Transform3D &p_cam_transform, RID p_dest_fb, const Rect2 p_rect) {
@@ -326,3 +339,39 @@ void DebugEffects::draw_shadow_frustum(RID p_light, const Projection &p_cam_proj
}
}
}
+
+void DebugEffects::draw_motion_vectors(RID p_velocity, RID p_depth, RID p_dest_fb, const Projection &p_current_projection, const Transform3D &p_current_transform, const Projection &p_previous_projection, const Transform3D &p_previous_transform, Size2i p_resolution) {
+ MaterialStorage *material_storage = MaterialStorage::get_singleton();
+ ERR_FAIL_NULL(material_storage);
+
+ UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
+ ERR_FAIL_NULL(uniform_set_cache);
+
+ 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_velocity(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_velocity }));
+ RD::Uniform u_source_depth(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 1, Vector<RID>({ default_sampler, p_depth }));
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, motion_vectors.pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_fb), false, RD::get_singleton()->draw_list_get_current_pass()));
+
+ Projection reprojection = p_previous_projection.flipped_y() * p_previous_transform.affine_inverse() * p_current_transform * p_current_projection.flipped_y().inverse();
+ RendererRD::MaterialStorage::store_camera(reprojection, motion_vectors.push_constant.reprojection_matrix);
+
+ motion_vectors.push_constant.resolution[0] = p_resolution.width;
+ motion_vectors.push_constant.resolution[1] = p_resolution.height;
+ motion_vectors.push_constant.force_derive_from_depth = false;
+
+ RID shader = motion_vectors.shader.version_get_shader(motion_vectors.shader_version, 0);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_velocity, u_source_depth), 0);
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &motion_vectors.push_constant, sizeof(MotionVectorsPushConstant));
+ RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
+
+#ifdef DRAW_DERIVATION_FROM_DEPTH_ON_TOP
+ motion_vectors.push_constant.force_derive_from_depth = true;
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &motion_vectors.push_constant, sizeof(MotionVectorsPushConstant));
+ RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
+#endif
+
+ RD::get_singleton()->draw_list_end();
+}
diff --git a/servers/rendering/renderer_rd/effects/debug_effects.h b/servers/rendering/renderer_rd/effects/debug_effects.h
index 21b7b03f84..b813d577e4 100644
--- a/servers/rendering/renderer_rd/effects/debug_effects.h
+++ b/servers/rendering/renderer_rd/effects/debug_effects.h
@@ -32,6 +32,7 @@
#define DEBUG_EFFECTS_RD_H
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
+#include "servers/rendering/renderer_rd/shaders/effects/motion_vectors.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/shadow_frustum.glsl.gen.h"
#include "servers/rendering/renderer_scene_render.h"
@@ -70,6 +71,20 @@ private:
PipelineCacheRD pipelines[SFP_MAX];
} shadow_frustum;
+ struct MotionVectorsPushConstant {
+ float reprojection_matrix[16];
+ float resolution[2];
+ uint32_t force_derive_from_depth;
+ float pad;
+ };
+
+ struct {
+ MotionVectorsShaderRD shader;
+ RID shader_version;
+ PipelineCacheRD pipeline;
+ MotionVectorsPushConstant push_constant;
+ } motion_vectors;
+
void _create_frustum_arrays();
protected:
@@ -78,6 +93,7 @@ public:
~DebugEffects();
void draw_shadow_frustum(RID p_light, const Projection &p_cam_projection, const Transform3D &p_cam_transform, RID p_dest_fb, const Rect2 p_rect);
+ void draw_motion_vectors(RID p_velocity, RID p_depth, RID p_dest_fb, const Projection &p_current_projection, const Transform3D &p_current_transform, const Projection &p_previous_projection, const Transform3D &p_previous_transform, Size2i p_resolution);
};
} // namespace RendererRD
diff --git a/servers/rendering/renderer_rd/effects/fsr2.cpp b/servers/rendering/renderer_rd/effects/fsr2.cpp
new file mode 100644
index 0000000000..0c38989304
--- /dev/null
+++ b/servers/rendering/renderer_rd/effects/fsr2.cpp
@@ -0,0 +1,891 @@
+/**************************************************************************/
+/* fsr2.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 "fsr2.h"
+
+#include "../storage_rd/material_storage.h"
+#include "../uniform_set_cache_rd.h"
+
+using namespace RendererRD;
+
+#ifndef _MSC_VER
+#include <wchar.h>
+#define wcscpy_s wcscpy
+#endif
+
+static RD::TextureType ffx_resource_type_to_rd_texture_type(FfxResourceType p_type) {
+ switch (p_type) {
+ case FFX_RESOURCE_TYPE_TEXTURE1D:
+ return RD::TEXTURE_TYPE_1D;
+ case FFX_RESOURCE_TYPE_TEXTURE2D:
+ return RD::TEXTURE_TYPE_2D;
+ case FFX_RESOURCE_TYPE_TEXTURE3D:
+ return RD::TEXTURE_TYPE_3D;
+ default:
+ return RD::TEXTURE_TYPE_MAX;
+ }
+}
+
+static FfxResourceType rd_texture_type_to_ffx_resource_type(RD::TextureType p_type) {
+ switch (p_type) {
+ case RD::TEXTURE_TYPE_1D:
+ return FFX_RESOURCE_TYPE_TEXTURE1D;
+ case RD::TEXTURE_TYPE_2D:
+ return FFX_RESOURCE_TYPE_TEXTURE2D;
+ case RD::TEXTURE_TYPE_3D:
+ return FFX_RESOURCE_TYPE_TEXTURE3D;
+ default:
+ return FFX_RESOURCE_TYPE_BUFFER;
+ }
+}
+
+static RD::DataFormat ffx_surface_format_to_rd_format(FfxSurfaceFormat p_format) {
+ switch (p_format) {
+ case FFX_SURFACE_FORMAT_R32G32B32A32_TYPELESS:
+ return RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
+ case FFX_SURFACE_FORMAT_R32G32B32A32_FLOAT:
+ return RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
+ case FFX_SURFACE_FORMAT_R16G16B16A16_FLOAT:
+ return RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ case FFX_SURFACE_FORMAT_R16G16B16A16_UNORM:
+ return RD::DATA_FORMAT_R16G16B16A16_UNORM;
+ case FFX_SURFACE_FORMAT_R32G32_FLOAT:
+ return RD::DATA_FORMAT_R32G32_SFLOAT;
+ case FFX_SURFACE_FORMAT_R32_UINT:
+ return RD::DATA_FORMAT_R32_UINT;
+ case FFX_SURFACE_FORMAT_R8G8B8A8_TYPELESS:
+ return RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ case FFX_SURFACE_FORMAT_R8G8B8A8_UNORM:
+ return RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ case FFX_SURFACE_FORMAT_R11G11B10_FLOAT:
+ return RD::DATA_FORMAT_B10G11R11_UFLOAT_PACK32;
+ case FFX_SURFACE_FORMAT_R16G16_FLOAT:
+ return RD::DATA_FORMAT_R16G16_SFLOAT;
+ case FFX_SURFACE_FORMAT_R16G16_UINT:
+ return RD::DATA_FORMAT_R16G16_UINT;
+ case FFX_SURFACE_FORMAT_R16_FLOAT:
+ return RD::DATA_FORMAT_R16_SFLOAT;
+ case FFX_SURFACE_FORMAT_R16_UINT:
+ return RD::DATA_FORMAT_R16_UINT;
+ case FFX_SURFACE_FORMAT_R16_UNORM:
+ return RD::DATA_FORMAT_R16_UNORM;
+ case FFX_SURFACE_FORMAT_R16_SNORM:
+ return RD::DATA_FORMAT_R16_SNORM;
+ case FFX_SURFACE_FORMAT_R8_UNORM:
+ return RD::DATA_FORMAT_R8_UNORM;
+ case FFX_SURFACE_FORMAT_R8_UINT:
+ return RD::DATA_FORMAT_R8_UINT;
+ case FFX_SURFACE_FORMAT_R8G8_UNORM:
+ return RD::DATA_FORMAT_R8G8_UNORM;
+ case FFX_SURFACE_FORMAT_R32_FLOAT:
+ return RD::DATA_FORMAT_R32_SFLOAT;
+ default:
+ return RD::DATA_FORMAT_MAX;
+ }
+}
+
+static FfxSurfaceFormat rd_format_to_ffx_surface_format(RD::DataFormat p_format) {
+ switch (p_format) {
+ case RD::DATA_FORMAT_R32G32B32A32_SFLOAT:
+ return FFX_SURFACE_FORMAT_R32G32B32A32_FLOAT;
+ case RD::DATA_FORMAT_R16G16B16A16_SFLOAT:
+ return FFX_SURFACE_FORMAT_R16G16B16A16_FLOAT;
+ case RD::DATA_FORMAT_R16G16B16A16_UNORM:
+ return FFX_SURFACE_FORMAT_R16G16B16A16_UNORM;
+ case RD::DATA_FORMAT_R32G32_SFLOAT:
+ return FFX_SURFACE_FORMAT_R32G32_FLOAT;
+ case RD::DATA_FORMAT_R32_UINT:
+ return FFX_SURFACE_FORMAT_R32_UINT;
+ case RD::DATA_FORMAT_R8G8B8A8_UNORM:
+ return FFX_SURFACE_FORMAT_R8G8B8A8_UNORM;
+ case RD::DATA_FORMAT_B10G11R11_UFLOAT_PACK32:
+ return FFX_SURFACE_FORMAT_R11G11B10_FLOAT;
+ case RD::DATA_FORMAT_R16G16_SFLOAT:
+ return FFX_SURFACE_FORMAT_R16G16_FLOAT;
+ case RD::DATA_FORMAT_R16G16_UINT:
+ return FFX_SURFACE_FORMAT_R16G16_UINT;
+ case RD::DATA_FORMAT_R16_SFLOAT:
+ return FFX_SURFACE_FORMAT_R16_FLOAT;
+ case RD::DATA_FORMAT_R16_UINT:
+ return FFX_SURFACE_FORMAT_R16_UINT;
+ case RD::DATA_FORMAT_R16_UNORM:
+ return FFX_SURFACE_FORMAT_R16_UNORM;
+ case RD::DATA_FORMAT_R16_SNORM:
+ return FFX_SURFACE_FORMAT_R16_SNORM;
+ case RD::DATA_FORMAT_R8_UNORM:
+ return FFX_SURFACE_FORMAT_R8_UNORM;
+ case RD::DATA_FORMAT_R8_UINT:
+ return FFX_SURFACE_FORMAT_R8_UINT;
+ case RD::DATA_FORMAT_R8G8_UNORM:
+ return FFX_SURFACE_FORMAT_R8G8_UNORM;
+ case RD::DATA_FORMAT_R32_SFLOAT:
+ return FFX_SURFACE_FORMAT_R32_FLOAT;
+ default:
+ return FFX_SURFACE_FORMAT_UNKNOWN;
+ }
+}
+
+static uint32_t ffx_usage_to_rd_usage_flags(uint32_t p_flags) {
+ uint32_t ret = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
+
+ if (p_flags & FFX_RESOURCE_USAGE_RENDERTARGET) {
+ ret |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ }
+
+ if (p_flags & FFX_RESOURCE_USAGE_UAV) {
+ ret |= RD::TEXTURE_USAGE_STORAGE_BIT;
+ ret |= RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
+ ret |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
+ }
+
+ return ret;
+}
+
+static FfxErrorCode create_backend_context_rd(FfxFsr2Interface *p_backend_interface, FfxDevice p_device) {
+ FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
+
+ // Store pointer to the device common to all contexts.
+ scratch.device = p_device;
+
+ // Create a ring buffer of uniform buffers.
+ // FIXME: This could be optimized to be a single memory block if it was possible for RD to create views into a particular memory range of a UBO.
+ for (uint32_t i = 0; i < FSR2_UBO_RING_BUFFER_SIZE; i++) {
+ scratch.ubo_ring_buffer[i] = RD::get_singleton()->uniform_buffer_create(FFX_MAX_CONST_SIZE * sizeof(uint32_t));
+ ERR_FAIL_COND_V(scratch.ubo_ring_buffer[i].is_null(), FFX_ERROR_BACKEND_API_ERROR);
+ }
+
+ return FFX_OK;
+}
+
+static FfxErrorCode get_device_capabilities_rd(FfxFsr2Interface *p_backend_interface, FfxDeviceCapabilities *p_out_device_capabilities, FfxDevice p_device) {
+ FSR2Effect::Device &effect_device = *reinterpret_cast<FSR2Effect::Device *>(p_device);
+
+ *p_out_device_capabilities = effect_device.capabilities;
+
+ return FFX_OK;
+}
+
+static FfxErrorCode destroy_backend_context_rd(FfxFsr2Interface *p_backend_interface) {
+ FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
+
+ for (uint32_t i = 0; i < FSR2_UBO_RING_BUFFER_SIZE; i++) {
+ RD::get_singleton()->free(scratch.ubo_ring_buffer[i]);
+ }
+
+ return FFX_OK;
+}
+
+static FfxErrorCode create_resource_rd(FfxFsr2Interface *p_backend_interface, const FfxCreateResourceDescription *p_create_resource_description, FfxResourceInternal *p_out_resource) {
+ // FSR2's base implementation won't issue a call to create a heap type that isn't just default on its own,
+ // so we can safely ignore it as RD does not expose this concept.
+ ERR_FAIL_COND_V(p_create_resource_description->heapType != FFX_HEAP_TYPE_DEFAULT, FFX_ERROR_INVALID_ARGUMENT);
+
+ RenderingDevice *rd = RD::get_singleton();
+ FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
+ FfxResourceDescription res_desc = p_create_resource_description->resourceDescription;
+
+ // FSR2's base implementation never requests buffer creation.
+ ERR_FAIL_COND_V(res_desc.type != FFX_RESOURCE_TYPE_TEXTURE1D && res_desc.type != FFX_RESOURCE_TYPE_TEXTURE2D && res_desc.type != FFX_RESOURCE_TYPE_TEXTURE3D, FFX_ERROR_INVALID_ARGUMENT);
+
+ if (res_desc.mipCount == 0) {
+ // Mipmap count must be derived from the resource's dimensions.
+ res_desc.mipCount = uint32_t(1 + floor(log2(MAX(MAX(res_desc.width, res_desc.height), res_desc.depth))));
+ }
+
+ Vector<PackedByteArray> initial_data;
+ if (p_create_resource_description->initDataSize) {
+ PackedByteArray byte_array;
+ byte_array.resize(p_create_resource_description->initDataSize);
+ memcpy(byte_array.ptrw(), p_create_resource_description->initData, p_create_resource_description->initDataSize);
+ initial_data.push_back(byte_array);
+ }
+
+ RD::TextureFormat texture_format;
+ texture_format.texture_type = ffx_resource_type_to_rd_texture_type(res_desc.type);
+ texture_format.format = ffx_surface_format_to_rd_format(res_desc.format);
+ texture_format.usage_bits = ffx_usage_to_rd_usage_flags(p_create_resource_description->usage);
+ texture_format.width = res_desc.width;
+ texture_format.height = res_desc.height;
+ texture_format.depth = res_desc.depth;
+ texture_format.mipmaps = res_desc.mipCount;
+
+ RID texture = rd->texture_create(texture_format, RD::TextureView(), initial_data);
+ ERR_FAIL_COND_V(texture.is_null(), FFX_ERROR_BACKEND_API_ERROR);
+
+ rd->set_resource_name(texture, String(p_create_resource_description->name));
+
+ // Add the resource to the storage and use the internal index to reference it.
+ p_out_resource->internalIndex = scratch.resources.add(texture, false, p_create_resource_description->id, res_desc);
+
+ return FFX_OK;
+}
+
+static FfxErrorCode register_resource_rd(FfxFsr2Interface *p_backend_interface, const FfxResource *p_in_resource, FfxResourceInternal *p_out_resource) {
+ if (p_in_resource->resource == nullptr) {
+ // Null resource case.
+ p_out_resource->internalIndex = -1;
+ return FFX_OK;
+ }
+
+ FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
+ const RID &rid = *reinterpret_cast<const RID *>(p_in_resource->resource);
+ ERR_FAIL_COND_V(rid.is_null(), FFX_ERROR_INVALID_ARGUMENT);
+
+ // Add the resource to the storage and use the internal index to reference it.
+ p_out_resource->internalIndex = scratch.resources.add(rid, true, FSR2Context::RESOURCE_ID_DYNAMIC, p_in_resource->description);
+
+ return FFX_OK;
+}
+
+static FfxErrorCode unregister_resources_rd(FfxFsr2Interface *p_backend_interface) {
+ FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
+ LocalVector<uint32_t> dynamic_list_copy = scratch.resources.dynamic_list;
+ for (uint32_t i : dynamic_list_copy) {
+ scratch.resources.remove(i);
+ }
+
+ return FFX_OK;
+}
+
+static FfxResourceDescription get_resource_description_rd(FfxFsr2Interface *p_backend_interface, FfxResourceInternal p_resource) {
+ if (p_resource.internalIndex != -1) {
+ FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
+ return scratch.resources.descriptions[p_resource.internalIndex];
+ } else {
+ return {};
+ }
+}
+
+static FfxErrorCode destroy_resource_rd(FfxFsr2Interface *p_backend_interface, FfxResourceInternal p_resource) {
+ if (p_resource.internalIndex != -1) {
+ FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
+ if (scratch.resources.rids[p_resource.internalIndex].is_valid()) {
+ RD::get_singleton()->free(scratch.resources.rids[p_resource.internalIndex]);
+ scratch.resources.remove(p_resource.internalIndex);
+ }
+ }
+
+ return FFX_OK;
+}
+
+static FfxErrorCode create_pipeline_rd(FfxFsr2Interface *p_backend_interface, FfxFsr2Pass p_pass, const FfxPipelineDescription *p_pipeline_description, FfxPipelineState *p_out_pipeline) {
+ FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
+ FSR2Effect::Device &device = *reinterpret_cast<FSR2Effect::Device *>(scratch.device);
+ FSR2Effect::Pass &effect_pass = device.passes[p_pass];
+
+ if (effect_pass.pipeline.pipeline_rid.is_null()) {
+ // Create pipeline for the device if it hasn't been created yet.
+ effect_pass.root_signature.shader_rid = effect_pass.shader->version_get_shader(effect_pass.shader_version, effect_pass.shader_variant);
+ ERR_FAIL_COND_V(effect_pass.root_signature.shader_rid.is_null(), FFX_ERROR_BACKEND_API_ERROR);
+
+ effect_pass.pipeline.pipeline_rid = RD::get_singleton()->compute_pipeline_create(effect_pass.root_signature.shader_rid);
+ ERR_FAIL_COND_V(effect_pass.pipeline.pipeline_rid.is_null(), FFX_ERROR_BACKEND_API_ERROR);
+ }
+
+ // While this is not their intended use, we use the pipeline and root signature pointers to store the
+ // RIDs to the pipeline and shader that RD needs for the compute pipeline.
+ p_out_pipeline->pipeline = reinterpret_cast<FfxPipeline>(&effect_pass.pipeline);
+ p_out_pipeline->rootSignature = reinterpret_cast<FfxRootSignature>(&effect_pass.root_signature);
+
+ p_out_pipeline->srvCount = effect_pass.sampled_bindings.size();
+ ERR_FAIL_COND_V(p_out_pipeline->srvCount > FFX_MAX_NUM_SRVS, FFX_ERROR_OUT_OF_RANGE);
+ memcpy(p_out_pipeline->srvResourceBindings, effect_pass.sampled_bindings.ptr(), sizeof(FfxResourceBinding) * p_out_pipeline->srvCount);
+
+ p_out_pipeline->uavCount = effect_pass.storage_bindings.size();
+ ERR_FAIL_COND_V(p_out_pipeline->uavCount > FFX_MAX_NUM_UAVS, FFX_ERROR_OUT_OF_RANGE);
+ memcpy(p_out_pipeline->uavResourceBindings, effect_pass.storage_bindings.ptr(), sizeof(FfxResourceBinding) * p_out_pipeline->uavCount);
+
+ p_out_pipeline->constCount = effect_pass.uniform_bindings.size();
+ ERR_FAIL_COND_V(p_out_pipeline->constCount > FFX_MAX_NUM_CONST_BUFFERS, FFX_ERROR_OUT_OF_RANGE);
+ memcpy(p_out_pipeline->cbResourceBindings, effect_pass.uniform_bindings.ptr(), sizeof(FfxResourceBinding) * p_out_pipeline->constCount);
+
+ bool low_resolution_mvs = (p_pipeline_description->contextFlags & FFX_FSR2_ENABLE_DISPLAY_RESOLUTION_MOTION_VECTORS) == 0;
+
+ if (p_pass == FFX_FSR2_PASS_ACCUMULATE || p_pass == FFX_FSR2_PASS_ACCUMULATE_SHARPEN) {
+ // Change the binding for motion vectors in this particular pass if low resolution MVs are used.
+ if (low_resolution_mvs) {
+ FfxResourceBinding &binding = p_out_pipeline->srvResourceBindings[2];
+ wcscpy_s(binding.name, L"r_dilated_motion_vectors");
+ }
+ }
+
+ return FFX_OK;
+}
+
+static FfxErrorCode destroy_pipeline_rd(FfxFsr2Interface *p_backend_interface, FfxPipelineState *p_pipeline) {
+ // We don't want to destroy pipelines when the FSR2 API deems it necessary as it'll do so whenever the context is destroyed.
+
+ return FFX_OK;
+}
+
+static FfxErrorCode schedule_gpu_job_rd(FfxFsr2Interface *p_backend_interface, const FfxGpuJobDescription *p_job) {
+ ERR_FAIL_NULL_V(p_backend_interface, FFX_ERROR_INVALID_ARGUMENT);
+ ERR_FAIL_NULL_V(p_job, FFX_ERROR_INVALID_ARGUMENT);
+
+ FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
+ scratch.gpu_jobs.push_back(*p_job);
+
+ return FFX_OK;
+}
+
+static FfxErrorCode execute_gpu_job_clear_float_rd(FSR2Context::Scratch &p_scratch, const FfxClearFloatJobDescription &p_job) {
+ RID resource = p_scratch.resources.rids[p_job.target.internalIndex];
+ FfxResourceDescription &desc = p_scratch.resources.descriptions[p_job.target.internalIndex];
+
+ ERR_FAIL_COND_V(desc.type == FFX_RESOURCE_TYPE_BUFFER, FFX_ERROR_INVALID_ARGUMENT);
+
+ Color color(p_job.color[0], p_job.color[1], p_job.color[2], p_job.color[3]);
+ RD::get_singleton()->texture_clear(resource, color, 0, desc.mipCount, 0, 1);
+
+ return FFX_OK;
+}
+
+static FfxErrorCode execute_gpu_job_copy_rd(FSR2Context::Scratch &p_scratch, const FfxCopyJobDescription &p_job) {
+ RID src = p_scratch.resources.rids[p_job.src.internalIndex];
+ RID dst = p_scratch.resources.rids[p_job.dst.internalIndex];
+ FfxResourceDescription &src_desc = p_scratch.resources.descriptions[p_job.src.internalIndex];
+ FfxResourceDescription &dst_desc = p_scratch.resources.descriptions[p_job.dst.internalIndex];
+
+ ERR_FAIL_COND_V(src_desc.type == FFX_RESOURCE_TYPE_BUFFER, FFX_ERROR_INVALID_ARGUMENT);
+ ERR_FAIL_COND_V(dst_desc.type == FFX_RESOURCE_TYPE_BUFFER, FFX_ERROR_INVALID_ARGUMENT);
+
+ for (uint32_t mip_level = 0; mip_level < src_desc.mipCount; mip_level++) {
+ // Only push the barriers on the last copy.
+ // FIXME: This could be optimized if RenderingDevice was able to copy multiple mip levels in a single command.
+ BitField<RD::BarrierMask> post_barrier = (mip_level == (src_desc.mipCount - 1)) ? RD::BARRIER_MASK_ALL_BARRIERS : RD::BARRIER_MASK_NO_BARRIER;
+ RD::get_singleton()->texture_copy(src, dst, Vector3(0, 0, 0), Vector3(0, 0, 0), Vector3(src_desc.width, src_desc.height, src_desc.depth), mip_level, mip_level, 0, 0, post_barrier);
+ }
+
+ return FFX_OK;
+}
+
+static FfxErrorCode execute_gpu_job_compute_rd(FSR2Context::Scratch &p_scratch, const FfxComputeJobDescription &p_job) {
+ UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
+ ERR_FAIL_NULL_V(uniform_set_cache, FFX_ERROR_BACKEND_API_ERROR);
+
+ FSR2Effect::RootSignature &root_signature = *reinterpret_cast<FSR2Effect::RootSignature *>(p_job.pipeline.rootSignature);
+ ERR_FAIL_COND_V(root_signature.shader_rid.is_null(), FFX_ERROR_INVALID_ARGUMENT);
+
+ FSR2Effect::Pipeline &backend_pipeline = *reinterpret_cast<FSR2Effect::Pipeline *>(p_job.pipeline.pipeline);
+ ERR_FAIL_COND_V(backend_pipeline.pipeline_rid.is_null(), FFX_ERROR_INVALID_ARGUMENT);
+
+ Vector<RD::Uniform> compute_uniforms;
+ for (uint32_t i = 0; i < p_job.pipeline.srvCount; i++) {
+ RID texture_rid = p_scratch.resources.rids[p_job.srvs[i].internalIndex];
+ RD::Uniform texture_uniform(RD::UNIFORM_TYPE_TEXTURE, p_job.pipeline.srvResourceBindings[i].slotIndex, texture_rid);
+ compute_uniforms.push_back(texture_uniform);
+ }
+
+ for (uint32_t i = 0; i < p_job.pipeline.uavCount; i++) {
+ RID image_rid = p_scratch.resources.rids[p_job.uavs[i].internalIndex];
+ RD::Uniform storage_uniform;
+ storage_uniform.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ storage_uniform.binding = p_job.pipeline.uavResourceBindings[i].slotIndex;
+
+ if (p_job.uavMip[i] > 0) {
+ LocalVector<RID> &mip_slice_rids = p_scratch.resources.mip_slice_rids[p_job.uavs[i].internalIndex];
+ if (mip_slice_rids.is_empty()) {
+ mip_slice_rids.resize(p_scratch.resources.descriptions[p_job.uavs[i].internalIndex].mipCount);
+ }
+
+ ERR_FAIL_COND_V(p_job.uavMip[i] >= mip_slice_rids.size(), FFX_ERROR_INVALID_ARGUMENT);
+
+ if (mip_slice_rids[p_job.uavMip[i]].is_null()) {
+ mip_slice_rids[p_job.uavMip[i]] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), image_rid, 0, p_job.uavMip[i]);
+ }
+
+ ERR_FAIL_COND_V(mip_slice_rids[p_job.uavMip[i]].is_null(), FFX_ERROR_BACKEND_API_ERROR);
+
+ storage_uniform.append_id(mip_slice_rids[p_job.uavMip[i]]);
+ } else {
+ storage_uniform.append_id(image_rid);
+ }
+
+ compute_uniforms.push_back(storage_uniform);
+ }
+
+ for (uint32_t i = 0; i < p_job.pipeline.constCount; i++) {
+ RID buffer_rid = p_scratch.ubo_ring_buffer[p_scratch.ubo_ring_buffer_index];
+ p_scratch.ubo_ring_buffer_index = (p_scratch.ubo_ring_buffer_index + 1) % FSR2_UBO_RING_BUFFER_SIZE;
+
+ BitField<RD::BarrierMask> post_barrier = (i == (p_job.pipeline.constCount - 1)) ? RD::BARRIER_MASK_ALL_BARRIERS : RD::BARRIER_MASK_NO_BARRIER;
+ RD::get_singleton()->buffer_update(buffer_rid, 0, p_job.cbs[i].uint32Size * sizeof(uint32_t), p_job.cbs[i].data, post_barrier);
+
+ RD::Uniform buffer_uniform(RD::UNIFORM_TYPE_UNIFORM_BUFFER, p_job.pipeline.cbResourceBindings[i].slotIndex, buffer_rid);
+ compute_uniforms.push_back(buffer_uniform);
+ }
+
+ FSR2Effect::Device &device = *reinterpret_cast<FSR2Effect::Device *>(p_scratch.device);
+ RD::Uniform u_point_clamp_sampler(RD::UniformType::UNIFORM_TYPE_SAMPLER, 0, device.point_clamp_sampler);
+ RD::Uniform u_linear_clamp_sampler(RD::UniformType::UNIFORM_TYPE_SAMPLER, 1, device.linear_clamp_sampler);
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, backend_pipeline.pipeline_rid);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(root_signature.shader_rid, 0, u_point_clamp_sampler, u_linear_clamp_sampler), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache_vec(root_signature.shader_rid, 1, compute_uniforms), 1);
+ RD::get_singleton()->compute_list_dispatch(compute_list, p_job.dimensions[0], p_job.dimensions[1], p_job.dimensions[2]);
+ RD::get_singleton()->compute_list_end();
+
+ return FFX_OK;
+}
+
+static FfxErrorCode execute_gpu_jobs_rd(FfxFsr2Interface *p_backend_interface, FfxCommandList p_command_list) {
+ ERR_FAIL_NULL_V(p_backend_interface, FFX_ERROR_INVALID_ARGUMENT);
+
+ FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
+ FfxErrorCode error_code = FFX_OK;
+ for (const FfxGpuJobDescription &job : scratch.gpu_jobs) {
+ switch (job.jobType) {
+ case FFX_GPU_JOB_CLEAR_FLOAT: {
+ error_code = execute_gpu_job_clear_float_rd(scratch, job.clearJobDescriptor);
+ } break;
+ case FFX_GPU_JOB_COPY: {
+ error_code = execute_gpu_job_copy_rd(scratch, job.copyJobDescriptor);
+ } break;
+ case FFX_GPU_JOB_COMPUTE: {
+ error_code = execute_gpu_job_compute_rd(scratch, job.computeJobDescriptor);
+ } break;
+ default: {
+ error_code = FFX_ERROR_INVALID_ARGUMENT;
+ } break;
+ }
+
+ if (error_code != FFX_OK) {
+ scratch.gpu_jobs.clear();
+ return error_code;
+ }
+ }
+
+ scratch.gpu_jobs.clear();
+
+ return FFX_OK;
+}
+
+static FfxResource get_resource_rd(RID *p_rid, const wchar_t *p_name) {
+ FfxResource res = {};
+ if (p_rid->is_null()) {
+ return res;
+ }
+
+ wcscpy_s(res.name, p_name);
+
+ RD::TextureFormat texture_format = RD::get_singleton()->texture_get_format(*p_rid);
+ res.description.type = rd_texture_type_to_ffx_resource_type(texture_format.texture_type);
+ res.description.format = rd_format_to_ffx_surface_format(texture_format.format);
+ res.description.width = texture_format.width;
+ res.description.height = texture_format.height;
+ res.description.depth = texture_format.depth;
+ res.description.mipCount = texture_format.mipmaps;
+ res.description.flags = FFX_RESOURCE_FLAGS_NONE;
+ res.resource = reinterpret_cast<void *>(p_rid);
+ res.isDepth = texture_format.usage_bits & RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+
+ return res;
+}
+
+FSR2Context::~FSR2Context() {
+ ffxFsr2ContextDestroy(&fsr_context);
+}
+
+FSR2Effect::FSR2Effect() {
+ FfxDeviceCapabilities &capabilities = device.capabilities;
+ uint64_t default_subgroup_size = RD::get_singleton()->limit_get(RD::LIMIT_SUBGROUP_SIZE);
+ capabilities.minimumSupportedShaderModel = FFX_SHADER_MODEL_5_1;
+ capabilities.waveLaneCountMin = RD::get_singleton()->limit_get(RD::LIMIT_SUBGROUP_MIN_SIZE);
+ capabilities.waveLaneCountMax = RD::get_singleton()->limit_get(RD::LIMIT_SUBGROUP_MAX_SIZE);
+ capabilities.fp16Supported = RD::get_singleton()->has_feature(RD::Features::SUPPORTS_FSR_HALF_FLOAT);
+ capabilities.raytracingSupported = false;
+
+ bool force_wave_64 = default_subgroup_size == 32 && capabilities.waveLaneCountMax == 64;
+ bool use_lut = force_wave_64 || default_subgroup_size == 64;
+
+ String general_defines_base =
+ "\n#define FFX_GPU\n"
+ "\n#define FFX_GLSL 1\n"
+ "\n#define FFX_FSR2_OPTION_LOW_RESOLUTION_MOTION_VECTORS 1\n"
+ "\n#define FFX_FSR2_OPTION_HDR_COLOR_INPUT 1\n"
+ "\n#define FFX_FSR2_OPTION_GODOT_REACTIVE_MASK_CLAMP 1\n"
+ "\n#define FFX_FSR2_OPTION_GODOT_DERIVE_INVALID_MOTION_VECTORS 1\n";
+
+ if (use_lut) {
+ general_defines_base += "\n#define FFX_FSR2_OPTION_REPROJECT_USE_LANCZOS_TYPE 1\n";
+ }
+
+ String general_defines = general_defines_base;
+ if (capabilities.fp16Supported) {
+ general_defines += "\n#define FFX_HALF 1\n";
+ }
+
+ Vector<String> modes;
+ modes.push_back("");
+
+ // Since Godot currently lacks a shader reflection mechanism to persist the name of the bindings in the shader cache and
+ // there's also no mechanism to compile the shaders offline, the bindings are created manually by looking at the GLSL
+ // files included in FSR2 and mapping the macro bindings (#define FSR2_BIND_*) to their respective implementation names.
+ //
+ // It is not guaranteed these will remain consistent at all between versions of FSR2, so it'll be necessary to keep these
+ // bindings up to date whenever the library is updated. In such cases, it is very likely the validation layer will throw an
+ // error if the bindings do not match.
+
+ {
+ Pass &pass = device.passes[FFX_FSR2_PASS_DEPTH_CLIP];
+ pass.shader = &shaders.depth_clip;
+ pass.shader->initialize(modes, general_defines);
+ pass.shader_version = pass.shader->version_create();
+
+ pass.sampled_bindings = {
+ FfxResourceBinding{ 0, 0, L"r_reconstructed_previous_nearest_depth" },
+ FfxResourceBinding{ 1, 0, L"r_dilated_motion_vectors" },
+ FfxResourceBinding{ 2, 0, L"r_dilatedDepth" },
+ FfxResourceBinding{ 3, 0, L"r_reactive_mask" },
+ FfxResourceBinding{ 4, 0, L"r_transparency_and_composition_mask" },
+ FfxResourceBinding{ 5, 0, L"r_prepared_input_color" },
+ FfxResourceBinding{ 6, 0, L"r_previous_dilated_motion_vectors" },
+ FfxResourceBinding{ 7, 0, L"r_input_motion_vectors" },
+ FfxResourceBinding{ 8, 0, L"r_input_color_jittered" },
+ FfxResourceBinding{ 9, 0, L"r_input_depth" },
+ FfxResourceBinding{ 10, 0, L"r_input_exposure" }
+ };
+
+ pass.storage_bindings = {
+ // FSR2_BIND_UAV_DEPTH_CLIP (11) does not point to anything.
+ FfxResourceBinding{ 12, 0, L"rw_dilated_reactive_masks" },
+ FfxResourceBinding{ 13, 0, L"rw_prepared_input_color" }
+ };
+
+ pass.uniform_bindings = {
+ FfxResourceBinding{ 14, 0, L"cbFSR2" }
+ };
+ }
+
+ {
+ Pass &pass = device.passes[FFX_FSR2_PASS_RECONSTRUCT_PREVIOUS_DEPTH];
+ pass.shader = &shaders.reconstruct_previous_depth;
+ pass.shader->initialize(modes, general_defines);
+ pass.shader_version = pass.shader->version_create();
+
+ pass.sampled_bindings = {
+ FfxResourceBinding{ 0, 0, L"r_input_motion_vectors" },
+ FfxResourceBinding{ 1, 0, L"r_input_depth" },
+ FfxResourceBinding{ 2, 0, L"r_input_color_jittered" },
+ FfxResourceBinding{ 3, 0, L"r_input_exposure" },
+ FfxResourceBinding{ 4, 0, L"r_luma_history" }
+ };
+
+ pass.storage_bindings = {
+ FfxResourceBinding{ 5, 0, L"rw_reconstructed_previous_nearest_depth" },
+ FfxResourceBinding{ 6, 0, L"rw_dilated_motion_vectors" },
+ FfxResourceBinding{ 7, 0, L"rw_dilatedDepth" },
+ FfxResourceBinding{ 8, 0, L"rw_prepared_input_color" },
+ FfxResourceBinding{ 9, 0, L"rw_luma_history" },
+ // FSR2_BIND_UAV_LUMA_INSTABILITY (10) does not point to anything.
+ FfxResourceBinding{ 11, 0, L"rw_lock_input_luma" }
+ };
+
+ pass.uniform_bindings = {
+ FfxResourceBinding{ 12, 0, L"cbFSR2" }
+ };
+ }
+
+ {
+ Pass &pass = device.passes[FFX_FSR2_PASS_LOCK];
+ pass.shader = &shaders.lock;
+ pass.shader->initialize(modes, general_defines);
+ pass.shader_version = pass.shader->version_create();
+
+ pass.sampled_bindings = {
+ FfxResourceBinding{ 0, 0, L"r_lock_input_luma" }
+ };
+
+ pass.storage_bindings = {
+ FfxResourceBinding{ 1, 0, L"rw_new_locks" },
+ FfxResourceBinding{ 2, 0, L"rw_reconstructed_previous_nearest_depth" }
+ };
+
+ pass.uniform_bindings = {
+ FfxResourceBinding{ 3, 0, L"cbFSR2" }
+ };
+ }
+
+ {
+ Vector<String> accumulate_modes;
+ accumulate_modes.push_back("\n");
+ accumulate_modes.push_back("\n#define FFX_FSR2_OPTION_APPLY_SHARPENING 1\n");
+
+ String general_defines_accumulate;
+ if (RD::get_singleton()->get_device_vendor_name() == "NVIDIA") {
+ // Workaround: Disable FP16 path for the accumulate pass on NVIDIA due to reduced occupancy and high VRAM throughput.
+ general_defines_accumulate = general_defines_base;
+ } else {
+ general_defines_accumulate = general_defines;
+ }
+
+ Pass &pass = device.passes[FFX_FSR2_PASS_ACCUMULATE];
+ pass.shader = &shaders.accumulate;
+ pass.shader->initialize(accumulate_modes, general_defines_accumulate);
+ pass.shader_version = pass.shader->version_create();
+
+ pass.sampled_bindings = {
+ FfxResourceBinding{ 0, 0, L"r_input_exposure" },
+ FfxResourceBinding{ 1, 0, L"r_dilated_reactive_masks" },
+ FfxResourceBinding{ 2, 0, L"r_input_motion_vectors" },
+ FfxResourceBinding{ 3, 0, L"r_internal_upscaled_color" },
+ FfxResourceBinding{ 4, 0, L"r_lock_status" },
+ FfxResourceBinding{ 5, 0, L"r_input_depth" },
+ FfxResourceBinding{ 6, 0, L"r_prepared_input_color" },
+ // FSR2_BIND_SRV_LUMA_INSTABILITY(7) does not point to anything.
+ FfxResourceBinding{ 8, 0, L"r_lanczos_lut" },
+ FfxResourceBinding{ 9, 0, L"r_upsample_maximum_bias_lut" },
+ FfxResourceBinding{ 10, 0, L"r_imgMips" },
+ FfxResourceBinding{ 11, 0, L"r_auto_exposure" },
+ FfxResourceBinding{ 12, 0, L"r_luma_history" }
+ };
+
+ pass.storage_bindings = {
+ FfxResourceBinding{ 13, 0, L"rw_internal_upscaled_color" },
+ FfxResourceBinding{ 14, 0, L"rw_lock_status" },
+ FfxResourceBinding{ 15, 0, L"rw_upscaled_output" },
+ FfxResourceBinding{ 16, 0, L"rw_new_locks" },
+ FfxResourceBinding{ 17, 0, L"rw_luma_history" }
+ };
+
+ pass.uniform_bindings = {
+ FfxResourceBinding{ 18, 0, L"cbFSR2" }
+ };
+
+ // Sharpen pass is a clone of the accumulate pass.
+ Pass &sharpen_pass = device.passes[FFX_FSR2_PASS_ACCUMULATE_SHARPEN];
+ sharpen_pass = pass;
+ sharpen_pass.shader_variant = 1;
+ }
+
+ {
+ Pass &pass = device.passes[FFX_FSR2_PASS_RCAS];
+ pass.shader = &shaders.rcas;
+ pass.shader->initialize(modes, general_defines_base);
+ pass.shader_version = pass.shader->version_create();
+
+ pass.sampled_bindings = {
+ FfxResourceBinding{ 0, 0, L"r_input_exposure" },
+ FfxResourceBinding{ 1, 0, L"r_rcas_input" }
+ };
+
+ pass.storage_bindings = {
+ FfxResourceBinding{ 2, 0, L"rw_upscaled_output" }
+ };
+
+ pass.uniform_bindings = {
+ FfxResourceBinding{ 3, 0, L"cbFSR2" },
+ FfxResourceBinding{ 4, 0, L"cbRCAS" }
+ };
+ }
+
+ {
+ Pass &pass = device.passes[FFX_FSR2_PASS_COMPUTE_LUMINANCE_PYRAMID];
+ pass.shader = &shaders.compute_luminance_pyramid;
+ pass.shader->initialize(modes, general_defines_base);
+ pass.shader_version = pass.shader->version_create();
+
+ pass.sampled_bindings = {
+ FfxResourceBinding{ 0, 0, L"r_input_color_jittered" }
+ };
+
+ pass.storage_bindings = {
+ FfxResourceBinding{ 1, 0, L"rw_spd_global_atomic" },
+ FfxResourceBinding{ 2, 0, L"rw_img_mip_shading_change" },
+ FfxResourceBinding{ 3, 0, L"rw_img_mip_5" },
+ FfxResourceBinding{ 4, 0, L"rw_auto_exposure" }
+ };
+
+ pass.uniform_bindings = {
+ FfxResourceBinding{ 5, 0, L"cbFSR2" },
+ FfxResourceBinding{ 6, 0, L"cbSPD" }
+ };
+ }
+
+ {
+ Pass &pass = device.passes[FFX_FSR2_PASS_GENERATE_REACTIVE];
+ pass.shader = &shaders.autogen_reactive;
+ pass.shader->initialize(modes, general_defines);
+ pass.shader_version = pass.shader->version_create();
+
+ pass.sampled_bindings = {
+ FfxResourceBinding{ 0, 0, L"r_input_opaque_only" },
+ FfxResourceBinding{ 1, 0, L"r_input_color_jittered" }
+ };
+
+ pass.storage_bindings = {
+ FfxResourceBinding{ 2, 0, L"rw_output_autoreactive" }
+ };
+
+ pass.uniform_bindings = {
+ FfxResourceBinding{ 3, 0, L"cbGenerateReactive" },
+ FfxResourceBinding{ 4, 0, L"cbFSR2" }
+ };
+ }
+
+ {
+ Pass &pass = device.passes[FFX_FSR2_PASS_TCR_AUTOGENERATE];
+ pass.shader = &shaders.tcr_autogen;
+ pass.shader->initialize(modes, general_defines);
+ pass.shader_version = pass.shader->version_create();
+
+ pass.sampled_bindings = {
+ FfxResourceBinding{ 0, 0, L"r_input_opaque_only" },
+ FfxResourceBinding{ 1, 0, L"r_input_color_jittered" },
+ FfxResourceBinding{ 2, 0, L"r_input_motion_vectors" },
+ FfxResourceBinding{ 3, 0, L"r_input_prev_color_pre_alpha" },
+ FfxResourceBinding{ 4, 0, L"r_input_prev_color_post_alpha" },
+ FfxResourceBinding{ 5, 0, L"r_reactive_mask" },
+ FfxResourceBinding{ 6, 0, L"r_transparency_and_composition_mask" },
+ FfxResourceBinding{ 13, 0, L"r_input_depth" }
+ };
+
+ pass.storage_bindings = {
+ FfxResourceBinding{ 7, 0, L"rw_output_autoreactive" },
+ FfxResourceBinding{ 8, 0, L"rw_output_autocomposition" },
+ FfxResourceBinding{ 9, 0, L"rw_output_prev_color_pre_alpha" },
+ FfxResourceBinding{ 10, 0, L"rw_output_prev_color_post_alpha" }
+ };
+
+ pass.uniform_bindings = {
+ FfxResourceBinding{ 11, 0, L"cbFSR2" },
+ FfxResourceBinding{ 12, 0, L"cbGenerateReactive" }
+ };
+ }
+
+ RD::SamplerState state;
+ state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
+ state.min_filter = RD::SAMPLER_FILTER_NEAREST;
+ state.repeat_u = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
+ state.repeat_v = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
+ state.repeat_w = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
+ state.min_lod = -1000.0f;
+ state.max_lod = 1000.0f;
+ state.anisotropy_max = 1.0;
+ device.point_clamp_sampler = RD::get_singleton()->sampler_create(state);
+ ERR_FAIL_COND(device.point_clamp_sampler.is_null());
+
+ state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
+ state.min_filter = RD::SAMPLER_FILTER_LINEAR;
+ device.linear_clamp_sampler = RD::get_singleton()->sampler_create(state);
+ ERR_FAIL_COND(device.linear_clamp_sampler.is_null());
+}
+
+FSR2Effect::~FSR2Effect() {
+ RD::get_singleton()->free(device.point_clamp_sampler);
+ RD::get_singleton()->free(device.linear_clamp_sampler);
+
+ for (uint32_t i = 0; i < FFX_FSR2_PASS_COUNT; i++) {
+ if (device.passes[i].pipeline.pipeline_rid.is_valid()) {
+ RD::get_singleton()->free(device.passes[i].pipeline.pipeline_rid);
+ }
+ device.passes[i].shader->version_free(device.passes[i].shader_version);
+ }
+}
+
+FSR2Context *FSR2Effect::create_context(Size2i p_internal_size, Size2i p_target_size) {
+ FSR2Context *context = memnew(RendererRD::FSR2Context);
+ context->fsr_desc.flags = FFX_FSR2_ENABLE_HIGH_DYNAMIC_RANGE;
+ context->fsr_desc.maxRenderSize.width = p_internal_size.x;
+ context->fsr_desc.maxRenderSize.height = p_internal_size.y;
+ context->fsr_desc.displaySize.width = p_target_size.x;
+ context->fsr_desc.displaySize.height = p_target_size.y;
+ context->fsr_desc.device = &device;
+
+ FfxFsr2Interface &functions = context->fsr_desc.callbacks;
+ functions.fpCreateBackendContext = create_backend_context_rd;
+ functions.fpGetDeviceCapabilities = get_device_capabilities_rd;
+ functions.fpDestroyBackendContext = destroy_backend_context_rd;
+ functions.fpCreateResource = create_resource_rd;
+ functions.fpRegisterResource = register_resource_rd;
+ functions.fpUnregisterResources = unregister_resources_rd;
+ functions.fpGetResourceDescription = get_resource_description_rd;
+ functions.fpDestroyResource = destroy_resource_rd;
+ functions.fpCreatePipeline = create_pipeline_rd;
+ functions.fpDestroyPipeline = destroy_pipeline_rd;
+ functions.fpScheduleGpuJob = schedule_gpu_job_rd;
+ functions.fpExecuteGpuJobs = execute_gpu_jobs_rd;
+ functions.scratchBuffer = &context->scratch;
+ functions.scratchBufferSize = sizeof(context->scratch);
+
+ FfxErrorCode result = ffxFsr2ContextCreate(&context->fsr_context, &context->fsr_desc);
+ if (result == FFX_OK) {
+ return context;
+ } else {
+ memdelete(context);
+ return nullptr;
+ }
+}
+
+void FSR2Effect::upscale(const Parameters &p_params) {
+ // TODO: Transparency & Composition mask is not implemented.
+ FfxFsr2DispatchDescription dispatch_desc = {};
+ RID color = p_params.color;
+ RID depth = p_params.depth;
+ RID velocity = p_params.velocity;
+ RID reactive = p_params.reactive;
+ RID exposure = p_params.exposure;
+ RID output = p_params.output;
+ dispatch_desc.commandList = nullptr;
+ dispatch_desc.color = get_resource_rd(&color, L"color");
+ dispatch_desc.depth = get_resource_rd(&depth, L"depth");
+ dispatch_desc.motionVectors = get_resource_rd(&velocity, L"velocity");
+ dispatch_desc.reactive = get_resource_rd(&reactive, L"reactive");
+ dispatch_desc.exposure = get_resource_rd(&exposure, L"exposure");
+ dispatch_desc.transparencyAndComposition = {};
+ dispatch_desc.output = get_resource_rd(&output, L"output");
+ dispatch_desc.colorOpaqueOnly = {};
+ dispatch_desc.jitterOffset.x = p_params.jitter.x;
+ dispatch_desc.jitterOffset.y = p_params.jitter.y;
+ dispatch_desc.motionVectorScale.x = float(p_params.internal_size.width);
+ dispatch_desc.motionVectorScale.y = float(p_params.internal_size.height);
+ dispatch_desc.reset = p_params.reset_accumulation;
+ dispatch_desc.renderSize.width = p_params.internal_size.width;
+ dispatch_desc.renderSize.height = p_params.internal_size.height;
+ dispatch_desc.enableSharpening = (p_params.sharpness > 1e-6f);
+ dispatch_desc.sharpness = p_params.sharpness;
+ dispatch_desc.frameTimeDelta = p_params.delta_time;
+ dispatch_desc.preExposure = 1.0f;
+ dispatch_desc.cameraNear = p_params.z_near;
+ dispatch_desc.cameraFar = p_params.z_far;
+ dispatch_desc.cameraFovAngleVertical = p_params.fovy;
+ dispatch_desc.viewSpaceToMetersFactor = 1.0f;
+ dispatch_desc.enableAutoReactive = false;
+ dispatch_desc.autoTcThreshold = 1.0f;
+ dispatch_desc.autoTcScale = 1.0f;
+ dispatch_desc.autoReactiveScale = 1.0f;
+ dispatch_desc.autoReactiveMax = 1.0f;
+
+ RendererRD::MaterialStorage::store_camera(p_params.reprojection, dispatch_desc.reprojectionMatrix);
+
+ FfxErrorCode result = ffxFsr2ContextDispatch(&p_params.context->fsr_context, &dispatch_desc);
+ ERR_FAIL_COND(result != FFX_OK);
+}
diff --git a/servers/rendering/renderer_rd/effects/fsr2.h b/servers/rendering/renderer_rd/effects/fsr2.h
new file mode 100644
index 0000000000..789714cc77
--- /dev/null
+++ b/servers/rendering/renderer_rd/effects/fsr2.h
@@ -0,0 +1,199 @@
+/**************************************************************************/
+/* fsr2.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 FSR2_RD_H
+#define FSR2_RD_H
+
+#include "servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_accumulate_pass.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_autogen_reactive_pass.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_compute_luminance_pyramid_pass.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_depth_clip_pass.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_lock_pass.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_rcas_pass.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_reconstruct_previous_depth_pass.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_tcr_autogen_pass.glsl.gen.h"
+
+// This flag doesn't actually control anything GCC specific in FSR2. It determines
+// if symbols should be exported, which is not required for Godot.
+#ifndef FFX_GCC
+#define FFX_GCC
+#endif
+
+#include "thirdparty/amd-fsr2/ffx_fsr2.h"
+
+#define FSR2_MAX_QUEUED_FRAMES (4)
+#define FSR2_MAX_UNIFORM_BUFFERS (4)
+#define FSR2_MAX_BUFFERED_DESCRIPTORS (FFX_FSR2_PASS_COUNT * FSR2_MAX_QUEUED_FRAMES)
+#define FSR2_UBO_RING_BUFFER_SIZE (FSR2_MAX_BUFFERED_DESCRIPTORS * FSR2_MAX_UNIFORM_BUFFERS)
+
+namespace RendererRD {
+class FSR2Context {
+public:
+ enum ResourceID : uint32_t {
+ RESOURCE_ID_DYNAMIC = 0xFFFFFFFF
+ };
+
+ struct Resources {
+ LocalVector<RID> rids;
+ LocalVector<LocalVector<RID>> mip_slice_rids;
+ LocalVector<uint32_t> ids;
+ LocalVector<FfxResourceDescription> descriptions;
+ LocalVector<uint32_t> dynamic_list;
+ LocalVector<uint32_t> free_list;
+
+ uint32_t add(RID p_rid, bool p_dynamic, uint32_t p_id, FfxResourceDescription p_description) {
+ uint32_t ret_index;
+ if (free_list.is_empty()) {
+ ret_index = rids.size();
+ uint32_t new_size = ret_index + 1;
+ rids.resize(new_size);
+ mip_slice_rids.resize(new_size);
+ ids.resize(new_size);
+ descriptions.resize(new_size);
+ } else {
+ uint32_t end_index = free_list.size() - 1;
+ ret_index = free_list[end_index];
+ free_list.resize(end_index);
+ }
+
+ rids[ret_index] = p_rid;
+ mip_slice_rids[ret_index].clear();
+ ids[ret_index] = p_id;
+ descriptions[ret_index] = p_description;
+
+ if (p_dynamic) {
+ dynamic_list.push_back(ret_index);
+ }
+
+ return ret_index;
+ }
+
+ void remove(uint32_t p_index) {
+ DEV_ASSERT(p_index < rids.size());
+ free_list.push_back(p_index);
+ rids[p_index] = RID();
+ mip_slice_rids[p_index].clear();
+ ids[p_index] = 0;
+ descriptions[p_index] = {};
+ dynamic_list.erase(p_index);
+ }
+
+ uint32_t size() const {
+ return rids.size();
+ }
+ };
+
+ struct Scratch {
+ Resources resources;
+ LocalVector<FfxGpuJobDescription> gpu_jobs;
+ RID ubo_ring_buffer[FSR2_UBO_RING_BUFFER_SIZE];
+ uint32_t ubo_ring_buffer_index = 0;
+ FfxDevice device = nullptr;
+ };
+
+ Scratch scratch;
+ FfxFsr2Context fsr_context;
+ FfxFsr2ContextDescription fsr_desc;
+
+ ~FSR2Context();
+};
+
+class FSR2Effect {
+public:
+ struct RootSignature {
+ // Proxy structure to store the shader required by RD that uses the terminology used by the FSR2 API.
+ RID shader_rid;
+ };
+
+ struct Pipeline {
+ RID pipeline_rid;
+ };
+
+ struct Pass {
+ ShaderRD *shader;
+ RID shader_version;
+ RootSignature root_signature;
+ uint32_t shader_variant = 0;
+ Pipeline pipeline;
+ Vector<FfxResourceBinding> sampled_bindings;
+ Vector<FfxResourceBinding> storage_bindings;
+ Vector<FfxResourceBinding> uniform_bindings;
+ };
+
+ struct Device {
+ Pass passes[FFX_FSR2_PASS_COUNT];
+ FfxDeviceCapabilities capabilities;
+ RID point_clamp_sampler;
+ RID linear_clamp_sampler;
+ };
+
+ struct Parameters {
+ FSR2Context *context;
+ Size2i internal_size;
+ RID color;
+ RID depth;
+ RID velocity;
+ RID reactive;
+ RID exposure;
+ RID output;
+ float z_near = 0.0f;
+ float z_far = 0.0f;
+ float fovy = 0.0f;
+ Vector2 jitter;
+ float delta_time = 0.0f;
+ float sharpness = 0.0f;
+ bool reset_accumulation = false;
+ Projection reprojection;
+ };
+
+ FSR2Effect();
+ ~FSR2Effect();
+ FSR2Context *create_context(Size2i p_internal_size, Size2i p_target_size);
+ void upscale(const Parameters &p_params);
+
+private:
+ struct {
+ Fsr2DepthClipPassShaderRD depth_clip;
+ Fsr2ReconstructPreviousDepthPassShaderRD reconstruct_previous_depth;
+ Fsr2LockPassShaderRD lock;
+ Fsr2AccumulatePassShaderRD accumulate;
+ Fsr2AccumulatePassShaderRD accumulate_sharpen;
+ Fsr2RcasPassShaderRD rcas;
+ Fsr2ComputeLuminancePyramidPassShaderRD compute_luminance_pyramid;
+ Fsr2AutogenReactivePassShaderRD autogen_reactive;
+ Fsr2TcrAutogenPassShaderRD tcr_autogen;
+ } shaders;
+
+ Device device;
+};
+
+} // namespace RendererRD
+
+#endif // FSR2_RD_H
diff --git a/servers/rendering/renderer_rd/effects/luminance.cpp b/servers/rendering/renderer_rd/effects/luminance.cpp
index 7462282932..3aa5f5706e 100644
--- a/servers/rendering/renderer_rd/effects/luminance.cpp
+++ b/servers/rendering/renderer_rd/effects/luminance.cpp
@@ -191,11 +191,10 @@ void Luminance::luminance_reduction(RID p_source_texture, const Size2i p_source_
RD::Uniform u_current_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_luminance_buffers->current }));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_current_texture), 1);
}
- 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, &push_constant, sizeof(LuminanceReduceRasterPushConstant));
- RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
}
} else {
diff --git a/servers/rendering/renderer_rd/effects/ss_effects.cpp b/servers/rendering/renderer_rd/effects/ss_effects.cpp
index b9346c0201..d123f24865 100644
--- a/servers/rendering/renderer_rd/effects/ss_effects.cpp
+++ b/servers/rendering/renderer_rd/effects/ss_effects.cpp
@@ -1429,7 +1429,7 @@ void SSEffects::screen_space_reflection(Ref<RenderSceneBuffersRD> p_render_buffe
push_constant.camera_z_far = p_projections[v].get_z_far();
push_constant.camera_z_near = p_projections[v].get_z_near();
push_constant.orthogonal = p_projections[v].is_orthogonal();
- push_constant.filter = false; //enabling causes arctifacts
+ push_constant.filter = false; // Enabling causes artifacts.
push_constant.screen_size[0] = p_ssr_buffers.size.x;
push_constant.screen_size[1] = p_ssr_buffers.size.y;
diff --git a/servers/rendering/renderer_rd/effects/taa.cpp b/servers/rendering/renderer_rd/effects/taa.cpp
index 61e0d3866c..c1037ec11a 100644
--- a/servers/rendering/renderer_rd/effects/taa.cpp
+++ b/servers/rendering/renderer_rd/effects/taa.cpp
@@ -47,20 +47,6 @@ TAA::~TAA() {
taa_shader.version_free(shader_version);
}
-void TAA::msaa_resolve(Ref<RenderSceneBuffersRD> p_render_buffers) {
- if (!p_render_buffers->has_velocity_buffer(true)) {
- // nothing to resolve
- return;
- }
-
- for (uint32_t v = 0; v < p_render_buffers->get_view_count(); v++) {
- RID velocity_buffer_msaa = p_render_buffers->get_velocity_buffer(true, v);
- RID velocity_buffer = p_render_buffers->get_velocity_buffer(false, v);
-
- RD::get_singleton()->texture_resolve_multisample(velocity_buffer_msaa, velocity_buffer);
- }
-}
-
void TAA::resolve(RID p_frame, RID p_temp, RID p_depth, RID p_velocity, RID p_prev_velocity, RID p_history, Size2 p_resolution, float p_z_near, float p_z_far) {
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
diff --git a/servers/rendering/renderer_rd/effects/taa.h b/servers/rendering/renderer_rd/effects/taa.h
index 9e7ad76fb8..f50e297fe5 100644
--- a/servers/rendering/renderer_rd/effects/taa.h
+++ b/servers/rendering/renderer_rd/effects/taa.h
@@ -45,7 +45,6 @@ public:
TAA();
~TAA();
- void msaa_resolve(Ref<RenderSceneBuffersRD> p_render_buffers);
void process(Ref<RenderSceneBuffersRD> p_render_buffers, RD::DataFormat p_format, float p_z_near, float p_z_far);
private:
diff --git a/servers/rendering/renderer_rd/effects/tone_mapper.cpp b/servers/rendering/renderer_rd/effects/tone_mapper.cpp
index 821960bb3b..48c6511408 100644
--- a/servers/rendering/renderer_rd/effects/tone_mapper.cpp
+++ b/servers/rendering/renderer_rd/effects/tone_mapper.cpp
@@ -89,12 +89,12 @@ void ToneMapper::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Ton
memset(&tonemap.push_constant, 0, sizeof(TonemapPushConstant));
- tonemap.push_constant.use_bcs = p_settings.use_bcs;
+ tonemap.push_constant.flags |= p_settings.use_bcs ? TONEMAP_FLAG_USE_BCS : 0;
tonemap.push_constant.bcs[0] = p_settings.brightness;
tonemap.push_constant.bcs[1] = p_settings.contrast;
tonemap.push_constant.bcs[2] = p_settings.saturation;
- tonemap.push_constant.use_glow = p_settings.use_glow;
+ tonemap.push_constant.flags |= p_settings.use_glow ? TONEMAP_FLAG_USE_GLOW : 0;
tonemap.push_constant.glow_intensity = p_settings.glow_intensity;
tonemap.push_constant.glow_map_strength = p_settings.glow_map_strength;
tonemap.push_constant.glow_levels[0] = p_settings.glow_levels[0]; // clean this up to just pass by pointer or something
@@ -114,19 +114,21 @@ void ToneMapper::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Ton
}
tonemap.push_constant.tonemapper = p_settings.tonemap_mode;
- tonemap.push_constant.use_auto_exposure = p_settings.use_auto_exposure;
+ tonemap.push_constant.flags |= p_settings.use_auto_exposure ? TONEMAP_FLAG_USE_AUTO_EXPOSURE : 0;
tonemap.push_constant.exposure = p_settings.exposure;
tonemap.push_constant.white = p_settings.white;
tonemap.push_constant.auto_exposure_scale = p_settings.auto_exposure_scale;
tonemap.push_constant.luminance_multiplier = p_settings.luminance_multiplier;
- tonemap.push_constant.use_color_correction = p_settings.use_color_correction;
+ tonemap.push_constant.flags |= p_settings.use_color_correction ? TONEMAP_FLAG_USE_COLOR_CORRECTION : 0;
- tonemap.push_constant.use_fxaa = p_settings.use_fxaa;
- tonemap.push_constant.use_debanding = p_settings.use_debanding;
+ tonemap.push_constant.flags |= p_settings.use_fxaa ? TONEMAP_FLAG_USE_FXAA : 0;
+ tonemap.push_constant.flags |= p_settings.use_debanding ? TONEMAP_FLAG_USE_DEBANDING : 0;
tonemap.push_constant.pixel_size[0] = 1.0 / p_settings.texture_size.x;
tonemap.push_constant.pixel_size[1] = 1.0 / p_settings.texture_size.y;
+ tonemap.push_constant.flags |= p_settings.convert_to_srgb ? TONEMAP_FLAG_CONVERT_TO_SRGB : 0;
+
if (p_settings.view_count > 1) {
// Use MULTIVIEW versions
mode += 6;
@@ -170,10 +172,9 @@ void ToneMapper::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Ton
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_exposure_texture), 1);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 2, u_glow_texture, u_glow_map), 2);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 3, u_color_correction_texture), 3);
- 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, &tonemap.push_constant, sizeof(TonemapPushConstant));
- RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
}
@@ -185,13 +186,13 @@ void ToneMapper::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_col
memset(&tonemap.push_constant, 0, sizeof(TonemapPushConstant));
- tonemap.push_constant.use_bcs = p_settings.use_bcs;
+ tonemap.push_constant.flags |= p_settings.use_bcs ? TONEMAP_FLAG_USE_BCS : 0;
tonemap.push_constant.bcs[0] = p_settings.brightness;
tonemap.push_constant.bcs[1] = p_settings.contrast;
tonemap.push_constant.bcs[2] = p_settings.saturation;
ERR_FAIL_COND_MSG(p_settings.use_glow, "Glow is not supported when using subpasses.");
- tonemap.push_constant.use_glow = p_settings.use_glow;
+ tonemap.push_constant.flags |= p_settings.use_glow ? TONEMAP_FLAG_USE_GLOW : 0;
int mode = p_settings.use_1d_color_correction ? TONEMAP_MODE_SUBPASS_1D_LUT : TONEMAP_MODE_SUBPASS;
if (p_settings.view_count > 1) {
@@ -200,16 +201,18 @@ void ToneMapper::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_col
}
tonemap.push_constant.tonemapper = p_settings.tonemap_mode;
- tonemap.push_constant.use_auto_exposure = p_settings.use_auto_exposure;
+ tonemap.push_constant.flags |= p_settings.use_auto_exposure ? TONEMAP_FLAG_USE_AUTO_EXPOSURE : 0;
tonemap.push_constant.exposure = p_settings.exposure;
tonemap.push_constant.white = p_settings.white;
tonemap.push_constant.auto_exposure_scale = p_settings.auto_exposure_scale;
- tonemap.push_constant.use_color_correction = p_settings.use_color_correction;
+ tonemap.push_constant.flags |= p_settings.use_color_correction ? TONEMAP_FLAG_USE_COLOR_CORRECTION : 0;
- tonemap.push_constant.use_debanding = p_settings.use_debanding;
+ tonemap.push_constant.flags |= p_settings.use_debanding ? TONEMAP_FLAG_USE_DEBANDING : 0;
tonemap.push_constant.luminance_multiplier = p_settings.luminance_multiplier;
+ tonemap.push_constant.flags |= p_settings.convert_to_srgb ? TONEMAP_FLAG_CONVERT_TO_SRGB : 0;
+
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
RID default_mipmap_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
@@ -250,8 +253,7 @@ void ToneMapper::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_col
RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, uniform_set_cache->get_cache(shader, 1, u_exposure_texture), 1); // should be set to a default texture, it's ignored
RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, uniform_set_cache->get_cache(shader, 2, u_glow_texture, u_glow_map), 2); // should be set to a default texture, it's ignored
RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, uniform_set_cache->get_cache(shader, 3, u_color_correction_texture), 3);
- RD::get_singleton()->draw_list_bind_index_array(p_subpass_draw_list, material_storage->get_quad_index_array());
RD::get_singleton()->draw_list_set_push_constant(p_subpass_draw_list, &tonemap.push_constant, sizeof(TonemapPushConstant));
- RD::get_singleton()->draw_list_draw(p_subpass_draw_list, true);
+ RD::get_singleton()->draw_list_draw(p_subpass_draw_list, false, 1u, 3u);
}
diff --git a/servers/rendering/renderer_rd/effects/tone_mapper.h b/servers/rendering/renderer_rd/effects/tone_mapper.h
index afd2f8e401..a1a99f931f 100644
--- a/servers/rendering/renderer_rd/effects/tone_mapper.h
+++ b/servers/rendering/renderer_rd/effects/tone_mapper.h
@@ -59,14 +59,23 @@ private:
TONEMAP_MODE_MAX
};
+ enum {
+ TONEMAP_FLAG_USE_BCS = (1 << 0),
+ TONEMAP_FLAG_USE_GLOW = (1 << 1),
+ TONEMAP_FLAG_USE_AUTO_EXPOSURE = (1 << 2),
+ TONEMAP_FLAG_USE_COLOR_CORRECTION = (1 << 3),
+ TONEMAP_FLAG_USE_FXAA = (1 << 4),
+ TONEMAP_FLAG_USE_DEBANDING = (1 << 5),
+ TONEMAP_FLAG_CONVERT_TO_SRGB = (1 << 6),
+ };
+
struct TonemapPushConstant {
float bcs[3]; // 12 - 12
- uint32_t use_bcs; // 4 - 16
+ uint32_t flags; // 4 - 16
- uint32_t use_glow; // 4 - 20
- uint32_t use_auto_exposure; // 4 - 24
- uint32_t use_color_correction; // 4 - 28
- uint32_t tonemapper; // 4 - 32
+ float pixel_size[2]; // 8 - 24
+ uint32_t tonemapper; // 4 - 28
+ uint32_t pad; // 4 - 32
uint32_t glow_texture_size[2]; // 8 - 40
float glow_intensity; // 4 - 44
@@ -79,10 +88,6 @@ private:
float white; // 4 - 88
float auto_exposure_scale; // 4 - 92
float luminance_multiplier; // 4 - 96
-
- float pixel_size[2]; // 8 - 104
- uint32_t use_fxaa; // 4 - 108
- uint32_t use_debanding; // 4 - 112
};
/* tonemap actually writes to a framebuffer, which is
@@ -141,6 +146,8 @@ public:
bool use_debanding = false;
Vector2i texture_size;
uint32_t view_count = 1;
+
+ bool convert_to_srgb = false;
};
void tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings);
diff --git a/servers/rendering/renderer_rd/effects/vrs.cpp b/servers/rendering/renderer_rd/effects/vrs.cpp
index 6ec8612029..63c99facdd 100644
--- a/servers/rendering/renderer_rd/effects/vrs.cpp
+++ b/servers/rendering/renderer_rd/effects/vrs.cpp
@@ -85,9 +85,8 @@ void VRS::copy_vrs(RID p_source_rd_texture, RID p_dest_framebuffer, bool p_multi
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_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
}
diff --git a/servers/rendering/renderer_rd/environment/fog.cpp b/servers/rendering/renderer_rd/environment/fog.cpp
index 98d826b1f9..7d4eb0e038 100644
--- a/servers/rendering/renderer_rd/environment/fog.cpp
+++ b/servers/rendering/renderer_rd/environment/fog.cpp
@@ -72,7 +72,7 @@ Dependency *Fog::fog_volume_get_dependency(RID p_fog_volume) const {
void Fog::fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) {
FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
- ERR_FAIL_COND(!fog_volume);
+ ERR_FAIL_NULL(fog_volume);
if (p_shape == fog_volume->shape) {
return;
@@ -84,7 +84,7 @@ void Fog::fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) {
void Fog::fog_volume_set_size(RID p_fog_volume, const Vector3 &p_size) {
FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
- ERR_FAIL_COND(!fog_volume);
+ ERR_FAIL_NULL(fog_volume);
fog_volume->size = p_size;
fog_volume->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
@@ -92,27 +92,27 @@ void Fog::fog_volume_set_size(RID p_fog_volume, const Vector3 &p_size) {
void Fog::fog_volume_set_material(RID p_fog_volume, RID p_material) {
FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
- ERR_FAIL_COND(!fog_volume);
+ ERR_FAIL_NULL(fog_volume);
fog_volume->material = p_material;
}
RID Fog::fog_volume_get_material(RID p_fog_volume) const {
FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
- ERR_FAIL_COND_V(!fog_volume, RID());
+ ERR_FAIL_NULL_V(fog_volume, RID());
return fog_volume->material;
}
RS::FogVolumeShape Fog::fog_volume_get_shape(RID p_fog_volume) const {
FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
- ERR_FAIL_COND_V(!fog_volume, RS::FOG_VOLUME_SHAPE_BOX);
+ ERR_FAIL_NULL_V(fog_volume, RS::FOG_VOLUME_SHAPE_BOX);
return fog_volume->shape;
}
AABB Fog::fog_volume_get_aabb(RID p_fog_volume) const {
FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
- ERR_FAIL_COND_V(!fog_volume, AABB());
+ ERR_FAIL_NULL_V(fog_volume, AABB());
switch (fog_volume->shape) {
case RS::FOG_VOLUME_SHAPE_ELLIPSOID:
@@ -133,7 +133,7 @@ AABB Fog::fog_volume_get_aabb(RID p_fog_volume) const {
Vector3 Fog::fog_volume_get_size(RID p_fog_volume) const {
const FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
- ERR_FAIL_COND_V(!fog_volume, Vector3());
+ ERR_FAIL_NULL_V(fog_volume, Vector3());
return fog_volume->size;
}
@@ -143,7 +143,7 @@ Vector3 Fog::fog_volume_get_size(RID p_fog_volume) const {
bool Fog::FogMaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
uniform_set_updated = true;
- return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, Fog::get_singleton()->volumetric_fog.shader.version_get_shader(shader_data->version, 0), VolumetricFogShader::FogSet::FOG_SET_MATERIAL, true);
+ return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, Fog::get_singleton()->volumetric_fog.shader.version_get_shader(shader_data->version, 0), VolumetricFogShader::FogSet::FOG_SET_MATERIAL, true, true);
}
Fog::FogMaterialData::~FogMaterialData() {
@@ -228,7 +228,7 @@ void Fog::init_fog_shader(uint32_t p_max_directional_lights, int p_roughness_lay
actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
actions.default_repeat = ShaderLanguage::REPEAT_DISABLE;
- actions.global_buffer_array_variable = "global_variables.data";
+ actions.global_buffer_array_variable = "global_shader_uniforms.data";
volumetric_fog.compiler.initialize(actions);
}
@@ -264,7 +264,7 @@ ALBEDO = vec3(1.0);
uniforms.push_back(u);
}
- uniforms.append_array(material_storage->get_default_sampler_uniforms(SAMPLERS_BINDING_FIRST_INDEX));
+ uniforms.append_array(material_storage->samplers_rd_get_default().get_uniforms(SAMPLERS_BINDING_FIRST_INDEX));
volumetric_fog.base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.default_shader_rd, VolumetricFogShader::FogSet::FOG_SET_BASE);
}
@@ -370,7 +370,7 @@ RS::ShaderNativeSourceCode Fog::FogShaderData::get_native_source_code() const {
Fog::FogShaderData::~FogShaderData() {
Fog *fog_singleton = Fog::get_singleton();
- ERR_FAIL_COND(!fog_singleton);
+ ERR_FAIL_NULL(fog_singleton);
//pipeline variants will clear themselves if shader is gone
if (version.is_valid()) {
fog_singleton->volumetric_fog.shader.version_free(version);
@@ -543,7 +543,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
if (p_cam_projection.is_orthogonal()) {
fog_near_size = fog_far_size;
} else {
- fog_near_size = Vector2();
+ fog_near_size = frustum_near_size.max(Vector2(0.001, 0.001));
}
params.fog_frustum_size_begin[0] = fog_near_size.x;
@@ -627,7 +627,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
for (int i = 0; i < (int)p_fog_volumes.size(); i++) {
FogVolumeInstance *fog_volume_instance = fog_volume_instance_owner.get_or_null(p_fog_volumes[i]);
- ERR_FAIL_COND(!fog_volume_instance);
+ ERR_FAIL_NULL(fog_volume_instance);
RID fog_volume = fog_volume_instance->volume;
RID fog_material = RendererRD::Fog::get_singleton()->fog_volume_get_material(fog_volume);
@@ -646,11 +646,11 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
material = static_cast<FogMaterialData *>(material_storage->material_get_data(fog_material, RendererRD::MaterialStorage::SHADER_TYPE_FOG));
}
- ERR_FAIL_COND(!material);
+ ERR_FAIL_NULL(material);
FogShaderData *shader_data = material->shader_data;
- ERR_FAIL_COND(!shader_data);
+ ERR_FAIL_NULL(shader_data);
any_uses_time |= shader_data->uses_time;
@@ -1002,7 +1002,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
if (p_cam_projection.is_orthogonal()) {
fog_near_size = fog_far_size;
} else {
- fog_near_size = Vector2();
+ fog_near_size = frustum_near_size.max(Vector2(0.001, 0.001));
}
params.fog_frustum_size_begin[0] = fog_near_size.x;
diff --git a/servers/rendering/renderer_rd/environment/fog.h b/servers/rendering/renderer_rd/environment/fog.h
index 206d7852a7..25fb190f44 100644
--- a/servers/rendering/renderer_rd/environment/fog.h
+++ b/servers/rendering/renderer_rd/environment/fog.h
@@ -257,25 +257,25 @@ public:
void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) {
Fog::FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance);
- ERR_FAIL_COND(!fvi);
+ ERR_FAIL_NULL(fvi);
fvi->transform = p_transform;
}
void fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) {
Fog::FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance);
- ERR_FAIL_COND(!fvi);
+ ERR_FAIL_NULL(fvi);
fvi->active = p_active;
}
RID fog_volume_instance_get_volume(RID p_fog_volume_instance) const {
Fog::FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance);
- ERR_FAIL_COND_V(!fvi, RID());
+ ERR_FAIL_NULL_V(fvi, RID());
return fvi->volume;
}
Vector3 fog_volume_instance_get_position(RID p_fog_volume_instance) const {
Fog::FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance);
- ERR_FAIL_COND_V(!fvi, Vector3());
+ ERR_FAIL_NULL_V(fvi, Vector3());
return fvi->transform.get_origin();
}
diff --git a/servers/rendering/renderer_rd/environment/gi.cpp b/servers/rendering/renderer_rd/environment/gi.cpp
index 964d4d9adf..0667ae87e5 100644
--- a/servers/rendering/renderer_rd/environment/gi.cpp
+++ b/servers/rendering/renderer_rd/environment/gi.cpp
@@ -64,7 +64,7 @@ void GI::voxel_gi_initialize(RID p_voxel_gi) {
void GI::voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND(!voxel_gi);
+ ERR_FAIL_NULL(voxel_gi);
if (voxel_gi->octree_buffer.is_valid()) {
RD::get_singleton()->free(voxel_gi->octree_buffer);
@@ -191,20 +191,20 @@ void GI::voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &p_to_cell_xfo
AABB GI::voxel_gi_get_bounds(RID p_voxel_gi) const {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND_V(!voxel_gi, AABB());
+ ERR_FAIL_NULL_V(voxel_gi, AABB());
return voxel_gi->bounds;
}
Vector3i GI::voxel_gi_get_octree_size(RID p_voxel_gi) const {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND_V(!voxel_gi, Vector3i());
+ ERR_FAIL_NULL_V(voxel_gi, Vector3i());
return voxel_gi->octree_size;
}
Vector<uint8_t> GI::voxel_gi_get_octree_cells(RID p_voxel_gi) const {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND_V(!voxel_gi, Vector<uint8_t>());
+ ERR_FAIL_NULL_V(voxel_gi, Vector<uint8_t>());
if (voxel_gi->octree_buffer.is_valid()) {
return RD::get_singleton()->buffer_get_data(voxel_gi->octree_buffer);
@@ -214,7 +214,7 @@ Vector<uint8_t> GI::voxel_gi_get_octree_cells(RID p_voxel_gi) const {
Vector<uint8_t> GI::voxel_gi_get_data_cells(RID p_voxel_gi) const {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND_V(!voxel_gi, Vector<uint8_t>());
+ ERR_FAIL_NULL_V(voxel_gi, Vector<uint8_t>());
if (voxel_gi->data_buffer.is_valid()) {
return RD::get_singleton()->buffer_get_data(voxel_gi->data_buffer);
@@ -224,7 +224,7 @@ Vector<uint8_t> GI::voxel_gi_get_data_cells(RID p_voxel_gi) const {
Vector<uint8_t> GI::voxel_gi_get_distance_field(RID p_voxel_gi) const {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND_V(!voxel_gi, Vector<uint8_t>());
+ ERR_FAIL_NULL_V(voxel_gi, Vector<uint8_t>());
if (voxel_gi->data_buffer.is_valid()) {
return RD::get_singleton()->texture_get_data(voxel_gi->sdf_texture, 0);
@@ -234,21 +234,21 @@ Vector<uint8_t> GI::voxel_gi_get_distance_field(RID p_voxel_gi) const {
Vector<int> GI::voxel_gi_get_level_counts(RID p_voxel_gi) const {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND_V(!voxel_gi, Vector<int>());
+ ERR_FAIL_NULL_V(voxel_gi, Vector<int>());
return voxel_gi->level_counts;
}
Transform3D GI::voxel_gi_get_to_cell_xform(RID p_voxel_gi) const {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND_V(!voxel_gi, Transform3D());
+ ERR_FAIL_NULL_V(voxel_gi, Transform3D());
return voxel_gi->to_cell_xform;
}
void GI::voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND(!voxel_gi);
+ ERR_FAIL_NULL(voxel_gi);
voxel_gi->dynamic_range = p_range;
voxel_gi->version++;
@@ -256,14 +256,14 @@ void GI::voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) {
float GI::voxel_gi_get_dynamic_range(RID p_voxel_gi) const {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND_V(!voxel_gi, 0);
+ ERR_FAIL_NULL_V(voxel_gi, 0);
return voxel_gi->dynamic_range;
}
void GI::voxel_gi_set_propagation(RID p_voxel_gi, float p_range) {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND(!voxel_gi);
+ ERR_FAIL_NULL(voxel_gi);
voxel_gi->propagation = p_range;
voxel_gi->version++;
@@ -271,72 +271,72 @@ void GI::voxel_gi_set_propagation(RID p_voxel_gi, float p_range) {
float GI::voxel_gi_get_propagation(RID p_voxel_gi) const {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND_V(!voxel_gi, 0);
+ ERR_FAIL_NULL_V(voxel_gi, 0);
return voxel_gi->propagation;
}
void GI::voxel_gi_set_energy(RID p_voxel_gi, float p_energy) {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND(!voxel_gi);
+ ERR_FAIL_NULL(voxel_gi);
voxel_gi->energy = p_energy;
}
float GI::voxel_gi_get_energy(RID p_voxel_gi) const {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND_V(!voxel_gi, 0);
+ ERR_FAIL_NULL_V(voxel_gi, 0);
return voxel_gi->energy;
}
void GI::voxel_gi_set_baked_exposure_normalization(RID p_voxel_gi, float p_baked_exposure) {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND(!voxel_gi);
+ ERR_FAIL_NULL(voxel_gi);
voxel_gi->baked_exposure = p_baked_exposure;
}
float GI::voxel_gi_get_baked_exposure_normalization(RID p_voxel_gi) const {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND_V(!voxel_gi, 0);
+ ERR_FAIL_NULL_V(voxel_gi, 0);
return voxel_gi->baked_exposure;
}
void GI::voxel_gi_set_bias(RID p_voxel_gi, float p_bias) {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND(!voxel_gi);
+ ERR_FAIL_NULL(voxel_gi);
voxel_gi->bias = p_bias;
}
float GI::voxel_gi_get_bias(RID p_voxel_gi) const {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND_V(!voxel_gi, 0);
+ ERR_FAIL_NULL_V(voxel_gi, 0);
return voxel_gi->bias;
}
void GI::voxel_gi_set_normal_bias(RID p_voxel_gi, float p_normal_bias) {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND(!voxel_gi);
+ ERR_FAIL_NULL(voxel_gi);
voxel_gi->normal_bias = p_normal_bias;
}
float GI::voxel_gi_get_normal_bias(RID p_voxel_gi) const {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND_V(!voxel_gi, 0);
+ ERR_FAIL_NULL_V(voxel_gi, 0);
return voxel_gi->normal_bias;
}
void GI::voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND(!voxel_gi);
+ ERR_FAIL_NULL(voxel_gi);
voxel_gi->interior = p_enable;
}
void GI::voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND(!voxel_gi);
+ ERR_FAIL_NULL(voxel_gi);
voxel_gi->use_two_bounces = p_enable;
voxel_gi->version++;
@@ -344,50 +344,50 @@ void GI::voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) {
bool GI::voxel_gi_is_using_two_bounces(RID p_voxel_gi) const {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND_V(!voxel_gi, false);
+ ERR_FAIL_NULL_V(voxel_gi, false);
return voxel_gi->use_two_bounces;
}
bool GI::voxel_gi_is_interior(RID p_voxel_gi) const {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND_V(!voxel_gi, 0);
+ ERR_FAIL_NULL_V(voxel_gi, 0);
return voxel_gi->interior;
}
uint32_t GI::voxel_gi_get_version(RID p_voxel_gi) const {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND_V(!voxel_gi, 0);
+ ERR_FAIL_NULL_V(voxel_gi, 0);
return voxel_gi->version;
}
uint32_t GI::voxel_gi_get_data_version(RID p_voxel_gi) {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND_V(!voxel_gi, 0);
+ ERR_FAIL_NULL_V(voxel_gi, 0);
return voxel_gi->data_version;
}
RID GI::voxel_gi_get_octree_buffer(RID p_voxel_gi) const {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND_V(!voxel_gi, RID());
+ ERR_FAIL_NULL_V(voxel_gi, RID());
return voxel_gi->octree_buffer;
}
RID GI::voxel_gi_get_data_buffer(RID p_voxel_gi) const {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND_V(!voxel_gi, RID());
+ ERR_FAIL_NULL_V(voxel_gi, RID());
return voxel_gi->data_buffer;
}
RID GI::voxel_gi_get_sdf_texture(RID p_voxel_gi) {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND_V(!voxel_gi, RID());
+ ERR_FAIL_NULL_V(voxel_gi, RID());
return voxel_gi->sdf_texture;
}
Dependency *GI::voxel_gi_get_dependency(RID p_voxel_gi) const {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND_V(!voxel_gi, nullptr);
+ ERR_FAIL_NULL_V(voxel_gi, nullptr);
return &voxel_gi->dependency;
}
@@ -395,6 +395,16 @@ Dependency *GI::voxel_gi_get_dependency(RID p_voxel_gi) const {
////////////////////////////////////////////////////////////////////////////////
// SDFGI
+static RID create_clear_texture(const RD::TextureFormat &p_format, const String &p_name) {
+ RID texture = RD::get_singleton()->texture_create(p_format, RD::TextureView());
+ ERR_FAIL_COND_V_MSG(texture.is_null(), RID(), String("Cannot create texture: ") + p_name);
+
+ RD::get_singleton()->set_resource_name(texture, p_name);
+ RD::get_singleton()->texture_clear(texture, Color(0, 0, 0, 0), 0, p_format.mipmaps, 0, p_format.array_layers);
+
+ return texture;
+}
+
void GI::SDFGI::create(RID p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size, GI *p_gi) {
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
@@ -424,39 +434,31 @@ void GI::SDFGI::create(RID p_env, const Vector3 &p_world_position, uint32_t p_re
{
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");
+ render_albedo = create_clear_texture(tf_render, "SDFGI 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");
+ render_emission = create_clear_texture(tf_render, "SDFGI Render Emission");
+ render_emission_aniso = create_clear_texture(tf_render, "SDFGI 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));
+ render_occlusion[i] = create_clear_texture(tf_render, String("SDFGI 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");
+ render_geom_facing = create_clear_texture(tf_render, "SDFGI 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");
+ render_sdf[0] = create_clear_texture(tf_render, "SDFGI Render SDF 0");
+ render_sdf[1] = create_clear_texture(tf_render, "SDFGI 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");
+ render_sdf_half[0] = create_clear_texture(tf_render, "SDFGI Render SDF Half 0");
+ render_sdf_half[1] = create_clear_texture(tf_render, "SDFGI Render SDF Half 1");
}
RD::TextureFormat tf_occlusion = tf_sdf;
@@ -496,10 +498,8 @@ void GI::SDFGI::create(RID p_env, const Vector3 &p_world_position, uint32_t p_re
tf_probe_average.format = RD::DATA_FORMAT_R32G32B32A32_SINT; //signed integer because SH are signed
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");
+ lightprobe_history_scroll = create_clear_texture(tf_probe_history, "SDFGI LightProbe History Scroll");
+ lightprobe_average_scroll = create_clear_texture(tf_probe_average, "SDFGI LightProbe Average Scroll");
{
//octahedral lightprobes
@@ -512,8 +512,7 @@ void GI::SDFGI::create(RID p_env, const Vector3 &p_world_position, uint32_t p_re
tf_octprobes.shareable_formats.push_back(RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32);
//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");
+ lightprobe_data = create_clear_texture(tf_octprobes, "SDFGI 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);
@@ -526,14 +525,12 @@ void GI::SDFGI::create(RID p_env, const Vector3 &p_world_position, uint32_t p_re
tf_ambient.height = probe_axis_count;
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");
+ ambient_texture = create_clear_texture(tf_ambient, "SDFGI 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");
+ occlusion_data = create_clear_texture(tf_occlusion, "SDFGI Occlusion Data");
{
RD::TextureView tv;
tv.format_override = RD::DATA_FORMAT_R4G4B4A4_UNORM_PACK16;
@@ -543,25 +540,17 @@ void GI::SDFGI::create(RID p_env, const Vector3 &p_world_position, uint32_t p_re
for (SDFGI::Cascade &cascade : cascades) {
/* 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.sdf_tex = create_clear_texture(tf_sdf, "SDFGI 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_data = create_clear_texture(tf_light, "SDFGI 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");
+ cascade.light_aniso_0_tex = create_clear_texture(tf_aniso0, "SDFGI Cascade Light Aniso 0 Texture");
+ cascade.light_aniso_1_tex = create_clear_texture(tf_aniso1, "SDFGI Cascade Light Aniso 1 Texture");
{
RD::TextureView tv;
tv.format_override = RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32;
cascade.light_tex = RD::get_singleton()->texture_create_shared(tv, cascade.light_data);
-
- RD::get_singleton()->texture_clear(cascade.light_tex, Color(0, 0, 0, 0), 0, 1, 0, 1);
- RD::get_singleton()->texture_clear(cascade.light_aniso_0_tex, Color(0, 0, 0, 0), 0, 1, 0, 1);
- RD::get_singleton()->texture_clear(cascade.light_aniso_1_tex, Color(0, 0, 0, 0), 0, 1, 0, 1);
}
cascade.cell_size = base_cell_size;
@@ -579,11 +568,11 @@ void GI::SDFGI::create(RID p_env, const Vector3 &p_world_position, uint32_t p_re
/* 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()->set_resource_name(cascade.lightprobe_history_tex, "SDFGI 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()->set_resource_name(cascade.lightprobe_average_tex, "SDFGI 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 */
@@ -2215,7 +2204,7 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_
RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_size, cascade_size, cascade_size);
RD::get_singleton()->compute_list_add_barrier(compute_list);
- //run one pass of fullsize jumpflood to fix up half size arctifacts
+ //run one pass of fullsize jumpflood to fix up half size artifacts
push_constant.half_size = false;
push_constant.step_size = 1;
@@ -2977,7 +2966,7 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID
push_constant.cell_offset = mipmaps[i].cell_offset;
push_constant.cell_count = mipmaps[i].cell_count;
- int64_t wg_todo = (mipmaps[i].cell_count - 1) / wg_size + 1;
+ int64_t wg_todo = (mipmaps[i].cell_count + wg_size - 1) / wg_size;
while (wg_todo) {
int64_t wg_count = MIN(wg_todo, wg_limit_x);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VoxelGIPushConstant));
@@ -2998,7 +2987,7 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID
push_constant.cell_offset = mipmaps[i].cell_offset;
push_constant.cell_count = mipmaps[i].cell_count;
- int64_t wg_todo = (mipmaps[i].cell_count - 1) / wg_size + 1;
+ int64_t wg_todo = (mipmaps[i].cell_count + wg_size - 1) / wg_size;
while (wg_todo) {
int64_t wg_count = MIN(wg_todo, wg_limit_x);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VoxelGIPushConstant));
@@ -4065,28 +4054,28 @@ void GI::voxel_gi_instance_free(RID p_rid) {
void GI::voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) {
VoxelGIInstance *voxel_gi = voxel_gi_instance_owner.get_or_null(p_probe);
- ERR_FAIL_COND(!voxel_gi);
+ ERR_FAIL_NULL(voxel_gi);
voxel_gi->transform = p_xform;
}
bool GI::voxel_gi_needs_update(RID p_probe) const {
VoxelGIInstance *voxel_gi = voxel_gi_instance_owner.get_or_null(p_probe);
- ERR_FAIL_COND_V(!voxel_gi, false);
+ ERR_FAIL_NULL_V(voxel_gi, false);
return voxel_gi->last_probe_version != voxel_gi_get_version(voxel_gi->probe);
}
void GI::voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects) {
VoxelGIInstance *voxel_gi = voxel_gi_instance_owner.get_or_null(p_probe);
- ERR_FAIL_COND(!voxel_gi);
+ ERR_FAIL_NULL(voxel_gi);
voxel_gi->update(p_update_light_instances, p_light_instances, p_dynamic_objects);
}
void GI::debug_voxel_gi(RID p_voxel_gi, RD::DrawListID p_draw_list, RID p_framebuffer, const Projection &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) {
VoxelGIInstance *voxel_gi = voxel_gi_instance_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_COND(!voxel_gi);
+ ERR_FAIL_NULL(voxel_gi);
voxel_gi->debug(p_draw_list, p_framebuffer, p_camera_with_transform, p_lighting, p_emission, p_alpha);
}
diff --git a/servers/rendering/renderer_rd/environment/gi.h b/servers/rendering/renderer_rd/environment/gi.h
index 651a660f5c..9a45919a2f 100644
--- a/servers/rendering/renderer_rd/environment/gi.h
+++ b/servers/rendering/renderer_rd/environment/gi.h
@@ -522,7 +522,7 @@ public:
_FORCE_INLINE_ RID voxel_gi_instance_get_texture(RID p_probe) {
VoxelGIInstance *voxel_gi = voxel_gi_instance_owner.get_or_null(p_probe);
- ERR_FAIL_COND_V(!voxel_gi, RID());
+ ERR_FAIL_NULL_V(voxel_gi, RID());
return voxel_gi->texture;
};
diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp
index ebf3c5f619..ba72ab3b08 100644
--- a/servers/rendering/renderer_rd/environment/sky.cpp
+++ b/servers/rendering/renderer_rd/environment/sky.cpp
@@ -170,7 +170,7 @@ RS::ShaderNativeSourceCode SkyRD::SkyShaderData::get_native_source_code() const
SkyRD::SkyShaderData::~SkyShaderData() {
RendererSceneRenderRD *scene_singleton = static_cast<RendererSceneRenderRD *>(RendererSceneRenderRD::singleton);
- ERR_FAIL_COND(!scene_singleton);
+ ERR_FAIL_NULL(scene_singleton);
//pipeline variants will clear themselves if shader is gone
if (version.is_valid()) {
scene_singleton->sky.sky_shader.shader.version_free(version);
@@ -185,7 +185,7 @@ bool SkyRD::SkyMaterialData::update_parameters(const HashMap<StringName, Variant
uniform_set_updated = true;
- return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, scene_singleton->sky.sky_shader.shader.version_get_shader(shader_data->version, 0), SKY_SET_MATERIAL, true);
+ return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, scene_singleton->sky.sky_shader.shader.version_get_shader(shader_data->version, 0), SKY_SET_MATERIAL, true, true);
}
SkyRD::SkyMaterialData::~SkyMaterialData() {
@@ -249,11 +249,9 @@ void SkyRD::_render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineC
}
}
- RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
-
RD::get_singleton()->draw_list_set_push_constant(draw_list, &sky_push_constant, sizeof(SkyPushConstant));
- RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
}
////////////////////////////////////////////////////////////////////////////////
@@ -876,7 +874,7 @@ void sky() {
uniforms.push_back(u);
}
- uniforms.append_array(material_storage->get_default_sampler_uniforms(SAMPLERS_BINDING_FIRST_INDEX));
+ uniforms.append_array(material_storage->samplers_rd_get_default().get_uniforms(SAMPLERS_BINDING_FIRST_INDEX));
sky_scene_state.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_UNIFORMS);
}
@@ -941,23 +939,6 @@ void sky() {
sky_scene_state.fog_only_texture_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_TEXTURES);
}
-
- { //create index array for copy shaders
- Vector<uint8_t> pv;
- pv.resize(6 * 4);
- {
- uint8_t *w = pv.ptrw();
- int *p32 = (int *)w;
- p32[0] = 0;
- p32[1] = 1;
- p32[2] = 2;
- p32[3] = 0;
- p32[4] = 2;
- p32[5] = 3;
- }
- index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, pv);
- index_array = RD::get_singleton()->index_array_create(index_buffer, 0, 6);
- }
}
void SkyRD::set_texture_format(RD::DataFormat p_texture_format) {
@@ -990,11 +971,9 @@ SkyRD::~SkyRD() {
if (RD::get_singleton()->uniform_set_is_valid(sky_scene_state.fog_only_texture_uniform_set)) {
RD::get_singleton()->free(sky_scene_state.fog_only_texture_uniform_set);
}
-
- RD::get_singleton()->free(index_buffer); //array gets freed as dependency
}
-void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const PagedArray<RID> &p_lights, RID p_camera_attributes, uint32_t p_view_count, const Projection *p_view_projections, const Vector3 *p_view_eye_offsets, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render) {
+void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const PagedArray<RID> &p_lights, RID p_camera_attributes, uint32_t p_view_count, const Projection *p_view_projections, const Vector3 *p_view_eye_offsets, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const Size2i p_screen_size, Vector2 p_jitter, RendererSceneRenderRD *p_scene_render) {
RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
ERR_FAIL_COND(p_env.is_null());
@@ -1028,11 +1007,11 @@ void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, con
material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::MaterialStorage::SHADER_TYPE_SKY));
}
- ERR_FAIL_COND(!material);
+ ERR_FAIL_NULL(material);
shader_data = material->shader_data;
- ERR_FAIL_COND(!shader_data);
+ ERR_FAIL_NULL(shader_data);
material->set_as_used();
@@ -1194,18 +1173,21 @@ void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, con
}
}
+ Projection correction;
+ correction.add_jitter_offset(p_jitter);
+
sky_scene_state.view_count = p_view_count;
sky_scene_state.cam_transform = p_cam_transform;
- sky_scene_state.cam_projection = p_cam_projection; // We only use this when rendering a single view.
+ sky_scene_state.cam_projection = correction * p_cam_projection; // We only use this when rendering a single view.
// Our info in our UBO is only used if we're rendering stereo.
for (uint32_t i = 0; i < p_view_count; i++) {
- Projection view_inv_projection = p_view_projections[i].inverse();
+ Projection view_inv_projection = (correction * p_view_projections[i]).inverse();
if (p_view_count > 1) {
RendererRD::MaterialStorage::store_camera(p_cam_projection * view_inv_projection, sky_scene_state.ubo.combined_reprojection[i]);
} else {
Projection ident;
- RendererRD::MaterialStorage::store_camera(ident, sky_scene_state.ubo.combined_reprojection[i]);
+ RendererRD::MaterialStorage::store_camera(correction, sky_scene_state.ubo.combined_reprojection[i]);
}
RendererRD::MaterialStorage::store_camera(view_inv_projection, sky_scene_state.ubo.view_inv_projections[i]);
@@ -1238,7 +1220,7 @@ void SkyRD::update_radiance_buffers(Ref<RenderSceneBuffersRD> p_render_buffers,
ERR_FAIL_COND(p_env.is_null());
Sky *sky = get_sky(RendererSceneRenderRD::get_singleton()->environment_get_sky(p_env));
- ERR_FAIL_COND(!sky);
+ ERR_FAIL_NULL(sky);
RID sky_material = sky_get_material(RendererSceneRenderRD::get_singleton()->environment_get_sky(p_env));
@@ -1256,11 +1238,11 @@ void SkyRD::update_radiance_buffers(Ref<RenderSceneBuffersRD> p_render_buffers,
material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::MaterialStorage::SHADER_TYPE_SKY));
}
- ERR_FAIL_COND(!material);
+ ERR_FAIL_NULL(material);
SkyShaderData *shader_data = material->shader_data;
- ERR_FAIL_COND(!shader_data);
+ ERR_FAIL_NULL(shader_data);
bool update_single_frame = sky->mode == RS::SKY_MODE_REALTIME || sky->mode == RS::SKY_MODE_QUALITY;
RS::SkyMode sky_mode = sky->mode;
@@ -1419,7 +1401,7 @@ void SkyRD::update_res_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, RID p
RS::EnvironmentBG background = RendererSceneRenderRD::get_singleton()->environment_get_background(p_env);
if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) {
- ERR_FAIL_COND(!sky);
+ ERR_FAIL_NULL(sky);
sky_material = sky_get_material(RendererSceneRenderRD::get_singleton()->environment_get_sky(p_env));
if (sky_material.is_valid()) {
@@ -1440,10 +1422,10 @@ void SkyRD::update_res_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, RID p
material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::MaterialStorage::SHADER_TYPE_SKY));
}
- ERR_FAIL_COND(!material);
+ ERR_FAIL_NULL(material);
SkyShaderData *shader_data = material->shader_data;
- ERR_FAIL_COND(!shader_data);
+ ERR_FAIL_NULL(shader_data);
if (!shader_data->uses_quarter_res && !shader_data->uses_half_res) {
return;
@@ -1527,7 +1509,7 @@ void SkyRD::draw_sky(RD::DrawListID p_draw_list, Ref<RenderSceneBuffersRD> p_ren
RS::EnvironmentBG background = RendererSceneRenderRD::get_singleton()->environment_get_background(p_env);
if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) {
- ERR_FAIL_COND(!sky);
+ ERR_FAIL_NULL(sky);
sky_material = sky_get_material(RendererSceneRenderRD::get_singleton()->environment_get_sky(p_env));
if (sky_material.is_valid()) {
@@ -1548,10 +1530,10 @@ void SkyRD::draw_sky(RD::DrawListID p_draw_list, Ref<RenderSceneBuffersRD> p_ren
material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::MaterialStorage::SHADER_TYPE_SKY));
}
- ERR_FAIL_COND(!material);
+ ERR_FAIL_NULL(material);
SkyShaderData *shader_data = material->shader_data;
- ERR_FAIL_COND(!shader_data);
+ ERR_FAIL_NULL(shader_data);
material->set_as_used();
@@ -1667,14 +1649,14 @@ void SkyRD::update_dirty_skys() {
RID SkyRD::sky_get_material(RID p_sky) const {
Sky *sky = get_sky(p_sky);
- ERR_FAIL_COND_V(!sky, RID());
+ ERR_FAIL_NULL_V(sky, RID());
return sky->material;
}
float SkyRD::sky_get_baked_exposure(RID p_sky) const {
Sky *sky = get_sky(p_sky);
- ERR_FAIL_COND_V(!sky, 1.0);
+ ERR_FAIL_NULL_V(sky, 1.0);
return sky->baked_exposure;
}
@@ -1693,7 +1675,7 @@ SkyRD::Sky *SkyRD::get_sky(RID p_sky) const {
void SkyRD::free_sky(RID p_sky) {
Sky *sky = get_sky(p_sky);
- ERR_FAIL_COND(!sky);
+ ERR_FAIL_NULL(sky);
sky->free();
sky_owner.free(p_sky);
@@ -1701,7 +1683,7 @@ void SkyRD::free_sky(RID p_sky) {
void SkyRD::sky_set_radiance_size(RID p_sky, int p_radiance_size) {
Sky *sky = get_sky(p_sky);
- ERR_FAIL_COND(!sky);
+ ERR_FAIL_NULL(sky);
if (sky->set_radiance_size(p_radiance_size)) {
invalidate_sky(sky);
@@ -1710,7 +1692,7 @@ void SkyRD::sky_set_radiance_size(RID p_sky, int p_radiance_size) {
void SkyRD::sky_set_mode(RID p_sky, RS::SkyMode p_mode) {
Sky *sky = get_sky(p_sky);
- ERR_FAIL_COND(!sky);
+ ERR_FAIL_NULL(sky);
if (sky->set_mode(p_mode)) {
invalidate_sky(sky);
@@ -1719,7 +1701,7 @@ void SkyRD::sky_set_mode(RID p_sky, RS::SkyMode p_mode) {
void SkyRD::sky_set_material(RID p_sky, RID p_material) {
Sky *sky = get_sky(p_sky);
- ERR_FAIL_COND(!sky);
+ ERR_FAIL_NULL(sky);
if (sky->set_material(p_material)) {
invalidate_sky(sky);
@@ -1728,7 +1710,7 @@ void SkyRD::sky_set_material(RID p_sky, RID p_material) {
Ref<Image> SkyRD::sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) {
Sky *sky = get_sky(p_sky);
- ERR_FAIL_COND_V(!sky, Ref<Image>());
+ ERR_FAIL_NULL_V(sky, Ref<Image>());
update_dirty_skys();
@@ -1737,7 +1719,7 @@ Ref<Image> SkyRD::sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irrad
RID SkyRD::sky_get_radiance_texture_rd(RID p_sky) const {
Sky *sky = get_sky(p_sky);
- ERR_FAIL_COND_V(!sky, RID());
+ ERR_FAIL_NULL_V(sky, RID());
return sky->radiance;
}
diff --git a/servers/rendering/renderer_rd/environment/sky.h b/servers/rendering/renderer_rd/environment/sky.h
index 7aee65fd67..b146a416f9 100644
--- a/servers/rendering/renderer_rd/environment/sky.h
+++ b/servers/rendering/renderer_rd/environment/sky.h
@@ -70,9 +70,6 @@ public:
private:
RD::DataFormat texture_format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- RID index_buffer;
- RID index_array;
-
enum SkyTextureSetVersion {
SKY_TEXTURE_SET_BACKGROUND,
SKY_TEXTURE_SET_HALF_RES,
@@ -297,7 +294,7 @@ public:
void set_texture_format(RD::DataFormat p_texture_format);
~SkyRD();
- void setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const PagedArray<RID> &p_lights, RID p_camera_attributes, uint32_t p_view_count, const Projection *p_view_projections, const Vector3 *p_view_eye_offsets, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render);
+ void setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const PagedArray<RID> &p_lights, RID p_camera_attributes, uint32_t p_view_count, const Projection *p_view_projections, const Vector3 *p_view_eye_offsets, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const Size2i p_screen_size, Vector2 p_jitter, RendererSceneRenderRD *p_scene_render);
void update_radiance_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_env, const Vector3 &p_global_pos, double p_time, float p_luminance_multiplier = 1.0);
void update_res_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_env, double p_time, float p_luminance_multiplier = 1.0);
void draw_sky(RD::DrawListID p_draw_list, Ref<RenderSceneBuffersRD> p_render_buffers, RID p_env, RID p_fb, double p_time, float p_luminance_multiplier = 1.0);
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 7bca1dc3be..efec3b5072 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -105,6 +105,12 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_voxelgi()
}
}
+void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_fsr2(RendererRD::FSR2Effect *p_effect) {
+ if (fsr2_context == nullptr) {
+ fsr2_context = p_effect->create_context(render_buffers->get_internal_size(), render_buffers->get_target_size());
+ }
+}
+
void RenderForwardClustered::RenderBufferDataForwardClustered::free_data() {
// JIC, should already have been cleared
if (render_buffers) {
@@ -120,6 +126,11 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::free_data() {
cluster_builder = nullptr;
}
+ if (fsr2_context) {
+ memdelete(fsr2_context);
+ fsr2_context = nullptr;
+ }
+
if (!render_sdfgi_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_sdfgi_uniform_set)) {
RD::get_singleton()->free(render_sdfgi_uniform_set);
}
@@ -230,6 +241,14 @@ RID RenderForwardClustered::RenderBufferDataForwardClustered::get_specular_only_
return FramebufferCacheRD::get_singleton()->get_cache_multiview(render_buffers->get_view_count(), specular);
}
+RID RenderForwardClustered::RenderBufferDataForwardClustered::get_velocity_only_fb() {
+ bool use_msaa = render_buffers->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED;
+
+ RID velocity = render_buffers->get_texture(RB_SCOPE_BUFFERS, use_msaa ? RB_TEX_VELOCITY_MSAA : RB_TEX_VELOCITY);
+
+ return FramebufferCacheRD::get_singleton()->get_cache_multiview(render_buffers->get_view_count(), velocity);
+}
+
void RenderForwardClustered::setup_render_buffer_data(Ref<RenderSceneBuffersRD> p_render_buffers) {
Ref<RenderBufferDataForwardClustered> data;
data.instantiate();
@@ -252,6 +271,7 @@ bool RenderForwardClustered::free(RID p_rid) {
template <RenderForwardClustered::PassMode p_pass_mode, uint32_t p_color_pass_flags>
void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) {
RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
+ RendererRD::ParticlesStorage *particles_storage = RendererRD::ParticlesStorage::get_singleton();
RD::DrawListID draw_list = p_draw_list;
RD::FramebufferFormatID framebuffer_format = p_framebuffer_Format;
@@ -284,8 +304,10 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
const GeometryInstanceSurfaceDataCache *surf = p_params->elements[i];
const RenderElementInfo &element_info = p_params->element_info[i];
- if ((p_pass_mode == PASS_MODE_COLOR && !(p_color_pass_flags & COLOR_PASS_FLAG_TRANSPARENT)) && !(surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) {
- continue; // Objects with "Depth-prepass" transparency are included in both render lists, but should only be rendered in the transparent pass
+ if (p_pass_mode == PASS_MODE_COLOR && surf->color_pass_inclusion_mask && (p_color_pass_flags & surf->color_pass_inclusion_mask) == 0) {
+ // Some surfaces can be repeated in multiple render lists. We exclude them from being rendered on the color pass based on the
+ // features supported by the pass compared to the exclusion mask.
+ continue;
}
if (surf->owner->instance_count == 0) {
@@ -433,10 +455,11 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
RID index_array_rd;
//skeleton and blend shape
+ bool pipeline_motion_vectors = pipeline_color_pass_flags & SceneShaderForwardClustered::PIPELINE_COLOR_PASS_FLAG_MOTION_VECTORS;
if (surf->owner->mesh_instance.is_valid()) {
- mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format);
+ mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, pipeline->get_vertex_input_mask(), pipeline_motion_vectors, vertex_array_rd, vertex_format);
} else {
- mesh_storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format);
+ mesh_storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, pipeline->get_vertex_input_mask(), pipeline_motion_vectors, vertex_array_rd, vertex_format);
}
index_array_rd = mesh_storage->mesh_surface_get_index_array(mesh_surface, element_info.lod_index);
@@ -476,7 +499,9 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
prev_material_uniform_set = material_uniform_set;
}
- if ((surf->owner->base_flags & (INSTANCE_DATA_FLAG_MULTIMESH | INSTANCE_DATA_FLAG_PARTICLES)) == INSTANCE_DATA_FLAG_MULTIMESH) {
+ if (surf->owner->base_flags & INSTANCE_DATA_FLAG_PARTICLES) {
+ particles_storage->particles_get_instance_buffer_motion_vectors_offsets(surf->owner->data->base, push_constant.multimesh_motion_vectors_current_offset, push_constant.multimesh_motion_vectors_previous_offset);
+ } else if (surf->owner->base_flags & INSTANCE_DATA_FLAG_MULTIMESH) {
mesh_storage->_multimesh_get_motion_vectors_offsets(surf->owner->data->base, push_constant.multimesh_motion_vectors_current_offset, push_constant.multimesh_motion_vectors_previous_offset);
} else {
push_constant.multimesh_motion_vectors_current_offset = 0;
@@ -578,7 +603,7 @@ void RenderForwardClustered::_render_list_with_threads(RenderListParameters *p_p
}
}
-void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) {
+void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers, bool p_apply_alpha_multiplier, bool p_pancake_shadows, int p_index) {
RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
Ref<RenderSceneBuffersRD> rd = p_render_data->render_buffers;
@@ -594,7 +619,7 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat
}
}
- p_render_data->scene_data->update_ubo(scene_state.uniform_buffers[p_index], get_debug_draw_mode(), env, reflection_probe_instance, p_render_data->camera_attributes, p_flip_y, p_pancake_shadows, p_screen_size, p_default_bg_color, _render_buffers_get_luminance_multiplier(), p_opaque_render_buffers);
+ p_render_data->scene_data->update_ubo(scene_state.uniform_buffers[p_index], get_debug_draw_mode(), env, reflection_probe_instance, p_render_data->camera_attributes, p_flip_y, p_pancake_shadows, p_screen_size, p_default_bg_color, _render_buffers_get_luminance_multiplier(), p_opaque_render_buffers, p_apply_alpha_multiplier);
// now do implementation UBO
@@ -703,7 +728,7 @@ void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, i
RendererRD::MaterialStorage::store_transform(inst->prev_transform, instance_data.prev_transform);
#ifdef REAL_T_IS_DOUBLE
- // Split the origin into two components, the float approximation and the missing precision
+ // Split the origin into two components, the float approximation and the missing precision.
// In the shader we will combine these back together to restore the lost precision.
RendererRD::MaterialStorage::split_double(inst->transform.origin.x, &instance_data.transform[12], &instance_data.transform[3]);
RendererRD::MaterialStorage::split_double(inst->transform.origin.y, &instance_data.transform[13], &instance_data.transform[7]);
@@ -723,6 +748,28 @@ void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, i
instance_data.lightmap_uv_scale[2] = inst->lightmap_uv_scale.size.x;
instance_data.lightmap_uv_scale[3] = inst->lightmap_uv_scale.size.y;
+ AABB surface_aabb = AABB(Vector3(0.0, 0.0, 0.0), Vector3(1.0, 1.0, 1.0));
+ uint64_t format = RendererRD::MeshStorage::get_singleton()->mesh_surface_get_format(surface->surface);
+ Vector4 uv_scale = Vector4(0.0, 0.0, 0.0, 0.0);
+
+ if (format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) {
+ surface_aabb = RendererRD::MeshStorage::get_singleton()->mesh_surface_get_aabb(surface->surface);
+ uv_scale = RendererRD::MeshStorage::get_singleton()->mesh_surface_get_uv_scale(surface->surface);
+ }
+
+ instance_data.compressed_aabb_position[0] = surface_aabb.position.x;
+ instance_data.compressed_aabb_position[1] = surface_aabb.position.y;
+ instance_data.compressed_aabb_position[2] = surface_aabb.position.z;
+
+ instance_data.compressed_aabb_size[0] = surface_aabb.size.x;
+ instance_data.compressed_aabb_size[1] = surface_aabb.size.y;
+ instance_data.compressed_aabb_size[2] = surface_aabb.size.z;
+
+ instance_data.uv_scale[0] = uv_scale.x;
+ instance_data.uv_scale[1] = uv_scale.y;
+ instance_data.uv_scale[2] = uv_scale.z;
+ instance_data.uv_scale[3] = uv_scale.w;
+
bool cant_repeat = instance_data.flags & INSTANCE_DATA_FLAG_MULTIMESH || inst->mesh_instance.is_valid();
if (prev_surface != nullptr && !cant_repeat && prev_surface->sort.sort_key1 == surface->sort.sort_key1 && prev_surface->sort.sort_key2 == surface->sort.sort_key2 && inst->mirror == prev_surface->owner->mirror && repeats < RenderElementInfo::MAX_REPEATS) {
@@ -771,8 +818,9 @@ _FORCE_INLINE_ static uint32_t _indices_to_primitives(RS::PrimitiveType p_primit
static const uint32_t subtractor[RS::PRIMITIVE_MAX] = { 0, 0, 1, 0, 1 };
return (p_indices - subtractor[p_primitive]) / divisor[p_primitive];
}
-void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, uint32_t p_color_pass_flags = 0, bool p_using_sdfgi, bool p_using_opaque_gi, bool p_append) {
+void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_using_sdfgi, bool p_using_opaque_gi, bool p_using_motion_pass, bool p_append) {
RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
+ uint64_t frame = RSG::rasterizer->get_frame_number();
if (p_render_list == RENDER_LIST_OPAQUE) {
scene_state.used_sss = false;
@@ -793,7 +841,9 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
if (!p_append) {
rl->clear();
if (p_render_list == RENDER_LIST_OPAQUE) {
- render_list[RENDER_LIST_ALPHA].clear(); //opaque fills alpha too
+ // Opaque fills motion and alpha lists.
+ render_list[RENDER_LIST_MOTION].clear();
+ render_list[RENDER_LIST_ALPHA].clear();
}
}
@@ -823,6 +873,7 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
}
bool uses_lightmap = false;
bool uses_gi = false;
+ bool uses_motion = false;
float fade_alpha = 1.0;
if (inst->fade_near || inst->fade_far) {
@@ -910,6 +961,14 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
inst->gi_offset_cache = 0xFFFFFFFF;
}
}
+
+ if (p_pass_mode == PASS_MODE_COLOR && p_using_motion_pass) {
+ bool transform_changed = inst->prev_transform_change_frame == frame;
+ bool has_mesh_instance = inst->mesh_instance.is_valid();
+ bool uses_particles = inst->base_flags & INSTANCE_DATA_FLAG_PARTICLES;
+ bool is_multimesh_with_motion = !uses_particles && (inst->base_flags & INSTANCE_DATA_FLAG_MULTIMESH) && mesh_storage->_multimesh_uses_motion_vectors_offsets(inst->data->base);
+ uses_motion = transform_changed || has_mesh_instance || uses_particles || is_multimesh_with_motion;
+ }
}
inst->flags_cache = flags;
@@ -986,11 +1045,18 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
if (!force_alpha && (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE))) {
rl->add_element(surf);
}
+
if (force_alpha || (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA)) {
+ surf->color_pass_inclusion_mask = COLOR_PASS_FLAG_TRANSPARENT;
render_list[RENDER_LIST_ALPHA].add_element(surf);
if (uses_gi) {
surf->sort.uses_forward_gi = 1;
}
+ } else if (p_using_motion_pass && (uses_motion || (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_MOTION_VECTOR))) {
+ surf->color_pass_inclusion_mask = COLOR_PASS_FLAG_MOTION_VECTORS;
+ render_list[RENDER_LIST_MOTION].add_element(surf);
+ } else {
+ surf->color_pass_inclusion_mask = 0;
}
if (uses_lightmap) {
@@ -1010,13 +1076,6 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE) {
scene_state.used_depth_texture = true;
}
-
- if (p_color_pass_flags & COLOR_PASS_FLAG_MOTION_VECTORS) {
- if ((flags & (INSTANCE_DATA_FLAG_MULTIMESH | INSTANCE_DATA_FLAG_PARTICLES)) == INSTANCE_DATA_FLAG_MULTIMESH && RendererRD::MeshStorage::get_singleton()->_multimesh_enable_motion_vectors(inst->data->base)) {
- inst->transforms_uniform_set = mesh_storage->multimesh_get_3d_uniform_set(inst->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
- }
- }
-
} else if (p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_SHADOW_DP) {
if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW) {
rl->add_element(surf);
@@ -1435,7 +1494,7 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo
// Note: when rendering stereoscopic (multiview) we are using our combined frustum projection to create
// our cluster data. We use reprojection in the shader to adjust for our left/right eye.
// This only works as we don't filter our cluster by depth buffer.
- // If we ever make this optimisation we should make it optional and only use it in mono.
+ // If we ever make this optimization we should make it optional and only use it in mono.
// What we win by filtering out a few lights, we loose by having to do the work double for stereo.
current_cluster_builder->begin(p_render_data->scene_data->cam_transform, p_render_data->scene_data->cam_projection, !p_render_data->reflection_probe.is_valid());
}
@@ -1583,16 +1642,24 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RENDER_TIMESTAMP("Setup 3D Scene");
+ bool using_debug_mvs = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS;
+ bool using_taa = rb->get_use_taa();
+ bool using_fsr2 = rb->get_scaling_3d_mode() == RS::VIEWPORT_SCALING_3D_MODE_FSR2;
+
// check if we need motion vectors
- if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS) {
- p_render_data->scene_data->calculate_motion_vectors = true;
- } else if (!is_reflection_probe && rb->get_use_taa()) {
- p_render_data->scene_data->calculate_motion_vectors = true;
+ bool motion_vectors_required;
+ if (using_debug_mvs) {
+ motion_vectors_required = true;
+ } else if (!is_reflection_probe && using_taa) {
+ motion_vectors_required = true;
+ } else if (!is_reflection_probe && using_fsr2) {
+ motion_vectors_required = true;
} else {
- p_render_data->scene_data->calculate_motion_vectors = false;
+ motion_vectors_required = false;
}
//p_render_data->scene_data->subsurface_scatter_width = subsurface_scatter_size;
+ p_render_data->scene_data->calculate_motion_vectors = motion_vectors_required;
p_render_data->scene_data->directional_light_count = 0;
p_render_data->scene_data->opaque_prepass_threshold = 0.99f;
@@ -1610,6 +1677,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
bool using_voxelgi = false;
bool reverse_cull = p_render_data->scene_data->cam_transform.basis.determinant() < 0;
bool using_ssil = !is_reflection_probe && p_render_data->environment.is_valid() && environment_get_ssil_enabled(p_render_data->environment);
+ bool using_motion_pass = rb_data.is_valid() && using_fsr2;
if (is_reflection_probe) {
uint32_t resolution = light_storage->reflection_probe_instance_get_resolution(p_render_data->reflection_probe);
@@ -1628,7 +1696,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
} else {
screen_size = rb->get_internal_size();
- if (rb->get_use_taa() || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS) {
+ if (p_render_data->scene_data->calculate_motion_vectors) {
color_pass_flags |= COLOR_PASS_FLAG_MOTION_VECTORS;
scene_shader.enable_advanced_shader_group();
}
@@ -1666,12 +1734,16 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
_setup_voxelgis(*p_render_data->voxel_gi_instances);
_setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, false);
- _update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example)
+ _update_render_base_uniform_set(rb->get_samplers()); // May have changed due to the above (light buffer enlarged, as an example).
- _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR, color_pass_flags, using_sdfgi, using_sdfgi || using_voxelgi);
+ _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR, using_sdfgi, using_sdfgi || using_voxelgi, using_motion_pass);
render_list[RENDER_LIST_OPAQUE].sort_by_key();
+ render_list[RENDER_LIST_MOTION].sort_by_key();
render_list[RENDER_LIST_ALPHA].sort_by_reverse_depth_and_priority();
- _fill_instance_data(RENDER_LIST_OPAQUE, p_render_data->render_info ? p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE] : (int *)nullptr);
+
+ int *render_info = p_render_data->render_info ? p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE] : (int *)nullptr;
+ _fill_instance_data(RENDER_LIST_OPAQUE, render_info);
+ _fill_instance_data(RENDER_LIST_MOTION, render_info);
_fill_instance_data(RENDER_LIST_ALPHA);
RD::get_singleton()->draw_command_end_label();
@@ -1769,7 +1841,8 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
case RS::ENV_BG_CANVAS: {
if (!is_reflection_probe) {
RID texture = RendererRD::TextureStorage::get_singleton()->render_target_get_rd_texture(rb->get_render_target());
- copy_effects->copy_to_fb_rect(texture, color_only_framebuffer, Rect2i(), false, false, false, false, RID(), false, false, true);
+ bool convert_to_linear = !RendererRD::TextureStorage::get_singleton()->render_target_is_using_hdr(rb->get_render_target());
+ copy_effects->copy_to_fb_rect(texture, color_only_framebuffer, Rect2i(), false, false, false, false, RID(), false, false, convert_to_linear);
}
keep_color = true;
} break;
@@ -1794,9 +1867,9 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
correction.set_depth_correction(true);
Projection projection = correction * p_render_data->scene_data->cam_projection;
- sky.setup_sky(p_render_data->environment, rb, *p_render_data->lights, p_render_data->camera_attributes, 1, &projection, &eye_offset, p_render_data->scene_data->cam_transform, projection, screen_size, this);
+ sky.setup_sky(p_render_data->environment, rb, *p_render_data->lights, p_render_data->camera_attributes, 1, &projection, &eye_offset, p_render_data->scene_data->cam_transform, projection, screen_size, Vector2(0.0f, 0.0f), this);
} else {
- sky.setup_sky(p_render_data->environment, rb, *p_render_data->lights, p_render_data->camera_attributes, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->view_eye_offset, p_render_data->scene_data->cam_transform, p_render_data->scene_data->cam_projection, screen_size, this);
+ sky.setup_sky(p_render_data->environment, rb, *p_render_data->lights, p_render_data->camera_attributes, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->view_eye_offset, p_render_data->scene_data->cam_transform, p_render_data->scene_data->cam_projection, screen_size, p_render_data->scene_data->taa_jitter, this);
}
sky_energy_multiplier *= bg_energy_multiplier;
@@ -1847,7 +1920,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, nullptr, RID());
- bool finish_depth = using_ssao || using_sdfgi || using_voxelgi;
+ bool finish_depth = using_ssao || using_ssil || using_sdfgi || using_voxelgi;
RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, depth_pass_mode, 0, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
_render_list_with_threads(&render_list_params, depth_framebuffer, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, finish_depth ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, needs_pre_resolve ? Vector<Color>() : depth_pass_clear);
@@ -1891,37 +1964,74 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
p_render_data->scene_data->directional_light_count = p_render_data->directional_light_count;
p_render_data->scene_data->opaque_prepass_threshold = 0.0f;
- _setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, true);
+ // Shadow pass can change the base uniform set samplers.
+ _update_render_base_uniform_set(rb->get_samplers());
+
+ _setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, true, using_motion_pass);
RENDER_TIMESTAMP("Render Opaque Pass");
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, true);
-
bool can_continue_color = !scene_state.used_screen_texture && !using_ssr && !using_sss;
bool can_continue_depth = !(scene_state.used_depth_texture || scene_state.used_normal_texture) && !using_ssr && !using_sss;
{
+ bool render_motion_pass = !render_list[RENDER_LIST_MOTION].elements.is_empty();
bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only || debug_voxelgis || debug_sdfgi_probes);
bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only || debug_voxelgis || debug_sdfgi_probes);
+ RD::FinalAction final_color_action = will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ;
+ RD::FinalAction final_depth_action = will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ;
- Vector<Color> c;
{
- Color cc = clear_color.srgb_to_linear();
- if (using_separate_specular || rb_data.is_valid()) {
- cc.a = 0; //subsurf scatter must be 0
+ Vector<Color> c;
+ {
+ Color cc = clear_color.srgb_to_linear();
+ if (using_separate_specular || rb_data.is_valid()) {
+ // Effects that rely on separate specular, like subsurface scattering, must clear the alpha to zero.
+ cc.a = 0;
+ }
+ c.push_back(cc);
+
+ if (rb_data.is_valid()) {
+ c.push_back(Color(0, 0, 0, 0)); // Separate specular.
+ c.push_back(Color(0, 0, 0, 0)); // Motion vector. Pushed to the clear color vector even if the framebuffer isn't bound.
+ }
}
- c.push_back(cc);
- if (rb_data.is_valid()) {
- c.push_back(Color(0, 0, 0, 0)); // Separate specular
- c.push_back(Color(0, 0, 0, 0)); // Motion vectors
+ uint32_t opaque_color_pass_flags = using_motion_pass ? (color_pass_flags & ~COLOR_PASS_FLAG_MOTION_VECTORS) : color_pass_flags;
+ RID opaque_framebuffer = using_motion_pass ? rb_data->get_color_pass_fb(opaque_color_pass_flags) : color_framebuffer;
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, opaque_color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
+ _render_list_with_threads(&render_list_params, opaque_framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, render_motion_pass ? RD::FINAL_ACTION_CONTINUE : final_color_action, depth_pre_pass ? (continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP) : RD::INITIAL_ACTION_CLEAR, render_motion_pass ? RD::FINAL_ACTION_CONTINUE : final_depth_action, c, 1.0, 0);
+ }
+
+ RD::get_singleton()->draw_command_end_label();
+
+ if (using_motion_pass) {
+ Vector<Color> motion_vector_clear_colors;
+ motion_vector_clear_colors.push_back(Color(-1, -1, 0, 0));
+ RD::get_singleton()->draw_list_begin(rb_data->get_velocity_only_fb(), RD::INITIAL_ACTION_CLEAR, render_motion_pass ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_CONTINUE, motion_vector_clear_colors);
+ RD::get_singleton()->draw_list_end();
+ }
+
+ if (render_motion_pass) {
+ RD::get_singleton()->draw_command_begin_label("Render Motion Pass");
+
+ RENDER_TIMESTAMP("Render Motion Pass");
+
+ rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_MOTION, p_render_data, radiance_texture, true);
+
+ RenderListParameters render_list_params(render_list[RENDER_LIST_MOTION].elements.ptr(), render_list[RENDER_LIST_MOTION].element_info.ptr(), render_list[RENDER_LIST_MOTION].elements.size(), reverse_cull, PASS_MODE_COLOR, color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
+ _render_list_with_threads(&render_list_params, color_framebuffer, RD::INITIAL_ACTION_CONTINUE, final_color_action, RD::INITIAL_ACTION_CONTINUE, final_depth_action);
+
+ if (will_continue_color) {
+ // Close the motion vectors framebuffer as it'll no longer be used.
+ RD::get_singleton()->draw_list_begin(rb_data->get_velocity_only_fb(), RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_CONTINUE);
+ RD::get_singleton()->draw_list_end();
}
}
- RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
- _render_list_with_threads(&render_list_params, color_framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? (continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP) : RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
if (will_continue_color && using_separate_specular) {
- // close the specular framebuffer, as it's no longer used
+ // Close the specular framebuffer as it'll no longer be used.
RD::get_singleton()->draw_list_begin(rb_data->get_specular_only_fb(), RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_CONTINUE);
RD::get_singleton()->draw_list_end();
}
@@ -2051,6 +2161,11 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
{
uint32_t transparent_color_pass_flags = (color_pass_flags | COLOR_PASS_FLAG_TRANSPARENT) & ~(COLOR_PASS_FLAG_SEPARATE_SPECULAR);
+ if (using_motion_pass) {
+ // Motion vectors on transparent draw calls are not required when using the reactive mask.
+ transparent_color_pass_flags &= ~(COLOR_PASS_FLAG_MOTION_VECTORS);
+ }
+
RID alpha_framebuffer = rb_data.is_valid() ? rb_data->get_color_pass_fb(transparent_color_pass_flags) : color_only_framebuffer;
RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), false, PASS_MODE_COLOR, transparent_color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
_render_list_with_threads(&render_list_params, alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
@@ -2063,12 +2178,14 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RD::get_singleton()->draw_command_begin_label("Resolve");
if (rb_data.is_valid() && rb->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED) {
+ bool resolve_velocity_buffer = (using_taa || using_fsr2) && rb->has_velocity_buffer(true);
for (uint32_t v = 0; v < rb->get_view_count(); v++) {
RD::get_singleton()->texture_resolve_multisample(rb->get_color_msaa(v), rb->get_internal_texture(v));
resolve_effects->resolve_depth(rb->get_depth_msaa(v), rb->get_depth_texture(v), rb->get_internal_size(), texture_multisamples[rb->get_msaa_3d()]);
- }
- if (taa && rb->get_use_taa()) {
- taa->msaa_resolve(rb);
+
+ if (resolve_velocity_buffer) {
+ RD::get_singleton()->texture_resolve_multisample(rb->get_velocity_buffer(true, v), rb->get_velocity_buffer(false, v));
+ }
}
}
@@ -2081,9 +2198,51 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
RD::get_singleton()->draw_command_end_label();
- if (rb_data.is_valid() && taa && rb->get_use_taa()) {
- RENDER_TIMESTAMP("TAA")
- taa->process(rb, _render_buffers_get_color_format(), p_render_data->scene_data->z_near, p_render_data->scene_data->z_far);
+ if (rb_data.is_valid() && (using_fsr2 || using_taa)) {
+ if (using_fsr2) {
+ rb->ensure_upscaled();
+ rb_data->ensure_fsr2(fsr2_effect);
+
+ RID exposure;
+ if (RSG::camera_attributes->camera_attributes_uses_auto_exposure(p_render_data->camera_attributes)) {
+ exposure = luminance->get_current_luminance_buffer(rb);
+ }
+
+ RENDER_TIMESTAMP("FSR2");
+ for (uint32_t v = 0; v < rb->get_view_count(); v++) {
+ real_t fov = p_render_data->scene_data->cam_projection.get_fov();
+ real_t aspect = p_render_data->scene_data->cam_projection.get_aspect();
+ real_t fovy = p_render_data->scene_data->cam_projection.get_fovy(fov, aspect);
+ Vector2 jitter = p_render_data->scene_data->taa_jitter * Vector2(rb->get_internal_size()) * 0.5f;
+ RendererRD::FSR2Effect::Parameters params;
+ params.context = rb_data->get_fsr2_context();
+ params.internal_size = rb->get_internal_size();
+ params.sharpness = CLAMP(1.0f - (rb->get_fsr_sharpness() / 2.0f), 0.0f, 1.0f);
+ params.color = rb->get_internal_texture(v);
+ params.depth = rb->get_depth_texture(v);
+ params.velocity = rb->get_velocity_buffer(false, v);
+ params.reactive = rb->get_internal_texture_reactive(v);
+ params.exposure = exposure;
+ params.output = rb->get_upscaled_texture(v);
+ params.z_near = p_render_data->scene_data->z_near;
+ params.z_far = p_render_data->scene_data->z_far;
+ params.fovy = fovy;
+ params.jitter = jitter;
+ params.delta_time = float(time_step);
+ params.reset_accumulation = false; // FIXME: The engine does not provide a way to reset the accumulation.
+
+ const Projection &prev_proj = p_render_data->scene_data->prev_cam_projection;
+ const Projection &cur_proj = p_render_data->scene_data->cam_projection;
+ const Transform3D &prev_transform = p_render_data->scene_data->prev_cam_transform;
+ const Transform3D &cur_transform = p_render_data->scene_data->cam_transform;
+ params.reprojection = prev_proj.flipped_y() * prev_transform.affine_inverse() * cur_transform * cur_proj.flipped_y().inverse();
+
+ fsr2_effect->upscale(params);
+ }
+ } else if (using_taa) {
+ RENDER_TIMESTAMP("TAA");
+ taa->process(rb, _render_buffers_get_color_format(), p_render_data->scene_data->z_near, p_render_data->scene_data->z_far);
+ }
}
if (rb_data.is_valid()) {
@@ -2326,7 +2485,7 @@ void RenderForwardClustered::_render_shadow_pass(RID p_light, RID p_shadow_atlas
void RenderForwardClustered::_render_shadow_begin() {
scene_state.shadow_passes.clear();
RD::get_singleton()->draw_command_begin_label("Shadow Setup");
- _update_render_base_uniform_set();
+ _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default());
render_list[RENDER_LIST_SECONDARY].clear();
scene_state.instance_data[RENDER_LIST_SECONDARY].clear();
@@ -2356,7 +2515,7 @@ void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const Page
render_data.instances = &p_instances;
render_data.render_info = p_render_info;
- _setup_environment(&render_data, true, Vector2(1, 1), !p_flip_y, Color(), false, p_use_pancake, shadow_pass_index);
+ _setup_environment(&render_data, true, Vector2(1, 1), !p_flip_y, Color(), false, false, p_use_pancake, shadow_pass_index);
if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) {
scene_data.screen_mesh_lod_threshold = 0.0;
@@ -2367,7 +2526,7 @@ void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const Page
PassMode pass_mode = p_use_dp ? PASS_MODE_SHADOW_DP : PASS_MODE_SHADOW;
uint32_t render_list_from = render_list[RENDER_LIST_SECONDARY].elements.size();
- _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode, 0, false, false, true);
+ _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode, false, false, false, true);
uint32_t render_list_size = render_list[RENDER_LIST_SECONDARY].elements.size() - render_list_from;
render_list[RENDER_LIST_SECONDARY].sort_by_key_range(render_list_from, render_list_size);
_fill_instance_data(RENDER_LIST_SECONDARY, p_render_info ? p_render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW] : (int *)nullptr, render_list_from, render_list_size, false);
@@ -2450,9 +2609,9 @@ void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, con
render_data.cluster_max_elements = 32;
render_data.instances = &p_instances;
- _update_render_base_uniform_set();
+ _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default());
- _setup_environment(&render_data, true, Vector2(1, 1), true, Color(), false, false);
+ _setup_environment(&render_data, true, Vector2(1, 1), true, Color(), false, false, false);
PassMode pass_mode = PASS_MODE_SHADOW;
@@ -2496,7 +2655,7 @@ void RenderForwardClustered::_render_material(const Transform3D &p_cam_transform
scene_shader.enable_advanced_shader_group();
- _update_render_base_uniform_set();
+ _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default());
_setup_environment(&render_data, true, Vector2(1, 1), false, Color());
@@ -2547,7 +2706,7 @@ void RenderForwardClustered::_render_uv2(const PagedArray<RenderGeometryInstance
scene_shader.enable_advanced_shader_group();
- _update_render_base_uniform_set();
+ _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default());
_setup_environment(&render_data, true, Vector2(1, 1), false, Color());
@@ -2616,7 +2775,7 @@ void RenderForwardClustered::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_bu
render_data.cluster_max_elements = 32;
render_data.instances = &p_instances;
- _update_render_base_uniform_set();
+ _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default());
PassMode pass_mode = PASS_MODE_SDF;
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
@@ -2696,13 +2855,10 @@ void RenderForwardClustered::base_uniforms_changed() {
render_base_uniform_set = RID();
}
-void RenderForwardClustered::_update_render_base_uniform_set() {
+void RenderForwardClustered::_update_render_base_uniform_set(const RendererRD::MaterialStorage::Samplers &p_samplers) {
RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
- RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
-
- if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != light_storage->lightmap_array_get_version()) || base_uniform_set_updated) {
- base_uniform_set_updated = false;
+ if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != light_storage->lightmap_array_get_version())) {
if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
RD::get_singleton()->free(render_base_uniform_set);
}
@@ -2726,22 +2882,22 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
RID sampler;
switch (decals_get_filter()) {
case RS::DECAL_FILTER_NEAREST: {
- sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
case RS::DECAL_FILTER_LINEAR: {
- sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
case RS::DECAL_FILTER_NEAREST_MIPMAPS: {
- sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
case RS::DECAL_FILTER_LINEAR_MIPMAPS: {
- sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
case RS::DECAL_FILTER_NEAREST_MIPMAPS_ANISOTROPIC: {
- sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
case RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
- sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
}
@@ -2756,22 +2912,22 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
RID sampler;
switch (light_projectors_get_filter()) {
case RS::LIGHT_PROJECTOR_FILTER_NEAREST: {
- sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
case RS::LIGHT_PROJECTOR_FILTER_LINEAR: {
- sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS: {
- sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS: {
- sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS_ANISOTROPIC: {
- sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
- sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
}
@@ -2862,7 +3018,7 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
uniforms.push_back(u);
}
- uniforms.append_array(material_storage->get_default_sampler_uniforms(SAMPLERS_BINDING_FIRST_INDEX));
+ uniforms.append_array(p_samplers.get_uniforms(SAMPLERS_BINDING_FIRST_INDEX));
render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, SCENE_UNIFORM_SET);
}
@@ -3477,9 +3633,13 @@ void RenderForwardClustered::_geometry_instance_add_surface_with_material(Geomet
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_PARTICLE_TRAILS;
}
+ if (p_material->shader_data->is_animated()) {
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_MOTION_VECTOR;
+ }
+
SceneShaderForwardClustered::MaterialData *material_shadow = nullptr;
void *surface_shadow = nullptr;
- if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_position && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_prepass_alpha && !p_material->shader_data->uses_alpha_clip && !p_material->shader_data->uses_alpha_antialiasing && p_material->shader_data->cull_mode == SceneShaderForwardClustered::ShaderData::CULL_BACK && !p_material->shader_data->uses_point_size) {
+ if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_position && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_prepass_alpha && !p_material->shader_data->uses_alpha_clip && !p_material->shader_data->uses_alpha_antialiasing && p_material->shader_data->cull_mode == SceneShaderForwardClustered::ShaderData::CULL_BACK && !p_material->shader_data->uses_point_size && !p_material->shader_data->uses_world_coordinates) {
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL;
material_shadow = static_cast<SceneShaderForwardClustered::MaterialData *>(RendererRD::MaterialStorage::get_singleton()->material_get_data(scene_shader.default_material, RendererRD::MaterialStorage::SHADER_TYPE_3D));
@@ -3578,7 +3738,7 @@ void RenderForwardClustered::_geometry_instance_add_surface(GeometryInstanceForw
m_src = scene_shader.default_material;
}
- ERR_FAIL_COND(!material);
+ ERR_FAIL_NULL(material);
_geometry_instance_add_surface_with_material_chain(ginstance, p_surface, material, m_src, p_mesh);
@@ -3721,6 +3881,10 @@ void RenderForwardClustered::_geometry_instance_update(RenderGeometryInstance *p
// Particles haven't been cleared or updated, update once now to ensure they are ready to render.
particles_storage->update_particles();
}
+
+ if (ginstance->data->dirty_dependencies) {
+ particles_storage->particles_update_dependency(ginstance->data->base, &ginstance->data->dependency_tracker);
+ }
} else if (ginstance->data->base_type == RS::INSTANCE_MESH) {
if (mesh_storage->skeleton_is_valid(ginstance->data->skeleton)) {
ginstance->transforms_uniform_set = mesh_storage->skeleton_get_3d_uniform_set(ginstance->data->skeleton, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
@@ -3760,6 +3924,7 @@ void RenderForwardClustered::_geometry_instance_dependency_changed(Dependency::D
case Dependency::DEPENDENCY_CHANGED_MATERIAL:
case Dependency::DEPENDENCY_CHANGED_MESH:
case Dependency::DEPENDENCY_CHANGED_PARTICLES:
+ case Dependency::DEPENDENCY_CHANGED_PARTICLES_INSTANCES:
case Dependency::DEPENDENCY_CHANGED_MULTIMESH:
case Dependency::DEPENDENCY_CHANGED_SKELETON_DATA: {
static_cast<RenderGeometryInstance *>(p_tracker->userdata)->_mark_dirty();
@@ -3799,7 +3964,7 @@ RenderGeometryInstance *RenderForwardClustered::geometry_instance_create(RID p_b
return ginstance;
}
-void RenderForwardClustered::GeometryInstanceForwardClustered::set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) {
+void RenderForwardClustered::GeometryInstanceForwardClustered::set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) {
uint64_t frame = RSG::rasterizer->get_frame_number();
if (frame != prev_transform_change_frame) {
prev_transform = transform;
@@ -3807,7 +3972,7 @@ void RenderForwardClustered::GeometryInstanceForwardClustered::set_transform(con
prev_transform_dirty = true;
}
- RenderGeometryInstanceBase::set_transform(p_transform, p_aabb, p_transformed_aabbb);
+ RenderGeometryInstanceBase::set_transform(p_transform, p_aabb, p_transformed_aabb);
}
void RenderForwardClustered::GeometryInstanceForwardClustered::set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) {
@@ -3836,7 +4001,7 @@ void RenderForwardClustered::GeometryInstanceForwardClustered::set_lightmap_capt
void RenderForwardClustered::geometry_instance_free(RenderGeometryInstance *p_geometry_instance) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
- ERR_FAIL_COND(!ginstance);
+ ERR_FAIL_NULL(ginstance);
if (ginstance->lightmap_sh != nullptr) {
geometry_instance_lightmap_sh.free(ginstance->lightmap_sh);
}
@@ -3979,6 +4144,7 @@ RenderForwardClustered::RenderForwardClustered() {
resolve_effects = memnew(RendererRD::Resolve());
taa = memnew(RendererRD::TAA);
+ fsr2_effect = memnew(RendererRD::FSR2Effect);
ss_effects = memnew(RendererRD::SSEffects);
}
@@ -3993,6 +4159,11 @@ RenderForwardClustered::~RenderForwardClustered() {
taa = nullptr;
}
+ if (fsr2_effect) {
+ memdelete(fsr2_effect);
+ fsr2_effect = nullptr;
+ }
+
if (resolve_effects != nullptr) {
memdelete(resolve_effects);
resolve_effects = nullptr;
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 a89c77c652..46deb30cde 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
@@ -33,6 +33,7 @@
#include "core/templates/paged_allocator.h"
#include "servers/rendering/renderer_rd/cluster_builder_rd.h"
+#include "servers/rendering/renderer_rd/effects/fsr2.h"
#include "servers/rendering/renderer_rd/effects/resolve.h"
#include "servers/rendering/renderer_rd/effects/ss_effects.h"
#include "servers/rendering/renderer_rd/effects/taa.h"
@@ -84,6 +85,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
enum RenderListType {
RENDER_LIST_OPAQUE, //used for opaque objects
+ RENDER_LIST_MOTION, //used for opaque objects with motion
RENDER_LIST_ALPHA, //used for transparent objects
RENDER_LIST_SECONDARY, //used for shadows and other objects
RENDER_LIST_MAX
@@ -100,6 +102,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
private:
RenderSceneBuffersRD *render_buffers = nullptr;
+ RendererRD::FSR2Context *fsr2_context = nullptr;
public:
ClusterBuilderRD *cluster_builder = nullptr;
@@ -140,10 +143,14 @@ class RenderForwardClustered : public RendererSceneRenderRD {
RID get_voxelgi(uint32_t p_layer) { return render_buffers->get_texture_slice(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_VOXEL_GI, p_layer, 0); }
RID get_voxelgi_msaa(uint32_t p_layer) { return render_buffers->get_texture_slice(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_VOXEL_GI_MSAA, p_layer, 0); }
+ void ensure_fsr2(RendererRD::FSR2Effect *p_effect);
+ RendererRD::FSR2Context *get_fsr2_context() const { return fsr2_context; }
+
RID get_color_only_fb();
RID get_color_pass_fb(uint32_t p_color_pass_flags);
RID get_depth_fb(DepthFrameBufferType p_type = DEPTH_FB);
RID get_specular_only_fb();
+ RID get_velocity_only_fb();
virtual void configure(RenderSceneBuffersRD *p_render_buffers) override;
virtual void free_data() override;
@@ -155,8 +162,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
uint64_t lightmap_texture_array_version = 0xFFFFFFFF;
- bool base_uniform_set_updated = false;
- void _update_render_base_uniform_set();
+ void _update_render_base_uniform_set(const RendererRD::MaterialStorage::Samplers &p_samplers);
RID _setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture);
RID _setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas = false, int p_index = 0);
@@ -292,6 +298,9 @@ class RenderForwardClustered : public RendererSceneRenderRD {
uint32_t gi_offset; //GI information when using lightmapping (VCT or lightmap index)
uint32_t layer_mask;
float lightmap_uv_scale[4];
+ float compressed_aabb_position[4];
+ float compressed_aabb_size[4];
+ float uv_scale[4];
};
UBO ubo;
@@ -346,7 +355,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
static RenderForwardClustered *singleton;
- void _setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false, int p_index = 0);
+ void _setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers = false, bool p_apply_alpha_multiplier = false, bool p_pancake_shadows = false, int p_index = 0);
void _setup_voxelgis(const PagedArray<RID> &p_voxelgis);
void _setup_lightmaps(const RenderDataRD *p_render_data, const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform);
@@ -373,7 +382,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
void _update_instance_data_buffer(RenderListType p_render_list);
void _fill_instance_data(RenderListType p_render_list, int *p_render_info = nullptr, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true);
- void _fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, uint32_t p_color_pass_flags, bool p_using_sdfgi = false, bool p_using_opaque_gi = false, bool p_append = false);
+ void _fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_using_sdfgi = false, bool p_using_opaque_gi = false, bool p_using_motion_pass = false, bool p_append = false);
HashMap<Size2i, RID> sdfgi_framebuffer_size_cache;
@@ -398,6 +407,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
FLAG_USES_NORMAL_TEXTURE = 16384,
FLAG_USES_DOUBLE_SIDED_SHADOWS = 32768,
FLAG_USES_PARTICLE_TRAILS = 65536,
+ FLAG_USES_MOTION_VECTOR = 131072,
};
union {
@@ -425,6 +435,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
RS::PrimitiveType primitive = RS::PRIMITIVE_MAX;
uint32_t flags = 0;
uint32_t surface_index = 0;
+ uint32_t color_pass_inclusion_mask = 0;
void *surface = nullptr;
RID material_uniform_set;
@@ -471,7 +482,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
virtual void _mark_dirty() override;
- virtual void set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) override;
+ virtual void set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) override;
virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override;
virtual void set_lightmap_capture(const Color *p_sh9) override;
@@ -564,6 +575,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
RendererRD::Resolve *resolve_effects = nullptr;
RendererRD::TAA *taa = nullptr;
+ RendererRD::FSR2Effect *fsr2_effect = nullptr;
RendererRD::SSEffects *ss_effects = nullptr;
/* Cluster builder */
@@ -633,10 +645,6 @@ public:
virtual void setup_added_decal(const Transform3D &p_transform, const Vector3 &p_half_size) override;
virtual void base_uniforms_changed() override;
- _FORCE_INLINE_ virtual void update_uniform_sets() override {
- base_uniform_set_updated = true;
- _update_render_base_uniform_set();
- }
/* SDFGI UPDATE */
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
index 298a6c0752..9676474a66 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
@@ -105,6 +105,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
actions.render_mode_flags["unshaded"] = &unshaded;
actions.render_mode_flags["wireframe"] = &wireframe;
actions.render_mode_flags["particle_trails"] = &uses_particle_trails;
+ actions.render_mode_flags["world_vertex_coords"] = &uses_world_coordinates;
actions.usage_flag_pointers["ALPHA"] = &uses_alpha;
actions.usage_flag_pointers["ALPHA_SCISSOR_THRESHOLD"] = &uses_alpha_clip;
@@ -412,7 +413,7 @@ SceneShaderForwardClustered::ShaderData::ShaderData() :
SceneShaderForwardClustered::ShaderData::~ShaderData() {
SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
- ERR_FAIL_COND(!shader_singleton);
+ ERR_FAIL_NULL(shader_singleton);
//pipeline variants will clear themselves if shader is gone
if (version.is_valid()) {
shader_singleton->shader.version_free(version);
@@ -436,7 +437,7 @@ void SceneShaderForwardClustered::MaterialData::set_next_pass(RID p_pass) {
bool SceneShaderForwardClustered::MaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
- return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardClustered::MATERIAL_UNIFORM_SET, true, RD::BARRIER_MASK_RASTER);
+ return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardClustered::MATERIAL_UNIFORM_SET, true, true, RD::BARRIER_MASK_RASTER);
}
SceneShaderForwardClustered::MaterialData::~MaterialData() {
@@ -707,6 +708,7 @@ void SceneShaderForwardClustered::init(const String p_defines) {
actions.render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n";
actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n";
actions.render_mode_defines["debug_shadow_splits"] = "#define DEBUG_DRAW_PSSM_SPLITS\n";
+ actions.render_mode_defines["fog_disabled"] = "#define FOG_DISABLED\n";
actions.base_texture_binding_index = 1;
actions.texture_layout_set = RenderForwardClustered::MATERIAL_UNIFORM_SET;
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
index 761b74defa..0739cd9f86 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
@@ -142,7 +142,7 @@ public:
bool valid = false;
RID version;
- uint32_t vertex_input_mask = 0;
+ uint64_t vertex_input_mask = 0;
PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][PIPELINE_VERSION_MAX];
PipelineCacheRD color_pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][PIPELINE_COLOR_PASS_FLAG_COUNT];
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 2053c3a9a6..8a672d8628 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -68,53 +68,40 @@ void RenderForwardMobile::ForwardIDStorageMobile::map_forward_id(RendererRD::For
forward_id_allocators[p_type].map[p_id] = p_index;
}
-void RenderForwardMobile::ForwardIDStorageMobile::fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, uint32_t &spec_constants, const GeometryInstanceForwardMobile *p_instance) {
- // first zero out our indices
+void RenderForwardMobile::fill_push_constant_instance_indices(SceneState::InstanceData *p_instance_data, const GeometryInstanceForwardMobile *p_instance) {
+ // First zero out our indices.
- p_push_constant->omni_lights[0] = 0xFFFFFFFF;
- p_push_constant->omni_lights[1] = 0xFFFFFFFF;
+ p_instance_data->omni_lights[0] = 0xFFFFFFFF;
+ p_instance_data->omni_lights[1] = 0xFFFFFFFF;
- p_push_constant->spot_lights[0] = 0xFFFFFFFF;
- p_push_constant->spot_lights[1] = 0xFFFFFFFF;
+ p_instance_data->spot_lights[0] = 0xFFFFFFFF;
+ p_instance_data->spot_lights[1] = 0xFFFFFFFF;
- p_push_constant->decals[0] = 0xFFFFFFFF;
- p_push_constant->decals[1] = 0xFFFFFFFF;
+ p_instance_data->decals[0] = 0xFFFFFFFF;
+ p_instance_data->decals[1] = 0xFFFFFFFF;
- p_push_constant->reflection_probes[0] = 0xFFFFFFFF;
- p_push_constant->reflection_probes[1] = 0xFFFFFFFF;
-
- if (p_instance->omni_light_count == 0) {
- spec_constants |= 1 << SPEC_CONSTANT_DISABLE_OMNI_LIGHTS;
- }
- if (p_instance->spot_light_count == 0) {
- spec_constants |= 1 << SPEC_CONSTANT_DISABLE_SPOT_LIGHTS;
- }
- if (p_instance->reflection_probe_count == 0) {
- spec_constants |= 1 << SPEC_CONSTANT_DISABLE_REFLECTION_PROBES;
- }
- if (p_instance->decals_count == 0) {
- spec_constants |= 1 << SPEC_CONSTANT_DISABLE_DECALS;
- }
+ p_instance_data->reflection_probes[0] = 0xFFFFFFFF;
+ p_instance_data->reflection_probes[1] = 0xFFFFFFFF;
for (uint32_t i = 0; i < MAX_RDL_CULL; i++) {
uint32_t ofs = i < 4 ? 0 : 1;
uint32_t shift = (i & 0x3) << 3;
uint32_t mask = ~(0xFF << shift);
if (i < p_instance->omni_light_count) {
- p_push_constant->omni_lights[ofs] &= mask;
- p_push_constant->omni_lights[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_OMNI_LIGHT].map[p_instance->omni_lights[i]]) << shift;
+ p_instance_data->omni_lights[ofs] &= mask;
+ p_instance_data->omni_lights[ofs] |= uint32_t(forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_OMNI_LIGHT].map[p_instance->omni_lights[i]]) << shift;
}
if (i < p_instance->spot_light_count) {
- p_push_constant->spot_lights[ofs] &= mask;
- p_push_constant->spot_lights[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_SPOT_LIGHT].map[p_instance->spot_lights[i]]) << shift;
+ p_instance_data->spot_lights[ofs] &= mask;
+ p_instance_data->spot_lights[ofs] |= uint32_t(forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_SPOT_LIGHT].map[p_instance->spot_lights[i]]) << shift;
}
if (i < p_instance->decals_count) {
- p_push_constant->decals[ofs] &= mask;
- p_push_constant->decals[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_DECAL].map[p_instance->decals[i]]) << shift;
+ p_instance_data->decals[ofs] &= mask;
+ p_instance_data->decals[ofs] |= uint32_t(forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_DECAL].map[p_instance->decals[i]]) << shift;
}
if (i < p_instance->reflection_probe_count) {
- p_push_constant->reflection_probes[ofs] &= mask;
- p_push_constant->reflection_probes[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_REFLECTION_PROBE].map[p_instance->reflection_probes[i]]) << shift;
+ p_instance_data->reflection_probes[ofs] &= mask;
+ p_instance_data->reflection_probes[ofs] |= uint32_t(forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_REFLECTION_PROBE].map[p_instance->reflection_probes[i]]) << shift;
}
}
}
@@ -367,6 +354,18 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
}
{
+ RD::Uniform u;
+ u.binding = 1;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ RID instance_buffer = scene_state.instance_buffer[p_render_list];
+ if (instance_buffer == RID()) {
+ instance_buffer = scene_shader.default_vec4_xform_buffer; // Any buffer will do since its not used.
+ }
+ u.append_id(instance_buffer);
+ uniforms.push_back(u);
+ }
+
+ {
RID radiance_texture;
if (p_radiance_texture.is_valid()) {
radiance_texture = p_radiance_texture;
@@ -461,15 +460,6 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
uniforms.push_back(u);
}
-
- {
- RD::Uniform u;
- u.binding = 8;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- RID cb = p_cluster_buffer.is_valid() ? p_cluster_buffer : default_vec4_xform_buffer;
- u.append_id(cb);
- uniforms.push_back(u);
- }
*/
{
@@ -682,8 +672,8 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
_fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR);
render_list[RENDER_LIST_OPAQUE].sort_by_key();
render_list[RENDER_LIST_ALPHA].sort_by_reverse_depth_and_priority();
- _fill_element_info(RENDER_LIST_OPAQUE);
- _fill_element_info(RENDER_LIST_ALPHA);
+ _fill_instance_data(RENDER_LIST_OPAQUE);
+ _fill_instance_data(RENDER_LIST_ALPHA);
if (p_render_data->render_info) {
p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME] = p_render_data->instances->size();
@@ -722,16 +712,9 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
using_subpass_post_process = false;
}
- // We do this last because our get_color_fbs creates and caches the framebuffer if we need it.
- RID four_subpasses = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_FOUR_SUBPASSES);
- if (using_subpass_post_process && four_subpasses.is_null()) {
- // can't do blit subpass because we don't have all subpasses
- using_subpass_post_process = false;
- }
-
if (using_subpass_post_process) {
// all as subpasses
- framebuffer = four_subpasses;
+ framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_FOUR_SUBPASSES);
} else if (using_subpass_transparent) {
// our tonemap pass is separate
framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_THREE_SUBPASSES);
@@ -750,7 +733,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
_setup_lightmaps(p_render_data, *p_render_data->lightmaps, p_render_data->scene_data->cam_transform);
_setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, false);
- _update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example)
+ _update_render_base_uniform_set(rb->get_samplers()); //may have changed due to the above (light buffer enlarged, as an example)
RD::get_singleton()->draw_command_end_label(); // Render Setup
@@ -759,7 +742,8 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
bool draw_sky = false;
bool draw_sky_fog_only = false;
// We invert luminance_multiplier for sky so that we can combine it with exposure value.
- float sky_energy_multiplier = 1.0 / _render_buffers_get_luminance_multiplier();
+ float inverse_luminance_multiplier = 1.0 / _render_buffers_get_luminance_multiplier();
+ float sky_energy_multiplier = inverse_luminance_multiplier;
Color clear_color = p_default_bg_color;
bool keep_color = false;
@@ -803,7 +787,8 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
if (rb_data.is_valid()) {
RID dest_framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_ONE_PASS);
RID texture = RendererRD::TextureStorage::get_singleton()->render_target_get_rd_texture(rb->get_render_target());
- copy_effects->copy_to_fb_rect(texture, dest_framebuffer, Rect2i(), false, false, false, false, RID(), false, false, true);
+ bool convert_to_linear = !RendererRD::TextureStorage::get_singleton()->render_target_is_using_hdr(rb->get_render_target());
+ copy_effects->copy_to_fb_rect(texture, dest_framebuffer, Rect2i(), false, false, false, false, RID(), false, false, convert_to_linear);
}
keep_color = true;
} break;
@@ -828,9 +813,9 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
correction.set_depth_correction(true);
Projection projection = correction * p_render_data->scene_data->cam_projection;
- sky.setup_sky(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, p_render_data->camera_attributes, 1, &projection, &eye_offset, p_render_data->scene_data->cam_transform, projection, screen_size, this);
+ sky.setup_sky(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, p_render_data->camera_attributes, 1, &projection, &eye_offset, p_render_data->scene_data->cam_transform, projection, screen_size, Vector2(0.0f, 0.0f), this);
} else {
- sky.setup_sky(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, p_render_data->camera_attributes, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->view_eye_offset, p_render_data->scene_data->cam_transform, p_render_data->scene_data->cam_projection, screen_size, this);
+ sky.setup_sky(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, p_render_data->camera_attributes, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->view_eye_offset, p_render_data->scene_data->cam_transform, p_render_data->scene_data->cam_projection, screen_size, p_render_data->scene_data->taa_jitter, this);
}
sky_energy_multiplier *= bg_energy_multiplier;
@@ -886,6 +871,9 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
p_render_data->scene_data->directional_light_count = p_render_data->directional_light_count;
+ // Shadow pass can change the base uniform set samplers.
+ _update_render_base_uniform_set(rb->get_samplers());
+
_setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, p_render_data->render_buffers.is_valid());
if (using_subpass_transparent && using_subpass_post_process) {
@@ -905,14 +893,14 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
// regular forward for now
Vector<Color> c;
{
- Color cc = clear_color.srgb_to_linear();
+ Color cc = clear_color.srgb_to_linear() * inverse_luminance_multiplier;
if (rb_data.is_valid()) {
cc.a = 0; // For transparent viewport backgrounds.
}
c.push_back(cc); // Our render buffer.
if (rb_data.is_valid()) {
if (p_render_data->render_buffers->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED) {
- c.push_back(clear_color.srgb_to_linear()); // Our resolve buffer.
+ c.push_back(clear_color.srgb_to_linear() * inverse_luminance_multiplier); // Our resolve buffer.
}
if (using_subpass_post_process) {
c.push_back(Color()); // Our 2D buffer we're copying into.
@@ -1246,7 +1234,7 @@ void RenderForwardMobile::_render_shadow_pass(RID p_light, RID p_shadow_atlas, i
void RenderForwardMobile::_render_shadow_begin() {
scene_state.shadow_passes.clear();
RD::get_singleton()->draw_command_begin_label("Shadow Setup");
- _update_render_base_uniform_set();
+ _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default());
render_list[RENDER_LIST_SECONDARY].clear();
}
@@ -1292,7 +1280,7 @@ void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedAr
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode, true);
uint32_t render_list_size = render_list[RENDER_LIST_SECONDARY].elements.size() - render_list_from;
render_list[RENDER_LIST_SECONDARY].sort_by_key_range(render_list_from, render_list_size);
- _fill_element_info(RENDER_LIST_SECONDARY, render_list_from, render_list_size);
+ _fill_instance_data(RENDER_LIST_SECONDARY, render_list_from, render_list_size);
{
//regular forward for now
@@ -1353,7 +1341,7 @@ void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, c
RD::get_singleton()->draw_command_begin_label("Render 3D Material");
- _update_render_base_uniform_set();
+ _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default());
RenderSceneDataRD scene_data;
scene_data.cam_projection = p_cam_projection;
@@ -1375,7 +1363,7 @@ void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, c
PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
render_list[RENDER_LIST_SECONDARY].sort_by_key();
- _fill_element_info(RENDER_LIST_SECONDARY);
+ _fill_instance_data(RENDER_LIST_SECONDARY);
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
@@ -1404,7 +1392,7 @@ void RenderForwardMobile::_render_uv2(const PagedArray<RenderGeometryInstance *>
RD::get_singleton()->draw_command_begin_label("Render UV2");
- _update_render_base_uniform_set();
+ _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default());
RenderSceneDataRD scene_data;
scene_data.dual_paraboloid_side = 0;
@@ -1420,7 +1408,7 @@ void RenderForwardMobile::_render_uv2(const PagedArray<RenderGeometryInstance *>
PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
render_list[RENDER_LIST_SECONDARY].sort_by_key();
- _fill_element_info(RENDER_LIST_SECONDARY);
+ _fill_instance_data(RENDER_LIST_SECONDARY);
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
@@ -1478,7 +1466,7 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const
RD::get_singleton()->draw_command_begin_label("Render Collider Heightfield");
- _update_render_base_uniform_set();
+ _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default());
RenderSceneDataRD scene_data;
scene_data.cam_projection = p_cam_projection;
@@ -1501,7 +1489,7 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
render_list[RENDER_LIST_SECONDARY].sort_by_key();
- _fill_element_info(RENDER_LIST_SECONDARY);
+ _fill_instance_data(RENDER_LIST_SECONDARY);
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
@@ -1522,9 +1510,8 @@ void RenderForwardMobile::base_uniforms_changed() {
render_base_uniform_set = RID();
}
-void RenderForwardMobile::_update_render_base_uniform_set() {
+void RenderForwardMobile::_update_render_base_uniform_set(const RendererRD::MaterialStorage::Samplers &p_samplers) {
RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
- RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != light_storage->lightmap_array_get_version())) {
if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
@@ -1552,22 +1539,22 @@ void RenderForwardMobile::_update_render_base_uniform_set() {
RID sampler;
switch (decals_get_filter()) {
case RS::DECAL_FILTER_NEAREST: {
- sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
case RS::DECAL_FILTER_LINEAR: {
- sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
case RS::DECAL_FILTER_NEAREST_MIPMAPS: {
- sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
case RS::DECAL_FILTER_LINEAR_MIPMAPS: {
- sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
case RS::DECAL_FILTER_NEAREST_MIPMAPS_ANISOTROPIC: {
- sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
case RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
- sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
}
@@ -1582,22 +1569,22 @@ void RenderForwardMobile::_update_render_base_uniform_set() {
RID sampler;
switch (light_projectors_get_filter()) {
case RS::LIGHT_PROJECTOR_FILTER_NEAREST: {
- sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
case RS::LIGHT_PROJECTOR_FILTER_LINEAR: {
- sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS: {
- sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS: {
- sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS_ANISOTROPIC: {
- sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
- sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
}
@@ -1680,7 +1667,7 @@ void RenderForwardMobile::_update_render_base_uniform_set() {
uniforms.push_back(u);
}
- uniforms.append_array(material_storage->get_default_sampler_uniforms(SAMPLERS_BINDING_FIRST_INDEX));
+ uniforms.append_array(p_samplers.get_uniforms(SAMPLERS_BINDING_FIRST_INDEX));
render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, SCENE_UNIFORM_SET);
}
@@ -1694,6 +1681,91 @@ RID RenderForwardMobile::_render_buffers_get_velocity_texture(Ref<RenderSceneBuf
return RID();
}
+void RenderForwardMobile::_update_instance_data_buffer(RenderListType p_render_list) {
+ if (scene_state.instance_data[p_render_list].size() > 0) {
+ if (scene_state.instance_buffer[p_render_list] == RID() || scene_state.instance_buffer_size[p_render_list] < scene_state.instance_data[p_render_list].size()) {
+ if (scene_state.instance_buffer[p_render_list] != RID()) {
+ RD::get_singleton()->free(scene_state.instance_buffer[p_render_list]);
+ }
+ uint32_t new_size = nearest_power_of_2_templated(MAX(uint64_t(INSTANCE_DATA_BUFFER_MIN_SIZE), scene_state.instance_data[p_render_list].size()));
+ scene_state.instance_buffer[p_render_list] = RD::get_singleton()->storage_buffer_create(new_size * sizeof(SceneState::InstanceData));
+ scene_state.instance_buffer_size[p_render_list] = new_size;
+ }
+ RD::get_singleton()->buffer_update(scene_state.instance_buffer[p_render_list], 0, sizeof(SceneState::InstanceData) * scene_state.instance_data[p_render_list].size(), scene_state.instance_data[p_render_list].ptr(), RD::BARRIER_MASK_RASTER);
+ }
+}
+
+void RenderForwardMobile::_fill_instance_data(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements, bool p_update_buffer) {
+ RenderList *rl = &render_list[p_render_list];
+ uint32_t element_total = p_max_elements >= 0 ? uint32_t(p_max_elements) : rl->elements.size();
+
+ scene_state.instance_data[p_render_list].resize(p_offset + element_total);
+ rl->element_info.resize(p_offset + element_total);
+
+ for (uint32_t i = 0; i < element_total; i++) {
+ GeometryInstanceSurfaceDataCache *surface = rl->elements[i + p_offset];
+ GeometryInstanceForwardMobile *inst = surface->owner;
+
+ SceneState::InstanceData &instance_data = scene_state.instance_data[p_render_list][i + p_offset];
+
+ if (inst->store_transform_cache) {
+ RendererRD::MaterialStorage::store_transform(inst->transform, instance_data.transform);
+
+#ifdef REAL_T_IS_DOUBLE
+ // Split the origin into two components, the float approximation and the missing precision.
+ // In the shader we will combine these back together to restore the lost precision.
+ RendererRD::MaterialStorage::split_double(inst->transform.origin.x, &instance_data.transform[12], &instance_data.transform[3]);
+ RendererRD::MaterialStorage::split_double(inst->transform.origin.y, &instance_data.transform[13], &instance_data.transform[7]);
+ RendererRD::MaterialStorage::split_double(inst->transform.origin.z, &instance_data.transform[14], &instance_data.transform[11]);
+#endif
+ } else {
+ RendererRD::MaterialStorage::store_transform(Transform3D(), instance_data.transform);
+ }
+
+ instance_data.flags = inst->flags_cache;
+ instance_data.gi_offset = inst->gi_offset_cache;
+ instance_data.layer_mask = inst->layer_mask;
+ instance_data.instance_uniforms_ofs = uint32_t(inst->shader_uniforms_offset);
+ instance_data.lightmap_uv_scale[0] = inst->lightmap_uv_scale.position.x;
+ instance_data.lightmap_uv_scale[1] = inst->lightmap_uv_scale.position.y;
+ instance_data.lightmap_uv_scale[2] = inst->lightmap_uv_scale.size.x;
+ instance_data.lightmap_uv_scale[3] = inst->lightmap_uv_scale.size.y;
+
+ AABB surface_aabb = AABB(Vector3(0.0, 0.0, 0.0), Vector3(1.0, 1.0, 1.0));
+ uint64_t format = RendererRD::MeshStorage::get_singleton()->mesh_surface_get_format(surface->surface);
+ Vector4 uv_scale = Vector4(0.0, 0.0, 0.0, 0.0);
+
+ if (format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) {
+ surface_aabb = RendererRD::MeshStorage::get_singleton()->mesh_surface_get_aabb(surface->surface);
+ uv_scale = RendererRD::MeshStorage::get_singleton()->mesh_surface_get_uv_scale(surface->surface);
+ }
+
+ fill_push_constant_instance_indices(&instance_data, inst);
+
+ instance_data.compressed_aabb_position[0] = surface_aabb.position.x;
+ instance_data.compressed_aabb_position[1] = surface_aabb.position.y;
+ instance_data.compressed_aabb_position[2] = surface_aabb.position.z;
+
+ instance_data.compressed_aabb_size[0] = surface_aabb.size.x;
+ instance_data.compressed_aabb_size[1] = surface_aabb.size.y;
+ instance_data.compressed_aabb_size[2] = surface_aabb.size.z;
+
+ instance_data.uv_scale[0] = uv_scale.x;
+ instance_data.uv_scale[1] = uv_scale.y;
+ instance_data.uv_scale[2] = uv_scale.z;
+ instance_data.uv_scale[3] = uv_scale.w;
+
+ RenderElementInfo &element_info = rl->element_info[p_offset + i];
+
+ element_info.lod_index = surface->lod_index;
+ element_info.uses_lightmap = surface->sort.uses_lightmap;
+ }
+
+ if (p_update_buffer) {
+ _update_instance_data_buffer(p_render_list);
+ }
+}
+
_FORCE_INLINE_ static uint32_t _indices_to_primitives(RS::PrimitiveType p_primitive, uint32_t p_indices) {
static const uint32_t divisor[RS::PRIMITIVE_MAX] = { 1, 2, 1, 3, 1 };
static const uint32_t subtractor[RS::PRIMITIVE_MAX] = { 0, 0, 1, 0, 1 };
@@ -1911,22 +1983,7 @@ void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data,
}
}
- p_render_data->scene_data->update_ubo(scene_state.uniform_buffers[p_index], get_debug_draw_mode(), env, reflection_probe_instance, p_render_data->camera_attributes, p_flip_y, p_pancake_shadows, p_screen_size, p_default_bg_color, _render_buffers_get_luminance_multiplier(), p_opaque_render_buffers);
-}
-
-void RenderForwardMobile::_fill_element_info(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements) {
- RenderList *rl = &render_list[p_render_list];
- uint32_t element_total = p_max_elements >= 0 ? uint32_t(p_max_elements) : rl->elements.size();
-
- rl->element_info.resize(p_offset + element_total);
-
- for (uint32_t i = 0; i < element_total; i++) {
- GeometryInstanceSurfaceDataCache *surface = rl->elements[i + p_offset];
- RenderElementInfo &element_info = rl->element_info[p_offset + i];
-
- element_info.lod_index = surface->lod_index;
- element_info.uses_lightmap = surface->sort.uses_lightmap;
- }
+ p_render_data->scene_data->update_ubo(scene_state.uniform_buffers[p_index], get_debug_draw_mode(), env, reflection_probe_instance, p_render_data->camera_attributes, p_flip_y, p_pancake_shadows, p_screen_size, p_default_bg_color, _render_buffers_get_luminance_multiplier(), p_opaque_render_buffers, false);
}
/// RENDERING ///
@@ -2014,39 +2071,17 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
uint32_t base_spec_constants = p_params->spec_constant_base_flags;
- // GeometryInstanceForwardMobile::PushConstant push_constant = inst->push_constant;
- GeometryInstanceForwardMobile::PushConstant push_constant;
+ SceneState::PushConstant push_constant;
+ push_constant.base_index = i + p_params->element_offset;
- if (inst->store_transform_cache) {
- RendererRD::MaterialStorage::store_transform(inst->transform, push_constant.transform);
-
-#ifdef REAL_T_IS_DOUBLE
- // Split the origin into two components, the float approximation and the missing precision
- // In the shader we will combine these back together to restore the lost precision.
- RendererRD::MaterialStorage::split_double(inst->transform.origin.x, &push_constant.transform[12], &push_constant.transform[3]);
- RendererRD::MaterialStorage::split_double(inst->transform.origin.y, &push_constant.transform[13], &push_constant.transform[7]);
- RendererRD::MaterialStorage::split_double(inst->transform.origin.z, &push_constant.transform[14], &push_constant.transform[11]);
-#endif
+ if constexpr (p_pass_mode == PASS_MODE_DEPTH_MATERIAL) {
+ push_constant.uv_offset[0] = p_params->uv_offset.x;
+ push_constant.uv_offset[1] = p_params->uv_offset.y;
} else {
- RendererRD::MaterialStorage::store_transform(Transform3D(), push_constant.transform);
+ push_constant.uv_offset[0] = 0.0;
+ push_constant.uv_offset[1] = 0.0;
}
- push_constant.flags = inst->flags_cache;
- push_constant.gi_offset = inst->gi_offset_cache;
- push_constant.layer_mask = inst->layer_mask;
- push_constant.instance_uniforms_ofs = uint32_t(inst->shader_uniforms_offset);
-
- if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL) {
- // abuse lightmap_uv_scale[0] here, should not be needed here
- push_constant.lightmap_uv_scale[0] = p_params->uv_offset.x;
- push_constant.lightmap_uv_scale[1] = p_params->uv_offset.y;
- } else {
- push_constant.lightmap_uv_scale[0] = inst->lightmap_uv_scale.position.x;
- push_constant.lightmap_uv_scale[1] = inst->lightmap_uv_scale.position.y;
- push_constant.lightmap_uv_scale[2] = inst->lightmap_uv_scale.size.x;
- push_constant.lightmap_uv_scale[3] = inst->lightmap_uv_scale.size.y;
- };
-
RID material_uniform_set;
SceneShaderForwardMobile::ShaderData *shader;
void *mesh_surface;
@@ -2063,7 +2098,19 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
if (inst->use_soft_shadow) {
base_spec_constants |= 1 << SPEC_CONSTANT_USING_SOFT_SHADOWS;
}
- forward_id_storage_mobile->fill_push_constant_instance_indices(&push_constant, base_spec_constants, inst);
+
+ if (inst->omni_light_count == 0) {
+ base_spec_constants |= 1 << SPEC_CONSTANT_DISABLE_OMNI_LIGHTS;
+ }
+ if (inst->spot_light_count == 0) {
+ base_spec_constants |= 1 << SPEC_CONSTANT_DISABLE_SPOT_LIGHTS;
+ }
+ if (inst->reflection_probe_count == 0) {
+ base_spec_constants |= 1 << SPEC_CONSTANT_DISABLE_REFLECTION_PROBES;
+ }
+ if (inst->decals_count == 0) {
+ base_spec_constants |= 1 << SPEC_CONSTANT_DISABLE_DECALS;
+ }
#ifdef DEBUG_ENABLED
if (unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_LIGHTING)) {
@@ -2145,9 +2192,9 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
//skeleton and blend shape
if (surf->owner->mesh_instance.is_valid()) {
- mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format);
+ mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, pipeline->get_vertex_input_mask(), false, vertex_array_rd, vertex_format);
} else {
- mesh_storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format);
+ mesh_storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, pipeline->get_vertex_input_mask(), false, vertex_array_rd, vertex_format);
}
index_array_rd = mesh_storage->mesh_surface_get_index_array(mesh_surface, element_info.lod_index);
@@ -2187,7 +2234,7 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
prev_material_uniform_set = material_uniform_set;
}
- RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(GeometryInstanceForwardMobile::PushConstant));
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(SceneState::PushConstant));
uint32_t instance_count = surf->owner->instance_count > 1 ? surf->owner->instance_count : 1;
if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_PARTICLE_TRAILS) {
@@ -2249,7 +2296,7 @@ void RenderForwardMobile::GeometryInstanceForwardMobile::set_lightmap_capture(co
void RenderForwardMobile::geometry_instance_free(RenderGeometryInstance *p_geometry_instance) {
GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
- ERR_FAIL_COND(!ginstance);
+ ERR_FAIL_NULL(ginstance);
if (ginstance->lightmap_sh != nullptr) {
geometry_instance_lightmap_sh.free(ginstance->lightmap_sh);
}
@@ -2379,7 +2426,7 @@ void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryI
SceneShaderForwardMobile::MaterialData *material_shadow = nullptr;
void *surface_shadow = nullptr;
- if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_prepass_alpha && !p_material->shader_data->uses_alpha_clip && !p_material->shader_data->uses_alpha_antialiasing) {
+ if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_prepass_alpha && !p_material->shader_data->uses_alpha_clip && !p_material->shader_data->uses_alpha_antialiasing && !p_material->shader_data->uses_world_coordinates) {
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL;
material_shadow = static_cast<SceneShaderForwardMobile::MaterialData *>(RendererRD::MaterialStorage::get_singleton()->material_get_data(scene_shader.default_material, RendererRD::MaterialStorage::SHADER_TYPE_3D));
@@ -2476,7 +2523,7 @@ void RenderForwardMobile::_geometry_instance_add_surface(GeometryInstanceForward
m_src = scene_shader.default_material;
}
- ERR_FAIL_COND(!material);
+ ERR_FAIL_NULL(material);
_geometry_instance_add_surface_with_material_chain(ginstance, p_surface, material, m_src, p_mesh);
@@ -2620,6 +2667,10 @@ void RenderForwardMobile::_geometry_instance_update(RenderGeometryInstance *p_ge
// Particles haven't been cleared or updated, update once now to ensure they are ready to render.
particles_storage->update_particles();
}
+
+ if (ginstance->data->dirty_dependencies) {
+ particles_storage->particles_update_dependency(ginstance->data->base, &ginstance->data->dependency_tracker);
+ }
} else if (ginstance->data->base_type == RS::INSTANCE_MESH) {
if (mesh_storage->skeleton_is_valid(ginstance->data->skeleton)) {
ginstance->transforms_uniform_set = mesh_storage->skeleton_get_3d_uniform_set(ginstance->data->skeleton, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
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 f2913dd185..50bf83b612 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
@@ -200,11 +200,11 @@ private:
uint64_t lightmap_texture_array_version = 0xFFFFFFFF;
- void _update_render_base_uniform_set();
+ void _update_render_base_uniform_set(const RendererRD::MaterialStorage::Samplers &p_samplers);
+ void _update_instance_data_buffer(RenderListType p_render_list);
+ void _fill_instance_data(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true);
void _fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_append = false);
- void _fill_element_info(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1);
- // void _update_instance_data_buffer(RenderListType p_render_list);
void _setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false, int p_index = 0);
void _setup_lightmaps(const RenderDataRD *p_render_data, const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform);
@@ -229,6 +229,32 @@ private:
struct SceneState {
LocalVector<RID> uniform_buffers;
+ struct PushConstant {
+ float uv_offset[2];
+ uint32_t base_index;
+ uint32_t pad;
+ };
+
+ struct InstanceData {
+ float transform[16];
+ uint32_t flags;
+ uint32_t instance_uniforms_ofs; // Base offset in global buffer for instance variables.
+ uint32_t gi_offset; // GI information when using lightmapping (VCT or lightmap index).
+ uint32_t layer_mask = 1;
+ float lightmap_uv_scale[4]; // Doubles as uv_offset when needed.
+ uint32_t reflection_probes[2]; // Packed reflection probes.
+ uint32_t omni_lights[2]; // Packed omni lights.
+ uint32_t spot_lights[2]; // Packed spot lights.
+ uint32_t decals[2]; // Packed spot lights.
+ float compressed_aabb_position[4];
+ float compressed_aabb_size[4];
+ float uv_scale[4];
+ };
+
+ RID instance_buffer[RENDER_LIST_MAX];
+ uint32_t instance_buffer_size[RENDER_LIST_MAX] = { 0, 0, 0 };
+ LocalVector<InstanceData> instance_data[RENDER_LIST_MAX];
+
// !BAS! We need to change lightmaps, we're not going to do this with a buffer but pushing the used lightmap in
LightmapData lightmaps[MAX_LIGHTMAPS];
RID lightmap_ids[MAX_LIGHTMAPS];
@@ -447,27 +473,11 @@ protected:
class GeometryInstanceForwardMobile : public RenderGeometryInstanceBase {
public:
- // this structure maps to our push constant in our shader and is populated right before our draw call
- struct PushConstant {
- float transform[16];
- uint32_t flags;
- uint32_t instance_uniforms_ofs; //base offset in global buffer for instance variables
- uint32_t gi_offset; //GI information when using lightmapping (VCT or lightmap index)
- uint32_t layer_mask = 1;
- float lightmap_uv_scale[4]; // doubles as uv_offset when needed
- uint32_t reflection_probes[2]; // packed reflection probes
- uint32_t omni_lights[2]; // packed omni lights
- uint32_t spot_lights[2]; // packed spot lights
- uint32_t decals[2]; // packed spot lights
- };
-
- // PushConstant push_constant; // we populate this from our instance data
-
//used during rendering
RID transforms_uniform_set;
bool use_projector = false;
bool use_soft_shadow = false;
- bool store_transform_cache = true; // if true we copy our transform into our PushConstant, if false we use our transforms UBO and clear our PushConstants transform
+ bool store_transform_cache = true; // If true we copy our transform into our per-draw buffer, if false we use our transforms UBO and clear our per-draw transform.
uint32_t instance_count = 0;
uint32_t trail_steps = 1;
@@ -534,12 +544,12 @@ protected:
virtual void free_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id) override;
virtual void map_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id, uint32_t p_index) override;
virtual bool uses_forward_ids() const override { return true; }
-
- void fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, uint32_t &spec_constants, const GeometryInstanceForwardMobile *p_instance);
};
ForwardIDStorageMobile *forward_id_storage_mobile = nullptr;
+ void fill_push_constant_instance_indices(SceneState::InstanceData *p_instance_data, const GeometryInstanceForwardMobile *p_instance);
+
virtual RendererRD::ForwardIDStorage *create_forward_id_storage() override {
forward_id_storage_mobile = memnew(ForwardIDStorageMobile);
return forward_id_storage_mobile;
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
index e4498ac533..b2c0d4b1bd 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
@@ -106,6 +106,7 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
actions.render_mode_flags["unshaded"] = &unshaded;
actions.render_mode_flags["wireframe"] = &wireframe;
actions.render_mode_flags["particle_trails"] = &uses_particle_trails;
+ actions.render_mode_flags["world_vertex_coords"] = &uses_world_coordinates;
actions.usage_flag_pointers["ALPHA"] = &uses_alpha;
actions.usage_flag_pointers["ALPHA_SCISSOR_THRESHOLD"] = &uses_alpha_clip;
@@ -364,7 +365,7 @@ SceneShaderForwardMobile::ShaderData::ShaderData() :
SceneShaderForwardMobile::ShaderData::~ShaderData() {
SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton;
- ERR_FAIL_COND(!shader_singleton);
+ ERR_FAIL_NULL(shader_singleton);
//pipeline variants will clear themselves if shader is gone
if (version.is_valid()) {
shader_singleton->shader.version_free(version);
@@ -388,7 +389,7 @@ void SceneShaderForwardMobile::MaterialData::set_next_pass(RID p_pass) {
bool SceneShaderForwardMobile::MaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton;
- return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardMobile::MATERIAL_UNIFORM_SET, true, RD::BARRIER_MASK_RASTER);
+ return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardMobile::MATERIAL_UNIFORM_SET, true, true, RD::BARRIER_MASK_RASTER);
}
SceneShaderForwardMobile::MaterialData::~MaterialData() {
@@ -610,6 +611,7 @@ void SceneShaderForwardMobile::init(const String p_defines) {
actions.render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n";
actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n";
actions.render_mode_defines["debug_shadow_splits"] = "#define DEBUG_DRAW_PSSM_SPLITS\n";
+ actions.render_mode_defines["fog_disabled"] = "#define FOG_DISABLED\n";
actions.base_texture_binding_index = 1;
actions.texture_layout_set = RenderForwardMobile::MATERIAL_UNIFORM_SET;
@@ -619,7 +621,7 @@ void SceneShaderForwardMobile::init(const String p_defines) {
actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
actions.global_buffer_array_variable = "global_shader_uniforms.data";
- actions.instance_uniform_index_variable = "draw_call.instance_uniforms_ofs";
+ actions.instance_uniform_index_variable = "instances.data[draw_call.instance_index].instance_uniforms_ofs";
actions.apply_luminance_multiplier = true; // apply luminance multiplier to screen texture
actions.check_multiview_samplers = RendererCompositorRD::get_singleton()->is_xr_enabled(); // Make sure we check sampling multiview textures.
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
index 0b98746d06..5c76d89247 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
@@ -97,7 +97,7 @@ public:
bool valid = false;
RID version;
- uint32_t vertex_input_mask = 0;
+ uint64_t vertex_input_mask = 0;
PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][SHADER_VERSION_MAX];
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
diff --git a/servers/rendering/renderer_rd/pipeline_cache_rd.h b/servers/rendering/renderer_rd/pipeline_cache_rd.h
index 52877109f7..2f1e79b397 100644
--- a/servers/rendering/renderer_rd/pipeline_cache_rd.h
+++ b/servers/rendering/renderer_rd/pipeline_cache_rd.h
@@ -91,7 +91,7 @@ public:
return result;
}
- _FORCE_INLINE_ uint32_t get_vertex_input_mask() {
+ _FORCE_INLINE_ uint64_t get_vertex_input_mask() {
if (input_mask == 0) {
ERR_FAIL_COND_V(shader.is_null(), 0);
input_mask = RD::get_singleton()->shader_get_vertex_input_attribute_mask(shader);
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index eb33f296d0..ecf2c29956 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -329,7 +329,7 @@ RendererCanvasRender::PolygonID RendererCanvasRenderRD::request_polygon(const Ve
void RendererCanvasRenderRD::free_polygon(PolygonID p_polygon) {
PolygonBuffers *pb_ptr = polygon_buffers.polygons.getptr(p_polygon);
- ERR_FAIL_COND(!pb_ptr);
+ ERR_FAIL_NULL(pb_ptr);
PolygonBuffers &pb = *pb_ptr;
@@ -348,7 +348,7 @@ void RendererCanvasRenderRD::free_polygon(PolygonID p_polygon) {
////////////////////
-void RendererCanvasRenderRD::_bind_canvas_texture(RD::DrawListID p_draw_list, RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID &r_last_texture, PushConstant &push_constant, Size2 &r_texpixel_size) {
+void RendererCanvasRenderRD::_bind_canvas_texture(RD::DrawListID p_draw_list, RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID &r_last_texture, PushConstant &push_constant, Size2 &r_texpixel_size, bool p_texture_is_data) {
if (p_texture == RID()) {
p_texture = default_canvas_texture;
}
@@ -363,7 +363,7 @@ void RendererCanvasRenderRD::_bind_canvas_texture(RD::DrawListID p_draw_list, RI
bool use_normal;
bool use_specular;
- bool success = RendererRD::TextureStorage::get_singleton()->canvas_texture_get_uniform_set(p_texture, p_base_filter, p_base_repeat, shader.default_version_rd_shader, CANVAS_TEXTURE_UNIFORM_SET, uniform_set, size, specular_shininess, use_normal, use_specular);
+ bool success = RendererRD::TextureStorage::get_singleton()->canvas_texture_get_uniform_set(p_texture, p_base_filter, p_base_repeat, shader.default_version_rd_shader, CANVAS_TEXTURE_UNIFORM_SET, bool(push_constant.flags & FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR), uniform_set, size, specular_shininess, use_normal, use_specular, p_texture_is_data);
//something odd happened
if (!success) {
_bind_canvas_texture(p_draw_list, default_canvas_texture, p_base_filter, p_base_repeat, r_last_texture, push_constant, r_texpixel_size);
@@ -421,6 +421,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
_update_transform_2d_to_mat2x3(base_transform, push_constant.world);
Color base_color = p_item->final_modulate;
+ bool use_linear_colors = texture_storage->render_target_is_using_hdr(p_render_target);
for (int i = 0; i < 4; i++) {
push_constant.modulation[i] = 0;
@@ -441,6 +442,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
push_constant.lights[3] = 0;
uint32_t base_flags = 0;
+ base_flags |= use_linear_colors ? FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR : 0;
uint16_t light_count = 0;
PipelineLightMode light_mode;
@@ -483,7 +485,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
continue;
}
- push_constant.flags = base_flags | (push_constant.flags & (FLAGS_DEFAULT_NORMAL_MAP_USED | FLAGS_DEFAULT_SPECULAR_MAP_USED)); //reset on each command for sanity, keep canvastexture binding config
+ push_constant.flags = base_flags | (push_constant.flags & (FLAGS_DEFAULT_NORMAL_MAP_USED | FLAGS_DEFAULT_SPECULAR_MAP_USED)); // Reset on each command for safety, keep canvastexture binding config.
switch (c->type) {
case Item::Command::TYPE_RECT: {
@@ -505,7 +507,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
//bind textures
- _bind_canvas_texture(p_draw_list, rect->texture, current_filter, current_repeat, last_texture, push_constant, texpixel_size);
+ _bind_canvas_texture(p_draw_list, rect->texture, current_filter, current_repeat, last_texture, push_constant, texpixel_size, bool(rect->flags & CANVAS_RECT_MSDF));
Rect2 src_rect;
Rect2 dst_rect;
@@ -566,10 +568,15 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
push_constant.flags |= FLAGS_USE_LCD;
}
- push_constant.modulation[0] = rect->modulate.r * base_color.r;
- push_constant.modulation[1] = rect->modulate.g * base_color.g;
- push_constant.modulation[2] = rect->modulate.b * base_color.b;
- push_constant.modulation[3] = rect->modulate.a * base_color.a;
+ Color modulated = rect->modulate * base_color;
+ if (use_linear_colors) {
+ modulated = modulated.srgb_to_linear();
+ }
+
+ push_constant.modulation[0] = modulated.r;
+ push_constant.modulation[1] = modulated.g;
+ push_constant.modulation[2] = modulated.b;
+ push_constant.modulation[3] = modulated.a;
push_constant.src_rect[0] = src_rect.position.x;
push_constant.src_rect[1] = src_rect.position.y;
@@ -618,10 +625,15 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
}
}
- push_constant.modulation[0] = np->color.r * base_color.r;
- push_constant.modulation[1] = np->color.g * base_color.g;
- push_constant.modulation[2] = np->color.b * base_color.b;
- push_constant.modulation[3] = np->color.a * base_color.a;
+ Color modulated = np->color * base_color;
+ if (use_linear_colors) {
+ modulated = modulated.srgb_to_linear();
+ }
+
+ push_constant.modulation[0] = modulated.r;
+ push_constant.modulation[1] = modulated.g;
+ push_constant.modulation[2] = modulated.b;
+ push_constant.modulation[3] = modulated.a;
push_constant.src_rect[0] = src_rect.position.x;
push_constant.src_rect[1] = src_rect.position.y;
@@ -676,10 +688,15 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
_bind_canvas_texture(p_draw_list, polygon->texture, current_filter, current_repeat, last_texture, push_constant, texpixel_size);
- push_constant.modulation[0] = base_color.r;
- push_constant.modulation[1] = base_color.g;
- push_constant.modulation[2] = base_color.b;
- push_constant.modulation[3] = base_color.a;
+ Color color = base_color;
+ if (use_linear_colors) {
+ color = color.srgb_to_linear();
+ }
+
+ push_constant.modulation[0] = color.r;
+ push_constant.modulation[1] = color.g;
+ push_constant.modulation[2] = color.b;
+ push_constant.modulation[3] = color.a;
for (int j = 0; j < 4; j++) {
push_constant.src_rect[j] = 0;
@@ -718,6 +735,9 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
push_constant.uvs[j * 2 + 0] = primitive->uvs[j].x;
push_constant.uvs[j * 2 + 1] = primitive->uvs[j].y;
Color col = primitive->colors[j] * base_color;
+ if (use_linear_colors) {
+ col = col.srgb_to_linear();
+ }
push_constant.colors[j * 2 + 0] = (uint32_t(Math::make_half_float(col.g)) << 16) | Math::make_half_float(col.r);
push_constant.colors[j * 2 + 1] = (uint32_t(Math::make_half_float(col.a)) << 16) | Math::make_half_float(col.b);
}
@@ -732,6 +752,9 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
push_constant.uvs[j * 2 + 0] = primitive->uvs[j + 1].x;
push_constant.uvs[j * 2 + 1] = primitive->uvs[j + 1].y;
Color col = primitive->colors[j + 1] * base_color;
+ if (use_linear_colors) {
+ col = col.srgb_to_linear();
+ }
push_constant.colors[j * 2 + 0] = (uint32_t(Math::make_half_float(col.g)) << 16) | Math::make_half_float(col.r);
push_constant.colors[j * 2 + 1] = (uint32_t(Math::make_half_float(col.a)) << 16) | Math::make_half_float(col.b);
}
@@ -849,10 +872,15 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
uint32_t surf_count = mesh_storage->mesh_get_surface_count(mesh);
static const PipelineVariant variant[RS::PRIMITIVE_MAX] = { PIPELINE_VARIANT_ATTRIBUTE_POINTS, PIPELINE_VARIANT_ATTRIBUTE_LINES, PIPELINE_VARIANT_ATTRIBUTE_LINES_STRIP, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLES, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLE_STRIP };
- push_constant.modulation[0] = base_color.r * modulate.r;
- push_constant.modulation[1] = base_color.g * modulate.g;
- push_constant.modulation[2] = base_color.b * modulate.b;
- push_constant.modulation[3] = base_color.a * modulate.a;
+ Color modulated = modulate * base_color;
+ if (use_linear_colors) {
+ modulated = modulated.srgb_to_linear();
+ }
+
+ push_constant.modulation[0] = modulated.r;
+ push_constant.modulation[1] = modulated.g;
+ push_constant.modulation[2] = modulated.b;
+ push_constant.modulation[3] = modulated.a;
for (int j = 0; j < 4; j++) {
push_constant.src_rect[j] = 0;
@@ -866,15 +894,15 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
RS::PrimitiveType primitive = mesh_storage->mesh_surface_get_primitive(surface);
ERR_CONTINUE(primitive < 0 || primitive >= RS::PRIMITIVE_MAX);
- uint32_t input_mask = pipeline_variants->variants[light_mode][variant[primitive]].get_vertex_input_mask();
+ uint64_t input_mask = pipeline_variants->variants[light_mode][variant[primitive]].get_vertex_input_mask();
RID vertex_array;
RD::VertexFormatID vertex_format = RD::INVALID_FORMAT_ID;
if (mesh_instance.is_valid()) {
- mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(mesh_instance, j, input_mask, vertex_array, vertex_format);
+ mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(mesh_instance, j, input_mask, false, vertex_array, vertex_format);
} else {
- mesh_storage->mesh_surface_get_vertex_arrays_and_format(surface, input_mask, vertex_array, vertex_format);
+ mesh_storage->mesh_surface_get_vertex_arrays_and_format(surface, input_mask, false, vertex_array, vertex_format);
}
RID pipeline = pipeline_variants->variants[light_mode][variant[primitive]].get_render_pipeline(vertex_format, p_framebuffer_format);
@@ -929,7 +957,48 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
c = c->next;
}
+#ifdef DEBUG_ENABLED
+ if (debug_redraw && p_item->debug_redraw_time > 0.0) {
+ Color dc = debug_redraw_color;
+ dc.a *= p_item->debug_redraw_time / debug_redraw_time;
+
+ RID pipeline = pipeline_variants->variants[PIPELINE_LIGHT_MODE_DISABLED][PIPELINE_VARIANT_QUAD].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format);
+ RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
+
+ //bind textures
+
+ _bind_canvas_texture(p_draw_list, RID(), current_filter, current_repeat, last_texture, push_constant, texpixel_size);
+ Rect2 src_rect;
+ Rect2 dst_rect;
+
+ dst_rect = Rect2(Vector2(), p_item->rect.size);
+ src_rect = Rect2(0, 0, 1, 1);
+
+ push_constant.modulation[0] = dc.r;
+ push_constant.modulation[1] = dc.g;
+ push_constant.modulation[2] = dc.b;
+ push_constant.modulation[3] = dc.a;
+
+ push_constant.src_rect[0] = src_rect.position.x;
+ push_constant.src_rect[1] = src_rect.position.y;
+ push_constant.src_rect[2] = src_rect.size.width;
+ push_constant.src_rect[3] = src_rect.size.height;
+
+ push_constant.dst_rect[0] = dst_rect.position.x;
+ push_constant.dst_rect[1] = dst_rect.position.y;
+ push_constant.dst_rect[2] = dst_rect.size.width;
+ push_constant.dst_rect[3] = dst_rect.size.height;
+
+ RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
+ RD::get_singleton()->draw_list_bind_index_array(p_draw_list, shader.quad_index_array);
+ RD::get_singleton()->draw_list_draw(p_draw_list, true);
+
+ p_item->debug_redraw_time -= RSG::rasterizer->get_frame_delta_time();
+
+ RenderingServerDefault::redraw_request();
+ }
+#endif
if (current_clip && reclip) {
//will make it re-enable clipping if needed afterwards
current_clip = nullptr;
@@ -1017,7 +1086,7 @@ RID RendererCanvasRenderRD::_create_base_uniform_set(RID p_to_render_target, boo
uniforms.push_back(u);
}
- uniforms.append_array(material_storage->get_default_sampler_uniforms(SAMPLERS_BINDING_FIRST_INDEX));
+ uniforms.append_array(material_storage->samplers_rd_get_default().get_uniforms(SAMPLERS_BINDING_FIRST_INDEX));
RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader.default_version_rd_shader, BASE_UNIFORM_SET);
if (p_backbuffer) {
@@ -1113,8 +1182,9 @@ void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_co
if (material_data->shader_data->version.is_valid() && material_data->shader_data->valid) {
pipeline_variants = &material_data->shader_data->pipeline_variants;
// Update uniform set.
- if (material_data->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(material_data->uniform_set)) { // Material may not have a uniform set.
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_data->uniform_set, MATERIAL_UNIFORM_SET);
+ RID uniform_set = texture_storage->render_target_is_using_hdr(p_to_render_target) ? material_data->uniform_set : material_data->uniform_set_srgb;
+ if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { // Material may not have a uniform set.
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set, MATERIAL_UNIFORM_SET);
material_data->set_as_used();
}
} else {
@@ -1532,7 +1602,7 @@ void RendererCanvasRenderRD::light_set_texture(RID p_rid, RID p_texture) {
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
CanvasLight *cl = canvas_light_owner.get_or_null(p_rid);
- ERR_FAIL_COND(!cl);
+ ERR_FAIL_NULL(cl);
if (cl->texture == p_texture) {
return;
}
@@ -1551,7 +1621,7 @@ void RendererCanvasRenderRD::light_set_texture(RID p_rid, RID p_texture) {
void RendererCanvasRenderRD::light_set_use_shadow(RID p_rid, bool p_enable) {
CanvasLight *cl = canvas_light_owner.get_or_null(p_rid);
- ERR_FAIL_COND(!cl);
+ ERR_FAIL_NULL(cl);
cl->shadow.enabled = p_enable;
}
@@ -1820,7 +1890,7 @@ RID RendererCanvasRenderRD::occluder_polygon_create() {
void RendererCanvasRenderRD::occluder_polygon_set_shape(RID p_occluder, const Vector<Vector2> &p_points, bool p_closed) {
OccluderPolygon *oc = occluder_polygon_owner.get_or_null(p_occluder);
- ERR_FAIL_COND(!oc);
+ ERR_FAIL_NULL(oc);
Vector<Vector2> lines;
@@ -1991,7 +2061,7 @@ void RendererCanvasRenderRD::occluder_polygon_set_shape(RID p_occluder, const Ve
void RendererCanvasRenderRD::occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) {
OccluderPolygon *oc = occluder_polygon_owner.get_or_null(p_occluder);
- ERR_FAIL_COND(!oc);
+ ERR_FAIL_NULL(oc);
oc->cull_mode = p_mode;
}
@@ -2221,7 +2291,7 @@ RS::ShaderNativeSourceCode RendererCanvasRenderRD::CanvasShaderData::get_native_
RendererCanvasRenderRD::CanvasShaderData::~CanvasShaderData() {
RendererCanvasRenderRD *canvas_singleton = static_cast<RendererCanvasRenderRD *>(RendererCanvasRender::singleton);
- ERR_FAIL_COND(!canvas_singleton);
+ ERR_FAIL_NULL(canvas_singleton);
//pipeline variants will clear themselves if shader is gone
if (version.is_valid()) {
canvas_singleton->shader.canvas_shader.version_free(version);
@@ -2235,12 +2305,14 @@ RendererRD::MaterialStorage::ShaderData *RendererCanvasRenderRD::_create_shader_
bool RendererCanvasRenderRD::CanvasMaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
RendererCanvasRenderRD *canvas_singleton = static_cast<RendererCanvasRenderRD *>(RendererCanvasRender::singleton);
-
- return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET, false);
+ bool uniform_set_changed = update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET, true, false, RD::BARRIER_MASK_ALL_BARRIERS);
+ bool uniform_set_srgb_changed = update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set_srgb, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET, false, false, RD::BARRIER_MASK_ALL_BARRIERS);
+ return uniform_set_changed || uniform_set_srgb_changed;
}
RendererCanvasRenderRD::CanvasMaterialData::~CanvasMaterialData() {
free_parameters_uniform_set(uniform_set);
+ free_parameters_uniform_set(uniform_set_srgb);
}
RendererRD::MaterialStorage::MaterialData *RendererCanvasRenderRD::_create_material_func(CanvasShaderData *p_shader) {
@@ -2396,7 +2468,7 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() {
actions.renames["LIGHT_VERTEX"] = "light_vertex";
actions.renames["SHADOW_VERTEX"] = "shadow_vertex";
actions.renames["UV"] = "uv";
- actions.renames["POINT_SIZE"] = "gl_PointSize";
+ actions.renames["POINT_SIZE"] = "point_size";
actions.renames["MODEL_MATRIX"] = "model_matrix";
actions.renames["CANVAS_MATRIX"] = "canvas_data.canvas_transform";
@@ -2444,10 +2516,12 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() {
actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n";
actions.usage_defines["LIGHT"] = "#define LIGHT_SHADER_CODE_USED\n";
actions.usage_defines["SPECULAR_SHININESS"] = "#define SPECULAR_SHININESS_USED\n";
+ actions.usage_defines["POINT_SIZE"] = "#define USE_POINT_SIZE\n";
actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n";
actions.render_mode_defines["light_only"] = "#define MODE_LIGHT_ONLY\n";
+ actions.render_mode_defines["world_vertex_coords"] = "#define USE_WORLD_VERTEX_COORDS\n";
actions.custom_samplers["TEXTURE"] = "texture_sampler";
actions.custom_samplers["NORMAL_TEXTURE"] = "texture_sampler";
@@ -2555,18 +2629,18 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() {
{ // default index buffer
Vector<uint8_t> pv;
- pv.resize(6 * 4);
+ pv.resize(6 * 2);
{
uint8_t *w = pv.ptrw();
- int *p32 = (int *)w;
- p32[0] = 0;
- p32[1] = 1;
- p32[2] = 2;
- p32[3] = 0;
- p32[4] = 2;
- p32[5] = 3;
+ uint16_t *p16 = (uint16_t *)w;
+ p16[0] = 0;
+ p16[1] = 1;
+ p16[2] = 2;
+ p16[3] = 0;
+ p16[4] = 2;
+ p16[5] = 3;
}
- shader.quad_index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, pv);
+ shader.quad_index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT16, pv);
shader.quad_index_array = RD::get_singleton()->index_array_create(shader.quad_index_buffer, 0, 6);
}
@@ -2671,7 +2745,7 @@ void fragment() {
bool RendererCanvasRenderRD::free(RID p_rid) {
if (canvas_light_owner.owns(p_rid)) {
CanvasLight *cl = canvas_light_owner.get_or_null(p_rid);
- ERR_FAIL_COND_V(!cl, false);
+ ERR_FAIL_NULL_V(cl, false);
light_set_use_shadow(p_rid, false);
canvas_light_owner.free(p_rid);
} else if (occluder_polygon_owner.owns(p_rid)) {
@@ -2709,6 +2783,12 @@ void RendererCanvasRenderRD::set_shadow_texture_size(int p_size) {
}
}
+void RendererCanvasRenderRD::set_debug_redraw(bool p_enabled, double p_time, const Color &p_color) {
+ debug_redraw = p_enabled;
+ debug_redraw_time = p_time;
+ debug_redraw_color = p_color;
+}
+
RendererCanvasRenderRD::~RendererCanvasRenderRD() {
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
//canvas state
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
index 1116bed6e4..7dbcd903e6 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
@@ -75,6 +75,8 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
FLAGS_CLIP_RECT_UV = (1 << 9),
FLAGS_TRANSPOSE_RECT = (1 << 10),
+ FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR = (1 << 11),
+
FLAGS_NINEPACH_DRAW_CENTER = (1 << 12),
FLAGS_USING_PARTICLES = (1 << 13),
@@ -195,6 +197,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
struct CanvasMaterialData : public RendererRD::MaterialStorage::MaterialData {
CanvasShaderData *shader_data = nullptr;
RID uniform_set;
+ RID uniform_set_srgb;
virtual void set_render_priority(int p_priority) {}
virtual void set_next_pass(RID p_pass) {}
@@ -415,7 +418,11 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
RID _create_base_uniform_set(RID p_to_render_target, bool p_backbuffer);
- inline void _bind_canvas_texture(RD::DrawListID p_draw_list, RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID &r_last_texture, PushConstant &push_constant, Size2 &r_texpixel_size); //recursive, so regular inline used instead.
+ bool debug_redraw = false;
+ Color debug_redraw_color;
+ double debug_redraw_time = 1.0;
+
+ inline void _bind_canvas_texture(RD::DrawListID p_draw_list, RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID &r_last_texture, PushConstant &push_constant, Size2 &r_texpixel_size, bool p_texture_is_data = false); //recursive, so regular inline used instead.
void _render_item(RenderingDevice::DrawListID p_draw_list, RID p_render_target, const Item *p_item, RenderingDevice::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, PipelineVariants *p_pipeline_variants, bool &r_sdf_used);
void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool &r_sdf_used, bool p_to_backbuffer = false);
@@ -447,6 +454,8 @@ public:
virtual void set_shadow_texture_size(int p_size);
+ void set_debug_redraw(bool p_enabled, double p_time, const Color &p_color);
+
void set_time(double p_time);
void update();
bool free(RID p_rid);
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
index 870da3c321..b9bda9329e 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
@@ -81,6 +81,7 @@ void RendererCompositorRD::blit_render_targets_to_screen(DisplayServer::WindowID
blit.push_constant.k2 = p_render_targets[i].lens_distortion.k2;
blit.push_constant.upscale = p_render_targets[i].lens_distortion.upscale;
blit.push_constant.aspect_ratio = p_render_targets[i].lens_distortion.aspect_ratio;
+ blit.push_constant.convert_to_srgb = texture_storage->render_target_is_using_hdr(p_render_targets[i].render_target);
RD::get_singleton()->draw_list_set_push_constant(draw_list, &blit.push_constant, sizeof(BlitPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, true);
@@ -102,8 +103,9 @@ void RendererCompositorRD::begin_frame(double frame_step) {
}
void RendererCompositorRD::end_frame(bool p_swap_buffers) {
- // TODO: Likely pass a bool to swap buffers to avoid display?
- RD::get_singleton()->swap_buffers();
+ if (p_swap_buffers) {
+ RD::get_singleton()->swap_buffers();
+ }
}
void RendererCompositorRD::initialize() {
@@ -125,18 +127,18 @@ void RendererCompositorRD::initialize() {
//create index array for copy shader
Vector<uint8_t> pv;
- pv.resize(6 * 4);
+ pv.resize(6 * 2);
{
uint8_t *w = pv.ptrw();
- int *p32 = (int *)w;
- p32[0] = 0;
- p32[1] = 1;
- p32[2] = 2;
- p32[3] = 0;
- p32[4] = 2;
- p32[5] = 3;
+ uint16_t *p16 = (uint16_t *)w;
+ p16[0] = 0;
+ p16[1] = 1;
+ p16[2] = 2;
+ p16[3] = 0;
+ p16[4] = 2;
+ p16[5] = 3;
}
- blit.index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, pv);
+ blit.index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT16, pv);
blit.array = RD::get_singleton()->index_array_create(blit.index_buffer, 0, 6);
blit.sampler = RD::get_singleton()->sampler_create(RD::SamplerState());
@@ -171,7 +173,7 @@ void RendererCompositorRD::set_boot_image(const Ref<Image> &p_image, const Color
RID texture = texture_storage->texture_allocate();
texture_storage->texture_2d_initialize(texture, p_image);
- RID rd_texture = texture_storage->texture_get_rd_texture(texture);
+ RID rd_texture = texture_storage->texture_get_rd_texture(texture, false);
RD::SamplerState sampler_state;
sampler_state.min_filter = p_use_filter ? RD::SAMPLER_FILTER_LINEAR : RD::SAMPLER_FILTER_NEAREST;
@@ -237,6 +239,7 @@ void RendererCompositorRD::set_boot_image(const Ref<Image> &p_image, const Color
blit.push_constant.k2 = 0;
blit.push_constant.upscale = 1.0;
blit.push_constant.aspect_ratio = 1.0;
+ blit.push_constant.convert_to_srgb = false;
RD::get_singleton()->draw_list_set_push_constant(draw_list, &blit.push_constant, sizeof(BlitPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, true);
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h
index 14fb4e6340..705fb9e8e5 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.h
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h
@@ -80,7 +80,7 @@ protected:
float upscale;
float aspect_ratio;
uint32_t layer;
- uint32_t pad1;
+ uint32_t convert_to_srgb;
};
struct Blit {
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index 646bdc5436..07d56eae0c 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -340,14 +340,16 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
// Glow, auto exposure and DoF (if enabled).
- Size2i internal_size = rb->get_internal_size();
Size2i target_size = rb->get_target_size();
-
bool can_use_effects = target_size.x >= 8 && target_size.y >= 8; // FIXME I think this should check internal size, we do all our post processing at this size...
bool can_use_storage = _render_buffers_can_be_storage();
+ bool use_fsr = fsr && can_use_effects && rb->get_scaling_3d_mode() == RS::VIEWPORT_SCALING_3D_MODE_FSR;
+ bool use_upscaled_texture = rb->has_upscaled_texture() && rb->get_scaling_3d_mode() == RS::VIEWPORT_SCALING_3D_MODE_FSR2;
+
RID render_target = rb->get_render_target();
- RID internal_texture = rb->get_internal_texture();
+ RID color_texture = use_upscaled_texture ? rb->get_upscaled_texture() : rb->get_internal_texture();
+ Size2i color_size = use_upscaled_texture ? target_size : rb->get_internal_size();
if (can_use_effects && RSG::camera_attributes->camera_attributes_uses_dof(p_render_data->camera_attributes)) {
RENDER_TIMESTAMP("Depth of Field");
@@ -358,17 +360,17 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
RendererRD::BokehDOF::BokehBuffers buffers;
// Textures we use
- buffers.base_texture_size = rb->get_internal_size();
+ buffers.base_texture_size = color_size;
buffers.secondary_texture = rb->get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0, 0, 0);
buffers.half_texture[0] = rb->get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_BLUR_1, 0, 0);
buffers.half_texture[1] = rb->get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0, 0, 1);
if (can_use_storage) {
for (uint32_t i = 0; i < rb->get_view_count(); i++) {
- buffers.base_texture = rb->get_internal_texture(i);
+ buffers.base_texture = use_upscaled_texture ? rb->get_upscaled_texture(i) : rb->get_internal_texture(i);
buffers.depth_texture = rb->get_depth_texture(i);
- // In stereo p_render_data->z_near and p_render_data->z_far can be offset for our combined frustrum
+ // In stereo p_render_data->z_near and p_render_data->z_far can be offset for our combined frustum.
float z_near = p_render_data->scene_data->view_projection[i].get_z_near();
float z_far = p_render_data->scene_data->view_projection[i].get_z_far();
bokeh_dof->bokeh_dof_compute(buffers, p_render_data->camera_attributes, z_near, z_far, p_render_data->scene_data->cam_orthogonal);
@@ -387,11 +389,11 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
buffers.base_weight_fb = rb->weight_buffers[0].fb;
for (uint32_t i = 0; i < rb->get_view_count(); i++) {
- buffers.base_texture = rb->get_internal_texture(i);
+ buffers.base_texture = use_upscaled_texture ? rb->get_upscaled_texture(i) : rb->get_internal_texture(i);
buffers.depth_texture = rb->get_depth_texture(i);
buffers.base_fb = FramebufferCacheRD::get_singleton()->get_cache(buffers.base_texture); // TODO move this into bokeh_dof_raster, we can do this internally
- // In stereo p_render_data->z_near and p_render_data->z_far can be offset for our combined frustrum
+ // In stereo p_render_data->z_near and p_render_data->z_far can be offset for our combined frustum.
float z_near = p_render_data->scene_data->view_projection[i].get_z_near();
float z_far = p_render_data->scene_data->view_projection[i].get_z_far();
bokeh_dof->bokeh_dof_raster(buffers, p_render_data->camera_attributes, z_near, z_far, p_render_data->scene_data->cam_orthogonal);
@@ -416,7 +418,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
double step = RSG::camera_attributes->camera_attributes_get_auto_exposure_adjust_speed(p_render_data->camera_attributes) * time_step;
float auto_exposure_min_sensitivity = RSG::camera_attributes->camera_attributes_get_auto_exposure_min_sensitivity(p_render_data->camera_attributes);
float auto_exposure_max_sensitivity = RSG::camera_attributes->camera_attributes_get_auto_exposure_max_sensitivity(p_render_data->camera_attributes);
- luminance->luminance_reduction(internal_texture, internal_size, luminance_buffers, auto_exposure_min_sensitivity, auto_exposure_max_sensitivity, step, set_immediate);
+ luminance->luminance_reduction(rb->get_internal_texture(), rb->get_internal_size(), luminance_buffers, auto_exposure_min_sensitivity, auto_exposure_max_sensitivity, step, set_immediate);
// Swap final reduce with prev luminance.
@@ -525,7 +527,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
}
tonemap.use_debanding = rb->get_use_debanding();
- tonemap.texture_size = Vector2i(rb->get_internal_size().x, rb->get_internal_size().y);
+ tonemap.texture_size = Vector2i(color_size.x, color_size.y);
if (p_render_data->environment.is_valid()) {
tonemap.tonemap_mode = environment_get_tone_mapper(p_render_data->environment);
@@ -552,8 +554,11 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
tonemap.luminance_multiplier = _render_buffers_get_luminance_multiplier();
tonemap.view_count = rb->get_view_count();
+ tonemap.convert_to_srgb = !texture_storage->render_target_is_using_hdr(render_target);
+
RID dest_fb;
- if (fsr && can_use_effects && rb->get_scaling_3d_mode() == RS::VIEWPORT_SCALING_3D_MODE_FSR) {
+ bool use_intermediate_fb = use_fsr;
+ if (use_intermediate_fb) {
// If we use FSR to upscale we need to write our result into an intermediate buffer.
// Note that this is cached so we only create the texture the first time.
RID dest_texture = rb->create_texture(SNAME("Tonemapper"), SNAME("destination"), _render_buffers_get_color_format(), RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT);
@@ -565,12 +570,12 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
dest_fb = texture_storage->render_target_get_rd_framebuffer(render_target);
}
- tone_mapper->tonemapper(internal_texture, dest_fb, tonemap);
+ tone_mapper->tonemapper(color_texture, dest_fb, tonemap);
RD::get_singleton()->draw_command_end_label();
}
- if (fsr && can_use_effects && rb->get_scaling_3d_mode() == RS::VIEWPORT_SCALING_3D_MODE_FSR) {
+ if (use_fsr) {
RD::get_singleton()->draw_command_begin_label("FSR 1.0 Upscale");
for (uint32_t v = 0; v < rb->get_view_count(); v++) {
@@ -647,6 +652,8 @@ void RendererSceneRenderRD::_post_process_subpass(RID p_source_texture, RID p_fr
tonemap.luminance_multiplier = _render_buffers_get_luminance_multiplier();
tonemap.view_count = rb->get_view_count();
+ tonemap.convert_to_srgb = !texture_storage->render_target_is_using_hdr(rb->get_render_target());
+
tone_mapper->tonemapper(draw_list, p_source_texture, RD::get_singleton()->framebuffer_get_format(p_framebuffer), tonemap);
RD::get_singleton()->draw_command_end_label();
@@ -697,7 +704,7 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(const RenderDataRD *p_ren
copy_effects->copy_to_fb_rect(shadow_atlas_texture, dest_fb, Rect2i(Vector2(), size), false, true);
- // Visualise our view frustum to show coverage.
+ // Visualize our view frustum to show coverage.
for (int i = 0; i < p_render_data->render_shadow_count; i++) {
RID light = p_render_data->render_shadows[i].light;
RID base = light_storage->light_instance_get_base_light(light);
@@ -728,6 +735,11 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(const RenderDataRD *p_ren
}
}
+ if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_INTERNAL_BUFFER) {
+ Size2 rtsize = texture_storage->render_target_get_size(render_target);
+ copy_effects->copy_to_fb_rect(rb->get_internal_texture(), texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false);
+ }
+
if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER && _render_buffers_get_normal_texture(rb).is_valid()) {
Size2 rtsize = texture_storage->render_target_get_size(render_target);
copy_effects->copy_to_fb_rect(_render_buffers_get_normal_texture(rb), texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false);
@@ -741,8 +753,12 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(const RenderDataRD *p_ren
}
if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS && _render_buffers_get_velocity_texture(rb).is_valid()) {
- Size2i rtsize = texture_storage->render_target_get_size(render_target);
- copy_effects->copy_to_fb_rect(_render_buffers_get_velocity_texture(rb), texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false);
+ RID velocity = _render_buffers_get_velocity_texture(rb);
+ RID depth = rb->get_depth_texture();
+ RID dest_fb = texture_storage->render_target_get_rd_framebuffer(render_target);
+ Size2i resolution = rb->get_internal_size();
+
+ debug_effects->draw_motion_vectors(velocity, depth, dest_fb, p_render_data->scene_data->cam_projection, p_render_data->scene_data->cam_transform, p_render_data->scene_data->prev_cam_projection, p_render_data->scene_data->prev_cam_transform, resolution);
}
}
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
index 4bce6a172e..211d191039 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
@@ -280,7 +280,6 @@ public:
RID render_buffers_get_default_voxel_gi_buffer();
virtual void base_uniforms_changed() = 0;
- virtual void update_uniform_sets(){};
virtual void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RenderingMethod::RenderInfo *r_render_info = nullptr) override;
diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp
index 46ae2d9551..10e37c7da8 100644
--- a/servers/rendering/renderer_rd/shader_rd.cpp
+++ b/servers/rendering/renderer_rd/shader_rd.cpp
@@ -314,7 +314,7 @@ void ShaderRD::_compile_variant(uint32_t p_variant, const CompileData *p_data) {
RS::ShaderNativeSourceCode ShaderRD::version_get_native_source_code(RID p_version) {
Version *version = version_owner.get_or_null(p_version);
RS::ShaderNativeSourceCode source_code;
- ERR_FAIL_COND_V(!version, source_code);
+ ERR_FAIL_NULL_V(version, source_code);
source_code.versions.resize(variant_defines.size());
@@ -567,7 +567,7 @@ void ShaderRD::version_set_code(RID p_version, const HashMap<String, String> &p_
ERR_FAIL_COND(is_compute);
Version *version = version_owner.get_or_null(p_version);
- ERR_FAIL_COND(!version);
+ ERR_FAIL_NULL(version);
version->vertex_globals = p_vertex_globals.utf8();
version->fragment_globals = p_fragment_globals.utf8();
version->uniforms = p_uniforms.utf8();
@@ -599,7 +599,7 @@ void ShaderRD::version_set_compute_code(RID p_version, const HashMap<String, Str
ERR_FAIL_COND(!is_compute);
Version *version = version_owner.get_or_null(p_version);
- ERR_FAIL_COND(!version);
+ ERR_FAIL_NULL(version);
version->compute_globals = p_compute_globals.utf8();
version->uniforms = p_uniforms.utf8();
@@ -630,7 +630,7 @@ void ShaderRD::version_set_compute_code(RID p_version, const HashMap<String, Str
bool ShaderRD::version_is_valid(RID p_version) {
Version *version = version_owner.get_or_null(p_version);
- ERR_FAIL_COND_V(!version, false);
+ ERR_FAIL_NULL_V(version, false);
if (version->dirty) {
_initialize_version(version);
diff --git a/servers/rendering/renderer_rd/shader_rd.h b/servers/rendering/renderer_rd/shader_rd.h
index 01eb99f7a2..9ce510386f 100644
--- a/servers/rendering/renderer_rd/shader_rd.h
+++ b/servers/rendering/renderer_rd/shader_rd.h
@@ -162,7 +162,7 @@ public:
ERR_FAIL_COND_V(!variants_enabled[p_variant], RID());
Version *version = version_owner.get_or_null(p_version);
- ERR_FAIL_COND_V(!version, RID());
+ ERR_FAIL_NULL_V(version, RID());
if (version->dirty) {
_initialize_version(version);
diff --git a/servers/rendering/renderer_rd/shaders/blit.glsl b/servers/rendering/renderer_rd/shaders/blit.glsl
index 14f190a49f..d451647bec 100644
--- a/servers/rendering/renderer_rd/shaders/blit.glsl
+++ b/servers/rendering/renderer_rd/shaders/blit.glsl
@@ -45,7 +45,7 @@ layout(push_constant, std140) uniform Pos {
float upscale;
float aspect_ratio;
uint layer;
- uint pad1;
+ bool convert_to_srgb;
}
data;
@@ -59,6 +59,13 @@ layout(binding = 0) uniform sampler2DArray src_rt;
layout(binding = 0) uniform sampler2D src_rt;
#endif
+vec3 linear_to_srgb(vec3 color) {
+ // If going to srgb, clamp from 0 to 1.
+ color = clamp(color, vec3(0.0), vec3(1.0));
+ const vec3 a = vec3(0.055f);
+ return mix((vec3(1.0f) + a) * pow(color.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * color.rgb, lessThan(color.rgb, vec3(0.0031308f)));
+}
+
void main() {
#ifdef APPLY_LENS_DISTORTION
vec2 coords = uv * 2.0 - 1.0;
@@ -94,4 +101,8 @@ void main() {
#else
color = texture(src_rt, uv);
#endif
+
+ if (data.convert_to_srgb) {
+ color.rgb = linear_to_srgb(color.rgb); // Regular linear -> SRGB conversion.
+ }
}
diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl
index 6270450c15..7a13ac7207 100644
--- a/servers/rendering/renderer_rd/shaders/canvas.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas.glsl
@@ -36,6 +36,12 @@ layout(set = 1, binding = 0, std140) uniform MaterialUniforms{
#GLOBALS
+#ifdef USE_ATTRIBUTES
+vec3 srgb_to_linear(vec3 color) {
+ return mix(pow((color.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), color.rgb * (1.0 / 12.92), lessThan(color.rgb, vec3(0.04045)));
+}
+#endif
+
void main() {
vec4 instance_custom = vec4(0.0);
#ifdef USE_PRIMITIVE
@@ -65,7 +71,11 @@ void main() {
#elif defined(USE_ATTRIBUTES)
vec2 vertex = vertex_attrib;
- vec4 color = color_attrib * draw_data.modulation;
+ vec4 color = color_attrib;
+ if (bool(draw_data.flags & FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR)) {
+ color.rgb = srgb_to_linear(color.rgb);
+ }
+ color *= draw_data.modulation;
vec2 uv = uv_attrib;
uvec4 bones = bone_attrib;
@@ -170,6 +180,10 @@ void main() {
#ifdef USE_POINT_SIZE
float point_size = 1.0;
#endif
+
+#ifdef USE_WORLD_VERTEX_COORDS
+ vertex = (model_matrix * vec4(vertex, 0.0, 1.0)).xy;
+#endif
{
#CODE : VERTEX
}
@@ -178,7 +192,7 @@ void main() {
pixel_size_interp = abs(draw_data.dst_rect.zw) * vertex_base;
#endif
-#if !defined(SKIP_TRANSFORM_USED)
+#if !defined(SKIP_TRANSFORM_USED) && !defined(USE_WORLD_VERTEX_COORDS)
vertex = (model_matrix * vec4(vertex, 0.0, 1.0)).xy;
#endif
@@ -563,9 +577,6 @@ void main() {
}
vec4 base_color = color;
- if (bool(draw_data.flags & FLAGS_USING_LIGHT_MASK)) {
- color = vec4(0.0); //invisible by default due to using light mask
- }
#ifdef MODE_LIGHT_ONLY
float light_only_alpha = 0.0;
diff --git a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
index 2dd5abb75f..7ac7cf9c07 100644
--- a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
@@ -12,7 +12,7 @@
#define FLAGS_CLIP_RECT_UV (1 << 9)
#define FLAGS_TRANSPOSE_RECT (1 << 10)
-#define FLAGS_USING_LIGHT_MASK (1 << 11)
+#define FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR (1 << 11)
#define FLAGS_NINEPACH_DRAW_CENTER (1 << 12)
#define FLAGS_USING_PARTICLES (1 << 13)
diff --git a/servers/rendering/renderer_rd/shaders/effects/SCsub b/servers/rendering/renderer_rd/shaders/effects/SCsub
index f06a2d86e2..810f781340 100644
--- a/servers/rendering/renderer_rd/shaders/effects/SCsub
+++ b/servers/rendering/renderer_rd/shaders/effects/SCsub
@@ -15,3 +15,5 @@ if "RD_GLSL" in env["BUILDERS"]:
# compile shaders
for glsl_file in glsl_files:
env.RD_GLSL(glsl_file)
+
+SConscript("fsr2/SCsub")
diff --git a/servers/rendering/renderer_rd/shaders/effects/blur_raster.glsl b/servers/rendering/renderer_rd/shaders/effects/blur_raster.glsl
index 31aabbe9d2..91a3b582b9 100644
--- a/servers/rendering/renderer_rd/shaders/effects/blur_raster.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/blur_raster.glsl
@@ -11,10 +11,9 @@ layout(location = 0) out vec2 uv_interp;
/* clang-format on */
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 = base_arr[gl_VertexIndex];
-
- gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
+ vec2 base_arr[3] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0));
+ gl_Position = vec4(base_arr[gl_VertexIndex], 0.0, 1.0);
+ uv_interp = clamp(gl_Position.xy, vec2(0.0, 0.0), vec2(1.0, 1.0)) * 2.0; // saturate(x) * 2.0
}
/* clang-format off */
diff --git a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl
index 1b487835d2..947aa793d9 100644
--- a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl
@@ -11,10 +11,9 @@ layout(location = 0) out vec2 uv_interp;
/* clang-format on */
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 = base_arr[gl_VertexIndex];
-
- gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
+ vec2 base_arr[3] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0));
+ gl_Position = vec4(base_arr[gl_VertexIndex], 0.0, 1.0);
+ uv_interp = clamp(gl_Position.xy, vec2(0.0, 0.0), vec2(1.0, 1.0)) * 2.0; // saturate(x) * 2.0
}
/* clang-format off */
diff --git a/servers/rendering/renderer_rd/shaders/effects/copy.glsl b/servers/rendering/renderer_rd/shaders/effects/copy.glsl
index 3a82861057..debf6b7367 100644
--- a/servers/rendering/renderer_rd/shaders/effects/copy.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/copy.glsl
@@ -57,7 +57,7 @@ layout(r32f, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffe
#elif defined(DST_IMAGE_8BIT)
layout(rgba8, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer;
#else
-layout(rgba32f, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer;
+layout(rgba16f, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer;
#endif
#ifdef MODE_GAUSSIAN_BLUR
@@ -103,12 +103,13 @@ void main() {
#ifdef MODE_GLOW
if (bool(params.flags & FLAG_GLOW_FIRST_PASS)) {
// Tonemap initial samples to reduce weight of fireflies: https://graphicrants.blogspot.com/2013/12/tone-mapping.html
- local_cache[dest_index] /= 1.0 + dot(local_cache[dest_index].rgb, vec3(0.299, 0.587, 0.114));
- local_cache[dest_index + 1] /= 1.0 + dot(local_cache[dest_index + 1].rgb, vec3(0.299, 0.587, 0.114));
- local_cache[dest_index + 16] /= 1.0 + dot(local_cache[dest_index + 16].rgb, vec3(0.299, 0.587, 0.114));
- local_cache[dest_index + 16 + 1] /= 1.0 + dot(local_cache[dest_index + 16 + 1].rgb, vec3(0.299, 0.587, 0.114));
+ vec3 tonemap_col = vec3(0.299, 0.587, 0.114) / max(params.glow_luminance_cap, 6.0);
+ local_cache[dest_index] /= 1.0 + dot(local_cache[dest_index].rgb, tonemap_col);
+ local_cache[dest_index + 1] /= 1.0 + dot(local_cache[dest_index + 1].rgb, tonemap_col);
+ local_cache[dest_index + 16] /= 1.0 + dot(local_cache[dest_index + 16].rgb, tonemap_col);
+ local_cache[dest_index + 16 + 1] /= 1.0 + dot(local_cache[dest_index + 16 + 1].rgb, tonemap_col);
}
- const float kernel[4] = { 0.174938, 0.165569, 0.140367, 0.106595 };
+ const float kernel[5] = { 0.2024, 0.1790, 0.1240, 0.0672, 0.0285 };
#else
// Simpler blur uses SIGMA2 for the gaussian kernel for a stronger effect.
const float kernel[4] = { 0.214607, 0.189879, 0.131514, 0.071303 };
@@ -126,6 +127,10 @@ void main() {
color_top += local_cache[read_index - 1] * kernel[1];
color_top += local_cache[read_index - 2] * kernel[2];
color_top += local_cache[read_index - 3] * kernel[3];
+#ifdef MODE_GLOW
+ color_top += local_cache[read_index + 4] * kernel[4];
+ color_top += local_cache[read_index - 4] * kernel[4];
+#endif // MODE_GLOW
vec4 color_bottom = vec4(0.0);
color_bottom += local_cache[read_index + 16] * kernel[0];
@@ -135,6 +140,10 @@ void main() {
color_bottom += local_cache[read_index - 1 + 16] * kernel[1];
color_bottom += local_cache[read_index - 2 + 16] * kernel[2];
color_bottom += local_cache[read_index - 3 + 16] * kernel[3];
+#ifdef MODE_GLOW
+ color_bottom += local_cache[read_index + 4 + 16] * kernel[4];
+ color_bottom += local_cache[read_index - 4 + 16] * kernel[4];
+#endif // MODE_GLOW
// rotate samples to take advantage of cache coherency
uint write_index = gl_LocalInvocationID.y * 2 + gl_LocalInvocationID.x * 16;
@@ -161,11 +170,15 @@ void main() {
color += temp_cache[index - 1] * kernel[1];
color += temp_cache[index - 2] * kernel[2];
color += temp_cache[index - 3] * kernel[3];
+#ifdef MODE_GLOW
+ color += temp_cache[index + 4] * kernel[4];
+ color += temp_cache[index - 4] * kernel[4];
+#endif // MODE_GLOW
#ifdef MODE_GLOW
if (bool(params.flags & FLAG_GLOW_FIRST_PASS)) {
// Undo tonemap to restore range: https://graphicrants.blogspot.com/2013/12/tone-mapping.html
- color /= 1.0 - dot(color.rgb, vec3(0.299, 0.587, 0.114));
+ color /= 1.0 - dot(color.rgb, vec3(0.299, 0.587, 0.114) / max(params.glow_luminance_cap, 6.0));
}
color *= params.glow_strength;
diff --git a/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_raster.glsl b/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_raster.glsl
index b8c64d09f4..7b3c2f1c3b 100644
--- a/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_raster.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_raster.glsl
@@ -31,9 +31,9 @@ layout(location = 0) out vec2 uv_interp;
/* clang-format on */
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 = base_arr[gl_VertexIndex] * float(params.face_size);
- gl_Position = vec4(base_arr[gl_VertexIndex] * 2.0 - 1.0, 0.0, 1.0);
+ vec2 base_arr[3] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0));
+ gl_Position = vec4(base_arr[gl_VertexIndex], 0.0, 1.0);
+ uv_interp = clamp(gl_Position.xy, vec2(0.0, 0.0), vec2(1.0, 1.0)) * 2.0; // saturate(x) * 2.0
}
/* clang-format off */
diff --git a/servers/rendering/renderer_rd/shaders/effects/cubemap_filter_raster.glsl b/servers/rendering/renderer_rd/shaders/effects/cubemap_filter_raster.glsl
index 0990dc7c2f..961ec96f00 100644
--- a/servers/rendering/renderer_rd/shaders/effects/cubemap_filter_raster.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/cubemap_filter_raster.glsl
@@ -35,9 +35,9 @@ layout(location = 0) out vec2 uv_interp;
/* clang-format on */
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 = base_arr[gl_VertexIndex];
- gl_Position = vec4(base_arr[gl_VertexIndex] * 2.0 - 1.0, 0.0, 1.0);
+ vec2 base_arr[3] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0));
+ gl_Position = vec4(base_arr[gl_VertexIndex], 0.0, 1.0);
+ uv_interp = clamp(gl_Position.xy, vec2(0.0, 0.0), vec2(1.0, 1.0)) * 2.0; // saturate(x) * 2.0
}
/* clang-format off */
diff --git a/servers/rendering/renderer_rd/shaders/effects/cubemap_roughness_raster.glsl b/servers/rendering/renderer_rd/shaders/effects/cubemap_roughness_raster.glsl
index c29accd8a7..05a20c459b 100644
--- a/servers/rendering/renderer_rd/shaders/effects/cubemap_roughness_raster.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/cubemap_roughness_raster.glsl
@@ -11,9 +11,9 @@ layout(location = 0) out vec2 uv_interp;
/* clang-format on */
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 = base_arr[gl_VertexIndex];
- gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
+ vec2 base_arr[3] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0));
+ gl_Position = vec4(base_arr[gl_VertexIndex], 0.0, 1.0);
+ uv_interp = clamp(gl_Position.xy, vec2(0.0, 0.0), vec2(1.0, 1.0)) * 2.0; // saturate(x) * 2.0
}
/* clang-format off */
diff --git a/servers/rendering/renderer_rd/shaders/effects/fsr2/SCsub b/servers/rendering/renderer_rd/shaders/effects/fsr2/SCsub
new file mode 100644
index 0000000000..f06a2d86e2
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/effects/fsr2/SCsub
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+
+Import("env")
+
+if "RD_GLSL" in env["BUILDERS"]:
+ # find all include files
+ gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + [str(f) for f in Glob("../*_inc.glsl")]
+
+ # find all shader code(all glsl files excluding our include files)
+ glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files]
+
+ # make sure we recompile shaders if include files change
+ env.Depends([f + ".gen.h" for f in glsl_files], gl_include_files + ["#glsl_builders.py"])
+
+ # compile shaders
+ for glsl_file in glsl_files:
+ env.RD_GLSL(glsl_file)
diff --git a/servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_accumulate_pass.glsl b/servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_accumulate_pass.glsl
new file mode 100644
index 0000000000..67fce9a342
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_accumulate_pass.glsl
@@ -0,0 +1,8 @@
+#[compute]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "../motion_vector_inc.glsl"
+#include "thirdparty/amd-fsr2/shaders/ffx_fsr2_accumulate_pass.glsl"
diff --git a/servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_autogen_reactive_pass.glsl b/servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_autogen_reactive_pass.glsl
new file mode 100644
index 0000000000..d362958aa6
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_autogen_reactive_pass.glsl
@@ -0,0 +1,8 @@
+#[compute]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "../motion_vector_inc.glsl"
+#include "thirdparty/amd-fsr2/shaders/ffx_fsr2_autogen_reactive_pass.glsl"
diff --git a/servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_compute_luminance_pyramid_pass.glsl b/servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_compute_luminance_pyramid_pass.glsl
new file mode 100644
index 0000000000..37504c2e53
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_compute_luminance_pyramid_pass.glsl
@@ -0,0 +1,7 @@
+#[compute]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "thirdparty/amd-fsr2/shaders/ffx_fsr2_compute_luminance_pyramid_pass.glsl"
diff --git a/servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_depth_clip_pass.glsl b/servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_depth_clip_pass.glsl
new file mode 100644
index 0000000000..0ee08e4c76
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_depth_clip_pass.glsl
@@ -0,0 +1,8 @@
+#[compute]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "../motion_vector_inc.glsl"
+#include "thirdparty/amd-fsr2/shaders/ffx_fsr2_depth_clip_pass.glsl"
diff --git a/servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_lock_pass.glsl b/servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_lock_pass.glsl
new file mode 100644
index 0000000000..8c8430d4b1
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_lock_pass.glsl
@@ -0,0 +1,7 @@
+#[compute]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "thirdparty/amd-fsr2/shaders/ffx_fsr2_lock_pass.glsl"
diff --git a/servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_rcas_pass.glsl b/servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_rcas_pass.glsl
new file mode 100644
index 0000000000..4120cfe644
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_rcas_pass.glsl
@@ -0,0 +1,7 @@
+#[compute]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "thirdparty/amd-fsr2/shaders/ffx_fsr2_rcas_pass.glsl"
diff --git a/servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_reconstruct_previous_depth_pass.glsl b/servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_reconstruct_previous_depth_pass.glsl
new file mode 100644
index 0000000000..f31abec215
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_reconstruct_previous_depth_pass.glsl
@@ -0,0 +1,8 @@
+#[compute]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "../motion_vector_inc.glsl"
+#include "thirdparty/amd-fsr2/shaders/ffx_fsr2_reconstruct_previous_depth_pass.glsl"
diff --git a/servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_tcr_autogen_pass.glsl b/servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_tcr_autogen_pass.glsl
new file mode 100644
index 0000000000..818374e43c
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/effects/fsr2/fsr2_tcr_autogen_pass.glsl
@@ -0,0 +1,8 @@
+#[compute]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "../motion_vector_inc.glsl"
+#include "thirdparty/amd-fsr2/shaders/ffx_fsr2_tcr_autogen_pass.glsl"
diff --git a/servers/rendering/renderer_rd/shaders/effects/luminance_reduce_raster.glsl b/servers/rendering/renderer_rd/shaders/effects/luminance_reduce_raster.glsl
index 29ebd74a90..05a84db6b6 100644
--- a/servers/rendering/renderer_rd/shaders/effects/luminance_reduce_raster.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/luminance_reduce_raster.glsl
@@ -11,10 +11,9 @@ layout(location = 0) out vec2 uv_interp;
/* clang-format on */
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 = base_arr[gl_VertexIndex];
-
- gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
+ vec2 base_arr[3] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0));
+ gl_Position = vec4(base_arr[gl_VertexIndex], 0.0, 1.0);
+ uv_interp = clamp(gl_Position.xy, vec2(0.0, 0.0), vec2(1.0, 1.0)) * 2.0; // saturate(x) * 2.0
}
/* clang-format off */
diff --git a/servers/rendering/renderer_rd/shaders/effects/motion_vector_inc.glsl b/servers/rendering/renderer_rd/shaders/effects/motion_vector_inc.glsl
new file mode 100644
index 0000000000..cbf202653e
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/effects/motion_vector_inc.glsl
@@ -0,0 +1,6 @@
+vec2 derive_motion_vector(vec2 uv, float depth, mat4 reprojection_matrix) {
+ vec4 previous_pos_ndc = reprojection_matrix * vec4(uv * 2.0f - 1.0f, depth * 2.0f - 1.0f, 1.0f);
+ return 0.5f + (previous_pos_ndc.xy / previous_pos_ndc.w) * 0.5f - uv;
+}
+
+#define FFX_FSR2_OPTION_GODOT_DERIVE_INVALID_MOTION_VECTORS_FUNCTION(i, j, k) derive_motion_vector(i, j, k)
diff --git a/servers/rendering/renderer_rd/shaders/effects/motion_vectors.glsl b/servers/rendering/renderer_rd/shaders/effects/motion_vectors.glsl
new file mode 100644
index 0000000000..d02ffe0b4f
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/effects/motion_vectors.glsl
@@ -0,0 +1,97 @@
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+layout(location = 0) out vec2 uv_interp;
+
+void main() {
+ vec2 base_arr[3] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0));
+ gl_Position = vec4(base_arr[gl_VertexIndex], 0.0, 1.0);
+ uv_interp = clamp(gl_Position.xy, vec2(0.0, 0.0), vec2(1.0, 1.0)) * 2.0; // saturate(x) * 2.0
+}
+
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "motion_vector_inc.glsl"
+
+layout(location = 0) in vec2 uv_interp;
+
+layout(set = 0, binding = 0) uniform sampler2D source_velocity;
+layout(set = 0, binding = 1) uniform sampler2D source_depth;
+
+layout(location = 0) out vec4 frag_color;
+
+layout(push_constant, std430) uniform Params {
+ highp mat4 reprojection_matrix;
+ vec2 resolution;
+ bool force_derive_from_depth;
+}
+params;
+
+// Based on distance to line segment from https://www.shadertoy.com/view/3tdSDj
+
+float line_segment(in vec2 p, in vec2 a, in vec2 b) {
+ vec2 aspect = vec2(params.resolution.x / params.resolution.y, 1.0f);
+ vec2 ba = (b - a) * aspect;
+ vec2 pa = (p - a) * aspect;
+ float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0f, 1.0f);
+ return length(pa - h * ba) * (params.resolution.y / 2.0f);
+}
+
+void main() {
+ // Retrieve motion vector data.
+ float cell_size = 32.0f;
+ float circle_radius = 2.0f;
+ vec3 nan_color = vec3(1.0f, 0.0f, 0.0f);
+ vec3 active_color = vec3(1.0f, 0.8f, 0.1f);
+ vec3 inactive_color = vec3(0.5f, 0.5f, 0.5f);
+ vec2 pos_pixel = uv_interp * params.resolution;
+ vec2 cell_pos_pixel = floor(pos_pixel / cell_size) * cell_size + (cell_size * 0.5f);
+ vec2 cell_pos_uv = cell_pos_pixel / params.resolution;
+ vec2 cell_pos_velocity = textureLod(source_velocity, cell_pos_uv, 0.0f).xy;
+ bool derive_velocity = params.force_derive_from_depth || all(lessThanEqual(cell_pos_velocity, vec2(-1.0f, -1.0f)));
+ if (derive_velocity) {
+ float depth = textureLod(source_depth, cell_pos_uv, 0.0f).x;
+ cell_pos_velocity = derive_motion_vector(cell_pos_uv, depth, params.reprojection_matrix);
+ }
+
+ vec2 cell_pos_previous_uv = cell_pos_uv + cell_pos_velocity;
+
+ // Draw the shapes.
+ float epsilon = 1e-6f;
+ vec2 cell_pos_delta_uv = cell_pos_uv - cell_pos_previous_uv;
+ bool motion_active = length(cell_pos_delta_uv) > epsilon;
+ vec3 color;
+ if (any(isnan(cell_pos_delta_uv))) {
+ color = nan_color;
+ } else if (motion_active) {
+ color = active_color;
+ } else {
+ color = inactive_color;
+ }
+
+ float alpha;
+ if (length(cell_pos_pixel - pos_pixel) <= circle_radius) {
+ // Circle center.
+ alpha = 1.0f;
+ } else if (motion_active) {
+ // Motion vector line.
+ alpha = 1.0f - line_segment(uv_interp, cell_pos_uv, cell_pos_previous_uv);
+ } else {
+ // Ignore pixel.
+ alpha = 0.0f;
+ }
+
+ if (derive_velocity) {
+ color = vec3(1.0f, 1.0f, 1.0f) - color;
+ alpha *= 0.5f;
+ }
+
+ frag_color = vec4(color, alpha);
+}
diff --git a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
index 1e01d94533..fecf70bd01 100644
--- a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
@@ -184,7 +184,7 @@ void main() {
vec4 test_normal_roughness = imageLoad(source_normal_roughness, test_pos);
vec3 test_normal = test_normal_roughness.xyz * 2.0 - 1.0;
test_normal = normalize(test_normal);
- test_normal.y = -test_normal.y; //because this code reads flipped
+ test_normal.y = -test_normal.y; // Because this code reads flipped.
if (dot(ray_dir, test_normal) < 0.001) {
// if depth was surpassed
@@ -203,6 +203,7 @@ void main() {
if (found) {
float margin_blend = 1.0;
+ vec2 final_pos = pos;
vec2 margin = vec2((params.screen_size.x + params.screen_size.y) * 0.05); // make a uniform margin
if (any(bvec4(lessThan(pos, vec2(0.0, 0.0)), greaterThan(pos, params.screen_size)))) {
@@ -219,16 +220,40 @@ void main() {
//margin_blend = 1.0;
}
- vec2 final_pos;
+ // Fade In / Fade Out
float grad = (steps_taken + 1.0) / float(params.num_steps);
float initial_fade = params.curve_fade_in == 0.0 ? 1.0 : pow(clamp(grad, 0.0, 1.0), params.curve_fade_in);
float fade = pow(clamp(1.0 - grad, 0.0, 1.0), params.distance_fade) * initial_fade;
+
+ // Ensure that precision errors do not introduce any fade. Even if it is just slightly below 1.0,
+ // strong specular light can leak through the reflection.
+ if (fade > 0.999) {
+ fade = 1.0;
+ }
+
// This is an ad-hoc term to fade out the SSR as roughness increases. Values used
// are meant to match the visual appearance of a ReflectionProbe.
float roughness_fade = smoothstep(0.4, 0.7, 1.0 - normal_roughness.w);
- final_pos = pos;
- vec4 final_color;
+ // Schlick term.
+ float metallic = texelFetch(source_metallic, ssC << 1, 0).w;
+
+ // F0 is the reflectance of normally incident light (perpendicular to the surface).
+ // Dielectric materials have a widely accepted default value of 0.04. We assume that metals reflect all light, so their F0 is 1.0.
+ float f0 = mix(0.04, 1.0, metallic);
+ float m = clamp(1.0 - dot(normal, -view_dir), 0.0, 1.0);
+ float m2 = m * m;
+ m = m2 * m2 * m; // pow(m,5)
+ float fresnel_term = f0 + (1.0 - f0) * m; // Fresnel Schlick term.
+
+ // The alpha value of final_color controls the blending with specular light in specular_merge.glsl.
+ // Note that the Fresnel term is multiplied with the RGB color instead of being a part of the alpha value.
+ // There is a key difference:
+ // - multiplying a term with RGB darkens the SSR light without introducing/taking away specular light.
+ // - combining a term into the Alpha value introduces specular light at the expense of the SSR light.
+ vec4 final_color = vec4(imageLoad(source_diffuse, ivec2(final_pos - 0.5)).rgb * fresnel_term, fade * margin_blend * roughness_fade);
+
+ imageStore(ssr_image, ssC, final_color);
#ifdef MODE_ROUGH
@@ -259,20 +284,6 @@ void main() {
#endif // MODE_ROUGH
- final_color = vec4(imageLoad(source_diffuse, ivec2(final_pos - 0.5)).rgb, fade * margin_blend * roughness_fade);
-
- // Schlick term.
- float metallic = texelFetch(source_metallic, ssC << 1, 0).w;
- // F0 is the reflectance of normally incident light (perpendicular to the surface).
- // Dielectric materials have a widely accepted default value of 0.04. We assume that metals reflect all light, so their F0 is 1.0.
- float f0 = mix(0.04, 1.0, metallic);
- float m = clamp(1.0 - dot(normal, -view_dir), 0.0, 1.0);
- float m2 = m * m;
- m = m2 * m2 * m; // pow(m,5)
- final_color.a *= f0 + (1.0 - f0) * m; // Fresnel Schlick term.
-
- imageStore(ssr_image, ssC, final_color);
-
} else {
#ifdef MODE_ROUGH
imageStore(blur_radius_image, ssC, vec4(0.0));
diff --git a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl
index a7da0812df..4df74b8626 100644
--- a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl
@@ -36,7 +36,7 @@ void main() {
if (any(greaterThanEqual(ssC.xy, params.screen_size))) { //too large, do nothing
return;
}
- //do not filter, SSR will generate arctifacts if this is done
+ //do not filter, SSR will generate artifacts if this is done
float divisor = 0.0;
vec4 color;
diff --git a/servers/rendering/renderer_rd/shaders/effects/specular_merge.glsl b/servers/rendering/renderer_rd/shaders/effects/specular_merge.glsl
index c62144fdaf..db710b7cdd 100644
--- a/servers/rendering/renderer_rd/shaders/effects/specular_merge.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/specular_merge.glsl
@@ -27,16 +27,11 @@ layout(location = 0) out vec2 uv_interp;
#endif //USE_MULTIVIEW
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));
-
-#ifdef USE_MULTIVIEW
- uv_interp = vec3(base_arr[gl_VertexIndex], ViewIndex);
-
- gl_Position = vec4(uv_interp.xy * 2.0 - 1.0, 0.0, 1.0);
-#else
- uv_interp = base_arr[gl_VertexIndex];
-
- gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
+ vec2 base_arr[3] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0));
+ gl_Position = vec4(base_arr[gl_VertexIndex], 0.0, 1.0);
+ uv_interp.xy = clamp(gl_Position.xy, vec2(0.0, 0.0), vec2(1.0, 1.0)) * 2.0; // saturate(x) * 2.0
+#ifdef MULTIVIEW
+ uv_interp.z = ViewIndex;
#endif
}
diff --git a/servers/rendering/renderer_rd/shaders/effects/taa_resolve.glsl b/servers/rendering/renderer_rd/shaders/effects/taa_resolve.glsl
index 02566d8e35..e50397cc5d 100644
--- a/servers/rendering/renderer_rd/shaders/effects/taa_resolve.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/taa_resolve.glsl
@@ -320,7 +320,7 @@ vec3 temporal_antialiasing(uvec2 pos_group_top_left, uvec2 pos_group, uvec2 pos_
vec2 velocity = imageLoad(velocity_buffer, ivec2(pos_screen)).xy;
// Get reprojected uv
- vec2 uv_reprojected = uv - velocity;
+ vec2 uv_reprojected = uv + velocity;
// Get input color
vec3 color_input = load_color(pos_group);
diff --git a/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl b/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl
index 52aee8b648..33ec991107 100644
--- a/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl
@@ -13,9 +13,9 @@
layout(location = 0) out vec2 uv_interp;
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 = base_arr[gl_VertexIndex];
- gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
+ vec2 base_arr[3] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0));
+ gl_Position = vec4(base_arr[gl_VertexIndex], 0.0, 1.0);
+ uv_interp = clamp(gl_Position.xy, vec2(0.0, 0.0), vec2(1.0, 1.0)) * 2.0; // saturate(x) * 2.0
}
#[fragment]
@@ -57,14 +57,21 @@ layout(set = 3, binding = 0) uniform sampler2D source_color_correction;
layout(set = 3, binding = 0) uniform sampler3D source_color_correction;
#endif
+#define FLAG_USE_BCS (1 << 0)
+#define FLAG_USE_GLOW (1 << 1)
+#define FLAG_USE_AUTO_EXPOSURE (1 << 2)
+#define FLAG_USE_COLOR_CORRECTION (1 << 3)
+#define FLAG_USE_FXAA (1 << 4)
+#define FLAG_USE_DEBANDING (1 << 5)
+#define FLAG_CONVERT_TO_SRGB (1 << 6)
+
layout(push_constant, std430) uniform Params {
vec3 bcs;
- bool use_bcs;
+ uint flags;
- bool use_glow;
- bool use_auto_exposure;
- bool use_color_correction;
+ vec2 pixel_size;
uint tonemapper;
+ uint pad;
uvec2 glow_texture_size;
float glow_intensity;
@@ -77,10 +84,6 @@ layout(push_constant, std430) uniform Params {
float white;
float auto_exposure_scale;
float luminance_multiplier;
-
- vec2 pixel_size;
- bool use_fxaa;
- bool use_debanding;
}
params;
@@ -318,10 +321,12 @@ vec3 apply_glow(vec3 color, vec3 glow) { // apply glow using the selected blendi
if (params.glow_mode == GLOW_MODE_ADD) {
return color + glow;
} else if (params.glow_mode == GLOW_MODE_SCREEN) {
- //need color clamping
+ // Needs color clamping.
+ glow.rgb = clamp(glow.rgb, vec3(0.0f), vec3(1.0f));
return max((color + glow) - (color * glow), vec3(0.0));
} else if (params.glow_mode == GLOW_MODE_SOFTLIGHT) {
- //need color clamping
+ // Needs color clamping.
+ glow.rgb = clamp(glow.rgb, vec3(0.0f), vec3(1.0f));
glow = glow * vec3(0.5f) + vec3(0.5f);
color.r = (glow.r <= 0.5f) ? (color.r - (1.0f - 2.0f * glow.r) * color.r * (1.0f - color.r)) : (((glow.r > 0.5f) && (color.r <= 0.25f)) ? (color.r + (2.0f * glow.r - 1.0f) * (4.0f * color.r * (4.0f * color.r + 1.0f) * (color.r - 1.0f) + 7.0f * color.r)) : (color.r + (2.0f * glow.r - 1.0f) * (sqrt(color.r) - color.r)));
@@ -439,7 +444,7 @@ void main() {
float exposure = params.exposure;
#ifndef SUBPASS
- if (params.use_auto_exposure) {
+ if (bool(params.flags & FLAG_USE_AUTO_EXPOSURE)) {
exposure *= 1.0 / (texelFetch(source_auto_exposure, ivec2(0, 0), 0).r * params.luminance_multiplier / params.auto_exposure_scale);
}
#endif
@@ -448,12 +453,12 @@ void main() {
// Early Tonemap & SRGB Conversion
#ifndef SUBPASS
- if (params.use_fxaa) {
+ if (bool(params.flags & FLAG_USE_FXAA)) {
// FXAA must be performed before glow to preserve the "bleed" effect of glow.
color.rgb = do_fxaa(color.rgb, exposure, uv_interp);
}
- if (params.use_glow && params.glow_mode == GLOW_MODE_MIX) {
+ if (bool(params.flags & FLAG_USE_GLOW) && params.glow_mode == GLOW_MODE_MIX) {
vec3 glow = gather_glow(source_glow, uv_interp) * params.luminance_multiplier;
if (params.glow_map_strength > 0.001) {
glow = mix(glow, texture(glow_map, uv_interp).rgb * glow, params.glow_map_strength);
@@ -464,11 +469,12 @@ void main() {
color.rgb = apply_tonemapping(color.rgb, params.white);
- color.rgb = linear_to_srgb(color.rgb); // regular linear -> SRGB conversion
-
+ if (bool(params.flags & FLAG_CONVERT_TO_SRGB)) {
+ color.rgb = linear_to_srgb(color.rgb); // Regular linear -> SRGB conversion.
+ }
#ifndef SUBPASS
// Glow
- if (params.use_glow && params.glow_mode != GLOW_MODE_MIX) {
+ if (bool(params.flags & FLAG_USE_GLOW) && params.glow_mode != GLOW_MODE_MIX) {
vec3 glow = gather_glow(source_glow, uv_interp) * params.glow_intensity * params.luminance_multiplier;
if (params.glow_map_strength > 0.001) {
glow = mix(glow, texture(glow_map, uv_interp).rgb * glow, params.glow_map_strength);
@@ -476,7 +482,9 @@ void main() {
// high dynamic range -> SRGB
glow = apply_tonemapping(glow, params.white);
- glow = linear_to_srgb(glow);
+ if (bool(params.flags & FLAG_CONVERT_TO_SRGB)) {
+ glow = linear_to_srgb(glow);
+ }
color.rgb = apply_glow(color.rgb, glow);
}
@@ -484,15 +492,15 @@ void main() {
// Additional effects
- if (params.use_bcs) {
+ if (bool(params.flags & FLAG_USE_BCS)) {
color.rgb = apply_bcs(color.rgb, params.bcs);
}
- if (params.use_color_correction) {
+ if (bool(params.flags & FLAG_USE_COLOR_CORRECTION)) {
color.rgb = apply_color_correction(color.rgb);
}
- if (params.use_debanding) {
+ if (bool(params.flags & FLAG_USE_DEBANDING)) {
// Debanding should be done at the end of tonemapping, but before writing to the LDR buffer.
// Otherwise, we're adding noise to an already-quantized image.
color.rgb += screen_space_dither(gl_FragCoord.xy);
diff --git a/servers/rendering/renderer_rd/shaders/effects/vrs.glsl b/servers/rendering/renderer_rd/shaders/effects/vrs.glsl
index b450bb9fe9..d3d39a8b92 100644
--- a/servers/rendering/renderer_rd/shaders/effects/vrs.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/vrs.glsl
@@ -20,13 +20,12 @@ 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];
+ vec2 base_arr[3] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0));
+ gl_Position = vec4(base_arr[gl_VertexIndex], 0.0, 1.0);
+ uv_interp.xy = clamp(gl_Position.xy, vec2(0.0, 0.0), vec2(1.0, 1.0)) * 2.0; // saturate(x) * 2.0
#ifdef MULTIVIEW
uv_interp.z = ViewIndex;
#endif
-
- gl_Position = vec4(uv_interp.xy * 2.0 - 1.0, 0.0, 1.0);
}
#[fragment]
diff --git a/servers/rendering/renderer_rd/shaders/environment/sky.glsl b/servers/rendering/renderer_rd/shaders/environment/sky.glsl
index d605917acc..4e5b11aed8 100644
--- a/servers/rendering/renderer_rd/shaders/environment/sky.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/sky.glsl
@@ -23,7 +23,7 @@ layout(push_constant, std430) uniform Params {
params;
void main() {
- vec2 base_arr[4] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 1.0), vec2(1.0, 1.0), vec2(1.0, -1.0));
+ vec2 base_arr[3] = vec2[](vec2(-1.0, -3.0), vec2(-1.0, 1.0), vec2(3.0, 1.0));
uv_interp = base_arr[gl_VertexIndex];
gl_Position = vec4(uv_interp, 1.0, 1.0);
}
diff --git a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl
index f961249dce..57b9a4c320 100644
--- a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl
@@ -576,8 +576,9 @@ void main() {
float attenuation = get_omni_attenuation(d, spot_lights.data[light_index].inv_radius, spot_lights.data[light_index].attenuation);
vec3 spot_dir = spot_lights.data[light_index].direction;
- float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights.data[light_index].cone_angle);
- float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights.data[light_index].cone_angle));
+ highp float cone_angle = spot_lights.data[light_index].cone_angle;
+ float scos = max(dot(-normalize(light_rel_vec), spot_dir), cone_angle);
+ float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - cone_angle));
attenuation *= 1.0 - pow(spot_rim, spot_lights.data[light_index].cone_attenuation);
vec3 light = spot_lights.data[light_index].color;
diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
index 9214a953aa..8e6db7583e 100644
--- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
@@ -10,17 +10,17 @@
/* INPUT ATTRIBS */
-layout(location = 0) in vec3 vertex_attrib;
+// Always contains vertex position in XYZ, can contain tangent angle in W.
+layout(location = 0) in vec4 vertex_angle_attrib;
//only for pure render depth when normal is not used
-#ifdef NORMAL_USED
-layout(location = 1) in vec2 normal_attrib;
+#if defined(NORMAL_USED) || defined(TANGENT_USED)
+// Contains Normal/Axis in RG, can contain tangent in BA.
+layout(location = 1) in vec4 axis_tangent_attrib;
#endif
-#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
-layout(location = 2) in vec2 tangent_attrib;
-#endif
+// Location 2 is unused.
#if defined(COLOR_USED)
layout(location = 3) in vec4 color_attrib;
@@ -58,6 +58,15 @@ layout(location = 10) in uvec4 bone_attrib;
layout(location = 11) in vec4 weight_attrib;
#endif
+#ifdef MOTION_VECTORS
+layout(location = 12) in vec4 previous_vertex_attrib;
+
+#if defined(NORMAL_USED) || defined(TANGENT_USED)
+layout(location = 13) in vec4 previous_normal_attrib;
+#endif
+
+#endif // MOTION_VECTORS
+
vec3 oct_to_vec3(vec2 e) {
vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y));
float t = max(-v.z, 0.0);
@@ -65,6 +74,16 @@ vec3 oct_to_vec3(vec2 e) {
return normalize(v);
}
+void axis_angle_to_tbn(vec3 axis, float angle, out vec3 tangent, out vec3 binormal, out vec3 normal) {
+ float c = cos(angle);
+ float s = sin(angle);
+ vec3 omc_axis = (1.0 - c) * axis;
+ vec3 s_axis = s * axis;
+ tangent = omc_axis.xxx * axis + vec3(c, -s_axis.z, s_axis.y);
+ binormal = omc_axis.yyy * axis + vec3(s_axis.z, c, -s_axis.x);
+ normal = omc_axis.zzz * axis + vec3(-s_axis.y, s_axis.x, c);
+}
+
/* Varyings */
layout(location = 0) out vec3 vertex_interp;
@@ -85,7 +104,7 @@ layout(location = 3) out vec2 uv_interp;
layout(location = 4) out vec2 uv2_interp;
#endif
-#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+#ifdef TANGENT_USED
layout(location = 5) out vec3 tangent_interp;
layout(location = 6) out vec3 binormal_interp;
#endif
@@ -161,7 +180,15 @@ vec3 double_add_vec3(vec3 base_a, vec3 prec_a, vec3 base_b, vec3 prec_b, out vec
}
#endif
-void vertex_shader(in uint instance_index, in bool is_multimesh, in uint multimesh_offset, in SceneData scene_data, in mat4 model_matrix, out vec4 screen_pos) {
+void vertex_shader(vec3 vertex_input,
+#ifdef NORMAL_USED
+ in vec3 normal_input,
+#endif
+#ifdef TANGENT_USED
+ in vec3 tangent_input,
+ in vec3 binormal_input,
+#endif
+ in uint instance_index, in bool is_multimesh, in uint multimesh_offset, in SceneData scene_data, in mat4 model_matrix, out vec4 screen_pos) {
vec4 instance_custom = vec4(0.0);
#if defined(COLOR_USED)
color_interp = color_attrib;
@@ -289,16 +316,14 @@ void vertex_shader(in uint instance_index, in bool is_multimesh, in uint multime
model_normal_matrix = model_normal_matrix * mat3(matrix);
}
- vec3 vertex = vertex_attrib;
+ vec3 vertex = vertex_input;
#ifdef NORMAL_USED
- vec3 normal = oct_to_vec3(normal_attrib * 2.0 - 1.0);
+ vec3 normal = normal_input;
#endif
-#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
- vec2 signed_tangent_attrib = tangent_attrib * 2.0 - 1.0;
- vec3 tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0));
- float binormalf = sign(signed_tangent_attrib.y);
- vec3 binormal = normalize(cross(normal, tangent) * binormalf);
+#ifdef TANGENT_USED
+ vec3 tangent = tangent_input;
+ vec3 binormal = binormal_input;
#endif
#ifdef UV_USED
@@ -309,6 +334,17 @@ void vertex_shader(in uint instance_index, in bool is_multimesh, in uint multime
uv2_interp = uv2_attrib;
#endif
+ vec4 uv_scale = instances.data[instance_index].uv_scale;
+
+ if (uv_scale != vec4(0.0)) { // Compression enabled
+#ifdef UV_USED
+ uv_interp = (uv_interp - 0.5) * uv_scale.xy;
+#endif
+#if defined(UV2_USED) || defined(USE_LIGHTMAP)
+ uv2_interp = (uv2_interp - 0.5) * uv_scale.zw;
+#endif
+ }
+
#ifdef OVERRIDE_POSITION
vec4 position;
#endif
@@ -333,7 +369,7 @@ void vertex_shader(in uint instance_index, in bool is_multimesh, in uint multime
normal = model_normal_matrix * normal;
#endif
-#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+#ifdef TANGENT_USED
tangent = model_normal_matrix * tangent;
binormal = model_normal_matrix * binormal;
@@ -375,13 +411,12 @@ void vertex_shader(in uint instance_index, in bool is_multimesh, in uint multime
normal = modelview_normal * normal;
#endif
-#endif
-
-#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+#ifdef TANGENT_USED
binormal = modelview_normal * binormal;
tangent = modelview_normal * tangent;
#endif
+#endif // !defined(SKIP_TRANSFORM_USED) && !defined(VERTEX_WORLD_COORDS_USED)
//using world coordinates
#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED)
@@ -391,7 +426,7 @@ void vertex_shader(in uint instance_index, in bool is_multimesh, in uint multime
normal = (scene_data.view_matrix * vec4(normal, 0.0)).xyz;
#endif
-#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+#ifdef TANGENT_USED
binormal = (scene_data.view_matrix * vec4(binormal, 0.0)).xyz;
tangent = (scene_data.view_matrix * vec4(tangent, 0.0)).xyz;
#endif
@@ -403,7 +438,7 @@ void vertex_shader(in uint instance_index, in bool is_multimesh, in uint multime
normal_interp = normal;
#endif
-#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+#ifdef TANGENT_USED
tangent_interp = tangent;
binormal_interp = binormal;
#endif
@@ -461,6 +496,46 @@ void vertex_shader(in uint instance_index, in bool is_multimesh, in uint multime
#endif
}
+void _unpack_vertex_attributes(vec4 p_vertex_in, vec3 p_compressed_aabb_position, vec3 p_compressed_aabb_size,
+#if defined(NORMAL_USED) || defined(TANGENT_USED)
+ vec4 p_normal_in,
+#ifdef NORMAL_USED
+ out vec3 r_normal,
+#endif
+ out vec3 r_tangent,
+ out vec3 r_binormal,
+#endif
+ out vec3 r_vertex) {
+
+ r_vertex = p_vertex_in.xyz * p_compressed_aabb_size + p_compressed_aabb_position;
+#ifdef NORMAL_USED
+ r_normal = oct_to_vec3(p_normal_in.xy * 2.0 - 1.0);
+#endif
+
+#if defined(NORMAL_USED) || defined(TANGENT_USED)
+
+ float binormal_sign;
+
+ // This works because the oct value (0, 1) maps onto (0, 0, -1) which encodes to (1, 1).
+ // Accordingly, if p_normal_in.z contains octahedral values, it won't equal (0, 1).
+ if (p_normal_in.z > 0.0 || p_normal_in.w < 1.0) {
+ // Uncompressed format.
+ vec2 signed_tangent_attrib = p_normal_in.zw * 2.0 - 1.0;
+ r_tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0));
+ binormal_sign = sign(signed_tangent_attrib.y);
+ r_binormal = normalize(cross(r_normal, r_tangent) * binormal_sign);
+ } else {
+ // Compressed format.
+ float angle = p_vertex_in.w;
+ binormal_sign = angle > 0.5 ? 1.0 : -1.0; // 0.5 does not exist in UNORM16, so values are either greater or smaller.
+ angle = abs(angle * 2.0 - 1.0) * M_PI; // 0.5 is basically zero, allowing to encode both signs reliably.
+ vec3 axis = r_normal;
+ axis_angle_to_tbn(axis, angle, r_tangent, r_binormal, r_normal);
+ r_binormal *= binormal_sign;
+ }
+#endif
+}
+
void main() {
uint instance_index = draw_call.instance_index;
@@ -472,16 +547,82 @@ void main() {
instance_index_interp = instance_index;
mat4 model_matrix = instances.data[instance_index].transform;
-#if defined(MOTION_VECTORS)
+
+#ifdef MOTION_VECTORS
+ // Previous vertex.
+ vec3 prev_vertex;
+#ifdef NORMAL_USED
+ vec3 prev_normal;
+#endif
+#if defined(NORMAL_USED) || defined(TANGENT_USED)
+ vec3 prev_tangent;
+ vec3 prev_binormal;
+#endif
+
+ _unpack_vertex_attributes(
+ previous_vertex_attrib,
+ instances.data[instance_index].compressed_aabb_position_pad.xyz,
+ instances.data[instance_index].compressed_aabb_size_pad.xyz,
+
+#if defined(NORMAL_USED) || defined(TANGENT_USED)
+ previous_normal_attrib,
+#ifdef NORMAL_USED
+ prev_normal,
+#endif
+ prev_tangent,
+ prev_binormal,
+#endif
+ prev_vertex);
+
global_time = scene_data_block.prev_data.time;
- vertex_shader(instance_index, is_multimesh, draw_call.multimesh_motion_vectors_previous_offset, scene_data_block.prev_data, instances.data[instance_index].prev_transform, prev_screen_position);
- global_time = scene_data_block.data.time;
- vertex_shader(instance_index, is_multimesh, draw_call.multimesh_motion_vectors_current_offset, scene_data_block.data, model_matrix, screen_position);
+ vertex_shader(prev_vertex,
+#ifdef NORMAL_USED
+ prev_normal,
+#endif
+#ifdef TANGENT_USED
+ prev_tangent,
+ prev_binormal,
+#endif
+ instance_index, is_multimesh, draw_call.multimesh_motion_vectors_previous_offset, scene_data_block.prev_data, instances.data[instance_index].prev_transform, prev_screen_position);
#else
- global_time = scene_data_block.data.time;
+ // Unused output.
vec4 screen_position;
- vertex_shader(instance_index, is_multimesh, draw_call.multimesh_motion_vectors_current_offset, scene_data_block.data, model_matrix, screen_position);
#endif
+
+ vec3 vertex;
+#ifdef NORMAL_USED
+ vec3 normal;
+#endif
+#if defined(NORMAL_USED) || defined(TANGENT_USED)
+ vec3 tangent;
+ vec3 binormal;
+#endif
+
+ _unpack_vertex_attributes(
+ vertex_angle_attrib,
+ instances.data[instance_index].compressed_aabb_position_pad.xyz,
+ instances.data[instance_index].compressed_aabb_size_pad.xyz,
+#if defined(NORMAL_USED) || defined(TANGENT_USED)
+ axis_tangent_attrib,
+#ifdef NORMAL_USED
+ normal,
+#endif
+ tangent,
+ binormal,
+#endif
+ vertex);
+
+ // Current vertex.
+ global_time = scene_data_block.data.time;
+ vertex_shader(vertex,
+#ifdef NORMAL_USED
+ normal,
+#endif
+#ifdef TANGENT_USED
+ tangent,
+ binormal,
+#endif
+ instance_index, is_multimesh, draw_call.multimesh_motion_vectors_current_offset, scene_data_block.data, model_matrix, screen_position);
}
#[fragment]
@@ -535,7 +676,7 @@ layout(location = 3) in vec2 uv_interp;
layout(location = 4) in vec2 uv2_interp;
#endif
-#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+#ifdef TANGENT_USED
layout(location = 5) in vec3 tangent_interp;
layout(location = 6) in vec3 binormal_interp;
#endif
@@ -758,7 +899,9 @@ void fragment_shader(in SceneData scene_data) {
float clearcoat_roughness = 0.0;
float anisotropy = 0.0;
vec2 anisotropy_flow = vec2(1.0, 0.0);
+#ifndef FOG_DISABLED
vec4 fog = vec4(0.0);
+#endif // !FOG_DISABLED
#if defined(CUSTOM_RADIANCE_USED)
vec4 custom_radiance = vec4(0.0);
#endif
@@ -771,7 +914,7 @@ void fragment_shader(in SceneData scene_data) {
float alpha = float(instances.data[instance_index].flags >> INSTANCE_FLAGS_FADE_SHIFT) / float(255.0);
-#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+#ifdef TANGENT_USED
vec3 binormal = normalize(binormal_interp);
vec3 tangent = normalize(tangent_interp);
#else
@@ -918,6 +1061,7 @@ void fragment_shader(in SceneData scene_data) {
/////////////////////// FOG //////////////////////
#ifndef MODE_RENDER_DEPTH
+#ifndef FOG_DISABLED
#ifndef CUSTOM_FOG_USED
// fog must be processed as early as possible and then packed.
// to maximize VGPR usage
@@ -953,6 +1097,7 @@ void fragment_shader(in SceneData scene_data) {
uint fog_rg = packHalf2x16(fog.rg);
uint fog_ba = packHalf2x16(fog.ba);
+#endif //!FOG_DISABLED
#endif //!MODE_RENDER_DEPTH
/////////////////////// DECALS ////////////////////////////////
@@ -1229,9 +1374,10 @@ void fragment_shader(in SceneData scene_data) {
} else if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap
bool uses_sh = bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP);
uint ofs = instances.data[instance_index].gi_offset & 0xFFFF;
+ uint slice = instances.data[instance_index].gi_offset >> 16;
vec3 uvw;
uvw.xy = uv2 * instances.data[instance_index].lightmap_uv_scale.zw + instances.data[instance_index].lightmap_uv_scale.xy;
- uvw.z = float((instances.data[instance_index].gi_offset >> 16) & 0xFFFF);
+ uvw.z = float(slice);
if (uses_sh) {
uvw.z *= 4.0; //SH textures use 4 times more data
@@ -1240,9 +1386,8 @@ void fragment_shader(in SceneData scene_data) {
vec3 lm_light_l1_0 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 2.0), 0.0).rgb;
vec3 lm_light_l1p1 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 3.0), 0.0).rgb;
- uint idx = instances.data[instance_index].gi_offset >> 20;
- vec3 n = normalize(lightmaps.data[idx].normal_xform * normal);
- float en = lightmaps.data[idx].exposure_normalization;
+ vec3 n = normalize(lightmaps.data[ofs].normal_xform * normal);
+ float en = lightmaps.data[ofs].exposure_normalization;
ambient_light += lm_light_l0 * 0.282095f * en;
ambient_light += lm_light_l1n1 * 0.32573 * n.y * en;
@@ -1256,8 +1401,7 @@ void fragment_shader(in SceneData scene_data) {
}
} else {
- uint idx = instances.data[instance_index].gi_offset >> 20;
- ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw, 0.0).rgb * lightmaps.data[idx].exposure_normalization;
+ ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw, 0.0).rgb * lightmaps.data[ofs].exposure_normalization;
}
}
#else
@@ -2206,8 +2350,10 @@ void fragment_shader(in SceneData scene_data) {
diffuse_light *= 1.0 - metallic;
ambient_light *= 1.0 - metallic;
+#ifndef FOG_DISABLED
//restore fog
fog = vec4(unpackHalf2x16(fog_rg), unpackHalf2x16(fog_ba));
+#endif //!FOG_DISABLED
#ifdef MODE_SEPARATE_SPECULAR
@@ -2224,11 +2370,15 @@ void fragment_shader(in SceneData scene_data) {
specular_buffer = vec4(specular_light, metallic);
#endif
+#ifndef FOG_DISABLED
diffuse_buffer.rgb = mix(diffuse_buffer.rgb, fog.rgb, fog.a);
specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), fog.a);
+#endif //!FOG_DISABLED
#else //MODE_SEPARATE_SPECULAR
+ alpha *= scene_data.pass_alpha_multiplier;
+
#ifdef MODE_UNSHADED
frag_color = vec4(albedo, alpha);
#else
@@ -2236,8 +2386,10 @@ void fragment_shader(in SceneData scene_data) {
//frag_color = vec4(1.0);
#endif //USE_NO_SHADING
+#ifndef FOG_DISABLED
// Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky.
frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a);
+#endif //!FOG_DISABLED
#endif //MODE_SEPARATE_SPECULAR
@@ -2249,7 +2401,7 @@ void fragment_shader(in SceneData scene_data) {
vec2 position_uv = position_clip * vec2(0.5, 0.5);
vec2 prev_position_uv = prev_position_clip * vec2(0.5, 0.5);
- motion_vector = position_uv - prev_position_uv;
+ motion_vector = prev_position_uv - position_uv;
#endif
}
diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl
index 8ead363f3b..bfd87b4ea1 100644
--- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl
@@ -28,6 +28,10 @@
#endif
#endif
+#if !defined(TANGENT_USED) && (defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED))
+#define TANGENT_USED
+#endif
+
layout(push_constant, std430) uniform DrawCall {
uint instance_index;
uint uv_offset;
@@ -211,6 +215,9 @@ struct InstanceData {
uint gi_offset; //GI information when using lightmapping (VCT or lightmap index)
uint layer_mask;
vec4 lightmap_uv_scale;
+ vec4 compressed_aabb_position_pad; // Only .xyz is used. .w is padding.
+ vec4 compressed_aabb_size_pad; // Only .xyz is used. .w is padding.
+ vec4 uv_scale;
};
layout(set = 1, binding = 2, std430) buffer restrict readonly InstanceDataBuffer {
diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
index b63eea1401..a9e9a617d6 100644
--- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
@@ -11,17 +11,17 @@
/* INPUT ATTRIBS */
-layout(location = 0) in vec3 vertex_attrib;
+// Always contains vertex position in XYZ, can contain tangent angle in W.
+layout(location = 0) in vec4 vertex_angle_attrib;
//only for pure render depth when normal is not used
#ifdef NORMAL_USED
-layout(location = 1) in vec2 normal_attrib;
+// Contains Normal/Axis in RG, can contain tangent in BA.
+layout(location = 1) in vec4 axis_tangent_attrib;
#endif
-#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
-layout(location = 2) in vec2 tangent_attrib;
-#endif
+// Location 2 is unused.
#if defined(COLOR_USED)
layout(location = 3) in vec4 color_attrib;
@@ -66,6 +66,16 @@ vec3 oct_to_vec3(vec2 e) {
return normalize(v);
}
+void axis_angle_to_tbn(vec3 axis, float angle, out vec3 tangent, out vec3 binormal, out vec3 normal) {
+ float c = cos(angle);
+ float s = sin(angle);
+ vec3 omc_axis = (1.0 - c) * axis;
+ vec3 s_axis = s * axis;
+ tangent = omc_axis.xxx * axis + vec3(c, -s_axis.z, s_axis.y);
+ binormal = omc_axis.yyy * axis + vec3(s_axis.z, c, -s_axis.x);
+ normal = omc_axis.zzz * axis + vec3(-s_axis.y, s_axis.x, c);
+}
+
/* Varyings */
layout(location = 0) highp out vec3 vertex_interp;
@@ -162,9 +172,9 @@ void main() {
color_interp = color_attrib;
#endif
- bool is_multimesh = bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH);
+ bool is_multimesh = bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH);
- mat4 model_matrix = draw_call.transform;
+ mat4 model_matrix = instances.data[draw_call.instance_index].transform;
mat4 inv_view_matrix = scene_data.inv_view_matrix;
#ifdef USE_DOUBLE_PRECISION
vec3 model_precision = vec3(model_matrix[0][3], model_matrix[1][3], model_matrix[2][3]);
@@ -178,7 +188,7 @@ void main() {
#endif
mat3 model_normal_matrix;
- if (bool(draw_call.flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) {
+ if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) {
model_normal_matrix = transpose(inverse(mat3(model_matrix)));
} else {
model_normal_matrix = mat3(model_matrix);
@@ -191,7 +201,7 @@ void main() {
//multimesh, instances are for it
#ifdef USE_PARTICLE_TRAILS
- uint trail_size = (draw_call.flags >> INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT) & INSTANCE_FLAGS_PARTICLE_TRAIL_MASK;
+ uint trail_size = (instances.data[draw_call.instance_index].flags >> INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT) & INSTANCE_FLAGS_PARTICLE_TRAIL_MASK;
uint stride = 3 + 1 + 1; //particles always uses this format
uint offset = trail_size * stride * gl_InstanceIndex;
@@ -238,22 +248,22 @@ void main() {
uint stride = 0;
{
//TODO implement a small lookup table for the stride
- if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) {
+ if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) {
stride += 2;
} else {
stride += 3;
}
- if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) {
+ if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) {
stride += 1;
}
- if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) {
+ if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) {
stride += 1;
}
}
uint offset = stride * gl_InstanceIndex;
- if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) {
+ if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) {
matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
offset += 2;
} else {
@@ -261,14 +271,14 @@ void main() {
offset += 3;
}
- if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) {
+ if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) {
#ifdef COLOR_USED
color_interp *= transforms.data[offset];
#endif
offset += 1;
}
- if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) {
+ if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) {
instance_custom = transforms.data[offset];
}
@@ -287,16 +297,31 @@ void main() {
model_normal_matrix = model_normal_matrix * mat3(matrix);
}
- vec3 vertex = vertex_attrib;
+ vec3 vertex = vertex_angle_attrib.xyz * instances.data[draw_call.instance_index].compressed_aabb_size_pad.xyz + instances.data[draw_call.instance_index].compressed_aabb_position_pad.xyz;
#ifdef NORMAL_USED
- vec3 normal = oct_to_vec3(normal_attrib * 2.0 - 1.0);
+ vec3 normal = oct_to_vec3(axis_tangent_attrib.xy * 2.0 - 1.0);
#endif
-#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
- vec2 signed_tangent_attrib = tangent_attrib * 2.0 - 1.0;
- vec3 tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0));
- float binormalf = sign(signed_tangent_attrib.y);
- vec3 binormal = normalize(cross(normal, tangent) * binormalf);
+#if defined(NORMAL_USED) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+
+ vec3 binormal;
+ float binormal_sign;
+ vec3 tangent;
+ if (axis_tangent_attrib.z > 0.0 || axis_tangent_attrib.w < 1.0) {
+ // Uncompressed format.
+ vec2 signed_tangent_attrib = axis_tangent_attrib.zw * 2.0 - 1.0;
+ tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0));
+ binormal_sign = sign(signed_tangent_attrib.y);
+ binormal = normalize(cross(normal, tangent) * binormal_sign);
+ } else {
+ // Compressed format.
+ float angle = vertex_angle_attrib.w;
+ binormal_sign = angle > 0.5 ? 1.0 : -1.0; // 0.5 does not exist in UNORM16, so values are either greater or smaller.
+ angle = abs(angle * 2.0 - 1.0) * M_PI; // 0.5 is basically zero, allowing to encode both signs reliably.
+ vec3 axis = normal;
+ axis_angle_to_tbn(axis, angle, tangent, binormal, normal);
+ binormal *= binormal_sign;
+ }
#endif
#ifdef UV_USED
@@ -307,6 +332,17 @@ void main() {
uv2_interp = uv2_attrib;
#endif
+ vec4 uv_scale = instances.data[draw_call.instance_index].uv_scale;
+
+ if (uv_scale != vec4(0.0)) { // Compression enabled
+#ifdef UV_USED
+ uv_interp = (uv_interp - 0.5) * uv_scale.xy;
+#endif
+#if defined(UV2_USED) || defined(USE_LIGHTMAP)
+ uv2_interp = (uv2_interp - 0.5) * uv_scale.zw;
+#endif
+ }
+
#ifdef OVERRIDE_POSITION
vec4 position;
#endif
@@ -372,13 +408,12 @@ void main() {
normal = modelview_normal * normal;
#endif
-#endif
-
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
binormal = modelview_normal * binormal;
tangent = modelview_normal * tangent;
#endif
+#endif // !defined(SKIP_TRANSFORM_USED) && !defined(VERTEX_WORLD_COORDS_USED)
//using world coordinates
#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED)
@@ -441,8 +476,7 @@ void main() {
#endif // MODE_RENDER_DEPTH
#ifdef MODE_RENDER_MATERIAL
if (scene_data.material_uv2_mode) {
- vec2 uv_offset = draw_call.lightmap_uv_scale.xy; // we are abusing lightmap_uv_scale here, we shouldn't have a lightmap during a depth pass...
- gl_Position.xy = (uv2_attrib.xy + uv_offset) * 2.0 - 1.0;
+ gl_Position.xy = (uv2_attrib.xy + draw_call.uv_offset) * 2.0 - 1.0;
gl_Position.z = 0.00001;
gl_Position.w = 1.0;
}
@@ -694,7 +728,9 @@ void main() {
float clearcoat_roughness = 0.0;
float anisotropy = 0.0;
vec2 anisotropy_flow = vec2(1.0, 0.0);
+#ifndef FOG_DISABLED
vec4 fog = vec4(0.0);
+#endif // !FOG_DISABLED
#if defined(CUSTOM_RADIANCE_USED)
vec4 custom_radiance = vec4(0.0);
#endif
@@ -763,7 +799,7 @@ void main() {
#endif // ALPHA_ANTIALIASING_EDGE_USED
mat4 inv_view_matrix = scene_data.inv_view_matrix;
- mat4 read_model_matrix = draw_call.transform;
+ mat4 read_model_matrix = instances.data[draw_call.instance_index].transform;
#ifdef USE_DOUBLE_PRECISION
read_model_matrix[0][3] = 0.0;
read_model_matrix[1][3] = 0.0;
@@ -860,6 +896,7 @@ void main() {
/////////////////////// FOG //////////////////////
#ifndef MODE_RENDER_DEPTH
+#ifndef FOG_DISABLED
#ifndef CUSTOM_FOG_USED
// fog must be processed as early as possible and then packed.
// to maximize VGPR usage
@@ -874,6 +911,7 @@ void main() {
uint fog_rg = packHalf2x16(fog.rg);
uint fog_ba = packHalf2x16(fog.ba);
+#endif //!FOG_DISABLED
#endif //!MODE_RENDER_DEPTH
/////////////////////// DECALS ////////////////////////////////
@@ -886,11 +924,11 @@ void main() {
if (!sc_disable_decals) { //Decals
// must implement
- uint decal_indices = draw_call.decals.x;
+ uint decal_indices = instances.data[draw_call.instance_index].decals.x;
for (uint i = 0; i < 8; i++) {
uint decal_index = decal_indices & 0xFF;
if (i == 3) {
- decal_indices = draw_call.decals.y;
+ decal_indices = instances.data[draw_call.instance_index].decals.y;
} else {
decal_indices = decal_indices >> 8;
}
@@ -899,6 +937,10 @@ void main() {
break;
}
+ if (!bool(decals.data[decal_index].mask & instances.data[draw_call.instance_index].layer_mask)) {
+ continue; //not masked
+ }
+
vec3 uv_local = (decals.data[decal_index].xform * vec4(vertex, 1.0)).xyz;
if (any(lessThan(uv_local, vec3(0.0, -1.0, 0.0))) || any(greaterThan(uv_local, vec3(1.0)))) {
continue; //out of decal
@@ -1089,8 +1131,8 @@ void main() {
#ifdef USE_LIGHTMAP
//lightmap
- if (bool(draw_call.flags & INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE)) { //has lightmap capture
- uint index = draw_call.gi_offset;
+ if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE)) { //has lightmap capture
+ uint index = instances.data[draw_call.instance_index].gi_offset;
vec3 wnormal = mat3(scene_data.inv_view_matrix) * normal;
const float c1 = 0.429043;
@@ -1110,14 +1152,13 @@ void main() {
2.0 * c2 * lightmap_captures.data[index].sh[2].rgb * wnormal.z) *
scene_data.emissive_exposure_normalization;
- } else if (bool(draw_call.flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap
- bool uses_sh = bool(draw_call.flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP);
- uint ofs = draw_call.gi_offset & 0xFFFF;
+ } else if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap
+ bool uses_sh = bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP);
+ uint ofs = instances.data[draw_call.instance_index].gi_offset & 0xFFFF;
+ uint slice = instances.data[draw_call.instance_index].gi_offset >> 16;
vec3 uvw;
- uvw.xy = uv2 * draw_call.lightmap_uv_scale.zw + draw_call.lightmap_uv_scale.xy;
- uvw.z = float((draw_call.gi_offset >> 16) & 0xFFFF);
-
- uint idx = draw_call.gi_offset >> 20;
+ uvw.xy = uv2 * instances.data[draw_call.instance_index].lightmap_uv_scale.zw + instances.data[draw_call.instance_index].lightmap_uv_scale.xy;
+ uvw.z = float(slice);
if (uses_sh) {
uvw.z *= 4.0; //SH textures use 4 times more data
@@ -1126,8 +1167,8 @@ void main() {
vec3 lm_light_l1_0 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 2.0), 0.0).rgb;
vec3 lm_light_l1p1 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 3.0), 0.0).rgb;
- vec3 n = normalize(lightmaps.data[idx].normal_xform * normal);
- float exposure_normalization = lightmaps.data[idx].exposure_normalization;
+ vec3 n = normalize(lightmaps.data[ofs].normal_xform * normal);
+ float exposure_normalization = lightmaps.data[ofs].exposure_normalization;
ambient_light += lm_light_l0 * 0.282095f;
ambient_light += lm_light_l1n1 * 0.32573 * n.y * exposure_normalization;
@@ -1141,7 +1182,7 @@ void main() {
}
} else {
- ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw, 0.0).rgb * lightmaps.data[idx].exposure_normalization;
+ ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw, 0.0).rgb * lightmaps.data[ofs].exposure_normalization;
}
}
@@ -1155,7 +1196,7 @@ void main() {
vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0);
vec4 ambient_accum = vec4(0.0, 0.0, 0.0, 0.0);
- uint reflection_indices = draw_call.reflection_probes.x;
+ uint reflection_indices = instances.data[draw_call.instance_index].reflection_probes.x;
#ifdef LIGHT_ANISOTROPY_USED
// https://google.github.io/filament/Filament.html#lighting/imagebasedlights/anisotropy
@@ -1172,7 +1213,7 @@ void main() {
for (uint i = 0; i < 8; i++) {
uint reflection_index = reflection_indices & 0xFF;
if (i == 3) {
- reflection_indices = draw_call.reflection_probes.y;
+ reflection_indices = instances.data[draw_call.instance_index].reflection_probes.y;
} else {
reflection_indices = reflection_indices >> 8;
}
@@ -1253,7 +1294,7 @@ void main() {
break;
}
- if (!bool(directional_lights.data[i].mask & draw_call.layer_mask)) {
+ if (!bool(directional_lights.data[i].mask & instances.data[draw_call.instance_index].layer_mask)) {
continue; //not masked
}
@@ -1525,7 +1566,7 @@ void main() {
break;
}
- if (!bool(directional_lights.data[i].mask & draw_call.layer_mask)) {
+ if (!bool(directional_lights.data[i].mask & instances.data[draw_call.instance_index].layer_mask)) {
continue; //not masked
}
@@ -1594,11 +1635,11 @@ void main() {
} //directional light
if (!sc_disable_omni_lights) { //omni lights
- uint light_indices = draw_call.omni_lights.x;
+ uint light_indices = instances.data[draw_call.instance_index].omni_lights.x;
for (uint i = 0; i < 8; i++) {
uint light_index = light_indices & 0xFF;
if (i == 3) {
- light_indices = draw_call.omni_lights.y;
+ light_indices = instances.data[draw_call.instance_index].omni_lights.y;
} else {
light_indices = light_indices >> 8;
}
@@ -1639,11 +1680,11 @@ void main() {
if (!sc_disable_spot_lights) { //spot lights
- uint light_indices = draw_call.spot_lights.x;
+ uint light_indices = instances.data[draw_call.instance_index].spot_lights.x;
for (uint i = 0; i < 8; i++) {
uint light_index = light_indices & 0xFF;
if (i == 3) {
- light_indices = draw_call.spot_lights.y;
+ light_indices = instances.data[draw_call.instance_index].spot_lights.y;
} else {
light_indices = light_indices >> 8;
}
@@ -1740,8 +1781,10 @@ void main() {
diffuse_light *= 1.0 - metallic;
ambient_light *= 1.0 - metallic;
+#ifndef FOG_DISABLED
//restore fog
fog = vec4(unpackHalf2x16(fog_rg), unpackHalf2x16(fog_ba));
+#endif // !FOG_DISABLED
#ifdef MODE_MULTIPLE_RENDER_TARGETS
@@ -1758,8 +1801,10 @@ void main() {
specular_buffer = vec4(specular_light, metallic);
#endif // MODE_UNSHADED
+#ifndef FOG_DISABLED
diffuse_buffer.rgb = mix(diffuse_buffer.rgb, fog.rgb, fog.a);
specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), fog.a);
+#endif // !FOG_DISABLED
#else //MODE_MULTIPLE_RENDER_TARGETS
@@ -1769,8 +1814,10 @@ void main() {
frag_color = vec4(emission + ambient_light + diffuse_light + specular_light, alpha);
#endif // MODE_UNSHADED
+#ifndef FOG_DISABLED
// Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky.
frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a);
+#endif // !FOG_DISABLED
// On mobile we use a UNORM buffer with 10bpp which results in a range from 0.0 - 1.0 resulting in HDR breaking
// We divide by sc_luminance_multiplier to support a range from 0.0 - 2.0 both increasing precision on bright and darker images
diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl
index d0a315858d..3de5e76970 100644
--- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl
@@ -15,20 +15,11 @@
#endif
#define USING_MOBILE_RENDERER
-/* don't exceed 128 bytes!! */
-/* put instance data into our push content, not a array */
-layout(push_constant, std430) uniform DrawCall {
- highp mat4 transform; // 64 - 64
- uint flags; // 04 - 68
- uint instance_uniforms_ofs; //base offset in global buffer for instance variables // 04 - 72
- uint gi_offset; //GI information when using lightmapping (VCT or lightmap index) // 04 - 76
- uint layer_mask; // 04 - 80
- highp vec4 lightmap_uv_scale; // 16 - 96 doubles as uv_offset when needed
- uvec2 reflection_probes; // 08 - 104
- uvec2 omni_lights; // 08 - 112
- uvec2 spot_lights; // 08 - 120
- uvec2 decals; // 08 - 128
+layout(push_constant, std430) uniform DrawCall {
+ vec2 uv_offset;
+ uint instance_index;
+ uint pad;
}
draw_call;
@@ -123,6 +114,29 @@ layout(set = 1, binding = 0, std140) uniform SceneDataBlock {
}
scene_data_block;
+struct InstanceData {
+ highp mat4 transform; // 64 - 64
+ uint flags; // 04 - 68
+ uint instance_uniforms_ofs; // Base offset in global buffer for instance variables. // 04 - 72
+ uint gi_offset; // GI information when using lightmapping (VCT or lightmap index). // 04 - 76
+ uint layer_mask; // 04 - 80
+ highp vec4 lightmap_uv_scale; // 16 - 96 Doubles as uv_offset when needed.
+
+ uvec2 reflection_probes; // 08 - 104
+ uvec2 omni_lights; // 08 - 112
+ uvec2 spot_lights; // 08 - 120
+ uvec2 decals; // 08 - 128
+
+ vec4 compressed_aabb_position_pad; // 16 - 144 // Only .xyz is used. .w is padding.
+ vec4 compressed_aabb_size_pad; // 16 - 160 // Only .xyz is used. .w is padding.
+ vec4 uv_scale; // 16 - 176
+};
+
+layout(set = 1, binding = 1, std430) buffer restrict readonly InstanceDataBuffer {
+ InstanceData data[];
+}
+instances;
+
#ifdef USE_RADIANCE_CUBEMAP_ARRAY
layout(set = 1, binding = 2) uniform mediump textureCubeArray radiance_cubemap;
diff --git a/servers/rendering/renderer_rd/shaders/particles.glsl b/servers/rendering/renderer_rd/shaders/particles.glsl
index 7ba03a27f7..5fa4154727 100644
--- a/servers/rendering/renderer_rd/shaders/particles.glsl
+++ b/servers/rendering/renderer_rd/shaders/particles.glsl
@@ -67,7 +67,7 @@ struct FrameParams {
float delta;
uint frame;
- uint pad0;
+ float amount_ratio;
uint pad1;
uint pad2;
@@ -77,6 +77,8 @@ struct FrameParams {
float particle_size;
mat4 emission_transform;
+ vec3 emitter_velocity;
+ float interp_to_end;
Attractor attractors[MAX_ATTRACTORS];
Collider colliders[MAX_COLLIDERS];
diff --git a/servers/rendering/renderer_rd/shaders/particles_copy.glsl b/servers/rendering/renderer_rd/shaders/particles_copy.glsl
index 67a894b86f..93c4d1009d 100644
--- a/servers/rendering/renderer_rd/shaders/particles_copy.glsl
+++ b/servers/rendering/renderer_rd/shaders/particles_copy.glsl
@@ -45,6 +45,9 @@ layout(set = 2, binding = 0, std430) restrict readonly buffer TrailBindPoses {
}
trail_bind_poses;
+#define PARAMS_FLAG_ORDER_BY_LIFETIME 1
+#define PARAMS_FLAG_COPY_MODE_2D 2
+
layout(push_constant, std430) uniform Params {
vec3 sort_direction;
uint total_particles;
@@ -57,10 +60,10 @@ layout(push_constant, std430) uniform Params {
vec3 align_up;
uint align_mode;
- bool order_by_lifetime;
uint lifetime_split;
bool lifetime_reverse;
- bool copy_mode_2d;
+ uint motion_vectors_current_offset;
+ uint flags;
mat4 inv_emission_transform;
}
@@ -103,7 +106,7 @@ void main() {
particle = uint(sort_buffer.data[particle].y); //use index from sort buffer
}
#else
- if (params.order_by_lifetime) {
+ if (bool(params.flags & PARAMS_FLAG_ORDER_BY_LIFETIME)) {
if (params.trail_size > 1) {
uint limit = (params.total_particles / params.trail_size) - params.lifetime_split;
@@ -179,7 +182,6 @@ void main() {
case TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY: {
vec3 v = particles.data[particle].velocity;
vec3 sv = v - params.sort_direction * dot(params.sort_direction, v); //screen velocity
- float s = (length(txform[0]) + length(txform[1]) + length(txform[2])) / 3.0;
if (length(sv) == 0) {
sv = params.align_up;
@@ -187,9 +189,9 @@ void main() {
sv = normalize(sv);
- txform[0].xyz = normalize(cross(sv, params.sort_direction)) * s;
- txform[1].xyz = sv * s;
- txform[2].xyz = params.sort_direction * s;
+ txform[0].xyz = normalize(cross(sv, params.sort_direction)) * length(txform[0]);
+ txform[1].xyz = sv * length(txform[1]);
+ txform[2].xyz = params.sort_direction * length(txform[2]);
} break;
}
@@ -201,7 +203,7 @@ void main() {
txform = txform * trail_bind_poses.data[part_ofs];
}
- if (params.copy_mode_2d) {
+ if (bool(params.flags & PARAMS_FLAG_COPY_MODE_2D)) {
// In global mode, bring 2D particles to local coordinates
// as they will be drawn with the node position as origin.
txform = params.inv_emission_transform * txform;
@@ -213,15 +215,16 @@ void main() {
}
txform = transpose(txform);
- if (params.copy_mode_2d) {
- uint write_offset = gl_GlobalInvocationID.x * (2 + 1 + 1); //xform + color + custom
+ uint instance_index = gl_GlobalInvocationID.x + params.motion_vectors_current_offset;
+ if (bool(params.flags & PARAMS_FLAG_COPY_MODE_2D)) {
+ uint write_offset = instance_index * (2 + 1 + 1); //xform + color + custom
instances.data[write_offset + 0] = txform[0];
instances.data[write_offset + 1] = txform[1];
instances.data[write_offset + 2] = particles.data[particle].color;
instances.data[write_offset + 3] = particles.data[particle].custom;
} else {
- uint write_offset = gl_GlobalInvocationID.x * (3 + 1 + 1); //xform + color + custom
+ uint write_offset = instance_index * (3 + 1 + 1); //xform + color + custom
instances.data[write_offset + 0] = txform[0];
instances.data[write_offset + 1] = txform[1];
diff --git a/servers/rendering/renderer_rd/shaders/scene_data_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_data_inc.glsl
index b57ee18521..f42fafc68a 100644
--- a/servers/rendering/renderer_rd/shaders/scene_data_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_data_inc.glsl
@@ -64,6 +64,6 @@ struct SceneData {
bool pancake_shadows;
uint camera_visible_layers;
- uint pad2;
+ float pass_alpha_multiplier;
uint pad3;
};
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
index ba8d901772..4fb577d697 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
@@ -71,7 +71,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, bool is_di
mat4 inv_view_matrix = scene_data_block.data.inv_view_matrix;
#ifdef USING_MOBILE_RENDERER
- mat4 read_model_matrix = draw_call.transform;
+ mat4 read_model_matrix = instances.data[draw_call.instance_index].transform;
#else
mat4 read_model_matrix = instances.data[instance_index_interp].transform;
#endif
@@ -584,7 +584,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
{
vec4 clamp_rect = omni_lights.data[idx].atlas_rect;
- //redo shadowmapping, but shrink the model a bit to avoid arctifacts
+ //redo shadowmapping, but shrink the model a bit to avoid artifacts
vec4 splane = (omni_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * omni_lights.data[idx].transmittance_bias, 1.0));
float shadow_len = length(splane.xyz);
diff --git a/servers/rendering/renderer_rd/shaders/skeleton.glsl b/servers/rendering/renderer_rd/shaders/skeleton.glsl
index 59c161548c..894dee1728 100644
--- a/servers/rendering/renderer_rd/shaders/skeleton.glsl
+++ b/servers/rendering/renderer_rd/shaders/skeleton.glsl
@@ -49,7 +49,7 @@ layout(push_constant, std430) uniform Params {
uint blend_shape_count;
bool normalized_blend_shapes;
- uint pad0;
+ uint normal_tangent_stride;
uint pad1;
vec2 skeleton_transform_x;
@@ -188,15 +188,15 @@ void main() {
vertex = uintBitsToFloat(uvec3(src_vertices.data[src_offset + 0], src_vertices.data[src_offset + 1], src_vertices.data[src_offset + 2]));
- src_offset += 3;
+ uint src_normal = params.vertex_count * params.vertex_stride + index * params.normal_tangent_stride;
if (params.has_normal) {
- normal = decode_uint_oct_to_norm(src_vertices.data[src_offset]);
- src_offset++;
+ normal = decode_uint_oct_to_norm(src_vertices.data[src_normal]);
+ src_normal++;
}
if (params.has_tangent) {
- tangent = decode_uint_oct_to_tang(src_vertices.data[src_offset]);
+ tangent = decode_uint_oct_to_tang(src_vertices.data[src_normal]);
}
if (params.has_blend_shape) {
@@ -208,19 +208,19 @@ void main() {
for (uint i = 0; i < params.blend_shape_count; i++) {
float w = blend_shape_weights.data[i];
if (abs(w) > 0.0001) {
- uint base_offset = (params.vertex_count * i + index) * params.vertex_stride;
+ uint base_offset = params.vertex_count * i * (params.vertex_stride + params.normal_tangent_stride) + index * params.vertex_stride;
blend_vertex += uintBitsToFloat(uvec3(src_blend_shapes.data[base_offset + 0], src_blend_shapes.data[base_offset + 1], src_blend_shapes.data[base_offset + 2])) * w;
- base_offset += 3;
+ uint base_normal = params.vertex_count * i * (params.vertex_stride + params.normal_tangent_stride) + params.vertex_count * params.vertex_stride + index * params.normal_tangent_stride;
if (params.has_normal) {
- blend_normal += decode_uint_oct_to_norm(src_blend_shapes.data[base_offset]) * w;
- base_offset++;
+ blend_normal += decode_uint_oct_to_norm(src_blend_shapes.data[base_normal]) * w;
+ base_normal++;
}
if (params.has_tangent) {
- blend_tangent += decode_uint_oct_to_tang(src_blend_shapes.data[base_offset]).rgb * w;
+ blend_tangent += decode_uint_oct_to_tang(src_blend_shapes.data[base_normal]).rgb * w;
}
blend_total += w;
@@ -291,15 +291,15 @@ void main() {
dst_vertices.data[dst_offset + 1] = uvertex.y;
dst_vertices.data[dst_offset + 2] = uvertex.z;
- dst_offset += 3;
+ uint dst_normal = params.vertex_count * params.vertex_stride + index * params.normal_tangent_stride;
if (params.has_normal) {
- dst_vertices.data[dst_offset] = encode_norm_to_uint_oct(normal);
- dst_offset++;
+ dst_vertices.data[dst_normal] = encode_norm_to_uint_oct(normal);
+ dst_normal++;
}
if (params.has_tangent) {
- dst_vertices.data[dst_offset] = encode_tang_to_uint_oct(tangent);
+ dst_vertices.data[dst_normal] = encode_tang_to_uint_oct(tangent);
}
#endif
diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
index a5ec62b546..4fd33ad71a 100644
--- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
@@ -174,14 +174,14 @@ void LightStorage::light_free(RID p_rid) {
void LightStorage::light_set_color(RID p_light, const Color &p_color) {
Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND(!light);
+ ERR_FAIL_NULL(light);
light->color = p_color;
}
void LightStorage::light_set_param(RID p_light, RS::LightParam p_param, float p_value) {
Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND(!light);
+ ERR_FAIL_NULL(light);
ERR_FAIL_INDEX(p_param, RS::LIGHT_PARAM_MAX);
if (light->param[p_param] == p_value) {
@@ -216,7 +216,7 @@ void LightStorage::light_set_param(RID p_light, RS::LightParam p_param, float p_
void LightStorage::light_set_shadow(RID p_light, bool p_enabled) {
Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND(!light);
+ ERR_FAIL_NULL(light);
light->shadow = p_enabled;
light->version++;
@@ -226,7 +226,7 @@ void LightStorage::light_set_shadow(RID p_light, bool p_enabled) {
void LightStorage::light_set_projector(RID p_light, RID p_texture) {
TextureStorage *texture_storage = TextureStorage::get_singleton();
Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND(!light);
+ ERR_FAIL_NULL(light);
if (light->projector == p_texture) {
return;
@@ -250,14 +250,14 @@ void LightStorage::light_set_projector(RID p_light, RID p_texture) {
void LightStorage::light_set_negative(RID p_light, bool p_enable) {
Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND(!light);
+ ERR_FAIL_NULL(light);
light->negative = p_enable;
}
void LightStorage::light_set_cull_mask(RID p_light, uint32_t p_mask) {
Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND(!light);
+ ERR_FAIL_NULL(light);
light->cull_mask = p_mask;
@@ -267,7 +267,7 @@ void LightStorage::light_set_cull_mask(RID p_light, uint32_t p_mask) {
void LightStorage::light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) {
Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND(!light);
+ ERR_FAIL_NULL(light);
light->distance_fade = p_enabled;
light->distance_fade_begin = p_begin;
@@ -277,7 +277,7 @@ void LightStorage::light_set_distance_fade(RID p_light, bool p_enabled, float p_
void LightStorage::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) {
Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND(!light);
+ ERR_FAIL_NULL(light);
light->reverse_cull = p_enabled;
@@ -287,7 +287,7 @@ void LightStorage::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled)
void LightStorage::light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) {
Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND(!light);
+ ERR_FAIL_NULL(light);
light->bake_mode = p_bake_mode;
@@ -297,7 +297,7 @@ void LightStorage::light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mod
void LightStorage::light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) {
Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND(!light);
+ ERR_FAIL_NULL(light);
light->max_sdfgi_cascade = p_cascade;
@@ -307,7 +307,7 @@ void LightStorage::light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade)
void LightStorage::light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) {
Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND(!light);
+ ERR_FAIL_NULL(light);
light->omni_shadow_mode = p_mode;
@@ -317,14 +317,14 @@ void LightStorage::light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMo
RS::LightOmniShadowMode LightStorage::light_omni_get_shadow_mode(RID p_light) {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, RS::LIGHT_OMNI_SHADOW_CUBE);
+ ERR_FAIL_NULL_V(light, RS::LIGHT_OMNI_SHADOW_CUBE);
return light->omni_shadow_mode;
}
void LightStorage::light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) {
Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND(!light);
+ ERR_FAIL_NULL(light);
light->directional_shadow_mode = p_mode;
light->version++;
@@ -333,7 +333,7 @@ void LightStorage::light_directional_set_shadow_mode(RID p_light, RS::LightDirec
void LightStorage::light_directional_set_blend_splits(RID p_light, bool p_enable) {
Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND(!light);
+ ERR_FAIL_NULL(light);
light->directional_blend_splits = p_enable;
light->version++;
@@ -342,63 +342,63 @@ void LightStorage::light_directional_set_blend_splits(RID p_light, bool p_enable
bool LightStorage::light_directional_get_blend_splits(RID p_light) const {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, false);
+ ERR_FAIL_NULL_V(light, false);
return light->directional_blend_splits;
}
void LightStorage::light_directional_set_sky_mode(RID p_light, RS::LightDirectionalSkyMode p_mode) {
Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND(!light);
+ ERR_FAIL_NULL(light);
light->directional_sky_mode = p_mode;
}
RS::LightDirectionalSkyMode LightStorage::light_directional_get_sky_mode(RID p_light) const {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL_SKY_MODE_LIGHT_AND_SKY);
+ ERR_FAIL_NULL_V(light, RS::LIGHT_DIRECTIONAL_SKY_MODE_LIGHT_AND_SKY);
return light->directional_sky_mode;
}
RS::LightDirectionalShadowMode LightStorage::light_directional_get_shadow_mode(RID p_light) {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL);
+ ERR_FAIL_NULL_V(light, RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL);
return light->directional_shadow_mode;
}
uint32_t LightStorage::light_get_max_sdfgi_cascade(RID p_light) {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, 0);
+ ERR_FAIL_NULL_V(light, 0);
return light->max_sdfgi_cascade;
}
RS::LightBakeMode LightStorage::light_get_bake_mode(RID p_light) {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, RS::LIGHT_BAKE_DISABLED);
+ ERR_FAIL_NULL_V(light, RS::LIGHT_BAKE_DISABLED);
return light->bake_mode;
}
uint64_t LightStorage::light_get_version(RID p_light) const {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, 0);
+ ERR_FAIL_NULL_V(light, 0);
return light->version;
}
uint32_t LightStorage::light_get_cull_mask(RID p_light) const {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, 0);
+ ERR_FAIL_NULL_V(light, 0);
return light->cull_mask;
}
AABB LightStorage::light_get_aabb(RID p_light) const {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, AABB());
+ ERR_FAIL_NULL_V(light, AABB());
switch (light->type) {
case RS::LIGHT_SPOT: {
@@ -471,21 +471,21 @@ void LightStorage::light_instance_free(RID p_light) {
void LightStorage::light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) {
LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
- ERR_FAIL_COND(!light_instance);
+ ERR_FAIL_NULL(light_instance);
light_instance->transform = p_transform;
}
void LightStorage::light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) {
LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
- ERR_FAIL_COND(!light_instance);
+ ERR_FAIL_NULL(light_instance);
light_instance->aabb = p_aabb;
}
void LightStorage::light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) {
LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
- ERR_FAIL_COND(!light_instance);
+ ERR_FAIL_NULL(light_instance);
ERR_FAIL_INDEX(p_pass, 6);
@@ -501,7 +501,7 @@ void LightStorage::light_instance_set_shadow_transform(RID p_light_instance, con
void LightStorage::light_instance_mark_visible(RID p_light_instance) {
LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
- ERR_FAIL_COND(!light_instance);
+ ERR_FAIL_NULL(light_instance);
light_instance->last_scene_pass = RendererSceneRenderRD::get_singleton()->get_scene_pass();
}
@@ -1026,7 +1026,7 @@ void LightStorage::reflection_probe_free(RID p_rid) {
void LightStorage::reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) {
ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND(!reflection_probe);
+ ERR_FAIL_NULL(reflection_probe);
reflection_probe->update_mode = p_mode;
reflection_probe->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_REFLECTION_PROBE);
@@ -1034,35 +1034,35 @@ void LightStorage::reflection_probe_set_update_mode(RID p_probe, RS::ReflectionP
void LightStorage::reflection_probe_set_intensity(RID p_probe, float p_intensity) {
ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND(!reflection_probe);
+ ERR_FAIL_NULL(reflection_probe);
reflection_probe->intensity = p_intensity;
}
void LightStorage::reflection_probe_set_ambient_mode(RID p_probe, RS::ReflectionProbeAmbientMode p_mode) {
ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND(!reflection_probe);
+ ERR_FAIL_NULL(reflection_probe);
reflection_probe->ambient_mode = p_mode;
}
void LightStorage::reflection_probe_set_ambient_color(RID p_probe, const Color &p_color) {
ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND(!reflection_probe);
+ ERR_FAIL_NULL(reflection_probe);
reflection_probe->ambient_color = p_color;
}
void LightStorage::reflection_probe_set_ambient_energy(RID p_probe, float p_energy) {
ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND(!reflection_probe);
+ ERR_FAIL_NULL(reflection_probe);
reflection_probe->ambient_color_energy = p_energy;
}
void LightStorage::reflection_probe_set_max_distance(RID p_probe, float p_distance) {
ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND(!reflection_probe);
+ ERR_FAIL_NULL(reflection_probe);
reflection_probe->max_distance = p_distance;
@@ -1071,7 +1071,7 @@ void LightStorage::reflection_probe_set_max_distance(RID p_probe, float p_distan
void LightStorage::reflection_probe_set_size(RID p_probe, const Vector3 &p_size) {
ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND(!reflection_probe);
+ ERR_FAIL_NULL(reflection_probe);
if (reflection_probe->size == p_size) {
return;
@@ -1082,7 +1082,7 @@ void LightStorage::reflection_probe_set_size(RID p_probe, const Vector3 &p_size)
void LightStorage::reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) {
ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND(!reflection_probe);
+ ERR_FAIL_NULL(reflection_probe);
reflection_probe->origin_offset = p_offset;
reflection_probe->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_REFLECTION_PROBE);
@@ -1090,7 +1090,7 @@ void LightStorage::reflection_probe_set_origin_offset(RID p_probe, const Vector3
void LightStorage::reflection_probe_set_as_interior(RID p_probe, bool p_enable) {
ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND(!reflection_probe);
+ ERR_FAIL_NULL(reflection_probe);
reflection_probe->interior = p_enable;
reflection_probe->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_REFLECTION_PROBE);
@@ -1098,14 +1098,14 @@ void LightStorage::reflection_probe_set_as_interior(RID p_probe, bool p_enable)
void LightStorage::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) {
ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND(!reflection_probe);
+ ERR_FAIL_NULL(reflection_probe);
reflection_probe->box_projection = p_enable;
}
void LightStorage::reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) {
ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND(!reflection_probe);
+ ERR_FAIL_NULL(reflection_probe);
reflection_probe->enable_shadows = p_enable;
reflection_probe->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_REFLECTION_PROBE);
@@ -1113,7 +1113,7 @@ void LightStorage::reflection_probe_set_enable_shadows(RID p_probe, bool p_enabl
void LightStorage::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) {
ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND(!reflection_probe);
+ ERR_FAIL_NULL(reflection_probe);
reflection_probe->cull_mask = p_layers;
reflection_probe->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_REFLECTION_PROBE);
@@ -1121,7 +1121,7 @@ void LightStorage::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers
void LightStorage::reflection_probe_set_resolution(RID p_probe, int p_resolution) {
ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND(!reflection_probe);
+ ERR_FAIL_NULL(reflection_probe);
ERR_FAIL_COND(p_resolution < 32);
reflection_probe->resolution = p_resolution;
@@ -1129,7 +1129,7 @@ void LightStorage::reflection_probe_set_resolution(RID p_probe, int p_resolution
void LightStorage::reflection_probe_set_mesh_lod_threshold(RID p_probe, float p_ratio) {
ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND(!reflection_probe);
+ ERR_FAIL_NULL(reflection_probe);
reflection_probe->mesh_lod_threshold = p_ratio;
@@ -1138,14 +1138,14 @@ void LightStorage::reflection_probe_set_mesh_lod_threshold(RID p_probe, float p_
void LightStorage::reflection_probe_set_baked_exposure(RID p_probe, float p_exposure) {
ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND(!reflection_probe);
+ ERR_FAIL_NULL(reflection_probe);
reflection_probe->baked_exposure = p_exposure;
}
AABB LightStorage::reflection_probe_get_aabb(RID p_probe) const {
const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, AABB());
+ ERR_FAIL_NULL_V(reflection_probe, AABB());
AABB aabb;
aabb.position = -reflection_probe->size / 2;
@@ -1156,103 +1156,103 @@ AABB LightStorage::reflection_probe_get_aabb(RID p_probe) const {
RS::ReflectionProbeUpdateMode LightStorage::reflection_probe_get_update_mode(RID p_probe) const {
const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, RS::REFLECTION_PROBE_UPDATE_ALWAYS);
+ ERR_FAIL_NULL_V(reflection_probe, RS::REFLECTION_PROBE_UPDATE_ALWAYS);
return reflection_probe->update_mode;
}
uint32_t LightStorage::reflection_probe_get_cull_mask(RID p_probe) const {
const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, 0);
+ ERR_FAIL_NULL_V(reflection_probe, 0);
return reflection_probe->cull_mask;
}
Vector3 LightStorage::reflection_probe_get_size(RID p_probe) const {
const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, Vector3());
+ ERR_FAIL_NULL_V(reflection_probe, Vector3());
return reflection_probe->size;
}
Vector3 LightStorage::reflection_probe_get_origin_offset(RID p_probe) const {
const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, Vector3());
+ ERR_FAIL_NULL_V(reflection_probe, Vector3());
return reflection_probe->origin_offset;
}
bool LightStorage::reflection_probe_renders_shadows(RID p_probe) const {
const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, false);
+ ERR_FAIL_NULL_V(reflection_probe, false);
return reflection_probe->enable_shadows;
}
float LightStorage::reflection_probe_get_origin_max_distance(RID p_probe) const {
const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, 0);
+ ERR_FAIL_NULL_V(reflection_probe, 0);
return reflection_probe->max_distance;
}
float LightStorage::reflection_probe_get_mesh_lod_threshold(RID p_probe) const {
const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, 0);
+ ERR_FAIL_NULL_V(reflection_probe, 0);
return reflection_probe->mesh_lod_threshold;
}
int LightStorage::reflection_probe_get_resolution(RID p_probe) const {
const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, 0);
+ ERR_FAIL_NULL_V(reflection_probe, 0);
return reflection_probe->resolution;
}
float LightStorage::reflection_probe_get_baked_exposure(RID p_probe) const {
const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, 1.0);
+ ERR_FAIL_NULL_V(reflection_probe, 1.0);
return reflection_probe->baked_exposure;
}
float LightStorage::reflection_probe_get_intensity(RID p_probe) const {
const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, 0);
+ ERR_FAIL_NULL_V(reflection_probe, 0);
return reflection_probe->intensity;
}
bool LightStorage::reflection_probe_is_interior(RID p_probe) const {
const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, false);
+ ERR_FAIL_NULL_V(reflection_probe, false);
return reflection_probe->interior;
}
bool LightStorage::reflection_probe_is_box_projection(RID p_probe) const {
const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, false);
+ ERR_FAIL_NULL_V(reflection_probe, false);
return reflection_probe->box_projection;
}
RS::ReflectionProbeAmbientMode LightStorage::reflection_probe_get_ambient_mode(RID p_probe) const {
const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, RS::REFLECTION_PROBE_AMBIENT_DISABLED);
+ ERR_FAIL_NULL_V(reflection_probe, RS::REFLECTION_PROBE_AMBIENT_DISABLED);
return reflection_probe->ambient_mode;
}
Color LightStorage::reflection_probe_get_ambient_color(RID p_probe) const {
const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, Color());
+ ERR_FAIL_NULL_V(reflection_probe, Color());
return reflection_probe->ambient_color;
}
float LightStorage::reflection_probe_get_ambient_color_energy(RID p_probe) const {
const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, 0);
+ ERR_FAIL_NULL_V(reflection_probe, 0);
return reflection_probe->ambient_color_energy;
}
@@ -1286,7 +1286,7 @@ void LightStorage::reflection_atlas_free(RID p_ref_atlas) {
void LightStorage::reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) {
ReflectionAtlas *ra = reflection_atlas_owner.get_or_null(p_ref_atlas);
- ERR_FAIL_COND(!ra);
+ ERR_FAIL_NULL(ra);
if (ra->size == p_reflection_size && ra->count == p_reflection_count) {
return; //no changes
@@ -1325,7 +1325,7 @@ void LightStorage::reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_s
int LightStorage::reflection_atlas_get_size(RID p_ref_atlas) const {
ReflectionAtlas *ra = reflection_atlas_owner.get_or_null(p_ref_atlas);
- ERR_FAIL_COND_V(!ra, 0);
+ ERR_FAIL_NULL_V(ra, 0);
return ra->size;
}
@@ -1349,7 +1349,7 @@ void LightStorage::reflection_probe_instance_free(RID p_instance) {
void LightStorage::reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) {
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!rpi);
+ ERR_FAIL_NULL(rpi);
rpi->transform = p_transform;
rpi->dirty = true;
@@ -1357,13 +1357,13 @@ void LightStorage::reflection_probe_instance_set_transform(RID p_instance, const
void LightStorage::reflection_probe_release_atlas_index(RID p_instance) {
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!rpi);
+ ERR_FAIL_NULL(rpi);
if (rpi->atlas.is_null()) {
return; //nothing to release
}
ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas);
- ERR_FAIL_COND(!atlas);
+ ERR_FAIL_NULL(atlas);
ERR_FAIL_INDEX(rpi->atlas_index, atlas->reflections.size());
atlas->reflections.write[rpi->atlas_index].owner = RID();
@@ -1375,7 +1375,7 @@ void LightStorage::reflection_probe_release_atlas_index(RID p_instance) {
bool LightStorage::reflection_probe_instance_needs_redraw(RID p_instance) {
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND_V(!rpi, false);
+ ERR_FAIL_NULL_V(rpi, false);
if (rpi->rendering) {
return false;
@@ -1394,7 +1394,7 @@ bool LightStorage::reflection_probe_instance_needs_redraw(RID p_instance) {
bool LightStorage::reflection_probe_instance_has_reflection(RID p_instance) {
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND_V(!rpi, false);
+ ERR_FAIL_NULL_V(rpi, false);
return rpi->atlas.is_valid();
}
@@ -1402,10 +1402,10 @@ bool LightStorage::reflection_probe_instance_has_reflection(RID p_instance) {
bool LightStorage::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) {
ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(p_reflection_atlas);
- ERR_FAIL_COND_V(!atlas, false);
+ ERR_FAIL_NULL_V(atlas, false);
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND_V(!rpi, false);
+ ERR_FAIL_NULL_V(rpi, false);
if (atlas->render_buffers.is_null()) {
atlas->render_buffers.instantiate();
@@ -1511,14 +1511,14 @@ bool LightStorage::reflection_probe_instance_begin_render(RID p_instance, RID p_
Ref<RenderSceneBuffers> LightStorage::reflection_probe_atlas_get_render_buffers(RID p_reflection_atlas) {
ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(p_reflection_atlas);
- ERR_FAIL_COND_V(!atlas, Ref<RenderSceneBuffersRD>());
+ ERR_FAIL_NULL_V(atlas, Ref<RenderSceneBuffersRD>());
return atlas->render_buffers;
}
bool LightStorage::reflection_probe_instance_postprocess_step(RID p_instance) {
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND_V(!rpi, false);
+ ERR_FAIL_NULL_V(rpi, false);
ERR_FAIL_COND_V(!rpi->rendering, false);
ERR_FAIL_COND_V(rpi->atlas.is_null(), false);
@@ -1569,30 +1569,30 @@ bool LightStorage::reflection_probe_instance_postprocess_step(RID p_instance) {
uint32_t LightStorage::reflection_probe_instance_get_resolution(RID p_instance) {
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND_V(!rpi, 0);
+ ERR_FAIL_NULL_V(rpi, 0);
ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas);
- ERR_FAIL_COND_V(!atlas, 0);
+ ERR_FAIL_NULL_V(atlas, 0);
return atlas->size;
}
RID LightStorage::reflection_probe_instance_get_framebuffer(RID p_instance, int p_index) {
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND_V(!rpi, RID());
+ ERR_FAIL_NULL_V(rpi, RID());
ERR_FAIL_INDEX_V(p_index, 6, RID());
ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas);
- ERR_FAIL_COND_V(!atlas, RID());
+ ERR_FAIL_NULL_V(atlas, RID());
return atlas->reflections[rpi->atlas_index].fbs[p_index];
}
RID LightStorage::reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index) {
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND_V(!rpi, RID());
+ ERR_FAIL_NULL_V(rpi, RID());
ERR_FAIL_INDEX_V(p_index, 6, RID());
ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas);
- ERR_FAIL_COND_V(!atlas, RID());
+ ERR_FAIL_NULL_V(atlas, RID());
return atlas->depth_fb;
}
@@ -1747,7 +1747,7 @@ void LightStorage::lightmap_set_textures(RID p_lightmap, RID p_light, bool p_use
TextureStorage *texture_storage = TextureStorage::get_singleton();
Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
- ERR_FAIL_COND(!lm);
+ ERR_FAIL_NULL(lm);
lightmap_array_version++;
@@ -1795,19 +1795,19 @@ void LightStorage::lightmap_set_textures(RID p_lightmap, RID p_light, bool p_use
void LightStorage::lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) {
Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
- ERR_FAIL_COND(!lm);
+ ERR_FAIL_NULL(lm);
lm->bounds = p_bounds;
}
void LightStorage::lightmap_set_probe_interior(RID p_lightmap, bool p_interior) {
Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
- ERR_FAIL_COND(!lm);
+ ERR_FAIL_NULL(lm);
lm->interior = p_interior;
}
void LightStorage::lightmap_set_probe_capture_data(RID p_lightmap, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) {
Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
- ERR_FAIL_COND(!lm);
+ ERR_FAIL_NULL(lm);
if (p_points.size()) {
ERR_FAIL_COND(p_points.size() * 9 != p_point_sh.size());
@@ -1823,33 +1823,33 @@ void LightStorage::lightmap_set_probe_capture_data(RID p_lightmap, const PackedV
void LightStorage::lightmap_set_baked_exposure_normalization(RID p_lightmap, float p_exposure) {
Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
- ERR_FAIL_COND(!lm);
+ ERR_FAIL_NULL(lm);
lm->baked_exposure = p_exposure;
}
PackedVector3Array LightStorage::lightmap_get_probe_capture_points(RID p_lightmap) const {
Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
- ERR_FAIL_COND_V(!lm, PackedVector3Array());
+ ERR_FAIL_NULL_V(lm, PackedVector3Array());
return lm->points;
}
PackedColorArray LightStorage::lightmap_get_probe_capture_sh(RID p_lightmap) const {
Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
- ERR_FAIL_COND_V(!lm, PackedColorArray());
+ ERR_FAIL_NULL_V(lm, PackedColorArray());
return lm->point_sh;
}
PackedInt32Array LightStorage::lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const {
Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
- ERR_FAIL_COND_V(!lm, PackedInt32Array());
+ ERR_FAIL_NULL_V(lm, PackedInt32Array());
return lm->tetrahedra;
}
PackedInt32Array LightStorage::lightmap_get_probe_capture_bsp_tree(RID p_lightmap) const {
Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
- ERR_FAIL_COND_V(!lm, PackedInt32Array());
+ ERR_FAIL_NULL_V(lm, PackedInt32Array());
return lm->bsp_tree;
}
@@ -1866,7 +1866,7 @@ Dependency *LightStorage::lightmap_get_dependency(RID p_lightmap) const {
void LightStorage::lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_point, Color *r_sh) {
Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
- ERR_FAIL_COND(!lm);
+ ERR_FAIL_NULL(lm);
for (int i = 0; i < 9; i++) {
r_sh[i] = Color(0, 0, 0, 0);
@@ -1916,13 +1916,13 @@ void LightStorage::lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_point,
bool LightStorage::lightmap_is_interior(RID p_lightmap) const {
const Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
- ERR_FAIL_COND_V(!lm, false);
+ ERR_FAIL_NULL_V(lm, false);
return lm->interior;
}
AABB LightStorage::lightmap_get_aabb(RID p_lightmap) const {
const Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
- ERR_FAIL_COND_V(!lm, AABB());
+ ERR_FAIL_NULL_V(lm, AABB());
return lm->bounds;
}
@@ -1940,7 +1940,7 @@ void LightStorage::lightmap_instance_free(RID p_lightmap) {
void LightStorage::lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) {
LightmapInstance *li = lightmap_instance_owner.get_or_null(p_lightmap);
- ERR_FAIL_COND(!li);
+ ERR_FAIL_NULL(li);
li->transform = p_transform;
}
@@ -1972,7 +1972,7 @@ void LightStorage::_update_shadow_atlas(ShadowAtlas *shadow_atlas) {
void LightStorage::shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits) {
ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas);
- ERR_FAIL_COND(!shadow_atlas);
+ ERR_FAIL_NULL(shadow_atlas);
ERR_FAIL_COND(p_size < 0);
p_size = next_power_of_2(p_size);
@@ -2007,7 +2007,7 @@ void LightStorage::shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits
void LightStorage::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) {
ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas);
- ERR_FAIL_COND(!shadow_atlas);
+ ERR_FAIL_NULL(shadow_atlas);
ERR_FAIL_INDEX(p_quadrant, 4);
ERR_FAIL_INDEX(p_subdivision, 16384);
@@ -2196,10 +2196,10 @@ bool LightStorage::_shadow_atlas_find_omni_shadows(ShadowAtlas *shadow_atlas, in
bool LightStorage::shadow_atlas_update_light(RID p_atlas, RID p_light_instance, float p_coverage, uint64_t p_light_version) {
ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas);
- ERR_FAIL_COND_V(!shadow_atlas, false);
+ ERR_FAIL_NULL_V(shadow_atlas, false);
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
- ERR_FAIL_COND_V(!li, false);
+ ERR_FAIL_NULL_V(li, false);
if (shadow_atlas->size == 0 || shadow_atlas->smallest_subdiv == 0) {
return false;
@@ -2341,7 +2341,7 @@ void LightStorage::_shadow_atlas_invalidate_shadow(ShadowAtlas::Quadrant::Shadow
void LightStorage::shadow_atlas_update(RID p_atlas) {
ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas);
- ERR_FAIL_COND(!shadow_atlas);
+ ERR_FAIL_NULL(shadow_atlas);
_update_shadow_atlas(shadow_atlas);
}
@@ -2416,7 +2416,7 @@ int LightStorage::get_directional_light_shadow_size(RID p_light_intance) {
Rect2i r = _get_directional_shadow_rect(directional_shadow.size, directional_shadow.light_count, 0);
LightInstance *light_instance = light_instance_owner.get_or_null(p_light_intance);
- ERR_FAIL_COND_V(!light_instance, 0);
+ ERR_FAIL_NULL_V(light_instance, 0);
switch (light_directional_get_shadow_mode(light_instance->light)) {
case RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL:
diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.h b/servers/rendering/renderer_rd/storage_rd/light_storage.h
index 512c440ae8..f5b846362a 100644
--- a/servers/rendering/renderer_rd/storage_rd/light_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/light_storage.h
@@ -490,7 +490,7 @@ public:
virtual RS::LightType light_get_type(RID p_light) const override {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL);
+ ERR_FAIL_NULL_V(light, RS::LIGHT_DIRECTIONAL);
return light->type;
}
@@ -498,21 +498,21 @@ public:
virtual float light_get_param(RID p_light, RS::LightParam p_param) override {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, 0);
+ ERR_FAIL_NULL_V(light, 0);
return light->param[p_param];
}
_FORCE_INLINE_ RID light_get_projector(RID p_light) {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, RID());
+ ERR_FAIL_NULL_V(light, RID());
return light->projector;
}
virtual Color light_get_color(RID p_light) override {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, Color());
+ ERR_FAIL_NULL_V(light, Color());
return light->color;
}
@@ -539,35 +539,35 @@ public:
virtual bool light_has_shadow(RID p_light) const override {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL);
+ ERR_FAIL_NULL_V(light, RS::LIGHT_DIRECTIONAL);
return light->shadow;
}
virtual bool light_has_projector(RID p_light) const override {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL);
+ ERR_FAIL_NULL_V(light, RS::LIGHT_DIRECTIONAL);
return TextureStorage::get_singleton()->owns_texture(light->projector);
}
_FORCE_INLINE_ bool light_is_negative(RID p_light) const {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL);
+ ERR_FAIL_NULL_V(light, RS::LIGHT_DIRECTIONAL);
return light->negative;
}
_FORCE_INLINE_ float light_get_transmittance_bias(RID p_light) const {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, 0.0);
+ ERR_FAIL_NULL_V(light, 0.0);
return light->param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS];
}
virtual bool light_get_reverse_cull_face_mode(RID p_light) const override {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, false);
+ ERR_FAIL_NULL_V(light, false);
return light->reverse_cull;
}
@@ -657,7 +657,7 @@ public:
ERR_FAIL_COND_V(!li->shadow_atlases.has(p_shadow_atlas), 0);
#endif
ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas);
- ERR_FAIL_COND_V(!shadow_atlas, 0);
+ ERR_FAIL_NULL_V(shadow_atlas, 0);
#ifdef DEBUG_ENABLED
ERR_FAIL_COND_V(!shadow_atlas->shadow_owners.has(p_light_instance), 0);
#endif
@@ -677,8 +677,7 @@ public:
return li->shadow_transform[p_index].camera;
}
- _FORCE_INLINE_ Transform3D
- light_instance_get_shadow_transform(RID p_light_instance, int p_index) {
+ _FORCE_INLINE_ Transform3D light_instance_get_shadow_transform(RID p_light_instance, int p_index) {
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
return li->shadow_transform[p_index].transform;
}
@@ -835,7 +834,7 @@ public:
_FORCE_INLINE_ RID reflection_atlas_get_texture(RID p_ref_atlas) {
ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(p_ref_atlas);
- ERR_FAIL_COND_V(!atlas, RID());
+ ERR_FAIL_NULL_V(atlas, RID());
return atlas->reflection;
}
@@ -859,47 +858,47 @@ public:
_FORCE_INLINE_ RID reflection_probe_instance_get_probe(RID p_instance) {
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND_V(!rpi, RID());
+ ERR_FAIL_NULL_V(rpi, RID());
return rpi->probe;
}
_FORCE_INLINE_ RendererRD::ForwardID reflection_probe_instance_get_forward_id(RID p_instance) {
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND_V(!rpi, 0);
+ ERR_FAIL_NULL_V(rpi, 0);
return rpi->forward_id;
}
_FORCE_INLINE_ void reflection_probe_instance_set_cull_mask(RID p_instance, uint32_t p_render_pass) {
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!rpi);
+ ERR_FAIL_NULL(rpi);
rpi->cull_mask = p_render_pass;
}
_FORCE_INLINE_ void reflection_probe_instance_set_render_pass(RID p_instance, uint32_t p_render_pass) {
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!rpi);
+ ERR_FAIL_NULL(rpi);
rpi->last_pass = p_render_pass;
}
_FORCE_INLINE_ uint32_t reflection_probe_instance_get_render_pass(RID p_instance) {
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND_V(!rpi, 0);
+ ERR_FAIL_NULL_V(rpi, 0);
return rpi->last_pass;
}
_FORCE_INLINE_ Transform3D reflection_probe_instance_get_transform(RID p_instance) {
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND_V(!rpi, Transform3D());
+ ERR_FAIL_NULL_V(rpi, Transform3D());
return rpi->transform;
}
_FORCE_INLINE_ int reflection_probe_instance_get_atlas_index(RID p_instance) {
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND_V(!rpi, -1);
+ ERR_FAIL_NULL_V(rpi, -1);
return rpi->atlas_index;
}
@@ -942,12 +941,12 @@ public:
}
_FORCE_INLINE_ RID lightmap_get_texture(RID p_lightmap) const {
const Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
- ERR_FAIL_COND_V(!lm, RID());
+ ERR_FAIL_NULL_V(lm, RID());
return lm->light_texture;
}
_FORCE_INLINE_ float lightmap_get_baked_exposure_normalization(RID p_lightmap) const {
const Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
- ERR_FAIL_COND_V(!lm, 1.0);
+ ERR_FAIL_NULL_V(lm, 1.0);
return lm->baked_exposure;
}
_FORCE_INLINE_ int32_t lightmap_get_array_index(RID p_lightmap) const {
@@ -1005,46 +1004,46 @@ public:
virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) override;
virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override;
virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_instance, float p_coverage, uint64_t p_light_version) override;
- _FORCE_INLINE_ bool shadow_atlas_owns_light_instance(RID p_atlas, RID p_light_intance) {
+ _FORCE_INLINE_ bool shadow_atlas_owns_light_instance(RID p_atlas, RID p_light_instance) {
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
- ERR_FAIL_COND_V(!atlas, false);
- return atlas->shadow_owners.has(p_light_intance);
+ ERR_FAIL_NULL_V(atlas, false);
+ return atlas->shadow_owners.has(p_light_instance);
}
- _FORCE_INLINE_ uint32_t shadow_atlas_get_light_instance_key(RID p_atlas, RID p_light_intance) {
+ _FORCE_INLINE_ uint32_t shadow_atlas_get_light_instance_key(RID p_atlas, RID p_light_instance) {
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
- ERR_FAIL_COND_V(!atlas, -1);
- return atlas->shadow_owners[p_light_intance];
+ ERR_FAIL_NULL_V(atlas, -1);
+ return atlas->shadow_owners[p_light_instance];
}
_FORCE_INLINE_ RID shadow_atlas_get_texture(RID p_atlas) {
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
- ERR_FAIL_COND_V(!atlas, RID());
+ ERR_FAIL_NULL_V(atlas, RID());
return atlas->depth;
}
_FORCE_INLINE_ int shadow_atlas_get_size(RID p_atlas) {
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
- ERR_FAIL_COND_V(!atlas, 0);
+ ERR_FAIL_NULL_V(atlas, 0);
return atlas->size;
}
_FORCE_INLINE_ int shadow_atlas_get_quadrant_shadow_size(RID p_atlas, uint32_t p_quadrant) {
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
- ERR_FAIL_COND_V(!atlas, 0);
+ ERR_FAIL_NULL_V(atlas, 0);
ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, 0);
return atlas->quadrants[p_quadrant].shadows.size();
}
_FORCE_INLINE_ uint32_t shadow_atlas_get_quadrant_subdivision(RID p_atlas, uint32_t p_quadrant) {
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
- ERR_FAIL_COND_V(!atlas, 0);
+ ERR_FAIL_NULL_V(atlas, 0);
ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, 0);
return atlas->quadrants[p_quadrant].subdivision;
}
_FORCE_INLINE_ RID shadow_atlas_get_fb(RID p_atlas) {
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
- ERR_FAIL_COND_V(!atlas, RID());
+ ERR_FAIL_NULL_V(atlas, RID());
return atlas->fb;
}
@@ -1053,7 +1052,7 @@ public:
/* DIRECTIONAL SHADOW */
virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override;
- virtual int get_directional_light_shadow_size(RID p_light_intance) override;
+ virtual int get_directional_light_shadow_size(RID p_light_instance) override;
virtual void set_directional_shadow_count(int p_count) override;
Rect2i get_directional_shadow_rect();
diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
index d055f01009..2e8c9d7f8e 100644
--- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
@@ -751,7 +751,7 @@ MaterialStorage::MaterialData::~MaterialData() {
}
}
-void MaterialStorage::MaterialData::update_textures(const HashMap<StringName, Variant> &p_parameters, const HashMap<StringName, HashMap<int, RID>> &p_default_textures, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color) {
+void MaterialStorage::MaterialData::update_textures(const HashMap<StringName, Variant> &p_parameters, const HashMap<StringName, HashMap<int, RID>> &p_default_textures, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color, bool p_3d_material) {
TextureStorage *texture_storage = TextureStorage::get_singleton();
MaterialStorage *material_storage = MaterialStorage::get_singleton();
@@ -917,7 +917,7 @@ void MaterialStorage::MaterialData::update_textures(const HashMap<StringName, Va
if (tex) {
rd_texture = (srgb && tex->rd_texture_srgb.is_valid()) ? tex->rd_texture_srgb : tex->rd_texture;
#ifdef TOOLS_ENABLED
- if (tex->detect_3d_callback && p_use_linear_color) {
+ if (tex->detect_3d_callback && p_3d_material) {
tex->detect_3d_callback(tex->detect_3d_callback_ud);
}
if (tex->detect_normal_callback && (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL || p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL)) {
@@ -931,11 +931,11 @@ void MaterialStorage::MaterialData::update_textures(const HashMap<StringName, Va
roughness_detect_texture = tex;
roughness_channel = RS::TextureDetectRoughnessChannel(p_texture_uniforms[i].hint - ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_R);
}
+#endif // TOOLS_ENABLED
if (tex->render_target) {
tex->render_target->was_used = true;
render_target_cache.push_back(tex->render_target);
}
-#endif
}
if (rd_texture.is_null()) {
rd_texture = texture_storage->texture_rd_get_default(TextureStorage::DEFAULT_RD_TEXTURE_WHITE);
@@ -986,7 +986,7 @@ void MaterialStorage::MaterialData::free_parameters_uniform_set(RID p_uniform_se
}
}
-bool MaterialStorage::MaterialData::update_parameters_uniform_set(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, const HashMap<StringName, HashMap<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, bool p_use_linear_color, uint32_t p_barrier) {
+bool MaterialStorage::MaterialData::update_parameters_uniform_set(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, const HashMap<StringName, HashMap<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, bool p_use_linear_color, bool p_3d_material, uint32_t p_barrier) {
if ((uint32_t)ubo_data.size() != p_ubo_size) {
p_uniform_dirty = true;
if (uniform_buffer.is_valid()) {
@@ -1033,7 +1033,7 @@ bool MaterialStorage::MaterialData::update_parameters_uniform_set(const HashMap<
}
if (p_textures_dirty && tex_uniform_count) {
- update_textures(p_parameters, p_default_texture_params, p_texture_uniforms, texture_cache.ptrw(), p_use_linear_color);
+ update_textures(p_parameters, p_default_texture_params, p_texture_uniforms, texture_cache.ptrw(), p_use_linear_color, p_3d_material);
}
if (p_ubo_size == 0 && (p_texture_uniforms.size() == 0)) {
@@ -1089,6 +1089,37 @@ void MaterialStorage::MaterialData::set_as_used() {
}
///////////////////////////////////////////////////////////////////////////
+// MaterialStorage::Samplers
+
+Vector<RD::Uniform> MaterialStorage::Samplers::get_uniforms(int p_first_index) const {
+ Vector<RD::Uniform> uniforms;
+
+ // Binding ids are aligned with samplers_inc.glsl.
+ uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, p_first_index + 0, rids[RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST][RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED]));
+ uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, p_first_index + 1, rids[RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR][RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED]));
+ uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, p_first_index + 2, rids[RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS][RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED]));
+ uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, p_first_index + 3, rids[RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS][RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED]));
+ uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, p_first_index + 4, rids[RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC][RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED]));
+ uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, p_first_index + 5, rids[RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC][RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED]));
+ uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, p_first_index + 6, rids[RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST][RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED]));
+ uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, p_first_index + 7, rids[RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR][RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED]));
+ uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, p_first_index + 8, rids[RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS][RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED]));
+ uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, p_first_index + 9, rids[RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS][RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED]));
+ uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, p_first_index + 10, rids[RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC][RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED]));
+ uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, p_first_index + 11, rids[RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC][RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED]));
+
+ return uniforms;
+}
+
+bool MaterialStorage::Samplers::is_valid() const {
+ return rids[1][1].is_valid();
+}
+
+bool MaterialStorage::Samplers::is_null() const {
+ return rids[1][1].is_null();
+}
+
+///////////////////////////////////////////////////////////////////////////
// MaterialStorage
MaterialStorage *MaterialStorage::singleton = nullptr;
@@ -1101,108 +1132,23 @@ MaterialStorage::MaterialStorage() {
singleton = this;
//default samplers
- for (int i = 1; i < RS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) {
- for (int j = 1; j < RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) {
- RD::SamplerState sampler_state;
- switch (i) {
- case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST: {
- sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
- sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
- sampler_state.max_lod = 0;
- } break;
- case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR: {
- sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler_state.max_lod = 0;
- } break;
- case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: {
- sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
- sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
- if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) {
- sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
- } else {
- sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
- }
- } break;
- case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: {
- sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
- if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) {
- sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
- } else {
- sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
- }
-
- } break;
- case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC: {
- sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
- sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
- if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) {
- sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
- } else {
- sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
- }
- sampler_state.use_anisotropy = true;
- sampler_state.anisotropy_max = 1 << int(GLOBAL_GET("rendering/textures/default_filters/anisotropic_filtering_level"));
- } break;
- case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC: {
- sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
- if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) {
- sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
- } else {
- sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
- }
- sampler_state.use_anisotropy = true;
- sampler_state.anisotropy_max = 1 << int(GLOBAL_GET("rendering/textures/default_filters/anisotropic_filtering_level"));
-
- } break;
- default: {
- }
- }
- switch (j) {
- case RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED: {
- sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
- sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
- sampler_state.repeat_w = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
-
- } break;
- case RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: {
- sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_REPEAT;
- sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_REPEAT;
- sampler_state.repeat_w = RD::SAMPLER_REPEAT_MODE_REPEAT;
- } break;
- case RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: {
- sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
- sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
- sampler_state.repeat_w = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
- } break;
- default: {
- }
- }
-
- default_rd_samplers[i][j] = RD::get_singleton()->sampler_create(sampler_state);
- }
- }
-
- //custom sampler
- sampler_rd_configure_custom(0.0f);
+ default_samplers = samplers_rd_allocate();
// buffers
{ //create index array for copy shaders
Vector<uint8_t> pv;
- pv.resize(6 * 4);
+ pv.resize(6 * 2);
{
uint8_t *w = pv.ptrw();
- int *p32 = (int *)w;
- p32[0] = 0;
- p32[1] = 1;
- p32[2] = 2;
- p32[3] = 0;
- p32[4] = 2;
- p32[5] = 3;
+ uint16_t *p16 = (uint16_t *)w;
+ p16[0] = 0;
+ p16[1] = 1;
+ p16[2] = 2;
+ p16[3] = 0;
+ p16[4] = 2;
+ p16[5] = 3;
}
- quad_index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, pv);
+ quad_index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT16, pv);
quad_index_array = RD::get_singleton()->index_array_create(quad_index_buffer, 0, 6);
}
@@ -1233,20 +1179,7 @@ MaterialStorage::~MaterialStorage() {
RD::get_singleton()->free(quad_index_buffer); //array gets freed as dependency
//def samplers
- for (int i = 1; i < RS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) {
- for (int j = 1; j < RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) {
- RD::get_singleton()->free(default_rd_samplers[i][j]);
- }
- }
-
- //custom samplers
- for (int i = 1; i < RS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) {
- for (int j = 0; j < RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) {
- if (custom_rd_samplers[i][j].is_valid()) {
- RD::get_singleton()->free(custom_rd_samplers[i][j]);
- }
- }
- }
+ samplers_rd_free(default_samplers);
singleton = nullptr;
}
@@ -1263,102 +1196,6 @@ bool MaterialStorage::free(RID p_rid) {
return false;
}
-/* Samplers */
-
-void MaterialStorage::sampler_rd_configure_custom(float p_mipmap_bias) {
- for (int i = 1; i < RS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) {
- for (int j = 1; j < RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) {
- RD::SamplerState sampler_state;
- switch (i) {
- case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST: {
- sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
- sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
- sampler_state.max_lod = 0;
- } break;
- case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR: {
- sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler_state.max_lod = 0;
- } break;
- case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: {
- sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
- sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
- if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) {
- sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
- } else {
- sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
- }
- sampler_state.lod_bias = p_mipmap_bias;
- } break;
- case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: {
- sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
- if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) {
- sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
- } else {
- sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
- }
- sampler_state.lod_bias = p_mipmap_bias;
-
- } break;
- case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC: {
- sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
- sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
- if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) {
- sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
- } else {
- sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
- }
- sampler_state.lod_bias = p_mipmap_bias;
- sampler_state.use_anisotropy = true;
- sampler_state.anisotropy_max = 1 << int(GLOBAL_GET("rendering/textures/default_filters/anisotropic_filtering_level"));
- } break;
- case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC: {
- sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
- if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) {
- sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
- } else {
- sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
- }
- sampler_state.lod_bias = p_mipmap_bias;
- sampler_state.use_anisotropy = true;
- sampler_state.anisotropy_max = 1 << int(GLOBAL_GET("rendering/textures/default_filters/anisotropic_filtering_level"));
-
- } break;
- default: {
- }
- }
- switch (j) {
- case RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED: {
- sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
- sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
- sampler_state.repeat_w = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
-
- } break;
- case RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: {
- sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_REPEAT;
- sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_REPEAT;
- sampler_state.repeat_w = RD::SAMPLER_REPEAT_MODE_REPEAT;
- } break;
- case RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: {
- sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
- sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
- sampler_state.repeat_w = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
- } break;
- default: {
- }
- }
-
- if (custom_rd_samplers[i][j].is_valid()) {
- RD::get_singleton()->free(custom_rd_samplers[i][j]);
- }
-
- custom_rd_samplers[i][j] = RD::get_singleton()->sampler_create(sampler_state);
- }
- }
-}
-
/* GLOBAL SHADER UNIFORM API */
int32_t MaterialStorage::_global_shader_uniform_allocate(uint32_t p_elements) {
@@ -1821,14 +1658,16 @@ void MaterialStorage::global_shader_parameters_load_settings(bool p_load_texture
if (gvtype >= RS::GLOBAL_VAR_TYPE_SAMPLER2D) {
//textire
if (!p_load_textures) {
- value = RID();
continue;
}
String path = value;
- Ref<Resource> resource = ResourceLoader::load(path);
- ERR_CONTINUE(resource.is_null());
- value = resource;
+ if (path.is_empty()) {
+ value = RID();
+ } else {
+ Ref<Resource> resource = ResourceLoader::load(path);
+ value = resource;
+ }
}
if (global_shader_uniforms.variables.has(name)) {
@@ -1995,7 +1834,7 @@ void MaterialStorage::shader_initialize(RID p_rid) {
void MaterialStorage::shader_free(RID p_rid) {
Shader *shader = shader_owner.get_or_null(p_rid);
- ERR_FAIL_COND(!shader);
+ ERR_FAIL_NULL(shader);
//make material unreference this
while (shader->owners.size()) {
@@ -2011,7 +1850,7 @@ void MaterialStorage::shader_free(RID p_rid) {
void MaterialStorage::shader_set_code(RID p_shader, const String &p_code) {
Shader *shader = shader_owner.get_or_null(p_shader);
- ERR_FAIL_COND(!shader);
+ ERR_FAIL_NULL(shader);
shader->code = p_code;
String mode_string = ShaderLanguage::get_shader_type(p_code);
@@ -2088,7 +1927,7 @@ void MaterialStorage::shader_set_code(RID p_shader, const String &p_code) {
void MaterialStorage::shader_set_path_hint(RID p_shader, const String &p_path) {
Shader *shader = shader_owner.get_or_null(p_shader);
- ERR_FAIL_COND(!shader);
+ ERR_FAIL_NULL(shader);
shader->path_hint = p_path;
if (shader->data) {
@@ -2098,13 +1937,13 @@ void MaterialStorage::shader_set_path_hint(RID p_shader, const String &p_path) {
String MaterialStorage::shader_get_code(RID p_shader) const {
Shader *shader = shader_owner.get_or_null(p_shader);
- ERR_FAIL_COND_V(!shader, String());
+ ERR_FAIL_NULL_V(shader, String());
return shader->code;
}
void MaterialStorage::get_shader_parameter_list(RID p_shader, List<PropertyInfo> *p_param_list) const {
Shader *shader = shader_owner.get_or_null(p_shader);
- ERR_FAIL_COND(!shader);
+ ERR_FAIL_NULL(shader);
if (shader->data) {
return shader->data->get_shader_uniform_list(p_param_list);
}
@@ -2112,7 +1951,7 @@ void MaterialStorage::get_shader_parameter_list(RID p_shader, List<PropertyInfo>
void MaterialStorage::shader_set_default_texture_parameter(RID p_shader, const StringName &p_name, RID p_texture, int p_index) {
Shader *shader = shader_owner.get_or_null(p_shader);
- ERR_FAIL_COND(!shader);
+ ERR_FAIL_NULL(shader);
if (p_texture.is_valid() && TextureStorage::get_singleton()->owns_texture(p_texture)) {
if (!shader->default_texture_parameter.has(p_name)) {
@@ -2139,7 +1978,7 @@ void MaterialStorage::shader_set_default_texture_parameter(RID p_shader, const S
RID MaterialStorage::shader_get_default_texture_parameter(RID p_shader, const StringName &p_name, int p_index) const {
Shader *shader = shader_owner.get_or_null(p_shader);
- ERR_FAIL_COND_V(!shader, RID());
+ ERR_FAIL_NULL_V(shader, RID());
if (shader->default_texture_parameter.has(p_name) && shader->default_texture_parameter[p_name].has(p_index)) {
return shader->default_texture_parameter[p_name][p_index];
}
@@ -2149,7 +1988,7 @@ RID MaterialStorage::shader_get_default_texture_parameter(RID p_shader, const St
Variant MaterialStorage::shader_get_parameter_default(RID p_shader, const StringName &p_param) const {
Shader *shader = shader_owner.get_or_null(p_shader);
- ERR_FAIL_COND_V(!shader, Variant());
+ ERR_FAIL_NULL_V(shader, Variant());
if (shader->data) {
return shader->data->get_default_parameter(p_param);
}
@@ -2163,7 +2002,7 @@ void MaterialStorage::shader_set_data_request_function(ShaderType p_shader_type,
RS::ShaderNativeSourceCode MaterialStorage::shader_get_native_source_code(RID p_shader) const {
Shader *shader = shader_owner.get_or_null(p_shader);
- ERR_FAIL_COND_V(!shader, RS::ShaderNativeSourceCode());
+ ERR_FAIL_NULL_V(shader, RS::ShaderNativeSourceCode());
if (shader->data) {
return shader->data->get_native_source_code();
}
@@ -2228,7 +2067,7 @@ void MaterialStorage::material_initialize(RID p_rid) {
void MaterialStorage::material_free(RID p_rid) {
Material *material = material_owner.get_or_null(p_rid);
- ERR_FAIL_COND(!material);
+ ERR_FAIL_NULL(material);
// Need to clear texture arrays to prevent spin locking of their RID's.
// This happens when the app is being closed.
@@ -2246,7 +2085,7 @@ void MaterialStorage::material_free(RID p_rid) {
void MaterialStorage::material_set_shader(RID p_material, RID p_shader) {
Material *material = material_owner.get_or_null(p_material);
- ERR_FAIL_COND(!material);
+ ERR_FAIL_NULL(material);
if (material->data) {
memdelete(material->data);
@@ -2266,7 +2105,7 @@ void MaterialStorage::material_set_shader(RID p_material, RID p_shader) {
}
Shader *shader = get_shader(p_shader);
- ERR_FAIL_COND(!shader);
+ ERR_FAIL_NULL(shader);
material->shader = shader;
material->shader_type = shader->type;
material->shader_id = p_shader.get_local_index();
@@ -2276,7 +2115,7 @@ void MaterialStorage::material_set_shader(RID p_material, RID p_shader) {
return;
}
- ERR_FAIL_COND(shader->data == nullptr);
+ ERR_FAIL_NULL(shader->data);
material->data = material_data_request_func[shader->type](shader->data);
material->data->self = p_material;
@@ -2298,7 +2137,7 @@ MaterialStorage::ShaderData *MaterialStorage::material_get_shader_data(RID p_mat
void MaterialStorage::material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) {
Material *material = material_owner.get_or_null(p_material);
- ERR_FAIL_COND(!material);
+ ERR_FAIL_NULL(material);
if (p_value.get_type() == Variant::NIL) {
material->params.erase(p_param);
@@ -2317,7 +2156,7 @@ void MaterialStorage::material_set_param(RID p_material, const StringName &p_par
Variant MaterialStorage::material_get_param(RID p_material, const StringName &p_param) const {
Material *material = material_owner.get_or_null(p_material);
- ERR_FAIL_COND_V(!material, Variant());
+ ERR_FAIL_NULL_V(material, Variant());
if (material->params.has(p_param)) {
return material->params[p_param];
} else {
@@ -2327,7 +2166,7 @@ Variant MaterialStorage::material_get_param(RID p_material, const StringName &p_
void MaterialStorage::material_set_next_pass(RID p_material, RID p_next_material) {
Material *material = material_owner.get_or_null(p_material);
- ERR_FAIL_COND(!material);
+ ERR_FAIL_NULL(material);
if (material->next_pass == p_next_material) {
return;
@@ -2343,7 +2182,7 @@ void MaterialStorage::material_set_next_pass(RID p_material, RID p_next_material
void MaterialStorage::material_set_render_priority(RID p_material, int priority) {
Material *material = material_owner.get_or_null(p_material);
- ERR_FAIL_COND(!material);
+ ERR_FAIL_NULL(material);
material->priority = priority;
if (material->data) {
material->data->set_render_priority(priority);
@@ -2353,7 +2192,7 @@ void MaterialStorage::material_set_render_priority(RID p_material, int priority)
bool MaterialStorage::material_is_animated(RID p_material) {
Material *material = material_owner.get_or_null(p_material);
- ERR_FAIL_COND_V(!material, false);
+ ERR_FAIL_NULL_V(material, false);
if (material->shader && material->shader->data) {
if (material->shader->data->is_animated()) {
return true;
@@ -2366,7 +2205,7 @@ bool MaterialStorage::material_is_animated(RID p_material) {
bool MaterialStorage::material_casts_shadows(RID p_material) {
Material *material = material_owner.get_or_null(p_material);
- ERR_FAIL_COND_V(!material, true);
+ ERR_FAIL_NULL_V(material, true);
if (material->shader && material->shader->data) {
if (material->shader->data->casts_shadows()) {
return true;
@@ -2379,7 +2218,7 @@ bool MaterialStorage::material_casts_shadows(RID p_material) {
void MaterialStorage::material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) {
Material *material = material_owner.get_or_null(p_material);
- ERR_FAIL_COND(!material);
+ ERR_FAIL_NULL(material);
if (material->shader && material->shader->data) {
material->shader->data->get_instance_param_list(r_parameters);
@@ -2391,31 +2230,106 @@ void MaterialStorage::material_get_instance_shader_parameters(RID p_material, Li
void MaterialStorage::material_update_dependency(RID p_material, DependencyTracker *p_instance) {
Material *material = material_owner.get_or_null(p_material);
- ERR_FAIL_COND(!material);
+ ERR_FAIL_NULL(material);
p_instance->update_dependency(&material->dependency);
if (material->next_pass.is_valid()) {
material_update_dependency(material->next_pass, p_instance);
}
}
-Vector<RD::Uniform> MaterialStorage::get_default_sampler_uniforms(int first_index) {
- Vector<RD::Uniform> uniforms;
+MaterialStorage::Samplers MaterialStorage::samplers_rd_allocate(float p_mipmap_bias) const {
+ Samplers samplers;
+ samplers.mipmap_bias = p_mipmap_bias;
+ samplers.use_nearest_mipmap_filter = GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter");
+ samplers.anisotropic_filtering_level = int(GLOBAL_GET("rendering/textures/default_filters/anisotropic_filtering_level"));
- // Binding ids are aligned with samplers_inc.glsl.
- uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, first_index + 0, sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)));
- uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, first_index + 1, sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)));
- uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, first_index + 2, sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)));
- uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, first_index + 3, sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)));
- uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, first_index + 4, sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)));
- uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, first_index + 5, sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)));
- uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, first_index + 6, sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED)));
- uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, first_index + 7, sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED)));
- uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, first_index + 8, sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED)));
- uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, first_index + 9, sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED)));
- uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, first_index + 10, sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED)));
- uniforms.push_back(RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, first_index + 11, sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED)));
+ RD::SamplerFilter mip_filter = samplers.use_nearest_mipmap_filter ? RD::SAMPLER_FILTER_NEAREST : RD::SAMPLER_FILTER_LINEAR;
+ float anisotropy_max = float(1 << samplers.anisotropic_filtering_level);
- return uniforms;
+ for (int i = 1; i < RS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) {
+ for (int j = 1; j < RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) {
+ RD::SamplerState sampler_state;
+ switch (i) {
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST: {
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
+ sampler_state.max_lod = 0;
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR: {
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.max_lod = 0;
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: {
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
+ sampler_state.mip_filter = mip_filter;
+ sampler_state.lod_bias = samplers.mipmap_bias;
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: {
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.mip_filter = mip_filter;
+ sampler_state.lod_bias = samplers.mipmap_bias;
+
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC: {
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
+ sampler_state.mip_filter = mip_filter;
+ sampler_state.lod_bias = samplers.mipmap_bias;
+ sampler_state.use_anisotropy = true;
+ sampler_state.anisotropy_max = anisotropy_max;
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC: {
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.mip_filter = mip_filter;
+ sampler_state.lod_bias = samplers.mipmap_bias;
+ sampler_state.use_anisotropy = true;
+ sampler_state.anisotropy_max = anisotropy_max;
+
+ } break;
+ default: {
+ }
+ }
+ switch (j) {
+ case RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED: {
+ sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
+ sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
+ sampler_state.repeat_w = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
+
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: {
+ sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_REPEAT;
+ sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_REPEAT;
+ sampler_state.repeat_w = RD::SAMPLER_REPEAT_MODE_REPEAT;
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: {
+ sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
+ sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
+ sampler_state.repeat_w = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
+ } break;
+ default: {
+ }
+ }
+
+ samplers.rids[i][j] = RD::get_singleton()->sampler_create(sampler_state);
+ }
+ }
+
+ return samplers;
+}
+
+void MaterialStorage::samplers_rd_free(Samplers &p_samplers) const {
+ for (int i = 1; i < RS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) {
+ for (int j = 1; j < RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) {
+ if (p_samplers.rids[i][j].is_valid()) {
+ RD::get_singleton()->free(p_samplers.rids[i][j]);
+ p_samplers.rids[i][j] = RID();
+ }
+ }
+ }
}
void MaterialStorage::material_set_data_request_function(ShaderType p_shader_type, MaterialStorage::MaterialDataRequestFunction p_function) {
diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.h b/servers/rendering/renderer_rd/storage_rd/material_storage.h
index b6da3df783..403fd286b4 100644
--- a/servers/rendering/renderer_rd/storage_rd/material_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/material_storage.h
@@ -78,7 +78,7 @@ public:
struct MaterialData {
Vector<RendererRD::TextureStorage::RenderTarget *> render_target_cache;
void update_uniform_buffer(const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const HashMap<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color);
- void update_textures(const HashMap<StringName, Variant> &p_parameters, const HashMap<StringName, HashMap<int, RID>> &p_default_textures, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color);
+ void update_textures(const HashMap<StringName, Variant> &p_parameters, const HashMap<StringName, HashMap<int, RID>> &p_default_textures, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color, bool p_3d_material);
void set_as_used();
virtual void set_render_priority(int p_priority) = 0;
@@ -87,7 +87,7 @@ public:
virtual ~MaterialData();
//to be used internally by update_parameters, in the most common configuration of material parameters
- bool update_parameters_uniform_set(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, const HashMap<StringName, HashMap<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, bool p_use_linear_color, uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS);
+ bool update_parameters_uniform_set(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, const HashMap<StringName, HashMap<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, RID &r_uniform_set, RID p_shader, uint32_t p_shader_uniform_set, bool p_use_linear_color, bool p_3d_material, uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS);
void free_parameters_uniform_set(RID p_uniform_set);
private:
@@ -105,13 +105,27 @@ public:
Vector<RID> texture_cache;
};
+ struct Samplers {
+ RID rids[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX];
+ float mipmap_bias = 0.0f;
+ bool use_nearest_mipmap_filter = false;
+ int anisotropic_filtering_level = 2;
+
+ _FORCE_INLINE_ RID get_sampler(RS::CanvasItemTextureFilter p_filter, RS::CanvasItemTextureRepeat p_repeat) const {
+ return rids[p_filter][p_repeat];
+ }
+
+ Vector<RD::Uniform> get_uniforms(int p_first_index) const;
+ bool is_valid() const;
+ bool is_null() const;
+ };
+
private:
static MaterialStorage *singleton;
/* Samplers */
- RID default_rd_samplers[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX];
- RID custom_rd_samplers[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX];
+ Samplers default_samplers;
/* Buffers */
@@ -335,18 +349,16 @@ public:
/* Samplers */
+ Samplers samplers_rd_allocate(float p_mipmap_bias = 0.0f) const;
+ void samplers_rd_free(Samplers &p_samplers) const;
+
_FORCE_INLINE_ RID sampler_rd_get_default(RS::CanvasItemTextureFilter p_filter, RS::CanvasItemTextureRepeat p_repeat) {
- return default_rd_samplers[p_filter][p_repeat];
- }
- _FORCE_INLINE_ RID sampler_rd_get_custom(RS::CanvasItemTextureFilter p_filter, RS::CanvasItemTextureRepeat p_repeat) {
- return custom_rd_samplers[p_filter][p_repeat];
+ return default_samplers.get_sampler(p_filter, p_repeat);
}
- void sampler_rd_configure_custom(float mipmap_bias);
-
- Vector<RD::Uniform> get_default_sampler_uniforms(int first_index);
-
- // void sampler_rd_set_default(float p_mipmap_bias);
+ _FORCE_INLINE_ const Samplers &samplers_rd_get_default() const {
+ return default_samplers;
+ }
/* Buffers */
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
index 67b5cdd291..14605b308e 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
@@ -29,7 +29,6 @@
/**************************************************************************/
#include "mesh_storage.h"
-#include "../../rendering_server_globals.h"
using namespace RendererRD;
@@ -229,7 +228,7 @@ void MeshStorage::mesh_free(RID p_rid) {
mesh_clear(p_rid);
mesh_set_shadow_mesh(p_rid, RID());
Mesh *mesh = mesh_owner.get_or_null(p_rid);
- ERR_FAIL_COND(!mesh);
+ ERR_FAIL_NULL(mesh);
mesh->dependency.deleted_notify(p_rid);
if (mesh->instances.size()) {
@@ -249,7 +248,7 @@ void MeshStorage::mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count
ERR_FAIL_COND(p_blend_shape_count < 0);
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND(!mesh);
+ ERR_FAIL_NULL(mesh);
ERR_FAIL_COND(mesh->surface_count > 0); //surfaces already exist
@@ -259,7 +258,7 @@ void MeshStorage::mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count
/// Returns stride
void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND(!mesh);
+ ERR_FAIL_NULL(mesh);
ERR_FAIL_COND(mesh->surface_count == RS::MAX_MESH_SURFACES);
@@ -271,10 +270,10 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
uint32_t skin_stride = 0;
for (int i = 0; i < RS::ARRAY_WEIGHTS; i++) {
- if ((p_surface.format & (1 << i))) {
+ if ((p_surface.format & (1ULL << i))) {
switch (i) {
case RS::ARRAY_VERTEX: {
- if (p_surface.format & RS::ARRAY_FLAG_USE_2D_VERTICES) {
+ if ((p_surface.format & RS::ARRAY_FLAG_USE_2D_VERTICES) || (p_surface.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) {
stride += sizeof(float) * 2;
} else {
stride += sizeof(float) * 3;
@@ -282,22 +281,31 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
} break;
case RS::ARRAY_NORMAL: {
- stride += sizeof(int32_t);
+ stride += sizeof(uint16_t) * 2;
} break;
case RS::ARRAY_TANGENT: {
- stride += sizeof(int32_t);
-
+ if (!(p_surface.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) {
+ stride += sizeof(uint16_t) * 2;
+ }
} break;
case RS::ARRAY_COLOR: {
attrib_stride += sizeof(uint32_t);
} break;
case RS::ARRAY_TEX_UV: {
- attrib_stride += sizeof(float) * 2;
+ if (p_surface.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) {
+ attrib_stride += sizeof(uint16_t) * 2;
+ } else {
+ attrib_stride += sizeof(float) * 2;
+ }
} break;
case RS::ARRAY_TEX_UV2: {
- attrib_stride += sizeof(float) * 2;
+ if (p_surface.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) {
+ attrib_stride += sizeof(uint16_t) * 2;
+ } else {
+ attrib_stride += sizeof(float) * 2;
+ }
} break;
case RS::ARRAY_CUSTOM0:
@@ -339,59 +347,96 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
#endif
- Mesh::Surface *s = memnew(Mesh::Surface);
+ uint64_t surface_version = p_surface.format & (uint64_t(RS::ARRAY_FLAG_FORMAT_VERSION_MASK) << RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT);
+ RS::SurfaceData new_surface = p_surface;
+#ifdef DISABLE_DEPRECATED
- s->format = p_surface.format;
- s->primitive = p_surface.primitive;
+ ERR_FAIL_COND_MSG(surface_version != RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION, "Surface version provided (" + itos(int(surface_version >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT)) + ") does not match current version (" + itos(RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) + ")");
- bool use_as_storage = (p_surface.skin_data.size() || mesh->blend_shape_count > 0);
+#else
- if (p_surface.vertex_data.size()) {
- s->vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.vertex_data.size(), p_surface.vertex_data, use_as_storage);
- s->vertex_buffer_size = p_surface.vertex_data.size();
+ if (surface_version != uint64_t(RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION)) {
+ RS::_fix_surface_compatibility(new_surface);
+ surface_version = new_surface.format & (RS::ARRAY_FLAG_FORMAT_VERSION_MASK << RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT);
+ ERR_FAIL_COND_MSG(surface_version != RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION,
+ "Surface version provided (" +
+ itos((surface_version >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK) +
+ ") does not match current version (" +
+ itos((RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK) +
+ ")");
}
+#endif
- if (p_surface.attribute_data.size()) {
- s->attribute_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.attribute_data.size(), p_surface.attribute_data);
+ Mesh::Surface *s = memnew(Mesh::Surface);
+
+ s->format = new_surface.format;
+ s->primitive = new_surface.primitive;
+
+ bool use_as_storage = (new_surface.skin_data.size() || mesh->blend_shape_count > 0);
+
+ if (new_surface.vertex_data.size()) {
+ // If we have an uncompressed surface that contains normals, but not tangents, we need to differentiate the array
+ // from a compressed array in the shader. To do so, we allow the the normal to read 4 components out of the buffer
+ // But only give it 2 components per normal. So essentially, each vertex reads the next normal in normal.zw.
+ // This allows us to avoid adding a shader permutation, and avoid passing dummy tangents. Since the stride is kept small
+ // this should still be a net win for bandwidth.
+ // If we do this, then the last normal will read past the end of the array. So we need to pad the array with dummy data.
+ if (!(new_surface.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) && (new_surface.format & RS::ARRAY_FORMAT_NORMAL) && !(new_surface.format & RS::ARRAY_FORMAT_TANGENT)) {
+ // Unfortunately, we need to copy the buffer, which is fine as doing a resize triggers a CoW anyway.
+ Vector<uint8_t> new_vertex_data;
+ new_vertex_data.resize_zeroed(new_surface.vertex_data.size() + sizeof(uint16_t) * 2);
+ memcpy(new_vertex_data.ptrw(), new_surface.vertex_data.ptr(), new_surface.vertex_data.size());
+ s->vertex_buffer = RD::get_singleton()->vertex_buffer_create(new_vertex_data.size(), new_vertex_data, use_as_storage);
+ s->vertex_buffer_size = new_vertex_data.size();
+ } else {
+ s->vertex_buffer = RD::get_singleton()->vertex_buffer_create(new_surface.vertex_data.size(), new_surface.vertex_data, use_as_storage);
+ s->vertex_buffer_size = new_surface.vertex_data.size();
+ }
}
- if (p_surface.skin_data.size()) {
- s->skin_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.skin_data.size(), p_surface.skin_data, use_as_storage);
- s->skin_buffer_size = p_surface.skin_data.size();
+
+ if (new_surface.attribute_data.size()) {
+ s->attribute_buffer = RD::get_singleton()->vertex_buffer_create(new_surface.attribute_data.size(), new_surface.attribute_data);
+ }
+ if (new_surface.skin_data.size()) {
+ s->skin_buffer = RD::get_singleton()->vertex_buffer_create(new_surface.skin_data.size(), new_surface.skin_data, use_as_storage);
+ s->skin_buffer_size = new_surface.skin_data.size();
}
- s->vertex_count = p_surface.vertex_count;
+ s->vertex_count = new_surface.vertex_count;
- if (p_surface.format & RS::ARRAY_FORMAT_BONES) {
+ if (new_surface.format & RS::ARRAY_FORMAT_BONES) {
mesh->has_bone_weights = true;
}
- if (p_surface.index_count) {
- bool is_index_16 = p_surface.vertex_count <= 65536 && p_surface.vertex_count > 0;
+ if (new_surface.index_count) {
+ bool is_index_16 = new_surface.vertex_count <= 65536 && new_surface.vertex_count > 0;
- s->index_buffer = RD::get_singleton()->index_buffer_create(p_surface.index_count, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, p_surface.index_data, false);
- s->index_count = p_surface.index_count;
+ s->index_buffer = RD::get_singleton()->index_buffer_create(new_surface.index_count, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, new_surface.index_data, false);
+ s->index_count = new_surface.index_count;
s->index_array = RD::get_singleton()->index_array_create(s->index_buffer, 0, s->index_count);
- if (p_surface.lods.size()) {
- s->lods = memnew_arr(Mesh::Surface::LOD, p_surface.lods.size());
- s->lod_count = p_surface.lods.size();
+ if (new_surface.lods.size()) {
+ s->lods = memnew_arr(Mesh::Surface::LOD, new_surface.lods.size());
+ s->lod_count = new_surface.lods.size();
- for (int i = 0; i < p_surface.lods.size(); i++) {
- uint32_t indices = p_surface.lods[i].index_data.size() / (is_index_16 ? 2 : 4);
- s->lods[i].index_buffer = RD::get_singleton()->index_buffer_create(indices, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, p_surface.lods[i].index_data);
+ for (int i = 0; i < new_surface.lods.size(); i++) {
+ uint32_t indices = new_surface.lods[i].index_data.size() / (is_index_16 ? 2 : 4);
+ s->lods[i].index_buffer = RD::get_singleton()->index_buffer_create(indices, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, new_surface.lods[i].index_data);
s->lods[i].index_array = RD::get_singleton()->index_array_create(s->lods[i].index_buffer, 0, indices);
- s->lods[i].edge_length = p_surface.lods[i].edge_length;
+ s->lods[i].edge_length = new_surface.lods[i].edge_length;
s->lods[i].index_count = indices;
}
}
}
- ERR_FAIL_COND_MSG(!p_surface.index_count && !p_surface.vertex_count, "Meshes must contain a vertex array, an index array, or both");
+ ERR_FAIL_COND_MSG(!new_surface.index_count && !new_surface.vertex_count, "Meshes must contain a vertex array, an index array, or both");
+
+ s->aabb = new_surface.aabb;
+ s->bone_aabbs = new_surface.bone_aabbs; //only really useful for returning them.
- s->aabb = p_surface.aabb;
- s->bone_aabbs = p_surface.bone_aabbs; //only really useful for returning them.
+ s->uv_scale = new_surface.uv_scale;
if (mesh->blend_shape_count > 0) {
- s->blend_shape_buffer = RD::get_singleton()->storage_buffer_create(p_surface.blend_shape_data.size(), p_surface.blend_shape_data);
+ s->blend_shape_buffer = RD::get_singleton()->storage_buffer_create(new_surface.blend_shape_data.size(), new_surface.blend_shape_data);
}
if (use_as_storage) {
@@ -434,13 +479,13 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
}
if (mesh->surface_count == 0) {
- mesh->aabb = p_surface.aabb;
+ mesh->aabb = new_surface.aabb;
} else {
- mesh->aabb.merge_with(p_surface.aabb);
+ mesh->aabb.merge_with(new_surface.aabb);
}
mesh->skeleton_aabb_version = 0;
- s->material = p_surface.material;
+ s->material = new_surface.material;
mesh->surfaces = (Mesh::Surface **)memrealloc(mesh->surfaces, sizeof(Mesh::Surface *) * (mesh->surface_count + 1));
mesh->surfaces[mesh->surface_count] = s;
@@ -463,13 +508,13 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
int MeshStorage::mesh_get_blend_shape_count(RID p_mesh) const {
const Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND_V(!mesh, -1);
+ ERR_FAIL_NULL_V(mesh, -1);
return mesh->blend_shape_count;
}
void MeshStorage::mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND(!mesh);
+ ERR_FAIL_NULL(mesh);
ERR_FAIL_INDEX((int)p_mode, 2);
mesh->blend_shape_mode = p_mode;
@@ -477,13 +522,13 @@ void MeshStorage::mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mod
RS::BlendShapeMode MeshStorage::mesh_get_blend_shape_mode(RID p_mesh) const {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND_V(!mesh, RS::BLEND_SHAPE_MODE_NORMALIZED);
+ ERR_FAIL_NULL_V(mesh, RS::BLEND_SHAPE_MODE_NORMALIZED);
return mesh->blend_shape_mode;
}
void MeshStorage::mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND(!mesh);
+ ERR_FAIL_NULL(mesh);
ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
ERR_FAIL_COND(p_data.size() == 0);
ERR_FAIL_COND(mesh->surfaces[p_surface]->vertex_buffer.is_null());
@@ -495,7 +540,7 @@ void MeshStorage::mesh_surface_update_vertex_region(RID p_mesh, int p_surface, i
void MeshStorage::mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND(!mesh);
+ ERR_FAIL_NULL(mesh);
ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
ERR_FAIL_COND(p_data.size() == 0);
ERR_FAIL_COND(mesh->surfaces[p_surface]->attribute_buffer.is_null());
@@ -507,7 +552,7 @@ void MeshStorage::mesh_surface_update_attribute_region(RID p_mesh, int p_surface
void MeshStorage::mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND(!mesh);
+ ERR_FAIL_NULL(mesh);
ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
ERR_FAIL_COND(p_data.size() == 0);
ERR_FAIL_COND(mesh->surfaces[p_surface]->skin_buffer.is_null());
@@ -519,7 +564,7 @@ void MeshStorage::mesh_surface_update_skin_region(RID p_mesh, int p_surface, int
void MeshStorage::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND(!mesh);
+ ERR_FAIL_NULL(mesh);
ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
mesh->surfaces[p_surface]->material = p_material;
@@ -529,7 +574,7 @@ void MeshStorage::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_mat
RID MeshStorage::mesh_surface_get_material(RID p_mesh, int p_surface) const {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND_V(!mesh, RID());
+ ERR_FAIL_NULL_V(mesh, RID());
ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_surface, mesh->surface_count, RID());
return mesh->surfaces[p_surface]->material;
@@ -537,7 +582,7 @@ RID MeshStorage::mesh_surface_get_material(RID p_mesh, int p_surface) const {
RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND_V(!mesh, RS::SurfaceData());
+ ERR_FAIL_NULL_V(mesh, RS::SurfaceData());
ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_surface, mesh->surface_count, RS::SurfaceData());
Mesh::Surface &s = *mesh->surfaces[p_surface];
@@ -546,6 +591,11 @@ RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const {
sd.format = s.format;
if (s.vertex_buffer.is_valid()) {
sd.vertex_data = RD::get_singleton()->buffer_get_data(s.vertex_buffer);
+ // When using an uncompressed buffer with normals, but without tangents, we have to trim the padding.
+ if (!(s.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) && (s.format & RS::ARRAY_FORMAT_NORMAL) && !(s.format & RS::ARRAY_FORMAT_TANGENT)) {
+ Vector<uint8_t> new_vertex_data;
+ sd.vertex_data.resize(sd.vertex_data.size() - sizeof(uint16_t) * 2);
+ }
}
if (s.attribute_buffer.is_valid()) {
sd.attribute_data = RD::get_singleton()->buffer_get_data(s.attribute_buffer);
@@ -561,6 +611,7 @@ RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const {
sd.index_data = RD::get_singleton()->buffer_get_data(s.index_buffer);
}
sd.aabb = s.aabb;
+ sd.uv_scale = s.uv_scale;
for (uint32_t i = 0; i < s.lod_count; i++) {
RS::SurfaceData::LOD lod;
lod.edge_length = s.lods[i].edge_length;
@@ -579,13 +630,13 @@ RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const {
int MeshStorage::mesh_get_surface_count(RID p_mesh) const {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND_V(!mesh, 0);
+ ERR_FAIL_NULL_V(mesh, 0);
return mesh->surface_count;
}
void MeshStorage::mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND(!mesh);
+ ERR_FAIL_NULL(mesh);
mesh->custom_aabb = p_aabb;
mesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
@@ -593,13 +644,13 @@ void MeshStorage::mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) {
AABB MeshStorage::mesh_get_custom_aabb(RID p_mesh) const {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND_V(!mesh, AABB());
+ ERR_FAIL_NULL_V(mesh, AABB());
return mesh->custom_aabb;
}
AABB MeshStorage::mesh_get_aabb(RID p_mesh, RID p_skeleton) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND_V(!mesh, AABB());
+ ERR_FAIL_NULL_V(mesh, AABB());
if (mesh->custom_aabb != AABB()) {
return mesh->custom_aabb;
@@ -707,7 +758,7 @@ AABB MeshStorage::mesh_get_aabb(RID p_mesh, RID p_skeleton) {
void MeshStorage::mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND(!mesh);
+ ERR_FAIL_NULL(mesh);
Mesh *shadow_mesh = mesh_owner.get_or_null(mesh->shadow_mesh);
if (shadow_mesh) {
@@ -726,7 +777,7 @@ void MeshStorage::mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) {
void MeshStorage::mesh_clear(RID p_mesh) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND(!mesh);
+ ERR_FAIL_NULL(mesh);
// Clear instance data before mesh data.
for (MeshInstance *mi : mesh->instances) {
@@ -784,14 +835,14 @@ void MeshStorage::mesh_clear(RID p_mesh) {
bool MeshStorage::mesh_needs_instance(RID p_mesh, bool p_has_skeleton) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND_V(!mesh, false);
+ ERR_FAIL_NULL_V(mesh, false);
return mesh->blend_shape_count > 0 || (mesh->has_bone_weights && p_has_skeleton);
}
Dependency *MeshStorage::mesh_get_dependency(RID p_mesh) const {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND_V(!mesh, nullptr);
+ ERR_FAIL_NULL_V(mesh, nullptr);
return &mesh->dependency;
}
@@ -800,7 +851,7 @@ Dependency *MeshStorage::mesh_get_dependency(RID p_mesh) const {
RID MeshStorage::mesh_instance_create(RID p_base) {
Mesh *mesh = mesh_owner.get_or_null(p_base);
- ERR_FAIL_COND_V(!mesh, RID());
+ ERR_FAIL_NULL_V(mesh, RID());
RID rid = mesh_instance_owner.make_rid();
MeshInstance *mi = mesh_instance_owner.get_or_null(rid);
@@ -839,7 +890,7 @@ void MeshStorage::mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton
void MeshStorage::mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) {
MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
- ERR_FAIL_COND(!mi);
+ ERR_FAIL_NULL(mi);
ERR_FAIL_INDEX(p_shape, (int)mi->blend_weights.size());
mi->blend_weights[p_shape] = p_weight;
mi->weights_dirty = true;
@@ -854,8 +905,11 @@ void MeshStorage::_mesh_instance_clear(MeshInstance *mi) {
}
memfree(surface.versions);
}
- if (surface.vertex_buffer.is_valid()) {
- RD::get_singleton()->free(surface.vertex_buffer);
+
+ for (uint32_t i = 0; i < 2; i++) {
+ if (surface.vertex_buffer[i].is_valid()) {
+ RD::get_singleton()->free(surface.vertex_buffer[i]);
+ }
}
}
mi->surfaces.clear();
@@ -881,35 +935,38 @@ void MeshStorage::_mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint3
MeshInstance::Surface s;
if ((mesh->blend_shape_count > 0 || (mesh->surfaces[p_surface]->format & RS::ARRAY_FORMAT_BONES)) && mesh->surfaces[p_surface]->vertex_buffer_size > 0) {
- //surface warrants transform
- s.vertex_buffer = RD::get_singleton()->vertex_buffer_create(mesh->surfaces[p_surface]->vertex_buffer_size, Vector<uint8_t>(), true);
-
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.binding = 1;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.append_id(s.vertex_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 2;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- if (mi->blend_weights_buffer.is_valid()) {
- u.append_id(mi->blend_weights_buffer);
- } else {
- u.append_id(default_rd_storage_buffer);
- }
- uniforms.push_back(u);
- }
- s.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, skeleton_shader.version_shader[0], SkeletonShader::UNIFORM_SET_INSTANCE);
+ _mesh_instance_add_surface_buffer(mi, mesh, &s, p_surface, 0);
}
mi->surfaces.push_back(s);
mi->dirty = true;
}
+void MeshStorage::_mesh_instance_add_surface_buffer(MeshInstance *mi, Mesh *mesh, MeshInstance::Surface *s, uint32_t p_surface, uint32_t p_buffer_index) {
+ s->vertex_buffer[p_buffer_index] = RD::get_singleton()->vertex_buffer_create(mesh->surfaces[p_surface]->vertex_buffer_size, Vector<uint8_t>(), true);
+
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.binding = 1;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.append_id(s->vertex_buffer[p_buffer_index]);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 2;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ if (mi->blend_weights_buffer.is_valid()) {
+ u.append_id(mi->blend_weights_buffer);
+ } else {
+ u.append_id(default_rd_storage_buffer);
+ }
+ uniforms.push_back(u);
+ }
+ s->uniform_set[p_buffer_index] = RD::get_singleton()->uniform_set_create(uniforms, skeleton_shader.version_shader[0], SkeletonShader::UNIFORM_SET_INSTANCE);
+}
+
void MeshStorage::mesh_instance_check_for_update(RID p_mesh_instance) {
MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
@@ -956,6 +1013,8 @@ void MeshStorage::update_mesh_instances() {
}
//process skeletons and blend shapes
+ uint64_t frame = RSG::rasterizer->get_frame_number();
+ bool uses_motion_vectors = (RSG::viewport->get_num_viewports_with_motion_vectors() > 0);
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
while (dirty_mesh_instance_arrays.first()) {
@@ -964,7 +1023,29 @@ void MeshStorage::update_mesh_instances() {
Skeleton *sk = skeleton_owner.get_or_null(mi->skeleton);
for (uint32_t i = 0; i < mi->surfaces.size(); i++) {
- if (mi->surfaces[i].uniform_set == RID() || mi->mesh->surfaces[i]->uniform_set == RID()) {
+ if (mi->surfaces[i].uniform_set[0].is_null() || mi->mesh->surfaces[i]->uniform_set.is_null()) {
+ // Skip over mesh instances that don't require their own uniform buffers.
+ continue;
+ }
+
+ mi->surfaces[i].previous_buffer = mi->surfaces[i].current_buffer;
+
+ if (uses_motion_vectors && (frame - mi->surfaces[i].last_change) == 1) {
+ // Previous buffer's data can only be one frame old to be able to use motion vectors.
+ uint32_t new_buffer_index = mi->surfaces[i].current_buffer ^ 1;
+
+ if (mi->surfaces[i].uniform_set[new_buffer_index].is_null()) {
+ // Create the new vertex buffer on demand where the result for the current frame will be stored.
+ _mesh_instance_add_surface_buffer(mi, mi->mesh, &mi->surfaces[i], i, new_buffer_index);
+ }
+
+ mi->surfaces[i].current_buffer = new_buffer_index;
+ }
+
+ mi->surfaces[i].last_change = frame;
+
+ RID mi_surface_uniform_set = mi->surfaces[i].uniform_set[mi->surfaces[i].current_buffer];
+ if (mi_surface_uniform_set.is_null()) {
continue;
}
@@ -972,7 +1053,7 @@ void MeshStorage::update_mesh_instances() {
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, skeleton_shader.pipeline[array_is_2d ? SkeletonShader::SHADER_MODE_2D : SkeletonShader::SHADER_MODE_3D]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, mi->surfaces[i].uniform_set, SkeletonShader::UNIFORM_SET_INSTANCE);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, mi_surface_uniform_set, SkeletonShader::UNIFORM_SET_INSTANCE);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, mi->mesh->surfaces[i]->uniform_set, SkeletonShader::UNIFORM_SET_SURFACE);
if (sk && sk->uniform_set_mi.is_valid()) {
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sk->uniform_set_mi, SkeletonShader::UNIFORM_SET_SKELETON);
@@ -987,8 +1068,10 @@ void MeshStorage::update_mesh_instances() {
push_constant.has_skeleton = sk != nullptr && sk->use_2d == array_is_2d && (mi->mesh->surfaces[i]->format & RS::ARRAY_FORMAT_BONES);
push_constant.has_blend_shape = mi->mesh->blend_shape_count > 0;
+ push_constant.normal_tangent_stride = (push_constant.has_normal ? 1 : 0) + (push_constant.has_tangent ? 1 : 0);
+
push_constant.vertex_count = mi->mesh->surfaces[i]->vertex_count;
- push_constant.vertex_stride = (mi->mesh->surfaces[i]->vertex_buffer_size / mi->mesh->surfaces[i]->vertex_count) / 4;
+ push_constant.vertex_stride = ((mi->mesh->surfaces[i]->vertex_buffer_size / mi->mesh->surfaces[i]->vertex_count) / 4) - push_constant.normal_tangent_stride;
push_constant.skin_stride = (mi->mesh->surfaces[i]->skin_buffer_size / mi->mesh->surfaces[i]->vertex_count) / 4;
push_constant.skin_weight_offset = (mi->mesh->surfaces[i]->format & RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 4 : 2;
@@ -1013,7 +1096,6 @@ void MeshStorage::update_mesh_instances() {
push_constant.blend_shape_count = mi->mesh->blend_shape_count;
push_constant.normalized_blend_shapes = mi->mesh->blend_shape_mode == RS::BLEND_SHAPE_MODE_NORMALIZED;
- push_constant.pad0 = 0;
push_constant.pad1 = 0;
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SkeletonShader::PushConstant));
@@ -1032,11 +1114,13 @@ void MeshStorage::update_mesh_instances() {
RD::get_singleton()->compute_list_end();
}
-void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, MeshInstance::Surface *mis) {
+void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint64_t p_input_mask, bool p_input_motion_vectors, MeshInstance::Surface *mis, uint32_t p_current_buffer, uint32_t p_previous_buffer) {
Vector<RD::VertexAttribute> attributes;
Vector<RID> buffers;
+ Vector<uint64_t> offsets;
- uint32_t stride = 0;
+ uint32_t position_stride = 0;
+ uint32_t normal_tangent_stride = 0;
uint32_t attribute_stride = 0;
uint32_t skin_stride = 0;
@@ -1044,8 +1128,9 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
RD::VertexAttribute vd;
RID buffer;
vd.location = i;
+ uint64_t offset = 0;
- if (!(s->format & (1 << i))) {
+ if (!(s->format & (1ULL << i))) {
// Not supplied by surface, use default value
buffer = mesh_default_rd_buffers[i];
vd.stride = 0;
@@ -1094,45 +1179,56 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
switch (i) {
case RS::ARRAY_VERTEX: {
- vd.offset = stride;
+ vd.offset = position_stride;
if (s->format & RS::ARRAY_FLAG_USE_2D_VERTICES) {
vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
- stride += sizeof(float) * 2;
+ position_stride = sizeof(float) * 2;
} else {
- vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
- stride += sizeof(float) * 3;
+ if (!mis && (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) {
+ vd.format = RD::DATA_FORMAT_R16G16B16A16_UNORM;
+ position_stride = sizeof(uint16_t) * 4;
+ } else {
+ vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
+ position_stride = sizeof(float) * 3;
+ }
}
if (mis) {
- buffer = mis->vertex_buffer;
+ buffer = mis->vertex_buffer[p_current_buffer];
} else {
buffer = s->vertex_buffer;
}
} break;
case RS::ARRAY_NORMAL: {
- vd.offset = stride;
- vd.format = RD::DATA_FORMAT_R16G16_UNORM;
- stride += sizeof(uint16_t) * 2;
-
- if (mis) {
- buffer = mis->vertex_buffer;
+ vd.offset = 0;
+ offset = position_stride * s->vertex_count;
+ if (!mis && (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) {
+ vd.format = RD::DATA_FORMAT_R16G16_UNORM;
+ normal_tangent_stride += sizeof(uint16_t) * 2;
} else {
- buffer = s->vertex_buffer;
+ vd.format = RD::DATA_FORMAT_R16G16B16A16_UNORM;
+ // A small trick here: if we are uncompressed and we have normals, but no tangents. We need
+ // the shader to think there are 4 components to "axis_tangent_attrib". So we give a size of 4,
+ // but a stride based on only having 2 elements.
+ if (!(s->format & RS::ARRAY_FORMAT_TANGENT)) {
+ normal_tangent_stride += sizeof(uint16_t) * 2;
+ } else {
+ normal_tangent_stride += sizeof(uint16_t) * 4;
+ }
}
- } break;
- case RS::ARRAY_TANGENT: {
- vd.offset = stride;
- vd.format = RD::DATA_FORMAT_R16G16_UNORM;
- stride += sizeof(uint16_t) * 2;
-
if (mis) {
- buffer = mis->vertex_buffer;
+ buffer = mis->vertex_buffer[p_current_buffer];
} else {
buffer = s->vertex_buffer;
}
} break;
+ case RS::ARRAY_TANGENT: {
+ buffer = mesh_default_rd_buffers[i];
+ vd.stride = 0;
+ vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
+ } break;
case RS::ARRAY_COLOR: {
vd.offset = attribute_stride;
@@ -1142,17 +1238,25 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
} break;
case RS::ARRAY_TEX_UV: {
vd.offset = attribute_stride;
-
- vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
- attribute_stride += sizeof(float) * 2;
+ if (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) {
+ vd.format = RD::DATA_FORMAT_R16G16_UNORM;
+ attribute_stride += sizeof(uint16_t) * 2;
+ } else {
+ vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
+ attribute_stride += sizeof(float) * 2;
+ }
buffer = s->attribute_buffer;
} break;
case RS::ARRAY_TEX_UV2: {
vd.offset = attribute_stride;
-
- vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
- attribute_stride += sizeof(float) * 2;
+ if (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) {
+ vd.format = RD::DATA_FORMAT_R16G16_UNORM;
+ attribute_stride += sizeof(uint16_t) * 2;
+ } else {
+ vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
+ attribute_stride += sizeof(float) * 2;
+ }
buffer = s->attribute_buffer;
} break;
case RS::ARRAY_CUSTOM0:
@@ -1187,12 +1291,40 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
}
}
- if (!(p_input_mask & (1 << i))) {
+ if (!(p_input_mask & (1ULL << i))) {
continue; // Shader does not need this, skip it (but computing stride was important anyway)
}
attributes.push_back(vd);
buffers.push_back(buffer);
+ offsets.push_back(offset);
+
+ if (p_input_motion_vectors) {
+ // Since the previous vertex, normal and tangent can't be part of the vertex format but they are required when motion
+ // vectors are enabled, we opt to push a copy of the vertex attribute with a different location and buffer (if it's
+ // part of an instance that has one).
+ switch (i) {
+ case RS::ARRAY_VERTEX: {
+ vd.location = ATTRIBUTE_LOCATION_PREV_VERTEX;
+ } break;
+ case RS::ARRAY_NORMAL: {
+ vd.location = ATTRIBUTE_LOCATION_PREV_NORMAL;
+ } break;
+ case RS::ARRAY_TANGENT: {
+ vd.location = ATTRIBUTE_LOCATION_PREV_TANGENT;
+ } break;
+ }
+
+ if (int(vd.location) != i) {
+ if (mis && buffer != mesh_default_rd_buffers[i]) {
+ buffer = mis->vertex_buffer[p_previous_buffer];
+ }
+
+ attributes.push_back(vd);
+ buffers.push_back(buffer);
+ offsets.push_back(offset);
+ }
+ }
}
//update final stride
@@ -1201,9 +1333,10 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
continue; //default location
}
int loc = attributes[i].location;
-
- if (loc < RS::ARRAY_COLOR) {
- attributes.write[i].stride = stride;
+ if (loc == RS::ARRAY_VERTEX || loc == ATTRIBUTE_LOCATION_PREV_VERTEX) {
+ attributes.write[i].stride = position_stride;
+ } else if ((loc < RS::ARRAY_COLOR) || ((loc >= ATTRIBUTE_LOCATION_PREV_NORMAL) && (loc <= ATTRIBUTE_LOCATION_PREV_TANGENT))) {
+ attributes.write[i].stride = normal_tangent_stride;
} else if (loc < RS::ARRAY_BONES) {
attributes.write[i].stride = attribute_stride;
} else {
@@ -1212,8 +1345,11 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
}
v.input_mask = p_input_mask;
+ v.current_buffer = p_current_buffer;
+ v.previous_buffer = p_previous_buffer;
+ v.input_motion_vectors = p_input_motion_vectors;
v.vertex_format = RD::get_singleton()->vertex_format_create(attributes);
- v.vertex_array = RD::get_singleton()->vertex_array_create(s->vertex_count, v.vertex_format, buffers);
+ v.vertex_array = RD::get_singleton()->vertex_array_create(s->vertex_count, v.vertex_format, buffers, offsets);
}
////////////////// MULTIMESH
@@ -1235,7 +1371,7 @@ void MeshStorage::multimesh_free(RID p_rid) {
void MeshStorage::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors, bool p_use_custom_data) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_NULL(multimesh);
if (multimesh->instances == p_instances && multimesh->xform_format == p_transform_format && multimesh->uses_colors == p_use_colors && multimesh->uses_custom_data == p_use_custom_data) {
return;
@@ -1289,12 +1425,9 @@ void MeshStorage::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::
multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MULTIMESH);
}
-bool MeshStorage::_multimesh_enable_motion_vectors(RID p_multimesh) {
- MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, false);
-
+void MeshStorage::_multimesh_enable_motion_vectors(MultiMesh *multimesh) {
if (multimesh->motion_vectors_enabled) {
- return false;
+ return;
}
multimesh->motion_vectors_enabled = true;
@@ -1307,43 +1440,57 @@ bool MeshStorage::_multimesh_enable_motion_vectors(RID p_multimesh) {
multimesh->data_cache.append_array(multimesh->data_cache);
}
- if (multimesh->buffer_set) {
+ uint32_t buffer_size = multimesh->instances * multimesh->stride_cache * sizeof(float);
+ uint32_t new_buffer_size = buffer_size * 2;
+ RID new_buffer = RD::get_singleton()->storage_buffer_create(new_buffer_size);
+
+ if (multimesh->buffer_set && multimesh->data_cache.is_empty()) {
+ // If the buffer was set but there's no data cached in the CPU, we copy the buffer directly on the GPU.
RD::get_singleton()->barrier();
- Vector<uint8_t> buffer_data = RD::get_singleton()->buffer_get_data(multimesh->buffer);
- if (!multimesh->data_cache.is_empty()) {
- memcpy(buffer_data.ptrw(), multimesh->data_cache.ptr(), buffer_data.size());
- }
+ RD::get_singleton()->buffer_copy(multimesh->buffer, new_buffer, 0, 0, buffer_size, RD::BARRIER_MASK_NO_BARRIER);
+ RD::get_singleton()->buffer_copy(multimesh->buffer, new_buffer, 0, buffer_size, buffer_size);
+ } else if (!multimesh->data_cache.is_empty()) {
+ // Simply upload the data cached in the CPU, which should already be doubled in size.
+ ERR_FAIL_COND(multimesh->data_cache.size() * sizeof(float) != size_t(new_buffer_size));
+ RD::get_singleton()->buffer_update(new_buffer, 0, new_buffer_size, multimesh->data_cache.ptr());
+ }
+ if (multimesh->buffer.is_valid()) {
RD::get_singleton()->free(multimesh->buffer);
- uint32_t buffer_size = multimesh->instances * multimesh->stride_cache * sizeof(float) * 2;
- multimesh->buffer = RD::get_singleton()->storage_buffer_create(buffer_size);
- RD::get_singleton()->buffer_update(multimesh->buffer, 0, buffer_data.size(), buffer_data.ptr(), RD::BARRIER_MASK_NO_BARRIER);
- RD::get_singleton()->buffer_update(multimesh->buffer, buffer_data.size(), buffer_data.size(), buffer_data.ptr());
- multimesh->uniform_set_3d = RID(); // Cleared by dependency
- return true;
}
- return false; // Update the transforms uniform set cache
+
+ multimesh->buffer = new_buffer;
+ multimesh->uniform_set_3d = RID(); // Cleared by dependency.
+
+ // Invalidate any references to the buffer that was released and the uniform set that was pointing to it.
+ multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MULTIMESH);
}
void MeshStorage::_multimesh_get_motion_vectors_offsets(RID p_multimesh, uint32_t &r_current_offset, uint32_t &r_prev_offset) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_NULL(multimesh);
r_current_offset = multimesh->motion_vectors_current_offset;
- if (RSG::rasterizer->get_frame_number() - multimesh->motion_vectors_last_change >= 2) {
+ if (!_multimesh_uses_motion_vectors(multimesh)) {
multimesh->motion_vectors_previous_offset = multimesh->motion_vectors_current_offset;
}
r_prev_offset = multimesh->motion_vectors_previous_offset;
}
+bool MeshStorage::_multimesh_uses_motion_vectors_offsets(RID p_multimesh) {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_NULL_V(multimesh, false);
+ return _multimesh_uses_motion_vectors(multimesh);
+}
+
int MeshStorage::multimesh_get_instance_count(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, 0);
+ ERR_FAIL_NULL_V(multimesh, 0);
return multimesh->instances;
}
void MeshStorage::multimesh_set_mesh(RID p_multimesh, RID p_mesh) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_NULL(multimesh);
if (multimesh->mesh == p_mesh) {
return;
}
@@ -1437,6 +1584,10 @@ void MeshStorage::_multimesh_update_motion_vectors_data_cache(MultiMesh *multime
}
}
+bool MeshStorage::_multimesh_uses_motion_vectors(MultiMesh *multimesh) {
+ return (RSG::rasterizer->get_frame_number() - multimesh->motion_vectors_last_change) < 2;
+}
+
void MeshStorage::_multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool p_aabb) {
uint32_t region_index = p_index / MULTIMESH_DIRTY_REGION_SIZE;
#ifdef DEBUG_ENABLED
@@ -1526,11 +1677,17 @@ void MeshStorage::_multimesh_re_create_aabb(MultiMesh *multimesh, const float *p
void MeshStorage::multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_NULL(multimesh);
ERR_FAIL_INDEX(p_index, multimesh->instances);
ERR_FAIL_COND(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_3D);
_multimesh_make_local(multimesh);
+
+ bool uses_motion_vectors = (RSG::viewport->get_num_viewports_with_motion_vectors() > 0);
+ if (uses_motion_vectors) {
+ _multimesh_enable_motion_vectors(multimesh);
+ }
+
_multimesh_update_motion_vectors_data_cache(multimesh);
{
@@ -1557,7 +1714,7 @@ void MeshStorage::multimesh_instance_set_transform(RID p_multimesh, int p_index,
void MeshStorage::multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_NULL(multimesh);
ERR_FAIL_INDEX(p_index, multimesh->instances);
ERR_FAIL_COND(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_2D);
@@ -1584,7 +1741,7 @@ void MeshStorage::multimesh_instance_set_transform_2d(RID p_multimesh, int p_ind
void MeshStorage::multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_NULL(multimesh);
ERR_FAIL_INDEX(p_index, multimesh->instances);
ERR_FAIL_COND(!multimesh->uses_colors);
@@ -1607,7 +1764,7 @@ void MeshStorage::multimesh_instance_set_color(RID p_multimesh, int p_index, con
void MeshStorage::multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_NULL(multimesh);
ERR_FAIL_INDEX(p_index, multimesh->instances);
ERR_FAIL_COND(!multimesh->uses_custom_data);
@@ -1630,21 +1787,21 @@ void MeshStorage::multimesh_instance_set_custom_data(RID p_multimesh, int p_inde
RID MeshStorage::multimesh_get_mesh(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, RID());
+ ERR_FAIL_NULL_V(multimesh, RID());
return multimesh->mesh;
}
Dependency *MeshStorage::multimesh_get_dependency(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, nullptr);
+ ERR_FAIL_NULL_V(multimesh, nullptr);
return &multimesh->dependency;
}
Transform3D MeshStorage::multimesh_instance_get_transform(RID p_multimesh, int p_index) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, Transform3D());
+ ERR_FAIL_NULL_V(multimesh, Transform3D());
ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform3D());
ERR_FAIL_COND_V(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_3D, Transform3D());
@@ -1675,7 +1832,7 @@ Transform3D MeshStorage::multimesh_instance_get_transform(RID p_multimesh, int p
Transform2D MeshStorage::multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, Transform2D());
+ ERR_FAIL_NULL_V(multimesh, Transform2D());
ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform2D());
ERR_FAIL_COND_V(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_2D, Transform2D());
@@ -1700,7 +1857,7 @@ Transform2D MeshStorage::multimesh_instance_get_transform_2d(RID p_multimesh, in
Color MeshStorage::multimesh_instance_get_color(RID p_multimesh, int p_index) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, Color());
+ ERR_FAIL_NULL_V(multimesh, Color());
ERR_FAIL_INDEX_V(p_index, multimesh->instances, Color());
ERR_FAIL_COND_V(!multimesh->uses_colors, Color());
@@ -1723,7 +1880,7 @@ Color MeshStorage::multimesh_instance_get_color(RID p_multimesh, int p_index) co
Color MeshStorage::multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, Color());
+ ERR_FAIL_NULL_V(multimesh, Color());
ERR_FAIL_INDEX_V(p_index, multimesh->instances, Color());
ERR_FAIL_COND_V(!multimesh->uses_custom_data, Color());
@@ -1746,9 +1903,14 @@ Color MeshStorage::multimesh_instance_get_custom_data(RID p_multimesh, int p_ind
void MeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_NULL(multimesh);
ERR_FAIL_COND(p_buffer.size() != (multimesh->instances * (int)multimesh->stride_cache));
+ bool uses_motion_vectors = (RSG::viewport->get_num_viewports_with_motion_vectors() > 0);
+ if (uses_motion_vectors) {
+ _multimesh_enable_motion_vectors(multimesh);
+ }
+
if (multimesh->motion_vectors_enabled) {
uint32_t frame = RSG::rasterizer->get_frame_number();
@@ -1780,7 +1942,7 @@ void MeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_b
Vector<float> MeshStorage::multimesh_get_buffer(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, Vector<float>());
+ ERR_FAIL_NULL_V(multimesh, Vector<float>());
if (multimesh->buffer.is_null()) {
return Vector<float>();
} else {
@@ -1802,7 +1964,7 @@ Vector<float> MeshStorage::multimesh_get_buffer(RID p_multimesh) const {
void MeshStorage::multimesh_set_visible_instances(RID p_multimesh, int p_visible) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_NULL(multimesh);
ERR_FAIL_COND(p_visible < -1 || p_visible > multimesh->instances);
if (multimesh->visible_instances == p_visible) {
return;
@@ -1824,13 +1986,13 @@ void MeshStorage::multimesh_set_visible_instances(RID p_multimesh, int p_visible
int MeshStorage::multimesh_get_visible_instances(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, 0);
+ ERR_FAIL_NULL_V(multimesh, 0);
return multimesh->visible_instances;
}
AABB MeshStorage::multimesh_get_aabb(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, AABB());
+ ERR_FAIL_NULL_V(multimesh, AABB());
if (multimesh->aabb_dirty) {
const_cast<MeshStorage *>(this)->_update_dirty_multimeshes();
}
@@ -1920,7 +2082,7 @@ void MeshStorage::_skeleton_make_dirty(Skeleton *skeleton) {
void MeshStorage::skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton) {
Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
- ERR_FAIL_COND(!skeleton);
+ ERR_FAIL_NULL(skeleton);
ERR_FAIL_COND(p_bones < 0);
if (skeleton->size == p_bones && skeleton->use_2d == p_2d_skeleton) {
@@ -1963,7 +2125,7 @@ void MeshStorage::skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_
int MeshStorage::skeleton_get_bone_count(RID p_skeleton) const {
Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
- ERR_FAIL_COND_V(!skeleton, 0);
+ ERR_FAIL_NULL_V(skeleton, 0);
return skeleton->size;
}
@@ -1971,7 +2133,7 @@ int MeshStorage::skeleton_get_bone_count(RID p_skeleton) const {
void MeshStorage::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) {
Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
- ERR_FAIL_COND(!skeleton);
+ ERR_FAIL_NULL(skeleton);
ERR_FAIL_INDEX(p_bone, skeleton->size);
ERR_FAIL_COND(skeleton->use_2d);
@@ -1996,7 +2158,7 @@ void MeshStorage::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const
Transform3D MeshStorage::skeleton_bone_get_transform(RID p_skeleton, int p_bone) const {
Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
- ERR_FAIL_COND_V(!skeleton, Transform3D());
+ ERR_FAIL_NULL_V(skeleton, Transform3D());
ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform3D());
ERR_FAIL_COND_V(skeleton->use_2d, Transform3D());
@@ -2023,7 +2185,7 @@ Transform3D MeshStorage::skeleton_bone_get_transform(RID p_skeleton, int p_bone)
void MeshStorage::skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) {
Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
- ERR_FAIL_COND(!skeleton);
+ ERR_FAIL_NULL(skeleton);
ERR_FAIL_INDEX(p_bone, skeleton->size);
ERR_FAIL_COND(!skeleton->use_2d);
@@ -2044,7 +2206,7 @@ void MeshStorage::skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, con
Transform2D MeshStorage::skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const {
Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
- ERR_FAIL_COND_V(!skeleton, Transform2D());
+ ERR_FAIL_NULL_V(skeleton, Transform2D());
ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform2D());
ERR_FAIL_COND_V(!skeleton->use_2d, Transform2D());
@@ -2093,7 +2255,7 @@ void MeshStorage::_update_dirty_skeletons() {
void MeshStorage::skeleton_update_dependency(RID p_skeleton, DependencyTracker *p_instance) {
Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
- ERR_FAIL_COND(!skeleton);
+ ERR_FAIL_NULL(skeleton);
p_instance->update_dependency(&skeleton->dependency);
}
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
index 4d46a62a76..f03334baac 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
@@ -31,6 +31,7 @@
#ifndef MESH_STORAGE_RD_H
#define MESH_STORAGE_RD_H
+#include "../../rendering_server_globals.h"
#include "core/templates/local_vector.h"
#include "core/templates/rid_owner.h"
#include "core/templates/self_list.h"
@@ -72,7 +73,7 @@ private:
struct Mesh {
struct Surface {
RS::PrimitiveType primitive = RS::PRIMITIVE_POINTS;
- uint32_t format = 0;
+ uint64_t format = 0;
RID vertex_buffer;
RID attribute_buffer;
@@ -89,7 +90,10 @@ private:
// cache-efficient structure.
struct Version {
- uint32_t input_mask = 0;
+ uint64_t input_mask = 0;
+ uint32_t current_buffer = 0;
+ uint32_t previous_buffer = 0;
+ bool input_motion_vectors = false;
RD::VertexFormatID vertex_format = 0;
RID vertex_array;
};
@@ -116,6 +120,8 @@ private:
Vector<AABB> bone_aabbs;
+ Vector4 uv_scale;
+
RID blend_shape_buffer;
RID material;
@@ -162,8 +168,11 @@ private:
Mesh *mesh = nullptr;
RID skeleton;
struct Surface {
- RID vertex_buffer;
- RID uniform_set;
+ RID vertex_buffer[2];
+ RID uniform_set[2];
+ uint32_t current_buffer = 0;
+ uint32_t previous_buffer = 0;
+ uint64_t last_change = 0;
Mesh::Surface::Version *versions = nullptr; //allocated on demand
uint32_t version_count = 0;
@@ -183,10 +192,11 @@ private:
weight_update_list(this), array_update_list(this) {}
};
- void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, MeshInstance::Surface *mis = nullptr);
+ void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint64_t p_input_mask, bool p_input_motion_vectors, MeshInstance::Surface *mis = nullptr, uint32_t p_current_buffer = 0, uint32_t p_previous_buffer = 0);
void _mesh_instance_clear(MeshInstance *mi);
void _mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface);
+ void _mesh_instance_add_surface_buffer(MeshInstance *mi, Mesh *mesh, MeshInstance::Surface *s, uint32_t p_surface, uint32_t p_buffer_index);
mutable RID_Owner<MeshInstance> mesh_instance_owner;
@@ -234,7 +244,9 @@ private:
MultiMesh *multimesh_dirty_list = nullptr;
_FORCE_INLINE_ void _multimesh_make_local(MultiMesh *multimesh) const;
+ _FORCE_INLINE_ void _multimesh_enable_motion_vectors(MultiMesh *multimesh);
_FORCE_INLINE_ void _multimesh_update_motion_vectors_data_cache(MultiMesh *multimesh);
+ _FORCE_INLINE_ bool _multimesh_uses_motion_vectors(MultiMesh *multimesh);
_FORCE_INLINE_ void _multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool p_aabb);
_FORCE_INLINE_ void _multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, bool p_aabb);
_FORCE_INLINE_ void _multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances);
@@ -255,7 +267,7 @@ private:
uint32_t blend_shape_count;
uint32_t normalized_blend_shapes;
- uint32_t pad0;
+ uint32_t normal_tangent_stride;
uint32_t pad1;
float skeleton_transform_x[2];
float skeleton_transform_y[2];
@@ -310,6 +322,12 @@ private:
Skeleton *skeleton_dirty_list = nullptr;
+ enum AttributeLocation {
+ ATTRIBUTE_LOCATION_PREV_VERTEX = 12,
+ ATTRIBUTE_LOCATION_PREV_NORMAL = 13,
+ ATTRIBUTE_LOCATION_PREV_TANGENT = 14
+ };
+
public:
static MeshStorage *get_singleton();
@@ -361,7 +379,7 @@ public:
_FORCE_INLINE_ const RID *mesh_get_surface_count_and_materials(RID p_mesh, uint32_t &r_surface_count) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND_V(!mesh, nullptr);
+ ERR_FAIL_NULL_V(mesh, nullptr);
r_surface_count = mesh->surface_count;
if (r_surface_count == 0) {
return nullptr;
@@ -378,7 +396,7 @@ public:
_FORCE_INLINE_ void *mesh_get_surface(RID p_mesh, uint32_t p_surface_index) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND_V(!mesh, nullptr);
+ ERR_FAIL_NULL_V(mesh, nullptr);
ERR_FAIL_UNSIGNED_INDEX_V(p_surface_index, mesh->surface_count, nullptr);
return mesh->surfaces[p_surface_index];
@@ -386,7 +404,7 @@ public:
_FORCE_INLINE_ RID mesh_get_shadow_mesh(RID p_mesh) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND_V(!mesh, RID());
+ ERR_FAIL_NULL_V(mesh, RID());
return mesh->shadow_mesh;
}
@@ -406,6 +424,21 @@ public:
return s->index_count ? s->index_count : s->vertex_count;
}
+ _FORCE_INLINE_ AABB mesh_surface_get_aabb(void *p_surface) {
+ Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
+ return s->aabb;
+ }
+
+ _FORCE_INLINE_ uint64_t mesh_surface_get_format(void *p_surface) {
+ Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
+ return s->format;
+ }
+
+ _FORCE_INLINE_ Vector4 mesh_surface_get_uv_scale(void *p_surface) {
+ Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
+ return s->uv_scale;
+ }
+
_FORCE_INLINE_ uint32_t mesh_surface_get_lod(void *p_surface, float p_model_scale, float p_distance_threshold, float p_mesh_lod_threshold, uint32_t &r_index_count) const {
Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
@@ -436,7 +469,7 @@ public:
}
}
- _FORCE_INLINE_ void mesh_surface_get_vertex_arrays_and_format(void *p_surface, uint32_t p_input_mask, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) {
+ _FORCE_INLINE_ void mesh_surface_get_vertex_arrays_and_format(void *p_surface, uint32_t p_input_mask, bool p_input_motion_vectors, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) {
Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
s->version_lock.lock();
@@ -444,9 +477,11 @@ public:
//there will never be more than, at much, 3 or 4 versions, so iterating is the fastest way
for (uint32_t i = 0; i < s->version_count; i++) {
- if (s->versions[i].input_mask != p_input_mask) {
+ if (s->versions[i].input_mask != p_input_mask || s->versions[i].input_motion_vectors != p_input_motion_vectors) {
+ // Find the version that matches the inputs required.
continue;
}
+
//we have this version, hooray
r_vertex_format = s->versions[i].vertex_format;
r_vertex_array_rd = s->versions[i].vertex_array;
@@ -458,7 +493,7 @@ public:
s->version_count++;
s->versions = (Mesh::Surface::Version *)memrealloc(s->versions, sizeof(Mesh::Surface::Version) * s->version_count);
- _mesh_surface_generate_version_for_input_mask(s->versions[version], s, p_input_mask);
+ _mesh_surface_generate_version_for_input_mask(s->versions[version], s, p_input_mask, p_input_motion_vectors);
r_vertex_format = s->versions[version].vertex_format;
r_vertex_array_rd = s->versions[version].vertex_array;
@@ -466,23 +501,34 @@ public:
s->version_lock.unlock();
}
- _FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint32_t p_surface_index, uint32_t p_input_mask, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) {
+ _FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint64_t p_surface_index, uint32_t p_input_mask, bool p_input_motion_vectors, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) {
MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
- ERR_FAIL_COND(!mi);
+ ERR_FAIL_NULL(mi);
Mesh *mesh = mi->mesh;
ERR_FAIL_UNSIGNED_INDEX(p_surface_index, mesh->surface_count);
MeshInstance::Surface *mis = &mi->surfaces[p_surface_index];
Mesh::Surface *s = mesh->surfaces[p_surface_index];
+ uint32_t current_buffer = mis->current_buffer;
+
+ // Using the previous buffer is only allowed if the surface was updated this frame and motion vectors are required.
+ uint32_t previous_buffer = p_input_motion_vectors && (RSG::rasterizer->get_frame_number() == mis->last_change) ? mis->previous_buffer : current_buffer;
s->version_lock.lock();
//there will never be more than, at much, 3 or 4 versions, so iterating is the fastest way
for (uint32_t i = 0; i < mis->version_count; i++) {
- if (mis->versions[i].input_mask != p_input_mask) {
+ if (mis->versions[i].input_mask != p_input_mask || mis->versions[i].input_motion_vectors != p_input_motion_vectors) {
+ // Find the version that matches the inputs required.
continue;
}
+
+ if (mis->versions[i].current_buffer != current_buffer || mis->versions[i].previous_buffer != previous_buffer) {
+ // Find the version that corresponds to the correct buffers that should be used.
+ continue;
+ }
+
//we have this version, hooray
r_vertex_format = mis->versions[i].vertex_format;
r_vertex_array_rd = mis->versions[i].vertex_array;
@@ -494,7 +540,7 @@ public:
mis->version_count++;
mis->versions = (Mesh::Surface::Version *)memrealloc(mis->versions, sizeof(Mesh::Surface::Version) * mis->version_count);
- _mesh_surface_generate_version_for_input_mask(mis->versions[version], s, p_input_mask, mis);
+ _mesh_surface_generate_version_for_input_mask(mis->versions[version], s, p_input_mask, p_input_motion_vectors, mis, current_buffer, previous_buffer);
r_vertex_format = mis->versions[version].vertex_format;
r_vertex_array_rd = mis->versions[version].vertex_array;
@@ -593,8 +639,9 @@ public:
virtual AABB multimesh_get_aabb(RID p_multimesh) const override;
void _update_dirty_multimeshes();
- bool _multimesh_enable_motion_vectors(RID p_multimesh);
void _multimesh_get_motion_vectors_offsets(RID p_multimesh, uint32_t &r_current_offset, uint32_t &r_prev_offset);
+ bool _multimesh_uses_motion_vectors_offsets(RID p_multimesh);
+ bool _multimesh_uses_motion_vectors(RID p_multimesh);
_FORCE_INLINE_ RS::MultimeshTransformFormat multimesh_get_transform_format(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
@@ -689,7 +736,7 @@ public:
_FORCE_INLINE_ RID skeleton_get_3d_uniform_set(RID p_skeleton, RID p_shader, uint32_t p_set) const {
Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
- ERR_FAIL_COND_V(!skeleton, RID());
+ ERR_FAIL_NULL_V(skeleton, RID());
if (skeleton->size == 0) {
return RID();
}
diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
index 8f647be5c9..3d3cb585ac 100644
--- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
@@ -72,6 +72,7 @@ ParticlesStorage::ParticlesStorage() {
actions.renames["ACTIVE"] = "particle_active";
actions.renames["RESTART"] = "restart";
actions.renames["CUSTOM"] = "PARTICLE.custom";
+ actions.renames["AMOUNT_RATIO"] = "FRAME.amount_ratio";
for (int i = 0; i < ParticlesShader::MAX_USERDATAS; i++) {
String udname = "USERDATA" + itos(i + 1);
actions.renames[udname] = "PARTICLE.userdata" + itos(i + 1);
@@ -88,6 +89,8 @@ ParticlesStorage::ParticlesStorage() {
actions.renames["INDEX"] = "index";
//actions.renames["GRAVITY"] = "current_gravity";
actions.renames["EMISSION_TRANSFORM"] = "FRAME.emission_transform";
+ actions.renames["EMITTER_VELOCITY"] = "FRAME.emitter_velocity";
+ actions.renames["INTERPOLATE_TO_END"] = "FRAME.interp_to_end";
actions.renames["RANDOM_SEED"] = "FRAME.random_seed";
actions.renames["FLAG_EMIT_POSITION"] = "EMISSION_FLAG_HAS_POSITION";
actions.renames["FLAG_EMIT_ROT_SCALE"] = "EMISSION_FLAG_HAS_ROTATION_SCALE";
@@ -152,7 +155,7 @@ void process() {
uniforms.push_back(u);
}
- uniforms.append_array(material_storage->get_default_sampler_uniforms(SAMPLERS_BINDING_FIRST_INDEX));
+ uniforms.append_array(material_storage->samplers_rd_get_default().get_uniforms(SAMPLERS_BINDING_FIRST_INDEX));
particles_shader.base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.default_shader_rd, BASE_UNIFORM_SET);
}
@@ -221,20 +224,22 @@ RID ParticlesStorage::particles_allocate() {
}
void ParticlesStorage::particles_initialize(RID p_rid) {
- particles_owner.initialize_rid(p_rid, Particles());
+ particles_owner.initialize_rid(p_rid);
}
void ParticlesStorage::particles_free(RID p_rid) {
- update_particles();
Particles *particles = particles_owner.get_or_null(p_rid);
+
particles->dependency.deleted_notify(p_rid);
+ particles->update_list.remove_from_list();
+
_particles_free_data(particles);
particles_owner.free(p_rid);
}
void ParticlesStorage::particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
if (particles->mode == p_mode) {
return;
}
@@ -246,7 +251,7 @@ void ParticlesStorage::particles_set_mode(RID p_particles, RS::ParticlesMode p_m
void ParticlesStorage::particles_set_emitting(RID p_particles, bool p_emitting) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->emitting = p_emitting;
}
@@ -254,7 +259,7 @@ void ParticlesStorage::particles_set_emitting(RID p_particles, bool p_emitting)
bool ParticlesStorage::particles_get_emitting(RID p_particles) {
ERR_FAIL_COND_V_MSG(RSG::threaded, false, "This function should never be used with threaded rendering, as it stalls the renderer.");
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND_V(!particles, false);
+ ERR_FAIL_NULL_V(particles, false);
return particles->emitting;
}
@@ -311,7 +316,7 @@ void ParticlesStorage::_particles_free_data(Particles *particles) {
void ParticlesStorage::particles_set_amount(RID p_particles, int p_amount) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
if (particles->amount == p_amount) {
return;
@@ -329,50 +334,57 @@ void ParticlesStorage::particles_set_amount(RID p_particles, int p_amount) {
particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_PARTICLES);
}
+void ParticlesStorage::particles_set_amount_ratio(RID p_particles, float p_amount_ratio) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_NULL(particles);
+
+ particles->amount_ratio = p_amount_ratio;
+}
+
void ParticlesStorage::particles_set_lifetime(RID p_particles, double p_lifetime) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->lifetime = p_lifetime;
}
void ParticlesStorage::particles_set_one_shot(RID p_particles, bool p_one_shot) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->one_shot = p_one_shot;
}
void ParticlesStorage::particles_set_pre_process_time(RID p_particles, double p_time) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->pre_process_time = p_time;
}
void ParticlesStorage::particles_set_explosiveness_ratio(RID p_particles, real_t p_ratio) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->explosiveness = p_ratio;
}
void ParticlesStorage::particles_set_randomness_ratio(RID p_particles, real_t p_ratio) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->randomness = p_ratio;
}
void ParticlesStorage::particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->custom_aabb = p_aabb;
particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
}
void ParticlesStorage::particles_set_speed_scale(RID p_particles, double p_scale) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->speed_scale = p_scale;
}
void ParticlesStorage::particles_set_use_local_coordinates(RID p_particles, bool p_enable) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->use_local_coords = p_enable;
particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_PARTICLES);
@@ -380,7 +392,7 @@ void ParticlesStorage::particles_set_use_local_coordinates(RID p_particles, bool
void ParticlesStorage::particles_set_fixed_fps(RID p_particles, int p_fps) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->fixed_fps = p_fps;
@@ -396,21 +408,21 @@ void ParticlesStorage::particles_set_fixed_fps(RID p_particles, int p_fps) {
void ParticlesStorage::particles_set_interpolate(RID p_particles, bool p_enable) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->interpolate = p_enable;
}
void ParticlesStorage::particles_set_fractional_delta(RID p_particles, bool p_enable) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->fractional_delta = p_enable;
}
void ParticlesStorage::particles_set_trails(RID p_particles, bool p_enable, double p_length) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
ERR_FAIL_COND(p_length < 0.01);
p_length = MIN(10.0, p_length);
@@ -429,7 +441,7 @@ void ParticlesStorage::particles_set_trails(RID p_particles, bool p_enable, doub
void ParticlesStorage::particles_set_trail_bind_poses(RID p_particles, const Vector<Transform3D> &p_bind_poses) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
if (particles->trail_bind_pose_buffer.is_valid() && particles->trail_bind_poses.size() != p_bind_poses.size()) {
_particles_free_data(particles);
@@ -446,21 +458,21 @@ void ParticlesStorage::particles_set_trail_bind_poses(RID p_particles, const Vec
void ParticlesStorage::particles_set_collision_base_size(RID p_particles, real_t p_size) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->collision_base_size = p_size;
}
void ParticlesStorage::particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->transform_align = p_transform_align;
}
void ParticlesStorage::particles_set_process_material(RID p_particles, RID p_material) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->process_material = p_material;
particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_PARTICLES); //the instance buffer may have changed
@@ -468,35 +480,35 @@ void ParticlesStorage::particles_set_process_material(RID p_particles, RID p_mat
RID ParticlesStorage::particles_get_process_material(RID p_particles) const {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND_V(!particles, RID());
+ ERR_FAIL_NULL_V(particles, RID());
return particles->process_material;
}
void ParticlesStorage::particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->draw_order = p_order;
}
void ParticlesStorage::particles_set_draw_passes(RID p_particles, int p_passes) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->draw_passes.resize(p_passes);
}
void ParticlesStorage::particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
ERR_FAIL_INDEX(p_pass, particles->draw_passes.size());
particles->draw_passes.write[p_pass] = p_mesh;
}
void ParticlesStorage::particles_restart(RID p_particles) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->restart_request = true;
}
@@ -520,7 +532,7 @@ void ParticlesStorage::_particles_allocate_emission_buffer(Particles *particles)
void ParticlesStorage::particles_set_subemitter(RID p_particles, RID p_subemitter_particles) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
ERR_FAIL_COND(p_particles == p_subemitter_particles);
particles->sub_emitter = p_subemitter_particles;
@@ -533,7 +545,7 @@ void ParticlesStorage::particles_set_subemitter(RID p_particles, RID p_subemitte
void ParticlesStorage::particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
ERR_FAIL_COND(particles->amount == 0);
if (particles->emitting) {
@@ -573,12 +585,14 @@ void ParticlesStorage::particles_emit(RID p_particles, const Transform3D &p_tran
void ParticlesStorage::particles_request_process(RID p_particles) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
if (!particles->dirty) {
particles->dirty = true;
- particles->update_list = particle_update_list;
- particle_update_list = particles;
+
+ if (!particles->update_list.in_list()) {
+ particle_update_list.add(&particles->update_list);
+ }
}
}
@@ -588,7 +602,7 @@ AABB ParticlesStorage::particles_get_current_aabb(RID p_particles) {
}
const Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND_V(!particles, AABB());
+ ERR_FAIL_NULL_V(particles, AABB());
int total_amount = particles->amount;
if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) {
@@ -639,48 +653,75 @@ AABB ParticlesStorage::particles_get_current_aabb(RID p_particles) {
AABB ParticlesStorage::particles_get_aabb(RID p_particles) const {
const Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND_V(!particles, AABB());
+ ERR_FAIL_NULL_V(particles, AABB());
return particles->custom_aabb;
}
void ParticlesStorage::particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->emission_transform = p_transform;
}
+void ParticlesStorage::particles_set_emitter_velocity(RID p_particles, const Vector3 &p_velocity) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_NULL(particles);
+
+ particles->emitter_velocity = p_velocity;
+}
+
+void ParticlesStorage::particles_set_interp_to_end(RID p_particles, float p_interp) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_NULL(particles);
+
+ particles->interp_to_end = p_interp;
+}
+
int ParticlesStorage::particles_get_draw_passes(RID p_particles) const {
const Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND_V(!particles, 0);
+ ERR_FAIL_NULL_V(particles, 0);
return particles->draw_passes.size();
}
RID ParticlesStorage::particles_get_draw_pass_mesh(RID p_particles, int p_pass) const {
const Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND_V(!particles, RID());
+ ERR_FAIL_NULL_V(particles, RID());
ERR_FAIL_INDEX_V(p_pass, particles->draw_passes.size(), RID());
return particles->draw_passes[p_pass];
}
+void ParticlesStorage::particles_update_dependency(RID p_particles, DependencyTracker *p_instance) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_NULL(particles);
+ p_instance->update_dependency(&particles->dependency);
+}
+
+void ParticlesStorage::particles_get_instance_buffer_motion_vectors_offsets(RID p_particles, uint32_t &r_current_offset, uint32_t &r_prev_offset) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_NULL(particles);
+ r_current_offset = particles->instance_motion_vectors_current_offset;
+ r_prev_offset = particles->instance_motion_vectors_previous_offset;
+}
+
void ParticlesStorage::particles_add_collision(RID p_particles, RID p_particles_collision_instance) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->collisions.insert(p_particles_collision_instance);
}
void ParticlesStorage::particles_remove_collision(RID p_particles, RID p_particles_collision_instance) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->collisions.erase(p_particles_collision_instance);
}
void ParticlesStorage::particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->has_sdf_collision = p_enable;
particles->sdf_collision_transform = p_xform;
particles->sdf_collision_to_screen = p_to_screen;
@@ -778,9 +819,13 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta
frame_params.cycle = p_particles->cycle_number;
frame_params.frame = p_particles->frame_counter++;
- frame_params.pad0 = 0;
+ frame_params.amount_ratio = p_particles->amount_ratio;
frame_params.pad1 = 0;
frame_params.pad2 = 0;
+ frame_params.emitter_velocity[0] = p_particles->emitter_velocity.x;
+ frame_params.emitter_velocity[1] = p_particles->emitter_velocity.y;
+ frame_params.emitter_velocity[2] = p_particles->emitter_velocity.z;
+ frame_params.interp_to_end = p_particles->interp_to_end;
{ //collision and attractors
@@ -1093,7 +1138,7 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta
m = static_cast<ParticleProcessMaterialData *>(material_storage->material_get_data(particles_shader.default_material, MaterialStorage::SHADER_TYPE_PARTICLES));
}
- ERR_FAIL_COND(!m);
+ ERR_FAIL_NULL(m);
p_particles->has_collision_cache = m->shader_data->uses_collision;
@@ -1129,7 +1174,7 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta
void ParticlesStorage::particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY) {
return;
@@ -1185,6 +1230,7 @@ void ParticlesStorage::particles_set_view_axis(RID p_particles, const Vector3 &p
copy_push_constant.order_by_lifetime = (particles->draw_order == RS::PARTICLES_DRAW_ORDER_LIFETIME || particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME);
copy_push_constant.lifetime_split = (MIN(int(particles->amount * particles->phase), particles->amount - 1) + 1) % particles->amount;
copy_push_constant.lifetime_reverse = particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME;
+ copy_push_constant.motion_vectors_current_offset = particles->instance_motion_vectors_current_offset;
copy_push_constant.frame_remainder = particles->interpolate ? particles->frame_remainder : 0.0;
copy_push_constant.total_particles = particles->amount;
@@ -1252,28 +1298,50 @@ void ParticlesStorage::_particles_update_buffers(Particles *particles) {
userdata_count = particle_shader_data->userdata_count;
}
+ bool uses_motion_vectors = RSG::viewport->get_num_viewports_with_motion_vectors() > 0;
+ bool index_draw_order = particles->draw_order == RS::ParticlesDrawOrder::PARTICLES_DRAW_ORDER_INDEX;
+ bool enable_motion_vectors = uses_motion_vectors && index_draw_order && !particles->instance_motion_vectors_enabled;
+ bool only_instances_changed = false;
+
if (userdata_count != particles->userdata_count) {
- // Mismatch userdata, re-create buffers.
+ // Mismatch userdata, re-create all buffers.
_particles_free_data(particles);
+ } else if (enable_motion_vectors) {
+ // Only motion vectors are required, release the transforms buffer and uniform set.
+ if (particles->particle_instance_buffer.is_valid()) {
+ RD::get_singleton()->free(particles->particle_instance_buffer);
+ particles->particle_instance_buffer = RID();
+ }
+
+ particles->particles_transforms_buffer_uniform_set = RID();
+ only_instances_changed = true;
+ } else if (!particles->particle_buffer.is_null()) {
+ // No operation is required because a buffer already exists, return early.
+ return;
}
- if (particles->amount > 0 && particles->particle_buffer.is_null()) {
+ if (particles->amount > 0) {
int total_amount = particles->amount;
if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) {
total_amount *= particles->trail_bind_poses.size();
}
uint32_t xform_size = particles->mode == RS::PARTICLES_MODE_2D ? 2 : 3;
-
- particles->particle_buffer = RD::get_singleton()->storage_buffer_create((sizeof(ParticleData) + userdata_count * sizeof(float) * 4) * total_amount);
-
- particles->userdata_count = userdata_count;
+ if (particles->particle_buffer.is_null()) {
+ particles->particle_buffer = RD::get_singleton()->storage_buffer_create((sizeof(ParticleData) + userdata_count * sizeof(float) * 4) * total_amount);
+ particles->userdata_count = userdata_count;
+ }
PackedByteArray data;
- data.resize_zeroed(sizeof(float) * 4 * (xform_size + 1 + 1) * total_amount);
+ uint32_t particle_instance_buffer_size = total_amount * (xform_size + 1 + 1) * sizeof(float) * 4;
+ if (uses_motion_vectors) {
+ particle_instance_buffer_size *= 2;
+ particles->instance_motion_vectors_enabled = true;
+ }
+
+ data.resize_zeroed(particle_instance_buffer_size);
- particles->particle_instance_buffer = RD::get_singleton()->storage_buffer_create(sizeof(float) * 4 * (xform_size + 1 + 1) * total_amount, data);
- //needs to clear it
+ particles->particle_instance_buffer = RD::get_singleton()->storage_buffer_create(particle_instance_buffer_size, data);
{
Vector<RD::Uniform> uniforms;
@@ -1295,17 +1363,26 @@ void ParticlesStorage::_particles_update_buffers(Particles *particles) {
particles->particles_copy_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.copy_shader.version_get_shader(particles_shader.copy_shader_version, 0), 0);
}
+
+ particles->instance_motion_vectors_current_offset = 0;
+ particles->instance_motion_vectors_previous_offset = 0;
+ particles->instance_motion_vectors_last_change = -1;
+
+ if (only_instances_changed) {
+ // Notify the renderer the instances uniform must be retrieved again, as it's the only element that has been changed because motion vectors were enabled.
+ particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_PARTICLES_INSTANCES);
+ }
}
}
void ParticlesStorage::update_particles() {
- while (particle_update_list) {
+ uint32_t frame = RSG::rasterizer->get_frame_number();
+ bool uses_motion_vectors = RSG::viewport->get_num_viewports_with_motion_vectors() > 0;
+ while (particle_update_list.first()) {
//use transform feedback to process particles
- Particles *particles = particle_update_list;
+ Particles *particles = particle_update_list.first()->self();
- //take and remove
- particle_update_list = particles->update_list;
- particles->update_list = nullptr;
+ particles->update_list.remove_from_list();
particles->dirty = false;
_particles_update_buffers(particles);
@@ -1461,16 +1538,25 @@ void ParticlesStorage::update_particles() {
// Ensure that memory is initialized (the code above should ensure that _particles_process is always called at least once upon clearing).
DEV_ASSERT(!particles->clear);
+ int total_amount = particles->amount;
+ if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) {
+ total_amount *= particles->trail_bind_poses.size();
+ }
+
+ // Swap offsets for motion vectors. Motion vectors can only be used when the draw order keeps the indices consistent across frames.
+ bool index_draw_order = particles->draw_order == RS::ParticlesDrawOrder::PARTICLES_DRAW_ORDER_INDEX;
+ particles->instance_motion_vectors_previous_offset = particles->instance_motion_vectors_current_offset;
+ if (uses_motion_vectors && index_draw_order && particles->instance_motion_vectors_enabled && (frame - particles->instance_motion_vectors_last_change) == 1) {
+ particles->instance_motion_vectors_current_offset = total_amount - particles->instance_motion_vectors_current_offset;
+ }
+
+ particles->instance_motion_vectors_last_change = frame;
+
// Copy particles to instance buffer.
if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY) {
//does not need view dependent operation, do copy here
ParticlesShader::CopyPushConstant copy_push_constant;
- int total_amount = particles->amount;
- if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) {
- total_amount *= particles->trail_bind_poses.size();
- }
-
// Affect 2D only.
if (particles->use_local_coords) {
// In local mode, particle positions are calculated locally (relative to the node position)
@@ -1506,6 +1592,7 @@ void ParticlesStorage::update_particles() {
copy_push_constant.order_by_lifetime = (particles->draw_order == RS::PARTICLES_DRAW_ORDER_LIFETIME || particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME);
copy_push_constant.lifetime_split = (MIN(int(particles->amount * particles->phase), particles->amount - 1) + 1) % particles->amount;
copy_push_constant.lifetime_reverse = particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME;
+ copy_push_constant.motion_vectors_current_offset = particles->instance_motion_vectors_current_offset;
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
copy_push_constant.copy_mode_2d = particles->mode == RS::PARTICLES_MODE_2D ? 1 : 0;
@@ -1533,7 +1620,7 @@ Dependency *ParticlesStorage::particles_get_dependency(RID p_particles) const {
bool ParticlesStorage::particles_is_inactive(RID p_particles) const {
ERR_FAIL_COND_V_MSG(RSG::threaded, false, "This function should never be used with threaded rendering, as it stalls the renderer.");
const Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND_V(!particles, false);
+ ERR_FAIL_NULL_V(particles, false);
return !particles->emitting && particles->inactive;
}
@@ -1629,7 +1716,7 @@ MaterialStorage::ShaderData *ParticlesStorage::_create_particles_shader_func() {
}
bool ParticlesStorage::ParticleProcessMaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
- return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, ParticlesStorage::get_singleton()->particles_shader.shader.version_get_shader(shader_data->version, 0), 3, true);
+ return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, ParticlesStorage::get_singleton()->particles_shader.shader.version_get_shader(shader_data->version, 0), 3, true, false);
}
ParticlesStorage::ParticleProcessMaterialData::~ParticleProcessMaterialData() {
@@ -1665,7 +1752,7 @@ void ParticlesStorage::particles_collision_free(RID p_rid) {
RID ParticlesStorage::particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const {
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND_V(!particles_collision, RID());
+ ERR_FAIL_NULL_V(particles_collision, RID());
ERR_FAIL_COND_V(particles_collision->type != RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE, RID());
if (particles_collision->heightfield_texture == RID()) {
@@ -1700,7 +1787,7 @@ RID ParticlesStorage::particles_collision_get_heightfield_framebuffer(RID p_part
void ParticlesStorage::particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) {
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND(!particles_collision);
+ ERR_FAIL_NULL(particles_collision);
if (p_type == particles_collision->type) {
return;
@@ -1716,13 +1803,13 @@ void ParticlesStorage::particles_collision_set_collision_type(RID p_particles_co
void ParticlesStorage::particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) {
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND(!particles_collision);
+ ERR_FAIL_NULL(particles_collision);
particles_collision->cull_mask = p_cull_mask;
}
void ParticlesStorage::particles_collision_set_sphere_radius(RID p_particles_collision, real_t p_radius) {
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND(!particles_collision);
+ ERR_FAIL_NULL(particles_collision);
particles_collision->radius = p_radius;
particles_collision->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
@@ -1730,7 +1817,7 @@ void ParticlesStorage::particles_collision_set_sphere_radius(RID p_particles_col
void ParticlesStorage::particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) {
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND(!particles_collision);
+ ERR_FAIL_NULL(particles_collision);
particles_collision->extents = p_extents;
particles_collision->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
@@ -1738,41 +1825,41 @@ void ParticlesStorage::particles_collision_set_box_extents(RID p_particles_colli
void ParticlesStorage::particles_collision_set_attractor_strength(RID p_particles_collision, real_t p_strength) {
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND(!particles_collision);
+ ERR_FAIL_NULL(particles_collision);
particles_collision->attractor_strength = p_strength;
}
void ParticlesStorage::particles_collision_set_attractor_directionality(RID p_particles_collision, real_t p_directionality) {
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND(!particles_collision);
+ ERR_FAIL_NULL(particles_collision);
particles_collision->attractor_directionality = p_directionality;
}
void ParticlesStorage::particles_collision_set_attractor_attenuation(RID p_particles_collision, real_t p_curve) {
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND(!particles_collision);
+ ERR_FAIL_NULL(particles_collision);
particles_collision->attractor_attenuation = p_curve;
}
void ParticlesStorage::particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) {
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND(!particles_collision);
+ ERR_FAIL_NULL(particles_collision);
particles_collision->field_texture = p_texture;
}
void ParticlesStorage::particles_collision_height_field_update(RID p_particles_collision) {
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND(!particles_collision);
+ ERR_FAIL_NULL(particles_collision);
particles_collision->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
}
void ParticlesStorage::particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) {
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND(!particles_collision);
+ ERR_FAIL_NULL(particles_collision);
ERR_FAIL_INDEX(p_resolution, RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_MAX);
if (particles_collision->heightfield_resolution == p_resolution) {
@@ -1789,7 +1876,7 @@ void ParticlesStorage::particles_collision_set_height_field_resolution(RID p_par
AABB ParticlesStorage::particles_collision_get_aabb(RID p_particles_collision) const {
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND_V(!particles_collision, AABB());
+ ERR_FAIL_NULL_V(particles_collision, AABB());
switch (particles_collision->type) {
case RS::PARTICLES_COLLISION_TYPE_SPHERE_ATTRACT:
@@ -1810,13 +1897,13 @@ AABB ParticlesStorage::particles_collision_get_aabb(RID p_particles_collision) c
Vector3 ParticlesStorage::particles_collision_get_extents(RID p_particles_collision) const {
const ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND_V(!particles_collision, Vector3());
+ ERR_FAIL_NULL_V(particles_collision, Vector3());
return particles_collision->extents;
}
bool ParticlesStorage::particles_collision_is_heightfield(RID p_particles_collision) const {
const ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND_V(!particles_collision, false);
+ ERR_FAIL_NULL_V(particles_collision, false);
return particles_collision->type == RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE;
}
@@ -1841,12 +1928,12 @@ void ParticlesStorage::particles_collision_instance_free(RID p_rid) {
void ParticlesStorage::particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) {
ParticlesCollisionInstance *pci = particles_collision_instance_owner.get_or_null(p_collision_instance);
- ERR_FAIL_COND(!pci);
+ ERR_FAIL_NULL(pci);
pci->transform = p_transform;
}
void ParticlesStorage::particles_collision_instance_set_active(RID p_collision_instance, bool p_active) {
ParticlesCollisionInstance *pci = particles_collision_instance_owner.get_or_null(p_collision_instance);
- ERR_FAIL_COND(!pci);
+ ERR_FAIL_NULL(pci);
pci->active = p_active;
}
diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.h b/servers/rendering/renderer_rd/storage_rd/particles_storage.h
index 612420a36c..a28d7b4154 100644
--- a/servers/rendering/renderer_rd/storage_rd/particles_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.h
@@ -123,7 +123,7 @@ private:
float delta;
uint32_t frame;
- uint32_t pad0;
+ float amount_ratio;
uint32_t pad1;
uint32_t pad2;
@@ -134,6 +134,9 @@ private:
float emission_transform[16];
+ float emitter_velocity[3];
+ float interp_to_end;
+
Attractor attractors[MAX_ATTRACTORS];
Collider colliders[MAX_COLLIDERS];
};
@@ -206,7 +209,7 @@ private:
RID particles_sort_uniform_set;
bool dirty = false;
- Particles *update_list = nullptr;
+ SelfList<Particles> update_list;
RID sub_emitter;
@@ -225,11 +228,19 @@ private:
double frame_remainder = 0;
real_t collision_base_size = 0.01;
+ uint32_t instance_motion_vectors_current_offset = 0;
+ uint32_t instance_motion_vectors_previous_offset = 0;
+ uint64_t instance_motion_vectors_last_change = -1;
+ bool instance_motion_vectors_enabled = false;
+
bool clear = true;
bool force_sub_emit = false;
Transform3D emission_transform;
+ Vector3 emitter_velocity;
+ float interp_to_end = 0.0;
+ float amount_ratio = 1.0;
Vector<uint8_t> emission_buffer_data;
@@ -245,7 +256,8 @@ private:
LocalVector<ParticlesFrameParams> frame_history;
LocalVector<ParticlesFrameParams> trail_params;
- Particles() {
+ Particles() :
+ update_list(this) {
}
};
@@ -288,10 +300,13 @@ private:
float align_up[3];
uint32_t align_mode;
- uint32_t order_by_lifetime;
uint32_t lifetime_split;
uint32_t lifetime_reverse;
- uint32_t copy_mode_2d;
+ uint32_t motion_vectors_current_offset;
+ struct {
+ uint32_t order_by_lifetime : 1;
+ uint32_t copy_mode_2d : 1;
+ };
float inv_emission_transform[16];
};
@@ -314,7 +329,7 @@ private:
} particles_shader;
- Particles *particle_update_list = nullptr;
+ SelfList<Particles>::List particle_update_list;
mutable RID_Owner<Particles, true> particles_owner;
@@ -417,6 +432,7 @@ public:
virtual void particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) override;
virtual void particles_set_emitting(RID p_particles, bool p_emitting) override;
virtual void particles_set_amount(RID p_particles, int p_amount) override;
+ virtual void particles_set_amount_ratio(RID p_particles, float p_amount_ratio) override;
virtual void particles_set_lifetime(RID p_particles, double p_lifetime) override;
virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) override;
virtual void particles_set_pre_process_time(RID p_particles, double p_time) override;
@@ -452,6 +468,8 @@ public:
virtual AABB particles_get_aabb(RID p_particles) const override;
virtual void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) override;
+ virtual void particles_set_emitter_velocity(RID p_particles, const Vector3 &p_velocity) override;
+ virtual void particles_set_interp_to_end(RID p_particles, float p_interp_to_end) override;
virtual bool particles_get_emitting(RID p_particles) override;
virtual int particles_get_draw_passes(RID p_particles) const override;
@@ -463,19 +481,19 @@ public:
_FORCE_INLINE_ RS::ParticlesMode particles_get_mode(RID p_particles) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND_V(!particles, RS::PARTICLES_MODE_2D);
+ ERR_FAIL_NULL_V(particles, RS::PARTICLES_MODE_2D);
return particles->mode;
}
_FORCE_INLINE_ uint32_t particles_get_frame_counter(RID p_particles) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND_V(!particles, false);
+ ERR_FAIL_NULL_V(particles, false);
return particles->frame_counter;
}
_FORCE_INLINE_ uint32_t particles_get_amount(RID p_particles, uint32_t &r_trail_divisor) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND_V(!particles, 0);
+ ERR_FAIL_NULL_V(particles, 0);
if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) {
r_trail_divisor = particles->trail_bind_poses.size();
@@ -488,21 +506,21 @@ public:
_FORCE_INLINE_ bool particles_has_collision(RID p_particles) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND_V(!particles, 0);
+ ERR_FAIL_NULL_V(particles, 0);
return particles->has_collision_cache;
}
_FORCE_INLINE_ uint32_t particles_is_using_local_coords(RID p_particles) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND_V(!particles, false);
+ ERR_FAIL_NULL_V(particles, false);
return particles->use_local_coords;
}
_FORCE_INLINE_ RID particles_get_instance_buffer_uniform_set(RID p_particles, RID p_shader, uint32_t p_set) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND_V(!particles, RID());
+ ERR_FAIL_NULL_V(particles, RID());
if (particles->particles_transforms_buffer_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(particles->particles_transforms_buffer_uniform_set)) {
_particles_update_buffers(particles);
Vector<RD::Uniform> uniforms;
@@ -521,12 +539,15 @@ public:
return particles->particles_transforms_buffer_uniform_set;
}
+ void particles_get_instance_buffer_motion_vectors_offsets(RID p_particles, uint32_t &r_current_offset, uint32_t &r_prev_offset);
+
virtual void particles_add_collision(RID p_particles, RID p_particles_collision_instance) override;
virtual void particles_remove_collision(RID p_particles, RID p_particles_collision_instance) override;
void particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture);
virtual void update_particles() override;
+ void particles_update_dependency(RID p_particles, DependencyTracker *p_instance);
Dependency *particles_get_dependency(RID p_particles) const;
/* Particles Collision */
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
index 71bc21d5d4..5ff5adc59a 100644
--- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
@@ -29,8 +29,8 @@
/**************************************************************************/
#include "render_scene_buffers_rd.h"
+#include "core/config/project_settings.h"
#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
-#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h"
RenderSceneBuffersRD::RenderSceneBuffersRD() {
@@ -40,6 +40,8 @@ RenderSceneBuffersRD::~RenderSceneBuffersRD() {
cleanup();
data_buffers.clear();
+
+ RendererRD::MaterialStorage::get_singleton()->samplers_rd_free(samplers);
}
void RenderSceneBuffersRD::_bind_methods() {
@@ -50,6 +52,7 @@ void RenderSceneBuffersRD::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_texture", "context", "name"), &RenderSceneBuffersRD::get_texture);
ClassDB::bind_method(D_METHOD("get_texture_format", "context", "name"), &RenderSceneBuffersRD::_get_texture_format);
ClassDB::bind_method(D_METHOD("get_texture_slice", "context", "name", "layer", "mipmap", "layers", "mipmaps"), &RenderSceneBuffersRD::get_texture_slice);
+ ClassDB::bind_method(D_METHOD("get_texture_slice_view", "context", "name", "layer", "mipmap", "layers", "mipmaps", "view"), &RenderSceneBuffersRD::_get_texture_slice_view);
ClassDB::bind_method(D_METHOD("get_texture_slice_size", "context", "name", "mipmap"), &RenderSceneBuffersRD::get_texture_slice_size);
ClassDB::bind_method(D_METHOD("clear_context", "context"), &RenderSceneBuffersRD::clear_context);
@@ -90,6 +93,27 @@ void RenderSceneBuffersRD::free_named_texture(NamedTexture &p_named_texture) {
p_named_texture.slices.clear(); // slices should be freed automatically as dependents...
}
+void RenderSceneBuffersRD::update_samplers() {
+ float computed_mipmap_bias = texture_mipmap_bias;
+
+ if (use_taa || (scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR2)) {
+ // Use negative mipmap LOD bias when TAA or FSR2 is enabled to compensate for loss of sharpness.
+ // This restores sharpness in still images to be roughly at the same level as without TAA,
+ // but moving scenes will still be blurrier.
+ computed_mipmap_bias -= 0.5;
+ }
+
+ if (screen_space_aa == RS::VIEWPORT_SCREEN_SPACE_AA_FXAA) {
+ // Use negative mipmap LOD bias when FXAA is enabled to compensate for loss of sharpness.
+ // If both TAA and FXAA are enabled, combine their negative LOD biases together.
+ computed_mipmap_bias -= 0.25;
+ }
+
+ RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
+ material_storage->samplers_rd_free(samplers);
+ samplers = material_storage->samplers_rd_allocate(computed_mipmap_bias);
+}
+
void RenderSceneBuffersRD::cleanup() {
// Free our data buffers (but don't destroy them)
for (KeyValue<StringName, Ref<RenderBufferCustomDataRD>> &E : data_buffers) {
@@ -105,7 +129,6 @@ void RenderSceneBuffersRD::cleanup() {
void RenderSceneBuffersRD::configure(const RenderSceneBuffersConfiguration *p_config) {
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
- RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
render_target = p_config->get_render_target();
target_size = p_config->get_target_size();
@@ -123,23 +146,10 @@ void RenderSceneBuffersRD::configure(const RenderSceneBuffersConfiguration *p_co
ERR_FAIL_COND_MSG(view_count == 0, "Must have at least 1 view");
- if (use_taa) {
- // Use negative mipmap LOD bias when TAA is enabled to compensate for loss of sharpness.
- // This restores sharpness in still images to be roughly at the same level as without TAA,
- // but moving scenes will still be blurrier.
- texture_mipmap_bias -= 0.5;
- }
+ update_samplers();
- if (screen_space_aa == RS::VIEWPORT_SCREEN_SPACE_AA_FXAA) {
- // Use negative mipmap LOD bias when FXAA is enabled to compensate for loss of sharpness.
- // If both TAA and FXAA are enabled, combine their negative LOD biases together.
- texture_mipmap_bias -= 0.25;
- }
-
- material_storage->sampler_rd_configure_custom(texture_mipmap_bias);
-
- // need to check if we really need to do this here..
- RendererSceneRenderRD::get_singleton()->update_uniform_sets();
+ // Notify the renderer the base uniform needs to be recreated.
+ RendererSceneRenderRD::get_singleton()->base_uniforms_changed();
// cleanout any old buffers we had.
cleanup();
@@ -243,8 +253,9 @@ void RenderSceneBuffersRD::set_fsr_sharpness(float p_fsr_sharpness) {
}
void RenderSceneBuffersRD::set_texture_mipmap_bias(float p_texture_mipmap_bias) {
- RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
- material_storage->sampler_rd_configure_custom(p_texture_mipmap_bias);
+ texture_mipmap_bias = p_texture_mipmap_bias;
+
+ update_samplers();
}
void RenderSceneBuffersRD::set_use_debanding(bool p_use_debanding) {
@@ -378,6 +389,15 @@ Ref<RDTextureFormat> RenderSceneBuffersRD::_get_texture_format(const StringName
return tf;
}
+RID RenderSceneBuffersRD::_get_texture_slice_view(const StringName &p_context, const StringName &p_texture_name, const uint32_t p_layer, const uint32_t p_mipmap, const uint32_t p_layers, const uint32_t p_mipmaps, const Ref<RDTextureView> p_view) {
+ RD::TextureView texture_view;
+ if (p_view.is_valid()) {
+ texture_view = p_view->base;
+ }
+
+ return get_texture_slice_view(p_context, p_texture_name, p_layer, p_mipmap, p_layers, p_mipmaps, texture_view);
+}
+
const RD::TextureFormat RenderSceneBuffersRD::get_texture_format(const StringName &p_context, const StringName &p_texture_name) const {
NTKey key(p_context, p_texture_name);
@@ -387,6 +407,10 @@ const RD::TextureFormat RenderSceneBuffersRD::get_texture_format(const StringNam
}
RID RenderSceneBuffersRD::get_texture_slice(const StringName &p_context, const StringName &p_texture_name, const uint32_t p_layer, const uint32_t p_mipmap, const uint32_t p_layers, const uint32_t p_mipmaps) {
+ return get_texture_slice_view(p_context, p_texture_name, p_layer, p_mipmap, p_layers, p_mipmaps, RD::TextureView());
+}
+
+RID RenderSceneBuffersRD::get_texture_slice_view(const StringName &p_context, const StringName &p_texture_name, const uint32_t p_layer, const uint32_t p_mipmap, const uint32_t p_layers, const uint32_t p_mipmaps, RD::TextureView p_view) {
NTKey key(p_context, p_texture_name);
// check if this is a known texture
@@ -403,19 +427,20 @@ RID RenderSceneBuffersRD::get_texture_slice(const StringName &p_context, const S
ERR_FAIL_COND_V(p_mipmap + p_mipmaps > named_texture.format.mipmaps, RID());
// asking the whole thing? just return the original
- if (p_layer == 0 && p_mipmap == 0 && named_texture.format.array_layers == p_layers && named_texture.format.mipmaps == p_mipmaps) {
+ RD::TextureView default_view = RD::TextureView();
+ if (p_layer == 0 && p_mipmap == 0 && named_texture.format.array_layers == p_layers && named_texture.format.mipmaps == p_mipmaps && p_view == default_view) {
return named_texture.texture;
}
// see if we have this
- NTSliceKey slice_key(p_layer, p_layers, p_mipmap, p_mipmaps);
+ NTSliceKey slice_key(p_layer, p_layers, p_mipmap, p_mipmaps, p_view);
if (named_texture.slices.has(slice_key)) {
return named_texture.slices[slice_key];
}
// create our slice
RID &slice = named_texture.slices[slice_key];
- slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), named_texture.texture, p_layer, p_mipmap, p_mipmaps, p_layers > 1 ? RD::TEXTURE_SLICE_2D_ARRAY : RD::TEXTURE_SLICE_2D, p_layers);
+ slice = RD::get_singleton()->texture_create_shared_from_slice(p_view, named_texture.texture, p_layer, p_mipmap, p_mipmaps, p_layers > 1 ? RD::TEXTURE_SLICE_2D_ARRAY : RD::TEXTURE_SLICE_2D, p_layers);
Array arr;
arr.push_back(p_context);
@@ -424,7 +449,12 @@ RID RenderSceneBuffersRD::get_texture_slice(const StringName &p_context, const S
arr.push_back(itos(p_layers));
arr.push_back(itos(p_mipmap));
arr.push_back(itos(p_mipmaps));
- RD::get_singleton()->set_resource_name(slice, String("RenderBuffer {0}/{1}, layer {2}/{3}, mipmap {4}/{5}").format(arr));
+ arr.push_back(itos(p_view.format_override));
+ arr.push_back(itos(p_view.swizzle_r));
+ arr.push_back(itos(p_view.swizzle_g));
+ arr.push_back(itos(p_view.swizzle_b));
+ arr.push_back(itos(p_view.swizzle_a));
+ RD::get_singleton()->set_resource_name(slice, String("RenderBuffer {0}/{1}, layer {2}/{3}, mipmap {4}/{5}, view {6}/{7}/{8}/{9}/{10}").format(arr));
// and return our slice
return slice;
@@ -469,7 +499,13 @@ void RenderSceneBuffersRD::allocate_blur_textures() {
return;
}
- uint32_t mipmaps_required = Image::get_image_required_mipmaps(internal_size.x, internal_size.y, Image::FORMAT_RGBAH);
+ Size2i blur_size = internal_size;
+ if (scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR2) {
+ // The blur texture should be as big as the target size when using an upscaler.
+ blur_size = target_size;
+ }
+
+ uint32_t mipmaps_required = Image::get_image_required_mipmaps(blur_size.x, blur_size.y, Image::FORMAT_RGBAH);
uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
if (can_be_storage) {
@@ -478,12 +514,12 @@ void RenderSceneBuffersRD::allocate_blur_textures() {
usage_bits += RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
}
- create_texture(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0, base_data_format, usage_bits, RD::TEXTURE_SAMPLES_1, internal_size, view_count, mipmaps_required);
- create_texture(RB_SCOPE_BUFFERS, RB_TEX_BLUR_1, base_data_format, usage_bits, RD::TEXTURE_SAMPLES_1, Size2i(internal_size.x >> 1, internal_size.y >> 1), view_count, mipmaps_required - 1);
+ create_texture(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0, base_data_format, usage_bits, RD::TEXTURE_SAMPLES_1, blur_size, view_count, mipmaps_required);
+ create_texture(RB_SCOPE_BUFFERS, RB_TEX_BLUR_1, base_data_format, usage_bits, RD::TEXTURE_SAMPLES_1, Size2i(blur_size.x >> 1, blur_size.y >> 1), view_count, mipmaps_required - 1);
// if !can_be_storage we need a half width version
if (!can_be_storage) {
- create_texture(RB_SCOPE_BUFFERS, RB_TEX_HALF_BLUR, base_data_format, usage_bits, RD::TEXTURE_SAMPLES_1, Size2i(internal_size.x >> 1, internal_size.y), 1, mipmaps_required);
+ create_texture(RB_SCOPE_BUFFERS, RB_TEX_HALF_BLUR, base_data_format, usage_bits, RD::TEXTURE_SAMPLES_1, Size2i(blur_size.x >> 1, blur_size.y), 1, mipmaps_required);
}
// TODO redo this:
@@ -492,8 +528,8 @@ void RenderSceneBuffersRD::allocate_blur_textures() {
RD::TextureFormat tf;
tf.format = RD::DATA_FORMAT_R16_SFLOAT; // We could probably use DATA_FORMAT_R8_SNORM if we don't pre-multiply by blur_size but that depends on whether we can remove DEPTH_GAP
- tf.width = internal_size.x;
- tf.height = internal_size.y;
+ tf.width = blur_size.x;
+ tf.height = blur_size.y;
tf.texture_type = RD::TEXTURE_TYPE_2D;
tf.array_layers = 1; // Our DOF effect handles one eye per turn
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
@@ -593,6 +629,16 @@ RID RenderSceneBuffersRD::get_depth_texture(const uint32_t p_layer) {
}
}
+// Upscaled texture.
+
+void RenderSceneBuffersRD::ensure_upscaled() {
+ if (!has_upscaled_texture()) {
+ uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | (can_be_storage ? RD::TEXTURE_USAGE_STORAGE_BIT : 0) | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ usage_bits |= RD::TEXTURE_USAGE_INPUT_ATTACHMENT_BIT;
+ create_texture(RB_SCOPE_BUFFERS, RB_TEX_COLOR_UPSCALED, base_data_format, usage_bits, RD::TEXTURE_SAMPLES_1, target_size);
+ }
+}
+
// Velocity texture.
void RenderSceneBuffersRD::ensure_velocity() {
@@ -600,7 +646,7 @@ void RenderSceneBuffersRD::ensure_velocity() {
uint32_t usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
if (msaa_3d != RS::VIEWPORT_MSAA_DISABLED) {
- uint32_t msaa_usage_bits = usage_bits | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
+ uint32_t msaa_usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
create_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY_MSAA, RD::DATA_FORMAT_R16G16_SFLOAT, msaa_usage_bits, texture_samples);
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h
index 85140c674c..43704119e7 100644
--- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h
@@ -31,9 +31,11 @@
#ifndef RENDER_SCENE_BUFFERS_RD_H
#define RENDER_SCENE_BUFFERS_RD_H
+#include "../effects/fsr2.h"
#include "../effects/vrs.h"
#include "../framebuffer_cache_rd.h"
#include "core/templates/hash_map.h"
+#include "material_storage.h"
#include "render_buffer_custom_data_rd.h"
#include "servers/rendering/rendering_device.h"
#include "servers/rendering/rendering_device_binds.h"
@@ -46,6 +48,7 @@
#define RB_TEXTURE SNAME("texture")
#define RB_TEX_COLOR SNAME("color")
#define RB_TEX_COLOR_MSAA SNAME("color_msaa")
+#define RB_TEX_COLOR_UPSCALED SNAME("color_upscaled")
#define RB_TEX_DEPTH SNAME("depth")
#define RB_TEX_DEPTH_MSAA SNAME("depth_msaa")
#define RB_TEX_VELOCITY SNAME("velocity")
@@ -113,9 +116,10 @@ private:
uint32_t layers;
uint32_t mipmap;
uint32_t mipmaps;
+ RD::TextureView texture_view;
bool operator==(const NTSliceKey &p_val) const {
- return (layer == p_val.layer) && (layers == p_val.layers) && (mipmap == p_val.mipmap) && (mipmaps == p_val.mipmaps);
+ return (layer == p_val.layer) && (layers == p_val.layers) && (mipmap == p_val.mipmap) && (mipmaps == p_val.mipmaps) && (texture_view == p_val.texture_view);
}
static uint32_t hash(const NTSliceKey &p_val) {
@@ -123,15 +127,21 @@ private:
h = hash_murmur3_one_32(p_val.layers, h);
h = hash_murmur3_one_32(p_val.mipmap, h);
h = hash_murmur3_one_32(p_val.mipmaps, h);
+ h = hash_murmur3_one_32(p_val.texture_view.format_override);
+ h = hash_murmur3_one_32(p_val.texture_view.swizzle_r, h);
+ h = hash_murmur3_one_32(p_val.texture_view.swizzle_g, h);
+ h = hash_murmur3_one_32(p_val.texture_view.swizzle_b, h);
+ h = hash_murmur3_one_32(p_val.texture_view.swizzle_a, h);
return hash_fmix32(h);
}
NTSliceKey() {}
- NTSliceKey(uint32_t p_layer, uint32_t p_layers, uint32_t p_mipmap, uint32_t p_mipmaps) {
+ NTSliceKey(uint32_t p_layer, uint32_t p_layers, uint32_t p_mipmap, uint32_t p_mipmaps, RD::TextureView p_texture_view) {
layer = p_layer;
layers = p_layers;
mipmap = p_mipmap;
mipmaps = p_mipmaps;
+ texture_view = p_texture_view;
}
};
@@ -153,6 +163,11 @@ private:
// Data buffers
mutable HashMap<StringName, Ref<RenderBufferCustomDataRD>> data_buffers;
+ // Samplers.
+ RendererRD::MaterialStorage::Samplers samplers;
+
+ void update_samplers();
+
protected:
static void _bind_methods();
@@ -184,6 +199,7 @@ public:
RID get_texture(const StringName &p_context, const StringName &p_texture_name) const;
const RD::TextureFormat get_texture_format(const StringName &p_context, const StringName &p_texture_name) const;
RID get_texture_slice(const StringName &p_context, const StringName &p_texture_name, const uint32_t p_layer, const uint32_t p_mipmap, const uint32_t p_layers = 1, const uint32_t p_mipmaps = 1);
+ RID get_texture_slice_view(const StringName &p_context, const StringName &p_texture_name, const uint32_t p_layer, const uint32_t p_mipmap, const uint32_t p_layers = 1, const uint32_t p_mipmaps = 1, RD::TextureView p_view = RD::TextureView());
Size2i get_texture_slice_size(const StringName &p_context, const StringName &p_texture_name, const uint32_t p_mipmap);
void clear_context(const StringName &p_context);
@@ -224,6 +240,14 @@ public:
_FORCE_INLINE_ RID get_internal_texture(const uint32_t p_layer) {
return get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_COLOR, p_layer, 0);
}
+ _FORCE_INLINE_ RID get_internal_texture_reactive(const uint32_t p_layer) {
+ RD::TextureView alpha_only_view;
+ alpha_only_view.swizzle_r = RD::TEXTURE_SWIZZLE_A;
+ alpha_only_view.swizzle_g = RD::TEXTURE_SWIZZLE_A;
+ alpha_only_view.swizzle_b = RD::TEXTURE_SWIZZLE_A;
+ alpha_only_view.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+ return get_texture_slice_view(RB_SCOPE_BUFFERS, RB_TEX_COLOR, p_layer, 0, 1, 1, alpha_only_view);
+ }
_FORCE_INLINE_ RID get_color_msaa() const {
return get_texture(RB_SCOPE_BUFFERS, RB_TEX_COLOR_MSAA);
}
@@ -245,6 +269,19 @@ public:
// back buffer (color)
RID get_back_buffer_texture() const { return has_texture(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0) ? get_texture(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0) : RID(); } // We (re)use our blur texture here.
+ // Upscaled.
+ void ensure_upscaled();
+
+ _FORCE_INLINE_ bool has_upscaled_texture() const {
+ return has_texture(RB_SCOPE_BUFFERS, RB_TEX_COLOR_UPSCALED);
+ }
+ _FORCE_INLINE_ RID get_upscaled_texture() const {
+ return get_texture(RB_SCOPE_BUFFERS, RB_TEX_COLOR_UPSCALED);
+ }
+ _FORCE_INLINE_ RID get_upscaled_texture(const uint32_t p_layer) {
+ return get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_COLOR_UPSCALED, p_layer, 0);
+ }
+
// Velocity, currently only used by TAA (Clustered) but we'll be using this in other places soon too.
void ensure_velocity();
@@ -252,6 +289,12 @@ public:
RID get_velocity_buffer(bool p_get_msaa);
RID get_velocity_buffer(bool p_get_msaa, uint32_t p_layer);
+ // Samplers adjusted with the mipmap bias that is best fit for the configuration of these render buffers.
+
+ _FORCE_INLINE_ RendererRD::MaterialStorage::Samplers get_samplers() const {
+ return samplers;
+ }
+
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Our classDB doesn't support calling our normal exposed functions
@@ -259,6 +302,7 @@ private:
RID _create_texture_from_format(const StringName &p_context, const StringName &p_texture_name, const Ref<RDTextureFormat> &p_texture_format, const Ref<RDTextureView> &p_view = Ref<RDTextureView>(), bool p_unique = true);
RID _create_texture_view(const StringName &p_context, const StringName &p_texture_name, const StringName p_view_name, const Ref<RDTextureView> p_view = Ref<RDTextureView>());
Ref<RDTextureFormat> _get_texture_format(const StringName &p_context, const StringName &p_texture_name) const;
+ RID _get_texture_slice_view(const StringName &p_context, const StringName &p_texture_name, const uint32_t p_layer, const uint32_t p_mipmap, const uint32_t p_layers = 1, const uint32_t p_mipmaps = 1, const Ref<RDTextureView> p_view = Ref<RDTextureView>());
// For color and depth as exposed to extensions, we return the buffer that we're rendering into.
// Resolving happens after effects etc. are run.
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp
index a7b8f985d9..40891f9a63 100644
--- a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp
@@ -38,7 +38,7 @@ RID RenderSceneDataRD::create_uniform_buffer() {
return RD::get_singleton()->uniform_buffer_create(sizeof(UBODATA));
}
-void RenderSceneDataRD::update_ubo(RID p_uniform_buffer, RS::ViewportDebugDraw p_debug_mode, RID p_env, RID p_reflection_probe_instance, RID p_camera_attributes, bool p_flip_y, bool p_pancake_shadows, const Size2i &p_screen_size, const Color &p_default_bg_color, float p_luminance_multiplier, bool p_opaque_render_buffers) {
+void RenderSceneDataRD::update_ubo(RID p_uniform_buffer, RS::ViewportDebugDraw p_debug_mode, RID p_env, RID p_reflection_probe_instance, RID p_camera_attributes, bool p_flip_y, bool p_pancake_shadows, const Size2i &p_screen_size, const Color &p_default_bg_color, float p_luminance_multiplier, bool p_opaque_render_buffers, bool p_apply_alpha_multiplier) {
RendererSceneRenderRD *render_scene_render = RendererSceneRenderRD::get_singleton();
UBODATA ubo_data;
@@ -89,6 +89,7 @@ void RenderSceneDataRD::update_ubo(RID p_uniform_buffer, RS::ViewportDebugDraw p
RendererRD::MaterialStorage::store_soft_shadow_kernel(render_scene_render->penumbra_shadow_kernel_get(), ubo.penumbra_shadow_kernel);
RendererRD::MaterialStorage::store_soft_shadow_kernel(render_scene_render->soft_shadow_kernel_get(), ubo.soft_shadow_kernel);
ubo.camera_visible_layers = camera_visible_layers;
+ ubo.pass_alpha_multiplier = p_opaque_render_buffers && p_apply_alpha_multiplier ? 0.0f : 1.0f;
ubo.viewport_size[0] = p_screen_size.x;
ubo.viewport_size[1] = p_screen_size.y;
@@ -234,6 +235,12 @@ void RenderSceneDataRD::update_ubo(RID p_uniform_buffer, RS::ViewportDebugDraw p
RendererRD::MaterialStorage::store_transform(prev_cam_transform, prev_ubo.inv_view_matrix);
RendererRD::MaterialStorage::store_transform(prev_cam_transform.affine_inverse(), prev_ubo.view_matrix);
+#ifdef REAL_T_IS_DOUBLE
+ RendererRD::MaterialStorage::split_double(-prev_cam_transform.origin.x, &prev_ubo.inv_view_matrix[12], &prev_ubo.inv_view_matrix[3]);
+ RendererRD::MaterialStorage::split_double(-prev_cam_transform.origin.y, &prev_ubo.inv_view_matrix[13], &prev_ubo.inv_view_matrix[7]);
+ RendererRD::MaterialStorage::split_double(-prev_cam_transform.origin.z, &prev_ubo.inv_view_matrix[14], &prev_ubo.inv_view_matrix[11]);
+#endif
+
for (uint32_t v = 0; v < view_count; v++) {
prev_projection = prev_correction * view_projection[v];
RendererRD::MaterialStorage::store_camera(prev_projection, prev_ubo.projection_matrix_view[v]);
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h
index 7546998a9b..f183207b57 100644
--- a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h
@@ -77,7 +77,7 @@ public:
float time_step;
RID create_uniform_buffer();
- void update_ubo(RID p_uniform_buffer, RS::ViewportDebugDraw p_debug_mode, RID p_env, RID p_reflection_probe_instance, RID p_camera_attributes, bool p_flip_y, bool p_pancake_shadows, const Size2i &p_screen_size, const Color &p_default_bg_color, float p_luminance_multiplier, bool p_opaque_render_buffers);
+ void update_ubo(RID p_uniform_buffer, RS::ViewportDebugDraw p_debug_mode, RID p_env, RID p_reflection_probe_instance, RID p_camera_attributes, bool p_flip_y, bool p_pancake_shadows, const Size2i &p_screen_size, const Color &p_default_bg_color, float p_luminance_multiplier, bool p_opaque_render_buffers, bool p_apply_alpha_multiplier);
RID get_uniform_buffer();
private:
@@ -144,7 +144,7 @@ private:
uint32_t pancake_shadows;
uint32_t camera_visible_layers;
- uint32_t pad2;
+ float pass_alpha_multiplier;
uint32_t pad3;
};
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
index d84f6e6850..166b850864 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
@@ -46,9 +46,11 @@ void TextureStorage::CanvasTexture::clear_sets() {
}
for (int i = 1; i < RS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) {
for (int j = 1; j < RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) {
- if (RD::get_singleton()->uniform_set_is_valid(uniform_sets[i][j])) {
- RD::get_singleton()->free(uniform_sets[i][j]);
- uniform_sets[i][j] = RID();
+ for (int k = 0; k < 2; k++) {
+ if (RD::get_singleton()->uniform_set_is_valid(uniform_sets[i][j][k])) {
+ RD::get_singleton()->free(uniform_sets[i][j][k]);
+ uniform_sets[i][j][k] = RID();
+ }
}
}
}
@@ -641,7 +643,7 @@ void TextureStorage::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS:
ct->clear_sets();
}
-bool TextureStorage::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular) {
+bool TextureStorage::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, bool p_use_srgb, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular, bool p_texture_is_data) {
MaterialStorage *material_storage = MaterialStorage::get_singleton();
CanvasTexture *ct = nullptr;
@@ -674,7 +676,7 @@ bool TextureStorage::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasIte
RS::CanvasItemTextureRepeat repeat = ct->texture_repeat != RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT ? ct->texture_repeat : p_base_repeat;
ERR_FAIL_COND_V(repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, false);
- RID uniform_set = ct->uniform_sets[filter][repeat];
+ RID uniform_set = ct->uniform_sets[filter][repeat][int(p_use_srgb)];
if (!RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
//create and update
Vector<RD::Uniform> uniforms;
@@ -688,7 +690,7 @@ bool TextureStorage::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasIte
u.append_id(texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE));
ct->size_cache = Size2i(1, 1);
} else {
- u.append_id(t->rd_texture);
+ u.append_id(t->rd_texture_srgb.is_valid() && p_use_srgb && !p_texture_is_data ? t->rd_texture_srgb : t->rd_texture);
ct->size_cache = Size2i(t->width_2d, t->height_2d);
if (t->render_target) {
t->render_target->was_used = true;
@@ -741,7 +743,7 @@ bool TextureStorage::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasIte
}
uniform_set = RD::get_singleton()->uniform_set_create(uniforms, p_base_shader, p_base_set);
- ct->uniform_sets[filter][repeat] = uniform_set;
+ ct->uniform_sets[filter][repeat][int(p_use_srgb)] = uniform_set;
ct->cleared_cache = false;
}
@@ -762,7 +764,7 @@ RID TextureStorage::texture_allocate() {
void TextureStorage::texture_free(RID p_texture) {
Texture *t = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!t);
+ ERR_FAIL_NULL(t);
ERR_FAIL_COND(t->is_render_target);
t->cleanup();
@@ -1087,7 +1089,7 @@ void TextureStorage::texture_3d_initialize(RID p_texture, Image::Format p_format
void TextureStorage::texture_proxy_initialize(RID p_texture, RID p_base) {
Texture *tex = texture_owner.get_or_null(p_base);
- ERR_FAIL_COND(!tex);
+ ERR_FAIL_NULL(tex);
Texture proxy_tex = *tex;
proxy_tex.rd_view.format_override = tex->rd_format;
@@ -1110,7 +1112,7 @@ void TextureStorage::_texture_2d_update(RID p_texture, const Ref<Image> &p_image
ERR_FAIL_COND(p_image.is_null() || p_image->is_empty());
Texture *tex = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!tex);
+ ERR_FAIL_NULL(tex);
ERR_FAIL_COND(tex->is_render_target);
ERR_FAIL_COND(p_image->get_width() != tex->width || p_image->get_height() != tex->height);
ERR_FAIL_COND(p_image->get_format() != tex->format);
@@ -1134,7 +1136,7 @@ void TextureStorage::texture_2d_update(RID p_texture, const Ref<Image> &p_image,
void TextureStorage::texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) {
Texture *tex = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!tex);
+ ERR_FAIL_NULL(tex);
ERR_FAIL_COND(tex->type != TextureStorage::TYPE_3D);
Image::Image3DValidateError verr = Image::validate_3d_image(tex->format, tex->width, tex->height, tex->depth, tex->mipmaps > 1, p_data);
@@ -1172,10 +1174,10 @@ void TextureStorage::texture_3d_update(RID p_texture, const Vector<Ref<Image>> &
void TextureStorage::texture_proxy_update(RID p_texture, RID p_proxy_to) {
Texture *tex = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!tex);
+ ERR_FAIL_NULL(tex);
ERR_FAIL_COND(!tex->is_proxy);
Texture *proxy_to = texture_owner.get_or_null(p_proxy_to);
- ERR_FAIL_COND(!proxy_to);
+ ERR_FAIL_NULL(proxy_to);
ERR_FAIL_COND(proxy_to->is_proxy);
if (tex->proxy_to.is_valid()) {
@@ -1189,7 +1191,7 @@ void TextureStorage::texture_proxy_update(RID p_texture, RID p_proxy_to) {
tex->rd_texture_srgb = RID();
}
Texture *prev_tex = texture_owner.get_or_null(tex->proxy_to);
- ERR_FAIL_COND(!prev_tex);
+ ERR_FAIL_NULL(prev_tex);
prev_tex->proxies.erase(p_texture);
}
@@ -1259,7 +1261,7 @@ void TextureStorage::texture_3d_placeholder_initialize(RID p_texture) {
Ref<Image> TextureStorage::texture_2d_get(RID p_texture) const {
Texture *tex = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND_V(!tex, Ref<Image>());
+ ERR_FAIL_NULL_V(tex, Ref<Image>());
#ifdef TOOLS_ENABLED
if (tex->image_cache_2d.is_valid() && !tex->is_render_target) {
@@ -1268,7 +1270,35 @@ Ref<Image> TextureStorage::texture_2d_get(RID p_texture) const {
#endif
Vector<uint8_t> data = RD::get_singleton()->texture_get_data(tex->rd_texture, 0);
ERR_FAIL_COND_V(data.size() == 0, Ref<Image>());
- Ref<Image> image = Image::create_from_data(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data);
+ Ref<Image> image;
+
+ // Expand RGB10_A2 into RGBAH. This is needed for capturing viewport data
+ // when using the mobile renderer with HDR mode on.
+ if (tex->rd_format == RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32) {
+ Vector<uint8_t> new_data;
+ new_data.resize(data.size() * 2);
+ uint16_t *ndp = (uint16_t *)new_data.ptr();
+
+ uint32_t *ptr = (uint32_t *)data.ptr();
+ uint32_t num_pixels = data.size() / 4;
+
+ for (uint32_t ofs = 0; ofs < num_pixels; ofs++) {
+ uint32_t px = ptr[ofs];
+ uint32_t r = (px & 0x3FF);
+ uint32_t g = ((px >> 10) & 0x3FF);
+ uint32_t b = ((px >> 20) & 0x3FF);
+ uint32_t a = ((px >> 30) & 0x3);
+
+ ndp[ofs * 4 + 0] = Math::make_half_float(float(r) / 1023.0);
+ ndp[ofs * 4 + 1] = Math::make_half_float(float(g) / 1023.0);
+ ndp[ofs * 4 + 2] = Math::make_half_float(float(b) / 1023.0);
+ ndp[ofs * 4 + 3] = Math::make_half_float(float(a) / 3.0);
+ }
+ image = Image::create_from_data(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, new_data);
+ } else {
+ image = Image::create_from_data(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data);
+ }
+
ERR_FAIL_COND_V(image->is_empty(), Ref<Image>());
if (tex->format != tex->validated_format) {
image->convert(tex->format);
@@ -1285,7 +1315,7 @@ Ref<Image> TextureStorage::texture_2d_get(RID p_texture) const {
Ref<Image> TextureStorage::texture_2d_layer_get(RID p_texture, int p_layer) const {
Texture *tex = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND_V(!tex, Ref<Image>());
+ ERR_FAIL_NULL_V(tex, Ref<Image>());
Vector<uint8_t> data = RD::get_singleton()->texture_get_data(tex->rd_texture, p_layer);
ERR_FAIL_COND_V(data.size() == 0, Ref<Image>());
@@ -1300,7 +1330,7 @@ Ref<Image> TextureStorage::texture_2d_layer_get(RID p_texture, int p_layer) cons
Vector<Ref<Image>> TextureStorage::texture_3d_get(RID p_texture) const {
Texture *tex = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND_V(!tex, Vector<Ref<Image>>());
+ ERR_FAIL_NULL_V(tex, Vector<Ref<Image>>());
ERR_FAIL_COND_V(tex->type != TextureStorage::TYPE_3D, Vector<Ref<Image>>());
Vector<uint8_t> all_data = RD::get_singleton()->texture_get_data(tex->rd_texture, 0);
@@ -1329,10 +1359,10 @@ Vector<Ref<Image>> TextureStorage::texture_3d_get(RID p_texture) const {
void TextureStorage::texture_replace(RID p_texture, RID p_by_texture) {
Texture *tex = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!tex);
+ ERR_FAIL_NULL(tex);
ERR_FAIL_COND(tex->proxy_to.is_valid()); //can't replace proxy
Texture *by_tex = texture_owner.get_or_null(p_by_texture);
- ERR_FAIL_COND(!by_tex);
+ ERR_FAIL_NULL(by_tex);
ERR_FAIL_COND(by_tex->proxy_to.is_valid()); //can't replace proxy
if (tex == by_tex) {
@@ -1374,7 +1404,7 @@ void TextureStorage::texture_replace(RID p_texture, RID p_by_texture) {
void TextureStorage::texture_set_size_override(RID p_texture, int p_width, int p_height) {
Texture *tex = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!tex);
+ ERR_FAIL_NULL(tex);
ERR_FAIL_COND(tex->type != TextureStorage::TYPE_2D);
tex->width_2d = p_width;
@@ -1383,28 +1413,28 @@ void TextureStorage::texture_set_size_override(RID p_texture, int p_width, int p
void TextureStorage::texture_set_path(RID p_texture, const String &p_path) {
Texture *tex = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!tex);
+ ERR_FAIL_NULL(tex);
tex->path = p_path;
}
String TextureStorage::texture_get_path(RID p_texture) const {
Texture *tex = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND_V(!tex, String());
+ ERR_FAIL_NULL_V(tex, String());
return tex->path;
}
Image::Format TextureStorage::texture_get_format(RID p_texture) const {
Texture *tex = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND_V(!tex, Image::FORMAT_MAX);
+ ERR_FAIL_NULL_V(tex, Image::FORMAT_MAX);
return tex->format;
}
void TextureStorage::texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) {
Texture *tex = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!tex);
+ ERR_FAIL_NULL(tex);
tex->detect_3d_callback_ud = p_userdata;
tex->detect_3d_callback = p_callback;
@@ -1412,7 +1442,7 @@ void TextureStorage::texture_set_detect_3d_callback(RID p_texture, RS::TextureDe
void TextureStorage::texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) {
Texture *tex = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!tex);
+ ERR_FAIL_NULL(tex);
tex->detect_normal_callback_ud = p_userdata;
tex->detect_normal_callback = p_callback;
@@ -1420,7 +1450,7 @@ void TextureStorage::texture_set_detect_normal_callback(RID p_texture, RS::Textu
void TextureStorage::texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) {
Texture *tex = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!tex);
+ ERR_FAIL_NULL(tex);
tex->detect_roughness_callback_ud = p_userdata;
tex->detect_roughness_callback = p_callback;
@@ -1524,7 +1554,7 @@ RID TextureStorage::texture_get_rd_texture(RID p_texture, bool p_srgb) const {
uint64_t TextureStorage::texture_get_native_handle(RID p_texture, bool p_srgb) const {
Texture *tex = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND_V(!tex, 0);
+ ERR_FAIL_NULL_V(tex, 0);
if (p_srgb && tex->rd_texture_srgb.is_valid()) {
return RD::get_singleton()->texture_get_native_handle(tex->rd_texture_srgb);
@@ -2388,14 +2418,14 @@ void TextureStorage::decal_free(RID p_rid) {
void TextureStorage::decal_set_size(RID p_decal, const Vector3 &p_size) {
Decal *decal = decal_owner.get_or_null(p_decal);
- ERR_FAIL_COND(!decal);
+ ERR_FAIL_NULL(decal);
decal->size = p_size;
decal->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
}
void TextureStorage::decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) {
Decal *decal = decal_owner.get_or_null(p_decal);
- ERR_FAIL_COND(!decal);
+ ERR_FAIL_NULL(decal);
ERR_FAIL_INDEX(p_type, RS::DECAL_TEXTURE_MAX);
if (decal->textures[p_type] == p_texture) {
@@ -2419,32 +2449,32 @@ void TextureStorage::decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID
void TextureStorage::decal_set_emission_energy(RID p_decal, float p_energy) {
Decal *decal = decal_owner.get_or_null(p_decal);
- ERR_FAIL_COND(!decal);
+ ERR_FAIL_NULL(decal);
decal->emission_energy = p_energy;
}
void TextureStorage::decal_set_albedo_mix(RID p_decal, float p_mix) {
Decal *decal = decal_owner.get_or_null(p_decal);
- ERR_FAIL_COND(!decal);
+ ERR_FAIL_NULL(decal);
decal->albedo_mix = p_mix;
}
void TextureStorage::decal_set_modulate(RID p_decal, const Color &p_modulate) {
Decal *decal = decal_owner.get_or_null(p_decal);
- ERR_FAIL_COND(!decal);
+ ERR_FAIL_NULL(decal);
decal->modulate = p_modulate;
}
void TextureStorage::decal_set_cull_mask(RID p_decal, uint32_t p_layers) {
Decal *decal = decal_owner.get_or_null(p_decal);
- ERR_FAIL_COND(!decal);
+ ERR_FAIL_NULL(decal);
decal->cull_mask = p_layers;
decal->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_DECAL);
}
void TextureStorage::decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) {
Decal *decal = decal_owner.get_or_null(p_decal);
- ERR_FAIL_COND(!decal);
+ ERR_FAIL_NULL(decal);
decal->distance_fade = p_enabled;
decal->distance_fade_begin = p_begin;
decal->distance_fade_length = p_length;
@@ -2452,14 +2482,14 @@ void TextureStorage::decal_set_distance_fade(RID p_decal, bool p_enabled, float
void TextureStorage::decal_set_fade(RID p_decal, float p_above, float p_below) {
Decal *decal = decal_owner.get_or_null(p_decal);
- ERR_FAIL_COND(!decal);
+ ERR_FAIL_NULL(decal);
decal->upper_fade = p_above;
decal->lower_fade = p_below;
}
void TextureStorage::decal_set_normal_fade(RID p_decal, float p_fade) {
Decal *decal = decal_owner.get_or_null(p_decal);
- ERR_FAIL_COND(!decal);
+ ERR_FAIL_NULL(decal);
decal->normal_fade = p_fade;
}
@@ -2480,21 +2510,21 @@ void TextureStorage::decal_atlas_remove_texture(RID p_texture) {
AABB TextureStorage::decal_get_aabb(RID p_decal) const {
Decal *decal = decal_owner.get_or_null(p_decal);
- ERR_FAIL_COND_V(!decal, AABB());
+ ERR_FAIL_NULL_V(decal, AABB());
return AABB(-decal->size / 2, decal->size);
}
uint32_t TextureStorage::decal_get_cull_mask(RID p_decal) const {
Decal *decal = decal_owner.get_or_null(p_decal);
- ERR_FAIL_COND_V(!decal, 0);
+ ERR_FAIL_NULL_V(decal, 0);
return decal->cull_mask;
}
Dependency *TextureStorage::decal_get_dependency(RID p_decal) {
Decal *decal = decal_owner.get_or_null(p_decal);
- ERR_FAIL_COND_V(!decal, nullptr);
+ ERR_FAIL_NULL_V(decal, nullptr);
return &decal->dependency;
}
@@ -2712,7 +2742,7 @@ void TextureStorage::texture_add_to_decal_atlas(RID p_texture, bool p_panorama_t
void TextureStorage::texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp) {
DecalAtlas::Texture *t = decal_atlas.textures.getptr(p_texture);
- ERR_FAIL_COND(!t);
+ ERR_FAIL_NULL(t);
t->users--;
if (p_panorama_to_dp) {
ERR_FAIL_COND(t->panorama_to_dp_users == 0);
@@ -2741,13 +2771,13 @@ void TextureStorage::decal_instance_free(RID p_decal_instance) {
void TextureStorage::decal_instance_set_transform(RID p_decal_instance, const Transform3D &p_transform) {
DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance);
- ERR_FAIL_COND(!di);
+ ERR_FAIL_NULL(di);
di->transform = p_transform;
}
void TextureStorage::decal_instance_set_sorting_offset(RID p_decal_instance, float p_sorting_offset) {
DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance);
- ERR_FAIL_COND(!di);
+ ERR_FAIL_NULL(di);
di->sorting_offset = p_sorting_offset;
}
@@ -3020,10 +3050,15 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
if (rt->size.width == 0 || rt->size.height == 0) {
return;
}
- //until we implement support for HDR monitors (and render target is attached to screen), this is enough.
- rt->color_format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- rt->color_format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
- rt->image_format = rt->is_transparent ? Image::FORMAT_RGBA8 : Image::FORMAT_RGB8;
+ if (rt->use_hdr) {
+ rt->color_format = RendererSceneRenderRD::get_singleton()->_render_buffers_get_color_format();
+ rt->color_format_srgb = rt->color_format;
+ rt->image_format = rt->is_transparent ? Image::FORMAT_RGBAH : Image::FORMAT_RGBH;
+ } else {
+ rt->color_format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ rt->color_format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
+ rt->image_format = rt->is_transparent ? Image::FORMAT_RGBA8 : Image::FORMAT_RGB8;
+ }
RD::TextureFormat rd_color_attachment_format;
RD::TextureView rd_view;
@@ -3106,6 +3141,7 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
tex->rd_format = rt->color_format;
tex->rd_format_srgb = rt->color_format_srgb;
tex->format = rt->image_format;
+ tex->validated_format = rt->use_hdr ? Image::FORMAT_RGBAH : Image::FORMAT_RGBA8;
Vector<RID> proxies = tex->proxies; //make a copy, since update may change it
for (int i = 0; i < proxies.size(); i++) {
@@ -3186,7 +3222,7 @@ Point2i TextureStorage::render_target_get_position(RID p_render_target) const {
void TextureStorage::render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
if (rt->size.x != p_width || rt->size.y != p_height || rt->view_count != p_view_count) {
rt->size.x = p_width;
rt->size.y = p_height;
@@ -3197,21 +3233,21 @@ void TextureStorage::render_target_set_size(RID p_render_target, int p_width, in
Size2i TextureStorage::render_target_get_size(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, Size2i());
+ ERR_FAIL_NULL_V(rt, Size2i());
return rt->size;
}
RID TextureStorage::render_target_get_texture(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, RID());
+ ERR_FAIL_NULL_V(rt, RID());
return rt->texture;
}
void TextureStorage::render_target_set_override(RID p_render_target, RID p_color_texture, RID p_depth_texture, RID p_velocity_texture) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
rt->overridden.color = p_color_texture;
rt->overridden.depth = p_depth_texture;
@@ -3220,21 +3256,21 @@ void TextureStorage::render_target_set_override(RID p_render_target, RID p_color
RID TextureStorage::render_target_get_override_color(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, RID());
+ ERR_FAIL_NULL_V(rt, RID());
return rt->overridden.color;
}
RID TextureStorage::render_target_get_override_depth(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, RID());
+ ERR_FAIL_NULL_V(rt, RID());
return rt->overridden.depth;
}
RID TextureStorage::render_target_get_override_depth_slice(RID p_render_target, const uint32_t p_layer) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, RID());
+ ERR_FAIL_NULL_V(rt, RID());
if (rt->overridden.depth.is_null()) {
return RID();
@@ -3253,14 +3289,14 @@ RID TextureStorage::render_target_get_override_depth_slice(RID p_render_target,
RID TextureStorage::render_target_get_override_velocity(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, RID());
+ ERR_FAIL_NULL_V(rt, RID());
return rt->overridden.velocity;
}
RID TextureStorage::render_target_get_override_velocity_slice(RID p_render_target, const uint32_t p_layer) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, RID());
+ ERR_FAIL_NULL_V(rt, RID());
if (rt->overridden.velocity.is_null()) {
return RID();
@@ -3279,14 +3315,14 @@ RID TextureStorage::render_target_get_override_velocity_slice(RID p_render_targe
void TextureStorage::render_target_set_transparent(RID p_render_target, bool p_is_transparent) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
rt->is_transparent = p_is_transparent;
_update_render_target(rt);
}
bool TextureStorage::render_target_get_transparent(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, false);
+ ERR_FAIL_NULL_V(rt, false);
return rt->is_transparent;
}
@@ -3300,19 +3336,19 @@ bool TextureStorage::render_target_get_direct_to_screen(RID p_render_target) con
bool TextureStorage::render_target_was_used(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, false);
+ ERR_FAIL_NULL_V(rt, false);
return rt->was_used;
}
void TextureStorage::render_target_set_as_unused(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
rt->was_used = false;
}
void TextureStorage::render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
if (p_msaa == rt->msaa) {
return;
}
@@ -3323,21 +3359,40 @@ void TextureStorage::render_target_set_msaa(RID p_render_target, RS::ViewportMSA
RS::ViewportMSAA TextureStorage::render_target_get_msaa(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, RS::VIEWPORT_MSAA_DISABLED);
+ ERR_FAIL_NULL_V(rt, RS::VIEWPORT_MSAA_DISABLED);
return rt->msaa;
}
+void TextureStorage::render_target_set_use_hdr(RID p_render_target, bool p_use_hdr) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_NULL(rt);
+
+ if (p_use_hdr == rt->use_hdr) {
+ return;
+ }
+
+ rt->use_hdr = p_use_hdr;
+ _update_render_target(rt);
+}
+
+bool TextureStorage::render_target_is_using_hdr(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_NULL_V(rt, false);
+
+ return rt->use_hdr;
+}
+
RID TextureStorage::render_target_get_rd_framebuffer(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, RID());
+ ERR_FAIL_NULL_V(rt, RID());
return rt->get_framebuffer();
}
RID TextureStorage::render_target_get_rd_texture(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, RID());
+ ERR_FAIL_NULL_V(rt, RID());
if (rt->overridden.color.is_valid()) {
return rt->overridden.color;
@@ -3348,7 +3403,7 @@ RID TextureStorage::render_target_get_rd_texture(RID p_render_target) {
RID TextureStorage::render_target_get_rd_texture_slice(RID p_render_target, uint32_t p_layer) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, RID());
+ ERR_FAIL_NULL_V(rt, RID());
if (rt->view_count == 1) {
return rt->color;
@@ -3366,20 +3421,20 @@ RID TextureStorage::render_target_get_rd_texture_slice(RID p_render_target, uint
RID TextureStorage::render_target_get_rd_texture_msaa(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, RID());
+ ERR_FAIL_NULL_V(rt, RID());
return rt->color_multisample;
}
RID TextureStorage::render_target_get_rd_backbuffer(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, RID());
+ ERR_FAIL_NULL_V(rt, RID());
return rt->backbuffer;
}
RID TextureStorage::render_target_get_rd_backbuffer_framebuffer(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, RID());
+ ERR_FAIL_NULL_V(rt, RID());
if (!rt->backbuffer.is_valid()) {
_create_render_target_backbuffer(rt);
@@ -3390,37 +3445,37 @@ RID TextureStorage::render_target_get_rd_backbuffer_framebuffer(RID p_render_tar
void TextureStorage::render_target_request_clear(RID p_render_target, const Color &p_clear_color) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
rt->clear_requested = true;
rt->clear_color = p_clear_color;
}
bool TextureStorage::render_target_is_clear_requested(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, false);
+ ERR_FAIL_NULL_V(rt, false);
return rt->clear_requested;
}
Color TextureStorage::render_target_get_clear_request_color(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, Color());
- return rt->clear_color;
+ ERR_FAIL_NULL_V(rt, Color());
+ return rt->use_hdr ? rt->clear_color.srgb_to_linear() : rt->clear_color;
}
void TextureStorage::render_target_disable_clear_request(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
rt->clear_requested = false;
}
void TextureStorage::render_target_do_clear_request(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
if (!rt->clear_requested) {
return;
}
Vector<Color> clear_colors;
- clear_colors.push_back(rt->clear_color);
+ clear_colors.push_back(rt->use_hdr ? rt->clear_color.srgb_to_linear() : rt->clear_color);
RD::get_singleton()->draw_list_begin(rt->get_framebuffer(), RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, clear_colors);
RD::get_singleton()->draw_list_end();
rt->clear_requested = false;
@@ -3428,7 +3483,7 @@ void TextureStorage::render_target_do_clear_request(RID p_render_target) {
void TextureStorage::render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
if (rt->sdf_oversize == p_size && rt->sdf_scale == p_scale) {
return;
}
@@ -3470,28 +3525,28 @@ Rect2i TextureStorage::_render_target_get_sdf_rect(const RenderTarget *rt) const
Rect2i TextureStorage::render_target_get_sdf_rect(RID p_render_target) const {
const RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, Rect2i());
+ ERR_FAIL_NULL_V(rt, Rect2i());
return _render_target_get_sdf_rect(rt);
}
void TextureStorage::render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
rt->sdf_enabled = p_enabled;
}
bool TextureStorage::render_target_is_sdf_enabled(RID p_render_target) const {
const RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, false);
+ ERR_FAIL_NULL_V(rt, false);
return rt->sdf_enabled;
}
RID TextureStorage::render_target_get_sdf_texture(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, RID());
+ ERR_FAIL_NULL_V(rt, RID());
if (rt->sdf_buffer_read.is_null()) {
// no texture, create a dummy one for the 2D uniform set
RD::TextureFormat tformat;
@@ -3629,7 +3684,7 @@ void TextureStorage::_render_target_clear_sdf(RenderTarget *rt) {
RID TextureStorage::render_target_get_sdf_framebuffer(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, RID());
+ ERR_FAIL_NULL_V(rt, RID());
if (rt->sdf_buffer_write_fb.is_null()) {
_render_target_allocate_sdf(rt);
@@ -3639,7 +3694,7 @@ RID TextureStorage::render_target_get_sdf_framebuffer(RID p_render_target) {
}
void TextureStorage::render_target_sdf_process(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
ERR_FAIL_COND(rt->sdf_buffer_write_fb.is_null());
RenderTargetSDF::PushConstant push_constant;
@@ -3717,7 +3772,7 @@ void TextureStorage::render_target_copy_to_back_buffer(RID p_render_target, cons
ERR_FAIL_NULL(copy_effects);
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
if (!rt->backbuffer.is_valid()) {
_create_render_target_backbuffer(rt);
}
@@ -3735,7 +3790,7 @@ void TextureStorage::render_target_copy_to_back_buffer(RID p_render_target, cons
// TODO figure out stereo support here
if (RendererSceneRenderRD::get_singleton()->_render_buffers_can_be_storage()) {
- copy_effects->copy_to_rect(rt->color, rt->backbuffer_mipmap0, region, false, false, false, true, true);
+ copy_effects->copy_to_rect(rt->color, rt->backbuffer_mipmap0, region, false, false, false, !rt->use_hdr, true);
} else {
copy_effects->copy_to_fb_rect(rt->color, rt->backbuffer_fb, region, false, false, false, false, RID(), false, true);
}
@@ -3759,7 +3814,7 @@ void TextureStorage::render_target_copy_to_back_buffer(RID p_render_target, cons
RID mipmap = rt->backbuffer_mipmaps[i];
if (RendererSceneRenderRD::get_singleton()->_render_buffers_can_be_storage()) {
- copy_effects->gaussian_blur(prev_texture, mipmap, region, texture_size, true);
+ copy_effects->gaussian_blur(prev_texture, mipmap, region, texture_size, !rt->use_hdr);
} else {
copy_effects->gaussian_blur_raster(prev_texture, mipmap, region, texture_size);
}
@@ -3770,7 +3825,7 @@ void TextureStorage::render_target_copy_to_back_buffer(RID p_render_target, cons
void TextureStorage::render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
CopyEffects *copy_effects = CopyEffects::get_singleton();
ERR_FAIL_NULL(copy_effects);
@@ -3789,9 +3844,9 @@ void TextureStorage::render_target_clear_back_buffer(RID p_render_target, const
}
}
- //single texture copy for backbuffer
+ // Single texture copy for backbuffer.
if (RendererSceneRenderRD::get_singleton()->_render_buffers_can_be_storage()) {
- copy_effects->set_color(rt->backbuffer_mipmap0, p_color, region, true);
+ copy_effects->set_color(rt->backbuffer_mipmap0, p_color, region, !rt->use_hdr);
} else {
copy_effects->set_color_raster(rt->backbuffer_mipmap0, p_color, region);
}
@@ -3799,7 +3854,7 @@ void TextureStorage::render_target_clear_back_buffer(RID p_render_target, const
void TextureStorage::render_target_gen_back_buffer_mipmaps(RID p_render_target, const Rect2i &p_region) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
CopyEffects *copy_effects = CopyEffects::get_singleton();
ERR_FAIL_NULL(copy_effects);
@@ -3833,7 +3888,7 @@ void TextureStorage::render_target_gen_back_buffer_mipmaps(RID p_render_target,
RID mipmap = rt->backbuffer_mipmaps[i];
if (RendererSceneRenderRD::get_singleton()->_render_buffers_can_be_storage()) {
- copy_effects->gaussian_blur(prev_texture, mipmap, region, texture_size, true);
+ copy_effects->gaussian_blur(prev_texture, mipmap, region, texture_size, !rt->use_hdr);
} else {
copy_effects->gaussian_blur_raster(prev_texture, mipmap, region, texture_size);
}
@@ -3844,51 +3899,51 @@ void TextureStorage::render_target_gen_back_buffer_mipmaps(RID p_render_target,
RID TextureStorage::render_target_get_framebuffer_uniform_set(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, RID());
+ ERR_FAIL_NULL_V(rt, RID());
return rt->framebuffer_uniform_set;
}
RID TextureStorage::render_target_get_backbuffer_uniform_set(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, RID());
+ ERR_FAIL_NULL_V(rt, RID());
return rt->backbuffer_uniform_set;
}
void TextureStorage::render_target_set_framebuffer_uniform_set(RID p_render_target, RID p_uniform_set) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
rt->framebuffer_uniform_set = p_uniform_set;
}
void TextureStorage::render_target_set_backbuffer_uniform_set(RID p_render_target, RID p_uniform_set) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(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);
+ ERR_FAIL_NULL(rt);
rt->vrs_mode = p_mode;
}
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);
+ ERR_FAIL_NULL_V(rt, RS::VIEWPORT_VRS_DISABLED);
return rt->vrs_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);
+ ERR_FAIL_NULL(rt);
rt->vrs_texture = p_texture;
}
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());
+ ERR_FAIL_NULL_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 6df6faa40a..276c8c4ce2 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h
@@ -96,7 +96,7 @@ private:
RS::CanvasItemTextureFilter texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT;
RS::CanvasItemTextureRepeat texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT;
- RID uniform_sets[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX];
+ RID uniform_sets[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX][2];
Size2i size_cache = Size2i(1, 1);
bool use_normal_cache = false;
@@ -341,6 +341,7 @@ private:
Image::Format image_format = Image::FORMAT_L8;
bool is_transparent = false;
+ bool use_hdr = false;
bool sdf_enabled = false;
@@ -474,7 +475,7 @@ public:
virtual void canvas_texture_set_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) override;
virtual void canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) override;
- bool canvas_texture_get_uniform_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular);
+ bool canvas_texture_get_uniform_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, bool p_use_srgb, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular, bool p_texture_is_data);
/* Texture API */
@@ -717,6 +718,8 @@ public:
virtual void render_target_set_as_unused(RID p_render_target) override;
virtual void render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) override;
virtual RS::ViewportMSAA render_target_get_msaa(RID p_render_target) const override;
+ virtual void render_target_set_use_hdr(RID p_render_target, bool p_use_hdr) override;
+ virtual bool render_target_is_using_hdr(RID p_render_target) const override;
void render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps);
void render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color);
diff --git a/servers/rendering/renderer_rd/storage_rd/utilities.cpp b/servers/rendering/renderer_rd/storage_rd/utilities.cpp
index cabac4e9ee..cb035c494c 100644
--- a/servers/rendering/renderer_rd/storage_rd/utilities.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/utilities.cpp
@@ -175,36 +175,34 @@ void Utilities::visibility_notifier_free(RID p_notifier) {
void Utilities::visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) {
VisibilityNotifier *vn = visibility_notifier_owner.get_or_null(p_notifier);
- ERR_FAIL_COND(!vn);
+ ERR_FAIL_NULL(vn);
vn->aabb = p_aabb;
vn->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
}
void Utilities::visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) {
VisibilityNotifier *vn = visibility_notifier_owner.get_or_null(p_notifier);
- ERR_FAIL_COND(!vn);
+ ERR_FAIL_NULL(vn);
vn->enter_callback = p_enter_callbable;
vn->exit_callback = p_exit_callable;
}
AABB Utilities::visibility_notifier_get_aabb(RID p_notifier) const {
const VisibilityNotifier *vn = visibility_notifier_owner.get_or_null(p_notifier);
- ERR_FAIL_COND_V(!vn, AABB());
+ ERR_FAIL_NULL_V(vn, AABB());
return vn->aabb;
}
void Utilities::visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) {
VisibilityNotifier *vn = visibility_notifier_owner.get_or_null(p_notifier);
- ERR_FAIL_COND(!vn);
+ ERR_FAIL_NULL(vn);
if (p_enter) {
if (!vn->enter_callback.is_null()) {
if (p_deferred) {
vn->enter_callback.call_deferred();
} else {
- Variant r;
- Callable::CallError ce;
- vn->enter_callback.callp(nullptr, 0, r, ce);
+ vn->enter_callback.call();
}
}
} else {
@@ -212,9 +210,7 @@ void Utilities::visibility_notifier_call(RID p_notifier, bool p_enter, bool p_de
if (p_deferred) {
vn->exit_callback.call_deferred();
} else {
- Variant r;
- Callable::CallError ce;
- vn->exit_callback.callp(nullptr, 0, r, ce);
+ vn->exit_callback.call();
}
}
}