diff options
Diffstat (limited to 'servers')
59 files changed, 797 insertions, 310 deletions
diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp index 455a8b49a1..65d88a0eba 100644 --- a/servers/audio/audio_stream.cpp +++ b/servers/audio/audio_stream.cpp @@ -810,7 +810,11 @@ void AudioStreamPlaybackRandomizer::tag_used_streams() { int AudioStreamPlaybackRandomizer::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) { if (playing.is_valid()) { - return playing->mix(p_buffer, p_rate_scale * pitch_scale, p_frames); + int mixed_samples = playing->mix(p_buffer, p_rate_scale * pitch_scale, p_frames); + for (int samp = 0; samp < mixed_samples; samp++) { + p_buffer[samp] *= volume_scale; + } + return mixed_samples; } else { for (int i = 0; i < p_frames; i++) { p_buffer[i] = AudioFrame(0, 0); diff --git a/servers/physics_2d/godot_area_2d.cpp b/servers/physics_2d/godot_area_2d.cpp index 4d2148aa07..d6c786706c 100644 --- a/servers/physics_2d/godot_area_2d.cpp +++ b/servers/physics_2d/godot_area_2d.cpp @@ -78,13 +78,6 @@ void GodotArea2D::set_space(GodotSpace2D *p_space) { } void GodotArea2D::set_monitor_callback(const Callable &p_callback) { - ObjectID id = p_callback.get_object_id(); - - if (id == monitor_callback.get_object_id()) { - monitor_callback = p_callback; - return; - } - _unregister_shapes(); monitor_callback = p_callback; @@ -100,13 +93,6 @@ void GodotArea2D::set_monitor_callback(const Callable &p_callback) { } void GodotArea2D::set_area_monitor_callback(const Callable &p_callback) { - ObjectID id = p_callback.get_object_id(); - - if (id == area_monitor_callback.get_object_id()) { - area_monitor_callback = p_callback; - return; - } - _unregister_shapes(); area_monitor_callback = p_callback; @@ -194,7 +180,7 @@ Variant GodotArea2D::get_param(PhysicsServer2D::AreaParameter p_param) const { } void GodotArea2D::_queue_monitor_update() { - ERR_FAIL_COND(!get_space()); + ERR_FAIL_NULL(get_space()); if (!monitor_query_list.in_list()) { get_space()->area_add_to_monitor_query_list(&monitor_query_list); diff --git a/servers/physics_2d/godot_body_2d.cpp b/servers/physics_2d/godot_body_2d.cpp index 4a7b470768..12c3e1e5b4 100644 --- a/servers/physics_2d/godot_body_2d.cpp +++ b/servers/physics_2d/godot_body_2d.cpp @@ -422,7 +422,7 @@ void GodotBody2D::integrate_forces(real_t p_step) { return; } - ERR_FAIL_COND(!get_space()); + ERR_FAIL_NULL(get_space()); int ac = areas.size(); @@ -615,7 +615,7 @@ void GodotBody2D::integrate_velocities(real_t p_step) { return; } - if (fi_callback_data || body_state_callback.get_object()) { + if (fi_callback_data || body_state_callback.is_valid()) { get_space()->body_add_to_state_query_list(&direct_state_query_list); } @@ -676,7 +676,7 @@ void GodotBody2D::call_queries() { Variant direct_state_variant = get_direct_state(); if (fi_callback_data) { - if (!fi_callback_data->callable.get_object()) { + if (!fi_callback_data->callable.is_valid()) { set_force_integration_callback(Callable()); } else { const Variant *vp[2] = { &direct_state_variant, &fi_callback_data->udata }; @@ -692,7 +692,7 @@ void GodotBody2D::call_queries() { } } - if (body_state_callback.get_object()) { + if (body_state_callback.is_valid()) { body_state_callback.call(direct_state_variant); } } @@ -719,7 +719,7 @@ void GodotBody2D::set_state_sync_callback(const Callable &p_callable) { } void GodotBody2D::set_force_integration_callback(const Callable &p_callable, const Variant &p_udata) { - if (p_callable.get_object()) { + if (p_callable.is_valid()) { if (!fi_callback_data) { fi_callback_data = memnew(ForceIntegrationCallbackData); } diff --git a/servers/physics_2d/godot_physics_server_2d.cpp b/servers/physics_2d/godot_physics_server_2d.cpp index 112ba240b6..8df17992ea 100644 --- a/servers/physics_2d/godot_physics_server_2d.cpp +++ b/servers/physics_2d/godot_physics_server_2d.cpp @@ -994,7 +994,7 @@ void GodotPhysicsServer2D::body_set_pickable(RID p_body, bool p_pickable) { bool GodotPhysicsServer2D::body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result) { GodotBody2D *body = body_owner.get_or_null(p_body); ERR_FAIL_NULL_V(body, false); - ERR_FAIL_COND_V(!body->get_space(), false); + ERR_FAIL_NULL_V(body->get_space(), false); ERR_FAIL_COND_V(body->get_space()->is_locked(), false); _update_shapes(); diff --git a/servers/physics_3d/godot_area_3d.cpp b/servers/physics_3d/godot_area_3d.cpp index 5bf16aa688..d0b287b058 100644 --- a/servers/physics_3d/godot_area_3d.cpp +++ b/servers/physics_3d/godot_area_3d.cpp @@ -87,12 +87,6 @@ void GodotArea3D::set_space(GodotSpace3D *p_space) { } void GodotArea3D::set_monitor_callback(const Callable &p_callback) { - ObjectID id = p_callback.get_object_id(); - if (id == monitor_callback.get_object_id()) { - monitor_callback = p_callback; - return; - } - _unregister_shapes(); monitor_callback = p_callback; @@ -108,12 +102,6 @@ void GodotArea3D::set_monitor_callback(const Callable &p_callback) { } void GodotArea3D::set_area_monitor_callback(const Callable &p_callback) { - ObjectID id = p_callback.get_object_id(); - if (id == area_monitor_callback.get_object_id()) { - area_monitor_callback = p_callback; - return; - } - _unregister_shapes(); area_monitor_callback = p_callback; @@ -223,7 +211,7 @@ Variant GodotArea3D::get_param(PhysicsServer3D::AreaParameter p_param) const { } void GodotArea3D::_queue_monitor_update() { - ERR_FAIL_COND(!get_space()); + ERR_FAIL_NULL(get_space()); if (!monitor_query_list.in_list()) { get_space()->area_add_to_monitor_query_list(&monitor_query_list); diff --git a/servers/physics_3d/godot_body_3d.cpp b/servers/physics_3d/godot_body_3d.cpp index 21d5e49828..e102d0f3c9 100644 --- a/servers/physics_3d/godot_body_3d.cpp +++ b/servers/physics_3d/godot_body_3d.cpp @@ -477,7 +477,7 @@ void GodotBody3D::integrate_forces(real_t p_step) { return; } - ERR_FAIL_COND(!get_space()); + ERR_FAIL_NULL(get_space()); int ac = areas.size(); @@ -674,7 +674,7 @@ void GodotBody3D::integrate_velocities(real_t p_step) { return; } - if (fi_callback_data || body_state_callback.get_object()) { + if (fi_callback_data || body_state_callback.is_valid()) { get_space()->body_add_to_state_query_list(&direct_state_query_list); } @@ -759,7 +759,7 @@ void GodotBody3D::call_queries() { Variant direct_state_variant = get_direct_state(); if (fi_callback_data) { - if (!fi_callback_data->callable.get_object()) { + if (!fi_callback_data->callable.is_valid()) { set_force_integration_callback(Callable()); } else { const Variant *vp[2] = { &direct_state_variant, &fi_callback_data->udata }; @@ -771,7 +771,7 @@ void GodotBody3D::call_queries() { } } - if (body_state_callback.get_object()) { + if (body_state_callback.is_valid()) { body_state_callback.call(direct_state_variant); } } @@ -798,7 +798,7 @@ void GodotBody3D::set_state_sync_callback(const Callable &p_callable) { } void GodotBody3D::set_force_integration_callback(const Callable &p_callable, const Variant &p_udata) { - if (p_callable.get_object()) { + if (p_callable.is_valid()) { if (!fi_callback_data) { fi_callback_data = memnew(ForceIntegrationCallbackData); } diff --git a/servers/physics_3d/godot_physics_server_3d.cpp b/servers/physics_3d/godot_physics_server_3d.cpp index 4118a19f10..8a7b4e0f07 100644 --- a/servers/physics_3d/godot_physics_server_3d.cpp +++ b/servers/physics_3d/godot_physics_server_3d.cpp @@ -912,7 +912,7 @@ void GodotPhysicsServer3D::body_set_ray_pickable(RID p_body, bool p_enable) { bool GodotPhysicsServer3D::body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result) { GodotBody3D *body = body_owner.get_or_null(p_body); ERR_FAIL_NULL_V(body, false); - ERR_FAIL_COND_V(!body->get_space(), false); + ERR_FAIL_NULL_V(body->get_space(), false); ERR_FAIL_COND_V(body->get_space()->is_locked(), false); _update_shapes(); @@ -1225,7 +1225,7 @@ void GodotPhysicsServer3D::joint_make_pin(RID p_joint, RID p_body_A, const Vecto ERR_FAIL_NULL(body_A); if (!p_body_B.is_valid()) { - ERR_FAIL_COND(!body_A->get_space()); + ERR_FAIL_NULL(body_A->get_space()); p_body_B = body_A->get_space()->get_static_global_body(); } @@ -1297,7 +1297,7 @@ void GodotPhysicsServer3D::joint_make_hinge(RID p_joint, RID p_body_A, const Tra ERR_FAIL_NULL(body_A); if (!p_body_B.is_valid()) { - ERR_FAIL_COND(!body_A->get_space()); + ERR_FAIL_NULL(body_A->get_space()); p_body_B = body_A->get_space()->get_static_global_body(); } @@ -1321,7 +1321,7 @@ void GodotPhysicsServer3D::joint_make_hinge_simple(RID p_joint, RID p_body_A, co ERR_FAIL_NULL(body_A); if (!p_body_B.is_valid()) { - ERR_FAIL_COND(!body_A->get_space()); + ERR_FAIL_NULL(body_A->get_space()); p_body_B = body_A->get_space()->get_static_global_body(); } @@ -1422,7 +1422,7 @@ void GodotPhysicsServer3D::joint_make_slider(RID p_joint, RID p_body_A, const Tr ERR_FAIL_NULL(body_A); if (!p_body_B.is_valid()) { - ERR_FAIL_COND(!body_A->get_space()); + ERR_FAIL_NULL(body_A->get_space()); p_body_B = body_A->get_space()->get_static_global_body(); } @@ -1462,7 +1462,7 @@ void GodotPhysicsServer3D::joint_make_cone_twist(RID p_joint, RID p_body_A, cons ERR_FAIL_NULL(body_A); if (!p_body_B.is_valid()) { - ERR_FAIL_COND(!body_A->get_space()); + ERR_FAIL_NULL(body_A->get_space()); p_body_B = body_A->get_space()->get_static_global_body(); } @@ -1502,7 +1502,7 @@ void GodotPhysicsServer3D::joint_make_generic_6dof(RID p_joint, RID p_body_A, co ERR_FAIL_NULL(body_A); if (!p_body_B.is_valid()) { - ERR_FAIL_COND(!body_A->get_space()); + ERR_FAIL_NULL(body_A->get_space()); p_body_B = body_A->get_space()->get_static_global_body(); } diff --git a/servers/physics_3d/godot_soft_body_3d.cpp b/servers/physics_3d/godot_soft_body_3d.cpp index 20b19ab243..0c2b935554 100644 --- a/servers/physics_3d/godot_soft_body_3d.cpp +++ b/servers/physics_3d/godot_soft_body_3d.cpp @@ -967,7 +967,7 @@ Vector3 GodotSoftBody3D::_compute_area_windforce(const GodotArea3D *p_area, cons void GodotSoftBody3D::predict_motion(real_t p_delta) { const real_t inv_delta = 1.0 / p_delta; - ERR_FAIL_COND(!get_space()); + ERR_FAIL_NULL(get_space()); bool gravity_done = false; Vector3 gravity; diff --git a/servers/rendering/dummy/environment/gi.h b/servers/rendering/dummy/environment/gi.h index a26938c740..5d0e84ae43 100644 --- a/servers/rendering/dummy/environment/gi.h +++ b/servers/rendering/dummy/environment/gi.h @@ -78,6 +78,8 @@ public: virtual bool voxel_gi_is_using_two_bounces(RID p_voxel_gi) const override { return false; } virtual uint32_t voxel_gi_get_version(RID p_voxel_gi) const override { return 0; } + + virtual void sdfgi_reset() override {} }; } // namespace RendererDummy diff --git a/servers/rendering/dummy/rasterizer_canvas_dummy.h b/servers/rendering/dummy/rasterizer_canvas_dummy.h index 455a669277..862b941a73 100644 --- a/servers/rendering/dummy/rasterizer_canvas_dummy.h +++ b/servers/rendering/dummy/rasterizer_canvas_dummy.h @@ -55,6 +55,8 @@ public: bool free(RID p_rid) override { return true; } void update() override {} + virtual void set_debug_redraw(bool p_enabled, double p_time, const Color &p_color) override {} + RasterizerCanvasDummy() {} ~RasterizerCanvasDummy() {} }; diff --git a/servers/rendering/dummy/storage/particles_storage.h b/servers/rendering/dummy/storage/particles_storage.h index a40c96a8f5..33dad3f2f4 100644 --- a/servers/rendering/dummy/storage/particles_storage.h +++ b/servers/rendering/dummy/storage/particles_storage.h @@ -47,6 +47,7 @@ public: virtual void particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) override {} virtual void particles_set_emitting(RID p_particles, bool p_emitting) override {} virtual void particles_set_amount(RID p_particles, int p_amount) override {} + virtual void particles_set_amount_ratio(RID p_particles, float p_amount_ratio) override {} virtual void particles_set_lifetime(RID p_particles, double p_lifetime) override {} virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) override {} virtual void particles_set_pre_process_time(RID p_particles, double p_time) override {} @@ -81,6 +82,8 @@ public: virtual AABB particles_get_aabb(RID p_particles) const override { return AABB(); } virtual void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) override {} + virtual void particles_set_emitter_velocity(RID p_particles, const Vector3 &p_velocity) override {} + virtual void particles_set_interp_to_end(RID p_particles, float p_interp) override {} virtual bool particles_get_emitting(RID p_particles) override { return false; } virtual int particles_get_draw_passes(RID p_particles) const override { return 0; } diff --git a/servers/rendering/environment/renderer_gi.h b/servers/rendering/environment/renderer_gi.h index 6eff319882..94e2c1afda 100644 --- a/servers/rendering/environment/renderer_gi.h +++ b/servers/rendering/environment/renderer_gi.h @@ -79,6 +79,8 @@ public: virtual bool voxel_gi_is_using_two_bounces(RID p_voxel_gi) const = 0; virtual uint32_t voxel_gi_get_version(RID p_probe) const = 0; + + virtual void sdfgi_reset() = 0; }; #endif // RENDERER_GI_H diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index d6040e8820..c5206017f7 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -30,6 +30,7 @@ #include "renderer_canvas_cull.h" +#include "core/config/project_settings.h" #include "core/math/geometry_2d.h" #include "renderer_viewport.h" #include "rendering_server_default.h" @@ -1557,6 +1558,11 @@ void RendererCanvasCull::canvas_item_clear(RID p_item) { ERR_FAIL_NULL(canvas_item); canvas_item->clear(); +#ifdef DEBUG_ENABLED + if (debug_redraw) { + canvas_item->debug_redraw_time = debug_redraw_time; + } +#endif } void RendererCanvasCull::canvas_item_set_draw_index(RID p_item, int p_index) { @@ -1612,6 +1618,15 @@ void RendererCanvasCull::canvas_item_set_visibility_notifier(RID p_item, bool p_ } } +void RendererCanvasCull::canvas_item_set_debug_redraw(bool p_enabled) { + debug_redraw = p_enabled; + RSG::canvas_render->set_debug_redraw(p_enabled, debug_redraw_time, debug_redraw_color); +} + +bool RendererCanvasCull::canvas_item_get_debug_redraw() const { + return debug_redraw; +} + void RendererCanvasCull::canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin, bool p_fit_empty, float p_fit_margin, bool p_blur_mipmaps) { Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_NULL(canvas_item); @@ -2151,6 +2166,9 @@ RendererCanvasCull::RendererCanvasCull() { z_last_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *)); disable_scale = false; + + debug_redraw_time = GLOBAL_DEF("debug/canvas_items/debug_redraw_time", 1.0); + debug_redraw_color = GLOBAL_DEF("debug/canvas_items/debug_redraw_color", Color(1.0, 0.2, 0.2, 0.5)); } RendererCanvasCull::~RendererCanvasCull() { diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h index 4f11d2c7b1..0f51abbb26 100644 --- a/servers/rendering/renderer_canvas_cull.h +++ b/servers/rendering/renderer_canvas_cull.h @@ -174,6 +174,10 @@ public: bool sdf_used = false; bool snapping_2d_transforms_to_pixel = false; + bool debug_redraw = false; + double debug_redraw_time = 0; + Color debug_redraw_color; + PagedAllocator<Item::VisibilityNotifierData> visibility_notifier_allocator; SelfList<Item::VisibilityNotifierData>::List visibility_notifier_list; @@ -260,6 +264,9 @@ public: void canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin = 5.0, bool p_fit_empty = false, float p_fit_margin = 0.0, bool p_blur_mipmaps = false); + void canvas_item_set_debug_redraw(bool p_enabled); + bool canvas_item_get_debug_redraw() const; + RID canvas_light_allocate(); void canvas_light_initialize(RID p_rid); diff --git a/servers/rendering/renderer_canvas_render.h b/servers/rendering/renderer_canvas_render.h index c30e53c29e..ef4de9ce54 100644 --- a/servers/rendering/renderer_canvas_render.h +++ b/servers/rendering/renderer_canvas_render.h @@ -358,6 +358,9 @@ public: Command *last_command = nullptr; Vector<CommandBlock> blocks; uint32_t current_block; +#ifdef DEBUG_ENABLED + mutable double debug_redraw_time = 0; +#endif template <class T> T *alloc_command() { @@ -517,6 +520,8 @@ public: virtual bool free(RID p_rid) = 0; virtual void update() = 0; + virtual void set_debug_redraw(bool p_enabled, double p_time, const Color &p_color) = 0; + RendererCanvasRender() { singleton = this; } virtual ~RendererCanvasRender() {} }; diff --git a/servers/rendering/renderer_rd/effects/debug_effects.cpp b/servers/rendering/renderer_rd/effects/debug_effects.cpp index abcd9bbfae..3033d42375 100644 --- a/servers/rendering/renderer_rd/effects/debug_effects.cpp +++ b/servers/rendering/renderer_rd/effects/debug_effects.cpp @@ -108,7 +108,7 @@ void DebugEffects::_create_frustum_arrays() { // Create our index_array PackedByteArray data; - data.resize(6 * 2 * 3 * 4); + data.resize(6 * 2 * 3 * 2); { uint8_t *w = data.ptrw(); uint16_t *p16 = (uint16_t *)w; @@ -142,7 +142,7 @@ void DebugEffects::_create_frustum_arrays() { // Create our lines_array PackedByteArray data; - data.resize(12 * 2 * 4); + data.resize(12 * 2 * 2); { uint8_t *w = data.ptrw(); uint16_t *p16 = (uint16_t *)w; diff --git a/servers/rendering/renderer_rd/environment/gi.cpp b/servers/rendering/renderer_rd/environment/gi.cpp index 0667ae87e5..dce8fadb63 100644 --- a/servers/rendering/renderer_rd/environment/gi.cpp +++ b/servers/rendering/renderer_rd/environment/gi.cpp @@ -392,6 +392,10 @@ Dependency *GI::voxel_gi_get_dependency(RID p_voxel_gi) const { return &voxel_gi->dependency; } +void GI::sdfgi_reset() { + sdfgi_current_version++; +} + //////////////////////////////////////////////////////////////////////////////// // SDFGI @@ -416,6 +420,7 @@ void GI::SDFGI::create(RID p_env, const Vector3 &p_world_position, uint32_t p_re y_scale_mode = RendererSceneRenderRD::get_singleton()->environment_get_sdfgi_y_scale(p_env); static const float y_scale[3] = { 2.0, 1.5, 1.0 }; y_mult = y_scale[y_scale_mode]; + version = gi->sdfgi_current_version; cascades.resize(num_cascades); probe_axis_count = SDFGI::PROBE_DIVISOR + 1; solid_cell_ratio = gi->sdfgi_solid_cell_ratio; diff --git a/servers/rendering/renderer_rd/environment/gi.h b/servers/rendering/renderer_rd/environment/gi.h index 9a45919a2f..c46d4cbd25 100644 --- a/servers/rendering/renderer_rd/environment/gi.h +++ b/servers/rendering/renderer_rd/environment/gi.h @@ -667,6 +667,7 @@ public: float y_mult = 1.0; + uint32_t version = 0; uint32_t render_pass = 0; int32_t cascade_dynamic_light_count[SDFGI::MAX_CASCADES]; //used dynamically @@ -701,11 +702,14 @@ public: Vector3 sdfgi_debug_probe_dir; bool sdfgi_debug_probe_enabled = false; Vector3i sdfgi_debug_probe_index; + uint32_t sdfgi_current_version = 0; /* SDFGI UPDATE */ int sdfgi_get_lightprobe_octahedron_size() const { return SDFGI::LIGHTPROBE_OCT_SIZE; } + virtual void sdfgi_reset() override; + struct SDFGIData { float grid_size[3]; uint32_t max_cascades; 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 efec3b5072..2397249ca5 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -1390,6 +1390,11 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo sdfgi->store_probes(); } + Size2i viewport_size = Size2i(1, 1); + if (rb.is_valid()) { + viewport_size = rb->get_internal_size(); + } + p_render_data->cube_shadows.clear(); p_render_data->shadows.clear(); p_render_data->directional_shadows.clear(); @@ -1412,7 +1417,7 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo //cube shadows are rendered in their own way for (const int &index : p_render_data->cube_shadows) { - _render_shadow_pass(p_render_data->render_shadows[index].light, p_render_data->shadow_atlas, p_render_data->render_shadows[index].pass, p_render_data->render_shadows[index].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info); + _render_shadow_pass(p_render_data->render_shadows[index].light, p_render_data->shadow_atlas, p_render_data->render_shadows[index].pass, p_render_data->render_shadows[index].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info, viewport_size); } if (p_render_data->directional_shadows.size()) { @@ -1442,11 +1447,11 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo //render directional shadows for (uint32_t i = 0; i < p_render_data->directional_shadows.size(); i++) { - _render_shadow_pass(p_render_data->render_shadows[p_render_data->directional_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->directional_shadows[i]].pass, p_render_data->render_shadows[p_render_data->directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, false, i == p_render_data->directional_shadows.size() - 1, false, p_render_data->render_info); + _render_shadow_pass(p_render_data->render_shadows[p_render_data->directional_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->directional_shadows[i]].pass, p_render_data->render_shadows[p_render_data->directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, false, i == p_render_data->directional_shadows.size() - 1, false, p_render_data->render_info, viewport_size); } //render positional shadows for (uint32_t i = 0; i < p_render_data->shadows.size(); i++) { - _render_shadow_pass(p_render_data->render_shadows[p_render_data->shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->shadows[i]].pass, p_render_data->render_shadows[p_render_data->shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, i == 0, i == p_render_data->shadows.size() - 1, true, p_render_data->render_info); + _render_shadow_pass(p_render_data->render_shadows[p_render_data->shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->shadows[i]].pass, p_render_data->render_shadows[p_render_data->shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, i == 0, i == p_render_data->shadows.size() - 1, true, p_render_data->render_info, viewport_size); } _render_shadow_process(); @@ -1734,7 +1739,12 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co _setup_voxelgis(*p_render_data->voxel_gi_instances); _setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, false); - _update_render_base_uniform_set(rb->get_samplers()); // May have changed due to the above (light buffer enlarged, as an example). + // May have changed due to the above (light buffer enlarged, as an example). + if (is_reflection_probe) { + _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), BASE_UNIFORM_SET_CACHE_DEFAULT); + } else { + _update_render_base_uniform_set(rb->get_samplers(), BASE_UNIFORM_SET_CACHE_VIEWPORT); + } _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR, using_sdfgi, using_sdfgi || using_voxelgi, using_motion_pass); render_list[RENDER_LIST_OPAQUE].sort_by_key(); @@ -1965,7 +1975,11 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co p_render_data->scene_data->opaque_prepass_threshold = 0.0f; // Shadow pass can change the base uniform set samplers. - _update_render_base_uniform_set(rb->get_samplers()); + if (is_reflection_probe) { + _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), BASE_UNIFORM_SET_CACHE_DEFAULT); + } else { + _update_render_base_uniform_set(rb->get_samplers(), BASE_UNIFORM_SET_CACHE_VIEWPORT); + } _setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, true, using_motion_pass); @@ -2137,6 +2151,12 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co RD::get_singleton()->draw_list_end(); } + if (rb_data.is_valid() && using_fsr2) { + // Make sure the upscaled texture is initialized, but not necessarily filled, before running screen copies + // so it properly detect if a dedicated copy texture should be used. + rb->ensure_upscaled(); + } + if (scene_state.used_screen_texture) { RENDER_TIMESTAMP("Copy Screen Texture"); @@ -2200,7 +2220,6 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co if (rb_data.is_valid() && (using_fsr2 || using_taa)) { if (using_fsr2) { - rb->ensure_upscaled(); rb_data->ensure_fsr2(fsr2_effect); RID exposure; @@ -2305,7 +2324,7 @@ void RenderForwardClustered::_render_buffers_debug_draw(const RenderDataRD *p_re } } -void RenderForwardClustered::_render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, bool p_open_pass, bool p_close_pass, bool p_clear_region, RenderingMethod::RenderInfo *p_render_info) { +void RenderForwardClustered::_render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, bool p_open_pass, bool p_close_pass, bool p_clear_region, RenderingMethod::RenderInfo *p_render_info, const Size2i &p_viewport_size) { RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); ERR_FAIL_COND(!light_storage->owns_light_instance(p_light)); @@ -2460,7 +2479,7 @@ void RenderForwardClustered::_render_shadow_pass(RID p_light, RID p_shadow_atlas if (render_cubemap) { //rendering to cubemap - _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, reverse_cull_face, false, false, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, Rect2(), false, true, true, true, p_render_info); + _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, reverse_cull_face, false, false, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, Rect2(), false, true, true, true, p_render_info, p_viewport_size); if (finalize_cubemap) { _render_shadow_process(); _render_shadow_end(); @@ -2478,20 +2497,20 @@ void RenderForwardClustered::_render_shadow_pass(RID p_light, RID p_shadow_atlas } else { //render shadow - _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, reverse_cull_face, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, atlas_rect, flip_y, p_clear_region, p_open_pass, p_close_pass, p_render_info); + _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, reverse_cull_face, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, atlas_rect, flip_y, p_clear_region, p_open_pass, p_close_pass, p_render_info, p_viewport_size); } } void RenderForwardClustered::_render_shadow_begin() { scene_state.shadow_passes.clear(); RD::get_singleton()->draw_command_begin_label("Shadow Setup"); - _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default()); + _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), BASE_UNIFORM_SET_CACHE_DEFAULT); render_list[RENDER_LIST_SECONDARY].clear(); scene_state.instance_data[RENDER_LIST_SECONDARY].clear(); } -void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_reverse_cull_face, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end, RenderingMethod::RenderInfo *p_render_info) { +void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_reverse_cull_face, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end, RenderingMethod::RenderInfo *p_render_info, const Size2i &p_viewport_size) { uint32_t shadow_pass_index = scene_state.shadow_passes.size(); SceneState::ShadowPass shadow_pass; @@ -2515,7 +2534,7 @@ void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const Page render_data.instances = &p_instances; render_data.render_info = p_render_info; - _setup_environment(&render_data, true, Vector2(1, 1), !p_flip_y, Color(), false, false, p_use_pancake, shadow_pass_index); + _setup_environment(&render_data, true, p_viewport_size, !p_flip_y, Color(), false, false, p_use_pancake, shadow_pass_index); if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) { scene_data.screen_mesh_lod_threshold = 0.0; @@ -2609,7 +2628,7 @@ void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, con render_data.cluster_max_elements = 32; render_data.instances = &p_instances; - _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default()); + _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), BASE_UNIFORM_SET_CACHE_DEFAULT); _setup_environment(&render_data, true, Vector2(1, 1), true, Color(), false, false, false); @@ -2655,7 +2674,7 @@ void RenderForwardClustered::_render_material(const Transform3D &p_cam_transform scene_shader.enable_advanced_shader_group(); - _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default()); + _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), BASE_UNIFORM_SET_CACHE_DEFAULT); _setup_environment(&render_data, true, Vector2(1, 1), false, Color()); @@ -2706,7 +2725,7 @@ void RenderForwardClustered::_render_uv2(const PagedArray<RenderGeometryInstance scene_shader.enable_advanced_shader_group(); - _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default()); + _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), BASE_UNIFORM_SET_CACHE_DEFAULT); _setup_environment(&render_data, true, Vector2(1, 1), false, Color()); @@ -2775,7 +2794,7 @@ void RenderForwardClustered::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_bu render_data.cluster_max_elements = 32; render_data.instances = &p_instances; - _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default()); + _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), BASE_UNIFORM_SET_CACHE_DEFAULT); PassMode pass_mode = PASS_MODE_SDF; _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode); @@ -2849,21 +2868,23 @@ void RenderForwardClustered::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_bu } void RenderForwardClustered::base_uniforms_changed() { - if (!render_base_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) { - RD::get_singleton()->free(render_base_uniform_set); + for (int i = 0; i < BASE_UNIFORM_SET_CACHE_MAX; i++) { + if (!render_base_uniform_set_cache[i].is_null() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set_cache[i])) { + RD::get_singleton()->free(render_base_uniform_set_cache[i]); + } + render_base_uniform_set_cache[i] = RID(); } - render_base_uniform_set = RID(); } -void RenderForwardClustered::_update_render_base_uniform_set(const RendererRD::MaterialStorage::Samplers &p_samplers) { +void RenderForwardClustered::_update_render_base_uniform_set(const RendererRD::MaterialStorage::Samplers &p_samplers, BaseUniformSetCache p_cache_index) { RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); - if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != light_storage->lightmap_array_get_version())) { - if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) { - RD::get_singleton()->free(render_base_uniform_set); + if (render_base_uniform_set_cache[p_cache_index].is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set_cache[p_cache_index]) || (lightmap_texture_array_version_cache[p_cache_index] != light_storage->lightmap_array_get_version())) { + if (render_base_uniform_set_cache[p_cache_index].is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set_cache[p_cache_index])) { + RD::get_singleton()->free(render_base_uniform_set_cache[p_cache_index]); } - lightmap_texture_array_version = light_storage->lightmap_array_get_version(); + lightmap_texture_array_version_cache[p_cache_index] = light_storage->lightmap_array_get_version(); Vector<RD::Uniform> uniforms; @@ -3020,8 +3041,9 @@ void RenderForwardClustered::_update_render_base_uniform_set(const RendererRD::M uniforms.append_array(p_samplers.get_uniforms(SAMPLERS_BINDING_FIRST_INDEX)); - render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, SCENE_UNIFORM_SET); + render_base_uniform_set_cache[p_cache_index] = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, SCENE_UNIFORM_SET); } + render_base_uniform_set = render_base_uniform_set_cache[p_cache_index]; } RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas, int p_index) { @@ -3481,14 +3503,18 @@ void RenderForwardClustered::sdfgi_update(const Ref<RenderSceneBuffers> &p_rende } bool needs_sdfgi = p_environment.is_valid() && environment_get_sdfgi_enabled(p_environment); + bool needs_reset = sdfgi.is_valid() ? sdfgi->version != gi.sdfgi_current_version : false; - if (!needs_sdfgi) { + if (!needs_sdfgi || needs_reset) { if (sdfgi.is_valid()) { // delete it sdfgi.unref(); rb->set_custom_data(RB_SCOPE_SDFGI, sdfgi); } - return; + + if (!needs_sdfgi) { + return; + } } // Ensure advanced shaders are available if SDFGI is used. @@ -3693,6 +3719,11 @@ void RenderForwardClustered::_geometry_instance_add_surface_with_material(Geomet sdcache->sort.priority = p_material->priority; sdcache->sort.uses_projector = ginstance->using_projectors; sdcache->sort.uses_softshadow = ginstance->using_softshadows; + + uint64_t format = RendererRD::MeshStorage::get_singleton()->mesh_surface_get_format(sdcache->surface); + if (p_material->shader_data->uses_tangent && !(format & RS::ARRAY_FORMAT_TANGENT)) { + WARN_PRINT_ED("Attempting to use a shader that requires tangents with a mesh that doesn't contain tangents. Ensure that meshes are imported with the 'ensure_tangents' option. If creating your own meshes, add an `ARRAY_TANGENT` array (when using ArrayMesh) or call `generate_tangents()` (when using SurfaceTool)."); + } } void RenderForwardClustered::_geometry_instance_add_surface_with_material_chain(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, SceneShaderForwardClustered::MaterialData *p_material, RID p_mat_src, RID p_mesh) { 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 46deb30cde..bedf119210 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -158,11 +158,20 @@ class RenderForwardClustered : public RendererSceneRenderRD { virtual void setup_render_buffer_data(Ref<RenderSceneBuffersRD> p_render_buffers) override; + enum BaseUniformSetCache { + BASE_UNIFORM_SET_CACHE_VIEWPORT, + BASE_UNIFORM_SET_CACHE_DEFAULT, + BASE_UNIFORM_SET_CACHE_MAX + }; + RID render_base_uniform_set; + // One for custom samplers, one for default samplers. + // Need to switch between them as default is needed for probes, shadows, materials, etc. + RID render_base_uniform_set_cache[BASE_UNIFORM_SET_CACHE_MAX]; - uint64_t lightmap_texture_array_version = 0xFFFFFFFF; + uint64_t lightmap_texture_array_version_cache[BASE_UNIFORM_SET_CACHE_MAX] = { 0xFFFFFFFF, 0xFFFFFFFF }; - void _update_render_base_uniform_set(const RendererRD::MaterialStorage::Samplers &p_samplers); + void _update_render_base_uniform_set(const RendererRD::MaterialStorage::Samplers &p_samplers, BaseUniformSetCache p_cache_index); RID _setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture); RID _setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas = false, int p_index = 0); @@ -593,9 +602,9 @@ class RenderForwardClustered : public RendererSceneRenderRD { /* Render shadows */ - void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true, RenderingMethod::RenderInfo *p_render_info = nullptr); + void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true, RenderingMethod::RenderInfo *p_render_info = nullptr, const Size2i &p_viewport_size = Size2i(1, 1)); void _render_shadow_begin(); - void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_reverse_cull_face, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr); + void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_reverse_cull_face, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr, const Size2i &p_viewport_size = Size2i(1, 1)); void _render_shadow_process(); void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS); 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 9676474a66..5134f4d545 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 @@ -65,6 +65,8 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { uses_discard = false; uses_roughness = false; uses_normal = false; + uses_tangent = false; + bool uses_normal_map = false; bool wireframe = false; unshaded = false; @@ -121,11 +123,16 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { actions.usage_flag_pointers["TIME"] = &uses_time; actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness; actions.usage_flag_pointers["NORMAL"] = &uses_normal; - actions.usage_flag_pointers["NORMAL_MAP"] = &uses_normal; + actions.usage_flag_pointers["NORMAL_MAP"] = &uses_normal_map; actions.usage_flag_pointers["POINT_SIZE"] = &uses_point_size; actions.usage_flag_pointers["POINT_COORD"] = &uses_point_size; + actions.usage_flag_pointers["TANGENT"] = &uses_tangent; + actions.usage_flag_pointers["BINORMAL"] = &uses_tangent; + actions.usage_flag_pointers["ANISOTROPY"] = &uses_tangent; + actions.usage_flag_pointers["ANISOTROPY_FLOW"] = &uses_tangent; + actions.write_flag_pointers["MODELVIEW_MATRIX"] = &writes_modelview_or_projection; actions.write_flag_pointers["PROJECTION_MATRIX"] = &writes_modelview_or_projection; actions.write_flag_pointers["VERTEX"] = &uses_vertex; @@ -150,6 +157,8 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { uses_normal_texture = gen_code.uses_normal_roughness_texture; uses_vertex_time = gen_code.uses_vertex_time; uses_fragment_time = gen_code.uses_fragment_time; + uses_normal |= uses_normal_map; + uses_tangent |= uses_normal_map; #if 0 print_line("**compiling shader:"); diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h index 0739cd9f86..3b83b2b582 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h @@ -165,6 +165,7 @@ public: bool uses_discard = false; bool uses_roughness = false; bool uses_normal = false; + bool uses_tangent = false; bool uses_particle_trails = false; bool unshaded = false; 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 8a672d8628..462fc4b524 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -53,6 +53,7 @@ RendererRD::ForwardID RenderForwardMobile::ForwardIDStorageMobile::allocate_forw index = forward_id_allocators[p_type].allocations.size(); forward_id_allocators[p_type].allocations.push_back(true); forward_id_allocators[p_type].map.push_back(0xFF); + forward_id_allocators[p_type].last_pass.push_back(0); } else { forward_id_allocators[p_type].allocations[index] = true; } @@ -64,44 +65,72 @@ void RenderForwardMobile::ForwardIDStorageMobile::free_forward_id(RendererRD::Fo forward_id_allocators[p_type].allocations[p_id] = false; } -void RenderForwardMobile::ForwardIDStorageMobile::map_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id, uint32_t p_index) { +void RenderForwardMobile::ForwardIDStorageMobile::map_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id, uint32_t p_index, uint64_t p_last_pass) { forward_id_allocators[p_type].map[p_id] = p_index; + forward_id_allocators[p_type].last_pass[p_id] = p_last_pass; } void RenderForwardMobile::fill_push_constant_instance_indices(SceneState::InstanceData *p_instance_data, const GeometryInstanceForwardMobile *p_instance) { - // First zero out our indices. + uint64_t current_frame = RSG::rasterizer->get_frame_number(); p_instance_data->omni_lights[0] = 0xFFFFFFFF; p_instance_data->omni_lights[1] = 0xFFFFFFFF; - p_instance_data->spot_lights[0] = 0xFFFFFFFF; - p_instance_data->spot_lights[1] = 0xFFFFFFFF; - - p_instance_data->decals[0] = 0xFFFFFFFF; - p_instance_data->decals[1] = 0xFFFFFFFF; - - p_instance_data->reflection_probes[0] = 0xFFFFFFFF; - p_instance_data->reflection_probes[1] = 0xFFFFFFFF; - - for (uint32_t i = 0; i < MAX_RDL_CULL; i++) { - uint32_t ofs = i < 4 ? 0 : 1; - uint32_t shift = (i & 0x3) << 3; + uint32_t idx = 0; + for (uint32_t i = 0; i < p_instance->omni_light_count; i++) { + uint32_t ofs = idx < 4 ? 0 : 1; + uint32_t shift = (idx & 0x3) << 3; uint32_t mask = ~(0xFF << shift); - if (i < p_instance->omni_light_count) { + + if (forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_OMNI_LIGHT].last_pass[p_instance->omni_lights[i]] == current_frame) { p_instance_data->omni_lights[ofs] &= mask; p_instance_data->omni_lights[ofs] |= uint32_t(forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_OMNI_LIGHT].map[p_instance->omni_lights[i]]) << shift; + idx++; } - if (i < p_instance->spot_light_count) { + } + + p_instance_data->spot_lights[0] = 0xFFFFFFFF; + p_instance_data->spot_lights[1] = 0xFFFFFFFF; + + idx = 0; + for (uint32_t i = 0; i < p_instance->spot_light_count; i++) { + uint32_t ofs = idx < 4 ? 0 : 1; + uint32_t shift = (idx & 0x3) << 3; + uint32_t mask = ~(0xFF << shift); + if (forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_SPOT_LIGHT].last_pass[p_instance->spot_lights[i]] == current_frame) { p_instance_data->spot_lights[ofs] &= mask; p_instance_data->spot_lights[ofs] |= uint32_t(forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_SPOT_LIGHT].map[p_instance->spot_lights[i]]) << shift; + idx++; } - if (i < p_instance->decals_count) { + } + + p_instance_data->decals[0] = 0xFFFFFFFF; + p_instance_data->decals[1] = 0xFFFFFFFF; + + idx = 0; + for (uint32_t i = 0; i < p_instance->decals_count; i++) { + uint32_t ofs = idx < 4 ? 0 : 1; + uint32_t shift = (idx & 0x3) << 3; + uint32_t mask = ~(0xFF << shift); + if (forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_DECAL].last_pass[p_instance->decals[i]] == current_frame) { p_instance_data->decals[ofs] &= mask; p_instance_data->decals[ofs] |= uint32_t(forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_DECAL].map[p_instance->decals[i]]) << shift; + idx++; } - if (i < p_instance->reflection_probe_count) { + } + + p_instance_data->reflection_probes[0] = 0xFFFFFFFF; + p_instance_data->reflection_probes[1] = 0xFFFFFFFF; + + idx = 0; + for (uint32_t i = 0; i < p_instance->reflection_probe_count; i++) { + uint32_t ofs = idx < 4 ? 0 : 1; + uint32_t shift = (idx & 0x3) << 3; + uint32_t mask = ~(0xFF << shift); + if (forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_REFLECTION_PROBE].last_pass[p_instance->reflection_probes[i]] == current_frame) { p_instance_data->reflection_probes[ofs] &= mask; p_instance_data->reflection_probes[ofs] |= uint32_t(forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_REFLECTION_PROBE].map[p_instance->reflection_probes[i]]) << shift; + idx++; } } } @@ -235,7 +264,7 @@ RID RenderForwardMobile::RenderBufferDataForwardMobile::get_color_fbs(Framebuffe RID render_target = render_buffers->get_render_target(); ERR_FAIL_COND_V(render_target.is_null(), RID()); RID target_buffer; - if (texture_storage->render_target_get_msaa(render_target) == RS::VIEWPORT_MSAA_DISABLED) { + if (view_count > 1 || texture_storage->render_target_get_msaa(render_target) == RS::VIEWPORT_MSAA_DISABLED) { target_buffer = texture_storage->render_target_get_rd_texture(render_target); } else { target_buffer = texture_storage->render_target_get_rd_texture_msaa(render_target); @@ -539,7 +568,6 @@ void RenderForwardMobile::_setup_lightmaps(const RenderDataRD *p_render_data, co void RenderForwardMobile::_pre_opaque_render(RenderDataRD *p_render_data) { RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); - RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); p_render_data->cube_shadows.clear(); p_render_data->shadows.clear(); @@ -598,28 +626,11 @@ void RenderForwardMobile::_pre_opaque_render(RenderDataRD *p_render_data) { //full barrier here, we need raster, transfer and compute and it depends from the previous work RD::get_singleton()->barrier(RD::BARRIER_MASK_ALL_BARRIERS, RD::BARRIER_MASK_ALL_BARRIERS); - - bool using_shadows = true; - - if (p_render_data->reflection_probe.is_valid()) { - if (!RSG::light_storage->reflection_probe_renders_shadows(light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe))) { - using_shadows = false; - } - } else { - //do not render reflections when rendering a reflection probe - light_storage->update_reflection_probe_buffer(p_render_data, *p_render_data->reflection_probes, p_render_data->scene_data->cam_transform.affine_inverse(), p_render_data->environment); - } - - uint32_t directional_light_count = 0; - uint32_t positional_light_count = 0; - light_storage->update_light_buffers(p_render_data, *p_render_data->lights, p_render_data->scene_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count, p_render_data->directional_light_soft_shadows); - texture_storage->update_decal_buffer(*p_render_data->decals, p_render_data->scene_data->cam_transform); - - p_render_data->directional_light_count = directional_light_count; } void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) { RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); + RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); ERR_FAIL_NULL(p_render_data); @@ -668,6 +679,25 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color bool using_subpass_transparent = true; bool using_subpass_post_process = true; + bool using_shadows = true; + + if (p_render_data->reflection_probe.is_valid()) { + if (!RSG::light_storage->reflection_probe_renders_shadows(light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe))) { + using_shadows = false; + } + } else { + //do not render reflections when rendering a reflection probe + light_storage->update_reflection_probe_buffer(p_render_data, *p_render_data->reflection_probes, p_render_data->scene_data->cam_transform.affine_inverse(), p_render_data->environment); + } + + // Update light and decal buffer first so we know what lights and decals are safe to pair with. + uint32_t directional_light_count = 0; + uint32_t positional_light_count = 0; + light_storage->update_light_buffers(p_render_data, *p_render_data->lights, p_render_data->scene_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count, p_render_data->directional_light_soft_shadows); + texture_storage->update_decal_buffer(*p_render_data->decals, p_render_data->scene_data->cam_transform); + + p_render_data->directional_light_count = directional_light_count; + // fill our render lists early so we can find out if we use various features _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR); render_list[RENDER_LIST_OPAQUE].sort_by_key(); @@ -733,7 +763,12 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color _setup_lightmaps(p_render_data, *p_render_data->lightmaps, p_render_data->scene_data->cam_transform); _setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, false); - _update_render_base_uniform_set(rb->get_samplers()); //may have changed due to the above (light buffer enlarged, as an example) + // May have changed due to the above (light buffer enlarged, as an example). + if (is_reflection_probe) { + _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), BASE_UNIFORM_SET_CACHE_DEFAULT); + } else { + _update_render_base_uniform_set(rb->get_samplers(), BASE_UNIFORM_SET_CACHE_VIEWPORT); + } RD::get_singleton()->draw_command_end_label(); // Render Setup @@ -872,7 +907,11 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color p_render_data->scene_data->directional_light_count = p_render_data->directional_light_count; // Shadow pass can change the base uniform set samplers. - _update_render_base_uniform_set(rb->get_samplers()); + if (is_reflection_probe) { + _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), BASE_UNIFORM_SET_CACHE_DEFAULT); + } else { + _update_render_base_uniform_set(rb->get_samplers(), BASE_UNIFORM_SET_CACHE_VIEWPORT); + } _setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, p_render_data->render_buffers.is_valid()); @@ -1234,7 +1273,7 @@ void RenderForwardMobile::_render_shadow_pass(RID p_light, RID p_shadow_atlas, i void RenderForwardMobile::_render_shadow_begin() { scene_state.shadow_passes.clear(); RD::get_singleton()->draw_command_begin_label("Shadow Setup"); - _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default()); + _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), BASE_UNIFORM_SET_CACHE_DEFAULT); render_list[RENDER_LIST_SECONDARY].clear(); } @@ -1341,7 +1380,7 @@ void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, c RD::get_singleton()->draw_command_begin_label("Render 3D Material"); - _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default()); + _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), BASE_UNIFORM_SET_CACHE_DEFAULT); RenderSceneDataRD scene_data; scene_data.cam_projection = p_cam_projection; @@ -1392,7 +1431,7 @@ void RenderForwardMobile::_render_uv2(const PagedArray<RenderGeometryInstance *> RD::get_singleton()->draw_command_begin_label("Render UV2"); - _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default()); + _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), BASE_UNIFORM_SET_CACHE_DEFAULT); RenderSceneDataRD scene_data; scene_data.dual_paraboloid_side = 0; @@ -1466,7 +1505,7 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const RD::get_singleton()->draw_command_begin_label("Render Collider Heightfield"); - _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default()); + _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), BASE_UNIFORM_SET_CACHE_DEFAULT); RenderSceneDataRD scene_data; scene_data.cam_projection = p_cam_projection; @@ -1504,23 +1543,23 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const } void RenderForwardMobile::base_uniforms_changed() { - if (!render_base_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) { - RD::get_singleton()->free(render_base_uniform_set); + for (int i = 0; i < BASE_UNIFORM_SET_CACHE_MAX; i++) { + if (!render_base_uniform_set_cache[i].is_null() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set_cache[i])) { + RD::get_singleton()->free(render_base_uniform_set_cache[i]); + } + render_base_uniform_set_cache[i] = RID(); } - render_base_uniform_set = RID(); } -void RenderForwardMobile::_update_render_base_uniform_set(const RendererRD::MaterialStorage::Samplers &p_samplers) { +void RenderForwardMobile::_update_render_base_uniform_set(const RendererRD::MaterialStorage::Samplers &p_samplers, BaseUniformSetCache p_cache_index) { RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); - if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != light_storage->lightmap_array_get_version())) { - if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) { - RD::get_singleton()->free(render_base_uniform_set); + if (render_base_uniform_set_cache[p_cache_index].is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set_cache[p_cache_index]) || (lightmap_texture_array_version_cache[p_cache_index] != light_storage->lightmap_array_get_version())) { + if (render_base_uniform_set_cache[p_cache_index].is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set_cache[p_cache_index])) { + RD::get_singleton()->free(render_base_uniform_set_cache[p_cache_index]); } - // This is all loaded into set 0 - - lightmap_texture_array_version = light_storage->lightmap_array_get_version(); + lightmap_texture_array_version_cache[p_cache_index] = light_storage->lightmap_array_get_version(); Vector<RD::Uniform> uniforms; @@ -1669,8 +1708,9 @@ void RenderForwardMobile::_update_render_base_uniform_set(const RendererRD::Mate uniforms.append_array(p_samplers.get_uniforms(SAMPLERS_BINDING_FIRST_INDEX)); - render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, SCENE_UNIFORM_SET); + render_base_uniform_set_cache[p_cache_index] = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, SCENE_UNIFORM_SET); } + render_base_uniform_set = render_base_uniform_set_cache[p_cache_index]; } RID RenderForwardMobile::_render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) { @@ -2478,6 +2518,11 @@ void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryI sdcache->sort.geometry_id = p_mesh.get_local_index(); // sdcache->sort.uses_forward_gi = ginstance->can_sdfgi; sdcache->sort.priority = p_material->priority; + + uint64_t format = RendererRD::MeshStorage::get_singleton()->mesh_surface_get_format(sdcache->surface); + if (p_material->shader_data->uses_tangent && !(format & RS::ARRAY_FORMAT_TANGENT)) { + WARN_PRINT_ED("Attempting to use a shader that requires tangents with a mesh that doesn't contain tangents. Ensure that meshes are imported with the 'ensure_tangents' option. If creating your own meshes, add an `ARRAY_TANGENT` array (when using ArrayMesh) or call `generate_tangents()` (when using SurfaceTool)."); + } } void RenderForwardMobile::_geometry_instance_add_surface_with_material_chain(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, SceneShaderForwardMobile::MaterialData *p_material, RID p_mat_src, RID p_mesh) { 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 50bf83b612..f10d3c1568 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -198,9 +198,19 @@ private: RID _setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas = false, int p_index = 0); void _pre_opaque_render(RenderDataRD *p_render_data); - uint64_t lightmap_texture_array_version = 0xFFFFFFFF; + enum BaseUniformSetCache { + BASE_UNIFORM_SET_CACHE_VIEWPORT, + BASE_UNIFORM_SET_CACHE_DEFAULT, + BASE_UNIFORM_SET_CACHE_MAX + }; + + // One for custom samplers, one for default samplers. + // Need to switch between them as default is needed for probes, shadows, materials, etc. + RID render_base_uniform_set_cache[BASE_UNIFORM_SET_CACHE_MAX]; + + uint64_t lightmap_texture_array_version_cache[BASE_UNIFORM_SET_CACHE_MAX] = { 0xFFFFFFFF, 0xFFFFFFFF }; - void _update_render_base_uniform_set(const RendererRD::MaterialStorage::Samplers &p_samplers); + void _update_render_base_uniform_set(const RendererRD::MaterialStorage::Samplers &p_samplers, BaseUniformSetCache p_cache_index); void _update_instance_data_buffer(RenderListType p_render_list); void _fill_instance_data(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true); @@ -535,6 +545,7 @@ protected: struct ForwardIDAllocator { LocalVector<bool> allocations; LocalVector<uint8_t> map; + LocalVector<uint64_t> last_pass; }; ForwardIDAllocator forward_id_allocators[RendererRD::FORWARD_ID_MAX]; @@ -542,7 +553,7 @@ protected: public: virtual RendererRD::ForwardID allocate_forward_id(RendererRD::ForwardIDType p_type) override; virtual void free_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id) override; - virtual void map_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id, uint32_t p_index) override; + virtual void map_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id, uint32_t p_index, uint64_t p_last_pass) override; virtual bool uses_forward_ids() const override { return true; } }; 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 9a3556ce35..f1cec0e07c 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 @@ -67,6 +67,8 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { uses_discard = false; uses_roughness = false; uses_normal = false; + uses_tangent = false; + bool uses_normal_map = false; bool wireframe = false; unshaded = false; @@ -122,7 +124,12 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { actions.usage_flag_pointers["TIME"] = &uses_time; actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness; actions.usage_flag_pointers["NORMAL"] = &uses_normal; - actions.usage_flag_pointers["NORMAL_MAP"] = &uses_normal; + actions.usage_flag_pointers["NORMAL_MAP"] = &uses_normal_map; + + actions.usage_flag_pointers["TANGENT"] = &uses_tangent; + actions.usage_flag_pointers["BINORMAL"] = &uses_tangent; + actions.usage_flag_pointers["ANISOTROPY"] = &uses_tangent; + actions.usage_flag_pointers["ANISOTROPY_FLOW"] = &uses_tangent; actions.usage_flag_pointers["POINT_SIZE"] = &uses_point_size; actions.usage_flag_pointers["POINT_COORD"] = &uses_point_size; @@ -150,6 +157,8 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { uses_screen_texture = gen_code.uses_screen_texture; uses_depth_texture = gen_code.uses_depth_texture; uses_normal_texture = gen_code.uses_normal_roughness_texture; + uses_normal |= uses_normal_map; + uses_tangent |= uses_normal_map; #ifdef DEBUG_ENABLED if (uses_sss) { @@ -621,7 +630,7 @@ void SceneShaderForwardMobile::init(const String p_defines) { actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP; actions.default_repeat = ShaderLanguage::REPEAT_ENABLE; actions.global_buffer_array_variable = "global_shader_uniforms.data"; - actions.instance_uniform_index_variable = "instances.data[instance_index].instance_uniforms_ofs"; + actions.instance_uniform_index_variable = "instances.data[draw_call.instance_index].instance_uniforms_ofs"; actions.apply_luminance_multiplier = true; // apply luminance multiplier to screen texture actions.check_multiview_samplers = RendererCompositorRD::get_singleton()->is_xr_enabled(); // Make sure we check sampling multiview textures. diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h index 5c76d89247..da189c6f67 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h @@ -119,6 +119,7 @@ public: bool uses_discard = false; bool uses_roughness = false; bool uses_normal = false; + bool uses_tangent = false; bool uses_particle_trails = false; bool unshaded = false; diff --git a/servers/rendering/renderer_rd/pipeline_cache_rd.h b/servers/rendering/renderer_rd/pipeline_cache_rd.h index 2f1e79b397..0ebebd0540 100644 --- a/servers/rendering/renderer_rd/pipeline_cache_rd.h +++ b/servers/rendering/renderer_rd/pipeline_cache_rd.h @@ -38,7 +38,7 @@ class PipelineCacheRD { SpinLock spin_lock; RID shader; - uint32_t input_mask; + uint64_t input_mask; RD::RenderPrimitive render_primitive; RD::PipelineRasterizationState rasterization_state; diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 885a00856e..0b1561939e 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -485,7 +485,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend continue; } - push_constant.flags = base_flags | (push_constant.flags & (FLAGS_DEFAULT_NORMAL_MAP_USED | FLAGS_DEFAULT_SPECULAR_MAP_USED)); //reset on each command for sanity, keep canvastexture binding config + push_constant.flags = base_flags | (push_constant.flags & (FLAGS_DEFAULT_NORMAL_MAP_USED | FLAGS_DEFAULT_SPECULAR_MAP_USED)); // Reset on each command for safety, keep canvastexture binding config. switch (c->type) { case Item::Command::TYPE_RECT: { @@ -957,7 +957,48 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend c = c->next; } +#ifdef DEBUG_ENABLED + if (debug_redraw && p_item->debug_redraw_time > 0.0) { + Color dc = debug_redraw_color; + dc.a *= p_item->debug_redraw_time / debug_redraw_time; + RID pipeline = pipeline_variants->variants[PIPELINE_LIGHT_MODE_DISABLED][PIPELINE_VARIANT_QUAD].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format); + RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline); + + //bind textures + + _bind_canvas_texture(p_draw_list, RID(), current_filter, current_repeat, last_texture, push_constant, texpixel_size); + + Rect2 src_rect; + Rect2 dst_rect; + + dst_rect = Rect2(Vector2(), p_item->rect.size); + src_rect = Rect2(0, 0, 1, 1); + + push_constant.modulation[0] = dc.r; + push_constant.modulation[1] = dc.g; + push_constant.modulation[2] = dc.b; + push_constant.modulation[3] = dc.a; + + push_constant.src_rect[0] = src_rect.position.x; + push_constant.src_rect[1] = src_rect.position.y; + push_constant.src_rect[2] = src_rect.size.width; + push_constant.src_rect[3] = src_rect.size.height; + + push_constant.dst_rect[0] = dst_rect.position.x; + push_constant.dst_rect[1] = dst_rect.position.y; + push_constant.dst_rect[2] = dst_rect.size.width; + push_constant.dst_rect[3] = dst_rect.size.height; + + RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant)); + RD::get_singleton()->draw_list_bind_index_array(p_draw_list, shader.quad_index_array); + RD::get_singleton()->draw_list_draw(p_draw_list, true); + + p_item->debug_redraw_time -= RSG::rasterizer->get_frame_delta_time(); + + RenderingServerDefault::redraw_request(); + } +#endif if (current_clip && reclip) { //will make it re-enable clipping if needed afterwards current_clip = nullptr; @@ -2718,7 +2759,7 @@ bool RendererCanvasRenderRD::free(RID p_rid) { } void RendererCanvasRenderRD::set_shadow_texture_size(int p_size) { - p_size = nearest_power_of_2_templated(p_size); + p_size = MAX(1, nearest_power_of_2_templated(p_size)); if (p_size == state.shadow_texture_size) { return; } @@ -2742,6 +2783,12 @@ void RendererCanvasRenderRD::set_shadow_texture_size(int p_size) { } } +void RendererCanvasRenderRD::set_debug_redraw(bool p_enabled, double p_time, const Color &p_color) { + debug_redraw = p_enabled; + debug_redraw_time = p_time; + debug_redraw_color = p_color; +} + RendererCanvasRenderRD::~RendererCanvasRenderRD() { RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); //canvas state diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h index 4c8cbd1c9f..7dbcd903e6 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h @@ -418,6 +418,10 @@ class RendererCanvasRenderRD : public RendererCanvasRender { RID _create_base_uniform_set(RID p_to_render_target, bool p_backbuffer); + bool debug_redraw = false; + Color debug_redraw_color; + double debug_redraw_time = 1.0; + inline void _bind_canvas_texture(RD::DrawListID p_draw_list, RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID &r_last_texture, PushConstant &push_constant, Size2 &r_texpixel_size, bool p_texture_is_data = false); //recursive, so regular inline used instead. void _render_item(RenderingDevice::DrawListID p_draw_list, RID p_render_target, const Item *p_item, RenderingDevice::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, PipelineVariants *p_pipeline_variants, bool &r_sdf_used); void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool &r_sdf_used, bool p_to_backbuffer = false); @@ -450,6 +454,8 @@ public: virtual void set_shadow_texture_size(int p_size); + void set_debug_redraw(bool p_enabled, double p_time, const Color &p_color); + void set_time(double p_time); void update(); bool free(RID p_rid); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 07d56eae0c..1a33f1d6e0 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -260,15 +260,29 @@ void RendererSceneRenderRD::_render_buffers_copy_screen_texture(const RenderData RD::get_singleton()->draw_command_begin_label("Copy screen texture"); - rb->allocate_blur_textures(); - + StringName texture_name; bool can_use_storage = _render_buffers_can_be_storage(); Size2i size = rb->get_internal_size(); + // When upscaling, the blur texture needs to be at the target size for post-processing to work. We prefer to use a + // dedicated backbuffer copy texture instead if the blur texture is not an option so shader effects work correctly. + Size2i target_size = rb->get_target_size(); + bool internal_size_matches = (size.width == target_size.width) && (size.height == target_size.height); + bool reuse_blur_texture = !rb->has_upscaled_texture() || internal_size_matches; + if (reuse_blur_texture) { + rb->allocate_blur_textures(); + texture_name = RB_TEX_BLUR_0; + } else { + uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + usage_bits |= can_use_storage ? RD::TEXTURE_USAGE_STORAGE_BIT : RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + rb->create_texture(RB_SCOPE_BUFFERS, RB_TEX_BACK_COLOR, rb->get_base_data_format(), usage_bits); + texture_name = RB_TEX_BACK_COLOR; + } + for (uint32_t v = 0; v < rb->get_view_count(); v++) { RID texture = rb->get_internal_texture(v); - int mipmaps = int(rb->get_texture_format(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0).mipmaps); - RID dest = rb->get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0, v, 0); + int mipmaps = int(rb->get_texture_format(RB_SCOPE_BUFFERS, texture_name).mipmaps); + RID dest = rb->get_texture_slice(RB_SCOPE_BUFFERS, texture_name, v, 0); if (can_use_storage) { copy_effects->copy_to_rect(texture, dest, Rect2i(0, 0, size.x, size.y)); @@ -279,8 +293,8 @@ void RendererSceneRenderRD::_render_buffers_copy_screen_texture(const RenderData for (int i = 1; i < mipmaps; i++) { RID source = dest; - dest = rb->get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0, v, i); - Size2i msize = rb->get_texture_slice_size(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0, i); + dest = rb->get_texture_slice(RB_SCOPE_BUFFERS, texture_name, v, i); + Size2i msize = rb->get_texture_slice_size(RB_SCOPE_BUFFERS, texture_name, i); if (can_use_storage) { copy_effects->make_mipmap(source, dest, msize); @@ -351,6 +365,8 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende RID color_texture = use_upscaled_texture ? rb->get_upscaled_texture() : rb->get_internal_texture(); Size2i color_size = use_upscaled_texture ? target_size : rb->get_internal_size(); + bool dest_is_msaa_2d = rb->get_view_count() == 1 && texture_storage->render_target_get_msaa(render_target) != RS::VIEWPORT_MSAA_DISABLED; + if (can_use_effects && RSG::camera_attributes->camera_attributes_uses_dof(p_render_data->camera_attributes)) { RENDER_TIMESTAMP("Depth of Field"); RD::get_singleton()->draw_command_begin_label("DOF"); @@ -567,7 +583,12 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende // If we do a bilinear upscale we just render into our render target and our shader will upscale automatically. // Target size in this case is lying as we never get our real target size communicated. // Bit nasty but... - dest_fb = texture_storage->render_target_get_rd_framebuffer(render_target); + + if (dest_is_msaa_2d) { + dest_fb = FramebufferCacheRD::get_singleton()->get_cache(texture_storage->render_target_get_rd_texture_msaa(render_target)); + } else { + dest_fb = texture_storage->render_target_get_rd_framebuffer(render_target); + } } tone_mapper->tonemapper(color_texture, dest_fb, tonemap); @@ -585,6 +606,13 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende fsr->fsr_upscale(rb, source_texture, dest_texture); } + if (dest_is_msaa_2d) { + // We can't upscale directly into our MSAA buffer so we need to do a copy + RID source_texture = texture_storage->render_target_get_rd_texture(render_target); + RID dest_fb = FramebufferCacheRD::get_singleton()->get_cache(texture_storage->render_target_get_rd_texture_msaa(render_target)); + copy_effects->copy_to_fb_rect(source_texture, dest_fb, Rect2i(Point2i(), rb->get_target_size())); + } + RD::get_singleton()->draw_command_end_label(); } diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp index 10e37c7da8..242b0301f1 100644 --- a/servers/rendering/renderer_rd/shader_rd.cpp +++ b/servers/rendering/renderer_rd/shader_rd.cpp @@ -480,6 +480,7 @@ void ShaderRD::_save_to_cache(Version *p_version, int p_group) { } void ShaderRD::_allocate_placeholders(Version *p_version, int p_group) { + ERR_FAIL_NULL(p_version->variants); for (uint32_t i = 0; i < group_to_variant_map[p_group].size(); i++) { int variant_id = group_to_variant_map[p_group][i]; RID shader = RD::get_singleton()->shader_create_placeholder(); diff --git a/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_raster.glsl b/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_raster.glsl index 7b3c2f1c3b..6c77ab4a91 100644 --- a/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_raster.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_raster.glsl @@ -33,7 +33,7 @@ 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 + uv_interp = clamp(gl_Position.xy, vec2(0.0, 0.0), vec2(1.0, 1.0)) * 2.0 * float(params.face_size); // 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 1e01d94533..fecf70bd01 100644 --- a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl @@ -184,7 +184,7 @@ void main() { vec4 test_normal_roughness = imageLoad(source_normal_roughness, test_pos); vec3 test_normal = test_normal_roughness.xyz * 2.0 - 1.0; test_normal = normalize(test_normal); - test_normal.y = -test_normal.y; //because this code reads flipped + test_normal.y = -test_normal.y; // Because this code reads flipped. if (dot(ray_dir, test_normal) < 0.001) { // if depth was surpassed @@ -203,6 +203,7 @@ void main() { if (found) { float margin_blend = 1.0; + vec2 final_pos = pos; vec2 margin = vec2((params.screen_size.x + params.screen_size.y) * 0.05); // make a uniform margin if (any(bvec4(lessThan(pos, vec2(0.0, 0.0)), greaterThan(pos, params.screen_size)))) { @@ -219,16 +220,40 @@ void main() { //margin_blend = 1.0; } - vec2 final_pos; + // Fade In / Fade Out float grad = (steps_taken + 1.0) / float(params.num_steps); float initial_fade = params.curve_fade_in == 0.0 ? 1.0 : pow(clamp(grad, 0.0, 1.0), params.curve_fade_in); float fade = pow(clamp(1.0 - grad, 0.0, 1.0), params.distance_fade) * initial_fade; + + // Ensure that precision errors do not introduce any fade. Even if it is just slightly below 1.0, + // strong specular light can leak through the reflection. + if (fade > 0.999) { + fade = 1.0; + } + // This is an ad-hoc term to fade out the SSR as roughness increases. Values used // are meant to match the visual appearance of a ReflectionProbe. float roughness_fade = smoothstep(0.4, 0.7, 1.0 - normal_roughness.w); - final_pos = pos; - vec4 final_color; + // Schlick term. + float metallic = texelFetch(source_metallic, ssC << 1, 0).w; + + // F0 is the reflectance of normally incident light (perpendicular to the surface). + // Dielectric materials have a widely accepted default value of 0.04. We assume that metals reflect all light, so their F0 is 1.0. + float f0 = mix(0.04, 1.0, metallic); + float m = clamp(1.0 - dot(normal, -view_dir), 0.0, 1.0); + float m2 = m * m; + m = m2 * m2 * m; // pow(m,5) + float fresnel_term = f0 + (1.0 - f0) * m; // Fresnel Schlick term. + + // The alpha value of final_color controls the blending with specular light in specular_merge.glsl. + // Note that the Fresnel term is multiplied with the RGB color instead of being a part of the alpha value. + // There is a key difference: + // - multiplying a term with RGB darkens the SSR light without introducing/taking away specular light. + // - combining a term into the Alpha value introduces specular light at the expense of the SSR light. + vec4 final_color = vec4(imageLoad(source_diffuse, ivec2(final_pos - 0.5)).rgb * fresnel_term, fade * margin_blend * roughness_fade); + + imageStore(ssr_image, ssC, final_color); #ifdef MODE_ROUGH @@ -259,20 +284,6 @@ void main() { #endif // MODE_ROUGH - final_color = vec4(imageLoad(source_diffuse, ivec2(final_pos - 0.5)).rgb, fade * margin_blend * roughness_fade); - - // Schlick term. - float metallic = texelFetch(source_metallic, ssC << 1, 0).w; - // F0 is the reflectance of normally incident light (perpendicular to the surface). - // Dielectric materials have a widely accepted default value of 0.04. We assume that metals reflect all light, so their F0 is 1.0. - float f0 = mix(0.04, 1.0, metallic); - float m = clamp(1.0 - dot(normal, -view_dir), 0.0, 1.0); - float m2 = m * m; - m = m2 * m2 * m; // pow(m,5) - final_color.a *= f0 + (1.0 - f0) * m; // Fresnel Schlick term. - - imageStore(ssr_image, ssC, final_color); - } else { #ifdef MODE_ROUGH imageStore(blur_radius_image, ssC, vec4(0.0)); diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl index 8e6db7583e..206c2fb245 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 @@ -1019,13 +1019,11 @@ void fragment_shader(in SceneData scene_data) { #endif // ALPHA_ANTIALIASING_EDGE_USED #ifdef MODE_RENDER_DEPTH -#ifdef USE_OPAQUE_PREPASS -#ifndef ALPHA_SCISSOR_USED +#if defined(USE_OPAQUE_PREPASS) || defined(ALPHA_ANTIALIASING_EDGE_USED) if (alpha < scene_data.opaque_prepass_threshold) { discard; } -#endif // !ALPHA_SCISSOR_USED -#endif // USE_OPAQUE_PREPASS +#endif // USE_OPAQUE_PREPASS || ALPHA_ANTIALIASING_EDGE_USED #endif // MODE_RENDER_DEPTH #endif // !USE_SHADOW_TO_OPACITY 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 a9e9a617d6..5ed3669703 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 @@ -854,13 +854,11 @@ void main() { #endif // ALPHA_ANTIALIASING_EDGE_USED #ifdef MODE_RENDER_DEPTH -#ifdef USE_OPAQUE_PREPASS -#ifndef ALPHA_SCISSOR_USED +#if defined(USE_OPAQUE_PREPASS) || defined(ALPHA_ANTIALIASING_EDGE_USED) if (alpha < scene_data.opaque_prepass_threshold) { discard; } -#endif // !ALPHA_SCISSOR_USED -#endif // USE_OPAQUE_PREPASS +#endif // USE_OPAQUE_PREPASS || ALPHA_ANTIALIASING_EDGE_USED #endif // MODE_RENDER_DEPTH #endif // !USE_SHADOW_TO_OPACITY diff --git a/servers/rendering/renderer_rd/shaders/particles.glsl b/servers/rendering/renderer_rd/shaders/particles.glsl index 7ba03a27f7..5fa4154727 100644 --- a/servers/rendering/renderer_rd/shaders/particles.glsl +++ b/servers/rendering/renderer_rd/shaders/particles.glsl @@ -67,7 +67,7 @@ struct FrameParams { float delta; uint frame; - uint pad0; + float amount_ratio; uint pad1; uint pad2; @@ -77,6 +77,8 @@ struct FrameParams { float particle_size; mat4 emission_transform; + vec3 emitter_velocity; + float interp_to_end; Attractor attractors[MAX_ATTRACTORS]; Collider colliders[MAX_COLLIDERS]; diff --git a/servers/rendering/renderer_rd/storage_rd/forward_id_storage.h b/servers/rendering/renderer_rd/storage_rd/forward_id_storage.h index bedf5e80c7..c8f8d4f7f2 100644 --- a/servers/rendering/renderer_rd/storage_rd/forward_id_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/forward_id_storage.h @@ -59,7 +59,7 @@ public: virtual RendererRD::ForwardID allocate_forward_id(RendererRD::ForwardIDType p_type) { return -1; } virtual void free_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id) {} - virtual void map_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id, uint32_t p_index) {} + virtual void map_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id, uint32_t p_index, uint64_t p_last_pass) {} virtual bool uses_forward_ids() const { return false; } }; diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp index 4fd33ad71a..1f6d1021f4 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp @@ -793,7 +793,7 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged real_t distance = (i < omni_light_count) ? omni_light_sort[index].depth : spot_light_sort[index].depth; if (using_forward_ids) { - forward_id_storage->map_forward_id(type == RS::LIGHT_OMNI ? RendererRD::FORWARD_ID_TYPE_OMNI_LIGHT : RendererRD::FORWARD_ID_TYPE_SPOT_LIGHT, light_instance->forward_id, index); + forward_id_storage->map_forward_id(type == RS::LIGHT_OMNI ? RendererRD::FORWARD_ID_TYPE_OMNI_LIGHT : RendererRD::FORWARD_ID_TYPE_SPOT_LIGHT, light_instance->forward_id, index, light_instance->last_pass); } Transform3D light_transform = light_instance->transform; @@ -1670,7 +1670,7 @@ void LightStorage::update_reflection_probe_buffer(RenderDataRD *p_render_data, c ReflectionProbeInstance *rpi = reflection_sort[i].probe_instance; if (using_forward_ids) { - forward_id_storage->map_forward_id(FORWARD_ID_TYPE_REFLECTION_PROBE, rpi->forward_id, i); + forward_id_storage->map_forward_id(FORWARD_ID_TYPE_REFLECTION_PROBE, rpi->forward_id, i, rpi->last_pass); } ReflectionProbe *probe = reflection_probe_owner.get_or_null(rpi->probe); diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp index 3bd35c53cc..2e8c9d7f8e 100644 --- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp @@ -2115,7 +2115,7 @@ void MaterialStorage::material_set_shader(RID p_material, RID p_shader) { return; } - ERR_FAIL_COND(shader->data == nullptr); + ERR_FAIL_NULL(shader->data); material->data = material_data_request_func[shader->type](shader->data); material->data->self = p_material; diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp index 14605b308e..da55b68109 100644 --- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp @@ -356,14 +356,12 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) #else if (surface_version != uint64_t(RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION)) { - RS::_fix_surface_compatibility(new_surface); + RS::get_singleton()->fix_surface_compatibility(new_surface); surface_version = new_surface.format & (RS::ARRAY_FLAG_FORMAT_VERSION_MASK << RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT); ERR_FAIL_COND_MSG(surface_version != RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION, - "Surface version provided (" + - itos((surface_version >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK) + - ") does not match current version (" + - itos((RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK) + - ")"); + vformat("Surface version provided (%d) does not match current version (%d).", + (surface_version >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK, + (RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK)); } #endif @@ -593,7 +591,6 @@ RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const { sd.vertex_data = RD::get_singleton()->buffer_get_data(s.vertex_buffer); // When using an uncompressed buffer with normals, but without tangents, we have to trim the padding. if (!(s.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) && (s.format & RS::ARRAY_FORMAT_NORMAL) && !(s.format & RS::ARRAY_FORMAT_TANGENT)) { - Vector<uint8_t> new_vertex_data; sd.vertex_data.resize(sd.vertex_data.size() - sizeof(uint16_t) * 2); } } diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h index f03334baac..db54816e09 100644 --- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h @@ -469,7 +469,7 @@ public: } } - _FORCE_INLINE_ void mesh_surface_get_vertex_arrays_and_format(void *p_surface, uint32_t p_input_mask, bool p_input_motion_vectors, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) { + _FORCE_INLINE_ void mesh_surface_get_vertex_arrays_and_format(void *p_surface, uint64_t p_input_mask, bool p_input_motion_vectors, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) { Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface); s->version_lock.lock(); @@ -501,7 +501,7 @@ public: s->version_lock.unlock(); } - _FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint64_t p_surface_index, uint32_t p_input_mask, bool p_input_motion_vectors, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) { + _FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint64_t p_surface_index, uint64_t p_input_mask, bool p_input_motion_vectors, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) { MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance); ERR_FAIL_NULL(mi); Mesh *mesh = mi->mesh; diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp index bf5a597bb9..3d3cb585ac 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp @@ -72,6 +72,7 @@ ParticlesStorage::ParticlesStorage() { actions.renames["ACTIVE"] = "particle_active"; actions.renames["RESTART"] = "restart"; actions.renames["CUSTOM"] = "PARTICLE.custom"; + actions.renames["AMOUNT_RATIO"] = "FRAME.amount_ratio"; for (int i = 0; i < ParticlesShader::MAX_USERDATAS; i++) { String udname = "USERDATA" + itos(i + 1); actions.renames[udname] = "PARTICLE.userdata" + itos(i + 1); @@ -88,6 +89,8 @@ ParticlesStorage::ParticlesStorage() { actions.renames["INDEX"] = "index"; //actions.renames["GRAVITY"] = "current_gravity"; actions.renames["EMISSION_TRANSFORM"] = "FRAME.emission_transform"; + actions.renames["EMITTER_VELOCITY"] = "FRAME.emitter_velocity"; + actions.renames["INTERPOLATE_TO_END"] = "FRAME.interp_to_end"; actions.renames["RANDOM_SEED"] = "FRAME.random_seed"; actions.renames["FLAG_EMIT_POSITION"] = "EMISSION_FLAG_HAS_POSITION"; actions.renames["FLAG_EMIT_ROT_SCALE"] = "EMISSION_FLAG_HAS_ROTATION_SCALE"; @@ -221,13 +224,15 @@ RID ParticlesStorage::particles_allocate() { } void ParticlesStorage::particles_initialize(RID p_rid) { - particles_owner.initialize_rid(p_rid, Particles()); + particles_owner.initialize_rid(p_rid); } void ParticlesStorage::particles_free(RID p_rid) { - update_particles(); Particles *particles = particles_owner.get_or_null(p_rid); + particles->dependency.deleted_notify(p_rid); + particles->update_list.remove_from_list(); + _particles_free_data(particles); particles_owner.free(p_rid); } @@ -329,6 +334,13 @@ void ParticlesStorage::particles_set_amount(RID p_particles, int p_amount) { particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_PARTICLES); } +void ParticlesStorage::particles_set_amount_ratio(RID p_particles, float p_amount_ratio) { + Particles *particles = particles_owner.get_or_null(p_particles); + ERR_FAIL_NULL(particles); + + particles->amount_ratio = p_amount_ratio; +} + void ParticlesStorage::particles_set_lifetime(RID p_particles, double p_lifetime) { Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_NULL(particles); @@ -577,8 +589,10 @@ void ParticlesStorage::particles_request_process(RID p_particles) { if (!particles->dirty) { particles->dirty = true; - particles->update_list = particle_update_list; - particle_update_list = particles; + + if (!particles->update_list.in_list()) { + particle_update_list.add(&particles->update_list); + } } } @@ -651,6 +665,20 @@ void ParticlesStorage::particles_set_emission_transform(RID p_particles, const T particles->emission_transform = p_transform; } +void ParticlesStorage::particles_set_emitter_velocity(RID p_particles, const Vector3 &p_velocity) { + Particles *particles = particles_owner.get_or_null(p_particles); + ERR_FAIL_NULL(particles); + + particles->emitter_velocity = p_velocity; +} + +void ParticlesStorage::particles_set_interp_to_end(RID p_particles, float p_interp) { + Particles *particles = particles_owner.get_or_null(p_particles); + ERR_FAIL_NULL(particles); + + particles->interp_to_end = p_interp; +} + int ParticlesStorage::particles_get_draw_passes(RID p_particles) const { const Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_NULL_V(particles, 0); @@ -791,9 +819,13 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta frame_params.cycle = p_particles->cycle_number; frame_params.frame = p_particles->frame_counter++; - frame_params.pad0 = 0; + frame_params.amount_ratio = p_particles->amount_ratio; frame_params.pad1 = 0; frame_params.pad2 = 0; + frame_params.emitter_velocity[0] = p_particles->emitter_velocity.x; + frame_params.emitter_velocity[1] = p_particles->emitter_velocity.y; + frame_params.emitter_velocity[2] = p_particles->emitter_velocity.z; + frame_params.interp_to_end = p_particles->interp_to_end; { //collision and attractors @@ -1345,14 +1377,12 @@ void ParticlesStorage::_particles_update_buffers(Particles *particles) { void ParticlesStorage::update_particles() { uint32_t frame = RSG::rasterizer->get_frame_number(); bool uses_motion_vectors = RSG::viewport->get_num_viewports_with_motion_vectors() > 0; - while (particle_update_list) { + while (particle_update_list.first()) { //use transform feedback to process particles - Particles *particles = particle_update_list; + Particles *particles = particle_update_list.first()->self(); - //take and remove - particle_update_list = particles->update_list; - particles->update_list = nullptr; + particles->update_list.remove_from_list(); particles->dirty = false; _particles_update_buffers(particles); diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.h b/servers/rendering/renderer_rd/storage_rd/particles_storage.h index b93932f482..a28d7b4154 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.h @@ -123,7 +123,7 @@ private: float delta; uint32_t frame; - uint32_t pad0; + float amount_ratio; uint32_t pad1; uint32_t pad2; @@ -134,6 +134,9 @@ private: float emission_transform[16]; + float emitter_velocity[3]; + float interp_to_end; + Attractor attractors[MAX_ATTRACTORS]; Collider colliders[MAX_COLLIDERS]; }; @@ -206,7 +209,7 @@ private: RID particles_sort_uniform_set; bool dirty = false; - Particles *update_list = nullptr; + SelfList<Particles> update_list; RID sub_emitter; @@ -235,6 +238,9 @@ private: bool force_sub_emit = false; Transform3D emission_transform; + Vector3 emitter_velocity; + float interp_to_end = 0.0; + float amount_ratio = 1.0; Vector<uint8_t> emission_buffer_data; @@ -250,7 +256,8 @@ private: LocalVector<ParticlesFrameParams> frame_history; LocalVector<ParticlesFrameParams> trail_params; - Particles() { + Particles() : + update_list(this) { } }; @@ -322,7 +329,7 @@ private: } particles_shader; - Particles *particle_update_list = nullptr; + SelfList<Particles>::List particle_update_list; mutable RID_Owner<Particles, true> particles_owner; @@ -425,6 +432,7 @@ public: virtual void particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) override; virtual void particles_set_emitting(RID p_particles, bool p_emitting) override; virtual void particles_set_amount(RID p_particles, int p_amount) override; + virtual void particles_set_amount_ratio(RID p_particles, float p_amount_ratio) override; virtual void particles_set_lifetime(RID p_particles, double p_lifetime) override; virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) override; virtual void particles_set_pre_process_time(RID p_particles, double p_time) override; @@ -460,6 +468,8 @@ public: virtual AABB particles_get_aabb(RID p_particles) const override; virtual void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) override; + virtual void particles_set_emitter_velocity(RID p_particles, const Vector3 &p_velocity) override; + virtual void particles_set_interp_to_end(RID p_particles, float p_interp_to_end) override; virtual bool particles_get_emitting(RID p_particles) override; virtual int particles_get_draw_passes(RID p_particles) const override; diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h index 43704119e7..b2946e6bbc 100644 --- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h +++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h @@ -58,6 +58,7 @@ #define RB_TEX_BLUR_1 SNAME("blur_1") #define RB_TEX_HALF_BLUR SNAME("half_blur") // only for raster! +#define RB_TEX_BACK_COLOR SNAME("back_color") #define RB_TEX_BACK_DEPTH SNAME("back_depth") class RenderSceneBuffersRD : public RenderSceneBuffers { @@ -267,7 +268,16 @@ public: } // back buffer (color) - RID get_back_buffer_texture() const { return has_texture(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0) ? get_texture(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0) : RID(); } // We (re)use our blur texture here. + RID get_back_buffer_texture() const { + // Prefer returning the dedicated backbuffer color texture if it was created. Return the reused blur texture otherwise. + if (has_texture(RB_SCOPE_BUFFERS, RB_TEX_BACK_COLOR)) { + return get_texture(RB_SCOPE_BUFFERS, RB_TEX_BACK_COLOR); + } else if (has_texture(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0)) { + return get_texture(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0); + } else { + return RID(); + } + } // Upscaled. void ensure_upscaled(); diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index 166b850864..678564a0e4 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -2862,7 +2862,7 @@ void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const Decal *decal = decal_sort[i].decal; if (using_forward_ids) { - forward_id_storage->map_forward_id(FORWARD_ID_TYPE_DECAL, decal_instance->forward_id, i); + forward_id_storage->map_forward_id(FORWARD_ID_TYPE_DECAL, decal_instance->forward_id, i, RSG::rasterizer->get_frame_number()); } decal_instance->cull_mask = decal->cull_mask; @@ -3511,7 +3511,9 @@ Rect2i TextureStorage::_render_target_get_sdf_rect(const RenderTarget *rt) const scale = 200; } break; default: { - } + ERR_PRINT("Invalid viewport SDF oversize, defaulting to 100%."); + scale = 100; + } break; } margin = (rt->size * scale / 100) - rt->size; @@ -3603,6 +3605,7 @@ void TextureStorage::_render_target_allocate_sdf(RenderTarget *rt) { scale = 25; } break; default: { + ERR_PRINT("Invalid viewport SDF scale, defaulting to 100%."); scale = 100; } break; } diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 1c5cbe9612..73aacf311f 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -2239,7 +2239,7 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in // This trick here is what stabilizes the shadow (make potential jaggies to not move) // at the cost of some wasted resolution. Still, the quality increase is very well worth it. - const real_t unit = (radius + soft_shadow_expand) * 2.0 / texture_size; + const real_t unit = (radius + soft_shadow_expand) * 4.0 / texture_size; x_max_cam = Math::snapped(x_vec.dot(center) + radius + soft_shadow_expand, unit); x_min_cam = Math::snapped(x_vec.dot(center) - radius - soft_shadow_expand, unit); y_max_cam = Math::snapped(y_vec.dot(center) + radius + soft_shadow_expand, unit); diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index 34d6a93e36..6b47c29382 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -116,19 +116,30 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) { if (p_viewport->size.width == 0 || p_viewport->size.height == 0) { p_viewport->render_buffers.unref(); } else { + const float EPSILON = 0.0001; float scaling_3d_scale = p_viewport->scaling_3d_scale; RS::ViewportScaling3DMode scaling_3d_mode = p_viewport->scaling_3d_mode; + bool upscaler_available = p_viewport->fsr_enabled; + + if ((!upscaler_available || scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_BILINEAR || scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR) && scaling_3d_scale >= (1.0 - EPSILON) && scaling_3d_scale <= (1.0 + EPSILON)) { + // No 3D scaling on bilinear or FSR? Ignore scaling mode, this just introduces overhead. + // - Mobile can't perform optimal path + // - FSR does an extra pass (or 2 extra passes if 2D-MSAA is enabled) + // Scaling = 1.0 on FSR2 has benefits + scaling_3d_scale = 1.0; + scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF; + } + bool scaling_3d_is_fsr = (scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR) || (scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR2); bool use_taa = p_viewport->use_taa; - if (scaling_3d_is_fsr && (scaling_3d_scale > 1.0)) { + if (scaling_3d_is_fsr && (scaling_3d_scale >= (1.0 + EPSILON))) { // FSR is not designed for downsampling. // Fall back to bilinear scaling. WARN_PRINT_ONCE("FSR 3D resolution scaling is not designed for downsampling. Falling back to bilinear 3D resolution scaling."); scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_BILINEAR; } - bool upscaler_available = p_viewport->fsr_enabled; if (scaling_3d_is_fsr && !upscaler_available) { // FSR is not actually available. // Fall back to bilinear scaling. @@ -143,8 +154,8 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) { use_taa = false; } - int width; - int height; + int target_width; + int target_height; int render_width; int render_height; @@ -152,40 +163,40 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) { case RS::VIEWPORT_SCALING_3D_MODE_BILINEAR: // Clamp 3D rendering resolution to reasonable values supported on most hardware. // This prevents freezing the engine or outright crashing on lower-end GPUs. - width = CLAMP(p_viewport->size.width * scaling_3d_scale, 1, 16384); - height = CLAMP(p_viewport->size.height * scaling_3d_scale, 1, 16384); - render_width = width; - render_height = height; + target_width = p_viewport->size.width; + target_height = p_viewport->size.height; + render_width = CLAMP(target_width * scaling_3d_scale, 1, 16384); + render_height = CLAMP(target_height * scaling_3d_scale, 1, 16384); break; case RS::VIEWPORT_SCALING_3D_MODE_FSR: case RS::VIEWPORT_SCALING_3D_MODE_FSR2: - width = p_viewport->size.width; - height = p_viewport->size.height; - render_width = MAX(width * scaling_3d_scale, 1.0); // width / (width * scaling) - render_height = MAX(height * scaling_3d_scale, 1.0); + target_width = p_viewport->size.width; + target_height = p_viewport->size.height; + render_width = MAX(target_width * scaling_3d_scale, 1.0); // target_width / (target_width * scaling) + render_height = MAX(target_height * scaling_3d_scale, 1.0); break; case RS::VIEWPORT_SCALING_3D_MODE_OFF: - width = p_viewport->size.width; - height = p_viewport->size.height; - render_width = width; - render_height = height; + target_width = p_viewport->size.width; + target_height = p_viewport->size.height; + render_width = target_width; + render_height = target_height; break; default: // This is an unknown mode. WARN_PRINT_ONCE(vformat("Unknown scaling mode: %d. Disabling 3D resolution scaling.", scaling_3d_mode)); scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF; scaling_3d_scale = 1.0; - width = p_viewport->size.width; - height = p_viewport->size.height; - render_width = width; - render_height = height; + target_width = p_viewport->size.width; + target_height = p_viewport->size.height; + render_width = target_width; + render_height = target_height; break; } uint32_t jitter_phase_count = 0; if (scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR2) { // Implementation has been copied from ffxFsr2GetJitterPhaseCount. - jitter_phase_count = uint32_t(8.0f * pow(float(width) / render_width, 2.0f)); + jitter_phase_count = uint32_t(8.0f * pow(float(target_width) / render_width, 2.0f)); } else if (use_taa) { // Default jitter count for TAA. jitter_phase_count = 16; @@ -201,7 +212,7 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) { RenderSceneBuffersConfiguration rb_config; rb_config.set_render_target(p_viewport->render_target); rb_config.set_internal_size(Size2i(render_width, render_height)); - rb_config.set_target_size(Size2(width, height)); + rb_config.set_target_size(Size2(target_width, target_height)); rb_config.set_view_count(p_viewport->view_count); rb_config.set_scaling_3d_mode(scaling_3d_mode); rb_config.set_msaa_3d(p_viewport->msaa_3d); @@ -259,6 +270,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { /* Camera should always be BEFORE any other 3D */ + bool can_draw_2d = !p_viewport->disable_2d && p_viewport->view_count == 1; // Stereo rendering does not support 2D, no depth data bool scenario_draw_canvas_bg = false; //draw canvas, or some layer of it, as BG for 3D instead of in front int scenario_canvas_max_layer = 0; bool force_clear_render_target = false; @@ -272,7 +284,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { if (RSG::scene->is_scenario(p_viewport->scenario)) { RID environment = RSG::scene->scenario_get_environment(p_viewport->scenario); if (RSG::scene->is_environment(environment)) { - if (!p_viewport->disable_2d && !viewport_is_environment_disabled(p_viewport)) { + if (can_draw_2d && !viewport_is_environment_disabled(p_viewport)) { scenario_draw_canvas_bg = RSG::scene->environment_get_background(environment) == RS::ENV_BG_CANVAS; scenario_canvas_max_layer = RSG::scene->environment_get_canvas_max_layer(environment); } else if (RSG::scene->environment_get_background(environment) == RS::ENV_BG_CANVAS) { @@ -307,7 +319,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { _draw_3d(p_viewport); } - if (!p_viewport->disable_2d) { + if (can_draw_2d) { RBMap<Viewport::CanvasKey, Viewport::CanvasData *> canvas_map; Rect2 clip_rect(0, 0, p_viewport->size.x, p_viewport->size.y); diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index 9ad2175332..cd5904f175 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -476,6 +476,8 @@ public: FUNC2(voxel_gi_set_interior, RID, bool) FUNC2(voxel_gi_set_use_two_bounces, RID, bool) + FUNC0(sdfgi_reset) + /* PARTICLES */ #undef ServerName @@ -490,6 +492,7 @@ public: FUNC2(particles_set_emitting, RID, bool) FUNC1R(bool, particles_get_emitting, RID) FUNC2(particles_set_amount, RID, int) + FUNC2(particles_set_amount_ratio, RID, float) FUNC2(particles_set_lifetime, RID, double) FUNC2(particles_set_one_shot, RID, bool) FUNC2(particles_set_pre_process_time, RID, double) @@ -521,6 +524,8 @@ public: FUNC1R(AABB, particles_get_current_aabb, RID) FUNC2(particles_set_emission_transform, RID, const Transform3D &) + FUNC2(particles_set_emitter_velocity, RID, const Vector3 &) + FUNC2(particles_set_interp_to_end, RID, float) /* PARTICLES COLLISION */ @@ -891,6 +896,9 @@ public: FUNC6(canvas_item_set_canvas_group_mode, RID, CanvasGroupMode, float, bool, float, bool) + FUNC1(canvas_item_set_debug_redraw, bool) + FUNC0RC(bool, canvas_item_get_debug_redraw) + FUNCRIDSPLIT(canvas_light) FUNC2(canvas_light_set_mode, RID, CanvasLightMode) diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp index 71f821205e..1e95cdde0c 100644 --- a/servers/rendering/shader_compiler.cpp +++ b/servers/rendering/shader_compiler.cpp @@ -432,13 +432,13 @@ static String _get_global_shader_uniform_from_type_and_index(const String &p_buf return "(" + p_buffer + "[" + p_index + "].xyzw)"; } case ShaderLanguage::TYPE_MAT2: { - return "mat2(" + p_buffer + "[" + p_index + "].xy," + p_buffer + "[" + p_index + "+1].xy)"; + return "mat2(" + p_buffer + "[" + p_index + "].xy," + p_buffer + "[" + p_index + "+1u].xy)"; } case ShaderLanguage::TYPE_MAT3: { - return "mat3(" + p_buffer + "[" + p_index + "].xyz," + p_buffer + "[" + p_index + "+1].xyz," + p_buffer + "[" + p_index + "+2].xyz)"; + return "mat3(" + p_buffer + "[" + p_index + "].xyz," + p_buffer + "[" + p_index + "+1u].xyz," + p_buffer + "[" + p_index + "+2u].xyz)"; } case ShaderLanguage::TYPE_MAT4: { - return "mat4(" + p_buffer + "[" + p_index + "].xyzw," + p_buffer + "[" + p_index + "+1].xyzw," + p_buffer + "[" + p_index + "+2].xyzw," + p_buffer + "[" + p_index + "+3].xyzw)"; + return "mat4(" + p_buffer + "[" + p_index + "].xyzw," + p_buffer + "[" + p_index + "+1u].xyzw," + p_buffer + "[" + p_index + "+2u].xyzw," + p_buffer + "[" + p_index + "+3u].xyzw)"; } default: { ERR_FAIL_V("void"); diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 34ffc1e90f..a2da26eb65 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -1377,7 +1377,7 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea if (p_allow_reassign) { break; } - ERR_FAIL_COND_V(!p_block->parent_block, false); + ERR_FAIL_NULL_V(p_block->parent_block, false); p_block = p_block->parent_block; } } @@ -4639,6 +4639,10 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const FunctionInfo &p_functi return false; } + if (shader->varyings.has(var->name)) { + return _validate_varying_assign(shader->varyings[var->name], r_message); + } + if (!(p_function_info.built_ins.has(var->name) && p_function_info.built_ins[var->name].constant)) { return true; } @@ -5418,7 +5422,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } if (error) { - _set_error(vformat(RTR("A constant value cannot be passed for '%s' parameter."), _get_qualifier_str(arg_qual))); + _set_error(vformat(RTR("A constant value cannot be passed for the '%s' parameter."), _get_qualifier_str(arg_qual))); return nullptr; } } diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp index 38574b0597..a6b4646f43 100644 --- a/servers/rendering/shader_types.cpp +++ b/servers/rendering/shader_types.cpp @@ -348,6 +348,8 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["NUMBER"] = constt(ShaderLanguage::TYPE_UINT); shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_UINT); shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4); + shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["EMITTER_VELOCITY"] = constt(ShaderLanguage::TYPE_VEC3); + shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["INTERPOLATE_TO_END"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT); shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["FLAG_EMIT_POSITION"] = constt(ShaderLanguage::TYPE_UINT); shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["FLAG_EMIT_ROT_SCALE"] = constt(ShaderLanguage::TYPE_UINT); @@ -359,6 +361,7 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_VELOCITY"] = constt(ShaderLanguage::TYPE_BOOL); shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_COLOR"] = constt(ShaderLanguage::TYPE_BOOL); shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_CUSTOM"] = constt(ShaderLanguage::TYPE_BOOL); + shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["AMOUNT_RATIO"] = ShaderLanguage::TYPE_FLOAT; shader_modes[RS::SHADER_PARTICLES].functions["start"].main_function = true; shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4; @@ -379,6 +382,8 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["NUMBER"] = constt(ShaderLanguage::TYPE_UINT); shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_UINT); shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4); + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["EMITTER_VELOCITY"] = constt(ShaderLanguage::TYPE_VEC3); + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["INTERPOLATE_TO_END"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT); shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["FLAG_EMIT_POSITION"] = constt(ShaderLanguage::TYPE_UINT); shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["FLAG_EMIT_ROT_SCALE"] = constt(ShaderLanguage::TYPE_UINT); @@ -389,6 +394,7 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["COLLISION_NORMAL"] = constt(ShaderLanguage::TYPE_VEC3); shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["COLLISION_DEPTH"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["ATTRACTOR_FORCE"] = constt(ShaderLanguage::TYPE_VEC3); + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["AMOUNT_RATIO"] = ShaderLanguage::TYPE_FLOAT; shader_modes[RS::SHADER_PARTICLES].functions["process"].main_function = true; { diff --git a/servers/rendering/storage/particles_storage.h b/servers/rendering/storage/particles_storage.h index 78c616f6d5..4f33de912c 100644 --- a/servers/rendering/storage/particles_storage.h +++ b/servers/rendering/storage/particles_storage.h @@ -49,6 +49,7 @@ public: virtual bool particles_get_emitting(RID p_particles) = 0; virtual void particles_set_amount(RID p_particles, int p_amount) = 0; + virtual void particles_set_amount_ratio(RID p_particles, float p_amount_ratio) = 0; virtual void particles_set_lifetime(RID p_particles, double p_lifetime) = 0; virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) = 0; virtual void particles_set_pre_process_time(RID p_particles, double p_time) = 0; @@ -85,6 +86,8 @@ public: virtual AABB particles_get_aabb(RID p_particles) const = 0; virtual void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) = 0; + virtual void particles_set_emitter_velocity(RID p_particles, const Vector3 &p_velocity) = 0; + virtual void particles_set_interp_to_end(RID p_particles, float p_interp_to_end) = 0; virtual int particles_get_draw_passes(RID p_particles) const = 0; virtual RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const = 0; diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 94ff59f7e1..43615f0d7e 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -323,16 +323,18 @@ RID RenderingServer::get_white_texture() { } void _get_axis_angle(const Vector3 &p_normal, const Vector4 &p_tangent, float &r_angle, Vector3 &r_axis) { - Vector3 tangent = Vector3(p_tangent.x, p_tangent.y, p_tangent.z); + Vector3 normal = p_normal.normalized(); + Vector3 tangent = Vector3(p_tangent.x, p_tangent.y, p_tangent.z).normalized(); float d = p_tangent.w; - Vector3 binormal = p_normal.cross(tangent); + Vector3 binormal = normal.cross(tangent).normalized(); + real_t angle; - r_angle = Math::acos((tangent.x + binormal.y + p_normal.z - 1.0) / 2.0); - float denom = 2.0 * Math::sin(r_angle); - r_axis.x = (p_normal.y - binormal.z) / denom; - r_axis.y = (tangent.z - p_normal.x) / denom; - r_axis.z = (binormal.x - tangent.y) / denom; - r_axis.normalize(); + Basis tbn = Basis(); + tbn.rows[0] = tangent; + tbn.rows[1] = binormal; + tbn.rows[2] = normal; + tbn.get_axis_angle(r_axis, angle); + r_angle = float(angle); if (d < 0.0) { r_angle = CLAMP((1.0 - r_angle / Math_PI) * 0.5, 0.0, 0.49999); @@ -346,13 +348,11 @@ void _get_axis_angle(const Vector3 &p_normal, const Vector4 &p_tangent, float &r void _get_tbn_from_axis_angle(const Vector3 &p_axis, float p_angle, Vector3 &r_normal, Vector4 &r_tangent) { float binormal_sign = p_angle > 0.5 ? 1.0 : -1.0; float angle = Math::abs(p_angle * 2.0 - 1.0) * Math_PI; - float c = cos(angle); - float s = sin(angle); - Vector3 omc_axis = (1.0 - c) * p_axis; - Vector3 s_axis = s * p_axis; - Vector3 tan = omc_axis.x * p_axis + Vector3(c, -s_axis.z, s_axis.y); + + Basis tbn = Basis(p_axis, angle); + Vector3 tan = tbn.rows[0]; r_tangent = Vector4(tan.x, tan.y, tan.z, binormal_sign); - r_normal = omc_axis.z * p_axis + Vector3(-s_axis.y, s_axis.x, c); + r_normal = tbn.rows[2]; } Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint32_t *p_offsets, uint32_t p_vertex_stride, uint32_t p_normal_stride, uint32_t p_attrib_stride, uint32_t p_skin_stride, Vector<uint8_t> &r_vertex_array, Vector<uint8_t> &r_attrib_array, Vector<uint8_t> &r_skin_array, int p_vertex_array_len, Vector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> &r_bone_aabb, Vector4 &r_uv_scale) { @@ -400,7 +400,14 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint max_val = max_val.abs().max(min_val.abs()); max_val2 = max_val2.abs().max(min_val2.abs()); - r_uv_scale = Vector4(max_val.x, max_val.y, max_val2.x, max_val2.y) * Vector4(2.0, 2.0, 2.0, 2.0); + if (min_val.x >= 0.0 && min_val2.x >= 0.0 && max_val.x <= 1.0 && max_val2.x <= 1.0 && + min_val.y >= 0.0 && min_val2.y >= 0.0 && max_val.y <= 1.0 && max_val2.y <= 1.0) { + // When all channels are in the 0-1 range, we will compress to 16-bit without scaling to + // preserve the bits as best as possible. + r_uv_scale = Vector4(0.0, 0.0, 0.0, 0.0); + } else { + r_uv_scale = Vector4(max_val.x, max_val.y, max_val2.x, max_val2.y) * Vector4(2.0, 2.0, 2.0, 2.0); + } } for (int ai = 0; ai < RS::ARRAY_MAX; ai++) { @@ -441,25 +448,22 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint const Vector3 *src = array.ptr(); - // Setting vertices means regenerating the AABB. - AABB aabb; + r_aabb = AABB(); if (p_format & ARRAY_FLAG_COMPRESS_ATTRIBUTES) { // First we need to generate the AABB for the entire surface. for (int i = 0; i < p_vertex_array_len; i++) { if (i == 0) { - aabb = AABB(src[i], SMALL_VEC3); + r_aabb = AABB(src[i], SMALL_VEC3); } else { - aabb.expand_to(src[i]); + r_aabb.expand_to(src[i]); } } - bool using_normals_tangents = (p_format & RS::ARRAY_FORMAT_NORMAL) && (p_format & RS::ARRAY_FORMAT_TANGENT); - - if (!using_normals_tangents) { + if (!(p_format & RS::ARRAY_FORMAT_NORMAL)) { // Early out if we are only setting vertex positions. for (int i = 0; i < p_vertex_array_len; i++) { - Vector3 pos = (src[i] - aabb.position) / aabb.size; + Vector3 pos = (src[i] - r_aabb.position) / r_aabb.size; uint16_t vector[4] = { (uint16_t)CLAMP(pos.x * 65535, 0, 65535), (uint16_t)CLAMP(pos.y * 65535, 0, 65535), @@ -474,13 +478,14 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint // Validate normal and tangent arrays. ERR_FAIL_COND_V(p_arrays[RS::ARRAY_NORMAL].get_type() != Variant::PACKED_VECTOR3_ARRAY, ERR_INVALID_PARAMETER); - Variant::Type tangent_type = p_arrays[RS::ARRAY_TANGENT].get_type(); - ERR_FAIL_COND_V(tangent_type != Variant::PACKED_FLOAT32_ARRAY && tangent_type != Variant::PACKED_FLOAT64_ARRAY, ERR_INVALID_PARAMETER); Vector<Vector3> normal_array = p_arrays[RS::ARRAY_NORMAL]; ERR_FAIL_COND_V(normal_array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER); const Vector3 *normal_src = normal_array.ptr(); + Variant::Type tangent_type = p_arrays[RS::ARRAY_TANGENT].get_type(); + ERR_FAIL_COND_V(tangent_type != Variant::PACKED_FLOAT32_ARRAY && tangent_type != Variant::PACKED_FLOAT64_ARRAY && tangent_type != Variant::NIL, ERR_INVALID_PARAMETER); + // We need a different version if using double precision tangents. if (tangent_type == Variant::PACKED_FLOAT32_ARRAY) { Vector<float> tangent_array = p_arrays[RS::ARRAY_TANGENT]; @@ -507,7 +512,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint // Store vertex position + angle. { - Vector3 pos = (src[i] - aabb.position) / aabb.size; + Vector3 pos = (src[i] - r_aabb.position) / r_aabb.size; uint16_t vector[4] = { (uint16_t)CLAMP(pos.x * 65535, 0, 65535), (uint16_t)CLAMP(pos.y * 65535, 0, 65535), @@ -518,7 +523,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(uint16_t) * 4); } } - } else { // PACKED_FLOAT64_ARRAY + } else if (tangent_type == Variant::PACKED_FLOAT64_ARRAY) { Vector<double> tangent_array = p_arrays[RS::ARRAY_TANGENT]; ERR_FAIL_COND_V(tangent_array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER); const double *tangent_src = tangent_array.ptr(); @@ -543,7 +548,41 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint // Store vertex position + angle. { - Vector3 pos = (src[i] - aabb.position) / aabb.size; + Vector3 pos = (src[i] - r_aabb.position) / r_aabb.size; + uint16_t vector[4] = { + (uint16_t)CLAMP(pos.x * 65535, 0, 65535), + (uint16_t)CLAMP(pos.y * 65535, 0, 65535), + (uint16_t)CLAMP(pos.z * 65535, 0, 65535), + (uint16_t)CLAMP(angle * 65535, 0, 65535) + }; + + memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(uint16_t) * 4); + } + } + } else { // No tangent array. + // Set data for vertex, normal, and tangent. + for (int i = 0; i < p_vertex_array_len; i++) { + float angle; + Vector3 axis; + // Generate an arbitrary vector that is tangential to normal. + Vector3 tan = Vector3(0.0, 1.0, 0.0).cross(normal_src[i].normalized()); + Vector4 tangent = Vector4(tan.x, tan.y, tan.z, 1.0); + _get_axis_angle(normal_src[i], tangent, angle, axis); + + // Store axis. + { + Vector2 res = axis.octahedron_encode(); + uint16_t vector[2] = { + (uint16_t)CLAMP(res.x * 65535, 0, 65535), + (uint16_t)CLAMP(res.y * 65535, 0, 65535), + }; + + memcpy(&vw[p_offsets[RS::ARRAY_NORMAL] + i * p_normal_stride], vector, 4); + } + + // Store vertex position + angle. + { + Vector3 pos = (src[i] - r_aabb.position) / r_aabb.size; uint16_t vector[4] = { (uint16_t)CLAMP(pos.x * 65535, 0, 65535), (uint16_t)CLAMP(pos.y * 65535, 0, 65535), @@ -562,14 +601,12 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(float) * 3); if (i == 0) { - aabb = AABB(src[i], SMALL_VEC3); + r_aabb = AABB(src[i], SMALL_VEC3); } else { - aabb.expand_to(src[i]); + r_aabb.expand_to(src[i]); } } } - - r_aabb = aabb; } } break; @@ -598,7 +635,8 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint // If using compression we store tangent while storing vertices. if (!(p_format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) { Variant::Type type = p_arrays[ai].get_type(); - ERR_FAIL_COND_V(type != Variant::PACKED_FLOAT32_ARRAY && type != Variant::PACKED_FLOAT64_ARRAY, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(type != Variant::PACKED_FLOAT32_ARRAY && type != Variant::PACKED_FLOAT64_ARRAY && type != Variant::NIL, ERR_INVALID_PARAMETER); + if (type == Variant::PACKED_FLOAT32_ARRAY) { Vector<float> array = p_arrays[ai]; ERR_FAIL_COND_V(array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER); @@ -612,9 +650,15 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint (uint16_t)CLAMP(res.y * 65535, 0, 65535), }; + if (vector[0] == 0 && vector[1] == 65535) { + // (1, 1) and (0, 1) decode to the same value, but (0, 1) messes with our compression detection. + // So we sanitize here. + vector[0] = 65535; + } + memcpy(&vw[p_offsets[ai] + i * p_normal_stride], vector, 4); } - } else { // PACKED_FLOAT64_ARRAY + } else if (type == Variant::PACKED_FLOAT64_ARRAY) { Vector<double> array = p_arrays[ai]; ERR_FAIL_COND_V(array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER); const double *src_ptr = array.ptr(); @@ -627,6 +671,36 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint (uint16_t)CLAMP(res.y * 65535, 0, 65535), }; + if (vector[0] == 0 && vector[1] == 65535) { + // (1, 1) and (0, 1) decode to the same value, but (0, 1) messes with our compression detection. + // So we sanitize here. + vector[0] = 65535; + } + + memcpy(&vw[p_offsets[ai] + i * p_normal_stride], vector, 4); + } + } else { // No tangent array. + ERR_FAIL_COND_V(p_arrays[RS::ARRAY_NORMAL].get_type() != Variant::PACKED_VECTOR3_ARRAY, ERR_INVALID_PARAMETER); + + Vector<Vector3> normal_array = p_arrays[RS::ARRAY_NORMAL]; + ERR_FAIL_COND_V(normal_array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER); + const Vector3 *normal_src = normal_array.ptr(); + // Set data for tangent. + for (int i = 0; i < p_vertex_array_len; i++) { + // Generate an arbitrary vector that is tangential to normal. + Vector3 tan = Vector3(0.0, 1.0, 0.0).cross(normal_src[i].normalized()); + Vector2 res = tan.octahedron_tangent_encode(1.0); + uint16_t vector[2] = { + (uint16_t)CLAMP(res.x * 65535, 0, 65535), + (uint16_t)CLAMP(res.y * 65535, 0, 65535), + }; + + if (vector[0] == 0 && vector[1] == 65535) { + // (1, 1) and (0, 1) decode to the same value, but (0, 1) messes with our compression detection. + // So we sanitize here. + vector[0] = 65535; + } + memcpy(&vw[p_offsets[ai] + i * p_normal_stride], vector, 4); } } @@ -661,8 +735,11 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint if (p_format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) { for (int i = 0; i < p_vertex_array_len; i++) { Vector2 vec = src[i]; - // Normalize into 0-1 from possible range -uv_scale - uv_scale. - vec = vec / (Vector2(r_uv_scale.x, r_uv_scale.y)) + Vector2(0.5, 0.5); + if (!r_uv_scale.is_zero_approx()) { + // Normalize into 0-1 from possible range -uv_scale - uv_scale. + vec = vec / (Vector2(r_uv_scale.x, r_uv_scale.y)) + Vector2(0.5, 0.5); + } + uint16_t uv[2] = { (uint16_t)CLAMP(vec.x * 65535, 0, 65535), (uint16_t)CLAMP(vec.y * 65535, 0, 65535) }; memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 4); } @@ -686,8 +763,10 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint if (p_format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) { for (int i = 0; i < p_vertex_array_len; i++) { Vector2 vec = src[i]; - // Normalize into 0-1 from possible range -uv_scale - uv_scale. - vec = vec / (Vector2(r_uv_scale.z, r_uv_scale.w)) + Vector2(0.5, 0.5); + if (!r_uv_scale.is_zero_approx()) { + // Normalize into 0-1 from possible range -uv_scale - uv_scale. + vec = vec / (Vector2(r_uv_scale.z, r_uv_scale.w)) + Vector2(0.5, 0.5); + } uint16_t uv[2] = { (uint16_t)CLAMP(vec.x * 65535, 0, 65535), (uint16_t)CLAMP(vec.y * 65535, 0, 65535) }; memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 4); } @@ -907,7 +986,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint uint32_t RenderingServer::mesh_surface_get_format_offset(BitField<ArrayFormat> p_format, int p_vertex_len, int p_array_index) const { ERR_FAIL_INDEX_V(p_array_index, ARRAY_MAX, 0); - p_format = int64_t(p_format) & ~ARRAY_FORMAT_INDEX; + p_format = uint64_t(p_format) & ~ARRAY_FORMAT_INDEX; uint32_t offsets[ARRAY_MAX]; uint32_t vstr; uint32_t ntstr; @@ -918,7 +997,7 @@ uint32_t RenderingServer::mesh_surface_get_format_offset(BitField<ArrayFormat> p } uint32_t RenderingServer::mesh_surface_get_format_vertex_stride(BitField<ArrayFormat> p_format, int p_vertex_len) const { - p_format = int64_t(p_format) & ~ARRAY_FORMAT_INDEX; + p_format = uint64_t(p_format) & ~ARRAY_FORMAT_INDEX; uint32_t offsets[ARRAY_MAX]; uint32_t vstr; uint32_t ntstr; @@ -929,18 +1008,18 @@ uint32_t RenderingServer::mesh_surface_get_format_vertex_stride(BitField<ArrayFo } uint32_t RenderingServer::mesh_surface_get_format_normal_tangent_stride(BitField<ArrayFormat> p_format, int p_vertex_len) const { - p_format = int64_t(p_format) & ~ARRAY_FORMAT_INDEX; + p_format = uint64_t(p_format) & ~ARRAY_FORMAT_INDEX; uint32_t offsets[ARRAY_MAX]; uint32_t vstr; uint32_t ntstr; uint32_t astr; uint32_t sstr; mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, ntstr, astr, sstr); - return vstr; + return ntstr; } uint32_t RenderingServer::mesh_surface_get_format_attribute_stride(BitField<ArrayFormat> p_format, int p_vertex_len) const { - p_format = int64_t(p_format) & ~ARRAY_FORMAT_INDEX; + p_format = uint64_t(p_format) & ~ARRAY_FORMAT_INDEX; uint32_t offsets[ARRAY_MAX]; uint32_t vstr; uint32_t ntstr; @@ -950,7 +1029,7 @@ uint32_t RenderingServer::mesh_surface_get_format_attribute_stride(BitField<Arra return astr; } uint32_t RenderingServer::mesh_surface_get_format_skin_stride(BitField<ArrayFormat> p_format, int p_vertex_len) const { - p_format = int64_t(p_format) & ~ARRAY_FORMAT_INDEX; + p_format = uint64_t(p_format) & ~ARRAY_FORMAT_INDEX; uint32_t offsets[ARRAY_MAX]; uint32_t vstr; uint32_t ntstr; @@ -1118,6 +1197,11 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa } break; } ERR_FAIL_COND_V(array_len == 0, ERR_INVALID_DATA); + } else if (i == RS::ARRAY_NORMAL) { + if (p_arrays[RS::ARRAY_TANGENT].get_type() == Variant::NIL) { + // We must use tangents if using normals. + format |= (1ULL << RS::ARRAY_TANGENT); + } } else if (i == RS::ARRAY_BONES) { switch (p_arrays[i].get_type()) { case Variant::PACKED_INT32_ARRAY: { @@ -1182,11 +1266,10 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa format |= RS::ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY; } - if (format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES && ((format & RS::ARRAY_FORMAT_NORMAL) || (format & RS::ARRAY_FORMAT_TANGENT))) { + if ((format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) && ((format & RS::ARRAY_FORMAT_NORMAL) || (format & RS::ARRAY_FORMAT_TANGENT))) { // If using normals or tangents, then we need all three. ERR_FAIL_COND_V_MSG(!(format & RS::ARRAY_FORMAT_VERTEX), ERR_INVALID_PARAMETER, "Can't use compression flag 'ARRAY_FLAG_COMPRESS_ATTRIBUTES' while using normals or tangents without vertex array."); ERR_FAIL_COND_V_MSG(!(format & RS::ARRAY_FORMAT_NORMAL), ERR_INVALID_PARAMETER, "Can't use compression flag 'ARRAY_FLAG_COMPRESS_ATTRIBUTES' while using tangents without normal array."); - ERR_FAIL_COND_V_MSG(!(format & RS::ARRAY_FORMAT_TANGENT), ERR_INVALID_PARAMETER, "Can't use compression flag 'ARRAY_FLAG_COMPRESS_ATTRIBUTES' while using normals without tangent array."); } int vertex_array_size = (vertex_element_size + normal_element_size) * array_len; @@ -1302,7 +1385,7 @@ void RenderingServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_p mesh_add_surface(p_mesh, sd); } -Array RenderingServer::_get_array_from_surface(uint64_t p_format, Vector<uint8_t> p_vertex_data, Vector<uint8_t> p_attrib_data, Vector<uint8_t> p_skin_data, int p_vertex_len, Vector<uint8_t> p_index_data, int p_index_len, const AABB &p_aabb) const { +Array RenderingServer::_get_array_from_surface(uint64_t p_format, Vector<uint8_t> p_vertex_data, Vector<uint8_t> p_attrib_data, Vector<uint8_t> p_skin_data, int p_vertex_len, Vector<uint8_t> p_index_data, int p_index_len, const AABB &p_aabb, const Vector4 &p_uv_scale) const { uint32_t offsets[RS::ARRAY_MAX]; uint32_t vertex_elem_size; @@ -1347,10 +1430,8 @@ Array RenderingServer::_get_array_from_surface(uint64_t p_format, Vector<uint8_t Vector3 *w = arr_3d.ptrw(); if (p_format & ARRAY_FLAG_COMPRESS_ATTRIBUTES) { - bool using_normals_tangents = (p_format & RS::ARRAY_FORMAT_NORMAL) && (p_format & RS::ARRAY_FORMAT_TANGENT); - // We only have vertices to read, so just read them and skip everything else. - if (!using_normals_tangents) { + if (!(p_format & RS::ARRAY_FORMAT_NORMAL)) { for (int j = 0; j < p_vertex_len; j++) { const uint16_t *v = reinterpret_cast<const uint16_t *>(&r[j * vertex_elem_size + offsets[i]]); Vector3 vec = Vector3(float(v[0]) / 65535.0, float(v[1]) / 65535.0, float(v[2]) / 65535.0); @@ -1387,7 +1468,7 @@ Array RenderingServer::_get_array_from_surface(uint64_t p_format, Vector<uint8_t tangentsw[j * 4 + 3] = tan.w; } ret[RS::ARRAY_NORMAL] = normals; - ret[RS::ARRAY_FORMAT_TANGENT] = tangents; + ret[RS::ARRAY_TANGENT] = tangents; } else { for (int j = 0; j < p_vertex_len; j++) { @@ -1460,7 +1541,12 @@ Array RenderingServer::_get_array_from_surface(uint64_t p_format, Vector<uint8_t if (p_format & ARRAY_FLAG_COMPRESS_ATTRIBUTES) { for (int j = 0; j < p_vertex_len; j++) { const uint16_t *v = reinterpret_cast<const uint16_t *>(&ar[j * attrib_elem_size + offsets[i]]); - w[j] = Vector2(float(v[0]) / 65535.0, float(v[1]) / 65535.0); + Vector2 vec = Vector2(float(v[0]) / 65535.0, float(v[1]) / 65535.0); + if (!p_uv_scale.is_zero_approx()) { + vec = (vec - Vector2(0.5, 0.5)) * Vector2(p_uv_scale.x, p_uv_scale.y); + } + + w[j] = vec; } } else { for (int j = 0; j < p_vertex_len; j++) { @@ -1480,7 +1566,11 @@ Array RenderingServer::_get_array_from_surface(uint64_t p_format, Vector<uint8_t if (p_format & ARRAY_FLAG_COMPRESS_ATTRIBUTES) { for (int j = 0; j < p_vertex_len; j++) { const uint16_t *v = reinterpret_cast<const uint16_t *>(&ar[j * attrib_elem_size + offsets[i]]); - w[j] = Vector2(float(v[0]) / 65535.0, float(v[1]) / 65535.0); + Vector2 vec = Vector2(float(v[0]) / 65535.0, float(v[1]) / 65535.0); + if (!p_uv_scale.is_zero_approx()) { + vec = (vec - Vector2(0.5, 0.5)) * Vector2(p_uv_scale.z, p_uv_scale.w); + } + w[j] = vec; } } else { for (int j = 0; j < p_vertex_len; j++) { @@ -1662,7 +1752,7 @@ TypedArray<Array> RenderingServer::mesh_surface_get_blend_shape_arrays(RID p_mes uint32_t normal_elem_size; uint32_t attrib_elem_size; uint32_t skin_elem_size; - //CLAY + mesh_surface_make_offsets_from_format(bs_format, sd.vertex_count, 0, bs_offsets, vertex_elem_size, normal_elem_size, attrib_elem_size, skin_elem_size); int divisor = (vertex_elem_size + normal_elem_size) * sd.vertex_count; @@ -1677,7 +1767,7 @@ TypedArray<Array> RenderingServer::mesh_surface_get_blend_shape_arrays(RID p_mes for (uint32_t i = 0; i < blend_shape_count; i++) { Vector<uint8_t> bs_data = blend_shape_data.slice(i * divisor, (i + 1) * divisor); Vector<uint8_t> unused; - blend_shape_array.set(i, _get_array_from_surface(bs_format, bs_data, unused, unused, sd.vertex_count, unused, 0, sd.aabb)); + blend_shape_array.set(i, _get_array_from_surface(bs_format, bs_data, unused, unused, sd.vertex_count, unused, 0, sd.aabb, sd.uv_scale)); } return blend_shape_array; @@ -1699,7 +1789,7 @@ Array RenderingServer::mesh_create_arrays_from_surface_data(const SurfaceData &p uint64_t format = p_data.format; - return _get_array_from_surface(format, vertex_data, attrib_data, skin_data, vertex_len, index_data, index_len, p_data.aabb); + return _get_array_from_surface(format, vertex_data, attrib_data, skin_data, vertex_len, index_data, index_len, p_data.aabb, p_data.uv_scale); } #if 0 Array RenderingServer::_mesh_surface_get_skeleton_aabb_bind(RID p_mesh, int p_surface) const { @@ -1833,9 +1923,7 @@ static RS::SurfaceData _dict_to_surf(const Dictionary &p_dictionary) { RS::SurfaceData sd; sd.primitive = RS::PrimitiveType(int(p_dictionary["primitive"])); - if (p_dictionary.has("uv_scale")) { - sd.format = p_dictionary["format"]; - } + sd.format = p_dictionary["format"]; sd.vertex_data = p_dictionary["vertex_data"]; if (p_dictionary.has("attribute_data")) { sd.attribute_data = p_dictionary["attribute_data"]; @@ -1853,7 +1941,9 @@ static RS::SurfaceData _dict_to_surf(const Dictionary &p_dictionary) { } sd.aabb = p_dictionary["aabb"]; - sd.uv_scale = p_dictionary["uv_scale"]; + if (p_dictionary.has("uv_scale")) { + sd.uv_scale = p_dictionary["uv_scale"]; + } if (p_dictionary.has("lods")) { Array lods = p_dictionary["lods"]; @@ -2024,15 +2114,39 @@ Vector<uint8_t> _convert_surface_version_1_to_surface_version_2(uint64_t p_forma return new_vertex_data; } +#ifdef TOOLS_ENABLED +void RenderingServer::set_surface_upgrade_callback(SurfaceUpgradeCallback p_callback) { + surface_upgrade_callback = p_callback; +} + +void RenderingServer::set_warn_on_surface_upgrade(bool p_warn) { + warn_on_surface_upgrade = p_warn; +} +#endif + #ifndef DISABLE_DEPRECATED -void RenderingServer::_fix_surface_compatibility(SurfaceData &p_surface) { +void RenderingServer::fix_surface_compatibility(SurfaceData &p_surface, const String &p_path) { uint64_t surface_version = p_surface.format & (ARRAY_FLAG_FORMAT_VERSION_MASK << ARRAY_FLAG_FORMAT_VERSION_SHIFT); ERR_FAIL_COND_MSG(surface_version > ARRAY_FLAG_FORMAT_CURRENT_VERSION, "Cannot convert surface with version provided (" + itos((surface_version >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK) + ") to current version (" + itos((RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK) + ")"); +#ifdef TOOLS_ENABLED + // Editor callback to ask user about re-saving all meshes. + if (surface_upgrade_callback && warn_on_surface_upgrade) { + surface_upgrade_callback(); + } + + if (warn_on_surface_upgrade) { + WARN_PRINT_ONCE_ED("At least one surface uses an old surface format and needs to be upgraded. The upgrade happens automatically at load time every time until the mesh is saved again or re-imported. Once saved (or re-imported), this mesh will be incompatible with earlier versions of Godot."); + + if (!p_path.is_empty()) { + WARN_PRINT("A surface of " + p_path + " uses an old surface format and needs to be upgraded."); + } + } +#endif + if (surface_version == ARRAY_FLAG_FORMAT_VERSION_1) { // The only difference for now is that Version 1 uses interleaved vertex positions while version 2 does not. // I.e. PNTPNTPNT -> PPPNTNTNT. - WARN_PRINT_ED("Upgrading mesh from older surface format. Once saved again (or re-imported), this mesh will be incompatible with earlier versions of Godot."); int vertex_size = 0; int normal_size = 0; @@ -2497,11 +2611,14 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("particles_set_emitting", "particles", "emitting"), &RenderingServer::particles_set_emitting); ClassDB::bind_method(D_METHOD("particles_get_emitting", "particles"), &RenderingServer::particles_get_emitting); ClassDB::bind_method(D_METHOD("particles_set_amount", "particles", "amount"), &RenderingServer::particles_set_amount); + ClassDB::bind_method(D_METHOD("particles_set_amount_ratio", "particles", "ratio"), &RenderingServer::particles_set_amount_ratio); ClassDB::bind_method(D_METHOD("particles_set_lifetime", "particles", "lifetime"), &RenderingServer::particles_set_lifetime); ClassDB::bind_method(D_METHOD("particles_set_one_shot", "particles", "one_shot"), &RenderingServer::particles_set_one_shot); ClassDB::bind_method(D_METHOD("particles_set_pre_process_time", "particles", "time"), &RenderingServer::particles_set_pre_process_time); ClassDB::bind_method(D_METHOD("particles_set_explosiveness_ratio", "particles", "ratio"), &RenderingServer::particles_set_explosiveness_ratio); ClassDB::bind_method(D_METHOD("particles_set_randomness_ratio", "particles", "ratio"), &RenderingServer::particles_set_randomness_ratio); + ClassDB::bind_method(D_METHOD("particles_set_interp_to_end", "particles", "factor"), &RenderingServer::particles_set_interp_to_end); + ClassDB::bind_method(D_METHOD("particles_set_emitter_velocity", "particles", "velocity"), &RenderingServer::particles_set_emitter_velocity); ClassDB::bind_method(D_METHOD("particles_set_custom_aabb", "particles", "aabb"), &RenderingServer::particles_set_custom_aabb); ClassDB::bind_method(D_METHOD("particles_set_speed_scale", "particles", "scale"), &RenderingServer::particles_set_speed_scale); ClassDB::bind_method(D_METHOD("particles_set_use_local_coordinates", "particles", "enable"), &RenderingServer::particles_set_use_local_coordinates); @@ -3330,7 +3447,7 @@ void RenderingServer::init() { GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lights_and_shadows/positional_shadow/soft_shadow_filter_quality", PROPERTY_HINT_ENUM, "Hard (Fastest),Soft Very Low (Faster),Soft Low (Fast),Soft Medium (Average),Soft High (Slow),Soft Ultra (Slowest)"), 2); GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/soft_shadow_filter_quality.mobile", 0); - GLOBAL_DEF("rendering/2d/shadow_atlas/size", 2048); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/2d/shadow_atlas/size", PROPERTY_HINT_RANGE, "128,16384"), 2048); // Number of commands that can be drawn per frame. GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/gl_compatibility/item_buffer_size", PROPERTY_HINT_RANGE, "128,1048576,1"), 16384); @@ -3360,8 +3477,8 @@ void RenderingServer::init() { GLOBAL_DEF("rendering/shading/overrides/force_lambert_over_burley", false); GLOBAL_DEF("rendering/shading/overrides/force_lambert_over_burley.mobile", true); - GLOBAL_DEF("rendering/driver/depth_prepass/enable", true); - GLOBAL_DEF("rendering/driver/depth_prepass/disable_for_vendors", "PowerVR,Mali,Adreno,Apple"); + GLOBAL_DEF_RST("rendering/driver/depth_prepass/enable", true); + GLOBAL_DEF_RST("rendering/driver/depth_prepass/disable_for_vendors", "PowerVR,Mali,Adreno,Apple"); GLOBAL_DEF_RST("rendering/textures/default_filters/use_nearest_mipmap_filter", false); GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/textures/default_filters/anisotropic_filtering_level", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Faster),4× (Fast),8× (Average),16× (Slow)")), 2); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 9d186f086c..fbc67fc84d 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -52,7 +52,7 @@ class RenderingServer : public Object { int mm_policy = 0; bool render_loop_enabled = true; - Array _get_array_from_surface(uint64_t p_format, Vector<uint8_t> p_vertex_data, Vector<uint8_t> p_attrib_data, Vector<uint8_t> p_skin_data, int p_vertex_len, Vector<uint8_t> p_index_data, int p_index_len, const AABB &p_aabb) const; + Array _get_array_from_surface(uint64_t p_format, Vector<uint8_t> p_vertex_data, Vector<uint8_t> p_attrib_data, Vector<uint8_t> p_skin_data, int p_vertex_len, Vector<uint8_t> p_index_data, int p_index_len, const AABB &p_aabb, const Vector4 &p_uv_scale) const; const Vector2 SMALL_VEC2 = Vector2(CMP_EPSILON, CMP_EPSILON); const Vector3 SMALL_VEC3 = Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON); @@ -298,6 +298,8 @@ public: ARRAY_FLAG_FORMAT_VERSION_MASK = 0xFF, // 8 bits version }; + static_assert(sizeof(ArrayFormat) == 8, "ArrayFormat should be 64 bits long."); + enum PrimitiveType { PRIMITIVE_POINTS, PRIMITIVE_LINES, @@ -631,6 +633,8 @@ public: virtual void voxel_gi_set_quality(VoxelGIQuality) = 0; + virtual void sdfgi_reset() = 0; + /* LIGHTMAP */ virtual RID lightmap_create() = 0; @@ -660,6 +664,7 @@ public: virtual void particles_set_emitting(RID p_particles, bool p_enable) = 0; virtual bool particles_get_emitting(RID p_particles) = 0; virtual void particles_set_amount(RID p_particles, int p_amount) = 0; + virtual void particles_set_amount_ratio(RID p_particles, float p_amount_ratio) = 0; virtual void particles_set_lifetime(RID p_particles, double p_lifetime) = 0; virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) = 0; virtual void particles_set_pre_process_time(RID p_particles, double p_time) = 0; @@ -717,6 +722,8 @@ public: virtual AABB particles_get_current_aabb(RID p_particles) = 0; virtual void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) = 0; // This is only used for 2D, in 3D it's automatic. + virtual void particles_set_emitter_velocity(RID p_particles, const Vector3 &p_velocity) = 0; + virtual void particles_set_interp_to_end(RID p_particles, float p_interp) = 0; /* PARTICLES COLLISION API */ @@ -1409,6 +1416,9 @@ public: virtual void canvas_item_set_canvas_group_mode(RID p_item, CanvasGroupMode p_mode, float p_clear_margin = 5.0, bool p_fit_empty = false, float p_fit_margin = 0.0, bool p_blur_mipmaps = false) = 0; + virtual void canvas_item_set_debug_redraw(bool p_enabled) = 0; + virtual bool canvas_item_get_debug_redraw() const = 0; + /* CANVAS LIGHT */ virtual RID canvas_light_create() = 0; @@ -1624,8 +1634,14 @@ public: RenderingServer(); virtual ~RenderingServer(); +#ifdef TOOLS_ENABLED + typedef void (*SurfaceUpgradeCallback)(); + void set_surface_upgrade_callback(SurfaceUpgradeCallback p_callback); + void set_warn_on_surface_upgrade(bool p_warn); +#endif + #ifndef DISABLE_DEPRECATED - static void _fix_surface_compatibility(SurfaceData &p_surface); + void fix_surface_compatibility(SurfaceData &p_surface, const String &p_path = ""); #endif private: @@ -1641,6 +1657,10 @@ private: TypedArray<Dictionary> _instance_geometry_get_shader_parameter_list(RID p_instance) const; TypedArray<Image> _bake_render_uv2(RID p_base, const TypedArray<RID> &p_material_overrides, const Size2i &p_image_size); void _particles_set_trail_bind_poses(RID p_particles, const TypedArray<Transform3D> &p_bind_poses); +#ifdef TOOLS_ENABLED + SurfaceUpgradeCallback surface_upgrade_callback = nullptr; + bool warn_on_surface_upgrade = true; +#endif }; // Make variant understand the enums. diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp index e584146d64..d6844bba6a 100644 --- a/servers/text/text_server_extension.cpp +++ b/servers/text/text_server_extension.cpp @@ -95,6 +95,9 @@ void TextServerExtension::_bind_methods() { GDVIRTUAL_BIND(_font_set_fixed_size, "font_rid", "fixed_size"); GDVIRTUAL_BIND(_font_get_fixed_size, "font_rid"); + GDVIRTUAL_BIND(_font_set_fixed_size_scale_mode, "font_rid", "fixed_size_scale_mode"); + GDVIRTUAL_BIND(_font_get_fixed_size_scale_mode, "font_rid"); + GDVIRTUAL_BIND(_font_set_allow_system_fallback, "font_rid", "allow_system_fallback"); GDVIRTUAL_BIND(_font_is_allow_system_fallback, "font_rid"); @@ -559,6 +562,16 @@ int64_t TextServerExtension::font_get_fixed_size(const RID &p_font_rid) const { return ret; } +void TextServerExtension::font_set_fixed_size_scale_mode(const RID &p_font_rid, TextServer::FixedSizeScaleMode p_fixed_size_scale_mode) { + GDVIRTUAL_CALL(_font_set_fixed_size_scale_mode, p_font_rid, p_fixed_size_scale_mode); +} + +TextServer::FixedSizeScaleMode TextServerExtension::font_get_fixed_size_scale_mode(const RID &p_font_rid) const { + FixedSizeScaleMode ret = FIXED_SIZE_SCALE_DISABLE; + GDVIRTUAL_CALL(_font_get_fixed_size_scale_mode, p_font_rid, ret); + return ret; +} + void TextServerExtension::font_set_allow_system_fallback(const RID &p_font_rid, bool p_allow_system_fallback) { GDVIRTUAL_CALL(_font_set_allow_system_fallback, p_font_rid, p_allow_system_fallback); } diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h index c40230e723..7605ed480d 100644 --- a/servers/text/text_server_extension.h +++ b/servers/text/text_server_extension.h @@ -153,6 +153,11 @@ public: GDVIRTUAL2(_font_set_fixed_size, RID, int64_t); GDVIRTUAL1RC(int64_t, _font_get_fixed_size, RID); + virtual void font_set_fixed_size_scale_mode(const RID &p_font_rid, FixedSizeScaleMode p_fixed_size_scale) override; + virtual FixedSizeScaleMode font_get_fixed_size_scale_mode(const RID &p_font_rid) const override; + GDVIRTUAL2(_font_set_fixed_size_scale_mode, RID, FixedSizeScaleMode); + GDVIRTUAL1RC(FixedSizeScaleMode, _font_get_fixed_size_scale_mode, RID); + virtual void font_set_subpixel_positioning(const RID &p_font_rid, SubpixelPositioning p_subpixel) override; virtual SubpixelPositioning font_get_subpixel_positioning(const RID &p_font_rid) const override; GDVIRTUAL2(_font_set_subpixel_positioning, RID, SubpixelPositioning); diff --git a/servers/text_server.cpp b/servers/text_server.cpp index e4eb4c730d..302d14bd8d 100644 --- a/servers/text_server.cpp +++ b/servers/text_server.cpp @@ -249,6 +249,9 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("font_set_fixed_size", "font_rid", "fixed_size"), &TextServer::font_set_fixed_size); ClassDB::bind_method(D_METHOD("font_get_fixed_size", "font_rid"), &TextServer::font_get_fixed_size); + ClassDB::bind_method(D_METHOD("font_set_fixed_size_scale_mode", "font_rid", "fixed_size_scale_mode"), &TextServer::font_set_fixed_size_scale_mode); + ClassDB::bind_method(D_METHOD("font_get_fixed_size_scale_mode", "font_rid"), &TextServer::font_get_fixed_size_scale_mode); + ClassDB::bind_method(D_METHOD("font_set_allow_system_fallback", "font_rid", "allow_system_fallback"), &TextServer::font_set_allow_system_fallback); ClassDB::bind_method(D_METHOD("font_is_allow_system_fallback", "font_rid"), &TextServer::font_is_allow_system_fallback); @@ -619,6 +622,11 @@ void TextServer::_bind_methods() { BIND_ENUM_CONSTANT(STRUCTURED_TEXT_LIST); BIND_ENUM_CONSTANT(STRUCTURED_TEXT_GDSCRIPT); BIND_ENUM_CONSTANT(STRUCTURED_TEXT_CUSTOM); + + /* Fixed size scale mode */ + BIND_ENUM_CONSTANT(FIXED_SIZE_SCALE_DISABLE); + BIND_ENUM_CONSTANT(FIXED_SIZE_SCALE_INTEGER_ONLY); + BIND_ENUM_CONSTANT(FIXED_SIZE_SCALE_ENABLED); } Vector2 TextServer::get_hex_code_box_size(int64_t p_size, int64_t p_index) const { diff --git a/servers/text_server.h b/servers/text_server.h index 260b44da8b..fdc0e9fc4d 100644 --- a/servers/text_server.h +++ b/servers/text_server.h @@ -207,6 +207,12 @@ public: STRUCTURED_TEXT_CUSTOM }; + enum FixedSizeScaleMode { + FIXED_SIZE_SCALE_DISABLE, + FIXED_SIZE_SCALE_INTEGER_ONLY, + FIXED_SIZE_SCALE_ENABLED, + }; + void _draw_hex_code_box_number(const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, uint8_t p_index, const Color &p_color) const; protected: @@ -281,6 +287,9 @@ public: virtual void font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) = 0; virtual int64_t font_get_fixed_size(const RID &p_font_rid) const = 0; + virtual void font_set_fixed_size_scale_mode(const RID &p_font_rid, FixedSizeScaleMode p_fixed_size_scale) = 0; + virtual FixedSizeScaleMode font_get_fixed_size_scale_mode(const RID &p_font_rid) const = 0; + virtual void font_set_allow_system_fallback(const RID &p_font_rid, bool p_allow_system_fallback) = 0; virtual bool font_is_allow_system_fallback(const RID &p_font_rid) const = 0; @@ -620,6 +629,7 @@ VARIANT_BITFIELD_CAST(TextServer::FontStyle); VARIANT_ENUM_CAST(TextServer::StructuredTextParser); VARIANT_ENUM_CAST(TextServer::FontAntialiasing); VARIANT_ENUM_CAST(TextServer::FontLCDSubpixelLayout); +VARIANT_ENUM_CAST(TextServer::FixedSizeScaleMode); GDVIRTUAL_NATIVE_PTR(Glyph); GDVIRTUAL_NATIVE_PTR(CaretInfo); diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp index 7e2c512554..dae342a037 100644 --- a/servers/xr_server.cpp +++ b/servers/xr_server.cpp @@ -198,9 +198,7 @@ void XRServer::remove_interface(const Ref<XRInterface> &p_interface) { }; ERR_FAIL_COND_MSG(idx == -1, "Interface not found."); - - print_verbose("XR: Removed interface" + p_interface->get_name()); - + print_verbose("XR: Removed interface \"" + p_interface->get_name() + "\""); emit_signal(SNAME("interface_removed"), p_interface->get_name()); interfaces.remove_at(idx); }; |
