diff options
Diffstat (limited to 'servers')
29 files changed, 575 insertions, 67 deletions
diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp index dc54e01ec8..0dc6d16050 100644 --- a/servers/audio/audio_stream.cpp +++ b/servers/audio/audio_stream.cpp @@ -90,6 +90,10 @@ Variant AudioStreamPlayback::get_parameter(const StringName &p_name) const { return ret; } +Ref<AudioSamplePlayback> AudioStreamPlayback::get_sample_playback() const { + return nullptr; +} + void AudioStreamPlayback::_bind_methods() { GDVIRTUAL_BIND(_start, "from_pos") GDVIRTUAL_BIND(_stop) @@ -101,6 +105,17 @@ void AudioStreamPlayback::_bind_methods() { GDVIRTUAL_BIND(_tag_used_streams); GDVIRTUAL_BIND(_set_parameter, "name", "value"); GDVIRTUAL_BIND(_get_parameter, "name"); + + ClassDB::bind_method(D_METHOD("set_sample_playback", "playback_sample"), &AudioStreamPlayback::set_sample_playback); + ClassDB::bind_method(D_METHOD("get_sample_playback"), &AudioStreamPlayback::get_sample_playback); +} + +AudioStreamPlayback::AudioStreamPlayback() {} + +AudioStreamPlayback::~AudioStreamPlayback() { + if (get_sample_playback().is_valid() && likely(AudioServer::get_singleton() != nullptr)) { + AudioServer::get_singleton()->stop_sample_playback(get_sample_playback()); + } } ////////////////////////////// @@ -271,10 +286,22 @@ void AudioStream::get_parameter_list(List<Parameter> *r_parameters) { } } +Ref<AudioSample> AudioStream::generate_sample() const { + ERR_FAIL_COND_V_MSG(!can_be_sampled(), nullptr, "Cannot generate a sample for a stream that cannot be sampled."); + Ref<AudioSample> sample; + sample.instantiate(); + sample->stream = this; + return sample; +} + void AudioStream::_bind_methods() { ClassDB::bind_method(D_METHOD("get_length"), &AudioStream::get_length); ClassDB::bind_method(D_METHOD("is_monophonic"), &AudioStream::is_monophonic); ClassDB::bind_method(D_METHOD("instantiate_playback"), &AudioStream::instantiate_playback); + ClassDB::bind_method(D_METHOD("can_be_sampled"), &AudioStream::can_be_sampled); + ClassDB::bind_method(D_METHOD("generate_sample"), &AudioStream::generate_sample); + ClassDB::bind_method(D_METHOD("is_meta_stream"), &AudioStream::is_meta_stream); + GDVIRTUAL_BIND(_instantiate_playback); GDVIRTUAL_BIND(_get_stream_name); GDVIRTUAL_BIND(_get_length); diff --git a/servers/audio/audio_stream.h b/servers/audio/audio_stream.h index aa1ad4cc3a..0ca4777d5c 100644 --- a/servers/audio/audio_stream.h +++ b/servers/audio/audio_stream.h @@ -43,6 +43,39 @@ class AudioStream; +class AudioSamplePlayback : public RefCounted { + GDCLASS(AudioSamplePlayback, RefCounted); + +public: + Ref<AudioStream> stream; + + float offset = 0.0f; + Vector<AudioFrame> volume_vector; + StringName bus; +}; + +class AudioSample : public RefCounted { + GDCLASS(AudioSample, RefCounted) + +public: + enum LoopMode { + LOOP_DISABLED, + LOOP_FORWARD, + LOOP_PINGPONG, + LOOP_BACKWARD, + }; + + Ref<AudioStream> stream; + Vector<AudioFrame> data; + int num_channels = 1; + int sample_rate = 44100; + LoopMode loop_mode = LOOP_DISABLED; + int loop_begin = 0; + int loop_end = 0; +}; + +/////////// + class AudioStreamPlayback : public RefCounted { GDCLASS(AudioStreamPlayback, RefCounted); @@ -75,6 +108,14 @@ public: virtual Variant get_parameter(const StringName &p_name) const; virtual int mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames); + + virtual void set_is_sample(bool p_is_sample) {} + virtual bool get_is_sample() const { return false; } + virtual Ref<AudioSamplePlayback> get_sample_playback() const; + virtual void set_sample_playback(const Ref<AudioSamplePlayback> &p_playback) {} + + AudioStreamPlayback(); + ~AudioStreamPlayback(); }; class AudioStreamPlaybackResampled : public AudioStreamPlayback { @@ -161,6 +202,11 @@ public: }; virtual void get_parameter_list(List<Parameter> *r_parameters); + + virtual bool can_be_sampled() const { return false; } + virtual Ref<AudioSample> generate_sample() const; + + virtual bool is_meta_stream() const { return false; } }; // Microphone @@ -292,6 +338,8 @@ public: virtual double get_length() const override; //if supported, otherwise return 0 virtual bool is_monophonic() const override; + virtual bool is_meta_stream() const override { return true; } + AudioStreamRandomizer(); }; diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index d37836ed96..fefb8bfd41 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -120,16 +120,18 @@ int AudioDriver::_get_configured_mix_rate() { StringName audio_driver_setting = "audio/driver/mix_rate"; int mix_rate = GLOBAL_GET(audio_driver_setting); +#ifdef WEB_ENABLED + // `0` is an acceptable value (resorts to the browser's default). + return MAX(0, mix_rate); +#else // !WEB_ENABLED // In the case of invalid mix rate, let's default to a sensible value.. if (mix_rate <= 0) { -#ifndef WEB_ENABLED WARN_PRINT(vformat("Invalid mix rate of %d, consider reassigning setting \'%s\'. \nDefaulting mix rate to value %d.", mix_rate, audio_driver_setting, AudioDriverManager::DEFAULT_MIX_RATE)); -#endif mix_rate = AudioDriverManager::DEFAULT_MIX_RATE; } - return mix_rate; +#endif } AudioDriver::SpeakerMode AudioDriver::get_speaker_mode_by_total_channels(int p_channels) const { @@ -181,6 +183,18 @@ PackedStringArray AudioDriver::get_input_device_list() { return list; } +void AudioDriver::start_sample_playback(const Ref<AudioSamplePlayback> &p_playback) { + if (p_playback.is_valid()) { + if (p_playback->stream.is_valid()) { + WARN_PRINT_ED(vformat(R"(Trying to play stream (%s) as a sample (%s), but the driver doesn't support sample playback.)", p_playback->get_instance_id(), p_playback->stream->get_instance_id())); + } else { + WARN_PRINT_ED(vformat(R"(Trying to play stream (%s) as a null sample, but the driver doesn't support sample playback.)", p_playback->get_instance_id())); + } + } else { + WARN_PRINT_ED("Trying to play a null sample playback from a driver that don't support sample playback."); + } +} + AudioDriverDummy AudioDriverManager::dummy_driver; AudioDriver *AudioDriverManager::drivers[MAX_DRIVERS] = { &AudioDriverManager::dummy_driver, @@ -367,6 +381,10 @@ void AudioServer::_mix_step() { continue; } + if (playback->stream_playback->get_is_sample()) { + continue; + } + bool fading_out = playback->state.load() == AudioStreamPlaybackListNode::FADE_OUT_TO_DELETION || playback->state.load() == AudioStreamPlaybackListNode::FADE_OUT_TO_PAUSE; AudioFrame *buf = mix_buffer.ptrw(); @@ -770,6 +788,8 @@ void AudioServer::set_bus_count(int p_count) { unlock(); + AudioDriver::get_singleton()->set_sample_bus_count(p_count); + emit_signal(SNAME("bus_layout_changed")); } @@ -785,6 +805,8 @@ void AudioServer::remove_bus(int p_index) { buses.remove_at(p_index); unlock(); + AudioDriver::get_singleton()->remove_sample_bus(p_index); + emit_signal(SNAME("bus_layout_changed")); } @@ -839,6 +861,8 @@ void AudioServer::add_bus(int p_at_pos) { buses.insert(p_at_pos, bus); } + AudioDriver::get_singleton()->add_sample_bus(p_at_pos); + emit_signal(SNAME("bus_layout_changed")); } @@ -863,6 +887,8 @@ void AudioServer::move_bus(int p_bus, int p_to_pos) { buses.insert(p_to_pos - 1, bus); } + AudioDriver::get_singleton()->move_sample_bus(p_bus, p_to_pos); + emit_signal(SNAME("bus_layout_changed")); } @@ -934,6 +960,8 @@ void AudioServer::set_bus_volume_db(int p_bus, float p_volume_db) { MARK_EDITED buses[p_bus]->volume_db = p_volume_db; + + AudioDriver::get_singleton()->set_sample_bus_volume_db(p_bus, p_volume_db); } float AudioServer::get_bus_volume_db(int p_bus) const { @@ -952,6 +980,8 @@ void AudioServer::set_bus_send(int p_bus, const StringName &p_send) { MARK_EDITED buses[p_bus]->send = p_send; + + AudioDriver::get_singleton()->set_sample_bus_send(p_bus, p_send); } StringName AudioServer::get_bus_send(int p_bus) const { @@ -965,6 +995,8 @@ void AudioServer::set_bus_solo(int p_bus, bool p_enable) { MARK_EDITED buses[p_bus]->solo = p_enable; + + AudioDriver::get_singleton()->set_sample_bus_solo(p_bus, p_enable); } bool AudioServer::is_bus_solo(int p_bus) const { @@ -979,6 +1011,8 @@ void AudioServer::set_bus_mute(int p_bus, bool p_enable) { MARK_EDITED buses[p_bus]->mute = p_enable; + + AudioDriver::get_singleton()->set_sample_bus_mute(p_bus, p_enable); } bool AudioServer::is_bus_mute(int p_bus) const { @@ -1214,6 +1248,13 @@ void AudioServer::set_playback_bus_exclusive(Ref<AudioStreamPlayback> p_playback void AudioServer::set_playback_bus_volumes_linear(Ref<AudioStreamPlayback> p_playback, const HashMap<StringName, Vector<AudioFrame>> &p_bus_volumes) { ERR_FAIL_COND(p_bus_volumes.size() > MAX_BUSES_PER_PLAYBACK); + // Samples. + if (p_playback->get_is_sample() && p_playback->get_sample_playback().is_valid()) { + Ref<AudioSamplePlayback> sample_playback = p_playback->get_sample_playback(); + AudioDriver::get_singleton()->set_sample_playback_bus_volumes_linear(sample_playback, p_bus_volumes); + return; + } + AudioStreamPlaybackListNode *playback_node = _find_playback_list_node(p_playback); if (!playback_node) { return; @@ -1265,6 +1306,13 @@ void AudioServer::set_playback_all_bus_volumes_linear(Ref<AudioStreamPlayback> p void AudioServer::set_playback_pitch_scale(Ref<AudioStreamPlayback> p_playback, float p_pitch_scale) { ERR_FAIL_COND(p_playback.is_null()); + // Samples. + if (p_playback->get_is_sample() && p_playback->get_sample_playback().is_valid()) { + Ref<AudioSamplePlayback> sample_playback = p_playback->get_sample_playback(); + AudioServer::get_singleton()->update_sample_playback_pitch_scale(sample_playback, p_pitch_scale); + return; + } + AudioStreamPlaybackListNode *playback_node = _find_playback_list_node(p_playback); if (!playback_node) { return; @@ -1385,6 +1433,7 @@ void AudioServer::init() { if (AudioDriver::get_singleton()) { AudioDriver::get_singleton()->start(); + AudioDriver::get_singleton()->set_sample_bus_count(1); } #ifdef TOOLS_ENABLED @@ -1597,6 +1646,9 @@ void AudioServer::set_bus_layout(const Ref<AudioBusLayout> &p_bus_layout) { } buses.resize(p_bus_layout->buses.size()); bus_map.clear(); + + AudioDriver::get_singleton()->set_sample_bus_count(buses.size()); + for (int i = 0; i < p_bus_layout->buses.size(); i++) { Bus *bus = memnew(Bus); if (i == 0) { @@ -1604,6 +1656,7 @@ void AudioServer::set_bus_layout(const Ref<AudioBusLayout> &p_bus_layout) { } else { bus->name = p_bus_layout->buses[i].name; bus->send = p_bus_layout->buses[i].send; + AudioDriver::get_singleton()->set_sample_bus_send(i, bus->send); } bus->solo = p_bus_layout->buses[i].solo; @@ -1611,6 +1664,10 @@ void AudioServer::set_bus_layout(const Ref<AudioBusLayout> &p_bus_layout) { bus->bypass = p_bus_layout->buses[i].bypass; bus->volume_db = p_bus_layout->buses[i].volume_db; + AudioDriver::get_singleton()->set_sample_bus_solo(i, bus->solo); + AudioDriver::get_singleton()->set_sample_bus_mute(i, bus->mute); + AudioDriver::get_singleton()->set_sample_bus_volume_db(i, bus->volume_db); + for (int j = 0; j < p_bus_layout->buses[i].effects.size(); j++) { Ref<AudioEffect> fx = p_bus_layout->buses[i].effects[j].effect; @@ -1638,6 +1695,8 @@ void AudioServer::set_bus_layout(const Ref<AudioBusLayout> &p_bus_layout) { set_edited(false); #endif unlock(); + + // Samples bus sync. } Ref<AudioBusLayout> AudioServer::generate_bus_layout() const { @@ -1705,6 +1764,82 @@ void AudioServer::get_argument_options(const StringName &p_function, int p_idx, } #endif +AudioServer::PlaybackType AudioServer::get_default_playback_type() const { + int playback_type = GLOBAL_GET("audio/general/default_playback_type"); + ERR_FAIL_COND_V_MSG( + playback_type < 0 || playback_type >= PlaybackType::PLAYBACK_TYPE_MAX, + PlaybackType::PLAYBACK_TYPE_STREAM, + vformat(R"(Project settings value (%s) for "audio/general/default_playback_type" is not supported)", playback_type)); + + switch (playback_type) { + case 1: { + return PlaybackType::PLAYBACK_TYPE_SAMPLE; + } break; + + case 0: + default: { + return PlaybackType::PLAYBACK_TYPE_STREAM; + } break; + } +} + +bool AudioServer::is_stream_registered_as_sample(const Ref<AudioStream> &p_stream) { + ERR_FAIL_COND_V_MSG(p_stream.is_null(), false, "Parameter p_stream is null."); + return AudioDriver::get_singleton()->is_stream_registered_as_sample(p_stream); +} + +void AudioServer::register_stream_as_sample(const Ref<AudioStream> &p_stream) { + ERR_FAIL_COND_MSG(p_stream.is_null(), "Parameter p_stream is null."); + ERR_FAIL_COND_MSG(!(p_stream->can_be_sampled()), "Parameter p_stream cannot be sampled."); + Ref<AudioSample> sample = p_stream->generate_sample(); + register_sample(sample); +} + +void AudioServer::unregister_stream_as_sample(const Ref<AudioStream> &p_stream) { + ERR_FAIL_COND_MSG(p_stream.is_null(), "Parameter p_stream is null."); + ERR_FAIL_COND_MSG(!(p_stream->can_be_sampled()), "Parameter p_stream cannot be sampled."); + Ref<AudioSample> sample = p_stream->generate_sample(); + unregister_sample(sample); +} + +void AudioServer::register_sample(const Ref<AudioSample> &p_sample) { + ERR_FAIL_COND_MSG(p_sample.is_null(), "Parameter p_sample is null."); + ERR_FAIL_COND_MSG(p_sample->stream.is_null(), "Parameter p_sample->stream is null."); + ERR_FAIL_COND_MSG(!(p_sample->stream->can_be_sampled()), "Parameter p_stream cannot be sampled."); + AudioDriver::get_singleton()->register_sample(p_sample); +} + +void AudioServer::unregister_sample(const Ref<AudioSample> &p_sample) { + ERR_FAIL_COND_MSG(p_sample.is_null(), "Parameter p_sample is null."); + ERR_FAIL_COND_MSG(p_sample->stream.is_null(), "Parameter p_sample->stream is null."); + AudioDriver::get_singleton()->unregister_sample(p_sample); +} + +void AudioServer::start_sample_playback(const Ref<AudioSamplePlayback> &p_playback) { + ERR_FAIL_COND_MSG(p_playback.is_null(), "Parameter p_playback is null."); + AudioDriver::get_singleton()->start_sample_playback(p_playback); +} + +void AudioServer::stop_sample_playback(const Ref<AudioSamplePlayback> &p_playback) { + ERR_FAIL_COND_MSG(p_playback.is_null(), "Parameter p_playback is null."); + AudioDriver::get_singleton()->stop_sample_playback(p_playback); +} + +void AudioServer::set_sample_playback_pause(const Ref<AudioSamplePlayback> &p_playback, bool p_paused) { + ERR_FAIL_COND_MSG(p_playback.is_null(), "Parameter p_playback is null."); + AudioDriver::get_singleton()->set_sample_playback_pause(p_playback, p_paused); +} + +bool AudioServer::is_sample_playback_active(const Ref<AudioSamplePlayback> &p_playback) { + ERR_FAIL_COND_V_MSG(p_playback.is_null(), false, "Parameter p_playback is null."); + return AudioDriver::get_singleton()->is_sample_playback_active(p_playback); +} + +void AudioServer::update_sample_playback_pitch_scale(const Ref<AudioSamplePlayback> &p_playback, float p_pitch_scale) { + ERR_FAIL_COND_MSG(p_playback.is_null(), "Parameter p_playback is null."); + return AudioDriver::get_singleton()->update_sample_playback_pitch_scale(p_playback, p_pitch_scale); +} + void AudioServer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_bus_count", "amount"), &AudioServer::set_bus_count); ClassDB::bind_method(D_METHOD("get_bus_count"), &AudioServer::get_bus_count); @@ -1774,6 +1909,9 @@ void AudioServer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_enable_tagging_used_audio_streams", "enable"), &AudioServer::set_enable_tagging_used_audio_streams); + ClassDB::bind_method(D_METHOD("is_stream_registered_as_sample", "stream"), &AudioServer::is_stream_registered_as_sample); + ClassDB::bind_method(D_METHOD("register_stream_as_sample", "stream"), &AudioServer::register_stream_as_sample); + ADD_PROPERTY(PropertyInfo(Variant::INT, "bus_count"), "set_bus_count", "get_bus_count"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "output_device"), "set_output_device", "get_output_device"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "input_device"), "set_input_device", "get_input_device"); @@ -1789,6 +1927,11 @@ void AudioServer::_bind_methods() { BIND_ENUM_CONSTANT(SPEAKER_SURROUND_31); BIND_ENUM_CONSTANT(SPEAKER_SURROUND_51); BIND_ENUM_CONSTANT(SPEAKER_SURROUND_71); + + BIND_ENUM_CONSTANT(PLAYBACK_TYPE_DEFAULT); + BIND_ENUM_CONSTANT(PLAYBACK_TYPE_STREAM); + BIND_ENUM_CONSTANT(PLAYBACK_TYPE_SAMPLE); + BIND_ENUM_CONSTANT(PLAYBACK_TYPE_MAX); } AudioServer::AudioServer() { diff --git a/servers/audio_server.h b/servers/audio_server.h index 7dd81beabe..4825e24336 100644 --- a/servers/audio_server.h +++ b/servers/audio_server.h @@ -42,9 +42,11 @@ #include <atomic> class AudioDriverDummy; +class AudioSample; class AudioStream; class AudioStreamWAV; class AudioStreamPlayback; +class AudioSamplePlayback; class AudioDriver { static AudioDriver *singleton; @@ -129,6 +131,28 @@ public: void reset_profiling_time() { prof_time.set(0); } #endif + // Samples handling. + virtual bool is_stream_registered_as_sample(const Ref<AudioStream> &p_stream) const { + return false; + } + virtual void register_sample(const Ref<AudioSample> &p_sample) {} + virtual void unregister_sample(const Ref<AudioSample> &p_sample) {} + virtual void start_sample_playback(const Ref<AudioSamplePlayback> &p_playback); + virtual void stop_sample_playback(const Ref<AudioSamplePlayback> &p_playback) {} + virtual void set_sample_playback_pause(const Ref<AudioSamplePlayback> &p_playback, bool p_paused) {} + virtual bool is_sample_playback_active(const Ref<AudioSamplePlayback> &p_playback) { return false; } + virtual void update_sample_playback_pitch_scale(const Ref<AudioSamplePlayback> &p_playback, float p_pitch_scale = 0.0f) {} + virtual void set_sample_playback_bus_volumes_linear(const Ref<AudioSamplePlayback> &p_playback, const HashMap<StringName, Vector<AudioFrame>> &p_bus_volumes) {} + + virtual void set_sample_bus_count(int p_count) {} + virtual void remove_sample_bus(int p_bus) {} + virtual void add_sample_bus(int p_at_pos = -1) {} + virtual void move_sample_bus(int p_bus, int p_to_pos) {} + virtual void set_sample_bus_send(int p_bus, const StringName &p_send) {} + virtual void set_sample_bus_volume_db(int p_bus, float p_volume_db) {} + virtual void set_sample_bus_solo(int p_bus, bool p_enable) {} + virtual void set_sample_bus_mute(int p_bus, bool p_enable) {} + AudioDriver() {} virtual ~AudioDriver() {} }; @@ -166,6 +190,13 @@ public: SPEAKER_SURROUND_71, }; + enum PlaybackType { + PLAYBACK_TYPE_DEFAULT, + PLAYBACK_TYPE_STREAM, + PLAYBACK_TYPE_SAMPLE, + PLAYBACK_TYPE_MAX + }; + enum { AUDIO_DATA_INVALID_ID = -1, MAX_CHANNELS_PER_BUS = 4, @@ -440,11 +471,25 @@ public: virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override; #endif + PlaybackType get_default_playback_type() const; + + bool is_stream_registered_as_sample(const Ref<AudioStream> &p_stream); + void register_stream_as_sample(const Ref<AudioStream> &p_stream); + void unregister_stream_as_sample(const Ref<AudioStream> &p_stream); + void register_sample(const Ref<AudioSample> &p_sample); + void unregister_sample(const Ref<AudioSample> &p_sample); + void start_sample_playback(const Ref<AudioSamplePlayback> &p_playback); + void stop_sample_playback(const Ref<AudioSamplePlayback> &p_playback); + void set_sample_playback_pause(const Ref<AudioSamplePlayback> &p_playback, bool p_paused); + bool is_sample_playback_active(const Ref<AudioSamplePlayback> &p_playback); + void update_sample_playback_pitch_scale(const Ref<AudioSamplePlayback> &p_playback, float p_pitch_scale = 0.0f); + AudioServer(); virtual ~AudioServer(); }; VARIANT_ENUM_CAST(AudioServer::SpeakerMode) +VARIANT_ENUM_CAST(AudioServer::PlaybackType) class AudioBusLayout : public Resource { GDCLASS(AudioBusLayout, Resource); diff --git a/servers/display_server_headless.h b/servers/display_server_headless.h index 51755ddfbd..60422c16cc 100644 --- a/servers/display_server_headless.h +++ b/servers/display_server_headless.h @@ -51,7 +51,18 @@ private: return memnew(DisplayServerHeadless()); } + static void _dispatch_input_events(const Ref<InputEvent> &p_event) { + static_cast<DisplayServerHeadless *>(get_singleton())->_dispatch_input_event(p_event); + } + + void _dispatch_input_event(const Ref<InputEvent> &p_event) { + if (input_event_callback.is_valid()) { + input_event_callback.call(p_event); + } + } + NativeMenu *native_menu = nullptr; + Callable input_event_callback; public: bool has_feature(Feature p_feature) const override { return false; } @@ -86,7 +97,11 @@ public: void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override {} void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override {} - void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override {} + + void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override { + input_event_callback = p_callable; + } + void window_set_input_text_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override {} void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override {} @@ -137,7 +152,9 @@ public: int64_t window_get_native_handle(HandleType p_handle_type, WindowID p_window = MAIN_WINDOW_ID) const override { return 0; } - void process_events() override {} + void process_events() override { + Input::get_singleton()->flush_buffered_events(); + } void set_native_icon(const String &p_filename) override {} void set_icon(const Ref<Image> &p_icon) override {} @@ -153,6 +170,7 @@ public: void tts_stop() override {} void mouse_set_mode(MouseMode p_mode) override {} + Point2i mouse_get_position() const override { return Point2i(); } void clipboard_set(const String &p_text) override {} void clipboard_set_primary(const String &p_text) override {} @@ -178,7 +196,9 @@ public: DisplayServerHeadless() { native_menu = memnew(NativeMenu); + Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events); } + ~DisplayServerHeadless() { if (native_menu) { memdelete(native_menu); diff --git a/servers/physics_2d/godot_body_2d.cpp b/servers/physics_2d/godot_body_2d.cpp index 01996dc43c..c401e6eee7 100644 --- a/servers/physics_2d/godot_body_2d.cpp +++ b/servers/physics_2d/godot_body_2d.cpp @@ -616,6 +616,8 @@ void GodotBody2D::integrate_velocities(real_t p_step) { return; } + ERR_FAIL_NULL(get_space()); + if (fi_callback_data || body_state_callback.is_valid()) { get_space()->body_add_to_state_query_list(&direct_state_query_list); } @@ -705,6 +707,8 @@ bool GodotBody2D::sleep_test(real_t p_step) { return false; } + ERR_FAIL_NULL_V(get_space(), true); + if (Math::abs(angular_velocity) < get_space()->get_body_angular_velocity_sleep_threshold() && Math::abs(linear_velocity.length_squared()) < get_space()->get_body_linear_velocity_sleep_threshold() * get_space()->get_body_linear_velocity_sleep_threshold()) { still_time += p_step; diff --git a/servers/physics_3d/godot_body_3d.cpp b/servers/physics_3d/godot_body_3d.cpp index 407957b904..669c4b985b 100644 --- a/servers/physics_3d/godot_body_3d.cpp +++ b/servers/physics_3d/godot_body_3d.cpp @@ -675,6 +675,8 @@ void GodotBody3D::integrate_velocities(real_t p_step) { return; } + ERR_FAIL_NULL(get_space()); + if (fi_callback_data || body_state_callback.is_valid()) { get_space()->body_add_to_state_query_list(&direct_state_query_list); } @@ -784,6 +786,8 @@ bool GodotBody3D::sleep_test(real_t p_step) { return false; } + ERR_FAIL_NULL_V(get_space(), true); + if (Math::abs(angular_velocity.length()) < get_space()->get_body_angular_velocity_sleep_threshold() && Math::abs(linear_velocity.length_squared()) < get_space()->get_body_linear_velocity_sleep_threshold() * get_space()->get_body_linear_velocity_sleep_threshold()) { still_time += p_step; diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index 7a15d202a3..fc2aae10c7 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -176,6 +176,8 @@ void register_server_types() { GDREGISTER_VIRTUAL_CLASS(AudioStreamPlaybackResampled); GDREGISTER_CLASS(AudioStreamMicrophone); GDREGISTER_CLASS(AudioStreamRandomizer); + GDREGISTER_CLASS(AudioSample); + GDREGISTER_CLASS(AudioSamplePlayback); GDREGISTER_VIRTUAL_CLASS(AudioEffect); GDREGISTER_VIRTUAL_CLASS(AudioEffectInstance); GDREGISTER_CLASS(AudioEffectEQ); diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index f872219425..c4286dcc0c 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -79,7 +79,7 @@ void RendererCanvasCull::_render_canvas_item_tree(RID p_to_render_target, Canvas } } -void _collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, Transform2D p_transform, RendererCanvasCull::Item *p_material_owner, const Color &p_modulate, RendererCanvasCull::Item **r_items, int &r_index, int p_z) { +void _collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, const Transform2D &p_transform, RendererCanvasCull::Item *p_material_owner, const Color &p_modulate, RendererCanvasCull::Item **r_items, int &r_index, int p_z) { int child_item_count = p_canvas_item->child_items.size(); RendererCanvasCull::Item **child_items = p_canvas_item->child_items.ptrw(); for (int i = 0; i < child_item_count; i++) { @@ -94,6 +94,11 @@ void _collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, Transform2 child_items[i]->ysort_index = r_index; child_items[i]->ysort_parent_abs_z_index = p_z; + if (!child_items[i]->repeat_source) { + child_items[i]->repeat_size = p_canvas_item->repeat_size; + child_items[i]->repeat_times = p_canvas_item->repeat_times; + } + // Y sorted canvas items are flattened into r_items. Calculate their absolute z index to use when rendering r_items. if (child_items[i]->z_relative) { abs_z = CLAMP(p_z + child_items[i]->z_index, RS::CANVAS_ITEM_Z_MIN, RS::CANVAS_ITEM_Z_MAX); @@ -270,17 +275,17 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 } else { ci->repeat_size = repeat_size; ci->repeat_times = repeat_times; + } - if (repeat_size.x || repeat_size.y) { - Size2 scale = final_xform.get_scale(); - rect.size += repeat_size * repeat_times / scale; - rect.position -= repeat_size / scale * (repeat_times / 2); - } + if (repeat_size.x || repeat_size.y) { + Size2 scale = final_xform.get_scale(); + rect.size += repeat_size * repeat_times / scale; + rect.position -= repeat_size / scale * (repeat_times / 2); } if (snapping_2d_transforms_to_pixel) { - final_xform.columns[2] = final_xform.columns[2].round(); - parent_xform.columns[2] = parent_xform.columns[2].round(); + final_xform.columns[2] = (final_xform.columns[2] + Point2(0.5, 0.5)).floor(); + parent_xform.columns[2] = (parent_xform.columns[2] + Point2(0.5, 0.5)).floor(); } final_xform = parent_xform * final_xform; @@ -352,7 +357,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 sorter.sort(child_items, child_item_count); for (i = 0; i < child_item_count; i++) { - _cull_canvas_item(child_items[i], final_xform * child_items[i]->ysort_xform, p_clip_rect, modulate * child_items[i]->ysort_modulate, child_items[i]->ysort_parent_abs_z_index, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner, false, p_canvas_cull_mask, repeat_size, repeat_times); + _cull_canvas_item(child_items[i], final_xform * child_items[i]->ysort_xform, p_clip_rect, modulate * child_items[i]->ysort_modulate, child_items[i]->ysort_parent_abs_z_index, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner, false, p_canvas_cull_mask, child_items[i]->repeat_size, child_items[i]->repeat_times); } } else { RendererCanvasRender::Item *canvas_group_from = nullptr; diff --git a/servers/rendering/renderer_canvas_render.h b/servers/rendering/renderer_canvas_render.h index 4a56548932..cb8180f989 100644 --- a/servers/rendering/renderer_canvas_render.h +++ b/servers/rendering/renderer_canvas_render.h @@ -545,8 +545,13 @@ public: virtual void set_debug_redraw(bool p_enabled, double p_time, const Color &p_color) = 0; - RendererCanvasRender() { singleton = this; } - virtual ~RendererCanvasRender() {} + RendererCanvasRender() { + ERR_FAIL_COND_MSG(singleton != nullptr, "A RendererCanvasRender singleton already exists."); + singleton = this; + } + virtual ~RendererCanvasRender() { + singleton = nullptr; + } }; #endif // RENDERER_CANVAS_RENDER_H diff --git a/servers/rendering/renderer_compositor.cpp b/servers/rendering/renderer_compositor.cpp index d364de5633..428cecead1 100644 --- a/servers/rendering/renderer_compositor.cpp +++ b/servers/rendering/renderer_compositor.cpp @@ -47,6 +47,7 @@ bool RendererCompositor::is_xr_enabled() const { } RendererCompositor::RendererCompositor() { + ERR_FAIL_COND_MSG(singleton != nullptr, "A RendererCompositor singleton already exists."); singleton = this; #ifndef _3D_DISABLED @@ -57,3 +58,7 @@ RendererCompositor::RendererCompositor() { } #endif // _3D_DISABLED } + +RendererCompositor::~RendererCompositor() { + singleton = nullptr; +} diff --git a/servers/rendering/renderer_compositor.h b/servers/rendering/renderer_compositor.h index 3c49e31516..ab789d5b4d 100644 --- a/servers/rendering/renderer_compositor.h +++ b/servers/rendering/renderer_compositor.h @@ -110,7 +110,7 @@ public: static RendererCompositor *get_singleton() { return singleton; } RendererCompositor(); - virtual ~RendererCompositor() {} + virtual ~RendererCompositor(); }; #endif // RENDERER_COMPOSITOR_H diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index aae32f0b3e..536fc7a04a 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -3585,22 +3585,31 @@ RID RenderForwardClustered::_render_buffers_get_velocity_texture(Ref<RenderScene } void RenderForwardClustered::environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) { + ERR_FAIL_NULL(ss_effects); + ERR_FAIL_COND(p_quality < RS::EnvironmentSSAOQuality::ENV_SSAO_QUALITY_VERY_LOW || p_quality > RS::EnvironmentSSAOQuality::ENV_SSAO_QUALITY_ULTRA); ss_effects->ssao_set_quality(p_quality, p_half_size, p_adaptive_target, p_blur_passes, p_fadeout_from, p_fadeout_to); } void RenderForwardClustered::environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) { + ERR_FAIL_NULL(ss_effects); + ERR_FAIL_COND(p_quality < RS::EnvironmentSSILQuality::ENV_SSIL_QUALITY_VERY_LOW || p_quality > RS::EnvironmentSSILQuality::ENV_SSIL_QUALITY_ULTRA); ss_effects->ssil_set_quality(p_quality, p_half_size, p_adaptive_target, p_blur_passes, p_fadeout_from, p_fadeout_to); } void RenderForwardClustered::environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) { + ERR_FAIL_NULL(ss_effects); + ERR_FAIL_COND(p_quality < RS::EnvironmentSSRRoughnessQuality::ENV_SSR_ROUGHNESS_QUALITY_DISABLED || p_quality > RS::EnvironmentSSRRoughnessQuality::ENV_SSR_ROUGHNESS_QUALITY_HIGH); ss_effects->ssr_set_roughness_quality(p_quality); } void RenderForwardClustered::sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) { + ERR_FAIL_NULL(ss_effects); + ERR_FAIL_COND(p_quality < RS::SubSurfaceScatteringQuality::SUB_SURFACE_SCATTERING_QUALITY_DISABLED || p_quality > RS::SubSurfaceScatteringQuality::SUB_SURFACE_SCATTERING_QUALITY_HIGH); ss_effects->sss_set_quality(p_quality); } void RenderForwardClustered::sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) { + ERR_FAIL_NULL(ss_effects); ss_effects->sss_set_scale(p_scale, p_depth_scale); } diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h index c7c5d34314..a78ced271a 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h @@ -78,7 +78,6 @@ class RendererCanvasRenderRD : public RendererCanvasRender { FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR = (1 << 11), FLAGS_NINEPACH_DRAW_CENTER = (1 << 12), - FLAGS_USING_PARTICLES = (1 << 13), FLAGS_USE_SKELETON = (1 << 15), FLAGS_NINEPATCH_H_MODE_SHIFT = 16, diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index 14d138181f..84ea6a5da2 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -299,6 +299,7 @@ RendererCompositorRD::RendererCompositorRD() { } } + ERR_FAIL_COND_MSG(singleton != nullptr, "A RendererCompositorRD singleton already exists."); singleton = this; utilities = memnew(RendererRD::Utilities); @@ -330,6 +331,7 @@ RendererCompositorRD::RendererCompositorRD() { } RendererCompositorRD::~RendererCompositorRD() { + singleton = nullptr; memdelete(uniform_set_cache); memdelete(framebuffer_cache); ShaderRD::set_shader_cache_dir(String()); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 1e4880e67a..96bcd72099 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -423,6 +423,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende Size2i target_size = rb->get_target_size(); bool can_use_effects = target_size.x >= 8 && target_size.y >= 8; // FIXME I think this should check internal size, we do all our post processing at this size... + can_use_effects &= _debug_draw_can_use_effects(debug_draw); bool can_use_storage = _render_buffers_can_be_storage(); bool use_fsr = fsr && can_use_effects && rb->get_scaling_3d_mode() == RS::VIEWPORT_SCALING_3D_MODE_FSR; @@ -699,7 +700,7 @@ void RendererSceneRenderRD::_post_process_subpass(RID p_source_texture, RID p_fr // FIXME: Our input it our internal_texture, shouldn't this be using internal_size ?? // Seeing we don't support FSR in our mobile renderer right now target_size = internal_size... Size2i target_size = rb->get_target_size(); - bool can_use_effects = target_size.x >= 8 && target_size.y >= 8; + bool can_use_effects = target_size.x >= 8 && target_size.y >= 8 && debug_draw == RS::VIEWPORT_DEBUG_DRAW_DISABLED; RD::DrawListID draw_list = RD::get_singleton()->draw_list_switch_to_next_pass(); @@ -764,6 +765,56 @@ void RendererSceneRenderRD::_disable_clear_request(const RenderDataRD *p_render_ texture_storage->render_target_disable_clear_request(p_render_data->render_buffers->get_render_target()); } +bool RendererSceneRenderRD::_debug_draw_can_use_effects(RS::ViewportDebugDraw p_debug_draw) { + bool can_use_effects = true; + switch (p_debug_draw) { + // No debug draw, use camera effects + case RS::VIEWPORT_DEBUG_DRAW_DISABLED: + can_use_effects = true; + break; + // Modes that completely override rendering to draw debug information should disable camera effects. + case RS::VIEWPORT_DEBUG_DRAW_UNSHADED: + case RS::VIEWPORT_DEBUG_DRAW_OVERDRAW: + case RS::VIEWPORT_DEBUG_DRAW_WIREFRAME: + case RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_ALBEDO: + case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS: + case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS: + case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS: + case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES: + case RS::VIEWPORT_DEBUG_DRAW_INTERNAL_BUFFER: + can_use_effects = false; + break; + // Modes that draws information over part of the viewport needs camera effects because we see partially the normal draw mode. + case RS::VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS: + case RS::VIEWPORT_DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS: + case RS::VIEWPORT_DEBUG_DRAW_DECAL_ATLAS: + case RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS: + // Modes that draws a buffer over viewport needs camera effects because if the buffer is not available it will be equivalent to normal draw mode. + case RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER: + case RS::VIEWPORT_DEBUG_DRAW_SSAO: + case RS::VIEWPORT_DEBUG_DRAW_SSIL: + case RS::VIEWPORT_DEBUG_DRAW_SDFGI: + case RS::VIEWPORT_DEBUG_DRAW_GI_BUFFER: + case RS::VIEWPORT_DEBUG_DRAW_OCCLUDERS: + can_use_effects = true; + break; + // Other debug draw modes keep camera effects. + case RS::VIEWPORT_DEBUG_DRAW_LIGHTING: + case RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_LIGHTING: + case RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_EMISSION: + case RS::VIEWPORT_DEBUG_DRAW_SCENE_LUMINANCE: + case RS::VIEWPORT_DEBUG_DRAW_PSSM_SPLITS: + case RS::VIEWPORT_DEBUG_DRAW_SDFGI_PROBES: + case RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD: + can_use_effects = true; + break; + default: + break; + } + + return can_use_effects; +} + void RendererSceneRenderRD::_render_buffers_debug_draw(const RenderDataRD *p_render_data) { RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 5c5f11aba6..a8e8e638cd 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -117,6 +117,7 @@ protected: RendererRD::GI gi; virtual void _update_shader_quality_settings() {} + static bool _debug_draw_can_use_effects(RS::ViewportDebugDraw p_debug_draw); private: RS::ViewportDebugDraw debug_draw = RS::VIEWPORT_DEBUG_DRAW_DISABLED; diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl index dbff09c301..4426d9eb66 100644 --- a/servers/rendering/renderer_rd/shaders/canvas.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas.glsl @@ -193,13 +193,6 @@ void main() { } } -#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE) - if (bool(draw_data.flags & FLAGS_USING_PARTICLES)) { - //scale by texture size - vertex /= draw_data.color_texture_pixel_size; - } -#endif - #ifdef USE_POINT_SIZE float point_size = 1.0; #endif diff --git a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl index 7ac7cf9c07..8649f4710b 100644 --- a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl @@ -14,7 +14,6 @@ #define FLAGS_TRANSPOSE_RECT (1 << 10) #define FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR (1 << 11) #define FLAGS_NINEPACH_DRAW_CENTER (1 << 12) -#define FLAGS_USING_PARTICLES (1 << 13) #define FLAGS_NINEPATCH_H_MODE_SHIFT 16 #define FLAGS_NINEPATCH_V_MODE_SHIFT 18 diff --git a/servers/rendering/renderer_rd/shaders/particles.glsl b/servers/rendering/renderer_rd/shaders/particles.glsl index 60c49bacae..7c5291038f 100644 --- a/servers/rendering/renderer_rd/shaders/particles.glsl +++ b/servers/rendering/renderer_rd/shaders/particles.glsl @@ -292,6 +292,24 @@ void main() { PARTICLE.velocity = particles.data[src_idx].velocity; PARTICLE.flags = PARTICLE_FLAG_TRAILED | ((frame_history.data[0].frame & PARTICLE_FRAME_MASK) << PARTICLE_FRAME_SHIFT); //mark it as trailed, save in which frame it will start PARTICLE.xform = particles.data[src_idx].xform; +#ifdef USERDATA1_USED + PARTICLE.userdata1 = particles.data[src_idx].userdata1; +#endif +#ifdef USERDATA2_USED + PARTICLE.userdata2 = particles.data[src_idx].userdata2; +#endif +#ifdef USERDATA3_USED + PARTICLE.userdata3 = particles.data[src_idx].userdata3; +#endif +#ifdef USERDATA4_USED + PARTICLE.userdata4 = particles.data[src_idx].userdata4; +#endif +#ifdef USERDATA5_USED + PARTICLE.userdata5 = particles.data[src_idx].userdata5; +#endif +#ifdef USERDATA6_USED + PARTICLE.userdata6 = particles.data[src_idx].userdata6; +#endif } if (!bool(particles.data[src_idx].flags & PARTICLE_FLAG_ACTIVE)) { // Disable the entire trail if the parent is no longer active. diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp index d1c8c71b7f..13b00be1c4 100644 --- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp @@ -1165,8 +1165,8 @@ MaterialStorage::MaterialStorage() { global_shader_uniforms.buffer_values = memnew_arr(GlobalShaderUniforms::Value, global_shader_uniforms.buffer_size); memset(global_shader_uniforms.buffer_values, 0, sizeof(GlobalShaderUniforms::Value) * global_shader_uniforms.buffer_size); global_shader_uniforms.buffer_usage = memnew_arr(GlobalShaderUniforms::ValueUsage, global_shader_uniforms.buffer_size); - global_shader_uniforms.buffer_dirty_regions = memnew_arr(bool, global_shader_uniforms.buffer_size / GlobalShaderUniforms::BUFFER_DIRTY_REGION_SIZE); - memset(global_shader_uniforms.buffer_dirty_regions, 0, sizeof(bool) * global_shader_uniforms.buffer_size / GlobalShaderUniforms::BUFFER_DIRTY_REGION_SIZE); + global_shader_uniforms.buffer_dirty_regions = memnew_arr(bool, 1 + (global_shader_uniforms.buffer_size / GlobalShaderUniforms::BUFFER_DIRTY_REGION_SIZE)); + memset(global_shader_uniforms.buffer_dirty_regions, 0, sizeof(bool) * (1 + (global_shader_uniforms.buffer_size / GlobalShaderUniforms::BUFFER_DIRTY_REGION_SIZE))); global_shader_uniforms.buffer = RD::get_singleton()->storage_buffer_create(sizeof(GlobalShaderUniforms::Value) * global_shader_uniforms.buffer_size); } @@ -1769,7 +1769,7 @@ void MaterialStorage::global_shader_parameters_instance_update(RID p_instance, i void MaterialStorage::_update_global_shader_uniforms() { MaterialStorage *material_storage = MaterialStorage::get_singleton(); if (global_shader_uniforms.buffer_dirty_region_count > 0) { - uint32_t total_regions = global_shader_uniforms.buffer_size / GlobalShaderUniforms::BUFFER_DIRTY_REGION_SIZE; + uint32_t total_regions = 1 + (global_shader_uniforms.buffer_size / GlobalShaderUniforms::BUFFER_DIRTY_REGION_SIZE); if (total_regions / global_shader_uniforms.buffer_dirty_region_count <= 4) { // 25% of regions dirty, just update all buffer RD::get_singleton()->buffer_update(global_shader_uniforms.buffer, 0, sizeof(GlobalShaderUniforms::Value) * global_shader_uniforms.buffer_size, global_shader_uniforms.buffer_values); diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 38f1fe57bd..59f7b3d9e1 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -5507,7 +5507,7 @@ Error RenderingDevice::initialize(RenderingContextDriver *p_context, DisplayServ for (uint32_t i = 0; i < frames.size(); i++) { // Staging was never used, create a block. err = _insert_staging_block(); - ERR_CONTINUE(err != OK); + ERR_FAIL_COND_V(err, FAILED); } draw_list = nullptr; diff --git a/servers/rendering/rendering_device_binds.cpp b/servers/rendering/rendering_device_binds.cpp index 3678b70254..986f01a52c 100644 --- a/servers/rendering/rendering_device_binds.cpp +++ b/servers/rendering/rendering_device_binds.cpp @@ -157,9 +157,6 @@ Error RDShaderFile::parse_versions_from_text(const String &p_text, const String } } - Ref<RDShaderFile> shader_file; - shader_file.instantiate(); - if (base_error.is_empty()) { if (stage_found[RD::SHADER_STAGE_COMPUTE] && stages_found > 1) { ERR_FAIL_V_MSG(ERR_PARSE_ERROR, "When writing compute shaders, [compute] mustbe the only stage present."); diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 9aa54d0bb7..f5e0b811a2 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -1238,6 +1238,7 @@ void ShaderLanguage::clear() { include_positions.push_back(FilePosition()); include_markers_handled.clear(); + calls_info.clear(); #ifdef DEBUG_ENABLED keyword_completion_context = CF_UNSPECIFIED; @@ -1445,8 +1446,12 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea *r_struct_name = shader->constants[p_identifier].struct_name; } if (r_constant_value) { - if (shader->constants[p_identifier].initializer && shader->constants[p_identifier].initializer->values.size() == 1) { - *r_constant_value = shader->constants[p_identifier].initializer->values[0]; + if (shader->constants[p_identifier].initializer && shader->constants[p_identifier].initializer->type == Node::NODE_TYPE_CONSTANT) { + ConstantNode *cnode = static_cast<ConstantNode *>(shader->constants[p_identifier].initializer); + + if (cnode->values.size() == 1) { + *r_constant_value = cnode->values[0]; + } } } if (r_type) { @@ -1542,7 +1547,7 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type } DataType na = p_op->arguments[0]->get_datatype(); - valid = na > TYPE_BOOL && na < TYPE_MAT2; + valid = na > TYPE_BVEC4 && na < TYPE_MAT2; ret_type = na; } break; case OP_ADD: @@ -1562,7 +1567,7 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type } if (na == nb) { - valid = (na > TYPE_BOOL && na <= TYPE_MAT4); + valid = (na > TYPE_BVEC4 && na <= TYPE_MAT4); ret_type = na; } else if (na == TYPE_INT && nb == TYPE_IVEC2) { valid = true; @@ -1771,7 +1776,7 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type DataType nb = p_op->arguments[1]->get_datatype(); if (na == nb) { - valid = (na > TYPE_BOOL && na <= TYPE_MAT4); + valid = (na > TYPE_BVEC4 && na <= TYPE_MAT4); ret_type = na; } else if (na == TYPE_IVEC2 && nb == TYPE_INT) { valid = true; @@ -3085,6 +3090,19 @@ const ShaderLanguage::BuiltinFuncConstArgs ShaderLanguage::builtin_func_const_ar { nullptr, 0, 0, 0 } }; +const ShaderLanguage::BuiltinEntry ShaderLanguage::frag_only_func_defs[] = { + { "dFdx" }, + { "dFdxCoarse" }, + { "dFdxFine" }, + { "dFdy" }, + { "dFdyCoarse" }, + { "dFdyFine" }, + { "fwidth" }, + { "fwidthCoarse" }, + { "fwidthFine" }, + { nullptr } +}; + bool ShaderLanguage::is_const_suffix_lut_initialized = false; bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str, bool *r_is_custom_function) { @@ -3964,12 +3982,9 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::C } value = Variant(array); } else { - PackedFloat32Array array; + PackedVector4Array array; for (int i = 0; i < array_size; i += 4) { - array.push_back(p_value[i].real); - array.push_back(p_value[i + 1].real); - array.push_back(p_value[i + 2].real); - array.push_back(p_value[i + 3].real); + array.push_back(Vector4(p_value[i].real, p_value[i + 1].real, p_value[i + 2].real, p_value[i + 3].real)); } value = Variant(array); } @@ -4201,7 +4216,7 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SOURCE_COLOR) { pi.type = Variant::PACKED_COLOR_ARRAY; } else { - pi.type = Variant::PACKED_FLOAT32_ARRAY; + pi.type = Variant::PACKED_VECTOR4_ARRAY; } } else { if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SOURCE_COLOR) { @@ -4610,6 +4625,58 @@ bool ShaderLanguage::_check_node_constness(const Node *p_node) const { return true; } +bool ShaderLanguage::_check_restricted_func(const StringName &p_name, const StringName &p_current_function) const { + int idx = 0; + + while (frag_only_func_defs[idx].name) { + if (StringName(frag_only_func_defs[idx].name) == p_name) { + if (is_supported_frag_only_funcs) { + if (p_current_function == "vertex" && stages->has(p_current_function)) { + return true; + } + } else { + return true; + } + break; + } + idx++; + } + + return false; +} + +bool ShaderLanguage::_validate_restricted_func(const StringName &p_name, const CallInfo *p_func_info, bool p_is_builtin_hint) { + const bool is_in_restricted_function = p_func_info->name == "vertex"; + + // No need to check up the hierarchy if it's a built-in. + if (!p_is_builtin_hint) { + for (const CallInfo *func_info : p_func_info->calls) { + if (is_in_restricted_function && func_info->name != p_name) { + // Skips check for non-called method. + continue; + } + + if (!_validate_restricted_func(p_name, func_info)) { + return false; + } + } + } + + if (!p_func_info->uses_restricted_functions.is_empty()) { + const Pair<StringName, TkPos> &first_element = p_func_info->uses_restricted_functions.get(0); + _set_tkpos(first_element.second); + + if (is_in_restricted_function) { + _set_error(vformat(RTR("'%s' cannot be used within the '%s' processor function."), first_element.first, "vertex")); + } else { + _set_error(vformat(RTR("'%s' cannot be used here, because '%s' is called by the '%s' processor function (which is not allowed)."), first_element.first, p_func_info->name, "vertex")); + } + return false; + } + + return true; +} + bool ShaderLanguage::_validate_assign(Node *p_node, const FunctionInfo &p_function_info, String *r_message) { if (p_node->type == Node::NODE_TYPE_OPERATOR) { OperatorNode *op = static_cast<OperatorNode *>(p_node); @@ -5266,6 +5333,36 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons const StringName &name = identifier; + if (name != current_function) { // Recursion is not allowed. + // Register call. + if (calls_info.has(name)) { + calls_info[current_function].calls.push_back(&calls_info[name]); + } + + int idx = 0; + bool is_builtin = false; + + while (frag_only_func_defs[idx].name) { + if (frag_only_func_defs[idx].name == name) { + // If a built-in function not found for the current shader type, then it shouldn't be parsed further. + if (!is_supported_frag_only_funcs) { + _set_error(vformat(RTR("Built-in function '%s' is not supported for the '%s' shader type."), name, shader_type_identifier)); + return nullptr; + } + // Register usage of the restricted function. + calls_info[current_function].uses_restricted_functions.push_back(Pair<StringName, TkPos>(name, _get_tkpos())); + is_builtin = true; + break; + } + idx++; + } + + // Recursively checks for the restricted function call. + if (is_supported_frag_only_funcs && current_function == "vertex" && stages->has(current_function) && !_validate_restricted_func(name, &calls_info[current_function], is_builtin)) { + return nullptr; + } + } + OperatorNode *func = alloc_node<OperatorNode>(); func->op = OP_CALL; VariableNode *funcname = alloc_node<VariableNode>(); @@ -8099,6 +8196,8 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f ShaderNode::Uniform::Scope uniform_scope = ShaderNode::Uniform::SCOPE_LOCAL; stages = &p_functions; + is_supported_frag_only_funcs = shader_type_identifier == "canvas_item" || shader_type_identifier == "spatial" || shader_type_identifier == "sky"; + const FunctionInfo &constants = p_functions.has("constants") ? p_functions["constants"] : FunctionInfo(); HashMap<String, String> defined_modes; @@ -9443,7 +9542,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f } } - constant.initializer = static_cast<ConstantNode *>(expr); + constant.initializer = expr; if (!_compare_datatypes(type, struct_name, 0, expr->get_datatype(), expr->get_datatype_name(), expr->get_array_size())) { return ERR_PARSE_ERROR; @@ -9541,6 +9640,11 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f shader->functions.insert(name, function); shader->vfunctions.push_back(function); + CallInfo call_info; + call_info.name = name; + + calls_info.insert(name, call_info); + func_node->name = name; func_node->return_type = type; func_node->return_struct_name = struct_name; @@ -10325,10 +10429,11 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_ } while (builtin_func_defs[idx].name) { - if (low_end && builtin_func_defs[idx].high_end) { + if ((low_end && builtin_func_defs[idx].high_end) || _check_restricted_func(builtin_func_defs[idx].name, skip_function)) { idx++; continue; } + matches.insert(String(builtin_func_defs[idx].name), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION); idx++; } @@ -10490,7 +10595,7 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_ } while (builtin_func_defs[idx].name) { - if (low_end && builtin_func_defs[idx].high_end) { + if ((low_end && builtin_func_defs[idx].high_end) || _check_restricted_func(builtin_func_defs[idx].name, block_function)) { idx++; continue; } @@ -10732,4 +10837,5 @@ ShaderLanguage::ShaderLanguage() { ShaderLanguage::~ShaderLanguage() { clear(); + global_func_set.clear(); } diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index 5615d7f457..edac819a1e 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -620,7 +620,7 @@ public: DataType type; StringName struct_name; DataPrecision precision; - ConstantNode *initializer = nullptr; + Node *initializer = nullptr; int array_size; }; @@ -913,6 +913,15 @@ private: Vector<FilePosition> include_positions; HashSet<String> include_markers_handled; + // Additional function information (eg. call hierarchy). No need to expose it to compiler. + struct CallInfo { + StringName name; + List<Pair<StringName, TkPos>> uses_restricted_functions; + List<CallInfo *> calls; + }; + + RBMap<StringName, CallInfo> calls_info; + #ifdef DEBUG_ENABLED struct Usage { int decl_line; @@ -1036,6 +1045,10 @@ private: bool _validate_assign(Node *p_node, const FunctionInfo &p_function_info, String *r_message = nullptr); bool _validate_operator(OperatorNode *p_op, DataType *r_ret_type = nullptr, int *r_ret_size = nullptr); + struct BuiltinEntry { + const char *name; + }; + struct BuiltinFuncDef { enum { MAX_ARGS = 5 }; const char *name; @@ -1078,11 +1091,13 @@ private: #endif // DEBUG_ENABLED const HashMap<StringName, FunctionInfo> *stages = nullptr; + bool is_supported_frag_only_funcs = false; bool _get_completable_identifier(BlockNode *p_block, CompletionType p_type, StringName &identifier); static const BuiltinFuncDef builtin_func_defs[]; static const BuiltinFuncOutArgs builtin_func_out_args[]; static const BuiltinFuncConstArgs builtin_func_const_args[]; + static const BuiltinEntry frag_only_func_defs[]; static bool is_const_suffix_lut_initialized; @@ -1097,6 +1112,9 @@ private: bool _validate_varying_assign(ShaderNode::Varying &p_varying, String *r_message); bool _check_node_constness(const Node *p_node) const; + bool _check_restricted_func(const StringName &p_name, const StringName &p_current_function) const; + bool _validate_restricted_func(const StringName &p_call_name, const CallInfo *p_func_info, bool p_is_builtin_hint = false); + Node *_parse_expression(BlockNode *p_block, const FunctionInfo &p_function_info); Error _parse_array_size(BlockNode *p_block, const FunctionInfo &p_function_info, bool p_forbid_unknown_size, Node **r_size_expression, int *r_array_size, bool *r_unknown_size); Node *_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info); diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp index ab9cf666ec..de396cd18b 100644 --- a/servers/rendering/shader_types.cpp +++ b/servers/rendering/shader_types.cpp @@ -77,12 +77,12 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["INSTANCE_CUSTOM"] = constt(ShaderLanguage::TYPE_VEC4); shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VERTEX_ID"] = constt(ShaderLanguage::TYPE_INT); shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["ROUGHNESS"] = ShaderLanguage::TYPE_FLOAT; - shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["BONE_INDICES"] = ShaderLanguage::TYPE_UVEC4; - shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["BONE_WEIGHTS"] = ShaderLanguage::TYPE_VEC4; - shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM0"] = ShaderLanguage::TYPE_VEC4; - shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM1"] = ShaderLanguage::TYPE_VEC4; - shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM2"] = ShaderLanguage::TYPE_VEC4; - shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM3"] = ShaderLanguage::TYPE_VEC4; + shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["BONE_INDICES"] = constt(ShaderLanguage::TYPE_UVEC4); + shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["BONE_WEIGHTS"] = constt(ShaderLanguage::TYPE_VEC4); + shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM0"] = constt(ShaderLanguage::TYPE_VEC4); + shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM1"] = constt(ShaderLanguage::TYPE_VEC4); + shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM2"] = constt(ShaderLanguage::TYPE_VEC4); + shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM3"] = constt(ShaderLanguage::TYPE_VEC4); shader_modes[RS::SHADER_SPATIAL].functions["vertex"].can_discard = false; shader_modes[RS::SHADER_SPATIAL].functions["vertex"].main_function = true; @@ -99,11 +99,11 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL); shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["MAIN_CAM_INV_VIEW_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); - shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["NODE_POSITION_WORLD"] = ShaderLanguage::TYPE_VEC3; - shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CAMERA_POSITION_WORLD"] = ShaderLanguage::TYPE_VEC3; - shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CAMERA_DIRECTION_WORLD"] = ShaderLanguage::TYPE_VEC3; - shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CAMERA_VISIBLE_LAYERS"] = ShaderLanguage::TYPE_UINT; - shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["NODE_POSITION_VIEW"] = ShaderLanguage::TYPE_VEC3; + shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["NODE_POSITION_WORLD"] = constt(ShaderLanguage::TYPE_VEC3); + shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CAMERA_POSITION_WORLD"] = constt(ShaderLanguage::TYPE_VEC3); + shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CAMERA_DIRECTION_WORLD"] = constt(ShaderLanguage::TYPE_VEC3); + shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CAMERA_VISIBLE_LAYERS"] = constt(ShaderLanguage::TYPE_UINT); + shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["NODE_POSITION_VIEW"] = constt(ShaderLanguage::TYPE_VEC3); shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEW_INDEX"] = constt(ShaderLanguage::TYPE_INT); shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEW_MONO_LEFT"] = constt(ShaderLanguage::TYPE_INT); @@ -147,11 +147,11 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2); - shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NODE_POSITION_WORLD"] = ShaderLanguage::TYPE_VEC3; - shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["CAMERA_POSITION_WORLD"] = ShaderLanguage::TYPE_VEC3; - shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["CAMERA_DIRECTION_WORLD"] = ShaderLanguage::TYPE_VEC3; - shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["CAMERA_VISIBLE_LAYERS"] = ShaderLanguage::TYPE_UINT; - shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NODE_POSITION_VIEW"] = ShaderLanguage::TYPE_VEC3; + shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NODE_POSITION_WORLD"] = constt(ShaderLanguage::TYPE_VEC3); + shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["CAMERA_POSITION_WORLD"] = constt(ShaderLanguage::TYPE_VEC3); + shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["CAMERA_DIRECTION_WORLD"] = constt(ShaderLanguage::TYPE_VEC3); + shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["CAMERA_VISIBLE_LAYERS"] = constt(ShaderLanguage::TYPE_UINT); + shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NODE_POSITION_VIEW"] = constt(ShaderLanguage::TYPE_VEC3); shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW_INDEX"] = constt(ShaderLanguage::TYPE_INT); shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW_MONO_LEFT"] = constt(ShaderLanguage::TYPE_INT); diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 7637d4e7da..dd3491f62c 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -3610,7 +3610,7 @@ void RenderingServer::init() { GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/environment/subsurface_scattering/subsurface_scattering_scale", PROPERTY_HINT_RANGE, "0.001,1,0.001"), 0.05); GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/environment/subsurface_scattering/subsurface_scattering_depth_scale", PROPERTY_HINT_RANGE, "0.001,1,0.001"), 0.01); - GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/limits/global_shader_variables/buffer_size", PROPERTY_HINT_RANGE, "1,1048576,1"), 65536); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/limits/global_shader_variables/buffer_size", PROPERTY_HINT_RANGE, "16,1048576,1"), 65536); GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/lightmapping/probe_capture/update_speed", PROPERTY_HINT_RANGE, "0.001,256,0.001"), 15); GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/lightmapping/primitive_meshes/texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.2); diff --git a/servers/server_wrap_mt_common.h b/servers/server_wrap_mt_common.h index 40867490ca..22cc7f353d 100644 --- a/servers/server_wrap_mt_common.h +++ b/servers/server_wrap_mt_common.h @@ -31,7 +31,7 @@ #ifndef SERVER_WRAP_MT_COMMON_H #define SERVER_WRAP_MT_COMMON_H -#ifdef DEBIG_ENABLED +#ifdef DEBUG_ENABLED #define MAIN_THREAD_SYNC_CHECK \ if (unlikely(Thread::is_main_thread() && Engine::get_singleton()->notify_frame_server_synced())) { \ MAIN_THREAD_SYNC_WARN \ diff --git a/servers/xr/xr_vrs.cpp b/servers/xr/xr_vrs.cpp index 9d1e2f2068..3e283a42f0 100644 --- a/servers/xr/xr_vrs.cpp +++ b/servers/xr/xr_vrs.cpp @@ -94,7 +94,14 @@ RID XRVRS::make_vrs_texture(const Size2 &p_target_size, const PackedVector2Array int32_t texel_width = RD::get_singleton()->limit_get(RD::LIMIT_VRS_TEXEL_WIDTH); int32_t texel_height = RD::get_singleton()->limit_get(RD::LIMIT_VRS_TEXEL_HEIGHT); + // Should return sensible data or graphics API does not support VRS. + ERR_FAIL_COND_V(texel_width < 1 || texel_height < 1, RID()); + Size2 vrs_size = Size2(0.5 + p_target_size.x / texel_width, 0.5 + p_target_size.y / texel_height).round(); + + // Make sure we have at least one pixel. + vrs_size = vrs_size.maxf(1.0); + float max_radius = 0.5 * MIN(vrs_size.x, vrs_size.y); // Maximum radius that fits inside of our image float min_radius = vrs_min_radius * max_radius / 100.0; // Minimum radius as a percentage of our size real_t outer_radius = MAX(1.0, (max_radius - min_radius) / vrs_strength); |