Skip to content

Commit

Permalink
ProjectSettings add dirty flag and project_settings_changed signal
Browse files Browse the repository at this point in the history
Most frames there will be no change in project settings, and it makes no sense to read settings every frame in case of changes, as a large number of string compares are involved.

This PR adds a signal to ProjectSettings that can be subscribed to in order to keep local settings up to date with ProjectSettings.

In addition a function `ProjectSettings::has_changes()` is provided for objects outside the signal system (e.g. Rasterizers).
  • Loading branch information
lawnjelly committed Feb 9, 2022
1 parent 4ed2c8e commit f0af293
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 36 deletions.
19 changes: 19 additions & 0 deletions core/project_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,26 @@ String ProjectSettings::globalize_path(const String &p_path) const {
return p_path;
}

void ProjectSettings::update() {
if (_dirty_this_frame) {
// A signal is sent a single time at the end of the frame when project settings
// are changed. This allows objects to respond.
// Alternatively objects outside the signal system can query ProjectSettings::has_changes()
if (_dirty_this_frame == 2) {
emit_signal("project_settings_changed");
}

_dirty_this_frame--;
}
}

bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) {
_THREAD_SAFE_METHOD_

// marking the project settings as dirty allows them only to be
// checked when dirty.
_dirty_this_frame = 2;

if (p_value.get_type() == Variant::NIL) {
props.erase(p_name);
} else {
Expand Down Expand Up @@ -1022,6 +1039,8 @@ void ProjectSettings::_bind_methods() {
ClassDB::bind_method(D_METHOD("property_get_revert", "name"), &ProjectSettings::property_get_revert);

ClassDB::bind_method(D_METHOD("save_custom", "file"), &ProjectSettings::_save_custom_bnd);

ADD_SIGNAL(MethodInfo("project_settings_changed"));
}

ProjectSettings::ProjectSettings() {
Expand Down
35 changes: 35 additions & 0 deletions core/project_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,37 @@
#include "core/os/thread_safe.h"
#include "core/set.h"

// Querying ProjectSettings is usually done at startup.
// Additionally, in order to keep track of changes to ProjectSettings,
// instead of Querying all the strings every frame just in case of changes,
// there is a signal "project_settings_changed" which objects can subscribe to.

// E.g. (from another Godot object)
// // Call your user written object function to Query the project settings once at creation,
// perhaps in an ENTER_TREE notification:
// _project_settings_changed()
// // Then connect your function to the signal so it is called every time something changes in future:
// ProjectSettings::get_singleton()->connect("project_settings_changed", this, "_project_settings_changed");

// Where for example your function may take the form:
// void _project_settings_changed() {
// _shadowmap_size = GLOBAL_GET("rendering/quality/shadow_atlas/size");
// }

// You may want to also disconnect from the signal in EXIT_TREE notification, if your object may be deleted
// before ProjectSettings:
// ProjectSettings::get_singleton()->disconnect("project_settings_changed", this, "_project_settings_changed");

// Additionally, for objects that are not regular Godot objects capable of subscribing to signals (e.g. Rasterizers),
// you can also query the function "has_changes()" each frame,
// and update your local settings whenever this is set.

class ProjectSettings : public Object {
GDCLASS(ProjectSettings, Object);
_THREAD_SAFE_CLASS_

int _dirty_this_frame = 2;

public:
typedef Map<String, Variant> CustomMap;
static const String PROJECT_DATA_DIR_NAME_SUFFIX;
Expand Down Expand Up @@ -168,6 +195,14 @@ class ProjectSettings : public Object {

bool has_custom_feature(const String &p_feature) const;

// Either use the signal `project_settings_changed` or query this function.
// N.B. _dirty_this_frame is set initially to 2.
// This is to cope with the situation where a project setting is changed in the iteration AFTER it is read.
// There is therefore the potential for a change to be missed. Persisting the counter
// for two frames avoids this, at the cost of a frame delay.
bool has_changes() const { return _dirty_this_frame == 1; }
void update();

ProjectSettings();
~ProjectSettings();
};
Expand Down
7 changes: 7 additions & 0 deletions doc/classes/ProjectSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1569,6 +1569,13 @@
Cell size used for the 2D hash grid that [VisibilityNotifier2D] uses (in pixels).
</member>
</members>
<signals>
<signal name="project_settings_changed">
<description>
Objects can use this signal to restrict reading of settings only to situations where a change has been made.
</description>
</signal>
</signals>
<constants>
</constants>
</class>
4 changes: 2 additions & 2 deletions editor/import_defaults_editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ void ImportDefaultsEditor::_save() {
} else {
ProjectSettings::get_singleton()->set("importer_defaults/" + settings->importer->get_importer_name(), Variant());
}

emit_signal("project_settings_changed");
// Calling ProjectSettings::set() causes the signal "project_settings_changed" to be sent to ProjectSettings.
// ProjectSettingsEditor subscribes to this and can reads the settings updated here.
}
}

Expand Down
88 changes: 55 additions & 33 deletions editor/plugins/spatial_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2462,6 +2462,49 @@ void SpatialEditorPlugin::edited_scene_changed() {
}
}

void SpatialEditorViewport::_project_settings_changed() {
if (viewport) {
_project_settings_change_pending = false;

//update shadow atlas if changed
int shadowmap_size = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/size");
int atlas_q0 = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/quadrant_0_subdiv");
int atlas_q1 = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/quadrant_1_subdiv");
int atlas_q2 = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/quadrant_2_subdiv");
int atlas_q3 = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/quadrant_3_subdiv");

viewport->set_shadow_atlas_size(shadowmap_size);
viewport->set_shadow_atlas_quadrant_subdiv(0, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q0));
viewport->set_shadow_atlas_quadrant_subdiv(1, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q1));
viewport->set_shadow_atlas_quadrant_subdiv(2, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q2));
viewport->set_shadow_atlas_quadrant_subdiv(3, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q3));

// Update MSAA, FXAA, debanding and HDR if changed.
int msaa_mode = ProjectSettings::get_singleton()->get("rendering/quality/filters/msaa");
viewport->set_msaa(Viewport::MSAA(msaa_mode));

bool use_fxaa = ProjectSettings::get_singleton()->get("rendering/quality/filters/use_fxaa");
viewport->set_use_fxaa(use_fxaa);

bool use_debanding = ProjectSettings::get_singleton()->get("rendering/quality/filters/use_debanding");
viewport->set_use_debanding(use_debanding);

float sharpen_intensity = ProjectSettings::get_singleton()->get("rendering/quality/filters/sharpen_intensity");
viewport->set_sharpen_intensity(sharpen_intensity);

bool hdr = ProjectSettings::get_singleton()->get("rendering/quality/depth/hdr");
viewport->set_hdr(hdr);

const bool use_32_bpc_depth = ProjectSettings::get_singleton()->get("rendering/quality/depth/use_32_bpc_depth");
viewport->set_use_32_bpc_depth(use_32_bpc_depth);

} else {
// Could not update immediately, set a pending update.
// This may never happen, but is included for safety
_project_settings_change_pending = true;
}
}

void SpatialEditorViewport::_notification(int p_what) {
if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
bool visible = is_visible_in_tree();
Expand Down Expand Up @@ -2583,46 +2626,16 @@ void SpatialEditorViewport::_notification(int p_what) {
}
}

//update shadow atlas if changed

int shadowmap_size = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/size");
int atlas_q0 = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/quadrant_0_subdiv");
int atlas_q1 = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/quadrant_1_subdiv");
int atlas_q2 = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/quadrant_2_subdiv");
int atlas_q3 = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/quadrant_3_subdiv");

viewport->set_shadow_atlas_size(shadowmap_size);
viewport->set_shadow_atlas_quadrant_subdiv(0, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q0));
viewport->set_shadow_atlas_quadrant_subdiv(1, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q1));
viewport->set_shadow_atlas_quadrant_subdiv(2, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q2));
viewport->set_shadow_atlas_quadrant_subdiv(3, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q3));
if (_project_settings_change_pending) {
_project_settings_changed();
}

bool shrink = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION));

if (shrink != (viewport_container->get_stretch_shrink() > 1)) {
viewport_container->set_stretch_shrink(shrink ? 2 : 1);
}

// Update MSAA, FXAA, debanding and HDR if changed.

int msaa_mode = ProjectSettings::get_singleton()->get("rendering/quality/filters/msaa");
viewport->set_msaa(Viewport::MSAA(msaa_mode));

bool use_fxaa = ProjectSettings::get_singleton()->get("rendering/quality/filters/use_fxaa");
viewport->set_use_fxaa(use_fxaa);

bool use_debanding = ProjectSettings::get_singleton()->get("rendering/quality/filters/use_debanding");
viewport->set_use_debanding(use_debanding);

float sharpen_intensity = ProjectSettings::get_singleton()->get("rendering/quality/filters/sharpen_intensity");
viewport->set_sharpen_intensity(sharpen_intensity);

const bool hdr = ProjectSettings::get_singleton()->get("rendering/quality/depth/hdr");
viewport->set_hdr(hdr);

const bool use_32_bpc_depth = ProjectSettings::get_singleton()->get("rendering/quality/depth/use_32_bpc_depth");
viewport->set_use_32_bpc_depth(use_32_bpc_depth);

bool show_info = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION));
info_label->set_visible(show_info);

Expand Down Expand Up @@ -2689,10 +2702,17 @@ void SpatialEditorViewport::_notification(int p_what) {
surface->connect("focus_entered", this, "_surface_focus_enter");
surface->connect("focus_exited", this, "_surface_focus_exit");

// Ensure we are up to date with project settings
_project_settings_changed();

// Any further changes to project settings get a signal
ProjectSettings::get_singleton()->connect("project_settings_changed", this, "_project_settings_changed");

_init_gizmo_instance(index);
}

if (p_what == NOTIFICATION_EXIT_TREE) {
ProjectSettings::get_singleton()->disconnect("project_settings_changed", this, "_project_settings_changed");
_finish_gizmo_instances();
}

Expand Down Expand Up @@ -3582,6 +3602,7 @@ void SpatialEditorViewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("_selection_menu_hide"), &SpatialEditorViewport::_selection_menu_hide);
ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &SpatialEditorViewport::can_drop_data_fw);
ClassDB::bind_method(D_METHOD("drop_data_fw"), &SpatialEditorViewport::drop_data_fw);
ClassDB::bind_method(D_METHOD("_project_settings_changed"), &SpatialEditorViewport::_project_settings_changed);

ADD_SIGNAL(MethodInfo("toggle_maximize_view", PropertyInfo(Variant::OBJECT, "viewport")));
ADD_SIGNAL(MethodInfo("clicked", PropertyInfo(Variant::OBJECT, "viewport")));
Expand Down Expand Up @@ -4104,6 +4125,7 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
gizmo_scale = 1.0;

preview_node = nullptr;
_project_settings_change_pending = false;

info_label = memnew(Label);
info_label->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, -90 * EDSCALE);
Expand Down
3 changes: 3 additions & 0 deletions editor/plugins/spatial_editor_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ class SpatialEditorViewport : public Control {

private:
int index;
bool _project_settings_change_pending;
ViewType view_type;
void _menu_option(int p_option);
void _set_auto_orthogonal();
Expand Down Expand Up @@ -458,6 +459,8 @@ class SpatialEditorViewport : public Control {
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);

void _project_settings_changed();

protected:
void _notification(int p_what);
static void _bind_methods();
Expand Down
10 changes: 9 additions & 1 deletion editor/project_settings_editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,16 @@ void ProjectSettingsEditor::_notification(int p_what) {
restart_icon->set_texture(get_icon("StatusWarning", "EditorIcons"));
restart_label->add_color_override("font_color", get_color("warning_color", "Editor"));

// The ImportDefaultsEditor changes settings which must be read by this object when changed
ProjectSettings::get_singleton()->connect("project_settings_changed", this, "_settings_changed");

} break;
case NOTIFICATION_EXIT_TREE: {
if (ProjectSettings::get_singleton()) {
ProjectSettings::get_singleton()->disconnect("project_settings_changed", this, "_settings_changed");
}
} break;

case NOTIFICATION_POPUP_HIDE: {
EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "project_settings", get_rect());
set_process_unhandled_input(false);
Expand Down Expand Up @@ -2141,7 +2150,6 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
import_defaults_editor = memnew(ImportDefaultsEditor);
import_defaults_editor->set_name(TTR("Import Defaults"));
tab_container->add_child(import_defaults_editor);
import_defaults_editor->connect("project_settings_changed", this, "_settings_changed");

timer = memnew(Timer);
timer->set_wait_time(1.5);
Expand Down
2 changes: 2 additions & 0 deletions scene/main/scene_tree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,8 @@ bool SceneTree::idle(float p_time) {

_call_idle_callbacks();

ProjectSettings::get_singleton()->update();

#ifdef TOOLS_ENABLED

if (Engine::get_singleton()->is_editor_hint()) {
Expand Down

0 comments on commit f0af293

Please sign in to comment.