summaryrefslogtreecommitdiffstats
path: root/servers
diff options
context:
space:
mode:
Diffstat (limited to 'servers')
-rw-r--r--servers/audio/audio_stream.cpp27
-rw-r--r--servers/audio/audio_stream.h48
-rw-r--r--servers/audio_server.cpp149
-rw-r--r--servers/audio_server.h45
-rw-r--r--servers/display_server_headless.h24
-rw-r--r--servers/physics_2d/godot_body_2d.cpp4
-rw-r--r--servers/physics_3d/godot_body_3d.cpp4
-rw-r--r--servers/register_server_types.cpp2
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp23
-rw-r--r--servers/rendering/renderer_canvas_render.h9
-rw-r--r--servers/rendering/renderer_compositor.cpp5
-rw-r--r--servers/rendering/renderer_compositor.h2
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp9
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.h1
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.cpp2
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp53
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.h1
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas.glsl7
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl1
-rw-r--r--servers/rendering/renderer_rd/shaders/particles.glsl18
-rw-r--r--servers/rendering/renderer_rd/storage_rd/material_storage.cpp6
-rw-r--r--servers/rendering/rendering_device.cpp2
-rw-r--r--servers/rendering/rendering_device_binds.cpp3
-rw-r--r--servers/rendering/shader_language.cpp134
-rw-r--r--servers/rendering/shader_language.h20
-rw-r--r--servers/rendering/shader_types.cpp32
-rw-r--r--servers/rendering_server.cpp2
-rw-r--r--servers/server_wrap_mt_common.h2
-rw-r--r--servers/xr/xr_vrs.cpp7
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);