diff options
Diffstat (limited to 'servers')
61 files changed, 1671 insertions, 522 deletions
diff --git a/servers/SCsub b/servers/SCsub index 76c11724d3..2cd4741d56 100644 --- a/servers/SCsub +++ b/servers/SCsub @@ -12,6 +12,7 @@ SConscript("physics_2d/SCsub") SConscript("rendering/SCsub") SConscript("audio/SCsub") SConscript("text/SCsub") +SConscript("debugger/SCsub") lib = env.add_library("servers", env.servers_sources) diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp index 170a7ef967..39060286a4 100644 --- a/servers/audio/audio_stream.cpp +++ b/servers/audio/audio_stream.cpp @@ -351,100 +351,372 @@ AudioStreamPlaybackMicrophone::AudioStreamPlaybackMicrophone() { //////////////////////////////// -void AudioStreamRandomPitch::set_audio_stream(const Ref<AudioStream> &p_audio_stream) { - audio_stream = p_audio_stream; - if (audio_stream.is_valid()) { - for (Set<AudioStreamPlaybackRandomPitch *>::Element *E = playbacks.front(); E; E = E->next()) { - E->get()->playback = audio_stream->instance_playback(); - } +void AudioStreamRandomizer::add_stream(int p_index) { + if (p_index < 0) { + p_index = audio_stream_pool.size(); + } + ERR_FAIL_COND(p_index > audio_stream_pool.size()); + PoolEntry entry{ nullptr, 1.0f }; + audio_stream_pool.insert(p_index, entry); + emit_signal(SNAME("changed")); + notify_property_list_changed(); +} + +void AudioStreamRandomizer::move_stream(int p_index_from, int p_index_to) { + ERR_FAIL_COND(p_index_from < 0); + ERR_FAIL_COND(p_index_from >= audio_stream_pool.size()); + ERR_FAIL_COND(p_index_to < 0); + ERR_FAIL_COND(p_index_to > audio_stream_pool.size()); + audio_stream_pool.insert(p_index_to, audio_stream_pool[p_index_from]); + // If 'from' is strictly after 'to' we need to increment the index by one because of the insertion. + if (p_index_from > p_index_to) { + p_index_from++; } + audio_stream_pool.remove_at(p_index_from); + emit_signal(SNAME("changed")); + notify_property_list_changed(); +} + +void AudioStreamRandomizer::remove_stream(int p_index) { + ERR_FAIL_COND(p_index < 0); + ERR_FAIL_COND(p_index >= audio_stream_pool.size()); + audio_stream_pool.remove_at(p_index); + emit_signal(SNAME("changed")); + notify_property_list_changed(); +} + +void AudioStreamRandomizer::set_stream(int p_index, Ref<AudioStream> p_stream) { + ERR_FAIL_COND(p_index < 0); + ERR_FAIL_COND(p_index >= audio_stream_pool.size()); + audio_stream_pool.write[p_index].stream = p_stream; + emit_signal(SNAME("changed")); } -Ref<AudioStream> AudioStreamRandomPitch::get_audio_stream() const { - return audio_stream; +Ref<AudioStream> AudioStreamRandomizer::get_stream(int p_index) const { + ERR_FAIL_COND_V(p_index < 0, nullptr); + ERR_FAIL_COND_V(p_index >= audio_stream_pool.size(), nullptr); + return audio_stream_pool[p_index].stream; } -void AudioStreamRandomPitch::set_random_pitch(float p_pitch) { +void AudioStreamRandomizer::set_stream_probability_weight(int p_index, float p_weight) { + ERR_FAIL_COND(p_index < 0); + ERR_FAIL_COND(p_index >= audio_stream_pool.size()); + audio_stream_pool.write[p_index].weight = p_weight; + emit_signal(SNAME("changed")); +} + +float AudioStreamRandomizer::get_stream_probability_weight(int p_index) const { + ERR_FAIL_COND_V(p_index < 0, 0); + ERR_FAIL_COND_V(p_index >= audio_stream_pool.size(), 0); + return audio_stream_pool[p_index].weight; +} + +void AudioStreamRandomizer::set_streams_count(int p_count) { + audio_stream_pool.resize(p_count); +} + +int AudioStreamRandomizer::get_streams_count() const { + return audio_stream_pool.size(); +} + +void AudioStreamRandomizer::set_random_pitch(float p_pitch) { if (p_pitch < 1) { p_pitch = 1; } - random_pitch = p_pitch; + random_pitch_scale = p_pitch; +} + +float AudioStreamRandomizer::get_random_pitch() const { + return random_pitch_scale; +} + +void AudioStreamRandomizer::set_random_volume_offset_db(float p_volume_offset_db) { + if (p_volume_offset_db < 0) { + p_volume_offset_db = 0; + } + random_volume_offset_db = p_volume_offset_db; +} + +float AudioStreamRandomizer::get_random_volume_offset_db() const { + return random_volume_offset_db; } -float AudioStreamRandomPitch::get_random_pitch() const { - return random_pitch; +void AudioStreamRandomizer::set_playback_mode(PlaybackMode p_playback_mode) { + playback_mode = p_playback_mode; } -Ref<AudioStreamPlayback> AudioStreamRandomPitch::instance_playback() { - Ref<AudioStreamPlaybackRandomPitch> playback; +AudioStreamRandomizer::PlaybackMode AudioStreamRandomizer::get_playback_mode() const { + return playback_mode; +} + +Ref<AudioStreamPlayback> AudioStreamRandomizer::instance_playback_random() { + Ref<AudioStreamPlaybackRandomizer> playback; playback.instantiate(); - if (audio_stream.is_valid()) { - playback->playback = audio_stream->instance_playback(); + playbacks.insert(playback.ptr()); + playback->randomizer = Ref<AudioStreamRandomizer>((AudioStreamRandomizer *)this); + + double total_weight = 0; + Vector<PoolEntry> local_pool; + for (const PoolEntry &entry : audio_stream_pool) { + if (entry.stream.is_valid() && entry.weight > 0) { + local_pool.push_back(entry); + total_weight += entry.weight; + } + } + if (local_pool.is_empty()) { + return playback; } + double chosen_cumulative_weight = Math::random(0.0, total_weight); + double cumulative_weight = 0; + for (PoolEntry &entry : local_pool) { + cumulative_weight += entry.weight; + if (cumulative_weight > chosen_cumulative_weight) { + playback->playback = entry.stream->instance_playback(); + last_playback = entry.stream; + break; + } + } + if (playback->playback.is_null()) { + // This indicates a floating point error. Take the last element. + last_playback = local_pool[local_pool.size() - 1].stream; + playback->playback = local_pool.write[local_pool.size() - 1].stream->instance_playback(); + } + return playback; +} + +Ref<AudioStreamPlayback> AudioStreamRandomizer::instance_playback_no_repeats() { + Ref<AudioStreamPlaybackRandomizer> playback; + double total_weight = 0; + Vector<PoolEntry> local_pool; + for (const PoolEntry &entry : audio_stream_pool) { + if (entry.stream == last_playback) { + continue; + } + if (entry.stream.is_valid() && entry.weight > 0) { + local_pool.push_back(entry); + total_weight += entry.weight; + } + } + if (local_pool.is_empty()) { + playback = instance_playback_random(); + WARN_PRINT("Playback stream pool is too small to prevent repeats."); + return playback; + } + + playback.instantiate(); playbacks.insert(playback.ptr()); - playback->random_pitch = Ref<AudioStreamRandomPitch>((AudioStreamRandomPitch *)this); + playback->randomizer = Ref<AudioStreamRandomizer>((AudioStreamRandomizer *)this); + double chosen_cumulative_weight = Math::random(0.0, total_weight); + double cumulative_weight = 0; + for (PoolEntry &entry : local_pool) { + cumulative_weight += entry.weight; + if (cumulative_weight > chosen_cumulative_weight) { + last_playback = entry.stream; + playback->playback = entry.stream->instance_playback(); + break; + } + } + if (playback->playback.is_null()) { + // This indicates a floating point error. Take the last element. + last_playback = local_pool[local_pool.size() - 1].stream; + playback->playback = local_pool.write[local_pool.size() - 1].stream->instance_playback(); + } return playback; } -String AudioStreamRandomPitch::get_stream_name() const { - if (audio_stream.is_valid()) { - return "Random: " + audio_stream->get_name(); +Ref<AudioStreamPlayback> AudioStreamRandomizer::instance_playback_sequential() { + Ref<AudioStreamPlaybackRandomizer> playback; + playback.instantiate(); + playbacks.insert(playback.ptr()); + playback->randomizer = Ref<AudioStreamRandomizer>((AudioStreamRandomizer *)this); + + Vector<Ref<AudioStream>> local_pool; + for (const PoolEntry &entry : audio_stream_pool) { + if (entry.stream.is_null()) { + continue; + } + if (local_pool.find(entry.stream) != -1) { + WARN_PRINT("Duplicate stream in sequential playback pool"); + continue; + } + local_pool.push_back(entry.stream); + } + if (local_pool.is_empty()) { + return playback; } - return "RandomPitch"; + bool found_last_stream = false; + for (Ref<AudioStream> &entry : local_pool) { + if (found_last_stream) { + last_playback = entry; + playback->playback = entry->instance_playback(); + break; + } + if (entry == last_playback) { + found_last_stream = true; + } + } + if (playback->playback.is_null()) { + // Wrap around + last_playback = local_pool[0]; + playback->playback = local_pool.write[0]->instance_playback(); + } + return playback; } -float AudioStreamRandomPitch::get_length() const { - if (audio_stream.is_valid()) { - return audio_stream->get_length(); +Ref<AudioStreamPlayback> AudioStreamRandomizer::instance_playback() { + switch (playback_mode) { + case PLAYBACK_RANDOM: + return instance_playback_random(); + case PLAYBACK_RANDOM_NO_REPEATS: + return instance_playback_no_repeats(); + case PLAYBACK_SEQUENTIAL: + return instance_playback_sequential(); + default: + ERR_FAIL_V_MSG(nullptr, "Unhandled playback mode."); } +} +String AudioStreamRandomizer::get_stream_name() const { + return "Randomizer"; +} + +float AudioStreamRandomizer::get_length() const { return 0; } -bool AudioStreamRandomPitch::is_monophonic() const { - if (audio_stream.is_valid()) { - return audio_stream->is_monophonic(); +bool AudioStreamRandomizer::is_monophonic() const { + for (const PoolEntry &entry : audio_stream_pool) { + if (entry.stream.is_valid() && entry.stream->is_monophonic()) { + return true; + } + } + return false; +} + +bool AudioStreamRandomizer::_get(const StringName &p_name, Variant &r_ret) const { + if (AudioStream::_get(p_name, r_ret)) { + return true; } + Vector<String> components = String(p_name).split("/", true, 2); + if (components.size() == 2 && components[0].begins_with("stream_") && components[0].trim_prefix("stream_").is_valid_int()) { + int index = components[0].trim_prefix("stream_").to_int(); + if (index < 0 || index >= (int)audio_stream_pool.size()) { + return false; + } - return true; // It doesn't really matter what we return here, but no sense instancing a many playbacks of a null stream. + if (components[1] == "stream") { + r_ret = get_stream(index); + return true; + } else if (components[1] == "weight") { + r_ret = get_stream_probability_weight(index); + return true; + } else { + return false; + } + } + return false; +} + +bool AudioStreamRandomizer::_set(const StringName &p_name, const Variant &p_value) { + if (AudioStream::_set(p_name, p_value)) { + return true; + } + Vector<String> components = String(p_name).split("/", true, 2); + if (components.size() == 2 && components[0].begins_with("stream_") && components[0].trim_prefix("stream_").is_valid_int()) { + int index = components[0].trim_prefix("stream_").to_int(); + if (index < 0 || index >= (int)audio_stream_pool.size()) { + return false; + } + + if (components[1] == "stream") { + set_stream(index, p_value); + return true; + } else if (components[1] == "weight") { + set_stream_probability_weight(index, p_value); + return true; + } else { + return false; + } + } + return false; +} + +void AudioStreamRandomizer::_get_property_list(List<PropertyInfo> *p_list) const { + AudioStream::_get_property_list(p_list); // Define the trivial scalar properties. + p_list->push_back(PropertyInfo(Variant::NIL, "Streams", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP)); + for (int i = 0; i < audio_stream_pool.size(); i++) { + p_list->push_back(PropertyInfo(Variant::OBJECT, vformat("stream_%d/stream", i), PROPERTY_HINT_RESOURCE_TYPE, "AudioStream")); + p_list->push_back(PropertyInfo(Variant::FLOAT, vformat("stream_%d/weight", i), PROPERTY_HINT_RANGE, "0,100,0.001,or_greater")); + } } -void AudioStreamRandomPitch::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_audio_stream", "stream"), &AudioStreamRandomPitch::set_audio_stream); - ClassDB::bind_method(D_METHOD("get_audio_stream"), &AudioStreamRandomPitch::get_audio_stream); +void AudioStreamRandomizer::_bind_methods() { + ClassDB::bind_method(D_METHOD("add_stream", "index"), &AudioStreamRandomizer::add_stream); + ClassDB::bind_method(D_METHOD("move_stream", "index_from", "index_to"), &AudioStreamRandomizer::move_stream); + ClassDB::bind_method(D_METHOD("remove_stream", "index"), &AudioStreamRandomizer::remove_stream); + + ClassDB::bind_method(D_METHOD("set_stream", "index", "stream"), &AudioStreamRandomizer::set_stream); + ClassDB::bind_method(D_METHOD("get_stream", "index"), &AudioStreamRandomizer::get_stream); + ClassDB::bind_method(D_METHOD("set_stream_probability_weight", "index", "weight"), &AudioStreamRandomizer::set_stream_probability_weight); + ClassDB::bind_method(D_METHOD("get_stream_probability_weight", "index"), &AudioStreamRandomizer::get_stream_probability_weight); + + ClassDB::bind_method(D_METHOD("set_streams_count", "count"), &AudioStreamRandomizer::set_streams_count); + ClassDB::bind_method(D_METHOD("get_streams_count"), &AudioStreamRandomizer::get_streams_count); + + ClassDB::bind_method(D_METHOD("set_random_pitch", "scale"), &AudioStreamRandomizer::set_random_pitch); + ClassDB::bind_method(D_METHOD("get_random_pitch"), &AudioStreamRandomizer::get_random_pitch); - ClassDB::bind_method(D_METHOD("set_random_pitch", "scale"), &AudioStreamRandomPitch::set_random_pitch); - ClassDB::bind_method(D_METHOD("get_random_pitch"), &AudioStreamRandomPitch::get_random_pitch); + ClassDB::bind_method(D_METHOD("set_random_volume_offset_db", "db_offset"), &AudioStreamRandomizer::set_random_volume_offset_db); + ClassDB::bind_method(D_METHOD("get_random_volume_offset_db"), &AudioStreamRandomizer::get_random_volume_offset_db); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "audio_stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_audio_stream", "get_audio_stream"); + ClassDB::bind_method(D_METHOD("set_playback_mode", "mode"), &AudioStreamRandomizer::set_playback_mode); + ClassDB::bind_method(D_METHOD("get_playback_mode"), &AudioStreamRandomizer::get_playback_mode); + + ADD_ARRAY("streams", "stream_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "streams_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_streams_count", "get_streams_count"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_mode", PROPERTY_HINT_ENUM, "Random (Avoid Repeats),Random,Sequential"), "set_playback_mode", "get_playback_mode"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "random_pitch", PROPERTY_HINT_RANGE, "1,16,0.01"), "set_random_pitch", "get_random_pitch"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "random_volume_offset_db", PROPERTY_HINT_RANGE, "0,40,0"), "set_random_volume_offset_db", "get_random_volume_offset_db"); + + BIND_ENUM_CONSTANT(PLAYBACK_RANDOM_NO_REPEATS); + BIND_ENUM_CONSTANT(PLAYBACK_RANDOM); + BIND_ENUM_CONSTANT(PLAYBACK_SEQUENTIAL); } -AudioStreamRandomPitch::AudioStreamRandomPitch() { - random_pitch = 1.1; +AudioStreamRandomizer::AudioStreamRandomizer() { + random_pitch_scale = 1.1; + random_volume_offset_db = 5; } -void AudioStreamPlaybackRandomPitch::start(float p_from_pos) { +void AudioStreamPlaybackRandomizer::start(float p_from_pos) { playing = playback; - float range_from = 1.0 / random_pitch->random_pitch; - float range_to = random_pitch->random_pitch; + { + float range_from = 1.0 / randomizer->random_pitch_scale; + float range_to = randomizer->random_pitch_scale; - pitch_scale = range_from + Math::randf() * (range_to - range_from); + pitch_scale = range_from + Math::randf() * (range_to - range_from); + } + { + float range_from = -randomizer->random_volume_offset_db; + float range_to = randomizer->random_volume_offset_db; + + float volume_offset_db = range_from + Math::randf() * (range_to - range_from); + volume_scale = Math::db2linear(volume_offset_db); + } if (playing.is_valid()) { playing->start(p_from_pos); } } -void AudioStreamPlaybackRandomPitch::stop() { +void AudioStreamPlaybackRandomizer::stop() { if (playing.is_valid()) { playing->stop(); - ; } } -bool AudioStreamPlaybackRandomPitch::is_playing() const { +bool AudioStreamPlaybackRandomizer::is_playing() const { if (playing.is_valid()) { return playing->is_playing(); } @@ -452,7 +724,7 @@ bool AudioStreamPlaybackRandomPitch::is_playing() const { return false; } -int AudioStreamPlaybackRandomPitch::get_loop_count() const { +int AudioStreamPlaybackRandomizer::get_loop_count() const { if (playing.is_valid()) { return playing->get_loop_count(); } @@ -460,7 +732,7 @@ int AudioStreamPlaybackRandomPitch::get_loop_count() const { return 0; } -float AudioStreamPlaybackRandomPitch::get_playback_position() const { +float AudioStreamPlaybackRandomizer::get_playback_position() const { if (playing.is_valid()) { return playing->get_playback_position(); } @@ -468,13 +740,13 @@ float AudioStreamPlaybackRandomPitch::get_playback_position() const { return 0; } -void AudioStreamPlaybackRandomPitch::seek(float p_time) { +void AudioStreamPlaybackRandomizer::seek(float p_time) { if (playing.is_valid()) { playing->seek(p_time); } } -int AudioStreamPlaybackRandomPitch::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) { +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); } else { @@ -485,7 +757,7 @@ int AudioStreamPlaybackRandomPitch::mix(AudioFrame *p_buffer, float p_rate_scale } } -AudioStreamPlaybackRandomPitch::~AudioStreamPlaybackRandomPitch() { - random_pitch->playbacks.erase(this); +AudioStreamPlaybackRandomizer::~AudioStreamPlaybackRandomizer() { + randomizer->playbacks.erase(this); } ///////////////////////////////////////////// diff --git a/servers/audio/audio_stream.h b/servers/audio/audio_stream.h index 32159e96ef..ce9bcabb9c 100644 --- a/servers/audio/audio_stream.h +++ b/servers/audio/audio_stream.h @@ -167,43 +167,86 @@ public: // -class AudioStreamPlaybackRandomPitch; +class AudioStreamPlaybackRandomizer; -class AudioStreamRandomPitch : public AudioStream { - GDCLASS(AudioStreamRandomPitch, AudioStream); - friend class AudioStreamPlaybackRandomPitch; +class AudioStreamRandomizer : public AudioStream { + GDCLASS(AudioStreamRandomizer, AudioStream); - Set<AudioStreamPlaybackRandomPitch *> playbacks; - Ref<AudioStream> audio_stream; - float random_pitch; +public: + enum PlaybackMode { + PLAYBACK_RANDOM_NO_REPEATS, + PLAYBACK_RANDOM, + PLAYBACK_SEQUENTIAL, + }; + +private: + friend class AudioStreamPlaybackRandomizer; + + struct PoolEntry { + Ref<AudioStream> stream; + float weight; + }; + + Set<AudioStreamPlaybackRandomizer *> playbacks; + Vector<PoolEntry> audio_stream_pool; + float random_pitch_scale; + float random_volume_offset_db; + + Ref<AudioStreamPlayback> instance_playback_random(); + Ref<AudioStreamPlayback> instance_playback_no_repeats(); + Ref<AudioStreamPlayback> instance_playback_sequential(); + + Ref<AudioStream> last_playback = nullptr; + PlaybackMode playback_mode = PLAYBACK_RANDOM_NO_REPEATS; protected: static void _bind_methods(); + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; + public: - void set_audio_stream(const Ref<AudioStream> &p_audio_stream); - Ref<AudioStream> get_audio_stream() const; + void add_stream(int p_index); + void move_stream(int p_index_from, int p_index_to); + void remove_stream(int p_index); + + void set_stream(int p_index, Ref<AudioStream> p_stream); + Ref<AudioStream> get_stream(int p_index) const; + void set_stream_probability_weight(int p_index, float p_weight); + float get_stream_probability_weight(int p_index) const; - void set_random_pitch(float p_pitch); + void set_streams_count(int p_count); + int get_streams_count() const; + + void set_random_pitch(float p_pitch_scale); float get_random_pitch() const; + void set_random_volume_offset_db(float p_volume_offset_db); + float get_random_volume_offset_db() const; + + void set_playback_mode(PlaybackMode p_playback_mode); + PlaybackMode get_playback_mode() const; + virtual Ref<AudioStreamPlayback> instance_playback() override; virtual String get_stream_name() const override; virtual float get_length() const override; //if supported, otherwise return 0 virtual bool is_monophonic() const override; - AudioStreamRandomPitch(); + AudioStreamRandomizer(); }; -class AudioStreamPlaybackRandomPitch : public AudioStreamPlayback { - GDCLASS(AudioStreamPlaybackRandomPitch, AudioStreamPlayback); - friend class AudioStreamRandomPitch; +class AudioStreamPlaybackRandomizer : public AudioStreamPlayback { + GDCLASS(AudioStreamPlaybackRandomizer, AudioStreamPlayback); + friend class AudioStreamRandomizer; - Ref<AudioStreamRandomPitch> random_pitch; + Ref<AudioStreamRandomizer> randomizer; Ref<AudioStreamPlayback> playback; Ref<AudioStreamPlayback> playing; + float pitch_scale; + float volume_scale; public: virtual void start(float p_from_pos = 0.0) override; @@ -217,7 +260,9 @@ public: virtual int mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) override; - ~AudioStreamPlaybackRandomPitch(); + ~AudioStreamPlaybackRandomizer(); }; +VARIANT_ENUM_CAST(AudioStreamRandomizer::PlaybackMode); + #endif // AUDIO_STREAM_H diff --git a/servers/audio/effects/audio_effect_record.cpp b/servers/audio/effects/audio_effect_record.cpp index 569832b8a8..a5866bb380 100644 --- a/servers/audio/effects/audio_effect_record.cpp +++ b/servers/audio/effects/audio_effect_record.cpp @@ -112,7 +112,7 @@ void AudioEffectRecordInstance::init() { ring_buffer_read_pos = 0; //We start a new recording - recording_data.resize(0); //Clear data completely and reset length + recording_data.clear(); //Clear data completely and reset length is_recording = true; #ifdef NO_THREADS diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index c89f811678..f00b8077d1 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -456,10 +456,12 @@ void AudioServer::_mix_step() { case AudioStreamPlaybackListNode::AWAITING_DELETION: case AudioStreamPlaybackListNode::FADE_OUT_TO_DELETION: playback_list.erase(playback, [](AudioStreamPlaybackListNode *p) { - if (p->prev_bus_details) + if (p->prev_bus_details) { delete p->prev_bus_details; - if (p->bus_details) + } + if (p->bus_details) { delete p->bus_details; + } p->stream_playback.unref(); delete p; }); diff --git a/servers/debugger/SCsub b/servers/debugger/SCsub new file mode 100644 index 0000000000..86681f9c74 --- /dev/null +++ b/servers/debugger/SCsub @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +Import("env") + +env.add_source_files(env.servers_sources, "*.cpp") diff --git a/servers/debugger/servers_debugger.cpp b/servers/debugger/servers_debugger.cpp new file mode 100644 index 0000000000..d1391937d9 --- /dev/null +++ b/servers/debugger/servers_debugger.cpp @@ -0,0 +1,463 @@ +/*************************************************************************/ +/* servers_debugger.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "servers_debugger.h" + +#include "core/config/project_settings.h" +#include "core/debugger/engine_debugger.h" +#include "core/debugger/engine_profiler.h" +#include "core/io/marshalls.h" +#include "servers/display_server.h" + +#define CHECK_SIZE(arr, expected, what) ERR_FAIL_COND_V_MSG((uint32_t)arr.size() < (uint32_t)(expected), false, String("Malformed ") + what + " message from script debugger, message too short. Expected size: " + itos(expected) + ", actual size: " + itos(arr.size())) +#define CHECK_END(arr, expected, what) ERR_FAIL_COND_V_MSG((uint32_t)arr.size() > (uint32_t)expected, false, String("Malformed ") + what + " message from script debugger, message too long. Expected size: " + itos(expected) + ", actual size: " + itos(arr.size())) + +Array ServersDebugger::ResourceUsage::serialize() { + infos.sort(); + + Array arr; + arr.push_back(infos.size() * 4); + for (const ResourceInfo &E : infos) { + arr.push_back(E.path); + arr.push_back(E.format); + arr.push_back(E.type); + arr.push_back(E.vram); + } + return arr; +} + +bool ServersDebugger::ResourceUsage::deserialize(const Array &p_arr) { + CHECK_SIZE(p_arr, 1, "ResourceUsage"); + uint32_t size = p_arr[0]; + CHECK_SIZE(p_arr, size, "ResourceUsage"); + int idx = 1; + for (uint32_t i = 0; i < size / 4; i++) { + ResourceInfo info; + info.path = p_arr[idx]; + info.format = p_arr[idx + 1]; + info.type = p_arr[idx + 2]; + info.vram = p_arr[idx + 3]; + infos.push_back(info); + } + CHECK_END(p_arr, idx, "ResourceUsage"); + return true; +} + +Array ServersDebugger::ScriptFunctionSignature::serialize() { + Array arr; + arr.push_back(name); + arr.push_back(id); + return arr; +} + +bool ServersDebugger::ScriptFunctionSignature::deserialize(const Array &p_arr) { + CHECK_SIZE(p_arr, 2, "ScriptFunctionSignature"); + name = p_arr[0]; + id = p_arr[1]; + CHECK_END(p_arr, 2, "ScriptFunctionSignature"); + return true; +} + +Array ServersDebugger::ServersProfilerFrame::serialize() { + Array arr; + arr.push_back(frame_number); + arr.push_back(frame_time); + arr.push_back(idle_time); + arr.push_back(physics_time); + arr.push_back(physics_frame_time); + arr.push_back(script_time); + + arr.push_back(servers.size()); + for (int i = 0; i < servers.size(); i++) { + ServerInfo &s = servers[i]; + arr.push_back(s.name); + arr.push_back(s.functions.size() * 2); + for (int j = 0; j < s.functions.size(); j++) { + ServerFunctionInfo &f = s.functions[j]; + arr.push_back(f.name); + arr.push_back(f.time); + } + } + + arr.push_back(script_functions.size() * 4); + for (int i = 0; i < script_functions.size(); i++) { + arr.push_back(script_functions[i].sig_id); + arr.push_back(script_functions[i].call_count); + arr.push_back(script_functions[i].self_time); + arr.push_back(script_functions[i].total_time); + } + return arr; +} + +bool ServersDebugger::ServersProfilerFrame::deserialize(const Array &p_arr) { + CHECK_SIZE(p_arr, 7, "ServersProfilerFrame"); + frame_number = p_arr[0]; + frame_time = p_arr[1]; + idle_time = p_arr[2]; + physics_time = p_arr[3]; + physics_frame_time = p_arr[4]; + script_time = p_arr[5]; + int servers_size = p_arr[6]; + int idx = 7; + while (servers_size) { + CHECK_SIZE(p_arr, idx + 2, "ServersProfilerFrame"); + servers_size--; + ServerInfo si; + si.name = p_arr[idx]; + int sub_data_size = p_arr[idx + 1]; + idx += 2; + CHECK_SIZE(p_arr, idx + sub_data_size, "ServersProfilerFrame"); + for (int j = 0; j < sub_data_size / 2; j++) { + ServerFunctionInfo sf; + sf.name = p_arr[idx]; + sf.time = p_arr[idx + 1]; + idx += 2; + si.functions.push_back(sf); + } + servers.push_back(si); + } + CHECK_SIZE(p_arr, idx + 1, "ServersProfilerFrame"); + int func_size = p_arr[idx]; + idx += 1; + CHECK_SIZE(p_arr, idx + func_size, "ServersProfilerFrame"); + for (int i = 0; i < func_size / 4; i++) { + ScriptFunctionInfo fi; + fi.sig_id = p_arr[idx]; + fi.call_count = p_arr[idx + 1]; + fi.self_time = p_arr[idx + 2]; + fi.total_time = p_arr[idx + 3]; + script_functions.push_back(fi); + idx += 4; + } + CHECK_END(p_arr, idx, "ServersProfilerFrame"); + return true; +} + +Array ServersDebugger::VisualProfilerFrame::serialize() { + Array arr; + arr.push_back(frame_number); + arr.push_back(areas.size() * 3); + for (int i = 0; i < areas.size(); i++) { + arr.push_back(areas[i].name); + arr.push_back(areas[i].cpu_msec); + arr.push_back(areas[i].gpu_msec); + } + return arr; +} + +bool ServersDebugger::VisualProfilerFrame::deserialize(const Array &p_arr) { + CHECK_SIZE(p_arr, 2, "VisualProfilerFrame"); + frame_number = p_arr[0]; + int size = p_arr[1]; + CHECK_SIZE(p_arr, size, "VisualProfilerFrame"); + int idx = 2; + areas.resize(size / 3); + RS::FrameProfileArea *w = areas.ptrw(); + for (int i = 0; i < size / 3; i++) { + w[i].name = p_arr[idx]; + w[i].cpu_msec = p_arr[idx + 1]; + w[i].gpu_msec = p_arr[idx + 2]; + idx += 3; + } + CHECK_END(p_arr, idx, "VisualProfilerFrame"); + return true; +} +class ServersDebugger::ScriptsProfiler : public EngineProfiler { + typedef ServersDebugger::ScriptFunctionSignature FunctionSignature; + typedef ServersDebugger::ScriptFunctionInfo FunctionInfo; + struct ProfileInfoSort { + bool operator()(ScriptLanguage::ProfilingInfo *A, ScriptLanguage::ProfilingInfo *B) const { + return A->total_time < B->total_time; + } + }; + Vector<ScriptLanguage::ProfilingInfo> info; + Vector<ScriptLanguage::ProfilingInfo *> ptrs; + Map<StringName, int> sig_map; + int max_frame_functions = 16; + +public: + void toggle(bool p_enable, const Array &p_opts) { + if (p_enable) { + sig_map.clear(); + for (int i = 0; i < ScriptServer::get_language_count(); i++) { + ScriptServer::get_language(i)->profiling_start(); + } + if (p_opts.size() == 1 && p_opts[0].get_type() == Variant::INT) { + max_frame_functions = MAX(0, int(p_opts[0])); + } + } else { + for (int i = 0; i < ScriptServer::get_language_count(); i++) { + ScriptServer::get_language(i)->profiling_stop(); + } + } + } + + void write_frame_data(Vector<FunctionInfo> &r_funcs, uint64_t &r_total, bool p_accumulated) { + int ofs = 0; + for (int i = 0; i < ScriptServer::get_language_count(); i++) { + if (p_accumulated) { + ofs += ScriptServer::get_language(i)->profiling_get_accumulated_data(&info.write[ofs], info.size() - ofs); + } else { + ofs += ScriptServer::get_language(i)->profiling_get_frame_data(&info.write[ofs], info.size() - ofs); + } + } + + for (int i = 0; i < ofs; i++) { + ptrs.write[i] = &info.write[i]; + } + + SortArray<ScriptLanguage::ProfilingInfo *, ProfileInfoSort> sa; + sa.sort(ptrs.ptrw(), ofs); + + int to_send = MIN(ofs, max_frame_functions); + + // Check signatures first, and compute total time. + r_total = 0; + for (int i = 0; i < to_send; i++) { + if (!sig_map.has(ptrs[i]->signature)) { + int idx = sig_map.size(); + FunctionSignature sig; + sig.name = ptrs[i]->signature; + sig.id = idx; + EngineDebugger::get_singleton()->send_message("servers:function_signature", sig.serialize()); + sig_map[ptrs[i]->signature] = idx; + } + r_total += ptrs[i]->self_time; + } + + // Send frame, script time, functions information then + r_funcs.resize(to_send); + + FunctionInfo *w = r_funcs.ptrw(); + for (int i = 0; i < to_send; i++) { + if (sig_map.has(ptrs[i]->signature)) { + w[i].sig_id = sig_map[ptrs[i]->signature]; + } + w[i].call_count = ptrs[i]->call_count; + w[i].total_time = ptrs[i]->total_time / 1000000.0; + w[i].self_time = ptrs[i]->self_time / 1000000.0; + } + } + + ScriptsProfiler() { + info.resize(GLOBAL_GET("debug/settings/profiler/max_functions")); + ptrs.resize(info.size()); + } +}; + +class ServersDebugger::ServersProfiler : public EngineProfiler { + bool skip_profile_frame = false; + typedef ServersDebugger::ServerInfo ServerInfo; + typedef ServersDebugger::ServerFunctionInfo ServerFunctionInfo; + + Map<StringName, ServerInfo> server_data; + ScriptsProfiler scripts_profiler; + + double frame_time = 0; + double idle_time = 0; + double physics_time = 0; + double physics_frame_time = 0; + + void _send_frame_data(bool p_final) { + ServersDebugger::ServersProfilerFrame frame; + frame.frame_number = Engine::get_singleton()->get_process_frames(); + frame.frame_time = frame_time; + frame.idle_time = idle_time; + frame.physics_time = physics_time; + frame.physics_frame_time = physics_frame_time; + Map<StringName, ServerInfo>::Element *E = server_data.front(); + while (E) { + if (!p_final) { + frame.servers.push_back(E->get()); + } + E->get().functions.clear(); + E = E->next(); + } + uint64_t time = 0; + scripts_profiler.write_frame_data(frame.script_functions, time, p_final); + frame.script_time = USEC_TO_SEC(time); + if (skip_profile_frame) { + skip_profile_frame = false; + return; + } + if (p_final) { + EngineDebugger::get_singleton()->send_message("servers:profile_total", frame.serialize()); + } else { + EngineDebugger::get_singleton()->send_message("servers:profile_frame", frame.serialize()); + } + } + +public: + void toggle(bool p_enable, const Array &p_opts) { + skip_profile_frame = false; + if (p_enable) { + server_data.clear(); // Clear old profiling data. + } else { + _send_frame_data(true); // Send final frame. + } + scripts_profiler.toggle(p_enable, p_opts); + } + + void add(const Array &p_data) { + String name = p_data[0]; + if (!server_data.has(name)) { + ServerInfo info; + info.name = name; + server_data[name] = info; + } + ServerInfo &srv = server_data[name]; + + ServerFunctionInfo fi; + fi.name = p_data[1]; + fi.time = p_data[2]; + srv.functions.push_back(fi); + } + + void tick(double p_frame_time, double p_idle_time, double p_physics_time, double p_physics_frame_time) { + frame_time = p_frame_time; + idle_time = p_idle_time; + physics_time = p_physics_time; + physics_frame_time = p_physics_frame_time; + _send_frame_data(false); + } + + void skip_frame() { + skip_profile_frame = true; + } +}; + +class ServersDebugger::VisualProfiler : public EngineProfiler { + typedef ServersDebugger::ServerInfo ServerInfo; + typedef ServersDebugger::ServerFunctionInfo ServerFunctionInfo; + + Map<StringName, ServerInfo> server_data; + +public: + void toggle(bool p_enable, const Array &p_opts) { + RS::get_singleton()->set_frame_profiling_enabled(p_enable); + } + + void add(const Array &p_data) {} + + void tick(double p_frame_time, double p_idle_time, double p_physics_time, double p_physics_frame_time) { + Vector<RS::FrameProfileArea> profile_areas = RS::get_singleton()->get_frame_profile(); + ServersDebugger::VisualProfilerFrame frame; + if (!profile_areas.size()) { + return; + } + + frame.frame_number = RS::get_singleton()->get_frame_profile_frame(); + frame.areas.append_array(profile_areas); + EngineDebugger::get_singleton()->send_message("visual:profile_frame", frame.serialize()); + } +}; + +ServersDebugger *ServersDebugger::singleton = nullptr; + +void ServersDebugger::initialize() { + if (EngineDebugger::is_active()) { + memnew(ServersDebugger); + } +} + +void ServersDebugger::deinitialize() { + if (singleton) { + memdelete(singleton); + } +} + +Error ServersDebugger::_capture(void *p_user, const String &p_cmd, const Array &p_data, bool &r_captured) { + ERR_FAIL_COND_V(!singleton, ERR_BUG); + r_captured = true; + if (p_cmd == "memory") { + singleton->_send_resource_usage(); + } else if (p_cmd == "draw") { // Forced redraw. + // For camera override to stay live when the game is paused from the editor. + double delta = 0.0; + if (singleton->last_draw_time) { + delta = (OS::get_singleton()->get_ticks_usec() - singleton->last_draw_time) / 1000000.0; + } + singleton->last_draw_time = OS::get_singleton()->get_ticks_usec(); + RenderingServer::get_singleton()->sync(); + if (RenderingServer::get_singleton()->has_changed()) { + RenderingServer::get_singleton()->draw(true, delta); + } + } else if (p_cmd == "foreground") { + singleton->last_draw_time = 0.0; + DisplayServer::get_singleton()->window_move_to_foreground(); + singleton->servers_profiler->skip_frame(); + } else { + r_captured = false; + } + return OK; +} + +void ServersDebugger::_send_resource_usage() { + ServersDebugger::ResourceUsage usage; + + List<RS::TextureInfo> tinfo; + RS::get_singleton()->texture_debug_usage(&tinfo); + + for (const RS::TextureInfo &E : tinfo) { + ServersDebugger::ResourceInfo info; + info.path = E.path; + info.vram = E.bytes; + info.id = E.texture; + info.type = "Texture"; + if (E.depth == 0) { + info.format = itos(E.width) + "x" + itos(E.height) + " " + Image::get_format_name(E.format); + } else { + info.format = itos(E.width) + "x" + itos(E.height) + "x" + itos(E.depth) + " " + Image::get_format_name(E.format); + } + usage.infos.push_back(info); + } + + EngineDebugger::get_singleton()->send_message("servers:memory_usage", usage.serialize()); +} + +ServersDebugger::ServersDebugger() { + singleton = this; + + // Generic servers profiler (audio/physics/...) + servers_profiler.instantiate(); + servers_profiler->bind("servers"); + + // Visual Profiler (cpu/gpu times) + visual_profiler.instantiate(); + visual_profiler->bind("visual"); + + EngineDebugger::Capture servers_cap(nullptr, &_capture); + EngineDebugger::register_message_capture("servers", servers_cap); +} + +ServersDebugger::~ServersDebugger() { + EngineDebugger::unregister_message_capture("servers"); + singleton = nullptr; +} diff --git a/servers/debugger/servers_debugger.h b/servers/debugger/servers_debugger.h new file mode 100644 index 0000000000..d1c55dc690 --- /dev/null +++ b/servers/debugger/servers_debugger.h @@ -0,0 +1,132 @@ +/*************************************************************************/ +/* servers_debugger.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef SERVER_DEBUGGER_H +#define SERVER_DEBUGGER_H + +#include "core/debugger/debugger_marshalls.h" + +#include "servers/rendering_server.h" + +class ServersDebugger { +public: + // Memory usage + struct ResourceInfo { + String path; + String format; + String type; + RID id; + int vram = 0; + bool operator<(const ResourceInfo &p_img) const { return vram == p_img.vram ? id < p_img.id : vram > p_img.vram; } + }; + + struct ResourceUsage { + List<ResourceInfo> infos; + + Array serialize(); + bool deserialize(const Array &p_arr); + }; + + // Script Profiler + struct ScriptFunctionSignature { + StringName name; + int id = -1; + + Array serialize(); + bool deserialize(const Array &p_arr); + }; + + struct ScriptFunctionInfo { + StringName name; + int sig_id = -1; + int call_count = 0; + double self_time = 0; + double total_time = 0; + }; + + // Servers profiler + struct ServerFunctionInfo { + StringName name; + double time = 0; + }; + + struct ServerInfo { + StringName name; + List<ServerFunctionInfo> functions; + }; + + struct ServersProfilerFrame { + int frame_number = 0; + double frame_time = 0; + double idle_time = 0; + double physics_time = 0; + double physics_frame_time = 0; + double script_time = 0; + List<ServerInfo> servers; + Vector<ScriptFunctionInfo> script_functions; + + Array serialize(); + bool deserialize(const Array &p_arr); + }; + + // Visual Profiler + struct VisualProfilerFrame { + uint64_t frame_number = 0; + Vector<RS::FrameProfileArea> areas; + + Array serialize(); + bool deserialize(const Array &p_arr); + }; + +private: + class ScriptsProfiler; + class ServersProfiler; + class VisualProfiler; + + double last_draw_time = 0.0; + Ref<ServersProfiler> servers_profiler; + Ref<VisualProfiler> visual_profiler; + + static ServersDebugger *singleton; + + static Error _capture(void *p_user, const String &p_cmd, const Array &p_data, bool &r_captured); + + void _send_resource_usage(); + + ServersDebugger(); + +public: + static void initialize(); + static void deinitialize(); + + ~ServersDebugger(); +}; + +#endif // SERVERS_DEBUGGER_H diff --git a/servers/display_server.cpp b/servers/display_server.cpp index d4ff42bc34..d880df2a9b 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -316,6 +316,11 @@ void DisplayServer::set_icon(const Ref<Image> &p_icon) { WARN_PRINT("Icon not supported by this display server."); } +int64_t DisplayServer::window_get_native_handle(HandleType p_handle_type, WindowID p_window) const { + WARN_PRINT("Native handle not supported by this display server."); + return 0; +} + void DisplayServer::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { WARN_PRINT("Changing the VSync mode is not supported by this display server."); } @@ -375,6 +380,7 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("screen_get_scale", "screen"), &DisplayServer::screen_get_scale, DEFVAL(SCREEN_OF_MAIN_WINDOW)); ClassDB::bind_method(D_METHOD("screen_is_touchscreen", "screen"), &DisplayServer::screen_is_touchscreen, DEFVAL(SCREEN_OF_MAIN_WINDOW)); ClassDB::bind_method(D_METHOD("screen_get_max_scale"), &DisplayServer::screen_get_max_scale); + ClassDB::bind_method(D_METHOD("screen_get_refresh_rate", "screen"), &DisplayServer::screen_get_refresh_rate, DEFVAL(SCREEN_OF_MAIN_WINDOW)); ClassDB::bind_method(D_METHOD("screen_set_orientation", "orientation", "screen"), &DisplayServer::screen_set_orientation, DEFVAL(SCREEN_OF_MAIN_WINDOW)); ClassDB::bind_method(D_METHOD("screen_get_orientation", "screen"), &DisplayServer::screen_get_orientation, DEFVAL(SCREEN_OF_MAIN_WINDOW)); @@ -388,6 +394,8 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("create_sub_window", "mode", "vsync_mode", "flags", "rect"), &DisplayServer::create_sub_window, DEFVAL(Rect2i())); ClassDB::bind_method(D_METHOD("delete_sub_window", "window_id"), &DisplayServer::delete_sub_window); + ClassDB::bind_method(D_METHOD("window_get_native_handle", "handle_type", "window_id"), &DisplayServer::window_get_native_handle, DEFVAL(MAIN_WINDOW_ID)); + ClassDB::bind_method(D_METHOD("window_set_title", "title", "window_id"), &DisplayServer::window_set_title, DEFVAL(MAIN_WINDOW_ID)); ClassDB::bind_method(D_METHOD("window_set_mouse_passthrough", "region", "window_id"), &DisplayServer::window_set_mouse_passthrough, DEFVAL(MAIN_WINDOW_ID)); @@ -532,6 +540,7 @@ void DisplayServer::_bind_methods() { BIND_ENUM_CONSTANT(WINDOW_MODE_MINIMIZED); BIND_ENUM_CONSTANT(WINDOW_MODE_MAXIMIZED); BIND_ENUM_CONSTANT(WINDOW_MODE_FULLSCREEN); + BIND_ENUM_CONSTANT(WINDOW_MODE_EXCLUSIVE_FULLSCREEN); BIND_ENUM_CONSTANT(WINDOW_FLAG_RESIZE_DISABLED); BIND_ENUM_CONSTANT(WINDOW_FLAG_BORDERLESS); @@ -552,6 +561,10 @@ void DisplayServer::_bind_methods() { BIND_ENUM_CONSTANT(VSYNC_ENABLED); BIND_ENUM_CONSTANT(VSYNC_ADAPTIVE); BIND_ENUM_CONSTANT(VSYNC_MAILBOX); + + BIND_ENUM_CONSTANT(DISPLAY_HANDLE); + BIND_ENUM_CONSTANT(WINDOW_HANDLE); + BIND_ENUM_CONSTANT(WINDOW_VIEW); } void DisplayServer::register_create_function(const char *p_name, CreateFunction p_function, GetRenderingDriversFunction p_get_drivers) { diff --git a/servers/display_server.h b/servers/display_server.h index 0c2bc5dd3a..bd38f28f17 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -53,7 +53,8 @@ public: WINDOW_MODE_WINDOWED, WINDOW_MODE_MINIMIZED, WINDOW_MODE_MAXIMIZED, - WINDOW_MODE_FULLSCREEN + WINDOW_MODE_FULLSCREEN, + WINDOW_MODE_EXCLUSIVE_FULLSCREEN, }; // Keep the VSyncMode enum values in sync with the `display/window/vsync/vsync_mode` @@ -65,6 +66,12 @@ public: VSYNC_MAILBOX }; + enum HandleType { + DISPLAY_HANDLE, + WINDOW_HANDLE, + WINDOW_VIEW, + }; + typedef DisplayServer *(*CreateFunction)(const String &, WindowMode, VSyncMode, uint32_t, const Size2i &, Error &r_error); typedef Vector<String> (*GetRenderingDriversFunction)(); @@ -168,6 +175,8 @@ public: SCREEN_OF_MAIN_WINDOW = -1 }; + const float SCREEN_REFRESH_RATE_FALLBACK = -1.0; // Returned by screen_get_refresh_rate if the method fails. + virtual int get_screen_count() const = 0; virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0; virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0; @@ -182,6 +191,7 @@ public: } return scale; } + virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0; virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const; // Keep the ScreenOrientation enum values in sync with the `display/window/handheld/orientation` @@ -232,6 +242,8 @@ public: virtual void show_window(WindowID p_id); virtual void delete_sub_window(WindowID p_id); + virtual int64_t window_get_native_handle(HandleType p_handle_type, WindowID p_window = MAIN_WINDOW_ID) const; + virtual WindowID get_window_at_screen_position(const Point2i &p_position) const = 0; virtual void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID) = 0; @@ -387,6 +399,7 @@ VARIANT_ENUM_CAST(DisplayServer::MouseMode) VARIANT_ENUM_CAST(DisplayServer::ScreenOrientation) VARIANT_ENUM_CAST(DisplayServer::WindowMode) VARIANT_ENUM_CAST(DisplayServer::WindowFlags) +VARIANT_ENUM_CAST(DisplayServer::HandleType) VARIANT_ENUM_CAST(DisplayServer::CursorShape) VARIANT_ENUM_CAST(DisplayServer::VSyncMode) diff --git a/servers/display_server_headless.h b/servers/display_server_headless.h index 4ef9dc622f..f74a8fad23 100644 --- a/servers/display_server_headless.h +++ b/servers/display_server_headless.h @@ -62,6 +62,7 @@ public: int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return 96; /* 0 might cause issues */ } float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return 1; } float screen_get_max_scale() const override { return 1; } + float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return SCREEN_REFRESH_RATE_FALLBACK; } Vector<DisplayServer::WindowID> get_window_list() const override { return Vector<DisplayServer::WindowID>(); } diff --git a/servers/physics_3d/godot_shape_3d.cpp b/servers/physics_3d/godot_shape_3d.cpp index 26fa470233..666e773c1c 100644 --- a/servers/physics_3d/godot_shape_3d.cpp +++ b/servers/physics_3d/godot_shape_3d.cpp @@ -52,11 +52,11 @@ subject to the following restrictions: 3. This notice may not be removed or altered from any source distribution. */ -#define _EDGE_IS_VALID_SUPPORT_THRESHOLD 0.0002 -#define _FACE_IS_VALID_SUPPORT_THRESHOLD 0.9998 +constexpr double edge_support_threshold = 0.0002; +constexpr double face_support_threshold = 0.9998; -#define _CYLINDER_EDGE_IS_VALID_SUPPORT_THRESHOLD 0.002 -#define _CYLINDER_FACE_IS_VALID_SUPPORT_THRESHOLD 0.999 +constexpr double cylinder_edge_support_threshold = 0.002; +constexpr double cylinder_face_support_threshold = 0.999; void GodotShape3D::configure(const AABB &p_aabb) { aabb = p_aabb; @@ -184,7 +184,7 @@ Vector3 GodotSeparationRayShape3D::get_support(const Vector3 &p_normal) const { } void GodotSeparationRayShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { - if (Math::abs(p_normal.z) < _EDGE_IS_VALID_SUPPORT_THRESHOLD) { + if (Math::abs(p_normal.z) < edge_support_threshold) { r_amount = 2; r_type = FEATURE_EDGE; r_supports[0] = Vector3(0, 0, 0); @@ -335,7 +335,7 @@ void GodotBoxShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 * Vector3 axis; axis[i] = 1.0; real_t dot = p_normal.dot(axis); - if (Math::abs(dot) > _FACE_IS_VALID_SUPPORT_THRESHOLD) { + if (Math::abs(dot) > face_support_threshold) { //Vector3 axis_b; bool neg = dot < 0; @@ -376,7 +376,7 @@ void GodotBoxShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 * Vector3 axis; axis[i] = 1.0; - if (Math::abs(p_normal.dot(axis)) < _EDGE_IS_VALID_SUPPORT_THRESHOLD) { + if (Math::abs(p_normal.dot(axis)) < edge_support_threshold) { r_amount = 2; r_type = FEATURE_EDGE; @@ -522,7 +522,7 @@ void GodotCapsuleShape3D::get_supports(const Vector3 &p_normal, int p_max, Vecto real_t d = n.y; - if (Math::abs(d) < _EDGE_IS_VALID_SUPPORT_THRESHOLD) { + if (Math::abs(d) < edge_support_threshold) { // make it flat n.y = 0.0; n.normalize(); @@ -703,7 +703,7 @@ Vector3 GodotCylinderShape3D::get_support(const Vector3 &p_normal) const { void GodotCylinderShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { real_t d = p_normal.y; - if (Math::abs(d) > _CYLINDER_FACE_IS_VALID_SUPPORT_THRESHOLD) { + if (Math::abs(d) > cylinder_face_support_threshold) { real_t h = (d > 0) ? height : -height; Vector3 n = p_normal; @@ -718,7 +718,7 @@ void GodotCylinderShape3D::get_supports(const Vector3 &p_normal, int p_max, Vect r_supports[1].x += radius; r_supports[2] = n; r_supports[2].z += radius; - } else if (Math::abs(d) < _CYLINDER_EDGE_IS_VALID_SUPPORT_THRESHOLD) { + } else if (Math::abs(d) < cylinder_edge_support_threshold) { // make it flat Vector3 n = p_normal; n.y = 0.0; @@ -911,7 +911,7 @@ void GodotConvexPolygonShape3D::get_supports(const Vector3 &p_normal, int p_max, } for (int i = 0; i < fc; i++) { - if (faces[i].plane.normal.dot(p_normal) > _FACE_IS_VALID_SUPPORT_THRESHOLD) { + if (faces[i].plane.normal.dot(p_normal) > face_support_threshold) { int ic = faces[i].indices.size(); const int *ind = faces[i].indices.ptr(); @@ -940,7 +940,7 @@ void GodotConvexPolygonShape3D::get_supports(const Vector3 &p_normal, int p_max, for (int i = 0; i < ec; i++) { real_t dot = (vertices[edges[i].a] - vertices[edges[i].b]).normalized().dot(p_normal); dot = ABS(dot); - if (dot < _EDGE_IS_VALID_SUPPORT_THRESHOLD && (edges[i].a == vtx || edges[i].b == vtx)) { + if (dot < edge_support_threshold && (edges[i].a == vtx || edges[i].b == vtx)) { r_amount = 2; r_type = FEATURE_EDGE; r_supports[0] = vertices[edges[i].a]; @@ -1140,7 +1140,7 @@ void GodotFaceShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 Vector3 n = p_normal; /** TEST FACE AS SUPPORT **/ - if (Math::abs(normal.dot(n)) > _FACE_IS_VALID_SUPPORT_THRESHOLD) { + if (Math::abs(normal.dot(n)) > face_support_threshold) { r_amount = 3; r_type = FEATURE_FACE; for (int i = 0; i < 3; i++) { @@ -1174,7 +1174,7 @@ void GodotFaceShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 // check if edge is valid as a support real_t dot = (vertex[i] - vertex[nx]).normalized().dot(n); dot = ABS(dot); - if (dot < _EDGE_IS_VALID_SUPPORT_THRESHOLD) { + if (dot < edge_support_threshold) { r_amount = 2; r_type = FEATURE_EDGE; r_supports[0] = vertex[i]; diff --git a/servers/physics_3d/godot_soft_body_3d.cpp b/servers/physics_3d/godot_soft_body_3d.cpp index 1de27760d5..095050b7f3 100644 --- a/servers/physics_3d/godot_soft_body_3d.cpp +++ b/servers/physics_3d/godot_soft_body_3d.cpp @@ -245,7 +245,7 @@ void GodotSoftBody3D::update_area() { const Vector3 a = x1 - x0; const Vector3 b = x2 - x0; const Vector3 cr = vec3_cross(a, b); - face.ra = cr.length(); + face.ra = cr.length() * 0.5; } // Node area. diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index 3fbf4fe436..f405dea770 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -56,6 +56,7 @@ #include "camera/camera_feed.h" #include "camera_server.h" #include "core/extension/native_extension_manager.h" +#include "debugger/servers_debugger.h" #include "display_server.h" #include "navigation_server_2d.h" #include "navigation_server_3d.h" @@ -80,7 +81,7 @@ ShaderTypes *shader_types = nullptr; PhysicsServer3D *_createGodotPhysics3DCallback() { - bool using_threads = GLOBAL_GET("physics/3d/run_on_thread"); + bool using_threads = GLOBAL_GET("physics/3d/run_on_separate_thread"); PhysicsServer3D *physics_server = memnew(GodotPhysicsServer3D(using_threads)); @@ -88,7 +89,7 @@ PhysicsServer3D *_createGodotPhysics3DCallback() { } PhysicsServer2D *_createGodotPhysics2DCallback() { - bool using_threads = GLOBAL_GET("physics/2d/run_on_thread"); + bool using_threads = GLOBAL_GET("physics/2d/run_on_separate_thread"); PhysicsServer2D *physics_server = memnew(GodotPhysicsServer2D(using_threads)); @@ -140,7 +141,7 @@ void register_server_types() { GDREGISTER_CLASS(AudioStreamPlayback); GDREGISTER_VIRTUAL_CLASS(AudioStreamPlaybackResampled); GDREGISTER_CLASS(AudioStreamMicrophone); - GDREGISTER_CLASS(AudioStreamRandomPitch); + GDREGISTER_CLASS(AudioStreamRandomizer); GDREGISTER_VIRTUAL_CLASS(AudioEffect); GDREGISTER_VIRTUAL_CLASS(AudioEffectInstance); GDREGISTER_CLASS(AudioEffectEQ); @@ -223,6 +224,8 @@ void register_server_types() { GDREGISTER_CLASS(PhysicsTestMotionParameters3D); GDREGISTER_CLASS(PhysicsTestMotionResult3D); + ServersDebugger::initialize(); + // Physics 2D GLOBAL_DEF(PhysicsServer2DManager::setting_property_name, "DEFAULT"); ProjectSettings::get_singleton()->set_custom_property_info(PhysicsServer2DManager::setting_property_name, PropertyInfo(Variant::STRING, PhysicsServer2DManager::setting_property_name, PROPERTY_HINT_ENUM, "DEFAULT")); @@ -241,6 +244,8 @@ void register_server_types() { } void unregister_server_types() { + ServersDebugger::deinitialize(); + NativeExtensionManager::get_singleton()->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SERVERS); memdelete(shader_types); diff --git a/servers/rendering/rasterizer_dummy.h b/servers/rendering/rasterizer_dummy.h index 83da8388e4..7d5a596c50 100644 --- a/servers/rendering/rasterizer_dummy.h +++ b/servers/rendering/rasterizer_dummy.h @@ -72,11 +72,11 @@ public: /* SHADOW ATLAS API */ RID shadow_atlas_create() override { return RID(); } - void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = false) override {} + void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) override {} void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override {} bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) override { return false; } - void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = false) override {} + void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override {} int get_directional_light_shadow_size(RID p_light_intance) override { return 0; } void set_directional_shadow_count(int p_count) override {} @@ -109,7 +109,7 @@ public: void environment_set_canvas_max_layer(RID p_env, int p_max_layer) override {} void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG) override {} - void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) override {} + void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, float p_glow_map_strength, RID p_glow_map) override {} void environment_glow_set_use_bicubic_upscale(bool p_enable) override {} void environment_glow_set_use_high_quality(bool p_enable) override {} diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp index 4ab50782df..02a0b6f184 100644 --- a/servers/rendering/renderer_rd/effects_rd.cpp +++ b/servers/rendering/renderer_rd/effects_rd.cpp @@ -115,6 +115,43 @@ RID EffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) return uniform_set; } +RID EffectsRD::_get_uniform_set_from_texture_pair(RID p_texture1, RID p_texture2, bool p_use_mipmaps) { + TexturePair tp; + tp.texture1 = p_texture1; + tp.texture2 = p_texture2; + + if (texture_pair_to_uniform_set_cache.has(tp)) { + RID uniform_set = texture_pair_to_uniform_set_cache[tp]; + if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) { + return uniform_set; + } + } + + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.binding = 0; + u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler); + u.ids.push_back(p_texture1); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.binding = 1; + u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler); + u.ids.push_back(p_texture2); + uniforms.push_back(u); + } + // anything with the same configuration (one texture in binding 0 for set 0), is good + RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, tonemap.shader.version_get_shader(tonemap.shader_version, 0), 2); + + texture_pair_to_uniform_set_cache[tp] = uniform_set; + + return uniform_set; +} + RID EffectsRD::_get_compute_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) { if (texture_to_compute_uniform_set_cache.has(p_texture)) { RID uniform_set = texture_to_compute_uniform_set_cache[p_texture]; @@ -445,12 +482,11 @@ void EffectsRD::set_color(RID p_dest_texture, const Color &p_color, const Rect2i RD::get_singleton()->compute_list_end(); } -void EffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst) { +void EffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, const Rect2i &p_region, bool p_8bit_dst) { ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use the compute version of the gaussian blur with the mobile renderer."); memset(©.push_constant, 0, sizeof(CopyPushConstant)); - uint32_t base_flags = 0; copy.push_constant.section[0] = p_region.position.x; copy.push_constant.section[1] = p_region.position.y; copy.push_constant.section[2] = p_region.size.width; @@ -460,23 +496,12 @@ void EffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back RD::DrawListID compute_list = RD::get_singleton()->compute_list_begin(); RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[p_8bit_dst ? COPY_MODE_GAUSSIAN_COPY_8BIT : COPY_MODE_GAUSSIAN_COPY]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_back_texture), 3); - - copy.push_constant.flags = base_flags | COPY_FLAG_HORIZONTAL; - RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); - - RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_region.size.width, p_region.size.height, 1); - - RD::get_singleton()->compute_list_add_barrier(compute_list); - - //VERTICAL - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_back_texture), 0); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_texture), 3); - copy.push_constant.flags = base_flags; RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_region.size.width, p_region.size.height, 1); + RD::get_singleton()->compute_list_end(); } @@ -828,6 +853,7 @@ void EffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Tone tonemap.push_constant.use_glow = p_settings.use_glow; tonemap.push_constant.glow_intensity = p_settings.glow_intensity; + tonemap.push_constant.glow_map_strength = p_settings.glow_map_strength; tonemap.push_constant.glow_levels[0] = p_settings.glow_levels[0]; // clean this up to just pass by pointer or something tonemap.push_constant.glow_levels[1] = p_settings.glow_levels[1]; tonemap.push_constant.glow_levels[2] = p_settings.glow_levels[2]; @@ -867,7 +893,7 @@ void EffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Tone RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer), false, RD::get_singleton()->draw_list_get_current_pass())); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_color), 0); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_settings.exposure_texture), 1); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_settings.glow_texture, true), 2); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture_pair(p_settings.glow_texture, p_settings.glow_map, true), 2); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_settings.color_correction_texture), 3); RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); @@ -907,7 +933,7 @@ void EffectsRD::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_colo RD::get_singleton()->draw_list_bind_render_pipeline(p_subpass_draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, p_dst_format_id, false, RD::get_singleton()->draw_list_get_current_pass())); RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_for_input(p_source_color), 0); RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_from_texture(p_settings.exposure_texture), 1); // should be set to a default texture, it's ignored - RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_from_texture(p_settings.glow_texture, true), 2); // should be set to a default texture, it's ignored + RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_from_texture_pair(p_settings.glow_texture, p_settings.glow_map, true), 2); // should be set to a default texture, it's ignored RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_from_texture(p_settings.color_correction_texture), 3); RD::get_singleton()->draw_list_bind_index_array(p_subpass_draw_list, index_array); @@ -1415,7 +1441,6 @@ void EffectsRD::downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_ RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_COMPUTE); - ss_effects.used_full_mips_last_frame = use_mips; ss_effects.used_full_mips_last_frame = use_full_mips; ss_effects.used_half_size_last_frame = use_half_size; } @@ -2306,8 +2331,8 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) { Vector<String> copy_modes; copy_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n"); copy_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n#define DST_IMAGE_8BIT\n"); - copy_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n"); - copy_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n#define GLOW_USE_AUTO_EXPOSURE\n"); + copy_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n#define MODE_GLOW\n"); + copy_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n#define MODE_GLOW\n#define GLOW_USE_AUTO_EXPOSURE\n"); copy_modes.push_back("\n#define MODE_SIMPLE_COPY\n"); copy_modes.push_back("\n#define MODE_SIMPLE_COPY\n#define DST_IMAGE_8BIT\n"); copy_modes.push_back("\n#define MODE_SIMPLE_COPY_DEPTH\n"); diff --git a/servers/rendering/renderer_rd/effects_rd.h b/servers/rendering/renderer_rd/effects_rd.h index a3fb4db3df..f5e5b1ace7 100644 --- a/servers/rendering/renderer_rd/effects_rd.h +++ b/servers/rendering/renderer_rd/effects_rd.h @@ -274,7 +274,7 @@ private: uint32_t glow_texture_size[2]; // 8 - 40 float glow_intensity; // 4 - 44 - uint32_t pad3; // 4 - 48 + float glow_map_strength; // 4 - 48 uint32_t glow_mode; // 4 - 52 float glow_levels[7]; // 28 - 80 @@ -874,6 +874,7 @@ private: } }; + Map<TexturePair, RID> texture_pair_to_uniform_set_cache; Map<RID, RID> texture_to_compute_uniform_set_cache; Map<TexturePair, RID> texture_pair_to_compute_uniform_set_cache; Map<TexturePair, RID> image_pair_to_compute_uniform_set_cache; @@ -882,6 +883,7 @@ private: RID _get_uniform_set_from_image(RID p_texture); RID _get_uniform_set_for_input(RID p_texture); RID _get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false); + RID _get_uniform_set_from_texture_pair(RID p_texture1, RID p_texture2, bool p_use_mipmaps = false); RID _get_compute_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false); RID _get_compute_uniform_set_from_texture_and_sampler(RID p_texture, RID p_sampler); RID _get_compute_uniform_set_from_texture_pair(RID p_texture, RID p_texture2, bool p_use_mipmaps = false); @@ -897,7 +899,7 @@ public: void copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false); void copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, float p_z_near, float p_z_far); void copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y = false, bool p_panorama = false); - void gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst = false); + void gaussian_blur(RID p_source_rd_texture, RID p_texture, const Rect2i &p_region, bool p_8bit_dst = false); void set_color(RID p_dest_texture, const Color &p_color, const Rect2i &p_region, bool p_8bit_dst = false); void gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength = 1.0, bool p_high_quality = false, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_threshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0); void gaussian_glow_raster(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, float p_strength = 1.0, bool p_high_quality = false, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_threshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0); @@ -943,10 +945,12 @@ public: GlowMode glow_mode = GLOW_MODE_ADD; float glow_intensity = 1.0; + float glow_map_strength = 0.0f; float glow_levels[7] = { 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0 }; Vector2i glow_texture_size; bool glow_use_bicubic_upscale = false; RID glow_texture; + RID glow_map; RS::EnvironmentToneMapper tonemap_mode = RS::ENV_TONE_MAPPER_LINEAR; float exposure = 1.0; diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index 36604073cc..d113fcd4f0 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -969,10 +969,11 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con if (inst->fade_near || inst->fade_far) { float fade_dist = inst->transform.origin.distance_to(p_render_data->cam_transform.origin); + // Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player. if (inst->fade_far && fade_dist > inst->fade_far_begin) { - fade_alpha = MAX(0.0, 1.0 - (fade_dist - inst->fade_far_begin) / (inst->fade_far_end - inst->fade_far_begin)); + fade_alpha = Math::smoothstep(0.0f, 1.0f, 1.0f - (fade_dist - inst->fade_far_begin) / (inst->fade_far_end - inst->fade_far_begin)); } else if (inst->fade_near && fade_dist < inst->fade_near_end) { - fade_alpha = MAX(0.0, (fade_dist - inst->fade_near_begin) / (inst->fade_near_end - inst->fade_near_begin)); + fade_alpha = Math::smoothstep(0.0f, 1.0f, (fade_dist - inst->fade_near_begin) / (inst->fade_near_end - inst->fade_near_begin)); } } @@ -1081,6 +1082,10 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con distance = -distance_max; } + if (p_render_data->cam_ortogonal) { + distance = 1.0; + } + uint32_t indices; surf->sort.lod_index = storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, &indices); if (p_render_data->render_info) { @@ -1386,7 +1391,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co projection = correction * p_render_data->cam_projection; } - sky.setup(env, p_render_data->render_buffers, projection, p_render_data->cam_transform, screen_size, this); + sky.setup(env, p_render_data->render_buffers, *p_render_data->lights, projection, p_render_data->cam_transform, screen_size, this); RID sky_rid = env->sky; if (sky_rid.is_valid()) { 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 b9c51f5461..a623af7533 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -633,7 +633,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color projection = correction * p_render_data->cam_projection; } - sky.setup(env, p_render_data->render_buffers, projection, p_render_data->cam_transform, screen_size, this); + sky.setup(env, p_render_data->render_buffers, *p_render_data->lights, projection, p_render_data->cam_transform, screen_size, this); RID sky_rid = env->sky; if (sky_rid.is_valid()) { @@ -1042,7 +1042,7 @@ void RenderForwardMobile::_render_uv2(const PagedArray<GeometryInstance *> &p_in RENDER_TIMESTAMP("Render Material"); { - RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, rp_uniform_set, true, 0); + RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, rp_uniform_set, true, false); //regular forward for now Vector<Color> clear = { Color(0, 0, 0, 0), @@ -1429,6 +1429,10 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const distance = -distance_max; } + if (p_render_data->cam_ortogonal) { + distance = 1.0; + } + uint32_t indices; surf->lod_index = storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, &indices); if (p_render_data->render_info) { diff --git a/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp index 0d0d7513d0..0d9477d850 100644 --- a/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp @@ -54,7 +54,7 @@ void RendererSceneEnvironmentRD::set_tonemap(RS::EnvironmentToneMapper p_tone_ma auto_exp_scale = p_auto_exp_scale; } -void RendererSceneEnvironmentRD::set_glow(bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) { +void RendererSceneEnvironmentRD::set_glow(bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, float p_glow_map_strength, RID p_glow_map) { ERR_FAIL_COND_MSG(p_levels.size() != 7, "Size of array of glow levels must be 7"); glow_enabled = p_enable; glow_levels = p_levels; @@ -66,6 +66,8 @@ void RendererSceneEnvironmentRD::set_glow(bool p_enable, Vector<float> p_levels, glow_hdr_bleed_threshold = p_hdr_bleed_threshold; glow_hdr_bleed_scale = p_hdr_bleed_scale; glow_hdr_luminance_cap = p_hdr_luminance_cap; + glow_map_strength = p_glow_map_strength; + glow_map = p_glow_map; } void RendererSceneEnvironmentRD::set_sdfgi(bool p_enable, int p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) { diff --git a/servers/rendering/renderer_rd/renderer_scene_environment_rd.h b/servers/rendering/renderer_rd/renderer_scene_environment_rd.h index 629d224b49..4e170b8cfb 100644 --- a/servers/rendering/renderer_rd/renderer_scene_environment_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_environment_rd.h @@ -102,6 +102,8 @@ public: float glow_hdr_bleed_threshold = 1.0; float glow_hdr_luminance_cap = 12.0; float glow_hdr_bleed_scale = 2.0; + float glow_map_strength = 0.0f; + RID glow_map = RID(); /// SSAO @@ -133,15 +135,15 @@ public: /// SDFGI bool sdfgi_enabled = false; - int sdfgi_cascades = 6; + int sdfgi_cascades = 4; float sdfgi_min_cell_size = 0.2; bool sdfgi_use_occlusion = false; - float sdfgi_bounce_feedback = 0.0; - bool sdfgi_read_sky_light = false; + float sdfgi_bounce_feedback = 0.5; + bool sdfgi_read_sky_light = true; float sdfgi_energy = 1.0; float sdfgi_normal_bias = 1.1; float sdfgi_probe_bias = 1.1; - RS::EnvironmentSDFGIYScale sdfgi_y_scale = RS::ENV_SDFGI_Y_SCALE_DISABLED; + RS::EnvironmentSDFGIYScale sdfgi_y_scale = RS::ENV_SDFGI_Y_SCALE_75_PERCENT; /// Adjustments @@ -154,7 +156,7 @@ public: void set_ambient_light(const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source); void set_tonemap(RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale); - void set_glow(bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap); + void set_glow(bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, float p_glow_map_strength, RID p_glow_map); void set_sdfgi(bool p_enable, int p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias); void set_fog(bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_fog_aerial_perspective); void set_volumetric_fog(bool p_enable, float p_density, const Color &p_scatterin, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject); diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp index 3069b1c379..cb07c75db4 100644 --- a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp @@ -46,7 +46,7 @@ void RendererSceneGIRD::SDFGI::create(RendererSceneEnvironmentRD *p_env, const V min_cell_size = p_env->sdfgi_min_cell_size; uses_occlusion = p_env->sdfgi_use_occlusion; y_scale_mode = p_env->sdfgi_y_scale; - static const float y_scale[3] = { 1.0, 1.5, 2.0 }; + static const float y_scale[3] = { 2.0, 1.5, 1.0 }; y_mult = y_scale[y_scale_mode]; cascades.resize(num_cascades); probe_axis_count = SDFGI::PROBE_DIVISOR + 1; diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.h b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h index 5e55262798..25f0dca3b7 100644 --- a/servers/rendering/renderer_rd/renderer_scene_gi_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h @@ -392,7 +392,7 @@ public: return voxel_gi->texture; }; - RS::VoxelGIQuality voxel_gi_quality = RS::VOXEL_GI_QUALITY_HIGH; + RS::VoxelGIQuality voxel_gi_quality = RS::VOXEL_GI_QUALITY_LOW; /* SDFGI */ @@ -504,12 +504,12 @@ public: RID cascades_ubo; bool uses_occlusion = false; - float bounce_feedback = 0.0; - bool reads_sky = false; + float bounce_feedback = 0.5; + bool reads_sky = true; float energy = 1.0; float normal_bias = 1.1; float probe_bias = 1.1; - RS::EnvironmentSDFGIYScale y_scale_mode = RS::ENV_SDFGI_Y_SCALE_DISABLED; + RS::EnvironmentSDFGIYScale y_scale_mode = RS::ENV_SDFGI_Y_SCALE_75_PERCENT; float y_mult = 1.0; @@ -536,7 +536,7 @@ public: }; RS::EnvironmentSDFGIRayCount sdfgi_ray_count = RS::ENV_SDFGI_RAY_COUNT_16; - RS::EnvironmentSDFGIFramesToConverge sdfgi_frames_to_converge = RS::ENV_SDFGI_CONVERGE_IN_10_FRAMES; + RS::EnvironmentSDFGIFramesToConverge sdfgi_frames_to_converge = RS::ENV_SDFGI_CONVERGE_IN_30_FRAMES; RS::EnvironmentSDFGIFramesToUpdateLight sdfgi_frames_to_update_light = RS::ENV_SDFGI_UPDATE_LIGHT_IN_4_FRAMES; float sdfgi_solid_cell_ratio = 0.25; diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 126f40584a..2d34d2a2a0 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -289,10 +289,10 @@ void RendererSceneRenderRD::environment_set_tonemap(RID p_env, RS::EnvironmentTo env->set_tonemap(p_tone_mapper, p_exposure, p_white, p_auto_exposure, p_min_luminance, p_max_luminance, p_auto_exp_speed, p_auto_exp_scale); } -void RendererSceneRenderRD::environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) { +void RendererSceneRenderRD::environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, float p_glow_map_strength, RID p_glow_map) { RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND(!env); - env->set_glow(p_enable, p_levels, p_intensity, p_strength, p_mix, p_bloom_threshold, p_blend_mode, p_hdr_bleed_threshold, p_hdr_bleed_scale, p_hdr_luminance_cap); + env->set_glow(p_enable, p_levels, p_intensity, p_strength, p_mix, p_bloom_threshold, p_blend_mode, p_hdr_bleed_threshold, p_hdr_bleed_scale, p_hdr_luminance_cap, p_glow_map_strength, p_glow_map); } void RendererSceneRenderRD::environment_glow_set_use_bicubic_upscale(bool p_enable) { @@ -925,7 +925,7 @@ void RendererSceneRenderRD::shadow_atlas_set_size(RID p_atlas, int p_size, bool } for (int i = 0; i < 4; i++) { //clear subdivisions - shadow_atlas->quadrants[i].shadows.resize(0); + shadow_atlas->quadrants[i].shadows.clear(); shadow_atlas->quadrants[i].shadows.resize(1 << shadow_atlas->quadrants[i].subdivision); } @@ -972,7 +972,7 @@ void RendererSceneRenderRD::shadow_atlas_set_quadrant_subdivision(RID p_atlas, i } } - shadow_atlas->quadrants[p_quadrant].shadows.resize(0); + shadow_atlas->quadrants[p_quadrant].shadows.clear(); shadow_atlas->quadrants[p_quadrant].shadows.resize(subdiv * subdiv); shadow_atlas->quadrants[p_quadrant].subdivision = subdiv; @@ -1132,11 +1132,11 @@ bool RendererSceneRenderRD::_shadow_atlas_find_omni_shadows(ShadowAtlas *shadow_ return false; } -bool RendererSceneRenderRD::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) { +bool RendererSceneRenderRD::shadow_atlas_update_light(RID p_atlas, RID p_light_instance, float p_coverage, uint64_t p_light_version) { ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas); ERR_FAIL_COND_V(!shadow_atlas, false); - LightInstance *li = light_instance_owner.get_or_null(p_light_intance); + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); ERR_FAIL_COND_V(!li, false); if (shadow_atlas->size == 0 || shadow_atlas->smallest_subdiv == 0) { @@ -1185,8 +1185,8 @@ bool RendererSceneRenderRD::shadow_atlas_update_light(RID p_atlas, RID p_light_i bool should_realloc = false; bool should_redraw = false; - if (shadow_atlas->shadow_owners.has(p_light_intance)) { - old_key = shadow_atlas->shadow_owners[p_light_intance]; + if (shadow_atlas->shadow_owners.has(p_light_instance)) { + old_key = shadow_atlas->shadow_owners[p_light_instance]; old_quadrant = (old_key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; old_shadow = old_key & ShadowAtlas::SHADOW_INDEX_MASK; @@ -1230,7 +1230,7 @@ bool RendererSceneRenderRD::shadow_atlas_update_light(RID p_atlas, RID p_light_i ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow]; _shadow_atlas_invalidate_shadow(sh, p_atlas, shadow_atlas, new_quadrant, new_shadow); - sh->owner = p_light_intance; + sh->owner = p_light_instance; sh->alloc_tick = tick; sh->version = p_light_version; @@ -1241,7 +1241,7 @@ bool RendererSceneRenderRD::shadow_atlas_update_light(RID p_atlas, RID p_light_i ShadowAtlas::Quadrant::Shadow *extra_sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_omni_shadow]; _shadow_atlas_invalidate_shadow(extra_sh, p_atlas, shadow_atlas, new_quadrant, new_omni_shadow); - extra_sh->owner = p_light_intance; + extra_sh->owner = p_light_instance; extra_sh->alloc_tick = tick; extra_sh->version = p_light_version; } @@ -1249,7 +1249,7 @@ bool RendererSceneRenderRD::shadow_atlas_update_light(RID p_atlas, RID p_light_i li->shadow_atlases.insert(p_atlas); //update it in map - shadow_atlas->shadow_owners[p_light_intance] = new_key; + shadow_atlas->shadow_owners[p_light_instance] = new_key; //make it dirty, as it should redraw anyway return true; } @@ -1270,10 +1270,10 @@ void RendererSceneRenderRD::_shadow_atlas_invalidate_shadow(RendererSceneRenderR omni_shadow->owner = RID(); } + p_shadow_atlas->shadow_owners.erase(p_shadow->owner); p_shadow->version = 0; p_shadow->owner = RID(); sli->shadow_atlases.erase(p_atlas); - p_shadow_atlas->shadow_owners.erase(p_shadow->owner); } } @@ -1920,6 +1920,11 @@ void RendererSceneRenderRD::_free_render_buffer_data(RenderBuffers *rb) { rb->ambient_buffer = RID(); rb->reflection_buffer = RID(); } + + if (rb->gi.voxel_gi_buffer.is_valid()) { + RD::get_singleton()->free(rb->gi.voxel_gi_buffer); + rb->gi.voxel_gi_buffer = RID(); + } } void RendererSceneRenderRD::_process_sss(RID p_render_buffers, const CameraMatrix &p_camera) { @@ -2496,8 +2501,17 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende tonemap.glow_texture_size.y = rb->blur[1].mipmaps[0].height; tonemap.glow_use_bicubic_upscale = glow_bicubic_upscale; tonemap.glow_texture = rb->blur[1].texture; + if (env->glow_map.is_valid()) { + tonemap.glow_map_strength = env->glow_map_strength; + tonemap.glow_map = storage->texture_get_rd_texture(env->glow_map); + } else { + tonemap.glow_map_strength = 0.0f; + tonemap.glow_map = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); + } + } else { tonemap.glow_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); + tonemap.glow_map = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); } if (rb->screen_space_aa == RS::VIEWPORT_SCREEN_SPACE_AA_FXAA) { @@ -2590,6 +2604,7 @@ void RendererSceneRenderRD::_post_process_subpass(RID p_source_texture, RID p_fr tonemap.use_glow = false; tonemap.glow_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); + tonemap.glow_map = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); tonemap.use_auto_exposure = false; tonemap.exposure_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); @@ -2636,8 +2651,12 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS) { if (p_shadow_atlas.is_valid()) { RID shadow_atlas_texture = shadow_atlas_get_texture(p_shadow_atlas); - Size2 rtsize = storage->render_target_get_size(rb->render_target); + if (shadow_atlas_texture.is_null()) { + shadow_atlas_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); + } + + Size2 rtsize = storage->render_target_get_size(rb->render_target); effects->copy_to_fb_rect(shadow_atlas_texture, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2i(Vector2(), rtsize / 2), false, true); } } @@ -3244,7 +3263,6 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const r_directional_light_count = 0; r_positional_light_count = 0; - sky.sky_scene_state.ubo.directional_light_count = 0; Plane camera_plane(-p_camera_transform.basis.get_axis(Vector3::AXIS_Z).normalized(), p_camera_transform.origin); @@ -3265,43 +3283,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const RS::LightType type = storage->light_get_type(base); switch (type) { case RS::LIGHT_DIRECTIONAL: { - // Copy to SkyDirectionalLightData - if (r_directional_light_count < sky.sky_scene_state.max_directional_lights) { - RendererSceneSkyRD::SkyDirectionalLightData &sky_light_data = sky.sky_scene_state.directional_lights[r_directional_light_count]; - Transform3D light_transform = li->transform; - Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized(); - - sky_light_data.direction[0] = world_direction.x; - sky_light_data.direction[1] = world_direction.y; - sky_light_data.direction[2] = -world_direction.z; - - float sign = storage->light_is_negative(base) ? -1 : 1; - sky_light_data.energy = sign * storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY); - - Color linear_col = storage->light_get_color(base).to_linear(); - sky_light_data.color[0] = linear_col.r; - sky_light_data.color[1] = linear_col.g; - sky_light_data.color[2] = linear_col.b; - - sky_light_data.enabled = true; - - float angular_diameter = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE); - if (angular_diameter > 0.0) { - // I know tan(0) is 0, but let's not risk it with numerical precision. - // technically this will keep expanding until reaching the sun, but all we care - // is expand until we reach the radius of the near plane (there can't be more occluders than that) - angular_diameter = Math::tan(Math::deg2rad(angular_diameter)); - if (storage->light_has_shadow(base)) { - r_directional_light_soft_shadows = true; - } - } else { - angular_diameter = 0.0; - } - sky_light_data.size = angular_diameter; - sky.sky_scene_state.ubo.directional_light_count++; - } - - if (r_directional_light_count >= cluster.max_directional_lights || storage->light_directional_is_sky_only(base)) { + if (r_directional_light_count >= cluster.max_directional_lights) { continue; } @@ -3378,6 +3360,9 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const // technically this will keep expanding until reaching the sun, but all we care // is expand until we reach the radius of the near plane (there can't be more occluders than that) angular_diameter = Math::tan(Math::deg2rad(angular_diameter)); + if (storage->light_has_shadow(base)) { + r_directional_light_soft_shadows = true; + } } else { angular_diameter = 0.0; } diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 276cb8f229..09c828ba37 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -293,7 +293,7 @@ private: uint32_t smallest_subdiv = 0; int size = 0; - bool use_16_bits = false; + bool use_16_bits = true; RID depth; RID fb; //for copying @@ -333,7 +333,7 @@ private: int light_count = 0; int size = 0; - bool use_16_bits = false; + bool use_16_bits = true; int current_light = 0; } directional_shadow; @@ -981,9 +981,9 @@ public: /* SHADOW ATLAS API */ virtual RID shadow_atlas_create() override; - virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = false) override; + virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) override; virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override; - virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) override; + virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_instance, float p_coverage, uint64_t p_light_version) override; _FORCE_INLINE_ bool shadow_atlas_owns_light_instance(RID p_atlas, RID p_light_intance) { ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas); ERR_FAIL_COND_V(!atlas, false); @@ -1002,7 +1002,7 @@ public: return Size2(atlas->size, atlas->size); } - virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = false) override; + virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override; virtual int get_directional_light_shadow_size(RID p_light_intance) override; virtual void set_directional_shadow_count(int p_count) override; @@ -1061,7 +1061,7 @@ public: virtual bool is_environment(RID p_env) const override; - virtual void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) override; + virtual void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, float p_glow_map_strength, RID p_glow_map) override; virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) override; virtual void environment_glow_set_use_high_quality(bool p_enable) override; diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp index 856ea5e74d..354516ae87 100644 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp @@ -590,6 +590,7 @@ void RendererSceneSkyRD::Sky::free(RendererStorageRD *p_storage) { if (material.is_valid()) { p_storage->free(material); + material = RID(); } } @@ -1039,8 +1040,8 @@ RendererSceneSkyRD::~RendererSceneSkyRD() { RD::get_singleton()->free(index_buffer); //array gets freed as dependency } -void RendererSceneSkyRD::setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const CameraMatrix &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render) { - ERR_FAIL_COND(!p_env); // I guess without an environment we also can't have a sky... +void RendererSceneSkyRD::setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const PagedArray<RID> &p_lights, const CameraMatrix &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render) { + ERR_FAIL_COND(!p_env); SkyMaterialData *material = nullptr; Sky *sky = get_sky(p_env->sky); @@ -1121,15 +1122,67 @@ void RendererSceneSkyRD::setup(RendererSceneEnvironmentRD *p_env, RID p_render_b } if (shader_data->uses_light) { + sky_scene_state.ubo.directional_light_count = 0; + // Run through the list of lights in the scene and pick out the Directional Lights. + // This can't be done in RenderSceneRenderRD::_setup lights because that needs to be called + // after the depth prepass, but this runs before the depth prepass + for (int i = 0; i < (int)p_lights.size(); i++) { + RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.get_or_null(p_lights[i]); + if (!li) { + continue; + } + RID base = li->light; + + ERR_CONTINUE(base.is_null()); + + RS::LightType type = storage->light_get_type(base); + if (type == RS::LIGHT_DIRECTIONAL) { + SkyDirectionalLightData &sky_light_data = sky_scene_state.directional_lights[sky_scene_state.ubo.directional_light_count]; + Transform3D light_transform = li->transform; + Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized(); + + sky_light_data.direction[0] = world_direction.x; + sky_light_data.direction[1] = world_direction.y; + sky_light_data.direction[2] = -world_direction.z; + + float sign = storage->light_is_negative(base) ? -1 : 1; + sky_light_data.energy = sign * storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY); + + Color linear_col = storage->light_get_color(base).to_linear(); + sky_light_data.color[0] = linear_col.r; + sky_light_data.color[1] = linear_col.g; + sky_light_data.color[2] = linear_col.b; + + sky_light_data.enabled = true; + + float angular_diameter = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE); + if (angular_diameter > 0.0) { + // I know tan(0) is 0, but let's not risk it with numerical precision. + // technically this will keep expanding until reaching the sun, but all we care + // is expand until we reach the radius of the near plane (there can't be more occluders than that) + angular_diameter = Math::tan(Math::deg2rad(angular_diameter)); + } else { + angular_diameter = 0.0; + } + sky_light_data.size = angular_diameter; + sky_scene_state.ubo.directional_light_count++; + if (sky_scene_state.ubo.directional_light_count >= sky_scene_state.max_directional_lights) { + break; + } + } + } // Check whether the directional_light_buffer changes bool light_data_dirty = false; + // Light buffer is dirty if we have fewer or more lights + // If we have fewer lights, make sure that old lights are disabled if (sky_scene_state.ubo.directional_light_count != sky_scene_state.last_frame_directional_light_count) { light_data_dirty = true; for (uint32_t i = sky_scene_state.ubo.directional_light_count; i < sky_scene_state.max_directional_lights; i++) { sky_scene_state.directional_lights[i].enabled = false; } } + if (!light_data_dirty) { for (uint32_t i = 0; i < sky_scene_state.ubo.directional_light_count; i++) { if (sky_scene_state.directional_lights[i].direction[0] != sky_scene_state.last_frame_directional_lights[i].direction[0] || diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h index d81a415c2d..13d24e2508 100644 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h @@ -292,7 +292,7 @@ public: void set_texture_format(RD::DataFormat p_texture_format); ~RendererSceneSkyRD(); - void setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const CameraMatrix &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render); + void setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const PagedArray<RID> &p_lights, const CameraMatrix &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render); void update(RendererSceneEnvironmentRD *p_env, const CameraMatrix &p_projection, const Transform3D &p_transform, double p_time, float p_luminance_multiplier = 1.0); void draw(RendererSceneEnvironmentRD *p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, uint32_t p_view_count, const CameraMatrix *p_projections, const Transform3D &p_transform, double p_time); // only called by clustered renderer void update_res_buffers(RendererSceneEnvironmentRD *p_env, uint32_t p_view_count, const CameraMatrix *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier = 1.0); diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index 2e63ac57d9..f345001539 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp @@ -6238,7 +6238,7 @@ void RendererStorageRD::skeleton_allocate_data(RID p_skeleton, int p_bones, bool if (skeleton->buffer.is_valid()) { RD::get_singleton()->free(skeleton->buffer); skeleton->buffer = RID(); - skeleton->data.resize(0); + skeleton->data.clear(); skeleton->uniform_set_mi = RID(); } @@ -7516,10 +7516,6 @@ void RendererStorageRD::_clear_render_target(RenderTarget *rt) { if (rt->backbuffer.is_valid()) { RD::get_singleton()->free(rt->backbuffer); rt->backbuffer = RID(); - for (int i = 0; i < rt->backbuffer_mipmaps.size(); i++) { - //just erase copies, since the rest are erased by dependency - RD::get_singleton()->free(rt->backbuffer_mipmaps[i].mipmap_copy); - } rt->backbuffer_mipmaps.clear(); rt->backbuffer_uniform_set = RID(); //chain deleted } @@ -7636,7 +7632,9 @@ void RendererStorageRD::_create_render_target_backbuffer(RenderTarget *rt) { tf.mipmaps = mipmaps_required; rt->backbuffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rt->backbuffer, "Render Target Back Buffer"); rt->backbuffer_mipmap0 = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rt->backbuffer, 0, 0); + RD::get_singleton()->set_resource_name(rt->backbuffer_mipmap0, "Back Buffer slice mipmap 0"); { Vector<RID> fb_tex; @@ -7651,23 +7649,10 @@ void RendererStorageRD::_create_render_target_backbuffer(RenderTarget *rt) { } //create mipmaps for (uint32_t i = 1; i < mipmaps_required; i++) { - RenderTarget::BackbufferMipmap mm; - { - mm.mipmap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rt->backbuffer, 0, i); - } - - { - Size2 mm_size = Image::get_image_mipmap_size(tf.width, tf.height, Image::FORMAT_RGBA8, i); + RID mipmap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rt->backbuffer, 0, i); + RD::get_singleton()->set_resource_name(mipmap, "Back Buffer slice mip: " + itos(i)); - RD::TextureFormat mmtf = tf; - mmtf.width = mm_size.width; - mmtf.height = mm_size.height; - mmtf.mipmaps = 1; - - mm.mipmap_copy = RD::get_singleton()->texture_create(mmtf, RD::TextureView()); - } - - rt->backbuffer_mipmaps.push_back(mm); + rt->backbuffer_mipmaps.push_back(mipmap); } } @@ -8111,7 +8096,7 @@ void RendererStorageRD::render_target_copy_to_back_buffer(RID p_render_target, c if (!p_gen_mipmaps) { return; } - + RD::get_singleton()->draw_command_begin_label("Gaussian Blur Mipmaps"); //then mipmap blur RID prev_texture = rt->color; //use color, not backbuffer, as bb has mipmaps. @@ -8121,10 +8106,11 @@ void RendererStorageRD::render_target_copy_to_back_buffer(RID p_render_target, c region.size.x = MAX(1, region.size.x >> 1); region.size.y = MAX(1, region.size.y >> 1); - const RenderTarget::BackbufferMipmap &mm = rt->backbuffer_mipmaps[i]; - effects->gaussian_blur(prev_texture, mm.mipmap, mm.mipmap_copy, region, true); - prev_texture = mm.mipmap; + RID mipmap = rt->backbuffer_mipmaps[i]; + effects->gaussian_blur(prev_texture, mipmap, region, true); + prev_texture = mipmap; } + RD::get_singleton()->draw_command_end_label(); } void RendererStorageRD::render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color) { @@ -8164,7 +8150,7 @@ void RendererStorageRD::render_target_gen_back_buffer_mipmaps(RID p_render_targe return; //nothing to do } } - + RD::get_singleton()->draw_command_begin_label("Gaussian Blur Mipmaps2"); //then mipmap blur RID prev_texture = rt->backbuffer_mipmap0; @@ -8174,10 +8160,11 @@ void RendererStorageRD::render_target_gen_back_buffer_mipmaps(RID p_render_targe region.size.x = MAX(1, region.size.x >> 1); region.size.y = MAX(1, region.size.y >> 1); - const RenderTarget::BackbufferMipmap &mm = rt->backbuffer_mipmaps[i]; - effects->gaussian_blur(prev_texture, mm.mipmap, mm.mipmap_copy, region, true); - prev_texture = mm.mipmap; + RID mipmap = rt->backbuffer_mipmaps[i]; + effects->gaussian_blur(prev_texture, mipmap, region, true); + prev_texture = mipmap; } + RD::get_singleton()->draw_command_end_label(); } RID RendererStorageRD::render_target_get_framebuffer_uniform_set(RID p_render_target) { diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h index 43bbcf6520..6febb71e93 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.h +++ b/servers/rendering/renderer_rd/renderer_storage_rd.h @@ -1169,12 +1169,7 @@ private: RID backbuffer_fb; RID backbuffer_mipmap0; - struct BackbufferMipmap { - RID mipmap; - RID mipmap_copy; - }; - - Vector<BackbufferMipmap> backbuffer_mipmaps; + Vector<RID> backbuffer_mipmaps; RID framebuffer_uniform_set; RID backbuffer_uniform_set; diff --git a/servers/rendering/renderer_rd/shaders/copy.glsl b/servers/rendering/renderer_rd/shaders/copy.glsl index d4d0ed0f56..ecf7bb9817 100644 --- a/servers/rendering/renderer_rd/shaders/copy.glsl +++ b/servers/rendering/renderer_rd/shaders/copy.glsl @@ -61,7 +61,7 @@ layout(rgba8, set = 3, binding = 0) uniform restrict writeonly image2D dest_buff layout(rgba32f, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer; #endif -#ifdef MODE_GAUSSIAN_GLOW +#ifdef MODE_GAUSSIAN_BLUR shared vec4 local_cache[256]; shared vec4 temp_cache[128]; #endif @@ -70,7 +70,7 @@ void main() { // Pixel being shaded ivec2 pos = ivec2(gl_GlobalInvocationID.xy); -#ifndef MODE_GAUSSIAN_GLOW // Glow needs the extra threads +#ifndef MODE_GAUSSIAN_BLUR // Gaussian blur needs the extra threads if (any(greaterThanEqual(pos, params.section.zw))) { //too large, do nothing return; } @@ -92,35 +92,11 @@ void main() { #ifdef MODE_GAUSSIAN_BLUR - //Simpler blur uses SIGMA2 for the gaussian kernel for a stronger effect - - if (bool(params.flags & FLAG_HORIZONTAL)) { - ivec2 base_pos = (pos + params.section.xy) << 1; - vec4 color = texelFetch(source_color, base_pos + ivec2(0, 0), 0) * 0.214607; - color += texelFetch(source_color, base_pos + ivec2(1, 0), 0) * 0.189879; - color += texelFetch(source_color, base_pos + ivec2(2, 0), 0) * 0.131514; - color += texelFetch(source_color, base_pos + ivec2(3, 0), 0) * 0.071303; - color += texelFetch(source_color, base_pos + ivec2(-1, 0), 0) * 0.189879; - color += texelFetch(source_color, base_pos + ivec2(-2, 0), 0) * 0.131514; - color += texelFetch(source_color, base_pos + ivec2(-3, 0), 0) * 0.071303; - imageStore(dest_buffer, pos + params.target, color); - } else { - ivec2 base_pos = (pos + params.section.xy); - vec4 color = texelFetch(source_color, base_pos + ivec2(0, 0), 0) * 0.38774; - color += texelFetch(source_color, base_pos + ivec2(0, 1), 0) * 0.24477; - color += texelFetch(source_color, base_pos + ivec2(0, 2), 0) * 0.06136; - color += texelFetch(source_color, base_pos + ivec2(0, -1), 0) * 0.24477; - color += texelFetch(source_color, base_pos + ivec2(0, -2), 0) * 0.06136; - imageStore(dest_buffer, pos + params.target, color); - } -#endif - -#ifdef MODE_GAUSSIAN_GLOW - // First pass copy texture into 16x16 local memory for every 8x8 thread block vec2 quad_center_uv = clamp(vec2(gl_GlobalInvocationID.xy + gl_LocalInvocationID.xy - 3.5) / params.section.zw, vec2(0.5 / params.section.zw), vec2(1.0 - 1.5 / params.section.zw)); uint dest_index = gl_LocalInvocationID.x * 2 + gl_LocalInvocationID.y * 2 * 16; +#ifdef MODE_GLOW if (bool(params.flags & FLAG_HIGH_QUALITY_GLOW)) { vec2 quad_offset_uv = clamp((vec2(gl_GlobalInvocationID.xy + gl_LocalInvocationID.xy - 3.0)) / params.section.zw, vec2(0.5 / params.section.zw), vec2(1.0 - 1.5 / params.section.zw)); @@ -128,12 +104,15 @@ void main() { local_cache[dest_index + 1] = (textureLod(source_color, quad_center_uv + vec2(1.0 / params.section.z, 0.0), 0) + textureLod(source_color, quad_offset_uv + vec2(1.0 / params.section.z, 0.0), 0)) * 0.5; local_cache[dest_index + 16] = (textureLod(source_color, quad_center_uv + vec2(0.0, 1.0 / params.section.w), 0) + textureLod(source_color, quad_offset_uv + vec2(0.0, 1.0 / params.section.w), 0)) * 0.5; local_cache[dest_index + 16 + 1] = (textureLod(source_color, quad_center_uv + vec2(1.0 / params.section.zw), 0) + textureLod(source_color, quad_offset_uv + vec2(1.0 / params.section.zw), 0)) * 0.5; - } else { + } else +#endif + { local_cache[dest_index] = textureLod(source_color, quad_center_uv, 0); local_cache[dest_index + 1] = textureLod(source_color, quad_center_uv + vec2(1.0 / params.section.z, 0.0), 0); local_cache[dest_index + 16] = textureLod(source_color, quad_center_uv + vec2(0.0, 1.0 / params.section.w), 0); local_cache[dest_index + 16 + 1] = textureLod(source_color, quad_center_uv + vec2(1.0 / params.section.zw), 0); } +#ifdef MODE_GLOW if (bool(params.flags & FLAG_GLOW_FIRST_PASS)) { // Tonemap initial samples to reduce weight of fireflies: https://graphicrants.blogspot.com/2013/12/tone-mapping.html local_cache[dest_index] /= 1.0 + dot(local_cache[dest_index].rgb, vec3(0.299, 0.587, 0.114)); @@ -141,29 +120,33 @@ void main() { local_cache[dest_index + 16] /= 1.0 + dot(local_cache[dest_index + 16].rgb, vec3(0.299, 0.587, 0.114)); local_cache[dest_index + 16 + 1] /= 1.0 + dot(local_cache[dest_index + 16 + 1].rgb, vec3(0.299, 0.587, 0.114)); } - + const float kernel[4] = { 0.174938, 0.165569, 0.140367, 0.106595 }; +#else + // Simpler blur uses SIGMA2 for the gaussian kernel for a stronger effect. + const float kernel[4] = { 0.214607, 0.189879, 0.131514, 0.071303 }; +#endif memoryBarrierShared(); barrier(); // Horizontal pass. Needs to copy into 8x16 chunk of local memory so vertical pass has full resolution uint read_index = gl_LocalInvocationID.x + gl_LocalInvocationID.y * 32 + 4; vec4 color_top = vec4(0.0); - color_top += local_cache[read_index] * 0.174938; - color_top += local_cache[read_index + 1] * 0.165569; - color_top += local_cache[read_index + 2] * 0.140367; - color_top += local_cache[read_index + 3] * 0.106595; - color_top += local_cache[read_index - 1] * 0.165569; - color_top += local_cache[read_index - 2] * 0.140367; - color_top += local_cache[read_index - 3] * 0.106595; + color_top += local_cache[read_index] * kernel[0]; + color_top += local_cache[read_index + 1] * kernel[1]; + color_top += local_cache[read_index + 2] * kernel[2]; + color_top += local_cache[read_index + 3] * kernel[3]; + color_top += local_cache[read_index - 1] * kernel[1]; + color_top += local_cache[read_index - 2] * kernel[2]; + color_top += local_cache[read_index - 3] * kernel[3]; vec4 color_bottom = vec4(0.0); - color_bottom += local_cache[read_index + 16] * 0.174938; - color_bottom += local_cache[read_index + 1 + 16] * 0.165569; - color_bottom += local_cache[read_index + 2 + 16] * 0.140367; - color_bottom += local_cache[read_index + 3 + 16] * 0.106595; - color_bottom += local_cache[read_index - 1 + 16] * 0.165569; - color_bottom += local_cache[read_index - 2 + 16] * 0.140367; - color_bottom += local_cache[read_index - 3 + 16] * 0.106595; + color_bottom += local_cache[read_index + 16] * kernel[0]; + color_bottom += local_cache[read_index + 1 + 16] * kernel[1]; + color_bottom += local_cache[read_index + 2 + 16] * kernel[2]; + color_bottom += local_cache[read_index + 3 + 16] * kernel[3]; + color_bottom += local_cache[read_index - 1 + 16] * kernel[1]; + color_bottom += local_cache[read_index - 2 + 16] * kernel[2]; + color_bottom += local_cache[read_index - 3 + 16] * kernel[3]; // rotate samples to take advantage of cache coherency uint write_index = gl_LocalInvocationID.y * 2 + gl_LocalInvocationID.x * 16; @@ -174,18 +157,24 @@ void main() { memoryBarrierShared(); barrier(); + // If destination outside of texture, can stop doing work now + if (any(greaterThanEqual(pos, params.section.zw))) { + return; + } + // Vertical pass uint index = gl_LocalInvocationID.y + gl_LocalInvocationID.x * 16 + 4; vec4 color = vec4(0.0); - color += temp_cache[index] * 0.174938; - color += temp_cache[index + 1] * 0.165569; - color += temp_cache[index + 2] * 0.140367; - color += temp_cache[index + 3] * 0.106595; - color += temp_cache[index - 1] * 0.165569; - color += temp_cache[index - 2] * 0.140367; - color += temp_cache[index - 3] * 0.106595; + color += temp_cache[index] * kernel[0]; + color += temp_cache[index + 1] * kernel[1]; + color += temp_cache[index + 2] * kernel[2]; + color += temp_cache[index + 3] * kernel[3]; + color += temp_cache[index - 1] * kernel[1]; + color += temp_cache[index - 2] * kernel[2]; + color += temp_cache[index - 3] * kernel[3]; +#ifdef MODE_GLOW if (bool(params.flags & FLAG_GLOW_FIRST_PASS)) { // Undo tonemap to restore range: https://graphicrants.blogspot.com/2013/12/tone-mapping.html color /= 1.0 - dot(color.rgb, vec3(0.299, 0.587, 0.114)); @@ -205,7 +194,7 @@ void main() { color = min(color * feedback, vec4(params.glow_luminance_cap)); } - +#endif imageStore(dest_buffer, pos + params.target, color); #endif diff --git a/servers/rendering/renderer_rd/shaders/light_data_inc.glsl b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl index fdc7729338..52787bb204 100644 --- a/servers/rendering/renderer_rd/shaders/light_data_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl @@ -1,6 +1,6 @@ #define LIGHT_BAKE_DISABLED 0 -#define LIGHT_BAKE_DYNAMIC 1 -#define LIGHT_BAKE_STATIC 2 +#define LIGHT_BAKE_STATIC 1 +#define LIGHT_BAKE_DYNAMIC 2 struct LightData { //this structure needs to be as packed as possible highp vec3 position; diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl index d22f936a35..16f77fb91a 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl @@ -877,17 +877,17 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v vec4 splane = (spot_lights.data[idx].shadow_matrix * vec4(vertex, 1.0)); splane /= splane.w; - vec2 proj_uv = normal_to_panorama(splane.xyz) * spot_lights.data[idx].projector_rect.zw; + vec2 proj_uv = splane.xy * spot_lights.data[idx].projector_rect.zw; if (sc_projector_use_mipmaps) { //ensure we have proper mipmaps vec4 splane_ddx = (spot_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0)); splane_ddx /= splane_ddx.w; - vec2 proj_uv_ddx = normal_to_panorama(splane_ddx.xyz) * spot_lights.data[idx].projector_rect.zw - proj_uv; + vec2 proj_uv_ddx = splane_ddx.xy * spot_lights.data[idx].projector_rect.zw - proj_uv; vec4 splane_ddy = (spot_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0)); splane_ddy /= splane_ddy.w; - vec2 proj_uv_ddy = normal_to_panorama(splane_ddy.xyz) * spot_lights.data[idx].projector_rect.zw - proj_uv; + vec2 proj_uv_ddy = splane_ddy.xy * spot_lights.data[idx].projector_rect.zw - proj_uv; vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, light_projector_sampler), proj_uv + spot_lights.data[idx].projector_rect.xy, proj_uv_ddx, proj_uv_ddy); color *= proj.rgb * proj.a; diff --git a/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl b/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl index fde5688301..57349e55b1 100644 --- a/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl +++ b/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl @@ -190,8 +190,7 @@ void main() { } vec2 final_pos; - float grad; - grad = steps_taken / float(params.num_steps); + 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; final_pos = pos; diff --git a/servers/rendering/renderer_rd/shaders/tonemap.glsl b/servers/rendering/renderer_rd/shaders/tonemap.glsl index 948c6e1e39..41d41758f4 100644 --- a/servers/rendering/renderer_rd/shaders/tonemap.glsl +++ b/servers/rendering/renderer_rd/shaders/tonemap.glsl @@ -45,6 +45,7 @@ layout(set = 0, binding = 0) uniform sampler2D source_color; layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure; layout(set = 2, binding = 0) uniform sampler2D source_glow; +layout(set = 2, binding = 1) uniform sampler2D glow_map; #ifdef USE_1D_LUT layout(set = 3, binding = 0) uniform sampler2D source_color_correction; @@ -63,7 +64,7 @@ layout(push_constant, binding = 1, std430) uniform Params { uvec2 glow_texture_size; float glow_intensity; - uint pad3; + float glow_map_strength; uint glow_mode; float glow_levels[7]; @@ -405,6 +406,9 @@ void main() { #ifndef SUBPASS if (params.use_glow && params.glow_mode == GLOW_MODE_MIX) { vec3 glow = gather_glow(source_glow, uv_interp) * params.luminance_multiplier; + if (params.glow_map_strength > 0.001) { + glow = mix(glow, texture(glow_map, uv_interp).rgb * glow, params.glow_map_strength); + } color.rgb = mix(color.rgb, glow, params.glow_intensity); } @@ -425,9 +429,11 @@ void main() { #ifndef SUBPASS // Glow - if (params.use_glow && params.glow_mode != GLOW_MODE_MIX) { vec3 glow = gather_glow(source_glow, uv_interp) * params.glow_intensity * params.luminance_multiplier; + if (params.glow_map_strength > 0.001) { + glow = mix(glow, texture(glow_map, uv_interp).rgb * glow, params.glow_map_strength); + } // high dynamic range -> SRGB glow = apply_tonemapping(glow, params.white); diff --git a/servers/rendering/renderer_scene.h b/servers/rendering/renderer_scene.h index 426d22f83e..4c58fce1c9 100644 --- a/servers/rendering/renderer_scene.h +++ b/servers/rendering/renderer_scene.h @@ -105,7 +105,7 @@ public: virtual Variant instance_geometry_get_shader_parameter(RID p_instance, const StringName &p_parameter) const = 0; virtual Variant instance_geometry_get_shader_parameter_default_value(RID p_instance, const StringName &p_parameter) const = 0; - virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = false) = 0; + virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) = 0; /* SKY API */ @@ -131,7 +131,7 @@ public: virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer) = 0; virtual void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG) = 0; - virtual void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) = 0; + virtual void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, float p_glow_map_strength, RID p_glow_map) = 0; virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) = 0; virtual void environment_glow_set_use_high_quality(bool p_enable) = 0; @@ -187,7 +187,7 @@ public: virtual void directional_shadow_quality_set(RS::ShadowQuality p_quality) = 0; virtual RID shadow_atlas_create() = 0; - virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_use_16_bits = false) = 0; + virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_use_16_bits = true) = 0; virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) = 0; /* Render Buffers */ diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 8ded180633..5b2be8e174 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -3871,8 +3871,12 @@ void RendererSceneCull::update_dirty_instances() { void RendererSceneCull::update() { //optimize bvhs - for (uint32_t i = 0; i < scenario_owner.get_rid_count(); i++) { - Scenario *s = scenario_owner.get_ptr_by_index(i); + + uint32_t rid_count = scenario_owner.get_rid_count(); + RID *rids = (RID *)alloca(sizeof(RID) * rid_count); + scenario_owner.fill_owned_buffer(rids); + for (uint32_t i = 0; i < rid_count; i++) { + Scenario *s = scenario_owner.get_or_null(rids[i]); s->indexers[Scenario::INDEXER_GEOMETRY].optimize_incremental(indexer_update_iterations); s->indexers[Scenario::INDEXER_VOLUMES].optimize_incremental(indexer_update_iterations); } diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index 1e770ef66c..ed0229f0f9 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -1113,7 +1113,7 @@ public: PASS6(environment_set_ssil, RID, bool, float, float, float, float) PASS6(environment_set_ssil_quality, RS::EnvironmentSSILQuality, bool, float, int, float, float) - PASS11(environment_set_glow, RID, bool, Vector<float>, float, float, float, float, RS::EnvironmentGlowBlendMode, float, float, float) + PASS13(environment_set_glow, RID, bool, Vector<float>, float, float, float, float, RS::EnvironmentGlowBlendMode, float, float, float, float, RID) PASS1(environment_glow_set_use_bicubic_upscale, bool) PASS1(environment_glow_set_use_high_quality, bool) diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h index c34a46d166..cedf6575fd 100644 --- a/servers/rendering/renderer_scene_render.h +++ b/servers/rendering/renderer_scene_render.h @@ -80,11 +80,11 @@ public: /* SHADOW ATLAS API */ virtual RID shadow_atlas_create() = 0; - virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = false) = 0; + virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) = 0; virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) = 0; virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) = 0; - virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = false) = 0; + virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) = 0; virtual int get_directional_light_shadow_size(RID p_light_intance) = 0; virtual void set_directional_shadow_count(int p_count) = 0; @@ -123,7 +123,7 @@ public: virtual void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) = 0; #endif - virtual void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) = 0; + virtual void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, float p_glow_map_strength, RID p_glow_map) = 0; virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) = 0; virtual void environment_glow_set_use_high_quality(bool p_enable) = 0; diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index 17a665922f..5a84bace2d 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -549,8 +549,13 @@ void RendererViewport::draw_viewports() { // get our xr interface in case we need it Ref<XRInterface> xr_interface; - if (XRServer::get_singleton() != nullptr) { - xr_interface = XRServer::get_singleton()->get_primary_interface(); + XRServer *xr_server = XRServer::get_singleton(); + if (xr_server != nullptr) { + // let our XR server know we're about to render our frames so we can get our frame timing + xr_server->pre_render(); + + // retrieve the interface responsible for rendering + xr_interface = xr_server->get_primary_interface(); } if (Engine::get_singleton()->is_editor_hint()) { @@ -582,19 +587,26 @@ void RendererViewport::draw_viewports() { bool visible = vp->viewport_to_screen_rect != Rect2(); - if (vp->use_xr && xr_interface.is_valid()) { - visible = true; // XR viewport is always visible regardless of update mode, output is sent to HMD. - - // Override our size, make sure it matches our required size and is created as a stereo target - Size2 xr_size = xr_interface->get_render_target_size(); - - // Would have been nice if we could call viewport_set_size here, - // but alas that takes our RID and we now have our pointer, - // also we only check if view_count changes in render_target_set_size so we need to call that for this to reliably change - vp->occlusion_buffer_dirty = vp->occlusion_buffer_dirty || (vp->size != xr_size); - vp->size = xr_size; - uint32_t view_count = xr_interface->get_view_count(); - RSG::storage->render_target_set_size(vp->render_target, vp->size.x, vp->size.y, view_count); + if (vp->use_xr) { + if (xr_interface.is_valid()) { + // Override our size, make sure it matches our required size and is created as a stereo target + Size2 xr_size = xr_interface->get_render_target_size(); + + // Would have been nice if we could call viewport_set_size here, + // but alas that takes our RID and we now have our pointer, + // also we only check if view_count changes in render_target_set_size so we need to call that for this to reliably change + vp->occlusion_buffer_dirty = vp->occlusion_buffer_dirty || (vp->size != xr_size); + vp->size = xr_size; + uint32_t view_count = xr_interface->get_view_count(); + RSG::storage->render_target_set_size(vp->render_target, vp->size.x, vp->size.y, view_count); + + // Inform xr interface we're about to render its viewport, if this returns false we don't render + visible = xr_interface->pre_draw_viewport(vp->render_target); + } else { + // don't render anything + visible = false; + vp->size = Size2(); + } } if (vp->update_mode == RS::VIEWPORT_UPDATE_ALWAYS || vp->update_mode == RS::VIEWPORT_UPDATE_ONCE) { @@ -647,7 +659,7 @@ void RendererViewport::draw_viewports() { // measure // commit our eyes - Vector<BlitToScreen> blits = xr_interface->commit_views(vp->render_target, vp->viewport_to_screen_rect); + Vector<BlitToScreen> blits = xr_interface->post_draw_viewport(vp->render_target, vp->viewport_to_screen_rect); if (vp->viewport_to_screen != DisplayServer::INVALID_WINDOW_ID && blits.size() > 0) { if (!blit_to_screen_list.has(vp->viewport_to_screen)) { blit_to_screen_list[vp->viewport_to_screen] = Vector<BlitToScreen>(); @@ -657,9 +669,6 @@ void RendererViewport::draw_viewports() { blit_to_screen_list[vp->viewport_to_screen].push_back(blits[b]); } } - - // and for our frame timing, mark when we've finished committing our eyes - XRServer::get_singleton()->_mark_commit(); } else { RSG::storage->render_target_set_external_texture(vp->render_target, 0); @@ -813,7 +822,7 @@ void RendererViewport::viewport_set_active(RID p_viewport, bool p_active) { ERR_FAIL_COND(!viewport); if (p_active) { - ERR_FAIL_COND_MSG(active_viewports.find(viewport) != -1, "Can't make active a Viewport that is already active."); + ERR_FAIL_COND_MSG(active_viewports.has(viewport), "Can't make active a Viewport that is already active."); viewport->occlusion_buffer_dirty = true; active_viewports.push_back(viewport); } else { diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h index 7bc8f9961b..2245d9a216 100644 --- a/servers/rendering/renderer_viewport.h +++ b/servers/rendering/renderer_viewport.h @@ -91,7 +91,7 @@ public: RID shadow_atlas; int shadow_atlas_size; - bool shadow_atlas_16_bits = false; + bool shadow_atlas_16_bits = true; bool sdf_active; @@ -247,7 +247,7 @@ public: void viewport_set_global_canvas_transform(RID p_viewport, const Transform2D &p_transform); void viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer); - void viewport_set_shadow_atlas_size(RID p_viewport, int p_size, bool p_16_bits = false); + void viewport_set_shadow_atlas_size(RID p_viewport, int p_size, bool p_16_bits = true); void viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv); void viewport_set_msaa(RID p_viewport, RS::ViewportMSAA p_msaa); diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 46fb3c8537..6fc5d0b3e8 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -451,7 +451,7 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("compute_list_add_barrier", "compute_list"), &RenderingDevice::compute_list_add_barrier); ClassDB::bind_method(D_METHOD("compute_list_end", "post_barrier"), &RenderingDevice::compute_list_end, DEFVAL(BARRIER_MASK_ALL)); - ClassDB::bind_method(D_METHOD("free", "rid"), &RenderingDevice::free); + ClassDB::bind_method(D_METHOD("free_rid", "rid"), &RenderingDevice::free); ClassDB::bind_method(D_METHOD("capture_timestamp", "name"), &RenderingDevice::capture_timestamp); ClassDB::bind_method(D_METHOD("get_captured_timestamps_count"), &RenderingDevice::get_captured_timestamps_count); diff --git a/servers/rendering/rendering_device_binds.cpp b/servers/rendering/rendering_device_binds.cpp index 19cde610ba..e50ac42027 100644 --- a/servers/rendering/rendering_device_binds.cpp +++ b/servers/rendering/rendering_device_binds.cpp @@ -99,11 +99,11 @@ Error RDShaderFile::parse_versions_from_text(const String &p_text, const String if (reading_versions) { String l = line.strip_edges(); if (!l.is_empty()) { - if (l.find("=") == -1) { + if (!l.contains("=")) { base_error = "Missing `=` in '" + l + "'. Version syntax is `version = \"<defines with C escaping>\";`."; break; } - if (l.find(";") == -1) { + if (!l.contains(";")) { // We don't require a semicolon per se, but it's needed for clang-format to handle things properly. base_error = "Missing `;` in '" + l + "'. Version syntax is `version = \"<defines with C escaping>\";`."; break; diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp index d7e9d210db..d93aad5d7b 100644 --- a/servers/rendering/rendering_server_default.cpp +++ b/servers/rendering/rendering_server_default.cpp @@ -93,6 +93,12 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) { RSG::rasterizer->end_frame(p_swap_buffers); + XRServer *xr_server = XRServer::get_singleton(); + if (xr_server != nullptr) { + // let our XR server know we're done so we can get our frame timing + xr_server->end_frame(); + } + RSG::canvas->update_visibility_notifiers(); RSG::scene->update_visibility_notifiers(); diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index ee684c69ed..6d2c36537b 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -259,7 +259,6 @@ public: command_queue.push(RSG::storage, &RendererStorage::mesh_initialize, mesh); command_queue.push(RSG::storage, &RendererStorage::mesh_set_blend_shape_count, mesh, p_blend_shape_count); for (int i = 0; i < p_surfaces.size(); i++) { - RSG::storage->mesh_add_surface(mesh, p_surfaces[i]); command_queue.push(RSG::storage, &RendererStorage::mesh_add_surface, mesh, p_surfaces[i]); } } @@ -629,7 +628,7 @@ public: FUNC6(environment_set_ssil, RID, bool, float, float, float, float) FUNC6(environment_set_ssil_quality, EnvironmentSSILQuality, bool, float, int, float, float) - FUNC11(environment_set_glow, RID, bool, Vector<float>, float, float, float, float, EnvironmentGlowBlendMode, float, float, float) + FUNC13(environment_set_glow, RID, bool, Vector<float>, float, float, float, float, EnvironmentGlowBlendMode, float, float, float, float, RID) FUNC1(environment_glow_set_use_bicubic_upscale, bool) FUNC1(environment_glow_set_use_high_quality, bool) diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp index 78e81eac0b..5b43ca4bcd 100644 --- a/servers/rendering/shader_compiler.cpp +++ b/servers/rendering/shader_compiler.cpp @@ -182,7 +182,7 @@ static String _mkid(const String &p_id) { static String f2sp0(float p_float) { String num = rtoss(p_float); - if (num.find(".") == -1 && num.find("e") == -1) { + if (!num.contains(".") && !num.contains("e")) { num += ".0"; } return num; @@ -813,6 +813,9 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene if (bnode->statements[i]->type == SL::Node::TYPE_CONTROL_FLOW || bnode->single_statement) { code += scode; //use directly + if (bnode->use_comma_between_statements && i + 1 < bnode->statements.size()) { + code += ","; + } } else { code += _mktab(p_level) + scode + ";\n"; } @@ -1287,10 +1290,10 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); } else if (cfnode->flow_op == SL::FLOW_OP_FOR) { String left = _dump_node_code(cfnode->blocks[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - String middle = _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - String right = _dump_node_code(cfnode->expressions[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + String middle = _dump_node_code(cfnode->blocks[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + String right = _dump_node_code(cfnode->blocks[2], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); code += _mktab(p_level) + "for (" + left + ";" + middle + ";" + right + ")\n"; - code += _dump_node_code(cfnode->blocks[1], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); + code += _dump_node_code(cfnode->blocks[3], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); } else if (cfnode->flow_op == SL::FLOW_OP_RETURN) { if (cfnode->expressions.size()) { diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 4e07582187..91201b2028 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -35,18 +35,6 @@ #define HAS_WARNING(flag) (warning_flags & flag) -static bool _is_text_char(char32_t c) { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'; -} - -static bool _is_number(char32_t c) { - return (c >= '0' && c <= '9'); -} - -static bool _is_hex(char32_t c) { - return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); -} - String ShaderLanguage::get_operator_text(Operator p_op) { static const char *op_names[OP_MAX] = { "==", "!=", @@ -543,7 +531,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { default: { char_idx--; //go back one, since we have no idea what this is - if (_is_number(GETCHAR(0)) || (GETCHAR(0) == '.' && _is_number(GETCHAR(1)))) { + if (is_digit(GETCHAR(0)) || (GETCHAR(0) == '.' && is_digit(GETCHAR(1)))) { // parse number bool hexa_found = false; bool period_found = false; @@ -584,7 +572,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { const char32_t symbol = String::char_lowercase(GETCHAR(i)); bool error = false; - if (_is_number(symbol)) { + if (is_digit(symbol)) { if (end_suffix_found) { error = true; } @@ -617,8 +605,8 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { break; } } - } else if (!hexa_found || !_is_hex(symbol)) { - if (_is_text_char(symbol)) { + } else if (!hexa_found || !is_hex_digit(symbol)) { + if (is_ascii_identifier_char(symbol)) { error = true; } else { break; @@ -649,7 +637,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { return _make_token(TK_ERROR, "Invalid (hexadecimal) numeric constant"); } } else if (period_found || exponent_found || float_suffix_found) { // Float - if (exponent_found && (!_is_number(last_char) && last_char != 'f')) { // checks for eg: "2E", "2E-", "2E+" + if (exponent_found && (!is_digit(last_char) && last_char != 'f')) { // checks for eg: "2E", "2E-", "2E+" return _make_token(TK_ERROR, "Invalid (float) numeric constant"); } if (period_found) { @@ -660,7 +648,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { } } else { //checks for eg. "1." or "1.99" notations - if (last_char != '.' && !_is_number(last_char)) { + if (last_char != '.' && !is_digit(last_char)) { return _make_token(TK_ERROR, "Invalid (float) numeric constant"); } } @@ -723,11 +711,11 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { return _make_token(TK_PERIOD); } - if (_is_text_char(GETCHAR(0))) { + if (is_ascii_identifier_char(GETCHAR(0))) { // parse identifier String str; - while (_is_text_char(GETCHAR(0))) { + while (is_ascii_identifier_char(GETCHAR(0))) { str += char32_t(GETCHAR(0)); char_idx++; } @@ -5208,9 +5196,15 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons #ifdef DEBUG_ENABLED if (check_warnings) { StringName func_name; + BlockNode *b = p_block; - if (p_block && p_block->parent_function) { - func_name = p_block->parent_function->name; + while (b) { + if (b->parent_function) { + func_name = b->parent_function->name; + break; + } else { + b = b->parent_block; + } } _parse_used_identifier(identifier, ident_type, func_name); @@ -5246,21 +5240,34 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons expression.push_back(e); continue; } else { - if (tk.type != TK_SEMICOLON) { - _set_error(vformat(RTR("Expected expression, found: '%s'."), get_token_text(tk))); - return nullptr; - } else { -#ifdef DEBUG_ENABLED - if (check_warnings && HAS_WARNING(ShaderWarning::FORMATTING_ERROR_FLAG)) { - _add_line_warning(ShaderWarning::FORMATTING_ERROR, RTR("Empty statement. Remove ';' to fix this warning.")); - } -#endif // DEBUG_ENABLED + bool valid = false; + if (p_block && p_block->block_type == BlockNode::BLOCK_TYPE_FOR_EXPRESSION && tk.type == TK_PARENTHESIS_CLOSE) { + valid = true; _set_tkpos(prepos); OperatorNode *func = alloc_node<OperatorNode>(); func->op = OP_EMPTY; expr = func; } + if (!valid) { + if (tk.type != TK_SEMICOLON) { + _set_error(vformat(RTR("Expected expression, found: '%s'."), get_token_text(tk))); + return nullptr; + } else { +#ifdef DEBUG_ENABLED + if (!p_block || (p_block->block_type != BlockNode::BLOCK_TYPE_FOR_INIT && p_block->block_type != BlockNode::BLOCK_TYPE_FOR_CONDITION)) { + if (check_warnings && HAS_WARNING(ShaderWarning::FORMATTING_ERROR_FLAG)) { + _add_line_warning(ShaderWarning::FORMATTING_ERROR, RTR("Empty statement. Remove ';' to fix this warning.")); + } + } +#endif // DEBUG_ENABLED + _set_tkpos(prepos); + + OperatorNode *func = alloc_node<OperatorNode>(); + func->op = OP_EMPTY; + expr = func; + } + } } ERR_FAIL_COND_V(!expr, nullptr); @@ -6365,6 +6372,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun } bool is_struct = shader->structs.has(tk.text); + bool is_var_init = false; + bool is_condition = false; if (tk.type == TK_CURLY_BRACKET_CLOSE) { //end of block if (p_just_one) { @@ -6375,6 +6384,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun return OK; } else if (tk.type == TK_CONST || is_token_precision(tk.type) || is_token_nonvoid_datatype(tk.type) || is_struct) { + is_var_init = true; + String struct_name = ""; if (is_struct) { struct_name = tk.text; @@ -6484,9 +6495,17 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun decl.name = name; #ifdef DEBUG_ENABLED - if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_LOCAL_VARIABLE_FLAG)) { - if (p_block && p_block->parent_function) { - StringName func_name = p_block->parent_function->name; + if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_LOCAL_VARIABLE_FLAG) && p_block) { + FunctionNode *parent_function = nullptr; + { + BlockNode *block = p_block; + while (block && !block->parent_function) { + block = block->parent_block; + } + parent_function = block->parent_function; + } + if (parent_function) { + StringName func_name = parent_function->name; if (!used_local_vars.has(func_name)) { used_local_vars.insert(func_name, Map<StringName, Usage>()); @@ -6763,14 +6782,9 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun array_size = 0; } - if (tk.type == TK_COMMA) { - if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR) { - _set_error(vformat("Multiple declarations in '%s' loop are not supported.", "for")); - return ERR_PARSE_ERROR; - } - } else if (tk.type == TK_SEMICOLON) { + if (tk.type == TK_SEMICOLON) { break; - } else { + } else if (tk.type != TK_COMMA) { _set_expected_error(",", ";"); return ERR_PARSE_ERROR; } @@ -7132,43 +7146,35 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun cf->flow_op = FLOW_OP_FOR; BlockNode *init_block = alloc_node<BlockNode>(); - init_block->block_type = BlockNode::BLOCK_TYPE_FOR; + init_block->block_type = BlockNode::BLOCK_TYPE_FOR_INIT; init_block->parent_block = p_block; init_block->single_statement = true; cf->blocks.push_back(init_block); - if (_parse_block(init_block, p_function_info, true, false, false) != OK) { - return ERR_PARSE_ERROR; - } - - Node *n = _parse_and_reduce_expression(init_block, p_function_info); - if (!n) { - return ERR_PARSE_ERROR; - } - - if (n->get_datatype() != TYPE_BOOL) { - _set_error(RTR("The middle expression is expected to be boolean.")); - return ERR_PARSE_ERROR; - } - - tk = _get_token(); - if (tk.type != TK_SEMICOLON) { - _set_expected_error(";"); - return ERR_PARSE_ERROR; + Error err = _parse_block(init_block, p_function_info, true, false, false); + if (err != OK) { + return err; } - cf->expressions.push_back(n); - - n = _parse_and_reduce_expression(init_block, p_function_info); - if (!n) { - return ERR_PARSE_ERROR; + BlockNode *condition_block = alloc_node<BlockNode>(); + condition_block->block_type = BlockNode::BLOCK_TYPE_FOR_CONDITION; + condition_block->parent_block = init_block; + condition_block->single_statement = true; + condition_block->use_comma_between_statements = true; + cf->blocks.push_back(condition_block); + err = _parse_block(condition_block, p_function_info, true, false, false); + if (err != OK) { + return err; } - cf->expressions.push_back(n); - - tk = _get_token(); - if (tk.type != TK_PARENTHESIS_CLOSE) { - _set_expected_error(")"); - return ERR_PARSE_ERROR; + BlockNode *expression_block = alloc_node<BlockNode>(); + expression_block->block_type = BlockNode::BLOCK_TYPE_FOR_EXPRESSION; + expression_block->parent_block = init_block; + expression_block->single_statement = true; + expression_block->use_comma_between_statements = true; + cf->blocks.push_back(expression_block); + err = _parse_block(expression_block, p_function_info, true, false, false); + if (err != OK) { + return err; } BlockNode *block = alloc_node<BlockNode>(); @@ -7176,8 +7182,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun cf->blocks.push_back(block); p_block->statements.push_back(cf); - Error err = _parse_block(block, p_function_info, true, true, true); - if (err) { + err = _parse_block(block, p_function_info, true, true, true); + if (err != OK) { return err; } @@ -7327,15 +7333,56 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun if (!expr) { return ERR_PARSE_ERROR; } + is_condition = expr->type == Node::TYPE_OPERATOR && expr->get_datatype() == TYPE_BOOL; + + if (expr->type == Node::TYPE_OPERATOR) { + OperatorNode *op = static_cast<OperatorNode *>(expr); + if (op->op == OP_EMPTY) { + is_var_init = true; + is_condition = true; + } + } + p_block->statements.push_back(expr); tk = _get_token(); - if (tk.type != TK_SEMICOLON) { + if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR_CONDITION) { + if (tk.type == TK_COMMA) { + if (!is_condition) { + _set_error(RTR("The middle expression is expected to be a boolean operator.")); + return ERR_PARSE_ERROR; + } + continue; + } + if (tk.type != TK_SEMICOLON) { + _set_expected_error(",", ";"); + return ERR_PARSE_ERROR; + } + } else if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR_EXPRESSION) { + if (tk.type == TK_COMMA) { + continue; + } + if (tk.type != TK_PARENTHESIS_CLOSE) { + _set_expected_error(",", ")"); + return ERR_PARSE_ERROR; + } + } else if (tk.type != TK_SEMICOLON) { _set_expected_error(";"); return ERR_PARSE_ERROR; } } + if (p_block) { + if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR_INIT && !is_var_init) { + _set_error(RTR("The left expression is expected to be a variable declaration.")); + return ERR_PARSE_ERROR; + } + if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR_CONDITION && !is_condition) { + _set_error(RTR("The middle expression is expected to be a boolean operator.")); + return ERR_PARSE_ERROR; + } + } + if (p_just_one) { break; } @@ -7470,7 +7517,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct const String smode = String(mode); - if (shader->render_modes.find(mode) != -1) { + if (shader->render_modes.has(mode)) { _set_error(vformat(RTR("Duplicated render mode: '%s'."), smode)); return ERR_PARSE_ERROR; } @@ -7483,7 +7530,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (smode.begins_with(name)) { if (!info.options.is_empty()) { - if (info.options.find(smode.substr(name.length() + 1)) != -1) { + if (info.options.has(smode.substr(name.length() + 1))) { found = true; if (defined_modes.has(name)) { @@ -7793,7 +7840,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } if (uniform) { - if (uniform_scope == ShaderNode::Uniform::SCOPE_GLOBAL) { + if (uniform_scope == ShaderNode::Uniform::SCOPE_GLOBAL && Engine::get_singleton()->is_editor_hint()) { // Type checking for global uniforms is not allowed outside the editor. //validate global uniform DataType gvtype = global_var_get_type_func(name); if (gvtype == TYPE_MAX) { @@ -7824,7 +7871,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (is_sampler_type(type)) { if (uniform_scope == ShaderNode::Uniform::SCOPE_INSTANCE) { - _set_error(vformat(RTR("Uniforms with '%s' qualifiers can't be of sampler type.", "instance"))); + _set_error(vformat(RTR("The '%s' qualifier is not supported for sampler types."), "SCOPE_INSTANCE")); return ERR_PARSE_ERROR; } uniform2.texture_order = texture_uniforms++; @@ -7840,7 +7887,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } } else { if (uniform_scope == ShaderNode::Uniform::SCOPE_INSTANCE && (type == TYPE_MAT2 || type == TYPE_MAT3 || type == TYPE_MAT4)) { - _set_error(vformat(RTR("Uniforms with '%s' qualifier can't be of matrix type.", "instance"))); + _set_error(vformat(RTR("The '%s' qualifier is not supported for matrix types."), "SCOPE_INSTANCE")); return ERR_PARSE_ERROR; } uniform2.texture_order = -1; @@ -9054,6 +9101,19 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_ } break; case COMPLETION_MAIN_FUNCTION: { for (const KeyValue<StringName, FunctionInfo> &E : p_info.functions) { + if (!E.value.main_function) { + continue; + } + bool found = false; + for (int i = 0; i < shader->functions.size(); i++) { + if (shader->functions[i].name == E.key) { + found = true; + break; + } + } + if (found) { + continue; + } ScriptCodeCompletionOption option(E.key, ScriptCodeCompletionOption::KIND_FUNCTION); r_options->push_back(option); } diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index 1307eeac2b..f39b21621d 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -504,7 +504,9 @@ public: enum BlockType { BLOCK_TYPE_STANDART, - BLOCK_TYPE_FOR, + BLOCK_TYPE_FOR_INIT, + BLOCK_TYPE_FOR_CONDITION, + BLOCK_TYPE_FOR_EXPRESSION, BLOCK_TYPE_SWITCH, BLOCK_TYPE_CASE, BLOCK_TYPE_DEFAULT, @@ -526,6 +528,7 @@ public: Map<StringName, Variable> variables; List<Node *> statements; bool single_statement = false; + bool use_comma_between_statements = false; BlockNode() : Node(TYPE_BLOCK) {} diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp index 9ae60c14cb..b8bb211a7a 100644 --- a/servers/rendering/shader_types.cpp +++ b/servers/rendering/shader_types.cpp @@ -435,7 +435,6 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["OBJECT_POSITION"] = constt(ShaderLanguage::TYPE_VEC3); shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["UVW"] = constt(ShaderLanguage::TYPE_VEC3); shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["EXTENTS"] = constt(ShaderLanguage::TYPE_VEC3); - shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4); shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["SDF"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["ALBEDO"] = ShaderLanguage::TYPE_VEC3; shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["DENSITY"] = ShaderLanguage::TYPE_FLOAT; diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 863aae6e4c..2037268134 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -933,7 +933,7 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa } } - ERR_FAIL_COND_V_MSG((bsformat & RS::ARRAY_FORMAT_BLEND_SHAPE_MASK) != (format & RS::ARRAY_FORMAT_BLEND_SHAPE_MASK), ERR_INVALID_PARAMETER, "Blend shape format must match the main array format for Vertex, Normal and Tangent arrays."); + ERR_FAIL_COND_V_MSG(bsformat != (format & RS::ARRAY_FORMAT_BLEND_SHAPE_MASK), ERR_INVALID_PARAMETER, "Blend shape format must match the main array format for Vertex, Normal and Tangent arrays."); } } @@ -1927,8 +1927,8 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(LIGHT_PARAM_MAX); BIND_ENUM_CONSTANT(LIGHT_BAKE_DISABLED); - BIND_ENUM_CONSTANT(LIGHT_BAKE_DYNAMIC); BIND_ENUM_CONSTANT(LIGHT_BAKE_STATIC); + BIND_ENUM_CONSTANT(LIGHT_BAKE_DYNAMIC); BIND_ENUM_CONSTANT(LIGHT_OMNI_SHADOW_DUAL_PARABOLOID); BIND_ENUM_CONSTANT(LIGHT_OMNI_SHADOW_CUBE); @@ -2317,7 +2317,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("environment_set_bg_energy", "env", "energy"), &RenderingServer::environment_set_bg_energy); ClassDB::bind_method(D_METHOD("environment_set_canvas_max_layer", "env", "max_layer"), &RenderingServer::environment_set_canvas_max_layer); ClassDB::bind_method(D_METHOD("environment_set_ambient_light", "env", "color", "ambient", "energy", "sky_contibution", "reflection_source"), &RenderingServer::environment_set_ambient_light, DEFVAL(RS::ENV_AMBIENT_SOURCE_BG), DEFVAL(1.0), DEFVAL(0.0), DEFVAL(RS::ENV_REFLECTION_SOURCE_BG)); - ClassDB::bind_method(D_METHOD("environment_set_glow", "env", "enable", "levels", "intensity", "strength", "mix", "bloom_threshold", "blend_mode", "hdr_bleed_threshold", "hdr_bleed_scale", "hdr_luminance_cap"), &RenderingServer::environment_set_glow); + ClassDB::bind_method(D_METHOD("environment_set_glow", "env", "enable", "levels", "intensity", "strength", "mix", "bloom_threshold", "blend_mode", "hdr_bleed_threshold", "hdr_bleed_scale", "hdr_luminance_cap", "glow_map_strength", "glow_map"), &RenderingServer::environment_set_glow); ClassDB::bind_method(D_METHOD("environment_set_tonemap", "env", "tone_mapper", "exposure", "white", "auto_exposure", "min_luminance", "max_luminance", "auto_exp_speed", "auto_exp_grey"), &RenderingServer::environment_set_tonemap); ClassDB::bind_method(D_METHOD("environment_set_adjustment", "env", "enable", "brightness", "contrast", "saturation", "use_1d_color_correction", "color_correction"), &RenderingServer::environment_set_adjustment); ClassDB::bind_method(D_METHOD("environment_set_ssr", "env", "enable", "max_steps", "fade_in", "fade_out", "depth_tolerance"), &RenderingServer::environment_set_ssr); @@ -2388,9 +2388,9 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(ENV_SSIL_QUALITY_HIGH); BIND_ENUM_CONSTANT(ENV_SSIL_QUALITY_ULTRA); - BIND_ENUM_CONSTANT(ENV_SDFGI_Y_SCALE_DISABLED); - BIND_ENUM_CONSTANT(ENV_SDFGI_Y_SCALE_75_PERCENT); BIND_ENUM_CONSTANT(ENV_SDFGI_Y_SCALE_50_PERCENT); + BIND_ENUM_CONSTANT(ENV_SDFGI_Y_SCALE_75_PERCENT); + BIND_ENUM_CONSTANT(ENV_SDFGI_Y_SCALE_100_PERCENT); BIND_ENUM_CONSTANT(ENV_SDFGI_RAY_COUNT_4); BIND_ENUM_CONSTANT(ENV_SDFGI_RAY_COUNT_8); @@ -2771,13 +2771,14 @@ void RenderingServer::mesh_add_surface_from_mesh_data(RID p_mesh, const Geometry const Geometry3D::MeshData::Face &f = p_mesh_data.faces[i]; for (int j = 2; j < f.indices.size(); j++) { -#define _ADD_VERTEX(m_idx) \ - vertices.push_back(p_mesh_data.vertices[f.indices[m_idx]]); \ - normals.push_back(f.plane.normal); + vertices.push_back(p_mesh_data.vertices[f.indices[0]]); + normals.push_back(f.plane.normal); + + vertices.push_back(p_mesh_data.vertices[f.indices[j - 1]]); + normals.push_back(f.plane.normal); - _ADD_VERTEX(0); - _ADD_VERTEX(j - 1); - _ADD_VERTEX(j); + vertices.push_back(p_mesh_data.vertices[f.indices[j]]); + normals.push_back(f.plane.normal); } } @@ -2829,12 +2830,12 @@ RenderingServer::RenderingServer() { GLOBAL_DEF("rendering/shadows/directional_shadow/size", 4096); GLOBAL_DEF("rendering/shadows/directional_shadow/size.mobile", 2048); ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/directional_shadow/size", PropertyInfo(Variant::INT, "rendering/shadows/directional_shadow/size", PROPERTY_HINT_RANGE, "256,16384")); - GLOBAL_DEF("rendering/shadows/directional_shadow/soft_shadow_quality", 3); + GLOBAL_DEF("rendering/shadows/directional_shadow/soft_shadow_quality", 2); GLOBAL_DEF("rendering/shadows/directional_shadow/soft_shadow_quality.mobile", 0); ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/directional_shadow/soft_shadow_quality", PropertyInfo(Variant::INT, "rendering/shadows/directional_shadow/soft_shadow_quality", PROPERTY_HINT_ENUM, "Hard (Fastest),Soft Very Low (Faster),Soft Low (Fast),Soft Medium (Average),Soft High (Slow),Soft Ultra (Slowest)")); GLOBAL_DEF("rendering/shadows/directional_shadow/16_bits", true); - GLOBAL_DEF("rendering/shadows/shadows/soft_shadow_quality", 3); + GLOBAL_DEF("rendering/shadows/shadows/soft_shadow_quality", 2); GLOBAL_DEF("rendering/shadows/shadows/soft_shadow_quality.mobile", 0); ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/shadows/soft_shadow_quality", PropertyInfo(Variant::INT, "rendering/shadows/shadows/soft_shadow_quality", PROPERTY_HINT_ENUM, "Hard (Fastest),Soft Very Low (Faster),Soft Low (Fast),Soft Medium (Average),Soft High (Slow),Soft Ultra (Slowest)")); @@ -2871,7 +2872,7 @@ RenderingServer::RenderingServer() { GLOBAL_DEF("rendering/global_illumination/gi/use_half_resolution", false); - GLOBAL_DEF("rendering/global_illumination/voxel_gi/quality", 1); + GLOBAL_DEF("rendering/global_illumination/voxel_gi/quality", 0); ProjectSettings::get_singleton()->set_custom_property_info("rendering/global_illumination/voxel_gi/quality", PropertyInfo(Variant::INT, "rendering/global_illumination/voxel_gi/quality", PROPERTY_HINT_ENUM, "Low (4 Cones - Fast),High (6 Cones - Slow)")); GLOBAL_DEF("rendering/shading/overrides/force_vertex_shading", false); @@ -2978,7 +2979,7 @@ RenderingServer::RenderingServer() { GLOBAL_DEF("rendering/global_illumination/sdfgi/probe_ray_count", 1); ProjectSettings::get_singleton()->set_custom_property_info("rendering/global_illumination/sdfgi/probe_ray_count", PropertyInfo(Variant::INT, "rendering/global_illumination/sdfgi/probe_ray_count", PROPERTY_HINT_ENUM, "8 (Fastest),16,32,64,96,128 (Slowest)")); - GLOBAL_DEF("rendering/global_illumination/sdfgi/frames_to_converge", 4); + GLOBAL_DEF("rendering/global_illumination/sdfgi/frames_to_converge", 5); ProjectSettings::get_singleton()->set_custom_property_info("rendering/global_illumination/sdfgi/frames_to_converge", PropertyInfo(Variant::INT, "rendering/global_illumination/sdfgi/frames_to_converge", PROPERTY_HINT_ENUM, "5 (Less Latency but Lower Quality),10,15,20,25,30 (More Latency but Higher Quality)")); GLOBAL_DEF("rendering/global_illumination/sdfgi/frames_to_update_lights", 2); ProjectSettings::get_singleton()->set_custom_property_info("rendering/global_illumination/sdfgi/frames_to_update_lights", PropertyInfo(Variant::INT, "rendering/global_illumination/sdfgi/frames_to_update_lights", PROPERTY_HINT_ENUM, "1 (Slower),2,4,8,16 (Faster)")); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 945fd052c6..5e58afe718 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -259,7 +259,7 @@ public: ARRAY_FORMAT_WEIGHTS = 1 << ARRAY_WEIGHTS, ARRAY_FORMAT_INDEX = 1 << ARRAY_INDEX, - ARRAY_FORMAT_BLEND_SHAPE_MASK = (~(ARRAY_FORMAT_COLOR | ARRAY_FORMAT_TEX_UV | ARRAY_FORMAT_TEX_UV2 | ARRAY_FORMAT_BONES | ARRAY_FORMAT_WEIGHTS | ARRAY_FORMAT_CUSTOM0 | ARRAY_FORMAT_CUSTOM1 | ARRAY_FORMAT_CUSTOM2 | ARRAY_FORMAT_CUSTOM3 | ARRAY_FORMAT_INDEX)) & 0x7FFFFFFF, + ARRAY_FORMAT_BLEND_SHAPE_MASK = ARRAY_FORMAT_VERTEX | ARRAY_FORMAT_NORMAL | ARRAY_FORMAT_TANGENT, ARRAY_FORMAT_CUSTOM_BASE = (ARRAY_INDEX + 1), ARRAY_FORMAT_CUSTOM_BITS = 3, @@ -447,8 +447,8 @@ public: enum LightBakeMode { LIGHT_BAKE_DISABLED, - LIGHT_BAKE_DYNAMIC, LIGHT_BAKE_STATIC, + LIGHT_BAKE_DYNAMIC, }; virtual void light_set_bake_mode(RID p_light, LightBakeMode p_bake_mode) = 0; @@ -473,7 +473,7 @@ public: virtual void light_directional_set_blend_splits(RID p_light, bool p_enable) = 0; virtual void light_directional_set_sky_only(RID p_light, bool p_sky_only) = 0; - virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = false) = 0; + virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) = 0; enum ShadowQuality { SHADOW_QUALITY_HARD, @@ -847,7 +847,7 @@ public: virtual void viewport_set_sdf_oversize_and_scale(RID p_viewport, ViewportSDFOversize p_oversize, ViewportSDFScale p_scale) = 0; - virtual void viewport_set_shadow_atlas_size(RID p_viewport, int p_size, bool p_16_bits = false) = 0; + virtual void viewport_set_shadow_atlas_size(RID p_viewport, int p_size, bool p_16_bits = true) = 0; virtual void viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv) = 0; enum ViewportMSAA { @@ -991,7 +991,7 @@ public: ENV_GLOW_BLEND_MODE_MIX, }; - virtual void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) = 0; + virtual void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, float p_glow_map_strength, RID p_glow_map) = 0; virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) = 0; virtual void environment_glow_set_use_high_quality(bool p_enable) = 0; @@ -1042,9 +1042,9 @@ public: virtual void environment_set_ssil_quality(EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) = 0; enum EnvironmentSDFGIYScale { - ENV_SDFGI_Y_SCALE_DISABLED, + ENV_SDFGI_Y_SCALE_50_PERCENT, ENV_SDFGI_Y_SCALE_75_PERCENT, - ENV_SDFGI_Y_SCALE_50_PERCENT + ENV_SDFGI_Y_SCALE_100_PERCENT, }; virtual void environment_set_sdfgi(RID p_env, bool p_enable, int p_cascades, float p_min_cell_size, EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) = 0; diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp index d7e7960496..3c5faa4ef7 100644 --- a/servers/text/text_server_extension.cpp +++ b/servers/text/text_server_extension.cpp @@ -210,10 +210,14 @@ void TextServerExtension::_bind_methods() { GDVIRTUAL_BIND(_shaped_text_set_preserve_control, "shaped", "enabled"); GDVIRTUAL_BIND(_shaped_text_get_preserve_control, "shaped"); - GDVIRTUAL_BIND(_shaped_text_add_string, "shaped", "text", "fonts", "size", "opentype_features", "language"); + GDVIRTUAL_BIND(_shaped_text_add_string, "shaped", "text", "fonts", "size", "opentype_features", "language", "meta"); GDVIRTUAL_BIND(_shaped_text_add_object, "shaped", "key", "size", "inline_align", "length"); GDVIRTUAL_BIND(_shaped_text_resize_object, "shaped", "key", "size", "inline_align"); + GDVIRTUAL_BIND(_shaped_get_span_count, "shaped"); + GDVIRTUAL_BIND(_shaped_get_span_meta, "shaped", "index"); + GDVIRTUAL_BIND(_shaped_set_span_update_font, "shaped", "index", "fonts", "size", "opentype_features"); + GDVIRTUAL_BIND(_shaped_text_substr, "shaped", "start", "length"); GDVIRTUAL_BIND(_shaped_text_get_parent, "shaped"); @@ -226,8 +230,8 @@ void TextServerExtension::_bind_methods() { GDVIRTUAL_BIND(_shaped_text_is_ready, "shaped"); - GDVIRTUAL_BIND(_shaped_text_get_glyphs, "shaped", "r_glyphs"); - GDVIRTUAL_BIND(_shaped_text_sort_logical, "shaped", "r_glyphs"); + GDVIRTUAL_BIND(_shaped_text_get_glyphs, "shaped"); + GDVIRTUAL_BIND(_shaped_text_sort_logical, "shaped"); GDVIRTUAL_BIND(_shaped_text_get_glyph_count, "shaped"); GDVIRTUAL_BIND(_shaped_text_get_range, "shaped"); @@ -239,7 +243,7 @@ void TextServerExtension::_bind_methods() { GDVIRTUAL_BIND(_shaped_text_get_trim_pos, "shaped"); GDVIRTUAL_BIND(_shaped_text_get_ellipsis_pos, "shaped"); GDVIRTUAL_BIND(_shaped_text_get_ellipsis_glyph_count, "shaped"); - GDVIRTUAL_BIND(_shaped_text_get_ellipsis_glyphs, "shaped", "r_glyphs"); + GDVIRTUAL_BIND(_shaped_text_get_ellipsis_glyphs, "shaped"); GDVIRTUAL_BIND(_shaped_text_overrun_trim_to_width, "shaped", "width", "trim_flags"); @@ -501,7 +505,7 @@ void TextServerExtension::font_set_hinting(RID p_font_rid, TextServer::Hinting p } TextServer::Hinting TextServerExtension::font_get_hinting(RID p_font_rid) const { - int ret; + TextServer::Hinting ret; if (GDVIRTUAL_CALL(_font_get_hinting, p_font_rid, ret)) { return (TextServer::Hinting)ret; } @@ -951,7 +955,7 @@ void TextServerExtension::shaped_text_set_direction(RID p_shaped, TextServer::Di } TextServer::Direction TextServerExtension::shaped_text_get_direction(RID p_shaped) const { - int ret; + TextServer::Direction ret; if (GDVIRTUAL_CALL(_shaped_text_get_direction, p_shaped, ret)) { return (TextServer::Direction)ret; } @@ -959,7 +963,7 @@ TextServer::Direction TextServerExtension::shaped_text_get_direction(RID p_shape } TextServer::Direction TextServerExtension::shaped_text_get_inferred_direction(RID p_shaped) const { - int ret; + TextServer::Direction ret; if (GDVIRTUAL_CALL(_shaped_text_get_inferred_direction, p_shaped, ret)) { return (TextServer::Direction)ret; } @@ -971,7 +975,7 @@ void TextServerExtension::shaped_text_set_orientation(RID p_shaped, TextServer:: } TextServer::Orientation TextServerExtension::shaped_text_get_orientation(RID p_shaped) const { - int ret; + TextServer::Orientation ret; if (GDVIRTUAL_CALL(_shaped_text_get_orientation, p_shaped, ret)) { return (TextServer::Orientation)ret; } @@ -1018,13 +1022,13 @@ bool TextServerExtension::shaped_text_get_preserve_control(RID p_shaped) const { return false; } -bool TextServerExtension::shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language) { +bool TextServerExtension::shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) { bool ret; Array fonts; for (int i = 0; i < p_fonts.size(); i++) { fonts.push_back(p_fonts[i]); } - if (GDVIRTUAL_CALL(_shaped_text_add_string, p_shaped, p_text, fonts, p_size, p_opentype_features, p_language, ret)) { + if (GDVIRTUAL_CALL(_shaped_text_add_string, p_shaped, p_text, fonts, p_size, p_opentype_features, p_language, p_meta, ret)) { return ret; } return false; @@ -1046,6 +1050,30 @@ bool TextServerExtension::shaped_text_resize_object(RID p_shaped, Variant p_key, return false; } +int TextServerExtension::shaped_get_span_count(RID p_shaped) const { + int ret; + if (GDVIRTUAL_CALL(_shaped_get_span_count, p_shaped, ret)) { + return ret; + } + return 0; +} + +Variant TextServerExtension::shaped_get_span_meta(RID p_shaped, int p_index) const { + Variant ret; + if (GDVIRTUAL_CALL(_shaped_get_span_meta, p_shaped, p_index, ret)) { + return ret; + } + return false; +} + +void TextServerExtension::shaped_set_span_update_font(RID p_shaped, int p_index, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features) { + Array fonts; + for (int i = 0; i < p_fonts.size(); i++) { + fonts.push_back(p_fonts[i]); + } + GDVIRTUAL_CALL(_shaped_set_span_update_font, p_shaped, p_index, fonts, p_size, p_opentype_features); +} + RID TextServerExtension::shaped_text_substr(RID p_shaped, int p_start, int p_length) const { RID ret; if (GDVIRTUAL_CALL(_shaped_text_substr, p_shaped, p_start, p_length, ret)) { @@ -1111,16 +1139,16 @@ bool TextServerExtension::shaped_text_is_ready(RID p_shaped) const { } const Glyph *TextServerExtension::shaped_text_get_glyphs(RID p_shaped) const { - const Glyph *ret; - if (GDVIRTUAL_CALL(_shaped_text_get_glyphs, p_shaped, &ret)) { + GDNativePtr<Glyph> ret; + if (GDVIRTUAL_CALL(_shaped_text_get_glyphs, p_shaped, ret)) { return ret; } return nullptr; } const Glyph *TextServerExtension::shaped_text_sort_logical(RID p_shaped) { - const Glyph *ret; - if (GDVIRTUAL_CALL(_shaped_text_sort_logical, p_shaped, &ret)) { + GDNativePtr<Glyph> ret; + if (GDVIRTUAL_CALL(_shaped_text_sort_logical, p_shaped, ret)) { return ret; } return nullptr; @@ -1183,8 +1211,8 @@ int TextServerExtension::shaped_text_get_ellipsis_pos(RID p_shaped) const { } const Glyph *TextServerExtension::shaped_text_get_ellipsis_glyphs(RID p_shaped) const { - const Glyph *ret; - if (GDVIRTUAL_CALL(_shaped_text_get_ellipsis_glyphs, p_shaped, &ret)) { + GDNativePtr<Glyph> ret; + if (GDVIRTUAL_CALL(_shaped_text_get_ellipsis_glyphs, p_shaped, ret)) { return ret; } return nullptr; diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h index 6e203f22ee..9e7f666be1 100644 --- a/servers/text/text_server_extension.h +++ b/servers/text/text_server_extension.h @@ -132,7 +132,7 @@ public: virtual void font_set_hinting(RID p_font_rid, Hinting p_hinting) override; virtual Hinting font_get_hinting(RID p_font_rid) const override; GDVIRTUAL2(_font_set_hinting, RID, Hinting); - GDVIRTUAL1RC(/*Hinting*/ int, _font_get_hinting, RID); + GDVIRTUAL1RC(Hinting, _font_get_hinting, RID); virtual void font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) override; virtual Dictionary font_get_variation_coordinates(RID p_font_rid) const override; @@ -317,8 +317,8 @@ public: virtual Direction shaped_text_get_direction(RID p_shaped) const override; virtual Direction shaped_text_get_inferred_direction(RID p_shaped) const override; GDVIRTUAL2(_shaped_text_set_direction, RID, Direction); - GDVIRTUAL1RC(/*Direction*/ int, _shaped_text_get_direction, RID); - GDVIRTUAL1RC(/*Direction*/ int, _shaped_text_get_inferred_direction, RID); + GDVIRTUAL1RC(Direction, _shaped_text_get_direction, RID); + GDVIRTUAL1RC(Direction, _shaped_text_get_inferred_direction, RID); virtual void shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) override; GDVIRTUAL2(_shaped_text_set_bidi_override, RID, const Array &); @@ -331,7 +331,7 @@ public: virtual void shaped_text_set_orientation(RID p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override; virtual Orientation shaped_text_get_orientation(RID p_shaped) const override; GDVIRTUAL2(_shaped_text_set_orientation, RID, Orientation); - GDVIRTUAL1RC(/*Orientation*/ int, _shaped_text_get_orientation, RID); + GDVIRTUAL1RC(Orientation, _shaped_text_get_orientation, RID); virtual void shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) override; virtual bool shaped_text_get_preserve_invalid(RID p_shaped) const override; @@ -343,13 +343,20 @@ public: GDVIRTUAL2(_shaped_text_set_preserve_control, RID, bool); GDVIRTUAL1RC(bool, _shaped_text_get_preserve_control, RID); - virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "") override; + virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant()) override; virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int p_length = 1) override; virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER) override; - GDVIRTUAL6R(bool, _shaped_text_add_string, RID, const String &, const Array &, int, const Dictionary &, const String &); + GDVIRTUAL7R(bool, _shaped_text_add_string, RID, const String &, const Array &, int, const Dictionary &, const String &, const Variant &); GDVIRTUAL5R(bool, _shaped_text_add_object, RID, Variant, const Size2 &, InlineAlignment, int); GDVIRTUAL4R(bool, _shaped_text_resize_object, RID, Variant, const Size2 &, InlineAlignment); + virtual int shaped_get_span_count(RID p_shaped) const override; + virtual Variant shaped_get_span_meta(RID p_shaped, int p_index) const override; + virtual void shaped_set_span_update_font(RID p_shaped, int p_index, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary()) override; + GDVIRTUAL1RC(int, _shaped_get_span_count, RID); + GDVIRTUAL2RC(Variant, _shaped_get_span_meta, RID, int); + GDVIRTUAL5(_shaped_set_span_update_font, RID, int, const Array &, int, const Dictionary &); + virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override; virtual RID shaped_text_get_parent(RID p_shaped) const override; GDVIRTUAL3RC(RID, _shaped_text_substr, RID, int, int); @@ -373,8 +380,8 @@ public: virtual const Glyph *shaped_text_get_glyphs(RID p_shaped) const override; virtual const Glyph *shaped_text_sort_logical(RID p_shaped) override; virtual int shaped_text_get_glyph_count(RID p_shaped) const override; - GDVIRTUAL2C(_shaped_text_get_glyphs, RID, GDNativePtr<const Glyph *>); - GDVIRTUAL2(_shaped_text_sort_logical, RID, GDNativePtr<const Glyph *>); + GDVIRTUAL1RC(GDNativePtr<Glyph>, _shaped_text_get_glyphs, RID); + GDVIRTUAL1R(GDNativePtr<Glyph>, _shaped_text_sort_logical, RID); GDVIRTUAL1RC(int, _shaped_text_get_glyph_count, RID); virtual Vector2i shaped_text_get_range(RID p_shaped) const override; @@ -393,7 +400,7 @@ public: virtual int shaped_text_get_ellipsis_glyph_count(RID p_shaped) const override; GDVIRTUAL1RC(int, _shaped_text_get_trim_pos, RID); GDVIRTUAL1RC(int, _shaped_text_get_ellipsis_pos, RID); - GDVIRTUAL2C(_shaped_text_get_ellipsis_glyphs, RID, GDNativePtr<const Glyph *>); + GDVIRTUAL1RC(GDNativePtr<Glyph>, _shaped_text_get_ellipsis_glyphs, RID); GDVIRTUAL1RC(int, _shaped_text_get_ellipsis_glyph_count, RID); virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint16_t p_trim_flags) override; diff --git a/servers/text_server.cpp b/servers/text_server.cpp index 17840584ee..b7cd39b9b2 100644 --- a/servers/text_server.cpp +++ b/servers/text_server.cpp @@ -363,10 +363,14 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("shaped_text_set_preserve_control", "shaped", "enabled"), &TextServer::shaped_text_set_preserve_control); ClassDB::bind_method(D_METHOD("shaped_text_get_preserve_control", "shaped"), &TextServer::shaped_text_get_preserve_control); - ClassDB::bind_method(D_METHOD("shaped_text_add_string", "shaped", "text", "fonts", "size", "opentype_features", "language"), &TextServer::shaped_text_add_string, DEFVAL(Dictionary()), DEFVAL("")); + ClassDB::bind_method(D_METHOD("shaped_text_add_string", "shaped", "text", "fonts", "size", "opentype_features", "language", "meta"), &TextServer::shaped_text_add_string, DEFVAL(Dictionary()), DEFVAL(""), DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("shaped_text_add_object", "shaped", "key", "size", "inline_align", "length"), &TextServer::shaped_text_add_object, DEFVAL(INLINE_ALIGNMENT_CENTER), DEFVAL(1)); ClassDB::bind_method(D_METHOD("shaped_text_resize_object", "shaped", "key", "size", "inline_align"), &TextServer::shaped_text_resize_object, DEFVAL(INLINE_ALIGNMENT_CENTER)); + ClassDB::bind_method(D_METHOD("shaped_get_span_count", "shaped"), &TextServer::shaped_get_span_count); + ClassDB::bind_method(D_METHOD("shaped_get_span_meta", "shaped", "index"), &TextServer::shaped_get_span_meta); + ClassDB::bind_method(D_METHOD("shaped_set_span_update_font", "shaped", "index", "fonts", "size", "opentype_features"), &TextServer::shaped_set_span_update_font, DEFVAL(Dictionary())); + ClassDB::bind_method(D_METHOD("shaped_text_substr", "shaped", "start", "length"), &TextServer::shaped_text_substr); ClassDB::bind_method(D_METHOD("shaped_text_get_parent", "shaped"), &TextServer::shaped_text_get_parent); ClassDB::bind_method(D_METHOD("shaped_text_fit_to_width", "shaped", "width", "jst_flags"), &TextServer::shaped_text_fit_to_width, DEFVAL(JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA)); diff --git a/servers/text_server.h b/servers/text_server.h index 599cc3afd0..629a633b9f 100644 --- a/servers/text_server.h +++ b/servers/text_server.h @@ -155,20 +155,6 @@ protected: TextServer::Direction direction = DIRECTION_LTR; // Desired text direction. TextServer::Orientation orientation = ORIENTATION_HORIZONTAL; - struct Span { - int start = -1; - int end = -1; - - Vector<RID> fonts; - int font_size = 0; - - Variant embedded_key; - - String language; - Dictionary features; - }; - Vector<Span> spans; - struct EmbeddedObject { int pos = 0; InlineAlignment inline_align = INLINE_ALIGNMENT_CENTER; @@ -387,10 +373,14 @@ public: virtual void shaped_text_set_preserve_control(RID p_shaped, bool p_enabled) = 0; virtual bool shaped_text_get_preserve_control(RID p_shaped) const = 0; - virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "") = 0; + virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant()) = 0; virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int p_length = 1) = 0; virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER) = 0; + virtual int shaped_get_span_count(RID p_shaped) const = 0; + virtual Variant shaped_get_span_meta(RID p_shaped, int p_index) const = 0; + virtual void shaped_set_span_update_font(RID p_shaped, int p_index, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary()) = 0; + virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const = 0; // Copy shaped substring (e.g. line break) without reshaping, but correctly reordered, preservers range. virtual RID shaped_text_get_parent(RID p_shaped) const = 0; @@ -567,7 +557,6 @@ VARIANT_ENUM_CAST(TextServer::SpacingType); VARIANT_ENUM_CAST(TextServer::FontStyle); GDVIRTUAL_NATIVE_PTR(Glyph); -GDVIRTUAL_NATIVE_PTR(Glyph *); GDVIRTUAL_NATIVE_PTR(CaretInfo); #endif // TEXT_SERVER_H diff --git a/servers/xr/xr_interface.cpp b/servers/xr/xr_interface.cpp index 758f2416ec..7ae111b5e7 100644 --- a/servers/xr/xr_interface.cpp +++ b/servers/xr/xr_interface.cpp @@ -168,8 +168,5 @@ XRInterface::TrackingStatus XRInterface::get_tracking_status() const { return XR_UNKNOWN_TRACKING; } -void XRInterface::notification(int p_what) { -} - void XRInterface::trigger_haptic_pulse(const String &p_action_name, const StringName &p_tracker_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec) { } diff --git a/servers/xr/xr_interface.h b/servers/xr/xr_interface.h index aee98f8fee..6e105ffc26 100644 --- a/servers/xr/xr_interface.h +++ b/servers/xr/xr_interface.h @@ -123,10 +123,13 @@ public: // note, external color/depth/vrs texture support will be added here soon. - virtual Vector<BlitToScreen> commit_views(RID p_render_target, const Rect2 &p_screen_rect) = 0; /* commit rendered views to the XR interface */ - virtual void process() = 0; - virtual void notification(int p_what); + virtual void pre_render(){}; + virtual bool pre_draw_viewport(RID p_render_target) { return true; }; /* inform XR interface we are about to start our viewport draw process */ + virtual Vector<BlitToScreen> post_draw_viewport(RID p_render_target, const Rect2 &p_screen_rect) = 0; /* inform XR interface we finished our viewport draw process */ + virtual void end_frame(){}; + + virtual void notification(int p_what){}; XRInterface(); ~XRInterface(); diff --git a/servers/xr/xr_interface_extension.cpp b/servers/xr/xr_interface_extension.cpp index 9dae3b162d..18131c1e89 100644 --- a/servers/xr/xr_interface_extension.cpp +++ b/servers/xr/xr_interface_extension.cpp @@ -52,9 +52,12 @@ void XRInterfaceExtension::_bind_methods() { GDVIRTUAL_BIND(_get_transform_for_view, "view", "cam_transform"); GDVIRTUAL_BIND(_get_projection_for_view, "view", "aspect", "z_near", "z_far"); - GDVIRTUAL_BIND(_commit_views, "render_target", "screen_rect"); - GDVIRTUAL_BIND(_process); + GDVIRTUAL_BIND(_pre_render); + GDVIRTUAL_BIND(_pre_draw_viewport, "render_target"); + GDVIRTUAL_BIND(_post_draw_viewport, "render_target", "screen_rect"); + GDVIRTUAL_BIND(_end_frame); + GDVIRTUAL_BIND(_notification, "what"); /** input and output **/ @@ -274,7 +277,7 @@ CameraMatrix XRInterfaceExtension::get_projection_for_view(uint32_t p_view, doub void XRInterfaceExtension::add_blit(RID p_render_target, Rect2 p_src_rect, Rect2i p_dst_rect, bool p_use_layer, uint32_t p_layer, bool p_apply_lens_distortion, Vector2 p_eye_center, double p_k1, double p_k2, double p_upscale, double p_aspect_ratio) { BlitToScreen blit; - ERR_FAIL_COND_MSG(!can_add_blits, "add_blit can only be called from an XR plugin from within _commit_views!"); + ERR_FAIL_COND_MSG(!can_add_blits, "add_blit can only be called from an XR plugin from within _post_draw_viewport!"); blit.render_target = p_render_target; blit.src_rect = p_src_rect; @@ -293,12 +296,31 @@ void XRInterfaceExtension::add_blit(RID p_render_target, Rect2 p_src_rect, Rect2 blits.push_back(blit); } -Vector<BlitToScreen> XRInterfaceExtension::commit_views(RID p_render_target, const Rect2 &p_screen_rect) { +void XRInterfaceExtension::process() { + GDVIRTUAL_CALL(_process); +} + +void XRInterfaceExtension::pre_render() { + GDVIRTUAL_CALL(_pre_render); +} + +bool XRInterfaceExtension::pre_draw_viewport(RID p_render_target) { + bool do_render = true; + + if (GDVIRTUAL_CALL(_pre_draw_viewport, p_render_target, do_render)) { + return do_render; + } else { + // if not implemented we're returning true + return true; + } +} + +Vector<BlitToScreen> XRInterfaceExtension::post_draw_viewport(RID p_render_target, const Rect2 &p_screen_rect) { // This is just so our XR plugin can add blits... blits.clear(); can_add_blits = true; - if (GDVIRTUAL_CALL(_commit_views, p_render_target, p_screen_rect)) { + if (GDVIRTUAL_CALL(_post_draw_viewport, p_render_target, p_screen_rect)) { return blits; } @@ -306,8 +328,8 @@ Vector<BlitToScreen> XRInterfaceExtension::commit_views(RID p_render_target, con return blits; } -void XRInterfaceExtension::process() { - GDVIRTUAL_CALL(_process); +void XRInterfaceExtension::end_frame() { + GDVIRTUAL_CALL(_end_frame); } void XRInterfaceExtension::notification(int p_what) { diff --git a/servers/xr/xr_interface_extension.h b/servers/xr/xr_interface_extension.h index e22ec2b872..5a436b9fd0 100644 --- a/servers/xr/xr_interface_extension.h +++ b/servers/xr/xr_interface_extension.h @@ -109,13 +109,20 @@ public: GDVIRTUAL4R(PackedFloat64Array, _get_projection_for_view, uint32_t, double, double, double); void add_blit(RID p_render_target, Rect2 p_src_rect, Rect2i p_dst_rect, bool p_use_layer = false, uint32_t p_layer = 0, bool p_apply_lens_distortion = false, Vector2 p_eye_center = Vector2(), double p_k1 = 0.0, double p_k2 = 0.0, double p_upscale = 1.0, double p_aspect_ratio = 1.0); - virtual Vector<BlitToScreen> commit_views(RID p_render_target, const Rect2 &p_screen_rect) override; - GDVIRTUAL2(_commit_views, RID, const Rect2 &); virtual void process() override; + virtual void pre_render() override; + virtual bool pre_draw_viewport(RID p_render_target) override; + virtual Vector<BlitToScreen> post_draw_viewport(RID p_render_target, const Rect2 &p_screen_rect) override; + virtual void end_frame() override; virtual void notification(int p_what) override; GDVIRTUAL0(_process); + GDVIRTUAL0(_pre_render); + GDVIRTUAL1R(bool, _pre_draw_viewport, RID); + GDVIRTUAL2(_post_draw_viewport, RID, const Rect2 &); + GDVIRTUAL0(_end_frame); + GDVIRTUAL1(_notification, int); /* access to some internals we need */ diff --git a/servers/xr/xr_positional_tracker.cpp b/servers/xr/xr_positional_tracker.cpp index 62e011654e..7b21eeba04 100644 --- a/servers/xr/xr_positional_tracker.cpp +++ b/servers/xr/xr_positional_tracker.cpp @@ -149,7 +149,7 @@ void XRPositionalTracker::set_pose(const StringName &p_action_name, const Transf new_pose->set_tracking_confidence(p_tracking_confidence); poses[p_action_name] = new_pose; - emit_signal("pose_changed", new_pose); + emit_signal(SNAME("pose_changed"), new_pose); // TODO discuss whether we also want to create and emit an InputEventXRPose event } @@ -182,20 +182,20 @@ void XRPositionalTracker::set_input(const StringName &p_action_name, const Varia case Variant::BOOL: { bool pressed = p_value; if (pressed) { - emit_signal("button_pressed", p_action_name); + emit_signal(SNAME("button_pressed"), p_action_name); } else { - emit_signal("button_released", p_action_name); + emit_signal(SNAME("button_released"), p_action_name); } // TODO discuss whether we also want to create and emit an InputEventXRButton event } break; case Variant::FLOAT: { - emit_signal("input_value_changed", p_action_name, p_value); + emit_signal(SNAME("input_value_changed"), p_action_name, p_value); // TODO discuss whether we also want to create and emit an InputEventXRValue event } break; case Variant::VECTOR2: { - emit_signal("input_axis_changed", p_action_name, p_value); + emit_signal(SNAME("input_axis_changed"), p_action_name, p_value); // TODO discuss whether we also want to create and emit an InputEventXRAxis event } break; diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp index 69f4c69b53..dbfe76a127 100644 --- a/servers/xr_server.cpp +++ b/servers/xr_server.cpp @@ -65,10 +65,6 @@ void XRServer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "primary_interface"), "set_primary_interface", "get_primary_interface"); - ClassDB::bind_method(D_METHOD("get_last_process_usec"), &XRServer::get_last_process_usec); - ClassDB::bind_method(D_METHOD("get_last_commit_usec"), &XRServer::get_last_commit_usec); - ClassDB::bind_method(D_METHOD("get_last_frame_usec"), &XRServer::get_last_frame_usec); - BIND_ENUM_CONSTANT(TRACKER_HEAD); BIND_ENUM_CONSTANT(TRACKER_CONTROLLER); BIND_ENUM_CONSTANT(TRACKER_BASESTATION); @@ -351,24 +347,9 @@ PackedStringArray XRServer::get_suggested_pose_names(const StringName &p_tracker return arr; } -uint64_t XRServer::get_last_process_usec() { - return last_process_usec; -}; - -uint64_t XRServer::get_last_commit_usec() { - return last_commit_usec; -}; - -uint64_t XRServer::get_last_frame_usec() { - return last_frame_usec; -}; - void XRServer::_process() { /* called from renderer_viewport.draw_viewports right before we start drawing our viewports */ - /* mark for our frame timing */ - last_process_usec = OS::get_singleton()->get_ticks_usec(); - /* process all active interfaces */ for (int i = 0; i < interfaces.size(); i++) { if (!interfaces[i].is_valid()) { @@ -379,13 +360,32 @@ void XRServer::_process() { }; }; -void XRServer::_mark_commit() { - /* time this */ - last_commit_usec = OS::get_singleton()->get_ticks_usec(); +void XRServer::pre_render() { + // called from RendererViewport.draw_viewports right before we start drawing our viewports + // note that we can have multiple interfaces active if we have interfaces that purely handle tracking - /* now store our difference as we may overwrite last_process_usec before this is accessed */ - last_frame_usec = last_commit_usec - last_process_usec; -}; + // process all active interfaces + for (int i = 0; i < interfaces.size(); i++) { + if (!interfaces[i].is_valid()) { + // ignore, not a valid reference + } else if (interfaces[i]->is_initialized()) { + interfaces.write[i]->pre_render(); + }; + }; +} + +void XRServer::end_frame() { + // called from RenderingServerDefault after Vulkan queues have been submitted + + // process all active interfaces + for (int i = 0; i < interfaces.size(); i++) { + if (!interfaces[i].is_valid()) { + // ignore, not a valid reference + } else if (interfaces[i]->is_initialized()) { + interfaces.write[i]->end_frame(); + }; + }; +} XRServer::XRServer() { singleton = this; diff --git a/servers/xr_server.h b/servers/xr_server.h index a820634bd9..d9188d2de1 100644 --- a/servers/xr_server.h +++ b/servers/xr_server.h @@ -84,10 +84,6 @@ private: Transform3D world_origin; /* our world origin point, maps a location in our virtual world to the origin point in our real world tracking volume */ Transform3D reference_frame; /* our reference frame */ - uint64_t last_process_usec; /* for frame timing, usec when we did our processing */ - uint64_t last_commit_usec; /* for frame timing, usec when we finished committing both eyes */ - uint64_t last_frame_usec; /* time it took between process and committing, we should probably average this over the last x frames */ - protected: static XRServer *singleton; @@ -175,12 +171,16 @@ public: PackedStringArray get_suggested_pose_names(const StringName &p_tracker_name) const; // Q: Should we add get_suggested_input_names and get_suggested_haptic_names even though we don't use them for the IDE? - uint64_t get_last_process_usec(); - uint64_t get_last_commit_usec(); - uint64_t get_last_frame_usec(); - + // Process is called before we handle our physics process and game process. This is where our interfaces will update controller data and such. void _process(); - void _mark_commit(); + + // Pre-render is called right before we're rendering our viewports. + // This is where interfaces such as OpenVR and OpenXR will update positioning data. + // Many of these interfaces will also do a predictive sync which ensures we run at a steady framerate. + void pre_render(); + + // End-frame is called right after Godot has finished its rendering bits. + void end_frame(); XRServer(); ~XRServer(); |