summaryrefslogtreecommitdiffstats
path: root/servers/rendering
diff options
context:
space:
mode:
Diffstat (limited to 'servers/rendering')
-rw-r--r--servers/rendering/dummy/rasterizer_dummy.h2
-rw-r--r--servers/rendering/dummy/rasterizer_scene_dummy.h1
-rw-r--r--servers/rendering/dummy/storage/light_storage.cpp86
-rw-r--r--servers/rendering/dummy/storage/light_storage.h36
-rw-r--r--servers/rendering/dummy/storage/material_storage.cpp6
-rw-r--r--servers/rendering/dummy/storage/mesh_storage.cpp10
-rw-r--r--servers/rendering/dummy/storage/mesh_storage.h58
-rw-r--r--servers/rendering/dummy/storage/utilities.h7
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp58
-rw-r--r--servers/rendering/renderer_canvas_cull.h3
-rw-r--r--servers/rendering/renderer_canvas_render.h10
-rw-r--r--servers/rendering/renderer_compositor.cpp5
-rw-r--r--servers/rendering/renderer_compositor.h4
-rw-r--r--servers/rendering/renderer_rd/cluster_builder_rd.h7
-rw-r--r--servers/rendering/renderer_rd/effects/fsr2.cpp3
-rw-r--r--servers/rendering/renderer_rd/environment/gi.cpp4
-rw-r--r--servers/rendering/renderer_rd/environment/sky.cpp2
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp56
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h6
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp3
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp60
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h8
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp3
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp63
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.h3
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.cpp2
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.h2
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp63
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.h6
-rw-r--r--servers/rendering/renderer_rd/shader_rd.cpp9
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas.glsl7
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl1
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl19
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_inc.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/ss_effects_downsample.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/tonemap.glsl19
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/sky.glsl8
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/volumetric_fog.glsl16
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl12
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl134
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl3
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl148
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl3
-rw-r--r--servers/rendering/renderer_rd/shaders/particles.glsl18
-rw-r--r--servers/rendering/renderer_rd/storage_rd/light_storage.cpp1
-rw-r--r--servers/rendering/renderer_rd/storage_rd/light_storage.h7
-rw-r--r--servers/rendering/renderer_rd/storage_rd/material_storage.cpp19
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp68
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.h48
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_data_rd.cpp3
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_data_rd.h5
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp6
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp19
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h5
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.cpp20
-rw-r--r--servers/rendering/renderer_scene_cull.cpp285
-rw-r--r--servers/rendering/renderer_scene_cull.h65
-rw-r--r--servers/rendering/renderer_scene_render.h1
-rw-r--r--servers/rendering/renderer_viewport.cpp12
-rw-r--r--servers/rendering/renderer_viewport.h2
-rw-r--r--servers/rendering/rendering_context_driver.cpp85
-rw-r--r--servers/rendering/rendering_context_driver.h15
-rw-r--r--servers/rendering/rendering_device.compat.inc11
-rw-r--r--servers/rendering/rendering_device.cpp182
-rw-r--r--servers/rendering/rendering_device.h38
-rw-r--r--servers/rendering/rendering_device_binds.cpp5
-rw-r--r--servers/rendering/rendering_device_commons.h38
-rw-r--r--servers/rendering/rendering_device_driver.h7
-rw-r--r--servers/rendering/rendering_device_graph.cpp11
-rw-r--r--servers/rendering/rendering_device_graph.h9
-rw-r--r--servers/rendering/rendering_method.h13
-rw-r--r--servers/rendering/rendering_server_constants.h48
-rw-r--r--servers/rendering/rendering_server_default.cpp14
-rw-r--r--servers/rendering/rendering_server_default.h12
-rw-r--r--servers/rendering/shader_compiler.cpp11
-rw-r--r--servers/rendering/shader_language.cpp399
-rw-r--r--servers/rendering/shader_language.h132
-rw-r--r--servers/rendering/shader_preprocessor.cpp2
-rw-r--r--servers/rendering/shader_types.cpp35
-rw-r--r--servers/rendering/storage/mesh_storage.cpp485
-rw-r--r--servers/rendering/storage/mesh_storage.h128
82 files changed, 2685 insertions, 545 deletions
diff --git a/servers/rendering/dummy/rasterizer_dummy.h b/servers/rendering/dummy/rasterizer_dummy.h
index a4f353359a..c3f5f3102d 100644
--- a/servers/rendering/dummy/rasterizer_dummy.h
+++ b/servers/rendering/dummy/rasterizer_dummy.h
@@ -88,7 +88,7 @@ public:
void blit_render_targets_to_screen(int p_screen, const BlitToScreen *p_render_targets, int p_amount) override {}
- void end_viewport(bool p_swap_buffers) override {}
+ void gl_end_frame(bool p_swap_buffers) override {}
void end_frame(bool p_swap_buffers) override {
if (p_swap_buffers) {
diff --git a/servers/rendering/dummy/rasterizer_scene_dummy.h b/servers/rendering/dummy/rasterizer_scene_dummy.h
index 083493003f..a699a58b1f 100644
--- a/servers/rendering/dummy/rasterizer_scene_dummy.h
+++ b/servers/rendering/dummy/rasterizer_scene_dummy.h
@@ -186,6 +186,7 @@ public:
virtual void decals_set_filter(RS::DecalFilter p_filter) override {}
virtual void light_projectors_set_filter(RS::LightProjectorFilter p_filter) override {}
+ virtual void lightmaps_set_bicubic_filter(bool p_enable) override {}
RasterizerSceneDummy() {}
~RasterizerSceneDummy() {}
diff --git a/servers/rendering/dummy/storage/light_storage.cpp b/servers/rendering/dummy/storage/light_storage.cpp
new file mode 100644
index 0000000000..443e047b37
--- /dev/null
+++ b/servers/rendering/dummy/storage/light_storage.cpp
@@ -0,0 +1,86 @@
+/**************************************************************************/
+/* light_storage.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 "light_storage.h"
+
+using namespace RendererDummy;
+
+LightStorage *LightStorage::singleton = nullptr;
+
+LightStorage *LightStorage::get_singleton() {
+ return singleton;
+}
+
+LightStorage::LightStorage() {
+ singleton = this;
+}
+
+LightStorage::~LightStorage() {
+ singleton = nullptr;
+}
+
+bool LightStorage::free(RID p_rid) {
+ if (owns_lightmap(p_rid)) {
+ lightmap_free(p_rid);
+ return true;
+ } else if (owns_lightmap_instance(p_rid)) {
+ lightmap_instance_free(p_rid);
+ return true;
+ }
+
+ return false;
+}
+
+/* LIGHTMAP API */
+
+RID LightStorage::lightmap_allocate() {
+ return lightmap_owner.allocate_rid();
+}
+
+void LightStorage::lightmap_initialize(RID p_lightmap) {
+ lightmap_owner.initialize_rid(p_lightmap, Lightmap());
+}
+
+void LightStorage::lightmap_free(RID p_rid) {
+ lightmap_set_textures(p_rid, RID(), false);
+ lightmap_owner.free(p_rid);
+}
+
+/* LIGHTMAP INSTANCE */
+
+RID LightStorage::lightmap_instance_create(RID p_lightmap) {
+ LightmapInstance li;
+ li.lightmap = p_lightmap;
+ return lightmap_instance_owner.make_rid(li);
+}
+
+void LightStorage::lightmap_instance_free(RID p_lightmap) {
+ lightmap_instance_owner.free(p_lightmap);
+}
diff --git a/servers/rendering/dummy/storage/light_storage.h b/servers/rendering/dummy/storage/light_storage.h
index 0a9602b603..c3b63cdbf6 100644
--- a/servers/rendering/dummy/storage/light_storage.h
+++ b/servers/rendering/dummy/storage/light_storage.h
@@ -36,7 +36,29 @@
namespace RendererDummy {
class LightStorage : public RendererLightStorage {
+private:
+ static LightStorage *singleton;
+ /* LIGHTMAP */
+ struct Lightmap {
+ // dummy lightmap, no data
+ };
+
+ mutable RID_Owner<Lightmap, true> lightmap_owner;
+ /* LIGHTMAP INSTANCE */
+
+ struct LightmapInstance {
+ RID lightmap;
+ };
+
+ mutable RID_Owner<LightmapInstance> lightmap_instance_owner;
+
public:
+ static LightStorage *get_singleton();
+
+ LightStorage();
+ virtual ~LightStorage();
+
+ bool free(RID p_rid);
/* Light API */
virtual RID directional_light_allocate() override { return RID(); }
@@ -146,9 +168,11 @@ public:
/* LIGHTMAP CAPTURE */
- virtual RID lightmap_allocate() override { return RID(); }
- virtual void lightmap_initialize(RID p_rid) override {}
- virtual void lightmap_free(RID p_rid) override {}
+ bool owns_lightmap(RID p_rid) { return lightmap_owner.owns(p_rid); }
+
+ virtual RID lightmap_allocate() override;
+ virtual void lightmap_initialize(RID p_rid) override;
+ virtual void lightmap_free(RID p_rid) override;
virtual void lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) override {}
virtual void lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) override {}
@@ -167,8 +191,10 @@ public:
/* LIGHTMAP INSTANCE */
- RID lightmap_instance_create(RID p_lightmap) override { return RID(); }
- void lightmap_instance_free(RID p_lightmap) override {}
+ bool owns_lightmap_instance(RID p_rid) { return lightmap_instance_owner.owns(p_rid); }
+
+ RID lightmap_instance_create(RID p_lightmap) override;
+ void lightmap_instance_free(RID p_lightmap) override;
void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override {}
/* SHADOW ATLAS API */
diff --git a/servers/rendering/dummy/storage/material_storage.cpp b/servers/rendering/dummy/storage/material_storage.cpp
index 64f6b55172..e8b553ca76 100644
--- a/servers/rendering/dummy/storage/material_storage.cpp
+++ b/servers/rendering/dummy/storage/material_storage.cpp
@@ -102,11 +102,7 @@ void MaterialStorage::get_shader_parameter_list(RID p_shader, List<PropertyInfo>
if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
continue;
}
- if (E.value.texture_order >= 0) {
- filtered_uniforms.push_back(Pair<StringName, int>(E.key, E.value.texture_order + 100000));
- } else {
- filtered_uniforms.push_back(Pair<StringName, int>(E.key, E.value.order));
- }
+ filtered_uniforms.push_back(Pair<StringName, int>(E.key, E.value.prop_order));
}
int uniform_count = filtered_uniforms.size();
sorter.sort(filtered_uniforms.ptr(), uniform_count);
diff --git a/servers/rendering/dummy/storage/mesh_storage.cpp b/servers/rendering/dummy/storage/mesh_storage.cpp
index 0b7ade1762..3f90c80826 100644
--- a/servers/rendering/dummy/storage/mesh_storage.cpp
+++ b/servers/rendering/dummy/storage/mesh_storage.cpp
@@ -64,22 +64,22 @@ void MeshStorage::mesh_clear(RID p_mesh) {
m->surfaces.clear();
}
-RID MeshStorage::multimesh_allocate() {
+RID MeshStorage::_multimesh_allocate() {
return multimesh_owner.allocate_rid();
}
-void MeshStorage::multimesh_initialize(RID p_rid) {
+void MeshStorage::_multimesh_initialize(RID p_rid) {
multimesh_owner.initialize_rid(p_rid, DummyMultiMesh());
}
-void MeshStorage::multimesh_free(RID p_rid) {
+void MeshStorage::_multimesh_free(RID p_rid) {
DummyMultiMesh *multimesh = multimesh_owner.get_or_null(p_rid);
ERR_FAIL_NULL(multimesh);
multimesh_owner.free(p_rid);
}
-void MeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) {
+void MeshStorage::_multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) {
DummyMultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL(multimesh);
multimesh->buffer.resize(p_buffer.size());
@@ -87,7 +87,7 @@ void MeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_b
memcpy(cache_data, p_buffer.ptr(), p_buffer.size() * sizeof(float));
}
-Vector<float> MeshStorage::multimesh_get_buffer(RID p_multimesh) const {
+Vector<float> MeshStorage::_multimesh_get_buffer(RID p_multimesh) const {
DummyMultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL_V(multimesh, Vector<float>());
diff --git a/servers/rendering/dummy/storage/mesh_storage.h b/servers/rendering/dummy/storage/mesh_storage.h
index d98b2e2ee7..ec19562147 100644
--- a/servers/rendering/dummy/storage/mesh_storage.h
+++ b/servers/rendering/dummy/storage/mesh_storage.h
@@ -146,34 +146,36 @@ public:
bool owns_multimesh(RID p_rid) { return multimesh_owner.owns(p_rid); }
- virtual RID multimesh_allocate() override;
- virtual void multimesh_initialize(RID p_rid) override;
- virtual void multimesh_free(RID p_rid) override;
-
- virtual void multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) override {}
- virtual int multimesh_get_instance_count(RID p_multimesh) const override { return 0; }
-
- virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh) override {}
- virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) override {}
- virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) override {}
- virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) override {}
- virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) override {}
-
- virtual void multimesh_set_custom_aabb(RID p_multimesh, const AABB &p_aabb) override {}
- virtual AABB multimesh_get_custom_aabb(RID p_multimesh) const override { return AABB(); }
-
- virtual RID multimesh_get_mesh(RID p_multimesh) const override { return RID(); }
- virtual AABB multimesh_get_aabb(RID p_multimesh) const override { return AABB(); }
-
- virtual Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const override { return Transform3D(); }
- virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const override { return Transform2D(); }
- virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const override { return Color(); }
- virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override { return Color(); }
- virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) override;
- virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const override;
-
- virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible) override {}
- virtual int multimesh_get_visible_instances(RID p_multimesh) const override { return 0; }
+ virtual RID _multimesh_allocate() override;
+ virtual void _multimesh_initialize(RID p_rid) override;
+ virtual void _multimesh_free(RID p_rid) override;
+
+ virtual void _multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) override {}
+ virtual int _multimesh_get_instance_count(RID p_multimesh) const override { return 0; }
+
+ virtual void _multimesh_set_mesh(RID p_multimesh, RID p_mesh) override {}
+ virtual void _multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) override {}
+ virtual void _multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) override {}
+ virtual void _multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) override {}
+ virtual void _multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) override {}
+
+ virtual void _multimesh_set_custom_aabb(RID p_multimesh, const AABB &p_aabb) override {}
+ virtual AABB _multimesh_get_custom_aabb(RID p_multimesh) const override { return AABB(); }
+
+ virtual RID _multimesh_get_mesh(RID p_multimesh) const override { return RID(); }
+ virtual AABB _multimesh_get_aabb(RID p_multimesh) const override { return AABB(); }
+
+ virtual Transform3D _multimesh_instance_get_transform(RID p_multimesh, int p_index) const override { return Transform3D(); }
+ virtual Transform2D _multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const override { return Transform2D(); }
+ virtual Color _multimesh_instance_get_color(RID p_multimesh, int p_index) const override { return Color(); }
+ virtual Color _multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override { return Color(); }
+ virtual void _multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) override;
+ virtual Vector<float> _multimesh_get_buffer(RID p_multimesh) const override;
+
+ virtual void _multimesh_set_visible_instances(RID p_multimesh, int p_visible) override {}
+ virtual int _multimesh_get_visible_instances(RID p_multimesh) const override { return 0; }
+
+ MultiMeshInterpolator *_multimesh_get_interpolator(RID p_multimesh) const override { return nullptr; }
/* SKELETON API */
diff --git a/servers/rendering/dummy/storage/utilities.h b/servers/rendering/dummy/storage/utilities.h
index 6e8af9afac..ae83547afd 100644
--- a/servers/rendering/dummy/storage/utilities.h
+++ b/servers/rendering/dummy/storage/utilities.h
@@ -31,6 +31,7 @@
#ifndef UTILITIES_DUMMY_H
#define UTILITIES_DUMMY_H
+#include "light_storage.h"
#include "material_storage.h"
#include "mesh_storage.h"
#include "servers/rendering/storage/utilities.h"
@@ -55,12 +56,16 @@ public:
return RS::INSTANCE_MESH;
} else if (RendererDummy::MeshStorage::get_singleton()->owns_multimesh(p_rid)) {
return RS::INSTANCE_MULTIMESH;
+ } else if (RendererDummy::LightStorage::get_singleton()->owns_lightmap(p_rid)) {
+ return RS::INSTANCE_LIGHTMAP;
}
return RS::INSTANCE_NONE;
}
virtual bool free(RID p_rid) override {
- if (RendererDummy::TextureStorage::get_singleton()->owns_texture(p_rid)) {
+ if (RendererDummy::LightStorage::get_singleton()->free(p_rid)) {
+ return true;
+ } else if (RendererDummy::TextureStorage::get_singleton()->owns_texture(p_rid)) {
RendererDummy::TextureStorage::get_singleton()->texture_free(p_rid);
return true;
} else if (RendererDummy::MeshStorage::get_singleton()->owns_mesh(p_rid)) {
diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp
index e92050a323..0ec161d8cf 100644
--- a/servers/rendering/renderer_canvas_cull.cpp
+++ b/servers/rendering/renderer_canvas_cull.cpp
@@ -51,7 +51,7 @@ void RendererCanvasCull::_render_canvas_item_tree(RID p_to_render_target, Canvas
memset(z_last_list, 0, z_range * sizeof(RendererCanvasRender::Item *));
for (int i = 0; i < p_child_item_count; i++) {
- _cull_canvas_item(p_child_items[i].item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr, true, p_canvas_cull_mask, p_child_items[i].mirror, 1);
+ _cull_canvas_item(p_child_items[i].item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr, true, p_canvas_cull_mask, Point2(), 1, nullptr);
}
RendererCanvasRender::Item *list = nullptr;
@@ -97,6 +97,7 @@ void _collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, const Tran
if (!child_items[i]->repeat_source) {
child_items[i]->repeat_size = p_canvas_item->repeat_size;
child_items[i]->repeat_times = p_canvas_item->repeat_times;
+ child_items[i]->repeat_source_item = p_canvas_item->repeat_source_item;
}
// Y sorted canvas items are flattened into r_items. Calculate their absolute z index to use when rendering r_items.
@@ -229,10 +230,13 @@ void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item *
ci->visibility_notifier->visible_in_frame = RSG::rasterizer->get_frame_number();
}
+ } else if (ci->repeat_source) {
+ // If repeat source does not draw itself it still needs transform updated as its child items' repeat offsets are relative to it.
+ ci->final_transform = p_transform;
}
}
-void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2D &p_parent_xform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool p_allow_y_sort, uint32_t p_canvas_cull_mask, const Point2 &p_repeat_size, int p_repeat_times) {
+void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2D &p_parent_xform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool p_allow_y_sort, uint32_t p_canvas_cull_mask, const Point2 &p_repeat_size, int p_repeat_times, RendererCanvasRender::Item *p_repeat_source_item) {
Item *ci = p_canvas_item;
if (!ci->visible) {
@@ -268,29 +272,45 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
Point2 repeat_size = p_repeat_size;
int repeat_times = p_repeat_times;
+ RendererCanvasRender::Item *repeat_source_item = p_repeat_source_item;
if (ci->repeat_source) {
repeat_size = ci->repeat_size;
repeat_times = ci->repeat_times;
+ repeat_source_item = ci;
} else {
ci->repeat_size = repeat_size;
ci->repeat_times = repeat_times;
- }
-
- if (repeat_size.x || repeat_size.y) {
- Size2 scale = final_xform.get_scale();
- rect.size += repeat_size * repeat_times / scale;
- rect.position -= repeat_size / scale * (repeat_times / 2);
+ ci->repeat_source_item = repeat_source_item;
}
if (snapping_2d_transforms_to_pixel) {
- final_xform.columns[2] = final_xform.columns[2].round();
- parent_xform.columns[2] = parent_xform.columns[2].round();
+ final_xform.columns[2] = (final_xform.columns[2] + Point2(0.5, 0.5)).floor();
+ parent_xform.columns[2] = (parent_xform.columns[2] + Point2(0.5, 0.5)).floor();
}
final_xform = parent_xform * final_xform;
Rect2 global_rect = final_xform.xform(rect);
+ if (repeat_source_item && (repeat_size.x || repeat_size.y)) {
+ // Top-left repeated rect.
+ Rect2 corner_rect = global_rect;
+ corner_rect.position -= repeat_source_item->final_transform.basis_xform((repeat_times / 2) * repeat_size);
+ global_rect = corner_rect;
+
+ // Plus top-right repeated rect.
+ Size2 size_x_offset = repeat_source_item->final_transform.basis_xform(repeat_times * Size2(repeat_size.x, 0));
+ corner_rect.position += size_x_offset;
+ global_rect = global_rect.merge(corner_rect);
+
+ // Plus bottom-right repeated rect.
+ corner_rect.position += repeat_source_item->final_transform.basis_xform(repeat_times * Size2(0, repeat_size.y));
+ global_rect = global_rect.merge(corner_rect);
+
+ // Plus bottom-left repeated rect.
+ corner_rect.position -= size_x_offset;
+ global_rect = global_rect.merge(corner_rect);
+ }
global_rect.position += p_clip_rect.position;
if (ci->use_parent_material && p_material_owner) {
@@ -357,7 +377,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
sorter.sort(child_items, child_item_count);
for (i = 0; i < child_item_count; i++) {
- _cull_canvas_item(child_items[i], final_xform * child_items[i]->ysort_xform, p_clip_rect, modulate * child_items[i]->ysort_modulate, child_items[i]->ysort_parent_abs_z_index, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner, false, p_canvas_cull_mask, child_items[i]->repeat_size, child_items[i]->repeat_times);
+ _cull_canvas_item(child_items[i], final_xform * child_items[i]->ysort_xform, p_clip_rect, modulate * child_items[i]->ysort_modulate, child_items[i]->ysort_parent_abs_z_index, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner, false, p_canvas_cull_mask, child_items[i]->repeat_size, child_items[i]->repeat_times, child_items[i]->repeat_source_item);
}
} else {
RendererCanvasRender::Item *canvas_group_from = nullptr;
@@ -381,14 +401,14 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
if (!child_items[i]->behind && !use_canvas_group) {
continue;
}
- _cull_canvas_item(child_items[i], final_xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, p_canvas_cull_mask, repeat_size, repeat_times);
+ _cull_canvas_item(child_items[i], final_xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, p_canvas_cull_mask, repeat_size, repeat_times, repeat_source_item);
}
_attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, final_xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from);
for (int i = 0; i < child_item_count; i++) {
if (child_items[i]->behind || use_canvas_group) {
continue;
}
- _cull_canvas_item(child_items[i], final_xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, p_canvas_cull_mask, repeat_size, repeat_times);
+ _cull_canvas_item(child_items[i], final_xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, p_canvas_cull_mask, repeat_size, repeat_times, repeat_source_item);
}
}
}
@@ -431,14 +451,22 @@ void RendererCanvasCull::canvas_set_item_mirroring(RID p_canvas, RID p_item, con
int idx = canvas->find_item(canvas_item);
ERR_FAIL_COND(idx == -1);
- canvas->child_items.write[idx].mirror = p_mirroring;
+
+ bool is_repeat_source = (p_mirroring.x || p_mirroring.y);
+ canvas_item->repeat_source = is_repeat_source;
+ canvas_item->repeat_source_item = is_repeat_source ? canvas_item : nullptr;
+ canvas_item->repeat_size = p_mirroring;
+ canvas_item->repeat_times = 1;
}
void RendererCanvasCull::canvas_set_item_repeat(RID p_item, const Point2 &p_repeat_size, int p_repeat_times) {
+ ERR_FAIL_COND(p_repeat_times < 0);
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_NULL(canvas_item);
- canvas_item->repeat_source = true;
+ bool is_repeat_source = (p_repeat_size.x || p_repeat_size.y) && p_repeat_times;
+ canvas_item->repeat_source = is_repeat_source;
+ canvas_item->repeat_source_item = is_repeat_source ? canvas_item : nullptr;
canvas_item->repeat_size = p_repeat_size;
canvas_item->repeat_times = p_repeat_times;
}
diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h
index 9f8cbea2e9..91c03054f7 100644
--- a/servers/rendering/renderer_canvas_cull.h
+++ b/servers/rendering/renderer_canvas_cull.h
@@ -126,7 +126,6 @@ public:
struct Canvas : public RendererViewport::CanvasBase {
HashSet<RID> viewports;
struct ChildItem {
- Point2 mirror;
Item *item = nullptr;
bool operator<(const ChildItem &p_item) const {
return item->index < p_item.item->index;
@@ -188,7 +187,7 @@ public:
private:
void _render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, uint32_t p_canvas_cull_mask, RenderingMethod::RenderInfo *r_render_info = nullptr);
- void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_parent_xform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool p_allow_y_sort, uint32_t p_canvas_cull_mask, const Point2 &p_repeat_size, int p_repeat_times);
+ void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_parent_xform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool p_allow_y_sort, uint32_t p_canvas_cull_mask, const Point2 &p_repeat_size, int p_repeat_times, RendererCanvasRender::Item *p_repeat_source_item);
static constexpr int z_range = RS::CANVAS_ITEM_Z_MAX - RS::CANVAS_ITEM_Z_MIN + 1;
diff --git a/servers/rendering/renderer_canvas_render.h b/servers/rendering/renderer_canvas_render.h
index 4a56548932..c57abee165 100644
--- a/servers/rendering/renderer_canvas_render.h
+++ b/servers/rendering/renderer_canvas_render.h
@@ -364,6 +364,7 @@ public:
bool repeat_source;
Point2 repeat_size;
int repeat_times = 1;
+ Item *repeat_source_item = nullptr;
Rect2 global_rect_cache;
@@ -545,8 +546,13 @@ public:
virtual void set_debug_redraw(bool p_enabled, double p_time, const Color &p_color) = 0;
- RendererCanvasRender() { singleton = this; }
- virtual ~RendererCanvasRender() {}
+ RendererCanvasRender() {
+ ERR_FAIL_COND_MSG(singleton != nullptr, "A RendererCanvasRender singleton already exists.");
+ singleton = this;
+ }
+ virtual ~RendererCanvasRender() {
+ singleton = nullptr;
+ }
};
#endif // RENDERER_CANVAS_RENDER_H
diff --git a/servers/rendering/renderer_compositor.cpp b/servers/rendering/renderer_compositor.cpp
index d364de5633..428cecead1 100644
--- a/servers/rendering/renderer_compositor.cpp
+++ b/servers/rendering/renderer_compositor.cpp
@@ -47,6 +47,7 @@ bool RendererCompositor::is_xr_enabled() const {
}
RendererCompositor::RendererCompositor() {
+ ERR_FAIL_COND_MSG(singleton != nullptr, "A RendererCompositor singleton already exists.");
singleton = this;
#ifndef _3D_DISABLED
@@ -57,3 +58,7 @@ RendererCompositor::RendererCompositor() {
}
#endif // _3D_DISABLED
}
+
+RendererCompositor::~RendererCompositor() {
+ singleton = nullptr;
+}
diff --git a/servers/rendering/renderer_compositor.h b/servers/rendering/renderer_compositor.h
index 3c49e31516..933b9e457f 100644
--- a/servers/rendering/renderer_compositor.h
+++ b/servers/rendering/renderer_compositor.h
@@ -98,7 +98,7 @@ public:
virtual void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) = 0;
- virtual void end_viewport(bool p_swap_buffers) = 0;
+ virtual void gl_end_frame(bool p_swap_buffers) = 0;
virtual void end_frame(bool p_swap_buffers) = 0;
virtual void finalize() = 0;
virtual uint64_t get_frame_number() const = 0;
@@ -110,7 +110,7 @@ public:
static RendererCompositor *get_singleton() { return singleton; }
RendererCompositor();
- virtual ~RendererCompositor() {}
+ virtual ~RendererCompositor();
};
#endif // RENDERER_COMPOSITOR_H
diff --git a/servers/rendering/renderer_rd/cluster_builder_rd.h b/servers/rendering/renderer_rd/cluster_builder_rd.h
index 3ca7af70ca..1badce2b81 100644
--- a/servers/rendering/renderer_rd/cluster_builder_rd.h
+++ b/servers/rendering/renderer_rd/cluster_builder_rd.h
@@ -185,7 +185,14 @@ private:
};
uint32_t cluster_size = 32;
+#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
+ // Results in visual artifacts on macOS and iOS when using MSAA and subgroups.
+ // Using subgroups and disabling MSAA is the optimal solution for now and also works
+ // with MoltenVK.
+ bool use_msaa = false;
+#else
bool use_msaa = true;
+#endif
Divisor divisor = DIVISOR_4;
Size2i screen_size;
diff --git a/servers/rendering/renderer_rd/effects/fsr2.cpp b/servers/rendering/renderer_rd/effects/fsr2.cpp
index 925352a7d1..551ea5dd97 100644
--- a/servers/rendering/renderer_rd/effects/fsr2.cpp
+++ b/servers/rendering/renderer_rd/effects/fsr2.cpp
@@ -800,9 +800,6 @@ FSR2Effect::~FSR2Effect() {
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);
}
}
diff --git a/servers/rendering/renderer_rd/environment/gi.cpp b/servers/rendering/renderer_rd/environment/gi.cpp
index c7752f8a86..12ff28d7b0 100644
--- a/servers/rendering/renderer_rd/environment/gi.cpp
+++ b/servers/rendering/renderer_rd/environment/gi.cpp
@@ -1790,6 +1790,10 @@ void GI::SDFGI::debug_probes(RID p_framebuffer, const uint32_t p_view_count, con
}
void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_render_data) {
+ if (p_render_data->sdfgi_update_data == nullptr) {
+ return;
+ }
+
RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
/* Update general SDFGI Buffer */
diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp
index b5d31f5414..5dc67725f1 100644
--- a/servers/rendering/renderer_rd/environment/sky.cpp
+++ b/servers/rendering/renderer_rd/environment/sky.cpp
@@ -1348,7 +1348,7 @@ void SkyRD::update_radiance_buffers(Ref<RenderSceneBuffersRD> p_render_buffers,
Basis local_view = Basis::looking_at(view_normals[i], view_up[i]);
RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_CUBEMAP, sky_shader.default_shader_rd, p_render_buffers);
- cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[0].framebuffers[i], RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD);
+ cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[0].framebuffers[i], RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, Rect2(), RDD::BreadcrumbMarker::SKY_PASS | uint32_t(i));
_render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, cm, local_view, p_global_pos, p_luminance_multiplier);
RD::get_singleton()->draw_list_end();
}
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 aae32f0b3e..36bd22b723 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -587,7 +587,7 @@ void RenderForwardClustered::_render_list_with_draw_list(RenderListParameters *p
RD::get_singleton()->draw_list_end();
}
-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) {
+void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, 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;
@@ -603,7 +603,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_apply_alpha_multiplier);
+ 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_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
@@ -1103,9 +1103,17 @@ void RenderForwardClustered::_setup_lightmaps(const RenderDataRD *p_render_data,
RID lightmap = light_storage->lightmap_instance_get_lightmap(p_lightmaps[i]);
+ // Transform (for directional lightmaps).
Basis to_lm = light_storage->lightmap_instance_get_transform(p_lightmaps[i]).basis.inverse() * p_cam_transform.basis;
to_lm = to_lm.inverse().transposed(); //will transform normals
RendererRD::MaterialStorage::store_transform_3x3(to_lm, scene_state.lightmaps[i].normal_xform);
+
+ // Light texture size.
+ Vector2i lightmap_size = light_storage->lightmap_get_light_texture_size(lightmap);
+ scene_state.lightmaps[i].texture_size[0] = lightmap_size[0];
+ scene_state.lightmaps[i].texture_size[1] = lightmap_size[1];
+
+ // Exposure.
scene_state.lightmaps[i].exposure_normalization = 1.0;
if (p_render_data->camera_attributes.is_valid()) {
float baked_exposure = light_storage->lightmap_get_baked_exposure_normalization(lightmap);
@@ -1126,6 +1134,10 @@ void RenderForwardClustered::_setup_lightmaps(const RenderDataRD *p_render_data,
/* SDFGI */
void RenderForwardClustered::_update_sdfgi(RenderDataRD *p_render_data) {
+ if (p_render_data->sdfgi_update_data == nullptr) {
+ return;
+ }
+
Ref<RenderSceneBuffersRD> rb;
if (p_render_data && p_render_data->render_buffers.is_valid()) {
rb = p_render_data->render_buffers;
@@ -1732,7 +1744,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
_setup_lightmaps(p_render_data, *p_render_data->lightmaps, p_render_data->scene_data->cam_transform);
_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);
+ _setup_environment(p_render_data, is_reflection_probe, screen_size, p_default_bg_color, false);
// May have changed due to the above (light buffer enlarged, as an example).
_update_render_base_uniform_set();
@@ -1745,7 +1757,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
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);
+ _fill_instance_data(RENDER_LIST_ALPHA, render_info);
RD::get_singleton()->draw_command_end_label();
@@ -1823,7 +1835,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
clear_color.r *= bg_energy_multiplier;
clear_color.g *= bg_energy_multiplier;
clear_color.b *= bg_energy_multiplier;
- if (!p_render_data->transparent_bg && rb->has_custom_data(RB_SCOPE_FOG) && environment_get_fog_enabled(p_render_data->environment)) {
+ if (!p_render_data->transparent_bg && (rb->has_custom_data(RB_SCOPE_FOG) || environment_get_fog_enabled(p_render_data->environment))) {
draw_sky_fog_only = true;
RendererRD::MaterialStorage::get_singleton()->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.srgb_to_linear()));
}
@@ -1833,7 +1845,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
clear_color.r *= bg_energy_multiplier;
clear_color.g *= bg_energy_multiplier;
clear_color.b *= bg_energy_multiplier;
- if (!p_render_data->transparent_bg && rb->has_custom_data(RB_SCOPE_FOG) && environment_get_fog_enabled(p_render_data->environment)) {
+ if (!p_render_data->transparent_bg && (rb->has_custom_data(RB_SCOPE_FOG) || environment_get_fog_enabled(p_render_data->environment))) {
draw_sky_fog_only = true;
RendererRD::MaterialStorage::get_singleton()->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.srgb_to_linear()));
}
@@ -1995,7 +2007,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
// Shadow pass can change the base uniform set samplers.
_update_render_base_uniform_set();
- _setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, true, using_motion_pass);
+ _setup_environment(p_render_data, is_reflection_probe, screen_size, p_default_bg_color, true, using_motion_pass);
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, samplers, true);
@@ -2209,7 +2221,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_data, radiance_texture, samplers, true);
- _setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, false);
+ _setup_environment(p_render_data, is_reflection_probe, screen_size, p_default_bg_color, false);
{
uint32_t transparent_color_pass_flags = (color_pass_flags | COLOR_PASS_FLAG_TRANSPARENT) & ~(COLOR_PASS_FLAG_SEPARATE_SPECULAR);
@@ -2219,7 +2231,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
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, 0, spec_constant_base_flags);
+ 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(), reverse_cull, 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, 0, spec_constant_base_flags);
_render_list_with_draw_list(&render_list_params, alpha_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE);
}
@@ -2562,6 +2574,7 @@ void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const Page
SceneState::ShadowPass shadow_pass;
RenderSceneDataRD scene_data;
+ scene_data.flip_y = !p_flip_y; // Q: Why is this inverted? Do we assume flip in shadow logic?
scene_data.cam_projection = p_projection;
scene_data.cam_transform = p_transform;
scene_data.view_projection[0] = p_projection;
@@ -2581,7 +2594,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, p_viewport_size, !p_flip_y, Color(), false, false, p_use_pancake, shadow_pass_index);
+ _setup_environment(&render_data, true, p_viewport_size, 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;
@@ -2654,6 +2667,7 @@ void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, con
RD::get_singleton()->draw_command_begin_label("Render Collider Heightfield");
RenderSceneDataRD scene_data;
+ scene_data.flip_y = true;
scene_data.cam_projection = p_cam_projection;
scene_data.cam_transform = p_cam_transform;
scene_data.view_projection[0] = p_cam_projection;
@@ -2673,7 +2687,7 @@ void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, con
_update_render_base_uniform_set();
- _setup_environment(&render_data, true, Vector2(1, 1), true, Color(), false, false, false);
+ _setup_environment(&render_data, true, Vector2(1, 1), Color(), false, false, false);
PassMode pass_mode = PASS_MODE_SHADOW;
@@ -2720,7 +2734,7 @@ void RenderForwardClustered::_render_material(const Transform3D &p_cam_transform
_update_render_base_uniform_set();
- _setup_environment(&render_data, true, Vector2(1, 1), false, Color());
+ _setup_environment(&render_data, true, Vector2(1, 1), Color());
PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
@@ -2771,7 +2785,7 @@ void RenderForwardClustered::_render_uv2(const PagedArray<RenderGeometryInstance
_update_render_base_uniform_set();
- _setup_environment(&render_data, true, Vector2(1, 1), false, Color());
+ _setup_environment(&render_data, true, Vector2(1, 1), Color());
PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
@@ -2887,7 +2901,7 @@ void RenderForwardClustered::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_bu
RendererRD::MaterialStorage::store_transform(to_bounds.affine_inverse() * scene_data.cam_transform, scene_state.ubo.sdf_to_bounds);
scene_data.emissive_exposure_normalization = p_exposure_normalization;
- _setup_environment(&render_data, true, Vector2(1, 1), false, Color());
+ _setup_environment(&render_data, true, Vector2(1, 1), Color());
RID rp_uniform_set = _setup_sdfgi_render_pass_uniform_set(p_albedo_texture, p_emission_texture, p_emission_aniso_texture, p_geom_facing_texture, RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default());
@@ -3585,22 +3599,31 @@ RID RenderForwardClustered::_render_buffers_get_velocity_texture(Ref<RenderScene
}
void RenderForwardClustered::environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) {
+ ERR_FAIL_NULL(ss_effects);
+ ERR_FAIL_COND(p_quality < RS::EnvironmentSSAOQuality::ENV_SSAO_QUALITY_VERY_LOW || p_quality > RS::EnvironmentSSAOQuality::ENV_SSAO_QUALITY_ULTRA);
ss_effects->ssao_set_quality(p_quality, p_half_size, p_adaptive_target, p_blur_passes, p_fadeout_from, p_fadeout_to);
}
void RenderForwardClustered::environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) {
+ ERR_FAIL_NULL(ss_effects);
+ ERR_FAIL_COND(p_quality < RS::EnvironmentSSILQuality::ENV_SSIL_QUALITY_VERY_LOW || p_quality > RS::EnvironmentSSILQuality::ENV_SSIL_QUALITY_ULTRA);
ss_effects->ssil_set_quality(p_quality, p_half_size, p_adaptive_target, p_blur_passes, p_fadeout_from, p_fadeout_to);
}
void RenderForwardClustered::environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) {
+ ERR_FAIL_NULL(ss_effects);
+ ERR_FAIL_COND(p_quality < RS::EnvironmentSSRRoughnessQuality::ENV_SSR_ROUGHNESS_QUALITY_DISABLED || p_quality > RS::EnvironmentSSRRoughnessQuality::ENV_SSR_ROUGHNESS_QUALITY_HIGH);
ss_effects->ssr_set_roughness_quality(p_quality);
}
void RenderForwardClustered::sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) {
+ ERR_FAIL_NULL(ss_effects);
+ ERR_FAIL_COND(p_quality < RS::SubSurfaceScatteringQuality::SUB_SURFACE_SCATTERING_QUALITY_DISABLED || p_quality > RS::SubSurfaceScatteringQuality::SUB_SURFACE_SCATTERING_QUALITY_HIGH);
ss_effects->sss_set_quality(p_quality);
}
void RenderForwardClustered::sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) {
+ ERR_FAIL_NULL(ss_effects);
ss_effects->sss_set_scale(p_scale, p_depth_scale);
}
@@ -4227,6 +4250,11 @@ void RenderForwardClustered::_update_shader_quality_settings() {
spec_constants.push_back(sc);
+ sc.constant_id = SPEC_CONSTANT_USE_LIGHTMAP_BICUBIC_FILTER;
+ sc.bool_value = lightmap_filter_bicubic_get();
+
+ spec_constants.push_back(sc);
+
scene_shader.set_default_specialization_constants(spec_constants);
base_uniforms_changed(); //also need this
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 ae9e5e7c10..5d14653db6 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
@@ -73,6 +73,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
SPEC_CONSTANT_DECAL_FILTER = 10,
SPEC_CONSTANT_PROJECTOR_FILTER = 11,
SPEC_CONSTANT_USE_DEPTH_FOG = 12,
+ SPEC_CONSTANT_USE_LIGHTMAP_BICUBIC_FILTER = 13,
};
enum {
@@ -235,8 +236,9 @@ class RenderForwardClustered : public RendererSceneRenderRD {
struct LightmapData {
float normal_xform[12];
- float pad[3];
+ float texture_size[2];
float exposure_normalization;
+ float pad;
};
struct LightmapCaptureData {
@@ -361,7 +363,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_apply_alpha_multiplier = 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, 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);
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 9e0dacc1f2..6846c3f693 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
@@ -636,11 +636,12 @@ void SceneShaderForwardClustered::init(const String p_defines) {
actions.renames["CUSTOM2"] = "custom2_attrib";
actions.renames["CUSTOM3"] = "custom3_attrib";
actions.renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB";
+ actions.renames["CLIP_SPACE_FAR"] = "SHADER_SPACE_FAR";
actions.renames["LIGHT_VERTEX"] = "light_vertex";
actions.renames["NODE_POSITION_WORLD"] = "read_model_matrix[3].xyz";
actions.renames["CAMERA_POSITION_WORLD"] = "scene_data.inv_view_matrix[3].xyz";
- actions.renames["CAMERA_DIRECTION_WORLD"] = "scene_data.view_matrix[3].xyz";
+ actions.renames["CAMERA_DIRECTION_WORLD"] = "scene_data.inv_view_matrix[2].xyz";
actions.renames["CAMERA_VISIBLE_LAYERS"] = "scene_data.camera_visible_layers";
actions.renames["NODE_POSITION_VIEW"] = "(scene_data.view_matrix * read_model_matrix)[3].xyz";
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 194a70dc22..48c226133d 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -563,9 +563,17 @@ void RenderForwardMobile::_setup_lightmaps(const RenderDataRD *p_render_data, co
RID lightmap = light_storage->lightmap_instance_get_lightmap(p_lightmaps[i]);
+ // Transform (for directional lightmaps).
Basis to_lm = light_storage->lightmap_instance_get_transform(p_lightmaps[i]).basis.inverse() * p_cam_transform.basis;
to_lm = to_lm.inverse().transposed(); //will transform normals
RendererRD::MaterialStorage::store_transform_3x3(to_lm, scene_state.lightmaps[i].normal_xform);
+
+ // Light texture size.
+ Vector2i lightmap_size = light_storage->lightmap_get_light_texture_size(lightmap);
+ scene_state.lightmaps[i].texture_size[0] = lightmap_size[0];
+ scene_state.lightmaps[i].texture_size[1] = lightmap_size[1];
+
+ // Exposure.
scene_state.lightmaps[i].exposure_normalization = 1.0;
if (p_render_data->camera_attributes.is_valid()) {
float baked_exposure = light_storage->lightmap_get_baked_exposure_normalization(lightmap);
@@ -804,7 +812,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
RD::get_singleton()->draw_command_begin_label("Render Setup");
_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);
+ _setup_environment(p_render_data, is_reflection_probe, screen_size, p_default_bg_color, false);
// May have changed due to the above (light buffer enlarged, as an example).
_update_render_base_uniform_set();
@@ -939,10 +947,13 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
}
{
+ RDD::BreadcrumbMarker breadcrumb;
if (rb_data.is_valid()) {
RD::get_singleton()->draw_command_begin_label("Render 3D Pass");
+ breadcrumb = RDD::BreadcrumbMarker::OPAQUE_PASS;
} else {
RD::get_singleton()->draw_command_begin_label("Render Reflection Probe Pass");
+ breadcrumb = RDD::BreadcrumbMarker::REFLECTION_PROBES;
}
// opaque pass
@@ -953,7 +964,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
// Shadow pass can change the base uniform set samplers.
_update_render_base_uniform_set();
- _setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, p_render_data->render_buffers.is_valid());
+ _setup_environment(p_render_data, is_reflection_probe, screen_size, p_default_bg_color, p_render_data->render_buffers.is_valid());
if (merge_transparent_pass && using_subpass_post_process) {
RENDER_TIMESTAMP("Render Opaque + Transparent + Tonemap");
@@ -984,7 +995,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
}
}
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, load_color ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, c, 0.0, 0);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, load_color ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, c, 0.0, 0, Rect2(), breadcrumb);
RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
if (copy_canvas) {
@@ -1018,11 +1029,6 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
RD::get_singleton()->draw_command_end_label(); // Draw Sky
}
- // rendering effects
- if (ce_has_pre_transparent) {
- _process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_PRE_TRANSPARENT, p_render_data);
- }
-
if (merge_transparent_pass) {
if (render_list[RENDER_LIST_ALPHA].element_info.size() > 0) {
// transparent pass
@@ -1058,6 +1064,11 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
RD::get_singleton()->draw_command_end_label(); // Render 3D Pass / Render Reflection Probe Pass
+ // rendering effects
+ if (ce_has_pre_transparent) {
+ _process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_PRE_TRANSPARENT, p_render_data);
+ }
+
if (scene_state.used_screen_texture) {
// Copy screen texture to backbuffer so we can read from it
_render_buffers_copy_screen_texture(p_render_data);
@@ -1075,13 +1086,13 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_data, radiance_texture, samplers, true);
// this may be needed if we re-introduced steps that change info, not sure which do so in the previous implementation
- //_setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, false);
+ //_setup_environment(p_render_data, is_reflection_probe, screen_size, p_default_bg_color, false);
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(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, spec_constant_base_flags, 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_params.framebuffer_format = fb_format;
render_list_params.subpass = RD::get_singleton()->draw_list_get_current_pass(); // Should now always be 0.
- draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE);
+ draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, Vector<Color>(), 0, 0, Rect2(), breadcrumb);
_render_list(draw_list, fb_format, &render_list_params, 0, render_list_params.element_count);
RD::get_singleton()->draw_list_end();
@@ -1310,6 +1321,7 @@ void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedAr
}
RenderSceneDataRD scene_data;
+ scene_data.flip_y = !p_flip_y; // Q: Why is this inverted? Do we assume flip in shadow logic?
scene_data.cam_projection = p_projection;
scene_data.cam_transform = p_transform;
scene_data.view_projection[0] = p_projection;
@@ -1327,7 +1339,7 @@ void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedAr
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), Color(), 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;
@@ -1415,7 +1427,7 @@ void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, c
render_data.scene_data = &scene_data;
render_data.instances = &p_instances;
- _setup_environment(&render_data, true, Vector2(1, 1), false, Color());
+ _setup_environment(&render_data, true, Vector2(1, 1), Color());
PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
@@ -1460,7 +1472,7 @@ void RenderForwardMobile::_render_uv2(const PagedArray<RenderGeometryInstance *>
render_data.scene_data = &scene_data;
render_data.instances = &p_instances;
- _setup_environment(&render_data, true, Vector2(1, 1), false, Color());
+ _setup_environment(&render_data, true, Vector2(1, 1), Color());
PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
@@ -1526,6 +1538,7 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const
_update_render_base_uniform_set();
RenderSceneDataRD scene_data;
+ scene_data.flip_y = true;
scene_data.cam_projection = p_cam_projection;
scene_data.cam_transform = p_cam_transform;
scene_data.view_projection[0] = p_cam_projection;
@@ -1541,7 +1554,7 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const
render_data.scene_data = &scene_data;
render_data.instances = &p_instances;
- _setup_environment(&render_data, true, Vector2(1, 1), true, Color(), false, false);
+ _setup_environment(&render_data, true, Vector2(1, 1), Color(), false, false);
PassMode pass_mode = PASS_MODE_SHADOW;
@@ -1974,7 +1987,7 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
}
}
-void RenderForwardMobile::_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 RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, const Color &p_default_bg_color, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) {
RID env = is_environment(p_render_data->environment) ? p_render_data->environment : RID();
RID reflection_probe_instance = p_render_data->reflection_probe.is_valid() ? RendererRD::LightStorage::get_singleton()->reflection_probe_instance_get_probe(p_render_data->reflection_probe) : RID();
@@ -1987,7 +2000,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, false);
+ 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_pancake_shadows, p_screen_size, p_default_bg_color, _render_buffers_get_luminance_multiplier(), p_opaque_render_buffers, false);
}
/// RENDERING ///
@@ -2056,6 +2069,10 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
uint32_t base_spec_constants = p_params->spec_constant_base_flags;
+ if (bool(inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH)) {
+ base_spec_constants |= 1 << SPEC_CONSTANT_IS_MULTIMESH;
+ }
+
SceneState::PushConstant push_constant;
push_constant.base_index = i + p_params->element_offset;
@@ -2167,9 +2184,7 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
} break;
}
- PipelineCacheRD *pipeline = nullptr;
-
- pipeline = &shader->pipelines[cull_variant][primitive][shader_version];
+ PipelineCacheRD *pipeline = &shader->pipelines[cull_variant][primitive][shader_version];
RD::VertexFormatID vertex_format = -1;
RID vertex_array_rd;
@@ -2199,8 +2214,6 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_params->force_wireframe, p_params->subpass, base_spec_constants);
if (pipeline_rd != prev_pipeline_rd) {
- // checking with prev shader does not make so much sense, as
- // the pipeline may still be different.
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline_rd);
prev_pipeline_rd = pipeline_rd;
}
@@ -2775,6 +2788,11 @@ void RenderForwardMobile::_update_shader_quality_settings() {
spec_constants.push_back(sc);
+ sc.constant_id = SPEC_CONSTANT_USE_LIGHTMAP_BICUBIC_FILTER;
+ sc.bool_value = lightmap_filter_bicubic_get();
+
+ spec_constants.push_back(sc);
+
scene_shader.set_default_specialization_constants(spec_constants);
base_uniforms_changed(); //also need this
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 aa1b8f34b2..fc60c770e8 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
@@ -81,7 +81,8 @@ private:
SPEC_CONSTANT_DISABLE_DECALS = 13,
SPEC_CONSTANT_DISABLE_FOG = 14,
SPEC_CONSTANT_USE_DEPTH_FOG = 16,
-
+ SPEC_CONSTANT_IS_MULTIMESH = 17,
+ SPEC_CONSTANT_USE_LIGHTMAP_BICUBIC_FILTER = 18,
};
enum {
@@ -197,7 +198,7 @@ private:
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 _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, 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);
RID render_base_uniform_set;
@@ -207,8 +208,9 @@ private:
struct LightmapData {
float normal_xform[12];
- float pad[3];
+ float texture_size[2];
float exposure_normalization;
+ float pad;
};
struct LightmapCaptureData {
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 dd722cc2dd..08982096c5 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
@@ -540,11 +540,12 @@ void SceneShaderForwardMobile::init(const String p_defines) {
actions.renames["CUSTOM2"] = "custom2_attrib";
actions.renames["CUSTOM3"] = "custom3_attrib";
actions.renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB";
+ actions.renames["CLIP_SPACE_FAR"] = "SHADER_SPACE_FAR";
actions.renames["LIGHT_VERTEX"] = "light_vertex";
actions.renames["NODE_POSITION_WORLD"] = "read_model_matrix[3].xyz";
actions.renames["CAMERA_POSITION_WORLD"] = "scene_data.inv_view_matrix[3].xyz";
- actions.renames["CAMERA_DIRECTION_WORLD"] = "scene_data.view_matrix[3].xyz";
+ actions.renames["CAMERA_DIRECTION_WORLD"] = "scene_data.inv_view_matrix[2].xyz";
actions.renames["CAMERA_VISIBLE_LAYERS"] = "scene_data.camera_visible_layers";
actions.renames["NODE_POSITION_VIEW"] = "(scene_data.view_matrix * read_model_matrix)[3].xyz";
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index fa8cf9c028..f51b4ae8d0 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -407,7 +407,7 @@ _FORCE_INLINE_ static uint32_t _indices_to_primitives(RS::PrimitiveType p_primit
return (p_indices - subtractor[p_primitive]) / divisor[p_primitive];
}
-void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_render_target, const Item *p_item, RD::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, PipelineVariants *p_pipeline_variants, bool &r_sdf_used, const Point2 &p_offset, RenderingMethod::RenderInfo *r_render_info) {
+void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_render_target, const Item *p_item, RD::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, PipelineVariants *p_pipeline_variants, bool &r_sdf_used, const Point2 &p_repeat_offset, RenderingMethod::RenderInfo *r_render_info) {
//create an empty push constant
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
@@ -425,11 +425,11 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
}
PushConstant push_constant;
- Transform2D base_transform = p_canvas_transform_inverse * p_item->final_transform;
-
- if (p_offset.x || p_offset.y) {
- base_transform *= Transform2D(0, p_offset / p_item->xform_curr.get_scale()); // TODO: Interpolate or explain why not needed.
+ Transform2D base_transform = p_item->final_transform;
+ if (p_item->repeat_source_item && (p_repeat_offset.x || p_repeat_offset.y)) {
+ base_transform.columns[2] += p_item->repeat_source_item->final_transform.basis_xform(p_repeat_offset);
}
+ base_transform = p_canvas_transform_inverse * base_transform;
Transform2D draw_transform;
_update_transform_2d_to_mat2x3(base_transform, push_constant.world);
@@ -509,11 +509,16 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
current_repeat = RenderingServer::CanvasItemTextureRepeat::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED;
}
+ Color modulated = rect->modulate * base_color;
+ if (use_linear_colors) {
+ modulated = modulated.srgb_to_linear();
+ }
+
//bind pipeline
if (rect->flags & CANVAS_RECT_LCD) {
RID pipeline = pipeline_variants->variants[light_mode][PIPELINE_VARIANT_QUAD_LCD_BLEND].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format);
RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
- RD::get_singleton()->draw_list_set_blend_constants(p_draw_list, rect->modulate);
+ RD::get_singleton()->draw_list_set_blend_constants(p_draw_list, modulated);
} else {
RID pipeline = pipeline_variants->variants[light_mode][PIPELINE_VARIANT_QUAD].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format);
RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
@@ -582,11 +587,6 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
push_constant.flags |= FLAGS_USE_LCD;
}
- 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;
@@ -1183,7 +1183,7 @@ void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_co
RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, clear_colors);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, clear_colors, 1, 0, Rect2(), RDD::BreadcrumbMarker::UI_PASS);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, fb_uniform_set, BASE_UNIFORM_SET);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, state.default_transforms_uniform_set, TRANSFORMS_UNIFORM_SET);
@@ -1250,18 +1250,17 @@ void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_co
_render_item(draw_list, p_to_render_target, ci, fb_format, canvas_transform_inverse, current_clip, p_lights, pipeline_variants, r_sdf_used, Point2(), r_render_info);
} else {
Point2 start_pos = ci->repeat_size * -(ci->repeat_times / 2);
- Point2 end_pos = ci->repeat_size * ci->repeat_times + ci->repeat_size + start_pos;
- Point2 pos = start_pos;
-
- do {
- do {
- _render_item(draw_list, p_to_render_target, ci, fb_format, canvas_transform_inverse, current_clip, p_lights, pipeline_variants, r_sdf_used, pos, r_render_info);
- pos.y += ci->repeat_size.y;
- } while (pos.y < end_pos.y);
-
- pos.x += ci->repeat_size.x;
- pos.y = start_pos.y;
- } while (pos.x < end_pos.x);
+ Point2 offset;
+
+ int repeat_times_x = ci->repeat_size.x ? ci->repeat_times : 0;
+ int repeat_times_y = ci->repeat_size.y ? ci->repeat_times : 0;
+ for (int ry = 0; ry <= repeat_times_y; ry++) {
+ offset.y = start_pos.y + ry * ci->repeat_size.y;
+ for (int rx = 0; rx <= repeat_times_x; rx++) {
+ offset.x = start_pos.x + rx * ci->repeat_size.x;
+ _render_item(draw_list, p_to_render_target, ci, fb_format, canvas_transform_inverse, current_clip, p_lights, pipeline_variants, r_sdf_used, offset, r_render_info);
+ }
+ }
}
prev_material = material;
@@ -1451,10 +1450,15 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
normal_transform.columns[2] = Vector2();
_update_transform_2d_to_mat4(normal_transform, state_buffer.canvas_normal_transform);
- state_buffer.canvas_modulate[0] = p_modulate.r;
- state_buffer.canvas_modulate[1] = p_modulate.g;
- state_buffer.canvas_modulate[2] = p_modulate.b;
- state_buffer.canvas_modulate[3] = p_modulate.a;
+ bool use_linear_colors = texture_storage->render_target_is_using_hdr(p_to_render_target);
+ Color modulate = p_modulate;
+ if (use_linear_colors) {
+ modulate = p_modulate.srgb_to_linear();
+ }
+ state_buffer.canvas_modulate[0] = modulate.r;
+ state_buffer.canvas_modulate[1] = modulate.g;
+ state_buffer.canvas_modulate[2] = modulate.b;
+ state_buffer.canvas_modulate[3] = modulate.a;
Size2 render_target_size = texture_storage->render_target_get_size(p_to_render_target);
state_buffer.screen_pixel_size[0] = 1.0 / render_target_size.x;
@@ -1734,6 +1738,7 @@ void RendererCanvasRenderRD::_update_shadow_atlas() {
state.shadow_fb = RD::get_singleton()->framebuffer_create(fb_textures);
}
}
+
void RendererCanvasRenderRD::light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) {
CanvasLight *cl = canvas_light_owner.get_or_null(p_rid);
ERR_FAIL_COND(!cl->shadow.enabled);
@@ -1819,7 +1824,7 @@ void RendererCanvasRenderRD::light_update_directional_shadow(RID p_rid, int p_sh
Vector2 center = p_clip_rect.get_center();
- float to_edge_distance = ABS(light_dir.dot(p_clip_rect.get_support(light_dir)) - light_dir.dot(center));
+ float to_edge_distance = ABS(light_dir.dot(p_clip_rect.get_support(-light_dir)) - light_dir.dot(center));
Vector2 from_pos = center - light_dir * (to_edge_distance + p_cull_distance);
float distance = to_edge_distance * 2.0 + p_cull_distance;
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
index c7c5d34314..9deb4814c7 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
@@ -78,7 +78,6 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR = (1 << 11),
FLAGS_NINEPACH_DRAW_CENTER = (1 << 12),
- FLAGS_USING_PARTICLES = (1 << 13),
FLAGS_USE_SKELETON = (1 << 15),
FLAGS_NINEPATCH_H_MODE_SHIFT = 16,
@@ -424,7 +423,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
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, const Point2 &p_offset, RenderingMethod::RenderInfo *r_render_info = nullptr);
+ 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, const Point2 &p_repeat_offset, RenderingMethod::RenderInfo *r_render_info = nullptr);
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, RenderingMethod::RenderInfo *r_render_info = nullptr);
_FORCE_INLINE_ void _update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4);
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
index 14d138181f..84ea6a5da2 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
@@ -299,6 +299,7 @@ RendererCompositorRD::RendererCompositorRD() {
}
}
+ ERR_FAIL_COND_MSG(singleton != nullptr, "A RendererCompositorRD singleton already exists.");
singleton = this;
utilities = memnew(RendererRD::Utilities);
@@ -330,6 +331,7 @@ RendererCompositorRD::RendererCompositorRD() {
}
RendererCompositorRD::~RendererCompositorRD() {
+ singleton = nullptr;
memdelete(uniform_set_cache);
memdelete(framebuffer_cache);
ShaderRD::set_shader_cache_dir(String());
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h
index 95c2b812d9..0222a99577 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.h
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h
@@ -122,7 +122,7 @@ public:
void begin_frame(double frame_step);
void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount);
- void end_viewport(bool p_swap_buffers) {}
+ void gl_end_frame(bool p_swap_buffers) {}
void end_frame(bool p_swap_buffers);
void finalize();
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index 1e4880e67a..7d6d5018d0 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -423,6 +423,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
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...
+ can_use_effects &= _debug_draw_can_use_effects(debug_draw);
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;
@@ -699,7 +700,7 @@ void RendererSceneRenderRD::_post_process_subpass(RID p_source_texture, RID p_fr
// FIXME: Our input it our internal_texture, shouldn't this be using internal_size ??
// Seeing we don't support FSR in our mobile renderer right now target_size = internal_size...
Size2i target_size = rb->get_target_size();
- bool can_use_effects = target_size.x >= 8 && target_size.y >= 8;
+ bool can_use_effects = target_size.x >= 8 && target_size.y >= 8 && debug_draw == RS::VIEWPORT_DEBUG_DRAW_DISABLED;
RD::DrawListID draw_list = RD::get_singleton()->draw_list_switch_to_next_pass();
@@ -764,6 +765,56 @@ void RendererSceneRenderRD::_disable_clear_request(const RenderDataRD *p_render_
texture_storage->render_target_disable_clear_request(p_render_data->render_buffers->get_render_target());
}
+bool RendererSceneRenderRD::_debug_draw_can_use_effects(RS::ViewportDebugDraw p_debug_draw) {
+ bool can_use_effects = true;
+ switch (p_debug_draw) {
+ // No debug draw, use camera effects
+ case RS::VIEWPORT_DEBUG_DRAW_DISABLED:
+ can_use_effects = true;
+ break;
+ // Modes that completely override rendering to draw debug information should disable camera effects.
+ case RS::VIEWPORT_DEBUG_DRAW_UNSHADED:
+ case RS::VIEWPORT_DEBUG_DRAW_OVERDRAW:
+ case RS::VIEWPORT_DEBUG_DRAW_WIREFRAME:
+ case RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_ALBEDO:
+ case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS:
+ case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS:
+ case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS:
+ case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES:
+ case RS::VIEWPORT_DEBUG_DRAW_INTERNAL_BUFFER:
+ can_use_effects = false;
+ break;
+ // Modes that draws information over part of the viewport needs camera effects because we see partially the normal draw mode.
+ case RS::VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS:
+ case RS::VIEWPORT_DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS:
+ case RS::VIEWPORT_DEBUG_DRAW_DECAL_ATLAS:
+ case RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS:
+ // Modes that draws a buffer over viewport needs camera effects because if the buffer is not available it will be equivalent to normal draw mode.
+ case RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER:
+ case RS::VIEWPORT_DEBUG_DRAW_SSAO:
+ case RS::VIEWPORT_DEBUG_DRAW_SSIL:
+ case RS::VIEWPORT_DEBUG_DRAW_SDFGI:
+ case RS::VIEWPORT_DEBUG_DRAW_GI_BUFFER:
+ case RS::VIEWPORT_DEBUG_DRAW_OCCLUDERS:
+ can_use_effects = true;
+ break;
+ // Other debug draw modes keep camera effects.
+ case RS::VIEWPORT_DEBUG_DRAW_LIGHTING:
+ case RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_LIGHTING:
+ case RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_EMISSION:
+ case RS::VIEWPORT_DEBUG_DRAW_SCENE_LUMINANCE:
+ case RS::VIEWPORT_DEBUG_DRAW_PSSM_SPLITS:
+ case RS::VIEWPORT_DEBUG_DRAW_SDFGI_PROBES:
+ case RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD:
+ can_use_effects = true;
+ break;
+ default:
+ break;
+ }
+
+ return can_use_effects;
+}
+
void RendererSceneRenderRD::_render_buffers_debug_draw(const RenderDataRD *p_render_data) {
RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
@@ -989,6 +1040,14 @@ void RendererSceneRenderRD::light_projectors_set_filter(RenderingServer::LightPr
_update_shader_quality_settings();
}
+void RendererSceneRenderRD::lightmaps_set_bicubic_filter(bool p_enable) {
+ if (lightmap_filter_bicubic == p_enable) {
+ return;
+ }
+ lightmap_filter_bicubic = p_enable;
+ _update_shader_quality_settings();
+}
+
int RendererSceneRenderRD::get_roughness_layers() const {
return sky.roughness_layers;
}
@@ -1073,6 +1132,7 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render
scene_data.camera_visible_layers = p_camera_data->visible_layers;
scene_data.taa_jitter = p_camera_data->taa_jitter;
scene_data.main_cam_transform = p_camera_data->main_transform;
+ scene_data.flip_y = !p_reflection_probe.is_valid();
scene_data.view_count = p_camera_data->view_count;
for (uint32_t v = 0; v < p_camera_data->view_count; v++) {
@@ -1431,6 +1491,7 @@ void RendererSceneRenderRD::init() {
decals_set_filter(RS::DecalFilter(int(GLOBAL_GET("rendering/textures/decals/filter"))));
light_projectors_set_filter(RS::LightProjectorFilter(int(GLOBAL_GET("rendering/textures/light_projectors/filter"))));
+ lightmaps_set_bicubic_filter(GLOBAL_GET("rendering/lightmapping/lightmap_gi/use_bicubic_filter"));
cull_argument.set_page_pool(&cull_argument_pool);
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
index 5c5f11aba6..022a4560f8 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
@@ -117,6 +117,7 @@ protected:
RendererRD::GI gi;
virtual void _update_shader_quality_settings() {}
+ static bool _debug_draw_can_use_effects(RS::ViewportDebugDraw p_debug_draw);
private:
RS::ViewportDebugDraw debug_draw = RS::VIEWPORT_DEBUG_DRAW_DISABLED;
@@ -132,6 +133,7 @@ private:
float *directional_soft_shadow_kernel = nullptr;
float *penumbra_shadow_kernel = nullptr;
float *soft_shadow_kernel = nullptr;
+ bool lightmap_filter_bicubic = false;
int directional_penumbra_shadow_samples = 0;
int directional_soft_shadow_samples = 0;
int penumbra_shadow_samples = 0;
@@ -261,6 +263,7 @@ public:
virtual void decals_set_filter(RS::DecalFilter p_filter) override;
virtual void light_projectors_set_filter(RS::LightProjectorFilter p_filter) override;
+ virtual void lightmaps_set_bicubic_filter(bool p_enable) override;
_FORCE_INLINE_ RS::ShadowQuality shadows_quality_get() const {
return shadows_quality;
@@ -291,6 +294,9 @@ public:
_FORCE_INLINE_ int directional_penumbra_shadow_samples_get() const {
return directional_penumbra_shadow_samples;
}
+ _FORCE_INLINE_ bool lightmap_filter_bicubic_get() const {
+ return lightmap_filter_bicubic;
+ }
_FORCE_INLINE_ int directional_soft_shadow_samples_get() const {
return directional_soft_shadow_samples;
}
diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp
index 1c1b8366e5..e6a745d3b4 100644
--- a/servers/rendering/renderer_rd/shader_rd.cpp
+++ b/servers/rendering/renderer_rd/shader_rd.cpp
@@ -191,9 +191,14 @@ void ShaderRD::_build_variant_code(StringBuilder &builder, uint32_t p_variant, c
for (const KeyValue<StringName, CharString> &E : p_version->code_sections) {
builder.append(String("#define ") + String(E.key) + "_CODE_USED\n");
}
-#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
- builder.append("#define MOLTENVK_USED\n");
+#if (defined(MACOS_ENABLED) || defined(IOS_ENABLED))
+ if (RD::get_singleton()->get_device_capabilities().device_family == RDD::DEVICE_VULKAN) {
+ builder.append("#define MOLTENVK_USED\n");
+ }
+ // Image atomics are supported on Metal 3.1 but no support in MoltenVK or SPIRV-Cross yet.
+ builder.append("#define NO_IMAGE_ATOMICS\n");
#endif
+
builder.append(String("#define RENDER_DRIVER_") + OS::get_singleton()->get_current_rendering_driver_name().to_upper() + "\n");
} break;
case StageTemplate::Chunk::TYPE_MATERIAL_UNIFORMS: {
diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl
index dbff09c301..4426d9eb66 100644
--- a/servers/rendering/renderer_rd/shaders/canvas.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas.glsl
@@ -193,13 +193,6 @@ void main() {
}
}
-#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE)
- if (bool(draw_data.flags & FLAGS_USING_PARTICLES)) {
- //scale by texture size
- vertex /= draw_data.color_texture_pixel_size;
- }
-#endif
-
#ifdef USE_POINT_SIZE
float point_size = 1.0;
#endif
diff --git a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
index 7ac7cf9c07..8649f4710b 100644
--- a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
@@ -14,7 +14,6 @@
#define FLAGS_TRANSPOSE_RECT (1 << 10)
#define FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR (1 << 11)
#define FLAGS_NINEPACH_DRAW_CENTER (1 << 12)
-#define FLAGS_USING_PARTICLES (1 << 13)
#define FLAGS_NINEPATCH_H_MODE_SHIFT 16
#define FLAGS_NINEPATCH_V_MODE_SHIFT 18
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 2010b58474..f2b93059b0 100644
--- a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl
@@ -11,9 +11,22 @@ layout(location = 0) out vec2 uv_interp;
/* clang-format on */
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
+ // old code, ARM driver bug on Mali-GXXx GPUs and Vulkan API 1.3.xxx
+ // https://github.com/godotengine/godot/pull/92817#issuecomment-2168625982
+ //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
+
+ vec2 vertex_base;
+ if (gl_VertexIndex == 0) {
+ vertex_base = vec2(-1.0, -1.0);
+ } else if (gl_VertexIndex == 1) {
+ vertex_base = vec2(-1.0, 3.0);
+ } else {
+ vertex_base = vec2(3.0, -1.0);
+ }
+ gl_Position = vec4(vertex_base, 0.0, 1.0);
+ uv_interp = clamp(vertex_base, 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/screen_space_reflection.glsl b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
index 8618f083b3..b730b2c819 100644
--- a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
@@ -90,7 +90,7 @@ void main() {
if (sc_multiview) {
view_dir = normalize(vertex + scene_data.eye_offset[params.view_index].xyz);
} else {
- view_dir = normalize(vertex);
+ view_dir = params.orthogonal ? vec3(0.0, 0.0, -1.0) : normalize(vertex);
}
vec3 ray_dir = normalize(reflect(view_dir, normal));
@@ -237,7 +237,7 @@ void main() {
// 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);
+ float roughness_fade = smoothstep(0.4, 0.7, 1.0 - roughness);
// Schlick term.
float metallic = texelFetch(source_metallic, ssC << 1, 0).w;
diff --git a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_inc.glsl b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_inc.glsl
index 26405ab040..9b692824a1 100644
--- a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_inc.glsl
@@ -20,7 +20,7 @@ vec3 reconstructCSPosition(vec2 screen_pos, float z) {
return pos.xyz;
} else {
if (params.orthogonal) {
- return vec3((screen_pos.xy * params.proj_info.xy + params.proj_info.zw), z);
+ return vec3(-(screen_pos.xy * params.proj_info.xy + params.proj_info.zw), z);
} else {
return vec3((screen_pos.xy * params.proj_info.xy + params.proj_info.zw) * z, z);
}
diff --git a/servers/rendering/renderer_rd/shaders/effects/ss_effects_downsample.glsl b/servers/rendering/renderer_rd/shaders/effects/ss_effects_downsample.glsl
index 4f81e36c58..0332e23993 100644
--- a/servers/rendering/renderer_rd/shaders/effects/ss_effects_downsample.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/ss_effects_downsample.glsl
@@ -50,7 +50,7 @@ layout(r16f, set = 2, binding = 3) uniform restrict writeonly image2DArray dest_
vec4 screen_space_to_view_space_depth(vec4 p_depth) {
if (params.orthogonal) {
vec4 depth = p_depth * 2.0 - 1.0;
- return ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0;
+ return -(depth * (params.z_far - params.z_near) - (params.z_far + params.z_near)) / 2.0;
}
float depth_linearize_mul = params.z_near;
@@ -68,7 +68,7 @@ vec4 screen_space_to_view_space_depth(vec4 p_depth) {
float screen_space_to_view_space_depth(float p_depth) {
if (params.orthogonal) {
float depth = p_depth * 2.0 - 1.0;
- return ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / (2.0 * params.z_far);
+ return -(depth * (params.z_far - params.z_near) - (params.z_far + params.z_near)) / 2.0;
}
float depth_linearize_mul = params.z_near;
diff --git a/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl b/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl
index 38eec2b61a..841f02f673 100644
--- a/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl
@@ -13,9 +13,22 @@
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
+ // old code, ARM driver bug on Mali-GXXx GPUs and Vulkan API 1.3.xxx
+ // https://github.com/godotengine/godot/pull/92817#issuecomment-2168625982
+ //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
+
+ vec2 vertex_base;
+ if (gl_VertexIndex == 0) {
+ vertex_base = vec2(-1.0, -1.0);
+ } else if (gl_VertexIndex == 1) {
+ vertex_base = vec2(-1.0, 3.0);
+ } else {
+ vertex_base = vec2(3.0, -1.0);
+ }
+ gl_Position = vec4(vertex_base, 0.0, 1.0);
+ uv_interp = clamp(vertex_base, vec2(0.0, 0.0), vec2(1.0, 1.0)) * 2.0; // saturate(x) * 2.0
}
#[fragment]
diff --git a/servers/rendering/renderer_rd/shaders/environment/sky.glsl b/servers/rendering/renderer_rd/shaders/environment/sky.glsl
index 35457a2482..5aa3735494 100644
--- a/servers/rendering/renderer_rd/shaders/environment/sky.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/sky.glsl
@@ -255,10 +255,6 @@ void main() {
frag_color.rgb = color;
frag_color.a = alpha;
- // For mobile renderer we're multiplying by 0.5 as we're using a UNORM buffer.
- // For both mobile and clustered, we also bake in the exposure value for the environment and camera.
- frag_color.rgb = frag_color.rgb * params.luminance_multiplier;
-
#if !defined(DISABLE_FOG) && !defined(USE_CUBEMAP_PASS)
// Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky.
@@ -278,6 +274,10 @@ void main() {
#endif // DISABLE_FOG
+ // For mobile renderer we're multiplying by 0.5 as we're using a UNORM buffer.
+ // For both mobile and clustered, we also bake in the exposure value for the environment and camera.
+ frag_color.rgb = frag_color.rgb * params.luminance_multiplier;
+
// Blending is disabled for Sky, so alpha doesn't blend.
// Alpha is used for subsurface scattering so make sure it doesn't get applied to Sky.
if (!AT_CUBEMAP_PASS && !AT_HALF_RES_PASS && !AT_QUARTER_RES_PASS) {
diff --git a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog.glsl b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog.glsl
index 6ba1fe2819..2360375c23 100644
--- a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog.glsl
@@ -34,7 +34,7 @@ layout(push_constant, std430) uniform Params {
}
params;
-#ifdef MOLTENVK_USED
+#ifdef NO_IMAGE_ATOMICS
layout(set = 1, binding = 1) volatile buffer emissive_only_map_buffer {
uint emissive_only_map[];
};
@@ -64,7 +64,7 @@ layout(set = 1, binding = 2, std140) uniform SceneParams {
}
scene_params;
-#ifdef MOLTENVK_USED
+#ifdef NO_IMAGE_ATOMICS
layout(set = 1, binding = 3) volatile buffer density_only_map_buffer {
uint density_only_map[];
};
@@ -117,7 +117,7 @@ void main() {
if (any(greaterThanEqual(pos, scene_params.fog_volume_size))) {
return; //do not compute
}
-#ifdef MOLTENVK_USED
+#ifdef NO_IMAGE_ATOMICS
uint lpos = pos.z * scene_params.fog_volume_size.x * scene_params.fog_volume_size.y + pos.y * scene_params.fog_volume_size.x + pos.x;
#endif
@@ -222,7 +222,7 @@ void main() {
density *= cull_mask;
if (abs(density) > 0.001) {
int final_density = int(density * DENSITY_SCALE);
-#ifdef MOLTENVK_USED
+#ifdef NO_IMAGE_ATOMICS
atomicAdd(density_only_map[lpos], uint(final_density));
#else
imageAtomicAdd(density_only_map, pos, uint(final_density));
@@ -236,7 +236,7 @@ void main() {
uvec3 emission_u = uvec3(emission.r * 511.0, emission.g * 511.0, emission.b * 255.0);
// R and G have 11 bits each and B has 10. Then pack them into a 32 bit uint
uint final_emission = emission_u.r << 21 | emission_u.g << 10 | emission_u.b;
-#ifdef MOLTENVK_USED
+#ifdef NO_IMAGE_ATOMICS
uint prev_emission = atomicAdd(emissive_only_map[lpos], final_emission);
#else
uint prev_emission = imageAtomicAdd(emissive_only_map, pos, final_emission);
@@ -252,7 +252,7 @@ void main() {
if (any(overflowing)) {
uvec3 overflow_factor = mix(uvec3(0), uvec3(2047 << 21, 2047 << 10, 1023), overflowing);
uint force_max = overflow_factor.r | overflow_factor.g | overflow_factor.b;
-#ifdef MOLTENVK_USED
+#ifdef NO_IMAGE_ATOMICS
atomicOr(emissive_only_map[lpos], force_max);
#else
imageAtomicOr(emissive_only_map, pos, force_max);
@@ -267,7 +267,7 @@ void main() {
uvec3 scattering_u = uvec3(scattering.r * 2047.0, scattering.g * 2047.0, scattering.b * 1023.0);
// R and G have 11 bits each and B has 10. Then pack them into a 32 bit uint
uint final_scattering = scattering_u.r << 21 | scattering_u.g << 10 | scattering_u.b;
-#ifdef MOLTENVK_USED
+#ifdef NO_IMAGE_ATOMICS
uint prev_scattering = atomicAdd(light_only_map[lpos], final_scattering);
#else
uint prev_scattering = imageAtomicAdd(light_only_map, pos, final_scattering);
@@ -283,7 +283,7 @@ void main() {
if (any(overflowing)) {
uvec3 overflow_factor = mix(uvec3(0), uvec3(2047 << 21, 2047 << 10, 1023), overflowing);
uint force_max = overflow_factor.r | overflow_factor.g | overflow_factor.b;
-#ifdef MOLTENVK_USED
+#ifdef NO_IMAGE_ATOMICS
atomicOr(light_only_map[lpos], force_max);
#else
imageAtomicOr(light_only_map, pos, force_max);
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 d0cfe6a3b8..a797891ab6 100644
--- a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl
@@ -190,7 +190,7 @@ params;
#ifndef MODE_COPY
layout(set = 0, binding = 15) uniform texture3D prev_density_texture;
-#ifdef MOLTENVK_USED
+#ifdef NO_IMAGE_ATOMICS
layout(set = 0, binding = 16) buffer density_only_map_buffer {
uint density_only_map[];
};
@@ -287,7 +287,7 @@ void main() {
if (any(greaterThanEqual(pos, params.fog_volume_size))) {
return; //do not compute
}
-#ifdef MOLTENVK_USED
+#ifdef NO_IMAGE_ATOMICS
uint lpos = pos.z * params.fog_volume_size.x * params.fog_volume_size.y + pos.y * params.fog_volume_size.x + pos.x;
#endif
@@ -353,7 +353,7 @@ void main() {
vec3 total_light = vec3(0.0);
float total_density = params.base_density;
-#ifdef MOLTENVK_USED
+#ifdef NO_IMAGE_ATOMICS
uint local_density = density_only_map[lpos];
#else
uint local_density = imageLoad(density_only_map, pos).x;
@@ -362,7 +362,7 @@ void main() {
total_density += float(int(local_density)) / DENSITY_SCALE;
total_density = max(0.0, total_density);
-#ifdef MOLTENVK_USED
+#ifdef NO_IMAGE_ATOMICS
uint scattering_u = light_only_map[lpos];
#else
uint scattering_u = imageLoad(light_only_map, pos).x;
@@ -370,7 +370,7 @@ void main() {
vec3 scattering = vec3(scattering_u >> 21, (scattering_u << 11) >> 21, scattering_u % 1024) / vec3(2047.0, 2047.0, 1023.0);
scattering += params.base_scattering * params.base_density;
-#ifdef MOLTENVK_USED
+#ifdef NO_IMAGE_ATOMICS
uint emission_u = emissive_only_map[lpos];
#else
uint emission_u = imageLoad(emissive_only_map, pos).x;
@@ -710,7 +710,7 @@ void main() {
final_density = mix(final_density, reprojected_density, reproject_amount);
imageStore(density_map, pos, final_density);
-#ifdef MOLTENVK_USED
+#ifdef NO_IMAGE_ATOMICS
density_only_map[lpos] = 0;
light_only_map[lpos] = 0;
emissive_only_map[lpos] = 0;
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 a7148aa0e2..aafb9b4764 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
@@ -7,6 +7,7 @@
#include "scene_forward_clustered_inc.glsl"
#define SHADER_IS_SRGB false
+#define SHADER_SPACE_FAR 0.0
/* INPUT ATTRIBS */
@@ -352,7 +353,7 @@ void vertex_shader(vec3 vertex_input,
}
#ifdef OVERRIDE_POSITION
- vec4 position;
+ vec4 position = vec4(1.0);
#endif
#ifdef USE_MULTIVIEW
@@ -638,6 +639,7 @@ void main() {
#VERSION_DEFINES
#define SHADER_IS_SRGB false
+#define SHADER_SPACE_FAR 0.0
/* Specialization Constants (Toggles) */
@@ -657,6 +659,7 @@ layout(constant_id = 9) const uint sc_directional_penumbra_shadow_samples = 4;
layout(constant_id = 10) const bool sc_decal_use_mipmaps = true;
layout(constant_id = 11) const bool sc_projector_use_mipmaps = true;
layout(constant_id = 12) const bool sc_use_depth_fog = false;
+layout(constant_id = 13) const bool sc_use_lightmap_bicubic_filter = false;
// not used in clustered renderer but we share some code with the mobile renderer that requires this.
const float sc_luminance_multiplier = 1.0;
@@ -701,6 +704,67 @@ layout(location = 9) in float dp_clip;
layout(location = 10) in flat uint instance_index_interp;
+#ifdef USE_LIGHTMAP
+// w0, w1, w2, and w3 are the four cubic B-spline basis functions
+float w0(float a) {
+ return (1.0 / 6.0) * (a * (a * (-a + 3.0) - 3.0) + 1.0);
+}
+
+float w1(float a) {
+ return (1.0 / 6.0) * (a * a * (3.0 * a - 6.0) + 4.0);
+}
+
+float w2(float a) {
+ return (1.0 / 6.0) * (a * (a * (-3.0 * a + 3.0) + 3.0) + 1.0);
+}
+
+float w3(float a) {
+ return (1.0 / 6.0) * (a * a * a);
+}
+
+// g0 and g1 are the two amplitude functions
+float g0(float a) {
+ return w0(a) + w1(a);
+}
+
+float g1(float a) {
+ return w2(a) + w3(a);
+}
+
+// h0 and h1 are the two offset functions
+float h0(float a) {
+ return -1.0 + w1(a) / (w0(a) + w1(a));
+}
+
+float h1(float a) {
+ return 1.0 + w3(a) / (w2(a) + w3(a));
+}
+
+vec4 textureArray_bicubic(texture2DArray tex, vec3 uv, vec2 texture_size) {
+ vec2 texel_size = vec2(1.0) / texture_size;
+
+ uv.xy = uv.xy * texture_size + vec2(0.5);
+
+ vec2 iuv = floor(uv.xy);
+ vec2 fuv = fract(uv.xy);
+
+ float g0x = g0(fuv.x);
+ float g1x = g1(fuv.x);
+ float h0x = h0(fuv.x);
+ float h1x = h1(fuv.x);
+ float h0y = h0(fuv.y);
+ float h1y = h1(fuv.y);
+
+ vec2 p0 = (vec2(iuv.x + h0x, iuv.y + h0y) - vec2(0.5)) * texel_size;
+ vec2 p1 = (vec2(iuv.x + h1x, iuv.y + h0y) - vec2(0.5)) * texel_size;
+ vec2 p2 = (vec2(iuv.x + h0x, iuv.y + h1y) - vec2(0.5)) * texel_size;
+ vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - vec2(0.5)) * texel_size;
+
+ return (g0(fuv.y) * (g0x * texture(sampler2DArray(tex, SAMPLER_LINEAR_CLAMP), vec3(p0, uv.z)) + g1x * texture(sampler2DArray(tex, SAMPLER_LINEAR_CLAMP), vec3(p1, uv.z)))) +
+ (g1(fuv.y) * (g0x * texture(sampler2DArray(tex, SAMPLER_LINEAR_CLAMP), vec3(p2, uv.z)) + g1x * texture(sampler2DArray(tex, SAMPLER_LINEAR_CLAMP), vec3(p3, uv.z))));
+}
+#endif //USE_LIGHTMAP
+
#ifdef USE_MULTIVIEW
#ifdef has_VK_KHR_multiview
#define ViewIndex gl_ViewIndex
@@ -1030,6 +1094,13 @@ void fragment_shader(in SceneData scene_data) {
vec3 light_vertex = vertex;
#endif //LIGHT_VERTEX_USED
+ mat3 model_normal_matrix;
+ if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) {
+ model_normal_matrix = transpose(inverse(mat3(read_model_matrix)));
+ } else {
+ model_normal_matrix = mat3(read_model_matrix);
+ }
+
mat4 read_view_matrix = scene_data.view_matrix;
vec2 read_viewport_size = scene_data.viewport_size;
{
@@ -1310,6 +1381,8 @@ void fragment_shader(in SceneData scene_data) {
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+#ifndef AMBIENT_LIGHT_DISABLED
+
if (scene_data.use_reflection_cubemap) {
#ifdef LIGHT_ANISOTROPY_USED
// https://google.github.io/filament/Filament.html#lighting/imagebasedlights/anisotropy
@@ -1397,14 +1470,15 @@ void fragment_shader(in SceneData scene_data) {
#endif //USE_RADIANCE_CUBEMAP_ARRAY
specular_light += clearcoat_light * horizon * horizon * Fc * scene_data.ambient_light_color_energy.a;
}
-#endif
+#endif // LIGHT_CLEARCOAT_USED
+#endif // !AMBIENT_LIGHT_DISABLED
#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
//radiance
/// GI ///
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
-
+#ifndef AMBIENT_LIGHT_DISABLED
#ifdef USE_LIGHTMAP
//lightmap
@@ -1439,27 +1513,38 @@ void fragment_shader(in SceneData scene_data) {
if (uses_sh) {
uvw.z *= 4.0; //SH textures use 4 times more data
- vec3 lm_light_l0 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 0.0), 0.0).rgb;
- vec3 lm_light_l1n1 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 1.0), 0.0).rgb;
- 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 lm_light_l0;
+ vec3 lm_light_l1n1;
+ vec3 lm_light_l1_0;
+ vec3 lm_light_l1p1;
+
+ if (sc_use_lightmap_bicubic_filter) {
+ lm_light_l0 = textureArray_bicubic(lightmap_textures[ofs], uvw + vec3(0.0, 0.0, 0.0), lightmaps.data[ofs].light_texture_size).rgb;
+ lm_light_l1n1 = textureArray_bicubic(lightmap_textures[ofs], uvw + vec3(0.0, 0.0, 1.0), lightmaps.data[ofs].light_texture_size).rgb;
+ lm_light_l1_0 = textureArray_bicubic(lightmap_textures[ofs], uvw + vec3(0.0, 0.0, 2.0), lightmaps.data[ofs].light_texture_size).rgb;
+ lm_light_l1p1 = textureArray_bicubic(lightmap_textures[ofs], uvw + vec3(0.0, 0.0, 3.0), lightmaps.data[ofs].light_texture_size).rgb;
+ } else {
+ lm_light_l0 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 0.0), 0.0).rgb;
+ lm_light_l1n1 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 1.0), 0.0).rgb;
+ lm_light_l1_0 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 2.0), 0.0).rgb;
+ 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[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;
- ambient_light += lm_light_l1_0 * 0.32573 * n.z * en;
- ambient_light += lm_light_l1p1 * 0.32573 * n.x * en;
- if (metallic > 0.01) { // since the more direct bounced light is lost, we can kind of fake it with this trick
- vec3 r = reflect(normalize(-vertex), normal);
- specular_light += lm_light_l1n1 * 0.32573 * r.y * en;
- specular_light += lm_light_l1_0 * 0.32573 * r.z * en;
- specular_light += lm_light_l1p1 * 0.32573 * r.x * en;
- }
+ ambient_light += lm_light_l0 * en;
+ ambient_light += lm_light_l1n1 * n.y * en;
+ ambient_light += lm_light_l1_0 * n.z * en;
+ ambient_light += lm_light_l1p1 * n.x * en;
} else {
- ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw, 0.0).rgb * lightmaps.data[ofs].exposure_normalization;
+ if (sc_use_lightmap_bicubic_filter) {
+ ambient_light += textureArray_bicubic(lightmap_textures[ofs], uvw, lightmaps.data[ofs].light_texture_size).rgb * lightmaps.data[ofs].exposure_normalization;
+ } else {
+ ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw, 0.0).rgb * lightmaps.data[ofs].exposure_normalization;
+ }
}
}
#else
@@ -1698,9 +1783,6 @@ void fragment_shader(in SceneData scene_data) {
//finalize ambient light here
{
-#if defined(AMBIENT_LIGHT_DISABLED)
- ambient_light = vec3(0.0, 0.0, 0.0);
-#else
ambient_light *= albedo.rgb;
ambient_light *= ao;
@@ -1713,15 +1795,14 @@ void fragment_shader(in SceneData scene_data) {
ambient_light *= 1.0 - ssil.a;
ambient_light += ssil.rgb * albedo.rgb;
}
-#endif // AMBIENT_LIGHT_DISABLED
}
-
+#endif // AMBIENT_LIGHT_DISABLED
// convert ao to direct light ao
ao = mix(1.0, ao, ao_light_affect);
//this saves some VGPRs
vec3 f0 = F0(metallic, specular, albedo);
-
+#ifndef AMBIENT_LIGHT_DISABLED
{
#if defined(DIFFUSE_TOON)
//simplify for toon, as
@@ -1743,6 +1824,7 @@ void fragment_shader(in SceneData scene_data) {
#endif
}
+#endif // !AMBIENT_LIGHT_DISABLED
#endif //GI !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
#if !defined(MODE_RENDER_DEPTH)
@@ -2243,7 +2325,7 @@ void fragment_shader(in SceneData scene_data) {
alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0));
#if defined(ALPHA_SCISSOR_USED)
- if (alpha < alpha_scissor) {
+ if (alpha < alpha_scissor_threshold) {
discard;
}
#endif // ALPHA_SCISSOR_USED
@@ -2289,7 +2371,7 @@ void fragment_shader(in SceneData scene_data) {
}
}
-#ifdef MOLTENVK_USED
+#ifdef NO_IMAGE_ATOMICS
imageStore(geom_facing_grid, grid_pos, uvec4(imageLoad(geom_facing_grid, grid_pos).r | facing_bits)); //store facing bits
#else
imageAtomicOr(geom_facing_grid, grid_pos, facing_bits); //store facing bits
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 441cf3c80c..03511aa3a8 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
@@ -94,8 +94,9 @@ directional_lights;
struct Lightmap {
mat3 normal_xform;
- vec3 pad;
+ vec2 light_texture_size;
float exposure_normalization;
+ float pad;
};
layout(set = 0, binding = 7, std140) restrict readonly buffer Lightmaps {
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 1637326b48..c266161834 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
@@ -8,6 +8,7 @@
#include "scene_forward_mobile_inc.glsl"
#define SHADER_IS_SRGB false
+#define SHADER_SPACE_FAR 0.0
/* INPUT ATTRIBS */
@@ -76,6 +77,10 @@ void axis_angle_to_tbn(vec3 axis, float angle, out vec3 tangent, out vec3 binorm
normal = omc_axis.zzz * axis + vec3(-s_axis.y, s_axis.x, c);
}
+/* Spec Constants */
+
+layout(constant_id = 17) const bool sc_is_multimesh = false;
+
/* Varyings */
layout(location = 0) highp out vec3 vertex_interp;
@@ -178,8 +183,6 @@ void main() {
color_interp = color_attrib;
#endif
- bool is_multimesh = bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH);
-
mat4 model_matrix = instances.data[draw_call.instance_index].transform;
mat4 inv_view_matrix = scene_data.inv_view_matrix;
#ifdef USE_DOUBLE_PRECISION
@@ -203,7 +206,7 @@ void main() {
mat4 matrix;
mat4 read_model_matrix = model_matrix;
- if (is_multimesh) {
+ if (sc_is_multimesh) {
//multimesh, instances are for it
#ifdef USE_PARTICLE_TRAILS
@@ -350,7 +353,7 @@ void main() {
}
#ifdef OVERRIDE_POSITION
- vec4 position;
+ vec4 position = vec4(1.0);
#endif
#ifdef USE_MULTIVIEW
@@ -399,7 +402,7 @@ void main() {
// Then we combine the translations from the model matrix and the view matrix using emulated doubles.
// We add the result to the vertex and ignore the final lost precision.
vec3 model_origin = model_matrix[3].xyz;
- if (is_multimesh) {
+ if (sc_is_multimesh) {
vertex = mat3(matrix) * vertex;
model_origin = double_add_vec3(model_origin, model_precision, matrix[3].xyz, vec3(0.0), model_precision);
}
@@ -496,6 +499,7 @@ void main() {
#VERSION_DEFINES
#define SHADER_IS_SRGB false
+#define SHADER_SPACE_FAR 0.0
/* Specialization Constants */
@@ -519,6 +523,7 @@ layout(constant_id = 9) const bool sc_disable_omni_lights = false;
layout(constant_id = 10) const bool sc_disable_spot_lights = false;
layout(constant_id = 11) const bool sc_disable_reflection_probes = false;
layout(constant_id = 12) const bool sc_disable_directional_lights = false;
+layout(constant_id = 18) const bool sc_use_lightmap_bicubic_filter = false;
#endif //!MODE_UNSHADED
@@ -565,6 +570,67 @@ layout(location = 9) highp in float dp_clip;
#endif
+#ifdef USE_LIGHTMAP
+// w0, w1, w2, and w3 are the four cubic B-spline basis functions
+float w0(float a) {
+ return (1.0 / 6.0) * (a * (a * (-a + 3.0) - 3.0) + 1.0);
+}
+
+float w1(float a) {
+ return (1.0 / 6.0) * (a * a * (3.0 * a - 6.0) + 4.0);
+}
+
+float w2(float a) {
+ return (1.0 / 6.0) * (a * (a * (-3.0 * a + 3.0) + 3.0) + 1.0);
+}
+
+float w3(float a) {
+ return (1.0 / 6.0) * (a * a * a);
+}
+
+// g0 and g1 are the two amplitude functions
+float g0(float a) {
+ return w0(a) + w1(a);
+}
+
+float g1(float a) {
+ return w2(a) + w3(a);
+}
+
+// h0 and h1 are the two offset functions
+float h0(float a) {
+ return -1.0 + w1(a) / (w0(a) + w1(a));
+}
+
+float h1(float a) {
+ return 1.0 + w3(a) / (w2(a) + w3(a));
+}
+
+vec4 textureArray_bicubic(texture2DArray tex, vec3 uv, vec2 texture_size) {
+ vec2 texel_size = vec2(1.0) / texture_size;
+
+ uv.xy = uv.xy * texture_size + vec2(0.5);
+
+ vec2 iuv = floor(uv.xy);
+ vec2 fuv = fract(uv.xy);
+
+ float g0x = g0(fuv.x);
+ float g1x = g1(fuv.x);
+ float h0x = h0(fuv.x);
+ float h1x = h1(fuv.x);
+ float h0y = h0(fuv.y);
+ float h1y = h1(fuv.y);
+
+ vec2 p0 = (vec2(iuv.x + h0x, iuv.y + h0y) - vec2(0.5)) * texel_size;
+ vec2 p1 = (vec2(iuv.x + h1x, iuv.y + h0y) - vec2(0.5)) * texel_size;
+ vec2 p2 = (vec2(iuv.x + h0x, iuv.y + h1y) - vec2(0.5)) * texel_size;
+ vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - vec2(0.5)) * texel_size;
+
+ return (g0(fuv.y) * (g0x * texture(sampler2DArray(tex, SAMPLER_LINEAR_CLAMP), vec3(p0, uv.z)) + g1x * texture(sampler2DArray(tex, SAMPLER_LINEAR_CLAMP), vec3(p1, uv.z)))) +
+ (g1(fuv.y) * (g0x * texture(sampler2DArray(tex, SAMPLER_LINEAR_CLAMP), vec3(p2, uv.z)) + g1x * texture(sampler2DArray(tex, SAMPLER_LINEAR_CLAMP), vec3(p3, uv.z))));
+}
+#endif //USE_LIGHTMAP
+
#ifdef USE_MULTIVIEW
#ifdef has_VK_KHR_multiview
#define ViewIndex gl_ViewIndex
@@ -837,6 +903,13 @@ void main() {
vec3 light_vertex = vertex;
#endif //LIGHT_VERTEX_USED
+ mat3 model_normal_matrix;
+ if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) {
+ model_normal_matrix = transpose(inverse(mat3(read_model_matrix)));
+ } else {
+ model_normal_matrix = mat3(read_model_matrix);
+ }
+
mat4 read_view_matrix = scene_data.view_matrix;
vec2 read_viewport_size = scene_data.viewport_size;
@@ -1069,6 +1142,8 @@ void main() {
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+#ifndef AMBIENT_LIGHT_DISABLED
+
if (scene_data.use_reflection_cubemap) {
#ifdef LIGHT_ANISOTROPY_USED
// https://google.github.io/filament/Filament.html#lighting/imagebasedlights/anisotropy
@@ -1156,13 +1231,14 @@ void main() {
#endif //USE_RADIANCE_CUBEMAP_ARRAY
specular_light += clearcoat_light * horizon * horizon * Fc * scene_data.ambient_light_color_energy.a;
}
-#endif
+#endif // LIGHT_CLEARCOAT_USED
+#endif // !AMBIENT_LIGHT_DISABLED
#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
//radiance
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
-
+#ifndef AMBIENT_LIGHT_DISABLED
#ifdef USE_LIGHTMAP
//lightmap
@@ -1197,27 +1273,36 @@ void main() {
if (uses_sh) {
uvw.z *= 4.0; //SH textures use 4 times more data
- vec3 lm_light_l0 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 0.0), 0.0).rgb;
- vec3 lm_light_l1n1 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 1.0), 0.0).rgb;
- 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 lm_light_l0;
+ vec3 lm_light_l1n1;
+ vec3 lm_light_l1_0;
+ vec3 lm_light_l1p1;
+
+ if (sc_use_lightmap_bicubic_filter) {
+ lm_light_l0 = textureArray_bicubic(lightmap_textures[ofs], uvw + vec3(0.0, 0.0, 0.0), lightmaps.data[ofs].light_texture_size).rgb;
+ lm_light_l1n1 = textureArray_bicubic(lightmap_textures[ofs], uvw + vec3(0.0, 0.0, 1.0), lightmaps.data[ofs].light_texture_size).rgb;
+ lm_light_l1_0 = textureArray_bicubic(lightmap_textures[ofs], uvw + vec3(0.0, 0.0, 2.0), lightmaps.data[ofs].light_texture_size).rgb;
+ lm_light_l1p1 = textureArray_bicubic(lightmap_textures[ofs], uvw + vec3(0.0, 0.0, 3.0), lightmaps.data[ofs].light_texture_size).rgb;
+ } else {
+ lm_light_l0 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 0.0), 0.0).rgb;
+ lm_light_l1n1 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 1.0), 0.0).rgb;
+ lm_light_l1_0 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 2.0), 0.0).rgb;
+ 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[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;
- ambient_light += lm_light_l1_0 * 0.32573 * n.z * exposure_normalization;
- ambient_light += lm_light_l1p1 * 0.32573 * n.x * exposure_normalization;
- if (metallic > 0.01) { // since the more direct bounced light is lost, we can kind of fake it with this trick
- vec3 r = reflect(normalize(-vertex), normal);
- specular_light += lm_light_l1n1 * 0.32573 * r.y * exposure_normalization;
- specular_light += lm_light_l1_0 * 0.32573 * r.z * exposure_normalization;
- specular_light += lm_light_l1p1 * 0.32573 * r.x * exposure_normalization;
- }
-
+ ambient_light += lm_light_l0 * exposure_normalization;
+ ambient_light += lm_light_l1n1 * n.y * exposure_normalization;
+ ambient_light += lm_light_l1_0 * n.z * exposure_normalization;
+ ambient_light += lm_light_l1p1 * n.x * exposure_normalization;
} else {
- ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw, 0.0).rgb * lightmaps.data[ofs].exposure_normalization;
+ if (sc_use_lightmap_bicubic_filter) {
+ ambient_light += textureArray_bicubic(lightmap_textures[ofs], uvw, lightmaps.data[ofs].light_texture_size).rgb * lightmaps.data[ofs].exposure_normalization;
+ } else {
+ ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw, 0.0).rgb * lightmaps.data[ofs].exposure_normalization;
+ }
}
}
@@ -1272,14 +1357,11 @@ void main() {
} //Reflection probes
// finalize ambient light here
- {
-#if defined(AMBIENT_LIGHT_DISABLED)
- ambient_light = vec3(0.0, 0.0, 0.0);
-#else
- ambient_light *= albedo.rgb;
- ambient_light *= ao;
-#endif // AMBIENT_LIGHT_DISABLED
- }
+
+ ambient_light *= albedo.rgb;
+ ambient_light *= ao;
+
+#endif // !AMBIENT_LIGHT_DISABLED
// convert ao to direct light ao
ao = mix(1.0, ao, ao_light_affect);
@@ -1287,6 +1369,7 @@ void main() {
//this saves some VGPRs
vec3 f0 = F0(metallic, specular, albedo);
+#ifndef AMBIENT_LIGHT_DISABLED
{
#if defined(DIFFUSE_TOON)
//simplify for toon, as
@@ -1308,6 +1391,7 @@ void main() {
#endif
}
+#endif // !AMBIENT_LIGHT_DISABLED
#endif // !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
#if !defined(MODE_RENDER_DEPTH)
@@ -1763,7 +1847,7 @@ void main() {
alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0));
#if defined(ALPHA_SCISSOR_USED)
- if (alpha < alpha_scissor) {
+ if (alpha < alpha_scissor_threshold) {
discard;
}
#endif // !ALPHA_SCISSOR_USED
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 7674e905e1..d971ff04c5 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
@@ -71,8 +71,9 @@ directional_lights;
struct Lightmap {
mediump mat3 normal_xform;
- vec3 pad;
+ vec2 light_texture_size;
float exposure_normalization;
+ float pad;
};
layout(set = 0, binding = 7, std140) restrict readonly buffer Lightmaps {
diff --git a/servers/rendering/renderer_rd/shaders/particles.glsl b/servers/rendering/renderer_rd/shaders/particles.glsl
index 60c49bacae..7c5291038f 100644
--- a/servers/rendering/renderer_rd/shaders/particles.glsl
+++ b/servers/rendering/renderer_rd/shaders/particles.glsl
@@ -292,6 +292,24 @@ void main() {
PARTICLE.velocity = particles.data[src_idx].velocity;
PARTICLE.flags = PARTICLE_FLAG_TRAILED | ((frame_history.data[0].frame & PARTICLE_FRAME_MASK) << PARTICLE_FRAME_SHIFT); //mark it as trailed, save in which frame it will start
PARTICLE.xform = particles.data[src_idx].xform;
+#ifdef USERDATA1_USED
+ PARTICLE.userdata1 = particles.data[src_idx].userdata1;
+#endif
+#ifdef USERDATA2_USED
+ PARTICLE.userdata2 = particles.data[src_idx].userdata2;
+#endif
+#ifdef USERDATA3_USED
+ PARTICLE.userdata3 = particles.data[src_idx].userdata3;
+#endif
+#ifdef USERDATA4_USED
+ PARTICLE.userdata4 = particles.data[src_idx].userdata4;
+#endif
+#ifdef USERDATA5_USED
+ PARTICLE.userdata5 = particles.data[src_idx].userdata5;
+#endif
+#ifdef USERDATA6_USED
+ PARTICLE.userdata6 = particles.data[src_idx].userdata6;
+#endif
}
if (!bool(particles.data[src_idx].flags & PARTICLE_FLAG_ACTIVE)) {
// Disable the entire trail if the parent is no longer active.
diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
index 8b2bb14b76..b07063cfda 100644
--- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
@@ -1813,6 +1813,7 @@ void LightStorage::lightmap_set_textures(RID p_lightmap, RID p_light, bool p_use
}
t->lightmap_users.insert(p_lightmap);
+ lm->light_texture_size = Vector2i(t->width, t->height);
if (using_lightmap_array) {
if (lm->array_index < 0) {
diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.h b/servers/rendering/renderer_rd/storage_rd/light_storage.h
index f152cc5dae..1db58d72f9 100644
--- a/servers/rendering/renderer_rd/storage_rd/light_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/light_storage.h
@@ -49,7 +49,7 @@ namespace RendererRD {
class LightStorage : public RendererLightStorage {
public:
- enum ShadowAtlastQuadrant {
+ enum ShadowAtlastQuadrant : uint32_t {
QUADRANT_SHIFT = 27,
OMNI_LIGHT_FLAG = 1 << 26,
SHADOW_INDEX_MASK = OMNI_LIGHT_FLAG - 1,
@@ -332,6 +332,7 @@ private:
bool interior = false;
AABB bounds = AABB(Vector3(), Vector3(1, 1, 1));
float baked_exposure = 1.0;
+ Vector2i light_texture_size;
int32_t array_index = -1; //unassigned
PackedVector3Array points;
PackedColorArray point_sh;
@@ -985,6 +986,10 @@ public:
const Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
return lm->uses_spherical_harmonics;
}
+ _FORCE_INLINE_ Vector2i lightmap_get_light_texture_size(RID p_lightmap) const {
+ const Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
+ return lm->light_texture_size;
+ }
_FORCE_INLINE_ uint64_t lightmap_array_get_version() const {
ERR_FAIL_COND_V(!using_lightmap_array, 0); //only for arrays
return lightmap_array_version;
diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
index d1c8c71b7f..63dc54e24c 100644
--- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
@@ -580,11 +580,7 @@ void MaterialStorage::ShaderData::get_shader_uniform_list(List<PropertyInfo> *p_
if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
continue;
}
- if (E.value.texture_order >= 0) {
- filtered_uniforms.push_back(Pair<StringName, int>(E.key, E.value.texture_order + 100000));
- } else {
- filtered_uniforms.push_back(Pair<StringName, int>(E.key, E.value.order));
- }
+ filtered_uniforms.push_back(Pair<StringName, int>(E.key, E.value.prop_order));
}
int uniform_count = filtered_uniforms.size();
sorter.sort(filtered_uniforms.ptr(), uniform_count);
@@ -634,7 +630,7 @@ bool MaterialStorage::ShaderData::is_parameter_texture(const StringName &p_param
return false;
}
- return uniforms[p_param].texture_order >= 0;
+ return uniforms[p_param].is_texture();
}
///////////////////////////////////////////////////////////////////////////
@@ -645,7 +641,7 @@ void MaterialStorage::MaterialData::update_uniform_buffer(const HashMap<StringNa
bool uses_global_buffer = false;
for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : p_uniforms) {
- if (E.value.order < 0) {
+ if (E.value.is_texture()) {
continue; // texture, does not go here
}
@@ -807,7 +803,8 @@ void MaterialStorage::MaterialData::update_textures(const HashMap<StringName, Va
if (V->value.is_array()) {
Array array = (Array)V->value;
if (uniform_array_size > 0) {
- for (int j = 0; j < array.size(); j++) {
+ int size = MIN(uniform_array_size, array.size());
+ for (int j = 0; j < size; j++) {
textures.push_back(array[j]);
}
} else {
@@ -1165,8 +1162,8 @@ MaterialStorage::MaterialStorage() {
global_shader_uniforms.buffer_values = memnew_arr(GlobalShaderUniforms::Value, global_shader_uniforms.buffer_size);
memset(global_shader_uniforms.buffer_values, 0, sizeof(GlobalShaderUniforms::Value) * global_shader_uniforms.buffer_size);
global_shader_uniforms.buffer_usage = memnew_arr(GlobalShaderUniforms::ValueUsage, global_shader_uniforms.buffer_size);
- global_shader_uniforms.buffer_dirty_regions = memnew_arr(bool, global_shader_uniforms.buffer_size / GlobalShaderUniforms::BUFFER_DIRTY_REGION_SIZE);
- memset(global_shader_uniforms.buffer_dirty_regions, 0, sizeof(bool) * global_shader_uniforms.buffer_size / GlobalShaderUniforms::BUFFER_DIRTY_REGION_SIZE);
+ global_shader_uniforms.buffer_dirty_regions = memnew_arr(bool, 1 + (global_shader_uniforms.buffer_size / GlobalShaderUniforms::BUFFER_DIRTY_REGION_SIZE));
+ memset(global_shader_uniforms.buffer_dirty_regions, 0, sizeof(bool) * (1 + (global_shader_uniforms.buffer_size / GlobalShaderUniforms::BUFFER_DIRTY_REGION_SIZE)));
global_shader_uniforms.buffer = RD::get_singleton()->storage_buffer_create(sizeof(GlobalShaderUniforms::Value) * global_shader_uniforms.buffer_size);
}
@@ -1769,7 +1766,7 @@ void MaterialStorage::global_shader_parameters_instance_update(RID p_instance, i
void MaterialStorage::_update_global_shader_uniforms() {
MaterialStorage *material_storage = MaterialStorage::get_singleton();
if (global_shader_uniforms.buffer_dirty_region_count > 0) {
- uint32_t total_regions = global_shader_uniforms.buffer_size / GlobalShaderUniforms::BUFFER_DIRTY_REGION_SIZE;
+ uint32_t total_regions = 1 + (global_shader_uniforms.buffer_size / GlobalShaderUniforms::BUFFER_DIRTY_REGION_SIZE);
if (total_regions / global_shader_uniforms.buffer_dirty_region_count <= 4) {
// 25% of regions dirty, just update all buffer
RD::get_singleton()->buffer_update(global_shader_uniforms.buffer, 0, sizeof(GlobalShaderUniforms::Value) * global_shader_uniforms.buffer_size, global_shader_uniforms.buffer_values);
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
index 99622996d4..539bdcbbd0 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
@@ -1056,8 +1056,9 @@ void MeshStorage::update_mesh_instances() {
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.
+ if (uses_motion_vectors && mi->surfaces[i].last_change && (frame - mi->surfaces[i].last_change) <= 2) {
+ // Use a 2-frame tolerance so that stepped skeletal animations have correct motion vectors
+ // (stepped animation is common for distant NPCs).
uint32_t new_buffer_index = mi->surfaces[i].current_buffer ^ 1;
if (mi->surfaces[i].uniform_set[new_buffer_index].is_null()) {
@@ -1380,14 +1381,16 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
////////////////// MULTIMESH
-RID MeshStorage::multimesh_allocate() {
+RID MeshStorage::_multimesh_allocate() {
return multimesh_owner.allocate_rid();
}
-void MeshStorage::multimesh_initialize(RID p_rid) {
+void MeshStorage::_multimesh_initialize(RID p_rid) {
multimesh_owner.initialize_rid(p_rid, MultiMesh());
}
-void MeshStorage::multimesh_free(RID p_rid) {
+void MeshStorage::_multimesh_free(RID p_rid) {
+ // Remove from interpolator.
+ _interpolation_data.notify_free_multimesh(p_rid);
_update_dirty_multimeshes();
multimesh_allocate_data(p_rid, 0, RS::MULTIMESH_TRANSFORM_2D);
MultiMesh *multimesh = multimesh_owner.get_or_null(p_rid);
@@ -1395,7 +1398,7 @@ void MeshStorage::multimesh_free(RID p_rid) {
multimesh_owner.free(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) {
+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_NULL(multimesh);
@@ -1439,12 +1442,10 @@ void MeshStorage::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::
multimesh->motion_vectors_current_offset = 0;
multimesh->motion_vectors_previous_offset = 0;
multimesh->motion_vectors_last_change = -1;
+ multimesh->motion_vectors_enabled = false;
if (multimesh->instances) {
uint32_t buffer_size = multimesh->instances * multimesh->stride_cache * sizeof(float);
- if (multimesh->motion_vectors_enabled) {
- buffer_size *= 2;
- }
multimesh->buffer = RD::get_singleton()->storage_buffer_create(buffer_size);
}
@@ -1507,13 +1508,13 @@ bool MeshStorage::_multimesh_uses_motion_vectors_offsets(RID p_multimesh) {
return _multimesh_uses_motion_vectors(multimesh);
}
-int MeshStorage::multimesh_get_instance_count(RID p_multimesh) const {
+int MeshStorage::_multimesh_get_instance_count(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL_V(multimesh, 0);
return multimesh->instances;
}
-void MeshStorage::multimesh_set_mesh(RID p_multimesh, RID p_mesh) {
+void MeshStorage::_multimesh_set_mesh(RID p_multimesh, RID p_mesh) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL(multimesh);
if (multimesh->mesh == p_mesh) {
@@ -1703,7 +1704,7 @@ void MeshStorage::_multimesh_re_create_aabb(MultiMesh *multimesh, const float *p
multimesh->aabb = aabb;
}
-void MeshStorage::multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) {
+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_NULL(multimesh);
ERR_FAIL_INDEX(p_index, multimesh->instances);
@@ -1740,7 +1741,7 @@ void MeshStorage::multimesh_instance_set_transform(RID p_multimesh, int p_index,
_multimesh_mark_dirty(multimesh, p_index, true);
}
-void MeshStorage::multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) {
+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_NULL(multimesh);
ERR_FAIL_INDEX(p_index, multimesh->instances);
@@ -1767,7 +1768,7 @@ void MeshStorage::multimesh_instance_set_transform_2d(RID p_multimesh, int p_ind
_multimesh_mark_dirty(multimesh, p_index, true);
}
-void MeshStorage::multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) {
+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_NULL(multimesh);
ERR_FAIL_INDEX(p_index, multimesh->instances);
@@ -1790,7 +1791,7 @@ void MeshStorage::multimesh_instance_set_color(RID p_multimesh, int p_index, con
_multimesh_mark_dirty(multimesh, p_index, false);
}
-void MeshStorage::multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) {
+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_NULL(multimesh);
ERR_FAIL_INDEX(p_index, multimesh->instances);
@@ -1813,7 +1814,7 @@ void MeshStorage::multimesh_instance_set_custom_data(RID p_multimesh, int p_inde
_multimesh_mark_dirty(multimesh, p_index, false);
}
-RID MeshStorage::multimesh_get_mesh(RID p_multimesh) const {
+RID MeshStorage::_multimesh_get_mesh(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL_V(multimesh, RID());
@@ -1827,7 +1828,7 @@ Dependency *MeshStorage::multimesh_get_dependency(RID p_multimesh) const {
return &multimesh->dependency;
}
-Transform3D MeshStorage::multimesh_instance_get_transform(RID p_multimesh, int p_index) const {
+Transform3D MeshStorage::_multimesh_instance_get_transform(RID p_multimesh, int p_index) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL_V(multimesh, Transform3D());
ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform3D());
@@ -1858,7 +1859,7 @@ Transform3D MeshStorage::multimesh_instance_get_transform(RID p_multimesh, int p
return t;
}
-Transform2D MeshStorage::multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const {
+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_NULL_V(multimesh, Transform2D());
ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform2D());
@@ -1883,7 +1884,7 @@ Transform2D MeshStorage::multimesh_instance_get_transform_2d(RID p_multimesh, in
return t;
}
-Color MeshStorage::multimesh_instance_get_color(RID p_multimesh, int p_index) const {
+Color MeshStorage::_multimesh_instance_get_color(RID p_multimesh, int p_index) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL_V(multimesh, Color());
ERR_FAIL_INDEX_V(p_index, multimesh->instances, Color());
@@ -1906,7 +1907,7 @@ Color MeshStorage::multimesh_instance_get_color(RID p_multimesh, int p_index) co
return c;
}
-Color MeshStorage::multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const {
+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_NULL_V(multimesh, Color());
ERR_FAIL_INDEX_V(p_index, multimesh->instances, Color());
@@ -1929,11 +1930,12 @@ Color MeshStorage::multimesh_instance_get_custom_data(RID p_multimesh, int p_ind
return c;
}
-void MeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) {
+void MeshStorage::_multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL(multimesh);
ERR_FAIL_COND(p_buffer.size() != (multimesh->instances * (int)multimesh->stride_cache));
+ bool used_motion_vectors = multimesh->motion_vectors_enabled;
bool uses_motion_vectors = (RSG::viewport->get_num_viewports_with_motion_vectors() > 0) || (RendererCompositorStorage::get_singleton()->get_num_compositor_effects_with_motion_vectors() > 0);
if (uses_motion_vectors) {
_multimesh_enable_motion_vectors(multimesh);
@@ -1952,6 +1954,11 @@ void MeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_b
{
const float *r = p_buffer.ptr();
RD::get_singleton()->buffer_update(multimesh->buffer, multimesh->motion_vectors_current_offset * multimesh->stride_cache * sizeof(float), p_buffer.size() * sizeof(float), r);
+ if (multimesh->motion_vectors_enabled && !used_motion_vectors) {
+ // Motion vectors were just enabled, and the other half of the buffer will be empty.
+ // Need to ensure that both halves are filled for correct operation.
+ RD::get_singleton()->buffer_update(multimesh->buffer, multimesh->motion_vectors_previous_offset * multimesh->stride_cache * sizeof(float), p_buffer.size() * sizeof(float), r);
+ }
multimesh->buffer_set = true;
}
@@ -1970,7 +1977,7 @@ void MeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_b
}
}
-Vector<float> MeshStorage::multimesh_get_buffer(RID p_multimesh) const {
+Vector<float> MeshStorage::_multimesh_get_buffer(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL_V(multimesh, Vector<float>());
if (multimesh->buffer.is_null()) {
@@ -1992,7 +1999,7 @@ Vector<float> MeshStorage::multimesh_get_buffer(RID p_multimesh) const {
}
}
-void MeshStorage::multimesh_set_visible_instances(RID p_multimesh, int p_visible) {
+void MeshStorage::_multimesh_set_visible_instances(RID p_multimesh, int p_visible) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL(multimesh);
ERR_FAIL_COND(p_visible < -1 || p_visible > multimesh->instances);
@@ -2014,26 +2021,26 @@ void MeshStorage::multimesh_set_visible_instances(RID p_multimesh, int p_visible
multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES);
}
-int MeshStorage::multimesh_get_visible_instances(RID p_multimesh) const {
+int MeshStorage::_multimesh_get_visible_instances(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL_V(multimesh, 0);
return multimesh->visible_instances;
}
-void MeshStorage::multimesh_set_custom_aabb(RID p_multimesh, const AABB &p_aabb) {
+void MeshStorage::_multimesh_set_custom_aabb(RID p_multimesh, const AABB &p_aabb) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL(multimesh);
multimesh->custom_aabb = p_aabb;
multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
}
-AABB MeshStorage::multimesh_get_custom_aabb(RID p_multimesh) const {
+AABB MeshStorage::_multimesh_get_custom_aabb(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL_V(multimesh, AABB());
return multimesh->custom_aabb;
}
-AABB MeshStorage::multimesh_get_aabb(RID p_multimesh) const {
+AABB MeshStorage::_multimesh_get_aabb(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL_V(multimesh, AABB());
if (multimesh->custom_aabb != AABB()) {
@@ -2046,6 +2053,13 @@ AABB MeshStorage::multimesh_get_aabb(RID p_multimesh) const {
return multimesh->aabb;
}
+MeshStorage::MultiMeshInterpolator *MeshStorage::_multimesh_get_interpolator(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_NULL_V_MSG(multimesh, nullptr, "Multimesh not found: " + itos(p_multimesh.get_id()));
+
+ return &multimesh->interpolator;
+}
+
void MeshStorage::_update_dirty_multimeshes() {
while (multimesh_dirty_list) {
MultiMesh *multimesh = multimesh_dirty_list;
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
index 5491f637bc..4344db783d 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
@@ -244,6 +244,8 @@ private:
bool dirty = false;
MultiMesh *dirty_list = nullptr;
+ RendererMeshStorage::MultiMeshInterpolator interpolator;
+
Dependency dependency;
};
@@ -621,36 +623,38 @@ public:
bool owns_multimesh(RID p_rid) { return multimesh_owner.owns(p_rid); };
- virtual RID multimesh_allocate() override;
- virtual void multimesh_initialize(RID p_multimesh) override;
- virtual void multimesh_free(RID p_rid) override;
+ virtual RID _multimesh_allocate() override;
+ virtual void _multimesh_initialize(RID p_multimesh) override;
+ virtual void _multimesh_free(RID p_rid) override;
+
+ virtual void _multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) override;
+ virtual int _multimesh_get_instance_count(RID p_multimesh) const override;
- virtual void multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) override;
- virtual int multimesh_get_instance_count(RID p_multimesh) const override;
+ virtual void _multimesh_set_mesh(RID p_multimesh, RID p_mesh) override;
+ virtual void _multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) override;
+ virtual void _multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) override;
+ virtual void _multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) override;
+ virtual void _multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) override;
- virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh) override;
- virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) override;
- virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) override;
- virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) override;
- virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) override;
+ virtual RID _multimesh_get_mesh(RID p_multimesh) const override;
- virtual RID multimesh_get_mesh(RID p_multimesh) const override;
+ virtual Transform3D _multimesh_instance_get_transform(RID p_multimesh, int p_index) const override;
+ virtual Transform2D _multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const override;
+ virtual Color _multimesh_instance_get_color(RID p_multimesh, int p_index) const override;
+ virtual Color _multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override;
- virtual Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const override;
- virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const override;
- virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const override;
- virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override;
+ virtual void _multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) override;
+ virtual Vector<float> _multimesh_get_buffer(RID p_multimesh) const override;
- virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) override;
- virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const override;
+ virtual void _multimesh_set_visible_instances(RID p_multimesh, int p_visible) override;
+ virtual int _multimesh_get_visible_instances(RID p_multimesh) const override;
- virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible) override;
- virtual int multimesh_get_visible_instances(RID p_multimesh) const override;
+ virtual void _multimesh_set_custom_aabb(RID p_multimesh, const AABB &p_aabb) override;
+ virtual AABB _multimesh_get_custom_aabb(RID p_multimesh) const override;
- virtual void multimesh_set_custom_aabb(RID p_multimesh, const AABB &p_aabb) override;
- virtual AABB multimesh_get_custom_aabb(RID p_multimesh) const override;
+ virtual AABB _multimesh_get_aabb(RID p_multimesh) const override;
- virtual AABB multimesh_get_aabb(RID p_multimesh) const override;
+ virtual MultiMeshInterpolator *_multimesh_get_interpolator(RID p_multimesh) const override;
void _update_dirty_multimeshes();
void _multimesh_get_motion_vectors_offsets(RID p_multimesh, uint32_t &r_current_offset, uint32_t &r_prev_offset);
diff --git a/servers/rendering/renderer_rd/storage_rd/render_data_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_data_rd.cpp
index ac4fbba75b..ddc4d09279 100644
--- a/servers/rendering/renderer_rd/storage_rd/render_data_rd.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/render_data_rd.cpp
@@ -30,9 +30,6 @@
#include "render_data_rd.h"
-void RenderDataRD::_bind_methods() {
-}
-
Ref<RenderSceneBuffers> RenderDataRD::get_render_scene_buffers() const {
return render_buffers;
}
diff --git a/servers/rendering/renderer_rd/storage_rd/render_data_rd.h b/servers/rendering/renderer_rd/storage_rd/render_data_rd.h
index 3cd397b8ed..888527e1ef 100644
--- a/servers/rendering/renderer_rd/storage_rd/render_data_rd.h
+++ b/servers/rendering/renderer_rd/storage_rd/render_data_rd.h
@@ -38,9 +38,6 @@
class RenderDataRD : public RenderData {
GDCLASS(RenderDataRD, RenderData);
-protected:
- static void _bind_methods();
-
public:
// Access methods to expose data externally
virtual Ref<RenderSceneBuffers> get_render_scene_buffers() const override;
@@ -76,6 +73,8 @@ public:
uint32_t directional_light_count = 0;
bool directional_light_soft_shadows = false;
+ bool lightmap_bicubic_filter = false;
+
RenderingMethod::RenderInfo *render_info = nullptr;
/* Viewport data */
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 b5fdf8bebb..2f44096dc8 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
@@ -70,8 +70,14 @@ void RenderSceneBuffersRD::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_render_target"), &RenderSceneBuffersRD::get_render_target);
ClassDB::bind_method(D_METHOD("get_view_count"), &RenderSceneBuffersRD::get_view_count);
ClassDB::bind_method(D_METHOD("get_internal_size"), &RenderSceneBuffersRD::get_internal_size);
+ ClassDB::bind_method(D_METHOD("get_target_size"), &RenderSceneBuffersRD::get_target_size);
+ ClassDB::bind_method(D_METHOD("get_scaling_3d_mode"), &RenderSceneBuffersRD::get_scaling_3d_mode);
+ ClassDB::bind_method(D_METHOD("get_fsr_sharpness"), &RenderSceneBuffersRD::get_fsr_sharpness);
ClassDB::bind_method(D_METHOD("get_msaa_3d"), &RenderSceneBuffersRD::get_msaa_3d);
+ ClassDB::bind_method(D_METHOD("get_texture_samples"), &RenderSceneBuffersRD::get_texture_samples);
+ ClassDB::bind_method(D_METHOD("get_screen_space_aa"), &RenderSceneBuffersRD::get_screen_space_aa);
ClassDB::bind_method(D_METHOD("get_use_taa"), &RenderSceneBuffersRD::get_use_taa);
+ ClassDB::bind_method(D_METHOD("get_use_debanding"), &RenderSceneBuffersRD::get_use_debanding);
}
void RenderSceneBuffersRD::update_sizes(NamedTexture &p_named_texture) {
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 dc1e64ddcc..148a556b46 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
@@ -34,15 +34,16 @@
#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h"
#include "servers/rendering/rendering_server_default.h"
-void RenderSceneDataRD::_bind_methods() {
-}
-
Transform3D RenderSceneDataRD::get_cam_transform() const {
return cam_transform;
}
Projection RenderSceneDataRD::get_cam_projection() const {
- return cam_projection;
+ Projection correction;
+ correction.set_depth_correction(flip_y);
+ correction.add_jitter_offset(taa_jitter);
+
+ return correction * cam_projection;
}
uint32_t RenderSceneDataRD::get_view_count() const {
@@ -58,14 +59,18 @@ Vector3 RenderSceneDataRD::get_view_eye_offset(uint32_t p_view) const {
Projection RenderSceneDataRD::get_view_projection(uint32_t p_view) const {
ERR_FAIL_UNSIGNED_INDEX_V(p_view, view_count, Projection());
- return view_projection[p_view];
+ Projection correction;
+ correction.set_depth_correction(flip_y);
+ correction.add_jitter_offset(taa_jitter);
+
+ return correction * view_projection[p_view];
}
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, bool p_apply_alpha_multiplier) {
+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_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;
@@ -76,7 +81,7 @@ void RenderSceneDataRD::update_ubo(RID p_uniform_buffer, RS::ViewportDebugDraw p
UBO &prev_ubo = ubo_data.prev_ubo;
Projection correction;
- correction.set_depth_correction(p_flip_y);
+ correction.set_depth_correction(flip_y);
correction.add_jitter_offset(taa_jitter);
Projection projection = correction * cam_projection;
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 f6785942ed..b2c93acd44 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
@@ -50,6 +50,7 @@ public:
Vector2 taa_jitter;
uint32_t camera_visible_layers;
bool cam_orthogonal = false;
+ bool flip_y = false;
// For billboards to cast correct shadows.
Transform3D main_cam_transform;
@@ -90,12 +91,10 @@ public:
virtual Projection get_view_projection(uint32_t p_view) const override;
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, bool p_apply_alpha_multiplier);
+ 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_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);
virtual RID get_uniform_buffer() const override;
private:
- static void _bind_methods();
-
RID uniform_buffer; // loaded into this uniform buffer (supplied externally)
// This struct is loaded into Set 1 - Binding 0, populated at start of rendering a frame, must match with shader code
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
index 6e5e8f63e0..be29716f45 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
@@ -1470,8 +1470,24 @@ void TextureStorage::texture_debug_usage(List<RS::TextureInfo> *r_info) {
tinfo.format = t->format;
tinfo.width = t->width;
tinfo.height = t->height;
- tinfo.depth = t->depth;
- tinfo.bytes = Image::get_image_data_size(t->width, t->height, t->format, t->mipmaps);
+ tinfo.bytes = Image::get_image_data_size(t->width, t->height, t->format, t->mipmaps > 1);
+
+ switch (t->type) {
+ case TextureType::TYPE_3D:
+ tinfo.depth = t->depth;
+ tinfo.bytes *= t->depth;
+ break;
+
+ case TextureType::TYPE_LAYERED:
+ tinfo.depth = t->layers;
+ tinfo.bytes *= t->layers;
+ break;
+
+ default:
+ tinfo.depth = 0;
+ break;
+ }
+
r_info->push_back(tinfo);
}
}
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index b02d3def88..1d25dec633 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -34,10 +34,16 @@
#include "core/object/worker_thread_pool.h"
#include "core/os/os.h"
#include "rendering_light_culler.h"
+#include "rendering_server_constants.h"
#include "rendering_server_default.h"
#include <new>
+#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
+// This is used only to obtain node paths for user-friendly physics interpolation warnings.
+#include "scene/main/node.h"
+#endif
+
/* HALTON SEQUENCE */
#ifndef _3D_DISABLED
@@ -53,6 +59,20 @@ static float get_halton_value(int p_index, int p_base) {
}
#endif // _3D_DISABLED
+/* EVENT QUEUING */
+
+void RendererSceneCull::tick() {
+ if (_interpolation_data.interpolation_enabled) {
+ update_interpolation_tick(true);
+ }
+}
+
+void RendererSceneCull::pre_draw(bool p_will_draw) {
+ if (_interpolation_data.interpolation_enabled) {
+ update_interpolation_frame(p_will_draw);
+ }
+}
+
/* CAMERA API */
RID RendererSceneCull::camera_allocate() {
@@ -93,6 +113,7 @@ void RendererSceneCull::camera_set_frustum(RID p_camera, float p_size, Vector2 p
void RendererSceneCull::camera_set_transform(RID p_camera, const Transform3D &p_transform) {
Camera *camera = camera_owner.get_or_null(p_camera);
ERR_FAIL_NULL(camera);
+
camera->transform = p_transform.orthonormalized();
}
@@ -924,8 +945,45 @@ void RendererSceneCull::instance_set_transform(RID p_instance, const Transform3D
Instance *instance = instance_owner.get_or_null(p_instance);
ERR_FAIL_NULL(instance);
- if (instance->transform == p_transform) {
- return; //must be checked to avoid worst evil
+#ifdef RENDERING_SERVER_DEBUG_PHYSICS_INTERPOLATION
+ print_line("instance_set_transform " + rtos(p_transform.origin.x) + " .. tick " + itos(Engine::get_singleton()->get_physics_frames()));
+#endif
+
+ if (!_interpolation_data.interpolation_enabled || !instance->interpolated || !instance->scenario) {
+ if (instance->transform == p_transform) {
+ return; // Must be checked to avoid worst evil.
+ }
+
+#ifdef DEBUG_ENABLED
+
+ for (int i = 0; i < 4; i++) {
+ const Vector3 &v = i < 3 ? p_transform.basis.rows[i] : p_transform.origin;
+ ERR_FAIL_COND(!v.is_finite());
+ }
+
+#endif
+ instance->transform = p_transform;
+ _instance_queue_update(instance, true);
+
+#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
+ if (_interpolation_data.interpolation_enabled && !instance->interpolated && Engine::get_singleton()->is_in_physics_frame()) {
+ PHYSICS_INTERPOLATION_NODE_WARNING(instance->object_id, "Non-interpolated instance triggered from physics process");
+ }
+#endif
+
+ return;
+ }
+
+ float new_checksum = TransformInterpolator::checksum_transform_3d(p_transform);
+ bool checksums_match = (instance->transform_checksum_curr == new_checksum) && (instance->transform_checksum_prev == new_checksum);
+
+ // We can't entirely reject no changes because we need the interpolation
+ // system to keep on stewing.
+
+ // Optimized check. First checks the checksums. If they pass it does the slow check at the end.
+ // Alternatively we can do this non-optimized and ignore the checksum... if no change.
+ if (checksums_match && (instance->transform_curr == p_transform) && (instance->transform_prev == p_transform)) {
+ return;
}
#ifdef DEBUG_ENABLED
@@ -936,8 +994,69 @@ void RendererSceneCull::instance_set_transform(RID p_instance, const Transform3D
}
#endif
- instance->transform = p_transform;
+
+ instance->transform_curr = p_transform;
+
+#ifdef RENDERING_SERVER_DEBUG_PHYSICS_INTERPOLATION
+ print_line("\tprev " + rtos(instance->transform_prev.origin.x) + ", curr " + rtos(instance->transform_curr.origin.x));
+#endif
+
+ // Keep checksums up to date.
+ instance->transform_checksum_curr = new_checksum;
+
+ if (!instance->on_interpolate_transform_list) {
+ _interpolation_data.instance_transform_update_list_curr->push_back(p_instance);
+ instance->on_interpolate_transform_list = true;
+ } else {
+ DEV_ASSERT(_interpolation_data.instance_transform_update_list_curr->size());
+ }
+
+ // If the instance is invisible, then we are simply updating the data flow, there is no need to calculate the interpolated
+ // transform or anything else.
+ // Ideally we would not even call the VisualServer::set_transform() when invisible but that would entail having logic
+ // to keep track of the previous transform on the SceneTree side. The "early out" below is less efficient but a lot cleaner codewise.
+ if (!instance->visible) {
+ return;
+ }
+
+ // Decide on the interpolation method... slerp if possible.
+ instance->interpolation_method = TransformInterpolator::find_method(instance->transform_prev.basis, instance->transform_curr.basis);
+
+ if (!instance->on_interpolate_list) {
+ _interpolation_data.instance_interpolate_update_list.push_back(p_instance);
+ instance->on_interpolate_list = true;
+ } else {
+ DEV_ASSERT(_interpolation_data.instance_interpolate_update_list.size());
+ }
+
_instance_queue_update(instance, true);
+
+#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
+ if (!Engine::get_singleton()->is_in_physics_frame()) {
+ PHYSICS_INTERPOLATION_NODE_WARNING(instance->object_id, "Interpolated instance triggered from outside physics process");
+ }
+#endif
+}
+
+void RendererSceneCull::instance_set_interpolated(RID p_instance, bool p_interpolated) {
+ Instance *instance = instance_owner.get_or_null(p_instance);
+ ERR_FAIL_NULL(instance);
+ instance->interpolated = p_interpolated;
+}
+
+void RendererSceneCull::instance_reset_physics_interpolation(RID p_instance) {
+ Instance *instance = instance_owner.get_or_null(p_instance);
+ ERR_FAIL_NULL(instance);
+
+ if (_interpolation_data.interpolation_enabled && instance->interpolated) {
+ instance->transform_prev = instance->transform_curr;
+ instance->transform_checksum_prev = instance->transform_checksum_curr;
+
+#ifdef RENDERING_SERVER_DEBUG_PHYSICS_INTERPOLATION
+ print_line("instance_reset_physics_interpolation .. tick " + itos(Engine::get_singleton()->get_physics_frames()));
+ print_line("\tprev " + rtos(instance->transform_prev.origin.x) + ", curr " + rtos(instance->transform_curr.origin.x));
+#endif
+ }
}
void RendererSceneCull::instance_attach_object_instance_id(RID p_instance, ObjectID p_id) {
@@ -990,6 +1109,23 @@ void RendererSceneCull::instance_set_visible(RID p_instance, bool p_visible) {
if (p_visible) {
if (instance->scenario != nullptr) {
+ // Special case for physics interpolation, we want to ensure the interpolated data is up to date
+ if (_interpolation_data.interpolation_enabled && instance->interpolated && !instance->on_interpolate_list) {
+ // Do all the extra work we normally do on instance_set_transform(), because this is optimized out for hidden instances.
+ // This prevents a glitch of stale interpolation transform data when unhiding before the next physics tick.
+ instance->interpolation_method = TransformInterpolator::find_method(instance->transform_prev.basis, instance->transform_curr.basis);
+ _interpolation_data.instance_interpolate_update_list.push_back(p_instance);
+ instance->on_interpolate_list = true;
+
+ // We must also place on the transform update list for a tick, so the system
+ // can auto-detect if the instance is no longer moving, and remove from the interpolate lists again.
+ // If this step is ignored, an unmoving instance could remain on the interpolate lists indefinitely
+ // (or rather until the object is deleted) and cause unnecessary updates and drawcalls.
+ if (!instance->on_interpolate_transform_list) {
+ _interpolation_data.instance_transform_update_list_curr->push_back(p_instance);
+ instance->on_interpolate_transform_list = true;
+ }
+ }
_instance_queue_update(instance, true, false);
}
} else if (instance->indexer_id.is_valid()) {
@@ -1574,11 +1710,22 @@ void RendererSceneCull::instance_geometry_get_shader_parameter_list(RID p_instan
void RendererSceneCull::_update_instance(Instance *p_instance) {
p_instance->version++;
+ // When not using interpolation the transform is used straight.
+ const Transform3D *instance_xform = &p_instance->transform;
+
+ // Can possibly use the most up to date current transform here when using physics interpolation ...
+ // uncomment the next line for this..
+ //if (_interpolation_data.interpolation_enabled && p_instance->interpolated) {
+ // instance_xform = &p_instance->transform_curr;
+ //}
+ // However it does seem that using the interpolated transform (transform) works for keeping AABBs
+ // up to date to avoid culling errors.
+
if (p_instance->base_type == RS::INSTANCE_LIGHT) {
InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data);
- RSG::light_storage->light_instance_set_transform(light->instance, p_instance->transform);
- RSG::light_storage->light_instance_set_aabb(light->instance, p_instance->transform.xform(p_instance->aabb));
+ RSG::light_storage->light_instance_set_transform(light->instance, *instance_xform);
+ RSG::light_storage->light_instance_set_aabb(light->instance, instance_xform->xform(p_instance->aabb));
light->make_shadow_dirty();
RS::LightBakeMode bake_mode = RSG::light_storage->light_get_bake_mode(p_instance->base);
@@ -1601,7 +1748,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
} else if (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE) {
InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(p_instance->base_data);
- RSG::light_storage->reflection_probe_instance_set_transform(reflection_probe->instance, p_instance->transform);
+ RSG::light_storage->reflection_probe_instance_set_transform(reflection_probe->instance, *instance_xform);
if (p_instance->scenario && p_instance->array_index >= 0) {
InstanceData &idata = p_instance->scenario->instance_data[p_instance->array_index];
@@ -1610,17 +1757,17 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
} else if (p_instance->base_type == RS::INSTANCE_DECAL) {
InstanceDecalData *decal = static_cast<InstanceDecalData *>(p_instance->base_data);
- RSG::texture_storage->decal_instance_set_transform(decal->instance, p_instance->transform);
+ RSG::texture_storage->decal_instance_set_transform(decal->instance, *instance_xform);
} else if (p_instance->base_type == RS::INSTANCE_LIGHTMAP) {
InstanceLightmapData *lightmap = static_cast<InstanceLightmapData *>(p_instance->base_data);
- RSG::light_storage->lightmap_instance_set_transform(lightmap->instance, p_instance->transform);
+ RSG::light_storage->lightmap_instance_set_transform(lightmap->instance, *instance_xform);
} else if (p_instance->base_type == RS::INSTANCE_VOXEL_GI) {
InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(p_instance->base_data);
- scene_render->voxel_gi_instance_set_transform_to_data(voxel_gi->probe_instance, p_instance->transform);
+ scene_render->voxel_gi_instance_set_transform_to_data(voxel_gi->probe_instance, *instance_xform);
} else if (p_instance->base_type == RS::INSTANCE_PARTICLES) {
- RSG::particles_storage->particles_set_emission_transform(p_instance->base, p_instance->transform);
+ RSG::particles_storage->particles_set_emission_transform(p_instance->base, *instance_xform);
} else if (p_instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) {
InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(p_instance->base_data);
@@ -1628,13 +1775,13 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
if (RSG::particles_storage->particles_collision_is_heightfield(p_instance->base)) {
heightfield_particle_colliders_update_list.insert(p_instance);
}
- RSG::particles_storage->particles_collision_instance_set_transform(collision->instance, p_instance->transform);
+ RSG::particles_storage->particles_collision_instance_set_transform(collision->instance, *instance_xform);
} else if (p_instance->base_type == RS::INSTANCE_FOG_VOLUME) {
InstanceFogVolumeData *volume = static_cast<InstanceFogVolumeData *>(p_instance->base_data);
- scene_render->fog_volume_instance_set_transform(volume->instance, p_instance->transform);
+ scene_render->fog_volume_instance_set_transform(volume->instance, *instance_xform);
} else if (p_instance->base_type == RS::INSTANCE_OCCLUDER) {
if (p_instance->scenario) {
- RendererSceneOcclusionCull::get_singleton()->scenario_set_instance(p_instance->scenario->self, p_instance->self, p_instance->base, p_instance->transform, p_instance->visible);
+ RendererSceneOcclusionCull::get_singleton()->scenario_set_instance(p_instance->scenario->self, p_instance->self, p_instance->base, *instance_xform, p_instance->visible);
}
}
@@ -1654,7 +1801,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
}
AABB new_aabb;
- new_aabb = p_instance->transform.xform(p_instance->aabb);
+ new_aabb = instance_xform->xform(p_instance->aabb);
p_instance->transformed_aabb = new_aabb;
if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) {
@@ -1681,11 +1828,11 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
}
ERR_FAIL_NULL(geom->geometry_instance);
- geom->geometry_instance->set_transform(p_instance->transform, p_instance->aabb, p_instance->transformed_aabb);
+ geom->geometry_instance->set_transform(*instance_xform, p_instance->aabb, p_instance->transformed_aabb);
}
// note: we had to remove is equal approx check here, it meant that det == 0.000004 won't work, which is the case for some of our scenes.
- if (p_instance->scenario == nullptr || !p_instance->visible || p_instance->transform.basis.determinant() == 0) {
+ if (p_instance->scenario == nullptr || !p_instance->visible || instance_xform->basis.determinant() == 0) {
p_instance->prev_transformed_aabb = p_instance->transformed_aabb;
return;
}
@@ -3089,7 +3236,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
Vector<Instance *> lights_with_shadow;
for (Instance *E : scenario->directional_lights) {
- if (!E->visible) {
+ if (!E->visible || !(E->layer_mask & p_visible_layers)) {
continue;
}
@@ -4180,6 +4327,8 @@ bool RendererSceneCull::free(RID p_rid) {
Instance *instance = instance_owner.get_or_null(p_rid);
+ _interpolation_data.notify_free_instance(p_rid, *instance);
+
instance_geometry_set_lightmap(p_rid, RID(), Rect2(), 0);
instance_set_scenario(p_rid, RID());
instance_set_base(p_rid, RID());
@@ -4240,6 +4389,108 @@ void RendererSceneCull::set_scene_render(RendererSceneRender *p_scene_render) {
geometry_instance_pair_mask = scene_render->geometry_instance_get_pair_mask();
}
+/* INTERPOLATION API */
+
+void RendererSceneCull::update_interpolation_tick(bool p_process) {
+ // MultiMesh: Update interpolation in storage.
+ RSG::mesh_storage->update_interpolation_tick(p_process);
+
+ // INSTANCES
+
+ // Detect any that were on the previous transform list that are no longer active;
+ // we should remove them from the interpolate list.
+
+ for (const RID &rid : *_interpolation_data.instance_transform_update_list_prev) {
+ Instance *instance = instance_owner.get_or_null(rid);
+
+ bool active = true;
+
+ // No longer active? (Either the instance deleted or no longer being transformed.)
+ if (instance && !instance->on_interpolate_transform_list) {
+ active = false;
+ instance->on_interpolate_list = false;
+
+ // Make sure the most recent transform is set...
+ instance->transform = instance->transform_curr;
+
+ // ... and that both prev and current are the same, just in case of any interpolations.
+ instance->transform_prev = instance->transform_curr;
+
+ // Make sure instances are updated one more time to ensure the AABBs are correct.
+ _instance_queue_update(instance, true);
+ }
+
+ if (!instance) {
+ active = false;
+ }
+
+ if (!active) {
+ _interpolation_data.instance_interpolate_update_list.erase(rid);
+ }
+ }
+
+ // Now for any in the transform list (being actively interpolated), keep the previous transform
+ // value up to date, ready for the next tick.
+ if (p_process) {
+ for (const RID &rid : *_interpolation_data.instance_transform_update_list_curr) {
+ Instance *instance = instance_owner.get_or_null(rid);
+ if (instance) {
+ instance->transform_prev = instance->transform_curr;
+ instance->transform_checksum_prev = instance->transform_checksum_curr;
+ instance->on_interpolate_transform_list = false;
+ }
+ }
+ }
+
+ // We maintain a mirror list for the transform updates, so we can detect when an instance
+ // is no longer being transformed, and remove it from the interpolate list.
+ SWAP(_interpolation_data.instance_transform_update_list_curr, _interpolation_data.instance_transform_update_list_prev);
+
+ // Prepare for the next iteration.
+ _interpolation_data.instance_transform_update_list_curr->clear();
+}
+
+void RendererSceneCull::update_interpolation_frame(bool p_process) {
+ // MultiMesh: Update interpolation in storage.
+ RSG::mesh_storage->update_interpolation_frame(p_process);
+
+ if (p_process) {
+ real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
+
+ for (const RID &rid : _interpolation_data.instance_interpolate_update_list) {
+ Instance *instance = instance_owner.get_or_null(rid);
+ if (instance) {
+ TransformInterpolator::interpolate_transform_3d_via_method(instance->transform_prev, instance->transform_curr, instance->transform, f, instance->interpolation_method);
+
+#ifdef RENDERING_SERVER_DEBUG_PHYSICS_INTERPOLATION
+ print_line("\t\tinterpolated: " + rtos(instance->transform.origin.x) + "\t( prev " + rtos(instance->transform_prev.origin.x) + ", curr " + rtos(instance->transform_curr.origin.x) + " ) on tick " + itos(Engine::get_singleton()->get_physics_frames()));
+#endif
+
+ // Make sure AABBs are constantly up to date through the interpolation.
+ _instance_queue_update(instance, true);
+ }
+ }
+ }
+}
+
+void RendererSceneCull::set_physics_interpolation_enabled(bool p_enabled) {
+ _interpolation_data.interpolation_enabled = p_enabled;
+}
+
+void RendererSceneCull::InterpolationData::notify_free_instance(RID p_rid, Instance &r_instance) {
+ r_instance.on_interpolate_list = false;
+ r_instance.on_interpolate_transform_list = false;
+
+ if (!interpolation_enabled) {
+ return;
+ }
+
+ // If the instance was on any of the lists, remove.
+ instance_interpolate_update_list.erase_multiple_unordered(p_rid);
+ instance_transform_update_list_curr->erase_multiple_unordered(p_rid);
+ instance_transform_update_list_prev->erase_multiple_unordered(p_rid);
+}
+
RendererSceneCull::RendererSceneCull() {
render_pass = 1;
singleton = this;
diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h
index 0039d14475..972f66d325 100644
--- a/servers/rendering/renderer_scene_cull.h
+++ b/servers/rendering/renderer_scene_cull.h
@@ -32,6 +32,7 @@
#define RENDERER_SCENE_CULL_H
#include "core/math/dynamic_bvh.h"
+#include "core/math/transform_interpolator.h"
#include "core/templates/bin_sorted_array.h"
#include "core/templates/local_vector.h"
#include "core/templates/paged_allocator.h"
@@ -66,6 +67,11 @@ public:
static RendererSceneCull *singleton;
+ /* EVENT QUEUING */
+
+ void tick();
+ void pre_draw(bool p_will_draw);
+
/* CAMERA API */
struct Camera {
@@ -406,8 +412,16 @@ public:
RID mesh_instance; //only used for meshes and when skeleton/blendshapes exist
+ // This is the main transform to be drawn with ...
+ // This will either be the interpolated transform (when using fixed timestep interpolation)
+ // or the ONLY transform (when not using FTI).
Transform3D transform;
+ // For interpolation we store the current transform (this physics tick)
+ // and the transform in the previous tick.
+ Transform3D transform_curr;
+ Transform3D transform_prev;
+
float lod_bias;
bool ignore_occlusion_culling;
@@ -418,13 +432,23 @@ public:
RS::ShadowCastingSetting cast_shadows;
uint32_t layer_mask;
- //fit in 32 bits
- bool mirror : 8;
- bool receive_shadows : 8;
- bool visible : 8;
- bool baked_light : 2; //this flag is only to know if it actually did use baked light
- bool dynamic_gi : 2; //same above for dynamic objects
- bool redraw_if_visible : 4;
+ // Fit in 32 bits.
+ bool mirror : 1;
+ bool receive_shadows : 1;
+ bool visible : 1;
+ bool baked_light : 1; // This flag is only to know if it actually did use baked light.
+ bool dynamic_gi : 1; // Same as above for dynamic objects.
+ bool redraw_if_visible : 1;
+
+ bool on_interpolate_list : 1;
+ bool on_interpolate_transform_list : 1;
+ bool interpolated : 1;
+ TransformInterpolator::Method interpolation_method : 3;
+
+ // For fixed timestep interpolation.
+ // Note 32 bits is plenty for checksum, no need for real_t
+ float transform_checksum_curr;
+ float transform_checksum_prev;
Instance *lightmap = nullptr;
Rect2 lightmap_uv_scale;
@@ -574,6 +598,14 @@ public:
baked_light = true;
dynamic_gi = false;
redraw_if_visible = false;
+
+ on_interpolate_list = false;
+ on_interpolate_transform_list = false;
+ interpolated = true;
+ interpolation_method = TransformInterpolator::INTERP_LERP;
+ transform_checksum_curr = 0.0;
+ transform_checksum_prev = 0.0;
+
lightmap_slice_index = 0;
lightmap = nullptr;
lightmap_cull_index = 0;
@@ -1027,6 +1059,8 @@ public:
virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask);
virtual void instance_set_pivot_data(RID p_instance, float p_sorting_offset, bool p_use_aabb_center);
virtual void instance_set_transform(RID p_instance, const Transform3D &p_transform);
+ virtual void instance_set_interpolated(RID p_instance, bool p_interpolated);
+ virtual void instance_reset_physics_interpolation(RID p_instance);
virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id);
virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight);
virtual void instance_set_surface_override_material(RID p_instance, int p_surface, RID p_material);
@@ -1384,6 +1418,7 @@ public:
PASS1(decals_set_filter, RS::DecalFilter)
PASS1(light_projectors_set_filter, RS::LightProjectorFilter)
+ PASS1(lightmaps_set_bicubic_filter, bool)
virtual void update();
@@ -1393,6 +1428,22 @@ public:
virtual void update_visibility_notifiers();
+ /* INTERPOLATION */
+
+ void update_interpolation_tick(bool p_process = true);
+ void update_interpolation_frame(bool p_process = true);
+ virtual void set_physics_interpolation_enabled(bool p_enabled);
+
+ struct InterpolationData {
+ void notify_free_instance(RID p_rid, Instance &r_instance);
+ LocalVector<RID> instance_interpolate_update_list;
+ LocalVector<RID> instance_transform_update_lists[2];
+ LocalVector<RID> *instance_transform_update_list_curr = &instance_transform_update_lists[0];
+ LocalVector<RID> *instance_transform_update_list_prev = &instance_transform_update_lists[1];
+
+ bool interpolation_enabled = false;
+ } _interpolation_data;
+
RendererSceneCull();
virtual ~RendererSceneCull();
};
diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h
index 719efa4df2..3446f5dd1b 100644
--- a/servers/rendering/renderer_scene_render.h
+++ b/servers/rendering/renderer_scene_render.h
@@ -338,6 +338,7 @@ public:
virtual void decals_set_filter(RS::DecalFilter p_filter) = 0;
virtual void light_projectors_set_filter(RS::LightProjectorFilter p_filter) = 0;
+ virtual void lightmaps_set_bicubic_filter(bool p_enable) = 0;
virtual void update() = 0;
virtual ~RendererSceneRender() {}
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index 80c1f67d8a..7e45eba1de 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -786,6 +786,7 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) {
if (OS::get_singleton()->get_current_rendering_driver_name().begins_with("opengl3")) {
if (blits.size() > 0) {
RSG::rasterizer->blit_render_targets_to_screen(vp->viewport_to_screen, blits.ptr(), blits.size());
+ RSG::rasterizer->gl_end_frame(p_swap_buffers);
}
} else if (blits.size() > 0) {
if (!blit_to_screen_list.has(vp->viewport_to_screen)) {
@@ -796,7 +797,6 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) {
blit_to_screen_list[vp->viewport_to_screen].push_back(blits[b]);
}
}
- RSG::rasterizer->end_viewport(p_swap_buffers && blits.size() > 0);
}
}
} else
@@ -826,10 +826,10 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) {
Vector<BlitToScreen> blit_to_screen_vec;
blit_to_screen_vec.push_back(blit);
RSG::rasterizer->blit_render_targets_to_screen(vp->viewport_to_screen, blit_to_screen_vec.ptr(), 1);
+ RSG::rasterizer->gl_end_frame(p_swap_buffers);
} else {
blit_to_screen_list[vp->viewport_to_screen].push_back(blit);
}
- RSG::rasterizer->end_viewport(p_swap_buffers);
}
}
@@ -899,6 +899,7 @@ void RendererViewport::viewport_set_use_xr(RID p_viewport, bool p_use_xr) {
void RendererViewport::viewport_set_scaling_3d_mode(RID p_viewport, RS::ViewportScaling3DMode p_mode) {
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_NULL(viewport);
+ ERR_FAIL_COND_EDMSG(p_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR && OS::get_singleton()->get_current_rendering_method() != "forward_plus", "FSR1 is only available when using the Forward+ renderer.");
ERR_FAIL_COND_EDMSG(p_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR2 && OS::get_singleton()->get_current_rendering_method() != "forward_plus", "FSR2 is only available when using the Forward+ renderer.");
if (viewport->scaling_3d_mode == p_mode) {
@@ -1270,6 +1271,13 @@ void RendererViewport::viewport_set_use_hdr_2d(RID p_viewport, bool p_use_hdr_2d
RSG::texture_storage->render_target_set_use_hdr(viewport->render_target, p_use_hdr_2d);
}
+bool RendererViewport::viewport_is_using_hdr_2d(RID p_viewport) const {
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
+ ERR_FAIL_NULL_V(viewport, false);
+
+ return viewport->use_hdr_2d;
+}
+
void RendererViewport::viewport_set_screen_space_aa(RID p_viewport, RS::ViewportScreenSpaceAA p_mode) {
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_NULL(viewport);
diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h
index b36fc7f57f..bf97905f86 100644
--- a/servers/rendering/renderer_viewport.h
+++ b/servers/rendering/renderer_viewport.h
@@ -262,6 +262,8 @@ public:
void viewport_set_transparent_background(RID p_viewport, bool p_enabled);
void viewport_set_use_hdr_2d(RID p_viewport, bool p_use_hdr_2d);
+ bool viewport_is_using_hdr_2d(RID p_viewport) const;
+
void viewport_set_global_canvas_transform(RID p_viewport, const Transform2D &p_transform);
void viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer);
diff --git a/servers/rendering/rendering_context_driver.cpp b/servers/rendering/rendering_context_driver.cpp
index 19c0b0838c..b623be4098 100644
--- a/servers/rendering/rendering_context_driver.cpp
+++ b/servers/rendering/rendering_context_driver.cpp
@@ -83,3 +83,88 @@ void RenderingContextDriver::window_destroy(DisplayServer::WindowID p_window) {
window_surface_map.erase(p_window);
}
+
+String RenderingContextDriver::get_driver_and_device_memory_report() const {
+ String report;
+
+ const uint32_t num_tracked_obj_types = static_cast<uint32_t>(get_tracked_object_type_count());
+
+ report += "=== Driver Memory Report ===";
+
+ report += "\nLaunch with --extra-gpu-memory-tracking and build with "
+ "DEBUG_ENABLED for this functionality to work.";
+ report += "\nDevice memory may be unavailable if the API does not support it"
+ "(e.g. VK_EXT_device_memory_report is unsupported).";
+ report += "\n";
+
+ report += "\nTotal Driver Memory:";
+ report += String::num_real(double(get_driver_total_memory()) / (1024.0 * 1024.0));
+ report += " MB";
+ report += "\nTotal Driver Num Allocations: ";
+ report += String::num_uint64(get_driver_allocation_count());
+
+ report += "\nTotal Device Memory:";
+ report += String::num_real(double(get_device_total_memory()) / (1024.0 * 1024.0));
+ report += " MB";
+ report += "\nTotal Device Num Allocations: ";
+ report += String::num_uint64(get_device_allocation_count());
+
+ report += "\n\nMemory use by object type (CSV format):";
+ report += "\n\nCategory; Driver memory in MB; Driver Allocation Count; "
+ "Device memory in MB; Device Allocation Count";
+
+ for (uint32_t i = 0u; i < num_tracked_obj_types; ++i) {
+ report += "\n";
+ report += get_tracked_object_name(i);
+ report += ";";
+ report += String::num_real(double(get_driver_memory_by_object_type(i)) / (1024.0 * 1024.0));
+ report += ";";
+ report += String::num_uint64(get_driver_allocs_by_object_type(i));
+ report += ";";
+ report += String::num_real(double(get_device_memory_by_object_type(i)) / (1024.0 * 1024.0));
+ report += ";";
+ report += String::num_uint64(get_device_allocs_by_object_type(i));
+ }
+
+ return report;
+}
+
+const char *RenderingContextDriver::get_tracked_object_name(uint32_t p_type_index) const {
+ return "Tracking Unsupported by API";
+}
+
+uint64_t RenderingContextDriver::get_tracked_object_type_count() const {
+ return 0;
+}
+
+uint64_t RenderingContextDriver::get_driver_total_memory() const {
+ return 0;
+}
+
+uint64_t RenderingContextDriver::get_driver_allocation_count() const {
+ return 0;
+}
+
+uint64_t RenderingContextDriver::get_driver_memory_by_object_type(uint32_t) const {
+ return 0;
+}
+
+uint64_t RenderingContextDriver::get_driver_allocs_by_object_type(uint32_t) const {
+ return 0;
+}
+
+uint64_t RenderingContextDriver::get_device_total_memory() const {
+ return 0;
+}
+
+uint64_t RenderingContextDriver::get_device_allocation_count() const {
+ return 0;
+}
+
+uint64_t RenderingContextDriver::get_device_memory_by_object_type(uint32_t) const {
+ return 0;
+}
+
+uint64_t RenderingContextDriver::get_device_allocs_by_object_type(uint32_t) const {
+ return 0;
+}
diff --git a/servers/rendering/rendering_context_driver.h b/servers/rendering/rendering_context_driver.h
index 539b3814a0..2e5951ae4f 100644
--- a/servers/rendering/rendering_context_driver.h
+++ b/servers/rendering/rendering_context_driver.h
@@ -101,6 +101,21 @@ public:
virtual bool surface_get_needs_resize(SurfaceID p_surface) const = 0;
virtual void surface_destroy(SurfaceID p_surface) = 0;
virtual bool is_debug_utils_enabled() const = 0;
+
+ String get_driver_and_device_memory_report() const;
+
+ virtual const char *get_tracked_object_name(uint32_t p_type_index) const;
+ virtual uint64_t get_tracked_object_type_count() const;
+
+ virtual uint64_t get_driver_total_memory() const;
+ virtual uint64_t get_driver_allocation_count() const;
+ virtual uint64_t get_driver_memory_by_object_type(uint32_t p_type) const;
+ virtual uint64_t get_driver_allocs_by_object_type(uint32_t p_type) const;
+
+ virtual uint64_t get_device_total_memory() const;
+ virtual uint64_t get_device_allocation_count() const;
+ virtual uint64_t get_device_memory_by_object_type(uint32_t p_type) const;
+ virtual uint64_t get_device_allocs_by_object_type(uint32_t p_type) const;
};
#endif // RENDERING_CONTEXT_DRIVER_H
diff --git a/servers/rendering/rendering_device.compat.inc b/servers/rendering/rendering_device.compat.inc
index ee9481280a..77e44bbc5e 100644
--- a/servers/rendering/rendering_device.compat.inc
+++ b/servers/rendering/rendering_device.compat.inc
@@ -86,7 +86,11 @@ RenderingDevice::FinalAction RenderingDevice::_convert_final_action_84976(FinalA
}
RenderingDevice::DrawListID RenderingDevice::_draw_list_begin_bind_compat_84976(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const TypedArray<RID> &p_storage_textures) {
- return draw_list_begin(p_framebuffer, _convert_initial_action_84976(p_initial_color_action), _convert_final_action_84976(p_final_color_action), _convert_initial_action_84976(p_initial_depth_action), _convert_final_action_84976(p_final_depth_action), p_clear_color_values, p_clear_depth, p_clear_stencil, p_region);
+ return draw_list_begin(p_framebuffer, _convert_initial_action_84976(p_initial_color_action), _convert_final_action_84976(p_final_color_action), _convert_initial_action_84976(p_initial_depth_action), _convert_final_action_84976(p_final_depth_action), p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, RDD::BreadcrumbMarker::NONE);
+}
+
+RenderingDevice::DrawListID RenderingDevice::_draw_list_begin_bind_compat_90993(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region) {
+ return draw_list_begin(p_framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, RDD::BreadcrumbMarker::NONE);
}
RenderingDevice::ComputeListID RenderingDevice::_compute_list_begin_bind_compat_84976(bool p_allow_draw_overlap) {
@@ -123,9 +127,11 @@ RenderingDevice::FramebufferFormatID RenderingDevice::_screen_get_framebuffer_fo
void RenderingDevice::_bind_compatibility_methods() {
ClassDB::bind_compatibility_method(D_METHOD("shader_create_from_bytecode", "binary_data"), &RenderingDevice::_shader_create_from_bytecode_bind_compat_79606);
+
ClassDB::bind_compatibility_method(D_METHOD("draw_list_end", "post_barrier"), &RenderingDevice::_draw_list_end_bind_compat_81356, DEFVAL(7));
ClassDB::bind_compatibility_method(D_METHOD("compute_list_end", "post_barrier"), &RenderingDevice::_compute_list_end_bind_compat_81356, DEFVAL(7));
ClassDB::bind_compatibility_method(D_METHOD("barrier", "from", "to"), &RenderingDevice::_barrier_bind_compat_81356, DEFVAL(7), DEFVAL(7));
+
ClassDB::bind_compatibility_method(D_METHOD("draw_list_end", "post_barrier"), &RenderingDevice::_draw_list_end_bind_compat_84976, DEFVAL(0x7FFF));
ClassDB::bind_compatibility_method(D_METHOD("compute_list_end", "post_barrier"), &RenderingDevice::_compute_list_end_bind_compat_84976, DEFVAL(0x7FFF));
ClassDB::bind_compatibility_method(D_METHOD("draw_list_begin", "framebuffer", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "storage_textures"), &RenderingDevice::_draw_list_begin_bind_compat_84976, DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()), DEFVAL(TypedArray<RID>()));
@@ -136,7 +142,10 @@ void RenderingDevice::_bind_compatibility_methods() {
ClassDB::bind_compatibility_method(D_METHOD("texture_copy", "from_texture", "to_texture", "from_pos", "to_pos", "size", "src_mipmap", "dst_mipmap", "src_layer", "dst_layer", "post_barrier"), &RenderingDevice::_texture_copy_bind_compat_84976, DEFVAL(0x7FFF));
ClassDB::bind_compatibility_method(D_METHOD("texture_clear", "texture", "color", "base_mipmap", "mipmap_count", "base_layer", "layer_count", "post_barrier"), &RenderingDevice::_texture_clear_bind_compat_84976, DEFVAL(0x7FFF));
ClassDB::bind_compatibility_method(D_METHOD("texture_resolve_multisample", "from_texture", "to_texture", "post_barrier"), &RenderingDevice::_texture_resolve_multisample_bind_compat_84976, DEFVAL(0x7FFF));
+
ClassDB::bind_compatibility_method(D_METHOD("screen_get_framebuffer_format"), &RenderingDevice::_screen_get_framebuffer_format_bind_compat_87340);
+
+ ClassDB::bind_compatibility_method(D_METHOD("draw_list_begin", "framebuffer", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region"), &RenderingDevice::_draw_list_begin_bind_compat_90993, DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()));
}
#endif
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index 38f1fe57bd..f0f267c246 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -82,11 +82,12 @@ static String _get_device_type_name(const RenderingContextDriver::Device &p_devi
}
static uint32_t _get_device_type_score(const RenderingContextDriver::Device &p_device) {
+ static const bool prefer_integrated = OS::get_singleton()->get_user_prefers_integrated_gpu();
switch (p_device.type) {
case RenderingContextDriver::DEVICE_TYPE_INTEGRATED_GPU:
- return 4;
+ return prefer_integrated ? 5 : 4;
case RenderingContextDriver::DEVICE_TYPE_DISCRETE_GPU:
- return 5;
+ return prefer_integrated ? 4 : 5;
case RenderingContextDriver::DEVICE_TYPE_VIRTUAL_GPU:
return 3;
case RenderingContextDriver::DEVICE_TYPE_CPU:
@@ -500,6 +501,8 @@ Error RenderingDevice::buffer_copy(RID p_src_buffer, RID p_dst_buffer, uint32_t
Error RenderingDevice::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data) {
_THREAD_SAFE_METHOD_
+ copy_bytes_count += p_size;
+
ERR_FAIL_COND_V_MSG(draw_list, ERR_INVALID_PARAMETER,
"Updating buffers is forbidden during creation of a draw list");
ERR_FAIL_COND_V_MSG(compute_list, ERR_INVALID_PARAMETER,
@@ -513,9 +516,23 @@ Error RenderingDevice::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p
ERR_FAIL_COND_V_MSG(p_offset + p_size > buffer->size, ERR_INVALID_PARAMETER,
"Attempted to write buffer (" + itos((p_offset + p_size) - buffer->size) + " bytes) past the end.");
+ gpu_copy_count++;
+
return _buffer_update(buffer, p_buffer, p_offset, (uint8_t *)p_data, p_size, true);
}
+String RenderingDevice::get_perf_report() const {
+ return perf_report_text;
+}
+
+void RenderingDevice::update_perf_report() {
+ perf_report_text = " gpu:" + String::num_int64(gpu_copy_count);
+ perf_report_text += " bytes:" + String::num_int64(copy_bytes_count);
+
+ gpu_copy_count = 0;
+ copy_bytes_count = 0;
+}
+
Error RenderingDevice::buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size) {
_THREAD_SAFE_METHOD_
@@ -1148,11 +1165,7 @@ Error RenderingDevice::_texture_update(RID p_texture, uint32_t p_layer, const Ve
ERR_FAIL_COND_V_MSG(p_validate_can_update && !(texture->usage_flags & TEXTURE_USAGE_CAN_UPDATE_BIT), ERR_INVALID_PARAMETER,
"Texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_UPDATE_BIT` to be set to be updatable.");
- uint32_t layer_count = texture->layers;
- if (texture->type == TEXTURE_TYPE_CUBE || texture->type == TEXTURE_TYPE_CUBE_ARRAY) {
- layer_count *= 6;
- }
- ERR_FAIL_COND_V(p_layer >= layer_count, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(p_layer >= texture->layers, ERR_INVALID_PARAMETER);
uint32_t width, height;
uint32_t tight_mip_size = get_image_format_required_size(texture->format, texture->width, texture->height, texture->depth, texture->mipmaps, &width, &height);
@@ -1584,11 +1597,7 @@ Vector<uint8_t> RenderingDevice::texture_get_data(RID p_texture, uint32_t p_laye
ERR_FAIL_COND_V_MSG(!(tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), Vector<uint8_t>(),
"Texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_FROM_BIT` to be set to be retrieved.");
- uint32_t layer_count = tex->layers;
- if (tex->type == TEXTURE_TYPE_CUBE || tex->type == TEXTURE_TYPE_CUBE_ARRAY) {
- layer_count *= 6;
- }
- ERR_FAIL_COND_V(p_layer >= layer_count, Vector<uint8_t>());
+ ERR_FAIL_COND_V(p_layer >= tex->layers, Vector<uint8_t>());
if ((tex->usage_flags & TEXTURE_USAGE_CPU_READ_BIT)) {
// Does not need anything fancy, map and read.
@@ -1606,7 +1615,7 @@ Vector<uint8_t> RenderingDevice::texture_get_data(RID p_texture, uint32_t p_laye
driver->texture_get_copyable_layout(tex->driver_id, subres, &mip_layouts[i]);
// Assuming layers are tightly packed. If this is not true on some driver, we must modify the copy algorithm.
- DEV_ASSERT(mip_layouts[i].layer_pitch == mip_layouts[i].size / layer_count);
+ DEV_ASSERT(mip_layouts[i].layer_pitch == mip_layouts[i].size / tex->layers);
work_buffer_size = STEPIFY(work_buffer_size, work_mip_alignment) + mip_layouts[i].size;
}
@@ -1617,9 +1626,6 @@ Vector<uint8_t> RenderingDevice::texture_get_data(RID p_texture, uint32_t p_laye
thread_local LocalVector<RDD::BufferTextureCopyRegion> command_buffer_texture_copy_regions_vector;
command_buffer_texture_copy_regions_vector.clear();
- uint32_t block_w = 0, block_h = 0;
- get_compressed_image_format_block_dimensions(tex->format, block_w, block_h);
-
uint32_t w = tex->width;
uint32_t h = tex->height;
uint32_t d = tex->depth;
@@ -1635,8 +1641,8 @@ Vector<uint8_t> RenderingDevice::texture_get_data(RID p_texture, uint32_t p_laye
copy_region.texture_region_size.z = d;
command_buffer_texture_copy_regions_vector.push_back(copy_region);
- w = MAX(block_w, w >> 1);
- h = MAX(block_h, h >> 1);
+ w = (w >> 1);
+ h = (h >> 1);
d = MAX(1u, d >> 1);
}
@@ -1653,6 +1659,10 @@ Vector<uint8_t> RenderingDevice::texture_get_data(RID p_texture, uint32_t p_laye
const uint8_t *read_ptr = driver->buffer_map(tmp_buffer);
ERR_FAIL_NULL_V(read_ptr, Vector<uint8_t>());
+ uint32_t block_w = 0;
+ uint32_t block_h = 0;
+ get_compressed_image_format_block_dimensions(tex->format, block_w, block_h);
+
Vector<uint8_t> buffer_data;
uint32_t tight_buffer_size = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, tex->mipmaps);
buffer_data.resize(tight_buffer_size);
@@ -1750,18 +1760,14 @@ Error RenderingDevice::texture_copy(RID p_from_texture, RID p_to_texture, const
ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), ERR_INVALID_PARAMETER,
"Source texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_FROM_BIT` to be set to be retrieved.");
- uint32_t src_layer_count = src_tex->layers;
uint32_t src_width, src_height, src_depth;
get_image_format_required_size(src_tex->format, src_tex->width, src_tex->height, src_tex->depth, p_src_mipmap + 1, &src_width, &src_height, &src_depth);
- if (src_tex->type == TEXTURE_TYPE_CUBE || src_tex->type == TEXTURE_TYPE_CUBE_ARRAY) {
- src_layer_count *= 6;
- }
ERR_FAIL_COND_V(p_from.x < 0 || p_from.x + p_size.x > src_width, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(p_from.y < 0 || p_from.y + p_size.y > src_height, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(p_from.z < 0 || p_from.z + p_size.z > src_depth, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(p_src_mipmap >= src_tex->mipmaps, ERR_INVALID_PARAMETER);
- ERR_FAIL_COND_V(p_src_layer >= src_layer_count, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(p_src_layer >= src_tex->layers, ERR_INVALID_PARAMETER);
Texture *dst_tex = texture_owner.get_or_null(p_to_texture);
ERR_FAIL_NULL_V(dst_tex, ERR_INVALID_PARAMETER);
@@ -1771,18 +1777,14 @@ Error RenderingDevice::texture_copy(RID p_from_texture, RID p_to_texture, const
ERR_FAIL_COND_V_MSG(!(dst_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER,
"Destination texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_TO_BIT` to be set to be retrieved.");
- uint32_t dst_layer_count = dst_tex->layers;
uint32_t dst_width, dst_height, dst_depth;
get_image_format_required_size(dst_tex->format, dst_tex->width, dst_tex->height, dst_tex->depth, p_dst_mipmap + 1, &dst_width, &dst_height, &dst_depth);
- if (dst_tex->type == TEXTURE_TYPE_CUBE || dst_tex->type == TEXTURE_TYPE_CUBE_ARRAY) {
- dst_layer_count *= 6;
- }
ERR_FAIL_COND_V(p_to.x < 0 || p_to.x + p_size.x > dst_width, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(p_to.y < 0 || p_to.y + p_size.y > dst_height, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(p_to.z < 0 || p_to.z + p_size.z > dst_depth, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(p_dst_mipmap >= dst_tex->mipmaps, ERR_INVALID_PARAMETER);
- ERR_FAIL_COND_V(p_dst_layer >= dst_layer_count, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(p_dst_layer >= dst_tex->layers, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V_MSG(src_tex->read_aspect_flags != dst_tex->read_aspect_flags, ERR_INVALID_PARAMETER,
"Source and destination texture must be of the same type (color or depth).");
@@ -1878,13 +1880,8 @@ Error RenderingDevice::texture_clear(RID p_texture, const Color &p_color, uint32
ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER,
"Source texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_TO_BIT` to be set to be cleared.");
- uint32_t src_layer_count = src_tex->layers;
- if (src_tex->type == TEXTURE_TYPE_CUBE || src_tex->type == TEXTURE_TYPE_CUBE_ARRAY) {
- src_layer_count *= 6;
- }
-
ERR_FAIL_COND_V(p_base_mipmap + p_mipmaps > src_tex->mipmaps, ERR_INVALID_PARAMETER);
- ERR_FAIL_COND_V(p_base_layer + p_layers > src_layer_count, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(p_base_layer + p_layers > src_tex->layers, ERR_INVALID_PARAMETER);
RDD::TextureSubresourceRange range;
range.aspect = src_tex->read_aspect_flags;
@@ -2846,6 +2843,7 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
for (int j = 0; j < (int)uniform_count; j++) {
if (uniforms[j].binding == set_uniform.binding) {
uniform_idx = j;
+ break;
}
}
ERR_FAIL_COND_V_MSG(uniform_idx == -1, RID(),
@@ -3086,7 +3084,7 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
ERR_FAIL_NULL_V_MSG(buffer, RID(), "Uniform buffer supplied (binding: " + itos(uniform.binding) + ") is invalid.");
ERR_FAIL_COND_V_MSG(buffer->size < (uint32_t)set_uniform.length, RID(),
- "Uniform buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " is smaller than size of shader uniform: (" + itos(set_uniform.length) + ").");
+ "Uniform buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + ") is smaller than size of shader uniform: (" + itos(set_uniform.length) + ").");
if (buffer->draw_tracker != nullptr) {
draw_trackers.push_back(buffer->draw_tracker);
@@ -3115,7 +3113,7 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
// If 0, then it's sized on link time.
ERR_FAIL_COND_V_MSG(set_uniform.length > 0 && buffer->size != (uint32_t)set_uniform.length, RID(),
- "Storage buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.length) + ").");
+ "Storage buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + ") does not match size of shader uniform: (" + itos(set_uniform.length) + ").");
if (set_uniform.writable && _buffer_make_mutable(buffer, buffer_id)) {
// The buffer must be mutable if it's used for writing.
@@ -3260,6 +3258,7 @@ RID RenderingDevice::render_pipeline_create(RID p_shader, FramebufferFormatID p_
for (int j = 0; j < vd.vertex_formats.size(); j++) {
if (vd.vertex_formats[j].location == i) {
found = true;
+ break;
}
}
@@ -3500,7 +3499,12 @@ Error RenderingDevice::screen_prepare_for_drawing(DisplayServer::WindowID p_scre
framebuffer = driver->swap_chain_acquire_framebuffer(main_queue, it->value, resize_required);
}
- ERR_FAIL_COND_V_MSG(framebuffer.id == 0, FAILED, "Unable to acquire framebuffer.");
+ if (framebuffer.id == 0) {
+ // Some drivers like NVIDIA are fast enough to invalidate the swap chain between resizing and acquisition (GH-94104).
+ // This typically occurs during continuous window resizing operations, especially if done quickly.
+ // Allow this to fail silently since it has no visual consequences.
+ return ERR_CANT_CREATE;
+ }
// Store the framebuffer that will be used next to draw to this screen.
screen_framebuffers[p_screen] = framebuffer;
@@ -3588,7 +3592,7 @@ RenderingDevice::DrawListID RenderingDevice::draw_list_begin_for_screen(DisplayS
clear_value.color = p_clear_color;
RDD::RenderPassID render_pass = driver->swap_chain_get_render_pass(sc_it->value);
- draw_graph.add_draw_list_begin(render_pass, fb_it->value, viewport, clear_value, true, false);
+ draw_graph.add_draw_list_begin(render_pass, fb_it->value, viewport, clear_value, true, false, RDD::BreadcrumbMarker::BLIT_PASS);
_draw_list_set_viewport(viewport);
_draw_list_set_scissor(viewport);
@@ -3637,7 +3641,7 @@ Error RenderingDevice::_draw_list_setup_framebuffer(Framebuffer *p_framebuffer,
return OK;
}
-Error RenderingDevice::_draw_list_render_pass_begin(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i p_viewport_offset, Point2i p_viewport_size, RDD::FramebufferID p_framebuffer_driver_id, RDD::RenderPassID p_render_pass) {
+Error RenderingDevice::_draw_list_render_pass_begin(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i p_viewport_offset, Point2i p_viewport_size, RDD::FramebufferID p_framebuffer_driver_id, RDD::RenderPassID p_render_pass, uint32_t p_breadcrumb) {
thread_local LocalVector<RDD::RenderPassClearValue> clear_values;
thread_local LocalVector<RDG::ResourceTracker *> resource_trackers;
thread_local LocalVector<RDG::ResourceUsage> resource_usages;
@@ -3685,7 +3689,7 @@ Error RenderingDevice::_draw_list_render_pass_begin(Framebuffer *p_framebuffer,
}
}
- draw_graph.add_draw_list_begin(p_render_pass, p_framebuffer_driver_id, Rect2i(p_viewport_offset, p_viewport_size), clear_values, uses_color, uses_depth);
+ draw_graph.add_draw_list_begin(p_render_pass, p_framebuffer_driver_id, Rect2i(p_viewport_offset, p_viewport_size), clear_values, uses_color, uses_depth, p_breadcrumb);
draw_graph.add_draw_list_usages(resource_trackers, resource_usages);
// Mark textures as bound.
@@ -3747,7 +3751,7 @@ void RenderingDevice::_draw_list_insert_clear_region(DrawList *p_draw_list, Fram
draw_graph.add_draw_list_clear_attachments(clear_attachments, rect);
}
-RenderingDevice::DrawListID RenderingDevice::draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region) {
+RenderingDevice::DrawListID RenderingDevice::draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, uint32_t p_breadcrumb) {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_V_MSG(draw_list != nullptr, INVALID_ID, "Only one draw list can be active at the same time.");
@@ -3793,7 +3797,7 @@ RenderingDevice::DrawListID RenderingDevice::draw_list_begin(RID p_framebuffer,
Error err = _draw_list_setup_framebuffer(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, &fb_driver_id, &render_pass, &draw_list_subpass_count);
ERR_FAIL_COND_V(err != OK, INVALID_ID);
- err = _draw_list_render_pass_begin(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, viewport_offset, viewport_size, fb_driver_id, render_pass);
+ err = _draw_list_render_pass_begin(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, viewport_offset, viewport_size, fb_driver_id, render_pass, p_breadcrumb);
if (err != OK) {
return INVALID_ID;
@@ -5080,13 +5084,19 @@ void RenderingDevice::swap_buffers() {
void RenderingDevice::submit() {
_THREAD_SAFE_METHOD_
+ ERR_FAIL_COND_MSG(is_main_instance, "Only local devices can submit and sync.");
+ ERR_FAIL_COND_MSG(local_device_processing, "device already submitted, call sync to wait until done.");
_end_frame();
_execute_frame(false);
+ local_device_processing = true;
}
void RenderingDevice::sync() {
_THREAD_SAFE_METHOD_
+ ERR_FAIL_COND_MSG(is_main_instance, "Only local devices can submit and sync.");
+ ERR_FAIL_COND_MSG(!local_device_processing, "sync can only be called after a submit");
_begin_frame();
+ local_device_processing = false;
}
void RenderingDevice::_free_pending_resources(int p_frame) {
@@ -5202,6 +5212,8 @@ void RenderingDevice::_begin_frame() {
frames[frame].draw_fence_signaled = false;
}
+ update_perf_report();
+
// Begin recording on the frame's command buffers.
driver->begin_segment(frame, frames_drawn++);
driver->command_buffer_begin(frames[frame].setup_command_buffer);
@@ -5338,7 +5350,7 @@ Error RenderingDevice::initialize(RenderingContextDriver *p_context, DisplayServ
Error err;
RenderingContextDriver::SurfaceID main_surface = 0;
- const bool main_instance = (singleton == this) && (p_main_window != DisplayServer::INVALID_WINDOW_ID);
+ is_main_instance = (singleton == this) && (p_main_window != DisplayServer::INVALID_WINDOW_ID);
if (p_main_window != DisplayServer::INVALID_WINDOW_ID) {
// Retrieve the surface from the main window if it was specified.
main_surface = p_context->surface_get_from_window(p_main_window);
@@ -5380,13 +5392,13 @@ Error RenderingDevice::initialize(RenderingContextDriver *p_context, DisplayServ
frame = 0;
frames.resize(frame_count);
- max_timestamp_query_elements = 256;
+ max_timestamp_query_elements = GLOBAL_GET("debug/settings/profiler/max_timestamp_query_elements");
device = context->device_get(device_index);
err = driver->initialize(device_index, frame_count);
ERR_FAIL_COND_V_MSG(err != OK, FAILED, "Failed to initialize driver for device.");
- if (main_instance) {
+ if (is_main_instance) {
// Only the singleton instance with a display should print this information.
String rendering_method;
if (OS::get_singleton()->get_current_rendering_method() == "mobile") {
@@ -5507,14 +5519,14 @@ Error RenderingDevice::initialize(RenderingContextDriver *p_context, DisplayServ
for (uint32_t i = 0; i < frames.size(); i++) {
// Staging was never used, create a block.
err = _insert_staging_block();
- ERR_CONTINUE(err != OK);
+ ERR_FAIL_COND_V(err, FAILED);
}
draw_list = nullptr;
compute_list = nullptr;
bool project_pipeline_cache_enable = GLOBAL_GET("rendering/rendering_device/pipeline_cache/enable");
- if (main_instance && project_pipeline_cache_enable) {
+ if (is_main_instance && project_pipeline_cache_enable) {
// Only the instance that is not a local device and is also the singleton is allowed to manage a pipeline cache.
pipeline_cache_file_path = vformat("user://vulkan/pipelines.%s.%s",
OS::get_singleton()->get_current_rendering_method(),
@@ -5631,7 +5643,7 @@ void RenderingDevice::_free_rids(T &p_owner, const char *p_type) {
void RenderingDevice::capture_timestamp(const String &p_name) {
ERR_FAIL_COND_MSG(draw_list != nullptr && draw_list->state.draw_count > 0, "Capturing timestamps during draw list creation is not allowed. Offending timestamp was: " + p_name);
ERR_FAIL_COND_MSG(compute_list != nullptr && compute_list->state.dispatch_count > 0, "Capturing timestamps during compute list creation is not allowed. Offending timestamp was: " + p_name);
- ERR_FAIL_COND(frames[frame].timestamp_count >= max_timestamp_query_elements);
+ ERR_FAIL_COND_MSG(frames[frame].timestamp_count >= max_timestamp_query_elements, vformat("Tried capturing more timestamps than the configured maximum (%d). You can increase this limit in the project settings under 'Debug/Settings' called 'Max Timestamp Query Elements'.", max_timestamp_query_elements));
draw_graph.add_capture_timestamp(frames[frame].timestamp_pool, frames[frame].timestamp_count);
@@ -5712,6 +5724,50 @@ uint64_t RenderingDevice::get_driver_resource(DriverResource p_resource, RID p_r
return driver->get_resource_native_handle(p_resource, driver_id);
}
+String RenderingDevice::get_driver_and_device_memory_report() const {
+ return context->get_driver_and_device_memory_report();
+}
+
+String RenderingDevice::get_tracked_object_name(uint32_t p_type_index) const {
+ return context->get_tracked_object_name(p_type_index);
+}
+
+uint64_t RenderingDevice::get_tracked_object_type_count() const {
+ return context->get_tracked_object_type_count();
+}
+
+uint64_t RenderingDevice::get_driver_total_memory() const {
+ return context->get_driver_total_memory();
+}
+
+uint64_t RenderingDevice::get_driver_allocation_count() const {
+ return context->get_driver_allocation_count();
+}
+
+uint64_t RenderingDevice::get_driver_memory_by_object_type(uint32_t p_type) const {
+ return context->get_driver_memory_by_object_type(p_type);
+}
+
+uint64_t RenderingDevice::get_driver_allocs_by_object_type(uint32_t p_type) const {
+ return context->get_driver_allocs_by_object_type(p_type);
+}
+
+uint64_t RenderingDevice::get_device_total_memory() const {
+ return context->get_device_total_memory();
+}
+
+uint64_t RenderingDevice::get_device_allocation_count() const {
+ return context->get_device_allocation_count();
+}
+
+uint64_t RenderingDevice::get_device_memory_by_object_type(uint32_t type) const {
+ return context->get_device_memory_by_object_type(type);
+}
+
+uint64_t RenderingDevice::get_device_allocs_by_object_type(uint32_t type) const {
+ return context->get_device_allocs_by_object_type(type);
+}
+
uint32_t RenderingDevice::get_captured_timestamps_count() const {
return frames[frame].timestamp_result_count;
}
@@ -5954,7 +6010,7 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_list_begin_for_screen", "screen", "clear_color"), &RenderingDevice::draw_list_begin_for_screen, DEFVAL(DisplayServer::MAIN_WINDOW_ID), DEFVAL(Color()));
- ClassDB::bind_method(D_METHOD("draw_list_begin", "framebuffer", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region"), &RenderingDevice::draw_list_begin, DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()));
+ ClassDB::bind_method(D_METHOD("draw_list_begin", "framebuffer", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "breadcrumb"), &RenderingDevice::draw_list_begin, DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()), DEFVAL(0));
#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("draw_list_begin_split", "framebuffer", "splits", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "storage_textures"), &RenderingDevice::_draw_list_begin_split, DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()), DEFVAL(TypedArray<RID>()));
#endif
@@ -6024,6 +6080,20 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_driver_resource", "resource", "rid", "index"), &RenderingDevice::get_driver_resource);
+ ClassDB::bind_method(D_METHOD("get_perf_report"), &RenderingDevice::get_perf_report);
+
+ ClassDB::bind_method(D_METHOD("get_driver_and_device_memory_report"), &RenderingDevice::get_driver_and_device_memory_report);
+ ClassDB::bind_method(D_METHOD("get_tracked_object_name", "type_index"), &RenderingDevice::get_tracked_object_name);
+ ClassDB::bind_method(D_METHOD("get_tracked_object_type_count"), &RenderingDevice::get_tracked_object_type_count);
+ ClassDB::bind_method(D_METHOD("get_driver_total_memory"), &RenderingDevice::get_driver_total_memory);
+ ClassDB::bind_method(D_METHOD("get_driver_allocation_count"), &RenderingDevice::get_driver_allocation_count);
+ ClassDB::bind_method(D_METHOD("get_driver_memory_by_object_type", "type"), &RenderingDevice::get_driver_memory_by_object_type);
+ ClassDB::bind_method(D_METHOD("get_driver_allocs_by_object_type", "type"), &RenderingDevice::get_driver_allocs_by_object_type);
+ ClassDB::bind_method(D_METHOD("get_device_total_memory"), &RenderingDevice::get_device_total_memory);
+ ClassDB::bind_method(D_METHOD("get_device_allocation_count"), &RenderingDevice::get_device_allocation_count);
+ ClassDB::bind_method(D_METHOD("get_device_memory_by_object_type", "type"), &RenderingDevice::get_device_memory_by_object_type);
+ ClassDB::bind_method(D_METHOD("get_device_allocs_by_object_type", "type"), &RenderingDevice::get_device_allocs_by_object_type);
+
BIND_ENUM_CONSTANT(DEVICE_TYPE_OTHER);
BIND_ENUM_CONSTANT(DEVICE_TYPE_INTEGRATED_GPU);
BIND_ENUM_CONSTANT(DEVICE_TYPE_DISCRETE_GPU);
@@ -6546,6 +6616,20 @@ void RenderingDevice::_bind_methods() {
BIND_CONSTANT(INVALID_ID);
BIND_CONSTANT(INVALID_FORMAT_ID);
+
+ BIND_ENUM_CONSTANT(NONE);
+ BIND_ENUM_CONSTANT(REFLECTION_PROBES);
+ BIND_ENUM_CONSTANT(SKY_PASS);
+ BIND_ENUM_CONSTANT(LIGHTMAPPER_PASS);
+ BIND_ENUM_CONSTANT(SHADOW_PASS_DIRECTIONAL);
+ BIND_ENUM_CONSTANT(SHADOW_PASS_CUBE);
+ BIND_ENUM_CONSTANT(OPAQUE_PASS);
+ BIND_ENUM_CONSTANT(ALPHA_PASS);
+ BIND_ENUM_CONSTANT(TRANSPARENT_PASS);
+ BIND_ENUM_CONSTANT(POST_PROCESSING_PASS);
+ BIND_ENUM_CONSTANT(BLIT_PASS);
+ BIND_ENUM_CONSTANT(UI_PASS);
+ BIND_ENUM_CONSTANT(DEBUG_PASS);
}
RenderingDevice::~RenderingDevice() {
diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h
index 38ffd5d23d..1405f585b2 100644
--- a/servers/rendering/rendering_device.h
+++ b/servers/rendering/rendering_device.h
@@ -88,6 +88,9 @@ private:
RenderingDeviceDriver *driver = nullptr;
RenderingContextDriver::Device device;
+ bool local_device_processing = false;
+ bool is_main_instance = false;
+
protected:
static void _bind_methods();
@@ -180,6 +183,12 @@ private:
Buffer *_get_buffer_from_owner(RID p_buffer);
Error _buffer_update(Buffer *p_buffer, RID p_buffer_id, size_t p_offset, const uint8_t *p_data, size_t p_data_size, bool p_use_draw_queue = false, uint32_t p_required_align = 32);
+ void update_perf_report();
+
+ uint32_t gpu_copy_count = 0;
+ uint32_t copy_bytes_count = 0;
+ String perf_report_text;
+
RID_Owner<Buffer> uniform_buffer_owner;
RID_Owner<Buffer> storage_buffer_owner;
RID_Owner<Buffer> texture_buffer_owner;
@@ -368,7 +377,9 @@ public:
// used for the render pipelines.
struct AttachmentFormat {
- enum { UNUSED_ATTACHMENT = 0xFFFFFFFF };
+ enum : uint32_t {
+ UNUSED_ATTACHMENT = 0xFFFFFFFF
+ };
DataFormat format;
TextureSamples samples;
uint32_t usage_flags;
@@ -812,6 +823,7 @@ private:
void _draw_list_end_bind_compat_81356(BitField<BarrierMask> p_post_barrier);
void _compute_list_end_bind_compat_81356(BitField<BarrierMask> p_post_barrier);
void _barrier_bind_compat_81356(BitField<BarrierMask> p_from, BitField<BarrierMask> p_to);
+
void _draw_list_end_bind_compat_84976(BitField<BarrierMask> p_post_barrier);
void _compute_list_end_bind_compat_84976(BitField<BarrierMask> p_post_barrier);
InitialAction _convert_initial_action_84976(InitialAction p_old_initial_action);
@@ -824,7 +836,10 @@ private:
Error _texture_copy_bind_compat_84976(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, BitField<BarrierMask> p_post_barrier);
Error _texture_clear_bind_compat_84976(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, BitField<BarrierMask> p_post_barrier);
Error _texture_resolve_multisample_bind_compat_84976(RID p_from_texture, RID p_to_texture, BitField<BarrierMask> p_post_barrier);
+
FramebufferFormatID _screen_get_framebuffer_format_bind_compat_87340() const;
+
+ DrawListID _draw_list_begin_bind_compat_90993(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2());
#endif
public:
@@ -853,6 +868,7 @@ public:
/******************/
/**** UNIFORMS ****/
/******************/
+ String get_perf_report() const;
enum StorageBufferUsage {
STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT = 1,
@@ -1136,7 +1152,7 @@ private:
void _draw_list_insert_clear_region(DrawList *p_draw_list, Framebuffer *p_framebuffer, Point2i p_viewport_offset, Point2i p_viewport_size, bool p_clear_color, const Vector<Color> &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil);
Error _draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, RDD::FramebufferID *r_framebuffer, RDD::RenderPassID *r_render_pass, uint32_t *r_subpass_count);
- Error _draw_list_render_pass_begin(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i p_viewport_offset, Point2i p_viewport_size, RDD::FramebufferID p_framebuffer_driver_id, RDD::RenderPassID p_render_pass);
+ Error _draw_list_render_pass_begin(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i p_viewport_offset, Point2i p_viewport_size, RDD::FramebufferID p_framebuffer_driver_id, RDD::RenderPassID p_render_pass, uint32_t p_breadcrumb);
void _draw_list_set_viewport(Rect2i p_rect);
void _draw_list_set_scissor(Rect2i p_rect);
_FORCE_INLINE_ DrawList *_get_draw_list_ptr(DrawListID p_id);
@@ -1145,7 +1161,7 @@ private:
public:
DrawListID draw_list_begin_for_screen(DisplayServer::WindowID p_screen = 0, const Color &p_clear_color = Color());
- DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2());
+ DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), uint32_t p_breadcrumb = 0);
void draw_list_set_blend_constants(DrawListID p_list, const Color &p_color);
void draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline);
@@ -1403,6 +1419,21 @@ public:
uint64_t get_driver_resource(DriverResource p_resource, RID p_rid = RID(), uint64_t p_index = 0);
+ String get_driver_and_device_memory_report() const;
+
+ String get_tracked_object_name(uint32_t p_type_index) const;
+ uint64_t get_tracked_object_type_count() const;
+
+ uint64_t get_driver_total_memory() const;
+ uint64_t get_driver_allocation_count() const;
+ uint64_t get_driver_memory_by_object_type(uint32_t p_type) const;
+ uint64_t get_driver_allocs_by_object_type(uint32_t p_type) const;
+
+ uint64_t get_device_total_memory() const;
+ uint64_t get_device_allocation_count() const;
+ uint64_t get_device_memory_by_object_type(uint32_t p_type) const;
+ uint64_t get_device_allocs_by_object_type(uint32_t p_type) const;
+
static RenderingDevice *get_singleton();
RenderingDevice();
@@ -1475,6 +1506,7 @@ VARIANT_ENUM_CAST(RenderingDevice::FinalAction)
VARIANT_ENUM_CAST(RenderingDevice::Limit)
VARIANT_ENUM_CAST(RenderingDevice::MemoryType)
VARIANT_ENUM_CAST(RenderingDevice::Features)
+VARIANT_ENUM_CAST(RenderingDevice::BreadcrumbMarker)
#ifndef DISABLE_DEPRECATED
VARIANT_BITFIELD_CAST(RenderingDevice::BarrierMask);
diff --git a/servers/rendering/rendering_device_binds.cpp b/servers/rendering/rendering_device_binds.cpp
index 3678b70254..d9ca286b15 100644
--- a/servers/rendering/rendering_device_binds.cpp
+++ b/servers/rendering/rendering_device_binds.cpp
@@ -112,7 +112,7 @@ Error RDShaderFile::parse_versions_from_text(const String &p_text, const String
}
Vector<String> slices = l.get_slice(";", 0).split("=");
String version = slices[0].strip_edges();
- if (!version.is_valid_identifier()) {
+ if (!version.is_valid_ascii_identifier()) {
base_error = "Version names must be valid identifiers, found '" + version + "' instead.";
break;
}
@@ -157,9 +157,6 @@ Error RDShaderFile::parse_versions_from_text(const String &p_text, const String
}
}
- Ref<RDShaderFile> shader_file;
- shader_file.instantiate();
-
if (base_error.is_empty()) {
if (stage_found[RD::SHADER_STAGE_COMPUTE] && stages_found > 1) {
ERR_FAIL_V_MSG(ERR_PARSE_ERROR, "When writing compute shaders, [compute] mustbe the only stage present.");
diff --git a/servers/rendering/rendering_device_commons.h b/servers/rendering/rendering_device_commons.h
index 918bf9b834..8c3996bd80 100644
--- a/servers/rendering/rendering_device_commons.h
+++ b/servers/rendering/rendering_device_commons.h
@@ -271,6 +271,44 @@ public:
DATA_FORMAT_MAX,
};
+ // Breadcrumb markers are useful for debugging GPU crashes (i.e. DEVICE_LOST). Internally
+ // they're just an uint32_t to "tag" a GPU command. These are only used for debugging and do not
+ // (or at least shouldn't) alter the execution behavior in any way.
+ //
+ // When a GPU crashes and Godot was built in dev or debug mode; Godot will dump what commands
+ // were being executed and what tag they were marked with.
+ // This makes narrowing down the cause of a crash easier. Note that a GPU can be executing
+ // multiple commands at the same time. It is also useful to identify data hazards.
+ //
+ // For example if each LIGHTMAPPER_PASS must be executed in sequential order, but dumps
+ // indicated that pass (LIGHTMAPPER_PASS | 5) was being executed at the same time as
+ // (LIGHTMAPPER_PASS | 4), that would indicate there is a missing barrier or a render graph bug.
+ //
+ // The enums are bitshifted by 16 bits so it's possible to add user data via bitwise operations.
+ // Using this enum is not mandatory; but it is recommended so that all subsystems agree what each
+ // ID means when dumping info.
+ enum BreadcrumbMarker {
+ NONE = 0,
+ // Environment
+ REFLECTION_PROBES = 1u << 16u,
+ SKY_PASS = 2u << 16u,
+ // Light mapping
+ LIGHTMAPPER_PASS = 3u << 16u,
+ // Shadows
+ SHADOW_PASS_DIRECTIONAL = 4u << 16u,
+ SHADOW_PASS_CUBE = 5u << 16u,
+ // Geometry passes
+ OPAQUE_PASS = 6u << 16u,
+ ALPHA_PASS = 7u << 16u,
+ TRANSPARENT_PASS = 8u << 16u,
+ // Screen effects
+ POST_PROCESSING_PASS = 9u << 16u,
+ BLIT_PASS = 10u << 16u,
+ UI_PASS = 11u << 16u,
+ // Other
+ DEBUG_PASS = 12u << 16u,
+ };
+
enum CompareOperator {
COMPARE_OP_NEVER,
COMPARE_OP_LESS,
diff --git a/servers/rendering/rendering_device_driver.h b/servers/rendering/rendering_device_driver.h
index 0b5fc51a1d..97c84c9d05 100644
--- a/servers/rendering/rendering_device_driver.h
+++ b/servers/rendering/rendering_device_driver.h
@@ -476,6 +476,7 @@ public:
// Only meaningful if API_TRAIT_SHADER_CHANGE_INVALIDATION is SHADER_CHANGE_INVALIDATION_ALL_OR_NONE_ACCORDING_TO_LAYOUT_HASH.
virtual uint32_t shader_get_layout_hash(ShaderID p_shader) { return 0; }
virtual void shader_free(ShaderID p_shader) = 0;
+ virtual void shader_destroy_modules(ShaderID p_shader) = 0;
protected:
// An optional service to implementations.
@@ -709,6 +710,11 @@ public:
virtual void command_begin_label(CommandBufferID p_cmd_buffer, const char *p_label_name, const Color &p_color) = 0;
virtual void command_end_label(CommandBufferID p_cmd_buffer) = 0;
+ /****************/
+ /**** DEBUG *****/
+ /****************/
+ virtual void command_insert_breadcrumb(CommandBufferID p_cmd_buffer, uint32_t p_data) = 0;
+
/********************/
/**** SUBMISSION ****/
/********************/
@@ -759,6 +765,7 @@ public:
DEVICE_OPENGL,
DEVICE_VULKAN,
DEVICE_DIRECTX,
+ DEVICE_METAL,
};
struct Capabilities {
diff --git a/servers/rendering/rendering_device_graph.cpp b/servers/rendering/rendering_device_graph.cpp
index 221ec72e4a..abcb76cd43 100644
--- a/servers/rendering/rendering_device_graph.cpp
+++ b/servers/rendering/rendering_device_graph.cpp
@@ -823,6 +823,9 @@ void RenderingDeviceGraph::_run_render_commands(int32_t p_level, const RecordedC
const RecordedDrawListCommand *draw_list_command = reinterpret_cast<const RecordedDrawListCommand *>(command);
const VectorView clear_values(draw_list_command->clear_values(), draw_list_command->clear_values_count);
+#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
+ driver->command_insert_breadcrumb(r_command_buffer, draw_list_command->breadcrumb);
+#endif
driver->command_begin_render_pass(r_command_buffer, draw_list_command->render_pass, draw_list_command->framebuffer, draw_list_command->command_buffer_type, draw_list_command->region, clear_values);
_run_draw_list_command(r_command_buffer, draw_list_command->instruction_data(), draw_list_command->instruction_data_size);
driver->command_end_render_pass(r_command_buffer);
@@ -1399,8 +1402,9 @@ void RenderingDeviceGraph::add_buffer_update(RDD::BufferID p_dst, ResourceTracke
_add_command_to_graph(&p_dst_tracker, &buffer_usage, 1, command_index, command);
}
-void RenderingDeviceGraph::add_compute_list_begin() {
+void RenderingDeviceGraph::add_compute_list_begin(RDD::BreadcrumbMarker p_phase, uint32_t p_breadcrumb_data) {
compute_instruction_list.clear();
+ compute_instruction_list.breadcrumb = p_breadcrumb_data | (p_phase & ((1 << 16) - 1));
compute_instruction_list.index++;
}
@@ -1490,12 +1494,13 @@ void RenderingDeviceGraph::add_compute_list_end() {
_add_command_to_graph(compute_instruction_list.command_trackers.ptr(), compute_instruction_list.command_tracker_usages.ptr(), compute_instruction_list.command_trackers.size(), command_index, command);
}
-void RenderingDeviceGraph::add_draw_list_begin(RDD::RenderPassID p_render_pass, RDD::FramebufferID p_framebuffer, Rect2i p_region, VectorView<RDD::RenderPassClearValue> p_clear_values, bool p_uses_color, bool p_uses_depth) {
+void RenderingDeviceGraph::add_draw_list_begin(RDD::RenderPassID p_render_pass, RDD::FramebufferID p_framebuffer, Rect2i p_region, VectorView<RDD::RenderPassClearValue> p_clear_values, bool p_uses_color, bool p_uses_depth, uint32_t p_breadcrumb) {
draw_instruction_list.clear();
draw_instruction_list.index++;
draw_instruction_list.render_pass = p_render_pass;
draw_instruction_list.framebuffer = p_framebuffer;
draw_instruction_list.region = p_region;
+ draw_instruction_list.breadcrumb = p_breadcrumb;
draw_instruction_list.clear_values.resize(p_clear_values.size());
for (uint32_t i = 0; i < p_clear_values.size(); i++) {
draw_instruction_list.clear_values[i] = p_clear_values[i];
@@ -1706,6 +1711,7 @@ void RenderingDeviceGraph::add_draw_list_end() {
command->framebuffer = draw_instruction_list.framebuffer;
command->command_buffer_type = command_buffer_type;
command->region = draw_instruction_list.region;
+ command->breadcrumb = draw_instruction_list.breadcrumb;
command->clear_values_count = draw_instruction_list.clear_values.size();
RDD::RenderPassClearValue *clear_values = command->clear_values();
@@ -1964,6 +1970,7 @@ void RenderingDeviceGraph::end(bool p_reorder_commands, bool p_full_barriers, RD
2, // TYPE_TEXTURE_GET_DATA
2, // TYPE_TEXTURE_RESOLVE
2, // TYPE_TEXTURE_UPDATE
+ 2, // TYPE_INSERT_BREADCRUMB
};
commands_sorted.clear();
diff --git a/servers/rendering/rendering_device_graph.h b/servers/rendering/rendering_device_graph.h
index baa15f63f6..e13e3a0429 100644
--- a/servers/rendering/rendering_device_graph.h
+++ b/servers/rendering/rendering_device_graph.h
@@ -218,13 +218,14 @@ private:
};
struct ComputeInstructionList : InstructionList {
- // No extra contents.
+ uint32_t breadcrumb;
};
struct DrawInstructionList : InstructionList {
RDD::RenderPassID render_pass;
RDD::FramebufferID framebuffer;
Rect2i region;
+ uint32_t breadcrumb;
LocalVector<RDD::RenderPassClearValue> clear_values;
};
@@ -296,6 +297,7 @@ private:
struct RecordedComputeListCommand : RecordedCommand {
uint32_t instruction_data_size = 0;
+ uint32_t breadcrumb = 0;
_FORCE_INLINE_ uint8_t *instruction_data() {
return reinterpret_cast<uint8_t *>(&this[1]);
@@ -312,6 +314,7 @@ private:
RDD::FramebufferID framebuffer;
RDD::CommandBufferType command_buffer_type;
Rect2i region;
+ uint32_t breadcrumb = 0;
uint32_t clear_values_count = 0;
_FORCE_INLINE_ RDD::RenderPassClearValue *clear_values() {
@@ -654,7 +657,7 @@ public:
void add_buffer_copy(RDD::BufferID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, ResourceTracker *p_dst_tracker, RDD::BufferCopyRegion p_region);
void add_buffer_get_data(RDD::BufferID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, RDD::BufferCopyRegion p_region);
void add_buffer_update(RDD::BufferID p_dst, ResourceTracker *p_dst_tracker, VectorView<RecordedBufferCopy> p_buffer_copies);
- void add_compute_list_begin();
+ void add_compute_list_begin(RDD::BreadcrumbMarker p_phase = RDD::BreadcrumbMarker::NONE, uint32_t p_breadcrumb_data = 0);
void add_compute_list_bind_pipeline(RDD::PipelineID p_pipeline);
void add_compute_list_bind_uniform_set(RDD::ShaderID p_shader, RDD::UniformSetID p_uniform_set, uint32_t set_index);
void add_compute_list_dispatch(uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups);
@@ -664,7 +667,7 @@ public:
void add_compute_list_usage(ResourceTracker *p_tracker, ResourceUsage p_usage);
void add_compute_list_usages(VectorView<ResourceTracker *> p_trackers, VectorView<ResourceUsage> p_usages);
void add_compute_list_end();
- void add_draw_list_begin(RDD::RenderPassID p_render_pass, RDD::FramebufferID p_framebuffer, Rect2i p_region, VectorView<RDD::RenderPassClearValue> p_clear_values, bool p_uses_color, bool p_uses_depth);
+ void add_draw_list_begin(RDD::RenderPassID p_render_pass, RDD::FramebufferID p_framebuffer, Rect2i p_region, VectorView<RDD::RenderPassClearValue> p_clear_values, bool p_uses_color, bool p_uses_depth, uint32_t p_breadcrumb = 0);
void add_draw_list_bind_index_buffer(RDD::BufferID p_buffer, RDD::IndexBufferFormat p_format, uint32_t p_offset);
void add_draw_list_bind_pipeline(RDD::PipelineID p_pipeline, BitField<RDD::PipelineStageBits> p_pipeline_stage_bits);
void add_draw_list_bind_uniform_set(RDD::ShaderID p_shader, RDD::UniformSetID p_uniform_set, uint32_t set_index);
diff --git a/servers/rendering/rendering_method.h b/servers/rendering/rendering_method.h
index aa5e7d83cc..f6212faf08 100644
--- a/servers/rendering/rendering_method.h
+++ b/servers/rendering/rendering_method.h
@@ -83,6 +83,8 @@ public:
virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask) = 0;
virtual void instance_set_pivot_data(RID p_instance, float p_sorting_offset, bool p_use_aabb_center) = 0;
virtual void instance_set_transform(RID p_instance, const Transform3D &p_transform) = 0;
+ virtual void instance_set_interpolated(RID p_instance, bool p_interpolated) = 0;
+ virtual void instance_reset_physics_interpolation(RID p_instance) = 0;
virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id) = 0;
virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight) = 0;
virtual void instance_set_surface_override_material(RID p_instance, int p_surface, RID p_material) = 0;
@@ -347,9 +349,20 @@ public:
virtual void decals_set_filter(RS::DecalFilter p_filter) = 0;
virtual void light_projectors_set_filter(RS::LightProjectorFilter p_filter) = 0;
+ virtual void lightmaps_set_bicubic_filter(bool p_enable) = 0;
virtual bool free(RID p_rid) = 0;
+ /* Physics interpolation */
+
+ virtual void update_interpolation_tick(bool p_process = true) = 0;
+ virtual void set_physics_interpolation_enabled(bool p_enabled) = 0;
+
+ /* Event queueing */
+
+ virtual void tick() = 0;
+ virtual void pre_draw(bool p_will_draw) = 0;
+
RenderingMethod();
virtual ~RenderingMethod();
};
diff --git a/servers/rendering/rendering_server_constants.h b/servers/rendering/rendering_server_constants.h
new file mode 100644
index 0000000000..6d27a3a022
--- /dev/null
+++ b/servers/rendering/rendering_server_constants.h
@@ -0,0 +1,48 @@
+/**************************************************************************/
+/* rendering_server_constants.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 RENDERING_SERVER_CONSTANTS_H
+#define RENDERING_SERVER_CONSTANTS_H
+
+// Use for constants etc. that need not be included as often as rendering_server.h
+// to reduce dependencies and prevent slow compilation.
+
+// This is a "cheap" include, and can be used from scene side code as well as servers.
+
+// N.B. ONLY allow these defined in DEV_ENABLED builds, they will slow
+// performance, and are only necessary to use for debugging.
+#ifdef DEV_ENABLED
+
+// Uncomment this define to produce debugging output for physics interpolation.
+//#define RENDERING_SERVER_DEBUG_PHYSICS_INTERPOLATION
+
+#endif // DEV_ENABLED
+
+#endif // RENDERING_SERVER_CONSTANTS_H
diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp
index 51ff009eaf..86efccef9a 100644
--- a/servers/rendering/rendering_server_default.cpp
+++ b/servers/rendering/rendering_server_default.cpp
@@ -381,12 +381,9 @@ void RenderingServerDefault::_thread_loop() {
/* INTERPOLATION */
-void RenderingServerDefault::tick() {
- RSG::canvas->tick();
-}
-
void RenderingServerDefault::set_physics_interpolation_enabled(bool p_enabled) {
RSG::canvas->set_physics_interpolation_enabled(p_enabled);
+ RSG::scene->set_physics_interpolation_enabled(p_enabled);
}
/* EVENT QUEUING */
@@ -411,6 +408,15 @@ void RenderingServerDefault::draw(bool p_swap_buffers, double frame_step) {
}
}
+void RenderingServerDefault::tick() {
+ RSG::canvas->tick();
+ RSG::scene->tick();
+}
+
+void RenderingServerDefault::pre_draw(bool p_will_draw) {
+ RSG::scene->pre_draw(p_will_draw);
+}
+
void RenderingServerDefault::_call_on_render_thread(const Callable &p_callable) {
p_callable.call();
}
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index 164ec3cc09..60fa546e16 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -344,6 +344,11 @@ public:
FUNC2(multimesh_set_buffer, RID, const Vector<float> &)
FUNC1RC(Vector<float>, multimesh_get_buffer, RID)
+ FUNC3(multimesh_set_buffer_interpolated, RID, const Vector<float> &, const Vector<float> &)
+ FUNC2(multimesh_set_physics_interpolated, RID, bool)
+ FUNC2(multimesh_set_physics_interpolation_quality, RID, MultimeshPhysicsInterpolationQuality)
+ FUNC2(multimesh_instance_reset_physics_interpolation, RID, int)
+
FUNC2(multimesh_set_visible_instances, RID, int)
FUNC1RC(int, multimesh_get_visible_instances, RID)
@@ -639,6 +644,7 @@ public:
FUNC3(viewport_set_canvas_transform, RID, RID, const Transform2D &)
FUNC2(viewport_set_transparent_background, RID, bool)
FUNC2(viewport_set_use_hdr_2d, RID, bool)
+ FUNC1RC(bool, viewport_is_using_hdr_2d, RID)
FUNC2(viewport_set_snap_2d_transforms_to_pixel, RID, bool)
FUNC2(viewport_set_snap_2d_vertices_to_pixel, RID, bool)
@@ -761,6 +767,7 @@ public:
FUNC1(directional_soft_shadow_filter_set_quality, ShadowQuality);
FUNC1(decals_set_filter, RS::DecalFilter);
FUNC1(light_projectors_set_filter, RS::LightProjectorFilter);
+ FUNC1(lightmaps_set_bicubic_filter, bool);
/* CAMERA ATTRIBUTES */
@@ -802,6 +809,8 @@ public:
FUNC2(instance_set_layer_mask, RID, uint32_t)
FUNC3(instance_set_pivot_data, RID, float, bool)
FUNC2(instance_set_transform, RID, const Transform3D &)
+ FUNC2(instance_set_interpolated, RID, bool)
+ FUNC1(instance_reset_physics_interpolation, RID)
FUNC2(instance_attach_object_instance_id, RID, ObjectID)
FUNC3(instance_set_blend_shape_weight, RID, int, float)
FUNC3(instance_set_surface_override_material, RID, int, RID)
@@ -1048,7 +1057,6 @@ public:
/* INTERPOLATION */
- virtual void tick() override;
virtual void set_physics_interpolation_enabled(bool p_enabled) override;
/* EVENT QUEUING */
@@ -1060,6 +1068,8 @@ public:
virtual bool has_changed() const override;
virtual void init() override;
virtual void finish() override;
+ virtual void tick() override;
+ virtual void pre_draw(bool p_will_draw) override;
virtual bool is_on_render_thread() override {
return Thread::get_caller_id() == server_thread;
diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp
index a4ee33ecc0..49e005ca96 100644
--- a/servers/rendering/shader_compiler.cpp
+++ b/servers/rendering/shader_compiler.cpp
@@ -922,7 +922,7 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
if (shader->uniforms.has(vnode->name)) {
//its a uniform!
const ShaderLanguage::ShaderNode::Uniform &u = shader->uniforms[vnode->name];
- if (u.texture_order >= 0) {
+ if (u.is_texture()) {
StringName name;
if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SCREEN_TEXTURE) {
name = "color_buffer";
@@ -1039,7 +1039,7 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
if (shader->uniforms.has(anode->name)) {
//its a uniform!
const ShaderLanguage::ShaderNode::Uniform &u = shader->uniforms[anode->name];
- if (u.texture_order >= 0) {
+ if (u.is_texture()) {
code = _mkid(anode->name); //texture, use as is
} else {
//a scalar or vector
@@ -1286,6 +1286,13 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
break;
}
if (function->arguments[j].tex_argument_check) {
+ if (function->arguments[j].tex_hint == ShaderLanguage::ShaderNode::Uniform::HINT_SCREEN_TEXTURE) {
+ is_screen_texture = true;
+ } else if (function->arguments[j].tex_hint == ShaderLanguage::ShaderNode::Uniform::HINT_DEPTH_TEXTURE) {
+ is_depth_texture = true;
+ } else if (function->arguments[j].tex_hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE) {
+ is_normal_roughness_texture = true;
+ }
sampler_name = _get_sampler_name(function->arguments[j].tex_argument_filter, function->arguments[j].tex_argument_repeat);
found = true;
break;
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index 9aa54d0bb7..4eaf7fcb55 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -39,6 +39,8 @@
#define HAS_WARNING(flag) (warning_flags & flag)
+int ShaderLanguage::instance_counter = 0;
+
String ShaderLanguage::get_operator_text(Operator p_op) {
static const char *op_names[OP_MAX] = { "==",
"!=",
@@ -94,6 +96,7 @@ const char *ShaderLanguage::token_names[TK_MAX] = {
"FLOAT_CONSTANT",
"INT_CONSTANT",
"UINT_CONSTANT",
+ "STRING_CONSTANT",
"TYPE_VOID",
"TYPE_BOOL",
"TYPE_BVEC2",
@@ -210,6 +213,7 @@ const char *ShaderLanguage::token_names[TK_MAX] = {
"HINT_ANISOTROPY_TEXTURE",
"HINT_SOURCE_COLOR",
"HINT_RANGE",
+ "HINT_ENUM",
"HINT_INSTANCE_INDEX",
"HINT_SCREEN_TEXTURE",
"HINT_NORMAL_ROUGHNESS_TEXTURE",
@@ -363,6 +367,7 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = {
{ TK_HINT_SOURCE_COLOR, "source_color", CF_UNSPECIFIED, {}, {} },
{ TK_HINT_RANGE, "hint_range", CF_UNSPECIFIED, {}, {} },
+ { TK_HINT_ENUM, "hint_enum", CF_UNSPECIFIED, {}, {} },
{ TK_HINT_INSTANCE_INDEX, "instance_index", CF_UNSPECIFIED, {}, {} },
// sampler hints
@@ -510,7 +515,54 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
return _make_token(TK_OP_NOT);
} break;
- //case '"' //string - no strings in shader
+ case '"': {
+ String _content = "";
+ bool _previous_backslash = false;
+
+ while (true) {
+ bool _ended = false;
+ char32_t c = GETCHAR(0);
+ if (c == 0) {
+ return _make_token(TK_ERROR, "EOF reached before string termination.");
+ }
+ switch (c) {
+ case '"': {
+ if (_previous_backslash) {
+ _content += '"';
+ _previous_backslash = false;
+ } else {
+ _ended = true;
+ }
+ break;
+ }
+ case '\\': {
+ if (_previous_backslash) {
+ _content += '\\';
+ }
+ _previous_backslash = !_previous_backslash;
+ break;
+ }
+ case '\n': {
+ return _make_token(TK_ERROR, "Unexpected end of string.");
+ }
+ default: {
+ if (!_previous_backslash) {
+ _content += c;
+ } else {
+ return _make_token(TK_ERROR, "Only \\\" and \\\\ escape characters supported.");
+ }
+ break;
+ }
+ }
+
+ char_idx++;
+ if (_ended) {
+ break;
+ }
+ }
+
+ return _make_token(TK_STRING_CONSTANT, _content);
+ } break;
//case '\'' //string - no strings in shader
case '{':
return _make_token(TK_CURLY_BRACKET_OPEN);
@@ -896,6 +948,13 @@ bool ShaderLanguage::_lookup_next(Token &r_tk) {
return false;
}
+ShaderLanguage::Token ShaderLanguage::_peek() {
+ TkPos pre_pos = _get_tkpos();
+ Token tk = _get_token();
+ _set_tkpos(pre_pos);
+ return tk;
+}
+
String ShaderLanguage::token_debug(const String &p_code) {
clear();
@@ -1118,6 +1177,9 @@ String ShaderLanguage::get_uniform_hint_name(ShaderNode::Uniform::Hint p_hint) {
case ShaderNode::Uniform::HINT_RANGE: {
result = "hint_range";
} break;
+ case ShaderNode::Uniform::HINT_ENUM: {
+ result = "hint_enum";
+ } break;
case ShaderNode::Uniform::HINT_SOURCE_COLOR: {
result = "source_color";
} break;
@@ -1238,6 +1300,7 @@ void ShaderLanguage::clear() {
include_positions.push_back(FilePosition());
include_markers_handled.clear();
+ calls_info.clear();
#ifdef DEBUG_ENABLED
keyword_completion_context = CF_UNSPECIFIED;
@@ -1445,8 +1508,12 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
*r_struct_name = shader->constants[p_identifier].struct_name;
}
if (r_constant_value) {
- if (shader->constants[p_identifier].initializer && shader->constants[p_identifier].initializer->values.size() == 1) {
- *r_constant_value = shader->constants[p_identifier].initializer->values[0];
+ if (shader->constants[p_identifier].initializer && shader->constants[p_identifier].initializer->type == Node::NODE_TYPE_CONSTANT) {
+ ConstantNode *cnode = static_cast<ConstantNode *>(shader->constants[p_identifier].initializer);
+
+ if (cnode->values.size() == 1) {
+ *r_constant_value = cnode->values[0];
+ }
}
}
if (r_type) {
@@ -1542,7 +1609,7 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
}
DataType na = p_op->arguments[0]->get_datatype();
- valid = na > TYPE_BOOL && na < TYPE_MAT2;
+ valid = na > TYPE_BVEC4 && na < TYPE_MAT2;
ret_type = na;
} break;
case OP_ADD:
@@ -1562,7 +1629,7 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
}
if (na == nb) {
- valid = (na > TYPE_BOOL && na <= TYPE_MAT4);
+ valid = (na > TYPE_BVEC4 && na <= TYPE_MAT4);
ret_type = na;
} else if (na == TYPE_INT && nb == TYPE_IVEC2) {
valid = true;
@@ -1771,7 +1838,7 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
DataType nb = p_op->arguments[1]->get_datatype();
if (na == nb) {
- valid = (na > TYPE_BOOL && na <= TYPE_MAT4);
+ valid = (na > TYPE_BVEC4 && na <= TYPE_MAT4);
ret_type = na;
} else if (na == TYPE_IVEC2 && nb == TYPE_INT) {
valid = true;
@@ -3085,6 +3152,19 @@ const ShaderLanguage::BuiltinFuncConstArgs ShaderLanguage::builtin_func_const_ar
{ nullptr, 0, 0, 0 }
};
+const ShaderLanguage::BuiltinEntry ShaderLanguage::frag_only_func_defs[] = {
+ { "dFdx" },
+ { "dFdxCoarse" },
+ { "dFdxFine" },
+ { "dFdy" },
+ { "dFdyCoarse" },
+ { "dFdyFine" },
+ { "fwidth" },
+ { "fwidthCoarse" },
+ { "fwidthFine" },
+ { nullptr }
+};
+
bool ShaderLanguage::is_const_suffix_lut_initialized = false;
bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str, bool *r_is_custom_function) {
@@ -3964,12 +4044,9 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::C
}
value = Variant(array);
} else {
- PackedFloat32Array array;
+ PackedVector4Array array;
for (int i = 0; i < array_size; i += 4) {
- array.push_back(p_value[i].real);
- array.push_back(p_value[i + 1].real);
- array.push_back(p_value[i + 2].real);
- array.push_back(p_value[i + 3].real);
+ array.push_back(Vector4(p_value[i].real, p_value[i + 1].real, p_value[i + 2].real, p_value[i + 3].real));
}
value = Variant(array);
}
@@ -4122,6 +4199,11 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform
if (p_uniform.array_size > 0) {
pi.type = Variant::PACKED_INT32_ARRAY;
// TODO: Handle range and encoding for for unsigned values.
+ } else if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_ENUM) {
+ pi.type = Variant::INT;
+ pi.hint = PROPERTY_HINT_ENUM;
+ String hint_string;
+ pi.hint_string = String(",").join(p_uniform.hint_enum_names);
} else {
pi.type = Variant::INT;
pi.hint = PROPERTY_HINT_RANGE;
@@ -4201,7 +4283,7 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform
if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SOURCE_COLOR) {
pi.type = Variant::PACKED_COLOR_ARRAY;
} else {
- pi.type = Variant::PACKED_FLOAT32_ARRAY;
+ pi.type = Variant::PACKED_VECTOR4_ARRAY;
}
} else {
if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SOURCE_COLOR) {
@@ -4610,6 +4692,67 @@ bool ShaderLanguage::_check_node_constness(const Node *p_node) const {
return true;
}
+bool ShaderLanguage::_check_restricted_func(const StringName &p_name, const StringName &p_current_function) const {
+ int idx = 0;
+
+ while (frag_only_func_defs[idx].name) {
+ if (StringName(frag_only_func_defs[idx].name) == p_name) {
+ if (is_supported_frag_only_funcs) {
+ if (p_current_function == "vertex" && stages->has(p_current_function)) {
+ return true;
+ }
+ } else {
+ return true;
+ }
+ break;
+ }
+ idx++;
+ }
+
+ return false;
+}
+
+bool ShaderLanguage::_validate_restricted_func(const StringName &p_name, const CallInfo *p_func_info, bool p_is_builtin_hint) {
+ const bool is_in_restricted_function = p_func_info->name == "vertex";
+
+ // No need to check up the hierarchy if it's a built-in.
+ if (!p_is_builtin_hint) {
+ for (const CallInfo *func_info : p_func_info->calls) {
+ if (is_in_restricted_function && func_info->name != p_name) {
+ // Skips check for non-called method.
+ continue;
+ }
+
+ if (!_validate_restricted_func(p_name, func_info)) {
+ return false;
+ }
+ }
+ }
+
+ if (!p_func_info->uses_restricted_items.is_empty()) {
+ const Pair<StringName, CallInfo::Item> &first_element = p_func_info->uses_restricted_items.get(0);
+
+ if (first_element.second.type == CallInfo::Item::ITEM_TYPE_VARYING) {
+ const ShaderNode::Varying &varying = shader->varyings[first_element.first];
+
+ if (varying.stage == ShaderNode::Varying::STAGE_VERTEX) {
+ return true;
+ }
+ }
+
+ _set_tkpos(first_element.second.pos);
+
+ if (is_in_restricted_function) {
+ _set_error(vformat(RTR("'%s' cannot be used within the '%s' processor function."), first_element.first, "vertex"));
+ } else {
+ _set_error(vformat(RTR("'%s' cannot be used here, because '%s' is called by the '%s' processor function (which is not allowed)."), first_element.first, p_func_info->name, "vertex"));
+ }
+ return false;
+ }
+
+ return true;
+}
+
bool ShaderLanguage::_validate_assign(Node *p_node, const FunctionInfo &p_function_info, String *r_message) {
if (p_node->type == Node::NODE_TYPE_OPERATOR) {
OperatorNode *op = static_cast<OperatorNode *>(p_node);
@@ -4683,7 +4826,16 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const FunctionInfo &p_functi
return false;
}
-bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(const StringName &p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat) {
+ShaderLanguage::ShaderNode::Uniform::Hint ShaderLanguage::_sanitize_hint(ShaderNode::Uniform::Hint p_hint) {
+ if (p_hint == ShaderNode::Uniform::HINT_SCREEN_TEXTURE ||
+ p_hint == ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE ||
+ p_hint == ShaderNode::Uniform::HINT_DEPTH_TEXTURE) {
+ return p_hint;
+ }
+ return ShaderNode::Uniform::HINT_NONE;
+}
+
+bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(const StringName &p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat, ShaderNode::Uniform::Hint p_hint) {
for (int i = 0; i < shader->vfunctions.size(); i++) {
if (shader->vfunctions[i].name == p_name) {
ERR_FAIL_INDEX_V(p_argument, shader->vfunctions[i].function->arguments.size(), false);
@@ -4692,20 +4844,21 @@ bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(const Str
_set_error(vformat(RTR("Sampler argument %d of function '%s' called more than once using both built-ins and uniform textures, this is not supported (use either one or the other)."), p_argument, String(p_name)));
return false;
} else if (arg->tex_argument_check) {
- //was checked, verify that filter and repeat are the same
- if (arg->tex_argument_filter == p_filter && arg->tex_argument_repeat == p_repeat) {
+ // Was checked, verify that filter, repeat, and hint are the same.
+ if (arg->tex_argument_filter == p_filter && arg->tex_argument_repeat == p_repeat && arg->tex_hint == _sanitize_hint(p_hint)) {
return true;
} else {
- _set_error(vformat(RTR("Sampler argument %d of function '%s' called more than once using textures that differ in either filter or repeat setting."), p_argument, String(p_name)));
+ _set_error(vformat(RTR("Sampler argument %d of function '%s' called more than once using textures that differ in either filter, repeat, or texture hint setting."), p_argument, String(p_name)));
return false;
}
} else {
arg->tex_argument_check = true;
arg->tex_argument_filter = p_filter;
arg->tex_argument_repeat = p_repeat;
+ arg->tex_hint = _sanitize_hint(p_hint);
for (KeyValue<StringName, HashSet<int>> &E : arg->tex_argument_connect) {
for (const int &F : E.value) {
- if (!_propagate_function_call_sampler_uniform_settings(E.key, F, p_filter, p_repeat)) {
+ if (!_propagate_function_call_sampler_uniform_settings(E.key, F, p_filter, p_repeat, p_hint)) {
return false;
}
}
@@ -5043,7 +5196,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_bloc
return an;
}
-ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, const FunctionInfo &p_function_info) {
+ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, const FunctionInfo &p_function_info, const ExpressionInfo *p_previous_expression_info) {
Vector<Expression> expression;
//Vector<TokenType> operators;
@@ -5266,6 +5419,36 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
const StringName &name = identifier;
+ if (name != current_function) { // Recursion is not allowed.
+ // Register call.
+ if (calls_info.has(name)) {
+ calls_info[current_function].calls.push_back(&calls_info[name]);
+ }
+
+ int idx = 0;
+ bool is_builtin = false;
+
+ while (frag_only_func_defs[idx].name) {
+ if (frag_only_func_defs[idx].name == name) {
+ // If a built-in function not found for the current shader type, then it shouldn't be parsed further.
+ if (!is_supported_frag_only_funcs) {
+ _set_error(vformat(RTR("Built-in function '%s' is not supported for the '%s' shader type."), name, shader_type_identifier));
+ return nullptr;
+ }
+ // Register usage of the restricted function.
+ calls_info[current_function].uses_restricted_items.push_back(Pair<StringName, CallInfo::Item>(name, CallInfo::Item(CallInfo::Item::ITEM_TYPE_BUILTIN, _get_tkpos())));
+ is_builtin = true;
+ break;
+ }
+ idx++;
+ }
+
+ // Recursively checks for the restricted function call.
+ if (is_supported_frag_only_funcs && current_function == "vertex" && stages->has(current_function) && !_validate_restricted_func(name, &calls_info[current_function], is_builtin)) {
+ return nullptr;
+ }
+ }
+
OperatorNode *func = alloc_node<OperatorNode>();
func->op = OP_CALL;
VariableNode *funcname = alloc_node<VariableNode>();
@@ -5370,10 +5553,11 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (shader->varyings.has(varname)) {
switch (shader->varyings[varname].stage) {
- case ShaderNode::Varying::STAGE_UNKNOWN: {
- _set_error(vformat(RTR("Varying '%s' must be assigned in the 'vertex' or 'fragment' function first."), varname));
- return nullptr;
- }
+ case ShaderNode::Varying::STAGE_UNKNOWN:
+ if (is_out_arg) {
+ error = true;
+ }
+ break;
case ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT_LIGHT:
[[fallthrough]];
case ShaderNode::Varying::STAGE_VERTEX:
@@ -5449,10 +5633,16 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
}
if (is_sampler_type(call_function->arguments[i].type)) {
- //let's see where our argument comes from
- ERR_CONTINUE(n->type != Node::NODE_TYPE_VARIABLE); //bug? this should always be a variable
- VariableNode *vn = static_cast<VariableNode *>(n);
- StringName varname = vn->name;
+ // Let's see where our argument comes from.
+ StringName varname;
+ if (n->type == Node::NODE_TYPE_VARIABLE) {
+ VariableNode *vn = static_cast<VariableNode *>(n);
+ varname = vn->name;
+ } else if (n->type == Node::NODE_TYPE_ARRAY) {
+ ArrayNode *an = static_cast<ArrayNode *>(n);
+ varname = an->name;
+ }
+
if (shader->uniforms.has(varname)) {
//being sampler, this either comes from a uniform
ShaderNode::Uniform *u = &shader->uniforms[varname];
@@ -5468,7 +5658,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
//propagate
- if (!_propagate_function_call_sampler_uniform_settings(name, i, u->filter, u->repeat)) {
+ if (!_propagate_function_call_sampler_uniform_settings(name, i, u->filter, u->repeat, u->hint)) {
return nullptr;
}
} else if (p_function_info.built_ins.has(varname)) {
@@ -5567,6 +5757,8 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
_set_tkpos(prev_pos);
ShaderNode::Varying &var = shader->varyings[identifier];
+ calls_info[current_function].uses_restricted_items.push_back(Pair<StringName, CallInfo::Item>(identifier, CallInfo::Item(CallInfo::Item::ITEM_TYPE_VARYING, prev_pos)));
+
String error;
if (is_token_operator_assign(next_token.type)) {
if (!_validate_varying_assign(shader->varyings[identifier], &error)) {
@@ -6359,6 +6551,10 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
pos = _get_tkpos();
tk = _get_token();
+ if (p_previous_expression_info != nullptr && tk.type == p_previous_expression_info->tt_break && !p_previous_expression_info->is_last_expr) {
+ break;
+ }
+
if (is_token_operator(tk.type)) {
Expression o;
o.is_op = true;
@@ -6465,6 +6661,31 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
expression.push_back(o);
+ if (o.op == OP_SELECT_IF) {
+ ExpressionInfo info;
+ info.expression = &expression;
+ info.tt_break = TK_COLON;
+
+ expr = _parse_and_reduce_expression(p_block, p_function_info, &info);
+ if (!expr) {
+ return nullptr;
+ }
+
+ expression.push_back({ true, { OP_SELECT_ELSE } });
+
+ if (p_previous_expression_info != nullptr) {
+ info.is_last_expr = p_previous_expression_info->is_last_expr;
+ } else {
+ info.is_last_expr = true;
+ }
+
+ expr = _parse_and_reduce_expression(p_block, p_function_info, &info);
+ if (!expr) {
+ return nullptr;
+ }
+
+ break;
+ }
} else {
_set_tkpos(pos); //something else, so rollback and end
break;
@@ -6777,6 +6998,10 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
}
+ if (p_previous_expression_info != nullptr) {
+ p_previous_expression_info->expression->push_back(expression[0]);
+ }
+
return expression[0].node;
}
@@ -6889,8 +7114,8 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha
return p_node;
}
-ShaderLanguage::Node *ShaderLanguage::_parse_and_reduce_expression(BlockNode *p_block, const FunctionInfo &p_function_info) {
- ShaderLanguage::Node *expr = _parse_expression(p_block, p_function_info);
+ShaderLanguage::Node *ShaderLanguage::_parse_and_reduce_expression(BlockNode *p_block, const FunctionInfo &p_function_info, const ExpressionInfo *p_previous_expression_info) {
+ ShaderLanguage::Node *expr = _parse_expression(p_block, p_function_info, p_previous_expression_info);
if (!expr) { //errored
return nullptr;
}
@@ -7294,6 +7519,9 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
return ERR_PARSE_ERROR;
}
tk = _get_token();
+ } else {
+ _set_expected_error("(");
+ return ERR_PARSE_ERROR;
}
}
} else {
@@ -7931,7 +8159,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
if (!expr) {
return ERR_PARSE_ERROR;
}
- is_condition = expr->type == Node::NODE_TYPE_OPERATOR && expr->get_datatype() == TYPE_BOOL;
+ is_condition = expr->get_datatype() == TYPE_BOOL;
if (expr->type == Node::NODE_TYPE_OPERATOR) {
OperatorNode *op = static_cast<OperatorNode *>(expr);
@@ -7947,7 +8175,12 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR_CONDITION) {
if (tk.type == TK_COMMA) {
if (!is_condition) {
- _set_error(RTR("The middle expression is expected to be a boolean operator."));
+ _set_error(RTR("The middle expression is expected to have a boolean data type."));
+ return ERR_PARSE_ERROR;
+ }
+ tk = _peek();
+ if (tk.type == TK_SEMICOLON) {
+ _set_error(vformat(RTR("Expected expression, found: '%s'."), get_token_text(tk)));
return ERR_PARSE_ERROR;
}
continue;
@@ -7958,6 +8191,11 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
}
} else if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR_EXPRESSION) {
if (tk.type == TK_COMMA) {
+ tk = _peek();
+ if (tk.type == TK_PARENTHESIS_CLOSE) {
+ _set_error(vformat(RTR("Expected expression, found: '%s'."), get_token_text(tk)));
+ return ERR_PARSE_ERROR;
+ }
continue;
}
if (tk.type != TK_PARENTHESIS_CLOSE) {
@@ -7976,7 +8214,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
return ERR_PARSE_ERROR;
}
if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR_CONDITION && !is_condition) {
- _set_error(RTR("The middle expression is expected to be a boolean operator."));
+ _set_error(RTR("The middle expression is expected to have a boolean data type."));
return ERR_PARSE_ERROR;
}
}
@@ -8081,6 +8319,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
int texture_binding = 0;
int uniforms = 0;
int instance_index = 0;
+ int prop_index = 0;
#ifdef DEBUG_ENABLED
uint64_t uniform_buffer_size = 0;
uint64_t max_uniform_buffer_size = 0;
@@ -8099,6 +8338,8 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
ShaderNode::Uniform::Scope uniform_scope = ShaderNode::Uniform::SCOPE_LOCAL;
stages = &p_functions;
+ is_supported_frag_only_funcs = shader_type_identifier == "canvas_item" || shader_type_identifier == "spatial" || shader_type_identifier == "sky";
+
const FunctionInfo &constants = p_functions.has("constants") ? p_functions["constants"] : FunctionInfo();
HashMap<String, String> defined_modes;
@@ -8633,6 +8874,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
++texture_binding;
}
uniform.order = -1;
+ uniform.prop_order = prop_index++;
} else {
if (uniform_scope == ShaderNode::Uniform::SCOPE_INSTANCE && (type == TYPE_MAT2 || type == TYPE_MAT3 || type == TYPE_MAT4)) {
_set_error(vformat(RTR("The '%s' qualifier is not supported for matrix types."), "SCOPE_INSTANCE"));
@@ -8641,6 +8883,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
uniform.texture_order = -1;
if (uniform_scope != ShaderNode::Uniform::SCOPE_INSTANCE) {
uniform.order = uniforms++;
+ uniform.prop_order = prop_index++;
#ifdef DEBUG_ENABLED
if (check_device_limit_warnings) {
if (uniform.array_size > 0) {
@@ -8836,6 +9079,40 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
new_hint = ShaderNode::Uniform::HINT_RANGE;
} break;
+ case TK_HINT_ENUM: {
+ if (type != TYPE_INT) {
+ _set_error(vformat(RTR("Enum hint is for '%s' only."), "int"));
+ return ERR_PARSE_ERROR;
+ }
+
+ tk = _get_token();
+ if (tk.type != TK_PARENTHESIS_OPEN) {
+ _set_expected_after_error("(", "hint_enum");
+ return ERR_PARSE_ERROR;
+ }
+
+ while (true) {
+ tk = _get_token();
+
+ if (tk.type != TK_STRING_CONSTANT) {
+ _set_error(RTR("Expected a string constant."));
+ return ERR_PARSE_ERROR;
+ }
+
+ uniform.hint_enum_names.push_back(tk.text);
+
+ tk = _get_token();
+
+ if (tk.type == TK_PARENTHESIS_CLOSE) {
+ break;
+ } else if (tk.type != TK_COMMA) {
+ _set_error(RTR("Expected ',' or ')' after string constant."));
+ return ERR_PARSE_ERROR;
+ }
+ }
+
+ new_hint = ShaderNode::Uniform::HINT_ENUM;
+ } break;
case TK_HINT_INSTANCE_INDEX: {
if (custom_instance_index != -1) {
_set_error(vformat(RTR("Can only specify '%s' once."), "instance_index"));
@@ -8930,7 +9207,9 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
default:
break;
}
- if (((new_filter != FILTER_DEFAULT || new_repeat != REPEAT_DEFAULT) || (new_hint != ShaderNode::Uniform::HINT_NONE && new_hint != ShaderNode::Uniform::HINT_SOURCE_COLOR && new_hint != ShaderNode::Uniform::HINT_RANGE)) && !is_sampler_type(type)) {
+
+ bool is_sampler_hint = new_hint != ShaderNode::Uniform::HINT_NONE && new_hint != ShaderNode::Uniform::HINT_SOURCE_COLOR && new_hint != ShaderNode::Uniform::HINT_RANGE && new_hint != ShaderNode::Uniform::HINT_ENUM;
+ if (((new_filter != FILTER_DEFAULT || new_repeat != REPEAT_DEFAULT) || is_sampler_hint) && !is_sampler_type(type)) {
_set_error(RTR("This hint is only for sampler types."));
return ERR_PARSE_ERROR;
}
@@ -9085,6 +9364,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
tk = _get_token();
if (tk.type == TK_IDENTIFIER) {
current_uniform_group_name = tk.text;
+ current_uniform_subgroup_name = "";
tk = _get_token();
if (tk.type == TK_PERIOD) {
tk = _get_token();
@@ -9401,6 +9681,9 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
_set_error(RTR("Array size mismatch."));
return ERR_PARSE_ERROR;
}
+ } else {
+ _set_expected_error("(");
+ return ERR_PARSE_ERROR;
}
array_size = constant.array_size;
@@ -9443,7 +9726,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
}
}
- constant.initializer = static_cast<ConstantNode *>(expr);
+ constant.initializer = expr;
if (!_compare_datatypes(type, struct_name, 0, expr->get_datatype(), expr->get_datatype_name(), expr->get_array_size())) {
return ERR_PARSE_ERROR;
@@ -9505,6 +9788,11 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
break;
}
+ if (is_constant) {
+ _set_error(vformat(RTR("'%s' qualifier cannot be used with a function return type."), "const"));
+ return ERR_PARSE_ERROR;
+ }
+
FunctionInfo builtins;
if (p_functions.has(name)) {
builtins = p_functions[name];
@@ -9541,6 +9829,11 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
shader->functions.insert(name, function);
shader->vfunctions.push_back(function);
+ CallInfo call_info;
+ call_info.name = name;
+
+ calls_info.insert(name, call_info);
+
func_node->name = name;
func_node->return_type = type;
func_node->return_struct_name = struct_name;
@@ -10325,10 +10618,11 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
}
while (builtin_func_defs[idx].name) {
- if (low_end && builtin_func_defs[idx].high_end) {
+ if ((low_end && builtin_func_defs[idx].high_end) || _check_restricted_func(builtin_func_defs[idx].name, skip_function)) {
idx++;
continue;
}
+
matches.insert(String(builtin_func_defs[idx].name), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
idx++;
}
@@ -10490,7 +10784,7 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
}
while (builtin_func_defs[idx].name) {
- if (low_end && builtin_func_defs[idx].high_end) {
+ if ((low_end && builtin_func_defs[idx].high_end) || _check_restricted_func(builtin_func_defs[idx].name, block_function)) {
idx++;
continue;
}
@@ -10623,15 +10917,21 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
}
} else if ((completion_base == DataType::TYPE_INT || completion_base == DataType::TYPE_FLOAT) && !completion_base_array) {
if (current_uniform_hint == ShaderNode::Uniform::HINT_NONE) {
- ScriptLanguage::CodeCompletionOption option("hint_range", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
+ Vector<String> options;
if (completion_base == DataType::TYPE_INT) {
- option.insert_text = "hint_range(0, 100, 1)";
+ options.push_back("hint_range(0, 100, 1)");
+ options.push_back("hint_enum(\"Zero\", \"One\", \"Two\")");
} else {
- option.insert_text = "hint_range(0.0, 1.0, 0.1)";
+ options.push_back("hint_range(0.0, 1.0, 0.1)");
}
- r_options->push_back(option);
+ for (const String &option_text : options) {
+ String hint_name = option_text.substr(0, option_text.find_char(char32_t('(')));
+ ScriptLanguage::CodeCompletionOption option(hint_name, ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
+ option.insert_text = option_text;
+ r_options->push_back(option);
+ }
}
} else if ((int(completion_base) > int(TYPE_MAT4) && int(completion_base) < int(TYPE_STRUCT))) {
Vector<String> options;
@@ -10707,17 +11007,16 @@ ShaderLanguage::ShaderLanguage() {
nodes = nullptr;
completion_class = TAG_GLOBAL;
- int idx = 0;
- while (builtin_func_defs[idx].name) {
- if (builtin_func_defs[idx].tag == SubClassTag::TAG_GLOBAL) {
- const StringName &name = StringName(builtin_func_defs[idx].name);
-
- if (!global_func_set.has(name)) {
- global_func_set.insert(name);
+ if (instance_counter == 0) {
+ int idx = 0;
+ while (builtin_func_defs[idx].name) {
+ if (builtin_func_defs[idx].tag == SubClassTag::TAG_GLOBAL) {
+ global_func_set.insert(builtin_func_defs[idx].name);
}
+ idx++;
}
- idx++;
}
+ instance_counter++;
#ifdef DEBUG_ENABLED
warnings_check_map.insert(ShaderWarning::UNUSED_CONSTANT, &used_constants);
@@ -10732,4 +11031,8 @@ ShaderLanguage::ShaderLanguage() {
ShaderLanguage::~ShaderLanguage() {
clear();
+ instance_counter--;
+ if (instance_counter == 0) {
+ global_func_set.clear();
+ }
}
diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h
index 5615d7f457..63dca99654 100644
--- a/servers/rendering/shader_language.h
+++ b/servers/rendering/shader_language.h
@@ -59,6 +59,7 @@ public:
TK_FLOAT_CONSTANT,
TK_INT_CONSTANT,
TK_UINT_CONSTANT,
+ TK_STRING_CONSTANT,
TK_TYPE_VOID,
TK_TYPE_BOOL,
TK_TYPE_BVEC2,
@@ -175,6 +176,7 @@ public:
TK_HINT_ANISOTROPY_TEXTURE,
TK_HINT_SOURCE_COLOR,
TK_HINT_RANGE,
+ TK_HINT_ENUM,
TK_HINT_INSTANCE_INDEX,
TK_HINT_SCREEN_TEXTURE,
TK_HINT_NORMAL_ROUGHNESS_TEXTURE,
@@ -578,49 +580,13 @@ public:
Node(NODE_TYPE_STRUCT) {}
};
- struct FunctionNode : public Node {
- struct Argument {
- ArgumentQualifier qualifier;
- StringName name;
- DataType type;
- StringName struct_name;
- DataPrecision precision;
- //for passing textures as arguments
- bool tex_argument_check;
- TextureFilter tex_argument_filter;
- TextureRepeat tex_argument_repeat;
- bool tex_builtin_check;
- StringName tex_builtin;
- bool is_const;
- int array_size;
-
- HashMap<StringName, HashSet<int>> tex_argument_connect;
- };
-
- StringName name;
- DataType return_type = TYPE_VOID;
- StringName return_struct_name;
- DataPrecision return_precision = PRECISION_DEFAULT;
- int return_array_size = 0;
- Vector<Argument> arguments;
- BlockNode *body = nullptr;
- bool can_discard = false;
-
- virtual DataType get_datatype() const override { return return_type; }
- virtual String get_datatype_name() const override { return String(return_struct_name); }
- virtual int get_array_size() const override { return return_array_size; }
-
- FunctionNode() :
- Node(NODE_TYPE_FUNCTION) {}
- };
-
struct ShaderNode : public Node {
struct Constant {
StringName name;
DataType type;
StringName struct_name;
DataPrecision precision;
- ConstantNode *initializer = nullptr;
+ Node *initializer = nullptr;
int array_size;
};
@@ -659,6 +625,7 @@ public:
enum Hint {
HINT_NONE,
HINT_RANGE,
+ HINT_ENUM,
HINT_SOURCE_COLOR,
HINT_NORMAL,
HINT_ROUGHNESS_NORMAL,
@@ -684,6 +651,7 @@ public:
};
int order = 0;
+ int prop_order = 0;
int texture_order = 0;
int texture_binding = 0;
DataType type = TYPE_VOID;
@@ -696,10 +664,16 @@ public:
TextureFilter filter = FILTER_DEFAULT;
TextureRepeat repeat = REPEAT_DEFAULT;
float hint_range[3];
+ PackedStringArray hint_enum_names;
int instance_index = 0;
String group;
String subgroup;
+ _FORCE_INLINE_ bool is_texture() const {
+ // Order is assigned to -1 for texture uniforms.
+ return order < 0;
+ }
+
Uniform() {
hint_range[0] = 0.0f;
hint_range[1] = 1.0f;
@@ -722,6 +696,43 @@ public:
Node(NODE_TYPE_SHADER) {}
};
+ struct FunctionNode : public Node {
+ struct Argument {
+ ArgumentQualifier qualifier;
+ StringName name;
+ DataType type;
+ StringName struct_name;
+ DataPrecision precision;
+ //for passing textures as arguments
+ bool tex_argument_check;
+ TextureFilter tex_argument_filter;
+ TextureRepeat tex_argument_repeat;
+ bool tex_builtin_check;
+ StringName tex_builtin;
+ ShaderNode::Uniform::Hint tex_hint;
+ bool is_const;
+ int array_size;
+
+ HashMap<StringName, HashSet<int>> tex_argument_connect;
+ };
+
+ StringName name;
+ DataType return_type = TYPE_VOID;
+ StringName return_struct_name;
+ DataPrecision return_precision = PRECISION_DEFAULT;
+ int return_array_size = 0;
+ Vector<Argument> arguments;
+ BlockNode *body = nullptr;
+ bool can_discard = false;
+
+ virtual DataType get_datatype() const override { return return_type; }
+ virtual String get_datatype_name() const override { return String(return_struct_name); }
+ virtual int get_array_size() const override { return return_array_size; }
+
+ FunctionNode() :
+ Node(NODE_TYPE_FUNCTION) {}
+ };
+
struct UniformOrderComparator {
_FORCE_INLINE_ bool operator()(const Pair<StringName, int> &A, const Pair<StringName, int> &B) const {
return A.second < B.second;
@@ -736,6 +747,12 @@ public:
};
};
+ struct ExpressionInfo {
+ Vector<Expression> *expression = nullptr;
+ TokenType tt_break = TK_EMPTY;
+ bool is_last_expr = false;
+ };
+
struct VarInfo {
StringName name;
DataType type;
@@ -800,6 +817,8 @@ public:
static bool is_control_flow_keyword(String p_keyword);
static void get_builtin_funcs(List<String> *r_keywords);
+ static int instance_counter;
+
struct BuiltInInfo {
DataType type = TYPE_VOID;
bool constant = false;
@@ -913,6 +932,28 @@ private:
Vector<FilePosition> include_positions;
HashSet<String> include_markers_handled;
+ // Additional function information (eg. call hierarchy). No need to expose it to compiler.
+ struct CallInfo {
+ struct Item {
+ enum ItemType {
+ ITEM_TYPE_BUILTIN,
+ ITEM_TYPE_VARYING,
+ } type;
+
+ TkPos pos;
+
+ Item() {}
+ Item(ItemType p_type, TkPos p_pos) :
+ type(p_type), pos(p_pos) {}
+ };
+
+ StringName name;
+ List<Pair<StringName, Item>> uses_restricted_items;
+ List<CallInfo *> calls;
+ };
+
+ RBMap<StringName, CallInfo> calls_info;
+
#ifdef DEBUG_ENABLED
struct Usage {
int decl_line;
@@ -1012,6 +1053,7 @@ private:
Token _make_token(TokenType p_type, const StringName &p_text = StringName());
Token _get_token();
bool _lookup_next(Token &r_tk);
+ Token _peek();
ShaderNode *shader = nullptr;
@@ -1036,6 +1078,10 @@ private:
bool _validate_assign(Node *p_node, const FunctionInfo &p_function_info, String *r_message = nullptr);
bool _validate_operator(OperatorNode *p_op, DataType *r_ret_type = nullptr, int *r_ret_size = nullptr);
+ struct BuiltinEntry {
+ const char *name;
+ };
+
struct BuiltinFuncDef {
enum { MAX_ARGS = 5 };
const char *name;
@@ -1078,11 +1124,13 @@ private:
#endif // DEBUG_ENABLED
const HashMap<StringName, FunctionInfo> *stages = nullptr;
+ bool is_supported_frag_only_funcs = false;
bool _get_completable_identifier(BlockNode *p_block, CompletionType p_type, StringName &identifier);
static const BuiltinFuncDef builtin_func_defs[];
static const BuiltinFuncOutArgs builtin_func_out_args[];
static const BuiltinFuncConstArgs builtin_func_const_args[];
+ static const BuiltinEntry frag_only_func_defs[];
static bool is_const_suffix_lut_initialized;
@@ -1092,18 +1140,22 @@ private:
bool _validate_function_call(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str, bool *r_is_custom_function = nullptr);
bool _parse_function_arguments(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, int *r_complete_arg = nullptr);
- bool _propagate_function_call_sampler_uniform_settings(const StringName &p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat);
+ ShaderNode::Uniform::Hint _sanitize_hint(ShaderNode::Uniform::Hint p_hint);
+ bool _propagate_function_call_sampler_uniform_settings(const StringName &p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat, ShaderNode::Uniform::Hint p_hint);
bool _propagate_function_call_sampler_builtin_reference(const StringName &p_name, int p_argument, const StringName &p_builtin);
bool _validate_varying_assign(ShaderNode::Varying &p_varying, String *r_message);
bool _check_node_constness(const Node *p_node) const;
- Node *_parse_expression(BlockNode *p_block, const FunctionInfo &p_function_info);
+ bool _check_restricted_func(const StringName &p_name, const StringName &p_current_function) const;
+ bool _validate_restricted_func(const StringName &p_call_name, const CallInfo *p_func_info, bool p_is_builtin_hint = false);
+
+ Node *_parse_expression(BlockNode *p_block, const FunctionInfo &p_function_info, const ExpressionInfo *p_previous_expression_info = nullptr);
Error _parse_array_size(BlockNode *p_block, const FunctionInfo &p_function_info, bool p_forbid_unknown_size, Node **r_size_expression, int *r_array_size, bool *r_unknown_size);
Node *_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info);
Node *_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info, DataType p_type, const StringName &p_struct_name, int p_array_size);
ShaderLanguage::Node *_reduce_expression(BlockNode *p_block, ShaderLanguage::Node *p_node);
- Node *_parse_and_reduce_expression(BlockNode *p_block, const FunctionInfo &p_function_info);
+ Node *_parse_and_reduce_expression(BlockNode *p_block, const FunctionInfo &p_function_info, const ExpressionInfo *p_previous_expression_info = nullptr);
Error _parse_block(BlockNode *p_block, const FunctionInfo &p_function_info, bool p_just_one = false, bool p_can_break = false, bool p_can_continue = false);
String _get_shader_type_list(const HashSet<String> &p_shader_types) const;
String _get_qualifier_str(ArgumentQualifier p_qualifier) const;
diff --git a/servers/rendering/shader_preprocessor.cpp b/servers/rendering/shader_preprocessor.cpp
index dbd1374941..27e39551ba 100644
--- a/servers/rendering/shader_preprocessor.cpp
+++ b/servers/rendering/shader_preprocessor.cpp
@@ -173,7 +173,7 @@ String ShaderPreprocessor::Tokenizer::get_identifier(bool *r_is_cursor, bool p_s
}
String id = vector_to_string(text);
- if (!id.is_valid_identifier()) {
+ if (!id.is_valid_ascii_identifier()) {
return "";
}
diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp
index ab9cf666ec..f498c0bf93 100644
--- a/servers/rendering/shader_types.cpp
+++ b/servers/rendering/shader_types.cpp
@@ -77,12 +77,12 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["INSTANCE_CUSTOM"] = constt(ShaderLanguage::TYPE_VEC4);
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VERTEX_ID"] = constt(ShaderLanguage::TYPE_INT);
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["ROUGHNESS"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["BONE_INDICES"] = ShaderLanguage::TYPE_UVEC4;
- shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["BONE_WEIGHTS"] = ShaderLanguage::TYPE_VEC4;
- shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM0"] = ShaderLanguage::TYPE_VEC4;
- shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM1"] = ShaderLanguage::TYPE_VEC4;
- shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM2"] = ShaderLanguage::TYPE_VEC4;
- shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM3"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["BONE_INDICES"] = constt(ShaderLanguage::TYPE_UVEC4);
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["BONE_WEIGHTS"] = constt(ShaderLanguage::TYPE_VEC4);
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM0"] = constt(ShaderLanguage::TYPE_VEC4);
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM1"] = constt(ShaderLanguage::TYPE_VEC4);
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM2"] = constt(ShaderLanguage::TYPE_VEC4);
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM3"] = constt(ShaderLanguage::TYPE_VEC4);
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].can_discard = false;
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].main_function = true;
@@ -97,13 +97,14 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["MODELVIEW_NORMAL_MATRIX"] = ShaderLanguage::TYPE_MAT3;
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEWPORT_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CLIP_SPACE_FAR"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["MAIN_CAM_INV_VIEW_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
- shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["NODE_POSITION_WORLD"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CAMERA_POSITION_WORLD"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CAMERA_DIRECTION_WORLD"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CAMERA_VISIBLE_LAYERS"] = ShaderLanguage::TYPE_UINT;
- shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["NODE_POSITION_VIEW"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["NODE_POSITION_WORLD"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CAMERA_POSITION_WORLD"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CAMERA_DIRECTION_WORLD"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CAMERA_VISIBLE_LAYERS"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["NODE_POSITION_VIEW"] = constt(ShaderLanguage::TYPE_VEC3);
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEW_INDEX"] = constt(ShaderLanguage::TYPE_INT);
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEW_MONO_LEFT"] = constt(ShaderLanguage::TYPE_INT);
@@ -147,11 +148,11 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2);
- shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NODE_POSITION_WORLD"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["CAMERA_POSITION_WORLD"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["CAMERA_DIRECTION_WORLD"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["CAMERA_VISIBLE_LAYERS"] = ShaderLanguage::TYPE_UINT;
- shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NODE_POSITION_VIEW"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NODE_POSITION_WORLD"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["CAMERA_POSITION_WORLD"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["CAMERA_DIRECTION_WORLD"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["CAMERA_VISIBLE_LAYERS"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NODE_POSITION_VIEW"] = constt(ShaderLanguage::TYPE_VEC3);
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW_INDEX"] = constt(ShaderLanguage::TYPE_INT);
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW_MONO_LEFT"] = constt(ShaderLanguage::TYPE_INT);
@@ -159,6 +160,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["EYE_OFFSET"] = constt(ShaderLanguage::TYPE_VEC3);
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["CLIP_SPACE_FAR"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["MODEL_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["MODEL_NORMAL_MATRIX"] = constt(ShaderLanguage::TYPE_MAT3);
@@ -202,6 +204,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["DIFFUSE_LIGHT"] = ShaderLanguage::TYPE_VEC3;
shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["SPECULAR_LIGHT"] = ShaderLanguage::TYPE_VEC3;
shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["CLIP_SPACE_FAR"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["ALPHA"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[RS::SHADER_SPATIAL].functions["light"].can_discard = true;
diff --git a/servers/rendering/storage/mesh_storage.cpp b/servers/rendering/storage/mesh_storage.cpp
new file mode 100644
index 0000000000..221ebaa277
--- /dev/null
+++ b/servers/rendering/storage/mesh_storage.cpp
@@ -0,0 +1,485 @@
+/**************************************************************************/
+/* mesh_storage.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 "mesh_storage.h"
+
+#include "core/math/transform_interpolator.h"
+
+#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
+#include "core/config/project_settings.h"
+#endif
+
+RID RendererMeshStorage::multimesh_allocate() {
+ return _multimesh_allocate();
+}
+
+void RendererMeshStorage::multimesh_initialize(RID p_rid) {
+ _multimesh_initialize(p_rid);
+}
+
+void RendererMeshStorage::multimesh_free(RID p_rid) {
+ _multimesh_free(p_rid);
+}
+
+void RendererMeshStorage::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors, bool p_use_custom_data) {
+ MultiMeshInterpolator *mmi = _multimesh_get_interpolator(p_multimesh);
+ if (mmi) {
+ mmi->_transform_format = p_transform_format;
+ mmi->_use_colors = p_use_colors;
+ mmi->_use_custom_data = p_use_custom_data;
+ mmi->_num_instances = p_instances;
+
+ mmi->_vf_size_xform = p_transform_format == RS::MULTIMESH_TRANSFORM_2D ? 8 : 12;
+ mmi->_vf_size_color = p_use_colors ? 4 : 0;
+ mmi->_vf_size_data = p_use_custom_data ? 4 : 0;
+
+ mmi->_stride = mmi->_vf_size_xform + mmi->_vf_size_color + mmi->_vf_size_data;
+
+ int size_in_floats = p_instances * mmi->_stride;
+ mmi->_data_curr.resize_zeroed(size_in_floats);
+ mmi->_data_prev.resize_zeroed(size_in_floats);
+ mmi->_data_interpolated.resize_zeroed(size_in_floats);
+ }
+
+ _multimesh_allocate_data(p_multimesh, p_instances, p_transform_format, p_use_colors, p_use_custom_data);
+}
+
+int RendererMeshStorage::multimesh_get_instance_count(RID p_multimesh) const {
+ return _multimesh_get_instance_count(p_multimesh);
+}
+
+void RendererMeshStorage::multimesh_set_mesh(RID p_multimesh, RID p_mesh) {
+ _multimesh_set_mesh(p_multimesh, p_mesh);
+}
+
+void RendererMeshStorage::multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) {
+ MultiMeshInterpolator *mmi = _multimesh_get_interpolator(p_multimesh);
+ if (mmi && mmi->interpolated) {
+ ERR_FAIL_COND(p_index >= mmi->_num_instances);
+ ERR_FAIL_COND(mmi->_vf_size_xform != 12);
+
+ int start = p_index * mmi->_stride;
+ float *ptr = mmi->_data_curr.ptrw();
+ ptr += start;
+
+ const Transform3D &t = p_transform;
+ ptr[0] = t.basis.rows[0][0];
+ ptr[1] = t.basis.rows[0][1];
+ ptr[2] = t.basis.rows[0][2];
+ ptr[3] = t.origin.x;
+ ptr[4] = t.basis.rows[1][0];
+ ptr[5] = t.basis.rows[1][1];
+ ptr[6] = t.basis.rows[1][2];
+ ptr[7] = t.origin.y;
+ ptr[8] = t.basis.rows[2][0];
+ ptr[9] = t.basis.rows[2][1];
+ ptr[10] = t.basis.rows[2][2];
+ ptr[11] = t.origin.z;
+
+ _multimesh_add_to_interpolation_lists(p_multimesh, *mmi);
+
+#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
+ if (!Engine::get_singleton()->is_in_physics_frame()) {
+ PHYSICS_INTERPOLATION_WARNING("MultiMesh interpolation is being triggered from outside physics process, this might lead to issues");
+ }
+#endif
+
+ return;
+ }
+
+ _multimesh_instance_set_transform(p_multimesh, p_index, p_transform);
+}
+
+void RendererMeshStorage::multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) {
+ _multimesh_instance_set_transform_2d(p_multimesh, p_index, p_transform);
+}
+
+void RendererMeshStorage::multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) {
+ MultiMeshInterpolator *mmi = _multimesh_get_interpolator(p_multimesh);
+ if (mmi && mmi->interpolated) {
+ ERR_FAIL_COND(p_index >= mmi->_num_instances);
+ ERR_FAIL_COND(mmi->_vf_size_color == 0);
+
+ int start = (p_index * mmi->_stride) + mmi->_vf_size_xform;
+ float *ptr = mmi->_data_curr.ptrw();
+ ptr += start;
+
+ if (mmi->_vf_size_color == 4) {
+ for (int n = 0; n < 4; n++) {
+ ptr[n] = p_color.components[n];
+ }
+ } else {
+#ifdef DEV_ENABLED
+ // The options are currently 4 or zero, but just in case this changes in future...
+ ERR_FAIL_COND(mmi->_vf_size_color != 0);
+#endif
+ }
+ _multimesh_add_to_interpolation_lists(p_multimesh, *mmi);
+ return;
+ }
+
+ _multimesh_instance_set_color(p_multimesh, p_index, p_color);
+}
+
+void RendererMeshStorage::multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) {
+ MultiMeshInterpolator *mmi = _multimesh_get_interpolator(p_multimesh);
+ if (mmi && mmi->interpolated) {
+ ERR_FAIL_COND(p_index >= mmi->_num_instances);
+ ERR_FAIL_COND(mmi->_vf_size_data == 0);
+
+ int start = (p_index * mmi->_stride) + mmi->_vf_size_xform + mmi->_vf_size_color;
+ float *ptr = mmi->_data_curr.ptrw();
+ ptr += start;
+
+ if (mmi->_vf_size_data == 4) {
+ for (int n = 0; n < 4; n++) {
+ ptr[n] = p_color.components[n];
+ }
+ } else {
+#ifdef DEV_ENABLED
+ // The options are currently 4 or zero, but just in case this changes in future...
+ ERR_FAIL_COND(mmi->_vf_size_data != 0);
+#endif
+ }
+ _multimesh_add_to_interpolation_lists(p_multimesh, *mmi);
+ return;
+ }
+
+ _multimesh_instance_set_custom_data(p_multimesh, p_index, p_color);
+}
+
+void RendererMeshStorage::multimesh_set_custom_aabb(RID p_multimesh, const AABB &p_aabb) {
+ _multimesh_set_custom_aabb(p_multimesh, p_aabb);
+}
+
+AABB RendererMeshStorage::multimesh_get_custom_aabb(RID p_multimesh) const {
+ return _multimesh_get_custom_aabb(p_multimesh);
+}
+
+RID RendererMeshStorage::multimesh_get_mesh(RID p_multimesh) const {
+ return _multimesh_get_mesh(p_multimesh);
+}
+
+Transform3D RendererMeshStorage::multimesh_instance_get_transform(RID p_multimesh, int p_index) const {
+ return _multimesh_instance_get_transform(p_multimesh, p_index);
+}
+
+Transform2D RendererMeshStorage::multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const {
+ return _multimesh_instance_get_transform_2d(p_multimesh, p_index);
+}
+
+Color RendererMeshStorage::multimesh_instance_get_color(RID p_multimesh, int p_index) const {
+ return _multimesh_instance_get_color(p_multimesh, p_index);
+}
+
+Color RendererMeshStorage::multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const {
+ return _multimesh_instance_get_custom_data(p_multimesh, p_index);
+}
+
+void RendererMeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) {
+ MultiMeshInterpolator *mmi = _multimesh_get_interpolator(p_multimesh);
+ if (mmi && mmi->interpolated) {
+ ERR_FAIL_COND_MSG(p_buffer.size() != mmi->_data_curr.size(), vformat("Buffer should have %d elements, got %d instead.", mmi->_data_curr.size(), p_buffer.size()));
+
+ mmi->_data_curr = p_buffer;
+ _multimesh_add_to_interpolation_lists(p_multimesh, *mmi);
+
+#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
+ if (!Engine::get_singleton()->is_in_physics_frame()) {
+ PHYSICS_INTERPOLATION_WARNING("MultiMesh interpolation is being triggered from outside physics process, this might lead to issues");
+ }
+#endif
+
+ return;
+ }
+
+ _multimesh_set_buffer(p_multimesh, p_buffer);
+}
+
+Vector<float> RendererMeshStorage::multimesh_get_buffer(RID p_multimesh) const {
+ return _multimesh_get_buffer(p_multimesh);
+}
+
+void RendererMeshStorage::multimesh_set_buffer_interpolated(RID p_multimesh, const Vector<float> &p_buffer, const Vector<float> &p_buffer_prev) {
+ MultiMeshInterpolator *mmi = _multimesh_get_interpolator(p_multimesh);
+ if (mmi) {
+ ERR_FAIL_COND_MSG(p_buffer.size() != mmi->_data_curr.size(), vformat("Buffer for current frame should have %d elements, got %d instead.", mmi->_data_curr.size(), p_buffer.size()));
+ ERR_FAIL_COND_MSG(p_buffer_prev.size() != mmi->_data_prev.size(), vformat("Buffer for previous frame should have %d elements, got %d instead.", mmi->_data_prev.size(), p_buffer_prev.size()));
+
+ // We are assuming that mmi->interpolated is the case. (Can possibly assert this?)
+ // Even if this flag hasn't been set - just calling this function suggests interpolation is desired.
+ mmi->_data_prev = p_buffer_prev;
+ mmi->_data_curr = p_buffer;
+ _multimesh_add_to_interpolation_lists(p_multimesh, *mmi);
+
+#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
+ if (!Engine::get_singleton()->is_in_physics_frame()) {
+ PHYSICS_INTERPOLATION_WARNING("MultiMesh interpolation is being triggered from outside physics process, this might lead to issues");
+ }
+#endif
+ }
+}
+
+void RendererMeshStorage::multimesh_set_physics_interpolated(RID p_multimesh, bool p_interpolated) {
+ MultiMeshInterpolator *mmi = _multimesh_get_interpolator(p_multimesh);
+ if (mmi) {
+ mmi->interpolated = p_interpolated;
+ }
+}
+
+void RendererMeshStorage::multimesh_set_physics_interpolation_quality(RID p_multimesh, RS::MultimeshPhysicsInterpolationQuality p_quality) {
+ ERR_FAIL_COND((p_quality < 0) || (p_quality > 1));
+ MultiMeshInterpolator *mmi = _multimesh_get_interpolator(p_multimesh);
+ if (mmi) {
+ mmi->quality = (int)p_quality;
+ }
+}
+
+void RendererMeshStorage::multimesh_instance_reset_physics_interpolation(RID p_multimesh, int p_index) {
+ MultiMeshInterpolator *mmi = _multimesh_get_interpolator(p_multimesh);
+ if (mmi) {
+ ERR_FAIL_INDEX(p_index, mmi->_num_instances);
+
+ float *w = mmi->_data_prev.ptrw();
+ const float *r = mmi->_data_curr.ptr();
+ int start = p_index * mmi->_stride;
+
+ for (int n = 0; n < mmi->_stride; n++) {
+ w[start + n] = r[start + n];
+ }
+ }
+}
+
+void RendererMeshStorage::multimesh_set_visible_instances(RID p_multimesh, int p_visible) {
+ return _multimesh_set_visible_instances(p_multimesh, p_visible);
+}
+
+int RendererMeshStorage::multimesh_get_visible_instances(RID p_multimesh) const {
+ return _multimesh_get_visible_instances(p_multimesh);
+}
+
+AABB RendererMeshStorage::multimesh_get_aabb(RID p_multimesh) const {
+ return _multimesh_get_aabb(p_multimesh);
+}
+
+void RendererMeshStorage::_multimesh_add_to_interpolation_lists(RID p_multimesh, MultiMeshInterpolator &r_mmi) {
+ if (!r_mmi.on_interpolate_update_list) {
+ r_mmi.on_interpolate_update_list = true;
+ _interpolation_data.multimesh_interpolate_update_list.push_back(p_multimesh);
+ }
+
+ if (!r_mmi.on_transform_update_list) {
+ r_mmi.on_transform_update_list = true;
+ _interpolation_data.multimesh_transform_update_list_curr->push_back(p_multimesh);
+ }
+}
+
+void RendererMeshStorage::InterpolationData::notify_free_multimesh(RID p_rid) {
+ // If the instance was on any of the lists, remove.
+ multimesh_interpolate_update_list.erase_multiple_unordered(p_rid);
+ multimesh_transform_update_lists[0].erase_multiple_unordered(p_rid);
+ multimesh_transform_update_lists[1].erase_multiple_unordered(p_rid);
+}
+
+void RendererMeshStorage::update_interpolation_tick(bool p_process) {
+ // Detect any that were on the previous transform list that are no longer active,
+ // we should remove them from the interpolate list.
+
+ for (unsigned int n = 0; n < _interpolation_data.multimesh_transform_update_list_prev->size(); n++) {
+ const RID &rid = (*_interpolation_data.multimesh_transform_update_list_prev)[n];
+
+ bool active = true;
+
+ // No longer active? (Either the instance deleted or no longer being transformed.)
+
+ MultiMeshInterpolator *mmi = _multimesh_get_interpolator(rid);
+ if (mmi && !mmi->on_transform_update_list) {
+ active = false;
+ mmi->on_interpolate_update_list = false;
+
+ // Make sure the most recent transform is set...
+ mmi->_data_interpolated = mmi->_data_curr; // TODO: Copy data rather than use Packed = function?
+
+ // ... and that both prev and current are the same, just in case of any interpolations.
+ mmi->_data_prev = mmi->_data_curr;
+ }
+
+ if (!mmi) {
+ active = false;
+ }
+
+ if (!active) {
+ _interpolation_data.multimesh_interpolate_update_list.erase(rid);
+ }
+ }
+
+ if (p_process) {
+ for (unsigned int i = 0; i < _interpolation_data.multimesh_transform_update_list_curr->size(); i++) {
+ const RID &rid = (*_interpolation_data.multimesh_transform_update_list_curr)[i];
+
+ MultiMeshInterpolator *mmi = _multimesh_get_interpolator(rid);
+ if (mmi) {
+ // Reset for next tick.
+ mmi->on_transform_update_list = false;
+ mmi->_data_prev = mmi->_data_curr;
+ }
+ }
+ }
+
+ // If any have left the transform list, remove from the interpolate list.
+
+ // We maintain a mirror list for the transform updates, so we can detect when an instance
+ // is no longer being transformed, and remove it from the interpolate list.
+ SWAP(_interpolation_data.multimesh_transform_update_list_curr, _interpolation_data.multimesh_transform_update_list_prev);
+
+ // Prepare for the next iteration.
+ _interpolation_data.multimesh_transform_update_list_curr->clear();
+}
+
+void RendererMeshStorage::update_interpolation_frame(bool p_process) {
+ if (p_process) {
+ // Only need 32 bits for interpolation, don't use real_t.
+ float f = Engine::get_singleton()->get_physics_interpolation_fraction();
+
+ for (unsigned int c = 0; c < _interpolation_data.multimesh_interpolate_update_list.size(); c++) {
+ const RID &rid = _interpolation_data.multimesh_interpolate_update_list[c];
+
+ // We could use the TransformInterpolator here to slerp transforms, but that might be too expensive,
+ // so just using a Basis lerp for now.
+ MultiMeshInterpolator *mmi = _multimesh_get_interpolator(rid);
+ if (mmi) {
+ // Make sure arrays are the correct size.
+ DEV_ASSERT(mmi->_data_prev.size() == mmi->_data_curr.size());
+
+ if (mmi->_data_interpolated.size() < mmi->_data_curr.size()) {
+ mmi->_data_interpolated.resize(mmi->_data_curr.size());
+ }
+ DEV_ASSERT(mmi->_data_interpolated.size() >= mmi->_data_curr.size());
+
+ DEV_ASSERT((mmi->_data_curr.size() % mmi->_stride) == 0);
+ int num = mmi->_data_curr.size() / mmi->_stride;
+
+ const float *pf_prev = mmi->_data_prev.ptr();
+ const float *pf_curr = mmi->_data_curr.ptr();
+ float *pf_int = mmi->_data_interpolated.ptrw();
+
+ bool use_lerp = mmi->quality == 0;
+
+ // Temporary transform (needed for swizzling).
+ Transform3D tp, tc, tr; // (transform prev, curr and result)
+
+ // Test for cache friendliness versus doing branchless.
+ for (int n = 0; n < num; n++) {
+ // Transform.
+ if (use_lerp) {
+ for (int i = 0; i < mmi->_vf_size_xform; i++) {
+ pf_int[i] = Math::lerp(pf_prev[i], pf_curr[i], f);
+ }
+ } else {
+ // Silly swizzling, this will slow things down.
+ // No idea why it is using this format...
+ // ... maybe due to the shader.
+ tp.basis.rows[0][0] = pf_prev[0];
+ tp.basis.rows[0][1] = pf_prev[1];
+ tp.basis.rows[0][2] = pf_prev[2];
+ tp.basis.rows[1][0] = pf_prev[4];
+ tp.basis.rows[1][1] = pf_prev[5];
+ tp.basis.rows[1][2] = pf_prev[6];
+ tp.basis.rows[2][0] = pf_prev[8];
+ tp.basis.rows[2][1] = pf_prev[9];
+ tp.basis.rows[2][2] = pf_prev[10];
+ tp.origin.x = pf_prev[3];
+ tp.origin.y = pf_prev[7];
+ tp.origin.z = pf_prev[11];
+
+ tc.basis.rows[0][0] = pf_curr[0];
+ tc.basis.rows[0][1] = pf_curr[1];
+ tc.basis.rows[0][2] = pf_curr[2];
+ tc.basis.rows[1][0] = pf_curr[4];
+ tc.basis.rows[1][1] = pf_curr[5];
+ tc.basis.rows[1][2] = pf_curr[6];
+ tc.basis.rows[2][0] = pf_curr[8];
+ tc.basis.rows[2][1] = pf_curr[9];
+ tc.basis.rows[2][2] = pf_curr[10];
+ tc.origin.x = pf_curr[3];
+ tc.origin.y = pf_curr[7];
+ tc.origin.z = pf_curr[11];
+
+ TransformInterpolator::interpolate_transform_3d(tp, tc, tr, f);
+
+ pf_int[0] = tr.basis.rows[0][0];
+ pf_int[1] = tr.basis.rows[0][1];
+ pf_int[2] = tr.basis.rows[0][2];
+ pf_int[4] = tr.basis.rows[1][0];
+ pf_int[5] = tr.basis.rows[1][1];
+ pf_int[6] = tr.basis.rows[1][2];
+ pf_int[8] = tr.basis.rows[2][0];
+ pf_int[9] = tr.basis.rows[2][1];
+ pf_int[10] = tr.basis.rows[2][2];
+ pf_int[3] = tr.origin.x;
+ pf_int[7] = tr.origin.y;
+ pf_int[11] = tr.origin.z;
+ }
+
+ pf_prev += mmi->_vf_size_xform;
+ pf_curr += mmi->_vf_size_xform;
+ pf_int += mmi->_vf_size_xform;
+
+ // Color.
+ if (mmi->_vf_size_color == 4) {
+ for (int i = 0; i < 4; i++) {
+ pf_int[i] = Math::lerp(pf_prev[i], pf_curr[i], f);
+ }
+
+ pf_prev += 4;
+ pf_curr += 4;
+ pf_int += 4;
+ }
+
+ // Custom data.
+ if (mmi->_vf_size_data == 4) {
+ for (int i = 0; i < 4; i++) {
+ pf_int[i] = Math::lerp(pf_prev[i], pf_curr[i], f);
+ }
+
+ pf_prev += 4;
+ pf_curr += 4;
+ pf_int += 4;
+ }
+ }
+
+ _multimesh_set_buffer(rid, mmi->_data_interpolated);
+
+ // TODO: Make sure AABBs are constantly up to date through the interpolation?
+ // NYI.
+ }
+ }
+ }
+}
diff --git a/servers/rendering/storage/mesh_storage.h b/servers/rendering/storage/mesh_storage.h
index 39fd4f393d..ecd2a967d0 100644
--- a/servers/rendering/storage/mesh_storage.h
+++ b/servers/rendering/storage/mesh_storage.h
@@ -89,39 +89,110 @@ public:
virtual void update_mesh_instances() = 0;
/* MULTIMESH API */
+ struct MultiMeshInterpolator {
+ RS::MultimeshTransformFormat _transform_format = RS::MULTIMESH_TRANSFORM_3D;
+ bool _use_colors = false;
+ bool _use_custom_data = false;
- virtual RID multimesh_allocate() = 0;
- virtual void multimesh_initialize(RID p_rid) = 0;
- virtual void multimesh_free(RID p_rid) = 0;
+ // The stride of the buffer in floats.
+ int _stride = 0;
- virtual void multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) = 0;
+ // Vertex format sizes in floats.
+ int _vf_size_xform = 0;
+ int _vf_size_color = 0;
+ int _vf_size_data = 0;
- virtual int multimesh_get_instance_count(RID p_multimesh) const = 0;
+ // Set by allocate, can be used to prevent indexing out of range.
+ int _num_instances = 0;
- virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh) = 0;
- virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) = 0;
- virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) = 0;
- virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) = 0;
- virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) = 0;
+ // Quality determines whether to use lerp or slerp etc.
+ int quality = 0;
+ bool interpolated = false;
+ bool on_interpolate_update_list = false;
+ bool on_transform_update_list = false;
- virtual void multimesh_set_custom_aabb(RID p_multimesh, const AABB &p_aabb) = 0;
- virtual AABB multimesh_get_custom_aabb(RID p_multimesh) const = 0;
+ Vector<float> _data_prev;
+ Vector<float> _data_curr;
+ Vector<float> _data_interpolated;
+ };
- virtual RID multimesh_get_mesh(RID p_multimesh) const = 0;
+ virtual RID multimesh_allocate();
+ virtual void multimesh_initialize(RID p_rid);
+ virtual void multimesh_free(RID p_rid);
- virtual Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const = 0;
- virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const = 0;
- virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const = 0;
- virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const = 0;
+ virtual void multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false);
- virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) = 0;
- virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const = 0;
+ virtual int multimesh_get_instance_count(RID p_multimesh) const;
- virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible) = 0;
- virtual int multimesh_get_visible_instances(RID p_multimesh) const = 0;
+ virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh);
+ virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform);
+ virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform);
+ virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color);
+ virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color);
- virtual AABB multimesh_get_aabb(RID p_multimesh) const = 0;
+ virtual void multimesh_set_custom_aabb(RID p_multimesh, const AABB &p_aabb);
+ virtual AABB multimesh_get_custom_aabb(RID p_multimesh) const;
+ virtual RID multimesh_get_mesh(RID p_multimesh) const;
+
+ virtual Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const;
+ virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const;
+ virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const;
+ virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const;
+
+ virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer);
+ virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const;
+
+ virtual void multimesh_set_buffer_interpolated(RID p_multimesh, const Vector<float> &p_buffer, const Vector<float> &p_buffer_prev);
+ virtual void multimesh_set_physics_interpolated(RID p_multimesh, bool p_interpolated);
+ virtual void multimesh_set_physics_interpolation_quality(RID p_multimesh, RS::MultimeshPhysicsInterpolationQuality p_quality);
+ virtual void multimesh_instance_reset_physics_interpolation(RID p_multimesh, int p_index);
+
+ virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible);
+ virtual int multimesh_get_visible_instances(RID p_multimesh) const;
+
+ virtual AABB multimesh_get_aabb(RID p_multimesh) const;
+
+ virtual RID _multimesh_allocate() = 0;
+ virtual void _multimesh_initialize(RID p_rid) = 0;
+ virtual void _multimesh_free(RID p_rid) = 0;
+
+ virtual void _multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) = 0;
+
+ virtual int _multimesh_get_instance_count(RID p_multimesh) const = 0;
+
+ virtual void _multimesh_set_mesh(RID p_multimesh, RID p_mesh) = 0;
+ virtual void _multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) = 0;
+ virtual void _multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) = 0;
+ virtual void _multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) = 0;
+ virtual void _multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) = 0;
+
+ virtual void _multimesh_set_custom_aabb(RID p_multimesh, const AABB &p_aabb) = 0;
+ virtual AABB _multimesh_get_custom_aabb(RID p_multimesh) const = 0;
+
+ virtual RID _multimesh_get_mesh(RID p_multimesh) const = 0;
+
+ virtual Transform3D _multimesh_instance_get_transform(RID p_multimesh, int p_index) const = 0;
+ virtual Transform2D _multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const = 0;
+ virtual Color _multimesh_instance_get_color(RID p_multimesh, int p_index) const = 0;
+ virtual Color _multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const = 0;
+
+ virtual void _multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) = 0;
+ virtual Vector<float> _multimesh_get_buffer(RID p_multimesh) const = 0;
+
+ virtual void _multimesh_set_visible_instances(RID p_multimesh, int p_visible) = 0;
+ virtual int _multimesh_get_visible_instances(RID p_multimesh) const = 0;
+
+ virtual AABB _multimesh_get_aabb(RID p_multimesh) const = 0;
+
+ // Multimesh is responsible for allocating / destroying a MultiMeshInterpolator object.
+ // This allows shared functionality for interpolation across backends.
+ virtual MultiMeshInterpolator *_multimesh_get_interpolator(RID p_multimesh) const = 0;
+
+private:
+ void _multimesh_add_to_interpolation_lists(RID p_multimesh, MultiMeshInterpolator &r_mmi);
+
+public:
/* SKELETON API */
virtual RID skeleton_allocate() = 0;
@@ -137,6 +208,19 @@ public:
virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) = 0;
virtual void skeleton_update_dependency(RID p_base, DependencyTracker *p_instance) = 0;
+
+ /* INTERPOLATION */
+
+ struct InterpolationData {
+ void notify_free_multimesh(RID p_rid);
+ LocalVector<RID> multimesh_interpolate_update_list;
+ LocalVector<RID> multimesh_transform_update_lists[2];
+ LocalVector<RID> *multimesh_transform_update_list_curr = &multimesh_transform_update_lists[0];
+ LocalVector<RID> *multimesh_transform_update_list_prev = &multimesh_transform_update_lists[1];
+ } _interpolation_data;
+
+ void update_interpolation_tick(bool p_process = true);
+ void update_interpolation_frame(bool p_process = true);
};
#endif // MESH_STORAGE_H