diff options
Diffstat (limited to 'servers')
271 files changed, 26818 insertions, 16637 deletions
diff --git a/servers/audio/audio_driver_dummy.cpp b/servers/audio/audio_driver_dummy.cpp index a2abbeb686..a28dcb1015 100644 --- a/servers/audio/audio_driver_dummy.cpp +++ b/servers/audio/audio_driver_dummy.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -39,16 +39,16 @@ Error AudioDriverDummy::init() { exit_thread = false; samples_in = nullptr; - mix_rate = GLOBAL_GET("audio/mix_rate"); + mix_rate = GLOBAL_GET("audio/driver/mix_rate"); speaker_mode = SPEAKER_MODE_STEREO; channels = 2; - int latency = GLOBAL_GET("audio/output_latency"); + int latency = GLOBAL_GET("audio/driver/output_latency"); buffer_frames = closest_power_of_2(latency * mix_rate / 1000); samples_in = memnew_arr(int32_t, buffer_frames * channels); - thread = Thread::create(AudioDriverDummy::thread_func, this); + thread.start(AudioDriverDummy::thread_func, this); return OK; }; @@ -86,31 +86,18 @@ AudioDriver::SpeakerMode AudioDriverDummy::get_speaker_mode() const { }; void AudioDriverDummy::lock() { - if (!thread) { - return; - } mutex.lock(); }; void AudioDriverDummy::unlock() { - if (!thread) { - return; - } mutex.unlock(); }; void AudioDriverDummy::finish() { - if (!thread) { - return; - } - exit_thread = true; - Thread::wait_to_finish(thread); + thread.wait_to_finish(); if (samples_in) { memdelete_arr(samples_in); }; - - memdelete(thread); - thread = nullptr; }; diff --git a/servers/audio/audio_driver_dummy.h b/servers/audio/audio_driver_dummy.h index 84a566e420..7d84e7ffc8 100644 --- a/servers/audio/audio_driver_dummy.h +++ b/servers/audio/audio_driver_dummy.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -37,7 +37,7 @@ #include "core/os/thread.h" class AudioDriverDummy : public AudioDriver { - Thread *thread = nullptr; + Thread thread; Mutex mutex; int32_t *samples_in; diff --git a/servers/audio/audio_effect.cpp b/servers/audio/audio_effect.cpp index d7279cdf48..3035828c95 100644 --- a/servers/audio/audio_effect.cpp +++ b/servers/audio/audio_effect.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/audio_effect.h b/servers/audio/audio_effect.h index b1be5dfea1..4556db9b93 100644 --- a/servers/audio/audio_effect.h +++ b/servers/audio/audio_effect.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/audio_filter_sw.cpp b/servers/audio/audio_filter_sw.cpp index f5eafb7e60..bcfa4c4c37 100644 --- a/servers/audio/audio_filter_sw.cpp +++ b/servers/audio/audio_filter_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -58,7 +58,7 @@ void AudioFilterSW::prepare_coefficients(Coeffs *p_coeffs) { final_cutoff = 1; //don't allow less than this } - double omega = 2.0 * Math_PI * final_cutoff / sampling_rate; + double omega = Math_TAU * final_cutoff / sampling_rate; double sin_v = Math::sin(omega); double cos_v = Math::cos(omega); @@ -132,7 +132,7 @@ void AudioFilterSW::prepare_coefficients(Coeffs *p_coeffs) { double hicutoff = resonance; double centercutoff = (cutoff + resonance) / 2.0; double bandwidth = (Math::log(centercutoff) - Math::log(hicutoff)) / Math::log((double)2); - omega = 2.0 * Math_PI * centercutoff / sampling_rate; + omega = Math_TAU * centercutoff / sampling_rate; alpha = Math::sin(omega) * Math::sinh(Math::log((double)2) / 2 * bandwidth * omega / Math::sin(omega)); a0 = 1 + alpha; @@ -197,7 +197,7 @@ void AudioFilterSW::set_stages(int p_stages) { //adjust for multiple stages /* Fouriertransform kernel to obtain response */ float AudioFilterSW::get_response(float p_freq, Coeffs *p_coeffs) { - float freq = p_freq / sampling_rate * Math_PI * 2.0f; + float freq = p_freq / sampling_rate * Math_TAU; float cx = p_coeffs->b0, cy = 0.0; diff --git a/servers/audio/audio_filter_sw.h b/servers/audio/audio_filter_sw.h index a7f570fbb4..540d6368e3 100644 --- a/servers/audio/audio_filter_sw.h +++ b/servers/audio/audio_filter_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/audio_rb_resampler.cpp b/servers/audio/audio_rb_resampler.cpp index 7613e70e64..3c8a1469cd 100644 --- a/servers/audio/audio_rb_resampler.cpp +++ b/servers/audio/audio_rb_resampler.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -131,7 +131,7 @@ bool AudioRBResampler::mix(AudioFrame *p_dest, int p_frames) { src_read = read_space; } - rb_read_pos = (rb_read_pos + src_read) & rb_mask; + rb_read_pos.set((rb_read_pos.get() + src_read) & rb_mask); // Create fadeout effect for the end of stream (note that it can be because of slow writer) if (p_frames - target_todo > 0) { @@ -183,8 +183,8 @@ Error AudioRBResampler::setup(int p_channels, int p_src_mix_rate, int p_target_m src_mix_rate = p_src_mix_rate; target_mix_rate = p_target_mix_rate; offset = 0; - rb_read_pos = 0; - rb_write_pos = 0; + rb_read_pos.set(0); + rb_write_pos.set(0); //avoid maybe strange noises upon load for (unsigned int i = 0; i < (rb_len * channels); i++) { @@ -205,8 +205,8 @@ void AudioRBResampler::clear() { memdelete_arr(read_buf); rb = nullptr; offset = 0; - rb_read_pos = 0; - rb_write_pos = 0; + rb_read_pos.set(0); + rb_write_pos.set(0); read_buf = nullptr; } @@ -214,8 +214,8 @@ AudioRBResampler::AudioRBResampler() { rb = nullptr; offset = 0; read_buf = nullptr; - rb_read_pos = 0; - rb_write_pos = 0; + rb_read_pos.set(0); + rb_write_pos.set(0); rb_bits = 0; rb_len = 0; diff --git a/servers/audio/audio_rb_resampler.h b/servers/audio/audio_rb_resampler.h index 12ec526adb..c0f981704b 100644 --- a/servers/audio/audio_rb_resampler.h +++ b/servers/audio/audio_rb_resampler.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -32,6 +32,7 @@ #define AUDIO_RB_RESAMPLER_H #include "core/os/memory.h" +#include "core/templates/safe_refcount.h" #include "core/typedefs.h" #include "servers/audio_server.h" @@ -44,8 +45,8 @@ struct AudioRBResampler { uint32_t src_mix_rate; uint32_t target_mix_rate; - volatile int rb_read_pos; - volatile int rb_write_pos; + SafeNumeric<int> rb_read_pos; + SafeNumeric<int> rb_write_pos; int32_t offset; //contains the fractional remainder of the resampler enum { @@ -62,8 +63,8 @@ struct AudioRBResampler { public: _FORCE_INLINE_ void flush() { - rb_read_pos = 0; - rb_write_pos = 0; + rb_read_pos.set(0); + rb_write_pos.set(0); offset = 0; } @@ -78,8 +79,8 @@ public: _FORCE_INLINE_ int get_writer_space() const { int space, r, w; - r = rb_read_pos; - w = rb_write_pos; + r = rb_read_pos.get(); + w = rb_write_pos.get(); if (r == w) { space = rb_len - 1; @@ -95,8 +96,8 @@ public: _FORCE_INLINE_ int get_reader_space() const { int space, r, w; - r = rb_read_pos; - w = rb_write_pos; + r = rb_read_pos.get(); + w = rb_write_pos.get(); if (r == w) { space = 0; @@ -110,48 +111,52 @@ public: } _FORCE_INLINE_ bool has_data() const { - return rb && rb_read_pos != rb_write_pos; + return rb && rb_read_pos.get() != rb_write_pos.get(); } _FORCE_INLINE_ float *get_write_buffer() { return read_buf; } _FORCE_INLINE_ void write(uint32_t p_frames) { ERR_FAIL_COND(p_frames >= rb_len); + int wp = rb_write_pos.get(); + switch (channels) { case 1: { for (uint32_t i = 0; i < p_frames; i++) { - rb[rb_write_pos] = read_buf[i]; - rb_write_pos = (rb_write_pos + 1) & rb_mask; + rb[wp] = read_buf[i]; + wp = (wp + 1) & rb_mask; } } break; case 2: { for (uint32_t i = 0; i < p_frames; i++) { - rb[(rb_write_pos << 1) + 0] = read_buf[(i << 1) + 0]; - rb[(rb_write_pos << 1) + 1] = read_buf[(i << 1) + 1]; - rb_write_pos = (rb_write_pos + 1) & rb_mask; + rb[(wp << 1) + 0] = read_buf[(i << 1) + 0]; + rb[(wp << 1) + 1] = read_buf[(i << 1) + 1]; + wp = (wp + 1) & rb_mask; } } break; case 4: { for (uint32_t i = 0; i < p_frames; i++) { - rb[(rb_write_pos << 2) + 0] = read_buf[(i << 2) + 0]; - rb[(rb_write_pos << 2) + 1] = read_buf[(i << 2) + 1]; - rb[(rb_write_pos << 2) + 2] = read_buf[(i << 2) + 2]; - rb[(rb_write_pos << 2) + 3] = read_buf[(i << 2) + 3]; - rb_write_pos = (rb_write_pos + 1) & rb_mask; + rb[(wp << 2) + 0] = read_buf[(i << 2) + 0]; + rb[(wp << 2) + 1] = read_buf[(i << 2) + 1]; + rb[(wp << 2) + 2] = read_buf[(i << 2) + 2]; + rb[(wp << 2) + 3] = read_buf[(i << 2) + 3]; + wp = (wp + 1) & rb_mask; } } break; case 6: { for (uint32_t i = 0; i < p_frames; i++) { - rb[(rb_write_pos * 6) + 0] = read_buf[(i * 6) + 0]; - rb[(rb_write_pos * 6) + 1] = read_buf[(i * 6) + 1]; - rb[(rb_write_pos * 6) + 2] = read_buf[(i * 6) + 2]; - rb[(rb_write_pos * 6) + 3] = read_buf[(i * 6) + 3]; - rb[(rb_write_pos * 6) + 4] = read_buf[(i * 6) + 4]; - rb[(rb_write_pos * 6) + 5] = read_buf[(i * 6) + 5]; - rb_write_pos = (rb_write_pos + 1) & rb_mask; + rb[(wp * 6) + 0] = read_buf[(i * 6) + 0]; + rb[(wp * 6) + 1] = read_buf[(i * 6) + 1]; + rb[(wp * 6) + 2] = read_buf[(i * 6) + 2]; + rb[(wp * 6) + 3] = read_buf[(i * 6) + 3]; + rb[(wp * 6) + 4] = read_buf[(i * 6) + 4]; + rb[(wp * 6) + 5] = read_buf[(i * 6) + 5]; + wp = (wp + 1) & rb_mask; } } break; } + + rb_write_pos.set(wp); } int get_channel_count() const; diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp index a7c9443dcf..ae07f999ed 100644 --- a/servers/audio/audio_stream.cpp +++ b/servers/audio/audio_stream.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -54,21 +54,21 @@ void AudioStreamPlaybackResampled::mix(AudioFrame *p_buffer, float p_rate_scale, for (int i = 0; i < p_frames; i++) { uint32_t idx = CUBIC_INTERP_HISTORY + uint32_t(mix_offset >> FP_BITS); - //standard cubic interpolation (great quality/performance ratio) - //this used to be moved to a LUT for greater performance, but nowadays CPU speed is generally faster than memory. + // 4 point, 4th order optimal resampling algorithm from: http://yehar.com/blog/wp-content/uploads/2009/08/deip.pdf float mu = (mix_offset & FP_MASK) / float(FP_LEN); AudioFrame y0 = internal_buffer[idx - 3]; AudioFrame y1 = internal_buffer[idx - 2]; AudioFrame y2 = internal_buffer[idx - 1]; AudioFrame y3 = internal_buffer[idx - 0]; - float mu2 = mu * mu; - AudioFrame a0 = y3 - y2 - y0 + y1; - AudioFrame a1 = y0 - y1 - a0; - AudioFrame a2 = y2 - y0; - AudioFrame a3 = y1; - - p_buffer[i] = (a0 * mu * mu2 + a1 * mu2 + a2 * mu + a3); + AudioFrame even1 = y2 + y1, odd1 = y2 - y1; + AudioFrame even2 = y3 + y0, odd2 = y3 - y0; + AudioFrame c0 = even1 * 0.46835497211269561 + even2 * 0.03164502784253309; + AudioFrame c1 = odd1 * 0.56001293337091440 + odd2 * 0.14666238593949288; + AudioFrame c2 = even1 * -0.250038759826233691 + even2 * 0.25003876124297131; + AudioFrame c3 = odd1 * -0.49949850957839148 + odd2 * 0.16649935475113800; + AudioFrame c4 = even1 * 0.00016095224137360 + even2 * -0.00016095810460478; + p_buffer[i] = (((c4 * mu + c3) * mu + c2) * mu + c1) * mu + c0; mix_offset += mix_increment; @@ -184,7 +184,7 @@ void AudioStreamPlaybackMicrophone::start(float p_from_pos) { return; } - if (!GLOBAL_GET("audio/enable_audio_input")) { + if (!GLOBAL_GET("audio/driver/enable_input")) { WARN_PRINT("Need to enable Project settings > Audio > Enable Audio Input option to use capturing."); return; } diff --git a/servers/audio/audio_stream.h b/servers/audio/audio_stream.h index 0bbb29b15c..93566783be 100644 --- a/servers/audio/audio_stream.h +++ b/servers/audio/audio_stream.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_amplify.cpp b/servers/audio/effects/audio_effect_amplify.cpp index 74fdcbc67a..c5c1174670 100644 --- a/servers/audio/effects/audio_effect_amplify.cpp +++ b/servers/audio/effects/audio_effect_amplify.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_amplify.h b/servers/audio/effects/audio_effect_amplify.h index 7245bbdcbe..2ece57854c 100644 --- a/servers/audio/effects/audio_effect_amplify.h +++ b/servers/audio/effects/audio_effect_amplify.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_capture.cpp b/servers/audio/effects/audio_effect_capture.cpp new file mode 100644 index 0000000000..37e4122e50 --- /dev/null +++ b/servers/audio/effects/audio_effect_capture.cpp @@ -0,0 +1,140 @@ +/*************************************************************************/ +/* audio_effect_capture.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "audio_effect_capture.h" + +bool AudioEffectCapture::can_get_buffer(int p_frames) const { + return buffer.data_left() >= p_frames; +} + +PackedVector2Array AudioEffectCapture::get_buffer(int p_frames) { + ERR_FAIL_COND_V(!buffer_initialized, PackedVector2Array()); + ERR_FAIL_INDEX_V(p_frames, buffer.size(), PackedVector2Array()); + int data_left = buffer.data_left(); + if (data_left < p_frames || p_frames == 0) { + return PackedVector2Array(); + } + + PackedVector2Array ret; + ret.resize(p_frames); + + Vector<AudioFrame> streaming_data; + streaming_data.resize(p_frames); + buffer.read(streaming_data.ptrw(), p_frames); + for (int32_t i = 0; i < p_frames; i++) { + ret.write[i] = Vector2(streaming_data[i].l, streaming_data[i].r); + } + return ret; +} + +void AudioEffectCapture::clear_buffer() { + const int32_t data_left = buffer.data_left(); + buffer.advance_read(data_left); +} + +void AudioEffectCapture::_bind_methods() { + ClassDB::bind_method(D_METHOD("can_get_buffer", "frames"), &AudioEffectCapture::can_get_buffer); + ClassDB::bind_method(D_METHOD("get_buffer", "frames"), &AudioEffectCapture::get_buffer); + ClassDB::bind_method(D_METHOD("clear_buffer"), &AudioEffectCapture::clear_buffer); + ClassDB::bind_method(D_METHOD("set_buffer_length", "buffer_length_seconds"), &AudioEffectCapture::set_buffer_length); + ClassDB::bind_method(D_METHOD("get_buffer_length"), &AudioEffectCapture::get_buffer_length); + ClassDB::bind_method(D_METHOD("get_frames_available"), &AudioEffectCapture::get_frames_available); + ClassDB::bind_method(D_METHOD("get_discarded_frames"), &AudioEffectCapture::get_discarded_frames); + ClassDB::bind_method(D_METHOD("get_buffer_length_frames"), &AudioEffectCapture::get_buffer_length_frames); + ClassDB::bind_method(D_METHOD("get_pushed_frames"), &AudioEffectCapture::get_pushed_frames); + + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "buffer_length", PROPERTY_HINT_RANGE, "0.01,10,0.01"), "set_buffer_length", "get_buffer_length"); +} + +Ref<AudioEffectInstance> AudioEffectCapture::instance() { + if (!buffer_initialized) { + float target_buffer_size = AudioServer::get_singleton()->get_mix_rate() * buffer_length_seconds; + ERR_FAIL_COND_V(target_buffer_size <= 0 || target_buffer_size >= (1 << 27), Ref<AudioEffectInstance>()); + buffer.resize(nearest_shift((int)target_buffer_size)); + buffer_initialized = true; + } + + clear_buffer(); + + Ref<AudioEffectCaptureInstance> ins; + ins.instance(); + ins->base = Ref<AudioEffectCapture>(this); + + return ins; +} + +void AudioEffectCapture::set_buffer_length(float p_buffer_length_seconds) { + ERR_FAIL_COND(buffer_initialized); + + buffer_length_seconds = p_buffer_length_seconds; +} + +float AudioEffectCapture::get_buffer_length() { + return buffer_length_seconds; +} + +int AudioEffectCapture::get_frames_available() const { + ERR_FAIL_COND_V(!buffer_initialized, 0); + return buffer.data_left(); +} + +int64_t AudioEffectCapture::get_discarded_frames() const { + return discarded_frames.get(); +} + +int AudioEffectCapture::get_buffer_length_frames() const { + ERR_FAIL_COND_V(!buffer_initialized, 0); + return buffer.size(); +} + +int64_t AudioEffectCapture::get_pushed_frames() const { + return pushed_frames.get(); +} + +void AudioEffectCaptureInstance::process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) { + RingBuffer<AudioFrame> &buffer = base->buffer; + + for (int i = 0; i < p_frame_count; i++) { + p_dst_frames[i] = p_src_frames[i]; + } + + if (buffer.space_left() >= p_frame_count) { + // Add incoming audio frames to the IO ring buffer + int32_t ret = buffer.write(p_src_frames, p_frame_count); + ERR_FAIL_COND_MSG(ret != p_frame_count, "Failed to add data to effect capture ring buffer despite sufficient space."); + base->pushed_frames.add(p_frame_count); + } else { + base->discarded_frames.add(p_frame_count); + } +} + +bool AudioEffectCaptureInstance::process_silence() const { + return true; +} diff --git a/servers/audio/effects/audio_effect_capture.h b/servers/audio/effects/audio_effect_capture.h new file mode 100644 index 0000000000..81d4ed6b0f --- /dev/null +++ b/servers/audio/effects/audio_effect_capture.h @@ -0,0 +1,82 @@ +/*************************************************************************/ +/* audio_effect_capture.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef AUDIO_EFFECT_CAPTURE_H +#define AUDIO_EFFECT_CAPTURE_H + +#include "core/config/engine.h" +#include "core/math/audio_frame.h" +#include "core/object/reference.h" +#include "core/templates/vector.h" +#include "servers/audio/audio_effect.h" +#include "servers/audio_server.h" + +class AudioEffectCapture; + +class AudioEffectCaptureInstance : public AudioEffectInstance { + GDCLASS(AudioEffectCaptureInstance, AudioEffectInstance); + friend class AudioEffectCapture; + Ref<AudioEffectCapture> base; + +public: + virtual void process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) override; + virtual bool process_silence() const override; +}; + +class AudioEffectCapture : public AudioEffect { + GDCLASS(AudioEffectCapture, AudioEffect) + friend class AudioEffectCaptureInstance; + + RingBuffer<AudioFrame> buffer; + SafeNumeric<uint64_t> discarded_frames; + SafeNumeric<uint64_t> pushed_frames; + float buffer_length_seconds = 0.1f; + bool buffer_initialized = false; + +protected: + static void _bind_methods(); + +public: + virtual Ref<AudioEffectInstance> instance() override; + + void set_buffer_length(float p_buffer_length_seconds); + float get_buffer_length(); + + bool can_get_buffer(int p_frames) const; + PackedVector2Array get_buffer(int p_len); + void clear_buffer(); + + int get_frames_available() const; + int64_t get_discarded_frames() const; + int get_buffer_length_frames() const; + int64_t get_pushed_frames() const; +}; + +#endif // AUDIO_EFFECT_CAPTURE_H diff --git a/servers/audio/effects/audio_effect_chorus.cpp b/servers/audio/effects/audio_effect_chorus.cpp index 2b530475f0..76a995eb37 100644 --- a/servers/audio/effects/audio_effect_chorus.cpp +++ b/servers/audio/effects/audio_effect_chorus.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -84,7 +84,7 @@ void AudioEffectChorusInstance::_process_chunk(const AudioFrame *p_src_frames, A if (v.cutoff == 0) { continue; } - float auxlp = expf(-2.0 * Math_PI * v.cutoff / mix_rate); + float auxlp = expf(-Math_TAU * v.cutoff / mix_rate); float c1 = 1.0 - auxlp; float c2 = auxlp; AudioFrame h = filter_h[vc]; @@ -104,7 +104,7 @@ void AudioEffectChorusInstance::_process_chunk(const AudioFrame *p_src_frames, A float phase = (float)(local_cycles & AudioEffectChorus::CYCLES_MASK) / (float)(1 << AudioEffectChorus::CYCLES_FRAC); - float wave_delay = sinf(phase * 2.0 * Math_PI) * max_depth_frames; + float wave_delay = sinf(phase * Math_TAU) * max_depth_frames; int wave_delay_frames = lrint(floor(wave_delay)); float wave_delay_frac = wave_delay - (float)wave_delay_frames; diff --git a/servers/audio/effects/audio_effect_chorus.h b/servers/audio/effects/audio_effect_chorus.h index b32b300dfa..f5b023734a 100644 --- a/servers/audio/effects/audio_effect_chorus.h +++ b/servers/audio/effects/audio_effect_chorus.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_compressor.cpp b/servers/audio/effects/audio_effect_compressor.cpp index 4b0b4dabea..bb4a90f3d6 100644 --- a/servers/audio/effects/audio_effect_compressor.cpp +++ b/servers/audio/effects/audio_effect_compressor.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_compressor.h b/servers/audio/effects/audio_effect_compressor.h index be187605c5..33c60680fc 100644 --- a/servers/audio/effects/audio_effect_compressor.h +++ b/servers/audio/effects/audio_effect_compressor.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_delay.cpp b/servers/audio/effects/audio_effect_delay.cpp index d6ab14be89..ba50eeb0a3 100644 --- a/servers/audio/effects/audio_effect_delay.cpp +++ b/servers/audio/effects/audio_effect_delay.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -75,7 +75,7 @@ void AudioEffectDelayInstance::_process_chunk(const AudioFrame *p_src_frames, Au tap2_vol.r *= CLAMP(1.0 + base->tap_2_pan, 0, 1); // feedback lowpass here - float lpf_c = expf(-2.0 * Math_PI * base->feedback_lowpass / mix_rate); // 0 .. 10khz + float lpf_c = expf(-Math_TAU * base->feedback_lowpass / mix_rate); // 0 .. 10khz float lpf_ic = 1.0 - lpf_c; const AudioFrame *src = p_src_frames; diff --git a/servers/audio/effects/audio_effect_delay.h b/servers/audio/effects/audio_effect_delay.h index 3b7f2ea458..ff267d5023 100644 --- a/servers/audio/effects/audio_effect_delay.h +++ b/servers/audio/effects/audio_effect_delay.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_distortion.cpp b/servers/audio/effects/audio_effect_distortion.cpp index dc5c2cc16f..06d51776a3 100644 --- a/servers/audio/effects/audio_effect_distortion.cpp +++ b/servers/audio/effects/audio_effect_distortion.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -36,8 +36,8 @@ void AudioEffectDistortionInstance::process(const AudioFrame *p_src_frames, Audi const float *src = (const float *)p_src_frames; float *dst = (float *)p_dst_frames; - //float lpf_c=expf(-2.0*Math_PI*keep_hf_hz.get()/(mix_rate*(float)OVERSAMPLE)); - float lpf_c = expf(-2.0 * Math_PI * base->keep_hf_hz / (AudioServer::get_singleton()->get_mix_rate())); + //float lpf_c=expf(-Math_TAU*keep_hf_hz.get()/(mix_rate*(float)OVERSAMPLE)); + float lpf_c = expf(-Math_TAU * base->keep_hf_hz / (AudioServer::get_singleton()->get_mix_rate())); float lpf_ic = 1.0 - lpf_c; float drive_f = base->drive; @@ -58,7 +58,8 @@ void AudioEffectDistortionInstance::process(const AudioFrame *p_src_frames, Audi switch (base->mode) { case AudioEffectDistortion::MODE_CLIP: { - a = powf(a, 1.0001 - drive_f); + float a_sign = a < 0 ? -1.0f : 1.0f; + a = powf(abs(a), 1.0001 - drive_f) * a_sign; if (a > 1.0) { a = 1.0; } else if (a < (-1.0)) { diff --git a/servers/audio/effects/audio_effect_distortion.h b/servers/audio/effects/audio_effect_distortion.h index 8149fc3f0a..9da800b79f 100644 --- a/servers/audio/effects/audio_effect_distortion.h +++ b/servers/audio/effects/audio_effect_distortion.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_eq.cpp b/servers/audio/effects/audio_effect_eq.cpp index ed4e7122b5..01ac605bd7 100644 --- a/servers/audio/effects/audio_effect_eq.cpp +++ b/servers/audio/effects/audio_effect_eq.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_eq.h b/servers/audio/effects/audio_effect_eq.h index 5a639f64d4..38c63a7d4f 100644 --- a/servers/audio/effects/audio_effect_eq.h +++ b/servers/audio/effects/audio_effect_eq.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_filter.cpp b/servers/audio/effects/audio_effect_filter.cpp index a5135ee1a6..c2d6074825 100644 --- a/servers/audio/effects/audio_effect_filter.cpp +++ b/servers/audio/effects/audio_effect_filter.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_filter.h b/servers/audio/effects/audio_effect_filter.h index 16940173ba..9a48ccf70b 100644 --- a/servers/audio/effects/audio_effect_filter.h +++ b/servers/audio/effects/audio_effect_filter.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_limiter.cpp b/servers/audio/effects/audio_effect_limiter.cpp index 27f1aaf71f..1a4b01d947 100644 --- a/servers/audio/effects/audio_effect_limiter.cpp +++ b/servers/audio/effects/audio_effect_limiter.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_limiter.h b/servers/audio/effects/audio_effect_limiter.h index 5204c42759..8f3092c0e2 100644 --- a/servers/audio/effects/audio_effect_limiter.h +++ b/servers/audio/effects/audio_effect_limiter.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_panner.cpp b/servers/audio/effects/audio_effect_panner.cpp index 32b7921d1f..238e979e13 100644 --- a/servers/audio/effects/audio_effect_panner.cpp +++ b/servers/audio/effects/audio_effect_panner.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_panner.h b/servers/audio/effects/audio_effect_panner.h index b4aa7a58b9..0938824c64 100644 --- a/servers/audio/effects/audio_effect_panner.h +++ b/servers/audio/effects/audio_effect_panner.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_phaser.cpp b/servers/audio/effects/audio_effect_phaser.cpp index ffeaa7d25e..9b70f03a19 100644 --- a/servers/audio/effects/audio_effect_phaser.cpp +++ b/servers/audio/effects/audio_effect_phaser.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -38,13 +38,13 @@ void AudioEffectPhaserInstance::process(const AudioFrame *p_src_frames, AudioFra float dmin = base->range_min / (sampling_rate / 2.0); float dmax = base->range_max / (sampling_rate / 2.0); - float increment = 2.f * Math_PI * (base->rate / sampling_rate); + float increment = Math_TAU * (base->rate / sampling_rate); for (int i = 0; i < p_frame_count; i++) { phase += increment; - while (phase >= Math_PI * 2.f) { - phase -= Math_PI * 2.f; + while (phase >= Math_TAU) { + phase -= Math_TAU; } float d = dmin + (dmax - dmin) * ((sin(phase) + 1.f) / 2.f); diff --git a/servers/audio/effects/audio_effect_phaser.h b/servers/audio/effects/audio_effect_phaser.h index dbf014dbac..563927c678 100644 --- a/servers/audio/effects/audio_effect_phaser.h +++ b/servers/audio/effects/audio_effect_phaser.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_pitch_shift.cpp b/servers/audio/effects/audio_effect_pitch_shift.cpp index fdba1b59a3..2123fe8548 100644 --- a/servers/audio/effects/audio_effect_pitch_shift.cpp +++ b/servers/audio/effects/audio_effect_pitch_shift.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_pitch_shift.h b/servers/audio/effects/audio_effect_pitch_shift.h index 0fa4de6b5b..18a9c33968 100644 --- a/servers/audio/effects/audio_effect_pitch_shift.h +++ b/servers/audio/effects/audio_effect_pitch_shift.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_record.cpp b/servers/audio/effects/audio_effect_record.cpp index 79388b2dc7..2015ede81f 100644 --- a/servers/audio/effects/audio_effect_record.cpp +++ b/servers/audio/effects/audio_effect_record.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -118,7 +118,7 @@ void AudioEffectRecordInstance::init() { #ifdef NO_THREADS AudioServer::get_singleton()->add_update_callback(&AudioEffectRecordInstance::_update, this); #else - io_thread = Thread::create(_thread_callback, this); + io_thread.start(_thread_callback, this); #endif } @@ -126,9 +126,7 @@ void AudioEffectRecordInstance::finish() { #ifdef NO_THREADS AudioServer::get_singleton()->remove_update_callback(&AudioEffectRecordInstance::_update, this); #else - if (thread_active) { - Thread::wait_to_finish(io_thread); - } + io_thread.wait_to_finish(); #endif } diff --git a/servers/audio/effects/audio_effect_record.h b/servers/audio/effects/audio_effect_record.h index 55080539d3..b97ec43946 100644 --- a/servers/audio/effects/audio_effect_record.h +++ b/servers/audio/effects/audio_effect_record.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -48,7 +48,7 @@ class AudioEffectRecordInstance : public AudioEffectInstance { Ref<AudioEffectRecord> base; bool is_recording; - Thread *io_thread; + Thread io_thread; bool thread_active = false; Vector<AudioFrame> ring_buffer; diff --git a/servers/audio/effects/audio_effect_reverb.cpp b/servers/audio/effects/audio_effect_reverb.cpp index f6465abfaf..b8d812680e 100644 --- a/servers/audio/effects/audio_effect_reverb.cpp +++ b/servers/audio/effects/audio_effect_reverb.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_reverb.h b/servers/audio/effects/audio_effect_reverb.h index 3a1922bc1d..141ba48e29 100644 --- a/servers/audio/effects/audio_effect_reverb.h +++ b/servers/audio/effects/audio_effect_reverb.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_spectrum_analyzer.cpp b/servers/audio/effects/audio_effect_spectrum_analyzer.cpp index 3f4f11ee8d..3f7ab74a74 100644 --- a/servers/audio/effects/audio_effect_spectrum_analyzer.cpp +++ b/servers/audio/effects/audio_effect_spectrum_analyzer.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -110,10 +110,11 @@ void AudioEffectSpectrumAnalyzerInstance::process(const AudioFrame *p_src_frames while (p_frame_count) { int to_fill = fft_size * 2 - temporal_fft_pos; to_fill = MIN(to_fill, p_frame_count); + const double to_fill_step = Math_TAU / (double)fft_size; float *fftw = temporal_fft.ptrw(); for (int i = 0; i < to_fill; i++) { //left and right buffers - float window = -0.5 * Math::cos(2.0 * Math_PI * (double)temporal_fft_pos / (double)fft_size) + 0.5; + float window = -0.5 * Math::cos(to_fill_step * (double)temporal_fft_pos) + 0.5; fftw[temporal_fft_pos * 2] = window * p_src_frames->l; fftw[temporal_fft_pos * 2 + 1] = 0; fftw[(temporal_fft_pos + fft_size * 2) * 2] = window * p_src_frames->r; diff --git a/servers/audio/effects/audio_effect_spectrum_analyzer.h b/servers/audio/effects/audio_effect_spectrum_analyzer.h index 0eacd43b57..fba276e2bb 100644 --- a/servers/audio/effects/audio_effect_spectrum_analyzer.h +++ b/servers/audio/effects/audio_effect_spectrum_analyzer.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_stereo_enhance.cpp b/servers/audio/effects/audio_effect_stereo_enhance.cpp index 4f9bee83e4..dfdf154aa4 100644 --- a/servers/audio/effects/audio_effect_stereo_enhance.cpp +++ b/servers/audio/effects/audio_effect_stereo_enhance.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_stereo_enhance.h b/servers/audio/effects/audio_effect_stereo_enhance.h index 98ee18ba5a..f99256470b 100644 --- a/servers/audio/effects/audio_effect_stereo_enhance.h +++ b/servers/audio/effects/audio_effect_stereo_enhance.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_stream_generator.cpp b/servers/audio/effects/audio_stream_generator.cpp index aba04550db..d1a05ccf2a 100644 --- a/servers/audio/effects/audio_stream_generator.cpp +++ b/servers/audio/effects/audio_stream_generator.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_stream_generator.h b/servers/audio/effects/audio_stream_generator.h index 49bda0fcf9..5d46771f4d 100644 --- a/servers/audio/effects/audio_stream_generator.h +++ b/servers/audio/effects/audio_stream_generator.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/eq.cpp b/servers/audio/effects/eq.cpp index 15abeea5f3..e0c3eb6d3a 100644 --- a/servers/audio/effects/eq.cpp +++ b/servers/audio/effects/eq.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -89,8 +89,8 @@ void EQ::recalculate_band_coefficients() { double frq_l = round(frq / pow(2.0, octave_size / 2.0)); double side_gain2 = POW2(Math_SQRT12); - double th = 2.0 * Math_PI * frq / mix_rate; - double th_l = 2.0 * Math_PI * frq_l / mix_rate; + double th = Math_TAU * frq / mix_rate; + double th_l = Math_TAU * frq_l / mix_rate; double c2a = side_gain2 * POW2(cos(th)) - 2.0 * side_gain2 * cos(th_l) * cos(th) + side_gain2 - POW2(sin(th_l)); diff --git a/servers/audio/effects/eq.h b/servers/audio/effects/eq.h index c908c9c8fb..afd5bf5334 100644 --- a/servers/audio/effects/eq.h +++ b/servers/audio/effects/eq.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/reverb.cpp b/servers/audio/effects/reverb.cpp index 1deb1499b5..7df2f99f67 100644 --- a/servers/audio/effects/reverb.cpp +++ b/servers/audio/effects/reverb.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -91,7 +91,7 @@ void Reverb::process(float *p_src, float *p_dst, int p_frames) { } if (params.hpf > 0) { - float hpaux = expf(-2.0 * Math_PI * params.hpf * 6000 / params.mix_rate); + float hpaux = expf(-Math_TAU * params.hpf * 6000 / params.mix_rate); float hp_a1 = (1.0 + hpaux) / 2.0; float hp_a2 = -(1.0 + hpaux) / 2.0; float hp_b1 = hpaux; @@ -293,7 +293,7 @@ void Reverb::update_parameters() { float auxdmp = params.damp / 2.0 + 0.5; //only half the range (0.5 .. 1.0 is enough) auxdmp *= auxdmp; - c.damp = expf(-2.0 * Math_PI * auxdmp * 10000 / params.mix_rate); // 0 .. 10khz + c.damp = expf(-Math_TAU * auxdmp * 10000 / params.mix_rate); // 0 .. 10khz } } diff --git a/servers/audio/effects/reverb.h b/servers/audio/effects/reverb.h index 7dd88f9faf..e7ce55098d 100644 --- a/servers/audio/effects/reverb.h +++ b/servers/audio/effects/reverb.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index bea5e9e432..138cb6e1f8 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -71,13 +71,20 @@ void AudioDriver::update_mix_time(int p_frames) { } } -double AudioDriver::get_time_since_last_mix() const { - return (OS::get_singleton()->get_ticks_usec() - _last_mix_time) / 1000000.0; +double AudioDriver::get_time_since_last_mix() { + lock(); + uint64_t last_mix_time = _last_mix_time; + unlock(); + return (OS::get_singleton()->get_ticks_usec() - last_mix_time) / 1000000.0; } -double AudioDriver::get_time_to_next_mix() const { - double total = (OS::get_singleton()->get_ticks_usec() - _last_mix_time) / 1000000.0; - double mix_buffer = _last_mix_frames / (double)get_mix_rate(); +double AudioDriver::get_time_to_next_mix() { + lock(); + uint64_t last_mix_time = _last_mix_time; + uint64_t last_mix_frames = _last_mix_frames; + unlock(); + double total = (OS::get_singleton()->get_ticks_usec() - last_mix_time) / 1000000.0; + double mix_buffer = last_mix_frames / (double)get_mix_rate(); return mix_buffer - total; } @@ -181,10 +188,10 @@ int AudioDriverManager::get_driver_count() { } void AudioDriverManager::initialize(int p_driver) { - GLOBAL_DEF_RST("audio/enable_audio_input", false); - GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE); - GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY); - GLOBAL_DEF_RST("audio/output_latency.web", 50); // Safer default output_latency for web. + GLOBAL_DEF_RST("audio/driver/enable_input", false); + GLOBAL_DEF_RST("audio/driver/mix_rate", DEFAULT_MIX_RATE); + GLOBAL_DEF_RST("audio/driver/output_latency", DEFAULT_OUTPUT_LATENCY); + GLOBAL_DEF_RST("audio/driver/output_latency.web", 50); // Safer default output_latency for web. int failed_driver = -1; @@ -394,6 +401,7 @@ void AudioServer::_mix_step() { for (int k = 0; k < bus->channels.size(); k++) { if (!bus->channels[k].active) { + bus->channels.write[k].peak_volume = AudioFrame(AUDIO_MIN_PEAK_DB, AUDIO_MIN_PEAK_DB); continue; } @@ -427,7 +435,7 @@ void AudioServer::_mix_step() { } } - bus->channels.write[k].peak_volume = AudioFrame(Math::linear2db(peak.l + 0.0000000001), Math::linear2db(peak.r + 0.0000000001)); + bus->channels.write[k].peak_volume = AudioFrame(Math::linear2db(peak.l + AUDIO_PEAK_OFFSET), Math::linear2db(peak.r + AUDIO_PEAK_OFFSET)); if (!bus->channels[k].used) { //see if any audio is contained, because channel was not used @@ -931,9 +939,9 @@ void AudioServer::init_channels_and_buffers() { } void AudioServer::init() { - channel_disable_threshold_db = GLOBAL_DEF_RST("audio/channel_disable_threshold_db", -60.0); - channel_disable_frames = float(GLOBAL_DEF_RST("audio/channel_disable_time", 2.0)) * get_mix_rate(); - ProjectSettings::get_singleton()->set_custom_property_info("audio/channel_disable_time", PropertyInfo(Variant::FLOAT, "audio/channel_disable_time", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater")); + channel_disable_threshold_db = GLOBAL_DEF_RST("audio/buses/channel_disable_threshold_db", -60.0); + channel_disable_frames = float(GLOBAL_DEF_RST("audio/buses/channel_disable_time", 2.0)) * get_mix_rate(); + ProjectSettings::get_singleton()->set_custom_property_info("audio/buses/channel_disable_time", PropertyInfo(Variant::FLOAT, "audio/buses/channel_disable_time", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater")); buffer_size = 1024; //hardcoded for now init_channels_and_buffers(); @@ -950,7 +958,7 @@ void AudioServer::init() { set_edited(false); //avoid editors from thinking this was edited #endif - GLOBAL_DEF_RST("audio/video_delay_compensation_ms", 0); + GLOBAL_DEF_RST("audio/video/video_delay_compensation_ms", 0); } void AudioServer::update() { @@ -1027,7 +1035,7 @@ void AudioServer::update() { } void AudioServer::load_default_bus_layout() { - String layout_path = ProjectSettings::get_singleton()->get("audio/default_bus_layout"); + String layout_path = ProjectSettings::get_singleton()->get("audio/buses/default_bus_layout"); if (ResourceLoader::exists(layout_path)) { Ref<AudioBusLayout> default_layout = ResourceLoader::load(layout_path); diff --git a/servers/audio_server.h b/servers/audio_server.h index 83377a5e9e..a1a373e1ca 100644 --- a/servers/audio_server.h +++ b/servers/audio_server.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -70,8 +70,8 @@ protected: #endif public: - double get_time_since_last_mix() const; //useful for video -> audio sync - double get_time_to_next_mix() const; + double get_time_since_last_mix(); //useful for video -> audio sync + double get_time_to_next_mix(); enum SpeakerMode { SPEAKER_MODE_STEREO, @@ -199,7 +199,7 @@ private: last_mix_with_audio = 0; used = false; active = false; - peak_volume = AudioFrame(0, 0); + peak_volume = AudioFrame(AUDIO_MIN_PEAK_DB, AUDIO_MIN_PEAK_DB); } }; diff --git a/servers/camera/SCsub b/servers/camera/SCsub index c949f3bb25..86681f9c74 100644 --- a/servers/camera/SCsub +++ b/servers/camera/SCsub @@ -3,5 +3,3 @@ Import("env") env.add_source_files(env.servers_sources, "*.cpp") - -Export("env") diff --git a/servers/camera/camera_feed.cpp b/servers/camera/camera_feed.cpp index 41f44abae8..be812cf62d 100644 --- a/servers/camera/camera_feed.cpp +++ b/servers/camera/camera_feed.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/camera/camera_feed.h b/servers/camera/camera_feed.h index dca583c9de..fc02af4249 100644 --- a/servers/camera/camera_feed.h +++ b/servers/camera/camera_feed.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/camera_server.cpp b/servers/camera_server.cpp index 3caea6b7c3..b06f32417c 100644 --- a/servers/camera_server.cpp +++ b/servers/camera_server.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/camera_server.h b/servers/camera_server.h index 54acce006a..97aa8f74ba 100644 --- a/servers/camera_server.h +++ b/servers/camera_server.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -95,15 +95,16 @@ public: int get_feed_index(int p_id); Ref<CameraFeed> get_feed_by_id(int p_id); - // add and remove feeds + // Add and remove feeds. void add_feed(const Ref<CameraFeed> &p_feed); void remove_feed(const Ref<CameraFeed> &p_feed); - // get our feeds + // Get our feeds. Ref<CameraFeed> get_feed(int p_index); int get_feed_count(); Array get_feeds(); + // Intended for use with custom CameraServer implementation. RID feed_texture(int p_id, FeedImage p_texture); CameraServer(); diff --git a/servers/display_server.cpp b/servers/display_server.cpp index e678c6919b..2fa333cc05 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -477,7 +477,7 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("enable_for_stealing_focus", "process_id"), &DisplayServer::enable_for_stealing_focus); - ClassDB::bind_method(D_METHOD("native_video_play", "path", "volume", "audio_track", "subtitle_track"), &DisplayServer::native_video_play); + ClassDB::bind_method(D_METHOD("native_video_play", "path", "volume", "audio_track", "subtitle_track", "screen"), &DisplayServer::native_video_play); ClassDB::bind_method(D_METHOD("native_video_is_playing"), &DisplayServer::native_video_is_playing); ClassDB::bind_method(D_METHOD("native_video_stop"), &DisplayServer::native_video_stop); ClassDB::bind_method(D_METHOD("native_video_pause"), &DisplayServer::native_video_pause); @@ -504,6 +504,11 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_native_icon", "filename"), &DisplayServer::set_native_icon); ClassDB::bind_method(D_METHOD("set_icon", "image"), &DisplayServer::set_icon); + ClassDB::bind_method(D_METHOD("tablet_get_driver_count"), &DisplayServer::tablet_get_driver_count); + ClassDB::bind_method(D_METHOD("tablet_get_driver_name", "idx"), &DisplayServer::tablet_get_driver_name); + ClassDB::bind_method(D_METHOD("tablet_get_current_driver"), &DisplayServer::tablet_get_current_driver); + ClassDB::bind_method(D_METHOD("tablet_set_current_driver", "name"), &DisplayServer::tablet_set_current_driver); + BIND_ENUM_CONSTANT(FEATURE_GLOBAL_MENU); BIND_ENUM_CONSTANT(FEATURE_SUBWINDOWS); BIND_ENUM_CONSTANT(FEATURE_TOUCHSCREEN); diff --git a/servers/display_server.h b/servers/display_server.h index 59bee794b8..3aab572120 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -83,7 +83,7 @@ protected: static DisplayServerCreate server_create_functions[MAX_SERVERS]; static int server_create_count; - friend class RenderingServerRaster; + friend class RendererViewport; virtual void _set_use_vsync(bool p_enable); public: @@ -340,6 +340,11 @@ public: virtual String keyboard_get_layout_language(int p_index) const; virtual String keyboard_get_layout_name(int p_index) const; + virtual int tablet_get_driver_count() const { return 1; }; + virtual String tablet_get_driver_name(int p_driver) const { return "default"; }; + virtual String tablet_get_current_driver() const { return "default"; }; + virtual void tablet_set_current_driver(const String &p_driver){}; + virtual void process_events() = 0; virtual void force_process_and_drop_events(); diff --git a/servers/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp index b20f6865cd..df348d2add 100644 --- a/servers/navigation_server_2d.cpp +++ b/servers/navigation_server_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/navigation_server_2d.h b/servers/navigation_server_2d.h index 895e41558a..7be5a74cb3 100644 --- a/servers/navigation_server_2d.h +++ b/servers/navigation_server_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp index 8f9b5df589..0e5ae82b0d 100644 --- a/servers/navigation_server_3d.cpp +++ b/servers/navigation_server_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h index e6421462b0..3761c3871a 100644 --- a/servers/navigation_server_3d.h +++ b/servers/navigation_server_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_2d/area_2d_sw.cpp b/servers/physics_2d/area_2d_sw.cpp index 7485f31afc..6485c8d1e9 100644 --- a/servers/physics_2d/area_2d_sw.cpp +++ b/servers/physics_2d/area_2d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -199,7 +199,7 @@ void Area2DSW::set_monitorable(bool p_monitorable) { } void Area2DSW::call_queries() { - if (monitor_callback_id.is_valid() && !monitored_bodies.empty()) { + if (monitor_callback_id.is_valid() && !monitored_bodies.is_empty()) { Variant res[5]; Variant *resptr[5]; for (int i = 0; i < 5; i++) { @@ -234,7 +234,7 @@ void Area2DSW::call_queries() { } } - if (area_monitor_callback_id.is_valid() && !monitored_areas.empty()) { + if (area_monitor_callback_id.is_valid() && !monitored_areas.is_empty()) { Variant res[5]; Variant *resptr[5]; for (int i = 0; i < 5; i++) { diff --git a/servers/physics_2d/area_2d_sw.h b/servers/physics_2d/area_2d_sw.h index d6b358a657..3bf603b30d 100644 --- a/servers/physics_2d/area_2d_sw.h +++ b/servers/physics_2d/area_2d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_2d/area_pair_2d_sw.cpp b/servers/physics_2d/area_pair_2d_sw.cpp index d7bceb9f02..21ad57e344 100644 --- a/servers/physics_2d/area_pair_2d_sw.cpp +++ b/servers/physics_2d/area_pair_2d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -89,7 +89,7 @@ AreaPair2DSW::~AreaPair2DSW() { area->remove_body_from_query(body, body_shape, area_shape); } } - body->remove_constraint(this); + body->remove_constraint(this, 0); area->remove_constraint(this); } diff --git a/servers/physics_2d/area_pair_2d_sw.h b/servers/physics_2d/area_pair_2d_sw.h index 5e8670b464..4015aad5d1 100644 --- a/servers/physics_2d/area_pair_2d_sw.h +++ b/servers/physics_2d/area_pair_2d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp index 75c9a95739..d0636047b7 100644 --- a/servers/physics_2d/body_2d_sw.cpp +++ b/servers/physics_2d/body_2d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -562,13 +562,13 @@ void Body2DSW::integrate_velocities(real_t p_step) { } void Body2DSW::wakeup_neighbours() { - for (Map<Constraint2DSW *, int>::Element *E = constraint_map.front(); E; E = E->next()) { - const Constraint2DSW *c = E->key(); + for (List<Pair<Constraint2DSW *, int>>::Element *E = constraint_list.front(); E; E = E->next()) { + const Constraint2DSW *c = E->get().first; Body2DSW **n = c->get_body_ptr(); int bc = c->get_body_count(); for (int i = 0; i < bc; i++) { - if (i == E->get()) { + if (i == E->get().second) { continue; } Body2DSW *b = n[i]; diff --git a/servers/physics_2d/body_2d_sw.h b/servers/physics_2d/body_2d_sw.h index bbc22a67df..60d55ab8bd 100644 --- a/servers/physics_2d/body_2d_sw.h +++ b/servers/physics_2d/body_2d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -33,6 +33,8 @@ #include "area_2d_sw.h" #include "collision_object_2d_sw.h" +#include "core/templates/list.h" +#include "core/templates/pair.h" #include "core/templates/vset.h" class Constraint2DSW; @@ -83,7 +85,7 @@ class Body2DSW : public CollisionObject2DSW { virtual void _shapes_changed(); Transform2D new_transform; - Map<Constraint2DSW *, int> constraint_map; + List<Pair<Constraint2DSW *, int>> constraint_list; struct AreaCMP { Area2DSW *area; @@ -162,7 +164,7 @@ public: _FORCE_INLINE_ int get_max_contacts_reported() const { return contacts.size(); } - _FORCE_INLINE_ bool can_report_contacts() const { return !contacts.empty(); } + _FORCE_INLINE_ bool can_report_contacts() const { return !contacts.is_empty(); } _FORCE_INLINE_ void add_contact(const Vector2 &p_local_pos, const Vector2 &p_local_normal, real_t p_depth, int p_local_shape, const Vector2 &p_collider_pos, int p_collider_shape, ObjectID p_collider_instance_id, const RID &p_collider, const Vector2 &p_collider_velocity_at_pos); _FORCE_INLINE_ void add_exception(const RID &p_exception) { exceptions.insert(p_exception); } @@ -179,10 +181,10 @@ public: _FORCE_INLINE_ Body2DSW *get_island_list_next() const { return island_list_next; } _FORCE_INLINE_ void set_island_list_next(Body2DSW *p_next) { island_list_next = p_next; } - _FORCE_INLINE_ void add_constraint(Constraint2DSW *p_constraint, int p_pos) { constraint_map[p_constraint] = p_pos; } - _FORCE_INLINE_ void remove_constraint(Constraint2DSW *p_constraint) { constraint_map.erase(p_constraint); } - const Map<Constraint2DSW *, int> &get_constraint_map() const { return constraint_map; } - _FORCE_INLINE_ void clear_constraint_map() { constraint_map.clear(); } + _FORCE_INLINE_ void add_constraint(Constraint2DSW *p_constraint, int p_pos) { constraint_list.push_back({ p_constraint, p_pos }); } + _FORCE_INLINE_ void remove_constraint(Constraint2DSW *p_constraint, int p_pos) { constraint_list.erase({ p_constraint, p_pos }); } + const List<Pair<Constraint2DSW *, int>> &get_constraint_list() const { return constraint_list; } + _FORCE_INLINE_ void clear_constraint_list() { constraint_list.clear(); } _FORCE_INLINE_ void set_omit_force_integration(bool p_omit_force_integration) { omit_force_integration = p_omit_force_integration; } _FORCE_INLINE_ bool get_omit_force_integration() const { return omit_force_integration; } diff --git a/servers/physics_2d/body_pair_2d_sw.cpp b/servers/physics_2d/body_pair_2d_sw.cpp index 2021aab17c..feced36a2b 100644 --- a/servers/physics_2d/body_pair_2d_sw.cpp +++ b/servers/physics_2d/body_pair_2d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -288,21 +288,17 @@ bool BodyPair2DSW::setup(real_t p_step) { if (A->is_shape_set_as_one_way_collision(shape_A)) { Vector2 direction = xform_A.get_axis(1).normalized(); bool valid = false; - if (B->get_linear_velocity().dot(direction) >= 0) { - for (int i = 0; i < contact_count; i++) { - Contact &c = contacts[i]; - if (!c.reused) { - continue; - } - if (c.normal.dot(direction) > 0) { //greater (normal inverted) - continue; - } - - valid = true; - break; + for (int i = 0; i < contact_count; i++) { + Contact &c = contacts[i]; + if (!c.reused) { + continue; } + if (c.normal.dot(direction) > -CMP_EPSILON) { //greater (normal inverted) + continue; + } + valid = true; + break; } - if (!valid) { collided = false; oneway_disabled = true; @@ -313,19 +309,16 @@ bool BodyPair2DSW::setup(real_t p_step) { if (B->is_shape_set_as_one_way_collision(shape_B)) { Vector2 direction = xform_B.get_axis(1).normalized(); bool valid = false; - if (A->get_linear_velocity().dot(direction) >= 0) { - for (int i = 0; i < contact_count; i++) { - Contact &c = contacts[i]; - if (!c.reused) { - continue; - } - if (c.normal.dot(direction) < 0) { //less (normal ok) - continue; - } - - valid = true; - break; + for (int i = 0; i < contact_count; i++) { + Contact &c = contacts[i]; + if (!c.reused) { + continue; + } + if (c.normal.dot(direction) < CMP_EPSILON) { //less (normal ok) + continue; } + valid = true; + break; } if (!valid) { collided = false; @@ -409,7 +402,7 @@ bool BodyPair2DSW::setup(real_t p_step) { kNormal += A->get_inv_inertia() * (c.rA.dot(c.rA) - rnA * rnA) + B->get_inv_inertia() * (c.rB.dot(c.rB) - rnB * rnB); c.mass_normal = 1.0f / kNormal; - Vector2 tangent = c.normal.tangent(); + Vector2 tangent = c.normal.orthogonal(); real_t rtA = c.rA.dot(tangent); real_t rtB = c.rB.dot(tangent); real_t kTangent = A->get_inv_mass() + B->get_inv_mass(); @@ -469,7 +462,7 @@ void BodyPair2DSW::solve(real_t p_step) { real_t vn = dv.dot(c.normal); real_t vbn = dbv.dot(c.normal); - Vector2 tangent = c.normal.tangent(); + Vector2 tangent = c.normal.orthogonal(); real_t vt = dv.dot(tangent); real_t jbn = (c.bias - vbn) * c.mass_normal; @@ -514,6 +507,6 @@ BodyPair2DSW::BodyPair2DSW(Body2DSW *p_A, int p_shape_A, Body2DSW *p_B, int p_sh } BodyPair2DSW::~BodyPair2DSW() { - A->remove_constraint(this); - B->remove_constraint(this); + A->remove_constraint(this, 0); + B->remove_constraint(this, 1); } diff --git a/servers/physics_2d/body_pair_2d_sw.h b/servers/physics_2d/body_pair_2d_sw.h index ea4d55841a..31ab9b9017 100644 --- a/servers/physics_2d/body_pair_2d_sw.h +++ b/servers/physics_2d/body_pair_2d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_2d/broad_phase_2d_basic.cpp b/servers/physics_2d/broad_phase_2d_basic.cpp index 3bdfc1a973..17424629a9 100644 --- a/servers/physics_2d/broad_phase_2d_basic.cpp +++ b/servers/physics_2d/broad_phase_2d_basic.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_2d/broad_phase_2d_basic.h b/servers/physics_2d/broad_phase_2d_basic.h index 97e1c900b9..ca1db360fb 100644 --- a/servers/physics_2d/broad_phase_2d_basic.h +++ b/servers/physics_2d/broad_phase_2d_basic.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_2d/broad_phase_2d_hash_grid.cpp b/servers/physics_2d/broad_phase_2d_hash_grid.cpp index c8b3d193c9..6cfe6908d1 100644 --- a/servers/physics_2d/broad_phase_2d_hash_grid.cpp +++ b/servers/physics_2d/broad_phase_2d_hash_grid.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -261,7 +261,7 @@ void BroadPhase2DHashGrid::_exit_grid(Element *p_elem, const Rect2 &p_rect, bool } } - if (pb->object_set.empty() && pb->static_object_set.empty()) { + if (pb->object_set.is_empty() && pb->static_object_set.is_empty()) { if (hash_table[idx] == pb) { hash_table[idx] = pb->next; } else { diff --git a/servers/physics_2d/broad_phase_2d_hash_grid.h b/servers/physics_2d/broad_phase_2d_hash_grid.h index 54994992c9..eb7c8879ac 100644 --- a/servers/physics_2d/broad_phase_2d_hash_grid.h +++ b/servers/physics_2d/broad_phase_2d_hash_grid.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_2d/broad_phase_2d_sw.cpp b/servers/physics_2d/broad_phase_2d_sw.cpp index 5ba557e70a..7f0af48b1f 100644 --- a/servers/physics_2d/broad_phase_2d_sw.cpp +++ b/servers/physics_2d/broad_phase_2d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_2d/broad_phase_2d_sw.h b/servers/physics_2d/broad_phase_2d_sw.h index e4444cd180..d17ee6e2d6 100644 --- a/servers/physics_2d/broad_phase_2d_sw.h +++ b/servers/physics_2d/broad_phase_2d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_2d/collision_object_2d_sw.cpp b/servers/physics_2d/collision_object_2d_sw.cpp index 6931d96fe4..7a2f312263 100644 --- a/servers/physics_2d/collision_object_2d_sw.cpp +++ b/servers/physics_2d/collision_object_2d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_2d/collision_object_2d_sw.h b/servers/physics_2d/collision_object_2d_sw.h index 36b7073a5c..2db3961f41 100644 --- a/servers/physics_2d/collision_object_2d_sw.h +++ b/servers/physics_2d/collision_object_2d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -61,7 +61,7 @@ private: Variant metadata; bool disabled; bool one_way_collision; - float one_way_collision_margin; + real_t one_way_collision_margin; Shape() { disabled = false; one_way_collision = false; @@ -153,7 +153,7 @@ public: return shapes[p_idx].disabled; } - _FORCE_INLINE_ void set_shape_as_one_way_collision(int p_idx, bool p_one_way_collision, float p_margin) { + _FORCE_INLINE_ void set_shape_as_one_way_collision(int p_idx, bool p_one_way_collision, real_t p_margin) { CRASH_BAD_INDEX(p_idx, shapes.size()); shapes.write[p_idx].one_way_collision = p_one_way_collision; shapes.write[p_idx].one_way_collision_margin = p_margin; @@ -163,7 +163,7 @@ public: return shapes[p_idx].one_way_collision; } - _FORCE_INLINE_ float get_shape_one_way_collision_margin(int p_idx) const { + _FORCE_INLINE_ real_t get_shape_one_way_collision_margin(int p_idx) const { CRASH_BAD_INDEX(p_idx, shapes.size()); return shapes[p_idx].one_way_collision_margin; } diff --git a/servers/physics_2d/collision_solver_2d_sat.cpp b/servers/physics_2d/collision_solver_2d_sat.cpp index d993754fee..29242a554b 100644 --- a/servers/physics_2d/collision_solver_2d_sat.cpp +++ b/servers/physics_2d/collision_solver_2d_sat.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -88,7 +88,7 @@ _FORCE_INLINE_ static void _generate_contacts_edge_edge(const Vector2 *p_points_ #endif Vector2 n = p_collector->normal; - Vector2 t = n.tangent(); + Vector2 t = n.orthogonal(); real_t dA = n.dot(p_points_A[0]); real_t dB = n.dot(p_points_B[0]); @@ -209,7 +209,7 @@ public: if (!test_axis(na)) { return false; } - if (!test_axis(na.tangent())) { + if (!test_axis(na.orthogonal())) { return false; } } @@ -219,7 +219,7 @@ public: if (!test_axis(nb)) { return false; } - if (!test_axis(nb.tangent())) { + if (!test_axis(nb.orthogonal())) { return false; } } @@ -450,7 +450,7 @@ static void _collision_segment_circle(const Shape2DSW *p_a, const Transform2D &p //segment normal if (!separator.test_axis( - (p_transform_a.xform(segment_A->get_b()) - p_transform_a.xform(segment_A->get_a())).normalized().tangent())) { + (p_transform_a.xform(segment_A->get_b()) - p_transform_a.xform(segment_A->get_a())).normalized().orthogonal())) { return; } diff --git a/servers/physics_2d/collision_solver_2d_sat.h b/servers/physics_2d/collision_solver_2d_sat.h index 6bb485f561..49cc5176f9 100644 --- a/servers/physics_2d/collision_solver_2d_sat.h +++ b/servers/physics_2d/collision_solver_2d_sat.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_2d/collision_solver_2d_sw.cpp b/servers/physics_2d/collision_solver_2d_sw.cpp index 0e056691c7..5bd4d498c6 100644 --- a/servers/physics_2d/collision_solver_2d_sw.cpp +++ b/servers/physics_2d/collision_solver_2d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_2d/collision_solver_2d_sw.h b/servers/physics_2d/collision_solver_2d_sw.h index f39cfee0a9..4f12ca9e88 100644 --- a/servers/physics_2d/collision_solver_2d_sw.h +++ b/servers/physics_2d/collision_solver_2d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_2d/constraint_2d_sw.h b/servers/physics_2d/constraint_2d_sw.h index d8751f588e..49ae4dd848 100644 --- a/servers/physics_2d/constraint_2d_sw.h +++ b/servers/physics_2d/constraint_2d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_2d/joints_2d_sw.cpp b/servers/physics_2d/joints_2d_sw.cpp index e7d26645e9..f503868ba5 100644 --- a/servers/physics_2d/joints_2d_sw.cpp +++ b/servers/physics_2d/joints_2d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -55,6 +55,14 @@ * SOFTWARE. */ +void Joint2DSW::copy_settings_from(Joint2DSW *p_joint) { + set_self(p_joint->get_self()); + set_max_force(p_joint->get_max_force()); + set_bias(p_joint->get_bias()); + set_max_bias(p_joint->get_max_bias()); + disable_collisions_between_bodies(p_joint->is_disabled_collisions_between_bodies()); +} + static inline real_t k_scalar(Body2DSW *a, Body2DSW *b, const Vector2 &rA, const Vector2 &rB, const Vector2 &n) { real_t value = 0; @@ -75,9 +83,9 @@ static inline real_t k_scalar(Body2DSW *a, Body2DSW *b, const Vector2 &rA, const static inline Vector2 relative_velocity(Body2DSW *a, Body2DSW *b, Vector2 rA, Vector2 rB) { - Vector2 sum = a->get_linear_velocity() - rA.tangent() * a->get_angular_velocity(); + Vector2 sum = a->get_linear_velocity() - rA.orthogonal() * a->get_angular_velocity(); if (b) { - return (b->get_linear_velocity() - rB.tangent() * b->get_angular_velocity()) - sum; + return (b->get_linear_velocity() - rB.orthogonal() * b->get_angular_velocity()) - sum; } else { return -sum; } @@ -199,10 +207,10 @@ PinJoint2DSW::PinJoint2DSW(const Vector2 &p_pos, Body2DSW *p_body_a, Body2DSW *p PinJoint2DSW::~PinJoint2DSW() { if (A) { - A->remove_constraint(this); + A->remove_constraint(this, 0); } if (B) { - B->remove_constraint(this); + B->remove_constraint(this, 1); } } @@ -264,7 +272,7 @@ bool GrooveJoint2DSW::setup(real_t p_step) { Space2DSW *space = A->get_space(); // calculate axis - Vector2 n = -(tb - ta).tangent().normalized(); + Vector2 n = -(tb - ta).orthogonal().normalized(); real_t d = ta.dot(n); xf_normal = n; @@ -282,7 +290,7 @@ bool GrooveJoint2DSW::setup(real_t p_step) { } else { clamp = 0.0f; //joint->r1 = cpvsub(cpvadd(cpvmult(cpvperp(n), -td), cpvmult(n, d)), a->p); - rA = ((-n.tangent() * -td) + n * d) - A->get_transform().get_origin(); + rA = ((-n.orthogonal() * -td) + n * d) - A->get_transform().get_origin(); } // Calculate mass tensor @@ -332,15 +340,15 @@ GrooveJoint2DSW::GrooveJoint2DSW(const Vector2 &p_a_groove1, const Vector2 &p_a_ A_groove_1 = A->get_inv_transform().xform(p_a_groove1); A_groove_2 = A->get_inv_transform().xform(p_a_groove2); B_anchor = B->get_inv_transform().xform(p_b_anchor); - A_groove_normal = -(A_groove_2 - A_groove_1).normalized().tangent(); + A_groove_normal = -(A_groove_2 - A_groove_1).normalized().orthogonal(); A->add_constraint(this, 0); B->add_constraint(this, 1); } GrooveJoint2DSW::~GrooveJoint2DSW() { - A->remove_constraint(this); - B->remove_constraint(this); + A->remove_constraint(this, 0); + B->remove_constraint(this, 1); } ////////////////////////////////////////////// @@ -436,6 +444,6 @@ DampedSpringJoint2DSW::DampedSpringJoint2DSW(const Vector2 &p_anchor_a, const Ve } DampedSpringJoint2DSW::~DampedSpringJoint2DSW() { - A->remove_constraint(this); - B->remove_constraint(this); + A->remove_constraint(this, 0); + B->remove_constraint(this, 1); } diff --git a/servers/physics_2d/joints_2d_sw.h b/servers/physics_2d/joints_2d_sw.h index 3c8aab77c8..6050dc2775 100644 --- a/servers/physics_2d/joints_2d_sw.h +++ b/servers/physics_2d/joints_2d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -49,7 +49,12 @@ public: _FORCE_INLINE_ void set_max_bias(real_t p_bias) { max_bias = p_bias; } _FORCE_INLINE_ real_t get_max_bias() const { return max_bias; } - virtual PhysicsServer2D::JointType get_type() const = 0; + virtual bool setup(real_t p_step) { return false; } + virtual void solve(real_t p_step) {} + + void copy_settings_from(Joint2DSW *p_joint); + + virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_TYPE_MAX; } Joint2DSW(Body2DSW **p_body_ptr = nullptr, int p_body_count = 0) : Constraint2DSW(p_body_ptr, p_body_count) { bias = 0; @@ -76,7 +81,7 @@ class PinJoint2DSW : public Joint2DSW { real_t softness; public: - virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_PIN; } + virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_TYPE_PIN; } virtual bool setup(real_t p_step); virtual void solve(real_t p_step); @@ -113,7 +118,7 @@ class GrooveJoint2DSW : public Joint2DSW { bool correct; public: - virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_GROOVE; } + virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_TYPE_GROOVE; } virtual bool setup(real_t p_step); virtual void solve(real_t p_step); @@ -146,7 +151,7 @@ class DampedSpringJoint2DSW : public Joint2DSW { real_t v_coef; public: - virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_DAMPED_SPRING; } + virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_TYPE_DAMPED_SPRING; } virtual bool setup(real_t p_step); virtual void solve(real_t p_step); diff --git a/servers/physics_2d/physics_server_2d_sw.cpp b/servers/physics_2d/physics_server_2d_sw.cpp index 755804fe36..1040437ca7 100644 --- a/servers/physics_2d/physics_server_2d_sw.cpp +++ b/servers/physics_2d/physics_server_2d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -149,24 +149,19 @@ void PhysicsServer2DSW::_shape_col_cbk(const Vector2 &p_point_A, const Vector2 & return; } + Vector2 rel_dir = (p_point_A - p_point_B); + real_t rel_length2 = rel_dir.length_squared(); if (cbk->valid_dir != Vector2()) { - if (p_point_A.distance_squared_to(p_point_B) > cbk->valid_depth * cbk->valid_depth) { - cbk->invalid_by_dir++; - return; - } - Vector2 rel_dir = (p_point_A - p_point_B).normalized(); - - if (cbk->valid_dir.dot(rel_dir) < Math_SQRT12) { //sqrt(2)/2.0 - 45 degrees - cbk->invalid_by_dir++; - - /* - print_line("A: "+p_point_A); - print_line("B: "+p_point_B); - print_line("discard too angled "+rtos(cbk->valid_dir.dot((p_point_A-p_point_B)))); - print_line("resnorm: "+(p_point_A-p_point_B).normalized()); - print_line("distance: "+rtos(p_point_A.distance_to(p_point_B))); - */ - return; + if (cbk->valid_depth < 10e20) { + if (rel_length2 > cbk->valid_depth * cbk->valid_depth || + (rel_length2 > CMP_EPSILON && cbk->valid_dir.dot(rel_dir.normalized()) < CMP_EPSILON)) { + cbk->invalid_by_dir++; + return; + } + } else { + if (rel_length2 > 0 && cbk->valid_dir.dot(rel_dir.normalized()) < CMP_EPSILON) { + return; + } } } @@ -182,8 +177,7 @@ void PhysicsServer2DSW::_shape_col_cbk(const Vector2 &p_point_A, const Vector2 & } } - real_t d = p_point_A.distance_squared_to(p_point_B); - if (d < min_depth) { + if (rel_length2 < min_depth) { return; } cbk->ptr[min_depth_idx * 2 + 0] = p_point_A; @@ -554,7 +548,7 @@ void PhysicsServer2DSW::body_set_space(RID p_body, RID p_space) { return; //pointless } - body->clear_constraint_map(); + body->clear_constraint_list(); body->set_space(space); }; @@ -673,7 +667,7 @@ void PhysicsServer2DSW::body_set_shape_disabled(RID p_body, int p_shape_idx, boo body->set_shape_as_disabled(p_shape_idx, p_disabled); } -void PhysicsServer2DSW::body_set_shape_as_one_way_collision(RID p_body, int p_shape_idx, bool p_enable, float p_margin) { +void PhysicsServer2DSW::body_set_shape_as_one_way_collision(RID p_body, int p_shape_idx, bool p_enable, real_t p_margin) { Body2DSW *body = body_owner.getornull(p_body); ERR_FAIL_COND(!body); ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count()); @@ -964,7 +958,7 @@ bool PhysicsServer2DSW::body_test_motion(RID p_body, const Transform2D &p_from, return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, p_margin, r_result, p_exclude_raycast_shapes); } -int PhysicsServer2DSW::body_test_ray_separation(RID p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, SeparationResult *r_results, int p_result_max, float p_margin) { +int PhysicsServer2DSW::body_test_ray_separation(RID p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin) { Body2DSW *body = body_owner.getornull(p_body); ERR_FAIL_COND_V(!body, false); ERR_FAIL_COND_V(!body->get_space(), false); @@ -991,6 +985,24 @@ PhysicsDirectBodyState2D *PhysicsServer2DSW::body_get_direct_state(RID p_body) { /* JOINT API */ +RID PhysicsServer2DSW::joint_create() { + Joint2DSW *joint = memnew(Joint2DSW); + RID joint_rid = joint_owner.make_rid(joint); + joint->set_self(joint_rid); + return joint_rid; +} + +void PhysicsServer2DSW::joint_clear(RID p_joint) { + Joint2DSW *joint = joint_owner.getornull(p_joint); + if (joint->get_type() != JOINT_TYPE_MAX) { + Joint2DSW *empty_joint = memnew(Joint2DSW); + empty_joint->copy_settings_from(joint); + + joint_owner.replace(p_joint, empty_joint); + memdelete(joint); + } +} + void PhysicsServer2DSW::joint_set_param(RID p_joint, JointParam p_param, real_t p_value) { Joint2DSW *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND(!joint); @@ -1054,52 +1066,63 @@ bool PhysicsServer2DSW::joint_is_disabled_collisions_between_bodies(RID p_joint) return joint->is_disabled_collisions_between_bodies(); } -RID PhysicsServer2DSW::pin_joint_create(const Vector2 &p_pos, RID p_body_a, RID p_body_b) { +void PhysicsServer2DSW::joint_make_pin(RID p_joint, const Vector2 &p_pos, RID p_body_a, RID p_body_b) { Body2DSW *A = body_owner.getornull(p_body_a); - ERR_FAIL_COND_V(!A, RID()); + ERR_FAIL_COND(!A); Body2DSW *B = nullptr; if (body_owner.owns(p_body_b)) { B = body_owner.getornull(p_body_b); - ERR_FAIL_COND_V(!B, RID()); + ERR_FAIL_COND(!B); } + Joint2DSW *prev_joint = joint_owner.getornull(p_joint); + ERR_FAIL_COND(prev_joint == nullptr); + Joint2DSW *joint = memnew(PinJoint2DSW(p_pos, A, B)); - RID self = joint_owner.make_rid(joint); - joint->set_self(self); - return self; + joint_owner.replace(p_joint, joint); + joint->copy_settings_from(prev_joint); + memdelete(prev_joint); } -RID PhysicsServer2DSW::groove_joint_create(const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, RID p_body_a, RID p_body_b) { +void PhysicsServer2DSW::joint_make_groove(RID p_joint, const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, RID p_body_a, RID p_body_b) { Body2DSW *A = body_owner.getornull(p_body_a); - ERR_FAIL_COND_V(!A, RID()); + ERR_FAIL_COND(!A); Body2DSW *B = body_owner.getornull(p_body_b); - ERR_FAIL_COND_V(!B, RID()); + ERR_FAIL_COND(!B); + + Joint2DSW *prev_joint = joint_owner.getornull(p_joint); + ERR_FAIL_COND(prev_joint == nullptr); Joint2DSW *joint = memnew(GrooveJoint2DSW(p_a_groove1, p_a_groove2, p_b_anchor, A, B)); - RID self = joint_owner.make_rid(joint); - joint->set_self(self); - return self; + + joint_owner.replace(p_joint, joint); + joint->copy_settings_from(prev_joint); + memdelete(prev_joint); } -RID PhysicsServer2DSW::damped_spring_joint_create(const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, RID p_body_a, RID p_body_b) { +void PhysicsServer2DSW::joint_make_damped_spring(RID p_joint, const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, RID p_body_a, RID p_body_b) { Body2DSW *A = body_owner.getornull(p_body_a); - ERR_FAIL_COND_V(!A, RID()); + ERR_FAIL_COND(!A); Body2DSW *B = body_owner.getornull(p_body_b); - ERR_FAIL_COND_V(!B, RID()); + ERR_FAIL_COND(!B); + + Joint2DSW *prev_joint = joint_owner.getornull(p_joint); + ERR_FAIL_COND(prev_joint == nullptr); Joint2DSW *joint = memnew(DampedSpringJoint2DSW(p_anchor_a, p_anchor_b, A, B)); - RID self = joint_owner.make_rid(joint); - joint->set_self(self); - return self; + + joint_owner.replace(p_joint, joint); + joint->copy_settings_from(prev_joint); + memdelete(prev_joint); } void PhysicsServer2DSW::pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) { Joint2DSW *j = joint_owner.getornull(p_joint); ERR_FAIL_COND(!j); - ERR_FAIL_COND(j->get_type() != JOINT_PIN); + ERR_FAIL_COND(j->get_type() != JOINT_TYPE_PIN); PinJoint2DSW *pin_joint = static_cast<PinJoint2DSW *>(j); pin_joint->set_param(p_param, p_value); @@ -1108,7 +1131,7 @@ void PhysicsServer2DSW::pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t PhysicsServer2DSW::pin_joint_get_param(RID p_joint, PinJointParam p_param) const { Joint2DSW *j = joint_owner.getornull(p_joint); ERR_FAIL_COND_V(!j, 0); - ERR_FAIL_COND_V(j->get_type() != JOINT_PIN, 0); + ERR_FAIL_COND_V(j->get_type() != JOINT_TYPE_PIN, 0); PinJoint2DSW *pin_joint = static_cast<PinJoint2DSW *>(j); return pin_joint->get_param(p_param); @@ -1117,7 +1140,7 @@ real_t PhysicsServer2DSW::pin_joint_get_param(RID p_joint, PinJointParam p_param void PhysicsServer2DSW::damped_spring_joint_set_param(RID p_joint, DampedSpringParam p_param, real_t p_value) { Joint2DSW *j = joint_owner.getornull(p_joint); ERR_FAIL_COND(!j); - ERR_FAIL_COND(j->get_type() != JOINT_DAMPED_SPRING); + ERR_FAIL_COND(j->get_type() != JOINT_TYPE_DAMPED_SPRING); DampedSpringJoint2DSW *dsj = static_cast<DampedSpringJoint2DSW *>(j); dsj->set_param(p_param, p_value); @@ -1126,7 +1149,7 @@ void PhysicsServer2DSW::damped_spring_joint_set_param(RID p_joint, DampedSpringP real_t PhysicsServer2DSW::damped_spring_joint_get_param(RID p_joint, DampedSpringParam p_param) const { Joint2DSW *j = joint_owner.getornull(p_joint); ERR_FAIL_COND_V(!j, 0); - ERR_FAIL_COND_V(j->get_type() != JOINT_DAMPED_SPRING, 0); + ERR_FAIL_COND_V(j->get_type() != JOINT_TYPE_DAMPED_SPRING, 0); DampedSpringJoint2DSW *dsj = static_cast<DampedSpringJoint2DSW *>(j); return dsj->get_param(p_param); @@ -1134,7 +1157,7 @@ real_t PhysicsServer2DSW::damped_spring_joint_get_param(RID p_joint, DampedSprin PhysicsServer2D::JointType PhysicsServer2DSW::joint_get_type(RID p_joint) const { Joint2DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND_V(!joint, JOINT_PIN); + ERR_FAIL_COND_V(!joint, JOINT_TYPE_PIN); return joint->get_type(); } @@ -1331,7 +1354,7 @@ int PhysicsServer2DSW::get_process_info(ProcessInfo p_info) { PhysicsServer2DSW *PhysicsServer2DSW::singletonsw = nullptr; -PhysicsServer2DSW::PhysicsServer2DSW() { +PhysicsServer2DSW::PhysicsServer2DSW(bool p_using_threads) { singletonsw = this; BroadPhase2DSW::create_func = BroadPhase2DHashGrid::_create; //BroadPhase2DSW::create_func=BroadPhase2DBasic::_create; @@ -1340,10 +1363,6 @@ PhysicsServer2DSW::PhysicsServer2DSW() { island_count = 0; active_objects = 0; collision_pairs = 0; -#ifdef NO_THREADS - using_threads = false; -#else - using_threads = int(ProjectSettings::get_singleton()->get("physics/2d/thread_model")) == 2; -#endif + using_threads = p_using_threads; flushing_queries = false; }; diff --git a/servers/physics_2d/physics_server_2d_sw.h b/servers/physics_2d/physics_server_2d_sw.h index 9bd9655e2c..65c5df0fce 100644 --- a/servers/physics_2d/physics_server_2d_sw.h +++ b/servers/physics_2d/physics_server_2d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -61,11 +61,11 @@ class PhysicsServer2DSW : public PhysicsServer2D { PhysicsDirectBodyState2DSW *direct_state; - mutable RID_PtrOwner<Shape2DSW> shape_owner; - mutable RID_PtrOwner<Space2DSW> space_owner; - mutable RID_PtrOwner<Area2DSW> area_owner; - mutable RID_PtrOwner<Body2DSW> body_owner; - mutable RID_PtrOwner<Joint2DSW> joint_owner; + mutable RID_PtrOwner<Shape2DSW, true> shape_owner; + mutable RID_PtrOwner<Space2DSW, true> space_owner; + mutable RID_PtrOwner<Area2DSW, true> area_owner; + mutable RID_PtrOwner<Body2DSW, true> body_owner; + mutable RID_PtrOwner<Joint2DSW, true> joint_owner; static PhysicsServer2DSW *singletonsw; @@ -191,7 +191,7 @@ public: virtual void body_clear_shapes(RID p_body) override; virtual void body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) override; - virtual void body_set_shape_as_one_way_collision(RID p_body, int p_shape_idx, bool p_enable, float p_margin) override; + virtual void body_set_shape_as_one_way_collision(RID p_body, int p_shape_idx, bool p_enable, real_t p_margin) override; virtual void body_attach_object_instance_id(RID p_body, ObjectID p_id) override; virtual ObjectID body_get_object_instance_id(RID p_body) const override; @@ -248,22 +248,27 @@ public: virtual void body_set_pickable(RID p_body, bool p_pickable) override; virtual bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override; - virtual int body_test_ray_separation(RID p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, SeparationResult *r_results, int p_result_max, float p_margin = 0.001) override; + virtual int body_test_ray_separation(RID p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override; // this function only works on physics process, errors and returns null otherwise virtual PhysicsDirectBodyState2D *body_get_direct_state(RID p_body) override; /* JOINT API */ + virtual RID joint_create() override; + + virtual void joint_clear(RID p_joint) override; + virtual void joint_set_param(RID p_joint, JointParam p_param, real_t p_value) override; virtual real_t joint_get_param(RID p_joint, JointParam p_param) const override; virtual void joint_disable_collisions_between_bodies(RID p_joint, const bool p_disabled) override; virtual bool joint_is_disabled_collisions_between_bodies(RID p_joint) const override; - virtual RID pin_joint_create(const Vector2 &p_pos, RID p_body_a, RID p_body_b = RID()) override; - virtual RID groove_joint_create(const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, RID p_body_a, RID p_body_b) override; - virtual RID damped_spring_joint_create(const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, RID p_body_a, RID p_body_b = RID()) override; + virtual void joint_make_pin(RID p_joint, const Vector2 &p_anchor, RID p_body_a, RID p_body_b = RID()) override; + virtual void joint_make_groove(RID p_joint, const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, RID p_body_a, RID p_body_b) override; + virtual void joint_make_damped_spring(RID p_joint, const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, RID p_body_a, RID p_body_b = RID()) override; + virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) override; virtual real_t pin_joint_get_param(RID p_joint, PinJointParam p_param) const override; virtual void damped_spring_joint_set_param(RID p_joint, DampedSpringParam p_param, real_t p_value) override; @@ -287,7 +292,7 @@ public: int get_process_info(ProcessInfo p_info) override; - PhysicsServer2DSW(); + PhysicsServer2DSW(bool p_using_threads = false); ~PhysicsServer2DSW() {} }; diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.cpp b/servers/physics_2d/physics_server_2d_wrap_mt.cpp index 49c38c6ce0..790c87cc44 100644 --- a/servers/physics_2d/physics_server_2d_wrap_mt.cpp +++ b/servers/physics_2d/physics_server_2d_wrap_mt.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -33,7 +33,7 @@ #include "core/os/os.h" void PhysicsServer2DWrapMT::thread_exit() { - exit = true; + exit.set(); } void PhysicsServer2DWrapMT::thread_step(real_t p_delta) { @@ -52,9 +52,9 @@ void PhysicsServer2DWrapMT::thread_loop() { physics_2d_server->init(); - exit = false; - step_thread_up = true; - while (!exit) { + exit.clear(); + step_thread_up.set(); + while (!exit.is_set()) { // flush commands one by one, until exit is requested command_queue.wait_and_flush_one(); } @@ -76,7 +76,7 @@ void PhysicsServer2DWrapMT::step(real_t p_step) { } void PhysicsServer2DWrapMT::sync() { - if (thread) { + if (create_thread) { if (first_frame) { first_frame = false; } else { @@ -97,8 +97,8 @@ void PhysicsServer2DWrapMT::end_sync() { void PhysicsServer2DWrapMT::init() { if (create_thread) { //OS::get_singleton()->release_rendering_thread(); - thread = Thread::create(_thread_callback, this); - while (!step_thread_up) { + thread.start(_thread_callback, this); + while (!step_thread_up.is_set()) { OS::get_singleton()->delay_usec(1000); } } else { @@ -107,37 +107,19 @@ void PhysicsServer2DWrapMT::init() { } void PhysicsServer2DWrapMT::finish() { - if (thread) { + if (thread.is_started()) { command_queue.push(this, &PhysicsServer2DWrapMT::thread_exit); - Thread::wait_to_finish(thread); - memdelete(thread); - - thread = nullptr; + thread.wait_to_finish(); } else { physics_2d_server->finish(); } - - line_shape_free_cached_ids(); - ray_shape_free_cached_ids(); - segment_shape_free_cached_ids(); - circle_shape_free_cached_ids(); - rectangle_shape_free_cached_ids(); - capsule_shape_free_cached_ids(); - convex_polygon_shape_free_cached_ids(); - concave_polygon_shape_free_cached_ids(); - - space_free_cached_ids(); - area_free_cached_ids(); - body_free_cached_ids(); } PhysicsServer2DWrapMT::PhysicsServer2DWrapMT(PhysicsServer2D *p_contained, bool p_create_thread) : command_queue(p_create_thread) { physics_2d_server = p_contained; create_thread = p_create_thread; - thread = nullptr; step_pending = 0; - step_thread_up = false; pool_max_size = GLOBAL_GET("memory/limits/multithreaded_server/rid_pool_prealloc"); diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.h b/servers/physics_2d/physics_server_2d_wrap_mt.h index 1269cadd33..3577f706de 100644 --- a/servers/physics_2d/physics_server_2d_wrap_mt.h +++ b/servers/physics_2d/physics_server_2d_wrap_mt.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -34,6 +34,7 @@ #include "core/config/project_settings.h" #include "core/os/thread.h" #include "core/templates/command_queue_mt.h" +#include "core/templates/safe_refcount.h" #include "servers/physics_server_2d.h" #ifdef DEBUG_SYNC @@ -52,9 +53,9 @@ class PhysicsServer2DWrapMT : public PhysicsServer2D { Thread::ID server_thread; Thread::ID main_thread; - volatile bool exit; - Thread *thread; - volatile bool step_thread_up; + SafeFlag exit; + Thread thread; + SafeFlag step_thread_up; bool create_thread; Semaphore step_sem; @@ -73,6 +74,8 @@ public: #define ServerName PhysicsServer2D #define ServerNameWrapMT PhysicsServer2DWrapMT #define server_name physics_2d_server +#define WRITE_ACTION + #include "servers/server_wrap_mt_common.h" //FUNC1RID(shape,ShapeType); todo fix @@ -93,7 +96,7 @@ public: FUNC1RC(real_t, shape_get_custom_solver_bias, RID); //these work well, but should be used from the main thread only - bool shape_collide(RID p_shape_A, const Transform2D &p_xform_A, const Vector2 &p_motion_A, RID p_shape_B, const Transform2D &p_xform_B, const Vector2 &p_motion_B, Vector2 *r_results, int p_result_max, int &r_result_count) { + bool shape_collide(RID p_shape_A, const Transform2D &p_xform_A, const Vector2 &p_motion_A, RID p_shape_B, const Transform2D &p_xform_B, const Vector2 &p_motion_B, Vector2 *r_results, int p_result_max, int &r_result_count) override { ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false); return physics_2d_server->shape_collide(p_shape_A, p_xform_A, p_motion_A, p_shape_B, p_xform_B, p_motion_B, r_results, p_result_max, r_result_count); } @@ -108,18 +111,18 @@ public: FUNC2RC(real_t, space_get_param, RID, SpaceParameter); // this function only works on physics process, errors and returns null otherwise - PhysicsDirectSpaceState2D *space_get_direct_state(RID p_space) { + PhysicsDirectSpaceState2D *space_get_direct_state(RID p_space) override { ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), nullptr); return physics_2d_server->space_get_direct_state(p_space); } FUNC2(space_set_debug_contacts, RID, int); - virtual Vector<Vector2> space_get_contacts(RID p_space) const { + virtual Vector<Vector2> space_get_contacts(RID p_space) const override { ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), Vector<Vector2>()); return physics_2d_server->space_get_contacts(p_space); } - virtual int space_get_contact_count(RID p_space) const { + virtual int space_get_contact_count(RID p_space) const override { ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), 0); return physics_2d_server->space_get_contact_count(p_space); } @@ -189,7 +192,7 @@ public: FUNC2RC(RID, body_get_shape, RID, int); FUNC3(body_set_shape_disabled, RID, int, bool); - FUNC4(body_set_shape_as_one_way_collision, RID, int, bool, float); + FUNC4(body_set_shape_as_one_way_collision, RID, int, bool, real_t); FUNC2(body_remove_shape, RID, int); FUNC1(body_clear_shapes, RID); @@ -244,30 +247,34 @@ public: FUNC4(body_set_force_integration_callback, RID, Object *, const StringName &, const Variant &); - bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) { + bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) override { return physics_2d_server->body_collide_shape(p_body, p_body_shape, p_shape, p_shape_xform, p_motion, r_results, p_result_max, r_result_count); } FUNC2(body_set_pickable, RID, bool); - bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) { + bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override { ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false); return physics_2d_server->body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, p_margin, r_result, p_exclude_raycast_shapes); } - int body_test_ray_separation(RID p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, SeparationResult *r_results, int p_result_max, float p_margin = 0.001) { + int body_test_ray_separation(RID p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override { ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false); return physics_2d_server->body_test_ray_separation(p_body, p_transform, p_infinite_inertia, r_recover_motion, r_results, p_result_max, p_margin); } // this function only works on physics process, errors and returns null otherwise - PhysicsDirectBodyState2D *body_get_direct_state(RID p_body) { + PhysicsDirectBodyState2D *body_get_direct_state(RID p_body) override { ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), nullptr); return physics_2d_server->body_get_direct_state(p_body); } /* JOINT API */ + FUNCRID(joint) + + FUNC1(joint_clear, RID) + FUNC3(joint_set_param, RID, JointParam, real_t); FUNC2RC(real_t, joint_get_param, RID, JointParam); @@ -280,9 +287,9 @@ public: //TODO need to convert this to FUNCRID, but it's a hassle.. - FUNC3R(RID, pin_joint_create, const Vector2 &, RID, RID); - FUNC5R(RID, groove_joint_create, const Vector2 &, const Vector2 &, const Vector2 &, RID, RID); - FUNC4R(RID, damped_spring_joint_create, const Vector2 &, const Vector2 &, RID, RID); + FUNC4(joint_make_pin, RID, const Vector2 &, RID, RID); + FUNC6(joint_make_groove, RID, const Vector2 &, const Vector2 &, const Vector2 &, RID, RID); + FUNC5(joint_make_damped_spring, RID, const Vector2 &, const Vector2 &, RID, RID); FUNC3(pin_joint_set_param, RID, PinJointParam, real_t); FUNC2RC(real_t, pin_joint_get_param, RID, PinJointParam); @@ -297,43 +304,28 @@ public: FUNC1(free, RID); FUNC1(set_active, bool); - virtual void init(); - virtual void step(real_t p_step); - virtual void sync(); - virtual void end_sync(); - virtual void flush_queries(); - virtual void finish(); + virtual void init() override; + virtual void step(real_t p_step) override; + virtual void sync() override; + virtual void end_sync() override; + virtual void flush_queries() override; + virtual void finish() override; - virtual bool is_flushing_queries() const { + virtual bool is_flushing_queries() const override { return physics_2d_server->is_flushing_queries(); } - int get_process_info(ProcessInfo p_info) { + int get_process_info(ProcessInfo p_info) override { return physics_2d_server->get_process_info(p_info); } PhysicsServer2DWrapMT(PhysicsServer2D *p_contained, bool p_create_thread); ~PhysicsServer2DWrapMT(); - template <class T> - static PhysicsServer2D *init_server() { -#ifdef NO_THREADS - return memnew(T); // Always single unsafe when no threads are available. -#else - int tm = GLOBAL_DEF("physics/2d/thread_model", 1); - if (tm == 0) { // single unsafe - return memnew(T); - } else if (tm == 1) { // single safe - return memnew(PhysicsServer2DWrapMT(memnew(T), false)); - } else { // multi threaded - return memnew(PhysicsServer2DWrapMT(memnew(T), true)); - } -#endif - } - #undef ServerNameWrapMT #undef ServerName #undef server_name +#undef WRITE_ACTION }; #ifdef DEBUG_SYNC diff --git a/servers/physics_2d/shape_2d_sw.cpp b/servers/physics_2d/shape_2d_sw.cpp index afb1112fc0..6e7e802a8b 100644 --- a/servers/physics_2d/shape_2d_sw.cpp +++ b/servers/physics_2d/shape_2d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -228,7 +228,7 @@ void SegmentShape2DSW::set_data(const Variant &p_data) { Rect2 r = p_data; a = r.position; b = r.size; - n = (b - a).tangent(); + n = (b - a).orthogonal(); Rect2 aabb; aabb.position = a; @@ -339,10 +339,10 @@ void RectangleShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_suppor } bool RectangleShape2DSW::contains_point(const Vector2 &p_point) const { - float x = p_point.x; - float y = p_point.y; - float edge_x = half_extents.x; - float edge_y = half_extents.y; + real_t x = p_point.x; + real_t y = p_point.y; + real_t edge_x = half_extents.x; + real_t edge_y = half_extents.y; return (x >= -edge_x) && (x < edge_x) && (y >= -edge_y) && (y < edge_y); } @@ -590,7 +590,11 @@ real_t ConvexPolygonShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 } void ConvexPolygonShape2DSW::set_data(const Variant &p_data) { +#ifdef REAL_T_IS_DOUBLE + ERR_FAIL_COND(p_data.get_type() != Variant::PACKED_VECTOR2_ARRAY && p_data.get_type() != Variant::PACKED_FLOAT64_ARRAY); +#else ERR_FAIL_COND(p_data.get_type() != Variant::PACKED_VECTOR2_ARRAY && p_data.get_type() != Variant::PACKED_FLOAT32_ARRAY); +#endif if (points) { memdelete_arr(points); @@ -612,7 +616,7 @@ void ConvexPolygonShape2DSW::set_data(const Variant &p_data) { for (int i = 0; i < point_count; i++) { Vector2 p = points[i].pos; Vector2 pn = points[(i + 1) % point_count].pos; - points[i].normal = (pn - p).tangent().normalized(); + points[i].normal = (pn - p).orthogonal().normalized(); } } else { Vector<real_t> dvr = p_data; @@ -740,7 +744,7 @@ bool ConcavePolygonShape2DSW::intersect_segment(const Vector2 &p_begin, const Ve if (nd < d) { d = nd; r_point = res; - r_normal = (b - a).tangent().normalized(); + r_normal = (b - a).orthogonal().normalized(); inters = true; } } @@ -829,7 +833,11 @@ int ConcavePolygonShape2DSW::_generate_bvh(BVH *p_bvh, int p_len, int p_depth) { } void ConcavePolygonShape2DSW::set_data(const Variant &p_data) { +#ifdef REAL_T_IS_DOUBLE + ERR_FAIL_COND(p_data.get_type() != Variant::PACKED_VECTOR2_ARRAY && p_data.get_type() != Variant::PACKED_FLOAT64_ARRAY); +#else ERR_FAIL_COND(p_data.get_type() != Variant::PACKED_VECTOR2_ARRAY && p_data.get_type() != Variant::PACKED_FLOAT32_ARRAY); +#endif Rect2 aabb; @@ -960,7 +968,7 @@ void ConcavePolygonShape2DSW::cull(const Rect2 &p_local_aabb, Callback p_callbac Vector2 a = pointptr[s.points[0]]; Vector2 b = pointptr[s.points[1]]; - SegmentShape2DSW ss(a, b, (b - a).tangent().normalized()); + SegmentShape2DSW ss(a, b, (b - a).orthogonal().normalized()); p_callback(p_userdata, &ss); stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node; diff --git a/servers/physics_2d/shape_2d_sw.h b/servers/physics_2d/shape_2d_sw.h index eca284f7a4..ee2730ebb5 100644 --- a/servers/physics_2d/shape_2d_sw.h +++ b/servers/physics_2d/shape_2d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -237,7 +237,7 @@ public: virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_SEGMENT; } _FORCE_INLINE_ Vector2 get_xformed_normal(const Transform2D &p_xform) const { - return (p_xform.xform(b) - p_xform.xform(a)).normalized().tangent(); + return (p_xform.xform(b) - p_xform.xform(a)).normalized().orthogonal(); } virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal, p_transform, r_min, r_max); } virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const; @@ -431,7 +431,7 @@ public: Vector2 a = points[p_idx].pos; p_idx++; Vector2 b = points[p_idx == point_count ? 0 : p_idx].pos; - return (p_xform.xform(b) - p_xform.xform(a)).normalized().tangent(); + return (p_xform.xform(b) - p_xform.xform(a)).normalized().orthogonal(); } virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_CONVEX_POLYGON; } diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp index edadcabe0b..9cbc01d1d3 100644 --- a/servers/physics_2d/space_2d_sw.cpp +++ b/servers/physics_2d/space_2d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -278,9 +278,9 @@ bool PhysicsDirectSpaceState2DSW::cast_motion(const RID &p_shape, const Transfor continue; } - //test initial overlap + //test initial overlap, ignore objects it's inside of. if (CollisionSolver2DSW::solve(shape, p_xform, Vector2(), col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), nullptr, nullptr, nullptr, p_margin)) { - return false; + continue; } //just do kinematic solving @@ -383,15 +383,6 @@ struct _RestCallbackData2D { static void _rest_cbk_result(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_userdata) { _RestCallbackData2D *rd = (_RestCallbackData2D *)p_userdata; - if (rd->valid_dir != Vector2()) { - if (p_point_A.distance_squared_to(p_point_B) > rd->valid_depth * rd->valid_depth) { - return; - } - if (rd->valid_dir.dot((p_point_A - p_point_B).normalized()) < Math_PI * 0.25) { - return; - } - } - Vector2 contact_rel = p_point_B - p_point_A; real_t len = contact_rel.length(); @@ -403,9 +394,21 @@ static void _rest_cbk_result(const Vector2 &p_point_A, const Vector2 &p_point_B, return; } + Vector2 normal = contact_rel / len; + + if (rd->valid_dir != Vector2()) { + if (len > rd->valid_depth) { + return; + } + + if (rd->valid_dir.dot(normal) > -CMP_EPSILON) { + return; + } + } + rd->best_len = len; rd->best_contact = p_point_B; - rd->best_normal = contact_rel / len; + rd->best_normal = normal; rd->best_object = rd->object; rd->best_shape = rd->shape; rd->best_local_shape = rd->local_shape; @@ -440,7 +443,6 @@ bool PhysicsDirectSpaceState2DSW::rest_info(RID p_shape, const Transform2D &p_sh } rcd.valid_dir = Vector2(); - rcd.valid_depth = 0; rcd.object = col_obj; rcd.shape = shape_idx; rcd.local_shape = 0; @@ -643,9 +645,9 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t Vector2 a = sr[k * 2 + 0]; Vector2 b = sr[k * 2 + 1]; - recover_motion += (b - a) * 0.4; + recover_motion += (b - a) / cbk.amount; - float depth = a.distance_to(b); + real_t depth = a.distance_to(b); if (depth > result.collision_depth) { result.collision_depth = depth; result.collision_point = b; @@ -740,10 +742,13 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co ExcludedShapeSW excluded_shape_pairs[max_excluded_shape_pairs]; int excluded_shape_pair_count = 0; - float separation_margin = MIN(p_margin, MAX(0.0, p_motion.length() - CMP_EPSILON)); //don't separate by more than the intended motion + real_t motion_length = p_motion.length(); + Vector2 motion_normal = p_motion / motion_length; Transform2D body_transform = p_from; + bool recovered = false; + { //STEP 1, FREE BODY IF STUCK @@ -794,7 +799,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) { cbk.valid_dir = col_obj_shape_xform.get_axis(1).normalized(); - float owc_margin = col_obj->get_shape_one_way_collision_margin(shape_idx); + real_t owc_margin = col_obj->get_shape_one_way_collision_margin(shape_idx); cbk.valid_depth = MAX(owc_margin, p_margin); //user specified, but never less than actual margin or it won't work cbk.invalid_by_dir = 0; @@ -805,7 +810,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co Vector2 lv = b->get_linear_velocity(); //compute displacement from linear velocity Vector2 motion = lv * PhysicsDirectBodyState2DSW::singleton->step; - float motion_len = motion.length(); + real_t motion_len = motion.length(); motion.normalize(); cbk.valid_depth += motion_len * MAX(motion.dot(-cbk.valid_dir), 0.0); } @@ -820,7 +825,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co bool did_collide = false; Shape2DSW *against_shape = col_obj->get_shape(shape_idx); - if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), cbkres, cbkptr, nullptr, separation_margin)) { + if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), cbkres, cbkptr, nullptr, p_margin)) { did_collide = cbk.passed > current_passed; //more passed, so collision actually existed } @@ -846,11 +851,20 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co } Vector2 recover_motion; - for (int i = 0; i < cbk.amount; i++) { Vector2 a = sr[i * 2 + 0]; Vector2 b = sr[i * 2 + 1]; - recover_motion += (b - a) * 0.4; + + // Compute plane on b towards a. + Vector2 n = (a - b).normalized(); + real_t d = n.dot(b); + + // Compute depth on recovered motion. + real_t depth = n.dot(a + recover_motion) - d; + if (depth > 0.0) { + // Only recover if there is penetration. + recover_motion -= n * depth * 0.4; + } } if (recover_motion == Vector2()) { @@ -858,6 +872,8 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co break; } + recovered = true; + body_transform.elements[2] += recover_motion; body_aabb.position += recover_motion; @@ -930,7 +946,10 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co //test initial overlap if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), nullptr, nullptr, nullptr, 0)) { if (col_obj->is_shape_set_as_one_way_collision(col_shape_idx)) { - continue; + Vector2 direction = col_obj_shape_xform.get_axis(1).normalized(); + if (motion_normal.dot(direction) < 0) { + continue; + } } stuck = true; @@ -940,13 +959,12 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co //just do kinematic solving real_t low = 0; real_t hi = 1; - Vector2 mnormal = p_motion.normalized(); for (int k = 0; k < 8; k++) { //steps should be customizable.. real_t ofs = (low + hi) * 0.5; - Vector2 sep = mnormal; //important optimization for this to work fast enough + Vector2 sep = motion_normal; //important optimization for this to work fast enough bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * ofs, against_shape, col_obj_shape_xform, Vector2(), nullptr, nullptr, &sep, 0); if (collided) { @@ -967,7 +985,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co cbk.valid_depth = 10e20; - Vector2 sep = mnormal; //important optimization for this to work fast enough + Vector2 sep = motion_normal; //important optimization for this to work fast enough bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * (hi + contact_max_allowed_penetration), col_obj->get_shape(col_shape_idx), col_obj_shape_xform, Vector2(), PhysicsServer2DSW::_shape_col_cbk, &cbk, &sep, 0); if (!collided || cbk.amount == 0) { continue; @@ -998,11 +1016,12 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co } bool collided = false; - if (safe >= 1) { - best_shape = -1; //no best shape with cast, reset to -1 - } - { + if (recovered || (safe < 1)) { + if (safe >= 1) { + best_shape = -1; //no best shape with cast, reset to -1 + } + //it collided, let's get the rest info in unsafe advance Transform2D ugt = body_transform; ugt.elements[2] += p_motion * unsafe; @@ -1011,9 +1030,10 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co rcd.best_len = 0; rcd.best_object = nullptr; rcd.best_shape = 0; - rcd.min_allowed_depth = test_motion_min_contact_depth; - //optimization + // Allowed depth can't be lower than motion length, in order to handle contacts at low speed. + rcd.min_allowed_depth = MIN(motion_length, test_motion_min_contact_depth); + int from_shape = best_shape != -1 ? best_shape : 0; int to_shape = best_shape != -1 ? best_shape + 1 : p_body->get_shape_count(); @@ -1061,7 +1081,22 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) { rcd.valid_dir = col_obj_shape_xform.get_axis(1).normalized(); - rcd.valid_depth = 10e20; + + real_t owc_margin = col_obj->get_shape_one_way_collision_margin(shape_idx); + rcd.valid_depth = MAX(owc_margin, p_margin); //user specified, but never less than actual margin or it won't work + + if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) { + const Body2DSW *b = static_cast<const Body2DSW *>(col_obj); + if (b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_RIGID) { + //fix for moving platforms (kinematic and dynamic), margin is increased by how much it moved in the given direction + Vector2 lv = b->get_linear_velocity(); + //compute displacement from linear velocity + Vector2 motion = lv * PhysicsDirectBodyState2DSW::singleton->step; + real_t motion_len = motion.length(); + motion.normalize(); + rcd.valid_depth += motion_len * MAX(motion.dot(-rcd.valid_dir), 0.0); + } + } } else { rcd.valid_dir = Vector2(); rcd.valid_depth = 0; @@ -1331,7 +1366,7 @@ Space2DSW::Space2DSW() { constraint_bias = 0.2; body_linear_velocity_sleep_threshold = GLOBAL_DEF("physics/2d/sleep_threshold_linear", 2.0); - body_angular_velocity_sleep_threshold = GLOBAL_DEF("physics/2d/sleep_threshold_angular", (8.0 / 180.0 * Math_PI)); + body_angular_velocity_sleep_threshold = GLOBAL_DEF("physics/2d/sleep_threshold_angular", Math::deg2rad(8.0)); body_time_to_sleep = GLOBAL_DEF("physics/2d/time_before_sleep", 0.5); ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/time_before_sleep", PropertyInfo(Variant::FLOAT, "physics/2d/time_before_sleep", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater")); diff --git a/servers/physics_2d/space_2d_sw.h b/servers/physics_2d/space_2d_sw.h index 93b62e0ba4..4d737d622f 100644 --- a/servers/physics_2d/space_2d_sw.h +++ b/servers/physics_2d/space_2d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -187,7 +187,7 @@ public: int test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, PhysicsServer2D::SeparationResult *r_results, int p_result_max, real_t p_margin); void set_debug_contacts(int p_amount) { contact_debug.resize(p_amount); } - _FORCE_INLINE_ bool is_debugging_contacts() const { return !contact_debug.empty(); } + _FORCE_INLINE_ bool is_debugging_contacts() const { return !contact_debug.is_empty(); } _FORCE_INLINE_ void add_debug_contact(const Vector2 &p_contact) { if (contact_debug_count < contact_debug.size()) { contact_debug.write[contact_debug_count++] = p_contact; diff --git a/servers/physics_2d/step_2d_sw.cpp b/servers/physics_2d/step_2d_sw.cpp index c7711bcd1d..6613d19729 100644 --- a/servers/physics_2d/step_2d_sw.cpp +++ b/servers/physics_2d/step_2d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -36,8 +36,8 @@ void Step2DSW::_populate_island(Body2DSW *p_body, Body2DSW **p_island, Constrain p_body->set_island_next(*p_island); *p_island = p_body; - for (Map<Constraint2DSW *, int>::Element *E = p_body->get_constraint_map().front(); E; E = E->next()) { - Constraint2DSW *c = (Constraint2DSW *)E->key(); + for (const List<Pair<Constraint2DSW *, int>>::Element *E = p_body->get_constraint_list().front(); E; E = E->next()) { + Constraint2DSW *c = (Constraint2DSW *)E->get().first; if (c->get_island_step() == _step) { continue; //already processed } @@ -46,7 +46,7 @@ void Step2DSW::_populate_island(Body2DSW *p_body, Body2DSW **p_island, Constrain *p_constraint_island = c; for (int i = 0; i < c->get_body_count(); i++) { - if (i == E->get()) { + if (i == E->get().second) { continue; } Body2DSW *b = c->get_body_ptr()[i]; diff --git a/servers/physics_2d/step_2d_sw.h b/servers/physics_2d/step_2d_sw.h index c1b2d01fb4..83b9130608 100644 --- a/servers/physics_2d/step_2d_sw.h +++ b/servers/physics_2d/step_2d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/area_3d_sw.cpp b/servers/physics_3d/area_3d_sw.cpp index 571f1435de..b6c5b3003c 100644 --- a/servers/physics_3d/area_3d_sw.cpp +++ b/servers/physics_3d/area_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -199,7 +199,7 @@ void Area3DSW::set_monitorable(bool p_monitorable) { } void Area3DSW::call_queries() { - if (monitor_callback_id.is_valid() && !monitored_bodies.empty()) { + if (monitor_callback_id.is_valid() && !monitored_bodies.is_empty()) { Variant res[5]; Variant *resptr[5]; for (int i = 0; i < 5; i++) { @@ -234,7 +234,7 @@ void Area3DSW::call_queries() { } } - if (area_monitor_callback_id.is_valid() && !monitored_areas.empty()) { + if (area_monitor_callback_id.is_valid() && !monitored_areas.is_empty()) { Variant res[5]; Variant *resptr[5]; for (int i = 0; i < 5; i++) { diff --git a/servers/physics_3d/area_3d_sw.h b/servers/physics_3d/area_3d_sw.h index a2efe6af51..8a0a1e963b 100644 --- a/servers/physics_3d/area_3d_sw.h +++ b/servers/physics_3d/area_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/area_pair_3d_sw.cpp b/servers/physics_3d/area_pair_3d_sw.cpp index a5fb20fe2b..4de5f1ba47 100644 --- a/servers/physics_3d/area_pair_3d_sw.cpp +++ b/servers/physics_3d/area_pair_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/area_pair_3d_sw.h b/servers/physics_3d/area_pair_3d_sw.h index 992d4747b9..fbdaa25cbb 100644 --- a/servers/physics_3d/area_pair_3d_sw.h +++ b/servers/physics_3d/area_pair_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/body_3d_sw.cpp b/servers/physics_3d/body_3d_sw.cpp index 841e593ba3..82356e77ef 100644 --- a/servers/physics_3d/body_3d_sw.cpp +++ b/servers/physics_3d/body_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/body_3d_sw.h b/servers/physics_3d/body_3d_sw.h index 6dbda8670a..8e21003a5f 100644 --- a/servers/physics_3d/body_3d_sw.h +++ b/servers/physics_3d/body_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -178,7 +178,7 @@ public: } _FORCE_INLINE_ int get_max_contacts_reported() const { return contacts.size(); } - _FORCE_INLINE_ bool can_report_contacts() const { return !contacts.empty(); } + _FORCE_INLINE_ bool can_report_contacts() const { return !contacts.is_empty(); } _FORCE_INLINE_ void add_contact(const Vector3 &p_local_pos, const Vector3 &p_local_normal, real_t p_depth, int p_local_shape, const Vector3 &p_collider_pos, int p_collider_shape, ObjectID p_collider_instance_id, const RID &p_collider, const Vector3 &p_collider_velocity_at_pos); _FORCE_INLINE_ void add_exception(const RID &p_exception) { exceptions.insert(p_exception); } @@ -426,7 +426,7 @@ public: ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector3()); return body->contacts[p_contact_idx].local_normal; } - virtual float get_contact_impulse(int p_contact_idx) const override { + virtual real_t get_contact_impulse(int p_contact_idx) const override { return 0.0f; // Only implemented for bullet } virtual int get_contact_local_shape(int p_contact_idx) const override { diff --git a/servers/physics_3d/body_pair_3d_sw.cpp b/servers/physics_3d/body_pair_3d_sw.cpp index 848138940e..6012ff1522 100644 --- a/servers/physics_3d/body_pair_3d_sw.cpp +++ b/servers/physics_3d/body_pair_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -367,8 +367,8 @@ void BodyPair3DSW::solve(real_t p_step) { Vector3 jb = c.normal * (c.acc_bias_impulse - jbnOld); - A->apply_bias_impulse(c.rA + A->get_center_of_mass(), -jb, MAX_BIAS_ROTATION / p_step); - B->apply_bias_impulse(c.rB + B->get_center_of_mass(), jb, MAX_BIAS_ROTATION / p_step); + A->apply_bias_impulse(-jb, c.rA + A->get_center_of_mass(), MAX_BIAS_ROTATION / p_step); + B->apply_bias_impulse(jb, c.rB + B->get_center_of_mass(), MAX_BIAS_ROTATION / p_step); crbA = A->get_biased_angular_velocity().cross(c.rA); crbB = B->get_biased_angular_velocity().cross(c.rB); @@ -383,8 +383,8 @@ void BodyPair3DSW::solve(real_t p_step) { Vector3 jb_com = c.normal * (c.acc_bias_impulse_center_of_mass - jbnOld_com); - A->apply_bias_impulse(A->get_center_of_mass(), -jb_com, 0.0f); - B->apply_bias_impulse(B->get_center_of_mass(), jb_com, 0.0f); + A->apply_bias_impulse(-jb_com, A->get_center_of_mass(), 0.0f); + B->apply_bias_impulse(jb_com, B->get_center_of_mass(), 0.0f); } c.active = true; diff --git a/servers/physics_3d/body_pair_3d_sw.h b/servers/physics_3d/body_pair_3d_sw.h index 5f08d0cfa9..4d049eafdc 100644 --- a/servers/physics_3d/body_pair_3d_sw.h +++ b/servers/physics_3d/body_pair_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/broad_phase_3d_basic.cpp b/servers/physics_3d/broad_phase_3d_basic.cpp index 15a5968087..b41c2530da 100644 --- a/servers/physics_3d/broad_phase_3d_basic.cpp +++ b/servers/physics_3d/broad_phase_3d_basic.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/broad_phase_3d_basic.h b/servers/physics_3d/broad_phase_3d_basic.h index 361d322e14..54d34e005f 100644 --- a/servers/physics_3d/broad_phase_3d_basic.h +++ b/servers/physics_3d/broad_phase_3d_basic.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/broad_phase_3d_sw.cpp b/servers/physics_3d/broad_phase_3d_sw.cpp index 1a20fdd0cb..8aa64034ec 100644 --- a/servers/physics_3d/broad_phase_3d_sw.cpp +++ b/servers/physics_3d/broad_phase_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/broad_phase_3d_sw.h b/servers/physics_3d/broad_phase_3d_sw.h index 081e75810f..283c087b96 100644 --- a/servers/physics_3d/broad_phase_3d_sw.h +++ b/servers/physics_3d/broad_phase_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/broad_phase_octree.cpp b/servers/physics_3d/broad_phase_octree.cpp index 1ace1a4fcf..11324fa4e4 100644 --- a/servers/physics_3d/broad_phase_octree.cpp +++ b/servers/physics_3d/broad_phase_octree.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/broad_phase_octree.h b/servers/physics_3d/broad_phase_octree.h index 761a90a051..ee681dda96 100644 --- a/servers/physics_3d/broad_phase_octree.h +++ b/servers/physics_3d/broad_phase_octree.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/collision_object_3d_sw.cpp b/servers/physics_3d/collision_object_3d_sw.cpp index e12f0659e2..293a7e6606 100644 --- a/servers/physics_3d/collision_object_3d_sw.cpp +++ b/servers/physics_3d/collision_object_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -43,7 +43,7 @@ void CollisionObject3DSW::add_shape(Shape3DSW *p_shape, const Transform &p_trans p_shape->add_owner(this); if (!pending_shape_update_list.in_list()) { - PhysicsServer3DSW::singleton->pending_shape_update_list.add(&pending_shape_update_list); + PhysicsServer3DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); } //_update_shapes(); //_shapes_changed(); @@ -56,7 +56,7 @@ void CollisionObject3DSW::set_shape(int p_index, Shape3DSW *p_shape) { p_shape->add_owner(this); if (!pending_shape_update_list.in_list()) { - PhysicsServer3DSW::singleton->pending_shape_update_list.add(&pending_shape_update_list); + PhysicsServer3DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); } //_update_shapes(); //_shapes_changed(); @@ -68,7 +68,7 @@ void CollisionObject3DSW::set_shape_transform(int p_index, const Transform &p_tr shapes.write[p_index].xform = p_transform; shapes.write[p_index].xform_inv = p_transform.affine_inverse(); if (!pending_shape_update_list.in_list()) { - PhysicsServer3DSW::singleton->pending_shape_update_list.add(&pending_shape_update_list); + PhysicsServer3DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); } //_update_shapes(); //_shapes_changed(); @@ -77,7 +77,7 @@ void CollisionObject3DSW::set_shape_transform(int p_index, const Transform &p_tr void CollisionObject3DSW::set_shape_as_disabled(int p_idx, bool p_enable) { shapes.write[p_idx].disabled = p_enable; if (!pending_shape_update_list.in_list()) { - PhysicsServer3DSW::singleton->pending_shape_update_list.add(&pending_shape_update_list); + PhysicsServer3DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); } } @@ -106,7 +106,7 @@ void CollisionObject3DSW::remove_shape(int p_index) { shapes.remove(p_index); if (!pending_shape_update_list.in_list()) { - PhysicsServer3DSW::singleton->pending_shape_update_list.add(&pending_shape_update_list); + PhysicsServer3DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); } //_update_shapes(); //_shapes_changed(); diff --git a/servers/physics_3d/collision_object_3d_sw.h b/servers/physics_3d/collision_object_3d_sw.h index e1220f8855..3847b81381 100644 --- a/servers/physics_3d/collision_object_3d_sw.h +++ b/servers/physics_3d/collision_object_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/collision_solver_3d_sat.cpp b/servers/physics_3d/collision_solver_3d_sat.cpp index 85f55ad66d..f507cacdc3 100644 --- a/servers/physics_3d/collision_solver_3d_sat.cpp +++ b/servers/physics_3d/collision_solver_3d_sat.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,7 +31,38 @@ #include "collision_solver_3d_sat.h" #include "core/math/geometry_3d.h" -#define _EDGE_IS_VALID_SUPPORT_THRESHOLD 0.02 +#include "gjk_epa.h" + +#define fallback_collision_solver gjk_epa_calculate_penetration + +// Cylinder SAT analytic methods and face-circle contact points for cylinder-trimesh and cylinder-box collision are based on ODE colliders. + +/* + * Cylinder-trimesh and Cylinder-box colliders by Alen Ladavac + * Ported to ODE by Nguyen Binh + */ + +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ struct _CollectorCallback { CollisionSolver3DSW::CallbackResult callback; @@ -82,6 +113,17 @@ static void _generate_contacts_point_face(const Vector3 *p_points_A, int p_point p_callback->call(*p_points_A, closest_B); } +static void _generate_contacts_point_circle(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) { +#ifdef DEBUG_ENABLED + ERR_FAIL_COND(p_point_count_A != 1); + ERR_FAIL_COND(p_point_count_B != 3); +#endif + + Vector3 closest_B = Plane(p_points_B[0], p_points_B[1], p_points_B[2]).project(*p_points_A); + + p_callback->call(*p_points_A, closest_B); +} + static void _generate_contacts_edge_edge(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) { #ifdef DEBUG_ENABLED ERR_FAIL_COND(p_point_count_A != 2); @@ -128,6 +170,104 @@ static void _generate_contacts_edge_edge(const Vector3 *p_points_A, int p_point_ p_callback->call(closest_A, closest_B); } +static void _generate_contacts_edge_circle(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) { +#ifdef DEBUG_ENABLED + ERR_FAIL_COND(p_point_count_A != 2); + ERR_FAIL_COND(p_point_count_B != 3); +#endif + + const Vector3 &circle_B_pos = p_points_B[0]; + Vector3 circle_B_line_1 = p_points_B[1] - circle_B_pos; + Vector3 circle_B_line_2 = p_points_B[2] - circle_B_pos; + + real_t circle_B_radius = circle_B_line_1.length(); + Vector3 circle_B_normal = circle_B_line_1.cross(circle_B_line_2).normalized(); + + Plane circle_plane(circle_B_pos, circle_B_normal); + + static const int max_clip = 2; + Vector3 contact_points[max_clip]; + int num_points = 0; + + // Project edge point in circle plane. + const Vector3 &edge_A_1 = p_points_A[0]; + Vector3 proj_point_1 = circle_plane.project(edge_A_1); + + Vector3 dist_vec = proj_point_1 - circle_B_pos; + real_t dist_sq = dist_vec.length_squared(); + + // Point 1 is inside disk, add as contact point. + if (dist_sq <= circle_B_radius * circle_B_radius) { + contact_points[num_points] = edge_A_1; + ++num_points; + } + + const Vector3 &edge_A_2 = p_points_A[1]; + Vector3 proj_point_2 = circle_plane.project(edge_A_2); + + Vector3 dist_vec_2 = proj_point_2 - circle_B_pos; + real_t dist_sq_2 = dist_vec_2.length_squared(); + + // Point 2 is inside disk, add as contact point. + if (dist_sq_2 <= circle_B_radius * circle_B_radius) { + contact_points[num_points] = edge_A_2; + ++num_points; + } + + if (num_points < 2) { + Vector3 line_vec = proj_point_2 - proj_point_1; + real_t line_length_sq = line_vec.length_squared(); + + // Create a quadratic formula of the form ax^2 + bx + c = 0 + real_t a, b, c; + + a = line_length_sq; + b = 2.0 * dist_vec.dot(line_vec); + c = dist_sq - circle_B_radius * circle_B_radius; + + // Solve for t. + real_t sqrtterm = b * b - 4.0 * a * c; + + // If the term we intend to square root is less than 0 then the answer won't be real, + // so the line doesn't intersect. + if (sqrtterm >= 0) { + sqrtterm = Math::sqrt(sqrtterm); + + Vector3 edge_dir = edge_A_2 - edge_A_1; + + real_t fraction_1 = (-b - sqrtterm) / (2.0 * a); + if ((fraction_1 > 0.0) && (fraction_1 < 1.0)) { + Vector3 face_point_1 = edge_A_1 + fraction_1 * edge_dir; + ERR_FAIL_COND(num_points >= max_clip); + contact_points[num_points] = face_point_1; + ++num_points; + } + + real_t fraction_2 = (-b + sqrtterm) / (2.0 * a); + if ((fraction_2 > 0.0) && (fraction_2 < 1.0) && !Math::is_equal_approx(fraction_1, fraction_2)) { + Vector3 face_point_2 = edge_A_1 + fraction_2 * edge_dir; + ERR_FAIL_COND(num_points >= max_clip); + contact_points[num_points] = face_point_2; + ++num_points; + } + } + } + + // Generate contact points. + for (int i = 0; i < num_points; i++) { + const Vector3 &contact_point_A = contact_points[i]; + + real_t d = circle_plane.distance_to(contact_point_A); + Vector3 closest_B = contact_point_A - circle_plane.normal * d; + + if (p_callback->normal.dot(contact_point_A) >= p_callback->normal.dot(closest_B)) { + continue; + } + + p_callback->call(contact_point_A, closest_B); + } +} + static void _generate_contacts_face_face(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) { #ifdef DEBUG_ENABLED ERR_FAIL_COND(p_point_count_A < 2); @@ -217,36 +357,229 @@ static void _generate_contacts_face_face(const Vector3 *p_points_A, int p_point_ } } -static void _generate_contacts_from_supports(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) { +static void _generate_contacts_face_circle(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) { +#ifdef DEBUG_ENABLED + ERR_FAIL_COND(p_point_count_A < 3); + ERR_FAIL_COND(p_point_count_B != 3); +#endif + + const Vector3 &circle_B_pos = p_points_B[0]; + Vector3 circle_B_line_1 = p_points_B[1] - circle_B_pos; + Vector3 circle_B_line_2 = p_points_B[2] - circle_B_pos; + + // Clip face with circle segments. + static const int circle_segments = 8; + Vector3 circle_points[circle_segments]; + + real_t angle_delta = 2.0 * Math_PI / circle_segments; + + for (int i = 0; i < circle_segments; ++i) { + Vector3 point_pos = circle_B_pos; + point_pos += circle_B_line_1 * Math::cos(i * angle_delta); + point_pos += circle_B_line_2 * Math::sin(i * angle_delta); + circle_points[i] = point_pos; + } + + _generate_contacts_face_face(p_points_A, p_point_count_A, circle_points, circle_segments, p_callback); + + // Clip face with circle plane. + Vector3 circle_B_normal = circle_B_line_1.cross(circle_B_line_2).normalized(); + + Plane circle_plane(circle_B_pos, circle_B_normal); + + static const int max_clip = 32; + Vector3 contact_points[max_clip]; + int num_points = 0; + + for (int i = 0; i < p_point_count_A; i++) { + int i_n = (i + 1) % p_point_count_A; + + const Vector3 &edge0_A = p_points_A[i]; + const Vector3 &edge1_A = p_points_A[i_n]; + + real_t dist0 = circle_plane.distance_to(edge0_A); + real_t dist1 = circle_plane.distance_to(edge1_A); + + // First point in front of plane, generate contact point. + if (dist0 * circle_plane.d >= 0) { + ERR_FAIL_COND(num_points >= max_clip); + contact_points[num_points] = edge0_A; + ++num_points; + } + + // Points on different sides, generate contact point. + if (dist0 * dist1 < 0) { + // calculate intersection + Vector3 rel = edge1_A - edge0_A; + real_t den = circle_plane.normal.dot(rel); + real_t dist = -(circle_plane.normal.dot(edge0_A) - circle_plane.d) / den; + Vector3 inters = edge0_A + rel * dist; + + ERR_FAIL_COND(num_points >= max_clip); + contact_points[num_points] = inters; + ++num_points; + } + } + + // Generate contact points. + for (int i = 0; i < num_points; i++) { + const Vector3 &contact_point_A = contact_points[i]; + + real_t d = circle_plane.distance_to(contact_point_A); + Vector3 closest_B = contact_point_A - circle_plane.normal * d; + + if (p_callback->normal.dot(contact_point_A) >= p_callback->normal.dot(closest_B)) { + continue; + } + + p_callback->call(contact_point_A, closest_B); + } +} + +static void _generate_contacts_circle_circle(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) { +#ifdef DEBUG_ENABLED + ERR_FAIL_COND(p_point_count_A != 3); + ERR_FAIL_COND(p_point_count_B != 3); +#endif + + const Vector3 &circle_A_pos = p_points_A[0]; + Vector3 circle_A_line_1 = p_points_A[1] - circle_A_pos; + Vector3 circle_A_line_2 = p_points_A[2] - circle_A_pos; + + real_t circle_A_radius = circle_A_line_1.length(); + Vector3 circle_A_normal = circle_A_line_1.cross(circle_A_line_2).normalized(); + + const Vector3 &circle_B_pos = p_points_B[0]; + Vector3 circle_B_line_1 = p_points_B[1] - circle_B_pos; + Vector3 circle_B_line_2 = p_points_B[2] - circle_B_pos; + + real_t circle_B_radius = circle_B_line_1.length(); + Vector3 circle_B_normal = circle_B_line_1.cross(circle_B_line_2).normalized(); + + static const int max_clip = 4; + Vector3 contact_points[max_clip]; + int num_points = 0; + + Vector3 centers_diff = circle_B_pos - circle_A_pos; + Vector3 norm_proj = circle_A_normal.dot(centers_diff) * circle_A_normal; + Vector3 comp_proj = centers_diff - norm_proj; + real_t proj_dist = comp_proj.length(); + if (!Math::is_zero_approx(proj_dist)) { + comp_proj /= proj_dist; + if ((proj_dist > circle_A_radius - circle_B_radius) && (proj_dist > circle_B_radius - circle_A_radius)) { + // Circles are overlapping, use the 2 points of intersection as contacts. + real_t radius_a_sqr = circle_A_radius * circle_A_radius; + real_t radius_b_sqr = circle_B_radius * circle_B_radius; + real_t d_sqr = proj_dist * proj_dist; + real_t s = (1.0 + (radius_a_sqr - radius_b_sqr) / d_sqr) * 0.5; + real_t h = Math::sqrt(MAX(radius_a_sqr - d_sqr * s * s, 0.0)); + Vector3 midpoint = circle_A_pos + s * comp_proj * proj_dist; + Vector3 h_vec = h * circle_A_normal.cross(comp_proj); + + Vector3 point_A = midpoint + h_vec; + contact_points[num_points] = point_A; + ++num_points; + + point_A = midpoint - h_vec; + contact_points[num_points] = point_A; + ++num_points; + + // Add 2 points from circle A and B along the line between the centers. + point_A = circle_A_pos + comp_proj * circle_A_radius; + contact_points[num_points] = point_A; + ++num_points; + + point_A = circle_B_pos - comp_proj * circle_B_radius - norm_proj; + contact_points[num_points] = point_A; + ++num_points; + } // Otherwise one circle is inside the other one, use 3 arbitrary equidistant points. + } // Otherwise circles are concentric, use 3 arbitrary equidistant points. + + if (num_points == 0) { + // Generate equidistant points. + if (circle_A_radius < circle_B_radius) { + // Circle A inside circle B. + for (int i = 0; i < 3; ++i) { + Vector3 circle_A_point = circle_A_pos; + circle_A_point += circle_A_line_1 * Math::cos(2.0 * Math_PI * i / 3.0); + circle_A_point += circle_A_line_2 * Math::sin(2.0 * Math_PI * i / 3.0); + + contact_points[num_points] = circle_A_point; + ++num_points; + } + } else { + // Circle B inside circle A. + for (int i = 0; i < 3; ++i) { + Vector3 circle_B_point = circle_B_pos; + circle_B_point += circle_B_line_1 * Math::cos(2.0 * Math_PI * i / 3.0); + circle_B_point += circle_B_line_2 * Math::sin(2.0 * Math_PI * i / 3.0); + + Vector3 circle_A_point = circle_B_point - norm_proj; + + contact_points[num_points] = circle_A_point; + ++num_points; + } + } + } + + Plane circle_B_plane(circle_B_pos, circle_B_normal); + + // Generate contact points. + for (int i = 0; i < num_points; i++) { + const Vector3 &contact_point_A = contact_points[i]; + + real_t d = circle_B_plane.distance_to(contact_point_A); + Vector3 closest_B = contact_point_A - circle_B_plane.normal * d; + + if (p_callback->normal.dot(contact_point_A) >= p_callback->normal.dot(closest_B)) { + continue; + } + + p_callback->call(contact_point_A, closest_B); + } +} + +static void _generate_contacts_from_supports(const Vector3 *p_points_A, int p_point_count_A, Shape3DSW::FeatureType p_feature_type_A, const Vector3 *p_points_B, int p_point_count_B, Shape3DSW::FeatureType p_feature_type_B, _CollectorCallback *p_callback) { #ifdef DEBUG_ENABLED ERR_FAIL_COND(p_point_count_A < 1); ERR_FAIL_COND(p_point_count_B < 1); #endif - static const GenerateContactsFunc generate_contacts_func_table[3][3] = { + static const GenerateContactsFunc generate_contacts_func_table[4][4] = { { _generate_contacts_point_point, _generate_contacts_point_edge, _generate_contacts_point_face, + _generate_contacts_point_circle, }, { nullptr, _generate_contacts_edge_edge, _generate_contacts_face_face, + _generate_contacts_edge_circle, }, { nullptr, nullptr, _generate_contacts_face_face, - } + _generate_contacts_face_circle, + }, + { + nullptr, + nullptr, + nullptr, + _generate_contacts_circle_circle, + }, }; int pointcount_B; int pointcount_A; const Vector3 *points_A; const Vector3 *points_B; + int version_A; + int version_B; - if (p_point_count_A > p_point_count_B) { + if (p_feature_type_A > p_feature_type_B) { //swap p_callback->swap = !p_callback->swap; p_callback->normal = -p_callback->normal; @@ -255,16 +588,17 @@ static void _generate_contacts_from_supports(const Vector3 *p_points_A, int p_po pointcount_A = p_point_count_B; points_A = p_points_B; points_B = p_points_A; + version_A = p_feature_type_B; + version_B = p_feature_type_A; } else { pointcount_B = p_point_count_B; pointcount_A = p_point_count_A; points_A = p_points_A; points_B = p_points_B; + version_A = p_feature_type_A; + version_B = p_feature_type_B; } - int version_A = (pointcount_A > 3 ? 3 : pointcount_A) - 1; - int version_B = (pointcount_B > 3 ? 3 : pointcount_B) - 1; - GenerateContactsFunc contacts_func = generate_contacts_func_table[version_A][version_B]; ERR_FAIL_COND(!contacts_func); contacts_func(points_A, pointcount_A, points_B, pointcount_B, p_callback); @@ -346,6 +680,17 @@ public: return true; } + static _FORCE_INLINE_ void test_contact_points(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata) { + SeparatorAxisTest<ShapeA, ShapeB, withMargin> *separator = (SeparatorAxisTest<ShapeA, ShapeB, withMargin> *)p_userdata; + Vector3 axis = (p_point_B - p_point_A); + real_t depth = axis.length(); + + // Filter out bogus directions with a treshold and re-testing axis. + if (separator->best_depth - depth > 0.001) { + separator->test_axis(axis / depth); + } + } + _FORCE_INLINE_ void generate_contacts() { // nothing to do, don't generate if (best_axis == Vector3(0.0, 0.0, 0.0)) { @@ -365,7 +710,8 @@ public: Vector3 supports_A[max_supports]; int support_count_A; - shape_A->get_supports(transform_A->basis.xform_inv(-best_axis).normalized(), max_supports, supports_A, support_count_A); + Shape3DSW::FeatureType support_type_A; + shape_A->get_supports(transform_A->basis.xform_inv(-best_axis).normalized(), max_supports, supports_A, support_count_A, support_type_A); for (int i = 0; i < support_count_A; i++) { supports_A[i] = transform_A->xform(supports_A[i]); } @@ -378,7 +724,8 @@ public: Vector3 supports_B[max_supports]; int support_count_B; - shape_B->get_supports(transform_B->basis.xform_inv(best_axis).normalized(), max_supports, supports_B, support_count_B); + Shape3DSW::FeatureType support_type_B; + shape_B->get_supports(transform_B->basis.xform_inv(best_axis).normalized(), max_supports, supports_B, support_count_B, support_type_B); for (int i = 0; i < support_count_B; i++) { supports_B[i] = transform_B->xform(supports_B[i]); } @@ -393,7 +740,7 @@ public: if (callback->prev_axis) { *callback->prev_axis = best_axis; } - _generate_contacts_from_supports(supports_A, support_count_A, supports_B, support_count_B, callback); + _generate_contacts_from_supports(supports_A, support_count_A, support_type_A, supports_B, support_count_B, support_type_B, callback); callback->collided = true; } @@ -529,6 +876,61 @@ static void _collision_sphere_capsule(const Shape3DSW *p_a, const Transform &p_t template <bool withMargin> static void _collision_sphere_cylinder(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + const SphereShape3DSW *sphere_A = static_cast<const SphereShape3DSW *>(p_a); + const CylinderShape3DSW *cylinder_B = static_cast<const CylinderShape3DSW *>(p_b); + + SeparatorAxisTest<SphereShape3DSW, CylinderShape3DSW, withMargin> separator(sphere_A, p_transform_a, cylinder_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + + if (!separator.test_previous_axis()) { + return; + } + + // Cylinder B end caps. + Vector3 cylinder_B_axis = p_transform_b.basis.get_axis(1).normalized(); + if (!separator.test_axis(cylinder_B_axis)) { + return; + } + + Vector3 cylinder_diff = p_transform_b.origin - p_transform_a.origin; + + // Cylinder B lateral surface. + if (!separator.test_axis(cylinder_B_axis.cross(cylinder_diff).cross(cylinder_B_axis).normalized())) { + return; + } + + // Closest point to cylinder caps. + const Vector3 &sphere_center = p_transform_a.origin; + Vector3 cyl_axis = p_transform_b.basis.get_axis(1); + Vector3 cap_axis = p_transform_b.basis.get_axis(0); + real_t height_scale = cyl_axis.length(); + real_t cap_dist = cylinder_B->get_height() * 0.5 * height_scale; + cyl_axis /= height_scale; + real_t radius_scale = cap_axis.length(); + real_t cap_radius = cylinder_B->get_radius() * radius_scale; + + for (int i = 0; i < 2; i++) { + Vector3 cap_dir = ((i == 0) ? cyl_axis : -cyl_axis); + Vector3 cap_pos = p_transform_b.origin + cap_dir * cap_dist; + + Vector3 closest_point; + + Vector3 diff = sphere_center - cap_pos; + Vector3 proj = diff - cap_dir.dot(diff) * cap_dir; + + real_t proj_len = proj.length(); + if (Math::is_zero_approx(proj_len)) { + // Point is equidistant to all circle points. + continue; + } + + closest_point = cap_pos + (cap_radius / proj_len) * proj; + + if (!separator.test_axis((closest_point - sphere_center).normalized())) { + return; + } + } + + separator.generate_contacts(); } template <bool withMargin> @@ -739,7 +1141,7 @@ static void _collision_box_capsule(const Shape3DSW *p_a, const Transform &p_tran // faces of A for (int i = 0; i < 3; i++) { - Vector3 axis = p_transform_a.basis.get_axis(i); + Vector3 axis = p_transform_a.basis.get_axis(i).normalized(); if (!separator.test_axis(axis)) { return; @@ -826,6 +1228,115 @@ static void _collision_box_capsule(const Shape3DSW *p_a, const Transform &p_tran template <bool withMargin> static void _collision_box_cylinder(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + const BoxShape3DSW *box_A = static_cast<const BoxShape3DSW *>(p_a); + const CylinderShape3DSW *cylinder_B = static_cast<const CylinderShape3DSW *>(p_b); + + SeparatorAxisTest<BoxShape3DSW, CylinderShape3DSW, withMargin> separator(box_A, p_transform_a, cylinder_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + + if (!separator.test_previous_axis()) { + return; + } + + // Faces of A. + for (int i = 0; i < 3; i++) { + Vector3 axis = p_transform_a.basis.get_axis(i).normalized(); + + if (!separator.test_axis(axis)) { + return; + } + } + + Vector3 cyl_axis = p_transform_b.basis.get_axis(1).normalized(); + + // Cylinder end caps. + { + if (!separator.test_axis(cyl_axis)) { + return; + } + } + + // Edges of A, cylinder lateral surface. + for (int i = 0; i < 3; i++) { + Vector3 box_axis = p_transform_a.basis.get_axis(i); + Vector3 axis = box_axis.cross(cyl_axis); + if (Math::is_zero_approx(axis.length_squared())) { + continue; + } + + if (!separator.test_axis(axis.normalized())) { + return; + } + } + + // Gather points of A. + Vector3 vertices_A[8]; + Vector3 box_extent = box_A->get_half_extents(); + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + for (int k = 0; k < 2; k++) { + Vector3 extent = box_extent; + extent.x *= (i * 2 - 1); + extent.y *= (j * 2 - 1); + extent.z *= (k * 2 - 1); + Vector3 &point = vertices_A[i * 2 * 2 + j * 2 + k]; + point = p_transform_a.origin; + for (int l = 0; l < 3; l++) { + point += p_transform_a.basis.get_axis(l) * extent[l]; + } + } + } + } + + // Points of A, cylinder lateral surface. + for (int i = 0; i < 8; i++) { + const Vector3 &point = vertices_A[i]; + Vector3 axis = Plane(cyl_axis, 0).project(point).normalized(); + + if (!separator.test_axis(axis)) { + return; + } + } + + // Edges of A, cylinder end caps rim. + int edges_start_A[12] = { 0, 2, 4, 6, 0, 1, 4, 5, 0, 1, 2, 3 }; + int edges_end_A[12] = { 1, 3, 5, 7, 2, 3, 6, 7, 4, 5, 6, 7 }; + + Vector3 cap_axis = cyl_axis * (cylinder_B->get_height() * 0.5); + + for (int i = 0; i < 2; i++) { + Vector3 cap_pos = p_transform_b.origin + ((i == 0) ? cap_axis : -cap_axis); + + for (int e = 0; e < 12; e++) { + const Vector3 &edge_start = vertices_A[edges_start_A[e]]; + const Vector3 &edge_end = vertices_A[edges_end_A[e]]; + + Vector3 edge_dir = (edge_end - edge_start); + edge_dir.normalize(); + + real_t edge_dot = edge_dir.dot(cyl_axis); + if (Math::is_zero_approx(edge_dot)) { + // Edge is perpendicular to cylinder axis. + continue; + } + + // Calculate intersection between edge and circle plane. + Vector3 edge_diff = cap_pos - edge_start; + real_t diff_dot = edge_diff.dot(cyl_axis); + Vector3 intersection = edge_start + edge_dir * diff_dot / edge_dot; + + // Calculate tangent that touches intersection. + Vector3 tangent = (cap_pos - intersection).cross(cyl_axis); + + // Axis is orthogonal both to tangent and edge direction. + Vector3 axis = tangent.cross(edge_dir); + + if (!separator.test_axis(axis.normalized())) { + return; + } + } + } + + separator.generate_contacts(); } template <bool withMargin> @@ -1111,6 +1622,19 @@ static void _collision_capsule_capsule(const Shape3DSW *p_a, const Transform &p_ template <bool withMargin> static void _collision_capsule_cylinder(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + const CapsuleShape3DSW *capsule_A = static_cast<const CapsuleShape3DSW *>(p_a); + const CylinderShape3DSW *cylinder_B = static_cast<const CylinderShape3DSW *>(p_b); + + SeparatorAxisTest<CapsuleShape3DSW, CylinderShape3DSW, withMargin> separator(capsule_A, p_transform_a, cylinder_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + + CollisionSolver3DSW::CallbackResult callback = SeparatorAxisTest<CapsuleShape3DSW, CylinderShape3DSW, withMargin>::test_contact_points; + + // Fallback to generic algorithm to find the best separating axis. + if (!fallback_collision_solver(p_a, p_transform_a, p_b, p_transform_b, callback, &separator)) { + return; + } + + separator.generate_contacts(); } template <bool withMargin> @@ -1236,14 +1760,165 @@ static void _collision_capsule_face(const Shape3DSW *p_a, const Transform &p_tra template <bool withMargin> static void _collision_cylinder_cylinder(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + const CylinderShape3DSW *cylinder_A = static_cast<const CylinderShape3DSW *>(p_a); + const CylinderShape3DSW *cylinder_B = static_cast<const CylinderShape3DSW *>(p_b); + + SeparatorAxisTest<CylinderShape3DSW, CylinderShape3DSW, withMargin> separator(cylinder_A, p_transform_a, cylinder_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + + Vector3 cylinder_A_axis = p_transform_a.basis.get_axis(1); + Vector3 cylinder_B_axis = p_transform_b.basis.get_axis(1); + + if (!separator.test_previous_axis()) { + return; + } + + // Cylinder A end caps. + if (!separator.test_axis(cylinder_A_axis.normalized())) { + return; + } + + // Cylinder B end caps. + if (!separator.test_axis(cylinder_A_axis.normalized())) { + return; + } + + Vector3 cylinder_diff = p_transform_b.origin - p_transform_a.origin; + + // Cylinder A lateral surface. + if (!separator.test_axis(cylinder_A_axis.cross(cylinder_diff).cross(cylinder_A_axis).normalized())) { + return; + } + + // Cylinder B lateral surface. + if (!separator.test_axis(cylinder_B_axis.cross(cylinder_diff).cross(cylinder_B_axis).normalized())) { + return; + } + + real_t proj = cylinder_A_axis.cross(cylinder_B_axis).cross(cylinder_B_axis).dot(cylinder_A_axis); + if (Math::is_zero_approx(proj)) { + // Parallel cylinders, handle with specific axes only. + // Note: GJKEPA with no margin can lead to degenerate cases in this situation. + separator.generate_contacts(); + return; + } + + CollisionSolver3DSW::CallbackResult callback = SeparatorAxisTest<CylinderShape3DSW, CylinderShape3DSW, withMargin>::test_contact_points; + + // Fallback to generic algorithm to find the best separating axis. + if (!fallback_collision_solver(p_a, p_transform_a, p_b, p_transform_b, callback, &separator)) { + return; + } + + separator.generate_contacts(); } template <bool withMargin> static void _collision_cylinder_convex_polygon(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + const CylinderShape3DSW *cylinder_A = static_cast<const CylinderShape3DSW *>(p_a); + const ConvexPolygonShape3DSW *convex_polygon_B = static_cast<const ConvexPolygonShape3DSW *>(p_b); + + SeparatorAxisTest<CylinderShape3DSW, ConvexPolygonShape3DSW, withMargin> separator(cylinder_A, p_transform_a, convex_polygon_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + + CollisionSolver3DSW::CallbackResult callback = SeparatorAxisTest<CylinderShape3DSW, ConvexPolygonShape3DSW, withMargin>::test_contact_points; + + // Fallback to generic algorithm to find the best separating axis. + if (!fallback_collision_solver(p_a, p_transform_a, p_b, p_transform_b, callback, &separator)) { + return; + } + + separator.generate_contacts(); } template <bool withMargin> static void _collision_cylinder_face(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + const CylinderShape3DSW *cylinder_A = static_cast<const CylinderShape3DSW *>(p_a); + const FaceShape3DSW *face_B = static_cast<const FaceShape3DSW *>(p_b); + + SeparatorAxisTest<CylinderShape3DSW, FaceShape3DSW, withMargin> separator(cylinder_A, p_transform_a, face_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + + if (!separator.test_previous_axis()) { + return; + } + + Vector3 vertex[3] = { + p_transform_b.xform(face_B->vertex[0]), + p_transform_b.xform(face_B->vertex[1]), + p_transform_b.xform(face_B->vertex[2]), + }; + + // Face B normal. + if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized())) { + return; + } + + Vector3 cyl_axis = p_transform_a.basis.get_axis(1).normalized(); + + // Cylinder end caps. + { + if (!separator.test_axis(cyl_axis)) { + return; + } + } + + // Edges of B, cylinder lateral surface. + for (int i = 0; i < 3; i++) { + Vector3 edge_axis = vertex[i] - vertex[(i + 1) % 3]; + Vector3 axis = edge_axis.cross(cyl_axis); + if (Math::is_zero_approx(axis.length_squared())) { + continue; + } + + if (!separator.test_axis(axis.normalized())) { + return; + } + } + + // Points of B, cylinder lateral surface. + for (int i = 0; i < 3; i++) { + const Vector3 &point = vertex[i]; + Vector3 axis = Plane(cyl_axis, 0).project(point).normalized(); + + if (!separator.test_axis(axis)) { + return; + } + } + + // Edges of B, cylinder end caps rim. + Vector3 cap_axis = cyl_axis * (cylinder_A->get_height() * 0.5); + + for (int i = 0; i < 2; i++) { + Vector3 cap_pos = p_transform_a.origin + ((i == 0) ? cap_axis : -cap_axis); + + for (int j = 0; j < 3; j++) { + const Vector3 &edge_start = vertex[j]; + const Vector3 &edge_end = vertex[(j + 1) % 3]; + Vector3 edge_dir = edge_end - edge_start; + edge_dir.normalize(); + + real_t edge_dot = edge_dir.dot(cyl_axis); + if (Math::is_zero_approx(edge_dot)) { + // Edge is perpendicular to cylinder axis. + continue; + } + + // Calculate intersection between edge and circle plane. + Vector3 edge_diff = cap_pos - edge_start; + real_t diff_dot = edge_diff.dot(cyl_axis); + Vector3 intersection = edge_start + edge_dir * diff_dot / edge_dot; + + // Calculate tangent that touches intersection. + Vector3 tangent = (cap_pos - intersection).cross(cyl_axis); + + // Axis is orthogonal both to tangent and edge direction. + Vector3 axis = tangent.cross(edge_dir); + + if (!separator.test_axis(axis.normalized())) { + return; + } + } + } + + separator.generate_contacts(); } template <bool withMargin> diff --git a/servers/physics_3d/collision_solver_3d_sat.h b/servers/physics_3d/collision_solver_3d_sat.h index 5eccfda9ac..97454c0b4a 100644 --- a/servers/physics_3d/collision_solver_3d_sat.h +++ b/servers/physics_3d/collision_solver_3d_sat.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/collision_solver_3d_sw.cpp b/servers/physics_3d/collision_solver_3d_sw.cpp index e2bfaf990d..fd9ea00d92 100644 --- a/servers/physics_3d/collision_solver_3d_sw.cpp +++ b/servers/physics_3d/collision_solver_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -46,8 +46,24 @@ bool CollisionSolver3DSW::solve_static_plane(const Shape3DSW *p_shape_A, const T static const int max_supports = 16; Vector3 supports[max_supports]; int support_count; - - p_shape_B->get_supports(p_transform_B.basis.xform_inv(-p.normal).normalized(), max_supports, supports, support_count); + Shape3DSW::FeatureType support_type; + p_shape_B->get_supports(p_transform_B.basis.xform_inv(-p.normal).normalized(), max_supports, supports, support_count, support_type); + + if (support_type == Shape3DSW::FEATURE_CIRCLE) { + ERR_FAIL_COND_V(support_count != 3, false); + + Vector3 circle_pos = supports[0]; + Vector3 circle_axis_1 = supports[1] - circle_pos; + Vector3 circle_axis_2 = supports[2] - circle_pos; + + // Use 3 equidistant points on the circle. + for (int i = 0; i < 3; ++i) { + Vector3 vertex_pos = circle_pos; + vertex_pos += circle_axis_1 * Math::cos(2.0 * Math_PI * i / 3.0); + vertex_pos += circle_axis_2 * Math::sin(2.0 * Math_PI * i / 3.0); + supports[i] = vertex_pos; + } + } bool found = false; @@ -265,8 +281,25 @@ bool CollisionSolver3DSW::solve_distance_plane(const Shape3DSW *p_shape_A, const static const int max_supports = 16; Vector3 supports[max_supports]; int support_count; + Shape3DSW::FeatureType support_type; + + p_shape_B->get_supports(p_transform_B.basis.xform_inv(-p.normal).normalized(), max_supports, supports, support_count, support_type); - p_shape_B->get_supports(p_transform_B.basis.xform_inv(-p.normal).normalized(), max_supports, supports, support_count); + if (support_type == Shape3DSW::FEATURE_CIRCLE) { + ERR_FAIL_COND_V(support_count != 3, false); + + Vector3 circle_pos = supports[0]; + Vector3 circle_axis_1 = supports[1] - circle_pos; + Vector3 circle_axis_2 = supports[2] - circle_pos; + + // Use 3 equidistant points on the circle. + for (int i = 0; i < 3; ++i) { + Vector3 vertex_pos = circle_pos; + vertex_pos += circle_axis_1 * Math::cos(2.0 * Math_PI * i / 3.0); + vertex_pos += circle_axis_2 * Math::sin(2.0 * Math_PI * i / 3.0); + supports[i] = vertex_pos; + } + } bool collided = false; Vector3 closest; diff --git a/servers/physics_3d/collision_solver_3d_sw.h b/servers/physics_3d/collision_solver_3d_sw.h index 13f54ca8fb..81d87e9773 100644 --- a/servers/physics_3d/collision_solver_3d_sw.h +++ b/servers/physics_3d/collision_solver_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/constraint_3d_sw.h b/servers/physics_3d/constraint_3d_sw.h index 081ddb0382..2571335c43 100644 --- a/servers/physics_3d/constraint_3d_sw.h +++ b/servers/physics_3d/constraint_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/gjk_epa.cpp b/servers/physics_3d/gjk_epa.cpp index e14949543e..aa7c11eec5 100644 --- a/servers/physics_3d/gjk_epa.cpp +++ b/servers/physics_3d/gjk_epa.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -64,7 +64,7 @@ GJK-EPA collision solver by Nathanael Presson, 2008 /* GJK */ #define GJK_MAX_ITERATIONS 128 -#define GJK_ACCURARY ((real_t)0.0001) +#define GJK_ACCURACY ((real_t)0.0001) #define GJK_MIN_DISTANCE ((real_t)0.0001) #define GJK_DUPLICATED_EPS ((real_t)0.0001) #define GJK_SIMPLEX2_EPS ((real_t)0.0) @@ -72,10 +72,13 @@ GJK-EPA collision solver by Nathanael Presson, 2008 #define GJK_SIMPLEX4_EPS ((real_t)0.0) /* EPA */ -#define EPA_MAX_VERTICES 64 +#define EPA_MAX_VERTICES 128 #define EPA_MAX_FACES (EPA_MAX_VERTICES*2) #define EPA_MAX_ITERATIONS 255 -#define EPA_ACCURACY ((real_t)0.0001) +// -- GODOT start -- +//#define EPA_ACCURACY ((real_t)0.0001) +#define EPA_ACCURACY ((real_t)0.00001) +// -- GODOT end -- #define EPA_FALLBACK (10*EPA_ACCURACY) #define EPA_PLANE_EPS ((real_t)0.00001) #define EPA_INSIDE_EPS ((real_t)0.01) @@ -237,7 +240,7 @@ struct GJK /* Check for termination */ const real_t omega=vec3_dot(m_ray,w)/rl; alpha=MAX(omega,alpha); - if(((rl-alpha)-(GJK_ACCURARY*rl))<=0) + if(((rl-alpha)-(GJK_ACCURACY*rl))<=0) {/* Return old simplex */ removevertice(m_simplices[m_current]); break; @@ -466,7 +469,7 @@ struct GJK if(ng&&(Math::abs(vl)>GJK_SIMPLEX4_EPS)) { real_t mindist=-1; - real_t subw[3]; + real_t subw[3] = {0.f, 0.f, 0.f}; U subm=0; for(U i=0;i<3;++i) { @@ -512,7 +515,6 @@ struct GJK { Vector3 n; real_t d; - real_t p; sSV* c[3]; sFace* f[3]; sFace* l[2]; @@ -661,8 +663,7 @@ struct GJK remove(m_hull,best); append(m_stock,best); best=findbest(); - if(best->p>=outer.p) { outer=*best; -} + outer=*best; } else { m_status=eStatus::InvalidHull;break; } } else { m_status=eStatus::AccuraryReached;break; } } else { m_status=eStatus::OutOfVertices;break; } @@ -688,24 +689,54 @@ struct GJK } } /* Fallback */ - m_status = eStatus::FallBack; - m_normal = -guess; - const real_t nl=m_normal.length(); - if(nl>0) { - m_normal = m_normal/nl; + m_status = eStatus::FallBack; + m_normal = -guess; + const real_t nl = m_normal.length(); + if (nl > 0) { + m_normal = m_normal/nl; } else { - m_normal = Vector3(1,0,0); -} + m_normal = Vector3(1,0,0); + } m_depth = 0; m_result.rank=1; m_result.c[0]=simplex.c[0]; m_result.p[0]=1; return(m_status); } + + bool getedgedist(sFace* face, sSV* a, sSV* b, real_t& dist) + { + const Vector3 ba = b->w - a->w; + const Vector3 n_ab = vec3_cross(ba, face->n); // Outward facing edge normal direction, on triangle plane + const real_t a_dot_nab = vec3_dot(a->w, n_ab); // Only care about the sign to determine inside/outside, so not normalization required + + if (a_dot_nab < 0) { + // Outside of edge a->b + const real_t ba_l2 = ba.length_squared(); + const real_t a_dot_ba = vec3_dot(a->w, ba); + const real_t b_dot_ba = vec3_dot(b->w, ba); + + if (a_dot_ba > 0) { + // Pick distance vertex a + dist = a->w.length(); + } else if (b_dot_ba < 0) { + // Pick distance vertex b + dist = b->w.length(); + } else { + // Pick distance to edge a->b + const real_t a_dot_b = vec3_dot(a->w, b->w); + dist = Math::sqrt(MAX((a->w.length_squared() * b->w.length_squared() - a_dot_b * a_dot_b) / ba_l2, 0.0)); + } + + return true; + } + + return false; + } + sFace* newface(sSV* a,sSV* b,sSV* c,bool forced) { - if(m_stock.root) - { + if (m_stock.root) { sFace* face=m_stock.root; remove(m_stock,face); append(m_hull,face); @@ -716,23 +747,23 @@ struct GJK face->n = vec3_cross(b->w-a->w,c->w-a->w); const real_t l=face->n.length(); const bool v=l>EPA_ACCURACY; - face->p = MIN(MIN( - vec3_dot(a->w,vec3_cross(face->n,a->w-b->w)), - vec3_dot(b->w,vec3_cross(face->n,b->w-c->w))), - vec3_dot(c->w,vec3_cross(face->n,c->w-a->w))) / - (v?l:1); - face->p = face->p>=-EPA_INSIDE_EPS?0:face->p; - if(v) - { - face->d = vec3_dot(a->w,face->n)/l; + if (v) { + if (!(getedgedist(face, a, b, face->d) || + getedgedist(face, b, c, face->d) || + getedgedist(face, c, a, face->d))) { + // Origin projects to the interior of the triangle + // Use distance to triangle plane + face->d = vec3_dot(a->w, face->n) / l; + } face->n /= l; - if(forced||(face->d>=-EPA_PLANE_EPS)) - { + if (forced||(face->d>=-EPA_PLANE_EPS)) { return(face); - } else { m_status=eStatus::NonConvex; -} - } else { m_status=eStatus::Degenerated; -} + } else { + m_status=eStatus::NonConvex; + } + } else { + m_status=eStatus::Degenerated; + } remove(m_hull,face); append(m_stock,face); return(nullptr); @@ -747,15 +778,13 @@ struct GJK { sFace* minf=m_hull.root; real_t mind=minf->d*minf->d; - real_t maxp=minf->p; for(sFace* f=minf->l[1];f;f=f->l[1]) { const real_t sqd=f->d*f->d; - if((f->p>=maxp)&&(sqd<mind)) + if(sqd<mind) { minf=f; mind=sqd; - maxp=f->p; } } return(minf); diff --git a/servers/physics_3d/gjk_epa.h b/servers/physics_3d/gjk_epa.h index dec0f269e1..be3ba4e664 100644 --- a/servers/physics_3d/gjk_epa.h +++ b/servers/physics_3d/gjk_epa.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp b/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp index 789d6687a4..9c4493f4a2 100644 --- a/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp +++ b/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -92,9 +92,9 @@ ConeTwistJoint3DSW::ConeTwistJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Trans m_rbAFrame = rbAFrame; m_rbBFrame = rbBFrame; - m_swingSpan1 = Math_PI / 4.0; - m_swingSpan2 = Math_PI / 4.0; - m_twistSpan = Math_PI * 2; + m_swingSpan1 = Math_TAU / 8.0; + m_swingSpan2 = Math_TAU / 8.0; + m_twistSpan = Math_TAU; m_biasFactor = 0.3f; m_relaxationFactor = 1.0f; diff --git a/servers/physics_3d/joints/cone_twist_joint_3d_sw.h b/servers/physics_3d/joints/cone_twist_joint_3d_sw.h index c713d8cf17..4e4d4e7f0c 100644 --- a/servers/physics_3d/joints/cone_twist_joint_3d_sw.h +++ b/servers/physics_3d/joints/cone_twist_joint_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -102,7 +102,7 @@ public: bool m_solveSwingLimit; public: - virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_CONE_TWIST; } + virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_CONE_TWIST; } virtual bool setup(real_t p_timestep); virtual void solve(real_t p_timestep); diff --git a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp index 9ce5ebb7ed..13b389251f 100644 --- a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp +++ b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -132,7 +132,7 @@ real_t G6DOFRotationalLimitMotor3DSW::solveAngularLimits( real_t oldaccumImpulse = m_accumulatedImpulse; real_t sum = oldaccumImpulse + clippedMotorImpulse; - m_accumulatedImpulse = sum > hi ? real_t(0.) : sum < lo ? real_t(0.) : sum; + m_accumulatedImpulse = sum > hi ? real_t(0.) : (sum < lo ? real_t(0.) : sum); clippedMotorImpulse = m_accumulatedImpulse - oldaccumImpulse; @@ -201,7 +201,7 @@ real_t G6DOFTranslationalLimitMotor3DSW::solveLinearAxis( real_t oldNormalImpulse = m_accumulatedImpulse[limit_index]; real_t sum = oldNormalImpulse + normalImpulse; - m_accumulatedImpulse[limit_index] = sum > hi ? real_t(0.) : sum < lo ? real_t(0.) : sum; + m_accumulatedImpulse[limit_index] = sum > hi ? real_t(0.) : (sum < lo ? real_t(0.) : sum); normalImpulse = m_accumulatedImpulse[limit_index] - oldNormalImpulse; Vector3 impulse_vector = axis_normal_on_a * normalImpulse; diff --git a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h index cc1423a1cb..d61a033231 100644 --- a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h +++ b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -103,19 +103,6 @@ public: m_enableLimit = false; } - G6DOFRotationalLimitMotor3DSW(const G6DOFRotationalLimitMotor3DSW &limot) { - m_targetVelocity = limot.m_targetVelocity; - m_maxMotorForce = limot.m_maxMotorForce; - m_limitSoftness = limot.m_limitSoftness; - m_loLimit = limot.m_loLimit; - m_hiLimit = limot.m_hiLimit; - m_ERP = limot.m_ERP; - m_bounce = limot.m_bounce; - m_currentLimit = limot.m_currentLimit; - m_currentLimitError = limot.m_currentLimitError; - m_enableMotor = limot.m_enableMotor; - } - //! Is limited bool isLimited() { return (m_loLimit < m_hiLimit); @@ -163,16 +150,6 @@ public: enable_limit[2] = true; } - G6DOFTranslationalLimitMotor3DSW(const G6DOFTranslationalLimitMotor3DSW &other) { - m_lowerLimit = other.m_lowerLimit; - m_upperLimit = other.m_upperLimit; - m_accumulatedImpulse = other.m_accumulatedImpulse; - - m_limitSoftness = other.m_limitSoftness; - m_damping = other.m_damping; - m_restitution = other.m_restitution; - } - //! Test limit /*! - free means upper < lower, @@ -242,11 +219,8 @@ protected: //!@} - Generic6DOFJoint3DSW &operator=(Generic6DOFJoint3DSW &other) { - ERR_PRINT("pito"); - (void)other; - return *this; - } + Generic6DOFJoint3DSW(Generic6DOFJoint3DSW const &) = delete; + void operator=(Generic6DOFJoint3DSW const &) = delete; void buildLinearJacobian( JacobianEntry3DSW &jacLinear, const Vector3 &normalWorld, @@ -260,7 +234,7 @@ protected: public: Generic6DOFJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &frameInA, const Transform &frameInB, bool useLinearReferenceFrameA); - virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_6DOF; } + virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_6DOF; } virtual bool setup(real_t p_timestep); virtual void solve(real_t p_timestep); diff --git a/servers/physics_3d/joints/hinge_joint_3d_sw.cpp b/servers/physics_3d/joints/hinge_joint_3d_sw.cpp index c6fbc0f55f..2b9f0038b4 100644 --- a/servers/physics_3d/joints/hinge_joint_3d_sw.cpp +++ b/servers/physics_3d/joints/hinge_joint_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/joints/hinge_joint_3d_sw.h b/servers/physics_3d/joints/hinge_joint_3d_sw.h index c5af888eca..b6117aa0bc 100644 --- a/servers/physics_3d/joints/hinge_joint_3d_sw.h +++ b/servers/physics_3d/joints/hinge_joint_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -96,7 +96,7 @@ class HingeJoint3DSW : public Joint3DSW { real_t m_appliedImpulse; public: - virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_HINGE; } + virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_HINGE; } virtual bool setup(real_t p_step); virtual void solve(real_t p_step); diff --git a/servers/physics_3d/joints/jacobian_entry_3d_sw.h b/servers/physics_3d/joints/jacobian_entry_3d_sw.h index 1737c21b3d..2829a5caf7 100644 --- a/servers/physics_3d/joints/jacobian_entry_3d_sw.h +++ b/servers/physics_3d/joints/jacobian_entry_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/joints/pin_joint_3d_sw.cpp b/servers/physics_3d/joints/pin_joint_3d_sw.cpp index f028ad88f9..9f708ce151 100644 --- a/servers/physics_3d/joints/pin_joint_3d_sw.cpp +++ b/servers/physics_3d/joints/pin_joint_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/joints/pin_joint_3d_sw.h b/servers/physics_3d/joints/pin_joint_3d_sw.h index 0181a4455b..1875983527 100644 --- a/servers/physics_3d/joints/pin_joint_3d_sw.h +++ b/servers/physics_3d/joints/pin_joint_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -74,7 +74,7 @@ class PinJoint3DSW : public Joint3DSW { Vector3 m_pivotInB; public: - virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_PIN; } + virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_PIN; } virtual bool setup(real_t p_step); virtual void solve(real_t p_step); diff --git a/servers/physics_3d/joints/slider_joint_3d_sw.cpp b/servers/physics_3d/joints/slider_joint_3d_sw.cpp index dd6cc04f7c..0adc471797 100644 --- a/servers/physics_3d/joints/slider_joint_3d_sw.cpp +++ b/servers/physics_3d/joints/slider_joint_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/joints/slider_joint_3d_sw.h b/servers/physics_3d/joints/slider_joint_3d_sw.h index 37394a1580..f52f6ace27 100644 --- a/servers/physics_3d/joints/slider_joint_3d_sw.h +++ b/servers/physics_3d/joints/slider_joint_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -243,7 +243,7 @@ public: bool setup(real_t p_step); void solve(real_t p_step); - virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_SLIDER; } + virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_SLIDER; } }; #endif // SLIDER_JOINT_SW_H diff --git a/servers/physics_3d/joints_3d_sw.h b/servers/physics_3d/joints_3d_sw.h index 6a010ee771..1fe573c69e 100644 --- a/servers/physics_3d/joints_3d_sw.h +++ b/servers/physics_3d/joints_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -36,7 +36,16 @@ class Joint3DSW : public Constraint3DSW { public: - virtual PhysicsServer3D::JointType get_type() const = 0; + virtual bool setup(real_t p_step) { return false; } + virtual void solve(real_t p_step) {} + + void copy_settings_from(Joint3DSW *p_joint) { + set_self(p_joint->get_self()); + set_priority(p_joint->get_priority()); + disable_collisions_between_bodies(p_joint->is_disabled_collisions_between_bodies()); + } + + virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_MAX; } _FORCE_INLINE_ Joint3DSW(Body3DSW **p_body_ptr = nullptr, int p_body_count = 0) : Constraint3DSW(p_body_ptr, p_body_count) { } diff --git a/servers/physics_3d/physics_server_3d_sw.cpp b/servers/physics_3d/physics_server_3d_sw.cpp index 07a7498fec..735e9094d2 100644 --- a/servers/physics_3d/physics_server_3d_sw.cpp +++ b/servers/physics_3d/physics_server_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -43,47 +43,63 @@ #define FLUSH_QUERY_CHECK(m_object) \ ERR_FAIL_COND_MSG(m_object->get_space() && flushing_queries, "Can't change this state while flushing queries. Use call_deferred() or set_deferred() to change monitoring state instead."); -RID PhysicsServer3DSW::shape_create(ShapeType p_shape) { - Shape3DSW *shape = nullptr; - switch (p_shape) { - case SHAPE_PLANE: { - shape = memnew(PlaneShape3DSW); - } break; - case SHAPE_RAY: { - shape = memnew(RayShape3DSW); - } break; - case SHAPE_SPHERE: { - shape = memnew(SphereShape3DSW); - } break; - case SHAPE_BOX: { - shape = memnew(BoxShape3DSW); - } break; - case SHAPE_CAPSULE: { - shape = memnew(CapsuleShape3DSW); - } break; - case SHAPE_CYLINDER: { - ERR_FAIL_V_MSG(RID(), "CylinderShape3D is not supported in GodotPhysics3D. Please switch to Bullet in the Project Settings."); - } break; - case SHAPE_CONVEX_POLYGON: { - shape = memnew(ConvexPolygonShape3DSW); - } break; - case SHAPE_CONCAVE_POLYGON: { - shape = memnew(ConcavePolygonShape3DSW); - } break; - case SHAPE_HEIGHTMAP: { - shape = memnew(HeightMapShape3DSW); - } break; - case SHAPE_CUSTOM: { - ERR_FAIL_V(RID()); - - } break; - } - - RID id = shape_owner.make_rid(shape); - shape->set_self(id); - - return id; -}; +RID PhysicsServer3DSW::plane_shape_create() { + Shape3DSW *shape = memnew(PlaneShape3DSW); + RID rid = shape_owner.make_rid(shape); + shape->set_self(rid); + return rid; +} +RID PhysicsServer3DSW::ray_shape_create() { + Shape3DSW *shape = memnew(RayShape3DSW); + RID rid = shape_owner.make_rid(shape); + shape->set_self(rid); + return rid; +} +RID PhysicsServer3DSW::sphere_shape_create() { + Shape3DSW *shape = memnew(SphereShape3DSW); + RID rid = shape_owner.make_rid(shape); + shape->set_self(rid); + return rid; +} +RID PhysicsServer3DSW::box_shape_create() { + Shape3DSW *shape = memnew(BoxShape3DSW); + RID rid = shape_owner.make_rid(shape); + shape->set_self(rid); + return rid; +} +RID PhysicsServer3DSW::capsule_shape_create() { + Shape3DSW *shape = memnew(CapsuleShape3DSW); + RID rid = shape_owner.make_rid(shape); + shape->set_self(rid); + return rid; +} +RID PhysicsServer3DSW::cylinder_shape_create() { + Shape3DSW *shape = memnew(CylinderShape3DSW); + RID rid = shape_owner.make_rid(shape); + shape->set_self(rid); + return rid; +} +RID PhysicsServer3DSW::convex_polygon_shape_create() { + Shape3DSW *shape = memnew(ConvexPolygonShape3DSW); + RID rid = shape_owner.make_rid(shape); + shape->set_self(rid); + return rid; +} +RID PhysicsServer3DSW::concave_polygon_shape_create() { + Shape3DSW *shape = memnew(ConcavePolygonShape3DSW); + RID rid = shape_owner.make_rid(shape); + shape->set_self(rid); + return rid; +} +RID PhysicsServer3DSW::heightmap_shape_create() { + Shape3DSW *shape = memnew(HeightMapShape3DSW); + RID rid = shape_owner.make_rid(shape); + shape->set_self(rid); + return rid; +} +RID PhysicsServer3DSW::custom_shape_create() { + ERR_FAIL_V(RID()); +} void PhysicsServer3DSW::shape_set_data(RID p_shape, const Variant &p_data) { Shape3DSW *shape = shape_owner.getornull(p_shape); @@ -174,7 +190,7 @@ real_t PhysicsServer3DSW::space_get_param(RID p_space, SpaceParameter p_param) c PhysicsDirectSpaceState3D *PhysicsServer3DSW::space_get_direct_state(RID p_space) { Space3DSW *space = space_owner.getornull(p_space); ERR_FAIL_COND_V(!space, nullptr); - ERR_FAIL_COND_V_MSG(space->is_locked(), nullptr, "Space state is inaccessible right now, wait for iteration or physics process notification."); + ERR_FAIL_COND_V_MSG((using_threads && !doing_sync) || space->is_locked(), nullptr, "Space state is inaccessible right now, wait for iteration or physics process notification."); return space->get_direct_state(); } @@ -413,13 +429,6 @@ void PhysicsServer3DSW::area_set_ray_pickable(RID p_area, bool p_enable) { area->set_ray_pickable(p_enable); } -bool PhysicsServer3DSW::area_is_ray_pickable(RID p_area) const { - Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND_V(!area, false); - - return area->is_ray_pickable(); -} - void PhysicsServer3DSW::area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) { Area3DSW *area = area_owner.getornull(p_area); ERR_FAIL_COND(!area); @@ -429,14 +438,8 @@ void PhysicsServer3DSW::area_set_area_monitor_callback(RID p_area, Object *p_rec /* BODY API */ -RID PhysicsServer3DSW::body_create(BodyMode p_mode, bool p_init_sleeping) { +RID PhysicsServer3DSW::body_create() { Body3DSW *body = memnew(Body3DSW); - if (p_mode != BODY_MODE_RIGID) { - body->set_mode(p_mode); - } - if (p_init_sleeping) { - body->set_state(BODY_STATE_SLEEPING, p_init_sleeping); - } RID rid = body_owner.make_rid(body); body->set_self(rid); return rid; @@ -857,12 +860,6 @@ void PhysicsServer3DSW::body_set_ray_pickable(RID p_body, bool p_enable) { body->set_ray_pickable(p_enable); } -bool PhysicsServer3DSW::body_is_ray_pickable(RID p_body) const { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, false); - return body->is_ray_pickable(); -} - bool PhysicsServer3DSW::body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result, bool p_exclude_raycast_shapes) { Body3DSW *body = body_owner.getornull(p_body); ERR_FAIL_COND_V(!body, false); @@ -874,7 +871,7 @@ bool PhysicsServer3DSW::body_test_motion(RID p_body, const Transform &p_from, co return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, body->get_kinematic_margin(), r_result, p_exclude_raycast_shapes); } -int PhysicsServer3DSW::body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, float p_margin) { +int PhysicsServer3DSW::body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin) { Body3DSW *body = body_owner.getornull(p_body); ERR_FAIL_COND_V(!body, false); ERR_FAIL_COND_V(!body->get_space(), false); @@ -886,6 +883,8 @@ int PhysicsServer3DSW::body_test_ray_separation(RID p_body, const Transform &p_t } PhysicsDirectBodyState3D *PhysicsServer3DSW::body_get_direct_state(RID p_body) { + ERR_FAIL_COND_V_MSG((using_threads && !doing_sync), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification."); + Body3DSW *body = body_owner.getornull(p_body); ERR_FAIL_COND_V(!body, nullptr); ERR_FAIL_COND_V_MSG(body->get_space()->is_locked(), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification."); @@ -896,30 +895,52 @@ PhysicsDirectBodyState3D *PhysicsServer3DSW::body_get_direct_state(RID p_body) { /* JOINT API */ -RID PhysicsServer3DSW::joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) { +RID PhysicsServer3DSW::joint_create() { + Joint3DSW *joint = memnew(Joint3DSW); + RID rid = joint_owner.make_rid(joint); + joint->set_self(rid); + return rid; +} + +void PhysicsServer3DSW::joint_clear(RID p_joint) { + Joint3DSW *joint = joint_owner.getornull(p_joint); + if (joint->get_type() != JOINT_TYPE_MAX) { + Joint3DSW *empty_joint = memnew(Joint3DSW); + empty_joint->copy_settings_from(joint); + + joint_owner.replace(p_joint, empty_joint); + memdelete(joint); + } +} + +void PhysicsServer3DSW::joint_make_pin(RID p_joint, RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) { Body3DSW *body_A = body_owner.getornull(p_body_A); - ERR_FAIL_COND_V(!body_A, RID()); + ERR_FAIL_COND(!body_A); if (!p_body_B.is_valid()) { - ERR_FAIL_COND_V(!body_A->get_space(), RID()); + ERR_FAIL_COND(!body_A->get_space()); p_body_B = body_A->get_space()->get_static_global_body(); } Body3DSW *body_B = body_owner.getornull(p_body_B); - ERR_FAIL_COND_V(!body_B, RID()); + ERR_FAIL_COND(!body_B); + + ERR_FAIL_COND(body_A == body_B); - ERR_FAIL_COND_V(body_A == body_B, RID()); + Joint3DSW *prev_joint = joint_owner.getornull(p_joint); + ERR_FAIL_COND(prev_joint == nullptr); Joint3DSW *joint = memnew(PinJoint3DSW(body_A, p_local_A, body_B, p_local_B)); - RID rid = joint_owner.make_rid(joint); - joint->set_self(rid); - return rid; + + joint->copy_settings_from(prev_joint); + joint_owner.replace(p_joint, joint); + memdelete(prev_joint); } void PhysicsServer3DSW::pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) { Joint3DSW *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND(!joint); - ERR_FAIL_COND(joint->get_type() != JOINT_PIN); + ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_PIN); PinJoint3DSW *pin_joint = static_cast<PinJoint3DSW *>(joint); pin_joint->set_param(p_param, p_value); } @@ -927,7 +948,7 @@ void PhysicsServer3DSW::pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t PhysicsServer3DSW::pin_joint_get_param(RID p_joint, PinJointParam p_param) const { Joint3DSW *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND_V(!joint, 0); - ERR_FAIL_COND_V(joint->get_type() != JOINT_PIN, 0); + ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_PIN, 0); PinJoint3DSW *pin_joint = static_cast<PinJoint3DSW *>(joint); return pin_joint->get_param(p_param); } @@ -935,7 +956,7 @@ real_t PhysicsServer3DSW::pin_joint_get_param(RID p_joint, PinJointParam p_param void PhysicsServer3DSW::pin_joint_set_local_a(RID p_joint, const Vector3 &p_A) { Joint3DSW *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND(!joint); - ERR_FAIL_COND(joint->get_type() != JOINT_PIN); + ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_PIN); PinJoint3DSW *pin_joint = static_cast<PinJoint3DSW *>(joint); pin_joint->set_pos_a(p_A); } @@ -943,7 +964,7 @@ void PhysicsServer3DSW::pin_joint_set_local_a(RID p_joint, const Vector3 &p_A) { Vector3 PhysicsServer3DSW::pin_joint_get_local_a(RID p_joint) const { Joint3DSW *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND_V(!joint, Vector3()); - ERR_FAIL_COND_V(joint->get_type() != JOINT_PIN, Vector3()); + ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_PIN, Vector3()); PinJoint3DSW *pin_joint = static_cast<PinJoint3DSW *>(joint); return pin_joint->get_position_a(); } @@ -951,7 +972,7 @@ Vector3 PhysicsServer3DSW::pin_joint_get_local_a(RID p_joint) const { void PhysicsServer3DSW::pin_joint_set_local_b(RID p_joint, const Vector3 &p_B) { Joint3DSW *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND(!joint); - ERR_FAIL_COND(joint->get_type() != JOINT_PIN); + ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_PIN); PinJoint3DSW *pin_joint = static_cast<PinJoint3DSW *>(joint); pin_joint->set_pos_b(p_B); } @@ -959,55 +980,63 @@ void PhysicsServer3DSW::pin_joint_set_local_b(RID p_joint, const Vector3 &p_B) { Vector3 PhysicsServer3DSW::pin_joint_get_local_b(RID p_joint) const { Joint3DSW *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND_V(!joint, Vector3()); - ERR_FAIL_COND_V(joint->get_type() != JOINT_PIN, Vector3()); + ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_PIN, Vector3()); PinJoint3DSW *pin_joint = static_cast<PinJoint3DSW *>(joint); return pin_joint->get_position_b(); } -RID PhysicsServer3DSW::joint_create_hinge(RID p_body_A, const Transform &p_frame_A, RID p_body_B, const Transform &p_frame_B) { +void PhysicsServer3DSW::joint_make_hinge(RID p_joint, RID p_body_A, const Transform &p_frame_A, RID p_body_B, const Transform &p_frame_B) { Body3DSW *body_A = body_owner.getornull(p_body_A); - ERR_FAIL_COND_V(!body_A, RID()); + ERR_FAIL_COND(!body_A); if (!p_body_B.is_valid()) { - ERR_FAIL_COND_V(!body_A->get_space(), RID()); + ERR_FAIL_COND(!body_A->get_space()); p_body_B = body_A->get_space()->get_static_global_body(); } Body3DSW *body_B = body_owner.getornull(p_body_B); - ERR_FAIL_COND_V(!body_B, RID()); + ERR_FAIL_COND(!body_B); + + ERR_FAIL_COND(body_A == body_B); - ERR_FAIL_COND_V(body_A == body_B, RID()); + Joint3DSW *prev_joint = joint_owner.getornull(p_joint); + ERR_FAIL_COND(prev_joint == nullptr); Joint3DSW *joint = memnew(HingeJoint3DSW(body_A, body_B, p_frame_A, p_frame_B)); - RID rid = joint_owner.make_rid(joint); - joint->set_self(rid); - return rid; + + joint->copy_settings_from(prev_joint); + joint_owner.replace(p_joint, joint); + memdelete(prev_joint); } -RID PhysicsServer3DSW::joint_create_hinge_simple(RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B) { +void PhysicsServer3DSW::joint_make_hinge_simple(RID p_joint, RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B) { Body3DSW *body_A = body_owner.getornull(p_body_A); - ERR_FAIL_COND_V(!body_A, RID()); + ERR_FAIL_COND(!body_A); if (!p_body_B.is_valid()) { - ERR_FAIL_COND_V(!body_A->get_space(), RID()); + ERR_FAIL_COND(!body_A->get_space()); p_body_B = body_A->get_space()->get_static_global_body(); } Body3DSW *body_B = body_owner.getornull(p_body_B); - ERR_FAIL_COND_V(!body_B, RID()); + ERR_FAIL_COND(!body_B); - ERR_FAIL_COND_V(body_A == body_B, RID()); + ERR_FAIL_COND(body_A == body_B); + + Joint3DSW *prev_joint = joint_owner.getornull(p_joint); + ERR_FAIL_COND(prev_joint == nullptr); Joint3DSW *joint = memnew(HingeJoint3DSW(body_A, body_B, p_pivot_A, p_pivot_B, p_axis_A, p_axis_B)); - RID rid = joint_owner.make_rid(joint); - joint->set_self(rid); - return rid; + + joint->copy_settings_from(prev_joint); + joint_owner.replace(p_joint, joint); + memdelete(prev_joint); } void PhysicsServer3DSW::hinge_joint_set_param(RID p_joint, HingeJointParam p_param, real_t p_value) { Joint3DSW *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND(!joint); - ERR_FAIL_COND(joint->get_type() != JOINT_HINGE); + ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_HINGE); HingeJoint3DSW *hinge_joint = static_cast<HingeJoint3DSW *>(joint); hinge_joint->set_param(p_param, p_value); } @@ -1015,7 +1044,7 @@ void PhysicsServer3DSW::hinge_joint_set_param(RID p_joint, HingeJointParam p_par real_t PhysicsServer3DSW::hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const { Joint3DSW *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND_V(!joint, 0); - ERR_FAIL_COND_V(joint->get_type() != JOINT_HINGE, 0); + ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_HINGE, 0); HingeJoint3DSW *hinge_joint = static_cast<HingeJoint3DSW *>(joint); return hinge_joint->get_param(p_param); } @@ -1023,7 +1052,7 @@ real_t PhysicsServer3DSW::hinge_joint_get_param(RID p_joint, HingeJointParam p_p void PhysicsServer3DSW::hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag, bool p_value) { Joint3DSW *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND(!joint); - ERR_FAIL_COND(joint->get_type() != JOINT_HINGE); + ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_HINGE); HingeJoint3DSW *hinge_joint = static_cast<HingeJoint3DSW *>(joint); hinge_joint->set_flag(p_flag, p_value); } @@ -1031,7 +1060,7 @@ void PhysicsServer3DSW::hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag, bool PhysicsServer3DSW::hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const { Joint3DSW *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND_V(!joint, false); - ERR_FAIL_COND_V(joint->get_type() != JOINT_HINGE, false); + ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_HINGE, false); HingeJoint3DSW *hinge_joint = static_cast<HingeJoint3DSW *>(joint); return hinge_joint->get_flag(p_flag); } @@ -1077,34 +1106,38 @@ bool PhysicsServer3DSW::joint_is_disabled_collisions_between_bodies(RID p_joint) PhysicsServer3DSW::JointType PhysicsServer3DSW::joint_get_type(RID p_joint) const { Joint3DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND_V(!joint, JOINT_PIN); + ERR_FAIL_COND_V(!joint, JOINT_TYPE_PIN); return joint->get_type(); } -RID PhysicsServer3DSW::joint_create_slider(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) { +void PhysicsServer3DSW::joint_make_slider(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) { Body3DSW *body_A = body_owner.getornull(p_body_A); - ERR_FAIL_COND_V(!body_A, RID()); + ERR_FAIL_COND(!body_A); if (!p_body_B.is_valid()) { - ERR_FAIL_COND_V(!body_A->get_space(), RID()); + ERR_FAIL_COND(!body_A->get_space()); p_body_B = body_A->get_space()->get_static_global_body(); } Body3DSW *body_B = body_owner.getornull(p_body_B); - ERR_FAIL_COND_V(!body_B, RID()); + ERR_FAIL_COND(!body_B); - ERR_FAIL_COND_V(body_A == body_B, RID()); + ERR_FAIL_COND(body_A == body_B); + + Joint3DSW *prev_joint = joint_owner.getornull(p_joint); + ERR_FAIL_COND(prev_joint == nullptr); Joint3DSW *joint = memnew(SliderJoint3DSW(body_A, body_B, p_local_frame_A, p_local_frame_B)); - RID rid = joint_owner.make_rid(joint); - joint->set_self(rid); - return rid; + + joint->copy_settings_from(prev_joint); + joint_owner.replace(p_joint, joint); + memdelete(prev_joint); } void PhysicsServer3DSW::slider_joint_set_param(RID p_joint, SliderJointParam p_param, real_t p_value) { Joint3DSW *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND(!joint); - ERR_FAIL_COND(joint->get_type() != JOINT_SLIDER); + ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_SLIDER); SliderJoint3DSW *slider_joint = static_cast<SliderJoint3DSW *>(joint); slider_joint->set_param(p_param, p_value); } @@ -1112,35 +1145,39 @@ void PhysicsServer3DSW::slider_joint_set_param(RID p_joint, SliderJointParam p_p real_t PhysicsServer3DSW::slider_joint_get_param(RID p_joint, SliderJointParam p_param) const { Joint3DSW *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND_V(!joint, 0); - ERR_FAIL_COND_V(joint->get_type() != JOINT_CONE_TWIST, 0); + ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_CONE_TWIST, 0); SliderJoint3DSW *slider_joint = static_cast<SliderJoint3DSW *>(joint); return slider_joint->get_param(p_param); } -RID PhysicsServer3DSW::joint_create_cone_twist(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) { +void PhysicsServer3DSW::joint_make_cone_twist(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) { Body3DSW *body_A = body_owner.getornull(p_body_A); - ERR_FAIL_COND_V(!body_A, RID()); + ERR_FAIL_COND(!body_A); if (!p_body_B.is_valid()) { - ERR_FAIL_COND_V(!body_A->get_space(), RID()); + ERR_FAIL_COND(!body_A->get_space()); p_body_B = body_A->get_space()->get_static_global_body(); } Body3DSW *body_B = body_owner.getornull(p_body_B); - ERR_FAIL_COND_V(!body_B, RID()); + ERR_FAIL_COND(!body_B); + + ERR_FAIL_COND(body_A == body_B); - ERR_FAIL_COND_V(body_A == body_B, RID()); + Joint3DSW *prev_joint = joint_owner.getornull(p_joint); + ERR_FAIL_COND(prev_joint == nullptr); Joint3DSW *joint = memnew(ConeTwistJoint3DSW(body_A, body_B, p_local_frame_A, p_local_frame_B)); - RID rid = joint_owner.make_rid(joint); - joint->set_self(rid); - return rid; + + joint->copy_settings_from(prev_joint); + joint_owner.replace(p_joint, joint); + memdelete(prev_joint); } void PhysicsServer3DSW::cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, real_t p_value) { Joint3DSW *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND(!joint); - ERR_FAIL_COND(joint->get_type() != JOINT_CONE_TWIST); + ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_CONE_TWIST); ConeTwistJoint3DSW *cone_twist_joint = static_cast<ConeTwistJoint3DSW *>(joint); cone_twist_joint->set_param(p_param, p_value); } @@ -1148,43 +1185,47 @@ void PhysicsServer3DSW::cone_twist_joint_set_param(RID p_joint, ConeTwistJointPa real_t PhysicsServer3DSW::cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const { Joint3DSW *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND_V(!joint, 0); - ERR_FAIL_COND_V(joint->get_type() != JOINT_CONE_TWIST, 0); + ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_CONE_TWIST, 0); ConeTwistJoint3DSW *cone_twist_joint = static_cast<ConeTwistJoint3DSW *>(joint); return cone_twist_joint->get_param(p_param); } -RID PhysicsServer3DSW::joint_create_generic_6dof(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) { +void PhysicsServer3DSW::joint_make_generic_6dof(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) { Body3DSW *body_A = body_owner.getornull(p_body_A); - ERR_FAIL_COND_V(!body_A, RID()); + ERR_FAIL_COND(!body_A); if (!p_body_B.is_valid()) { - ERR_FAIL_COND_V(!body_A->get_space(), RID()); + ERR_FAIL_COND(!body_A->get_space()); p_body_B = body_A->get_space()->get_static_global_body(); } Body3DSW *body_B = body_owner.getornull(p_body_B); - ERR_FAIL_COND_V(!body_B, RID()); + ERR_FAIL_COND(!body_B); + + ERR_FAIL_COND(body_A == body_B); - ERR_FAIL_COND_V(body_A == body_B, RID()); + Joint3DSW *prev_joint = joint_owner.getornull(p_joint); + ERR_FAIL_COND(prev_joint == nullptr); Joint3DSW *joint = memnew(Generic6DOFJoint3DSW(body_A, body_B, p_local_frame_A, p_local_frame_B, true)); - RID rid = joint_owner.make_rid(joint); - joint->set_self(rid); - return rid; + + joint->copy_settings_from(prev_joint); + joint_owner.replace(p_joint, joint); + memdelete(prev_joint); } void PhysicsServer3DSW::generic_6dof_joint_set_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param, real_t p_value) { Joint3DSW *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND(!joint); - ERR_FAIL_COND(joint->get_type() != JOINT_6DOF); + ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_6DOF); Generic6DOFJoint3DSW *generic_6dof_joint = static_cast<Generic6DOFJoint3DSW *>(joint); generic_6dof_joint->set_param(p_axis, p_param, p_value); } -real_t PhysicsServer3DSW::generic_6dof_joint_get_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param) { +real_t PhysicsServer3DSW::generic_6dof_joint_get_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param) const { Joint3DSW *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND_V(!joint, 0); - ERR_FAIL_COND_V(joint->get_type() != JOINT_6DOF, 0); + ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_6DOF, 0); Generic6DOFJoint3DSW *generic_6dof_joint = static_cast<Generic6DOFJoint3DSW *>(joint); return generic_6dof_joint->get_param(p_axis, p_param); } @@ -1192,15 +1233,15 @@ real_t PhysicsServer3DSW::generic_6dof_joint_get_param(RID p_joint, Vector3::Axi void PhysicsServer3DSW::generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag, bool p_enable) { Joint3DSW *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND(!joint); - ERR_FAIL_COND(joint->get_type() != JOINT_6DOF); + ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_6DOF); Generic6DOFJoint3DSW *generic_6dof_joint = static_cast<Generic6DOFJoint3DSW *>(joint); generic_6dof_joint->set_flag(p_axis, p_flag, p_enable); } -bool PhysicsServer3DSW::generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag) { +bool PhysicsServer3DSW::generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag) const { Joint3DSW *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND_V(!joint, false); - ERR_FAIL_COND_V(joint->get_type() != JOINT_6DOF, false); + ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_6DOF, false); Generic6DOFJoint3DSW *generic_6dof_joint = static_cast<Generic6DOFJoint3DSW *>(joint); return generic_6dof_joint->get_flag(p_axis, p_flag); } @@ -1317,6 +1358,10 @@ void PhysicsServer3DSW::step(real_t p_step) { #endif } +void PhysicsServer3DSW::sync() { + doing_sync = true; +}; + void PhysicsServer3DSW::flush_queries() { #ifndef _3D_DISABLED @@ -1370,6 +1415,10 @@ void PhysicsServer3DSW::flush_queries() { #endif }; +void PhysicsServer3DSW::end_sync() { + doing_sync = false; +}; + void PhysicsServer3DSW::finish() { memdelete(stepper); memdelete(direct_state); @@ -1431,14 +1480,15 @@ void PhysicsServer3DSW::_shape_col_cbk(const Vector3 &p_point_A, const Vector3 & } } -PhysicsServer3DSW *PhysicsServer3DSW::singleton = nullptr; -PhysicsServer3DSW::PhysicsServer3DSW() { - singleton = this; +PhysicsServer3DSW *PhysicsServer3DSW::singletonsw = nullptr; +PhysicsServer3DSW::PhysicsServer3DSW(bool p_using_threads) { + singletonsw = this; BroadPhase3DSW::create_func = BroadPhaseOctree::_create; island_count = 0; active_objects = 0; collision_pairs = 0; - + using_threads = p_using_threads; active = true; flushing_queries = false; + doing_sync = false; }; diff --git a/servers/physics_3d/physics_server_3d_sw.h b/servers/physics_3d/physics_server_3d_sw.h index f96a8863c3..afda161fa8 100644 --- a/servers/physics_3d/physics_server_3d_sw.h +++ b/servers/physics_3d/physics_server_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -50,6 +50,8 @@ class PhysicsServer3DSW : public PhysicsServer3D { int active_objects; int collision_pairs; + bool using_threads; + bool doing_sync; bool flushing_queries; Step3DSW *stepper; @@ -57,20 +59,20 @@ class PhysicsServer3DSW : public PhysicsServer3D { PhysicsDirectBodyState3DSW *direct_state; - mutable RID_PtrOwner<Shape3DSW> shape_owner; - mutable RID_PtrOwner<Space3DSW> space_owner; - mutable RID_PtrOwner<Area3DSW> area_owner; - mutable RID_PtrOwner<Body3DSW> body_owner; - mutable RID_PtrOwner<Joint3DSW> joint_owner; + mutable RID_PtrOwner<Shape3DSW, true> shape_owner; + mutable RID_PtrOwner<Space3DSW, true> space_owner; + mutable RID_PtrOwner<Area3DSW, true> area_owner; + mutable RID_PtrOwner<Body3DSW, true> body_owner; + mutable RID_PtrOwner<Joint3DSW, true> joint_owner; //void _clear_query(QuerySW *p_query); friend class CollisionObject3DSW; SelfList<CollisionObject3DSW>::List pending_shape_update_list; void _update_shapes(); -public: - static PhysicsServer3DSW *singleton; + static PhysicsServer3DSW *singletonsw; +public: struct CollCbkData { int max; int amount; @@ -79,7 +81,17 @@ public: static void _shape_col_cbk(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata); - virtual RID shape_create(ShapeType p_shape) override; + virtual RID plane_shape_create() override; + virtual RID ray_shape_create() override; + virtual RID sphere_shape_create() override; + virtual RID box_shape_create() override; + virtual RID capsule_shape_create() override; + virtual RID cylinder_shape_create() override; + virtual RID convex_polygon_shape_create() override; + virtual RID concave_polygon_shape_create() override; + virtual RID heightmap_shape_create() override; + virtual RID custom_shape_create() override; + virtual void shape_set_data(RID p_shape, const Variant &p_data) override; virtual void shape_set_custom_solver_bias(RID p_shape, real_t p_bias) override; @@ -140,7 +152,6 @@ public: virtual Transform area_get_transform(RID p_area) const override; virtual void area_set_ray_pickable(RID p_area, bool p_enable) override; - virtual bool area_is_ray_pickable(RID p_area) const override; virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) override; virtual void area_set_collision_layer(RID p_area, uint32_t p_layer) override; @@ -153,7 +164,7 @@ public: /* BODY API */ // create a body of a given type - virtual RID body_create(BodyMode p_mode = BODY_MODE_RIGID, bool p_init_sleeping = false) override; + virtual RID body_create() override; virtual void body_set_space(RID p_body, RID p_space) override; virtual RID body_get_space(RID p_body) const override; @@ -232,17 +243,16 @@ public: virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant()) override; virtual void body_set_ray_pickable(RID p_body, bool p_enable) override; - virtual bool body_is_ray_pickable(RID p_body) const override; virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override; - virtual int body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, float p_margin = 0.001) override; + virtual int body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override; // this function only works on physics process, errors and returns null otherwise virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) override; /* SOFT BODY */ - virtual RID soft_body_create(bool p_init_sleeping = false) override { return RID(); } + virtual RID soft_body_create() override { return RID(); } virtual void soft_body_update_rendering_server(RID p_body, class SoftBodyRenderingServerHandler *p_rendering_server_handler) override {} @@ -266,49 +276,52 @@ public: virtual Vector3 soft_body_get_vertex_position(RID p_body, int vertex_index) const override { return Vector3(); } virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) override {} - virtual bool soft_body_is_ray_pickable(RID p_body) const override { return false; } virtual void soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) override {} - virtual int soft_body_get_simulation_precision(RID p_body) override { return 0; } + virtual int soft_body_get_simulation_precision(RID p_body) const override { return 0; } virtual void soft_body_set_total_mass(RID p_body, real_t p_total_mass) override {} - virtual real_t soft_body_get_total_mass(RID p_body) override { return 0.; } + virtual real_t soft_body_get_total_mass(RID p_body) const override { return 0.; } virtual void soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) override {} - virtual real_t soft_body_get_linear_stiffness(RID p_body) override { return 0.; } + virtual real_t soft_body_get_linear_stiffness(RID p_body) const override { return 0.; } - virtual void soft_body_set_areaAngular_stiffness(RID p_body, real_t p_stiffness) override {} - virtual real_t soft_body_get_areaAngular_stiffness(RID p_body) override { return 0.; } + virtual void soft_body_set_angular_stiffness(RID p_body, real_t p_stiffness) override {} + virtual real_t soft_body_get_angular_stiffness(RID p_body) const override { return 0.; } virtual void soft_body_set_volume_stiffness(RID p_body, real_t p_stiffness) override {} - virtual real_t soft_body_get_volume_stiffness(RID p_body) override { return 0.; } + virtual real_t soft_body_get_volume_stiffness(RID p_body) const override { return 0.; } virtual void soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) override {} - virtual real_t soft_body_get_pressure_coefficient(RID p_body) override { return 0.; } + virtual real_t soft_body_get_pressure_coefficient(RID p_body) const override { return 0.; } virtual void soft_body_set_pose_matching_coefficient(RID p_body, real_t p_pose_matching_coefficient) override {} - virtual real_t soft_body_get_pose_matching_coefficient(RID p_body) override { return 0.; } + virtual real_t soft_body_get_pose_matching_coefficient(RID p_body) const override { return 0.; } virtual void soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) override {} - virtual real_t soft_body_get_damping_coefficient(RID p_body) override { return 0.; } + virtual real_t soft_body_get_damping_coefficient(RID p_body) const override { return 0.; } virtual void soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) override {} - virtual real_t soft_body_get_drag_coefficient(RID p_body) override { return 0.; } + virtual real_t soft_body_get_drag_coefficient(RID p_body) const override { return 0.; } virtual void soft_body_set_mesh(RID p_body, const REF &p_mesh) override {} virtual void soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) override {} - virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index) override { return Vector3(); } + virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index) const override { return Vector3(); } virtual Vector3 soft_body_get_point_offset(RID p_body, int p_point_index) const override { return Vector3(); } virtual void soft_body_remove_all_pinned_points(RID p_body) override {} virtual void soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) override {} - virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) override { return false; } + virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) const override { return false; } /* JOINT API */ - virtual RID joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) override; + virtual RID joint_create() override; + + virtual void joint_clear(RID p_joint) override; //resets type + + virtual void joint_make_pin(RID p_joint, RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) override; virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) override; virtual real_t pin_joint_get_param(RID p_joint, PinJointParam p_param) const override; @@ -319,8 +332,8 @@ public: virtual void pin_joint_set_local_b(RID p_joint, const Vector3 &p_B) override; virtual Vector3 pin_joint_get_local_b(RID p_joint) const override; - virtual RID joint_create_hinge(RID p_body_A, const Transform &p_frame_A, RID p_body_B, const Transform &p_frame_B) override; - virtual RID joint_create_hinge_simple(RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B) override; + virtual void joint_make_hinge(RID p_joint, RID p_body_A, const Transform &p_frame_A, RID p_body_B, const Transform &p_frame_B) override; + virtual void joint_make_hinge_simple(RID p_joint, RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B) override; virtual void hinge_joint_set_param(RID p_joint, HingeJointParam p_param, real_t p_value) override; virtual real_t hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const override; @@ -328,26 +341,23 @@ public: virtual void hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag, bool p_value) override; virtual bool hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const override; - virtual RID joint_create_slider(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override; //reference frame is A + virtual void joint_make_slider(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override; //reference frame is A virtual void slider_joint_set_param(RID p_joint, SliderJointParam p_param, real_t p_value) override; virtual real_t slider_joint_get_param(RID p_joint, SliderJointParam p_param) const override; - virtual RID joint_create_cone_twist(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override; //reference frame is A + virtual void joint_make_cone_twist(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override; //reference frame is A virtual void cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, real_t p_value) override; virtual real_t cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const override; - virtual RID joint_create_generic_6dof(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override; //reference frame is A + virtual void joint_make_generic_6dof(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override; //reference frame is A virtual void generic_6dof_joint_set_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param, real_t p_value) override; - virtual real_t generic_6dof_joint_get_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param) override; + virtual real_t generic_6dof_joint_get_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param) const override; virtual void generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag, bool p_enable) override; - virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag) override; - - virtual void generic_6dof_joint_set_precision(RID p_joint, int precision) override {} - virtual int generic_6dof_joint_get_precision(RID p_joint) override { return 0; } + virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag) const override; virtual JointType joint_get_type(RID p_joint) const override; @@ -364,14 +374,16 @@ public: virtual void set_active(bool p_active) override; virtual void init() override; virtual void step(real_t p_step) override; + virtual void sync() override; virtual void flush_queries() override; + virtual void end_sync() override; virtual void finish() override; virtual bool is_flushing_queries() const override { return flushing_queries; } int get_process_info(ProcessInfo p_info) override; - PhysicsServer3DSW(); + PhysicsServer3DSW(bool p_using_threads = false); ~PhysicsServer3DSW() {} }; diff --git a/servers/physics_3d/physics_server_3d_wrap_mt.cpp b/servers/physics_3d/physics_server_3d_wrap_mt.cpp new file mode 100644 index 0000000000..f73f67a756 --- /dev/null +++ b/servers/physics_3d/physics_server_3d_wrap_mt.cpp @@ -0,0 +1,140 @@ +/*************************************************************************/ +/* physics_server_3d_wrap_mt.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "physics_server_3d_wrap_mt.h" + +#include "core/os/os.h" + +void PhysicsServer3DWrapMT::thread_exit() { + exit = true; +} + +void PhysicsServer3DWrapMT::thread_step(real_t p_delta) { + physics_3d_server->step(p_delta); + step_sem.post(); +} + +void PhysicsServer3DWrapMT::_thread_callback(void *_instance) { + PhysicsServer3DWrapMT *vsmt = reinterpret_cast<PhysicsServer3DWrapMT *>(_instance); + + vsmt->thread_loop(); +} + +void PhysicsServer3DWrapMT::thread_loop() { + server_thread = Thread::get_caller_id(); + + physics_3d_server->init(); + + exit = false; + step_thread_up = true; + while (!exit) { + // flush commands one by one, until exit is requested + command_queue.wait_and_flush_one(); + } + + command_queue.flush_all(); // flush all + + physics_3d_server->finish(); +} + +/* EVENT QUEUING */ + +void PhysicsServer3DWrapMT::step(real_t p_step) { + if (create_thread) { + command_queue.push(this, &PhysicsServer3DWrapMT::thread_step, p_step); + } else { + command_queue.flush_all(); //flush all pending from other threads + physics_3d_server->step(p_step); + } +} + +void PhysicsServer3DWrapMT::sync() { + if (create_thread) { + if (first_frame) { + first_frame = false; + } else { + step_sem.wait(); //must not wait if a step was not issued + } + } + physics_3d_server->sync(); +} + +void PhysicsServer3DWrapMT::flush_queries() { + physics_3d_server->flush_queries(); +} + +void PhysicsServer3DWrapMT::end_sync() { + physics_3d_server->end_sync(); +} + +void PhysicsServer3DWrapMT::init() { + if (create_thread) { + //OS::get_singleton()->release_rendering_thread(); + thread.start(_thread_callback, this); + while (!step_thread_up) { + OS::get_singleton()->delay_usec(1000); + } + } else { + physics_3d_server->init(); + } +} + +void PhysicsServer3DWrapMT::finish() { + if (thread.is_started()) { + command_queue.push(this, &PhysicsServer3DWrapMT::thread_exit); + thread.wait_to_finish(); + } else { + physics_3d_server->finish(); + } +} + +PhysicsServer3DWrapMT::PhysicsServer3DWrapMT(PhysicsServer3D *p_contained, bool p_create_thread) : + command_queue(p_create_thread) { + physics_3d_server = p_contained; + create_thread = p_create_thread; + step_pending = 0; + step_thread_up = false; + + pool_max_size = GLOBAL_GET("memory/limits/multithreaded_server/rid_pool_prealloc"); + + if (!p_create_thread) { + server_thread = Thread::get_caller_id(); + } else { + server_thread = 0; + } + + main_thread = Thread::get_caller_id(); + first_frame = true; +} + +PhysicsServer3DWrapMT::~PhysicsServer3DWrapMT() { + memdelete(physics_3d_server); + //finish(); +} diff --git a/servers/physics_3d/physics_server_3d_wrap_mt.h b/servers/physics_3d/physics_server_3d_wrap_mt.h new file mode 100644 index 0000000000..f60e1332d5 --- /dev/null +++ b/servers/physics_3d/physics_server_3d_wrap_mt.h @@ -0,0 +1,422 @@ +/*************************************************************************/ +/* physics_server_3d_wrap_mt.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef PHYSICS3DSERVERWRAPMT_H +#define PHYSICS3DSERVERWRAPMT_H + +#include "core/config/project_settings.h" +#include "core/os/thread.h" +#include "core/templates/command_queue_mt.h" +#include "servers/physics_server_3d.h" + +#ifdef DEBUG_SYNC +#define SYNC_DEBUG print_line("sync on: " + String(__FUNCTION__)); +#else +#define SYNC_DEBUG +#endif + +class PhysicsServer3DWrapMT : public PhysicsServer3D { + mutable PhysicsServer3D *physics_3d_server; + + mutable CommandQueueMT command_queue; + + static void _thread_callback(void *_instance); + void thread_loop(); + + Thread::ID server_thread; + Thread::ID main_thread; + volatile bool exit = false; + Thread thread; + volatile bool step_thread_up = false; + bool create_thread = false; + + Semaphore step_sem; + int step_pending; + void thread_step(real_t p_delta); + void thread_flush(); + + void thread_exit(); + + bool first_frame = true; + + Mutex alloc_mutex; + int pool_max_size = 0; + +public: +#define ServerName PhysicsServer3D +#define ServerNameWrapMT PhysicsServer3DWrapMT +#define server_name physics_3d_server +#define WRITE_ACTION + +#include "servers/server_wrap_mt_common.h" + + //FUNC1RID(shape,ShapeType); todo fix + FUNCRID(plane_shape) + FUNCRID(ray_shape) + FUNCRID(sphere_shape) + FUNCRID(box_shape) + FUNCRID(capsule_shape) + FUNCRID(cylinder_shape) + FUNCRID(convex_polygon_shape) + FUNCRID(concave_polygon_shape) + FUNCRID(heightmap_shape) + FUNCRID(custom_shape) + + FUNC2(shape_set_data, RID, const Variant &); + FUNC2(shape_set_custom_solver_bias, RID, real_t); + + FUNC2(shape_set_margin, RID, real_t) + FUNC1RC(real_t, shape_get_margin, RID) + + FUNC1RC(ShapeType, shape_get_type, RID); + FUNC1RC(Variant, shape_get_data, RID); + FUNC1RC(real_t, shape_get_custom_solver_bias, RID); +#if 0 + //these work well, but should be used from the main thread only + bool shape_collide(RID p_shape_A, const Transform &p_xform_A, const Vector3 &p_motion_A, RID p_shape_B, const Transform &p_xform_B, const Vector3 &p_motion_B, Vector3 *r_results, int p_result_max, int &r_result_count) { + ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false); + return physics_3d_server->shape_collide(p_shape_A, p_xform_A, p_motion_A, p_shape_B, p_xform_B, p_motion_B, r_results, p_result_max, r_result_count); + } +#endif + /* SPACE API */ + + FUNCRID(space); + FUNC2(space_set_active, RID, bool); + FUNC1RC(bool, space_is_active, RID); + + FUNC3(space_set_param, RID, SpaceParameter, real_t); + FUNC2RC(real_t, space_get_param, RID, SpaceParameter); + + // this function only works on physics process, errors and returns null otherwise + PhysicsDirectSpaceState3D *space_get_direct_state(RID p_space) override { + ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), nullptr); + return physics_3d_server->space_get_direct_state(p_space); + } + + FUNC2(space_set_debug_contacts, RID, int); + virtual Vector<Vector3> space_get_contacts(RID p_space) const override { + ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), Vector<Vector3>()); + return physics_3d_server->space_get_contacts(p_space); + } + + virtual int space_get_contact_count(RID p_space) const override { + ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), 0); + return physics_3d_server->space_get_contact_count(p_space); + } + + /* AREA API */ + + //FUNC0RID(area); + FUNCRID(area); + + FUNC2(area_set_space, RID, RID); + FUNC1RC(RID, area_get_space, RID); + + FUNC2(area_set_space_override_mode, RID, AreaSpaceOverrideMode); + FUNC1RC(AreaSpaceOverrideMode, area_get_space_override_mode, RID); + + FUNC4(area_add_shape, RID, RID, const Transform &, bool); + FUNC3(area_set_shape, RID, int, RID); + FUNC3(area_set_shape_transform, RID, int, const Transform &); + FUNC3(area_set_shape_disabled, RID, int, bool); + + FUNC1RC(int, area_get_shape_count, RID); + FUNC2RC(RID, area_get_shape, RID, int); + FUNC2RC(Transform, area_get_shape_transform, RID, int); + FUNC2(area_remove_shape, RID, int); + FUNC1(area_clear_shapes, RID); + + FUNC2(area_attach_object_instance_id, RID, ObjectID); + FUNC1RC(ObjectID, area_get_object_instance_id, RID); + + FUNC3(area_set_param, RID, AreaParameter, const Variant &); + FUNC2(area_set_transform, RID, const Transform &); + + FUNC2RC(Variant, area_get_param, RID, AreaParameter); + FUNC1RC(Transform, area_get_transform, RID); + + FUNC2(area_set_collision_mask, RID, uint32_t); + FUNC2(area_set_collision_layer, RID, uint32_t); + + FUNC2(area_set_monitorable, RID, bool); + FUNC2(area_set_ray_pickable, RID, bool); + + FUNC3(area_set_monitor_callback, RID, Object *, const StringName &); + FUNC3(area_set_area_monitor_callback, RID, Object *, const StringName &); + + /* BODY API */ + + //FUNC2RID(body,BodyMode,bool); + FUNCRID(body) + + FUNC2(body_set_space, RID, RID); + FUNC1RC(RID, body_get_space, RID); + + FUNC2(body_set_mode, RID, BodyMode); + FUNC1RC(BodyMode, body_get_mode, RID); + + FUNC4(body_add_shape, RID, RID, const Transform &, bool); + FUNC3(body_set_shape, RID, int, RID); + FUNC3(body_set_shape_transform, RID, int, const Transform &); + + FUNC1RC(int, body_get_shape_count, RID); + FUNC2RC(Transform, body_get_shape_transform, RID, int); + FUNC2RC(RID, body_get_shape, RID, int); + + FUNC3(body_set_shape_disabled, RID, int, bool); + + FUNC2(body_remove_shape, RID, int); + FUNC1(body_clear_shapes, RID); + + FUNC2(body_attach_object_instance_id, RID, ObjectID); + FUNC1RC(ObjectID, body_get_object_instance_id, RID); + + FUNC2(body_set_enable_continuous_collision_detection, RID, bool); + FUNC1RC(bool, body_is_continuous_collision_detection_enabled, RID); + + FUNC2(body_set_collision_layer, RID, uint32_t); + FUNC1RC(uint32_t, body_get_collision_layer, RID); + + FUNC2(body_set_collision_mask, RID, uint32_t); + FUNC1RC(uint32_t, body_get_collision_mask, RID); + + FUNC2(body_set_user_flags, RID, uint32_t); + FUNC1RC(uint32_t, body_get_user_flags, RID); + + FUNC3(body_set_param, RID, BodyParameter, real_t); + FUNC2RC(real_t, body_get_param, RID, BodyParameter); + + FUNC2(body_set_kinematic_safe_margin, RID, real_t); + FUNC1RC(real_t, body_get_kinematic_safe_margin, RID); + + FUNC3(body_set_state, RID, BodyState, const Variant &); + FUNC2RC(Variant, body_get_state, RID, BodyState); + + FUNC2(body_set_applied_force, RID, const Vector3 &); + FUNC1RC(Vector3, body_get_applied_force, RID); + + FUNC2(body_set_applied_torque, RID, const Vector3 &); + FUNC1RC(Vector3, body_get_applied_torque, RID); + + FUNC2(body_add_central_force, RID, const Vector3 &); + FUNC3(body_add_force, RID, const Vector3 &, const Vector3 &); + FUNC2(body_add_torque, RID, const Vector3 &); + FUNC2(body_apply_torque_impulse, RID, const Vector3 &); + FUNC2(body_apply_central_impulse, RID, const Vector3 &); + FUNC3(body_apply_impulse, RID, const Vector3 &, const Vector3 &); + FUNC2(body_set_axis_velocity, RID, const Vector3 &); + + FUNC3(body_set_axis_lock, RID, BodyAxis, bool); + FUNC2RC(bool, body_is_axis_locked, RID, BodyAxis); + + FUNC2(body_add_collision_exception, RID, RID); + FUNC2(body_remove_collision_exception, RID, RID); + FUNC2S(body_get_collision_exceptions, RID, List<RID> *); + + FUNC2(body_set_max_contacts_reported, RID, int); + FUNC1RC(int, body_get_max_contacts_reported, RID); + + FUNC2(body_set_contacts_reported_depth_threshold, RID, real_t); + FUNC1RC(real_t, body_get_contacts_reported_depth_threshold, RID); + + FUNC2(body_set_omit_force_integration, RID, bool); + FUNC1RC(bool, body_is_omitting_force_integration, RID); + + FUNC4(body_set_force_integration_callback, RID, Object *, const StringName &, const Variant &); + + FUNC2(body_set_ray_pickable, RID, bool); + + bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override { + ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false); + return physics_3d_server->body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, r_result, p_exclude_raycast_shapes); + } + + int body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override { + ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false); + return physics_3d_server->body_test_ray_separation(p_body, p_transform, p_infinite_inertia, r_recover_motion, r_results, p_result_max, p_margin); + } + + // this function only works on physics process, errors and returns null otherwise + PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) override { + ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), nullptr); + return physics_3d_server->body_get_direct_state(p_body); + } + + /* SOFT BODY API */ + + FUNCRID(soft_body) + + FUNC2(soft_body_update_rendering_server, RID, class SoftBodyRenderingServerHandler *) + + FUNC2(soft_body_set_space, RID, RID) + FUNC1RC(RID, soft_body_get_space, RID) + + FUNC2(soft_body_set_ray_pickable, RID, bool); + + FUNC2(soft_body_set_collision_layer, RID, uint32_t) + FUNC1RC(uint32_t, soft_body_get_collision_layer, RID) + + FUNC2(soft_body_set_collision_mask, RID, uint32_t) + FUNC1RC(uint32_t, soft_body_get_collision_mask, RID) + + FUNC2(soft_body_add_collision_exception, RID, RID) + FUNC2(soft_body_remove_collision_exception, RID, RID) + FUNC2S(soft_body_get_collision_exceptions, RID, List<RID> *) + + FUNC3(soft_body_set_state, RID, BodyState, const Variant &); + FUNC2RC(Variant, soft_body_get_state, RID, BodyState); + + FUNC2(soft_body_set_transform, RID, const Transform &); + FUNC2RC(Vector3, soft_body_get_vertex_position, RID, int); + + FUNC2(soft_body_set_simulation_precision, RID, int); + FUNC1RC(int, soft_body_get_simulation_precision, RID); + + FUNC2(soft_body_set_total_mass, RID, real_t); + FUNC1RC(real_t, soft_body_get_total_mass, RID); + + FUNC2(soft_body_set_linear_stiffness, RID, real_t); + FUNC1RC(real_t, soft_body_get_linear_stiffness, RID); + + FUNC2(soft_body_set_angular_stiffness, RID, real_t); + FUNC1RC(real_t, soft_body_get_angular_stiffness, RID); + + FUNC2(soft_body_set_volume_stiffness, RID, real_t); + FUNC1RC(real_t, soft_body_get_volume_stiffness, RID); + + FUNC2(soft_body_set_pressure_coefficient, RID, real_t); + FUNC1RC(real_t, soft_body_get_pressure_coefficient, RID); + + FUNC2(soft_body_set_pose_matching_coefficient, RID, real_t); + FUNC1RC(real_t, soft_body_get_pose_matching_coefficient, RID); + + FUNC2(soft_body_set_damping_coefficient, RID, real_t); + FUNC1RC(real_t, soft_body_get_damping_coefficient, RID); + + FUNC2(soft_body_set_drag_coefficient, RID, real_t); + FUNC1RC(real_t, soft_body_get_drag_coefficient, RID); + + FUNC2(soft_body_set_mesh, RID, const REF &); + + FUNC3(soft_body_move_point, RID, int, const Vector3 &); + FUNC2RC(Vector3, soft_body_get_point_global_position, RID, int); + FUNC2RC(Vector3, soft_body_get_point_offset, RID, int); + + FUNC1(soft_body_remove_all_pinned_points, RID); + FUNC3(soft_body_pin_point, RID, int, bool); + FUNC2RC(bool, soft_body_is_point_pinned, RID, int); + + /* JOINT API */ + + FUNCRID(joint) + + FUNC1(joint_clear, RID) + + FUNC5(joint_make_pin, RID, RID, const Vector3 &, RID, const Vector3 &) + + FUNC3(pin_joint_set_param, RID, PinJointParam, real_t) + FUNC2RC(real_t, pin_joint_get_param, RID, PinJointParam) + + FUNC2(pin_joint_set_local_a, RID, const Vector3 &) + FUNC1RC(Vector3, pin_joint_get_local_a, RID) + + FUNC2(pin_joint_set_local_b, RID, const Vector3 &) + FUNC1RC(Vector3, pin_joint_get_local_b, RID) + + FUNC5(joint_make_hinge, RID, RID, const Transform &, RID, const Transform &) + FUNC7(joint_make_hinge_simple, RID, RID, const Vector3 &, const Vector3 &, RID, const Vector3 &, const Vector3 &) + + FUNC3(hinge_joint_set_param, RID, HingeJointParam, real_t) + FUNC2RC(real_t, hinge_joint_get_param, RID, HingeJointParam) + + FUNC3(hinge_joint_set_flag, RID, HingeJointFlag, bool) + FUNC2RC(bool, hinge_joint_get_flag, RID, HingeJointFlag) + + FUNC5(joint_make_slider, RID, RID, const Transform &, RID, const Transform &) + + FUNC3(slider_joint_set_param, RID, SliderJointParam, real_t) + FUNC2RC(real_t, slider_joint_get_param, RID, SliderJointParam) + + FUNC5(joint_make_cone_twist, RID, RID, const Transform &, RID, const Transform &) + + FUNC3(cone_twist_joint_set_param, RID, ConeTwistJointParam, real_t) + FUNC2RC(real_t, cone_twist_joint_get_param, RID, ConeTwistJointParam) + + FUNC5(joint_make_generic_6dof, RID, RID, const Transform &, RID, const Transform &) + + FUNC4(generic_6dof_joint_set_param, RID, Vector3::Axis, G6DOFJointAxisParam, real_t) + FUNC3RC(real_t, generic_6dof_joint_get_param, RID, Vector3::Axis, G6DOFJointAxisParam) + + FUNC4(generic_6dof_joint_set_flag, RID, Vector3::Axis, G6DOFJointAxisFlag, bool) + FUNC3RC(bool, generic_6dof_joint_get_flag, RID, Vector3::Axis, G6DOFJointAxisFlag) + + FUNC1RC(JointType, joint_get_type, RID); + + FUNC2(joint_set_solver_priority, RID, int); + FUNC1RC(int, joint_get_solver_priority, RID); + + FUNC2(joint_disable_collisions_between_bodies, RID, const bool); + FUNC1RC(bool, joint_is_disabled_collisions_between_bodies, RID); + + /* MISC */ + + FUNC1(free, RID); + FUNC1(set_active, bool); + + virtual void init() override; + virtual void step(real_t p_step) override; + virtual void sync() override; + virtual void end_sync() override; + virtual void flush_queries() override; + virtual void finish() override; + + virtual bool is_flushing_queries() const override { + return physics_3d_server->is_flushing_queries(); + } + + int get_process_info(ProcessInfo p_info) override { + return physics_3d_server->get_process_info(p_info); + } + + PhysicsServer3DWrapMT(PhysicsServer3D *p_contained, bool p_create_thread); + ~PhysicsServer3DWrapMT(); + +#undef ServerNameWrapMT +#undef ServerName +#undef server_name +#undef WRITE_ACTION +}; + +#ifdef DEBUG_SYNC +#undef DEBUG_SYNC +#endif +#undef SYNC_DEBUG + +#endif // PHYSICS3DSERVERWRAPMT_H diff --git a/servers/physics_3d/shape_3d_sw.cpp b/servers/physics_3d/shape_3d_sw.cpp index 107f850ebd..5bac4f19b9 100644 --- a/servers/physics_3d/shape_3d_sw.cpp +++ b/servers/physics_3d/shape_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -34,10 +34,12 @@ #include "core/math/quick_hull.h" #include "core/templates/sort_array.h" -#define _POINT_SNAP 0.001953125 #define _EDGE_IS_VALID_SUPPORT_THRESHOLD 0.0002 #define _FACE_IS_VALID_SUPPORT_THRESHOLD 0.9998 +#define _CYLINDER_EDGE_IS_VALID_SUPPORT_THRESHOLD 0.002 +#define _CYLINDER_FACE_IS_VALID_SUPPORT_THRESHOLD 0.999 + void Shape3DSW::configure(const AABB &p_aabb) { aabb = p_aabb; configured = true; @@ -50,7 +52,8 @@ void Shape3DSW::configure(const AABB &p_aabb) { Vector3 Shape3DSW::get_support(const Vector3 &p_normal) const { Vector3 res; int amnt; - get_supports(p_normal, 1, &res, amnt); + FeatureType type; + get_supports(p_normal, 1, &res, amnt, type); return res; } @@ -167,16 +170,19 @@ Vector3 RayShape3DSW::get_support(const Vector3 &p_normal) const { } } -void RayShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const { +void RayShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { if (Math::abs(p_normal.z) < _EDGE_IS_VALID_SUPPORT_THRESHOLD) { r_amount = 2; + r_type = FEATURE_EDGE; r_supports[0] = Vector3(0, 0, 0); r_supports[1] = Vector3(0, 0, length); } else if (p_normal.z > 0) { r_amount = 1; + r_type = FEATURE_POINT; *r_supports = Vector3(0, 0, length); } else { r_amount = 1; + r_type = FEATURE_POINT; *r_supports = Vector3(0, 0, 0); } } @@ -246,9 +252,10 @@ Vector3 SphereShape3DSW::get_support(const Vector3 &p_normal) const { return p_normal * radius; } -void SphereShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const { +void SphereShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { *r_supports = p_normal * radius; r_amount = 1; + r_type = FEATURE_POINT; } bool SphereShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const { @@ -261,7 +268,7 @@ bool SphereShape3DSW::intersect_point(const Vector3 &p_point) const { Vector3 SphereShape3DSW::get_closest_point_to(const Vector3 &p_point) const { Vector3 p = p_point; - float l = p.length(); + real_t l = p.length(); if (l < radius) { return p_point; } @@ -312,7 +319,7 @@ Vector3 BoxShape3DSW::get_support(const Vector3 &p_normal) const { return point; } -void BoxShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const { +void BoxShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { static const int next[3] = { 1, 2, 0 }; static const int next2[3] = { 2, 0, 1 }; @@ -325,6 +332,7 @@ void BoxShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_s bool neg = dot < 0; r_amount = 4; + r_type = FEATURE_FACE; Vector3 point; point[i] = half_extents[i]; @@ -362,6 +370,7 @@ void BoxShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_s if (Math::abs(p_normal.dot(axis)) < _EDGE_IS_VALID_SUPPORT_THRESHOLD) { r_amount = 2; + r_type = FEATURE_EDGE; int i_n = next[i]; int i_n2 = next2[i]; @@ -389,6 +398,7 @@ void BoxShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_s (p_normal.z < 0) ? -half_extents.z : half_extents.z); r_amount = 1; + r_type = FEATURE_POINT; r_supports[0] = point; } @@ -429,7 +439,7 @@ Vector3 BoxShape3DSW::get_closest_point_to(const Vector3 &p_point) const { } //check segments - float min_distance = 1e20; + real_t min_distance = 1e20; Vector3 closest_vertex = half_extents * p_point.sign(); Vector3 s[2] = { closest_vertex, @@ -442,7 +452,7 @@ Vector3 BoxShape3DSW::get_closest_point_to(const Vector3 &p_point) const { Vector3 closest_edge = Geometry3D::get_closest_point_to_segment(p_point, s); - float d = p_point.distance_to(closest_edge); + real_t d = p_point.distance_to(closest_edge); if (d < min_distance) { min_point = closest_edge; min_distance = d; @@ -500,7 +510,7 @@ Vector3 CapsuleShape3DSW::get_support(const Vector3 &p_normal) const { return n; } -void CapsuleShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const { +void CapsuleShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { Vector3 n = p_normal; real_t d = n.z; @@ -512,6 +522,7 @@ void CapsuleShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 n *= radius; r_amount = 2; + r_type = FEATURE_EDGE; r_supports[0] = n; r_supports[0].z += height * 0.5; r_supports[1] = n; @@ -523,6 +534,7 @@ void CapsuleShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 n *= radius; n.z += h * 0.5; r_amount = 1; + r_type = FEATURE_POINT; *r_supports = n; } } @@ -642,6 +654,186 @@ CapsuleShape3DSW::CapsuleShape3DSW() { height = radius = 0; } +/********** CYLINDER *************/ + +void CylinderShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const { + Vector3 cylinder_axis = p_transform.basis.get_axis(1).normalized(); + real_t axis_dot = cylinder_axis.dot(p_normal); + + Vector3 local_normal = p_transform.basis.xform_inv(p_normal); + real_t scale = local_normal.length(); + real_t scaled_radius = radius * scale; + real_t scaled_height = height * scale; + + real_t length; + if (Math::abs(axis_dot) > 1.0) { + length = scaled_height * 0.5; + } else { + length = Math::abs(axis_dot * scaled_height * 0.5) + scaled_radius * Math::sqrt(1.0 - axis_dot * axis_dot); + } + + real_t distance = p_normal.dot(p_transform.origin); + + r_min = distance - length; + r_max = distance + length; +} + +Vector3 CylinderShape3DSW::get_support(const Vector3 &p_normal) const { + Vector3 n = p_normal; + real_t h = (n.y > 0) ? height : -height; + real_t s = Math::sqrt(n.x * n.x + n.z * n.z); + if (Math::is_zero_approx(s)) { + n.x = radius; + n.y = h * 0.5; + n.z = 0.0; + } else { + real_t d = radius / s; + n.x = n.x * d; + n.y = h * 0.5; + n.z = n.z * d; + } + + return n; +} + +void CylinderShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { + real_t d = p_normal.y; + if (Math::abs(d) > _CYLINDER_FACE_IS_VALID_SUPPORT_THRESHOLD) { + real_t h = (d > 0) ? height : -height; + + Vector3 n = p_normal; + n.x = 0.0; + n.z = 0.0; + n.y = h * 0.5; + + r_amount = 3; + r_type = FEATURE_CIRCLE; + r_supports[0] = n; + r_supports[1] = n; + r_supports[1].x += radius; + r_supports[2] = n; + r_supports[2].z += radius; + } else if (Math::abs(d) < _CYLINDER_EDGE_IS_VALID_SUPPORT_THRESHOLD) { + // make it flat + Vector3 n = p_normal; + n.y = 0.0; + n.normalize(); + n *= radius; + + r_amount = 2; + r_type = FEATURE_EDGE; + r_supports[0] = n; + r_supports[0].y += height * 0.5; + r_supports[1] = n; + r_supports[1].y -= height * 0.5; + } else { + r_amount = 1; + r_type = FEATURE_POINT; + r_supports[0] = get_support(p_normal); + return; + + Vector3 n = p_normal; + real_t h = n.y * Math::sqrt(0.25 * height * height + radius * radius); + if (Math::abs(h) > 1.0) { + // Top or bottom surface. + n.y = (n.y > 0.0) ? height * 0.5 : -height * 0.5; + } else { + // Lateral surface. + n.y = height * 0.5 * h; + } + + real_t s = Math::sqrt(n.x * n.x + n.z * n.z); + if (Math::is_zero_approx(s)) { + n.x = 0.0; + n.z = 0.0; + } else { + real_t scaled_radius = radius / s; + n.x = n.x * scaled_radius; + n.z = n.z * scaled_radius; + } + + r_supports[0] = n; + } +} + +bool CylinderShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const { + return Geometry3D::segment_intersects_cylinder(p_begin, p_end, height, radius, &r_result, &r_normal, 1); +} + +bool CylinderShape3DSW::intersect_point(const Vector3 &p_point) const { + if (Math::abs(p_point.y) < height * 0.5) { + return Vector3(p_point.x, 0, p_point.z).length() < radius; + } + return false; +} + +Vector3 CylinderShape3DSW::get_closest_point_to(const Vector3 &p_point) const { + if (Math::absf(p_point.y) > height * 0.5) { + // Project point to top disk. + real_t dir = p_point.y > 0.0 ? 1.0 : -1.0; + Vector3 circle_pos(0.0, dir * height * 0.5, 0.0); + Plane circle_plane(circle_pos, Vector3(0.0, dir, 0.0)); + Vector3 proj_point = circle_plane.project(p_point); + + // Clip position. + Vector3 delta_point_1 = proj_point - circle_pos; + real_t dist_point_1 = delta_point_1.length_squared(); + if (!Math::is_zero_approx(dist_point_1)) { + dist_point_1 = Math::sqrt(dist_point_1); + proj_point = circle_pos + delta_point_1 * MIN(dist_point_1, radius) / dist_point_1; + } + + return proj_point; + } else { + Vector3 s[2] = { + Vector3(0, -height * 0.5, 0), + Vector3(0, height * 0.5, 0), + }; + + Vector3 p = Geometry3D::get_closest_point_to_segment(p_point, s); + + if (p.distance_to(p_point) < radius) { + return p_point; + } + + return p + (p_point - p).normalized() * radius; + } +} + +Vector3 CylinderShape3DSW::get_moment_of_inertia(real_t p_mass) const { + // use bad AABB approximation + Vector3 extents = get_aabb().size * 0.5; + + return Vector3( + (p_mass / 3.0) * (extents.y * extents.y + extents.z * extents.z), + (p_mass / 3.0) * (extents.x * extents.x + extents.z * extents.z), + (p_mass / 3.0) * (extents.y * extents.y + extents.y * extents.y)); +} + +void CylinderShape3DSW::_setup(real_t p_height, real_t p_radius) { + height = p_height; + radius = p_radius; + configure(AABB(Vector3(-radius, -height * 0.5, -radius), Vector3(radius * 2.0, height, radius * 2.0))); +} + +void CylinderShape3DSW::set_data(const Variant &p_data) { + Dictionary d = p_data; + ERR_FAIL_COND(!d.has("radius")); + ERR_FAIL_COND(!d.has("height")); + _setup(d["height"], d["radius"]); +} + +Variant CylinderShape3DSW::get_data() const { + Dictionary d; + d["radius"] = radius; + d["height"] = height; + return d; +} + +CylinderShape3DSW::CylinderShape3DSW() { + height = radius = 0; +} + /********** CONVEX POLYGON *************/ void ConvexPolygonShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const { @@ -689,7 +881,7 @@ Vector3 ConvexPolygonShape3DSW::get_support(const Vector3 &p_normal) const { return vrts[vert_support_idx]; } -void ConvexPolygonShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const { +void ConvexPolygonShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { const Geometry3D::MeshData::Face *faces = mesh.faces.ptr(); int fc = mesh.faces.size(); @@ -734,6 +926,7 @@ void ConvexPolygonShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Ve r_supports[j] = vertices[ind[j]]; } r_amount = m; + r_type = FEATURE_FACE; return; } } @@ -743,6 +936,7 @@ void ConvexPolygonShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Ve dot = ABS(dot); if (dot < _EDGE_IS_VALID_SUPPORT_THRESHOLD && (edges[i].a == vtx || edges[i].b == vtx)) { r_amount = 2; + r_type = FEATURE_EDGE; r_supports[0] = vertices[edges[i].a]; r_supports[1] = vertices[edges[i].b]; return; @@ -751,6 +945,7 @@ void ConvexPolygonShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Ve r_supports[0] = vertices[vtx]; r_amount = 1; + r_type = FEATURE_POINT; } bool ConvexPolygonShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const { @@ -839,7 +1034,7 @@ Vector3 ConvexPolygonShape3DSW::get_closest_point_to(const Vector3 &p_point) con return p_point; } - float min_distance = 1e20; + real_t min_distance = 1e20; Vector3 min_point; //check edges @@ -852,7 +1047,7 @@ Vector3 ConvexPolygonShape3DSW::get_closest_point_to(const Vector3 &p_point) con }; Vector3 closest = Geometry3D::get_closest_point_to_segment(p_point, s); - float d = closest.distance_to(p_point); + real_t d = closest.distance_to(p_point); if (d < min_distance) { min_distance = d; min_point = closest; @@ -935,12 +1130,13 @@ Vector3 FaceShape3DSW::get_support(const Vector3 &p_normal) const { return vertex[vert_support_idx]; } -void FaceShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const { +void FaceShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { Vector3 n = p_normal; /** TEST FACE AS SUPPORT **/ if (normal.dot(n) > _FACE_IS_VALID_SUPPORT_THRESHOLD) { r_amount = 3; + r_type = FEATURE_FACE; for (int i = 0; i < 3; i++) { r_supports[i] = vertex[i]; } @@ -974,6 +1170,7 @@ void FaceShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_ dot = ABS(dot); if (dot < _EDGE_IS_VALID_SUPPORT_THRESHOLD) { r_amount = 2; + r_type = FEATURE_EDGE; r_supports[0] = vertex[i]; r_supports[1] = vertex[nx]; return; @@ -981,6 +1178,7 @@ void FaceShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_ } r_amount = 1; + r_type = FEATURE_POINT; r_supports[0] = vertex[vert_support_idx]; } diff --git a/servers/physics_3d/shape_3d_sw.h b/servers/physics_3d/shape_3d_sw.h index 2a2cd42255..cafe978abb 100644 --- a/servers/physics_3d/shape_3d_sw.h +++ b/servers/physics_3d/shape_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -67,8 +67,11 @@ protected: void configure(const AABB &p_aabb); public: - enum { - MAX_SUPPORTS = 8 + enum FeatureType { + FEATURE_POINT, + FEATURE_EDGE, + FEATURE_FACE, + FEATURE_CIRCLE, }; virtual real_t get_area() const { return aabb.get_area(); } @@ -85,7 +88,7 @@ public: virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const = 0; virtual Vector3 get_support(const Vector3 &p_normal) const; - virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const = 0; + virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const = 0; virtual Vector3 get_closest_point_to(const Vector3 &p_point) const = 0; virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const = 0; virtual bool intersect_point(const Vector3 &p_point) const = 0; @@ -110,7 +113,7 @@ class ConcaveShape3DSW : public Shape3DSW { public: virtual bool is_concave() const { return true; } typedef void (*Callback)(void *p_userdata, Shape3DSW *p_convex); - virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const { r_amount = 0; } + virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { r_amount = 0; } virtual void cull(const AABB &p_local_aabb, Callback p_callback, void *p_userdata) const = 0; @@ -129,7 +132,7 @@ public: virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_PLANE; } virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const; virtual Vector3 get_support(const Vector3 &p_normal) const; - virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const { r_amount = 0; } + virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { r_amount = 0; } virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const; virtual bool intersect_point(const Vector3 &p_point) const; @@ -156,7 +159,7 @@ public: virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_RAY; } virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const; virtual Vector3 get_support(const Vector3 &p_normal) const; - virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const; + virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const; virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const; virtual bool intersect_point(const Vector3 &p_point) const; @@ -184,7 +187,7 @@ public: virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const; virtual Vector3 get_support(const Vector3 &p_normal) const; - virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const; + virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const; virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const; virtual bool intersect_point(const Vector3 &p_point) const; virtual Vector3 get_closest_point_to(const Vector3 &p_point) const; @@ -209,7 +212,7 @@ public: virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const; virtual Vector3 get_support(const Vector3 &p_normal) const; - virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const; + virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const; virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const; virtual bool intersect_point(const Vector3 &p_point) const; virtual Vector3 get_closest_point_to(const Vector3 &p_point) const; @@ -238,7 +241,7 @@ public: virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const; virtual Vector3 get_support(const Vector3 &p_normal) const; - virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const; + virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const; virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const; virtual bool intersect_point(const Vector3 &p_point) const; virtual Vector3 get_closest_point_to(const Vector3 &p_point) const; @@ -251,6 +254,35 @@ public: CapsuleShape3DSW(); }; +class CylinderShape3DSW : public Shape3DSW { + real_t height; + real_t radius; + + void _setup(real_t p_height, real_t p_radius); + +public: + _FORCE_INLINE_ real_t get_height() const { return height; } + _FORCE_INLINE_ real_t get_radius() const { return radius; } + + virtual real_t get_area() const { return 4.0 / 3.0 * Math_PI * radius * radius * radius + height * Math_PI * radius * radius; } + + virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_CYLINDER; } + + virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const; + virtual Vector3 get_support(const Vector3 &p_normal) const; + virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const; + virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const; + virtual bool intersect_point(const Vector3 &p_point) const; + virtual Vector3 get_closest_point_to(const Vector3 &p_point) const; + + virtual Vector3 get_moment_of_inertia(real_t p_mass) const; + + virtual void set_data(const Variant &p_data); + virtual Variant get_data() const; + + CylinderShape3DSW(); +}; + struct ConvexPolygonShape3DSW : public Shape3DSW { Geometry3D::MeshData mesh; @@ -263,7 +295,7 @@ public: virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const; virtual Vector3 get_support(const Vector3 &p_normal) const; - virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const; + virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const; virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const; virtual bool intersect_point(const Vector3 &p_point) const; virtual Vector3 get_closest_point_to(const Vector3 &p_point) const; @@ -399,7 +431,7 @@ struct FaceShape3DSW : public Shape3DSW { void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const; Vector3 get_support(const Vector3 &p_normal) const; - virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const; + virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const; bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const; virtual bool intersect_point(const Vector3 &p_point) const; virtual Vector3 get_closest_point_to(const Vector3 &p_point) const; @@ -437,7 +469,7 @@ struct MotionShape3DSW : public Shape3DSW { } return support; } - virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const { r_amount = 0; } + virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { r_amount = 0; } bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const { return false; } virtual bool intersect_point(const Vector3 &p_point) const { return false; } virtual Vector3 get_closest_point_to(const Vector3 &p_point) const { return p_point; } diff --git a/servers/physics_3d/space_3d_sw.cpp b/servers/physics_3d/space_3d_sw.cpp index d9170cd986..dd5754b9ac 100644 --- a/servers/physics_3d/space_3d_sw.cpp +++ b/servers/physics_3d/space_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -181,7 +181,7 @@ int PhysicsDirectSpaceState3DSW::intersect_shape(const RID &p_shape, const Trans return 0; } - Shape3DSW *shape = static_cast<PhysicsServer3DSW *>(PhysicsServer3D::get_singleton())->shape_owner.getornull(p_shape); + Shape3DSW *shape = PhysicsServer3DSW::singletonsw->shape_owner.getornull(p_shape); ERR_FAIL_COND_V(!shape, 0); AABB aabb = p_xform.xform(shape->get_aabb()); @@ -232,7 +232,7 @@ int PhysicsDirectSpaceState3DSW::intersect_shape(const RID &p_shape, const Trans } bool PhysicsDirectSpaceState3DSW::cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, ShapeRestInfo *r_info) { - Shape3DSW *shape = static_cast<PhysicsServer3DSW *>(PhysicsServer3D::get_singleton())->shape_owner.getornull(p_shape); + Shape3DSW *shape = PhysicsServer3DSW::singletonsw->shape_owner.getornull(p_shape); ERR_FAIL_COND_V(!shape, false); AABB aabb = p_xform.xform(shape->get_aabb()); @@ -274,11 +274,11 @@ bool PhysicsDirectSpaceState3DSW::cast_motion(const RID &p_shape, const Transfor continue; } - //test initial overlap + //test initial overlap, ignore objects it's inside of. sep_axis = p_motion.normalized(); if (!CollisionSolver3DSW::solve_distance(shape, p_xform, col_obj->get_shape(shape_idx), col_obj_xform, point_A, point_B, aabb, &sep_axis)) { - return false; + continue; } //just do kinematic solving @@ -340,7 +340,7 @@ bool PhysicsDirectSpaceState3DSW::collide_shape(RID p_shape, const Transform &p_ return false; } - Shape3DSW *shape = static_cast<PhysicsServer3DSW *>(PhysicsServer3D::get_singleton())->shape_owner.getornull(p_shape); + Shape3DSW *shape = PhysicsServer3DSW::singletonsw->shape_owner.getornull(p_shape); ERR_FAIL_COND_V(!shape, 0); AABB aabb = p_shape_xform.xform(shape->get_aabb()); @@ -384,6 +384,8 @@ bool PhysicsDirectSpaceState3DSW::collide_shape(RID p_shape, const Transform &p_ struct _RestCallbackData { const CollisionObject3DSW *object; const CollisionObject3DSW *best_object; + int local_shape; + int best_local_shape; int shape; int best_shape; Vector3 best_contact; @@ -409,10 +411,11 @@ static void _rest_cbk_result(const Vector3 &p_point_A, const Vector3 &p_point_B, rd->best_normal = contact_rel / len; rd->best_object = rd->object; rd->best_shape = rd->shape; + rd->best_local_shape = rd->local_shape; } bool PhysicsDirectSpaceState3DSW::rest_info(RID p_shape, const Transform &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { - Shape3DSW *shape = static_cast<PhysicsServer3DSW *>(PhysicsServer3D::get_singleton())->shape_owner.getornull(p_shape); + Shape3DSW *shape = PhysicsServer3DSW::singletonsw->shape_owner.getornull(p_shape); ERR_FAIL_COND_V(!shape, 0); AABB aabb = p_shape_xform.xform(shape->get_aabb()); @@ -468,15 +471,15 @@ bool PhysicsDirectSpaceState3DSW::rest_info(RID p_shape, const Transform &p_shap } Vector3 PhysicsDirectSpaceState3DSW::get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const { - CollisionObject3DSW *obj = PhysicsServer3DSW::singleton->area_owner.getornull(p_object); + CollisionObject3DSW *obj = PhysicsServer3DSW::singletonsw->area_owner.getornull(p_object); if (!obj) { - obj = PhysicsServer3DSW::singleton->body_owner.getornull(p_object); + obj = PhysicsServer3DSW::singletonsw->body_owner.getornull(p_object); } ERR_FAIL_COND_V(!obj, Vector3()); ERR_FAIL_COND_V(obj->get_space() != space, Vector3()); - float min_distance = 1e20; + real_t min_distance = 1e20; Vector3 min_point; bool shapes_found = false; @@ -492,7 +495,7 @@ Vector3 PhysicsDirectSpaceState3DSW::get_closest_point_to_object_volume(RID p_ob Vector3 point = shape->get_closest_point_to(shape_xform.affine_inverse().xform(p_point)); point = shape_xform.xform(point); - float dist = point.distance_to(p_point); + real_t dist = point.distance_to(p_point); if (dist < min_distance) { min_distance = dist; min_point = point; @@ -649,9 +652,9 @@ int Space3DSW::test_body_ray_separation(Body3DSW *p_body, const Transform &p_tra Vector3 a = sr[k * 2 + 0]; Vector3 b = sr[k * 2 + 1]; - recover_motion += (b - a) * 0.4; + recover_motion += (b - a) / cbk.amount; - float depth = a.distance_to(b); + real_t depth = a.distance_to(b); if (depth > result.collision_depth) { result.collision_depth = depth; result.collision_point = b; @@ -739,8 +742,13 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons body_aabb = p_from.xform(p_body->get_inv_transform().xform(body_aabb)); body_aabb = body_aabb.grow(p_margin); + real_t motion_length = p_motion.length(); + Vector3 motion_normal = p_motion / motion_length; + Transform body_transform = p_from; + bool recovered = false; + { //STEP 1, FREE BODY IF STUCK @@ -791,7 +799,17 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons for (int i = 0; i < cbk.amount; i++) { Vector3 a = sr[i * 2 + 0]; Vector3 b = sr[i * 2 + 1]; - recover_motion += (b - a) * 0.4; + + // Compute plane on b towards a. + Vector3 n = (a - b).normalized(); + real_t d = n.dot(b); + + // Compute depth on recovered motion. + real_t depth = n.dot(a + recover_motion) - d; + if (depth > 0.0) { + // Only recover if there is penetration. + recover_motion -= n * depth * 0.4; + } } if (recover_motion == Vector3()) { @@ -799,6 +817,8 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons break; } + recovered = true; + body_transform.origin += recover_motion; body_aabb.position += recover_motion; @@ -848,14 +868,14 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons //test initial overlap, does it collide if going all the way? Vector3 point_A, point_B; - Vector3 sep_axis = p_motion.normalized(); + Vector3 sep_axis = motion_normal; Transform col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); //test initial overlap, does it collide if going all the way? if (CollisionSolver3DSW::solve_distance(&mshape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj_xform, point_A, point_B, motion_aabb, &sep_axis)) { continue; } - sep_axis = p_motion.normalized(); + sep_axis = motion_normal; if (!CollisionSolver3DSW::solve_distance(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj_xform, point_A, point_B, motion_aabb, &sep_axis)) { stuck = true; @@ -865,13 +885,12 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons //just do kinematic solving real_t low = 0; real_t hi = 1; - Vector3 mnormal = p_motion.normalized(); for (int k = 0; k < 8; k++) { //steps should be customizable.. real_t ofs = (low + hi) * 0.5; - Vector3 sep = mnormal; //important optimization for this to work fast enough + Vector3 sep = motion_normal; //important optimization for this to work fast enough mshape.motion = body_shape_xform_inv.basis.xform(p_motion * ofs); @@ -912,16 +931,11 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons } bool collided = false; - if (safe >= 1) { - //not collided - collided = false; - if (r_result) { - r_result->motion = p_motion; - r_result->remainder = Vector3(); - r_result->motion += (body_transform.get_origin() - p_from.get_origin()); + if (recovered || (safe < 1)) { + if (safe >= 1) { + best_shape = -1; //no best shape with cast, reset to -1 } - } else { //it collided, let's get the rest info in unsafe advance Transform ugt = body_transform; ugt.origin += p_motion * unsafe; @@ -930,25 +944,40 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons rcd.best_len = 0; rcd.best_object = nullptr; rcd.best_shape = 0; - rcd.min_allowed_depth = test_motion_min_contact_depth; - Transform body_shape_xform = ugt * p_body->get_shape_transform(best_shape); - Shape3DSW *body_shape = p_body->get_shape(best_shape); + // Allowed depth can't be lower than motion length, in order to handle contacts at low speed. + rcd.min_allowed_depth = MIN(motion_length, test_motion_min_contact_depth); - body_aabb.position += p_motion * unsafe; + int from_shape = best_shape != -1 ? best_shape : 0; + int to_shape = best_shape != -1 ? best_shape + 1 : p_body->get_shape_count(); - int amount = _cull_aabb_for_body(p_body, body_aabb); + for (int j = from_shape; j < to_shape; j++) { + if (p_body->is_shape_set_as_disabled(j)) { + continue; + } - for (int i = 0; i < amount; i++) { - const CollisionObject3DSW *col_obj = intersection_query_results[i]; - int shape_idx = intersection_query_subindex_results[i]; + Transform body_shape_xform = ugt * p_body->get_shape_transform(j); + Shape3DSW *body_shape = p_body->get_shape(j); - rcd.object = col_obj; - rcd.shape = shape_idx; - bool sc = CollisionSolver3DSW::solve_static(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), _rest_cbk_result, &rcd, nullptr, p_margin); - if (!sc) { + if (p_exclude_raycast_shapes && body_shape->get_type() == PhysicsServer3D::SHAPE_RAY) { continue; } + + body_aabb.position += p_motion * unsafe; + + int amount = _cull_aabb_for_body(p_body, body_aabb); + + for (int i = 0; i < amount; i++) { + const CollisionObject3DSW *col_obj = intersection_query_results[i]; + int shape_idx = intersection_query_subindex_results[i]; + + rcd.object = col_obj; + rcd.shape = shape_idx; + bool sc = CollisionSolver3DSW::solve_static(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), _rest_cbk_result, &rcd, nullptr, p_margin); + if (!sc) { + continue; + } + } } if (rcd.best_len != 0) { @@ -956,7 +985,7 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons r_result->collider = rcd.best_object->get_self(); r_result->collider_id = rcd.best_object->get_instance_id(); r_result->collider_shape = rcd.best_shape; - r_result->collision_local_shape = best_shape; + r_result->collision_local_shape = rcd.best_local_shape; r_result->collision_normal = rcd.best_normal; r_result->collision_point = rcd.best_contact; //r_result->collider_metadata = rcd.best_object->get_shape_metadata(rcd.best_shape); @@ -972,17 +1001,15 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons } collided = true; - } else { - if (r_result) { - r_result->motion = p_motion; - r_result->remainder = Vector3(); - r_result->motion += (body_transform.get_origin() - p_from.get_origin()); - } - - collided = false; } } + if (!collided && r_result) { + r_result->motion = p_motion; + r_result->remainder = Vector3(); + r_result->motion += (body_transform.get_origin() - p_from.get_origin()); + } + return collided; } @@ -1211,7 +1238,7 @@ Space3DSW::Space3DSW() { constraint_bias = 0.01; body_linear_velocity_sleep_threshold = GLOBAL_DEF("physics/3d/sleep_threshold_linear", 0.1); - body_angular_velocity_sleep_threshold = GLOBAL_DEF("physics/3d/sleep_threshold_angular", (8.0 / 180.0 * Math_PI)); + body_angular_velocity_sleep_threshold = GLOBAL_DEF("physics/3d/sleep_threshold_angular", Math::deg2rad(8.0)); body_time_to_sleep = GLOBAL_DEF("physics/3d/time_before_sleep", 0.5); ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/time_before_sleep", PropertyInfo(Variant::FLOAT, "physics/3d/time_before_sleep", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater")); body_angular_velocity_damp_ratio = 10; diff --git a/servers/physics_3d/space_3d_sw.h b/servers/physics_3d/space_3d_sw.h index 22535a6adb..eed3d86a72 100644 --- a/servers/physics_3d/space_3d_sw.h +++ b/servers/physics_3d/space_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -182,7 +182,7 @@ public: PhysicsDirectSpaceState3DSW *get_direct_state(); void set_debug_contacts(int p_amount) { contact_debug.resize(p_amount); } - _FORCE_INLINE_ bool is_debugging_contacts() const { return !contact_debug.empty(); } + _FORCE_INLINE_ bool is_debugging_contacts() const { return !contact_debug.is_empty(); } _FORCE_INLINE_ void add_debug_contact(const Vector3 &p_contact) { if (contact_debug_count < contact_debug.size()) { contact_debug.write[contact_debug_count++] = p_contact; diff --git a/servers/physics_3d/step_3d_sw.cpp b/servers/physics_3d/step_3d_sw.cpp index 9a2a0073a1..d9370de6a3 100644 --- a/servers/physics_3d/step_3d_sw.cpp +++ b/servers/physics_3d/step_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/step_3d_sw.h b/servers/physics_3d/step_3d_sw.h index 9dbb61308f..55c48ec0eb 100644 --- a/servers/physics_3d/step_3d_sw.h +++ b/servers/physics_3d/step_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp index 1ea8985543..83ebc0c55b 100644 --- a/servers/physics_server_2d.cpp +++ b/servers/physics_server_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -42,7 +42,7 @@ void PhysicsDirectBodyState2D::integrate_forces() { real_t av = get_angular_velocity(); - float damp = 1.0 - step * get_total_linear_damp(); + real_t damp = 1.0 - step * get_total_linear_damp(); if (damp < 0) { // reached zero in the given time damp = 0; @@ -168,11 +168,11 @@ Vector2 PhysicsShapeQueryParameters2D::get_motion() const { return motion; } -void PhysicsShapeQueryParameters2D::set_margin(float p_margin) { +void PhysicsShapeQueryParameters2D::set_margin(real_t p_margin) { margin = p_margin; } -float PhysicsShapeQueryParameters2D::get_margin() const { +real_t PhysicsShapeQueryParameters2D::get_margin() const { return margin; } @@ -311,7 +311,7 @@ Array PhysicsDirectSpaceState2D::_intersect_shape(const Ref<PhysicsShapeQueryPar Array PhysicsDirectSpaceState2D::_cast_motion(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query) { ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array()); - float closest_safe, closest_unsafe; + real_t closest_safe, closest_unsafe; bool res = cast_motion(p_shape_query->shape, p_shape_query->transform, p_shape_query->motion, p_shape_query->margin, closest_safe, closest_unsafe, p_shape_query->exclude, p_shape_query->collision_mask, p_shape_query->collide_with_bodies, p_shape_query->collide_with_areas); if (!res) { return Array(); @@ -517,7 +517,7 @@ PhysicsTestMotionResult2D::PhysicsTestMotionResult2D() { /////////////////////////////////////// -bool PhysicsServer2D::_body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, float p_margin, const Ref<PhysicsTestMotionResult2D> &p_result) { +bool PhysicsServer2D::_body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin, const Ref<PhysicsTestMotionResult2D> &p_result) { MotionResult *r = nullptr; if (p_result.is_valid()) { r = p_result->get_result_ptr(); @@ -655,12 +655,16 @@ void PhysicsServer2D::_bind_methods() { /* JOINT API */ + ClassDB::bind_method(D_METHOD("joint_create"), &PhysicsServer2D::joint_create); + + ClassDB::bind_method(D_METHOD("joint_clear", "joint"), &PhysicsServer2D::joint_clear); + ClassDB::bind_method(D_METHOD("joint_set_param", "joint", "param", "value"), &PhysicsServer2D::joint_set_param); ClassDB::bind_method(D_METHOD("joint_get_param", "joint", "param"), &PhysicsServer2D::joint_get_param); - ClassDB::bind_method(D_METHOD("pin_joint_create", "anchor", "body_a", "body_b"), &PhysicsServer2D::pin_joint_create, DEFVAL(RID())); - ClassDB::bind_method(D_METHOD("groove_joint_create", "groove1_a", "groove2_a", "anchor_b", "body_a", "body_b"), &PhysicsServer2D::groove_joint_create, DEFVAL(RID()), DEFVAL(RID())); - ClassDB::bind_method(D_METHOD("damped_spring_joint_create", "anchor_a", "anchor_b", "body_a", "body_b"), &PhysicsServer2D::damped_spring_joint_create, DEFVAL(RID())); + ClassDB::bind_method(D_METHOD("joint_make_pin", "joint", "anchor", "body_a", "body_b"), &PhysicsServer2D::joint_make_pin, DEFVAL(RID())); + ClassDB::bind_method(D_METHOD("joint_make_groove", "joint", "groove1_a", "groove2_a", "anchor_b", "body_a", "body_b"), &PhysicsServer2D::joint_make_groove, DEFVAL(RID()), DEFVAL(RID())); + ClassDB::bind_method(D_METHOD("joint_make_damped_spring", "joint", "anchor_a", "anchor_b", "body_a", "body_b"), &PhysicsServer2D::joint_make_damped_spring, DEFVAL(RID())); ClassDB::bind_method(D_METHOD("damped_spring_joint_set_param", "joint", "param", "value"), &PhysicsServer2D::damped_spring_joint_set_param); ClassDB::bind_method(D_METHOD("damped_spring_joint_get_param", "joint", "param"), &PhysicsServer2D::damped_spring_joint_get_param); @@ -727,9 +731,10 @@ void PhysicsServer2D::_bind_methods() { BIND_ENUM_CONSTANT(BODY_STATE_SLEEPING); BIND_ENUM_CONSTANT(BODY_STATE_CAN_SLEEP); - BIND_ENUM_CONSTANT(JOINT_PIN); - BIND_ENUM_CONSTANT(JOINT_GROOVE); - BIND_ENUM_CONSTANT(JOINT_DAMPED_SPRING); + BIND_ENUM_CONSTANT(JOINT_TYPE_PIN); + BIND_ENUM_CONSTANT(JOINT_TYPE_GROOVE); + BIND_ENUM_CONSTANT(JOINT_TYPE_DAMPED_SPRING); + BIND_ENUM_CONSTANT(JOINT_TYPE_MAX); BIND_ENUM_CONSTANT(JOINT_PARAM_BIAS); BIND_ENUM_CONSTANT(JOINT_PARAM_MAX_BIAS); diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h index f7607d5dd5..28f22ce06b 100644 --- a/servers/physics_server_2d.h +++ b/servers/physics_server_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -45,10 +45,10 @@ protected: public: virtual Vector2 get_total_gravity() const = 0; // get gravity vector working on this body space/area - virtual float get_total_linear_damp() const = 0; // get density of this body space/area - virtual float get_total_angular_damp() const = 0; // get density of this body space/area + virtual real_t get_total_linear_damp() const = 0; // get density of this body space/area + virtual real_t get_total_angular_damp() const = 0; // get density of this body space/area - virtual float get_inverse_mass() const = 0; // get the mass + virtual real_t get_inverse_mass() const = 0; // get the mass virtual real_t get_inverse_inertia() const = 0; // get density of this body space virtual void set_linear_velocity(const Vector2 &p_velocity) = 0; @@ -103,7 +103,7 @@ class PhysicsShapeQueryParameters2D : public Reference { RID shape; Transform2D transform; Vector2 motion; - float margin; + real_t margin; Set<RID> exclude; uint32_t collision_mask; @@ -125,8 +125,8 @@ public: void set_motion(const Vector2 &p_motion); Vector2 get_motion() const; - void set_margin(float p_margin); - float get_margin() const; + void set_margin(real_t p_margin); + real_t get_margin() const; void set_collision_mask(int p_collision_mask); int get_collision_mask() const; @@ -182,11 +182,11 @@ public: virtual int intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) = 0; virtual int intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_instance_id, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) = 0; - virtual int intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, float p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; + virtual int intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; - virtual bool cast_motion(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, float p_margin, float &p_closest_safe, float &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; + virtual bool cast_motion(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; - virtual bool collide_shape(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, float p_margin, Vector2 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; + virtual bool collide_shape(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, Vector2 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; struct ShapeRestInfo { Vector2 point; @@ -198,7 +198,7 @@ public: Variant metadata; }; - virtual bool rest_info(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, float p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; + virtual bool rest_info(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; PhysicsDirectSpaceState2D(); }; @@ -230,7 +230,7 @@ class PhysicsServer2D : public Object { static PhysicsServer2D *singleton; - virtual bool _body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, float p_margin = 0.08, const Ref<PhysicsTestMotionResult2D> &p_result = Ref<PhysicsTestMotionResult2D>()); + virtual bool _body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.08, const Ref<PhysicsTestMotionResult2D> &p_result = Ref<PhysicsTestMotionResult2D>()); protected: static void _bind_methods(); @@ -393,7 +393,7 @@ public: virtual Variant body_get_shape_metadata(RID p_body, int p_shape_idx) const = 0; virtual void body_set_shape_disabled(RID p_body, int p_shape, bool p_disabled) = 0; - virtual void body_set_shape_as_one_way_collision(RID p_body, int p_shape, bool p_enabled, float p_margin = 0) = 0; + virtual void body_set_shape_as_one_way_collision(RID p_body, int p_shape, bool p_enabled, real_t p_margin = 0) = 0; virtual void body_remove_shape(RID p_body, int p_shape_idx) = 0; virtual void body_clear_shapes(RID p_body) = 0; @@ -431,8 +431,8 @@ public: BODY_PARAM_MAX, }; - virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value) = 0; - virtual float body_get_param(RID p_body, BodyParameter p_param) const = 0; + virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value) = 0; + virtual real_t body_get_param(RID p_body, BodyParameter p_param) const = 0; //state enum BodyState { @@ -450,15 +450,15 @@ public: virtual void body_set_applied_force(RID p_body, const Vector2 &p_force) = 0; virtual Vector2 body_get_applied_force(RID p_body) const = 0; - virtual void body_set_applied_torque(RID p_body, float p_torque) = 0; - virtual float body_get_applied_torque(RID p_body) const = 0; + virtual void body_set_applied_torque(RID p_body, real_t p_torque) = 0; + virtual real_t body_get_applied_torque(RID p_body) const = 0; virtual void body_add_central_force(RID p_body, const Vector2 &p_force) = 0; virtual void body_add_force(RID p_body, const Vector2 &p_force, const Vector2 &p_position = Vector2()) = 0; - virtual void body_add_torque(RID p_body, float p_torque) = 0; + virtual void body_add_torque(RID p_body, real_t p_torque) = 0; virtual void body_apply_central_impulse(RID p_body, const Vector2 &p_impulse) = 0; - virtual void body_apply_torque_impulse(RID p_body, float p_torque) = 0; + virtual void body_apply_torque_impulse(RID p_body, real_t p_torque) = 0; virtual void body_apply_impulse(RID p_body, const Vector2 &p_impulse, const Vector2 &p_position = Vector2()) = 0; virtual void body_set_axis_velocity(RID p_body, const Vector2 &p_axis_velocity) = 0; @@ -471,8 +471,8 @@ public: virtual int body_get_max_contacts_reported(RID p_body) const = 0; //missing remove - virtual void body_set_contacts_reported_depth_threshold(RID p_body, float p_threshold) = 0; - virtual float body_get_contacts_reported_depth_threshold(RID p_body) const = 0; + virtual void body_set_contacts_reported_depth_threshold(RID p_body, real_t p_threshold) = 0; + virtual real_t body_get_contacts_reported_depth_threshold(RID p_body) const = 0; virtual void body_set_omit_force_integration(RID p_body, bool p_omit) = 0; virtual bool body_is_omitting_force_integration(RID p_body) const = 0; @@ -506,10 +506,10 @@ public: } }; - virtual bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, float p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) = 0; + virtual bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) = 0; struct SeparationResult { - float collision_depth; + real_t collision_depth; Vector2 collision_point; Vector2 collision_normal; Vector2 collider_velocity; @@ -520,14 +520,19 @@ public: Variant collider_metadata; }; - virtual int body_test_ray_separation(RID p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, SeparationResult *r_results, int p_result_max, float p_margin = 0.001) = 0; + virtual int body_test_ray_separation(RID p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) = 0; /* JOINT API */ + virtual RID joint_create() = 0; + + virtual void joint_clear(RID p_joint) = 0; + enum JointType { - JOINT_PIN, - JOINT_GROOVE, - JOINT_DAMPED_SPRING + JOINT_TYPE_PIN, + JOINT_TYPE_GROOVE, + JOINT_TYPE_DAMPED_SPRING, + JOINT_TYPE_MAX }; enum JointParam { @@ -542,9 +547,9 @@ public: virtual void joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable) = 0; virtual bool joint_is_disabled_collisions_between_bodies(RID p_joint) const = 0; - virtual RID pin_joint_create(const Vector2 &p_anchor, RID p_body_a, RID p_body_b = RID()) = 0; - virtual RID groove_joint_create(const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, RID p_body_a, RID p_body_b) = 0; - virtual RID damped_spring_joint_create(const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, RID p_body_a, RID p_body_b = RID()) = 0; + virtual void joint_make_pin(RID p_joint, const Vector2 &p_anchor, RID p_body_a, RID p_body_b = RID()) = 0; + virtual void joint_make_groove(RID p_joint, const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, RID p_body_a, RID p_body_b) = 0; + virtual void joint_make_damped_spring(RID p_joint, const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, RID p_body_a, RID p_body_b = RID()) = 0; enum PinJointParam { PIN_JOINT_SOFTNESS @@ -576,7 +581,7 @@ public: virtual void set_active(bool p_active) = 0; virtual void init() = 0; - virtual void step(float p_step) = 0; + virtual void step(real_t p_step) = 0; virtual void sync() = 0; virtual void flush_queries() = 0; virtual void end_sync() = 0; diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp index fabd661970..af25029f04 100644 --- a/servers/physics_server_3d.cpp +++ b/servers/physics_server_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -42,13 +42,13 @@ void PhysicsDirectBodyState3D::integrate_forces() { Vector3 av = get_angular_velocity(); - float linear_damp = 1.0 - step * get_total_linear_damp(); + real_t linear_damp = 1.0 - step * get_total_linear_damp(); if (linear_damp < 0) { // reached zero in the given time linear_damp = 0; } - float angular_damp = 1.0 - step * get_total_angular_damp(); + real_t angular_damp = 1.0 - step * get_total_angular_damp(); if (angular_damp < 0) { // reached zero in the given time angular_damp = 0; @@ -128,7 +128,7 @@ void PhysicsDirectBodyState3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "angular_velocity"), "set_angular_velocity", "get_angular_velocity"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity"), "set_linear_velocity", "get_linear_velocity"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleep_state", "is_sleeping"); - ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform"), "set_transform", "get_transform"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "transform"), "set_transform", "get_transform"); } PhysicsDirectBodyState3D::PhysicsDirectBodyState3D() {} @@ -164,11 +164,11 @@ Transform PhysicsShapeQueryParameters3D::get_transform() const { return transform; } -void PhysicsShapeQueryParameters3D::set_margin(float p_margin) { +void PhysicsShapeQueryParameters3D::set_margin(real_t p_margin) { margin = p_margin; } -float PhysicsShapeQueryParameters3D::get_margin() const { +real_t PhysicsShapeQueryParameters3D::get_margin() const { return margin; } @@ -303,7 +303,7 @@ Array PhysicsDirectSpaceState3D::_intersect_shape(const Ref<PhysicsShapeQueryPar Array PhysicsDirectSpaceState3D::_cast_motion(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, const Vector3 &p_motion) { ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array()); - float closest_safe = 1.0f, closest_unsafe = 1.0f; + real_t closest_safe = 1.0f, closest_unsafe = 1.0f; bool res = cast_motion(p_shape_query->shape, p_shape_query->transform, p_motion, p_shape_query->margin, closest_safe, closest_unsafe, p_shape_query->exclude, p_shape_query->collision_mask, p_shape_query->collide_with_bodies, p_shape_query->collide_with_areas); if (!res) { return Array(); @@ -398,10 +398,47 @@ void PhysicsShapeQueryResult3D::_bind_methods() { /////////////////////////////////////// +RID PhysicsServer3D::shape_create(ShapeType p_shape) { + switch (p_shape) { + case SHAPE_PLANE: + return plane_shape_create(); + case SHAPE_RAY: + return ray_shape_create(); + case SHAPE_SPHERE: + return sphere_shape_create(); + case SHAPE_BOX: + return box_shape_create(); + case SHAPE_CAPSULE: + return capsule_shape_create(); + case SHAPE_CYLINDER: + return cylinder_shape_create(); + case SHAPE_CONVEX_POLYGON: + return convex_polygon_shape_create(); + case SHAPE_CONCAVE_POLYGON: + return concave_polygon_shape_create(); + case SHAPE_HEIGHTMAP: + return heightmap_shape_create(); + case SHAPE_CUSTOM: + return custom_shape_create(); + default: + return RID(); + } +} + void PhysicsServer3D::_bind_methods() { #ifndef _3D_DISABLED - ClassDB::bind_method(D_METHOD("shape_create", "type"), &PhysicsServer3D::shape_create); + ClassDB::bind_method(D_METHOD("plane_shape_create"), &PhysicsServer3D::plane_shape_create); + ClassDB::bind_method(D_METHOD("ray_shape_create"), &PhysicsServer3D::ray_shape_create); + ClassDB::bind_method(D_METHOD("sphere_shape_create"), &PhysicsServer3D::sphere_shape_create); + ClassDB::bind_method(D_METHOD("box_shape_create"), &PhysicsServer3D::box_shape_create); + ClassDB::bind_method(D_METHOD("capsule_shape_create"), &PhysicsServer3D::capsule_shape_create); + ClassDB::bind_method(D_METHOD("cylinder_shape_create"), &PhysicsServer3D::cylinder_shape_create); + ClassDB::bind_method(D_METHOD("convex_polygon_shape_create"), &PhysicsServer3D::convex_polygon_shape_create); + ClassDB::bind_method(D_METHOD("concave_polygon_shape_create"), &PhysicsServer3D::concave_polygon_shape_create); + ClassDB::bind_method(D_METHOD("heightmap_shape_create"), &PhysicsServer3D::heightmap_shape_create); + ClassDB::bind_method(D_METHOD("custom_shape_create"), &PhysicsServer3D::custom_shape_create); + ClassDB::bind_method(D_METHOD("shape_set_data", "shape", "data"), &PhysicsServer3D::shape_set_data); ClassDB::bind_method(D_METHOD("shape_get_type", "shape"), &PhysicsServer3D::shape_get_type); @@ -450,9 +487,8 @@ void PhysicsServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("area_set_monitorable", "area", "monitorable"), &PhysicsServer3D::area_set_monitorable); ClassDB::bind_method(D_METHOD("area_set_ray_pickable", "area", "enable"), &PhysicsServer3D::area_set_ray_pickable); - ClassDB::bind_method(D_METHOD("area_is_ray_pickable", "area"), &PhysicsServer3D::area_is_ray_pickable); - ClassDB::bind_method(D_METHOD("body_create", "mode", "init_sleeping"), &PhysicsServer3D::body_create, DEFVAL(BODY_MODE_RIGID), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("body_create"), &PhysicsServer3D::body_create); ClassDB::bind_method(D_METHOD("body_set_space", "body", "space"), &PhysicsServer3D::body_set_space); ClassDB::bind_method(D_METHOD("body_get_space", "body"), &PhysicsServer3D::body_get_space); @@ -517,19 +553,22 @@ void PhysicsServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("body_set_force_integration_callback", "body", "receiver", "method", "userdata"), &PhysicsServer3D::body_set_force_integration_callback, DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("body_set_ray_pickable", "body", "enable"), &PhysicsServer3D::body_set_ray_pickable); - ClassDB::bind_method(D_METHOD("body_is_ray_pickable", "body"), &PhysicsServer3D::body_is_ray_pickable); ClassDB::bind_method(D_METHOD("body_get_direct_state", "body"), &PhysicsServer3D::body_get_direct_state); /* JOINT API */ - BIND_ENUM_CONSTANT(JOINT_PIN); - BIND_ENUM_CONSTANT(JOINT_HINGE); - BIND_ENUM_CONSTANT(JOINT_SLIDER); - BIND_ENUM_CONSTANT(JOINT_CONE_TWIST); - BIND_ENUM_CONSTANT(JOINT_6DOF); + ClassDB::bind_method(D_METHOD("joint_create"), &PhysicsServer3D::joint_create); + ClassDB::bind_method(D_METHOD("joint_clear", "joint"), &PhysicsServer3D::joint_clear); + + BIND_ENUM_CONSTANT(JOINT_TYPE_PIN); + BIND_ENUM_CONSTANT(JOINT_TYPE_HINGE); + BIND_ENUM_CONSTANT(JOINT_TYPE_SLIDER); + BIND_ENUM_CONSTANT(JOINT_TYPE_CONE_TWIST); + BIND_ENUM_CONSTANT(JOINT_TYPE_6DOF); + BIND_ENUM_CONSTANT(JOINT_TYPE_MAX); - ClassDB::bind_method(D_METHOD("joint_create_pin", "body_A", "local_A", "body_B", "local_B"), &PhysicsServer3D::joint_create_pin); + ClassDB::bind_method(D_METHOD("joint_make_pin", "joint", "body_A", "local_A", "body_B", "local_B"), &PhysicsServer3D::joint_make_pin); ClassDB::bind_method(D_METHOD("pin_joint_set_param", "joint", "param", "value"), &PhysicsServer3D::pin_joint_set_param); ClassDB::bind_method(D_METHOD("pin_joint_get_param", "joint", "param"), &PhysicsServer3D::pin_joint_get_param); @@ -555,7 +594,7 @@ void PhysicsServer3D::_bind_methods() { BIND_ENUM_CONSTANT(HINGE_JOINT_FLAG_USE_LIMIT); BIND_ENUM_CONSTANT(HINGE_JOINT_FLAG_ENABLE_MOTOR); - ClassDB::bind_method(D_METHOD("joint_create_hinge", "body_A", "hinge_A", "body_B", "hinge_B"), &PhysicsServer3D::joint_create_hinge); + ClassDB::bind_method(D_METHOD("joint_make_hinge", "joint", "body_A", "hinge_A", "body_B", "hinge_B"), &PhysicsServer3D::joint_make_hinge); ClassDB::bind_method(D_METHOD("hinge_joint_set_param", "joint", "param", "value"), &PhysicsServer3D::hinge_joint_set_param); ClassDB::bind_method(D_METHOD("hinge_joint_get_param", "joint", "param"), &PhysicsServer3D::hinge_joint_get_param); @@ -563,7 +602,7 @@ void PhysicsServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("hinge_joint_set_flag", "joint", "flag", "enabled"), &PhysicsServer3D::hinge_joint_set_flag); ClassDB::bind_method(D_METHOD("hinge_joint_get_flag", "joint", "flag"), &PhysicsServer3D::hinge_joint_get_flag); - ClassDB::bind_method(D_METHOD("joint_create_slider", "body_A", "local_ref_A", "body_B", "local_ref_B"), &PhysicsServer3D::joint_create_slider); + ClassDB::bind_method(D_METHOD("joint_make_slider", "joint", "body_A", "local_ref_A", "body_B", "local_ref_B"), &PhysicsServer3D::joint_make_slider); ClassDB::bind_method(D_METHOD("slider_joint_set_param", "joint", "param", "value"), &PhysicsServer3D::slider_joint_set_param); ClassDB::bind_method(D_METHOD("slider_joint_get_param", "joint", "param"), &PhysicsServer3D::slider_joint_get_param); @@ -593,7 +632,7 @@ void PhysicsServer3D::_bind_methods() { BIND_ENUM_CONSTANT(SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING); BIND_ENUM_CONSTANT(SLIDER_JOINT_MAX); - ClassDB::bind_method(D_METHOD("joint_create_cone_twist", "body_A", "local_ref_A", "body_B", "local_ref_B"), &PhysicsServer3D::joint_create_cone_twist); + ClassDB::bind_method(D_METHOD("joint_make_cone_twist", "joint", "body_A", "local_ref_A", "body_B", "local_ref_B"), &PhysicsServer3D::joint_make_cone_twist); ClassDB::bind_method(D_METHOD("cone_twist_joint_set_param", "joint", "param", "value"), &PhysicsServer3D::cone_twist_joint_set_param); ClassDB::bind_method(D_METHOD("cone_twist_joint_get_param", "joint", "param"), &PhysicsServer3D::cone_twist_joint_get_param); @@ -631,7 +670,7 @@ void PhysicsServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("joint_set_solver_priority", "joint", "priority"), &PhysicsServer3D::joint_set_solver_priority); ClassDB::bind_method(D_METHOD("joint_get_solver_priority", "joint"), &PhysicsServer3D::joint_get_solver_priority); - ClassDB::bind_method(D_METHOD("joint_create_generic_6dof", "body_A", "local_ref_A", "body_B", "local_ref_B"), &PhysicsServer3D::joint_create_generic_6dof); + ClassDB::bind_method(D_METHOD("joint_make_generic_6dof", "joint", "body_A", "local_ref_A", "body_B", "local_ref_B"), &PhysicsServer3D::joint_make_generic_6dof); ClassDB::bind_method(D_METHOD("generic_6dof_joint_set_param", "joint", "axis", "param", "value"), &PhysicsServer3D::generic_6dof_joint_set_param); ClassDB::bind_method(D_METHOD("generic_6dof_joint_get_param", "joint", "axis", "param"), &PhysicsServer3D::generic_6dof_joint_get_param); @@ -718,7 +757,6 @@ void PhysicsServer3D::_bind_methods() { } PhysicsServer3D::PhysicsServer3D() { - ERR_FAIL_COND(singleton != nullptr); singleton = this; } diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h index 3f7ad26257..e16857192c 100644 --- a/servers/physics_server_3d.h +++ b/servers/physics_server_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -44,12 +44,12 @@ protected: public: virtual Vector3 get_total_gravity() const = 0; - virtual float get_total_angular_damp() const = 0; - virtual float get_total_linear_damp() const = 0; + virtual real_t get_total_angular_damp() const = 0; + virtual real_t get_total_linear_damp() const = 0; virtual Vector3 get_center_of_mass() const = 0; virtual Basis get_principal_inertia_axes() const = 0; - virtual float get_inverse_mass() const = 0; // get the mass + virtual real_t get_inverse_mass() const = 0; // get the mass virtual Vector3 get_inverse_inertia() const = 0; // get density of this body space virtual Basis get_inverse_inertia_tensor() const = 0; // get density of this body space @@ -76,7 +76,7 @@ public: virtual Vector3 get_contact_local_position(int p_contact_idx) const = 0; virtual Vector3 get_contact_local_normal(int p_contact_idx) const = 0; - virtual float get_contact_impulse(int p_contact_idx) const = 0; + virtual real_t get_contact_impulse(int p_contact_idx) const = 0; virtual int get_contact_local_shape(int p_contact_idx) const = 0; virtual RID get_contact_collider(int p_contact_idx) const = 0; @@ -103,7 +103,7 @@ class PhysicsShapeQueryParameters3D : public Reference { RES shape_ref; RID shape; Transform transform; - float margin; + real_t margin; Set<RID> exclude; uint32_t collision_mask; @@ -122,8 +122,8 @@ public: void set_transform(const Transform &p_transform); Transform get_transform() const; - void set_margin(float p_margin); - float get_margin() const; + void set_margin(real_t p_margin); + real_t get_margin() const; void set_collision_mask(int p_collision_mask); int get_collision_mask() const; @@ -174,7 +174,7 @@ public: virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_ray = false) = 0; - virtual int intersect_shape(const RID &p_shape, const Transform &p_xform, float p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; + virtual int intersect_shape(const RID &p_shape, const Transform &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; struct ShapeRestInfo { Vector3 point; @@ -185,11 +185,11 @@ public: Vector3 linear_velocity; //velocity at contact point }; - virtual bool cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, float p_margin, float &p_closest_safe, float &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = nullptr) = 0; + virtual bool cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = nullptr) = 0; - virtual bool collide_shape(RID p_shape, const Transform &p_shape_xform, float p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; + virtual bool collide_shape(RID p_shape, const Transform &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; - virtual bool rest_info(RID p_shape, const Transform &p_shape_xform, float p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; + virtual bool rest_info(RID p_shape, const Transform &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; virtual Vector3 get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const = 0; @@ -240,7 +240,19 @@ public: SHAPE_CUSTOM, ///< Server-Implementation based custom shape, calling shape_create() with this value will result in an error }; - virtual RID shape_create(ShapeType p_shape) = 0; + RID shape_create(ShapeType p_shape); + + virtual RID plane_shape_create() = 0; + virtual RID ray_shape_create() = 0; + virtual RID sphere_shape_create() = 0; + virtual RID box_shape_create() = 0; + virtual RID capsule_shape_create() = 0; + virtual RID cylinder_shape_create() = 0; + virtual RID convex_polygon_shape_create() = 0; + virtual RID concave_polygon_shape_create() = 0; + virtual RID heightmap_shape_create() = 0; + virtual RID custom_shape_create() = 0; + virtual void shape_set_data(RID p_shape, const Variant &p_data) = 0; virtual void shape_set_custom_solver_bias(RID p_shape, real_t p_bias) = 0; @@ -344,7 +356,6 @@ public: virtual void area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) = 0; virtual void area_set_ray_pickable(RID p_area, bool p_enable) = 0; - virtual bool area_is_ray_pickable(RID p_area) const = 0; /* BODY API */ @@ -357,7 +368,7 @@ public: BODY_MODE_CHARACTER }; - virtual RID body_create(BodyMode p_mode = BODY_MODE_RIGID, bool p_init_sleeping = false) = 0; + virtual RID body_create() = 0; virtual void body_set_space(RID p_body, RID p_space) = 0; virtual RID body_get_space(RID p_body) const = 0; @@ -404,8 +415,8 @@ public: BODY_PARAM_MAX, }; - virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value) = 0; - virtual float body_get_param(RID p_body, BodyParameter p_param) const = 0; + virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value) = 0; + virtual real_t body_get_param(RID p_body, BodyParameter p_param) const = 0; virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin) = 0; virtual real_t body_get_kinematic_safe_margin(RID p_body) const = 0; @@ -459,8 +470,8 @@ public: virtual int body_get_max_contacts_reported(RID p_body) const = 0; //missing remove - virtual void body_set_contacts_reported_depth_threshold(RID p_body, float p_threshold) = 0; - virtual float body_get_contacts_reported_depth_threshold(RID p_body) const = 0; + virtual void body_set_contacts_reported_depth_threshold(RID p_body, real_t p_threshold) = 0; + virtual real_t body_get_contacts_reported_depth_threshold(RID p_body) const = 0; virtual void body_set_omit_force_integration(RID p_body, bool p_omit) = 0; virtual bool body_is_omitting_force_integration(RID p_body) const = 0; @@ -468,7 +479,6 @@ public: virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant()) = 0; virtual void body_set_ray_pickable(RID p_body, bool p_enable) = 0; - virtual bool body_is_ray_pickable(RID p_body) const = 0; // this function only works on physics process, errors and returns null otherwise virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) = 0; @@ -495,7 +505,7 @@ public: virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) = 0; struct SeparationResult { - float collision_depth; + real_t collision_depth; Vector3 collision_point; Vector3 collision_normal; Vector3 collider_velocity; @@ -506,11 +516,11 @@ public: Variant collider_metadata; }; - virtual int body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, float p_margin = 0.001) = 0; + virtual int body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) = 0; /* SOFT BODY */ - virtual RID soft_body_create(bool p_init_sleeping = false) = 0; + virtual RID soft_body_create() = 0; virtual void soft_body_update_rendering_server(RID p_body, class SoftBodyRenderingServerHandler *p_rendering_server_handler) = 0; @@ -536,55 +546,59 @@ public: virtual Vector3 soft_body_get_vertex_position(RID p_body, int vertex_index) const = 0; virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) = 0; - virtual bool soft_body_is_ray_pickable(RID p_body) const = 0; virtual void soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) = 0; - virtual int soft_body_get_simulation_precision(RID p_body) = 0; + virtual int soft_body_get_simulation_precision(RID p_body) const = 0; virtual void soft_body_set_total_mass(RID p_body, real_t p_total_mass) = 0; - virtual real_t soft_body_get_total_mass(RID p_body) = 0; + virtual real_t soft_body_get_total_mass(RID p_body) const = 0; virtual void soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) = 0; - virtual real_t soft_body_get_linear_stiffness(RID p_body) = 0; + virtual real_t soft_body_get_linear_stiffness(RID p_body) const = 0; - virtual void soft_body_set_areaAngular_stiffness(RID p_body, real_t p_stiffness) = 0; - virtual real_t soft_body_get_areaAngular_stiffness(RID p_body) = 0; + virtual void soft_body_set_angular_stiffness(RID p_body, real_t p_stiffness) = 0; + virtual real_t soft_body_get_angular_stiffness(RID p_body) const = 0; virtual void soft_body_set_volume_stiffness(RID p_body, real_t p_stiffness) = 0; - virtual real_t soft_body_get_volume_stiffness(RID p_body) = 0; + virtual real_t soft_body_get_volume_stiffness(RID p_body) const = 0; virtual void soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) = 0; - virtual real_t soft_body_get_pressure_coefficient(RID p_body) = 0; + virtual real_t soft_body_get_pressure_coefficient(RID p_body) const = 0; virtual void soft_body_set_pose_matching_coefficient(RID p_body, real_t p_pose_matching_coefficient) = 0; - virtual real_t soft_body_get_pose_matching_coefficient(RID p_body) = 0; + virtual real_t soft_body_get_pose_matching_coefficient(RID p_body) const = 0; virtual void soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) = 0; - virtual real_t soft_body_get_damping_coefficient(RID p_body) = 0; + virtual real_t soft_body_get_damping_coefficient(RID p_body) const = 0; virtual void soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) = 0; - virtual real_t soft_body_get_drag_coefficient(RID p_body) = 0; + virtual real_t soft_body_get_drag_coefficient(RID p_body) const = 0; virtual void soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) = 0; - virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index) = 0; + virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index) const = 0; virtual Vector3 soft_body_get_point_offset(RID p_body, int p_point_index) const = 0; virtual void soft_body_remove_all_pinned_points(RID p_body) = 0; virtual void soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) = 0; - virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) = 0; + virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) const = 0; /* JOINT API */ enum JointType { - JOINT_PIN, - JOINT_HINGE, - JOINT_SLIDER, - JOINT_CONE_TWIST, - JOINT_6DOF + JOINT_TYPE_PIN, + JOINT_TYPE_HINGE, + JOINT_TYPE_SLIDER, + JOINT_TYPE_CONE_TWIST, + JOINT_TYPE_6DOF, + JOINT_TYPE_MAX, }; + virtual RID joint_create() = 0; + + virtual void joint_clear(RID p_joint) = 0; + virtual JointType joint_get_type(RID p_joint) const = 0; virtual void joint_set_solver_priority(RID p_joint, int p_priority) = 0; @@ -593,7 +607,7 @@ public: virtual void joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable) = 0; virtual bool joint_is_disabled_collisions_between_bodies(RID p_joint) const = 0; - virtual RID joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) = 0; + virtual void joint_make_pin(RID p_joint, RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) = 0; enum PinJointParam { PIN_JOINT_BIAS, @@ -601,8 +615,8 @@ public: PIN_JOINT_IMPULSE_CLAMP }; - virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, float p_value) = 0; - virtual float pin_joint_get_param(RID p_joint, PinJointParam p_param) const = 0; + virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) = 0; + virtual real_t pin_joint_get_param(RID p_joint, PinJointParam p_param) const = 0; virtual void pin_joint_set_local_a(RID p_joint, const Vector3 &p_A) = 0; virtual Vector3 pin_joint_get_local_a(RID p_joint) const = 0; @@ -628,11 +642,11 @@ public: HINGE_JOINT_FLAG_MAX }; - virtual RID joint_create_hinge(RID p_body_A, const Transform &p_hinge_A, RID p_body_B, const Transform &p_hinge_B) = 0; - virtual RID joint_create_hinge_simple(RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B) = 0; + virtual void joint_make_hinge(RID p_joint, RID p_body_A, const Transform &p_hinge_A, RID p_body_B, const Transform &p_hinge_B) = 0; + virtual void joint_make_hinge_simple(RID p_joint, RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B) = 0; - virtual void hinge_joint_set_param(RID p_joint, HingeJointParam p_param, float p_value) = 0; - virtual float hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const = 0; + virtual void hinge_joint_set_param(RID p_joint, HingeJointParam p_param, real_t p_value) = 0; + virtual real_t hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const = 0; virtual void hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag, bool p_value) = 0; virtual bool hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const = 0; @@ -665,10 +679,10 @@ public: }; - virtual RID joint_create_slider(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) = 0; //reference frame is A + virtual void joint_make_slider(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) = 0; //reference frame is A - virtual void slider_joint_set_param(RID p_joint, SliderJointParam p_param, float p_value) = 0; - virtual float slider_joint_get_param(RID p_joint, SliderJointParam p_param) const = 0; + virtual void slider_joint_set_param(RID p_joint, SliderJointParam p_param, real_t p_value) = 0; + virtual real_t slider_joint_get_param(RID p_joint, SliderJointParam p_param) const = 0; enum ConeTwistJointParam { CONE_TWIST_JOINT_SWING_SPAN, @@ -679,10 +693,10 @@ public: CONE_TWIST_MAX }; - virtual RID joint_create_cone_twist(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) = 0; //reference frame is A + virtual void joint_make_cone_twist(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) = 0; //reference frame is A - virtual void cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, float p_value) = 0; - virtual float cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const = 0; + virtual void cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, real_t p_value) = 0; + virtual real_t cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const = 0; enum G6DOFJointAxisParam { G6DOF_JOINT_LINEAR_LOWER_LIMIT, @@ -720,16 +734,13 @@ public: G6DOF_JOINT_FLAG_MAX }; - virtual RID joint_create_generic_6dof(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) = 0; //reference frame is A + virtual void joint_make_generic_6dof(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) = 0; //reference frame is A - virtual void generic_6dof_joint_set_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param, float p_value) = 0; - virtual float generic_6dof_joint_get_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param) = 0; + virtual void generic_6dof_joint_set_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param, real_t p_value) = 0; + virtual real_t generic_6dof_joint_get_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param) const = 0; virtual void generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag, bool p_enable) = 0; - virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag) = 0; - - virtual void generic_6dof_joint_set_precision(RID p_joint, int precision) = 0; - virtual int generic_6dof_joint_get_precision(RID p_joint) = 0; + virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag) const = 0; /* QUERY API */ @@ -744,8 +755,10 @@ public: virtual void set_active(bool p_active) = 0; virtual void init() = 0; - virtual void step(float p_step) = 0; + virtual void step(real_t p_step) = 0; + virtual void sync() = 0; virtual void flush_queries() = 0; + virtual void end_sync() = 0; virtual void finish() = 0; virtual bool is_flushing_queries() const = 0; diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index 34980aaf66..deb230c4fb 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -36,6 +36,7 @@ #include "audio/audio_effect.h" #include "audio/audio_stream.h" #include "audio/effects/audio_effect_amplify.h" +#include "audio/effects/audio_effect_capture.h" #include "audio/effects/audio_effect_chorus.h" #include "audio/effects/audio_effect_compressor.h" #include "audio/effects/audio_effect_delay.h" @@ -60,14 +61,15 @@ #include "physics_2d/physics_server_2d_sw.h" #include "physics_2d/physics_server_2d_wrap_mt.h" #include "physics_3d/physics_server_3d_sw.h" +#include "physics_3d/physics_server_3d_wrap_mt.h" #include "physics_server_2d.h" #include "physics_server_3d.h" -#include "rendering/rasterizer.h" +#include "rendering/renderer_compositor.h" #include "rendering/rendering_device.h" #include "rendering/rendering_device_binds.h" - #include "rendering_server.h" #include "servers/rendering/shader_types.h" +#include "text_server.h" #include "xr/xr_interface.h" #include "xr/xr_positional_tracker.h" #include "xr_server.h" @@ -75,11 +77,19 @@ ShaderTypes *shader_types = nullptr; PhysicsServer3D *_createGodotPhysics3DCallback() { - return memnew(PhysicsServer3DSW); + bool using_threads = GLOBAL_GET("physics/3d/run_on_thread"); + + PhysicsServer3D *physics_server = memnew(PhysicsServer3DSW(using_threads)); + + return memnew(PhysicsServer3DWrapMT(physics_server, using_threads)); } PhysicsServer2D *_createGodotPhysics2DCallback() { - return PhysicsServer2DWrapMT::init_server<PhysicsServer2DSW>(); + bool using_threads = GLOBAL_GET("physics/2d/run_on_thread"); + + PhysicsServer2D *physics_server = memnew(PhysicsServer2DSW(using_threads)); + + return memnew(PhysicsServer2DWrapMT(physics_server, using_threads)); } static bool has_server_feature_callback(const String &p_feature) { @@ -94,6 +104,16 @@ static bool has_server_feature_callback(const String &p_feature) { void preregister_server_types() { shader_types = memnew(ShaderTypes); + + GLOBAL_DEF("internationalization/rendering/text_driver", ""); + String text_driver_options; + for (int i = 0; i < TextServerManager::get_interface_count(); i++) { + if (i > 0) { + text_driver_options += ","; + } + text_driver_options += TextServerManager::get_interface_name(i); + } + ProjectSettings::get_singleton()->set_custom_property_info("internationalization/rendering/text_driver", PropertyInfo(Variant::STRING, "internationalization/rendering/text_driver", PROPERTY_HINT_ENUM, text_driver_options)); } void register_server_types() { @@ -102,6 +122,11 @@ void register_server_types() { ClassDB::register_virtual_class<DisplayServer>(); ClassDB::register_virtual_class<RenderingServer>(); ClassDB::register_class<AudioServer>(); + + ClassDB::register_class<TextServerManager>(); + ClassDB::register_virtual_class<TextServer>(); + TextServer::initialize_hex_code_box_fonts(); + ClassDB::register_virtual_class<PhysicsServer2D>(); ClassDB::register_virtual_class<PhysicsServer3D>(); ClassDB::register_virtual_class<NavigationServer2D>(); @@ -161,6 +186,8 @@ void register_server_types() { ClassDB::register_class<AudioEffectRecord>(); ClassDB::register_class<AudioEffectSpectrumAnalyzer>(); ClassDB::register_virtual_class<AudioEffectSpectrumAnalyzerInstance>(); + + ClassDB::register_class<AudioEffectCapture>(); } ClassDB::register_virtual_class<RenderingDevice>(); @@ -209,6 +236,7 @@ void register_server_types() { void unregister_server_types() { memdelete(shader_types); + TextServer::finish_hex_code_box_fonts(); } void register_server_singletons() { @@ -219,6 +247,7 @@ void register_server_singletons() { Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer3D", PhysicsServer3D::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer2D", NavigationServer2D::get_singleton_mut())); Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer3D", NavigationServer3D::get_singleton_mut())); + Engine::get_singleton()->add_singleton(Engine::Singleton("TextServerManager", TextServerManager::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("XRServer", XRServer::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("CameraServer", CameraServer::get_singleton())); } diff --git a/servers/register_server_types.h b/servers/register_server_types.h index 7d1dad37af..f6a65cb653 100644 --- a/servers/register_server_types.h +++ b/servers/register_server_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/SCsub b/servers/rendering/SCsub index 5ea0d40486..0939b68482 100644 --- a/servers/rendering/SCsub +++ b/servers/rendering/SCsub @@ -4,4 +4,4 @@ Import("env") env.add_source_files(env.servers_sources, "*.cpp") -SConscript("rasterizer_rd/SCsub") +SConscript("renderer_rd/SCsub") diff --git a/servers/rendering/rasterizer.h b/servers/rendering/rasterizer.h deleted file mode 100644 index 4df140f8c3..0000000000 --- a/servers/rendering/rasterizer.h +++ /dev/null @@ -1,1413 +0,0 @@ -/*************************************************************************/ -/* rasterizer.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef RASTERIZER_H -#define RASTERIZER_H - -#include "core/math/camera_matrix.h" -#include "core/templates/pair.h" -#include "core/templates/self_list.h" -#include "servers/rendering_server.h" - -class RasterizerScene { -public: - /* SHADOW ATLAS API */ - - virtual RID shadow_atlas_create() = 0; - virtual void shadow_atlas_set_size(RID p_atlas, int p_size) = 0; - virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) = 0; - virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) = 0; - - virtual void directional_shadow_atlas_set_size(int p_size) = 0; - virtual int get_directional_light_shadow_size(RID p_light_intance) = 0; - virtual void set_directional_shadow_count(int p_count) = 0; - - /* SDFGI UPDATE */ - - struct InstanceBase; - - virtual void sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) = 0; - virtual int sdfgi_get_pending_region_count(RID p_render_buffers) const = 0; - virtual AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const = 0; - virtual uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const = 0; - virtual void sdfgi_update_probes(RID p_render_buffers, RID p_environment, const RID *p_directional_light_instances, uint32_t p_directional_light_count, const RID *p_positional_light_instances, uint32_t p_positional_light_count) = 0; - - /* SKY API */ - - virtual RID sky_create() = 0; - virtual void sky_set_radiance_size(RID p_sky, int p_radiance_size) = 0; - virtual void sky_set_mode(RID p_sky, RS::SkyMode p_samples) = 0; - virtual void sky_set_material(RID p_sky, RID p_material) = 0; - virtual Ref<Image> sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) = 0; - - /* ENVIRONMENT API */ - - virtual RID environment_create() = 0; - - virtual void environment_set_background(RID p_env, RS::EnvironmentBG p_bg) = 0; - virtual void environment_set_sky(RID p_env, RID p_sky) = 0; - virtual void environment_set_sky_custom_fov(RID p_env, float p_scale) = 0; - virtual void environment_set_sky_orientation(RID p_env, const Basis &p_orientation) = 0; - virtual void environment_set_bg_color(RID p_env, const Color &p_color) = 0; - virtual void environment_set_bg_energy(RID p_env, float p_energy) = 0; - virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer) = 0; - virtual void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG, const Color &p_ao_color = Color()) = 0; -// FIXME: Disabled during Vulkan refactoring, should be ported. -#if 0 - virtual void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) = 0; -#endif - - virtual void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) = 0; - virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) = 0; - virtual void environment_glow_set_use_high_quality(bool p_enable) = 0; - - virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, RS::EnvVolumetricFogShadowFilter p_shadow_filter) = 0; - - virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) = 0; - virtual void environment_set_volumetric_fog_filter_active(bool p_enable) = 0; - virtual void environment_set_volumetric_fog_directional_shadow_shrink_size(int p_shrink_size) = 0; - virtual void environment_set_volumetric_fog_positional_shadow_shrink_size(int p_shrink_size) = 0; - - virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) = 0; - virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) = 0; - - virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_bias, float p_light_affect, float p_ao_channel_affect, RS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) = 0; - - virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size) = 0; - - virtual void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, bool p_use_multibounce, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) = 0; - - virtual void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) = 0; - virtual void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) = 0; - - virtual void environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) = 0; - - virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) = 0; - - virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective) = 0; - - virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) = 0; - - virtual bool is_environment(RID p_env) const = 0; - virtual RS::EnvironmentBG environment_get_background(RID p_env) const = 0; - virtual int environment_get_canvas_max_layer(RID p_env) const = 0; - - virtual RID camera_effects_create() = 0; - - virtual void camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) = 0; - virtual void camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) = 0; - - virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) = 0; - virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) = 0; - - virtual void shadows_quality_set(RS::ShadowQuality p_quality) = 0; - virtual void directional_shadow_quality_set(RS::ShadowQuality p_quality) = 0; - - struct InstanceDependency { - void instance_notify_changed(bool p_aabb, bool p_dependencies); - void instance_notify_deleted(RID p_deleted); - - ~InstanceDependency(); - - private: - friend struct InstanceBase; - Map<InstanceBase *, uint32_t> instances; - }; - - struct InstanceBase { - RS::InstanceType base_type; - RID base; - - RID skeleton; - RID material_override; - - RID instance_data; - - Transform transform; - - int depth_layer; - uint32_t layer_mask; - uint32_t instance_version; - - //RID sampled_light; - - Vector<RID> materials; - Vector<RID> light_instances; - Vector<RID> reflection_probe_instances; - Vector<RID> gi_probe_instances; - - Vector<float> blend_values; - - RS::ShadowCastingSetting cast_shadows; - - //fit in 32 bits - bool mirror : 8; - bool receive_shadows : 8; - bool visible : 8; - bool baked_light : 2; //this flag is only to know if it actually did use baked light - bool dynamic_gi : 2; //this flag is only to know if it actually did use baked light - bool redraw_if_visible : 4; - - float depth; //used for sorting - - SelfList<InstanceBase> dependency_item; - - InstanceBase *lightmap; - Rect2 lightmap_uv_scale; - int lightmap_slice_index; - uint32_t lightmap_cull_index; - Vector<Color> lightmap_sh; //spherical harmonic - - AABB aabb; - AABB transformed_aabb; - - struct InstanceShaderParameter { - int32_t index = -1; - Variant value; - Variant default_value; - PropertyInfo info; - }; - - Map<StringName, InstanceShaderParameter> instance_shader_parameters; - bool instance_allocated_shader_parameters = false; - int32_t instance_allocated_shader_parameters_offset = -1; - - virtual void dependency_deleted(RID p_dependency) {} - virtual void dependency_changed(bool p_aabb, bool p_dependencies) {} - - Set<InstanceDependency *> dependencies; - - void instance_increase_version() { - instance_version++; - } - - void update_dependency(InstanceDependency *p_dependency) { - dependencies.insert(p_dependency); - p_dependency->instances[this] = instance_version; - } - - void clean_up_dependencies() { - List<Pair<InstanceDependency *, Map<InstanceBase *, uint32_t>::Element *>> to_clean_up; - for (Set<InstanceDependency *>::Element *E = dependencies.front(); E; E = E->next()) { - InstanceDependency *dep = E->get(); - Map<InstanceBase *, uint32_t>::Element *F = dep->instances.find(this); - ERR_CONTINUE(!F); - if (F->get() != instance_version) { - Pair<InstanceDependency *, Map<InstanceBase *, uint32_t>::Element *> p; - p.first = dep; - p.second = F; - to_clean_up.push_back(p); - } - } - - while (to_clean_up.size()) { - to_clean_up.front()->get().first->instances.erase(to_clean_up.front()->get().second); - to_clean_up.pop_front(); - } - } - - void clear_dependencies() { - for (Set<InstanceDependency *>::Element *E = dependencies.front(); E; E = E->next()) { - InstanceDependency *dep = E->get(); - dep->instances.erase(this); - } - dependencies.clear(); - } - - InstanceBase() : - dependency_item(this) { - base_type = RS::INSTANCE_NONE; - cast_shadows = RS::SHADOW_CASTING_SETTING_ON; - receive_shadows = true; - visible = true; - depth_layer = 0; - layer_mask = 1; - instance_version = 0; - baked_light = false; - dynamic_gi = false; - redraw_if_visible = false; - lightmap_slice_index = 0; - lightmap = nullptr; - lightmap_cull_index = 0; - } - - virtual ~InstanceBase() { - clear_dependencies(); - } - }; - - virtual RID light_instance_create(RID p_light) = 0; - virtual void light_instance_set_transform(RID p_light_instance, const Transform &p_transform) = 0; - virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) = 0; - virtual void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) = 0; - virtual void light_instance_mark_visible(RID p_light_instance) = 0; - virtual bool light_instances_can_render_shadow_cube() const { - return true; - } - - virtual RID reflection_atlas_create() = 0; - virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) = 0; - - virtual RID reflection_probe_instance_create(RID p_probe) = 0; - virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) = 0; - virtual void reflection_probe_release_atlas_index(RID p_instance) = 0; - virtual bool reflection_probe_instance_needs_redraw(RID p_instance) = 0; - virtual bool reflection_probe_instance_has_reflection(RID p_instance) = 0; - virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) = 0; - virtual bool reflection_probe_instance_postprocess_step(RID p_instance) = 0; - - virtual RID decal_instance_create(RID p_decal) = 0; - virtual void decal_instance_set_transform(RID p_decal, const Transform &p_transform) = 0; - - virtual RID gi_probe_instance_create(RID p_gi_probe) = 0; - virtual void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) = 0; - virtual bool gi_probe_needs_update(RID p_probe) const = 0; - virtual void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, int p_dynamic_object_count, InstanceBase **p_dynamic_objects) = 0; - - virtual void gi_probe_set_quality(RS::GIProbeQuality) = 0; - - virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) = 0; - - virtual void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) = 0; - virtual void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 0; - virtual void render_sdfgi(RID p_render_buffers, int p_region, InstanceBase **p_cull_result, int p_cull_count) = 0; - virtual void render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const RID **p_positional_light_cull_result, const uint32_t *p_positional_light_cull_count) = 0; - virtual void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, InstanceBase **p_cull_result, int p_cull_count) = 0; - - virtual void set_scene_pass(uint64_t p_pass) = 0; - virtual void set_time(double p_time, double p_step) = 0; - virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) = 0; - - virtual RID render_buffers_create() = 0; - virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding) = 0; - - virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_limit) = 0; - virtual bool screen_space_roughness_limiter_is_active() const = 0; - - virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) = 0; - virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) = 0; - - virtual TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) = 0; - - virtual bool free(RID p_rid) = 0; - - virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) = 0; - - virtual void update() = 0; - virtual ~RasterizerScene() {} -}; - -class RasterizerStorage { - Color default_clear_color; - -public: - /* TEXTURE API */ - - virtual RID texture_2d_create(const Ref<Image> &p_image) = 0; - virtual RID texture_2d_layered_create(const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) = 0; - virtual RID texture_3d_create(Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) = 0; - virtual RID texture_proxy_create(RID p_base) = 0; //all slices, then all the mipmaps, must be coherent - - virtual void texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0; //mostly used for video and streaming - virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0; - virtual void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) = 0; - virtual void texture_proxy_update(RID p_proxy, RID p_base) = 0; - - //these two APIs can be used together or in combination with the others. - virtual RID texture_2d_placeholder_create() = 0; - virtual RID texture_2d_layered_placeholder_create(RenderingServer::TextureLayeredType p_layered_type) = 0; - virtual RID texture_3d_placeholder_create() = 0; - - virtual Ref<Image> texture_2d_get(RID p_texture) const = 0; - virtual Ref<Image> texture_2d_layer_get(RID p_texture, int p_layer) const = 0; - virtual Vector<Ref<Image>> texture_3d_get(RID p_texture) const = 0; - - virtual void texture_replace(RID p_texture, RID p_by_texture) = 0; - virtual void texture_set_size_override(RID p_texture, int p_width, int p_height) = 0; - - virtual void texture_set_path(RID p_texture, const String &p_path) = 0; - virtual String texture_get_path(RID p_texture) const = 0; - - virtual void texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) = 0; - virtual void texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) = 0; - virtual void texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) = 0; - - virtual void texture_debug_usage(List<RS::TextureInfo> *r_info) = 0; - - virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) = 0; - - virtual Size2 texture_size_with_proxy(RID p_proxy) = 0; - - virtual void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) = 0; - virtual void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) = 0; - - /* CANVAS TEXTURE API */ - - virtual RID canvas_texture_create() = 0; - virtual void canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) = 0; - virtual void canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_base_color, float p_shininess) = 0; - - virtual void canvas_texture_set_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) = 0; - virtual void canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) = 0; - - /* SHADER API */ - - virtual RID shader_create() = 0; - - virtual void shader_set_code(RID p_shader, const String &p_code) = 0; - virtual String shader_get_code(RID p_shader) const = 0; - virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const = 0; - - virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) = 0; - virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const = 0; - virtual Variant shader_get_param_default(RID p_material, const StringName &p_param) const = 0; - - /* COMMON MATERIAL API */ - - virtual RID material_create() = 0; - - virtual void material_set_render_priority(RID p_material, int priority) = 0; - virtual void material_set_shader(RID p_shader_material, RID p_shader) = 0; - - virtual void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) = 0; - virtual Variant material_get_param(RID p_material, const StringName &p_param) const = 0; - - virtual void material_set_next_pass(RID p_material, RID p_next_material) = 0; - - virtual bool material_is_animated(RID p_material) = 0; - virtual bool material_casts_shadows(RID p_material) = 0; - - struct InstanceShaderParam { - PropertyInfo info; - int index; - Variant default_value; - }; - - virtual void material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) = 0; - - virtual void material_update_dependency(RID p_material, RasterizerScene::InstanceBase *p_instance) = 0; - - /* MESH API */ - - virtual RID mesh_create() = 0; - - /// Returns stride - virtual void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) = 0; - - virtual int mesh_get_blend_shape_count(RID p_mesh) const = 0; - - virtual void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) = 0; - virtual RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const = 0; - - virtual void mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) = 0; - - virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) = 0; - virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const = 0; - - virtual RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const = 0; - - virtual int mesh_get_surface_count(RID p_mesh) const = 0; - - virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) = 0; - virtual AABB mesh_get_custom_aabb(RID p_mesh) const = 0; - - virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) = 0; - - virtual void mesh_clear(RID p_mesh) = 0; - - /* MULTIMESH API */ - - virtual RID multimesh_create() = 0; - - virtual void multimesh_allocate(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) = 0; - - virtual int multimesh_get_instance_count(RID p_multimesh) const = 0; - - virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh) = 0; - virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) = 0; - virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) = 0; - virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) = 0; - virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) = 0; - - virtual RID multimesh_get_mesh(RID p_multimesh) const = 0; - - virtual Transform multimesh_instance_get_transform(RID p_multimesh, int p_index) const = 0; - virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const = 0; - virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const = 0; - virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const = 0; - - virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) = 0; - virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const = 0; - - virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible) = 0; - virtual int multimesh_get_visible_instances(RID p_multimesh) const = 0; - - virtual AABB multimesh_get_aabb(RID p_multimesh) const = 0; - - /* IMMEDIATE API */ - - virtual RID immediate_create() = 0; - virtual void immediate_begin(RID p_immediate, RS::PrimitiveType p_rimitive, RID p_texture = RID()) = 0; - virtual void immediate_vertex(RID p_immediate, const Vector3 &p_vertex) = 0; - virtual void immediate_normal(RID p_immediate, const Vector3 &p_normal) = 0; - virtual void immediate_tangent(RID p_immediate, const Plane &p_tangent) = 0; - virtual void immediate_color(RID p_immediate, const Color &p_color) = 0; - virtual void immediate_uv(RID p_immediate, const Vector2 &tex_uv) = 0; - virtual void immediate_uv2(RID p_immediate, const Vector2 &tex_uv) = 0; - virtual void immediate_end(RID p_immediate) = 0; - virtual void immediate_clear(RID p_immediate) = 0; - virtual void immediate_set_material(RID p_immediate, RID p_material) = 0; - virtual RID immediate_get_material(RID p_immediate) const = 0; - virtual AABB immediate_get_aabb(RID p_immediate) const = 0; - - /* SKELETON API */ - - virtual RID skeleton_create() = 0; - virtual void skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) = 0; - virtual int skeleton_get_bone_count(RID p_skeleton) const = 0; - virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) = 0; - virtual Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const = 0; - virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) = 0; - virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const = 0; - virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) = 0; - - /* Light API */ - - virtual RID light_create(RS::LightType p_type) = 0; - - RID directional_light_create() { return light_create(RS::LIGHT_DIRECTIONAL); } - RID omni_light_create() { return light_create(RS::LIGHT_OMNI); } - RID spot_light_create() { return light_create(RS::LIGHT_SPOT); } - - virtual void light_set_color(RID p_light, const Color &p_color) = 0; - virtual void light_set_param(RID p_light, RS::LightParam p_param, float p_value) = 0; - virtual void light_set_shadow(RID p_light, bool p_enabled) = 0; - virtual void light_set_shadow_color(RID p_light, const Color &p_color) = 0; - virtual void light_set_projector(RID p_light, RID p_texture) = 0; - virtual void light_set_negative(RID p_light, bool p_enable) = 0; - virtual void light_set_cull_mask(RID p_light, uint32_t p_mask) = 0; - virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) = 0; - virtual void light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) = 0; - virtual void light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) = 0; - - virtual void light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) = 0; - - virtual void light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) = 0; - virtual void light_directional_set_blend_splits(RID p_light, bool p_enable) = 0; - virtual bool light_directional_get_blend_splits(RID p_light) const = 0; - virtual void light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode) = 0; - virtual RS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const = 0; - - virtual RS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light) = 0; - virtual RS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light) = 0; - - virtual bool light_has_shadow(RID p_light) const = 0; - - virtual RS::LightType light_get_type(RID p_light) const = 0; - virtual AABB light_get_aabb(RID p_light) const = 0; - virtual float light_get_param(RID p_light, RS::LightParam p_param) = 0; - virtual Color light_get_color(RID p_light) = 0; - virtual RS::LightBakeMode light_get_bake_mode(RID p_light) = 0; - virtual uint32_t light_get_max_sdfgi_cascade(RID p_light) = 0; - virtual uint64_t light_get_version(RID p_light) const = 0; - - /* PROBE API */ - - virtual RID reflection_probe_create() = 0; - - virtual void reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) = 0; - virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution) = 0; - virtual void reflection_probe_set_intensity(RID p_probe, float p_intensity) = 0; - virtual void reflection_probe_set_ambient_mode(RID p_probe, RS::ReflectionProbeAmbientMode p_mode) = 0; - virtual void reflection_probe_set_ambient_color(RID p_probe, const Color &p_color) = 0; - virtual void reflection_probe_set_ambient_energy(RID p_probe, float p_energy) = 0; - virtual void reflection_probe_set_max_distance(RID p_probe, float p_distance) = 0; - virtual void reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) = 0; - virtual void reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) = 0; - virtual void reflection_probe_set_as_interior(RID p_probe, bool p_enable) = 0; - virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) = 0; - virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) = 0; - virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) = 0; - - virtual AABB reflection_probe_get_aabb(RID p_probe) const = 0; - virtual RS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const = 0; - virtual uint32_t reflection_probe_get_cull_mask(RID p_probe) const = 0; - virtual Vector3 reflection_probe_get_extents(RID p_probe) const = 0; - virtual Vector3 reflection_probe_get_origin_offset(RID p_probe) const = 0; - virtual float reflection_probe_get_origin_max_distance(RID p_probe) const = 0; - virtual bool reflection_probe_renders_shadows(RID p_probe) const = 0; - - virtual void base_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) = 0; - virtual void skeleton_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) = 0; - - /* DECAL API */ - - virtual RID decal_create() = 0; - virtual void decal_set_extents(RID p_decal, const Vector3 &p_extents) = 0; - virtual void decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) = 0; - virtual void decal_set_emission_energy(RID p_decal, float p_energy) = 0; - virtual void decal_set_albedo_mix(RID p_decal, float p_mix) = 0; - virtual void decal_set_modulate(RID p_decal, const Color &p_modulate) = 0; - virtual void decal_set_cull_mask(RID p_decal, uint32_t p_layers) = 0; - virtual void decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) = 0; - virtual void decal_set_fade(RID p_decal, float p_above, float p_below) = 0; - virtual void decal_set_normal_fade(RID p_decal, float p_fade) = 0; - - virtual AABB decal_get_aabb(RID p_decal) const = 0; - - /* GI PROBE API */ - - virtual RID gi_probe_create() = 0; - - virtual void gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) = 0; - - virtual AABB gi_probe_get_bounds(RID p_gi_probe) const = 0; - virtual Vector3i gi_probe_get_octree_size(RID p_gi_probe) const = 0; - virtual Vector<uint8_t> gi_probe_get_octree_cells(RID p_gi_probe) const = 0; - virtual Vector<uint8_t> gi_probe_get_data_cells(RID p_gi_probe) const = 0; - virtual Vector<uint8_t> gi_probe_get_distance_field(RID p_gi_probe) const = 0; - - virtual Vector<int> gi_probe_get_level_counts(RID p_gi_probe) const = 0; - virtual Transform gi_probe_get_to_cell_xform(RID p_gi_probe) const = 0; - - virtual void gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) = 0; - virtual float gi_probe_get_dynamic_range(RID p_gi_probe) const = 0; - - virtual void gi_probe_set_propagation(RID p_gi_probe, float p_range) = 0; - virtual float gi_probe_get_propagation(RID p_gi_probe) const = 0; - - virtual void gi_probe_set_energy(RID p_gi_probe, float p_energy) = 0; - virtual float gi_probe_get_energy(RID p_gi_probe) const = 0; - - virtual void gi_probe_set_ao(RID p_gi_probe, float p_ao) = 0; - virtual float gi_probe_get_ao(RID p_gi_probe) const = 0; - - virtual void gi_probe_set_ao_size(RID p_gi_probe, float p_strength) = 0; - virtual float gi_probe_get_ao_size(RID p_gi_probe) const = 0; - - virtual void gi_probe_set_bias(RID p_gi_probe, float p_bias) = 0; - virtual float gi_probe_get_bias(RID p_gi_probe) const = 0; - - virtual void gi_probe_set_normal_bias(RID p_gi_probe, float p_range) = 0; - virtual float gi_probe_get_normal_bias(RID p_gi_probe) const = 0; - - virtual void gi_probe_set_interior(RID p_gi_probe, bool p_enable) = 0; - virtual bool gi_probe_is_interior(RID p_gi_probe) const = 0; - - virtual void gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) = 0; - virtual bool gi_probe_is_using_two_bounces(RID p_gi_probe) const = 0; - - virtual void gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) = 0; - virtual float gi_probe_get_anisotropy_strength(RID p_gi_probe) const = 0; - - virtual uint32_t gi_probe_get_version(RID p_probe) = 0; - - /* LIGHTMAP CAPTURE */ - - virtual RID lightmap_create() = 0; - - virtual void lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) = 0; - virtual void lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) = 0; - virtual void lightmap_set_probe_interior(RID p_lightmap, bool p_interior) = 0; - virtual void lightmap_set_probe_capture_data(RID p_lightmap, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) = 0; - virtual PackedVector3Array lightmap_get_probe_capture_points(RID p_lightmap) const = 0; - virtual PackedColorArray lightmap_get_probe_capture_sh(RID p_lightmap) const = 0; - virtual PackedInt32Array lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const = 0; - virtual PackedInt32Array lightmap_get_probe_capture_bsp_tree(RID p_lightmap) const = 0; - virtual AABB lightmap_get_aabb(RID p_lightmap) const = 0; - virtual void lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_point, Color *r_sh) = 0; - virtual bool lightmap_is_interior(RID p_lightmap) const = 0; - virtual void lightmap_set_probe_capture_update_speed(float p_speed) = 0; - virtual float lightmap_get_probe_capture_update_speed() const = 0; - - /* PARTICLES */ - - virtual RID particles_create() = 0; - - virtual void particles_set_emitting(RID p_particles, bool p_emitting) = 0; - virtual bool particles_get_emitting(RID p_particles) = 0; - - virtual void particles_set_amount(RID p_particles, int p_amount) = 0; - virtual void particles_set_lifetime(RID p_particles, float p_lifetime) = 0; - virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) = 0; - virtual void particles_set_pre_process_time(RID p_particles, float p_time) = 0; - virtual void particles_set_explosiveness_ratio(RID p_particles, float p_ratio) = 0; - virtual void particles_set_randomness_ratio(RID p_particles, float p_ratio) = 0; - virtual void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) = 0; - virtual void particles_set_speed_scale(RID p_particles, float p_scale) = 0; - virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable) = 0; - virtual void particles_set_process_material(RID p_particles, RID p_material) = 0; - virtual void particles_set_fixed_fps(RID p_particles, int p_fps) = 0; - virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) = 0; - virtual void particles_set_collision_base_size(RID p_particles, float p_size) = 0; - virtual void particles_restart(RID p_particles) = 0; - virtual void particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) = 0; - virtual void particles_set_subemitter(RID p_particles, RID p_subemitter_particles) = 0; - - virtual bool particles_is_inactive(RID p_particles) const = 0; - - virtual void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) = 0; - - virtual void particles_set_draw_passes(RID p_particles, int p_count) = 0; - virtual void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) = 0; - - virtual void particles_request_process(RID p_particles) = 0; - virtual AABB particles_get_current_aabb(RID p_particles) = 0; - virtual AABB particles_get_aabb(RID p_particles) const = 0; - - virtual void particles_set_emission_transform(RID p_particles, const Transform &p_transform) = 0; - - virtual int particles_get_draw_passes(RID p_particles) const = 0; - virtual RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const = 0; - - virtual void particles_set_view_axis(RID p_particles, const Vector3 &p_axis) = 0; - - virtual void particles_add_collision(RID p_particles, RasterizerScene::InstanceBase *p_instance) = 0; - virtual void particles_remove_collision(RID p_particles, RasterizerScene::InstanceBase *p_instance) = 0; - - virtual void update_particles() = 0; - - /* PARTICLES COLLISION */ - - virtual RID particles_collision_create() = 0; - virtual void particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) = 0; - virtual void particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) = 0; - virtual void particles_collision_set_sphere_radius(RID p_particles_collision, float p_radius) = 0; //for spheres - virtual void particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) = 0; //for non-spheres - virtual void particles_collision_set_attractor_strength(RID p_particles_collision, float p_strength) = 0; - virtual void particles_collision_set_attractor_directionality(RID p_particles_collision, float p_directionality) = 0; - virtual void particles_collision_set_attractor_attenuation(RID p_particles_collision, float p_curve) = 0; - virtual void particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) = 0; //for SDF and vector field, heightfield is dynamic - virtual void particles_collision_height_field_update(RID p_particles_collision) = 0; //for SDF and vector field - virtual void particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) = 0; //for SDF and vector field - virtual AABB particles_collision_get_aabb(RID p_particles_collision) const = 0; - virtual bool particles_collision_is_heightfield(RID p_particles_collision) const = 0; - virtual RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const = 0; - - /* GLOBAL VARIABLES */ - - virtual void global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value) = 0; - virtual void global_variable_remove(const StringName &p_name) = 0; - virtual Vector<StringName> global_variable_get_list() const = 0; - - virtual void global_variable_set(const StringName &p_name, const Variant &p_value) = 0; - virtual void global_variable_set_override(const StringName &p_name, const Variant &p_value) = 0; - virtual Variant global_variable_get(const StringName &p_name) const = 0; - virtual RS::GlobalVariableType global_variable_get_type(const StringName &p_name) const = 0; - - virtual void global_variables_load_settings(bool p_load_textures = true) = 0; - virtual void global_variables_clear() = 0; - - virtual int32_t global_variables_instance_allocate(RID p_instance) = 0; - virtual void global_variables_instance_free(RID p_instance) = 0; - virtual void global_variables_instance_update(RID p_instance, int p_index, const Variant &p_value) = 0; - - /* RENDER TARGET */ - - enum RenderTargetFlags { - RENDER_TARGET_TRANSPARENT, - RENDER_TARGET_DIRECT_TO_SCREEN, - RENDER_TARGET_FLAG_MAX - }; - - virtual RID render_target_create() = 0; - virtual void render_target_set_position(RID p_render_target, int p_x, int p_y) = 0; - virtual void render_target_set_size(RID p_render_target, int p_width, int p_height) = 0; - virtual RID render_target_get_texture(RID p_render_target) = 0; - virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) = 0; - virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) = 0; - virtual bool render_target_was_used(RID p_render_target) = 0; - virtual void render_target_set_as_unused(RID p_render_target) = 0; - - virtual void render_target_request_clear(RID p_render_target, const Color &p_clear_color) = 0; - virtual bool render_target_is_clear_requested(RID p_render_target) = 0; - virtual Color render_target_get_clear_request_color(RID p_render_target) = 0; - virtual void render_target_disable_clear_request(RID p_render_target) = 0; - virtual void render_target_do_clear_request(RID p_render_target) = 0; - - virtual void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) = 0; - virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const = 0; - - virtual RS::InstanceType get_base_type(RID p_rid) const = 0; - virtual bool free(RID p_rid) = 0; - - virtual bool has_os_feature(const String &p_feature) const = 0; - - virtual void update_dirty_resources() = 0; - - virtual void set_debug_generate_wireframes(bool p_generate) = 0; - - virtual void render_info_begin_capture() = 0; - virtual void render_info_end_capture() = 0; - virtual int get_captured_render_info(RS::RenderInfo p_info) = 0; - - virtual int get_render_info(RS::RenderInfo p_info) = 0; - virtual String get_video_adapter_name() const = 0; - virtual String get_video_adapter_vendor() const = 0; - - static RasterizerStorage *base_singleton; - - void set_default_clear_color(const Color &p_color) { - default_clear_color = p_color; - } - - Color get_default_clear_color() const { - return default_clear_color; - } -#define TIMESTAMP_BEGIN() \ - { \ - if (RSG::storage->capturing_timestamps) \ - RSG::storage->capture_timestamps_begin(); \ - } - -#define RENDER_TIMESTAMP(m_text) \ - { \ - if (RSG::storage->capturing_timestamps) \ - RSG::storage->capture_timestamp(m_text); \ - } - - bool capturing_timestamps = false; - - virtual void capture_timestamps_begin() = 0; - virtual void capture_timestamp(const String &p_name) = 0; - virtual uint32_t get_captured_timestamps_count() const = 0; - virtual uint64_t get_captured_timestamps_frame() const = 0; - virtual uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const = 0; - virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const = 0; - virtual String get_captured_timestamp_name(uint32_t p_index) const = 0; - - RasterizerStorage(); - virtual ~RasterizerStorage() {} -}; - -class RasterizerCanvas { -public: - static RasterizerCanvas *singleton; - - enum CanvasRectFlags { - CANVAS_RECT_REGION = 1, - CANVAS_RECT_TILE = 2, - CANVAS_RECT_FLIP_H = 4, - CANVAS_RECT_FLIP_V = 8, - CANVAS_RECT_TRANSPOSE = 16, - CANVAS_RECT_CLIP_UV = 32, - CANVAS_RECT_IS_GROUP = 64, - }; - - struct Light { - bool enabled; - Color color; - Transform2D xform; - float height; - float energy; - float scale; - int z_min; - int z_max; - int layer_min; - int layer_max; - int item_mask; - int item_shadow_mask; - float directional_distance; - RS::CanvasLightMode mode; - RS::CanvasLightBlendMode blend_mode; - RID texture; - Vector2 texture_offset; - RID canvas; - bool use_shadow; - int shadow_buffer_size; - RS::CanvasLightShadowFilter shadow_filter; - Color shadow_color; - float shadow_smooth; - - //void *texture_cache; // implementation dependent - Rect2 rect_cache; - Transform2D xform_cache; - float radius_cache; //used for shadow far plane - //CameraMatrix shadow_matrix_cache; - - Transform2D light_shader_xform; - //Vector2 light_shader_pos; - - Light *shadows_next_ptr; - Light *filter_next_ptr; - Light *next_ptr; - Light *directional_next_ptr; - - RID light_internal; - uint64_t version; - - int32_t render_index_cache; - - Light() { - version = 0; - enabled = true; - color = Color(1, 1, 1); - shadow_color = Color(0, 0, 0, 0); - height = 0; - z_min = -1024; - z_max = 1024; - layer_min = 0; - layer_max = 0; - item_mask = 1; - scale = 1.0; - energy = 1.0; - item_shadow_mask = 1; - mode = RS::CANVAS_LIGHT_MODE_POINT; - blend_mode = RS::CANVAS_LIGHT_BLEND_MODE_ADD; - // texture_cache = nullptr; - next_ptr = nullptr; - directional_next_ptr = nullptr; - filter_next_ptr = nullptr; - use_shadow = false; - shadow_buffer_size = 2048; - shadow_filter = RS::CANVAS_LIGHT_FILTER_NONE; - shadow_smooth = 0.0; - render_index_cache = -1; - directional_distance = 10000.0; - } - }; - - //easier wrap to avoid mistakes - - struct Item; - - typedef uint64_t PolygonID; - virtual PolygonID request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>()) = 0; - virtual void free_polygon(PolygonID p_polygon) = 0; - - //also easier to wrap to avoid mistakes - struct Polygon { - PolygonID polygon_id; - Rect2 rect_cache; - - _FORCE_INLINE_ void create(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>()) { - ERR_FAIL_COND(polygon_id != 0); - { - uint32_t pc = p_points.size(); - const Vector2 *v2 = p_points.ptr(); - rect_cache.position = *v2; - for (uint32_t i = 1; i < pc; i++) { - rect_cache.expand_to(v2[i]); - } - } - polygon_id = singleton->request_polygon(p_indices, p_points, p_colors, p_uvs, p_bones, p_weights); - } - - _FORCE_INLINE_ Polygon() { polygon_id = 0; } - _FORCE_INLINE_ ~Polygon() { - if (polygon_id) { - singleton->free_polygon(polygon_id); - } - } - }; - - //item - - struct Item { - //commands are allocated in blocks of 4k to improve performance - //and cache coherence. - //blocks always grow but never shrink. - - struct CommandBlock { - enum { - MAX_SIZE = 4096 - }; - uint32_t usage; - uint8_t *memory; - }; - - struct Command { - enum Type { - TYPE_RECT, - TYPE_NINEPATCH, - TYPE_POLYGON, - TYPE_PRIMITIVE, - TYPE_MESH, - TYPE_MULTIMESH, - TYPE_PARTICLES, - TYPE_TRANSFORM, - TYPE_CLIP_IGNORE, - }; - - Command *next; - Type type; - virtual ~Command() {} - }; - - struct CommandRect : public Command { - Rect2 rect; - Color modulate; - Rect2 source; - uint8_t flags; - - RID texture; - - CommandRect() { - flags = 0; - type = TYPE_RECT; - } - }; - - struct CommandNinePatch : public Command { - Rect2 rect; - Rect2 source; - float margin[4]; - bool draw_center; - Color color; - RS::NinePatchAxisMode axis_x; - RS::NinePatchAxisMode axis_y; - - RID texture; - - CommandNinePatch() { - draw_center = true; - type = TYPE_NINEPATCH; - } - }; - - struct CommandPolygon : public Command { - RS::PrimitiveType primitive; - Polygon polygon; - - RID texture; - - CommandPolygon() { - type = TYPE_POLYGON; - } - }; - - struct CommandPrimitive : public Command { - uint32_t point_count; - Vector2 points[4]; - Vector2 uvs[4]; - Color colors[4]; - - RID texture; - - CommandPrimitive() { - type = TYPE_PRIMITIVE; - } - }; - - struct CommandMesh : public Command { - RID mesh; - Transform2D transform; - Color modulate; - - RID texture; - - CommandMesh() { type = TYPE_MESH; } - }; - - struct CommandMultiMesh : public Command { - RID multimesh; - - RID texture; - - CommandMultiMesh() { type = TYPE_MULTIMESH; } - }; - - struct CommandParticles : public Command { - RID particles; - - RID texture; - - CommandParticles() { type = TYPE_PARTICLES; } - }; - - struct CommandTransform : public Command { - Transform2D xform; - CommandTransform() { type = TYPE_TRANSFORM; } - }; - - struct CommandClipIgnore : public Command { - bool ignore; - CommandClipIgnore() { - type = TYPE_CLIP_IGNORE; - ignore = false; - } - }; - - struct ViewportRender { - RenderingServer *owner; - void *udata; - Rect2 rect; - }; - - Transform2D xform; - bool clip; - bool visible; - bool behind; - bool update_when_visible; - - struct CanvasGroup { - RS::CanvasGroupMode mode; - bool fit_empty; - float fit_margin; - bool blur_mipmaps; - float clear_margin; - }; - - CanvasGroup *canvas_group = nullptr; - int light_mask; - int z_final; - - mutable bool custom_rect; - mutable bool rect_dirty; - mutable Rect2 rect; - RID material; - RID skeleton; - - Item *next; - - struct CopyBackBuffer { - Rect2 rect; - Rect2 screen_rect; - bool full; - }; - CopyBackBuffer *copy_back_buffer; - - Color final_modulate; - Transform2D final_transform; - Rect2 final_clip_rect; - Item *final_clip_owner; - Item *material_owner; - Item *canvas_group_owner; - ViewportRender *vp_render; - bool distance_field; - bool light_masked; - - Rect2 global_rect_cache; - - const Rect2 &get_rect() const { - if (custom_rect || (!rect_dirty && !update_when_visible)) { - return rect; - } - - //must update rect - - if (commands == nullptr) { - rect = Rect2(); - rect_dirty = false; - return rect; - } - - Transform2D xf; - bool found_xform = false; - bool first = true; - - const Item::Command *c = commands; - - while (c) { - Rect2 r; - - switch (c->type) { - case Item::Command::TYPE_RECT: { - const Item::CommandRect *crect = static_cast<const Item::CommandRect *>(c); - r = crect->rect; - - } break; - case Item::Command::TYPE_NINEPATCH: { - const Item::CommandNinePatch *style = static_cast<const Item::CommandNinePatch *>(c); - r = style->rect; - } break; - - case Item::Command::TYPE_POLYGON: { - const Item::CommandPolygon *polygon = static_cast<const Item::CommandPolygon *>(c); - r = polygon->polygon.rect_cache; - } break; - case Item::Command::TYPE_PRIMITIVE: { - const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(c); - for (uint32_t j = 0; j < primitive->point_count; j++) { - if (j == 0) { - r.position = primitive->points[0]; - } else { - r.expand_to(primitive->points[j]); - } - } - } break; - case Item::Command::TYPE_MESH: { - const Item::CommandMesh *mesh = static_cast<const Item::CommandMesh *>(c); - AABB aabb = RasterizerStorage::base_singleton->mesh_get_aabb(mesh->mesh, RID()); - - r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y); - - } break; - case Item::Command::TYPE_MULTIMESH: { - const Item::CommandMultiMesh *multimesh = static_cast<const Item::CommandMultiMesh *>(c); - AABB aabb = RasterizerStorage::base_singleton->multimesh_get_aabb(multimesh->multimesh); - - r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y); - - } break; - case Item::Command::TYPE_PARTICLES: { - const Item::CommandParticles *particles_cmd = static_cast<const Item::CommandParticles *>(c); - if (particles_cmd->particles.is_valid()) { - AABB aabb = RasterizerStorage::base_singleton->particles_get_aabb(particles_cmd->particles); - r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y); - } - - } break; - case Item::Command::TYPE_TRANSFORM: { - const Item::CommandTransform *transform = static_cast<const Item::CommandTransform *>(c); - xf = transform->xform; - found_xform = true; - [[fallthrough]]; - } - default: { - c = c->next; - continue; - } - } - - if (found_xform) { - r = xf.xform(r); - found_xform = false; - } - - if (first) { - rect = r; - first = false; - } else { - rect = rect.merge(r); - } - c = c->next; - } - - rect_dirty = false; - return rect; - } - - Command *commands; - Command *last_command; - Vector<CommandBlock> blocks; - uint32_t current_block; - - template <class T> - T *alloc_command() { - T *command; - if (commands == nullptr) { - // As the most common use case of canvas items is to - // use only one command, the first is done with it's - // own allocation. The rest of them use blocks. - command = memnew(T); - command->next = nullptr; - commands = command; - last_command = command; - } else { - //Subsequent commands go into a block. - - while (true) { - if (unlikely(current_block == (uint32_t)blocks.size())) { - // If we need more blocks, we allocate them - // (they won't be freed until this CanvasItem is - // deleted, though). - CommandBlock cb; - cb.memory = (uint8_t *)memalloc(CommandBlock::MAX_SIZE); - cb.usage = 0; - blocks.push_back(cb); - } - - CommandBlock *c = &blocks.write[current_block]; - size_t space_left = CommandBlock::MAX_SIZE - c->usage; - if (space_left < sizeof(T)) { - current_block++; - continue; - } - - //allocate block and add to the linked list - void *memory = c->memory + c->usage; - command = memnew_placement(memory, T); - command->next = nullptr; - last_command->next = command; - last_command = command; - c->usage += sizeof(T); - break; - } - } - - rect_dirty = true; - return command; - } - - void clear() { - // The first one is always allocated on heap - // the rest go in the blocks - Command *c = commands; - while (c) { - Command *n = c->next; - if (c == commands) { - memdelete(commands); - commands = nullptr; - } else { - c->~Command(); - } - c = n; - } - { - uint32_t cbc = MIN((current_block + 1), (uint32_t)blocks.size()); - CommandBlock *blockptr = blocks.ptrw(); - for (uint32_t i = 0; i < cbc; i++) { - blockptr[i].usage = 0; - } - } - - last_command = nullptr; - commands = nullptr; - current_block = 0; - clip = false; - rect_dirty = true; - final_clip_owner = nullptr; - material_owner = nullptr; - light_masked = false; - } - - RS::CanvasItemTextureFilter texture_filter; - RS::CanvasItemTextureRepeat texture_repeat; - - Item() { - commands = nullptr; - last_command = nullptr; - current_block = 0; - light_mask = 1; - vp_render = nullptr; - next = nullptr; - final_clip_owner = nullptr; - canvas_group_owner = nullptr; - clip = false; - final_modulate = Color(1, 1, 1, 1); - visible = true; - rect_dirty = true; - custom_rect = false; - behind = false; - material_owner = nullptr; - copy_back_buffer = nullptr; - distance_field = false; - light_masked = false; - update_when_visible = false; - z_final = 0; - texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT; - texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT; - } - virtual ~Item() { - clear(); - for (int i = 0; i < blocks.size(); i++) { - memfree(blocks[i].memory); - } - if (copy_back_buffer) { - memdelete(copy_back_buffer); - } - } - }; - - virtual void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) = 0; - virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) = 0; - - struct LightOccluderInstance { - bool enabled; - RID canvas; - RID polygon; - RID occluder; - Rect2 aabb_cache; - Transform2D xform; - Transform2D xform_cache; - int light_mask; - bool sdf_collision; - RS::CanvasOccluderPolygonCullMode cull_cache; - - LightOccluderInstance *next; - - LightOccluderInstance() { - enabled = true; - sdf_collision = false; - next = nullptr; - light_mask = 1; - cull_cache = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED; - } - }; - - virtual RID light_create() = 0; - virtual void light_set_texture(RID p_rid, RID p_texture) = 0; - virtual void light_set_use_shadow(RID p_rid, bool p_enable) = 0; - virtual void light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) = 0; - virtual void light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders) = 0; - - virtual void render_sdf(RID p_render_target, LightOccluderInstance *p_occluders) = 0; - - virtual RID occluder_polygon_create() = 0; - virtual void occluder_polygon_set_shape(RID p_occluder, const Vector<Vector2> &p_points, bool p_closed) = 0; - virtual void occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) = 0; - virtual void set_shadow_texture_size(int p_size) = 0; - - virtual void draw_window_margins(int *p_margins, RID *p_margin_textures) = 0; - - virtual bool free(RID p_rid) = 0; - virtual void update() = 0; - - RasterizerCanvas() { singleton = this; } - virtual ~RasterizerCanvas() {} -}; - -class Rasterizer { -protected: - static Rasterizer *(*_create_func)(); - -public: - static Rasterizer *create(); - - virtual RasterizerStorage *get_storage() = 0; - virtual RasterizerCanvas *get_canvas() = 0; - virtual RasterizerScene *get_scene() = 0; - - virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true) = 0; - - virtual void initialize() = 0; - virtual void begin_frame(double frame_step) = 0; - - struct BlitToScreen { - RID render_target; - Rect2i rect; - //lens distorted parameters for VR should go here - }; - - virtual void prepare_for_blitting_render_targets() = 0; - virtual void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) = 0; - - virtual void end_frame(bool p_swap_buffers) = 0; - virtual void finalize() = 0; - virtual uint64_t get_frame_number() const = 0; - virtual float get_frame_delta_time() const = 0; - - virtual bool is_low_end() const = 0; - - virtual ~Rasterizer() {} -}; - -#endif // RASTERIZER_H diff --git a/servers/rendering/rasterizer_rd/light_cluster_builder.cpp b/servers/rendering/rasterizer_rd/light_cluster_builder.cpp deleted file mode 100644 index efb48e6df7..0000000000 --- a/servers/rendering/rasterizer_rd/light_cluster_builder.cpp +++ /dev/null @@ -1,252 +0,0 @@ -/*************************************************************************/ -/* light_cluster_builder.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "light_cluster_builder.h" - -void LightClusterBuilder::begin(const Transform &p_view_transform, const CameraMatrix &p_cam_projection) { - view_xform = p_view_transform; - projection = p_cam_projection; - z_near = -projection.get_z_near(); - z_far = -projection.get_z_far(); - - //reset counts - light_count = 0; - refprobe_count = 0; - decal_count = 0; - item_count = 0; - sort_id_count = 0; -} - -void LightClusterBuilder::bake_cluster() { - float slice_depth = (z_near - z_far) / depth; - - uint8_t *cluster_dataw = cluster_data.ptrw(); - Cell *cluster_data_ptr = (Cell *)cluster_dataw; - //clear the cluster - zeromem(cluster_data_ptr, (width * height * depth * sizeof(Cell))); - - /* Step 1, create cell positions and count them */ - - for (uint32_t i = 0; i < item_count; i++) { - const Item &item = items[i]; - - int from_slice = Math::floor((z_near - (item.aabb.position.z + item.aabb.size.z)) / slice_depth); - int to_slice = Math::floor((z_near - item.aabb.position.z) / slice_depth); - - if (from_slice >= (int)depth || to_slice < 0) { - continue; //sorry no go - } - - from_slice = MAX(0, from_slice); - to_slice = MIN((int)depth - 1, to_slice); - - for (int j = from_slice; j <= to_slice; j++) { - Vector3 min = item.aabb.position; - Vector3 max = item.aabb.position + item.aabb.size; - - float limit_near = MIN((z_near - slice_depth * j), max.z); - float limit_far = MAX((z_near - slice_depth * (j + 1)), min.z); - - max.z = limit_near; - min.z = limit_near; - - Vector3 proj_min = projection.xform(min); - Vector3 proj_max = projection.xform(max); - - int near_from_x = int(Math::floor((proj_min.x * 0.5 + 0.5) * width)); - int near_from_y = int(Math::floor((-proj_max.y * 0.5 + 0.5) * height)); - int near_to_x = int(Math::floor((proj_max.x * 0.5 + 0.5) * width)); - int near_to_y = int(Math::floor((-proj_min.y * 0.5 + 0.5) * height)); - - max.z = limit_far; - min.z = limit_far; - - proj_min = projection.xform(min); - proj_max = projection.xform(max); - - int far_from_x = int(Math::floor((proj_min.x * 0.5 + 0.5) * width)); - int far_from_y = int(Math::floor((-proj_max.y * 0.5 + 0.5) * height)); - int far_to_x = int(Math::floor((proj_max.x * 0.5 + 0.5) * width)); - int far_to_y = int(Math::floor((-proj_min.y * 0.5 + 0.5) * height)); - - //print_line(itos(j) + " near - " + Vector2i(near_from_x, near_from_y) + " -> " + Vector2i(near_to_x, near_to_y)); - //print_line(itos(j) + " far - " + Vector2i(far_from_x, far_from_y) + " -> " + Vector2i(far_to_x, far_to_y)); - - int from_x = MIN(near_from_x, far_from_x); - int from_y = MIN(near_from_y, far_from_y); - int to_x = MAX(near_to_x, far_to_x); - int to_y = MAX(near_to_y, far_to_y); - - if (from_x >= (int)width || to_x < 0 || from_y >= (int)height || to_y < 0) { - continue; - } - - int sx = MAX(0, from_x); - int sy = MAX(0, from_y); - int dx = MIN((int)width - 1, to_x); - int dy = MIN((int)height - 1, to_y); - - //print_line(itos(j) + " - " + Vector2i(sx, sy) + " -> " + Vector2i(dx, dy)); - - for (int x = sx; x <= dx; x++) { - for (int y = sy; y <= dy; y++) { - uint32_t offset = j * (width * height) + y * width + x; - - if (unlikely(sort_id_count == sort_id_max)) { - sort_id_max = nearest_power_of_2_templated(sort_id_max + 1); - sort_ids = (SortID *)memrealloc(sort_ids, sizeof(SortID) * sort_id_max); - if (ids.size()) { - ids.resize(sort_id_max); - RD::get_singleton()->free(items_buffer); - items_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * sort_id_max); - } - } - - sort_ids[sort_id_count].cell_index = offset; - sort_ids[sort_id_count].item_index = item.index; - sort_ids[sort_id_count].item_type = item.type; - - sort_id_count++; - - //for now, only count - cluster_data_ptr[offset].item_pointers[item.type]++; - //print_line("at offset " + itos(offset) + " value: " + itos(cluster_data_ptr[offset].item_pointers[item.type])); - } - } - } - } - - /* Step 2, Assign pointers (and reset counters) */ - - uint32_t offset = 0; - for (uint32_t i = 0; i < (width * height * depth); i++) { - for (int j = 0; j < ITEM_TYPE_MAX; j++) { - uint32_t count = cluster_data_ptr[i].item_pointers[j]; //save count - cluster_data_ptr[i].item_pointers[j] = offset; //replace count by pointer - offset += count; //increase offset by count; - } - } - - //print_line("offset: " + itos(offset)); - /* Step 3, Place item lists */ - - uint32_t *ids_ptr = ids.ptrw(); - - for (uint32_t i = 0; i < sort_id_count; i++) { - const SortID &id = sort_ids[i]; - Cell &cell = cluster_data_ptr[id.cell_index]; - uint32_t pointer = cell.item_pointers[id.item_type] & POINTER_MASK; - uint32_t counter = cell.item_pointers[id.item_type] >> COUNTER_SHIFT; - ids_ptr[pointer + counter] = id.item_index; - - cell.item_pointers[id.item_type] = pointer | ((counter + 1) << COUNTER_SHIFT); - } - - RD::get_singleton()->texture_update(cluster_texture, 0, cluster_data, true); - RD::get_singleton()->buffer_update(items_buffer, 0, offset * sizeof(uint32_t), ids_ptr, true); -} - -void LightClusterBuilder::setup(uint32_t p_width, uint32_t p_height, uint32_t p_depth) { - if (width == p_width && height == p_height && depth == p_depth) { - return; - } - if (cluster_texture.is_valid()) { - RD::get_singleton()->free(cluster_texture); - } - - width = p_width; - height = p_height; - depth = p_depth; - - cluster_data.resize(width * height * depth * sizeof(Cell)); - - { - RD::TextureFormat tf; - tf.format = RD::DATA_FORMAT_R32G32B32A32_UINT; - tf.type = RD::TEXTURE_TYPE_3D; - tf.width = width; - tf.height = height; - tf.depth = depth; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; - - cluster_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); - } -} - -RID LightClusterBuilder::get_cluster_texture() const { - return cluster_texture; -} - -RID LightClusterBuilder::get_cluster_indices_buffer() const { - return items_buffer; -} - -LightClusterBuilder::LightClusterBuilder() { - //initialize accumulators to something - lights = (LightData *)memalloc(sizeof(LightData) * 1024); - light_max = 1024; - - refprobes = (OrientedBoxData *)memalloc(sizeof(OrientedBoxData) * 1024); - refprobe_max = 1024; - - decals = (OrientedBoxData *)memalloc(sizeof(OrientedBoxData) * 1024); - decal_max = 1024; - - items = (Item *)memalloc(sizeof(Item) * 1024); - item_max = 1024; - - sort_ids = (SortID *)memalloc(sizeof(SortID) * 1024); - ids.resize(2014); - items_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 1024); - item_max = 1024; -} - -LightClusterBuilder::~LightClusterBuilder() { - if (cluster_data.size()) { - RD::get_singleton()->free(cluster_texture); - } - - if (lights) { - memfree(lights); - } - if (refprobes) { - memfree(refprobes); - } - if (decals) { - memfree(decals); - } - if (items) { - memfree(items); - } - if (sort_ids) { - memfree(sort_ids); - RD::get_singleton()->free(items_buffer); - } -} diff --git a/servers/rendering/rasterizer_rd/light_cluster_builder.h b/servers/rendering/rasterizer_rd/light_cluster_builder.h deleted file mode 100644 index b1da083dad..0000000000 --- a/servers/rendering/rasterizer_rd/light_cluster_builder.h +++ /dev/null @@ -1,290 +0,0 @@ -/*************************************************************************/ -/* light_cluster_builder.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef LIGHT_CLUSTER_BUILDER_H -#define LIGHT_CLUSTER_BUILDER_H - -#include "servers/rendering/rasterizer_rd/rasterizer_storage_rd.h" - -class LightClusterBuilder { -public: - enum LightType { - LIGHT_TYPE_OMNI, - LIGHT_TYPE_SPOT - }; - - enum ItemType { - ITEM_TYPE_OMNI_LIGHT, - ITEM_TYPE_SPOT_LIGHT, - ITEM_TYPE_REFLECTION_PROBE, - ITEM_TYPE_DECAL, - ITEM_TYPE_MAX //should always be 4 - }; - - enum { - COUNTER_SHIFT = 20, //one million total ids - POINTER_MASK = (1 << COUNTER_SHIFT) - 1, - COUNTER_MASK = 0xfff // 4096 items per cell - }; - -private: - struct LightData { - float position[3]; - uint32_t type; - float radius; - float spot_aperture; - uint32_t pad[2]; - }; - - uint32_t light_count = 0; - uint32_t light_max = 0; - LightData *lights = nullptr; - - struct OrientedBoxData { - float position[3]; - uint32_t pad; - float x_axis[3]; - uint32_t pad2; - float y_axis[3]; - uint32_t pad3; - float z_axis[3]; - uint32_t pad4; - }; - - uint32_t refprobe_count = 0; - uint32_t refprobe_max = 0; - OrientedBoxData *refprobes = nullptr; - - uint32_t decal_count = 0; - uint32_t decal_max = 0; - OrientedBoxData *decals = nullptr; - - struct Item { - AABB aabb; - ItemType type; - uint32_t index; - }; - - Item *items = nullptr; - uint32_t item_count = 0; - uint32_t item_max = 0; - - uint32_t width = 0; - uint32_t height = 0; - uint32_t depth = 0; - - struct Cell { - uint32_t item_pointers[ITEM_TYPE_MAX]; - }; - - Vector<uint8_t> cluster_data; - RID cluster_texture; - - struct SortID { - uint32_t cell_index; - uint32_t item_index; - ItemType item_type; - }; - - SortID *sort_ids = nullptr; - Vector<uint32_t> ids; - uint32_t sort_id_count = 0; - uint32_t sort_id_max = 0; - RID items_buffer; - - Transform view_xform; - CameraMatrix projection; - float z_far = 0; - float z_near = 0; - - _FORCE_INLINE_ void _add_item(const AABB &p_aabb, ItemType p_type, uint32_t p_index) { - if (unlikely(item_count == item_max)) { - item_max = nearest_power_of_2_templated(item_max + 1); - items = (Item *)memrealloc(items, sizeof(Item) * item_max); - } - - Item &item = items[item_count]; - item.aabb = p_aabb; - item.index = p_index; - item.type = p_type; - item_count++; - } - -public: - void begin(const Transform &p_view_transform, const CameraMatrix &p_cam_projection); - - _FORCE_INLINE_ void add_light(LightType p_type, const Transform &p_transform, float p_radius, float p_spot_aperture) { - if (unlikely(light_count == light_max)) { - light_max = nearest_power_of_2_templated(light_max + 1); - lights = (LightData *)memrealloc(lights, sizeof(LightData) * light_max); - } - - LightData &ld = lights[light_count]; - ld.type = p_type; - ld.position[0] = p_transform.origin.x; - ld.position[1] = p_transform.origin.y; - ld.position[2] = p_transform.origin.z; - ld.radius = p_radius; - ld.spot_aperture = p_spot_aperture; - - Transform xform = view_xform * p_transform; - - ld.radius *= xform.basis.get_uniform_scale(); - - AABB aabb; - - switch (p_type) { - case LIGHT_TYPE_OMNI: { - aabb.position = xform.origin; - aabb.size = Vector3(ld.radius, ld.radius, ld.radius); - aabb.position -= aabb.size; - aabb.size *= 2.0; - - _add_item(aabb, ITEM_TYPE_OMNI_LIGHT, light_count); - } break; - case LIGHT_TYPE_SPOT: { - float r = ld.radius; - real_t len = Math::tan(Math::deg2rad(ld.spot_aperture)) * r; - - aabb.position = xform.origin; - aabb.expand_to(xform.xform(Vector3(len, len, -r))); - aabb.expand_to(xform.xform(Vector3(-len, len, -r))); - aabb.expand_to(xform.xform(Vector3(-len, -len, -r))); - aabb.expand_to(xform.xform(Vector3(len, -len, -r))); - _add_item(aabb, ITEM_TYPE_SPOT_LIGHT, light_count); - } break; - } - - light_count++; - } - - _FORCE_INLINE_ void add_reflection_probe(const Transform &p_transform, const Vector3 &p_half_extents) { - if (unlikely(refprobe_count == refprobe_max)) { - refprobe_max = nearest_power_of_2_templated(refprobe_max + 1); - refprobes = (OrientedBoxData *)memrealloc(refprobes, sizeof(OrientedBoxData) * refprobe_max); - } - - Transform xform = view_xform * p_transform; - - OrientedBoxData &rp = refprobes[refprobe_count]; - Vector3 origin = xform.origin; - rp.position[0] = origin.x; - rp.position[1] = origin.y; - rp.position[2] = origin.z; - - Vector3 x_axis = xform.basis.get_axis(0) * p_half_extents.x; - rp.x_axis[0] = x_axis.x; - rp.x_axis[1] = x_axis.y; - rp.x_axis[2] = x_axis.z; - - Vector3 y_axis = xform.basis.get_axis(1) * p_half_extents.y; - rp.y_axis[0] = y_axis.x; - rp.y_axis[1] = y_axis.y; - rp.y_axis[2] = y_axis.z; - - Vector3 z_axis = xform.basis.get_axis(2) * p_half_extents.z; - rp.z_axis[0] = z_axis.x; - rp.z_axis[1] = z_axis.y; - rp.z_axis[2] = z_axis.z; - - AABB aabb; - - aabb.position = origin + x_axis + y_axis + z_axis; - aabb.expand_to(origin + x_axis + y_axis - z_axis); - aabb.expand_to(origin + x_axis - y_axis + z_axis); - aabb.expand_to(origin + x_axis - y_axis - z_axis); - aabb.expand_to(origin - x_axis + y_axis + z_axis); - aabb.expand_to(origin - x_axis + y_axis - z_axis); - aabb.expand_to(origin - x_axis - y_axis + z_axis); - aabb.expand_to(origin - x_axis - y_axis - z_axis); - - _add_item(aabb, ITEM_TYPE_REFLECTION_PROBE, refprobe_count); - - refprobe_count++; - } - - _FORCE_INLINE_ void add_decal(const Transform &p_transform, const Vector3 &p_half_extents) { - if (unlikely(decal_count == decal_max)) { - decal_max = nearest_power_of_2_templated(decal_max + 1); - decals = (OrientedBoxData *)memrealloc(decals, sizeof(OrientedBoxData) * decal_max); - } - - Transform xform = view_xform * p_transform; - - OrientedBoxData &dc = decals[decal_count]; - - Vector3 origin = xform.origin; - dc.position[0] = origin.x; - dc.position[1] = origin.y; - dc.position[2] = origin.z; - - Vector3 x_axis = xform.basis.get_axis(0) * p_half_extents.x; - dc.x_axis[0] = x_axis.x; - dc.x_axis[1] = x_axis.y; - dc.x_axis[2] = x_axis.z; - - Vector3 y_axis = xform.basis.get_axis(1) * p_half_extents.y; - dc.y_axis[0] = y_axis.x; - dc.y_axis[1] = y_axis.y; - dc.y_axis[2] = y_axis.z; - - Vector3 z_axis = xform.basis.get_axis(2) * p_half_extents.z; - dc.z_axis[0] = z_axis.x; - dc.z_axis[1] = z_axis.y; - dc.z_axis[2] = z_axis.z; - - AABB aabb; - - aabb.position = origin + x_axis + y_axis + z_axis; - aabb.expand_to(origin + x_axis + y_axis - z_axis); - aabb.expand_to(origin + x_axis - y_axis + z_axis); - aabb.expand_to(origin + x_axis - y_axis - z_axis); - aabb.expand_to(origin - x_axis + y_axis + z_axis); - aabb.expand_to(origin - x_axis + y_axis - z_axis); - aabb.expand_to(origin - x_axis - y_axis + z_axis); - aabb.expand_to(origin - x_axis - y_axis - z_axis); - - _add_item(aabb, ITEM_TYPE_DECAL, decal_count); - - decal_count++; - } - - void bake_cluster(); - - void setup(uint32_t p_width, uint32_t p_height, uint32_t p_depth); - - RID get_cluster_texture() const; - RID get_cluster_indices_buffer() const; - - LightClusterBuilder(); - ~LightClusterBuilder(); -}; - -#endif // LIGHT_CLUSTER_BUILDER_H diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h deleted file mode 100644 index db083a75cc..0000000000 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h +++ /dev/null @@ -1,602 +0,0 @@ -/*************************************************************************/ -/* rasterizer_scene_high_end_rd.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef RASTERIZER_SCENE_HIGHEND_RD_H -#define RASTERIZER_SCENE_HIGHEND_RD_H - -#include "servers/rendering/rasterizer_rd/rasterizer_scene_rd.h" -#include "servers/rendering/rasterizer_rd/rasterizer_storage_rd.h" -#include "servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h" -#include "servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl.gen.h" - -class RasterizerSceneHighEndRD : public RasterizerSceneRD { - enum { - SCENE_UNIFORM_SET = 0, - RADIANCE_UNIFORM_SET = 1, - VIEW_DEPENDANT_UNIFORM_SET = 2, - RENDER_BUFFERS_UNIFORM_SET = 3, - TRANSFORMS_UNIFORM_SET = 4, - MATERIAL_UNIFORM_SET = 5 - }; - - enum { - SDFGI_MAX_CASCADES = 8, - MAX_GI_PROBES = 8 - }; - - /* Scene Shader */ - - enum ShaderVersion { - SHADER_VERSION_DEPTH_PASS, - SHADER_VERSION_DEPTH_PASS_DP, - SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS, - SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE, - SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL, - SHADER_VERSION_DEPTH_PASS_WITH_SDF, - SHADER_VERSION_COLOR_PASS, - SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI, - SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR, - SHADER_VERSION_LIGHTMAP_COLOR_PASS, - SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR, - SHADER_VERSION_MAX - }; - - struct { - SceneHighEndShaderRD scene_shader; - ShaderCompilerRD compiler; - } shader; - - RasterizerStorageRD *storage; - - /* Material */ - - struct ShaderData : public RasterizerStorageRD::ShaderData { - enum BlendMode { //used internally - BLEND_MODE_MIX, - BLEND_MODE_ADD, - BLEND_MODE_SUB, - BLEND_MODE_MUL, - BLEND_MODE_ALPHA_TO_COVERAGE - }; - - enum DepthDraw { - DEPTH_DRAW_DISABLED, - DEPTH_DRAW_OPAQUE, - DEPTH_DRAW_ALWAYS - }; - - enum DepthTest { - DEPTH_TEST_DISABLED, - DEPTH_TEST_ENABLED - }; - - enum Cull { - CULL_DISABLED, - CULL_FRONT, - CULL_BACK - }; - - enum CullVariant { - CULL_VARIANT_NORMAL, - CULL_VARIANT_REVERSED, - CULL_VARIANT_DOUBLE_SIDED, - CULL_VARIANT_MAX - - }; - - enum AlphaAntiAliasing { - ALPHA_ANTIALIASING_OFF, - ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE, - ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE - }; - - bool valid; - RID version; - uint32_t vertex_input_mask; - RenderPipelineVertexFormatCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][SHADER_VERSION_MAX]; - - String path; - - Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms; - Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms; - - Vector<uint32_t> ubo_offsets; - uint32_t ubo_size; - - String code; - Map<StringName, RID> default_texture_params; - - DepthDraw depth_draw; - DepthTest depth_test; - - bool uses_point_size; - bool uses_alpha; - bool uses_blend_alpha; - bool uses_alpha_clip; - bool uses_depth_pre_pass; - bool uses_discard; - bool uses_roughness; - bool uses_normal; - - bool unshaded; - bool uses_vertex; - bool uses_sss; - bool uses_transmittance; - bool uses_screen_texture; - bool uses_depth_texture; - bool uses_normal_texture; - bool uses_time; - bool writes_modelview_or_projection; - bool uses_world_coordinates; - - uint64_t last_pass = 0; - uint32_t index = 0; - - virtual void set_code(const String &p_Code); - virtual void set_default_texture_param(const StringName &p_name, RID p_texture); - virtual void get_param_list(List<PropertyInfo> *p_param_list) const; - void get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const; - - virtual bool is_param_texture(const StringName &p_param) const; - virtual bool is_animated() const; - virtual bool casts_shadows() const; - virtual Variant get_default_parameter(const StringName &p_parameter) const; - ShaderData(); - virtual ~ShaderData(); - }; - - RasterizerStorageRD::ShaderData *_create_shader_func(); - static RasterizerStorageRD::ShaderData *_create_shader_funcs() { - return static_cast<RasterizerSceneHighEndRD *>(singleton)->_create_shader_func(); - } - - struct MaterialData : public RasterizerStorageRD::MaterialData { - uint64_t last_frame; - ShaderData *shader_data; - RID uniform_buffer; - RID uniform_set; - Vector<RID> texture_cache; - Vector<uint8_t> ubo_data; - uint64_t last_pass = 0; - uint32_t index = 0; - RID next_pass; - uint8_t priority; - virtual void set_render_priority(int p_priority); - virtual void set_next_pass(RID p_pass); - virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); - virtual ~MaterialData(); - }; - - RasterizerStorageRD::MaterialData *_create_material_func(ShaderData *p_shader); - static RasterizerStorageRD::MaterialData *_create_material_funcs(RasterizerStorageRD::ShaderData *p_shader) { - return static_cast<RasterizerSceneHighEndRD *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader)); - } - - /* Push Constant */ - - struct PushConstant { - uint32_t index; - uint32_t pad; - float bake_uv2_offset[2]; - }; - - /* Framebuffer */ - - struct RenderBufferDataHighEnd : public RenderBufferData { - //for rendering, may be MSAAd - - RID color; - RID depth; - RID specular; - RID normal_roughness_buffer; - RID giprobe_buffer; - - RID ambient_buffer; - RID reflection_buffer; - - RS::ViewportMSAA msaa; - RD::TextureSamples texture_samples; - - RID color_msaa; - RID depth_msaa; - RID specular_msaa; - RID normal_roughness_buffer_msaa; - RID roughness_buffer_msaa; - RID giprobe_buffer_msaa; - - RID depth_fb; - RID depth_normal_roughness_fb; - RID depth_normal_roughness_giprobe_fb; - RID color_fb; - RID color_specular_fb; - RID specular_only_fb; - int width, height; - - RID render_sdfgi_uniform_set; - void ensure_specular(); - void ensure_gi(); - void ensure_giprobe(); - void clear(); - virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa); - - RID uniform_set; - - ~RenderBufferDataHighEnd(); - }; - - virtual RenderBufferData *_create_render_buffer_data(); - void _allocate_normal_roughness_texture(RenderBufferDataHighEnd *rb); - - RID shadow_sampler; - RID render_base_uniform_set; - RID view_dependant_uniform_set; - - uint64_t lightmap_texture_array_version = 0xFFFFFFFF; - - virtual void _base_uniforms_changed(); - void _render_buffers_clear_uniform_set(RenderBufferDataHighEnd *rb); - virtual void _render_buffers_uniform_set_changed(RID p_render_buffers); - virtual RID _render_buffers_get_normal_texture(RID p_render_buffers); - virtual RID _render_buffers_get_ambient_texture(RID p_render_buffers); - virtual RID _render_buffers_get_reflection_texture(RID p_render_buffers); - - void _update_render_base_uniform_set(); - void _setup_view_dependant_uniform_set(RID p_shadow_atlas, RID p_reflection_atlas, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count); - void _update_render_buffers_uniform_set(RID p_render_buffers); - - struct LightmapData { - float normal_xform[12]; - }; - - struct LightmapCaptureData { - float sh[9 * 4]; - }; - - enum { - INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 6, - INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 7, - INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 8, - INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 9, - INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 10, - INSTANCE_DATA_FLAG_USE_GIPROBE = 1 << 11, - INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12, - INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13, - INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14, - INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA = 1 << 15, - INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT = 16, - INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_MASK = 0x7, - INSTANCE_DATA_FLAG_SKELETON = 1 << 19, - }; - - struct InstanceData { - float transform[16]; - float normal_transform[16]; - uint32_t flags; - uint32_t instance_uniforms_ofs; //instance_offset in instancing/skeleton buffer - uint32_t gi_offset; //GI information when using lightmapping (VCT or lightmap) - uint32_t mask; - float lightmap_uv_scale[4]; - }; - - struct SceneState { - struct UBO { - float projection_matrix[16]; - float inv_projection_matrix[16]; - - float camera_matrix[16]; - float inv_camera_matrix[16]; - - float viewport_size[2]; - float screen_pixel_size[2]; - - float directional_penumbra_shadow_kernel[128]; //32 vec4s - float directional_soft_shadow_kernel[128]; - float penumbra_shadow_kernel[128]; - float soft_shadow_kernel[128]; - - uint32_t directional_penumbra_shadow_samples; - uint32_t directional_soft_shadow_samples; - uint32_t penumbra_shadow_samples; - uint32_t soft_shadow_samples; - - float ambient_light_color_energy[4]; - - float ambient_color_sky_mix; - uint32_t use_ambient_light; - uint32_t use_ambient_cubemap; - uint32_t use_reflection_cubemap; - - float radiance_inverse_xform[12]; - - float shadow_atlas_pixel_size[2]; - float directional_shadow_pixel_size[2]; - - uint32_t directional_light_count; - float dual_paraboloid_side; - float z_far; - float z_near; - - uint32_t ssao_enabled; - float ssao_light_affect; - float ssao_ao_affect; - uint32_t roughness_limiter_enabled; - - float roughness_limiter_amount; - float roughness_limiter_limit; - uint32_t roughness_limiter_pad[2]; - - float ao_color[4]; - - float sdf_to_bounds[16]; - - int32_t sdf_offset[3]; - uint32_t material_uv2_mode; - - int32_t sdf_size[3]; - uint32_t gi_upscale_for_msaa; - - uint32_t volumetric_fog_enabled; - float volumetric_fog_inv_length; - float volumetric_fog_detail_spread; - uint32_t volumetric_fog_pad; - - // Fog - uint32_t fog_enabled; - float fog_density; - float fog_height; - float fog_height_density; - - float fog_light_color[3]; - float fog_sun_scatter; - - float fog_aerial_perspective; - - float time; - float reflection_multiplier; - - uint32_t pancake_shadows; - }; - - UBO ubo; - - RID uniform_buffer; - - LightmapData *lightmaps; - uint32_t max_lightmaps; - RID lightmap_buffer; - - LightmapCaptureData *lightmap_captures; - uint32_t max_lightmap_captures; - RID lightmap_capture_buffer; - - RID instance_buffer; - InstanceData *instances; - uint32_t max_instances; - - bool used_screen_texture = false; - bool used_normal_texture = false; - bool used_depth_texture = false; - bool used_sss = false; - uint32_t current_shader_index = 0; - uint32_t current_material_index = 0; - - } scene_state; - - /* Render List */ - - struct RenderList { - int max_elements; - - struct Element { - RasterizerScene::InstanceBase *instance; - MaterialData *material; - union { - struct { - //from least significant to most significant in sort, TODO: should be endian swapped on big endian - uint64_t geometry_index : 20; - uint64_t material_index : 15; - uint64_t shader_index : 12; - uint64_t uses_instancing : 1; - uint64_t uses_forward_gi : 1; - uint64_t uses_lightmap : 1; - uint64_t depth_layer : 4; - uint64_t priority : 8; - }; - - uint64_t sort_key; - }; - uint32_t surface_index; - }; - - Element *base_elements; - Element **elements; - - int element_count; - int alpha_element_count; - - void clear() { - element_count = 0; - alpha_element_count = 0; - } - - //should eventually be replaced by radix - - struct SortByKey { - _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const { - return A->sort_key < B->sort_key; - } - }; - - void sort_by_key(bool p_alpha) { - SortArray<Element *, SortByKey> sorter; - if (p_alpha) { - sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count); - } else { - sorter.sort(elements, element_count); - } - } - - struct SortByDepth { - _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const { - return A->instance->depth < B->instance->depth; - } - }; - - void sort_by_depth(bool p_alpha) { //used for shadows - - SortArray<Element *, SortByDepth> sorter; - if (p_alpha) { - sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count); - } else { - sorter.sort(elements, element_count); - } - } - - struct SortByReverseDepthAndPriority { - _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const { - uint32_t layer_A = uint32_t(A->priority); - uint32_t layer_B = uint32_t(B->priority); - if (layer_A == layer_B) { - return A->instance->depth > B->instance->depth; - } else { - return layer_A < layer_B; - } - } - }; - - void sort_by_reverse_depth_and_priority(bool p_alpha) { //used for alpha - - SortArray<Element *, SortByReverseDepthAndPriority> sorter; - if (p_alpha) { - sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count); - } else { - sorter.sort(elements, element_count); - } - } - - _FORCE_INLINE_ Element *add_element() { - if (element_count + alpha_element_count >= max_elements) { - return nullptr; - } - elements[element_count] = &base_elements[element_count]; - return elements[element_count++]; - } - - _FORCE_INLINE_ Element *add_alpha_element() { - if (element_count + alpha_element_count >= max_elements) { - return nullptr; - } - int idx = max_elements - alpha_element_count - 1; - elements[idx] = &base_elements[idx]; - alpha_element_count++; - return elements[idx]; - } - - void init() { - element_count = 0; - alpha_element_count = 0; - elements = memnew_arr(Element *, max_elements); - base_elements = memnew_arr(Element, max_elements); - for (int i = 0; i < max_elements; i++) { - elements[i] = &base_elements[i]; // assign elements - } - } - - RenderList() { - max_elements = 0; - } - - ~RenderList() { - memdelete_arr(elements); - memdelete_arr(base_elements); - } - }; - - RenderList render_list; - - static RasterizerSceneHighEndRD *singleton; - uint64_t render_pass; - double time; - RID default_shader; - RID default_material; - RID overdraw_material_shader; - RID overdraw_material; - RID wireframe_material_shader; - RID wireframe_material; - RID default_shader_rd; - RID default_shader_sdfgi_rd; - RID default_radiance_uniform_set; - RID default_render_buffers_uniform_set; - - RID default_vec4_xform_buffer; - RID default_vec4_xform_uniform_set; - - enum PassMode { - PASS_MODE_COLOR, - PASS_MODE_COLOR_SPECULAR, - PASS_MODE_COLOR_TRANSPARENT, - PASS_MODE_SHADOW, - PASS_MODE_SHADOW_DP, - PASS_MODE_DEPTH, - PASS_MODE_DEPTH_NORMAL_ROUGHNESS, - PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE, - PASS_MODE_DEPTH_MATERIAL, - PASS_MODE_SDF, - }; - - void _setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false); - void _setup_lightmaps(InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, const Transform &p_cam_transform); - - void _fill_instances(RenderList::Element **p_elements, int p_element_count, bool p_for_depth, bool p_has_sdfgi = false, bool p_has_opaque_gi = false); - void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderList::Element **p_elements, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi, RID p_radiance_uniform_set, RID p_render_buffers_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2()); - _FORCE_INLINE_ void _add_geometry(InstanceBase *p_instance, uint32_t p_surface, RID p_material, PassMode p_pass_mode, uint32_t p_geometry_index, bool p_using_sdfgi = false); - _FORCE_INLINE_ void _add_geometry_with_material(InstanceBase *p_instance, uint32_t p_surface, MaterialData *p_material, RID p_material_rid, PassMode p_pass_mode, uint32_t p_geometry_index, bool p_using_sdfgi = false); - - void _fill_render_list(InstanceBase **p_cull_result, int p_cull_count, PassMode p_pass_mode, bool p_using_sdfgi = false); - - Map<Size2i, RID> sdfgi_framebuffer_size_cache; - -protected: - virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, int p_directional_light_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color); - virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake); - virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region); - virtual void _render_uv2(InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region); - virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, InstanceBase **p_cull_result, int p_cull_count, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture); - virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, InstanceBase **p_cull_result, int p_cull_count); - -public: - virtual void set_time(double p_time, double p_step); - - virtual bool free(RID p_rid); - - RasterizerSceneHighEndRD(RasterizerStorageRD *p_storage); - ~RasterizerSceneHighEndRD(); -}; -#endif // RASTERIZER_SCENE_HIGHEND_RD_H diff --git a/servers/rendering/rasterizer_rd/shaders/resolve.glsl b/servers/rendering/rasterizer_rd/shaders/resolve.glsl deleted file mode 100644 index 9429a66dc9..0000000000 --- a/servers/rendering/rasterizer_rd/shaders/resolve.glsl +++ /dev/null @@ -1,110 +0,0 @@ -#[compute] - -#version 450 - -VERSION_DEFINES - -layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; - -#ifdef MODE_RESOLVE_GI -layout(set = 0, binding = 0) uniform sampler2DMS source_depth; -layout(set = 0, binding = 1) uniform sampler2DMS source_normal_roughness; - -layout(r32f, set = 1, binding = 0) uniform restrict writeonly image2D dest_depth; -layout(rgba8, set = 1, binding = 1) uniform restrict writeonly image2D dest_normal_roughness; - -#ifdef GIPROBE_RESOLVE -layout(set = 2, binding = 0) uniform usampler2DMS source_giprobe; -layout(rg8ui, set = 3, binding = 0) uniform restrict writeonly uimage2D dest_giprobe; -#endif - -#endif - -layout(push_constant, binding = 16, std430) uniform Params { - ivec2 screen_size; - int sample_count; - uint pad; -} -params; - -void main() { - // Pixel being shaded - ivec2 pos = ivec2(gl_GlobalInvocationID.xy); - if (any(greaterThanEqual(pos, params.screen_size))) { //too large, do nothing - return; - } - -#ifdef MODE_RESOLVE_GI - - float best_depth = 1e20; - vec4 best_normal_roughness = vec4(0.0); -#ifdef GIPROBE_RESOLVE - uvec2 best_giprobe; -#endif - -#if 0 - - for(int i=0;i<params.sample_count;i++) { - float depth = texelFetch(source_depth,pos,i).r; - if (depth < best_depth) { //use the depth closest to camera - best_depth = depth; - best_normal_roughness = texelFetch(source_normal_roughness,pos,i); - -#ifdef GIPROBE_RESOLVE - best_giprobe = texelFetch(source_giprobe,pos,i).rg; -#endif - } - } - -#else - - float depths[16]; - int depth_indices[16]; - int depth_amount[16]; - int depth_count = 0; - - for (int i = 0; i < params.sample_count; i++) { - float depth = texelFetch(source_depth, pos, i).r; - int depth_index = -1; - for (int j = 0; j < depth_count; j++) { - if (abs(depths[j] - depth) < 0.000001) { - depth_index = j; - break; - } - } - - if (depth_index == -1) { - depths[depth_count] = depth; - depth_indices[depth_count] = i; - depth_amount[depth_count] = 1; - depth_count += 1; - } else { - depth_amount[depth_index] += 1; - } - } - - int depth_least = 0xFFFF; - int best_index = 0; - for (int j = 0; j < depth_count; j++) { - if (depth_amount[j] < depth_least) { - best_index = depth_indices[j]; - depth_least = depth_amount[j]; - } - } - - best_depth = texelFetch(source_depth, pos, best_index).r; - best_normal_roughness = texelFetch(source_normal_roughness, pos, best_index); -#ifdef GIPROBE_RESOLVE - best_giprobe = texelFetch(source_giprobe, pos, best_index).rg; -#endif - -#endif - - imageStore(dest_depth, pos, vec4(best_depth)); - imageStore(dest_normal_roughness, pos, vec4(best_normal_roughness)); -#ifdef GIPROBE_RESOLVE - imageStore(dest_giprobe, pos, uvec4(best_giprobe, 0, 0)); -#endif - -#endif -} diff --git a/servers/rendering/rasterizer_rd/shaders/shadow_reduce.glsl b/servers/rendering/rasterizer_rd/shaders/shadow_reduce.glsl deleted file mode 100644 index 29443ae7db..0000000000 --- a/servers/rendering/rasterizer_rd/shaders/shadow_reduce.glsl +++ /dev/null @@ -1,105 +0,0 @@ -#[compute] - -#version 450 - -VERSION_DEFINES - -#define BLOCK_SIZE 8 - -layout(local_size_x = BLOCK_SIZE, local_size_y = BLOCK_SIZE, local_size_z = 1) in; - -#ifdef MODE_REDUCE - -shared float tmp_data[BLOCK_SIZE * BLOCK_SIZE]; -const uint swizzle_table[BLOCK_SIZE] = uint[](0, 4, 2, 6, 1, 5, 3, 7); -const uint unswizzle_table[BLOCK_SIZE] = uint[](0, 0, 0, 1, 0, 2, 1, 3); - -#endif - -layout(r32f, set = 0, binding = 0) uniform restrict readonly image2D source_depth; -layout(r32f, set = 0, binding = 1) uniform restrict writeonly image2D dst_depth; - -layout(push_constant, binding = 1, std430) uniform Params { - ivec2 source_size; - ivec2 source_offset; - uint min_size; - uint gaussian_kernel_version; - ivec2 filter_dir; -} -params; - -void main() { -#ifdef MODE_REDUCE - - uvec2 pos = gl_LocalInvocationID.xy; - - ivec2 image_offset = params.source_offset; - ivec2 image_pos = image_offset + ivec2(gl_GlobalInvocationID.xy); - uint dst_t = swizzle_table[pos.y] * BLOCK_SIZE + swizzle_table[pos.x]; - tmp_data[dst_t] = imageLoad(source_depth, min(image_pos, params.source_size - ivec2(1))).r; - ivec2 image_size = params.source_size; - - uint t = pos.y * BLOCK_SIZE + pos.x; - - //neighbours - uint size = BLOCK_SIZE; - - do { - groupMemoryBarrier(); - barrier(); - - size >>= 1; - image_size >>= 1; - image_offset >>= 1; - - if (all(lessThan(pos, uvec2(size)))) { - uint nx = t + size; - uint ny = t + (BLOCK_SIZE * size); - uint nxy = ny + size; - - tmp_data[t] += tmp_data[nx]; - tmp_data[t] += tmp_data[ny]; - tmp_data[t] += tmp_data[nxy]; - tmp_data[t] /= 4.0; - } - - } while (size > params.min_size); - - if (all(lessThan(pos, uvec2(size)))) { - image_pos = ivec2(unswizzle_table[size + pos.x], unswizzle_table[size + pos.y]); - image_pos += image_offset + ivec2(gl_WorkGroupID.xy) * int(size); - - image_size = max(ivec2(1), image_size); //in case image size became 0 - - if (all(lessThan(image_pos, uvec2(image_size)))) { - imageStore(dst_depth, image_pos, vec4(tmp_data[t])); - } - } -#endif - -#ifdef MODE_FILTER - - ivec2 image_pos = params.source_offset + ivec2(gl_GlobalInvocationID.xy); - if (any(greaterThanEqual(image_pos, params.source_size))) { - return; - } - - ivec2 clamp_min = ivec2(params.source_offset); - ivec2 clamp_max = ivec2(params.source_size) - 1; - - //gaussian kernel, size 9, sigma 4 - const int kernel_size = 9; - const float gaussian_kernel[kernel_size * 3] = float[]( - 0.000229, 0.005977, 0.060598, 0.241732, 0.382928, 0.241732, 0.060598, 0.005977, 0.000229, - 0.028532, 0.067234, 0.124009, 0.179044, 0.20236, 0.179044, 0.124009, 0.067234, 0.028532, - 0.081812, 0.101701, 0.118804, 0.130417, 0.134535, 0.130417, 0.118804, 0.101701, 0.081812); - float accum = 0.0; - for (int i = 0; i < kernel_size; i++) { - ivec2 ofs = clamp(image_pos + params.filter_dir * (i - kernel_size / 2), clamp_min, clamp_max); - accum += imageLoad(source_depth, ofs).r * gaussian_kernel[params.gaussian_kernel_version + i]; - } - - imageStore(dst_depth, image_pos, vec4(accum)); - -#endif -} diff --git a/servers/rendering/rasterizer_rd/shaders/ssao.glsl b/servers/rendering/rasterizer_rd/shaders/ssao.glsl deleted file mode 100644 index 346338181a..0000000000 --- a/servers/rendering/rasterizer_rd/shaders/ssao.glsl +++ /dev/null @@ -1,249 +0,0 @@ -#[compute] - -#version 450 - -VERSION_DEFINES - -layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; - -#define TWO_PI 6.283185307179586476925286766559 - -#ifdef SSAO_QUALITY_HIGH -#define NUM_SAMPLES (20) -#endif - -#ifdef SSAO_QUALITY_ULTRA -#define NUM_SAMPLES (48) -#endif - -#ifdef SSAO_QUALITY_LOW -#define NUM_SAMPLES (8) -#endif - -#if !defined(SSAO_QUALITY_LOW) && !defined(SSAO_QUALITY_HIGH) && !defined(SSAO_QUALITY_ULTRA) -#define NUM_SAMPLES (12) -#endif - -// If using depth mip levels, the log of the maximum pixel offset before we need to switch to a lower -// miplevel to maintain reasonable spatial locality in the cache -// If this number is too small (< 3), too many taps will land in the same pixel, and we'll get bad variance that manifests as flashing. -// If it is too high (> 5), we'll get bad performance because we're not using the MIP levels effectively -#define LOG_MAX_OFFSET (3) - -// This must be less than or equal to the MAX_MIP_LEVEL defined in SSAO.cpp -#define MAX_MIP_LEVEL (4) - -// This is the number of turns around the circle that the spiral pattern makes. This should be prime to prevent -// taps from lining up. This particular choice was tuned for NUM_SAMPLES == 9 - -const int ROTATIONS[] = int[]( - 1, 1, 2, 3, 2, 5, 2, 3, 2, - 3, 3, 5, 5, 3, 4, 7, 5, 5, 7, - 9, 8, 5, 5, 7, 7, 7, 8, 5, 8, - 11, 12, 7, 10, 13, 8, 11, 8, 7, 14, - 11, 11, 13, 12, 13, 19, 17, 13, 11, 18, - 19, 11, 11, 14, 17, 21, 15, 16, 17, 18, - 13, 17, 11, 17, 19, 18, 25, 18, 19, 19, - 29, 21, 19, 27, 31, 29, 21, 18, 17, 29, - 31, 31, 23, 18, 25, 26, 25, 23, 19, 34, - 19, 27, 21, 25, 39, 29, 17, 21, 27); - -//#define NUM_SPIRAL_TURNS (7) -const int NUM_SPIRAL_TURNS = ROTATIONS[NUM_SAMPLES - 1]; - -layout(set = 0, binding = 0) uniform sampler2D source_depth_mipmaps; -layout(r8, set = 1, binding = 0) uniform restrict writeonly image2D dest_image; - -#ifndef USE_HALF_SIZE -layout(set = 2, binding = 0) uniform sampler2D source_depth; -#endif - -layout(set = 3, binding = 0) uniform sampler2D source_normal; - -layout(push_constant, binding = 1, std430) uniform Params { - ivec2 screen_size; - float z_far; - float z_near; - - bool orthogonal; - float intensity_div_r6; - float radius; - float bias; - - vec4 proj_info; - vec2 pixel_size; - float proj_scale; - uint pad; -} -params; - -vec3 reconstructCSPosition(vec2 S, float z) { - if (params.orthogonal) { - return vec3((S.xy * params.proj_info.xy + params.proj_info.zw), z); - } else { - return vec3((S.xy * params.proj_info.xy + params.proj_info.zw) * z, z); - } -} - -vec3 getPosition(ivec2 ssP) { - vec3 P; -#ifdef USE_HALF_SIZE - P.z = texelFetch(source_depth_mipmaps, ssP, 0).r; - P.z = -P.z; -#else - P.z = texelFetch(source_depth, ssP, 0).r; - - P.z = P.z * 2.0 - 1.0; - if (params.orthogonal) { - P.z = ((P.z + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; - } else { - P.z = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - P.z * (params.z_far - params.z_near)); - } - P.z = -P.z; -#endif - // Offset to pixel center - P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z); - return P; -} - -/** Returns a unit vector and a screen-space radius for the tap on a unit disk (the caller should scale by the actual disk radius) */ -vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR) { - // Radius relative to ssR - float alpha = (float(sampleNumber) + 0.5) * (1.0 / float(NUM_SAMPLES)); - float angle = alpha * (float(NUM_SPIRAL_TURNS) * 6.28) + spinAngle; - - ssR = alpha; - return vec2(cos(angle), sin(angle)); -} - -/** Read the camera-space position of the point at screen-space pixel ssP + unitOffset * ssR. Assumes length(unitOffset) == 1 */ -vec3 getOffsetPosition(ivec2 ssP, float ssR) { - // Derivation: - // mipLevel = floor(log(ssR / MAX_OFFSET)); - - int mipLevel = clamp(int(floor(log2(ssR))) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); - - vec3 P; - - // We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map. - // Manually clamp to the texture size because texelFetch bypasses the texture unit - ivec2 mipP = clamp(ssP >> mipLevel, ivec2(0), (params.screen_size >> mipLevel) - ivec2(1)); - -#ifdef USE_HALF_SIZE - P.z = texelFetch(source_depth_mipmaps, mipP, mipLevel).r; - P.z = -P.z; -#else - if (mipLevel < 1) { - //read from depth buffer - P.z = texelFetch(source_depth, mipP, 0).r; - P.z = P.z * 2.0 - 1.0; - if (params.orthogonal) { - P.z = ((P.z + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; - } else { - P.z = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - P.z * (params.z_far - params.z_near)); - } - P.z = -P.z; - - } else { - //read from mipmaps - P.z = texelFetch(source_depth_mipmaps, mipP, mipLevel - 1).r; - P.z = -P.z; - } -#endif - - // Offset to pixel center - P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z); - - return P; -} - -/** Compute the occlusion due to sample with index \a i about the pixel at \a ssC that corresponds - to camera-space point \a C with unit normal \a n_C, using maximum screen-space sampling radius \a ssDiskRadius - - Note that units of H() in the HPG12 paper are meters, not - unitless. The whole falloff/sampling function is therefore - unitless. In this implementation, we factor out (9 / radius). - - Four versions of the falloff function are implemented below -*/ -float sampleAO(in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius, in float p_radius, in int tapIndex, in float randomPatternRotationAngle) { - // Offset on the unit disk, spun for this pixel - float ssR; - vec2 unitOffset = tapLocation(tapIndex, randomPatternRotationAngle, ssR); - ssR *= ssDiskRadius; - - ivec2 ssP = ivec2(ssR * unitOffset) + ssC; - - if (any(lessThan(ssP, ivec2(0))) || any(greaterThanEqual(ssP, params.screen_size))) { - return 0.0; - } - - // The occluding point in camera space - vec3 Q = getOffsetPosition(ssP, ssR); - - vec3 v = Q - C; - - float vv = dot(v, v); - float vn = dot(v, n_C); - - const float epsilon = 0.01; - float radius2 = p_radius * p_radius; - - // A: From the HPG12 paper - // Note large epsilon to avoid overdarkening within cracks - //return float(vv < radius2) * max((vn - bias) / (epsilon + vv), 0.0) * radius2 * 0.6; - - // B: Smoother transition to zero (lowers contrast, smoothing out corners). [Recommended] - float f = max(radius2 - vv, 0.0); - return f * f * f * max((vn - params.bias) / (epsilon + vv), 0.0); - - // C: Medium contrast (which looks better at high radii), no division. Note that the - // contribution still falls off with radius^2, but we've adjusted the rate in a way that is - // more computationally efficient and happens to be aesthetically pleasing. - // return 4.0 * max(1.0 - vv * invRadius2, 0.0) * max(vn - bias, 0.0); - - // D: Low contrast, no division operation - // return 2.0 * float(vv < radius * radius) * max(vn - bias, 0.0); -} - -void main() { - // Pixel being shaded - ivec2 ssC = ivec2(gl_GlobalInvocationID.xy); - if (any(greaterThanEqual(ssC, params.screen_size))) { //too large, do nothing - return; - } - - // World space point being shaded - vec3 C = getPosition(ssC); - -#ifdef USE_HALF_SIZE - vec3 n_C = texelFetch(source_normal, ssC << 1, 0).xyz * 2.0 - 1.0; -#else - vec3 n_C = texelFetch(source_normal, ssC, 0).xyz * 2.0 - 1.0; -#endif - n_C = normalize(n_C); - n_C.y = -n_C.y; //because this code reads flipped - - // Hash function used in the HPG12 AlchemyAO paper - float randomPatternRotationAngle = mod(float((3 * ssC.x ^ ssC.y + ssC.x * ssC.y) * 10), TWO_PI); - - // Reconstruct normals from positions. These will lead to 1-pixel black lines - // at depth discontinuities, however the blur will wipe those out so they are not visible - // in the final image. - - // Choose the screen-space sample radius - // proportional to the projected area of the sphere - - float ssDiskRadius = -params.proj_scale * params.radius; - if (!params.orthogonal) { - ssDiskRadius = -params.proj_scale * params.radius / C.z; - } - float sum = 0.0; - for (int i = 0; i < NUM_SAMPLES; ++i) { - sum += sampleAO(ssC, C, n_C, ssDiskRadius, params.radius, i, randomPatternRotationAngle); - } - - float A = max(0.0, 1.0 - sum * params.intensity_div_r6 * (5.0 / float(NUM_SAMPLES))); - - imageStore(dest_image, ssC, vec4(A)); -} diff --git a/servers/rendering/rasterizer_rd/shaders/ssao_blur.glsl b/servers/rendering/rasterizer_rd/shaders/ssao_blur.glsl deleted file mode 100644 index 3e63e3cb59..0000000000 --- a/servers/rendering/rasterizer_rd/shaders/ssao_blur.glsl +++ /dev/null @@ -1,153 +0,0 @@ -#[compute] - -#version 450 - -VERSION_DEFINES - -layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; - -layout(set = 0, binding = 0) uniform sampler2D source_ssao; -layout(set = 1, binding = 0) uniform sampler2D source_depth; -#ifdef MODE_UPSCALE -layout(set = 2, binding = 0) uniform sampler2D source_depth_mipmaps; -#endif - -layout(r8, set = 3, binding = 0) uniform restrict writeonly image2D dest_image; - -////////////////////////////////////////////////////////////////////////////////////////////// -// Tunable Parameters: - -layout(push_constant, binding = 1, std430) uniform Params { - float edge_sharpness; /** Increase to make depth edges crisper. Decrease to reduce flicker. */ - int filter_scale; - float z_far; - float z_near; - bool orthogonal; - uint pad0; - uint pad1; - uint pad2; - ivec2 axis; /** (1, 0) or (0, 1) */ - ivec2 screen_size; -} -params; - -/** Filter radius in pixels. This will be multiplied by SCALE. */ -#define R (4) - -////////////////////////////////////////////////////////////////////////////////////////////// - -// Gaussian coefficients -const float gaussian[R + 1] = - //float[](0.356642, 0.239400, 0.072410, 0.009869); - //float[](0.398943, 0.241971, 0.053991, 0.004432, 0.000134); // stddev = 1.0 - float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); // stddev = 2.0 -//float[](0.111220, 0.107798, 0.098151, 0.083953, 0.067458, 0.050920, 0.036108); // stddev = 3.0 - -void main() { - // Pixel being shaded - ivec2 ssC = ivec2(gl_GlobalInvocationID.xy); - if (any(greaterThanEqual(ssC, params.screen_size))) { //too large, do nothing - return; - } - -#ifdef MODE_UPSCALE - - //closest one should be the same pixel, but check nearby just in case - float depth = texelFetch(source_depth, ssC, 0).r; - - depth = depth * 2.0 - 1.0; - if (params.orthogonal) { - depth = ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; - } else { - depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near)); - } - - vec2 pixel_size = 1.0 / vec2(params.screen_size); - vec2 closest_uv = vec2(ssC) * pixel_size + pixel_size * 0.5; - vec2 from_uv = closest_uv; - vec2 ps2 = pixel_size; // * 2.0; - - float closest_depth = abs(textureLod(source_depth_mipmaps, closest_uv, 0.0).r - depth); - - vec2 offsets[4] = vec2[](vec2(ps2.x, 0), vec2(-ps2.x, 0), vec2(0, ps2.y), vec2(0, -ps2.y)); - for (int i = 0; i < 4; i++) { - vec2 neighbour = from_uv + offsets[i]; - float neighbour_depth = abs(textureLod(source_depth_mipmaps, neighbour, 0.0).r - depth); - if (neighbour_depth < closest_depth) { - closest_uv = neighbour; - closest_depth = neighbour_depth; - } - } - - float visibility = textureLod(source_ssao, closest_uv, 0.0).r; - imageStore(dest_image, ssC, vec4(visibility)); -#else - - float depth = texelFetch(source_depth, ssC, 0).r; - -#ifdef MODE_FULL_SIZE - depth = depth * 2.0 - 1.0; - - if (params.orthogonal) { - depth = ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; - } else { - depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near)); - } - -#endif - float depth_divide = 1.0 / params.z_far; - - //depth *= depth_divide; - - /* - if (depth > params.z_far * 0.999) { - discard; //skybox - } - */ - - float sum = texelFetch(source_ssao, ssC, 0).r; - - // Base weight for depth falloff. Increase this for more blurriness, - // decrease it for better edge discrimination - float BASE = gaussian[0]; - float totalWeight = BASE; - sum *= totalWeight; - - ivec2 clamp_limit = params.screen_size - ivec2(1); - - for (int r = -R; r <= R; ++r) { - // We already handled the zero case above. This loop should be unrolled and the static branch optimized out, - // so the IF statement has no runtime cost - if (r != 0) { - ivec2 ppos = ssC + params.axis * (r * params.filter_scale); - float value = texelFetch(source_ssao, clamp(ppos, ivec2(0), clamp_limit), 0).r; - ivec2 rpos = clamp(ppos, ivec2(0), clamp_limit); - - float temp_depth = texelFetch(source_depth, rpos, 0).r; -#ifdef MODE_FULL_SIZE - temp_depth = temp_depth * 2.0 - 1.0; - if (params.orthogonal) { - temp_depth = ((temp_depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; - } else { - temp_depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - temp_depth * (params.z_far - params.z_near)); - } - //temp_depth *= depth_divide; -#endif - // spatial domain: offset gaussian tap - float weight = 0.3 + gaussian[abs(r)]; - //weight *= max(0.0, dot(temp_normal, normal)); - - // range domain (the "bilateral" weight). As depth difference increases, decrease weight. - weight *= max(0.0, 1.0 - params.edge_sharpness * abs(temp_depth - depth)); - - sum += value * weight; - totalWeight += weight; - } - } - - const float epsilon = 0.0001; - float visibility = sum / (totalWeight + epsilon); - - imageStore(dest_image, ssC, vec4(visibility)); -#endif -} diff --git a/servers/rendering/rasterizer_rd/shaders/ssao_minify.glsl b/servers/rendering/rasterizer_rd/shaders/ssao_minify.glsl deleted file mode 100644 index 263fca386f..0000000000 --- a/servers/rendering/rasterizer_rd/shaders/ssao_minify.glsl +++ /dev/null @@ -1,45 +0,0 @@ -#[compute] - -#version 450 - -VERSION_DEFINES - -layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; - -layout(push_constant, binding = 1, std430) uniform Params { - vec2 pixel_size; - float z_far; - float z_near; - ivec2 source_size; - bool orthogonal; - uint pad; -} -params; - -#ifdef MINIFY_START -layout(set = 0, binding = 0) uniform sampler2D source_texture; -#else -layout(r32f, set = 0, binding = 0) uniform restrict readonly image2D source_image; -#endif -layout(r32f, set = 1, binding = 0) uniform restrict writeonly image2D dest_image; - -void main() { - ivec2 pos = ivec2(gl_GlobalInvocationID.xy); - - if (any(greaterThan(pos, params.source_size >> 1))) { //too large, do nothing - return; - } - -#ifdef MINIFY_START - float depth = texelFetch(source_texture, pos << 1, 0).r * 2.0 - 1.0; - if (params.orthogonal) { - depth = ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; - } else { - depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near)); - } -#else - float depth = imageLoad(source_image, pos << 1).r; -#endif - - imageStore(dest_image, pos, vec4(depth)); -} diff --git a/servers/rendering/rendering_server_canvas.cpp b/servers/rendering/renderer_canvas_cull.cpp index ffc1ec391d..e34bc9acb8 100644 --- a/servers/rendering/rendering_server_canvas.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rendering_server_canvas.cpp */ +/* renderer_canvas_cull.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,20 +28,20 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "rendering_server_canvas.h" +#include "renderer_canvas_cull.h" #include "core/math/geometry_2d.h" +#include "renderer_viewport.h" +#include "rendering_server_default.h" #include "rendering_server_globals.h" -#include "rendering_server_raster.h" -#include "rendering_server_viewport.h" static const int z_range = RS::CANVAS_ITEM_Z_MAX - RS::CANVAS_ITEM_Z_MIN + 1; -void RenderingServerCanvas::_render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_directional_lights, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel) { +void RendererCanvasCull::_render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel) { RENDER_TIMESTAMP("Cull CanvasItem Tree"); - memset(z_list, 0, z_range * sizeof(RasterizerCanvas::Item *)); - memset(z_last_list, 0, z_range * sizeof(RasterizerCanvas::Item *)); + memset(z_list, 0, z_range * sizeof(RendererCanvasRender::Item *)); + memset(z_last_list, 0, z_range * sizeof(RendererCanvasRender::Item *)); for (int i = 0; i < p_child_item_count; i++) { _cull_canvas_item(p_child_items[i].item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr); @@ -50,8 +50,8 @@ void RenderingServerCanvas::_render_canvas_item_tree(RID p_to_render_target, Can _cull_canvas_item(p_canvas_item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr); } - RasterizerCanvas::Item *list = nullptr; - RasterizerCanvas::Item *list_end = nullptr; + RendererCanvasRender::Item *list = nullptr; + RendererCanvasRender::Item *list_end = nullptr; for (int i = 0; i < z_range; i++) { if (!z_list[i]) { @@ -75,9 +75,9 @@ void RenderingServerCanvas::_render_canvas_item_tree(RID p_to_render_target, Can } } -void _collect_ysort_children(RenderingServerCanvas::Item *p_canvas_item, Transform2D p_transform, RenderingServerCanvas::Item *p_material_owner, RenderingServerCanvas::Item **r_items, int &r_index) { +void _collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, Transform2D p_transform, RendererCanvasCull::Item *p_material_owner, RendererCanvasCull::Item **r_items, int &r_index) { int child_item_count = p_canvas_item->child_items.size(); - RenderingServerCanvas::Item **child_items = p_canvas_item->child_items.ptrw(); + RendererCanvasCull::Item **child_items = p_canvas_item->child_items.ptrw(); for (int i = 0; i < child_item_count; i++) { if (child_items[i]->visible) { if (r_items) { @@ -97,14 +97,14 @@ void _collect_ysort_children(RenderingServerCanvas::Item *p_canvas_item, Transfo } } -void _mark_ysort_dirty(RenderingServerCanvas::Item *ysort_owner, RID_PtrOwner<RenderingServerCanvas::Item> &canvas_item_owner) { +void _mark_ysort_dirty(RendererCanvasCull::Item *ysort_owner, RID_PtrOwner<RendererCanvasCull::Item, true> &canvas_item_owner) { do { ysort_owner->ysort_children_count = -1; ysort_owner = canvas_item_owner.owns(ysort_owner->parent) ? canvas_item_owner.getornull(ysort_owner->parent) : nullptr; } while (ysort_owner && ysort_owner->sort_y); } -void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RasterizerCanvas::Item **z_list, RasterizerCanvas::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner) { +void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner) { Item *ci = p_canvas_item; if (!ci->visible) { @@ -144,7 +144,7 @@ void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transfo if (ci->clip) { if (p_canvas_clip != nullptr) { - ci->final_clip_rect = p_canvas_clip->final_clip_rect.clip(global_rect); + ci->final_clip_rect = p_canvas_clip->final_clip_rect.intersection(global_rect); } else { ci->final_clip_rect = global_rect; } @@ -176,7 +176,7 @@ void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transfo p_z = ci->z_index; } - RasterizerCanvas::Item *canvas_group_from = nullptr; + RendererCanvasRender::Item *canvas_group_from = nullptr; bool use_canvas_group = ci->canvas_group != nullptr && (ci->canvas_group->fit_empty || ci->commands != nullptr); if (use_canvas_group) { int zidx = p_z - RS::CANVAS_ITEM_Z_MIN; @@ -195,7 +195,7 @@ void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transfo } if (ci->copy_back_buffer) { - ci->copy_back_buffer->screen_rect = xform.xform(ci->copy_back_buffer->rect).clip(p_clip_rect); + ci->copy_back_buffer->screen_rect = xform.xform(ci->copy_back_buffer->rect).intersection(p_clip_rect); } if (use_canvas_group) { @@ -213,7 +213,7 @@ void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transfo //compute a global rect (in global coords) for children in the same z layer Rect2 rect_accum; - RasterizerCanvas::Item *c = canvas_group_from; + RendererCanvasRender::Item *c = canvas_group_from; while (c) { if (c == canvas_group_from) { rect_accum = c->global_rect_cache; @@ -227,7 +227,7 @@ void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transfo // We have two choices now, if user has drawn something, we must assume users wants to draw the "mask", so compute the size based on this. // If nothing has been drawn, we just take it over and draw it ourselves. if (ci->canvas_group->fit_empty && (ci->commands == nullptr || - (ci->commands->next == nullptr && ci->commands->type == Item::Command::TYPE_RECT && (static_cast<Item::CommandRect *>(ci->commands)->flags & RasterizerCanvas::CANVAS_RECT_IS_GROUP)))) { + (ci->commands->next == nullptr && ci->commands->type == Item::Command::TYPE_RECT && (static_cast<Item::CommandRect *>(ci->commands)->flags & RendererCanvasRender::CANVAS_RECT_IS_GROUP)))) { // No commands, or sole command is the one used to draw, so we (re)create the draw command. ci->clear(); @@ -238,9 +238,9 @@ void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transfo rect_accum = rect_accum.grow(ci->canvas_group->fit_margin); //draw it? - RasterizerCanvas::Item::CommandRect *crect = ci->alloc_command<RasterizerCanvas::Item::CommandRect>(); + RendererCanvasRender::Item::CommandRect *crect = ci->alloc_command<RendererCanvasRender::Item::CommandRect>(); - crect->flags = RasterizerCanvas::CANVAS_RECT_IS_GROUP; // so we can recognize it later + crect->flags = RendererCanvasRender::CANVAS_RECT_IS_GROUP; // so we can recognize it later crect->rect = xform.affine_inverse().xform(rect_accum); crect->modulate = Color(1, 1, 1, 1); @@ -256,14 +256,14 @@ void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transfo global_rect.position += p_clip_rect.position; } - // Very important that this is cleared after used in RasterizerCanvas to avoid + // Very important that this is cleared after used in RendererCanvasRender to avoid // potential crashes. canvas_group_from->canvas_group_owner = ci; } } if (ci->update_when_visible) { - RenderingServerRaster::redraw_request(); + RenderingServerDefault::redraw_request(); } if ((ci->commands != nullptr && p_clip_rect.intersects(global_rect, true)) || ci->vp_render || ci->copy_back_buffer) { @@ -302,7 +302,7 @@ void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transfo } } -void RenderingServerCanvas::render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_directional_lights, const Rect2 &p_clip_rect, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_transforms_to_pixel, bool p_snap_2d_vertices_to_pixel) { +void RendererCanvasCull::render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, const Rect2 &p_clip_rect, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_transforms_to_pixel, bool p_snap_2d_vertices_to_pixel) { RENDER_TIMESTAMP(">Render Canvas"); sdf_used = false; @@ -352,19 +352,19 @@ void RenderingServerCanvas::render_canvas(RID p_render_target, Canvas *p_canvas, RENDER_TIMESTAMP("<End Render Canvas"); } -bool RenderingServerCanvas::was_sdf_used() { +bool RendererCanvasCull::was_sdf_used() { return sdf_used; } -RID RenderingServerCanvas::canvas_create() { +RID RendererCanvasCull::canvas_allocate() { + return canvas_owner.allocate_rid(); +} +void RendererCanvasCull::canvas_initialize(RID p_rid) { Canvas *canvas = memnew(Canvas); - ERR_FAIL_COND_V(!canvas, RID()); - RID rid = canvas_owner.make_rid(canvas); - - return rid; + canvas_owner.initialize_rid(p_rid, canvas); } -void RenderingServerCanvas::canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring) { +void RendererCanvasCull::canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring) { Canvas *canvas = canvas_owner.getornull(p_canvas); ERR_FAIL_COND(!canvas); Item *canvas_item = canvas_item_owner.getornull(p_item); @@ -375,17 +375,17 @@ void RenderingServerCanvas::canvas_set_item_mirroring(RID p_canvas, RID p_item, canvas->child_items.write[idx].mirror = p_mirroring; } -void RenderingServerCanvas::canvas_set_modulate(RID p_canvas, const Color &p_color) { +void RendererCanvasCull::canvas_set_modulate(RID p_canvas, const Color &p_color) { Canvas *canvas = canvas_owner.getornull(p_canvas); ERR_FAIL_COND(!canvas); canvas->modulate = p_color; } -void RenderingServerCanvas::canvas_set_disable_scale(bool p_disable) { +void RendererCanvasCull::canvas_set_disable_scale(bool p_disable) { disable_scale = p_disable; } -void RenderingServerCanvas::canvas_set_parent(RID p_canvas, RID p_parent, float p_scale) { +void RendererCanvasCull::canvas_set_parent(RID p_canvas, RID p_parent, float p_scale) { Canvas *canvas = canvas_owner.getornull(p_canvas); ERR_FAIL_COND(!canvas); @@ -393,14 +393,15 @@ void RenderingServerCanvas::canvas_set_parent(RID p_canvas, RID p_parent, float canvas->parent_scale = p_scale; } -RID RenderingServerCanvas::canvas_item_create() { +RID RendererCanvasCull::canvas_item_allocate() { + return canvas_item_owner.allocate_rid(); +} +void RendererCanvasCull::canvas_item_initialize(RID p_rid) { Item *canvas_item = memnew(Item); - ERR_FAIL_COND_V(!canvas_item, RID()); - - return canvas_item_owner.make_rid(canvas_item); + canvas_item_owner.initialize_rid(p_rid, canvas_item); } -void RenderingServerCanvas::canvas_item_set_parent(RID p_item, RID p_parent) { +void RendererCanvasCull::canvas_item_set_parent(RID p_item, RID p_parent) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -444,7 +445,7 @@ void RenderingServerCanvas::canvas_item_set_parent(RID p_item, RID p_parent) { canvas_item->parent = p_parent; } -void RenderingServerCanvas::canvas_item_set_visible(RID p_item, bool p_visible) { +void RendererCanvasCull::canvas_item_set_visible(RID p_item, bool p_visible) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -453,35 +454,35 @@ void RenderingServerCanvas::canvas_item_set_visible(RID p_item, bool p_visible) _mark_ysort_dirty(canvas_item, canvas_item_owner); } -void RenderingServerCanvas::canvas_item_set_light_mask(RID p_item, int p_mask) { +void RendererCanvasCull::canvas_item_set_light_mask(RID p_item, int p_mask) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->light_mask = p_mask; } -void RenderingServerCanvas::canvas_item_set_transform(RID p_item, const Transform2D &p_transform) { +void RendererCanvasCull::canvas_item_set_transform(RID p_item, const Transform2D &p_transform) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->xform = p_transform; } -void RenderingServerCanvas::canvas_item_set_clip(RID p_item, bool p_clip) { +void RendererCanvasCull::canvas_item_set_clip(RID p_item, bool p_clip) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->clip = p_clip; } -void RenderingServerCanvas::canvas_item_set_distance_field_mode(RID p_item, bool p_enable) { +void RendererCanvasCull::canvas_item_set_distance_field_mode(RID p_item, bool p_enable) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->distance_field = p_enable; } -void RenderingServerCanvas::canvas_item_set_custom_rect(RID p_item, bool p_custom_rect, const Rect2 &p_rect) { +void RendererCanvasCull::canvas_item_set_custom_rect(RID p_item, bool p_custom_rect, const Rect2 &p_rect) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -489,42 +490,42 @@ void RenderingServerCanvas::canvas_item_set_custom_rect(RID p_item, bool p_custo canvas_item->rect = p_rect; } -void RenderingServerCanvas::canvas_item_set_modulate(RID p_item, const Color &p_color) { +void RendererCanvasCull::canvas_item_set_modulate(RID p_item, const Color &p_color) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->modulate = p_color; } -void RenderingServerCanvas::canvas_item_set_self_modulate(RID p_item, const Color &p_color) { +void RendererCanvasCull::canvas_item_set_self_modulate(RID p_item, const Color &p_color) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->self_modulate = p_color; } -void RenderingServerCanvas::canvas_item_set_draw_behind_parent(RID p_item, bool p_enable) { +void RendererCanvasCull::canvas_item_set_draw_behind_parent(RID p_item, bool p_enable) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->behind = p_enable; } -void RenderingServerCanvas::canvas_item_set_update_when_visible(RID p_item, bool p_update) { +void RendererCanvasCull::canvas_item_set_update_when_visible(RID p_item, bool p_update) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->update_when_visible = p_update; } -void RenderingServerCanvas::canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width) { +void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); Item::CommandPrimitive *line = canvas_item->alloc_command<Item::CommandPrimitive>(); ERR_FAIL_COND(!line); if (p_width > 1.001) { - Vector2 t = (p_from - p_to).tangent().normalized(); + Vector2 t = (p_from - p_to).orthogonal().normalized(); line->points[0] = p_from + t * p_width; line->points[1] = p_from - t * p_width; line->points[2] = p_to - t * p_width; @@ -540,93 +541,146 @@ void RenderingServerCanvas::canvas_item_add_line(RID p_item, const Point2 &p_fro } } -void RenderingServerCanvas::canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) { +void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width, bool p_antialiased) { ERR_FAIL_COND(p_points.size() < 2); Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); + Color color = Color(1, 1, 1, 1); + + Vector<int> indices; + int pc = p_points.size(); + int pc2 = pc * 2; + + Vector2 prev_t; + int j2; + Item::CommandPolygon *pline = canvas_item->alloc_command<Item::CommandPolygon>(); ERR_FAIL_COND(!pline); - if (true || p_width <= 1) { -#define TODO make thick lines possible - Vector<int> indices; - int pc = p_points.size(); - indices.resize((pc - 1) * 2); - { - int *iptr = indices.ptrw(); - for (int i = 0; i < (pc - 1); i++) { - iptr[i * 2 + 0] = i; - iptr[i * 2 + 1] = i + 1; - } - } + PackedColorArray colors; + PackedVector2Array points; - pline->primitive = RS::PRIMITIVE_LINES; - pline->polygon.create(indices, p_points, p_colors); - } else { -#if 0 - //make a trianglestrip for drawing the line... - Vector2 prev_t; - pline->triangles.resize(p_points.size() * 2); - if (p_antialiased) { - pline->lines.resize(p_points.size() * 2); - } + colors.resize(pc2); + points.resize(pc2); - if (p_colors.size() == 0) { - pline->triangle_colors.push_back(Color(1, 1, 1, 1)); - if (p_antialiased) { - pline->line_colors.push_back(Color(1, 1, 1, 1)); - } - } else if (p_colors.size() == 1) { - pline->triangle_colors = p_colors; - pline->line_colors = p_colors; - } else { - if (p_colors.size() != p_points.size()) { - pline->triangle_colors.push_back(p_colors[0]); - pline->line_colors.push_back(p_colors[0]); - } else { - pline->triangle_colors.resize(pline->triangles.size()); - pline->line_colors.resize(pline->lines.size()); - } - } + Vector2 *points_ptr = points.ptrw(); + Color *colors_ptr = colors.ptrw(); + + if (p_antialiased) { + Color color2 = Color(1, 1, 1, 0); + + PackedColorArray colors_top; + PackedVector2Array points_top; + + colors_top.resize(pc2); + points_top.resize(pc2); - for (int i = 0; i < p_points.size(); i++) { + PackedColorArray colors_bottom; + PackedVector2Array points_bottom; + + colors_bottom.resize(pc2); + points_bottom.resize(pc2); + + Item::CommandPolygon *pline_top = canvas_item->alloc_command<Item::CommandPolygon>(); + ERR_FAIL_COND(!pline_top); + + Item::CommandPolygon *pline_bottom = canvas_item->alloc_command<Item::CommandPolygon>(); + ERR_FAIL_COND(!pline_bottom); + + //make three trianglestrip's for drawing the antialiased line... + + Vector2 *points_top_ptr = points_top.ptrw(); + Vector2 *points_bottom_ptr = points_bottom.ptrw(); + + Color *colors_top_ptr = colors_top.ptrw(); + Color *colors_bottom_ptr = colors_bottom.ptrw(); + + for (int i = 0, j = 0; i < pc; i++, j += 2) { Vector2 t; - if (i == p_points.size() - 1) { + if (i == pc - 1) { t = prev_t; } else { - t = (p_points[i + 1] - p_points[i]).normalized().tangent(); + t = (p_points[i + 1] - p_points[i]).normalized().orthogonal(); if (i == 0) { prev_t = t; } } + j2 = j + 1; + Vector2 tangent = ((t + prev_t).normalized()) * p_width * 0.5; + Vector2 pos = p_points[i]; - if (p_antialiased) { - pline->lines.write[i] = p_points[i] + tangent; - pline->lines.write[p_points.size() * 2 - i - 1] = p_points[i] - tangent; - if (pline->line_colors.size() > 1) { - pline->line_colors.write[i] = p_colors[i]; - pline->line_colors.write[p_points.size() * 2 - i - 1] = p_colors[i]; + points_ptr[j] = pos + tangent; + points_ptr[j2] = pos - tangent; + + points_top_ptr[j] = pos + tangent + tangent; + points_top_ptr[j2] = pos + tangent; + + points_bottom_ptr[j] = pos - tangent; + points_bottom_ptr[j2] = pos - tangent - tangent; + + if (i < p_colors.size()) { + color = p_colors[i]; + color2 = Color(color.r, color.g, color.b, 0); + } + + colors_ptr[j] = color; + colors_ptr[j2] = color; + + colors_top_ptr[j] = color2; + colors_top_ptr[j2] = color; + + colors_bottom_ptr[j] = color; + colors_bottom_ptr[j2] = color2; + + prev_t = t; + } + + pline_top->primitive = RS::PRIMITIVE_TRIANGLE_STRIP; + pline_top->polygon.create(indices, points_top, colors_top); + + pline_bottom->primitive = RS::PRIMITIVE_TRIANGLE_STRIP; + pline_bottom->polygon.create(indices, points_bottom, colors_bottom); + } else { + //make a trianglestrip for drawing the line... + + for (int i = 0, j = 0; i < pc; i++, j += 2) { + Vector2 t; + if (i == pc - 1) { + t = prev_t; + } else { + t = (p_points[i + 1] - p_points[i]).normalized().orthogonal(); + if (i == 0) { + prev_t = t; } } - pline->triangles.write[i * 2 + 0] = p_points[i] + tangent; - pline->triangles.write[i * 2 + 1] = p_points[i] - tangent; + j2 = j + 1; - if (pline->triangle_colors.size() > 1) { - pline->triangle_colors.write[i * 2 + 0] = p_colors[i]; - pline->triangle_colors.write[i * 2 + 1] = p_colors[i]; + Vector2 tangent = ((t + prev_t).normalized()) * p_width * 0.5; + Vector2 pos = p_points[i]; + + points_ptr[j] = pos + tangent; + points_ptr[j2] = pos - tangent; + + if (i < p_colors.size()) { + color = p_colors[i]; } + colors_ptr[j] = color; + colors_ptr[j2] = color; + prev_t = t; } -#endif } + + pline->primitive = RS::PRIMITIVE_TRIANGLE_STRIP; + pline->polygon.create(indices, points, colors); } -void RenderingServerCanvas::canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) { +void RendererCanvasCull::canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) { ERR_FAIL_COND(p_points.size() < 2); Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -643,7 +697,7 @@ void RenderingServerCanvas::canvas_item_add_multiline(RID p_item, const Vector<P } } -void RenderingServerCanvas::canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) { +void RendererCanvasCull::canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -653,7 +707,7 @@ void RenderingServerCanvas::canvas_item_add_rect(RID p_item, const Rect2 &p_rect rect->rect = p_rect; } -void RenderingServerCanvas::canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) { +void RendererCanvasCull::canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -668,8 +722,10 @@ void RenderingServerCanvas::canvas_item_add_circle(RID p_item, const Point2 &p_p static const int circle_points = 64; points.resize(circle_points); + const real_t circle_point_step = Math_TAU / circle_points; + for (int i = 0; i < circle_points; i++) { - float angle = (i / float(circle_points)) * 2 * Math_PI; + float angle = i * circle_point_step; points.write[i].x = Math::cos(angle) * p_radius; points.write[i].y = Math::sin(angle) * p_radius; points.write[i] += p_pos; @@ -687,7 +743,7 @@ void RenderingServerCanvas::canvas_item_add_circle(RID p_item, const Point2 &p_p circle->polygon.create(indices, points, color); } -void RenderingServerCanvas::canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile, const Color &p_modulate, bool p_transpose) { +void RendererCanvasCull::canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile, const Color &p_modulate, bool p_transpose) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -697,28 +753,28 @@ void RenderingServerCanvas::canvas_item_add_texture_rect(RID p_item, const Rect2 rect->rect = p_rect; rect->flags = 0; if (p_tile) { - rect->flags |= RasterizerCanvas::CANVAS_RECT_TILE; - rect->flags |= RasterizerCanvas::CANVAS_RECT_REGION; + rect->flags |= RendererCanvasRender::CANVAS_RECT_TILE; + rect->flags |= RendererCanvasRender::CANVAS_RECT_REGION; rect->source = Rect2(0, 0, fabsf(p_rect.size.width), fabsf(p_rect.size.height)); } if (p_rect.size.x < 0) { - rect->flags |= RasterizerCanvas::CANVAS_RECT_FLIP_H; + rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_H; rect->rect.size.x = -rect->rect.size.x; } if (p_rect.size.y < 0) { - rect->flags |= RasterizerCanvas::CANVAS_RECT_FLIP_V; + rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_V; rect->rect.size.y = -rect->rect.size.y; } if (p_transpose) { - rect->flags |= RasterizerCanvas::CANVAS_RECT_TRANSPOSE; + rect->flags |= RendererCanvasRender::CANVAS_RECT_TRANSPOSE; SWAP(rect->rect.size.x, rect->rect.size.y); } rect->texture = p_texture; } -void RenderingServerCanvas::canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) { +void RendererCanvasCull::canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -730,36 +786,36 @@ void RenderingServerCanvas::canvas_item_add_texture_rect_region(RID p_item, cons rect->texture = p_texture; rect->source = p_src_rect; - rect->flags = RasterizerCanvas::CANVAS_RECT_REGION; + rect->flags = RendererCanvasRender::CANVAS_RECT_REGION; if (p_rect.size.x < 0) { - rect->flags |= RasterizerCanvas::CANVAS_RECT_FLIP_H; + rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_H; rect->rect.size.x = -rect->rect.size.x; } if (p_src_rect.size.x < 0) { - rect->flags ^= RasterizerCanvas::CANVAS_RECT_FLIP_H; + rect->flags ^= RendererCanvasRender::CANVAS_RECT_FLIP_H; rect->source.size.x = -rect->source.size.x; } if (p_rect.size.y < 0) { - rect->flags |= RasterizerCanvas::CANVAS_RECT_FLIP_V; + rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_V; rect->rect.size.y = -rect->rect.size.y; } if (p_src_rect.size.y < 0) { - rect->flags ^= RasterizerCanvas::CANVAS_RECT_FLIP_V; + rect->flags ^= RendererCanvasRender::CANVAS_RECT_FLIP_V; rect->source.size.y = -rect->source.size.y; } if (p_transpose) { - rect->flags |= RasterizerCanvas::CANVAS_RECT_TRANSPOSE; + rect->flags |= RendererCanvasRender::CANVAS_RECT_TRANSPOSE; SWAP(rect->rect.size.x, rect->rect.size.y); } if (p_clip_uv) { - rect->flags |= RasterizerCanvas::CANVAS_RECT_CLIP_UV; + rect->flags |= RendererCanvasRender::CANVAS_RECT_CLIP_UV; } } -void RenderingServerCanvas::canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, RS::NinePatchAxisMode p_x_axis_mode, RS::NinePatchAxisMode p_y_axis_mode, bool p_draw_center, const Color &p_modulate) { +void RendererCanvasCull::canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, RS::NinePatchAxisMode p_x_axis_mode, RS::NinePatchAxisMode p_y_axis_mode, bool p_draw_center, const Color &p_modulate) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -772,15 +828,15 @@ void RenderingServerCanvas::canvas_item_add_nine_patch(RID p_item, const Rect2 & style->source = p_source; style->draw_center = p_draw_center; style->color = p_modulate; - style->margin[MARGIN_LEFT] = p_topleft.x; - style->margin[MARGIN_TOP] = p_topleft.y; - style->margin[MARGIN_RIGHT] = p_bottomright.x; - style->margin[MARGIN_BOTTOM] = p_bottomright.y; + style->margin[SIDE_LEFT] = p_topleft.x; + style->margin[SIDE_TOP] = p_topleft.y; + style->margin[SIDE_RIGHT] = p_bottomright.x; + style->margin[SIDE_BOTTOM] = p_bottomright.y; style->axis_x = p_x_axis_mode; style->axis_y = p_y_axis_mode; } -void RenderingServerCanvas::canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width) { +void RendererCanvasCull::canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width) { uint32_t pc = p_points.size(); ERR_FAIL_COND(pc == 0 || pc > 4); @@ -809,7 +865,7 @@ void RenderingServerCanvas::canvas_item_add_primitive(RID p_item, const Vector<P prim->texture = p_texture; } -void RenderingServerCanvas::canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture) { +void RendererCanvasCull::canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); #ifdef DEBUG_ENABLED @@ -821,7 +877,7 @@ void RenderingServerCanvas::canvas_item_add_polygon(RID p_item, const Vector<Poi ERR_FAIL_COND(uv_size != 0 && (uv_size != pointcount)); #endif Vector<int> indices = Geometry2D::triangulate_polygon(p_points); - ERR_FAIL_COND_MSG(indices.empty(), "Invalid polygon data, triangulation failed."); + ERR_FAIL_COND_MSG(indices.is_empty(), "Invalid polygon data, triangulation failed."); Item::CommandPolygon *polygon = canvas_item->alloc_command<Item::CommandPolygon>(); ERR_FAIL_COND(!polygon); @@ -830,16 +886,16 @@ void RenderingServerCanvas::canvas_item_add_polygon(RID p_item, const Vector<Poi polygon->polygon.create(indices, p_points, p_colors, p_uvs); } -void RenderingServerCanvas::canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, const Vector<int> &p_bones, const Vector<float> &p_weights, RID p_texture, int p_count) { +void RendererCanvasCull::canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, const Vector<int> &p_bones, const Vector<float> &p_weights, RID p_texture, int p_count) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); int vertex_count = p_points.size(); ERR_FAIL_COND(vertex_count == 0); - ERR_FAIL_COND(!p_colors.empty() && p_colors.size() != vertex_count && p_colors.size() != 1); - ERR_FAIL_COND(!p_uvs.empty() && p_uvs.size() != vertex_count); - ERR_FAIL_COND(!p_bones.empty() && p_bones.size() != vertex_count * 4); - ERR_FAIL_COND(!p_weights.empty() && p_weights.size() != vertex_count * 4); + ERR_FAIL_COND(!p_colors.is_empty() && p_colors.size() != vertex_count && p_colors.size() != 1); + ERR_FAIL_COND(!p_uvs.is_empty() && p_uvs.size() != vertex_count); + ERR_FAIL_COND(!p_bones.is_empty() && p_bones.size() != vertex_count * 4); + ERR_FAIL_COND(!p_weights.is_empty() && p_weights.size() != vertex_count * 4); Vector<int> indices = p_indices; @@ -853,7 +909,7 @@ void RenderingServerCanvas::canvas_item_add_triangle_array(RID p_item, const Vec polygon->primitive = RS::PRIMITIVE_TRIANGLES; } -void RenderingServerCanvas::canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform) { +void RendererCanvasCull::canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -862,7 +918,7 @@ void RenderingServerCanvas::canvas_item_add_set_transform(RID p_item, const Tran tr->xform = p_transform; } -void RenderingServerCanvas::canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform, const Color &p_modulate, RID p_texture) { +void RendererCanvasCull::canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform, const Color &p_modulate, RID p_texture) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -876,7 +932,7 @@ void RenderingServerCanvas::canvas_item_add_mesh(RID p_item, const RID &p_mesh, m->modulate = p_modulate; } -void RenderingServerCanvas::canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture) { +void RendererCanvasCull::canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -890,7 +946,7 @@ void RenderingServerCanvas::canvas_item_add_particles(RID p_item, RID p_particle RSG::storage->particles_request_process(p_particles); } -void RenderingServerCanvas::canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture) { +void RendererCanvasCull::canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -901,7 +957,7 @@ void RenderingServerCanvas::canvas_item_add_multimesh(RID p_item, RID p_mesh, RI mm->texture = p_texture; } -void RenderingServerCanvas::canvas_item_add_clip_ignore(RID p_item, bool p_ignore) { +void RendererCanvasCull::canvas_item_add_clip_ignore(RID p_item, bool p_ignore) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -910,7 +966,7 @@ void RenderingServerCanvas::canvas_item_add_clip_ignore(RID p_item, bool p_ignor ci->ignore = p_ignore; } -void RenderingServerCanvas::canvas_item_set_sort_children_by_y(RID p_item, bool p_enable) { +void RendererCanvasCull::canvas_item_set_sort_children_by_y(RID p_item, bool p_enable) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -919,7 +975,7 @@ void RenderingServerCanvas::canvas_item_set_sort_children_by_y(RID p_item, bool _mark_ysort_dirty(canvas_item, canvas_item_owner); } -void RenderingServerCanvas::canvas_item_set_z_index(RID p_item, int p_z) { +void RendererCanvasCull::canvas_item_set_z_index(RID p_item, int p_z) { ERR_FAIL_COND(p_z < RS::CANVAS_ITEM_Z_MIN || p_z > RS::CANVAS_ITEM_Z_MAX); Item *canvas_item = canvas_item_owner.getornull(p_item); @@ -928,25 +984,25 @@ void RenderingServerCanvas::canvas_item_set_z_index(RID p_item, int p_z) { canvas_item->z_index = p_z; } -void RenderingServerCanvas::canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable) { +void RendererCanvasCull::canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->z_relative = p_enable; } -void RenderingServerCanvas::canvas_item_attach_skeleton(RID p_item, RID p_skeleton) { +void RendererCanvasCull::canvas_item_attach_skeleton(RID p_item, RID p_skeleton) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->skeleton = p_skeleton; } -void RenderingServerCanvas::canvas_item_set_copy_to_backbuffer(RID p_item, bool p_enable, const Rect2 &p_rect) { +void RendererCanvasCull::canvas_item_set_copy_to_backbuffer(RID p_item, bool p_enable, const Rect2 &p_rect) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); if (p_enable && (canvas_item->copy_back_buffer == nullptr)) { - canvas_item->copy_back_buffer = memnew(RasterizerCanvas::Item::CopyBackBuffer); + canvas_item->copy_back_buffer = memnew(RendererCanvasRender::Item::CopyBackBuffer); } if (!p_enable && (canvas_item->copy_back_buffer != nullptr)) { memdelete(canvas_item->copy_back_buffer); @@ -959,14 +1015,14 @@ void RenderingServerCanvas::canvas_item_set_copy_to_backbuffer(RID p_item, bool } } -void RenderingServerCanvas::canvas_item_clear(RID p_item) { +void RendererCanvasCull::canvas_item_clear(RID p_item) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->clear(); } -void RenderingServerCanvas::canvas_item_set_draw_index(RID p_item, int p_index) { +void RendererCanvasCull::canvas_item_set_draw_index(RID p_item, int p_index) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -985,21 +1041,21 @@ void RenderingServerCanvas::canvas_item_set_draw_index(RID p_item, int p_index) } } -void RenderingServerCanvas::canvas_item_set_material(RID p_item, RID p_material) { +void RendererCanvasCull::canvas_item_set_material(RID p_item, RID p_material) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->material = p_material; } -void RenderingServerCanvas::canvas_item_set_use_parent_material(RID p_item, bool p_enable) { +void RendererCanvasCull::canvas_item_set_use_parent_material(RID p_item, bool p_enable) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->use_parent_material = p_enable; } -void RenderingServerCanvas::canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin, bool p_fit_empty, float p_fit_margin, bool p_blur_mipmaps) { +void RendererCanvasCull::canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin, bool p_fit_empty, float p_fit_margin, bool p_blur_mipmaps) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -1010,7 +1066,7 @@ void RenderingServerCanvas::canvas_item_set_canvas_group_mode(RID p_item, RS::Ca } } else { if (canvas_item->canvas_group == nullptr) { - canvas_item->canvas_group = memnew(RasterizerCanvas::Item::CanvasGroup); + canvas_item->canvas_group = memnew(RendererCanvasRender::Item::CanvasGroup); } canvas_item->canvas_group->mode = p_mode; canvas_item->canvas_group->fit_empty = p_fit_empty; @@ -1020,14 +1076,17 @@ void RenderingServerCanvas::canvas_item_set_canvas_group_mode(RID p_item, RS::Ca } } -RID RenderingServerCanvas::canvas_light_create() { - RasterizerCanvas::Light *clight = memnew(RasterizerCanvas::Light); +RID RendererCanvasCull::canvas_light_allocate() { + return canvas_light_owner.allocate_rid(); +} +void RendererCanvasCull::canvas_light_initialize(RID p_rid) { + RendererCanvasRender::Light *clight = memnew(RendererCanvasRender::Light); clight->light_internal = RSG::canvas_render->light_create(); - return canvas_light_owner.make_rid(clight); + return canvas_light_owner.initialize_rid(p_rid, clight); } -void RenderingServerCanvas::canvas_light_set_mode(RID p_light, RS::CanvasLightMode p_mode) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_mode(RID p_light, RS::CanvasLightMode p_mode) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); if (clight->mode == p_mode) { @@ -1047,8 +1106,8 @@ void RenderingServerCanvas::canvas_light_set_mode(RID p_light, RS::CanvasLightMo } } -void RenderingServerCanvas::canvas_light_attach_to_canvas(RID p_light, RID p_canvas) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_attach_to_canvas(RID p_light, RID p_canvas) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); if (clight->canvas.is_valid()) { @@ -1076,29 +1135,29 @@ void RenderingServerCanvas::canvas_light_attach_to_canvas(RID p_light, RID p_can } } -void RenderingServerCanvas::canvas_light_set_enabled(RID p_light, bool p_enabled) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_enabled(RID p_light, bool p_enabled) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->enabled = p_enabled; } -void RenderingServerCanvas::canvas_light_set_texture_scale(RID p_light, float p_scale) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_texture_scale(RID p_light, float p_scale) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->scale = p_scale; } -void RenderingServerCanvas::canvas_light_set_transform(RID p_light, const Transform2D &p_transform) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_transform(RID p_light, const Transform2D &p_transform) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->xform = p_transform; } -void RenderingServerCanvas::canvas_light_set_texture(RID p_light, RID p_texture) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_texture(RID p_light, RID p_texture) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); if (clight->texture == p_texture) { @@ -1109,80 +1168,80 @@ void RenderingServerCanvas::canvas_light_set_texture(RID p_light, RID p_texture) RSG::canvas_render->light_set_texture(clight->light_internal, p_texture); } -void RenderingServerCanvas::canvas_light_set_texture_offset(RID p_light, const Vector2 &p_offset) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_texture_offset(RID p_light, const Vector2 &p_offset) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->texture_offset = p_offset; } -void RenderingServerCanvas::canvas_light_set_color(RID p_light, const Color &p_color) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_color(RID p_light, const Color &p_color) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->color = p_color; } -void RenderingServerCanvas::canvas_light_set_height(RID p_light, float p_height) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_height(RID p_light, float p_height) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->height = p_height; } -void RenderingServerCanvas::canvas_light_set_energy(RID p_light, float p_energy) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_energy(RID p_light, float p_energy) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->energy = p_energy; } -void RenderingServerCanvas::canvas_light_set_z_range(RID p_light, int p_min_z, int p_max_z) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_z_range(RID p_light, int p_min_z, int p_max_z) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->z_min = p_min_z; clight->z_max = p_max_z; } -void RenderingServerCanvas::canvas_light_set_layer_range(RID p_light, int p_min_layer, int p_max_layer) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_layer_range(RID p_light, int p_min_layer, int p_max_layer) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->layer_max = p_max_layer; clight->layer_min = p_min_layer; } -void RenderingServerCanvas::canvas_light_set_item_cull_mask(RID p_light, int p_mask) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_item_cull_mask(RID p_light, int p_mask) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->item_mask = p_mask; } -void RenderingServerCanvas::canvas_light_set_item_shadow_cull_mask(RID p_light, int p_mask) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_item_shadow_cull_mask(RID p_light, int p_mask) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->item_shadow_mask = p_mask; } -void RenderingServerCanvas::canvas_light_set_directional_distance(RID p_light, float p_distance) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_directional_distance(RID p_light, float p_distance) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->directional_distance = p_distance; } -void RenderingServerCanvas::canvas_light_set_blend_mode(RID p_light, RS::CanvasLightBlendMode p_mode) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_blend_mode(RID p_light, RS::CanvasLightBlendMode p_mode) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->blend_mode = p_mode; } -void RenderingServerCanvas::canvas_light_set_shadow_enabled(RID p_light, bool p_enabled) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_shadow_enabled(RID p_light, bool p_enabled) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); if (clight->use_shadow == p_enabled) { @@ -1193,34 +1252,37 @@ void RenderingServerCanvas::canvas_light_set_shadow_enabled(RID p_light, bool p_ RSG::canvas_render->light_set_use_shadow(clight->light_internal, clight->use_shadow); } -void RenderingServerCanvas::canvas_light_set_shadow_filter(RID p_light, RS::CanvasLightShadowFilter p_filter) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_shadow_filter(RID p_light, RS::CanvasLightShadowFilter p_filter) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->shadow_filter = p_filter; } -void RenderingServerCanvas::canvas_light_set_shadow_color(RID p_light, const Color &p_color) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_shadow_color(RID p_light, const Color &p_color) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->shadow_color = p_color; } -void RenderingServerCanvas::canvas_light_set_shadow_smooth(RID p_light, float p_smooth) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_shadow_smooth(RID p_light, float p_smooth) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->shadow_smooth = p_smooth; } -RID RenderingServerCanvas::canvas_light_occluder_create() { - RasterizerCanvas::LightOccluderInstance *occluder = memnew(RasterizerCanvas::LightOccluderInstance); +RID RendererCanvasCull::canvas_light_occluder_allocate() { + return canvas_light_occluder_owner.allocate_rid(); +} +void RendererCanvasCull::canvas_light_occluder_initialize(RID p_rid) { + RendererCanvasRender::LightOccluderInstance *occluder = memnew(RendererCanvasRender::LightOccluderInstance); - return canvas_light_occluder_owner.make_rid(occluder); + return canvas_light_occluder_owner.initialize_rid(p_rid, occluder); } -void RenderingServerCanvas::canvas_light_occluder_attach_to_canvas(RID p_occluder, RID p_canvas) { - RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); +void RendererCanvasCull::canvas_light_occluder_attach_to_canvas(RID p_occluder, RID p_canvas) { + RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); ERR_FAIL_COND(!occluder); if (occluder->canvas.is_valid()) { @@ -1240,15 +1302,15 @@ void RenderingServerCanvas::canvas_light_occluder_attach_to_canvas(RID p_occlude } } -void RenderingServerCanvas::canvas_light_occluder_set_enabled(RID p_occluder, bool p_enabled) { - RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); +void RendererCanvasCull::canvas_light_occluder_set_enabled(RID p_occluder, bool p_enabled) { + RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); ERR_FAIL_COND(!occluder); occluder->enabled = p_enabled; } -void RenderingServerCanvas::canvas_light_occluder_set_polygon(RID p_occluder, RID p_polygon) { - RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); +void RendererCanvasCull::canvas_light_occluder_set_polygon(RID p_occluder, RID p_polygon) { + RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); ERR_FAIL_COND(!occluder); if (occluder->polygon.is_valid()) { @@ -1275,32 +1337,35 @@ void RenderingServerCanvas::canvas_light_occluder_set_polygon(RID p_occluder, RI } } -void RenderingServerCanvas::canvas_light_occluder_set_as_sdf_collision(RID p_occluder, bool p_enable) { - RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); +void RendererCanvasCull::canvas_light_occluder_set_as_sdf_collision(RID p_occluder, bool p_enable) { + RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); ERR_FAIL_COND(!occluder); } -void RenderingServerCanvas::canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform) { - RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); +void RendererCanvasCull::canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform) { + RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); ERR_FAIL_COND(!occluder); occluder->xform = p_xform; } -void RenderingServerCanvas::canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask) { - RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); +void RendererCanvasCull::canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask) { + RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); ERR_FAIL_COND(!occluder); occluder->light_mask = p_mask; } -RID RenderingServerCanvas::canvas_occluder_polygon_create() { +RID RendererCanvasCull::canvas_occluder_polygon_allocate() { + return canvas_light_occluder_polygon_owner.allocate_rid(); +} +void RendererCanvasCull::canvas_occluder_polygon_initialize(RID p_rid) { LightOccluderPolygon *occluder_poly = memnew(LightOccluderPolygon); occluder_poly->occluder = RSG::canvas_render->occluder_polygon_create(); - return canvas_light_occluder_polygon_owner.make_rid(occluder_poly); + return canvas_light_occluder_polygon_owner.initialize_rid(p_rid, occluder_poly); } -void RenderingServerCanvas::canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const Vector<Vector2> &p_shape, bool p_closed) { +void RendererCanvasCull::canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const Vector<Vector2> &p_shape, bool p_closed) { LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_occluder_polygon); ERR_FAIL_COND(!occluder_poly); @@ -1319,66 +1384,69 @@ void RenderingServerCanvas::canvas_occluder_polygon_set_shape(RID p_occluder_pol RSG::canvas_render->occluder_polygon_set_shape(occluder_poly->occluder, p_shape, p_closed); - for (Set<RasterizerCanvas::LightOccluderInstance *>::Element *E = occluder_poly->owners.front(); E; E = E->next()) { + for (Set<RendererCanvasRender::LightOccluderInstance *>::Element *E = occluder_poly->owners.front(); E; E = E->next()) { E->get()->aabb_cache = occluder_poly->aabb; } } -void RenderingServerCanvas::canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon, RS::CanvasOccluderPolygonCullMode p_mode) { +void RendererCanvasCull::canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon, RS::CanvasOccluderPolygonCullMode p_mode) { LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_occluder_polygon); ERR_FAIL_COND(!occluder_poly); occluder_poly->cull_mode = p_mode; RSG::canvas_render->occluder_polygon_set_cull_mode(occluder_poly->occluder, p_mode); - for (Set<RasterizerCanvas::LightOccluderInstance *>::Element *E = occluder_poly->owners.front(); E; E = E->next()) { + for (Set<RendererCanvasRender::LightOccluderInstance *>::Element *E = occluder_poly->owners.front(); E; E = E->next()) { E->get()->cull_cache = p_mode; } } -void RenderingServerCanvas::canvas_set_shadow_texture_size(int p_size) { +void RendererCanvasCull::canvas_set_shadow_texture_size(int p_size) { RSG::canvas_render->set_shadow_texture_size(p_size); } -RID RenderingServerCanvas::canvas_texture_create() { - return RSG::storage->canvas_texture_create(); +RID RendererCanvasCull::canvas_texture_allocate() { + return RSG::storage->canvas_texture_allocate(); +} +void RendererCanvasCull::canvas_texture_initialize(RID p_rid) { + RSG::storage->canvas_texture_initialize(p_rid); } -void RenderingServerCanvas::canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) { +void RendererCanvasCull::canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) { RSG::storage->canvas_texture_set_channel(p_canvas_texture, p_channel, p_texture); } -void RenderingServerCanvas::canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_base_color, float p_shininess) { +void RendererCanvasCull::canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_base_color, float p_shininess) { RSG::storage->canvas_texture_set_shading_parameters(p_canvas_texture, p_base_color, p_shininess); } -void RenderingServerCanvas::canvas_texture_set_texture_filter(RID p_canvas_texture, RS::CanvasItemTextureFilter p_filter) { +void RendererCanvasCull::canvas_texture_set_texture_filter(RID p_canvas_texture, RS::CanvasItemTextureFilter p_filter) { RSG::storage->canvas_texture_set_texture_filter(p_canvas_texture, p_filter); } -void RenderingServerCanvas::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS::CanvasItemTextureRepeat p_repeat) { +void RendererCanvasCull::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS::CanvasItemTextureRepeat p_repeat) { RSG::storage->canvas_texture_set_texture_repeat(p_canvas_texture, p_repeat); } -void RenderingServerCanvas::canvas_item_set_default_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) { +void RendererCanvasCull::canvas_item_set_default_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) { Item *ci = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!ci); ci->texture_filter = p_filter; } -void RenderingServerCanvas::canvas_item_set_default_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) { +void RendererCanvasCull::canvas_item_set_default_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) { Item *ci = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!ci); ci->texture_repeat = p_repeat; } -bool RenderingServerCanvas::free(RID p_rid) { +bool RendererCanvasCull::free(RID p_rid) { if (canvas_owner.owns(p_rid)) { Canvas *canvas = canvas_owner.getornull(p_rid); ERR_FAIL_COND_V(!canvas, false); while (canvas->viewports.size()) { - RenderingServerViewport::Viewport *vp = RSG::viewport->viewport_owner.getornull(canvas->viewports.front()->get()); + RendererViewport::Viewport *vp = RSG::viewport->viewport_owner.getornull(canvas->viewports.front()->get()); ERR_FAIL_COND_V(!vp, true); - Map<RID, RenderingServerViewport::Viewport::CanvasData>::Element *E = vp->canvas_map.find(p_rid); + Map<RID, RendererViewport::Viewport::CanvasData>::Element *E = vp->canvas_map.find(p_rid); ERR_FAIL_COND_V(!E, true); vp->canvas_map.erase(p_rid); @@ -1389,11 +1457,11 @@ bool RenderingServerCanvas::free(RID p_rid) { canvas->child_items[i].item->parent = RID(); } - for (Set<RasterizerCanvas::Light *>::Element *E = canvas->lights.front(); E; E = E->next()) { + for (Set<RendererCanvasRender::Light *>::Element *E = canvas->lights.front(); E; E = E->next()) { E->get()->canvas = RID(); } - for (Set<RasterizerCanvas::LightOccluderInstance *>::Element *E = canvas->occluders.front(); E; E = E->next()) { + for (Set<RendererCanvasRender::LightOccluderInstance *>::Element *E = canvas->occluders.front(); E; E = E->next()) { E->get()->canvas = RID(); } @@ -1434,7 +1502,7 @@ bool RenderingServerCanvas::free(RID p_rid) { memdelete(canvas_item); } else if (canvas_light_owner.owns(p_rid)) { - RasterizerCanvas::Light *canvas_light = canvas_light_owner.getornull(p_rid); + RendererCanvasRender::Light *canvas_light = canvas_light_owner.getornull(p_rid); ERR_FAIL_COND_V(!canvas_light, true); if (canvas_light->canvas.is_valid()) { @@ -1450,7 +1518,7 @@ bool RenderingServerCanvas::free(RID p_rid) { memdelete(canvas_light); } else if (canvas_light_occluder_owner.owns(p_rid)) { - RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_rid); + RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_rid); ERR_FAIL_COND_V(!occluder, true); if (occluder->polygon.is_valid()) { @@ -1487,14 +1555,14 @@ bool RenderingServerCanvas::free(RID p_rid) { return true; } -RenderingServerCanvas::RenderingServerCanvas() { - z_list = (RasterizerCanvas::Item **)memalloc(z_range * sizeof(RasterizerCanvas::Item *)); - z_last_list = (RasterizerCanvas::Item **)memalloc(z_range * sizeof(RasterizerCanvas::Item *)); +RendererCanvasCull::RendererCanvasCull() { + z_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *)); + z_last_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *)); disable_scale = false; } -RenderingServerCanvas::~RenderingServerCanvas() { +RendererCanvasCull::~RendererCanvasCull() { memfree(z_list); memfree(z_last_list); } diff --git a/servers/rendering/rendering_server_canvas.h b/servers/rendering/renderer_canvas_cull.h index 83b76539c4..b71f8e5a9a 100644 --- a/servers/rendering/rendering_server_canvas.h +++ b/servers/rendering/renderer_canvas_cull.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rendering_server_canvas.h */ +/* renderer_canvas_cull.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,15 +28,15 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef VISUALSERVERCANVAS_H -#define VISUALSERVERCANVAS_H +#ifndef RENDERING_SERVER_CANVAS_CULL_H +#define RENDERING_SERVER_CANVAS_CULL_H -#include "rasterizer.h" -#include "rendering_server_viewport.h" +#include "renderer_compositor.h" +#include "renderer_viewport.h" -class RenderingServerCanvas { +class RendererCanvasCull { public: - struct Item : public RasterizerCanvas::Item { + struct Item : public RendererCanvasRender::Item { RID parent; // canvas it belongs to List<Item *>::Element *E; int z_index; @@ -93,7 +93,7 @@ public: Rect2 aabb; RS::CanvasOccluderPolygonCullMode cull_mode; RID occluder; - Set<RasterizerCanvas::LightOccluderInstance *> owners; + Set<RendererCanvasRender::LightOccluderInstance *> owners; LightOccluderPolygon() { active = false; @@ -101,11 +101,11 @@ public: } }; - RID_PtrOwner<LightOccluderPolygon> canvas_light_occluder_polygon_owner; + RID_PtrOwner<LightOccluderPolygon, true> canvas_light_occluder_polygon_owner; - RID_PtrOwner<RasterizerCanvas::LightOccluderInstance> canvas_light_occluder_owner; + RID_PtrOwner<RendererCanvasRender::LightOccluderInstance, true> canvas_light_occluder_owner; - struct Canvas : public RenderingServerViewport::CanvasBase { + struct Canvas : public RendererViewport::CanvasBase { Set<RID> viewports; struct ChildItem { Point2 mirror; @@ -115,10 +115,10 @@ public: } }; - Set<RasterizerCanvas::Light *> lights; - Set<RasterizerCanvas::Light *> directional_lights; + Set<RendererCanvasRender::Light *> lights; + Set<RendererCanvasRender::Light *> directional_lights; - Set<RasterizerCanvas::LightOccluderInstance *> occluders; + Set<RendererCanvasRender::LightOccluderInstance *> occluders; bool children_order_dirty; Vector<ChildItem> child_items; @@ -148,33 +148,37 @@ public: } }; - mutable RID_PtrOwner<Canvas> canvas_owner; - RID_PtrOwner<Item> canvas_item_owner; - RID_PtrOwner<RasterizerCanvas::Light> canvas_light_owner; + mutable RID_PtrOwner<Canvas, true> canvas_owner; + RID_PtrOwner<Item, true> canvas_item_owner; + RID_PtrOwner<RendererCanvasRender::Light, true> canvas_light_owner; bool disable_scale; bool sdf_used = false; bool snapping_2d_transforms_to_pixel = false; private: - void _render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_directional_lights, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel); - void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RasterizerCanvas::Item **z_list, RasterizerCanvas::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner); + void _render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel); + void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner); - RasterizerCanvas::Item **z_list; - RasterizerCanvas::Item **z_last_list; + RendererCanvasRender::Item **z_list; + RendererCanvasRender::Item **z_last_list; public: - void render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_directional_lights, const Rect2 &p_clip_rect, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_transforms_to_pixel, bool p_snap_2d_vertices_to_pixel); + void render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, const Rect2 &p_clip_rect, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_transforms_to_pixel, bool p_snap_2d_vertices_to_pixel); bool was_sdf_used(); - RID canvas_create(); + RID canvas_allocate(); + void canvas_initialize(RID p_rid); + void canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring); void canvas_set_modulate(RID p_canvas, const Color &p_color); void canvas_set_parent(RID p_canvas, RID p_parent, float p_scale); void canvas_set_disable_scale(bool p_disable); - RID canvas_item_create(); + RID canvas_item_allocate(); + void canvas_item_initialize(RID p_rid); + void canvas_item_set_parent(RID p_item, RID p_parent); void canvas_item_set_visible(RID p_item, bool p_visible); @@ -192,7 +196,7 @@ public: void canvas_item_set_update_when_visible(RID p_item, bool p_update); void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0); - void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0); + void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false); void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0); void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color); void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color); @@ -222,7 +226,9 @@ public: void canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin = 5.0, bool p_fit_empty = false, float p_fit_margin = 0.0, bool p_blur_mipmaps = false); - RID canvas_light_create(); + RID canvas_light_allocate(); + void canvas_light_initialize(RID p_rid); + void canvas_light_set_mode(RID p_light, RS::CanvasLightMode p_mode); void canvas_light_attach_to_canvas(RID p_light, RID p_canvas); void canvas_light_set_enabled(RID p_light, bool p_enabled); @@ -246,7 +252,9 @@ public: void canvas_light_set_shadow_color(RID p_light, const Color &p_color); void canvas_light_set_shadow_smooth(RID p_light, float p_smooth); - RID canvas_light_occluder_create(); + RID canvas_light_occluder_allocate(); + void canvas_light_occluder_initialize(RID p_rid); + void canvas_light_occluder_attach_to_canvas(RID p_occluder, RID p_canvas); void canvas_light_occluder_set_enabled(RID p_occluder, bool p_enabled); void canvas_light_occluder_set_polygon(RID p_occluder, RID p_polygon); @@ -254,14 +262,18 @@ public: void canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform); void canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask); - RID canvas_occluder_polygon_create(); + RID canvas_occluder_polygon_allocate(); + void canvas_occluder_polygon_initialize(RID p_rid); + void canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const Vector<Vector2> &p_shape, bool p_closed); void canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon, RS::CanvasOccluderPolygonCullMode p_mode); void canvas_set_shadow_texture_size(int p_size); - RID canvas_texture_create(); + RID canvas_texture_allocate(); + void canvas_texture_initialize(RID p_rid); + void canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture); void canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_base_color, float p_shininess); @@ -272,8 +284,8 @@ public: void canvas_item_set_default_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat); bool free(RID p_rid); - RenderingServerCanvas(); - ~RenderingServerCanvas(); + RendererCanvasCull(); + ~RendererCanvasCull(); }; #endif // VISUALSERVERCANVAS_H diff --git a/servers/rendering/renderer_canvas_render.cpp b/servers/rendering/renderer_canvas_render.cpp new file mode 100644 index 0000000000..1945435586 --- /dev/null +++ b/servers/rendering/renderer_canvas_render.cpp @@ -0,0 +1,31 @@ +/*************************************************************************/ +/* renderer_canvas_render.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "renderer_canvas_render.h" diff --git a/servers/rendering/renderer_canvas_render.h b/servers/rendering/renderer_canvas_render.h new file mode 100644 index 0000000000..f08986b021 --- /dev/null +++ b/servers/rendering/renderer_canvas_render.h @@ -0,0 +1,604 @@ +/*************************************************************************/ +/* renderer_canvas_render.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RENDERINGSERVERCANVASRENDER_H +#define RENDERINGSERVERCANVASRENDER_H + +#include "servers/rendering/renderer_storage.h" + +class RendererCanvasRender { +public: + static RendererCanvasRender *singleton; + + enum CanvasRectFlags { + CANVAS_RECT_REGION = 1, + CANVAS_RECT_TILE = 2, + CANVAS_RECT_FLIP_H = 4, + CANVAS_RECT_FLIP_V = 8, + CANVAS_RECT_TRANSPOSE = 16, + CANVAS_RECT_CLIP_UV = 32, + CANVAS_RECT_IS_GROUP = 64, + }; + + struct Light { + bool enabled; + Color color; + Transform2D xform; + float height; + float energy; + float scale; + int z_min; + int z_max; + int layer_min; + int layer_max; + int item_mask; + int item_shadow_mask; + float directional_distance; + RS::CanvasLightMode mode; + RS::CanvasLightBlendMode blend_mode; + RID texture; + Vector2 texture_offset; + RID canvas; + bool use_shadow; + int shadow_buffer_size; + RS::CanvasLightShadowFilter shadow_filter; + Color shadow_color; + float shadow_smooth; + + //void *texture_cache; // implementation dependent + Rect2 rect_cache; + Transform2D xform_cache; + float radius_cache; //used for shadow far plane + //CameraMatrix shadow_matrix_cache; + + Transform2D light_shader_xform; + //Vector2 light_shader_pos; + + Light *shadows_next_ptr; + Light *filter_next_ptr; + Light *next_ptr; + Light *directional_next_ptr; + + RID light_internal; + uint64_t version; + + int32_t render_index_cache; + + Light() { + version = 0; + enabled = true; + color = Color(1, 1, 1); + shadow_color = Color(0, 0, 0, 0); + height = 0; + z_min = -1024; + z_max = 1024; + layer_min = 0; + layer_max = 0; + item_mask = 1; + scale = 1.0; + energy = 1.0; + item_shadow_mask = 1; + mode = RS::CANVAS_LIGHT_MODE_POINT; + blend_mode = RS::CANVAS_LIGHT_BLEND_MODE_ADD; + // texture_cache = nullptr; + next_ptr = nullptr; + directional_next_ptr = nullptr; + filter_next_ptr = nullptr; + use_shadow = false; + shadow_buffer_size = 2048; + shadow_filter = RS::CANVAS_LIGHT_FILTER_NONE; + shadow_smooth = 0.0; + render_index_cache = -1; + directional_distance = 10000.0; + } + }; + + //easier wrap to avoid mistakes + + struct Item; + + typedef uint64_t PolygonID; + virtual PolygonID request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>()) = 0; + virtual void free_polygon(PolygonID p_polygon) = 0; + + //also easier to wrap to avoid mistakes + struct Polygon { + PolygonID polygon_id; + Rect2 rect_cache; + + _FORCE_INLINE_ void create(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>()) { + ERR_FAIL_COND(polygon_id != 0); + { + uint32_t pc = p_points.size(); + const Vector2 *v2 = p_points.ptr(); + rect_cache.position = *v2; + for (uint32_t i = 1; i < pc; i++) { + rect_cache.expand_to(v2[i]); + } + } + polygon_id = singleton->request_polygon(p_indices, p_points, p_colors, p_uvs, p_bones, p_weights); + } + + _FORCE_INLINE_ Polygon() { polygon_id = 0; } + _FORCE_INLINE_ ~Polygon() { + if (polygon_id) { + singleton->free_polygon(polygon_id); + } + } + }; + + //item + + struct Item { + //commands are allocated in blocks of 4k to improve performance + //and cache coherence. + //blocks always grow but never shrink. + + struct CommandBlock { + enum { + MAX_SIZE = 4096 + }; + uint32_t usage; + uint8_t *memory; + }; + + struct Command { + enum Type { + TYPE_RECT, + TYPE_NINEPATCH, + TYPE_POLYGON, + TYPE_PRIMITIVE, + TYPE_MESH, + TYPE_MULTIMESH, + TYPE_PARTICLES, + TYPE_TRANSFORM, + TYPE_CLIP_IGNORE, + }; + + Command *next; + Type type; + virtual ~Command() {} + }; + + struct CommandRect : public Command { + Rect2 rect; + Color modulate; + Rect2 source; + uint8_t flags; + + RID texture; + + CommandRect() { + flags = 0; + type = TYPE_RECT; + } + }; + + struct CommandNinePatch : public Command { + Rect2 rect; + Rect2 source; + float margin[4]; + bool draw_center; + Color color; + RS::NinePatchAxisMode axis_x; + RS::NinePatchAxisMode axis_y; + + RID texture; + + CommandNinePatch() { + draw_center = true; + type = TYPE_NINEPATCH; + } + }; + + struct CommandPolygon : public Command { + RS::PrimitiveType primitive; + Polygon polygon; + + RID texture; + + CommandPolygon() { + type = TYPE_POLYGON; + } + }; + + struct CommandPrimitive : public Command { + uint32_t point_count; + Vector2 points[4]; + Vector2 uvs[4]; + Color colors[4]; + + RID texture; + + CommandPrimitive() { + type = TYPE_PRIMITIVE; + } + }; + + struct CommandMesh : public Command { + RID mesh; + Transform2D transform; + Color modulate; + + RID texture; + + CommandMesh() { type = TYPE_MESH; } + }; + + struct CommandMultiMesh : public Command { + RID multimesh; + + RID texture; + + CommandMultiMesh() { type = TYPE_MULTIMESH; } + }; + + struct CommandParticles : public Command { + RID particles; + + RID texture; + + CommandParticles() { type = TYPE_PARTICLES; } + }; + + struct CommandTransform : public Command { + Transform2D xform; + CommandTransform() { type = TYPE_TRANSFORM; } + }; + + struct CommandClipIgnore : public Command { + bool ignore; + CommandClipIgnore() { + type = TYPE_CLIP_IGNORE; + ignore = false; + } + }; + + struct ViewportRender { + RenderingServer *owner; + void *udata; + Rect2 rect; + }; + + Transform2D xform; + bool clip; + bool visible; + bool behind; + bool update_when_visible; + + struct CanvasGroup { + RS::CanvasGroupMode mode; + bool fit_empty; + float fit_margin; + bool blur_mipmaps; + float clear_margin; + }; + + CanvasGroup *canvas_group = nullptr; + int light_mask; + int z_final; + + mutable bool custom_rect; + mutable bool rect_dirty; + mutable Rect2 rect; + RID material; + RID skeleton; + + Item *next; + + struct CopyBackBuffer { + Rect2 rect; + Rect2 screen_rect; + bool full; + }; + CopyBackBuffer *copy_back_buffer; + + Color final_modulate; + Transform2D final_transform; + Rect2 final_clip_rect; + Item *final_clip_owner; + Item *material_owner; + Item *canvas_group_owner; + ViewportRender *vp_render; + bool distance_field; + bool light_masked; + + Rect2 global_rect_cache; + + const Rect2 &get_rect() const { + if (custom_rect || (!rect_dirty && !update_when_visible)) { + return rect; + } + + //must update rect + + if (commands == nullptr) { + rect = Rect2(); + rect_dirty = false; + return rect; + } + + Transform2D xf; + bool found_xform = false; + bool first = true; + + const Item::Command *c = commands; + + while (c) { + Rect2 r; + + switch (c->type) { + case Item::Command::TYPE_RECT: { + const Item::CommandRect *crect = static_cast<const Item::CommandRect *>(c); + r = crect->rect; + + } break; + case Item::Command::TYPE_NINEPATCH: { + const Item::CommandNinePatch *style = static_cast<const Item::CommandNinePatch *>(c); + r = style->rect; + } break; + + case Item::Command::TYPE_POLYGON: { + const Item::CommandPolygon *polygon = static_cast<const Item::CommandPolygon *>(c); + r = polygon->polygon.rect_cache; + } break; + case Item::Command::TYPE_PRIMITIVE: { + const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(c); + for (uint32_t j = 0; j < primitive->point_count; j++) { + if (j == 0) { + r.position = primitive->points[0]; + } else { + r.expand_to(primitive->points[j]); + } + } + } break; + case Item::Command::TYPE_MESH: { + const Item::CommandMesh *mesh = static_cast<const Item::CommandMesh *>(c); + AABB aabb = RendererStorage::base_singleton->mesh_get_aabb(mesh->mesh, RID()); + + r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y); + + } break; + case Item::Command::TYPE_MULTIMESH: { + const Item::CommandMultiMesh *multimesh = static_cast<const Item::CommandMultiMesh *>(c); + AABB aabb = RendererStorage::base_singleton->multimesh_get_aabb(multimesh->multimesh); + + r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y); + + } break; + case Item::Command::TYPE_PARTICLES: { + const Item::CommandParticles *particles_cmd = static_cast<const Item::CommandParticles *>(c); + if (particles_cmd->particles.is_valid()) { + AABB aabb = RendererStorage::base_singleton->particles_get_aabb(particles_cmd->particles); + r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y); + } + + } break; + case Item::Command::TYPE_TRANSFORM: { + const Item::CommandTransform *transform = static_cast<const Item::CommandTransform *>(c); + xf = transform->xform; + found_xform = true; + [[fallthrough]]; + } + default: { + c = c->next; + continue; + } + } + + if (found_xform) { + r = xf.xform(r); + found_xform = false; + } + + if (first) { + rect = r; + first = false; + } else { + rect = rect.merge(r); + } + c = c->next; + } + + rect_dirty = false; + return rect; + } + + Command *commands; + Command *last_command; + Vector<CommandBlock> blocks; + uint32_t current_block; + + template <class T> + T *alloc_command() { + T *command; + if (commands == nullptr) { + // As the most common use case of canvas items is to + // use only one command, the first is done with it's + // own allocation. The rest of them use blocks. + command = memnew(T); + command->next = nullptr; + commands = command; + last_command = command; + } else { + //Subsequent commands go into a block. + + while (true) { + if (unlikely(current_block == (uint32_t)blocks.size())) { + // If we need more blocks, we allocate them + // (they won't be freed until this CanvasItem is + // deleted, though). + CommandBlock cb; + cb.memory = (uint8_t *)memalloc(CommandBlock::MAX_SIZE); + cb.usage = 0; + blocks.push_back(cb); + } + + CommandBlock *c = &blocks.write[current_block]; + size_t space_left = CommandBlock::MAX_SIZE - c->usage; + if (space_left < sizeof(T)) { + current_block++; + continue; + } + + //allocate block and add to the linked list + void *memory = c->memory + c->usage; + command = memnew_placement(memory, T); + command->next = nullptr; + last_command->next = command; + last_command = command; + c->usage += sizeof(T); + break; + } + } + + rect_dirty = true; + return command; + } + + void clear() { + // The first one is always allocated on heap + // the rest go in the blocks + Command *c = commands; + while (c) { + Command *n = c->next; + if (c == commands) { + memdelete(commands); + commands = nullptr; + } else { + c->~Command(); + } + c = n; + } + { + uint32_t cbc = MIN((current_block + 1), (uint32_t)blocks.size()); + CommandBlock *blockptr = blocks.ptrw(); + for (uint32_t i = 0; i < cbc; i++) { + blockptr[i].usage = 0; + } + } + + last_command = nullptr; + commands = nullptr; + current_block = 0; + clip = false; + rect_dirty = true; + final_clip_owner = nullptr; + material_owner = nullptr; + light_masked = false; + } + + RS::CanvasItemTextureFilter texture_filter; + RS::CanvasItemTextureRepeat texture_repeat; + + Item() { + commands = nullptr; + last_command = nullptr; + current_block = 0; + light_mask = 1; + vp_render = nullptr; + next = nullptr; + final_clip_owner = nullptr; + canvas_group_owner = nullptr; + clip = false; + final_modulate = Color(1, 1, 1, 1); + visible = true; + rect_dirty = true; + custom_rect = false; + behind = false; + material_owner = nullptr; + copy_back_buffer = nullptr; + distance_field = false; + light_masked = false; + update_when_visible = false; + z_final = 0; + texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT; + texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT; + } + virtual ~Item() { + clear(); + for (int i = 0; i < blocks.size(); i++) { + memfree(blocks[i].memory); + } + if (copy_back_buffer) { + memdelete(copy_back_buffer); + } + } + }; + + virtual void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) = 0; + virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) = 0; + + struct LightOccluderInstance { + bool enabled; + RID canvas; + RID polygon; + RID occluder; + Rect2 aabb_cache; + Transform2D xform; + Transform2D xform_cache; + int light_mask; + bool sdf_collision; + RS::CanvasOccluderPolygonCullMode cull_cache; + + LightOccluderInstance *next; + + LightOccluderInstance() { + enabled = true; + sdf_collision = false; + next = nullptr; + light_mask = 1; + cull_cache = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED; + } + }; + + virtual RID light_create() = 0; + virtual void light_set_texture(RID p_rid, RID p_texture) = 0; + virtual void light_set_use_shadow(RID p_rid, bool p_enable) = 0; + virtual void light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) = 0; + virtual void light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders) = 0; + + virtual void render_sdf(RID p_render_target, LightOccluderInstance *p_occluders) = 0; + + virtual RID occluder_polygon_create() = 0; + virtual void occluder_polygon_set_shape(RID p_occluder, const Vector<Vector2> &p_points, bool p_closed) = 0; + virtual void occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) = 0; + virtual void set_shadow_texture_size(int p_size) = 0; + + virtual void draw_window_margins(int *p_margins, RID *p_margin_textures) = 0; + + virtual bool free(RID p_rid) = 0; + virtual void update() = 0; + + RendererCanvasRender() { singleton = this; } + virtual ~RendererCanvasRender() {} +}; + +#endif // RENDERINGSERVERCANVASRENDER_H diff --git a/servers/rendering/renderer_compositor.cpp b/servers/rendering/renderer_compositor.cpp new file mode 100644 index 0000000000..8861522d34 --- /dev/null +++ b/servers/rendering/renderer_compositor.cpp @@ -0,0 +1,42 @@ +/*************************************************************************/ +/* renderer_compositor.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "renderer_compositor.h" + +#include "core/os/os.h" +#include "core/string/print_string.h" + +RendererCompositor *(*RendererCompositor::_create_func)() = nullptr; + +RendererCompositor *RendererCompositor::create() { + return _create_func(); +} + +RendererCanvasRender *RendererCanvasRender::singleton = nullptr; diff --git a/servers/rendering/renderer_compositor.h b/servers/rendering/renderer_compositor.h new file mode 100644 index 0000000000..919ae2c6da --- /dev/null +++ b/servers/rendering/renderer_compositor.h @@ -0,0 +1,78 @@ +/*************************************************************************/ +/* renderer_compositor.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RENDERING_SERVER_COMPOSITOR_H +#define RENDERING_SERVER_COMPOSITOR_H + +#include "core/math/camera_matrix.h" +#include "core/templates/pair.h" +#include "core/templates/self_list.h" +#include "servers/rendering/renderer_canvas_render.h" +#include "servers/rendering/renderer_scene.h" +#include "servers/rendering/renderer_scene_render.h" +#include "servers/rendering/renderer_storage.h" +#include "servers/rendering_server.h" + +class RendererCompositor { +protected: + static RendererCompositor *(*_create_func)(); + +public: + static RendererCompositor *create(); + + virtual RendererStorage *get_storage() = 0; + virtual RendererCanvasRender *get_canvas() = 0; + virtual RendererSceneRender *get_scene() = 0; + + virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true) = 0; + + virtual void initialize() = 0; + virtual void begin_frame(double frame_step) = 0; + + struct BlitToScreen { + RID render_target; + Rect2i rect; + //lens distorted parameters for VR should go here + }; + + virtual void prepare_for_blitting_render_targets() = 0; + virtual void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) = 0; + + virtual void end_frame(bool p_swap_buffers) = 0; + virtual void finalize() = 0; + virtual uint64_t get_frame_number() const = 0; + virtual float get_frame_delta_time() const = 0; + + virtual bool is_low_end() const = 0; + + virtual ~RendererCompositor() {} +}; + +#endif // RASTERIZER_H diff --git a/servers/rendering/rasterizer_rd/SCsub b/servers/rendering/renderer_rd/SCsub index 6a2e682c67..6a2e682c67 100644 --- a/servers/rendering/rasterizer_rd/SCsub +++ b/servers/rendering/renderer_rd/SCsub diff --git a/servers/rendering/renderer_rd/cluster_builder_rd.cpp b/servers/rendering/renderer_rd/cluster_builder_rd.cpp new file mode 100644 index 0000000000..0fdd864d47 --- /dev/null +++ b/servers/rendering/renderer_rd/cluster_builder_rd.cpp @@ -0,0 +1,555 @@ +/*************************************************************************/ +/* cluster_builder_rd.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "cluster_builder_rd.h" +#include "servers/rendering/rendering_device.h" +#include "servers/rendering/rendering_server_globals.h" + +ClusterBuilderSharedDataRD::ClusterBuilderSharedDataRD() { + RD::VertexFormatID vertex_format; + + { + Vector<RD::VertexAttribute> attributes; + { + RD::VertexAttribute va; + va.format = RD::DATA_FORMAT_R32G32B32_SFLOAT; + va.stride = sizeof(float) * 3; + attributes.push_back(va); + } + vertex_format = RD::get_singleton()->vertex_format_create(attributes); + } + + { + Vector<String> versions; + versions.push_back(""); + cluster_render.cluster_render_shader.initialize(versions); + cluster_render.shader_version = cluster_render.cluster_render_shader.version_create(); + cluster_render.shader = cluster_render.cluster_render_shader.version_get_shader(cluster_render.shader_version, 0); + cluster_render.shader_pipelines[ClusterRender::PIPELINE_NORMAL] = RD::get_singleton()->render_pipeline_create(cluster_render.shader, RD::get_singleton()->framebuffer_format_create_empty(), vertex_format, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState(), 0); + RD::PipelineMultisampleState ms; + ms.sample_count = RD::TEXTURE_SAMPLES_4; + cluster_render.shader_pipelines[ClusterRender::PIPELINE_MSAA] = RD::get_singleton()->render_pipeline_create(cluster_render.shader, RD::get_singleton()->framebuffer_format_create_empty(), vertex_format, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), ms, RD::PipelineDepthStencilState(), RD::PipelineColorBlendState(), 0); + } + { + Vector<String> versions; + versions.push_back(""); + cluster_store.cluster_store_shader.initialize(versions); + cluster_store.shader_version = cluster_store.cluster_store_shader.version_create(); + cluster_store.shader = cluster_store.cluster_store_shader.version_get_shader(cluster_store.shader_version, 0); + cluster_store.shader_pipeline = RD::get_singleton()->compute_pipeline_create(cluster_store.shader); + } + { + Vector<String> versions; + versions.push_back(""); + cluster_debug.cluster_debug_shader.initialize(versions); + cluster_debug.shader_version = cluster_debug.cluster_debug_shader.version_create(); + cluster_debug.shader = cluster_debug.cluster_debug_shader.version_get_shader(cluster_debug.shader_version, 0); + cluster_debug.shader_pipeline = RD::get_singleton()->compute_pipeline_create(cluster_debug.shader); + } + + { // SPHERE + static const uint32_t icosphere_vertex_count = 42; + static const float icosphere_vertices[icosphere_vertex_count * 3] = { + 0, 0, -1, 0.7236073, -0.5257253, -0.4472195, -0.276388, -0.8506492, -0.4472199, -0.8944262, 0, -0.4472156, -0.276388, 0.8506492, -0.4472199, 0.7236073, 0.5257253, -0.4472195, 0.276388, -0.8506492, 0.4472199, -0.7236073, -0.5257253, 0.4472195, -0.7236073, 0.5257253, 0.4472195, 0.276388, 0.8506492, 0.4472199, 0.8944262, 0, 0.4472156, 0, 0, 1, -0.1624555, -0.4999952, -0.8506544, 0.4253227, -0.3090114, -0.8506542, 0.2628688, -0.8090116, -0.5257377, 0.8506479, 0, -0.5257359, 0.4253227, 0.3090114, -0.8506542, -0.5257298, 0, -0.8506517, -0.6881894, -0.4999969, -0.5257362, -0.1624555, 0.4999952, -0.8506544, -0.6881894, 0.4999969, -0.5257362, 0.2628688, 0.8090116, -0.5257377, 0.9510579, -0.3090126, 0, 0.9510579, 0.3090126, 0, 0, -1, 0, 0.5877856, -0.8090167, 0, -0.9510579, -0.3090126, 0, -0.5877856, -0.8090167, 0, -0.5877856, 0.8090167, 0, -0.9510579, 0.3090126, 0, 0.5877856, 0.8090167, 0, 0, 1, 0, 0.6881894, -0.4999969, 0.5257362, -0.2628688, -0.8090116, 0.5257377, -0.8506479, 0, 0.5257359, -0.2628688, 0.8090116, 0.5257377, 0.6881894, 0.4999969, 0.5257362, 0.1624555, -0.4999952, 0.8506544, 0.5257298, 0, 0.8506517, -0.4253227, -0.3090114, 0.8506542, -0.4253227, 0.3090114, 0.8506542, 0.1624555, 0.4999952, 0.8506544 + }; + static const uint32_t icosphere_triangle_count = 80; + static const uint32_t icosphere_triangle_indices[icosphere_triangle_count * 3] = { + 0, 13, 12, 1, 13, 15, 0, 12, 17, 0, 17, 19, 0, 19, 16, 1, 15, 22, 2, 14, 24, 3, 18, 26, 4, 20, 28, 5, 21, 30, 1, 22, 25, 2, 24, 27, 3, 26, 29, 4, 28, 31, 5, 30, 23, 6, 32, 37, 7, 33, 39, 8, 34, 40, 9, 35, 41, 10, 36, 38, 38, 41, 11, 38, 36, 41, 36, 9, 41, 41, 40, 11, 41, 35, 40, 35, 8, 40, 40, 39, 11, 40, 34, 39, 34, 7, 39, 39, 37, 11, 39, 33, 37, 33, 6, 37, 37, 38, 11, 37, 32, 38, 32, 10, 38, 23, 36, 10, 23, 30, 36, 30, 9, 36, 31, 35, 9, 31, 28, 35, 28, 8, 35, 29, 34, 8, 29, 26, 34, 26, 7, 34, 27, 33, 7, 27, 24, 33, 24, 6, 33, 25, 32, 6, 25, 22, 32, 22, 10, 32, 30, 31, 9, 30, 21, 31, 21, 4, 31, 28, 29, 8, 28, 20, 29, 20, 3, 29, 26, 27, 7, 26, 18, 27, 18, 2, 27, 24, 25, 6, 24, 14, 25, 14, 1, 25, 22, 23, 10, 22, 15, 23, 15, 5, 23, 16, 21, 5, 16, 19, 21, 19, 4, 21, 19, 20, 4, 19, 17, 20, 17, 3, 20, 17, 18, 3, 17, 12, 18, 12, 2, 18, 15, 16, 5, 15, 13, 16, 13, 0, 16, 12, 14, 2, 12, 13, 14, 13, 1, 14 + }; + + Vector<uint8_t> vertex_data; + vertex_data.resize(sizeof(float) * icosphere_vertex_count * 3); + copymem(vertex_data.ptrw(), icosphere_vertices, vertex_data.size()); + + sphere_vertex_buffer = RD::get_singleton()->vertex_buffer_create(vertex_data.size(), vertex_data); + + Vector<uint8_t> index_data; + index_data.resize(sizeof(uint32_t) * icosphere_triangle_count * 3); + copymem(index_data.ptrw(), icosphere_triangle_indices, index_data.size()); + + sphere_index_buffer = RD::get_singleton()->index_buffer_create(icosphere_triangle_count * 3, RD::INDEX_BUFFER_FORMAT_UINT32, index_data); + + Vector<RID> buffers; + buffers.push_back(sphere_vertex_buffer); + + sphere_vertex_array = RD::get_singleton()->vertex_array_create(icosphere_vertex_count, vertex_format, buffers); + + sphere_index_array = RD::get_singleton()->index_array_create(sphere_index_buffer, 0, icosphere_triangle_count * 3); + + float min_d = 1e20; + for (uint32_t i = 0; i < icosphere_triangle_count; i++) { + Vector3 vertices[3]; + for (uint32_t j = 0; j < 3; j++) { + uint32_t index = icosphere_triangle_indices[i * 3 + j]; + for (uint32_t k = 0; k < 3; k++) { + vertices[j][k] = icosphere_vertices[index * 3 + k]; + } + } + Plane p(vertices[0], vertices[1], vertices[2]); + min_d = MIN(Math::abs(p.d), min_d); + } + sphere_overfit = 1.0 / min_d; + } + + { // CONE + static const uint32_t cone_vertex_count = 99; + static const float cone_vertices[cone_vertex_count * 3] = { + 0, 1, -1, 0.1950903, 0.9807853, -1, 0.3826835, 0.9238795, -1, 0.5555703, 0.8314696, -1, 0.7071068, 0.7071068, -1, 0.8314697, 0.5555702, -1, 0.9238795, 0.3826834, -1, 0.9807853, 0.1950903, -1, 1, 0, -1, 0.9807853, -0.1950902, -1, 0.9238796, -0.3826833, -1, 0.8314697, -0.5555702, -1, 0.7071068, -0.7071068, -1, 0.5555702, -0.8314697, -1, 0.3826833, -0.9238796, -1, 0.1950901, -0.9807853, -1, -3.25841e-7, -1, -1, -0.1950907, -0.9807852, -1, -0.3826839, -0.9238793, -1, -0.5555707, -0.8314693, -1, -0.7071073, -0.7071063, -1, -0.83147, -0.5555697, -1, -0.9238799, -0.3826827, -1, 0, 0, 0, -0.9807854, -0.1950894, -1, -1, 9.65599e-7, -1, -0.9807851, 0.1950913, -1, -0.9238791, 0.3826845, -1, -0.8314689, 0.5555713, -1, -0.7071059, 0.7071077, -1, -0.5555691, 0.8314704, -1, -0.3826821, 0.9238801, -1, -0.1950888, 0.9807856, -1 + }; + static const uint32_t cone_triangle_count = 62; + static const uint32_t cone_triangle_indices[cone_triangle_count * 3] = { + 0, 23, 1, 1, 23, 2, 2, 23, 3, 3, 23, 4, 4, 23, 5, 5, 23, 6, 6, 23, 7, 7, 23, 8, 8, 23, 9, 9, 23, 10, 10, 23, 11, 11, 23, 12, 12, 23, 13, 13, 23, 14, 14, 23, 15, 15, 23, 16, 16, 23, 17, 17, 23, 18, 18, 23, 19, 19, 23, 20, 20, 23, 21, 21, 23, 22, 22, 23, 24, 24, 23, 25, 25, 23, 26, 26, 23, 27, 27, 23, 28, 28, 23, 29, 29, 23, 30, 30, 23, 31, 31, 23, 32, 32, 23, 0, 7, 15, 24, 32, 0, 1, 1, 2, 3, 3, 4, 5, 5, 6, 3, 6, 7, 3, 7, 8, 9, 9, 10, 7, 10, 11, 7, 11, 12, 15, 12, 13, 15, 13, 14, 15, 15, 16, 17, 17, 18, 19, 19, 20, 24, 20, 21, 24, 21, 22, 24, 24, 25, 26, 26, 27, 28, 28, 29, 30, 30, 31, 32, 32, 1, 3, 15, 17, 24, 17, 19, 24, 24, 26, 32, 26, 28, 32, 28, 30, 32, 32, 3, 7, 7, 11, 15, 32, 7, 24 + }; + + Vector<uint8_t> vertex_data; + vertex_data.resize(sizeof(float) * cone_vertex_count * 3); + copymem(vertex_data.ptrw(), cone_vertices, vertex_data.size()); + + cone_vertex_buffer = RD::get_singleton()->vertex_buffer_create(vertex_data.size(), vertex_data); + + Vector<uint8_t> index_data; + index_data.resize(sizeof(uint32_t) * cone_triangle_count * 3); + copymem(index_data.ptrw(), cone_triangle_indices, index_data.size()); + + cone_index_buffer = RD::get_singleton()->index_buffer_create(cone_triangle_count * 3, RD::INDEX_BUFFER_FORMAT_UINT32, index_data); + + Vector<RID> buffers; + buffers.push_back(cone_vertex_buffer); + + cone_vertex_array = RD::get_singleton()->vertex_array_create(cone_vertex_count, vertex_format, buffers); + + cone_index_array = RD::get_singleton()->index_array_create(cone_index_buffer, 0, cone_triangle_count * 3); + + float min_d = 1e20; + for (uint32_t i = 0; i < cone_triangle_count; i++) { + Vector3 vertices[3]; + int32_t zero_index = -1; + for (uint32_t j = 0; j < 3; j++) { + uint32_t index = cone_triangle_indices[i * 3 + j]; + for (uint32_t k = 0; k < 3; k++) { + vertices[j][k] = cone_vertices[index * 3 + k]; + } + if (vertices[j] == Vector3()) { + zero_index = j; + } + } + + if (zero_index != -1) { + Vector3 a = vertices[(zero_index + 1) % 3]; + Vector3 b = vertices[(zero_index + 2) % 3]; + Vector3 c = a + Vector3(0, 0, 1); + Plane p(a, b, c); + min_d = MIN(Math::abs(p.d), min_d); + } + } + cone_overfit = 1.0 / min_d; + } + + { // BOX + static const uint32_t box_vertex_count = 8; + static const float box_vertices[box_vertex_count * 3] = { + -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1 + }; + static const uint32_t box_triangle_count = 12; + static const uint32_t box_triangle_indices[box_triangle_count * 3] = { + 1, 2, 0, 3, 6, 2, 7, 4, 6, 5, 0, 4, 6, 0, 2, 3, 5, 7, 1, 3, 2, 3, 7, 6, 7, 5, 4, 5, 1, 0, 6, 4, 0, 3, 1, 5 + }; + + Vector<uint8_t> vertex_data; + vertex_data.resize(sizeof(float) * box_vertex_count * 3); + copymem(vertex_data.ptrw(), box_vertices, vertex_data.size()); + + box_vertex_buffer = RD::get_singleton()->vertex_buffer_create(vertex_data.size(), vertex_data); + + Vector<uint8_t> index_data; + index_data.resize(sizeof(uint32_t) * box_triangle_count * 3); + copymem(index_data.ptrw(), box_triangle_indices, index_data.size()); + + box_index_buffer = RD::get_singleton()->index_buffer_create(box_triangle_count * 3, RD::INDEX_BUFFER_FORMAT_UINT32, index_data); + + Vector<RID> buffers; + buffers.push_back(box_vertex_buffer); + + box_vertex_array = RD::get_singleton()->vertex_array_create(box_vertex_count, vertex_format, buffers); + + box_index_array = RD::get_singleton()->index_array_create(box_index_buffer, 0, box_triangle_count * 3); + } +} +ClusterBuilderSharedDataRD::~ClusterBuilderSharedDataRD() { + RD::get_singleton()->free(sphere_vertex_buffer); + RD::get_singleton()->free(sphere_index_buffer); + RD::get_singleton()->free(cone_vertex_buffer); + RD::get_singleton()->free(cone_index_buffer); + RD::get_singleton()->free(box_vertex_buffer); + RD::get_singleton()->free(box_index_buffer); + + cluster_render.cluster_render_shader.version_free(cluster_render.shader_version); + cluster_store.cluster_store_shader.version_free(cluster_store.shader_version); + cluster_debug.cluster_debug_shader.version_free(cluster_debug.shader_version); +} + +///////////////////////////// + +void ClusterBuilderRD::_clear() { + if (cluster_buffer.is_null()) { + return; //nothing to clear + } + RD::get_singleton()->free(cluster_buffer); + RD::get_singleton()->free(cluster_render_buffer); + RD::get_singleton()->free(element_buffer); + cluster_buffer = RID(); + cluster_render_buffer = RID(); + element_buffer = RID(); + + memfree(render_elements); + + render_elements = nullptr; + render_element_max = 0; + render_element_count = 0; + + RD::get_singleton()->free(framebuffer); + framebuffer = RID(); + + cluster_render_uniform_set = RID(); + cluster_store_uniform_set = RID(); +} + +void ClusterBuilderRD::setup(Size2i p_screen_size, uint32_t p_max_elements, RID p_depth_buffer, RID p_depth_buffer_sampler, RID p_color_buffer) { + ERR_FAIL_COND(p_max_elements == 0); + ERR_FAIL_COND(p_screen_size.x < 1); + ERR_FAIL_COND(p_screen_size.y < 1); + + _clear(); + + screen_size = p_screen_size; + + cluster_screen_size.width = (p_screen_size.width - 1) / cluster_size + 1; + cluster_screen_size.height = (p_screen_size.height - 1) / cluster_size + 1; + + max_elements_by_type = p_max_elements; + if (max_elements_by_type % 32) { //need to be 32 aligned + max_elements_by_type += 32 - (max_elements_by_type % 32); + } + + cluster_buffer_size = cluster_screen_size.x * cluster_screen_size.y * (max_elements_by_type / 32 + 32) * ELEMENT_TYPE_MAX * 4; + + render_element_max = max_elements_by_type * ELEMENT_TYPE_MAX; + + uint32_t element_tag_bits_size = render_element_max / 32; + uint32_t element_tag_depth_bits_size = render_element_max; + cluster_render_buffer_size = cluster_screen_size.x * cluster_screen_size.y * (element_tag_bits_size + element_tag_depth_bits_size) * 4; // tag bits (element was used) and tag depth (depth range in which it was used) + + cluster_render_buffer = RD::get_singleton()->storage_buffer_create(cluster_render_buffer_size); + cluster_buffer = RD::get_singleton()->storage_buffer_create(cluster_buffer_size); + + render_elements = (RenderElementData *)memalloc(sizeof(RenderElementData *) * render_element_max); + render_element_count = 0; + + element_buffer = RD::get_singleton()->storage_buffer_create(sizeof(RenderElementData) * render_element_max); + + uint32_t div_value = 1 << divisor; + if (use_msaa) { + framebuffer = RD::get_singleton()->framebuffer_create_empty(p_screen_size / div_value, RD::TEXTURE_SAMPLES_4); + } else { + framebuffer = RD::get_singleton()->framebuffer_create_empty(p_screen_size / div_value); + } + + { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 1; + u.ids.push_back(state_uniform); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 2; + u.ids.push_back(element_buffer); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 3; + u.ids.push_back(cluster_render_buffer); + uniforms.push_back(u); + } + + cluster_render_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shared->cluster_render.shader, 0); + } + + { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 1; + u.ids.push_back(cluster_render_buffer); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 2; + u.ids.push_back(cluster_buffer); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 3; + u.ids.push_back(element_buffer); + uniforms.push_back(u); + } + + cluster_store_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shared->cluster_store.shader, 0); + } + + if (p_color_buffer.is_valid()) { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 1; + u.ids.push_back(cluster_buffer); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 2; + u.ids.push_back(p_color_buffer); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 3; + u.ids.push_back(p_depth_buffer); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; + u.binding = 4; + u.ids.push_back(p_depth_buffer_sampler); + uniforms.push_back(u); + } + + debug_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shared->cluster_debug.shader, 0); + } else { + debug_uniform_set = RID(); + } +} + +void ClusterBuilderRD::begin(const Transform &p_view_transform, const CameraMatrix &p_cam_projection, bool p_flip_y) { + view_xform = p_view_transform.affine_inverse(); + projection = p_cam_projection; + z_near = projection.get_z_near(); + z_far = projection.get_z_far(); + orthogonal = p_cam_projection.is_orthogonal(); + adjusted_projection = projection; + if (!orthogonal) { + adjusted_projection.adjust_perspective_znear(0.0001); + } + + CameraMatrix correction; + correction.set_depth_correction(p_flip_y); + projection = correction * projection; + adjusted_projection = correction * adjusted_projection; + + //reset counts + render_element_count = 0; + for (uint32_t i = 0; i < ELEMENT_TYPE_MAX; i++) { + cluster_count_by_type[i] = 0; + } +} + +void ClusterBuilderRD::bake_cluster() { + RENDER_TIMESTAMP(">Bake Cluster"); + + RD::get_singleton()->draw_command_begin_label("Bake Light Cluster"); + + //clear cluster buffer + RD::get_singleton()->buffer_clear(cluster_buffer, 0, cluster_buffer_size, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); + + if (render_element_count > 0) { + //clear render buffer + RD::get_singleton()->buffer_clear(cluster_render_buffer, 0, cluster_render_buffer_size, RD::BARRIER_MASK_RASTER); + + { //fill state uniform + + StateUniform state; + + RendererStorageRD::store_camera(adjusted_projection, state.projection); + state.inv_z_far = 1.0 / z_far; + state.screen_to_clusters_shift = get_shift_from_power_of_2(cluster_size); + state.screen_to_clusters_shift -= divisor; //screen is smaller, shift one less + + state.cluster_screen_width = cluster_screen_size.x; + state.cluster_depth_offset = (render_element_max / 32); + state.cluster_data_size = state.cluster_depth_offset + render_element_max; + + RD::get_singleton()->buffer_update(state_uniform, 0, sizeof(StateUniform), &state, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); + } + + //update instances + + RD::get_singleton()->buffer_update(element_buffer, 0, sizeof(RenderElementData) * render_element_count, render_elements, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); + + RENDER_TIMESTAMP("Render Elements"); + + //render elements + { + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD); + ClusterBuilderSharedDataRD::ClusterRender::PushConstant push_constant = {}; + + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, shared->cluster_render.shader_pipelines[use_msaa ? ClusterBuilderSharedDataRD::ClusterRender::PIPELINE_MSAA : ClusterBuilderSharedDataRD::ClusterRender::PIPELINE_NORMAL]); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, cluster_render_uniform_set, 0); + + for (uint32_t i = 0; i < render_element_count;) { + push_constant.base_index = i; + switch (render_elements[i].type) { + case ELEMENT_TYPE_OMNI_LIGHT: { + RD::get_singleton()->draw_list_bind_vertex_array(draw_list, shared->sphere_vertex_array); + RD::get_singleton()->draw_list_bind_index_array(draw_list, shared->sphere_index_array); + } break; + case ELEMENT_TYPE_SPOT_LIGHT: { + RD::get_singleton()->draw_list_bind_vertex_array(draw_list, shared->cone_vertex_array); + RD::get_singleton()->draw_list_bind_index_array(draw_list, shared->cone_index_array); + } break; + case ELEMENT_TYPE_DECAL: + case ELEMENT_TYPE_REFLECTION_PROBE: { + RD::get_singleton()->draw_list_bind_vertex_array(draw_list, shared->box_vertex_array); + RD::get_singleton()->draw_list_bind_index_array(draw_list, shared->box_index_array); + } break; + } + + RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ClusterBuilderSharedDataRD::ClusterRender::PushConstant)); + + uint32_t instances = 1; +#if 0 + for (uint32_t j = i+1; j < element_count; j++) { + if (elements[i].type!=elements[j].type) { + break; + } + instances++; + } +#endif + RD::get_singleton()->draw_list_draw(draw_list, true, instances); + i += instances; + } + RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_COMPUTE); + } + //store elements + RENDER_TIMESTAMP("Pack Elements"); + + { + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, shared->cluster_store.shader_pipeline); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cluster_store_uniform_set, 0); + + ClusterBuilderSharedDataRD::ClusterStore::PushConstant push_constant; + push_constant.cluster_render_data_size = render_element_max / 32 + render_element_max; + push_constant.max_render_element_count_div_32 = render_element_max / 32; + push_constant.cluster_screen_size[0] = cluster_screen_size.x; + push_constant.cluster_screen_size[1] = cluster_screen_size.y; + push_constant.render_element_count_div_32 = render_element_count > 0 ? (render_element_count - 1) / 32 + 1 : 0; + push_constant.max_cluster_element_count_div_32 = max_elements_by_type / 32; + push_constant.pad1 = 0; + push_constant.pad2 = 0; + + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ClusterBuilderSharedDataRD::ClusterStore::PushConstant)); + + RD::get_singleton()->compute_list_dispatch_threads(compute_list, cluster_screen_size.x, cluster_screen_size.y, 1); + + RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); + } + } else { + RD::get_singleton()->barrier(RD::BARRIER_MASK_TRANSFER, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); + } + RENDER_TIMESTAMP("<Bake Cluster"); + RD::get_singleton()->draw_command_end_label(); +} + +void ClusterBuilderRD::debug(ElementType p_element) { + ERR_FAIL_COND(debug_uniform_set.is_null()); + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, shared->cluster_debug.shader_pipeline); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, debug_uniform_set, 0); + + ClusterBuilderSharedDataRD::ClusterDebug::PushConstant push_constant; + push_constant.screen_size[0] = screen_size.x; + push_constant.screen_size[1] = screen_size.y; + push_constant.cluster_screen_size[0] = cluster_screen_size.x; + push_constant.cluster_screen_size[1] = cluster_screen_size.y; + push_constant.cluster_shift = get_shift_from_power_of_2(cluster_size); + push_constant.cluster_type = p_element; + push_constant.orthogonal = orthogonal; + push_constant.z_far = z_far; + push_constant.z_near = z_near; + push_constant.max_cluster_element_count_div_32 = max_elements_by_type / 32; + + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ClusterBuilderSharedDataRD::ClusterDebug::PushConstant)); + + RD::get_singleton()->compute_list_dispatch_threads(compute_list, screen_size.x, screen_size.y, 1); + + RD::get_singleton()->compute_list_end(); +} + +RID ClusterBuilderRD::get_cluster_buffer() const { + return cluster_buffer; +} + +uint32_t ClusterBuilderRD::get_cluster_size() const { + return cluster_size; +} + +uint32_t ClusterBuilderRD::get_max_cluster_elements() const { + return max_elements_by_type; +} + +void ClusterBuilderRD::set_shared(ClusterBuilderSharedDataRD *p_shared) { + shared = p_shared; +} + +ClusterBuilderRD::ClusterBuilderRD() { + state_uniform = RD::get_singleton()->uniform_buffer_create(sizeof(StateUniform)); +} + +ClusterBuilderRD::~ClusterBuilderRD() { + _clear(); + RD::get_singleton()->free(state_uniform); +} diff --git a/servers/rendering/renderer_rd/cluster_builder_rd.h b/servers/rendering/renderer_rd/cluster_builder_rd.h new file mode 100644 index 0000000000..dc1707b534 --- /dev/null +++ b/servers/rendering/renderer_rd/cluster_builder_rd.h @@ -0,0 +1,378 @@ +/*************************************************************************/ +/* cluster_builder_rd.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef CLUSTER_BUILDER_RD_H +#define CLUSTER_BUILDER_RD_H + +#include "servers/rendering/renderer_rd/renderer_storage_rd.h" +#include "servers/rendering/renderer_rd/shaders/cluster_debug.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/cluster_render.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/cluster_store.glsl.gen.h" + +class ClusterBuilderSharedDataRD { + friend class ClusterBuilderRD; + + RID sphere_vertex_buffer; + RID sphere_vertex_array; + RID sphere_index_buffer; + RID sphere_index_array; + float sphere_overfit = 0.0; //because an icosphere is not a perfect sphere, we need to enlarge it to cover the sphere area + + RID cone_vertex_buffer; + RID cone_vertex_array; + RID cone_index_buffer; + RID cone_index_array; + float cone_overfit = 0.0; //because an cone mesh is not a perfect sphere, we need to enlarge it to cover the actual cone area + + RID box_vertex_buffer; + RID box_vertex_array; + RID box_index_buffer; + RID box_index_array; + + enum Divisor { + DIVISOR_1, + DIVISOR_2, + DIVISOR_4, + }; + + struct ClusterRender { + struct PushConstant { + uint32_t base_index; + uint32_t pad0; + uint32_t pad1; + uint32_t pad2; + }; + + ClusterRenderShaderRD cluster_render_shader; + RID shader_version; + RID shader; + enum PipelineVersion { + PIPELINE_NORMAL, + PIPELINE_MSAA, + PIPELINE_MAX + }; + + RID shader_pipelines[PIPELINE_MAX]; + } cluster_render; + + struct ClusterStore { + struct PushConstant { + uint32_t cluster_render_data_size; // how much data for a single cluster takes + uint32_t max_render_element_count_div_32; //divided by 32 + uint32_t cluster_screen_size[2]; + uint32_t render_element_count_div_32; //divided by 32 + uint32_t max_cluster_element_count_div_32; //divided by 32 + uint32_t pad1; + uint32_t pad2; + }; + + ClusterStoreShaderRD cluster_store_shader; + RID shader_version; + RID shader; + RID shader_pipeline; + } cluster_store; + + struct ClusterDebug { + struct PushConstant { + uint32_t screen_size[2]; + uint32_t cluster_screen_size[2]; + + uint32_t cluster_shift; + uint32_t cluster_type; + float z_near; + float z_far; + + uint32_t orthogonal; + uint32_t max_cluster_element_count_div_32; + uint32_t pad1; + uint32_t pad2; + }; + + ClusterDebugShaderRD cluster_debug_shader; + RID shader_version; + RID shader; + RID shader_pipeline; + } cluster_debug; + +public: + ClusterBuilderSharedDataRD(); + ~ClusterBuilderSharedDataRD(); +}; + +class ClusterBuilderRD { +public: + enum LightType { + LIGHT_TYPE_OMNI, + LIGHT_TYPE_SPOT + }; + + enum BoxType { + BOX_TYPE_REFLECTION_PROBE, + BOX_TYPE_DECAL, + }; + + enum ElementType { + ELEMENT_TYPE_OMNI_LIGHT, + ELEMENT_TYPE_SPOT_LIGHT, + ELEMENT_TYPE_DECAL, + ELEMENT_TYPE_REFLECTION_PROBE, + ELEMENT_TYPE_MAX, + + }; + +private: + ClusterBuilderSharedDataRD *shared = nullptr; + + struct RenderElementData { + uint32_t type; //0-4 + uint32_t touches_near; + uint32_t touches_far; + uint32_t original_index; + float transform_inv[12]; //transposed transform for less space + float scale[3]; + uint32_t pad; + }; + + uint32_t cluster_count_by_type[ELEMENT_TYPE_MAX] = {}; + uint32_t max_elements_by_type = 0; + + RenderElementData *render_elements = nullptr; + uint32_t render_element_count = 0; + uint32_t render_element_max = 0; + + Transform view_xform; + CameraMatrix adjusted_projection; + CameraMatrix projection; + float z_far = 0; + float z_near = 0; + bool orthogonal = false; + + enum Divisor { + DIVISOR_1, + DIVISOR_2, + DIVISOR_4, + }; + + uint32_t cluster_size = 32; + bool use_msaa = true; + Divisor divisor = DIVISOR_4; + + Size2i screen_size; + Size2i cluster_screen_size; + + RID framebuffer; + RID cluster_render_buffer; //used for creating + RID cluster_buffer; //used for rendering + RID element_buffer; //used for storing, to hint element touches far plane or near plane + uint32_t cluster_render_buffer_size = 0; + uint32_t cluster_buffer_size = 0; + + RID cluster_render_uniform_set; + RID cluster_store_uniform_set; + + //persistent data + + void _clear(); + + struct StateUniform { + float projection[16]; + float inv_z_far; + uint32_t screen_to_clusters_shift; // shift to obtain coordinates in block indices + uint32_t cluster_screen_width; // + uint32_t cluster_data_size; // how much data for a single cluster takes + uint32_t cluster_depth_offset; + uint32_t pad0; + uint32_t pad1; + uint32_t pad2; + }; + + RID state_uniform; + + RID debug_uniform_set; + +public: + void setup(Size2i p_screen_size, uint32_t p_max_elements, RID p_depth_buffer, RID p_depth_buffer_sampler, RID p_color_buffer); + + void begin(const Transform &p_view_transform, const CameraMatrix &p_cam_projection, bool p_flip_y); + + _FORCE_INLINE_ void add_light(LightType p_type, const Transform &p_transform, float p_radius, float p_spot_aperture) { + if (p_type == LIGHT_TYPE_OMNI && cluster_count_by_type[ELEMENT_TYPE_OMNI_LIGHT] == max_elements_by_type) { + return; //max number elements reached + } + if (p_type == LIGHT_TYPE_SPOT && cluster_count_by_type[ELEMENT_TYPE_SPOT_LIGHT] == max_elements_by_type) { + return; //max number elements reached + } + + RenderElementData &e = render_elements[render_element_count]; + + Transform xform = view_xform * p_transform; + + float radius = xform.basis.get_uniform_scale(); + if (radius > 0.98 || radius < 1.02) { + xform.basis.orthonormalize(); + } + + radius *= p_radius; + + if (p_type == LIGHT_TYPE_OMNI) { + radius *= shared->sphere_overfit; // overfit icosphere + + //omni + float depth = -xform.origin.z; + if (orthogonal) { + e.touches_near = (depth - radius) < z_near; + } else { + //contains camera inside light + float radius2 = radius * shared->sphere_overfit; // overfit again for outer size (camera may be outside actual sphere but behind an icosphere vertex) + e.touches_near = xform.origin.length_squared() < radius2 * radius2; + } + + e.touches_far = (depth + radius) > z_far; + e.scale[0] = radius; + e.scale[1] = radius; + e.scale[2] = radius; + e.type = ELEMENT_TYPE_OMNI_LIGHT; + e.original_index = cluster_count_by_type[ELEMENT_TYPE_OMNI_LIGHT]; + + RendererStorageRD::store_transform_transposed_3x4(xform, e.transform_inv); + + cluster_count_by_type[ELEMENT_TYPE_OMNI_LIGHT]++; + + } else { + //spot + radius *= shared->cone_overfit; // overfit icosphere + + real_t len = Math::tan(Math::deg2rad(p_spot_aperture)) * radius; + //approximate, probably better to use a cone support function + float max_d = -1e20; + float min_d = 1e20; +#define CONE_MINMAX(m_x, m_y) \ + { \ + float d = -xform.xform(Vector3(len * m_x, len * m_y, -radius)).z; \ + min_d = MIN(d, min_d); \ + max_d = MAX(d, max_d); \ + } + + CONE_MINMAX(1, 1); + CONE_MINMAX(-1, 1); + CONE_MINMAX(-1, -1); + CONE_MINMAX(1, -1); + + if (orthogonal) { + e.touches_near = min_d < z_near; + } else { + //contains camera inside light + Plane base_plane(xform.origin, -xform.basis.get_axis(Vector3::AXIS_Z)); + float dist = base_plane.distance_to(Vector3()); + if (dist >= 0 && dist < radius) { + //inside, check angle + float angle = Math::rad2deg(Math::acos((-xform.origin.normalized()).dot(-xform.basis.get_axis(Vector3::AXIS_Z)))); + e.touches_near = angle < p_spot_aperture * 1.05; //overfit aperture a little due to cone overfit + } else { + e.touches_near = false; + } + } + + e.touches_far = max_d > z_far; + + e.scale[0] = len * shared->cone_overfit; + e.scale[1] = len * shared->cone_overfit; + e.scale[2] = radius; + + e.type = ELEMENT_TYPE_SPOT_LIGHT; + e.original_index = cluster_count_by_type[ELEMENT_TYPE_SPOT_LIGHT]; //use omni since they share index + + RendererStorageRD::store_transform_transposed_3x4(xform, e.transform_inv); + + cluster_count_by_type[ELEMENT_TYPE_SPOT_LIGHT]++; + } + + render_element_count++; + } + + _FORCE_INLINE_ void add_box(BoxType p_box_type, const Transform &p_transform, const Vector3 &p_half_extents) { + if (p_box_type == BOX_TYPE_DECAL && cluster_count_by_type[ELEMENT_TYPE_DECAL] == max_elements_by_type) { + return; //max number elements reached + } + if (p_box_type == BOX_TYPE_REFLECTION_PROBE && cluster_count_by_type[ELEMENT_TYPE_REFLECTION_PROBE] == max_elements_by_type) { + return; //max number elements reached + } + + RenderElementData &e = render_elements[render_element_count]; + Transform xform = view_xform * p_transform; + + //extract scale and scale the matrix by it, makes things simpler + Vector3 scale = p_half_extents; + for (uint32_t i = 0; i < 3; i++) { + float s = xform.basis.elements[i].length(); + scale[i] *= s; + xform.basis.elements[i] /= s; + }; + + float box_depth = Math::abs(xform.basis.xform_inv(Vector3(0, 0, -1)).dot(scale)); + float depth = -xform.origin.z; + + if (orthogonal) { + e.touches_near = depth - box_depth < z_near; + } else { + //contains camera inside box + Vector3 inside = xform.xform_inv(Vector3(0, 0, 0)).abs(); + e.touches_near = inside.x < scale.x && inside.y < scale.y && inside.z < scale.z; + } + + e.touches_far = depth + box_depth > z_far; + + e.scale[0] = scale.x; + e.scale[1] = scale.y; + e.scale[2] = scale.z; + + e.type = (p_box_type == BOX_TYPE_DECAL) ? ELEMENT_TYPE_DECAL : ELEMENT_TYPE_REFLECTION_PROBE; + e.original_index = cluster_count_by_type[e.type]; + + RendererStorageRD::store_transform_transposed_3x4(xform, e.transform_inv); + + cluster_count_by_type[e.type]++; + render_element_count++; + } + + void bake_cluster(); + void debug(ElementType p_element); + + RID get_cluster_buffer() const; + uint32_t get_cluster_size() const; + uint32_t get_max_cluster_elements() const; + + void set_shared(ClusterBuilderSharedDataRD *p_shared); + + ClusterBuilderRD(); + ~ClusterBuilderRD(); +}; + +#endif // CLUSTER_BUILDER_H diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp index 97c1e7ba70..bc304aedd8 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp +++ b/servers/rendering/renderer_rd/effects_rd.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rasterizer_effects_rd.cpp */ +/* effects_rd.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,9 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "rasterizer_effects_rd.h" +#include "effects_rd.h" #include "core/config/project_settings.h" +#include "core/math/math_defs.h" #include "core/os/os.h" #include "thirdparty/misc/cubemap_coeffs.h" @@ -58,7 +59,7 @@ static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_arra } } -RID RasterizerEffectsRD::_get_uniform_set_from_image(RID p_image) { +RID EffectsRD::_get_uniform_set_from_image(RID p_image) { if (image_to_uniform_set_cache.has(p_image)) { RID uniform_set = image_to_uniform_set_cache[p_image]; if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) { @@ -67,7 +68,7 @@ RID RasterizerEffectsRD::_get_uniform_set_from_image(RID p_image) { } Vector<RD::Uniform> uniforms; RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 0; u.ids.push_back(p_image); uniforms.push_back(u); @@ -79,7 +80,7 @@ RID RasterizerEffectsRD::_get_uniform_set_from_image(RID p_image) { return uniform_set; } -RID RasterizerEffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) { +RID EffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) { if (texture_to_uniform_set_cache.has(p_texture)) { RID uniform_set = texture_to_uniform_set_cache[p_texture]; if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) { @@ -89,12 +90,12 @@ RID RasterizerEffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use Vector<RD::Uniform> uniforms; RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; u.binding = 0; u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler); u.ids.push_back(p_texture); uniforms.push_back(u); - //any thing with the same configuration (one texture in binding 0 for set 0), is good + //anything with the same configuration (one texture in binding 0 for set 0), is good RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, tonemap.shader.version_get_shader(tonemap.shader_version, 0), 0); texture_to_uniform_set_cache[p_texture] = uniform_set; @@ -102,7 +103,7 @@ RID RasterizerEffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use return uniform_set; } -RID RasterizerEffectsRD::_get_compute_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) { +RID EffectsRD::_get_compute_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) { if (texture_to_compute_uniform_set_cache.has(p_texture)) { RID uniform_set = texture_to_compute_uniform_set_cache[p_texture]; if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) { @@ -112,7 +113,7 @@ RID RasterizerEffectsRD::_get_compute_uniform_set_from_texture(RID p_texture, bo Vector<RD::Uniform> uniforms; RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; u.binding = 0; u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler); u.ids.push_back(p_texture); @@ -125,7 +126,34 @@ RID RasterizerEffectsRD::_get_compute_uniform_set_from_texture(RID p_texture, bo return uniform_set; } -RID RasterizerEffectsRD::_get_compute_uniform_set_from_texture_pair(RID p_texture1, RID p_texture2, bool p_use_mipmaps) { +RID EffectsRD::_get_compute_uniform_set_from_texture_and_sampler(RID p_texture, RID p_sampler) { + TextureSamplerPair tsp; + tsp.texture = p_texture; + tsp.sampler = p_sampler; + + if (texture_sampler_to_compute_uniform_set_cache.has(tsp)) { + RID uniform_set = texture_sampler_to_compute_uniform_set_cache[tsp]; + if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) { + return uniform_set; + } + } + + Vector<RD::Uniform> uniforms; + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.binding = 0; + u.ids.push_back(p_sampler); + u.ids.push_back(p_texture); + uniforms.push_back(u); + //any thing with the same configuration (one texture in binding 0 for set 0), is good + RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.blur_shader.version_get_shader(ssao.blur_shader_version, 0), 0); + + texture_sampler_to_compute_uniform_set_cache[tsp] = uniform_set; + + return uniform_set; +} + +RID EffectsRD::_get_compute_uniform_set_from_texture_pair(RID p_texture1, RID p_texture2, bool p_use_mipmaps) { TexturePair tp; tp.texture1 = p_texture1; tp.texture2 = p_texture2; @@ -140,7 +168,7 @@ RID RasterizerEffectsRD::_get_compute_uniform_set_from_texture_pair(RID p_textur Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; u.binding = 0; u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler); u.ids.push_back(p_texture1); @@ -148,7 +176,7 @@ RID RasterizerEffectsRD::_get_compute_uniform_set_from_texture_pair(RID p_textur } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; u.binding = 1; u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler); u.ids.push_back(p_texture2); @@ -162,7 +190,7 @@ RID RasterizerEffectsRD::_get_compute_uniform_set_from_texture_pair(RID p_textur return uniform_set; } -RID RasterizerEffectsRD::_get_compute_uniform_set_from_image_pair(RID p_texture1, RID p_texture2) { +RID EffectsRD::_get_compute_uniform_set_from_image_pair(RID p_texture1, RID p_texture2) { TexturePair tp; tp.texture1 = p_texture1; tp.texture2 = p_texture2; @@ -177,14 +205,14 @@ RID RasterizerEffectsRD::_get_compute_uniform_set_from_image_pair(RID p_texture1 Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 0; u.ids.push_back(p_texture1); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(p_texture2); uniforms.push_back(u); @@ -197,7 +225,7 @@ RID RasterizerEffectsRD::_get_compute_uniform_set_from_image_pair(RID p_texture1 return uniform_set; } -void RasterizerEffectsRD::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y, bool p_panorama) { +void EffectsRD::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y, bool p_panorama) { zeromem(©_to_fb.push_constant, sizeof(CopyToFbPushConstant)); copy_to_fb.push_constant.use_section = true; @@ -218,7 +246,7 @@ void RasterizerEffectsRD::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_f RD::get_singleton()->draw_list_draw(draw_list, true); } -void RasterizerEffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_alpha_to_zero, bool p_srgb, RID p_secondary) { +void EffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_alpha_to_zero, bool p_srgb, RID p_secondary) { zeromem(©_to_fb.push_constant, sizeof(CopyToFbPushConstant)); if (p_flip_y) { @@ -246,7 +274,7 @@ void RasterizerEffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_fr RD::get_singleton()->draw_list_end(); } -void RasterizerEffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_all_source, bool p_8_bit_dst, bool p_alpha_to_one) { +void EffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_all_source, bool p_8_bit_dst, bool p_alpha_to_one) { zeromem(©.push_constant, sizeof(CopyPushConstant)); if (p_flip_y) { copy.push_constant.flags |= COPY_FLAG_FLIP_Y; @@ -271,19 +299,16 @@ void RasterizerEffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_textu copy.push_constant.target[0] = p_rect.position.x; copy.push_constant.target[1] = p_rect.position.y; - int32_t x_groups = (p_rect.size.width - 1) / 8 + 1; - int32_t y_groups = (p_rect.size.height - 1) / 8 + 1; - RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[p_8_bit_dst ? COPY_MODE_SIMPLY_COPY_8BIT : COPY_MODE_SIMPLY_COPY]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 3); RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_rect.size.width, p_rect.size.height, 1); RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array) { +void EffectsRD::copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array) { zeromem(©.push_constant, sizeof(CopyPushConstant)); copy.push_constant.section[0] = 0; @@ -294,19 +319,16 @@ void RasterizerEffectsRD::copy_cubemap_to_panorama(RID p_source_cube, RID p_dest copy.push_constant.target[1] = 0; copy.push_constant.camera_z_far = p_lod; - int32_t x_groups = (p_panorama_size.width - 1) / 8 + 1; - int32_t y_groups = (p_panorama_size.height - 1) / 8 + 1; - RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[p_is_array ? COPY_MODE_CUBE_ARRAY_TO_PANORAMA : COPY_MODE_CUBE_TO_PANORAMA]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_cube), 0); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_panorama), 3); RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_panorama_size.width, p_panorama_size.height, 1); RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, float p_z_near, float p_z_far) { +void EffectsRD::copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, float p_z_near, float p_z_far) { zeromem(©.push_constant, sizeof(CopyPushConstant)); if (p_flip_y) { copy.push_constant.flags |= COPY_FLAG_FLIP_Y; @@ -321,19 +343,16 @@ void RasterizerEffectsRD::copy_depth_to_rect_and_linearize(RID p_source_rd_textu copy.push_constant.camera_z_far = p_z_far; copy.push_constant.camera_z_near = p_z_near; - int32_t x_groups = (p_rect.size.width - 1) / 8 + 1; - int32_t y_groups = (p_rect.size.height - 1) / 8 + 1; - RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[COPY_MODE_LINEARIZE_DEPTH]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 3); RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_rect.size.width, p_rect.size.height, 1); RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y) { +void EffectsRD::copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y) { zeromem(©.push_constant, sizeof(CopyPushConstant)); if (p_flip_y) { copy.push_constant.flags |= COPY_FLAG_FLIP_Y; @@ -346,19 +365,16 @@ void RasterizerEffectsRD::copy_depth_to_rect(RID p_source_rd_texture, RID p_dest copy.push_constant.target[0] = p_rect.position.x; copy.push_constant.target[1] = p_rect.position.y; - int32_t x_groups = (p_rect.size.width - 1) / 8 + 1; - int32_t y_groups = (p_rect.size.height - 1) / 8 + 1; - RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[COPY_MODE_SIMPLY_COPY_DEPTH]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 3); RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_rect.size.width, p_rect.size.height, 1); RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::set_color(RID p_dest_texture, const Color &p_color, const Rect2i &p_region, bool p_8bit_dst) { +void EffectsRD::set_color(RID p_dest_texture, const Color &p_color, const Rect2i &p_region, bool p_8bit_dst) { zeromem(©.push_constant, sizeof(CopyPushConstant)); copy.push_constant.section[0] = 0; @@ -372,18 +388,15 @@ void RasterizerEffectsRD::set_color(RID p_dest_texture, const Color &p_color, co copy.push_constant.set_color[2] = p_color.b; copy.push_constant.set_color[3] = p_color.a; - int32_t x_groups = (p_region.size.width - 1) / 8 + 1; - int32_t y_groups = (p_region.size.height - 1) / 8 + 1; - RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[p_8bit_dst ? COPY_MODE_SET_COLOR_8BIT : COPY_MODE_SET_COLOR]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 3); RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_region.size.width, p_region.size.height, 1); RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst) { +void EffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst) { zeromem(©.push_constant, sizeof(CopyPushConstant)); uint32_t base_flags = 0; @@ -392,8 +405,6 @@ void RasterizerEffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, copy.push_constant.section[2] = p_region.size.width; copy.push_constant.section[3] = p_region.size.height; - int32_t x_groups = (p_region.size.width - 1) / 8 + 1; - int32_t y_groups = (p_region.size.height - 1) / 8 + 1; //HORIZONTAL RD::DrawListID compute_list = RD::get_singleton()->compute_list_begin(); RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[p_8bit_dst ? COPY_MODE_GAUSSIAN_COPY_8BIT : COPY_MODE_GAUSSIAN_COPY]); @@ -403,7 +414,7 @@ void RasterizerEffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, copy.push_constant.flags = base_flags | COPY_FLAG_HORIZONTAL; RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_region.size.width, p_region.size.height, 1); RD::get_singleton()->compute_list_add_barrier(compute_list); @@ -414,19 +425,16 @@ void RasterizerEffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, copy.push_constant.flags = base_flags; RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_region.size.width, p_region.size.height, 1); RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength, bool p_high_quality, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_treshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) { +void EffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength, bool p_high_quality, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_treshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) { zeromem(©.push_constant, sizeof(CopyPushConstant)); CopyMode copy_mode = p_first_pass && p_auto_exposure.is_valid() ? COPY_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE : COPY_MODE_GAUSSIAN_GLOW; uint32_t base_flags = 0; - int32_t x_groups = (p_size.width + 7) / 8; - int32_t y_groups = (p_size.height + 7) / 8; - copy.push_constant.section[2] = p_size.x; copy.push_constant.section[3] = p_size.y; @@ -451,16 +459,13 @@ void RasterizerEffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_back_text copy.push_constant.flags = base_flags | (p_first_pass ? COPY_FLAG_GLOW_FIRST_PASS : 0) | (p_high_quality ? COPY_FLAG_HIGH_QUALITY_GLOW : 0); RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_size.width, p_size.height, 1); RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::screen_space_reflection(RID p_diffuse, RID p_normal_roughness, RenderingServer::EnvironmentSSRRoughnessQuality p_roughness_quality, RID p_blur_radius, RID p_blur_radius2, RID p_metallic, const Color &p_metallic_mask, RID p_depth, RID p_scale_depth, RID p_scale_normal, RID p_output, RID p_output_blur, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const CameraMatrix &p_camera) { +void EffectsRD::screen_space_reflection(RID p_diffuse, RID p_normal_roughness, RenderingServer::EnvironmentSSRRoughnessQuality p_roughness_quality, RID p_blur_radius, RID p_blur_radius2, RID p_metallic, const Color &p_metallic_mask, RID p_depth, RID p_scale_depth, RID p_scale_normal, RID p_output, RID p_output_blur, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const CameraMatrix &p_camera) { RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - int32_t x_groups = (p_screen_size.width - 1) / 8 + 1; - int32_t y_groups = (p_screen_size.height - 1) / 8 + 1; - { //scale color and depth to half ssr_scale.push_constant.camera_z_far = p_camera.get_z_far(); ssr_scale.push_constant.camera_z_near = p_camera.get_z_near(); @@ -478,7 +483,7 @@ void RasterizerEffectsRD::screen_space_reflection(RID p_diffuse, RID p_normal_ro RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssr_scale.push_constant, sizeof(ScreenSpaceReflectionScalePushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.width, p_screen_size.height, 1); RD::get_singleton()->compute_list_add_barrier(compute_list); } @@ -519,7 +524,7 @@ void RasterizerEffectsRD::screen_space_reflection(RID p_diffuse, RID p_normal_ro } RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_scale_normal), 2); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.width, p_screen_size.height, 1); } if (p_roughness_quality != RS::ENV_SSR_ROUGNESS_QUALITY_DISABLED) { @@ -557,7 +562,7 @@ void RasterizerEffectsRD::screen_space_reflection(RID p_diffuse, RID p_normal_ro RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssr_filter.push_constant, sizeof(ScreenSpaceReflectionFilterPushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.width, p_screen_size.height, 1); RD::get_singleton()->compute_list_add_barrier(compute_list); @@ -572,18 +577,15 @@ void RasterizerEffectsRD::screen_space_reflection(RID p_diffuse, RID p_normal_ro RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssr_filter.push_constant, sizeof(ScreenSpaceReflectionFilterPushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.width, p_screen_size.height, 1); } RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::sub_surface_scattering(RID p_diffuse, RID p_diffuse2, RID p_depth, const CameraMatrix &p_camera, const Size2i &p_screen_size, float p_scale, float p_depth_scale, RenderingServer::SubSurfaceScatteringQuality p_quality) { +void EffectsRD::sub_surface_scattering(RID p_diffuse, RID p_diffuse2, RID p_depth, const CameraMatrix &p_camera, const Size2i &p_screen_size, float p_scale, float p_depth_scale, RenderingServer::SubSurfaceScatteringQuality p_quality) { RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - int32_t x_groups = (p_screen_size.width - 1) / 8 + 1; - int32_t y_groups = (p_screen_size.height - 1) / 8 + 1; - Plane p = p_camera.xform4(Plane(1, 0, -1, 1)); p.normal /= p.d; float unit_size = p.normal.x; @@ -607,7 +609,7 @@ void RasterizerEffectsRD::sub_surface_scattering(RID p_diffuse, RID p_diffuse2, RD::get_singleton()->compute_list_set_push_constant(compute_list, &sss.push_constant, sizeof(SubSurfaceScatteringPushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.width, p_screen_size.height, 1); RD::get_singleton()->compute_list_add_barrier(compute_list); @@ -618,13 +620,13 @@ void RasterizerEffectsRD::sub_surface_scattering(RID p_diffuse, RID p_diffuse2, sss.push_constant.vertical = true; RD::get_singleton()->compute_list_set_push_constant(compute_list, &sss.push_constant, sizeof(SubSurfaceScatteringPushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.width, p_screen_size.height, 1); RD::get_singleton()->compute_list_end(); } } -void RasterizerEffectsRD::merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection) { +void EffectsRD::merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection) { RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>()); if (p_reflection.is_valid()) { @@ -654,7 +656,7 @@ void RasterizerEffectsRD::merge_specular(RID p_dest_framebuffer, RID p_specular, RD::get_singleton()->draw_list_end(); } -void RasterizerEffectsRD::make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size) { +void EffectsRD::make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size) { zeromem(©.push_constant, sizeof(CopyPushConstant)); copy.push_constant.section[0] = 0; @@ -662,42 +664,36 @@ void RasterizerEffectsRD::make_mipmap(RID p_source_rd_texture, RID p_dest_textur copy.push_constant.section[2] = p_size.width; copy.push_constant.section[3] = p_size.height; - int32_t x_groups = (p_size.width - 1) / 8 + 1; - int32_t y_groups = (p_size.height - 1) / 8 + 1; - RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[COPY_MODE_MIPMAP]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 3); RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_size.width, p_size.height, 1); RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, float p_z_near, float p_z_far, float p_bias, bool p_dp_flip) { +void EffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, float p_z_near, float p_z_far, bool p_dp_flip) { CopyToDPPushConstant push_constant; - push_constant.screen_size[0] = p_rect.size.x; - push_constant.screen_size[1] = p_rect.size.y; - push_constant.dest_offset[0] = p_rect.position.x; - push_constant.dest_offset[1] = p_rect.position.y; - push_constant.bias = p_bias; + push_constant.screen_rect[0] = p_rect.position.x; + push_constant.screen_rect[1] = p_rect.position.y; + push_constant.screen_rect[2] = p_rect.size.width; + push_constant.screen_rect[3] = p_rect.size.height; push_constant.z_far = p_z_far; push_constant.z_near = p_z_near; push_constant.z_flip = p_dp_flip; - int32_t x_groups = (p_rect.size.width - 1) / 8 + 1; - int32_t y_groups = (p_rect.size.height - 1) / 8 + 1; + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, cube_to_dp.pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0); + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); - RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, cube_to_dp.pipeline); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 1); - RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(CopyToDPPushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); - RD::get_singleton()->compute_list_end(); + RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(CopyToDPPushConstant)); + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_TRANSFER); } -void RasterizerEffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings) { +void EffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings) { zeromem(&tonemap.push_constant, sizeof(TonemapPushConstant)); tonemap.push_constant.use_bcs = p_settings.use_bcs; @@ -718,7 +714,10 @@ void RasterizerEffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, tonemap.push_constant.glow_texture_size[1] = p_settings.glow_texture_size.y; tonemap.push_constant.glow_mode = p_settings.glow_mode; - TonemapMode mode = p_settings.glow_use_bicubic_upscale ? TONEMAP_MODE_BICUBIC_GLOW_FILTER : TONEMAP_MODE_NORMAL; + int mode = p_settings.glow_use_bicubic_upscale ? TONEMAP_MODE_BICUBIC_GLOW_FILTER : TONEMAP_MODE_NORMAL; + if (p_settings.use_1d_color_correction) { + mode += 2; + } tonemap.push_constant.tonemapper = p_settings.tonemap_mode; tonemap.push_constant.use_auto_exposure = p_settings.use_auto_exposure; @@ -746,7 +745,7 @@ void RasterizerEffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, RD::get_singleton()->draw_list_end(); } -void RasterizerEffectsRD::luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set) { +void EffectsRD::luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set) { luminance_reduce.push_constant.source_size[0] = p_source_size.x; luminance_reduce.push_constant.source_size[1] = p_source_size.y; luminance_reduce.push_constant.max_luminance = p_max_luminance; @@ -776,10 +775,7 @@ void RasterizerEffectsRD::luminance_reduction(RID p_source_texture, const Size2i RD::get_singleton()->compute_list_set_push_constant(compute_list, &luminance_reduce.push_constant, sizeof(LuminanceReducePushConstant)); - int32_t x_groups = (luminance_reduce.push_constant.source_size[0] - 1) / 8 + 1; - int32_t y_groups = (luminance_reduce.push_constant.source_size[1] - 1) / 8 + 1; - - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, luminance_reduce.push_constant.source_size[0], luminance_reduce.push_constant.source_size[1], 1); luminance_reduce.push_constant.source_size[0] = MAX(luminance_reduce.push_constant.source_size[0] / 8, 1); luminance_reduce.push_constant.source_size[1] = MAX(luminance_reduce.push_constant.source_size[1] / 8, 1); @@ -788,7 +784,7 @@ void RasterizerEffectsRD::luminance_reduction(RID p_source_texture, const Size2i RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_secondary_texture, RID p_halfsize_texture1, RID p_halfsize_texture2, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RenderingServer::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) { +void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_secondary_texture, RID p_halfsize_texture1, RID p_halfsize_texture2, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RenderingServer::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) { bokeh.push_constant.blur_far_active = p_dof_far; bokeh.push_constant.blur_far_begin = p_dof_far_begin; bokeh.push_constant.blur_far_end = p_dof_far_begin + p_dof_far_size; @@ -820,14 +816,12 @@ void RasterizerEffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, con RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_texture), 1); - int32_t x_groups = (p_base_texture_size.x - 1) / 8 + 1; - int32_t y_groups = (p_base_texture_size.y - 1) / 8 + 1; bokeh.push_constant.size[0] = p_base_texture_size.x; bokeh.push_constant.size[1] = p_base_texture_size.y; RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_base_texture_size.x, p_base_texture_size.y, 1); RD::get_singleton()->compute_list_add_barrier(compute_list); if (p_bokeh_shape == RS::DOF_BOKEH_BOX || p_bokeh_shape == RS::DOF_BOKEH_HEXAGON) { @@ -844,8 +838,6 @@ void RasterizerEffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, con RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_halfsize_texture1), 0); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_base_texture), 1); - x_groups = ((p_base_texture_size.x >> 1) - 1) / 8 + 1; - y_groups = ((p_base_texture_size.y >> 1) - 1) / 8 + 1; bokeh.push_constant.size[0] = p_base_texture_size.x >> 1; bokeh.push_constant.size[1] = p_base_texture_size.y >> 1; bokeh.push_constant.half_size = true; @@ -859,7 +851,7 @@ void RasterizerEffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, con RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, bokeh.push_constant.size[0], bokeh.push_constant.size[1], 1); RD::get_singleton()->compute_list_add_barrier(compute_list); //third pass @@ -875,7 +867,7 @@ void RasterizerEffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, con RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, bokeh.push_constant.size[0], bokeh.push_constant.size[1], 1); RD::get_singleton()->compute_list_add_barrier(compute_list); if (p_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == RS::DOF_BLUR_QUALITY_LOW) { @@ -886,8 +878,6 @@ void RasterizerEffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, con RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_halfsize_texture2), 1); - x_groups = (p_base_texture_size.x - 1) / 8 + 1; - y_groups = (p_base_texture_size.y - 1) / 8 + 1; bokeh.push_constant.size[0] = p_base_texture_size.x; bokeh.push_constant.size[1] = p_base_texture_size.y; bokeh.push_constant.half_size = false; @@ -895,7 +885,7 @@ void RasterizerEffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, con RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_base_texture_size.x, p_base_texture_size.y, 1); } } else { //circle @@ -913,15 +903,13 @@ void RasterizerEffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, con RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_halfsize_texture1), 0); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_base_texture), 1); - x_groups = ((p_base_texture_size.x >> 1) - 1) / 8 + 1; - y_groups = ((p_base_texture_size.y >> 1) - 1) / 8 + 1; bokeh.push_constant.size[0] = p_base_texture_size.x >> 1; bokeh.push_constant.size[1] = p_base_texture_size.y >> 1; bokeh.push_constant.half_size = true; RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, bokeh.push_constant.size[0], bokeh.push_constant.size[1], 1); RD::get_singleton()->compute_list_add_barrier(compute_list); //circle is just one pass, then upscale @@ -933,8 +921,6 @@ void RasterizerEffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, con RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_halfsize_texture1), 1); - x_groups = (p_base_texture_size.x - 1) / 8 + 1; - y_groups = (p_base_texture_size.y - 1) / 8 + 1; bokeh.push_constant.size[0] = p_base_texture_size.x; bokeh.push_constant.size[1] = p_base_texture_size.y; bokeh.push_constant.half_size = false; @@ -942,166 +928,355 @@ void RasterizerEffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, con RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_base_texture_size.x, p_base_texture_size.y, 1); } RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, const Size2i &p_depth_buffer_size, RID p_depth_mipmaps_texture, const Vector<RID> &depth_mipmaps, RID p_ao1, bool p_half_size, RID p_ao2, RID p_upscale_buffer, float p_intensity, float p_radius, float p_bias, const CameraMatrix &p_projection, RS::EnvironmentSSAOQuality p_quality, RS::EnvironmentSSAOBlur p_blur, float p_edge_sharpness) { - //minify first - ssao.minify_push_constant.orthogonal = p_projection.is_orthogonal(); - ssao.minify_push_constant.z_near = p_projection.get_z_near(); - ssao.minify_push_constant.z_far = p_projection.get_z_far(); - ssao.minify_push_constant.pixel_size[0] = 1.0 / p_depth_buffer_size.x; - ssao.minify_push_constant.pixel_size[1] = 1.0 / p_depth_buffer_size.y; - ssao.minify_push_constant.source_size[0] = p_depth_buffer_size.x; - ssao.minify_push_constant.source_size[1] = p_depth_buffer_size.y; - - RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - - /* FIRST PASS */ - // Minify the depth buffer. - - for (int i = 0; i < depth_mipmaps.size(); i++) { - if (i == 0) { - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_MINIFY_FIRST]); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_buffer), 0); - } else { - if (i == 1) { - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_MINIFY_MIPMAP]); - } +void EffectsRD::gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass) { + RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, ssao.gather_uniform_set, 0); + if ((p_settings.quality == RS::ENV_SSAO_QUALITY_ULTRA) && !p_adaptive_base_pass) { + RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, ssao.importance_map_uniform_set, 1); + } - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(depth_mipmaps[i - 1]), 0); + for (int i = 0; i < 4; i++) { + if ((p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) { + continue; } - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(depth_mipmaps[i]), 1); - RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.minify_push_constant, sizeof(SSAOMinifyPushConstant)); - // shrink after set - ssao.minify_push_constant.source_size[0] = MAX(1, ssao.minify_push_constant.source_size[0] >> 1); - ssao.minify_push_constant.source_size[1] = MAX(1, ssao.minify_push_constant.source_size[1] >> 1); + ssao.gather_push_constant.pass_coord_offset[0] = i % 2; + ssao.gather_push_constant.pass_coord_offset[1] = i / 2; + ssao.gather_push_constant.pass_uv_offset[0] = ((i % 2) - 0.0) / p_settings.full_screen_size.x; + ssao.gather_push_constant.pass_uv_offset[1] = ((i / 2) - 0.0) / p_settings.full_screen_size.y; + ssao.gather_push_constant.pass = i; + RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, _get_uniform_set_from_image(p_ao_slices[i]), 2); + RD::get_singleton()->compute_list_set_push_constant(p_compute_list, &ssao.gather_push_constant, sizeof(SSAOGatherPushConstant)); - int x_groups = (ssao.minify_push_constant.source_size[0] - 1) / 8 + 1; - int y_groups = (ssao.minify_push_constant.source_size[1] - 1) / 8 + 1; + Size2i size = Size2i(p_settings.full_screen_size.x >> (p_settings.half_size ? 2 : 1), p_settings.full_screen_size.y >> (p_settings.half_size ? 2 : 1)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); - RD::get_singleton()->compute_list_add_barrier(compute_list); + RD::get_singleton()->compute_list_dispatch_threads(p_compute_list, size.x, size.y, 1); } + RD::get_singleton()->compute_list_add_barrier(p_compute_list); +} - /* SECOND PASS */ - // Gather samples +void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_depth_mipmaps_texture, const Vector<RID> &p_depth_mipmaps, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets) { + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->draw_command_begin_label("SSAO"); + /* FIRST PASS */ + // Downsample and deinterleave the depth buffer. + { + RD::get_singleton()->draw_command_begin_label("Downsample Depth"); + if (p_invalidate_uniform_sets) { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 0; + u.ids.push_back(p_depth_mipmaps[1]); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 1; + u.ids.push_back(p_depth_mipmaps[2]); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 2; + u.ids.push_back(p_depth_mipmaps[3]); + uniforms.push_back(u); + } + ssao.downsample_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.downsample_shader.version_get_shader(ssao.downsample_shader_version, 2), 2); + } - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[(SSAO_GATHER_LOW + p_quality) + (p_half_size ? 4 : 0)]); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_mipmaps_texture), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_ao1), 1); - if (!p_half_size) { - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_buffer), 2); - } - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_normal_buffer), 3); + float depth_linearize_mul = -p_projection.matrix[3][2]; + float depth_linearize_add = p_projection.matrix[2][2]; + if (depth_linearize_mul * depth_linearize_add < 0) { + depth_linearize_add = -depth_linearize_add; + } - ssao.gather_push_constant.screen_size[0] = p_depth_buffer_size.x; - ssao.gather_push_constant.screen_size[1] = p_depth_buffer_size.y; - if (p_half_size) { - ssao.gather_push_constant.screen_size[0] >>= 1; - ssao.gather_push_constant.screen_size[1] >>= 1; - } - ssao.gather_push_constant.z_far = p_projection.get_z_far(); - ssao.gather_push_constant.z_near = p_projection.get_z_near(); - ssao.gather_push_constant.orthogonal = p_projection.is_orthogonal(); + ssao.downsample_push_constant.orthogonal = p_projection.is_orthogonal(); + ssao.downsample_push_constant.z_near = depth_linearize_mul; + ssao.downsample_push_constant.z_far = depth_linearize_add; + if (ssao.downsample_push_constant.orthogonal) { + ssao.downsample_push_constant.z_near = p_projection.get_z_near(); + ssao.downsample_push_constant.z_far = p_projection.get_z_far(); + } + ssao.downsample_push_constant.pixel_size[0] = 1.0 / p_settings.full_screen_size.x; + ssao.downsample_push_constant.pixel_size[1] = 1.0 / p_settings.full_screen_size.y; + ssao.downsample_push_constant.radius_sq = p_settings.radius * p_settings.radius; + + int downsample_pipeline = SSAO_DOWNSAMPLE; + if (p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) { + downsample_pipeline = SSAO_DOWNSAMPLE_HALF; + } else if (p_settings.quality > RS::ENV_SSAO_QUALITY_MEDIUM) { + downsample_pipeline = SSAO_DOWNSAMPLE_MIPMAP; + } - ssao.gather_push_constant.proj_info[0] = -2.0f / (ssao.gather_push_constant.screen_size[0] * p_projection.matrix[0][0]); - ssao.gather_push_constant.proj_info[1] = -2.0f / (ssao.gather_push_constant.screen_size[1] * p_projection.matrix[1][1]); - ssao.gather_push_constant.proj_info[2] = (1.0f - p_projection.matrix[0][2]) / p_projection.matrix[0][0]; - ssao.gather_push_constant.proj_info[3] = (1.0f + p_projection.matrix[1][2]) / p_projection.matrix[1][1]; - //ssao.gather_push_constant.proj_info[2] = (1.0f - p_projection.matrix[0][2]) / p_projection.matrix[0][0]; - //ssao.gather_push_constant.proj_info[3] = -(1.0f + p_projection.matrix[1][2]) / p_projection.matrix[1][1]; + if (p_settings.half_size) { + downsample_pipeline++; + } - ssao.gather_push_constant.radius = p_radius; + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[downsample_pipeline]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_buffer), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_depth_mipmaps[0]), 1); + if (p_settings.quality > RS::ENV_SSAO_QUALITY_MEDIUM) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, ssao.downsample_uniform_set, 2); + } + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.downsample_push_constant, sizeof(SSAODownsamplePushConstant)); - ssao.gather_push_constant.proj_scale = float(p_projection.get_pixels_per_meter(ssao.gather_push_constant.screen_size[0])); - ssao.gather_push_constant.bias = p_bias; - ssao.gather_push_constant.intensity_div_r6 = p_intensity / pow(p_radius, 6.0f); + Size2i size(MAX(1, p_settings.full_screen_size.x >> (p_settings.half_size ? 2 : 1)), MAX(1, p_settings.full_screen_size.y >> (p_settings.half_size ? 2 : 1))); - ssao.gather_push_constant.pixel_size[0] = 1.0 / p_depth_buffer_size.x; - ssao.gather_push_constant.pixel_size[1] = 1.0 / p_depth_buffer_size.y; + RD::get_singleton()->compute_list_dispatch_threads(compute_list, size.x, size.y, 1); + RD::get_singleton()->compute_list_add_barrier(compute_list); + RD::get_singleton()->draw_command_end_label(); // Downsample SSAO + } - RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.gather_push_constant, sizeof(SSAOGatherPushConstant)); + /* SECOND PASS */ + // Sample SSAO + { + RD::get_singleton()->draw_command_begin_label("Gather Samples"); + ssao.gather_push_constant.screen_size[0] = p_settings.full_screen_size.x; + ssao.gather_push_constant.screen_size[1] = p_settings.full_screen_size.y; + + ssao.gather_push_constant.half_screen_pixel_size[0] = 1.0 / p_settings.half_screen_size.x; + ssao.gather_push_constant.half_screen_pixel_size[1] = 1.0 / p_settings.half_screen_size.y; + float tan_half_fov_x = 1.0 / p_projection.matrix[0][0]; + float tan_half_fov_y = 1.0 / p_projection.matrix[1][1]; + ssao.gather_push_constant.NDC_to_view_mul[0] = tan_half_fov_x * 2.0; + ssao.gather_push_constant.NDC_to_view_mul[1] = tan_half_fov_y * -2.0; + ssao.gather_push_constant.NDC_to_view_add[0] = tan_half_fov_x * -1.0; + ssao.gather_push_constant.NDC_to_view_add[1] = tan_half_fov_y; + ssao.gather_push_constant.is_orthogonal = p_projection.is_orthogonal(); + + ssao.gather_push_constant.half_screen_pixel_size_x025[0] = ssao.gather_push_constant.half_screen_pixel_size[0] * 0.25; + ssao.gather_push_constant.half_screen_pixel_size_x025[1] = ssao.gather_push_constant.half_screen_pixel_size[1] * 0.25; + + float radius_near_limit = (p_settings.radius * 1.2f); + if (p_settings.quality <= RS::ENV_SSAO_QUALITY_LOW) { + radius_near_limit *= 1.50f; + + if (p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) { + ssao.gather_push_constant.radius *= 0.8f; + } + if (p_settings.half_size) { + ssao.gather_push_constant.radius *= 0.5f; + } + } + radius_near_limit /= tan_half_fov_y; + ssao.gather_push_constant.radius = p_settings.radius; + ssao.gather_push_constant.intensity = p_settings.intensity; + ssao.gather_push_constant.shadow_power = p_settings.power; + ssao.gather_push_constant.shadow_clamp = 0.98; + ssao.gather_push_constant.fade_out_mul = -1.0 / (p_settings.fadeout_to - p_settings.fadeout_from); + ssao.gather_push_constant.fade_out_add = p_settings.fadeout_from / (p_settings.fadeout_to - p_settings.fadeout_from) + 1.0; + ssao.gather_push_constant.horizon_angle_threshold = p_settings.horizon; + ssao.gather_push_constant.inv_radius_near_limit = 1.0f / radius_near_limit; + ssao.gather_push_constant.neg_inv_radius = -1.0 / ssao.gather_push_constant.radius; + + ssao.gather_push_constant.load_counter_avg_div = 9.0 / float((p_settings.quarter_screen_size.x) * (p_settings.quarter_screen_size.y) * 255); + ssao.gather_push_constant.adaptive_sample_limit = p_settings.adaptive_target; + + ssao.gather_push_constant.detail_intensity = p_settings.detail; + ssao.gather_push_constant.quality = MAX(0, p_settings.quality - 1); + ssao.gather_push_constant.size_multiplier = p_settings.half_size ? 2 : 1; + + if (p_invalidate_uniform_sets) { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.binding = 0; + u.ids.push_back(ssao.mirror_sampler); + u.ids.push_back(p_depth_mipmaps_texture); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 1; + u.ids.push_back(p_normal_buffer); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 2; + u.ids.push_back(ssao.gather_constants_buffer); + uniforms.push_back(u); + } + ssao.gather_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.gather_shader.version_get_shader(ssao.gather_shader_version, 0), 0); + } - int x_groups = (ssao.gather_push_constant.screen_size[0] - 1) / 8 + 1; - int y_groups = (ssao.gather_push_constant.screen_size[1] - 1) / 8 + 1; + if (p_invalidate_uniform_sets) { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 0; + u.ids.push_back(p_ao_pong); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.binding = 1; + u.ids.push_back(default_sampler); + u.ids.push_back(p_importance_map); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 2; + u.ids.push_back(ssao.importance_map_load_counter); + uniforms.push_back(u); + } + ssao.importance_map_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.gather_shader.version_get_shader(ssao.gather_shader_version, 2), 1); + } - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); - RD::get_singleton()->compute_list_add_barrier(compute_list); + if (p_settings.quality == RS::ENV_SSAO_QUALITY_ULTRA) { + RD::get_singleton()->draw_command_begin_label("Generate Importance Map"); + ssao.importance_map_push_constant.half_screen_pixel_size[0] = 1.0 / p_settings.half_screen_size.x; + ssao.importance_map_push_constant.half_screen_pixel_size[1] = 1.0 / p_settings.half_screen_size.y; + ssao.importance_map_push_constant.intensity = p_settings.intensity; + ssao.importance_map_push_constant.power = p_settings.power; + //base pass + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER_BASE]); + gather_ssao(compute_list, p_ao_pong_slices, p_settings, true); + //generate importance map + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GENERATE_IMPORTANCE_MAP]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ao_pong), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_importance_map), 1); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.importance_map_push_constant, sizeof(SSAOImportanceMapPushConstant)); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_settings.quarter_screen_size.x, p_settings.quarter_screen_size.y, 1); + RD::get_singleton()->compute_list_add_barrier(compute_list); + //process importance map A + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_PROCESS_IMPORTANCE_MAPA]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_importance_map), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_importance_map_pong), 1); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.importance_map_push_constant, sizeof(SSAOImportanceMapPushConstant)); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_settings.quarter_screen_size.x, p_settings.quarter_screen_size.y, 1); + RD::get_singleton()->compute_list_add_barrier(compute_list); + //process Importance Map B + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_PROCESS_IMPORTANCE_MAPB]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_importance_map_pong), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_importance_map), 1); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, ssao.counter_uniform_set, 2); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.importance_map_push_constant, sizeof(SSAOImportanceMapPushConstant)); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_settings.quarter_screen_size.x, p_settings.quarter_screen_size.y, 1); + RD::get_singleton()->compute_list_add_barrier(compute_list); - /* THIRD PASS */ - // Blur horizontal - - ssao.blur_push_constant.edge_sharpness = p_edge_sharpness; - ssao.blur_push_constant.filter_scale = p_blur; - ssao.blur_push_constant.screen_size[0] = ssao.gather_push_constant.screen_size[0]; - ssao.blur_push_constant.screen_size[1] = ssao.gather_push_constant.screen_size[1]; - ssao.blur_push_constant.z_far = p_projection.get_z_far(); - ssao.blur_push_constant.z_near = p_projection.get_z_near(); - ssao.blur_push_constant.orthogonal = p_projection.is_orthogonal(); - ssao.blur_push_constant.axis[0] = 1; - ssao.blur_push_constant.axis[1] = 0; - - if (p_blur != RS::ENV_SSAO_BLUR_DISABLED) { - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[p_half_size ? SSAO_BLUR_PASS_HALF : SSAO_BLUR_PASS]); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ao1), 0); - if (p_half_size) { - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_mipmaps_texture), 1); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER_ADAPTIVE]); + RD::get_singleton()->draw_command_end_label(); // Importance Map } else { - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_buffer), 1); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER]); } - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_ao2), 3); - - RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.blur_push_constant, sizeof(SSAOBlurPushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); - RD::get_singleton()->compute_list_add_barrier(compute_list); - - /* THIRD PASS */ - // Blur vertical - - ssao.blur_push_constant.axis[0] = 0; - ssao.blur_push_constant.axis[1] = 1; + gather_ssao(compute_list, p_ao_slices, p_settings, false); + RD::get_singleton()->draw_command_end_label(); // Gather SSAO + } - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ao2), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_ao1), 3); + // /* THIRD PASS */ + // // Blur + // + { + RD::get_singleton()->draw_command_begin_label("Edge Aware Blur"); + ssao.blur_push_constant.edge_sharpness = 1.0 - p_settings.sharpness; + ssao.blur_push_constant.half_screen_pixel_size[0] = 1.0 / p_settings.half_screen_size.x; + ssao.blur_push_constant.half_screen_pixel_size[1] = 1.0 / p_settings.half_screen_size.y; + + int blur_passes = p_settings.quality > RS::ENV_SSAO_QUALITY_VERY_LOW ? p_settings.blur_passes : 1; + + for (int pass = 0; pass < blur_passes; pass++) { + int blur_pipeline = SSAO_BLUR_PASS; + if (p_settings.quality > RS::ENV_SSAO_QUALITY_VERY_LOW) { + if (pass < blur_passes - 2) { + blur_pipeline = SSAO_BLUR_PASS_WIDE; + } + blur_pipeline = SSAO_BLUR_PASS_SMART; + } - RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.blur_push_constant, sizeof(SSAOBlurPushConstant)); + for (int i = 0; i < 4; i++) { + if ((p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) { + continue; + } + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[blur_pipeline]); + if (pass % 2 == 0) { + if (p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ao_slices[i]), 0); + } else { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture_and_sampler(p_ao_slices[i], ssao.mirror_sampler), 0); + } + + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_ao_pong_slices[i]), 1); + } else { + if (p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ao_pong_slices[i]), 0); + } else { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture_and_sampler(p_ao_pong_slices[i], ssao.mirror_sampler), 0); + } + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_ao_slices[i]), 1); + } + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.blur_push_constant, sizeof(SSAOBlurPushConstant)); + + Size2i size(p_settings.full_screen_size.x >> (p_settings.half_size ? 2 : 1), p_settings.full_screen_size.y >> (p_settings.half_size ? 2 : 1)); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, size.x, size.y, 1); + } - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + if (p_settings.quality > RS::ENV_SSAO_QUALITY_VERY_LOW) { + RD::get_singleton()->compute_list_add_barrier(compute_list); + } + } + RD::get_singleton()->draw_command_end_label(); // Blur } - if (p_half_size) { //must upscale - - /* FOURTH PASS */ - // upscale if half size - //back to full size - ssao.blur_push_constant.screen_size[0] = p_depth_buffer_size.x; - ssao.blur_push_constant.screen_size[1] = p_depth_buffer_size.y; - RD::get_singleton()->compute_list_add_barrier(compute_list); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_BLUR_UPSCALE]); + /* FOURTH PASS */ + // Interleave buffers + // back to full size + { + RD::get_singleton()->draw_command_begin_label("Interleave Buffers"); + ssao.interleave_push_constant.inv_sharpness = 1.0 - p_settings.sharpness; + ssao.interleave_push_constant.pixel_size[0] = 1.0 / p_settings.full_screen_size.x; + ssao.interleave_push_constant.pixel_size[1] = 1.0 / p_settings.full_screen_size.y; + ssao.interleave_push_constant.size_modifier = uint32_t(p_settings.half_size ? 4 : 2); + + int interleave_pipeline = SSAO_INTERLEAVE_HALF; + if (p_settings.quality == RS::ENV_SSAO_QUALITY_LOW) { + interleave_pipeline = SSAO_INTERLEAVE; + } else if (p_settings.quality >= RS::ENV_SSAO_QUALITY_MEDIUM) { + interleave_pipeline = SSAO_INTERLEAVE_SMART; + } - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ao1), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_upscale_buffer), 3); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_buffer), 1); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_mipmaps_texture), 2); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[interleave_pipeline]); - RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.blur_push_constant, sizeof(SSAOBlurPushConstant)); //not used but set anyway + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_upscale_buffer), 0); + if (p_settings.quality > RS::ENV_SSAO_QUALITY_VERY_LOW && p_settings.blur_passes % 2 == 0) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ao), 1); + } else { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ao_pong), 1); + } - x_groups = (p_depth_buffer_size.x - 1) / 8 + 1; - y_groups = (p_depth_buffer_size.y - 1) / 8 + 1; + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.interleave_push_constant, sizeof(SSAOInterleavePushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_settings.full_screen_size.x, p_settings.full_screen_size.y, 1); + RD::get_singleton()->compute_list_add_barrier(compute_list); + RD::get_singleton()->draw_command_end_label(); // Interleave } + RD::get_singleton()->draw_command_end_label(); //SSAO + RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_TRANSFER); //wait for upcoming transfer - RD::get_singleton()->compute_list_end(); + int zero[1] = { 0 }; + RD::get_singleton()->buffer_update(ssao.importance_map_load_counter, 0, sizeof(uint32_t), &zero, 0); //no barrier } -void RasterizerEffectsRD::roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve) { +void EffectsRD::roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve) { roughness_limiter.push_constant.screen_size[0] = p_size.x; roughness_limiter.push_constant.screen_size[1] = p_size.y; roughness_limiter.push_constant.curve = p_curve; @@ -1111,17 +1286,14 @@ void RasterizerEffectsRD::roughness_limit(RID p_source_normal, RID p_roughness, RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_normal), 0); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_roughness), 1); - int x_groups = (p_size.x - 1) / 8 + 1; - int y_groups = (p_size.y - 1) / 8 + 1; - RD::get_singleton()->compute_list_set_push_constant(compute_list, &roughness_limiter.push_constant, sizeof(RoughnessLimiterPushConstant)); //not used but set anyway - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_size.x, p_size.y, 1); RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) { +void EffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) { zeromem(&roughness.push_constant, sizeof(CubemapRoughnessPushConstant)); roughness.push_constant.face_id = p_face_id > 9 ? 0 : p_face_id; @@ -1146,7 +1318,7 @@ void RasterizerEffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_ RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size) { +void EffectsRD::cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size) { cubemap_downsampler.push_constant.face_size = p_size.x; RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); @@ -1164,11 +1336,11 @@ void RasterizerEffectsRD::cubemap_downsample(RID p_source_cubemap, RID p_dest_cu RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array) { +void EffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array) { Vector<RD::Uniform> uniforms; for (int i = 0; i < p_dest_cubemap.size(); i++) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = i; u.ids.push_back(p_dest_cubemap[i]); uniforms.push_back(u); @@ -1193,7 +1365,7 @@ void RasterizerEffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_des RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_fog, RenderPipelineVertexFormatCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position) { +void EffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_fog, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position) { SkyPushConstant sky_push_constant; zeromem(&sky_push_constant, sizeof(SkyPushConstant)); @@ -1229,7 +1401,7 @@ void RasterizerEffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_ RD::get_singleton()->draw_list_draw(draw_list, true); } -void RasterizerEffectsRD::resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_giprobe, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_giprobe, Vector2i p_screen_size, int p_samples) { +void EffectsRD::resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_giprobe, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_giprobe, Vector2i p_screen_size, int p_samples, uint32_t p_barrier) { ResolvePushConstant push_constant; push_constant.screen_size[0] = p_screen_size.x; push_constant.screen_size[1] = p_screen_size.y; @@ -1246,57 +1418,12 @@ void RasterizerEffectsRD::resolve_gi(RID p_source_depth, RID p_source_normal_rou RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ResolvePushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.x, p_screen_size.y, 1, 8, 8, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.x, p_screen_size.y, 1); - RD::get_singleton()->compute_list_end(); + RD::get_singleton()->compute_list_end(p_barrier); } -void RasterizerEffectsRD::reduce_shadow(RID p_source_shadow, RID p_dest_shadow, const Size2i &p_source_size, const Rect2i &p_source_rect, int p_shrink_limit, RD::ComputeListID compute_list) { - uint32_t push_constant[8] = { (uint32_t)p_source_size.x, (uint32_t)p_source_size.y, (uint32_t)p_source_rect.position.x, (uint32_t)p_source_rect.position.y, (uint32_t)p_shrink_limit, 0, 0, 0 }; - - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, shadow_reduce.pipelines[SHADOW_REDUCE_REDUCE]); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_source_shadow, p_dest_shadow), 0); - RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(uint32_t) * 8); - - RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_source_rect.size.width, p_source_rect.size.height, 1, 8, 8, 1); -} -void RasterizerEffectsRD::filter_shadow(RID p_shadow, RID p_backing_shadow, const Size2i &p_source_size, const Rect2i &p_source_rect, RenderingServer::EnvVolumetricFogShadowFilter p_filter, RD::ComputeListID compute_list, bool p_vertical, bool p_horizontal) { - uint32_t push_constant[8] = { (uint32_t)p_source_size.x, (uint32_t)p_source_size.y, (uint32_t)p_source_rect.position.x, (uint32_t)p_source_rect.position.y, 0, 0, 0, 0 }; - - switch (p_filter) { - case RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_DISABLED: - case RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_LOW: { - push_constant[5] = 0; - } break; - case RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_MEDIUM: { - push_constant[5] = 9; - } break; - case RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_HIGH: { - push_constant[5] = 18; - } break; - } - - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, shadow_reduce.pipelines[SHADOW_REDUCE_FILTER]); - if (p_vertical) { - push_constant[6] = 1; - push_constant[7] = 0; - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_shadow, p_backing_shadow), 0); - RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(uint32_t) * 8); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_source_rect.size.width, p_source_rect.size.height, 1, 8, 8, 1); - } - if (p_vertical && p_horizontal) { - RD::get_singleton()->compute_list_add_barrier(compute_list); - } - if (p_horizontal) { - push_constant[6] = 0; - push_constant[7] = 1; - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_backing_shadow, p_shadow), 0); - RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(uint32_t) * 8); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_source_rect.size.width, p_source_rect.size.height, 1, 8, 8, 1); - } -} - -void RasterizerEffectsRD::sort_buffer(RID p_uniform_set, int p_size) { +void EffectsRD::sort_buffer(RID p_uniform_set, int p_size) { Sort::PushConstant push_constant; push_constant.total_elements = p_size; @@ -1365,7 +1492,7 @@ void RasterizerEffectsRD::sort_buffer(RID p_uniform_set, int p_size) { RD::get_singleton()->compute_list_end(); } -RasterizerEffectsRD::RasterizerEffectsRD() { +EffectsRD::EffectsRD() { { // Initialize copy Vector<String> copy_modes; copy_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n"); @@ -1423,6 +1550,8 @@ RasterizerEffectsRD::RasterizerEffectsRD() { Vector<String> tonemap_modes; tonemap_modes.push_back("\n"); tonemap_modes.push_back("\n#define USE_GLOW_FILTER_BICUBIC\n"); + tonemap_modes.push_back("\n#define USE_1D_LUT\n"); + tonemap_modes.push_back("\n#define USE_GLOW_FILTER_BICUBIC\n#define USE_1D_LUT\n"); tonemap.shader.initialize(tonemap_modes); @@ -1457,8 +1586,12 @@ RasterizerEffectsRD::RasterizerEffectsRD() { cube_to_dp.shader.initialize(copy_modes); cube_to_dp.shader_version = cube_to_dp.shader.version_create(); - - cube_to_dp.pipeline = RD::get_singleton()->compute_pipeline_create(cube_to_dp.shader.version_get_shader(cube_to_dp.shader_version, 0)); + RID shader = cube_to_dp.shader.version_get_shader(cube_to_dp.shader_version, 0); + RD::PipelineDepthStencilState dss; + dss.enable_depth_test = true; + dss.depth_compare_operator = RD::COMPARE_OP_ALWAYS; + dss.enable_depth_write = true; + cube_to_dp.pipeline.setup(shader, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), dss, RD::PipelineColorBlendState(), 0); } { @@ -1481,57 +1614,144 @@ RasterizerEffectsRD::RasterizerEffectsRD() { { // Initialize ssao + + RD::SamplerState sampler; + sampler.mag_filter = RD::SAMPLER_FILTER_NEAREST; + sampler.min_filter = RD::SAMPLER_FILTER_NEAREST; + sampler.mip_filter = RD::SAMPLER_FILTER_NEAREST; + sampler.repeat_u = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; + sampler.repeat_v = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; + sampler.repeat_w = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; + sampler.max_lod = 4; + + ssao.mirror_sampler = RD::get_singleton()->sampler_create(sampler); + uint32_t pipeline = 0; { Vector<String> ssao_modes; - ssao_modes.push_back("\n#define MINIFY_START\n"); ssao_modes.push_back("\n"); + ssao_modes.push_back("\n#define USE_HALF_SIZE\n"); + ssao_modes.push_back("\n#define GENERATE_MIPS\n"); + ssao_modes.push_back("\n#define GENERATE_MIPS\n#define USE_HALF_SIZE"); + ssao_modes.push_back("\n#define USE_HALF_BUFFERS\n"); + ssao_modes.push_back("\n#define USE_HALF_BUFFERS\n#define USE_HALF_SIZE"); - ssao.minify_shader.initialize(ssao_modes); + ssao.downsample_shader.initialize(ssao_modes); - ssao.minify_shader_version = ssao.minify_shader.version_create(); + ssao.downsample_shader_version = ssao.downsample_shader.version_create(); - for (int i = 0; i <= SSAO_MINIFY_MIPMAP; i++) { - ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.minify_shader.version_get_shader(ssao.minify_shader_version, i)); + for (int i = 0; i <= SSAO_DOWNSAMPLE_HALF_RES_HALF; i++) { + ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.downsample_shader.version_get_shader(ssao.downsample_shader_version, i)); pipeline++; } } { Vector<String> ssao_modes; - ssao_modes.push_back("\n#define SSAO_QUALITY_LOW\n"); + ssao_modes.push_back("\n"); - ssao_modes.push_back("\n#define SSAO_QUALITY_HIGH\n"); - ssao_modes.push_back("\n#define SSAO_QUALITY_ULTRA\n"); - ssao_modes.push_back("\n#define SSAO_QUALITY_LOW\n#define USE_HALF_SIZE\n"); - ssao_modes.push_back("\n#define USE_HALF_SIZE\n"); - ssao_modes.push_back("\n#define SSAO_QUALITY_HIGH\n#define USE_HALF_SIZE\n"); - ssao_modes.push_back("\n#define SSAO_QUALITY_ULTRA\n#define USE_HALF_SIZE\n"); + ssao_modes.push_back("\n#define SSAO_BASE\n"); + ssao_modes.push_back("\n#define ADAPTIVE\n"); ssao.gather_shader.initialize(ssao_modes); ssao.gather_shader_version = ssao.gather_shader.version_create(); - for (int i = SSAO_GATHER_LOW; i <= SSAO_GATHER_ULTRA_HALF; i++) { - ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.gather_shader.version_get_shader(ssao.gather_shader_version, i - SSAO_GATHER_LOW)); + for (int i = SSAO_GATHER; i <= SSAO_GATHER_ADAPTIVE; i++) { + ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.gather_shader.version_get_shader(ssao.gather_shader_version, i - SSAO_GATHER)); pipeline++; } + + ssao.gather_constants_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SSAOGatherConstants)); + SSAOGatherConstants gather_constants; + + const int sub_pass_count = 5; + for (int pass = 0; pass < 4; pass++) { + for (int subPass = 0; subPass < sub_pass_count; subPass++) { + int a = pass; + int b = subPass; + + int spmap[5]{ 0, 1, 4, 3, 2 }; + b = spmap[subPass]; + + float ca, sa; + float angle0 = (float(a) + float(b) / float(sub_pass_count)) * Math_PI * 0.5f; + + ca = Math::cos(angle0); + sa = Math::sin(angle0); + + float scale = 1.0f + (a - 1.5f + (b - (sub_pass_count - 1.0f) * 0.5f) / float(sub_pass_count)) * 0.07f; + + gather_constants.rotation_matrices[pass * 20 + subPass * 4 + 0] = scale * ca; + gather_constants.rotation_matrices[pass * 20 + subPass * 4 + 1] = scale * -sa; + gather_constants.rotation_matrices[pass * 20 + subPass * 4 + 2] = -scale * sa; + gather_constants.rotation_matrices[pass * 20 + subPass * 4 + 3] = -scale * ca; + } + } + + RD::get_singleton()->buffer_update(ssao.gather_constants_buffer, 0, sizeof(SSAOGatherConstants), &gather_constants); } { Vector<String> ssao_modes; - ssao_modes.push_back("\n#define MODE_FULL_SIZE\n"); - ssao_modes.push_back("\n"); - ssao_modes.push_back("\n#define MODE_UPSCALE\n"); + ssao_modes.push_back("\n#define GENERATE_MAP\n"); + ssao_modes.push_back("\n#define PROCESS_MAPA\n"); + ssao_modes.push_back("\n#define PROCESS_MAPB\n"); + + ssao.importance_map_shader.initialize(ssao_modes); + + ssao.importance_map_shader_version = ssao.importance_map_shader.version_create(); + + for (int i = SSAO_GENERATE_IMPORTANCE_MAP; i <= SSAO_PROCESS_IMPORTANCE_MAPB; i++) { + ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.importance_map_shader.version_get_shader(ssao.importance_map_shader_version, i - SSAO_GENERATE_IMPORTANCE_MAP)); + + pipeline++; + } + ssao.importance_map_load_counter = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t)); + int zero[1] = { 0 }; + RD::get_singleton()->buffer_update(ssao.importance_map_load_counter, 0, sizeof(uint32_t), &zero); + RD::get_singleton()->set_resource_name(ssao.importance_map_load_counter, "Importance Map Load Counter"); + + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 0; + u.ids.push_back(ssao.importance_map_load_counter); + uniforms.push_back(u); + } + ssao.counter_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.importance_map_shader.version_get_shader(ssao.importance_map_shader_version, 2), 2); + RD::get_singleton()->set_resource_name(ssao.counter_uniform_set, "Load Counter Uniform Set"); + } + { + Vector<String> ssao_modes; + ssao_modes.push_back("\n#define MODE_NON_SMART\n"); + ssao_modes.push_back("\n#define MODE_SMART\n"); + ssao_modes.push_back("\n#define MODE_WIDE\n"); ssao.blur_shader.initialize(ssao_modes); ssao.blur_shader_version = ssao.blur_shader.version_create(); - for (int i = SSAO_BLUR_PASS; i <= SSAO_BLUR_UPSCALE; i++) { + for (int i = SSAO_BLUR_PASS; i <= SSAO_BLUR_PASS_WIDE; i++) { ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.blur_shader.version_get_shader(ssao.blur_shader_version, i - SSAO_BLUR_PASS)); pipeline++; } } + { + Vector<String> ssao_modes; + ssao_modes.push_back("\n#define MODE_NON_SMART\n"); + ssao_modes.push_back("\n#define MODE_SMART\n"); + ssao_modes.push_back("\n#define MODE_HALF\n"); + + ssao.interleave_shader.initialize(ssao_modes); + + ssao.interleave_shader_version = ssao.interleave_shader.version_create(); + for (int i = SSAO_INTERLEAVE; i <= SSAO_INTERLEAVE_HALF; i++) { + ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.interleave_shader.version_get_shader(ssao.interleave_shader_version, i - SSAO_INTERLEAVE)); + RD::get_singleton()->set_resource_name(ssao.pipelines[pipeline], "Interleave Pipeline " + itos(i)); + pipeline++; + } + } ERR_FAIL_COND(pipeline != SSAO_MAX); } @@ -1561,7 +1781,7 @@ RasterizerEffectsRD::RasterizerEffectsRD() { { // Initialize cubemap filter - filter.use_high_quality = GLOBAL_GET("rendering/quality/reflections/fast_filter_high_quality"); + filter.use_high_quality = GLOBAL_GET("rendering/reflections/sky_reflections/fast_filter_high_quality"); Vector<String> cubemap_filter_modes; cubemap_filter_modes.push_back("\n#define USE_HIGH_QUALITY\n"); @@ -1577,16 +1797,16 @@ RasterizerEffectsRD::RasterizerEffectsRD() { if (filter.use_high_quality) { filter.coefficient_buffer = RD::get_singleton()->storage_buffer_create(sizeof(high_quality_coeffs)); - RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(high_quality_coeffs), &high_quality_coeffs[0], false); + RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(high_quality_coeffs), &high_quality_coeffs[0]); } else { filter.coefficient_buffer = RD::get_singleton()->storage_buffer_create(sizeof(low_quality_coeffs)); - RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(low_quality_coeffs), &low_quality_coeffs[0], false); + RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(low_quality_coeffs), &low_quality_coeffs[0]); } Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 0; u.ids.push_back(filter.coefficient_buffer); uniforms.push_back(u); @@ -1699,20 +1919,6 @@ RasterizerEffectsRD::RasterizerEffectsRD() { } { - Vector<String> shadow_reduce_modes; - shadow_reduce_modes.push_back("\n#define MODE_REDUCE\n"); - shadow_reduce_modes.push_back("\n#define MODE_FILTER\n"); - - shadow_reduce.shader.initialize(shadow_reduce_modes); - - shadow_reduce.shader_version = shadow_reduce.shader.version_create(); - - for (int i = 0; i < SHADOW_REDUCE_MAX; i++) { - shadow_reduce.pipelines[i] = RD::get_singleton()->compute_pipeline_create(shadow_reduce.shader.version_get_shader(shadow_reduce.shader_version, i)); - } - } - - { Vector<String> sort_modes; sort_modes.push_back("\n#define MODE_SORT_BLOCK\n"); sort_modes.push_back("\n#define MODE_SORT_STEP\n"); @@ -1733,12 +1939,14 @@ RasterizerEffectsRD::RasterizerEffectsRD() { sampler.max_lod = 0; default_sampler = RD::get_singleton()->sampler_create(sampler); + RD::get_singleton()->set_resource_name(default_sampler, "Default Linear Sampler"); sampler.min_filter = RD::SAMPLER_FILTER_LINEAR; sampler.mip_filter = RD::SAMPLER_FILTER_LINEAR; sampler.max_lod = 1e20; default_mipmap_sampler = RD::get_singleton()->sampler_create(sampler); + RD::get_singleton()->set_resource_name(default_mipmap_sampler, "Default MipMap Sampler"); { //create index array for copy shaders Vector<uint8_t> pv; @@ -1758,7 +1966,7 @@ RasterizerEffectsRD::RasterizerEffectsRD() { } } -RasterizerEffectsRD::~RasterizerEffectsRD() { +EffectsRD::~EffectsRD() { if (RD::get_singleton()->uniform_set_is_valid(filter.image_uniform_set)) { RD::get_singleton()->free(filter.image_uniform_set); } @@ -1772,6 +1980,10 @@ RasterizerEffectsRD::~RasterizerEffectsRD() { RD::get_singleton()->free(index_buffer); //array gets freed as dependency RD::get_singleton()->free(filter.coefficient_buffer); + RD::get_singleton()->free(ssao.mirror_sampler); + RD::get_singleton()->free(ssao.gather_constants_buffer); + RD::get_singleton()->free(ssao.importance_map_load_counter); + bokeh.shader.version_free(bokeh.shader_version); copy.shader.version_free(copy.shader_version); copy_to_fb.shader.version_free(copy_to_fb.shader_version); @@ -1786,11 +1998,12 @@ RasterizerEffectsRD::~RasterizerEffectsRD() { specular_merge.shader.version_free(specular_merge.shader_version); ssao.blur_shader.version_free(ssao.blur_shader_version); ssao.gather_shader.version_free(ssao.gather_shader_version); - ssao.minify_shader.version_free(ssao.minify_shader_version); + ssao.downsample_shader.version_free(ssao.downsample_shader_version); + ssao.interleave_shader.version_free(ssao.interleave_shader_version); + ssao.importance_map_shader.version_free(ssao.importance_map_shader_version); ssr.shader.version_free(ssr.shader_version); ssr_filter.shader.version_free(ssr_filter.shader_version); ssr_scale.shader.version_free(ssr_scale.shader_version); sss.shader.version_free(sss.shader_version); tonemap.shader.version_free(tonemap.shader_version); - shadow_reduce.shader.version_free(shadow_reduce.shader_version); } diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h b/servers/rendering/renderer_rd/effects_rd.h index a0bdd59fd2..1ba25e301b 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h +++ b/servers/rendering/renderer_rd/effects_rd.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rasterizer_effects_rd.h */ +/* effects_rd.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,36 +28,37 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef RASTERIZER_EFFECTS_RD_H -#define RASTERIZER_EFFECTS_RD_H +#ifndef EFFECTS_RD_H +#define EFFECTS_RD_H #include "core/math/camera_matrix.h" -#include "servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h" -#include "servers/rendering/rasterizer_rd/shaders/bokeh_dof.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/copy.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/copy_to_fb.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/cube_to_dp.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/cubemap_downsampler.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/cubemap_filter.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/cubemap_roughness.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/luminance_reduce.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/resolve.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/roughness_limiter.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/screen_space_reflection_filter.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/screen_space_reflection_scale.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/shadow_reduce.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/sort.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/specular_merge.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/ssao.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/ssao_blur.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/ssao_minify.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/subsurface_scattering.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/tonemap.glsl.gen.h" +#include "servers/rendering/renderer_rd/pipeline_cache_rd.h" +#include "servers/rendering/renderer_rd/shaders/bokeh_dof.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/copy.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/copy_to_fb.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/cube_to_dp.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/cubemap_filter.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/luminance_reduce.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/resolve.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/roughness_limiter.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/screen_space_reflection_filter.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/sort.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/specular_merge.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/ssao.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/ssao_blur.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/ssao_downsample.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/ssao_interleave.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/tonemap.glsl.gen.h" #include "servers/rendering_server.h" -class RasterizerEffectsRD { +class EffectsRD { enum CopyMode { COPY_MODE_GAUSSIAN_COPY, COPY_MODE_GAUSSIAN_COPY_8BIT, @@ -144,7 +145,7 @@ class RasterizerEffectsRD { CopyToFbPushConstant push_constant; CopyToFbShaderRD shader; RID shader_version; - RenderPipelineVertexFormatCacheRD pipelines[COPY_TO_FB_MAX]; + PipelineCacheRD pipelines[COPY_TO_FB_MAX]; } copy_to_fb; @@ -167,6 +168,8 @@ class RasterizerEffectsRD { enum TonemapMode { TONEMAP_MODE_NORMAL, TONEMAP_MODE_BICUBIC_GLOW_FILTER, + TONEMAP_MODE_1D_LUT, + TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT, TONEMAP_MODE_MAX }; @@ -198,13 +201,13 @@ class RasterizerEffectsRD { /* tonemap actually writes to a framebuffer, which is * better to do using the raster pipeline rather than - * comptute, as that framebuffer might be in different formats + * compute, as that framebuffer might be in different formats */ struct Tonemap { TonemapPushConstant push_constant; TonemapShaderRD shader; RID shader_version; - RenderPipelineVertexFormatCacheRD pipelines[TONEMAP_MODE_MAX]; + PipelineCacheRD pipelines[TONEMAP_MODE_MAX]; } tonemap; enum LuminanceReduceMode { @@ -230,18 +233,17 @@ class RasterizerEffectsRD { } luminance_reduce; struct CopyToDPPushConstant { - int32_t screen_size[2]; - int32_t dest_offset[2]; - float bias; float z_far; float z_near; uint32_t z_flip; + uint32_t pad; + float screen_rect[4]; }; struct CoptToDP { CubeToDpShaderRD shader; RID shader_version; - RID pipeline; + PipelineCacheRD pipeline; } cube_to_dp; struct BokehPushConstant { @@ -286,71 +288,121 @@ class RasterizerEffectsRD { } bokeh; enum SSAOMode { - SSAO_MINIFY_FIRST, - SSAO_MINIFY_MIPMAP, - SSAO_GATHER_LOW, - SSAO_GATHER_MEDIUM, - SSAO_GATHER_HIGH, - SSAO_GATHER_ULTRA, - SSAO_GATHER_LOW_HALF, - SSAO_GATHER_MEDIUM_HALF, - SSAO_GATHER_HIGH_HALF, - SSAO_GATHER_ULTRA_HALF, + SSAO_DOWNSAMPLE, + SSAO_DOWNSAMPLE_HALF_RES, + SSAO_DOWNSAMPLE_MIPMAP, + SSAO_DOWNSAMPLE_MIPMAP_HALF_RES, + SSAO_DOWNSAMPLE_HALF, + SSAO_DOWNSAMPLE_HALF_RES_HALF, + SSAO_GATHER, + SSAO_GATHER_BASE, + SSAO_GATHER_ADAPTIVE, + SSAO_GENERATE_IMPORTANCE_MAP, + SSAO_PROCESS_IMPORTANCE_MAPA, + SSAO_PROCESS_IMPORTANCE_MAPB, SSAO_BLUR_PASS, - SSAO_BLUR_PASS_HALF, - SSAO_BLUR_UPSCALE, + SSAO_BLUR_PASS_SMART, + SSAO_BLUR_PASS_WIDE, + SSAO_INTERLEAVE, + SSAO_INTERLEAVE_SMART, + SSAO_INTERLEAVE_HALF, SSAO_MAX }; - struct SSAOMinifyPushConstant { + struct SSAODownsamplePushConstant { float pixel_size[2]; float z_far; float z_near; - int32_t source_size[2]; uint32_t orthogonal; - uint32_t pad; + float radius_sq; + uint32_t pad[2]; }; struct SSAOGatherPushConstant { int32_t screen_size[2]; - float z_far; - float z_near; + int pass; + int quality; + + float half_screen_pixel_size[2]; + int size_multiplier; + float detail_intensity; + + float NDC_to_view_mul[2]; + float NDC_to_view_add[2]; + + float pad[2]; + float half_screen_pixel_size_x025[2]; - uint32_t orthogonal; - float intensity_div_r6; float radius; - float bias; + float intensity; + float shadow_power; + float shadow_clamp; - float proj_info[4]; - float pixel_size[2]; - float proj_scale; - uint32_t pad; + float fade_out_mul; + float fade_out_add; + float horizon_angle_threshold; + float inv_radius_near_limit; + + bool is_orthogonal; + float neg_inv_radius; + float load_counter_avg_div; + float adaptive_sample_limit; + + int32_t pass_coord_offset[2]; + float pass_uv_offset[2]; + }; + + struct SSAOGatherConstants { + float rotation_matrices[80]; //5 vec4s * 4 + }; + + struct SSAOImportanceMapPushConstant { + float half_screen_pixel_size[2]; + float intensity; + float power; }; struct SSAOBlurPushConstant { float edge_sharpness; - int32_t filter_scale; - float z_far; - float z_near; - uint32_t orthogonal; - uint32_t pad[3]; - int32_t axis[2]; - int32_t screen_size[2]; + float pad; + float half_screen_pixel_size[2]; + }; + + struct SSAOInterleavePushConstant { + float inv_sharpness; + uint32_t size_modifier; + float pixel_size[2]; }; struct SSAO { - SSAOMinifyPushConstant minify_push_constant; - SsaoMinifyShaderRD minify_shader; - RID minify_shader_version; + SSAODownsamplePushConstant downsample_push_constant; + SsaoDownsampleShaderRD downsample_shader; + RID downsample_shader_version; + RID downsample_uniform_set; SSAOGatherPushConstant gather_push_constant; SsaoShaderRD gather_shader; RID gather_shader_version; + RID gather_uniform_set; + RID gather_constants_buffer; + bool gather_initialized = false; + + SSAOImportanceMapPushConstant importance_map_push_constant; + SsaoImportanceMapShaderRD importance_map_shader; + RID importance_map_shader_version; + RID importance_map_load_counter; + RID importance_map_uniform_set; + RID counter_uniform_set; SSAOBlurPushConstant blur_push_constant; SsaoBlurShaderRD blur_shader; RID blur_shader_version; + SSAOInterleavePushConstant interleave_push_constant; + SsaoInterleaveShaderRD interleave_shader; + RID interleave_shader_version; + + RID mirror_sampler; RID pipelines[SSAO_MAX]; } ssao; @@ -424,7 +476,7 @@ class RasterizerEffectsRD { struct SpecularMerge { SpecularMergeShaderRD shader; RID shader_version; - RenderPipelineVertexFormatCacheRD pipelines[SPECULAR_MERGE_MAX]; + PipelineCacheRD pipelines[SPECULAR_MERGE_MAX]; } specular_merge; @@ -544,18 +596,6 @@ class RasterizerEffectsRD { RID pipelines[RESOLVE_MODE_MAX]; //3 quality levels } resolve; - enum ShadowReduceMode { - SHADOW_REDUCE_REDUCE, - SHADOW_REDUCE_FILTER, - SHADOW_REDUCE_MAX - }; - - struct ShadowReduce { - ShadowReduceShaderRD shader; - RID shader_version; - RID pipelines[SHADOW_REDUCE_MAX]; - } shadow_reduce; - enum SortMode { SORT_MODE_BLOCK, SORT_MODE_STEP, @@ -596,13 +636,27 @@ class RasterizerEffectsRD { } }; + struct TextureSamplerPair { + RID texture; + RID sampler; + _FORCE_INLINE_ bool operator<(const TextureSamplerPair &p_pair) const { + if (texture == p_pair.texture) { + return sampler < p_pair.sampler; + } else { + return texture < p_pair.texture; + } + } + }; + Map<RID, RID> texture_to_compute_uniform_set_cache; Map<TexturePair, RID> texture_pair_to_compute_uniform_set_cache; Map<TexturePair, RID> image_pair_to_compute_uniform_set_cache; + Map<TextureSamplerPair, RID> texture_sampler_to_compute_uniform_set_cache; RID _get_uniform_set_from_image(RID p_texture); RID _get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false); RID _get_compute_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false); + RID _get_compute_uniform_set_from_texture_and_sampler(RID p_texture, RID p_sampler); RID _get_compute_uniform_set_from_texture_pair(RID p_texture, RID p_texture2, bool p_use_mipmaps = false); RID _get_compute_uniform_set_from_image_pair(RID p_texture, RID p_texture2); @@ -619,7 +673,7 @@ public: void cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size); void make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size); - void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, float p_z_near, float p_z_far, float p_bias, bool p_dp_flip); + void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_texture, const Rect2 &p_rect, float p_z_near, float p_z_far, bool p_dp_flip); void luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false); void bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_secondary_texture, RID p_bokeh_texture1, RID p_bokeh_texture2, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RS::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal); @@ -654,6 +708,7 @@ public: float saturation = 1.0; bool use_color_correction = false; + bool use_1d_color_correction = false; RID color_correction_texture; bool use_fxaa = false; @@ -661,28 +716,46 @@ public: Vector2i texture_size; }; + struct SSAOSettings { + float radius = 1.0; + float intensity = 2.0; + float power = 1.5; + float detail = 0.5; + float horizon = 0.06; + float sharpness = 0.98; + + RS::EnvironmentSSAOQuality quality = RS::ENV_SSAO_QUALITY_MEDIUM; + bool half_size = false; + float adaptive_target = 0.5; + int blur_passes = 2; + float fadeout_from = 50.0; + float fadeout_to = 300.0; + + Size2i full_screen_size = Size2i(); + Size2i half_screen_size = Size2i(); + Size2i quarter_screen_size = Size2i(); + }; + void tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings); - void generate_ssao(RID p_depth_buffer, RID p_normal_buffer, const Size2i &p_depth_buffer_size, RID p_depth_mipmaps_texture, const Vector<RID> &depth_mipmaps, RID p_ao1, bool p_half_size, RID p_ao2, RID p_upscale_buffer, float p_intensity, float p_radius, float p_bias, const CameraMatrix &p_projection, RS::EnvironmentSSAOQuality p_quality, RS::EnvironmentSSAOBlur p_blur, float p_edge_sharpness); + void gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass); + void generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_depth_mipmaps_texture, const Vector<RID> &depth_mipmaps, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets); void roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve); void cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size); void cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array); - void render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_fog, RenderPipelineVertexFormatCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position); + void render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_fog, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position); void screen_space_reflection(RID p_diffuse, RID p_normal_roughness, RS::EnvironmentSSRRoughnessQuality p_roughness_quality, RID p_blur_radius, RID p_blur_radius2, RID p_metallic, const Color &p_metallic_mask, RID p_depth, RID p_scale_depth, RID p_scale_normal, RID p_output, RID p_output_blur, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const CameraMatrix &p_camera); void merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection); void sub_surface_scattering(RID p_diffuse, RID p_diffuse2, RID p_depth, const CameraMatrix &p_camera, const Size2i &p_screen_size, float p_scale, float p_depth_scale, RS::SubSurfaceScatteringQuality p_quality); - void resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_giprobe, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_giprobe, Vector2i p_screen_size, int p_samples); - - void reduce_shadow(RID p_source_shadow, RID p_dest_shadow, const Size2i &p_source_size, const Rect2i &p_source_rect, int p_shrink_limit, RenderingDevice::ComputeListID compute_list); - void filter_shadow(RID p_shadow, RID p_backing_shadow, const Size2i &p_source_size, const Rect2i &p_source_rect, RS::EnvVolumetricFogShadowFilter p_filter, RenderingDevice::ComputeListID compute_list, bool p_vertical = true, bool p_horizontal = true); + void resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_giprobe, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_giprobe, Vector2i p_screen_size, int p_samples, uint32_t p_barrier = RD::BARRIER_MASK_ALL); void sort_buffer(RID p_uniform_set, int p_size); - RasterizerEffectsRD(); - ~RasterizerEffectsRD(); + EffectsRD(); + ~EffectsRD(); }; #endif // !RASTERIZER_EFFECTS_RD_H diff --git a/servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.cpp b/servers/rendering/renderer_rd/pipeline_cache_rd.cpp index 5cc3da8d4e..b2b919c40e 100644 --- a/servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.cpp +++ b/servers/rendering/renderer_rd/pipeline_cache_rd.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* render_pipeline_vertex_format_cache_rd.cpp */ +/* pipeline_cache_rd.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,10 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "render_pipeline_vertex_format_cache_rd.h" +#include "pipeline_cache_rd.h" #include "core/os/memory.h" -RID RenderPipelineVertexFormatCacheRD::_generate_version(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe) { +RID PipelineCacheRD::_generate_version(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe) { RD::PipelineMultisampleState multisample_state_version = multisample_state; multisample_state_version.sample_count = RD::get_singleton()->framebuffer_format_get_texture_samples(p_framebuffer_format_id); @@ -49,7 +49,7 @@ RID RenderPipelineVertexFormatCacheRD::_generate_version(RD::VertexFormatID p_ve return pipeline; } -void RenderPipelineVertexFormatCacheRD::_clear() { +void PipelineCacheRD::_clear() { if (versions) { for (uint32_t i = 0; i < version_count; i++) { //shader may be gone, so this may not be valid @@ -63,7 +63,7 @@ void RenderPipelineVertexFormatCacheRD::_clear() { } } -void RenderPipelineVertexFormatCacheRD::setup(RID p_shader, RD::RenderPrimitive p_primitive, const RD::PipelineRasterizationState &p_rasterization_state, RD::PipelineMultisampleState p_multisample, const RD::PipelineDepthStencilState &p_depth_stencil_state, const RD::PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags) { +void PipelineCacheRD::setup(RID p_shader, RD::RenderPrimitive p_primitive, const RD::PipelineRasterizationState &p_rasterization_state, RD::PipelineMultisampleState p_multisample, const RD::PipelineDepthStencilState &p_depth_stencil_state, const RD::PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags) { ERR_FAIL_COND(p_shader.is_null()); _clear(); shader = p_shader; @@ -76,24 +76,24 @@ void RenderPipelineVertexFormatCacheRD::setup(RID p_shader, RD::RenderPrimitive dynamic_state_flags = p_dynamic_state_flags; } -void RenderPipelineVertexFormatCacheRD::update_shader(RID p_shader) { +void PipelineCacheRD::update_shader(RID p_shader) { ERR_FAIL_COND(p_shader.is_null()); _clear(); setup(p_shader, render_primitive, rasterization_state, multisample_state, depth_stencil_state, blend_state, dynamic_state_flags); } -void RenderPipelineVertexFormatCacheRD::clear() { +void PipelineCacheRD::clear() { _clear(); shader = RID(); //clear shader input_mask = 0; } -RenderPipelineVertexFormatCacheRD::RenderPipelineVertexFormatCacheRD() { +PipelineCacheRD::PipelineCacheRD() { version_count = 0; versions = nullptr; input_mask = 0; } -RenderPipelineVertexFormatCacheRD::~RenderPipelineVertexFormatCacheRD() { +PipelineCacheRD::~PipelineCacheRD() { _clear(); } diff --git a/servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h b/servers/rendering/renderer_rd/pipeline_cache_rd.h index 6a72dbc77c..b1c8f21ecc 100644 --- a/servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h +++ b/servers/rendering/renderer_rd/pipeline_cache_rd.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* render_pipeline_vertex_format_cache_rd.h */ +/* pipeline_cache_rd.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef RENDER_PIPELINE_CACHE_RD_H -#define RENDER_PIPELINE_CACHE_RD_H +#ifndef PIPELINE_CACHE_RD_H +#define PIPELINE_CACHE_RD_H #include "core/os/spin_lock.h" #include "servers/rendering/rendering_device.h" -class RenderPipelineVertexFormatCacheRD { +class PipelineCacheRD { SpinLock spin_lock; RID shader; @@ -89,8 +89,8 @@ public: return input_mask; } void clear(); - RenderPipelineVertexFormatCacheRD(); - ~RenderPipelineVertexFormatCacheRD(); + PipelineCacheRD(); + ~PipelineCacheRD(); }; #endif // RENDER_PIPELINE_CACHE_RD_H diff --git a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 921a7b966e..7d6e2fa8e4 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rasterizer_canvas_rd.cpp */ +/* renderer_canvas_render_rd.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "rasterizer_canvas_rd.h" +#include "renderer_canvas_render_rd.h" #include "core/config/project_settings.h" #include "core/math/geometry_2d.h" #include "core/math/math_funcs.h" -#include "rasterizer_rd.h" +#include "renderer_compositor_rd.h" -void RasterizerCanvasRD::_update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4) { +void RendererCanvasRenderRD::_update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4) { p_mat4[0] = p_transform.elements[0][0]; p_mat4[1] = p_transform.elements[0][1]; p_mat4[2] = 0; @@ -53,7 +53,7 @@ void RasterizerCanvasRD::_update_transform_2d_to_mat4(const Transform2D &p_trans p_mat4[15] = 1; } -void RasterizerCanvasRD::_update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4) { +void RendererCanvasRenderRD::_update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4) { p_mat2x4[0] = p_transform.elements[0][0]; p_mat2x4[1] = p_transform.elements[1][0]; p_mat2x4[2] = 0; @@ -65,7 +65,7 @@ void RasterizerCanvasRD::_update_transform_2d_to_mat2x4(const Transform2D &p_tra p_mat2x4[7] = p_transform.elements[2][1]; } -void RasterizerCanvasRD::_update_transform_2d_to_mat2x3(const Transform2D &p_transform, float *p_mat2x3) { +void RendererCanvasRenderRD::_update_transform_2d_to_mat2x3(const Transform2D &p_transform, float *p_mat2x3) { p_mat2x3[0] = p_transform.elements[0][0]; p_mat2x3[1] = p_transform.elements[0][1]; p_mat2x3[2] = p_transform.elements[1][0]; @@ -74,7 +74,7 @@ void RasterizerCanvasRD::_update_transform_2d_to_mat2x3(const Transform2D &p_tra p_mat2x3[5] = p_transform.elements[2][1]; } -void RasterizerCanvasRD::_update_transform_to_mat4(const Transform &p_transform, float *p_mat4) { +void RendererCanvasRenderRD::_update_transform_to_mat4(const Transform &p_transform, float *p_mat4) { p_mat4[0] = p_transform.basis.elements[0][0]; p_mat4[1] = p_transform.basis.elements[1][0]; p_mat4[2] = p_transform.basis.elements[2][0]; @@ -93,7 +93,7 @@ void RasterizerCanvasRD::_update_transform_to_mat4(const Transform &p_transform, p_mat4[15] = 1; } -RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, const Vector<int> &p_bones, const Vector<float> &p_weights) { +RendererCanvasRender::PolygonID RendererCanvasRenderRD::request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, const Vector<int> &p_bones, const Vector<float> &p_weights) { // Care must be taken to generate array formats // in ways where they could be reused, so we will // put single-occuring elements first, and repeated @@ -119,9 +119,9 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int Vector<uint8_t> polygon_buffer; polygon_buffer.resize(buffer_size * sizeof(float)); Vector<RD::VertexAttribute> descriptions; - descriptions.resize(4); + descriptions.resize(5); Vector<RID> buffers; - buffers.resize(4); + buffers.resize(5); { const uint8_t *r = polygon_buffer.ptr(); @@ -184,7 +184,7 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int vd.stride = 0; descriptions.write[1] = vd; - buffers.write[1] = storage->mesh_get_default_rd_buffer(RasterizerStorageRD::DEFAULT_RD_BUFFER_COLOR); + buffers.write[1] = storage->mesh_get_default_rd_buffer(RendererStorageRD::DEFAULT_RD_BUFFER_COLOR); } //uvs @@ -212,13 +212,13 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int vd.stride = 0; descriptions.write[2] = vd; - buffers.write[2] = storage->mesh_get_default_rd_buffer(RasterizerStorageRD::DEFAULT_RD_BUFFER_TEX_UV); + buffers.write[2] = storage->mesh_get_default_rd_buffer(RendererStorageRD::DEFAULT_RD_BUFFER_TEX_UV); } //bones if ((uint32_t)p_indices.size() == vertex_count * 4 && (uint32_t)p_weights.size() == vertex_count * 4) { RD::VertexAttribute vd; - vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT; + vd.format = RD::DATA_FORMAT_R16G16B16A16_UINT; vd.offset = base_offset * sizeof(float); vd.location = RS::ARRAY_BONES; vd.stride = stride * sizeof(float); @@ -226,16 +226,42 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int descriptions.write[3] = vd; const int *bone_ptr = p_bones.ptr(); - const float *weight_ptr = p_weights.ptr(); for (uint32_t i = 0; i < vertex_count; i++) { uint16_t *bone16w = (uint16_t *)&uptr[base_offset + i * stride]; - uint16_t *weight16w = (uint16_t *)&uptr[base_offset + i * stride + 2]; bone16w[0] = bone_ptr[i * 4 + 0]; bone16w[1] = bone_ptr[i * 4 + 1]; bone16w[2] = bone_ptr[i * 4 + 2]; bone16w[3] = bone_ptr[i * 4 + 3]; + } + + base_offset += 2; + } else { + RD::VertexAttribute vd; + vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT; + vd.offset = 0; + vd.location = RS::ARRAY_BONES; + vd.stride = 0; + + descriptions.write[3] = vd; + buffers.write[3] = storage->mesh_get_default_rd_buffer(RendererStorageRD::DEFAULT_RD_BUFFER_BONES); + } + + //weights + if ((uint32_t)p_weights.size() == vertex_count * 4) { + RD::VertexAttribute vd; + vd.format = RD::DATA_FORMAT_R16G16B16A16_UNORM; + vd.offset = base_offset * sizeof(float); + vd.location = RS::ARRAY_WEIGHTS; + vd.stride = stride * sizeof(float); + + descriptions.write[4] = vd; + + const float *weight_ptr = p_weights.ptr(); + + for (uint32_t i = 0; i < vertex_count; i++) { + uint16_t *weight16w = (uint16_t *)&uptr[base_offset + i * stride]; weight16w[0] = CLAMP(weight_ptr[i * 4 + 0] * 65535, 0, 65535); weight16w[1] = CLAMP(weight_ptr[i * 4 + 1] * 65535, 0, 65535); @@ -243,16 +269,16 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int weight16w[3] = CLAMP(weight_ptr[i * 4 + 3] * 65535, 0, 65535); } - base_offset += 4; + base_offset += 2; } else { RD::VertexAttribute vd; - vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT; + vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; vd.offset = 0; - vd.location = RS::ARRAY_BONES; + vd.location = RS::ARRAY_WEIGHTS; vd.stride = 0; - descriptions.write[3] = vd; - buffers.write[3] = storage->mesh_get_default_rd_buffer(RasterizerStorageRD::DEFAULT_RD_BUFFER_BONES); + descriptions.write[4] = vd; + buffers.write[4] = storage->mesh_get_default_rd_buffer(RendererStorageRD::DEFAULT_RD_BUFFER_BONES); } //check that everything is as it should be @@ -293,7 +319,7 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int return id; } -void RasterizerCanvasRD::free_polygon(PolygonID p_polygon) { +void RendererCanvasRenderRD::free_polygon(PolygonID p_polygon) { PolygonBuffers *pb_ptr = polygon_buffers.polygons.getptr(p_polygon); ERR_FAIL_COND(!pb_ptr); @@ -314,7 +340,7 @@ void RasterizerCanvasRD::free_polygon(PolygonID p_polygon) { //////////////////// -void RasterizerCanvasRD::_bind_canvas_texture(RD::DrawListID p_draw_list, RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID &r_last_texture, PushConstant &push_constant, Size2 &r_texpixel_size) { +void RendererCanvasRenderRD::_bind_canvas_texture(RD::DrawListID p_draw_list, RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID &r_last_texture, PushConstant &push_constant, Size2 &r_texpixel_size) { if (p_texture == RID()) { p_texture = default_canvas_texture; } @@ -364,7 +390,7 @@ void RasterizerCanvasRD::_bind_canvas_texture(RD::DrawListID p_draw_list, RID p_ r_last_texture = p_texture; } -void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_item, RD::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, PipelineVariants *p_pipeline_variants) { +void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, const Item *p_item, RD::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, PipelineVariants *p_pipeline_variants) { //create an empty push constant RS::CanvasItemTextureFilter current_filter = default_filter; @@ -575,10 +601,10 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ push_constant.flags |= FLAGS_NINEPACH_DRAW_CENTER; } - push_constant.ninepatch_margins[0] = np->margin[MARGIN_LEFT]; - push_constant.ninepatch_margins[1] = np->margin[MARGIN_TOP]; - push_constant.ninepatch_margins[2] = np->margin[MARGIN_RIGHT]; - push_constant.ninepatch_margins[3] = np->margin[MARGIN_BOTTOM]; + push_constant.ninepatch_margins[0] = np->margin[SIDE_LEFT]; + push_constant.ninepatch_margins[1] = np->margin[SIDE_TOP]; + push_constant.ninepatch_margins[2] = np->margin[SIDE_RIGHT]; + push_constant.ninepatch_margins[3] = np->margin[SIDE_BOTTOM]; RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant)); RD::get_singleton()->draw_list_bind_index_array(p_draw_list, shader.quad_index_array); @@ -848,7 +874,7 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); //not used, so keep white - RenderingServerRaster::redraw_request(); + RenderingServerDefault::redraw_request(); storage->particles_request_process(particles_cmd->particles); //enable instancing @@ -990,13 +1016,13 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ } } -RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_backbuffer) { +RID RendererCanvasRenderRD::_create_base_uniform_set(RID p_to_render_target, bool p_backbuffer) { //re create canvas state Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 1; u.ids.push_back(state.canvas_state_buffer); uniforms.push_back(u); @@ -1004,7 +1030,7 @@ RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_ { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 2; u.ids.push_back(state.lights_uniform_buffer); uniforms.push_back(u); @@ -1012,7 +1038,7 @@ RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_ { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 3; u.ids.push_back(storage->decal_atlas_get_texture()); uniforms.push_back(u); @@ -1020,7 +1046,7 @@ RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_ { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 4; u.ids.push_back(state.shadow_texture); uniforms.push_back(u); @@ -1028,7 +1054,7 @@ RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_ { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 5; u.ids.push_back(state.shadow_sampler); uniforms.push_back(u); @@ -1036,7 +1062,7 @@ RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_ { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 6; RID screen; if (p_backbuffer) { @@ -1044,7 +1070,7 @@ RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_ } else { screen = storage->render_target_get_rd_backbuffer(p_to_render_target); if (screen.is_null()) { //unallocated backbuffer - screen = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE); + screen = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); } } u.ids.push_back(screen); @@ -1053,7 +1079,7 @@ RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_ { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 7; RID sdf = storage->render_target_get_sdf_texture(p_to_render_target); u.ids.push_back(sdf); @@ -1063,7 +1089,7 @@ RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_ { //needs samplers for the material (uses custom textures) create them RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 8; u.ids.resize(12); RID *ids_ptr = u.ids.ptrw(); @@ -1084,7 +1110,7 @@ RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_ { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 9; u.ids.push_back(storage->global_variables_get_storage_buffer()); uniforms.push_back(u); @@ -1100,7 +1126,7 @@ RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_ return uniform_set; } -void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool p_to_backbuffer) { +void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool p_to_backbuffer) { Item *current_clip = nullptr; Transform2D canvas_transform_inverse = p_canvas_transform_inverse; @@ -1167,7 +1193,7 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, if (material != prev_material) { MaterialData *material_data = nullptr; if (material.is_valid()) { - material_data = (MaterialData *)storage->material_get_data(material, RasterizerStorageRD::SHADER_TYPE_2D); + material_data = (MaterialData *)storage->material_get_data(material, RendererStorageRD::SHADER_TYPE_2D); } if (material_data) { @@ -1192,7 +1218,7 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, RD::get_singleton()->draw_list_end(); } -void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_light_list, const Transform2D &p_canvas_transform, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) { +void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_light_list, const Transform2D &p_canvas_transform, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) { r_sdf_used = false; int item_count = 0; @@ -1341,7 +1367,7 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite } if (light_count > 0) { - RD::get_singleton()->buffer_update(state.lights_uniform_buffer, 0, sizeof(LightUniform) * light_count, &state.light_uniforms[0], true); + RD::get_singleton()->buffer_update(state.lights_uniform_buffer, 0, sizeof(LightUniform) * light_count, &state.light_uniforms[0]); } { @@ -1395,7 +1421,7 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite //print_line("w: " + itos(ssize.width) + " s: " + rtos(canvas_scale)); state_buffer.tex_to_sdf = 1.0 / ((canvas_scale.x + canvas_scale.y) * 0.5); - RD::get_singleton()->buffer_update(state.canvas_state_buffer, 0, sizeof(State::Buffer), &state_buffer, true); + RD::get_singleton()->buffer_update(state.canvas_state_buffer, 0, sizeof(State::Buffer), &state_buffer); } { //default filter/repeat @@ -1423,7 +1449,7 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite } if (ci->material.is_valid()) { - MaterialData *md = (MaterialData *)storage->material_get_data(ci->material, RasterizerStorageRD::SHADER_TYPE_2D); + MaterialData *md = (MaterialData *)storage->material_get_data(ci->material, RendererStorageRD::SHADER_TYPE_2D); if (md && md->shader_data->valid) { if (md->shader_data->uses_screen_texture && canvas_group_owner == nullptr) { if (!material_screen_texture_found) { @@ -1435,12 +1461,12 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite if (md->shader_data->uses_sdf) { r_sdf_used = true; } - if (md->last_frame != RasterizerRD::singleton->get_frame_number()) { - md->last_frame = RasterizerRD::singleton->get_frame_number(); + if (md->last_frame != RendererCompositorRD::singleton->get_frame_number()) { + md->last_frame = RendererCompositorRD::singleton->get_frame_number(); if (!RD::get_singleton()->uniform_set_is_valid(md->uniform_set)) { // uniform set may be gone because a dependency was erased. In this case, it will happen // if a texture is deleted, so just re-create it. - storage->material_force_update_textures(ci->material, RasterizerStorageRD::SHADER_TYPE_2D); + storage->material_force_update_textures(ci->material, RendererStorageRD::SHADER_TYPE_2D); } } } @@ -1501,12 +1527,12 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite } } -RID RasterizerCanvasRD::light_create() { +RID RendererCanvasRenderRD::light_create() { CanvasLight canvas_light; return canvas_light_owner.make_rid(canvas_light); } -void RasterizerCanvasRD::light_set_texture(RID p_rid, RID p_texture) { +void RendererCanvasRenderRD::light_set_texture(RID p_rid, RID p_texture) { CanvasLight *cl = canvas_light_owner.getornull(p_rid); ERR_FAIL_COND(!cl); if (cl->texture == p_texture) { @@ -1522,14 +1548,14 @@ void RasterizerCanvasRD::light_set_texture(RID p_rid, RID p_texture) { } } -void RasterizerCanvasRD::light_set_use_shadow(RID p_rid, bool p_enable) { +void RendererCanvasRenderRD::light_set_use_shadow(RID p_rid, bool p_enable) { CanvasLight *cl = canvas_light_owner.getornull(p_rid); ERR_FAIL_COND(!cl); cl->shadow.enabled = p_enable; } -void RasterizerCanvasRD::_update_shadow_atlas() { +void RendererCanvasRenderRD::_update_shadow_atlas() { if (state.shadow_fb == RID()) { //ah, we lack the shadow texture.. RD::get_singleton()->free(state.shadow_texture); //erase placeholder @@ -1538,7 +1564,7 @@ void RasterizerCanvasRD::_update_shadow_atlas() { { //texture RD::TextureFormat tf; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.width = state.shadow_texture_size; tf.height = state.max_lights_per_render * 2; tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; @@ -1549,7 +1575,7 @@ void RasterizerCanvasRD::_update_shadow_atlas() { } { RD::TextureFormat tf; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.width = state.shadow_texture_size; tf.height = state.max_lights_per_render * 2; tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; @@ -1562,7 +1588,7 @@ void RasterizerCanvasRD::_update_shadow_atlas() { state.shadow_fb = RD::get_singleton()->framebuffer_create(fb_textures); } } -void RasterizerCanvasRD::light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) { +void RendererCanvasRenderRD::light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) { CanvasLight *cl = canvas_light_owner.getornull(p_rid); ERR_FAIL_COND(!cl->shadow.enabled); @@ -1596,7 +1622,7 @@ void RasterizerCanvasRD::light_update_shadow(RID p_rid, int p_shadow_index, cons projection.set_frustum(xmin, xmax, ymin, ymax, nearp, farp); } - Vector3 cam_target = Basis(Vector3(0, 0, Math_PI * 2 * ((i + 3) / 4.0))).xform(Vector3(0, 1, 0)); + Vector3 cam_target = Basis(Vector3(0, 0, Math_TAU * ((i + 3) / 4.0))).xform(Vector3(0, 1, 0)); projection = projection * CameraMatrix(Transform().looking_at(cam_target, Vector3(0, 0, -1)).affine_inverse()); ShadowRenderPushConstant push_constant; @@ -1640,7 +1666,7 @@ void RasterizerCanvasRD::light_update_shadow(RID p_rid, int p_shadow_index, cons } } -void RasterizerCanvasRD::light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders) { +void RendererCanvasRenderRD::light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders) { CanvasLight *cl = canvas_light_owner.getornull(p_rid); ERR_FAIL_COND(!cl->shadow.enabled); @@ -1663,7 +1689,7 @@ void RasterizerCanvasRD::light_update_directional_shadow(RID p_rid, int p_shadow to_light_xform[2] = from_pos; to_light_xform[1] = light_dir; - to_light_xform[0] = -light_dir.tangent(); + to_light_xform[0] = -light_dir.orthogonal(); to_light_xform.invert(); @@ -1720,7 +1746,7 @@ void RasterizerCanvasRD::light_update_directional_shadow(RID p_rid, int p_shadow cl->shadow.directional_xform = to_shadow * to_light_xform; } -void RasterizerCanvasRD::render_sdf(RID p_render_target, LightOccluderInstance *p_occluders) { +void RendererCanvasRenderRD::render_sdf(RID p_render_target, LightOccluderInstance *p_occluders) { RID fb = storage->render_target_get_sdf_framebuffer(p_render_target); Rect2i rect = storage->render_target_get_sdf_rect(p_render_target); @@ -1782,7 +1808,7 @@ void RasterizerCanvasRD::render_sdf(RID p_render_target, LightOccluderInstance * storage->render_target_sdf_process(p_render_target); //done rendering, process it } -RID RasterizerCanvasRD::occluder_polygon_create() { +RID RendererCanvasRenderRD::occluder_polygon_create() { OccluderPolygon occluder; occluder.line_point_count = 0; occluder.sdf_point_count = 0; @@ -1791,27 +1817,30 @@ RID RasterizerCanvasRD::occluder_polygon_create() { return occluder_polygon_owner.make_rid(occluder); } -void RasterizerCanvasRD::occluder_polygon_set_shape(RID p_occluder, const Vector<Vector2> &p_points, bool p_closed) { +void RendererCanvasRenderRD::occluder_polygon_set_shape(RID p_occluder, const Vector<Vector2> &p_points, bool p_closed) { OccluderPolygon *oc = occluder_polygon_owner.getornull(p_occluder); ERR_FAIL_COND(!oc); Vector<Vector2> lines; - int lc = p_points.size() * 2; - lines.resize(lc - (p_closed ? 0 : 2)); - { - Vector2 *w = lines.ptrw(); - const Vector2 *r = p_points.ptr(); + if (p_points.size()) { + int lc = p_points.size() * 2; - int max = lc / 2; - if (!p_closed) { - max--; - } - for (int i = 0; i < max; i++) { - Vector2 a = r[i]; - Vector2 b = r[(i + 1) % (lc / 2)]; - w[i * 2 + 0] = a; - w[i * 2 + 1] = b; + lines.resize(lc - (p_closed ? 0 : 2)); + { + Vector2 *w = lines.ptrw(); + const Vector2 *r = p_points.ptr(); + + int max = lc / 2; + if (!p_closed) { + max--; + } + for (int i = 0; i < max; i++) { + Vector2 a = r[i]; + Vector2 b = r[(i + 1) % (lc / 2)]; + w[i * 2 + 0] = a; + w[i * 2 + 1] = b; + } } } @@ -1832,7 +1861,7 @@ void RasterizerCanvasRD::occluder_polygon_set_shape(RID p_occluder, const Vector if (lines.size()) { Vector<uint8_t> geometry; Vector<uint8_t> indices; - lc = lines.size(); + int lc = lines.size(); geometry.resize(lc * 6 * sizeof(float)); indices.resize(lc * 3 * sizeof(uint16_t)); @@ -1902,19 +1931,21 @@ void RasterizerCanvasRD::occluder_polygon_set_shape(RID p_occluder, const Vector Vector<int> sdf_indices; - if (p_closed) { - sdf_indices = Geometry2D::triangulate_polygon(p_points); - oc->sdf_is_lines = false; - } else { - int max = p_points.size(); - sdf_indices.resize(max * 2); + if (p_points.size()) { + if (p_closed) { + sdf_indices = Geometry2D::triangulate_polygon(p_points); + oc->sdf_is_lines = false; + } else { + int max = p_points.size(); + sdf_indices.resize(max * 2); - int *iw = sdf_indices.ptrw(); - for (int i = 0; i < max; i++) { - iw[i * 2 + 0] = i; - iw[i * 2 + 1] = (i + 1) % max; + int *iw = sdf_indices.ptrw(); + for (int i = 0; i < max; i++) { + iw[i * 2 + 0] = i; + iw[i * 2 + 1] = (i + 1) % max; + } + oc->sdf_is_lines = true; } - oc->sdf_is_lines = true; } if (oc->sdf_index_count != sdf_indices.size() && oc->sdf_point_count != p_points.size() && oc->sdf_vertex_array.is_valid()) { @@ -1955,13 +1986,13 @@ void RasterizerCanvasRD::occluder_polygon_set_shape(RID p_occluder, const Vector } } -void RasterizerCanvasRD::occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) { +void RendererCanvasRenderRD::occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) { OccluderPolygon *oc = occluder_polygon_owner.getornull(p_occluder); ERR_FAIL_COND(!oc); oc->cull_mode = p_mode; } -void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) { +void RendererCanvasRenderRD::ShaderData::set_code(const String &p_code) { //compile code = p_code; @@ -1994,7 +2025,7 @@ void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) { actions.uniforms = &uniforms; - RasterizerCanvasRD *canvas_singleton = (RasterizerCanvasRD *)RasterizerCanvas::singleton; + RendererCanvasRenderRD *canvas_singleton = (RendererCanvasRenderRD *)RendererCanvasRender::singleton; Error err = canvas_singleton->shader.compiler.compile(RS::SHADER_CANVAS_ITEM, code, &actions, path, gen_code); @@ -2139,7 +2170,7 @@ void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) { valid = true; } -void RasterizerCanvasRD::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { +void RendererCanvasRenderRD::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { if (!p_texture.is_valid()) { default_texture_params.erase(p_name); } else { @@ -2147,7 +2178,7 @@ void RasterizerCanvasRD::ShaderData::set_default_texture_param(const StringName } } -void RasterizerCanvasRD::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const { +void RendererCanvasRenderRD::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const { Map<int, StringName> order; for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { @@ -2168,13 +2199,13 @@ void RasterizerCanvasRD::ShaderData::get_param_list(List<PropertyInfo> *p_param_ } } -void RasterizerCanvasRD::ShaderData::get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const { +void RendererCanvasRenderRD::ShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const { for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { continue; } - RasterizerStorage::InstanceShaderParam p; + RendererStorage::InstanceShaderParam p; p.info = ShaderLanguage::uniform_to_property_info(E->get()); p.info.name = E->key(); //supply name p.index = E->get().instance_index; @@ -2183,7 +2214,7 @@ void RasterizerCanvasRD::ShaderData::get_instance_param_list(List<RasterizerStor } } -bool RasterizerCanvasRD::ShaderData::is_param_texture(const StringName &p_param) const { +bool RendererCanvasRenderRD::ShaderData::is_param_texture(const StringName &p_param) const { if (!uniforms.has(p_param)) { return false; } @@ -2191,15 +2222,15 @@ bool RasterizerCanvasRD::ShaderData::is_param_texture(const StringName &p_param) return uniforms[p_param].texture_order >= 0; } -bool RasterizerCanvasRD::ShaderData::is_animated() const { +bool RendererCanvasRenderRD::ShaderData::is_animated() const { return false; } -bool RasterizerCanvasRD::ShaderData::casts_shadows() const { +bool RendererCanvasRenderRD::ShaderData::casts_shadows() const { return false; } -Variant RasterizerCanvasRD::ShaderData::get_default_parameter(const StringName &p_parameter) const { +Variant RendererCanvasRenderRD::ShaderData::get_default_parameter(const StringName &p_parameter) const { if (uniforms.has(p_parameter)) { ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; @@ -2208,14 +2239,19 @@ Variant RasterizerCanvasRD::ShaderData::get_default_parameter(const StringName & return Variant(); } -RasterizerCanvasRD::ShaderData::ShaderData() { +RS::ShaderNativeSourceCode RendererCanvasRenderRD::ShaderData::get_native_source_code() const { + RendererCanvasRenderRD *canvas_singleton = (RendererCanvasRenderRD *)RendererCanvasRender::singleton; + return canvas_singleton->shader.canvas_shader.version_get_native_source_code(version); +} + +RendererCanvasRenderRD::ShaderData::ShaderData() { valid = false; uses_screen_texture = false; uses_sdf = false; } -RasterizerCanvasRD::ShaderData::~ShaderData() { - RasterizerCanvasRD *canvas_singleton = (RasterizerCanvasRD *)RasterizerCanvas::singleton; +RendererCanvasRenderRD::ShaderData::~ShaderData() { + RendererCanvasRenderRD *canvas_singleton = (RendererCanvasRenderRD *)RendererCanvasRender::singleton; ERR_FAIL_COND(!canvas_singleton); //pipeline variants will clear themselves if shader is gone if (version.is_valid()) { @@ -2223,13 +2259,13 @@ RasterizerCanvasRD::ShaderData::~ShaderData() { } } -RasterizerStorageRD::ShaderData *RasterizerCanvasRD::_create_shader_func() { +RendererStorageRD::ShaderData *RendererCanvasRenderRD::_create_shader_func() { ShaderData *shader_data = memnew(ShaderData); return shader_data; } -void RasterizerCanvasRD::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { - RasterizerCanvasRD *canvas_singleton = (RasterizerCanvasRD *)RasterizerCanvas::singleton; +void RendererCanvasRenderRD::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { + RendererCanvasRenderRD *canvas_singleton = (RendererCanvasRenderRD *)RendererCanvasRender::singleton; if ((uint32_t)ubo_data.size() != shader_data->ubo_size) { p_uniform_dirty = true; @@ -2289,7 +2325,7 @@ void RasterizerCanvasRD::MaterialData::update_parameters(const Map<StringName, V { if (shader_data->ubo_size) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 0; u.ids.push_back(uniform_buffer); uniforms.push_back(u); @@ -2298,7 +2334,7 @@ void RasterizerCanvasRD::MaterialData::update_parameters(const Map<StringName, V const RID *textures = texture_cache.ptrw(); for (uint32_t i = 0; i < tex_uniform_count; i++) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1 + i; u.ids.push_back(textures[i]); uniforms.push_back(u); @@ -2308,7 +2344,7 @@ void RasterizerCanvasRD::MaterialData::update_parameters(const Map<StringName, V uniform_set = RD::get_singleton()->uniform_set_create(uniforms, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET); } -RasterizerCanvasRD::MaterialData::~MaterialData() { +RendererCanvasRenderRD::MaterialData::~MaterialData() { if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { RD::get_singleton()->free(uniform_set); } @@ -2318,7 +2354,7 @@ RasterizerCanvasRD::MaterialData::~MaterialData() { } } -RasterizerStorageRD::MaterialData *RasterizerCanvasRD::_create_material_func(ShaderData *p_shader) { +RendererStorageRD::MaterialData *RendererCanvasRenderRD::_create_material_func(ShaderData *p_shader) { MaterialData *material_data = memnew(MaterialData); material_data->shader_data = p_shader; material_data->last_frame = false; @@ -2326,14 +2362,14 @@ RasterizerStorageRD::MaterialData *RasterizerCanvasRD::_create_material_func(Sha return material_data; } -void RasterizerCanvasRD::set_time(double p_time) { +void RendererCanvasRenderRD::set_time(double p_time) { state.time = p_time; } -void RasterizerCanvasRD::update() { +void RendererCanvasRenderRD::update() { } -RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { +RendererCanvasRenderRD::RendererCanvasRenderRD(RendererStorageRD *p_storage) { storage = p_storage; { //create default samplers @@ -2457,8 +2493,8 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { actions.renames["COLOR"] = "color"; actions.renames["NORMAL"] = "normal"; - actions.renames["NORMALMAP"] = "normal_map"; - actions.renames["NORMALMAP_DEPTH"] = "normal_depth"; + actions.renames["NORMAL_MAP"] = "normal_map"; + actions.renames["NORMAL_MAP_DEPTH"] = "normal_map_depth"; actions.renames["TEXTURE"] = "color_texture"; actions.renames["TEXTURE_PIXEL_SIZE"] = "draw_data.color_texture_pixel_size"; actions.renames["NORMAL_TEXTURE"] = "normal_texture"; @@ -2470,7 +2506,7 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { actions.renames["FRAGCOORD"] = "gl_FragCoord"; actions.renames["POINT_COORD"] = "gl_PointCoord"; - actions.renames["LIGHT_POSITION"] = "light_pos"; + actions.renames["LIGHT_POSITION"] = "light_position"; actions.renames["LIGHT_COLOR"] = "light_color"; actions.renames["LIGHT_ENERGY"] = "light_energy"; actions.renames["LIGHT"] = "light"; @@ -2486,7 +2522,7 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; actions.usage_defines["SCREEN_PIXEL_SIZE"] = "@SCREEN_UV"; actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n"; - actions.usage_defines["NORMALMAP"] = "#define NORMALMAP_USED\n"; + actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n"; actions.usage_defines["LIGHT"] = "#define LIGHT_SHADER_CODE_USED\n"; actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; @@ -2636,7 +2672,7 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { { //default shadow texture to keep uniform set happy RD::TextureFormat tf; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.width = 4; tf.height = 4; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT; @@ -2650,7 +2686,7 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 0; u.ids.push_back(storage->get_default_rd_storage_buffer()); uniforms.push_back(u); @@ -2659,27 +2695,33 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { state.default_transforms_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader.default_version_rd_shader, TRANSFORMS_UNIFORM_SET); } - default_canvas_texture = storage->canvas_texture_create(); + default_canvas_texture = storage->canvas_texture_allocate(); + storage->canvas_texture_initialize(default_canvas_texture); - state.shadow_texture_size = GLOBAL_GET("rendering/quality/2d_shadow_atlas/size"); + state.shadow_texture_size = GLOBAL_GET("rendering/2d/shadow_atlas/size"); //create functions for shader and material - storage->shader_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_2D, _create_shader_funcs); - storage->material_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_2D, _create_material_funcs); + storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_2D, _create_shader_funcs); + storage->material_set_data_request_function(RendererStorageRD::SHADER_TYPE_2D, _create_material_funcs); state.time = 0; { - default_canvas_group_shader = storage->shader_create(); + default_canvas_group_shader = storage->shader_allocate(); + storage->shader_initialize(default_canvas_group_shader); + storage->shader_set_code(default_canvas_group_shader, "shader_type canvas_item; \nvoid fragment() {\n\tvec4 c = textureLod(SCREEN_TEXTURE,SCREEN_UV,0.0); if (c.a > 0.0001) c.rgb/=c.a; COLOR *= c; \n}\n"); - default_canvas_group_material = storage->material_create(); + + default_canvas_group_material = storage->material_allocate(); + storage->material_initialize(default_canvas_group_material); + storage->material_set_shader(default_canvas_group_material, default_canvas_group_shader); } static_assert(sizeof(PushConstant) == 128); } -bool RasterizerCanvasRD::free(RID p_rid) { +bool RendererCanvasRenderRD::free(RID p_rid) { if (canvas_light_owner.owns(p_rid)) { CanvasLight *cl = canvas_light_owner.getornull(p_rid); ERR_FAIL_COND_V(!cl, false); @@ -2695,7 +2737,7 @@ bool RasterizerCanvasRD::free(RID p_rid) { return true; } -void RasterizerCanvasRD::set_shadow_texture_size(int p_size) { +void RendererCanvasRenderRD::set_shadow_texture_size(int p_size) { p_size = nearest_power_of_2_templated(p_size); if (p_size == state.shadow_texture_size) { return; @@ -2709,7 +2751,7 @@ void RasterizerCanvasRD::set_shadow_texture_size(int p_size) { { //create a default shadow texture to keep uniform set happy (and that it gets erased when a new one is created) RD::TextureFormat tf; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.width = 4; tf.height = 4; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT; @@ -2720,7 +2762,7 @@ void RasterizerCanvasRD::set_shadow_texture_size(int p_size) { } } -RasterizerCanvasRD::~RasterizerCanvasRD() { +RendererCanvasRenderRD::~RendererCanvasRenderRD() { //canvas state storage->free(default_canvas_group_material); diff --git a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h index b09d6578f3..cb947d7180 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rasterizer_canvas_rd.h */ +/* renderer_canvas_render_rd.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,19 +28,20 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef RASTERIZER_CANVAS_RD_H -#define RASTERIZER_CANVAS_RD_H +#ifndef RENDERING_SERVER_CANVAS_RENDER_RD_H +#define RENDERING_SERVER_CANVAS_RENDER_RD_H -#include "servers/rendering/rasterizer.h" -#include "servers/rendering/rasterizer_rd/rasterizer_storage_rd.h" -#include "servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h" -#include "servers/rendering/rasterizer_rd/shader_compiler_rd.h" -#include "servers/rendering/rasterizer_rd/shaders/canvas.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl.gen.h" +#include "servers/rendering/renderer_canvas_render.h" +#include "servers/rendering/renderer_compositor.h" +#include "servers/rendering/renderer_rd/pipeline_cache_rd.h" +#include "servers/rendering/renderer_rd/renderer_storage_rd.h" +#include "servers/rendering/renderer_rd/shader_compiler_rd.h" +#include "servers/rendering/renderer_rd/shaders/canvas.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/canvas_occlusion.glsl.gen.h" #include "servers/rendering/rendering_device.h" -class RasterizerCanvasRD : public RasterizerCanvas { - RasterizerStorageRD *storage; +class RendererCanvasRenderRD : public RendererCanvasRender { + RendererStorageRD *storage; enum { BASE_UNIFORM_SET = 0, @@ -133,7 +134,7 @@ class RasterizerCanvasRD : public RasterizerCanvas { }; struct PipelineVariants { - RenderPipelineVertexFormatCacheRD variants[PIPELINE_LIGHT_MODE_MAX][PIPELINE_VARIANT_MAX]; + PipelineCacheRD variants[PIPELINE_LIGHT_MODE_MAX][PIPELINE_VARIANT_MAX]; }; struct { @@ -151,7 +152,7 @@ class RasterizerCanvasRD : public RasterizerCanvas { ShaderCompilerRD compiler; } shader; - struct ShaderData : public RasterizerStorageRD::ShaderData { + struct ShaderData : public RendererStorageRD::ShaderData { enum BlendMode { //used internally BLEND_MODE_MIX, BLEND_MODE_ADD, @@ -181,22 +182,24 @@ class RasterizerCanvasRD : public RasterizerCanvas { virtual void set_code(const String &p_Code); virtual void set_default_texture_param(const StringName &p_name, RID p_texture); virtual void get_param_list(List<PropertyInfo> *p_param_list) const; - virtual void get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const; + virtual void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const; virtual bool is_param_texture(const StringName &p_param) const; virtual bool is_animated() const; virtual bool casts_shadows() const; virtual Variant get_default_parameter(const StringName &p_parameter) const; + virtual RS::ShaderNativeSourceCode get_native_source_code() const; + ShaderData(); virtual ~ShaderData(); }; - RasterizerStorageRD::ShaderData *_create_shader_func(); - static RasterizerStorageRD::ShaderData *_create_shader_funcs() { - return static_cast<RasterizerCanvasRD *>(singleton)->_create_shader_func(); + RendererStorageRD::ShaderData *_create_shader_func(); + static RendererStorageRD::ShaderData *_create_shader_funcs() { + return static_cast<RendererCanvasRenderRD *>(singleton)->_create_shader_func(); } - struct MaterialData : public RasterizerStorageRD::MaterialData { + struct MaterialData : public RendererStorageRD::MaterialData { uint64_t last_frame; ShaderData *shader_data; RID uniform_buffer; @@ -210,9 +213,9 @@ class RasterizerCanvasRD : public RasterizerCanvas { virtual ~MaterialData(); }; - RasterizerStorageRD::MaterialData *_create_material_func(ShaderData *p_shader); - static RasterizerStorageRD::MaterialData *_create_material_funcs(RasterizerStorageRD::ShaderData *p_shader) { - return static_cast<RasterizerCanvasRD *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader)); + RendererStorageRD::MaterialData *_create_material_func(ShaderData *p_shader); + static RendererStorageRD::MaterialData *_create_material_funcs(RendererStorageRD::ShaderData *p_shader) { + return static_cast<RendererCanvasRenderRD *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader)); } /**************************/ @@ -462,8 +465,8 @@ public: void set_time(double p_time); void update(); bool free(RID p_rid); - RasterizerCanvasRD(RasterizerStorageRD *p_storage); - ~RasterizerCanvasRD(); + RendererCanvasRenderRD(RendererStorageRD *p_storage); + ~RendererCanvasRenderRD(); }; #endif // RASTERIZER_CANVAS_RD_H diff --git a/servers/rendering/rasterizer_rd/rasterizer_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index 5f8cf0ee8c..be2552bd32 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rasterizer_rd.cpp */ +/* renderer_compositor_rd.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,15 +28,15 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "rasterizer_rd.h" +#include "renderer_compositor_rd.h" #include "core/config/project_settings.h" -void RasterizerRD::prepare_for_blitting_render_targets() { +void RendererCompositorRD::prepare_for_blitting_render_targets() { RD::get_singleton()->prepare_screen_for_drawing(); } -void RasterizerRD::blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) { +void RendererCompositorRD::blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) { RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin_for_screen(p_screen); for (int i = 0; i < p_amount; i++) { @@ -47,7 +47,7 @@ void RasterizerRD::blit_render_targets_to_screen(DisplayServer::WindowID p_scree if (!render_target_descriptors.has(rd_texture) || !RD::get_singleton()->uniform_set_is_valid(render_target_descriptors[rd_texture])) { Vector<RD::Uniform> uniforms; RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; u.binding = 0; u.ids.push_back(copy_viewports_sampler); u.ids.push_back(rd_texture); @@ -76,7 +76,7 @@ void RasterizerRD::blit_render_targets_to_screen(DisplayServer::WindowID p_scree RD::get_singleton()->draw_list_end(); } -void RasterizerRD::begin_frame(double frame_step) { +void RendererCompositorRD::begin_frame(double frame_step) { frame++; delta = frame_step; time += frame_step; @@ -88,14 +88,14 @@ void RasterizerRD::begin_frame(double frame_step) { scene->set_time(time, frame_step); } -void RasterizerRD::end_frame(bool p_swap_buffers) { +void RendererCompositorRD::end_frame(bool p_swap_buffers) { #ifndef _MSC_VER #warning TODO: likely pass a bool to swap buffers to avoid display? #endif RD::get_singleton()->swap_buffers(); //probably should pass some bool to avoid display? } -void RasterizerRD::initialize() { +void RendererCompositorRD::initialize() { { //create framebuffer copy shader RenderingDevice::ShaderStageData vert; vert.shader_stage = RenderingDevice::SHADER_STAGE_VERTEX; @@ -154,12 +154,9 @@ void RasterizerRD::initialize() { } } -ThreadWorkPool RasterizerRD::thread_work_pool; -uint64_t RasterizerRD::frame = 1; - -void RasterizerRD::finalize() { - thread_work_pool.finish(); +uint64_t RendererCompositorRD::frame = 1; +void RendererCompositorRD::finalize() { memdelete(scene); memdelete(canvas); memdelete(storage); @@ -170,14 +167,13 @@ void RasterizerRD::finalize() { RD::get_singleton()->free(copy_viewports_sampler); } -RasterizerRD *RasterizerRD::singleton = nullptr; +RendererCompositorRD *RendererCompositorRD::singleton = nullptr; -RasterizerRD::RasterizerRD() { +RendererCompositorRD::RendererCompositorRD() { singleton = this; - thread_work_pool.init(); time = 0; - storage = memnew(RasterizerStorageRD); - canvas = memnew(RasterizerCanvasRD(storage)); - scene = memnew(RasterizerSceneHighEndRD(storage)); + storage = memnew(RendererStorageRD); + canvas = memnew(RendererCanvasRenderRD(storage)); + scene = memnew(RendererSceneRenderForward(storage)); } diff --git a/servers/rendering/rasterizer_rd/rasterizer_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h index 59fb8d2049..cb85fc79e0 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_rd.h +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rasterizer_rd.h */ +/* renderer_compositor_rd.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,21 +28,21 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef RASTERIZER_RD_H -#define RASTERIZER_RD_H +#ifndef RENDERING_SERVER_COMPOSITOR_RD_H +#define RENDERING_SERVER_COMPOSITOR_RD_H #include "core/os/os.h" #include "core/templates/thread_work_pool.h" -#include "servers/rendering/rasterizer.h" -#include "servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h" -#include "servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h" -#include "servers/rendering/rasterizer_rd/rasterizer_storage_rd.h" +#include "servers/rendering/renderer_compositor.h" +#include "servers/rendering/renderer_rd/renderer_canvas_render_rd.h" +#include "servers/rendering/renderer_rd/renderer_scene_render_forward.h" +#include "servers/rendering/renderer_rd/renderer_storage_rd.h" -class RasterizerRD : public Rasterizer { +class RendererCompositorRD : public RendererCompositor { protected: - RasterizerCanvasRD *canvas; - RasterizerStorageRD *storage; - RasterizerSceneHighEndRD *scene; + RendererCanvasRenderRD *canvas; + RendererStorageRD *storage; + RendererSceneRenderForward *scene; RID copy_viewports_rd_shader; RID copy_viewports_rd_pipeline; @@ -58,9 +58,9 @@ protected: static uint64_t frame; public: - RasterizerStorage *get_storage() { return storage; } - RasterizerCanvas *get_canvas() { return canvas; } - RasterizerScene *get_scene() { return scene; } + RendererStorage *get_storage() { return storage; } + RendererCanvasRender *get_canvas() { return canvas; } + RendererSceneRender *get_scene() { return scene; } void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter) {} @@ -80,8 +80,8 @@ public: return OK; } - static Rasterizer *_create_current() { - return memnew(RasterizerRD); + static RendererCompositor *_create_current() { + return memnew(RendererCompositorRD); } static void make_current() { @@ -90,10 +90,8 @@ public: virtual bool is_low_end() const { return false; } - static ThreadWorkPool thread_work_pool; - - static RasterizerRD *singleton; - RasterizerRD(); - ~RasterizerRD() {} + static RendererCompositorRD *singleton; + RendererCompositorRD(); + ~RendererCompositorRD() {} }; #endif // RASTERIZER_RD_H diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp index 313188ba87..a57dee7314 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rasterizer_scene_high_end_rd.cpp */ +/* renderer_scene_render_forward.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "rasterizer_scene_high_end_rd.h" +#include "renderer_scene_render_forward.h" #include "core/config/project_settings.h" #include "servers/rendering/rendering_device.h" -#include "servers/rendering/rendering_server_raster.h" +#include "servers/rendering/rendering_server_default.h" /* SCENE SHADER */ -void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) { +void RendererSceneRenderForward::ShaderData::set_code(const String &p_code) { //compile code = p_code; @@ -112,7 +112,7 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) { actions.usage_flag_pointers["TIME"] = &uses_time; actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness; actions.usage_flag_pointers["NORMAL"] = &uses_normal; - actions.usage_flag_pointers["NORMALMAP"] = &uses_normal; + actions.usage_flag_pointers["NORMAL_MAP"] = &uses_normal; actions.usage_flag_pointers["POINT_SIZE"] = &uses_point_size; actions.usage_flag_pointers["POINT_COORD"] = &uses_point_size; @@ -123,7 +123,7 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) { actions.uniforms = &uniforms; - RasterizerSceneHighEndRD *scene_singleton = (RasterizerSceneHighEndRD *)RasterizerSceneHighEndRD::singleton; + RendererSceneRenderForward *scene_singleton = (RendererSceneRenderForward *)RendererSceneRenderForward::singleton; Error err = scene_singleton->shader.compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code); @@ -257,6 +257,9 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) { RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[j]; for (int k = 0; k < SHADER_VERSION_MAX; k++) { + if (!static_cast<RendererSceneRenderForward *>(singleton)->shader.scene_shader.is_variant_enabled(k)) { + continue; + } RD::PipelineRasterizationState raster_state; raster_state.cull_mode = cull_mode_rd; raster_state.wireframe = wireframe; @@ -321,7 +324,7 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) { valid = true; } -void RasterizerSceneHighEndRD::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { +void RendererSceneRenderForward::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { if (!p_texture.is_valid()) { default_texture_params.erase(p_name); } else { @@ -329,7 +332,7 @@ void RasterizerSceneHighEndRD::ShaderData::set_default_texture_param(const Strin } } -void RasterizerSceneHighEndRD::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const { +void RendererSceneRenderForward::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const { Map<int, StringName> order; for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { @@ -351,13 +354,13 @@ void RasterizerSceneHighEndRD::ShaderData::get_param_list(List<PropertyInfo> *p_ } } -void RasterizerSceneHighEndRD::ShaderData::get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const { +void RendererSceneRenderForward::ShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const { for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { continue; } - RasterizerStorage::InstanceShaderParam p; + RendererStorage::InstanceShaderParam p; p.info = ShaderLanguage::uniform_to_property_info(E->get()); p.info.name = E->key(); //supply name p.index = E->get().instance_index; @@ -366,7 +369,7 @@ void RasterizerSceneHighEndRD::ShaderData::get_instance_param_list(List<Rasteriz } } -bool RasterizerSceneHighEndRD::ShaderData::is_param_texture(const StringName &p_param) const { +bool RendererSceneRenderForward::ShaderData::is_param_texture(const StringName &p_param) const { if (!uniforms.has(p_param)) { return false; } @@ -374,15 +377,15 @@ bool RasterizerSceneHighEndRD::ShaderData::is_param_texture(const StringName &p_ return uniforms[p_param].texture_order >= 0; } -bool RasterizerSceneHighEndRD::ShaderData::is_animated() const { +bool RendererSceneRenderForward::ShaderData::is_animated() const { return false; } -bool RasterizerSceneHighEndRD::ShaderData::casts_shadows() const { +bool RendererSceneRenderForward::ShaderData::casts_shadows() const { return false; } -Variant RasterizerSceneHighEndRD::ShaderData::get_default_parameter(const StringName &p_parameter) const { +Variant RendererSceneRenderForward::ShaderData::get_default_parameter(const StringName &p_parameter) const { if (uniforms.has(p_parameter)) { ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; @@ -391,13 +394,19 @@ Variant RasterizerSceneHighEndRD::ShaderData::get_default_parameter(const String return Variant(); } -RasterizerSceneHighEndRD::ShaderData::ShaderData() { +RS::ShaderNativeSourceCode RendererSceneRenderForward::ShaderData::get_native_source_code() const { + RendererSceneRenderForward *scene_singleton = (RendererSceneRenderForward *)RendererSceneRenderForward::singleton; + + return scene_singleton->shader.scene_shader.version_get_native_source_code(version); +} + +RendererSceneRenderForward::ShaderData::ShaderData() { valid = false; uses_screen_texture = false; } -RasterizerSceneHighEndRD::ShaderData::~ShaderData() { - RasterizerSceneHighEndRD *scene_singleton = (RasterizerSceneHighEndRD *)RasterizerSceneHighEndRD::singleton; +RendererSceneRenderForward::ShaderData::~ShaderData() { + RendererSceneRenderForward *scene_singleton = (RendererSceneRenderForward *)RendererSceneRenderForward::singleton; ERR_FAIL_COND(!scene_singleton); //pipeline variants will clear themselves if shader is gone if (version.is_valid()) { @@ -405,21 +414,21 @@ RasterizerSceneHighEndRD::ShaderData::~ShaderData() { } } -RasterizerStorageRD::ShaderData *RasterizerSceneHighEndRD::_create_shader_func() { +RendererStorageRD::ShaderData *RendererSceneRenderForward::_create_shader_func() { ShaderData *shader_data = memnew(ShaderData); return shader_data; } -void RasterizerSceneHighEndRD::MaterialData::set_render_priority(int p_priority) { +void RendererSceneRenderForward::MaterialData::set_render_priority(int p_priority) { priority = p_priority - RS::MATERIAL_RENDER_PRIORITY_MIN; //8 bits } -void RasterizerSceneHighEndRD::MaterialData::set_next_pass(RID p_pass) { +void RendererSceneRenderForward::MaterialData::set_next_pass(RID p_pass) { next_pass = p_pass; } -void RasterizerSceneHighEndRD::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { - RasterizerSceneHighEndRD *scene_singleton = (RasterizerSceneHighEndRD *)RasterizerSceneHighEndRD::singleton; +void RendererSceneRenderForward::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { + RendererSceneRenderForward *scene_singleton = (RendererSceneRenderForward *)RendererSceneRenderForward::singleton; if ((uint32_t)ubo_data.size() != shader_data->ubo_size) { p_uniform_dirty = true; @@ -444,7 +453,7 @@ void RasterizerSceneHighEndRD::MaterialData::update_parameters(const Map<StringN //check whether buffer changed if (p_uniform_dirty && ubo_data.size()) { update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false); - RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw()); + RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw(), RD::BARRIER_MASK_RASTER); } uint32_t tex_uniform_count = shader_data->texture_uniforms.size(); @@ -479,7 +488,7 @@ void RasterizerSceneHighEndRD::MaterialData::update_parameters(const Map<StringN { if (shader_data->ubo_size) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 0; u.ids.push_back(uniform_buffer); uniforms.push_back(u); @@ -488,7 +497,7 @@ void RasterizerSceneHighEndRD::MaterialData::update_parameters(const Map<StringN const RID *textures = texture_cache.ptrw(); for (uint32_t i = 0; i < tex_uniform_count; i++) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1 + i; u.ids.push_back(textures[i]); uniforms.push_back(u); @@ -498,7 +507,7 @@ void RasterizerSceneHighEndRD::MaterialData::update_parameters(const Map<StringN uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_singleton->shader.scene_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET); } -RasterizerSceneHighEndRD::MaterialData::~MaterialData() { +RendererSceneRenderForward::MaterialData::~MaterialData() { if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { RD::get_singleton()->free(uniform_set); } @@ -508,7 +517,7 @@ RasterizerSceneHighEndRD::MaterialData::~MaterialData() { } } -RasterizerStorageRD::MaterialData *RasterizerSceneHighEndRD::_create_material_func(ShaderData *p_shader) { +RendererStorageRD::MaterialData *RendererSceneRenderForward::_create_material_func(ShaderData *p_shader) { MaterialData *material_data = memnew(MaterialData); material_data->shader_data = p_shader; material_data->last_frame = false; @@ -516,11 +525,11 @@ RasterizerStorageRD::MaterialData *RasterizerSceneHighEndRD::_create_material_fu return material_data; } -RasterizerSceneHighEndRD::RenderBufferDataHighEnd::~RenderBufferDataHighEnd() { +RendererSceneRenderForward::RenderBufferDataForward::~RenderBufferDataForward() { clear(); } -void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::ensure_specular() { +void RendererSceneRenderForward::RenderBufferDataForward::ensure_specular() { if (!specular.is_valid()) { RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; @@ -574,20 +583,7 @@ void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::ensure_specular() { } } -void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::ensure_gi() { - if (!reflection_buffer.is_valid()) { - RD::TextureFormat tf; - tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; - tf.width = width; - tf.height = height; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - - reflection_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); - ambient_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); - } -} - -void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::ensure_giprobe() { +void RendererSceneRenderForward::RenderBufferDataForward::ensure_giprobe() { if (!giprobe_buffer.is_valid()) { RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R8G8_UINT; @@ -623,17 +619,7 @@ void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::ensure_giprobe() { } } -void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::clear() { - if (ambient_buffer != RID() && ambient_buffer != color) { - RD::get_singleton()->free(ambient_buffer); - ambient_buffer = RID(); - } - - if (reflection_buffer != RID() && reflection_buffer != specular) { - RD::get_singleton()->free(reflection_buffer); - reflection_buffer = RID(); - } - +void RendererSceneRenderForward::RenderBufferDataForward::clear() { if (giprobe_buffer != RID()) { RD::get_singleton()->free(giprobe_buffer); giprobe_buffer = RID(); @@ -687,7 +673,7 @@ void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::clear() { } } -void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) { +void RendererSceneRenderForward::RenderBufferDataForward::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) { clear(); msaa = p_msaa; @@ -717,7 +703,7 @@ void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::configure(RID p_color_bu tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; tf.width = p_width; tf.height = p_height; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; RD::TextureSamples ts[RS::VIEWPORT_MSAA_MAX] = { @@ -754,7 +740,7 @@ void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::configure(RID p_color_bu } } -void RasterizerSceneHighEndRD::_allocate_normal_roughness_texture(RenderBufferDataHighEnd *rb) { +void RendererSceneRenderForward::_allocate_normal_roughness_texture(RenderBufferDataForward *rb) { if (rb->normal_roughness_buffer.is_valid()) { return; } @@ -763,7 +749,7 @@ void RasterizerSceneHighEndRD::_allocate_normal_roughness_texture(RenderBufferDa tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; tf.width = rb->width; tf.height = rb->height; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) { tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; @@ -779,7 +765,7 @@ void RasterizerSceneHighEndRD::_allocate_normal_roughness_texture(RenderBufferDa fb.push_back(rb->normal_roughness_buffer); rb->depth_normal_roughness_fb = RD::get_singleton()->framebuffer_create(fb); } else { - tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; tf.samples = rb->texture_samples; rb->normal_roughness_buffer_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView()); @@ -792,264 +778,103 @@ void RasterizerSceneHighEndRD::_allocate_normal_roughness_texture(RenderBufferDa _render_buffers_clear_uniform_set(rb); } -RasterizerSceneRD::RenderBufferData *RasterizerSceneHighEndRD::_create_render_buffer_data() { - return memnew(RenderBufferDataHighEnd); +RendererSceneRenderRD::RenderBufferData *RendererSceneRenderForward::_create_render_buffer_data() { + return memnew(RenderBufferDataForward); } -bool RasterizerSceneHighEndRD::free(RID p_rid) { - if (RasterizerSceneRD::free(p_rid)) { +bool RendererSceneRenderForward::free(RID p_rid) { + if (RendererSceneRenderRD::free(p_rid)) { return true; } return false; } -void RasterizerSceneHighEndRD::_fill_instances(RenderList::Element **p_elements, int p_element_count, bool p_for_depth, bool p_has_sdfgi, bool p_has_opaque_gi) { - uint32_t lightmap_captures_used = 0; - - for (int i = 0; i < p_element_count; i++) { - const RenderList::Element *e = p_elements[i]; - InstanceData &id = scene_state.instances[i]; - bool store_transform = true; - id.flags = 0; - id.mask = e->instance->layer_mask; - id.instance_uniforms_ofs = e->instance->instance_allocated_shader_parameters_offset >= 0 ? e->instance->instance_allocated_shader_parameters_offset : 0; - - if (e->instance->base_type == RS::INSTANCE_MULTIMESH) { - id.flags |= INSTANCE_DATA_FLAG_MULTIMESH; - uint32_t stride; - if (storage->multimesh_get_transform_format(e->instance->base) == RS::MULTIMESH_TRANSFORM_2D) { - id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D; - stride = 2; - } else { - stride = 3; - } - if (storage->multimesh_uses_colors(e->instance->base)) { - id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR; - stride += 1; - } - if (storage->multimesh_uses_custom_data(e->instance->base)) { - id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA; - stride += 1; - } - - id.flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT); - } else if (e->instance->base_type == RS::INSTANCE_PARTICLES) { - id.flags |= INSTANCE_DATA_FLAG_MULTIMESH; - uint32_t stride; - if (false) { // 2D particles - id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D; - stride = 2; - } else { - stride = 3; - } - - id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR; - stride += 1; - - id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA; - stride += 1; - - id.flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT); - - if (!storage->particles_is_using_local_coords(e->instance->base)) { - store_transform = false; - } - - } else if (e->instance->base_type == RS::INSTANCE_MESH) { - if (e->instance->skeleton.is_valid()) { - id.flags |= INSTANCE_DATA_FLAG_SKELETON; - } - } - - if (store_transform) { - RasterizerStorageRD::store_transform(e->instance->transform, id.transform); - RasterizerStorageRD::store_transform(Transform(e->instance->transform.basis.inverse().transposed()), id.normal_transform); - } else { - RasterizerStorageRD::store_transform(Transform(), id.transform); - RasterizerStorageRD::store_transform(Transform(), id.normal_transform); - } - - if (p_for_depth) { - id.gi_offset = 0xFFFFFFFF; - continue; - } - - if (e->instance->lightmap) { - int32_t lightmap_index = storage->lightmap_get_array_index(e->instance->lightmap->base); - if (lightmap_index >= 0) { - id.gi_offset = lightmap_index; - id.gi_offset |= e->instance->lightmap_slice_index << 12; - id.gi_offset |= e->instance->lightmap_cull_index << 20; - id.lightmap_uv_scale[0] = e->instance->lightmap_uv_scale.position.x; - id.lightmap_uv_scale[1] = e->instance->lightmap_uv_scale.position.y; - id.lightmap_uv_scale[2] = e->instance->lightmap_uv_scale.size.width; - id.lightmap_uv_scale[3] = e->instance->lightmap_uv_scale.size.height; - id.flags |= INSTANCE_DATA_FLAG_USE_LIGHTMAP; - if (storage->lightmap_uses_spherical_harmonics(e->instance->lightmap->base)) { - id.flags |= INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP; - } - } else { - id.gi_offset = 0xFFFFFFFF; - } - } else if (!e->instance->lightmap_sh.empty()) { - if (lightmap_captures_used < scene_state.max_lightmap_captures) { - const Color *src_capture = e->instance->lightmap_sh.ptr(); - LightmapCaptureData &lcd = scene_state.lightmap_captures[lightmap_captures_used]; - for (int j = 0; j < 9; j++) { - lcd.sh[j * 4 + 0] = src_capture[j].r; - lcd.sh[j * 4 + 1] = src_capture[j].g; - lcd.sh[j * 4 + 2] = src_capture[j].b; - lcd.sh[j * 4 + 3] = src_capture[j].a; - } - id.flags |= INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE; - id.gi_offset = lightmap_captures_used; - lightmap_captures_used++; - } - - } else { - if (p_has_opaque_gi) { - id.flags |= INSTANCE_DATA_FLAG_USE_GI_BUFFERS; - } - - if (!e->instance->gi_probe_instances.empty()) { - uint32_t written = 0; - for (int j = 0; j < e->instance->gi_probe_instances.size(); j++) { - RID probe = e->instance->gi_probe_instances[j]; - - uint32_t index = gi_probe_instance_get_render_index(probe); - - if (written == 0) { - id.gi_offset = index; - id.flags |= INSTANCE_DATA_FLAG_USE_GIPROBE; - written = 1; - } else { - id.gi_offset = index << 16; - written = 2; - break; - } - } - if (written == 0) { - id.gi_offset = 0xFFFFFFFF; - } else if (written == 1) { - id.gi_offset |= 0xFFFF0000; - } - } else { - if (p_has_sdfgi && (e->instance->baked_light || e->instance->dynamic_gi)) { - id.flags |= INSTANCE_DATA_FLAG_USE_SDFGI; - } - id.gi_offset = 0xFFFFFFFF; - } - } - } - - RD::get_singleton()->buffer_update(scene_state.instance_buffer, 0, sizeof(InstanceData) * p_element_count, scene_state.instances, true); - if (lightmap_captures_used) { - RD::get_singleton()->buffer_update(scene_state.lightmap_capture_buffer, 0, sizeof(LightmapCaptureData) * lightmap_captures_used, scene_state.lightmap_captures, true); - } -} - /// RENDERING /// -void RasterizerSceneHighEndRD::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderList::Element **p_elements, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi, RID p_radiance_uniform_set, RID p_render_buffers_uniform_set, bool p_force_wireframe, const Vector2 &p_uv_offset) { +template <RendererSceneRenderForward::PassMode p_pass_mode> +void RendererSceneRenderForward::_render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) { RD::DrawListID draw_list = p_draw_list; RD::FramebufferFormatID framebuffer_format = p_framebuffer_Format; //global scope bindings RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_base_uniform_set, SCENE_UNIFORM_SET); - if (p_radiance_uniform_set.is_valid()) { - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_radiance_uniform_set, RADIANCE_UNIFORM_SET); - } else { - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, default_radiance_uniform_set, RADIANCE_UNIFORM_SET); - } - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, view_dependant_uniform_set, VIEW_DEPENDANT_UNIFORM_SET); - if (p_render_buffers_uniform_set.is_valid()) { - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_render_buffers_uniform_set, RENDER_BUFFERS_UNIFORM_SET); - } else { - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, default_render_buffers_uniform_set, RENDER_BUFFERS_UNIFORM_SET); - } + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_params->render_pass_uniform_set, RENDER_PASS_UNIFORM_SET); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, default_vec4_xform_uniform_set, TRANSFORMS_UNIFORM_SET); - MaterialData *prev_material = nullptr; + RID prev_material_uniform_set; RID prev_vertex_array_rd; RID prev_index_array_rd; RID prev_pipeline_rd; RID prev_xforms_uniform_set; - PushConstant push_constant; - zeromem(&push_constant, sizeof(PushConstant)); - push_constant.bake_uv2_offset[0] = p_uv_offset.x; - push_constant.bake_uv2_offset[1] = p_uv_offset.y; + bool shadow_pass = (p_params->pass_mode == PASS_MODE_SHADOW) || (p_params->pass_mode == PASS_MODE_SHADOW_DP); + + SceneState::PushConstant push_constant; + + if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL) { + push_constant.uv_offset = Math::make_half_float(p_params->uv_offset.y) << 16; + push_constant.uv_offset |= Math::make_half_float(p_params->uv_offset.x); + } else { + push_constant.uv_offset = 0; + } + + for (uint32_t i = p_from_element; i < p_to_element; i++) { + const GeometryInstanceSurfaceDataCache *surf = p_params->elements[i]; + const RenderElementInfo &element_info = p_params->element_info[i]; + + push_constant.base_index = i + p_params->element_offset; - for (int i = 0; i < p_element_count; i++) { - const RenderList::Element *e = p_elements[i]; + RID material_uniform_set; + ShaderData *shader; + void *mesh_surface; - MaterialData *material = e->material; - ShaderData *shader = material->shader_data; - RID xforms_uniform_set; + if (shadow_pass || p_params->pass_mode == PASS_MODE_DEPTH) { //regular depth pass can use these too + material_uniform_set = surf->material_uniform_set_shadow; + shader = surf->shader_shadow; + mesh_surface = surf->surface_shadow; + + } else { + material_uniform_set = surf->material_uniform_set; + shader = surf->shader; + mesh_surface = surf->surface; + } + + if (!mesh_surface) { + continue; + } //find cull variant ShaderData::CullVariant cull_variant; - if (p_pass_mode == PASS_MODE_DEPTH_MATERIAL || p_pass_mode == PASS_MODE_SDF || ((p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_SHADOW_DP) && e->instance->cast_shadows == RS::SHADOW_CASTING_SETTING_DOUBLE_SIDED)) { + if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL || p_params->pass_mode == PASS_MODE_SDF || ((p_params->pass_mode == PASS_MODE_SHADOW || p_params->pass_mode == PASS_MODE_SHADOW_DP) && surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS)) { cull_variant = ShaderData::CULL_VARIANT_DOUBLE_SIDED; } else { - bool mirror = e->instance->mirror; - if (p_reverse_cull) { + bool mirror = surf->owner->mirror; + if (p_params->reverse_cull) { mirror = !mirror; } cull_variant = mirror ? ShaderData::CULL_VARIANT_REVERSED : ShaderData::CULL_VARIANT_NORMAL; } - //find primitive and vertex format - RS::PrimitiveType primitive; - - switch (e->instance->base_type) { - case RS::INSTANCE_MESH: { - primitive = storage->mesh_surface_get_primitive(e->instance->base, e->surface_index); - if (e->instance->skeleton.is_valid()) { - xforms_uniform_set = storage->skeleton_get_3d_uniform_set(e->instance->skeleton, default_shader_rd, TRANSFORMS_UNIFORM_SET); - } - } break; - case RS::INSTANCE_MULTIMESH: { - RID mesh = storage->multimesh_get_mesh(e->instance->base); - ERR_CONTINUE(!mesh.is_valid()); //should be a bug - primitive = storage->mesh_surface_get_primitive(mesh, e->surface_index); - - xforms_uniform_set = storage->multimesh_get_3d_uniform_set(e->instance->base, default_shader_rd, TRANSFORMS_UNIFORM_SET); - - } break; - case RS::INSTANCE_IMMEDIATE: { - ERR_CONTINUE(true); //should be a bug - } break; - case RS::INSTANCE_PARTICLES: { - RID mesh = storage->particles_get_draw_pass_mesh(e->instance->base, e->surface_index >> 16); - ERR_CONTINUE(!mesh.is_valid()); //should be a bug - primitive = storage->mesh_surface_get_primitive(mesh, e->surface_index & 0xFFFF); - - xforms_uniform_set = storage->particles_get_instance_buffer_uniform_set(e->instance->base, default_shader_rd, TRANSFORMS_UNIFORM_SET); - - } break; - default: { - ERR_CONTINUE(true); //should be a bug - } - } + RS::PrimitiveType primitive = surf->primitive; + RID xforms_uniform_set = surf->owner->transforms_uniform_set; ShaderVersion shader_version = SHADER_VERSION_MAX; // Assigned to silence wrong -Wmaybe-initialized. - switch (p_pass_mode) { + switch (p_params->pass_mode) { case PASS_MODE_COLOR: case PASS_MODE_COLOR_TRANSPARENT: { - if (e->uses_lightmap) { + if (element_info.uses_lightmap) { shader_version = SHADER_VERSION_LIGHTMAP_COLOR_PASS; - } else if (e->uses_forward_gi) { + } else if (element_info.uses_forward_gi) { shader_version = SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI; } else { shader_version = SHADER_VERSION_COLOR_PASS; } } break; case PASS_MODE_COLOR_SPECULAR: { - if (e->uses_lightmap) { + if (element_info.uses_lightmap) { shader_version = SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR; } else { shader_version = SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR; @@ -1076,7 +901,7 @@ void RasterizerSceneHighEndRD::_render_list(RenderingDevice::DrawListID p_draw_l } break; } - RenderPipelineVertexFormatCacheRD *pipeline = nullptr; + PipelineCacheRD *pipeline = nullptr; pipeline = &shader->pipelines[cull_variant][primitive][shader_version]; @@ -1084,28 +909,15 @@ void RasterizerSceneHighEndRD::_render_list(RenderingDevice::DrawListID p_draw_l RID vertex_array_rd; RID index_array_rd; - switch (e->instance->base_type) { - case RS::INSTANCE_MESH: { - storage->mesh_surface_get_arrays_and_format(e->instance->base, e->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, index_array_rd, vertex_format); - } break; - case RS::INSTANCE_MULTIMESH: { - RID mesh = storage->multimesh_get_mesh(e->instance->base); - ERR_CONTINUE(!mesh.is_valid()); //should be a bug - storage->mesh_surface_get_arrays_and_format(mesh, e->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, index_array_rd, vertex_format); - } break; - case RS::INSTANCE_IMMEDIATE: { - ERR_CONTINUE(true); //should be a bug - } break; - case RS::INSTANCE_PARTICLES: { - RID mesh = storage->particles_get_draw_pass_mesh(e->instance->base, e->surface_index >> 16); - ERR_CONTINUE(!mesh.is_valid()); //should be a bug - storage->mesh_surface_get_arrays_and_format(mesh, e->surface_index & 0xFFFF, pipeline->get_vertex_input_mask(), vertex_array_rd, index_array_rd, vertex_format); - } break; - default: { - ERR_CONTINUE(true); //should be a bug - } + //skeleton and blend shape + if (surf->owner->mesh_instance.is_valid()) { + storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format); + } else { + storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format); } + index_array_rd = storage->mesh_surface_get_index_array(mesh_surface, element_info.lod_index); + if (prev_vertex_array_rd != vertex_array_rd) { RD::get_singleton()->draw_list_bind_vertex_array(draw_list, vertex_array_rd); prev_vertex_array_rd = vertex_array_rd; @@ -1118,7 +930,7 @@ void RasterizerSceneHighEndRD::_render_list(RenderingDevice::DrawListID p_draw_l prev_index_array_rd = index_array_rd; } - RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_force_wireframe); + RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_params->force_wireframe); if (pipeline_rd != prev_pipeline_rd) { // checking with prev shader does not make so much sense, as @@ -1132,40 +944,87 @@ void RasterizerSceneHighEndRD::_render_list(RenderingDevice::DrawListID p_draw_l prev_xforms_uniform_set = xforms_uniform_set; } - if (material != prev_material) { + if (material_uniform_set != prev_material_uniform_set) { //update uniform set - if (material->uniform_set.is_valid()) { - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material->uniform_set, MATERIAL_UNIFORM_SET); + if (material_uniform_set.is_valid()) { + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_uniform_set, MATERIAL_UNIFORM_SET); } - prev_material = material; + prev_material_uniform_set = material_uniform_set; } - push_constant.index = i; - RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(PushConstant)); + RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(SceneState::PushConstant)); - switch (e->instance->base_type) { - case RS::INSTANCE_MESH: { - RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid()); - } break; - case RS::INSTANCE_MULTIMESH: { - uint32_t instances = storage->multimesh_get_instances_to_draw(e->instance->base); - RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instances); - } break; - case RS::INSTANCE_IMMEDIATE: { - } break; - case RS::INSTANCE_PARTICLES: { - uint32_t instances = storage->particles_get_amount(e->instance->base); - RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instances); - } break; - default: { - ERR_CONTINUE(true); //should be a bug - } - } + uint32_t instance_count = surf->owner->instance_count > 1 ? surf->owner->instance_count : element_info.repeat; + RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instance_count); + i += element_info.repeat - 1; //skip equal elements } } -void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers, bool p_pancake_shadows) { +void RendererSceneRenderForward::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) { + //use template for faster performance (pass mode comparisons are inlined) + + switch (p_params->pass_mode) { + case PASS_MODE_COLOR: { + _render_list_template<PASS_MODE_COLOR>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_COLOR_SPECULAR: { + _render_list_template<PASS_MODE_COLOR_SPECULAR>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_COLOR_TRANSPARENT: { + _render_list_template<PASS_MODE_COLOR_TRANSPARENT>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_SHADOW: { + _render_list_template<PASS_MODE_SHADOW>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_SHADOW_DP: { + _render_list_template<PASS_MODE_SHADOW_DP>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_DEPTH: { + _render_list_template<PASS_MODE_DEPTH>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: { + _render_list_template<PASS_MODE_DEPTH_NORMAL_ROUGHNESS>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE: { + _render_list_template<PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_DEPTH_MATERIAL: { + _render_list_template<PASS_MODE_DEPTH_MATERIAL>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_SDF: { + _render_list_template<PASS_MODE_SDF>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + } +} + +void RendererSceneRenderForward::_render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params) { + uint32_t render_total = p_params->element_count; + uint32_t total_threads = RendererThreadPool::singleton->thread_work_pool.get_thread_count(); + uint32_t render_from = p_thread * render_total / total_threads; + uint32_t render_to = (p_thread + 1 == total_threads) ? render_total : ((p_thread + 1) * render_total / total_threads); + _render_list(thread_draw_lists[p_thread], p_params->framebuffer_format, p_params, render_from, render_to); +} + +void RendererSceneRenderForward::_render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) { + RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(p_framebuffer); + p_params->framebuffer_format = fb_format; + + if ((uint32_t)p_params->element_count > render_list_thread_threshold && false) { // secondary command buffers need more testing at this time + //multi threaded + thread_draw_lists.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count()); + RD::get_singleton()->draw_list_begin_split(p_framebuffer, thread_draw_lists.size(), thread_draw_lists.ptr(), p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures); + RendererThreadPool::singleton->thread_work_pool.do_work(thread_draw_lists.size(), this, &RendererSceneRenderForward::_render_list_thread_function, p_params); + RD::get_singleton()->draw_list_end(p_params->barrier); + } else { + //single threaded + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures); + _render_list(draw_list, fb_format, p_params, 0, p_params->element_count); + RD::get_singleton()->draw_list_end(p_params->barrier); + } +} + +void RendererSceneRenderForward::_setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2i &p_screen_size, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) { //CameraMatrix projection = p_cam_projection; //projection.flip_y(); // Vulkan and modern APIs use Y-Down CameraMatrix correction; @@ -1173,28 +1032,38 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, RID p_rende CameraMatrix projection = correction * p_cam_projection; //store camera into ubo - RasterizerStorageRD::store_camera(projection, scene_state.ubo.projection_matrix); - RasterizerStorageRD::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix); - RasterizerStorageRD::store_transform(p_cam_transform, scene_state.ubo.camera_matrix); - RasterizerStorageRD::store_transform(p_cam_transform.affine_inverse(), scene_state.ubo.inv_camera_matrix); + RendererStorageRD::store_camera(projection, scene_state.ubo.projection_matrix); + RendererStorageRD::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix); + RendererStorageRD::store_transform(p_cam_transform, scene_state.ubo.camera_matrix); + RendererStorageRD::store_transform(p_cam_transform.affine_inverse(), scene_state.ubo.inv_camera_matrix); scene_state.ubo.z_far = p_zfar; scene_state.ubo.z_near = p_znear; scene_state.ubo.pancake_shadows = p_pancake_shadows; - RasterizerStorageRD::store_soft_shadow_kernel(directional_penumbra_shadow_kernel_get(), scene_state.ubo.directional_penumbra_shadow_kernel); - RasterizerStorageRD::store_soft_shadow_kernel(directional_soft_shadow_kernel_get(), scene_state.ubo.directional_soft_shadow_kernel); - RasterizerStorageRD::store_soft_shadow_kernel(penumbra_shadow_kernel_get(), scene_state.ubo.penumbra_shadow_kernel); - RasterizerStorageRD::store_soft_shadow_kernel(soft_shadow_kernel_get(), scene_state.ubo.soft_shadow_kernel); + RendererStorageRD::store_soft_shadow_kernel(directional_penumbra_shadow_kernel_get(), scene_state.ubo.directional_penumbra_shadow_kernel); + RendererStorageRD::store_soft_shadow_kernel(directional_soft_shadow_kernel_get(), scene_state.ubo.directional_soft_shadow_kernel); + RendererStorageRD::store_soft_shadow_kernel(penumbra_shadow_kernel_get(), scene_state.ubo.penumbra_shadow_kernel); + RendererStorageRD::store_soft_shadow_kernel(soft_shadow_kernel_get(), scene_state.ubo.soft_shadow_kernel); scene_state.ubo.directional_penumbra_shadow_samples = directional_penumbra_shadow_samples_get(); scene_state.ubo.directional_soft_shadow_samples = directional_soft_shadow_samples_get(); scene_state.ubo.penumbra_shadow_samples = penumbra_shadow_samples_get(); scene_state.ubo.soft_shadow_samples = soft_shadow_samples_get(); - scene_state.ubo.screen_pixel_size[0] = p_screen_pixel_size.x; - scene_state.ubo.screen_pixel_size[1] = p_screen_pixel_size.y; + Size2 screen_pixel_size = Vector2(1.0, 1.0) / Size2(p_screen_size); + scene_state.ubo.screen_pixel_size[0] = screen_pixel_size.x; + scene_state.ubo.screen_pixel_size[1] = screen_pixel_size.y; + + scene_state.ubo.cluster_shift = get_shift_from_power_of_2(p_cluster_size); + scene_state.ubo.max_cluster_element_count_div_32 = p_max_cluster_elements / 32; + { + uint32_t cluster_screen_width = (p_screen_size.width - 1) / p_cluster_size + 1; + uint32_t cluster_screen_height = (p_screen_size.height - 1) / p_cluster_size + 1; + scene_state.ubo.cluster_type_size = cluster_screen_width * cluster_screen_height * (scene_state.ubo.max_cluster_element_count_div_32 + 32); + scene_state.ubo.cluster_width = cluster_screen_width; + } if (p_shadow_atlas.is_valid()) { Vector2 sas = shadow_atlas_get_size(p_shadow_atlas); @@ -1214,7 +1083,7 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, RID p_rende scene_state.ubo.fog_enabled = false; if (p_render_buffers.is_valid()) { - RenderBufferDataHighEnd *render_buffers = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers); + RenderBufferDataForward *render_buffers = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); if (render_buffers->msaa != RS::VIEWPORT_MSAA_DISABLED) { scene_state.ubo.gi_upscale_for_msaa = true; } @@ -1330,7 +1199,7 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, RID p_rende Basis sky_transform = environment_get_sky_orientation(p_environment); sky_transform = sky_transform.inverse() * p_cam_transform.basis; - RasterizerStorageRD::store_transform_3x3(sky_transform, scene_state.ubo.radiance_inverse_xform); + RendererStorageRD::store_transform_3x3(sky_transform, scene_state.ubo.radiance_inverse_xform); scene_state.ubo.use_ambient_cubemap = (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ambient_src == RS::ENV_AMBIENT_SOURCE_SKY; scene_state.ubo.use_ambient_light = scene_state.ubo.use_ambient_cubemap || ambient_src == RS::ENV_AMBIENT_SOURCE_COLOR; @@ -1394,267 +1263,337 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, RID p_rende scene_state.ubo.roughness_limiter_amount = screen_space_roughness_limiter_get_amount(); scene_state.ubo.roughness_limiter_limit = screen_space_roughness_limiter_get_limit(); - RD::get_singleton()->buffer_update(scene_state.uniform_buffer, 0, sizeof(SceneState::UBO), &scene_state.ubo, true); -} - -void RasterizerSceneHighEndRD::_add_geometry(InstanceBase *p_instance, uint32_t p_surface, RID p_material, PassMode p_pass_mode, uint32_t p_geometry_index, bool p_using_sdfgi) { - RID m_src; - - m_src = p_instance->material_override.is_valid() ? p_instance->material_override : p_material; - - if (unlikely(get_debug_draw_mode() != RS::VIEWPORT_DEBUG_DRAW_DISABLED)) { - if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW) { - m_src = overdraw_material; - } else if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_LIGHTING) { - m_src = default_material; + if (p_index >= (int)scene_state.uniform_buffers.size()) { + uint32_t from = scene_state.uniform_buffers.size(); + scene_state.uniform_buffers.resize(p_index + 1); + render_pass_uniform_sets.resize(p_index + 1); + for (uint32_t i = from; i < scene_state.uniform_buffers.size(); i++) { + scene_state.uniform_buffers[i] = RD::get_singleton()->uniform_buffer_create(sizeof(SceneState::UBO)); } } + RD::get_singleton()->buffer_update(scene_state.uniform_buffers[p_index], 0, sizeof(SceneState::UBO), &scene_state.ubo, RD::BARRIER_MASK_RASTER); +} - MaterialData *material = nullptr; - - if (m_src.is_valid()) { - material = (MaterialData *)storage->material_get_data(m_src, RasterizerStorageRD::SHADER_TYPE_3D); - if (!material || !material->shader_data->valid) { - material = nullptr; +void RendererSceneRenderForward::_update_instance_data_buffer(RenderListType p_render_list) { + if (scene_state.instance_data[p_render_list].size() > 0) { + if (scene_state.instance_buffer[p_render_list] == RID() || scene_state.instance_buffer_size[p_render_list] < scene_state.instance_data[p_render_list].size()) { + if (scene_state.instance_buffer[p_render_list] != RID()) { + RD::get_singleton()->free(scene_state.instance_buffer[p_render_list]); + } + uint32_t new_size = nearest_power_of_2_templated(MAX(uint64_t(INSTANCE_DATA_BUFFER_MIN_SIZE), scene_state.instance_data[p_render_list].size())); + scene_state.instance_buffer[p_render_list] = RD::get_singleton()->storage_buffer_create(new_size * sizeof(SceneState::InstanceData)); + scene_state.instance_buffer_size[p_render_list] = new_size; } + RD::get_singleton()->buffer_update(scene_state.instance_buffer[p_render_list], 0, sizeof(SceneState::InstanceData) * scene_state.instance_data[p_render_list].size(), scene_state.instance_data[p_render_list].ptr(), RD::BARRIER_MASK_RASTER); } +} +void RendererSceneRenderForward::_fill_instance_data(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements, bool p_update_buffer) { + RenderList *rl = &render_list[p_render_list]; + uint32_t element_total = p_max_elements >= 0 ? uint32_t(p_max_elements) : rl->elements.size(); - if (!material) { - material = (MaterialData *)storage->material_get_data(default_material, RasterizerStorageRD::SHADER_TYPE_3D); - m_src = default_material; - } + scene_state.instance_data[p_render_list].resize(p_offset + element_total); + rl->element_info.resize(p_offset + element_total); - ERR_FAIL_COND(!material); + uint32_t repeats = 0; + GeometryInstanceSurfaceDataCache *prev_surface = nullptr; + for (uint32_t i = 0; i < element_total; i++) { + GeometryInstanceSurfaceDataCache *surface = rl->elements[i + p_offset]; + GeometryInstanceForward *inst = surface->owner; - _add_geometry_with_material(p_instance, p_surface, material, m_src, p_pass_mode, p_geometry_index, p_using_sdfgi); + SceneState::InstanceData &instance_data = scene_state.instance_data[p_render_list][i + p_offset]; - while (material->next_pass.is_valid()) { - material = (MaterialData *)storage->material_get_data(material->next_pass, RasterizerStorageRD::SHADER_TYPE_3D); - if (!material || !material->shader_data->valid) { - break; + if (inst->store_transform_cache) { + RendererStorageRD::store_transform(inst->transform, instance_data.transform); + } else { + RendererStorageRD::store_transform(Transform(), instance_data.transform); } - _add_geometry_with_material(p_instance, p_surface, material, material->next_pass, p_pass_mode, p_geometry_index, p_using_sdfgi); - } -} -void RasterizerSceneHighEndRD::_add_geometry_with_material(InstanceBase *p_instance, uint32_t p_surface, MaterialData *p_material, RID p_material_rid, PassMode p_pass_mode, uint32_t p_geometry_index, bool p_using_sdfgi) { - bool has_read_screen_alpha = p_material->shader_data->uses_screen_texture || p_material->shader_data->uses_depth_texture || p_material->shader_data->uses_normal_texture; - bool has_base_alpha = (p_material->shader_data->uses_alpha || has_read_screen_alpha); - bool has_blend_alpha = p_material->shader_data->uses_blend_alpha; - bool has_alpha = has_base_alpha || has_blend_alpha; + instance_data.flags = inst->flags_cache; + instance_data.gi_offset = inst->gi_offset_cache; + instance_data.layer_mask = inst->layer_mask; + instance_data.instance_uniforms_ofs = uint32_t(inst->shader_parameters_offset); + instance_data.lightmap_uv_scale[0] = inst->lightmap_uv_scale.position.x; + instance_data.lightmap_uv_scale[1] = inst->lightmap_uv_scale.position.y; + instance_data.lightmap_uv_scale[2] = inst->lightmap_uv_scale.size.x; + instance_data.lightmap_uv_scale[3] = inst->lightmap_uv_scale.size.y; - if (p_material->shader_data->uses_sss) { - scene_state.used_sss = true; - } + bool cant_repeat = instance_data.flags & INSTANCE_DATA_FLAG_MULTIMESH || inst->mesh_instance.is_valid(); - if (p_material->shader_data->uses_screen_texture) { - scene_state.used_screen_texture = true; - } + if (prev_surface != nullptr && !cant_repeat && prev_surface->sort.sort_key1 == surface->sort.sort_key1 && prev_surface->sort.sort_key2 == surface->sort.sort_key2) { + //this element is the same as the previous one, count repeats to draw it using instancing + repeats++; + } else { + if (repeats > 0) { + for (uint32_t j = 1; j <= repeats; j++) { + rl->element_info[p_offset + i - j].repeat = j; + } + } + repeats = 1; + } - if (p_material->shader_data->uses_depth_texture) { - scene_state.used_depth_texture = true; - } + RenderElementInfo &element_info = rl->element_info[p_offset + i]; - if (p_material->shader_data->uses_normal_texture) { - scene_state.used_normal_texture = true; - } + element_info.lod_index = surface->sort.lod_index; + element_info.uses_forward_gi = surface->sort.uses_forward_gi; + element_info.uses_lightmap = surface->sort.uses_lightmap; - if (p_pass_mode != PASS_MODE_COLOR && p_pass_mode != PASS_MODE_COLOR_SPECULAR) { - if (has_blend_alpha || has_read_screen_alpha || (has_base_alpha && !p_material->shader_data->uses_depth_pre_pass) || p_material->shader_data->depth_draw == ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == ShaderData::DEPTH_TEST_DISABLED || p_instance->cast_shadows == RS::SHADOW_CASTING_SETTING_OFF) { - //conditions in which no depth pass should be processed - return; + if (cant_repeat) { + prev_surface = nullptr; + } else { + prev_surface = surface; } + } - if ((p_pass_mode != PASS_MODE_DEPTH_MATERIAL && p_pass_mode != PASS_MODE_SDF) && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) { - //shader does not use discard and does not write a vertex position, use generic material - if (p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_DEPTH) { - p_material = (MaterialData *)storage->material_get_data(default_material, RasterizerStorageRD::SHADER_TYPE_3D); - } else if ((p_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS || p_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE) && !p_material->shader_data->uses_normal && !p_material->shader_data->uses_roughness) { - p_material = (MaterialData *)storage->material_get_data(default_material, RasterizerStorageRD::SHADER_TYPE_3D); - } + if (repeats > 0) { + for (uint32_t j = 1; j <= repeats; j++) { + rl->element_info[p_offset + element_total - j].repeat = j; } - - has_alpha = false; } - has_alpha = has_alpha || p_material->shader_data->depth_test == ShaderData::DEPTH_TEST_DISABLED; - - RenderList::Element *e = has_alpha ? render_list.add_alpha_element() : render_list.add_element(); + if (p_update_buffer) { + _update_instance_data_buffer(p_render_list); + } +} - if (!e) { - return; +void RendererSceneRenderForward::_fill_render_list(RenderListType p_render_list, const PagedArray<GeometryInstance *> &p_instances, PassMode p_pass_mode, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_using_sdfgi, bool p_using_opaque_gi, const Plane &p_lod_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, bool p_append) { + if (p_render_list == RENDER_LIST_OPAQUE) { + scene_state.used_sss = false; + scene_state.used_screen_texture = false; + scene_state.used_normal_texture = false; + scene_state.used_depth_texture = false; } + uint32_t lightmap_captures_used = 0; - e->instance = p_instance; - e->material = p_material; - e->surface_index = p_surface; - e->sort_key = 0; + Plane near_plane(p_cam_transform.origin, -p_cam_transform.basis.get_axis(Vector3::AXIS_Z)); + near_plane.d += p_cam_projection.get_z_near(); + float z_max = p_cam_projection.get_z_far() - p_cam_projection.get_z_near(); - if (e->material->last_pass != render_pass) { - if (!RD::get_singleton()->uniform_set_is_valid(e->material->uniform_set)) { - //uniform set no longer valid, probably a texture changed - storage->material_force_update_textures(p_material_rid, RasterizerStorageRD::SHADER_TYPE_3D); - } - e->material->last_pass = render_pass; - e->material->index = scene_state.current_material_index++; - if (e->material->shader_data->last_pass != render_pass) { - e->material->shader_data->last_pass = scene_state.current_material_index++; - e->material->shader_data->index = scene_state.current_shader_index++; + RenderList *rl = &render_list[p_render_list]; + _update_dirty_geometry_instances(); + + if (!p_append) { + rl->clear(); + if (p_render_list == RENDER_LIST_OPAQUE) { + render_list[RENDER_LIST_ALPHA].clear(); //opaque fills alpha too } } - e->geometry_index = p_geometry_index; - e->material_index = e->material->index; - e->uses_instancing = e->instance->base_type == RS::INSTANCE_MULTIMESH; - e->uses_lightmap = e->instance->lightmap != nullptr || !e->instance->lightmap_sh.empty(); - e->uses_forward_gi = has_alpha && (e->instance->gi_probe_instances.size() || p_using_sdfgi); - e->shader_index = e->shader_index; - e->depth_layer = e->instance->depth_layer; - e->priority = p_material->priority; - if (p_material->shader_data->uses_time) { - RenderingServerRaster::redraw_request(); - } -} + //fill list -void RasterizerSceneHighEndRD::_fill_render_list(InstanceBase **p_cull_result, int p_cull_count, PassMode p_pass_mode, bool p_using_sdfgi) { - scene_state.current_shader_index = 0; - scene_state.current_material_index = 0; - scene_state.used_sss = false; - scene_state.used_screen_texture = false; - scene_state.used_normal_texture = false; - scene_state.used_depth_texture = false; + for (int i = 0; i < (int)p_instances.size(); i++) { + GeometryInstanceForward *inst = static_cast<GeometryInstanceForward *>(p_instances[i]); - uint32_t geometry_index = 0; + Vector3 support_min = inst->transformed_aabb.get_support(-near_plane.normal); + inst->depth = near_plane.distance_to(support_min); + uint32_t depth_layer = CLAMP(int(inst->depth * 16 / z_max), 0, 15); - //fill list + uint32_t flags = inst->base_flags; //fill flags if appropriate - for (int i = 0; i < p_cull_count; i++) { - InstanceBase *inst = p_cull_result[i]; + bool uses_lightmap = false; + bool uses_gi = false; - //add geometry for drawing - switch (inst->base_type) { - case RS::INSTANCE_MESH: { - const RID *materials = nullptr; - uint32_t surface_count; + if (p_render_list == RENDER_LIST_OPAQUE) { + //setup GI - materials = storage->mesh_get_surface_count_and_materials(inst->base, surface_count); - if (!materials) { - continue; //nothing to do + if (inst->lightmap_instance.is_valid()) { + int32_t lightmap_cull_index = -1; + for (uint32_t j = 0; j < scene_state.lightmaps_used; j++) { + if (scene_state.lightmap_ids[j] == inst->lightmap_instance) { + lightmap_cull_index = j; + break; + } + } + if (lightmap_cull_index >= 0) { + inst->gi_offset_cache = inst->lightmap_slice_index << 16; + inst->gi_offset_cache |= lightmap_cull_index; + flags |= INSTANCE_DATA_FLAG_USE_LIGHTMAP; + if (scene_state.lightmap_has_sh[lightmap_cull_index]) { + flags |= INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP; + } + uses_lightmap = true; + } else { + inst->gi_offset_cache = 0xFFFFFFFF; } - const RID *inst_materials = inst->materials.ptr(); - - for (uint32_t j = 0; j < surface_count; j++) { - RID material = inst_materials[j].is_valid() ? inst_materials[j] : materials[j]; + } else if (inst->lightmap_sh) { + if (lightmap_captures_used < scene_state.max_lightmap_captures) { + const Color *src_capture = inst->lightmap_sh->sh; + LightmapCaptureData &lcd = scene_state.lightmap_captures[lightmap_captures_used]; + for (int j = 0; j < 9; j++) { + lcd.sh[j * 4 + 0] = src_capture[j].r; + lcd.sh[j * 4 + 1] = src_capture[j].g; + lcd.sh[j * 4 + 2] = src_capture[j].b; + lcd.sh[j * 4 + 3] = src_capture[j].a; + } + flags |= INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE; + inst->gi_offset_cache = lightmap_captures_used; + lightmap_captures_used++; + uses_lightmap = true; + } - uint32_t surface_index = storage->mesh_surface_get_render_pass_index(inst->base, j, render_pass, &geometry_index); - _add_geometry(inst, j, material, p_pass_mode, surface_index, p_using_sdfgi); + } else if (!low_end) { + if (p_using_opaque_gi) { + flags |= INSTANCE_DATA_FLAG_USE_GI_BUFFERS; } - //mesh->last_pass=frame; + if (inst->gi_probes[0].is_valid()) { + uint32_t probe0_index = 0xFFFF; + uint32_t probe1_index = 0xFFFF; - } break; + for (uint32_t j = 0; j < scene_state.giprobes_used; j++) { + if (scene_state.giprobe_ids[j] == inst->gi_probes[0]) { + probe0_index = j; + } else if (scene_state.giprobe_ids[j] == inst->gi_probes[1]) { + probe1_index = j; + } + } - case RS::INSTANCE_MULTIMESH: { - if (storage->multimesh_get_instances_to_draw(inst->base) == 0) { - //not visible, 0 instances - continue; - } + if (probe0_index == 0xFFFF && probe1_index != 0xFFFF) { + //0 must always exist if a probe exists + SWAP(probe0_index, probe1_index); + } - RID mesh = storage->multimesh_get_mesh(inst->base); - if (!mesh.is_valid()) { - continue; + inst->gi_offset_cache = probe0_index | (probe1_index << 16); + flags |= INSTANCE_DATA_FLAG_USE_GIPROBE; + uses_gi = true; + } else { + if (p_using_sdfgi && inst->can_sdfgi) { + flags |= INSTANCE_DATA_FLAG_USE_SDFGI; + uses_gi = true; + } + inst->gi_offset_cache = 0xFFFFFFFF; } + } + } + inst->flags_cache = flags; - const RID *materials = nullptr; - uint32_t surface_count; + GeometryInstanceSurfaceDataCache *surf = inst->surface_caches; - materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count); - if (!materials) { - continue; //nothing to do - } + while (surf) { + surf->sort.uses_forward_gi = 0; + surf->sort.uses_lightmap = 0; - for (uint32_t j = 0; j < surface_count; j++) { - uint32_t surface_index = storage->mesh_surface_get_multimesh_render_pass_index(mesh, j, render_pass, &geometry_index); - _add_geometry(inst, j, materials[j], p_pass_mode, surface_index, p_using_sdfgi); - } + // LOD - } break; -#if 0 - case RS::INSTANCE_IMMEDIATE: { - RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.getornull(inst->base); - ERR_CONTINUE(!immediate); + if (p_screen_lod_threshold > 0.0 && storage->mesh_surface_has_lod(surf->surface)) { + //lod + Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_lod_plane.normal); + Vector3 lod_support_max = inst->transformed_aabb.get_support(p_lod_plane.normal); - _add_geometry(immediate, inst, nullptr, -1, p_depth_pass, p_shadow_pass); + float distance_min = p_lod_plane.distance_to(lod_support_min); + float distance_max = p_lod_plane.distance_to(lod_support_max); - } break; -#endif - case RS::INSTANCE_PARTICLES: { - int draw_passes = storage->particles_get_draw_passes(inst->base); + float distance = 0.0; - for (int j = 0; j < draw_passes; j++) { - RID mesh = storage->particles_get_draw_pass_mesh(inst->base, j); - if (!mesh.is_valid()) - continue; + if (distance_min * distance_max < 0.0) { + //crossing plane + distance = 0.0; + } else if (distance_min >= 0.0) { + distance = distance_min; + } else if (distance_max <= 0.0) { + distance = -distance_max; + } - const RID *materials = nullptr; - uint32_t surface_count; + surf->sort.lod_index = storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_lod_distance_multiplier, p_screen_lod_threshold); + } else { + surf->sort.lod_index = 0; + } - materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count); - if (!materials) { - continue; //nothing to do + // ADD Element + if (p_pass_mode == PASS_MODE_COLOR) { + if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) { + rl->add_element(surf); + } + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA) { + render_list[RENDER_LIST_ALPHA].add_element(surf); + if (uses_gi) { + surf->sort.uses_forward_gi = 1; } + } - for (uint32_t k = 0; k < surface_count; k++) { - uint32_t surface_index = storage->mesh_surface_get_particles_render_pass_index(mesh, j, render_pass, &geometry_index); - _add_geometry(inst, (j << 16) | k, materials[j], p_pass_mode, surface_index, p_using_sdfgi); - } + if (uses_lightmap) { + surf->sort.uses_lightmap = 1; } - } break; + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_SUBSURFACE_SCATTERING) { + scene_state.used_sss = true; + } + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_SCREEN_TEXTURE) { + scene_state.used_screen_texture = true; + } + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_NORMAL_TEXTURE) { + scene_state.used_normal_texture = true; + } + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE) { + scene_state.used_depth_texture = true; + } - default: { + } else if (p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_SHADOW_DP) { + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW) { + rl->add_element(surf); + } + } else { + if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) { + rl->add_element(surf); + } } + + surf->sort.depth_layer = depth_layer; + + surf = surf->next; } } + + if (p_render_list == RENDER_LIST_OPAQUE && lightmap_captures_used) { + RD::get_singleton()->buffer_update(scene_state.lightmap_capture_buffer, 0, sizeof(LightmapCaptureData) * lightmap_captures_used, scene_state.lightmap_captures, RD::BARRIER_MASK_RASTER); + } +} + +void RendererSceneRenderForward::_setup_giprobes(const PagedArray<RID> &p_giprobes) { + scene_state.giprobes_used = MIN(p_giprobes.size(), uint32_t(MAX_GI_PROBES)); + for (uint32_t i = 0; i < scene_state.giprobes_used; i++) { + scene_state.giprobe_ids[i] = p_giprobes[i]; + } } -void RasterizerSceneHighEndRD::_setup_lightmaps(InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, const Transform &p_cam_transform) { - uint32_t lightmaps_used = 0; - for (int i = 0; i < p_lightmap_cull_count; i++) { +void RendererSceneRenderForward::_setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform &p_cam_transform) { + scene_state.lightmaps_used = 0; + for (int i = 0; i < (int)p_lightmaps.size(); i++) { if (i >= (int)scene_state.max_lightmaps) { break; } - InstanceBase *lm = p_lightmap_cull_result[i]; - Basis to_lm = lm->transform.basis.inverse() * p_cam_transform.basis; + RID lightmap = lightmap_instance_get_lightmap(p_lightmaps[i]); + + Basis to_lm = lightmap_instance_get_transform(p_lightmaps[i]).basis.inverse() * p_cam_transform.basis; to_lm = to_lm.inverse().transposed(); //will transform normals - RasterizerStorageRD::store_transform_3x3(to_lm, scene_state.lightmaps[i].normal_xform); - lm->lightmap_cull_index = i; - lightmaps_used++; + RendererStorageRD::store_transform_3x3(to_lm, scene_state.lightmaps[i].normal_xform); + scene_state.lightmap_ids[i] = p_lightmaps[i]; + scene_state.lightmap_has_sh[i] = storage->lightmap_uses_spherical_harmonics(lightmap); + + scene_state.lightmaps_used++; } - if (lightmaps_used > 0) { - RD::get_singleton()->buffer_update(scene_state.lightmap_buffer, 0, sizeof(LightmapData) * lightmaps_used, scene_state.lightmaps, true); + if (scene_state.lightmaps_used > 0) { + RD::get_singleton()->buffer_update(scene_state.lightmap_buffer, 0, sizeof(LightmapData) * scene_state.lightmaps_used, scene_state.lightmaps, RD::BARRIER_MASK_RASTER); } } -void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, int p_directional_light_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color) { - RenderBufferDataHighEnd *render_buffer = nullptr; +void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_cluster_buffer, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color, float p_screen_lod_threshold) { + RenderBufferDataForward *render_buffer = nullptr; if (p_render_buffer.is_valid()) { - render_buffer = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffer); + render_buffer = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffer); } //first of all, make a new render pass - render_pass++; - //fill up ubo RENDER_TIMESTAMP("Setup 3D Scene"); - if (p_reflection_probe.is_valid()) { - scene_state.ubo.reflection_multiplier = 0.0; - } else { - scene_state.ubo.reflection_multiplier = 1.0; + float lod_distance_multiplier = p_cam_projection.get_lod_multiplier(); + Plane lod_camera_plane(p_cam_transform.get_origin(), -p_cam_transform.basis.get_axis(Vector3::AXIS_Z)); + + if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) { + p_screen_lod_threshold = 0.0; } //scene_state.ubo.subsurface_scatter_width = subsurface_scatter_size; @@ -1662,9 +1601,8 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor Vector2 vp_he = p_cam_projection.get_viewport_half_extents(); scene_state.ubo.viewport_size[0] = vp_he.x; scene_state.ubo.viewport_size[1] = vp_he.y; - scene_state.ubo.directional_light_count = p_directional_light_count; + scene_state.ubo.directional_light_count = 0; - Size2 screen_pixel_size; Size2i screen_size; RID opaque_framebuffer; RID opaque_specular_framebuffer; @@ -1679,16 +1617,13 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor bool using_giprobe = false; if (render_buffer) { - screen_pixel_size.width = 1.0 / render_buffer->width; - screen_pixel_size.height = 1.0 / render_buffer->height; screen_size.x = render_buffer->width; screen_size.y = render_buffer->height; opaque_framebuffer = render_buffer->color_fb; - if (p_gi_probe_cull_count > 0) { + if (!low_end && p_gi_probes.size() > 0) { using_giprobe = true; - render_buffer->ensure_gi(); } if (!p_environment.is_valid() && using_giprobe) { @@ -1698,7 +1633,6 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor if (environment_is_sdfgi_enabled(p_environment)) { depth_pass_mode = using_giprobe ? PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE : PASS_MODE_DEPTH_NORMAL_ROUGHNESS; // also giprobe using_sdfgi = true; - render_buffer->ensure_gi(); } else { depth_pass_mode = using_giprobe ? PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE : PASS_MODE_DEPTH_NORMAL_ROUGHNESS; } @@ -1737,8 +1671,6 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor alpha_framebuffer = opaque_framebuffer; } else if (p_reflection_probe.is_valid()) { uint32_t resolution = reflection_probe_instance_get_resolution(p_reflection_probe); - screen_pixel_size.width = 1.0 / resolution; - screen_pixel_size.height = 1.0 / resolution; screen_size.x = resolution; screen_size.y = resolution; @@ -1753,15 +1685,23 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor ERR_FAIL(); //bug? } - _setup_lightmaps(p_lightmap_cull_result, p_lightmap_cull_count, p_cam_transform); - _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), false); + RD::get_singleton()->draw_command_begin_label("Render Setup"); + + _setup_lightmaps(p_lightmaps, p_cam_transform); + _setup_giprobes(p_gi_probes); + _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_size, p_cluster_size, p_max_cluster_elements, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), false); _update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example) - render_list.clear(); - _fill_render_list(p_cull_result, p_cull_count, PASS_MODE_COLOR, using_sdfgi); + _fill_render_list(RENDER_LIST_OPAQUE, p_instances, PASS_MODE_COLOR, p_cam_projection, p_cam_transform, using_sdfgi, using_sdfgi || using_giprobe, lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold); + render_list[RENDER_LIST_OPAQUE].sort_by_key(); + render_list[RENDER_LIST_ALPHA].sort_by_depth(); + _fill_instance_data(RENDER_LIST_OPAQUE); + _fill_instance_data(RENDER_LIST_ALPHA); - bool using_sss = render_buffer && scene_state.used_sss && sub_surface_scattering_get_quality() != RS::SUB_SURFACE_SCATTERING_QUALITY_DISABLED; + RD::get_singleton()->draw_command_end_label(); + + bool using_sss = !low_end && render_buffer && scene_state.used_sss && sub_surface_scattering_get_quality() != RS::SUB_SURFACE_SCATTERING_QUALITY_DISABLED; if (using_sss) { using_separate_specular = true; @@ -1769,7 +1709,7 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor using_separate_specular = true; opaque_specular_framebuffer = render_buffer->color_specular_fb; } - RID radiance_uniform_set; + RID radiance_texture; bool draw_sky = false; bool draw_sky_fog_only = false; @@ -1819,6 +1759,7 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor // setup sky if used for ambient, reflections, or background if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_environment) == RS::ENV_AMBIENT_SOURCE_SKY) { RENDER_TIMESTAMP("Setup Sky"); + RD::get_singleton()->draw_command_begin_label("Setup Sky"); CameraMatrix projection = p_cam_projection; if (p_reflection_probe.is_valid()) { CameraMatrix correction; @@ -1831,69 +1772,83 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor RID sky = environment_get_sky(p_environment); if (sky.is_valid()) { _update_sky(p_environment, projection, p_cam_transform); - radiance_uniform_set = sky_get_radiance_uniform_set_rd(sky, default_shader_rd, RADIANCE_UNIFORM_SET); + radiance_texture = sky_get_radiance_texture_rd(sky); } else { // do not try to draw sky if invalid draw_sky = false; } + RD::get_singleton()->draw_command_end_label(); } } else { clear_color = p_default_bg_color; } - _setup_view_dependant_uniform_set(p_shadow_atlas, p_reflection_atlas, p_gi_probe_cull_result, p_gi_probe_cull_count); - - render_list.sort_by_key(false); - - _fill_instances(render_list.elements, render_list.element_count, false, false, using_sdfgi || using_giprobe); - bool debug_giprobes = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION; bool debug_sdfgi_probes = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SDFGI_PROBES; - - bool depth_pre_pass = depth_framebuffer.is_valid(); - RID render_buffers_uniform_set; + bool depth_pre_pass = !low_end && depth_framebuffer.is_valid(); bool using_ssao = depth_pre_pass && p_render_buffer.is_valid() && p_environment.is_valid() && environment_is_ssao_enabled(p_environment); bool continue_depth = false; if (depth_pre_pass) { //depth pre pass - RENDER_TIMESTAMP("Render Depth Pre-Pass"); + + bool needs_pre_resolve = _needs_post_prepass_render(using_sdfgi || using_giprobe); + if (needs_pre_resolve) { + RENDER_TIMESTAMP("GI + Render Depth Pre-Pass (parallel)"); + } else { + RENDER_TIMESTAMP("Render Depth Pre-Pass"); + } + if (needs_pre_resolve) { + //pre clear the depth framebuffer, as AMD (and maybe others?) use compute for it, and barrier other compute shaders. + RD::get_singleton()->draw_list_begin(depth_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE, depth_pass_clear); + RD::get_singleton()->draw_list_end(); + //start compute processes here, so they run at the same time as depth pre-pass + _post_prepass_render(using_sdfgi || using_giprobe); + } + + RD::get_singleton()->draw_command_begin_label("Render Depth Pre-Pass"); + + RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, RID(), RID(), RID(), RID(), RID(), PagedArray<RID>(), PagedArray<RID>()); bool finish_depth = using_ssao || using_sdfgi || using_giprobe; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(depth_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, finish_depth ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, depth_pass_clear); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(depth_framebuffer), render_list.elements, render_list.element_count, false, depth_pass_mode, render_buffer == nullptr, radiance_uniform_set, RID(), get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME); - RD::get_singleton()->draw_list_end(); + RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), false, depth_pass_mode, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold); + _render_list_with_threads(&render_list_params, depth_framebuffer, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, finish_depth ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, needs_pre_resolve ? Vector<Color>() : depth_pass_clear); + + RD::get_singleton()->draw_command_end_label(); + + if (needs_pre_resolve) { + _pre_resolve_render(using_sdfgi || using_giprobe); + } if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { RENDER_TIMESTAMP("Resolve Depth Pre-Pass"); + RD::get_singleton()->draw_command_begin_label("Resolve Depth Pre-Pass"); if (depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS || depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE) { + if (needs_pre_resolve) { + RD::get_singleton()->barrier(RD::BARRIER_MASK_RASTER, RD::BARRIER_MASK_COMPUTE); + } static int texture_samples[RS::VIEWPORT_MSAA_MAX] = { 1, 2, 4, 8, 16 }; storage->get_effects()->resolve_gi(render_buffer->depth_msaa, render_buffer->normal_roughness_buffer_msaa, using_giprobe ? render_buffer->giprobe_buffer_msaa : RID(), render_buffer->depth, render_buffer->normal_roughness_buffer, using_giprobe ? render_buffer->giprobe_buffer : RID(), Vector2i(render_buffer->width, render_buffer->height), texture_samples[render_buffer->msaa]); } else if (finish_depth) { - RD::get_singleton()->texture_resolve_multisample(render_buffer->depth_msaa, render_buffer->depth, true); + RD::get_singleton()->texture_resolve_multisample(render_buffer->depth_msaa, render_buffer->depth); } + RD::get_singleton()->draw_command_end_label(); } continue_depth = !finish_depth; } - if (using_ssao) { - _process_ssao(p_render_buffer, p_environment, render_buffer->normal_roughness_buffer, p_cam_projection); - } + _pre_opaque_render(using_ssao, using_sdfgi || using_giprobe, render_buffer ? render_buffer->normal_roughness_buffer : RID(), render_buffer ? render_buffer->giprobe_buffer : RID()); - if (using_sdfgi || using_giprobe) { - _process_gi(p_render_buffer, render_buffer->normal_roughness_buffer, render_buffer->ambient_buffer, render_buffer->reflection_buffer, render_buffer->giprobe_buffer, p_environment, p_cam_projection, p_cam_transform, p_gi_probe_cull_result, p_gi_probe_cull_count); - } + RD::get_singleton()->draw_command_begin_label("Render Opaque Pass"); - if (p_render_buffer.is_valid()) { - //update the render buffers uniform set in case it changed - _update_render_buffers_uniform_set(p_render_buffer); - render_buffers_uniform_set = render_buffer->uniform_set; - } + scene_state.ubo.directional_light_count = _get_render_state_directional_light_count(); - _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), p_render_buffer.is_valid()); + _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_size, p_cluster_size, p_max_cluster_elements, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), p_render_buffer.is_valid()); RENDER_TIMESTAMP("Render Opaque Pass"); + RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_buffer, radiance_texture, p_shadow_atlas, p_reflection_atlas, p_cluster_buffer, p_gi_probes, p_lightmaps, true); + bool can_continue_color = !scene_state.used_screen_texture && !using_ssr && !using_sss; bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr && !using_sss; @@ -1913,17 +1868,17 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor } RID framebuffer = using_separate_specular ? opaque_specular_framebuffer : opaque_framebuffer; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? (continue_depth ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CONTINUE) : RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(framebuffer), render_list.elements, render_list.element_count, false, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, radiance_uniform_set, render_buffers_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME); - RD::get_singleton()->draw_list_end(); - + RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), false, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold); + _render_list_with_threads(&render_list_params, framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? (continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP) : RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0); if (will_continue_color && using_separate_specular) { // close the specular framebuffer, as it's no longer used - draw_list = RD::get_singleton()->draw_list_begin(render_buffer->specular_only_fb, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_CONTINUE); + RD::get_singleton()->draw_list_begin(render_buffer->specular_only_fb, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_CONTINUE); RD::get_singleton()->draw_list_end(); } } + RD::get_singleton()->draw_command_end_label(); + if (debug_giprobes) { //debug giprobes bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only); @@ -1933,9 +1888,11 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor dc.set_depth_correction(true); CameraMatrix cm = (dc * p_cam_projection) * CameraMatrix(p_cam_transform.affine_inverse()); RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, RD::INITIAL_ACTION_CONTINUE, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ); - for (int i = 0; i < p_gi_probe_cull_count; i++) { - _debug_giprobe(p_gi_probe_cull_result[i], draw_list, opaque_framebuffer, cm, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION, 1.0); + RD::get_singleton()->draw_command_begin_label("Debug GIProbes"); + for (int i = 0; i < (int)p_gi_probes.size(); i++) { + _debug_giprobe(p_gi_probes[i], draw_list, opaque_framebuffer, cm, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION, 1.0); } + RD::get_singleton()->draw_command_end_label(); RD::get_singleton()->draw_list_end(); } @@ -1948,7 +1905,9 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor dc.set_depth_correction(true); CameraMatrix cm = (dc * p_cam_projection) * CameraMatrix(p_cam_transform.affine_inverse()); RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, RD::INITIAL_ACTION_CONTINUE, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ); + RD::get_singleton()->draw_command_begin_label("Debug SDFGI"); _debug_sdfgi_probes(p_render_buffer, draw_list, opaque_framebuffer, cm); + RD::get_singleton()->draw_command_end_label(); RD::get_singleton()->draw_list_end(); } @@ -1961,30 +1920,35 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor correction.set_depth_correction(true); projection = correction * p_cam_projection; } - + RD::get_singleton()->draw_command_begin_label("Draw Sky"); _draw_sky(can_continue_color, can_continue_depth, opaque_framebuffer, p_environment, projection, p_cam_transform); + RD::get_singleton()->draw_command_end_label(); } if (render_buffer && !can_continue_color && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { - RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color, true); + RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color); if (using_separate_specular) { - RD::get_singleton()->texture_resolve_multisample(render_buffer->specular_msaa, render_buffer->specular, true); + RD::get_singleton()->texture_resolve_multisample(render_buffer->specular_msaa, render_buffer->specular); } } if (render_buffer && !can_continue_depth && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { - RD::get_singleton()->texture_resolve_multisample(render_buffer->depth_msaa, render_buffer->depth, true); + RD::get_singleton()->texture_resolve_multisample(render_buffer->depth_msaa, render_buffer->depth); } if (using_separate_specular) { if (using_sss) { RENDER_TIMESTAMP("Sub Surface Scattering"); + RD::get_singleton()->draw_command_begin_label("Process Sub Surface Scattering"); _process_sss(p_render_buffer, p_cam_projection); + RD::get_singleton()->draw_command_end_label(); } if (using_ssr) { RENDER_TIMESTAMP("Screen Space Reflection"); + RD::get_singleton()->draw_command_begin_label("Process Screen Space Reflections"); _process_ssr(p_render_buffer, render_buffer->color_fb, render_buffer->normal_roughness_buffer, render_buffer->specular, render_buffer->specular, Color(0, 0, 0, 1), p_environment, p_cam_projection, render_buffer->msaa == RS::VIEWPORT_MSAA_DISABLED); + RD::get_singleton()->draw_command_end_label(); } else { //just mix specular back RENDER_TIMESTAMP("Merge Specular"); @@ -1994,115 +1958,161 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor RENDER_TIMESTAMP("Render Transparent Pass"); - _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), false); + RD::get_singleton()->draw_command_begin_label("Render Transparent Pass"); - render_list.sort_by_reverse_depth_and_priority(true); + rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_buffer, radiance_texture, p_shadow_atlas, p_reflection_atlas, p_cluster_buffer, p_gi_probes, p_lightmaps, true); - _fill_instances(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false, using_sdfgi); + _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_size, p_cluster_size, p_max_cluster_elements, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), false); { - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(alpha_framebuffer), &render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false, PASS_MODE_COLOR, render_buffer == nullptr, radiance_uniform_set, render_buffers_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME); - RD::get_singleton()->draw_list_end(); + RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), false, PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold); + _render_list_with_threads(&render_list_params, alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); } + RD::get_singleton()->draw_command_end_label(); + + RD::get_singleton()->draw_command_begin_label("Resolve"); + if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { - RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color, true); + RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color); } -} -void RasterizerSceneHighEndRD::_render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake) { - RENDER_TIMESTAMP("Setup Rendering Shadow"); + RD::get_singleton()->draw_command_end_label(); +} +void RendererSceneRenderForward::_render_shadow_begin() { + scene_state.shadow_passes.clear(); + RD::get_singleton()->draw_command_begin_label("Shadow Setup"); _update_render_base_uniform_set(); - render_pass++; + render_list[RENDER_LIST_SECONDARY].clear(); + scene_state.instance_data[RENDER_LIST_SECONDARY].clear(); +} +void RendererSceneRenderForward::_render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end) { + uint32_t shadow_pass_index = scene_state.shadow_passes.size(); + + SceneState::ShadowPass shadow_pass; scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1; - _setup_environment(RID(), RID(), p_projection, p_transform, RID(), true, Vector2(1, 1), RID(), true, Color(), 0, p_zfar, false, p_use_pancake); + _setup_environment(RID(), RID(), p_projection, p_transform, RID(), true, Vector2(1, 1), 1, 32, RID(), !p_flip_y, Color(), 0, p_zfar, false, p_use_pancake, shadow_pass_index); - render_list.clear(); + if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) { + p_screen_lod_threshold = 0.0; + } PassMode pass_mode = p_use_dp ? PASS_MODE_SHADOW_DP : PASS_MODE_SHADOW; - _fill_render_list(p_cull_result, p_cull_count, pass_mode); + uint32_t render_list_from = render_list[RENDER_LIST_SECONDARY].elements.size(); + _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, p_projection, p_transform, false, false, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold, true); + uint32_t render_list_size = render_list[RENDER_LIST_SECONDARY].elements.size() - render_list_from; + render_list[RENDER_LIST_SECONDARY].sort_by_key_range(render_list_from, render_list_size); + _fill_instance_data(RENDER_LIST_SECONDARY, render_list_from, render_list_size, false); - _setup_view_dependant_uniform_set(RID(), RID(), nullptr, 0); + { + //regular forward for now + bool flip_cull = p_use_dp_flip; + if (p_flip_y) { + flip_cull = !flip_cull; + } - RENDER_TIMESTAMP("Render Shadow"); + shadow_pass.element_from = render_list_from; + shadow_pass.element_count = render_list_size; + shadow_pass.flip_cull = flip_cull; + shadow_pass.pass_mode = pass_mode; - render_list.sort_by_key(false); + shadow_pass.rp_uniform_set = RID(); //will be filled later when instance buffer is complete + shadow_pass.camera_plane = p_camera_plane; + shadow_pass.screen_lod_threshold = p_screen_lod_threshold; + shadow_pass.lod_distance_multiplier = p_lod_distance_multiplier; - _fill_instances(render_list.elements, render_list.element_count, true); + shadow_pass.framebuffer = p_framebuffer; + shadow_pass.initial_depth_action = p_begin ? (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION : RD::INITIAL_ACTION_CLEAR) : (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION_CONTINUE : RD::INITIAL_ACTION_CONTINUE); + shadow_pass.final_depth_action = p_end ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE; + shadow_pass.rect = p_rect; - { - //regular forward for now - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, p_use_dp_flip, pass_mode, true, RID(), RID()); - RD::get_singleton()->draw_list_end(); + scene_state.shadow_passes.push_back(shadow_pass); } } -void RasterizerSceneHighEndRD::_render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, InstanceBase **p_cull_result, int p_cull_count) { - RENDER_TIMESTAMP("Setup Render Collider Heightfield"); +void RendererSceneRenderForward::_render_shadow_process() { + _update_instance_data_buffer(RENDER_LIST_SECONDARY); + //render shadows one after the other, so this can be done un-barriered and the driver can optimize (as well as allow us to run compute at the same time) - _update_render_base_uniform_set(); + for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) { + //render passes need to be configured after instance buffer is done, since they need the latest version + SceneState::ShadowPass &shadow_pass = scene_state.shadow_passes[i]; + shadow_pass.rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, RID(), RID(), RID(), RID(), RID(), PagedArray<RID>(), PagedArray<RID>(), false, i); + } - render_pass++; + RD::get_singleton()->draw_command_end_label(); +} +void RendererSceneRenderForward::_render_shadow_end(uint32_t p_barrier) { + RD::get_singleton()->draw_command_begin_label("Shadow Render"); - scene_state.ubo.dual_paraboloid_side = 0; + for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) { + SceneState::ShadowPass &shadow_pass = scene_state.shadow_passes[i]; + RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, true, shadow_pass.rp_uniform_set, false, Vector2(), shadow_pass.camera_plane, shadow_pass.lod_distance_multiplier, shadow_pass.screen_lod_threshold, shadow_pass.element_from, RD::BARRIER_MASK_NO_BARRIER); + _render_list_with_threads(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, shadow_pass.final_depth_action, Vector<Color>(), 1.0, 0, shadow_pass.rect); + } - _setup_environment(RID(), RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), RID(), true, Color(), 0, p_cam_projection.get_z_far(), false, false); + if (p_barrier != RD::BARRIER_MASK_NO_BARRIER) { + RD::get_singleton()->barrier(RD::BARRIER_MASK_RASTER, p_barrier); + } + RD::get_singleton()->draw_command_end_label(); +} - render_list.clear(); +void RendererSceneRenderForward::_render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) { + RENDER_TIMESTAMP("Setup Render Collider Heightfield"); - PassMode pass_mode = PASS_MODE_SHADOW; + RD::get_singleton()->draw_command_begin_label("Render Collider Heightfield"); + + _update_render_base_uniform_set(); + scene_state.ubo.dual_paraboloid_side = 0; - _fill_render_list(p_cull_result, p_cull_count, pass_mode); + _setup_environment(RID(), RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), 1, 32, RID(), true, Color(), 0, p_cam_projection.get_z_far(), false, false); - _setup_view_dependant_uniform_set(RID(), RID(), nullptr, 0); + PassMode pass_mode = PASS_MODE_SHADOW; - RENDER_TIMESTAMP("Render Collider Heightield"); + _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, p_cam_projection, p_cam_transform); + render_list[RENDER_LIST_SECONDARY].sort_by_key(); + _fill_instance_data(RENDER_LIST_SECONDARY); - render_list.sort_by_key(false); + RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, RID(), RID(), RID(), RID(), RID(), PagedArray<RID>(), PagedArray<RID>()); - _fill_instances(render_list.elements, render_list.element_count, true); + RENDER_TIMESTAMP("Render Collider Heightfield"); { //regular forward for now - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_fb), render_list.elements, render_list.element_count, false, pass_mode, true, RID(), RID()); - RD::get_singleton()->draw_list_end(); + RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), false, pass_mode, true, rp_uniform_set); + _render_list_with_threads(&render_list_params, p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ); } + RD::get_singleton()->draw_command_end_label(); } -void RasterizerSceneHighEndRD::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) { +void RendererSceneRenderForward::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) { RENDER_TIMESTAMP("Setup Rendering Material"); - _update_render_base_uniform_set(); + RD::get_singleton()->draw_command_begin_label("Render Material"); - render_pass++; + _update_render_base_uniform_set(); scene_state.ubo.dual_paraboloid_side = 0; - scene_state.ubo.material_uv2_mode = true; - - _setup_environment(RID(), RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), RID(), false, Color(), 0, 0); + scene_state.ubo.material_uv2_mode = false; - render_list.clear(); + _setup_environment(RID(), RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), 1, 32, RID(), false, Color(), 0, 0); PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL; - _fill_render_list(p_cull_result, p_cull_count, pass_mode); + _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, p_cam_projection, p_cam_transform); + render_list[RENDER_LIST_SECONDARY].sort_by_key(); + _fill_instance_data(RENDER_LIST_SECONDARY); - _setup_view_dependant_uniform_set(RID(), RID(), nullptr, 0); + RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, RID(), RID(), RID(), RID(), RID(), PagedArray<RID>(), PagedArray<RID>()); RENDER_TIMESTAMP("Render Material"); - render_list.sort_by_key(false); - - _fill_instances(render_list.elements, render_list.element_count, true); - { + RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, true, rp_uniform_set); //regular forward for now Vector<Color> clear; clear.push_back(Color(0, 0, 0, 0)); @@ -2111,37 +2121,36 @@ void RasterizerSceneHighEndRD::_render_material(const Transform &p_cam_transform clear.push_back(Color(0, 0, 0, 0)); clear.push_back(Color(0, 0, 0, 0)); RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, true, pass_mode, true, RID(), RID()); + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); RD::get_singleton()->draw_list_end(); } + + RD::get_singleton()->draw_command_end_label(); } -void RasterizerSceneHighEndRD::_render_uv2(InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) { +void RendererSceneRenderForward::_render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) { RENDER_TIMESTAMP("Setup Rendering UV2"); - _update_render_base_uniform_set(); + RD::get_singleton()->draw_command_begin_label("Render UV2"); - render_pass++; + _update_render_base_uniform_set(); scene_state.ubo.dual_paraboloid_side = 0; scene_state.ubo.material_uv2_mode = true; - _setup_environment(RID(), RID(), CameraMatrix(), Transform(), RID(), true, Vector2(1, 1), RID(), false, Color(), 0, 0); - - render_list.clear(); + _setup_environment(RID(), RID(), CameraMatrix(), Transform(), RID(), true, Vector2(1, 1), 1, 32, RID(), false, Color(), 0, 0); PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL; - _fill_render_list(p_cull_result, p_cull_count, pass_mode); + _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, CameraMatrix(), Transform()); + render_list[RENDER_LIST_SECONDARY].sort_by_key(); + _fill_instance_data(RENDER_LIST_SECONDARY); - _setup_view_dependant_uniform_set(RID(), RID(), nullptr, 0); + RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, RID(), RID(), RID(), RID(), RID(), PagedArray<RID>(), PagedArray<RID>()); RENDER_TIMESTAMP("Render Material"); - render_list.sort_by_key(false); - - _fill_instances(render_list.elements, render_list.element_count, true); - { + RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, true, rp_uniform_set, true); //regular forward for now Vector<Color> clear; clear.push_back(Color(0, 0, 0, 0)); @@ -2169,69 +2178,36 @@ void RasterizerSceneHighEndRD::_render_uv2(InstanceBase **p_cull_result, int p_c Vector2 ofs = uv_offsets[i]; ofs.x /= p_region.size.width; ofs.y /= p_region.size.height; - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, true, pass_mode, true, RID(), RID(), true, ofs); //first wireframe, for pseudo conservative + render_list_params.uv_offset = ofs; + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //first wireframe, for pseudo conservative } - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, true, pass_mode, true, RID(), RID(), false); //second regular triangles + render_list_params.uv_offset = Vector2(); + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //second regular triangles RD::get_singleton()->draw_list_end(); } + + RD::get_singleton()->draw_command_end_label(); } -void RasterizerSceneHighEndRD::_render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, InstanceBase **p_cull_result, int p_cull_count, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) { +void RendererSceneRenderForward::_render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) { RENDER_TIMESTAMP("Render SDFGI"); + RD::get_singleton()->draw_command_begin_label("Render SDFGI Voxel"); + _update_render_base_uniform_set(); - RenderBufferDataHighEnd *render_buffer = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers); + RenderBufferDataForward *render_buffer = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); ERR_FAIL_COND(!render_buffer); - render_pass++; - render_list.clear(); - PassMode pass_mode = PASS_MODE_SDF; - _fill_render_list(p_cull_result, p_cull_count, pass_mode); - render_list.sort_by_key(false); - _fill_instances(render_list.elements, render_list.element_count, true); - - _setup_view_dependant_uniform_set(RID(), RID(), nullptr, 0); + _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, CameraMatrix(), Transform()); + render_list[RENDER_LIST_SECONDARY].sort_by_key(); + _fill_instance_data(RENDER_LIST_SECONDARY); Vector3 half_extents = p_bounds.size * 0.5; Vector3 center = p_bounds.position + half_extents; - if (render_buffer->render_sdfgi_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_buffer->render_sdfgi_uniform_set)) { - Vector<RD::Uniform> uniforms; - { - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 0; - u.ids.push_back(p_albedo_texture); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 1; - u.ids.push_back(p_emission_texture); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 2; - u.ids.push_back(p_emission_aniso_texture); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 3; - u.ids.push_back(p_geom_facing_texture); - uniforms.push_back(u); - } - - render_buffer->render_sdfgi_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_sdfgi_rd, RENDER_BUFFERS_UNIFORM_SET); - } - Vector<RID> sbs; sbs.push_back(p_albedo_texture); sbs.push_back(p_emission_texture); @@ -2276,9 +2252,11 @@ void RasterizerSceneHighEndRD::_render_sdfgi(RID p_render_buffers, const Vector3 to_bounds.origin = p_bounds.position; to_bounds.basis.scale(p_bounds.size); - RasterizerStorageRD::store_transform(to_bounds.affine_inverse() * cam_xform, scene_state.ubo.sdf_to_bounds); + RendererStorageRD::store_transform(to_bounds.affine_inverse() * cam_xform, scene_state.ubo.sdf_to_bounds); - _setup_environment(RID(), RID(), camera_proj, cam_xform, RID(), true, Vector2(1, 1), RID(), false, Color(), 0, 0); + _setup_environment(RID(), RID(), camera_proj, cam_xform, RID(), true, Vector2(1, 1), 1, 32, RID(), false, Color(), 0, 0); + + RID rp_uniform_set = _setup_sdfgi_render_pass_uniform_set(p_albedo_texture, p_emission_texture, p_emission_aniso_texture, p_geom_facing_texture); Map<Size2i, RID>::Element *E = sdfgi_framebuffer_size_cache.find(fb_size); if (!E) { @@ -2286,20 +2264,21 @@ void RasterizerSceneHighEndRD::_render_sdfgi(RID p_render_buffers, const Vector3 E = sdfgi_framebuffer_size_cache.insert(fb_size, fb); } - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(E->get(), RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, Rect2(), sbs); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(E->get()), render_list.elements, render_list.element_count, true, pass_mode, true, RID(), render_buffer->render_sdfgi_uniform_set, false); //second regular triangles - RD::get_singleton()->draw_list_end(); + RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, true, rp_uniform_set, false); + _render_list_with_threads(&render_list_params, E->get(), RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, Rect2(), sbs); } + + RD::get_singleton()->draw_command_end_label(); } -void RasterizerSceneHighEndRD::_base_uniforms_changed() { +void RendererSceneRenderForward::_base_uniforms_changed() { if (!render_base_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) { RD::get_singleton()->free(render_base_uniform_set); } render_base_uniform_set = RID(); } -void RasterizerSceneHighEndRD::_update_render_base_uniform_set() { +void RendererSceneRenderForward::_update_render_base_uniform_set() { if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != storage->lightmap_array_get_version())) { if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) { RD::get_singleton()->free(render_base_uniform_set); @@ -2311,7 +2290,7 @@ void RasterizerSceneHighEndRD::_update_render_base_uniform_set() { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 1; u.ids.resize(12); RID *ids_ptr = u.ids.ptrw(); @@ -2333,7 +2312,7 @@ void RasterizerSceneHighEndRD::_update_render_base_uniform_set() { { RD::Uniform u; u.binding = 2; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.ids.push_back(shadow_sampler); uniforms.push_back(u); } @@ -2341,124 +2320,82 @@ void RasterizerSceneHighEndRD::_update_render_base_uniform_set() { { RD::Uniform u; u.binding = 3; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.ids.push_back(scene_state.uniform_buffer); + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(get_omni_light_buffer()); uniforms.push_back(u); } { RD::Uniform u; u.binding = 4; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.ids.push_back(scene_state.instance_buffer); + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(get_spot_light_buffer()); uniforms.push_back(u); } { RD::Uniform u; u.binding = 5; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.ids.push_back(get_positional_light_buffer()); - uniforms.push_back(u); - } - - { - RD::Uniform u; - u.binding = 6; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(get_reflection_probe_buffer()); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 7; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 6; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.ids.push_back(get_directional_light_buffer()); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 10; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 7; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(scene_state.lightmap_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 11; - u.type = RD::UNIFORM_TYPE_TEXTURE; - u.ids = storage->lightmap_array_get_textures(); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 12; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 8; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(scene_state.lightmap_capture_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 13; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 9; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID decal_atlas = storage->decal_atlas_get_texture(); u.ids.push_back(decal_atlas); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 14; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 10; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID decal_atlas = storage->decal_atlas_get_texture_srgb(); u.ids.push_back(decal_atlas); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 15; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 11; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(get_decal_buffer()); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 16; - u.type = RD::UNIFORM_TYPE_TEXTURE; - u.ids.push_back(get_cluster_builder_texture()); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 17; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.ids.push_back(get_cluster_builder_indices_buffer()); - uniforms.push_back(u); - } - - { - RD::Uniform u; - u.binding = 18; - u.type = RD::UNIFORM_TYPE_TEXTURE; - if (directional_shadow_get_texture().is_valid()) { - u.ids.push_back(directional_shadow_get_texture()); - } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE)); - } - uniforms.push_back(u); - } - - { - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.binding = 19; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 12; u.ids.push_back(storage->global_variables_get_storage_buffer()); uniforms.push_back(u); } - { + if (!low_end) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.binding = 20; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 13; u.ids.push_back(sdfgi_get_ubo()); uniforms.push_back(u); } @@ -2467,9 +2404,13 @@ void RasterizerSceneHighEndRD::_update_render_base_uniform_set() { } } -void RasterizerSceneHighEndRD::_setup_view_dependant_uniform_set(RID p_shadow_atlas, RID p_reflection_atlas, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count) { - if (view_dependant_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(view_dependant_uniform_set)) { - RD::get_singleton()->free(view_dependant_uniform_set); +RID RendererSceneRenderForward::_setup_render_pass_uniform_set(RenderListType p_render_list, RID p_render_buffers, RID p_radiance_texture, RID p_shadow_atlas, RID p_reflection_atlas, RID p_cluster_buffer, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, bool p_use_directional_shadow_atlas, int p_index) { + //there should always be enough uniform buffers for render passes, otherwise bugs + ERR_FAIL_INDEX_V(p_index, (int)scene_state.uniform_buffers.size(), RID()); + + RenderBufferDataForward *rb = nullptr; + if (p_render_buffers.is_valid()) { + rb = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); } //default render buffer and scene state uniform set @@ -2477,211 +2418,930 @@ void RasterizerSceneHighEndRD::_setup_view_dependant_uniform_set(RID p_shadow_at Vector<RD::Uniform> uniforms; { - RID ref_texture = p_reflection_atlas.is_valid() ? reflection_atlas_get_texture(p_reflection_atlas) : RID(); RD::Uniform u; u.binding = 0; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.ids.push_back(scene_state.uniform_buffers[p_index]); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 1; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + RID instance_buffer = scene_state.instance_buffer[p_render_list]; + if (instance_buffer == RID()) { + instance_buffer = default_vec4_xform_buffer; // any buffer will do since its not used + } + u.ids.push_back(instance_buffer); + uniforms.push_back(u); + } + { + RID radiance_texture; + if (p_radiance_texture.is_valid()) { + radiance_texture = p_radiance_texture; + } else { + radiance_texture = storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK); + } + RD::Uniform u; + u.binding = 2; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.push_back(radiance_texture); + uniforms.push_back(u); + } + + { + RID ref_texture = p_reflection_atlas.is_valid() ? reflection_atlas_get_texture(p_reflection_atlas) : RID(); + RD::Uniform u; + u.binding = 3; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; if (ref_texture.is_valid()) { u.ids.push_back(ref_texture); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK)); } uniforms.push_back(u); } { RD::Uniform u; - u.binding = 1; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 4; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID texture; if (p_shadow_atlas.is_valid()) { texture = shadow_atlas_get_texture(p_shadow_atlas); } if (!texture.is_valid()) { - texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE); + texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); } u.ids.push_back(texture); uniforms.push_back(u); } + { + RD::Uniform u; + u.binding = 5; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + if (p_use_directional_shadow_atlas && directional_shadow_get_texture().is_valid()) { + u.ids.push_back(directional_shadow_get_texture()); + } else { + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE)); + } + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 6; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.resize(scene_state.max_lightmaps); + RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); + for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) { + if (i < p_lightmaps.size()) { + RID base = lightmap_instance_get_lightmap(p_lightmaps[i]); + RID texture = storage->lightmap_get_texture(base); + RID rd_texture = storage->texture_get_rd_texture(texture); + u.ids.write[i] = rd_texture; + } else { + u.ids.write[i] = default_tex; + } + } + uniforms.push_back(u); + } { RD::Uniform u; - u.binding = 2; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID default_tex = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); + u.binding = 7; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.resize(MAX_GI_PROBES); + RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); for (int i = 0; i < MAX_GI_PROBES; i++) { - if (i < p_gi_probe_cull_count) { - RID tex = gi_probe_instance_get_texture(p_gi_probe_cull_result[i]); + if (i < (int)p_gi_probes.size()) { + RID tex = gi_probe_instance_get_texture(p_gi_probes[i]); if (!tex.is_valid()) { tex = default_tex; } - u.ids.push_back(tex); + u.ids.write[i] = tex; } else { - u.ids.push_back(default_tex); + u.ids.write[i] = default_tex; } } uniforms.push_back(u); } - view_dependant_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, VIEW_DEPENDANT_UNIFORM_SET); -} -void RasterizerSceneHighEndRD::_render_buffers_clear_uniform_set(RenderBufferDataHighEnd *rb) { - if (!rb->uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(rb->uniform_set)) { - RD::get_singleton()->free(rb->uniform_set); + { + RD::Uniform u; + u.binding = 8; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + RID cb = p_cluster_buffer.is_valid() ? p_cluster_buffer : default_vec4_xform_buffer; + u.ids.push_back(cb); + uniforms.push_back(u); } - rb->uniform_set = RID(); -} - -void RasterizerSceneHighEndRD::_render_buffers_uniform_set_changed(RID p_render_buffers) { - RenderBufferDataHighEnd *rb = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers); - - _render_buffers_clear_uniform_set(rb); -} - -RID RasterizerSceneHighEndRD::_render_buffers_get_normal_texture(RID p_render_buffers) { - RenderBufferDataHighEnd *rb = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers); - - return rb->normal_roughness_buffer; -} - -RID RasterizerSceneHighEndRD::_render_buffers_get_ambient_texture(RID p_render_buffers) { - RenderBufferDataHighEnd *rb = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers); - - return rb->ambient_buffer; -} - -RID RasterizerSceneHighEndRD::_render_buffers_get_reflection_texture(RID p_render_buffers) { - RenderBufferDataHighEnd *rb = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers); - - return rb->reflection_buffer; -} -void RasterizerSceneHighEndRD::_update_render_buffers_uniform_set(RID p_render_buffers) { - RenderBufferDataHighEnd *rb = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers); + { + RD::Uniform u; + u.binding = 9; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID texture = (false && rb && rb->depth.is_valid()) ? rb->depth : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); + u.ids.push_back(texture); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 10; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID bbt = rb ? render_buffers_get_back_buffer_texture(p_render_buffers) : RID(); + RID texture = bbt.is_valid() ? bbt : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); + u.ids.push_back(texture); + uniforms.push_back(u); + } - if (rb->uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->uniform_set)) { - Vector<RD::Uniform> uniforms; - { - RD::Uniform u; - u.binding = 0; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = false && rb->depth.is_valid() ? rb->depth : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE); - u.ids.push_back(texture); - uniforms.push_back(u); - } + if (!low_end) { { RD::Uniform u; - u.binding = 1; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID bbt = render_buffers_get_back_buffer_texture(p_render_buffers); - RID texture = bbt.is_valid() ? bbt : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK); - u.ids.push_back(texture); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 2; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = rb->normal_roughness_buffer.is_valid() ? rb->normal_roughness_buffer : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_NORMAL); + u.binding = 11; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID texture = rb && rb->normal_roughness_buffer.is_valid() ? rb->normal_roughness_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_NORMAL); u.ids.push_back(texture); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 4; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID aot = render_buffers_get_ao_texture(p_render_buffers); - RID texture = aot.is_valid() ? aot : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK); + u.binding = 12; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID aot = rb ? render_buffers_get_ao_texture(p_render_buffers) : RID(); + RID texture = aot.is_valid() ? aot : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); u.ids.push_back(texture); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 5; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = rb->ambient_buffer.is_valid() ? rb->ambient_buffer : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK); + u.binding = 13; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID ambient_buffer = p_render_buffers.is_valid() ? render_buffers_get_gi_ambient_texture(p_render_buffers) : RID(); + RID texture = ambient_buffer.is_valid() ? ambient_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); u.ids.push_back(texture); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 6; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = rb->reflection_buffer.is_valid() ? rb->reflection_buffer : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK); + u.binding = 14; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID reflection_buffer = p_render_buffers.is_valid() ? render_buffers_get_gi_reflection_texture(p_render_buffers) : RID(); + RID texture = reflection_buffer.is_valid() ? reflection_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); u.ids.push_back(texture); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 7; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 15; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID t; - if (render_buffers_is_sdfgi_enabled(p_render_buffers)) { + if (rb && render_buffers_is_sdfgi_enabled(p_render_buffers)) { t = render_buffers_get_sdfgi_irradiance_probes(p_render_buffers); } else { - t = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); + t = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); } u.ids.push_back(t); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 8; - u.type = RD::UNIFORM_TYPE_TEXTURE; - if (render_buffers_is_sdfgi_enabled(p_render_buffers)) { + u.binding = 16; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + if (rb && render_buffers_is_sdfgi_enabled(p_render_buffers)) { u.ids.push_back(render_buffers_get_sdfgi_occlusion_texture(p_render_buffers)); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } uniforms.push_back(u); } { RD::Uniform u; - u.binding = 9; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.ids.push_back(render_buffers_get_gi_probe_buffer(p_render_buffers)); + u.binding = 17; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.ids.push_back(rb ? render_buffers_get_gi_probe_buffer(p_render_buffers) : render_buffers_get_default_gi_probe_buffer()); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 10; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 18; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID vfog = RID(); - if (p_render_buffers.is_valid() && render_buffers_has_volumetric_fog(p_render_buffers)) { + if (rb && render_buffers_has_volumetric_fog(p_render_buffers)) { vfog = render_buffers_get_volumetric_fog_texture(p_render_buffers); if (vfog.is_null()) { - vfog = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); + vfog = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); } } else { - vfog = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); + vfog = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); } u.ids.push_back(vfog); uniforms.push_back(u); } - rb->uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RENDER_BUFFERS_UNIFORM_SET); } + + if (p_index >= (int)render_pass_uniform_sets.size()) { + render_pass_uniform_sets.resize(p_index + 1); + } + + if (render_pass_uniform_sets[p_index].is_valid() && RD::get_singleton()->uniform_set_is_valid(render_pass_uniform_sets[p_index])) { + RD::get_singleton()->free(render_pass_uniform_sets[p_index]); + } + + render_pass_uniform_sets[p_index] = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RENDER_PASS_UNIFORM_SET); + return render_pass_uniform_sets[p_index]; +} + +RID RendererSceneRenderForward::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture) { + if (sdfgi_pass_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sdfgi_pass_uniform_set)) { + RD::get_singleton()->free(sdfgi_pass_uniform_set); + } + + Vector<RD::Uniform> uniforms; + + { + RD::Uniform u; + u.binding = 0; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.ids.push_back(scene_state.uniform_buffers[0]); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 1; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(scene_state.instance_buffer[RENDER_LIST_SECONDARY]); + uniforms.push_back(u); + } + { + // No radiance texture. + RID radiance_texture = storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK); + RD::Uniform u; + u.binding = 2; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.push_back(radiance_texture); + uniforms.push_back(u); + } + + { + // No reflection atlas. + RID ref_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK); + RD::Uniform u; + u.binding = 3; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.push_back(ref_texture); + uniforms.push_back(u); + } + + { + // No shadow atlas. + RD::Uniform u; + u.binding = 4; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); + u.ids.push_back(texture); + uniforms.push_back(u); + } + + { + // No directional shadow atlas. + RD::Uniform u; + u.binding = 5; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); + u.ids.push_back(texture); + uniforms.push_back(u); + } + + { + // No Lightmaps + RD::Uniform u; + u.binding = 6; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.resize(scene_state.max_lightmaps); + RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); + for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) { + u.ids.write[i] = default_tex; + } + + uniforms.push_back(u); + } + + { + // No GIProbes + RD::Uniform u; + u.binding = 7; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.resize(MAX_GI_PROBES); + RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); + for (int i = 0; i < MAX_GI_PROBES; i++) { + u.ids.write[i] = default_tex; + } + + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.binding = 8; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + RID cb = default_vec4_xform_buffer; + u.ids.push_back(cb); + uniforms.push_back(u); + } + + // actual sdfgi stuff + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 9; + u.ids.push_back(p_albedo_texture); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 10; + u.ids.push_back(p_emission_texture); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 11; + u.ids.push_back(p_emission_aniso_texture); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 12; + u.ids.push_back(p_geom_facing_texture); + uniforms.push_back(u); + } + + sdfgi_pass_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_sdfgi_rd, RENDER_PASS_UNIFORM_SET); + return sdfgi_pass_uniform_set; +} + +void RendererSceneRenderForward::_render_buffers_clear_uniform_set(RenderBufferDataForward *rb) { } -RasterizerSceneHighEndRD *RasterizerSceneHighEndRD::singleton = nullptr; +void RendererSceneRenderForward::_render_buffers_uniform_set_changed(RID p_render_buffers) { + RenderBufferDataForward *rb = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); + + _render_buffers_clear_uniform_set(rb); +} -void RasterizerSceneHighEndRD::set_time(double p_time, double p_step) { +RID RendererSceneRenderForward::_render_buffers_get_normal_texture(RID p_render_buffers) { + RenderBufferDataForward *rb = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); + + return rb->normal_roughness_buffer; +} + +RendererSceneRenderForward *RendererSceneRenderForward::singleton = nullptr; + +void RendererSceneRenderForward::set_time(double p_time, double p_step) { time = p_time; - RasterizerSceneRD::set_time(p_time, p_step); + RendererSceneRenderRD::set_time(p_time, p_step); +} + +void RendererSceneRenderForward::_geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + if (ginstance->dirty_list_element.in_list()) { + return; + } + + //clear surface caches + GeometryInstanceSurfaceDataCache *surf = ginstance->surface_caches; + + while (surf) { + GeometryInstanceSurfaceDataCache *next = surf->next; + geometry_instance_surface_alloc.free(surf); + surf = next; + } + + ginstance->surface_caches = nullptr; + + geometry_instance_dirty_list.add(&ginstance->dirty_list_element); } -RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storage) : - RasterizerSceneRD(p_storage) { +void RendererSceneRenderForward::_geometry_instance_add_surface_with_material(GeometryInstanceForward *ginstance, uint32_t p_surface, MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh) { + bool has_read_screen_alpha = p_material->shader_data->uses_screen_texture || p_material->shader_data->uses_depth_texture || p_material->shader_data->uses_normal_texture; + bool has_base_alpha = (p_material->shader_data->uses_alpha || has_read_screen_alpha); + bool has_blend_alpha = p_material->shader_data->uses_blend_alpha; + bool has_alpha = has_base_alpha || has_blend_alpha; + + uint32_t flags = 0; + + if (p_material->shader_data->uses_sss) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SUBSURFACE_SCATTERING; + } + + if (p_material->shader_data->uses_screen_texture) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SCREEN_TEXTURE; + } + + if (p_material->shader_data->uses_depth_texture) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE; + } + + if (p_material->shader_data->uses_normal_texture) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_NORMAL_TEXTURE; + } + + if (ginstance->data->cast_double_sided_shaodows) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS; + } + + if (has_alpha || has_read_screen_alpha || p_material->shader_data->depth_draw == ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == ShaderData::DEPTH_TEST_DISABLED) { + //material is only meant for alpha pass + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA; + if (p_material->shader_data->uses_depth_pre_pass && !(p_material->shader_data->depth_draw == ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == ShaderData::DEPTH_TEST_DISABLED)) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH; + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW; + } + } else { + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE; + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH; + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW; + } + + MaterialData *material_shadow = nullptr; + void *surface_shadow = nullptr; + if (!p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL; + material_shadow = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D); + + RID shadow_mesh = storage->mesh_get_shadow_mesh(p_mesh); + + if (shadow_mesh.is_valid()) { + surface_shadow = storage->mesh_get_surface(shadow_mesh, p_surface); + } + + } else { + material_shadow = p_material; + } + + GeometryInstanceSurfaceDataCache *sdcache = geometry_instance_surface_alloc.alloc(); + + sdcache->flags = flags; + + sdcache->shader = p_material->shader_data; + sdcache->material_uniform_set = p_material->uniform_set; + sdcache->surface = storage->mesh_get_surface(p_mesh, p_surface); + sdcache->primitive = storage->mesh_surface_get_primitive(sdcache->surface); + sdcache->surface_index = p_surface; + + if (ginstance->data->dirty_dependencies) { + storage->base_update_dependency(p_mesh, &ginstance->data->dependency_tracker); + } + + //shadow + sdcache->shader_shadow = material_shadow->shader_data; + sdcache->material_uniform_set_shadow = material_shadow->uniform_set; + + sdcache->surface_shadow = surface_shadow ? surface_shadow : sdcache->surface; + + sdcache->owner = ginstance; + + sdcache->next = ginstance->surface_caches; + ginstance->surface_caches = sdcache; + + //sortkey + + sdcache->sort.sort_key1 = 0; + sdcache->sort.sort_key2 = 0; + + sdcache->sort.surface_index = p_surface; + sdcache->sort.material_id_low = p_material_id & 0x3FFF; + sdcache->sort.material_id_hi = p_material_id >> 14; + sdcache->sort.shader_id = p_shader_id; + sdcache->sort.geometry_id = p_mesh.get_local_index(); //only meshes can repeat anyway + sdcache->sort.uses_forward_gi = ginstance->can_sdfgi; + sdcache->sort.priority = p_material->priority; +} + +void RendererSceneRenderForward::_geometry_instance_add_surface(GeometryInstanceForward *ginstance, uint32_t p_surface, RID p_material, RID p_mesh) { + RID m_src; + + m_src = ginstance->data->material_override.is_valid() ? ginstance->data->material_override : p_material; + + MaterialData *material = nullptr; + + if (m_src.is_valid()) { + material = (MaterialData *)storage->material_get_data(m_src, RendererStorageRD::SHADER_TYPE_3D); + if (!material || !material->shader_data->valid) { + material = nullptr; + } + } + + if (material) { + if (ginstance->data->dirty_dependencies) { + storage->material_update_dependency(m_src, &ginstance->data->dependency_tracker); + } + } else { + material = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D); + m_src = default_material; + } + + ERR_FAIL_COND(!material); + + _geometry_instance_add_surface_with_material(ginstance, p_surface, material, m_src.get_local_index(), storage->material_get_shader_id(m_src), p_mesh); + + while (material->next_pass.is_valid()) { + RID next_pass = material->next_pass; + material = (MaterialData *)storage->material_get_data(next_pass, RendererStorageRD::SHADER_TYPE_3D); + if (!material || !material->shader_data->valid) { + break; + } + if (ginstance->data->dirty_dependencies) { + storage->material_update_dependency(next_pass, &ginstance->data->dependency_tracker); + } + _geometry_instance_add_surface_with_material(ginstance, p_surface, material, next_pass.get_local_index(), storage->material_get_shader_id(next_pass), p_mesh); + } +} + +void RendererSceneRenderForward::_geometry_instance_update(GeometryInstance *p_geometry_instance) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + + if (ginstance->data->dirty_dependencies) { + ginstance->data->dependency_tracker.update_begin(); + } + + //add geometry for drawing + switch (ginstance->data->base_type) { + case RS::INSTANCE_MESH: { + const RID *materials = nullptr; + uint32_t surface_count; + RID mesh = ginstance->data->base; + + materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count); + if (materials) { + //if no materials, no surfaces. + const RID *inst_materials = ginstance->data->surface_materials.ptr(); + uint32_t surf_mat_count = ginstance->data->surface_materials.size(); + + for (uint32_t j = 0; j < surface_count; j++) { + RID material = (j < surf_mat_count && inst_materials[j].is_valid()) ? inst_materials[j] : materials[j]; + _geometry_instance_add_surface(ginstance, j, material, mesh); + } + } + + ginstance->instance_count = 1; + + } break; + + case RS::INSTANCE_MULTIMESH: { + RID mesh = storage->multimesh_get_mesh(ginstance->data->base); + if (mesh.is_valid()) { + const RID *materials = nullptr; + uint32_t surface_count; + + materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count); + if (materials) { + for (uint32_t j = 0; j < surface_count; j++) { + _geometry_instance_add_surface(ginstance, j, materials[j], mesh); + } + } + + ginstance->instance_count = storage->multimesh_get_instances_to_draw(ginstance->data->base); + } + + } break; +#if 0 + case RS::INSTANCE_IMMEDIATE: { + RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.getornull(inst->base); + ERR_CONTINUE(!immediate); + + _add_geometry(immediate, inst, nullptr, -1, p_depth_pass, p_shadow_pass); + + } break; +#endif + case RS::INSTANCE_PARTICLES: { + int draw_passes = storage->particles_get_draw_passes(ginstance->data->base); + + for (int j = 0; j < draw_passes; j++) { + RID mesh = storage->particles_get_draw_pass_mesh(ginstance->data->base, j); + if (!mesh.is_valid()) + continue; + + const RID *materials = nullptr; + uint32_t surface_count; + + materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count); + if (materials) { + for (uint32_t k = 0; k < surface_count; k++) { + _geometry_instance_add_surface(ginstance, k, materials[k], mesh); + } + } + } + + ginstance->instance_count = storage->particles_get_amount(ginstance->data->base); + + } break; + + default: { + } + } + + //Fill push constant + + bool store_transform = true; + + if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH; + uint32_t stride; + if (storage->multimesh_get_transform_format(ginstance->data->base) == RS::MULTIMESH_TRANSFORM_2D) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D; + stride = 2; + } else { + stride = 3; + } + if (storage->multimesh_uses_colors(ginstance->data->base)) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR; + stride += 1; + } + if (storage->multimesh_uses_custom_data(ginstance->data->base)) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA; + stride += 1; + } + + ginstance->base_flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT); + ginstance->transforms_uniform_set = storage->multimesh_get_3d_uniform_set(ginstance->data->base, default_shader_rd, TRANSFORMS_UNIFORM_SET); + + } else if (ginstance->data->base_type == RS::INSTANCE_PARTICLES) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH; + uint32_t stride; + if (false) { // 2D particles + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D; + stride = 2; + } else { + stride = 3; + } + + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR; + stride += 1; + + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA; + stride += 1; + + ginstance->base_flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT); + + if (!storage->particles_is_using_local_coords(ginstance->data->base)) { + store_transform = false; + } + ginstance->transforms_uniform_set = storage->particles_get_instance_buffer_uniform_set(ginstance->data->base, default_shader_rd, TRANSFORMS_UNIFORM_SET); + + } else if (ginstance->data->base_type == RS::INSTANCE_MESH) { + if (storage->skeleton_is_valid(ginstance->data->skeleton)) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_SKELETON; + ginstance->transforms_uniform_set = storage->skeleton_get_3d_uniform_set(ginstance->data->skeleton, default_shader_rd, TRANSFORMS_UNIFORM_SET); + if (ginstance->data->dirty_dependencies) { + storage->skeleton_update_dependency(ginstance->data->skeleton, &ginstance->data->dependency_tracker); + } + } + } + + ginstance->store_transform_cache = store_transform; + ginstance->can_sdfgi = false; + + if (!lightmap_instance_is_valid(ginstance->lightmap_instance) && !low_end) { + if (ginstance->gi_probes[0].is_null() && (ginstance->data->use_baked_light || ginstance->data->use_dynamic_gi)) { + ginstance->can_sdfgi = true; + } + } + + if (ginstance->data->dirty_dependencies) { + ginstance->data->dependency_tracker.update_end(); + ginstance->data->dirty_dependencies = false; + } + + ginstance->dirty_list_element.remove_from_list(); +} + +void RendererSceneRenderForward::_update_dirty_geometry_instances() { + while (geometry_instance_dirty_list.first()) { + _geometry_instance_update(geometry_instance_dirty_list.first()->self()); + } +} + +void RendererSceneRenderForward::_geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker) { + switch (p_notification) { + case RendererStorage::DEPENDENCY_CHANGED_MATERIAL: + case RendererStorage::DEPENDENCY_CHANGED_MESH: + case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH: + case RendererStorage::DEPENDENCY_CHANGED_SKELETON_DATA: { + static_cast<RendererSceneRenderForward *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata)); + } break; + case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES: { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_tracker->userdata); + if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) { + ginstance->instance_count = static_cast<RendererSceneRenderForward *>(singleton)->storage->multimesh_get_instances_to_draw(ginstance->data->base); + } + } break; + default: { + //rest of notifications of no interest + } break; + } +} +void RendererSceneRenderForward::_geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker) { + static_cast<RendererSceneRenderForward *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata)); +} + +RendererSceneRender::GeometryInstance *RendererSceneRenderForward::geometry_instance_create(RID p_base) { + RS::InstanceType type = storage->get_base_type(p_base); + ERR_FAIL_COND_V(!((1 << type) & RS::INSTANCE_GEOMETRY_MASK), nullptr); + + GeometryInstanceForward *ginstance = geometry_instance_alloc.alloc(); + ginstance->data = memnew(GeometryInstanceForward::Data); + + ginstance->data->base = p_base; + ginstance->data->base_type = type; + ginstance->data->dependency_tracker.userdata = ginstance; + ginstance->data->dependency_tracker.changed_callback = _geometry_instance_dependency_changed; + ginstance->data->dependency_tracker.deleted_callback = _geometry_instance_dependency_deleted; + + _geometry_instance_mark_dirty(ginstance); + + return ginstance; +} +void RendererSceneRenderForward::geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->skeleton = p_skeleton; + _geometry_instance_mark_dirty(ginstance); + ginstance->data->dirty_dependencies = true; +} +void RendererSceneRenderForward::geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->material_override = p_override; + _geometry_instance_mark_dirty(ginstance); + ginstance->data->dirty_dependencies = true; +} +void RendererSceneRenderForward::geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->surface_materials = p_materials; + _geometry_instance_mark_dirty(ginstance); + ginstance->data->dirty_dependencies = true; +} +void RendererSceneRenderForward::geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->mesh_instance = p_mesh_instance; + _geometry_instance_mark_dirty(ginstance); +} +void RendererSceneRenderForward::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->transform = p_transform; + ginstance->mirror = p_transform.basis.determinant() < 0; + ginstance->data->aabb = p_aabb; + ginstance->transformed_aabb = p_transformed_aabb; + + Vector3 model_scale_vec = p_transform.basis.get_scale_abs(); + // handle non uniform scale here + + float max_scale = MAX(model_scale_vec.x, MAX(model_scale_vec.y, model_scale_vec.z)); + float min_scale = MIN(model_scale_vec.x, MIN(model_scale_vec.y, model_scale_vec.z)); + ginstance->non_uniform_scale = max_scale >= 0.0 && (min_scale / max_scale) < 0.9; + + ginstance->lod_model_scale = max_scale; +} +void RendererSceneRenderForward::geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->lod_bias = p_lod_bias; +} +void RendererSceneRenderForward::geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->use_baked_light = p_enable; + _geometry_instance_mark_dirty(ginstance); +} +void RendererSceneRenderForward::geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->use_dynamic_gi = p_enable; + _geometry_instance_mark_dirty(ginstance); +} +void RendererSceneRenderForward::geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->lightmap_instance = p_lightmap_instance; + ginstance->lightmap_uv_scale = p_lightmap_uv_scale; + ginstance->lightmap_slice_index = p_lightmap_slice_index; + _geometry_instance_mark_dirty(ginstance); +} +void RendererSceneRenderForward::geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + if (p_sh9) { + if (ginstance->lightmap_sh == nullptr) { + ginstance->lightmap_sh = geometry_instance_lightmap_sh.alloc(); + } + + copymem(ginstance->lightmap_sh->sh, p_sh9, sizeof(Color) * 9); + } else { + if (ginstance->lightmap_sh != nullptr) { + geometry_instance_lightmap_sh.free(ginstance->lightmap_sh); + ginstance->lightmap_sh = nullptr; + } + } + _geometry_instance_mark_dirty(ginstance); +} +void RendererSceneRenderForward::geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->shader_parameters_offset = p_offset; + _geometry_instance_mark_dirty(ginstance); +} +void RendererSceneRenderForward::geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + + ginstance->data->cast_double_sided_shaodows = p_enable; + _geometry_instance_mark_dirty(ginstance); +} + +void RendererSceneRenderForward::geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->layer_mask = p_layer_mask; +} + +void RendererSceneRenderForward::geometry_instance_free(GeometryInstance *p_geometry_instance) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + if (ginstance->lightmap_sh != nullptr) { + geometry_instance_lightmap_sh.free(ginstance->lightmap_sh); + } + GeometryInstanceSurfaceDataCache *surf = ginstance->surface_caches; + while (surf) { + GeometryInstanceSurfaceDataCache *next = surf->next; + geometry_instance_surface_alloc.free(surf); + surf = next; + } + memdelete(ginstance->data); + geometry_instance_alloc.free(ginstance); +} + +uint32_t RendererSceneRenderForward::geometry_instance_get_pair_mask() { + return (1 << RS::INSTANCE_GI_PROBE); +} +void RendererSceneRenderForward::geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) { +} +void RendererSceneRenderForward::geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) { +} +void RendererSceneRenderForward::geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) { +} + +Transform RendererSceneRenderForward::geometry_instance_get_transform(GeometryInstance *p_instance) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_instance); + ERR_FAIL_COND_V(!ginstance, Transform()); + return ginstance->transform; +} +AABB RendererSceneRenderForward::geometry_instance_get_aabb(GeometryInstance *p_instance) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_instance); + ERR_FAIL_COND_V(!ginstance, AABB()); + return ginstance->data->aabb; +} + +void RendererSceneRenderForward::geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + if (p_gi_probe_instance_count > 0) { + ginstance->gi_probes[0] = p_gi_probe_instances[0]; + } else { + ginstance->gi_probes[0] = RID(); + } + + if (p_gi_probe_instance_count > 1) { + ginstance->gi_probes[1] = p_gi_probe_instances[1]; + } else { + ginstance->gi_probes[1] = RID(); + } +} + +RendererSceneRenderForward::RendererSceneRenderForward(RendererStorageRD *p_storage) : + RendererSceneRenderRD(p_storage) { singleton = this; + low_end = is_low_end(); storage = p_storage; /* SCENE SHADER */ { String defines; + if (low_end) { + defines += "\n#define LOW_END_MODE \n"; + } + defines += "\n#define MAX_ROUGHNESS_LOD " + itos(get_roughness_layers() - 1) + ".0\n"; if (is_using_radiance_cubemap_array()) { defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n"; @@ -2691,11 +3351,10 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag { //lightmaps - scene_state.max_lightmaps = storage->lightmap_array_get_size(); + scene_state.max_lightmaps = low_end ? 2 : MAX_LIGHTMAPS; defines += "\n#define MAX_LIGHTMAP_TEXTURES " + itos(scene_state.max_lightmaps) + "\n"; defines += "\n#define MAX_LIGHTMAPS " + itos(scene_state.max_lightmaps) + "\n"; - scene_state.lightmaps = memnew_arr(LightmapData, scene_state.max_lightmaps); scene_state.lightmap_buffer = RD::get_singleton()->storage_buffer_create(sizeof(LightmapData) * scene_state.max_lightmaps); } { @@ -2721,10 +3380,20 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag shader_versions.push_back("\n#define USE_LIGHTMAP\n"); shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n#define USE_LIGHTMAP\n"); shader.scene_shader.initialize(shader_versions, defines); + + if (is_low_end()) { + //disable the high end versions + shader.scene_shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS, false); + shader.scene_shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE, false); + shader.scene_shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_SDF, false); + shader.scene_shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI, false); + shader.scene_shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR, false); + shader.scene_shader.set_variant_enabled(SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR, false); + } } - storage->shader_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_3D, _create_shader_funcs); - storage->material_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_3D, _create_material_funcs); + storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_shader_funcs); + storage->material_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_material_funcs); { //shader compiler @@ -2762,8 +3431,8 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag actions.renames["FRAGCOORD"] = "gl_FragCoord"; actions.renames["FRONT_FACING"] = "gl_FrontFacing"; - actions.renames["NORMALMAP"] = "normalmap"; - actions.renames["NORMALMAP_DEPTH"] = "normaldepth"; + actions.renames["NORMAL_MAP"] = "normal_map"; + actions.renames["NORMAL_MAP_DEPTH"] = "normal_map_depth"; actions.renames["ALBEDO"] = "albedo"; actions.renames["ALPHA"] = "alpha"; actions.renames["METALLIC"] = "metallic"; @@ -2795,6 +3464,12 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag actions.renames["FOG"] = "custom_fog"; actions.renames["RADIANCE"] = "custom_radiance"; actions.renames["IRRADIANCE"] = "custom_irradiance"; + actions.renames["BONE_INDICES"] = "bone_attrib"; + actions.renames["BONE_WEIGHTS"] = "weight_attrib"; + actions.renames["CUSTOM0"] = "custom0_attrib"; + actions.renames["CUSTOM1"] = "custom1_attrib"; + actions.renames["CUSTOM2"] = "custom2_attrib"; + actions.renames["CUSTOM3"] = "custom3_attrib"; //for light actions.renames["VIEW"] = "view"; @@ -2805,6 +3480,7 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag actions.renames["DIFFUSE_LIGHT"] = "diffuse_light"; actions.renames["SPECULAR_LIGHT"] = "specular_light"; + actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n"; actions.usage_defines["TANGENT"] = "#define TANGENT_USED\n"; actions.usage_defines["BINORMAL"] = "@TANGENT"; actions.usage_defines["RIM"] = "#define LIGHT_RIM_USED\n"; @@ -2817,8 +3493,14 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag actions.usage_defines["AO_LIGHT_AFFECT"] = "#define AO_USED\n"; actions.usage_defines["UV"] = "#define UV_USED\n"; actions.usage_defines["UV2"] = "#define UV2_USED\n"; - actions.usage_defines["NORMALMAP"] = "#define NORMALMAP_USED\n"; - actions.usage_defines["NORMALMAP_DEPTH"] = "@NORMALMAP"; + actions.usage_defines["BONE_INDICES"] = "#define BONES_USED\n"; + actions.usage_defines["BONE_WEIGHTS"] = "#define WEIGHTS_USED\n"; + actions.usage_defines["CUSTOM0"] = "#define CUSTOM0\n"; + actions.usage_defines["CUSTOM1"] = "#define CUSTOM1\n"; + actions.usage_defines["CUSTOM2"] = "#define CUSTOM2\n"; + actions.usage_defines["CUSTOM3"] = "#define CUSTOM3\n"; + actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n"; + actions.usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP"; actions.usage_defines["COLOR"] = "#define COLOR_USED\n"; actions.usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n"; actions.usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n"; @@ -2847,7 +3529,7 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag actions.render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n"; actions.render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n"; - bool force_lambert = GLOBAL_GET("rendering/quality/shading/force_lambert_over_burley"); + bool force_lambert = GLOBAL_GET("rendering/shading/overrides/force_lambert_over_burley"); if (!force_lambert) { actions.render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n"; @@ -2859,7 +3541,7 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag actions.render_mode_defines["sss_mode_skin"] = "#define SSS_MODE_SKIN\n"; - bool force_blinn = GLOBAL_GET("rendering/quality/shading/force_blinn_over_ggx"); + bool force_blinn = GLOBAL_GET("rendering/shading/overrides/force_blinn_over_ggx"); if (!force_blinn) { actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; @@ -2885,45 +3567,40 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP; actions.default_repeat = ShaderLanguage::REPEAT_ENABLE; actions.global_buffer_array_variable = "global_variables.data"; - actions.instance_uniform_index_variable = "instances.data[instance_index].instance_uniforms_ofs"; + actions.instance_uniform_index_variable = "draw_call.instance_uniforms_ofs"; shader.compiler.initialize(actions); } - //render list - render_list.max_elements = GLOBAL_DEF_RST("rendering/limits/rendering/max_renderable_elements", (int)128000); - render_list.init(); - render_pass = 0; - - { - scene_state.max_instances = render_list.max_elements; - scene_state.instances = memnew_arr(InstanceData, scene_state.max_instances); - scene_state.instance_buffer = RD::get_singleton()->storage_buffer_create(sizeof(InstanceData) * scene_state.max_instances); - } - - scene_state.uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SceneState::UBO)); - { //default material and shader - default_shader = storage->shader_create(); + default_shader = storage->shader_allocate(); + storage->shader_initialize(default_shader); storage->shader_set_code(default_shader, "shader_type spatial; void vertex() { ROUGHNESS = 0.8; } void fragment() { ALBEDO=vec3(0.6); ROUGHNESS=0.8; METALLIC=0.2; } \n"); - default_material = storage->material_create(); + default_material = storage->material_allocate(); + storage->material_initialize(default_material); storage->material_set_shader(default_material, default_shader); - MaterialData *md = (MaterialData *)storage->material_get_data(default_material, RasterizerStorageRD::SHADER_TYPE_3D); + MaterialData *md = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D); default_shader_rd = shader.scene_shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS); - default_shader_sdfgi_rd = shader.scene_shader.version_get_shader(md->shader_data->version, SHADER_VERSION_DEPTH_PASS_WITH_SDF); + if (!low_end) { + default_shader_sdfgi_rd = shader.scene_shader.version_get_shader(md->shader_data->version, SHADER_VERSION_DEPTH_PASS_WITH_SDF); + } } { - overdraw_material_shader = storage->shader_create(); + overdraw_material_shader = storage->shader_allocate(); + storage->shader_initialize(overdraw_material_shader); storage->shader_set_code(overdraw_material_shader, "shader_type spatial;\nrender_mode blend_add,unshaded;\n void fragment() { ALBEDO=vec3(0.4,0.8,0.8); ALPHA=0.2; }"); - overdraw_material = storage->material_create(); + overdraw_material = storage->material_allocate(); + storage->material_initialize(overdraw_material); storage->material_set_shader(overdraw_material, overdraw_material_shader); - wireframe_material_shader = storage->shader_create(); + wireframe_material_shader = storage->shader_allocate(); + storage->shader_initialize(wireframe_material_shader); storage->shader_set_code(wireframe_material_shader, "shader_type spatial;\nrender_mode wireframe,unshaded;\n void fragment() { ALBEDO=vec3(0.0,0.0,0.0); }"); - wireframe_material = storage->material_create(); + wireframe_material = storage->material_allocate(); + storage->material_initialize(wireframe_material); storage->material_set_shader(wireframe_material, wireframe_material_shader); } @@ -2931,7 +3608,7 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag default_vec4_xform_buffer = RD::get_singleton()->storage_buffer_create(256); Vector<RD::Uniform> uniforms; RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(default_vec4_xform_buffer); u.binding = 0; uniforms.push_back(u); @@ -2947,73 +3624,23 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag shadow_sampler = RD::get_singleton()->sampler_create(sampler); } - { - Vector<RD::Uniform> uniforms; - - RD::Uniform u; - u.binding = 0; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK); - u.ids.push_back(texture); - uniforms.push_back(u); - - default_radiance_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RADIANCE_UNIFORM_SET); - } - - { //render buffers - Vector<RD::Uniform> uniforms; - for (int i = 0; i < 7; i++) { - RD::Uniform u; - u.binding = i; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = storage->texture_rd_get_default(i == 0 ? RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE : (i == 2 ? RasterizerStorageRD::DEFAULT_RD_TEXTURE_NORMAL : RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK)); - u.ids.push_back(texture); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 7; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); - u.ids.push_back(texture); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 8; - u.type = RD::UNIFORM_TYPE_TEXTURE; - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 9; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.ids.push_back(render_buffers_get_default_gi_probe_buffer()); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 10; - u.type = RD::UNIFORM_TYPE_TEXTURE; - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); - uniforms.push_back(u); - } - - default_render_buffers_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RENDER_BUFFERS_UNIFORM_SET); - } + render_list_thread_threshold = GLOBAL_GET("rendering/limits/forward_renderer/threaded_render_minimum_instances"); } -RasterizerSceneHighEndRD::~RasterizerSceneHighEndRD() { +RendererSceneRenderForward::~RendererSceneRenderForward() { directional_shadow_atlas_set_size(0); //clear base uniform set if still valid - if (view_dependant_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(view_dependant_uniform_set)) { - RD::get_singleton()->free(view_dependant_uniform_set); + for (uint32_t i = 0; i < render_pass_uniform_sets.size(); i++) { + if (render_pass_uniform_sets[i].is_valid() && RD::get_singleton()->uniform_set_is_valid(render_pass_uniform_sets[i])) { + RD::get_singleton()->free(render_pass_uniform_sets[i]); + } + } + + if (sdfgi_pass_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sdfgi_pass_uniform_set)) { + RD::get_singleton()->free(sdfgi_pass_uniform_set); } - RD::get_singleton()->free(default_render_buffers_uniform_set); - RD::get_singleton()->free(default_radiance_uniform_set); RD::get_singleton()->free(default_vec4_xform_buffer); RD::get_singleton()->free(shadow_sampler); @@ -3026,12 +3653,16 @@ RasterizerSceneHighEndRD::~RasterizerSceneHighEndRD() { storage->free(default_material); { - RD::get_singleton()->free(scene_state.uniform_buffer); - RD::get_singleton()->free(scene_state.instance_buffer); + for (uint32_t i = 0; i < scene_state.uniform_buffers.size(); i++) { + RD::get_singleton()->free(scene_state.uniform_buffers[i]); + } RD::get_singleton()->free(scene_state.lightmap_buffer); RD::get_singleton()->free(scene_state.lightmap_capture_buffer); - memdelete_arr(scene_state.instances); - memdelete_arr(scene_state.lightmaps); + for (uint32_t i = 0; i < RENDER_LIST_MAX; i++) { + if (scene_state.instance_buffer[i] != RID()) { + RD::get_singleton()->free(scene_state.instance_buffer[i]); + } + } memdelete_arr(scene_state.lightmap_captures); } diff --git a/servers/rendering/renderer_rd/renderer_scene_render_forward.h b/servers/rendering/renderer_rd/renderer_scene_render_forward.h new file mode 100644 index 0000000000..af78c50fda --- /dev/null +++ b/servers/rendering/renderer_rd/renderer_scene_render_forward.h @@ -0,0 +1,771 @@ +/*************************************************************************/ +/* renderer_scene_render_forward.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RENDERING_SERVER_SCENE_RENDER_FORWARD_H +#define RENDERING_SERVER_SCENE_RENDER_FORWARD_H + +#include "core/templates/paged_allocator.h" +#include "servers/rendering/renderer_rd/pipeline_cache_rd.h" +#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h" +#include "servers/rendering/renderer_rd/renderer_storage_rd.h" +#include "servers/rendering/renderer_rd/shaders/scene_forward.glsl.gen.h" + +class RendererSceneRenderForward : public RendererSceneRenderRD { + enum { + SCENE_UNIFORM_SET = 0, + RENDER_PASS_UNIFORM_SET = 1, + TRANSFORMS_UNIFORM_SET = 2, + MATERIAL_UNIFORM_SET = 3 + }; + + enum { + SDFGI_MAX_CASCADES = 8, + MAX_GI_PROBES = 8, + MAX_LIGHTMAPS = 8, + MAX_GI_PROBES_PER_INSTANCE = 2, + INSTANCE_DATA_BUFFER_MIN_SIZE = 4096 + }; + + enum RenderListType { + RENDER_LIST_OPAQUE, //used for opaque objects + RENDER_LIST_ALPHA, //used for transparent objects + RENDER_LIST_SECONDARY, //used for shadows and other objects + RENDER_LIST_MAX + + }; + + /* Scene Shader */ + + enum ShaderVersion { + SHADER_VERSION_DEPTH_PASS, + SHADER_VERSION_DEPTH_PASS_DP, + SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS, + SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE, + SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL, + SHADER_VERSION_DEPTH_PASS_WITH_SDF, + SHADER_VERSION_COLOR_PASS, + SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI, + SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR, + SHADER_VERSION_LIGHTMAP_COLOR_PASS, + SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR, + SHADER_VERSION_MAX + }; + + struct { + SceneForwardShaderRD scene_shader; + ShaderCompilerRD compiler; + } shader; + + RendererStorageRD *storage; + + /* Material */ + + struct ShaderData : public RendererStorageRD::ShaderData { + enum BlendMode { //used internally + BLEND_MODE_MIX, + BLEND_MODE_ADD, + BLEND_MODE_SUB, + BLEND_MODE_MUL, + BLEND_MODE_ALPHA_TO_COVERAGE + }; + + enum DepthDraw { + DEPTH_DRAW_DISABLED, + DEPTH_DRAW_OPAQUE, + DEPTH_DRAW_ALWAYS + }; + + enum DepthTest { + DEPTH_TEST_DISABLED, + DEPTH_TEST_ENABLED + }; + + enum Cull { + CULL_DISABLED, + CULL_FRONT, + CULL_BACK + }; + + enum CullVariant { + CULL_VARIANT_NORMAL, + CULL_VARIANT_REVERSED, + CULL_VARIANT_DOUBLE_SIDED, + CULL_VARIANT_MAX + + }; + + enum AlphaAntiAliasing { + ALPHA_ANTIALIASING_OFF, + ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE, + ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE + }; + + bool valid; + RID version; + uint32_t vertex_input_mask; + PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][SHADER_VERSION_MAX]; + + String path; + + Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms; + Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms; + + Vector<uint32_t> ubo_offsets; + uint32_t ubo_size; + + String code; + Map<StringName, RID> default_texture_params; + + DepthDraw depth_draw; + DepthTest depth_test; + + bool uses_point_size; + bool uses_alpha; + bool uses_blend_alpha; + bool uses_alpha_clip; + bool uses_depth_pre_pass; + bool uses_discard; + bool uses_roughness; + bool uses_normal; + + bool unshaded; + bool uses_vertex; + bool uses_sss; + bool uses_transmittance; + bool uses_screen_texture; + bool uses_depth_texture; + bool uses_normal_texture; + bool uses_time; + bool writes_modelview_or_projection; + bool uses_world_coordinates; + + uint64_t last_pass = 0; + uint32_t index = 0; + + virtual void set_code(const String &p_Code); + virtual void set_default_texture_param(const StringName &p_name, RID p_texture); + virtual void get_param_list(List<PropertyInfo> *p_param_list) const; + void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const; + + virtual bool is_param_texture(const StringName &p_param) const; + virtual bool is_animated() const; + virtual bool casts_shadows() const; + virtual Variant get_default_parameter(const StringName &p_parameter) const; + virtual RS::ShaderNativeSourceCode get_native_source_code() const; + + ShaderData(); + virtual ~ShaderData(); + }; + + RendererStorageRD::ShaderData *_create_shader_func(); + static RendererStorageRD::ShaderData *_create_shader_funcs() { + return static_cast<RendererSceneRenderForward *>(singleton)->_create_shader_func(); + } + + struct MaterialData : public RendererStorageRD::MaterialData { + uint64_t last_frame; + ShaderData *shader_data; + RID uniform_buffer; + RID uniform_set; + Vector<RID> texture_cache; + Vector<uint8_t> ubo_data; + uint64_t last_pass = 0; + uint32_t index = 0; + RID next_pass; + uint8_t priority; + virtual void set_render_priority(int p_priority); + virtual void set_next_pass(RID p_pass); + virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); + virtual ~MaterialData(); + }; + + RendererStorageRD::MaterialData *_create_material_func(ShaderData *p_shader); + static RendererStorageRD::MaterialData *_create_material_funcs(RendererStorageRD::ShaderData *p_shader) { + return static_cast<RendererSceneRenderForward *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader)); + } + + /* Framebuffer */ + + struct RenderBufferDataForward : public RenderBufferData { + //for rendering, may be MSAAd + + RID color; + RID depth; + RID specular; + RID normal_roughness_buffer; + RID giprobe_buffer; + + RS::ViewportMSAA msaa; + RD::TextureSamples texture_samples; + + RID color_msaa; + RID depth_msaa; + RID specular_msaa; + RID normal_roughness_buffer_msaa; + RID roughness_buffer_msaa; + RID giprobe_buffer_msaa; + + RID depth_fb; + RID depth_normal_roughness_fb; + RID depth_normal_roughness_giprobe_fb; + RID color_fb; + RID color_specular_fb; + RID specular_only_fb; + int width, height; + + RID render_sdfgi_uniform_set; + void ensure_specular(); + void ensure_giprobe(); + void clear(); + virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa); + + ~RenderBufferDataForward(); + }; + + virtual RenderBufferData *_create_render_buffer_data(); + void _allocate_normal_roughness_texture(RenderBufferDataForward *rb); + + RID shadow_sampler; + RID render_base_uniform_set; + LocalVector<RID> render_pass_uniform_sets; + RID sdfgi_pass_uniform_set; + + uint64_t lightmap_texture_array_version = 0xFFFFFFFF; + + virtual void _base_uniforms_changed(); + void _render_buffers_clear_uniform_set(RenderBufferDataForward *rb); + virtual void _render_buffers_uniform_set_changed(RID p_render_buffers); + virtual RID _render_buffers_get_normal_texture(RID p_render_buffers); + + void _update_render_base_uniform_set(); + RID _setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture); + RID _setup_render_pass_uniform_set(RenderListType p_render_list, RID p_render_buffers, RID p_radiance_texture, RID p_shadow_atlas, RID p_reflection_atlas, RID p_cluster_buffer, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, bool p_use_directional_shadow_atlas = false, int p_index = 0); + + enum PassMode { + PASS_MODE_COLOR, + PASS_MODE_COLOR_SPECULAR, + PASS_MODE_COLOR_TRANSPARENT, + PASS_MODE_SHADOW, + PASS_MODE_SHADOW_DP, + PASS_MODE_DEPTH, + PASS_MODE_DEPTH_NORMAL_ROUGHNESS, + PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE, + PASS_MODE_DEPTH_MATERIAL, + PASS_MODE_SDF, + }; + + struct GeometryInstanceSurfaceDataCache; + struct RenderElementInfo; + + struct RenderListParameters { + GeometryInstanceSurfaceDataCache **elements = nullptr; + RenderElementInfo *element_info = nullptr; + int element_count = 0; + bool reverse_cull = false; + PassMode pass_mode = PASS_MODE_COLOR; + bool no_gi = false; + RID render_pass_uniform_set; + bool force_wireframe = false; + Vector2 uv_offset; + Plane lod_plane; + float lod_distance_multiplier = 0.0; + float screen_lod_threshold = 0.0; + RD::FramebufferFormatID framebuffer_format = 0; + uint32_t element_offset = 0; + uint32_t barrier = RD::BARRIER_MASK_ALL; + + RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), const Plane &p_lod_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL) { + elements = p_elements; + element_info = p_element_info; + element_count = p_element_count; + reverse_cull = p_reverse_cull; + pass_mode = p_pass_mode; + no_gi = p_no_gi; + render_pass_uniform_set = p_render_pass_uniform_set; + force_wireframe = p_force_wireframe; + uv_offset = p_uv_offset; + lod_plane = p_lod_plane; + lod_distance_multiplier = p_lod_distance_multiplier; + screen_lod_threshold = p_screen_lod_threshold; + element_offset = p_element_offset; + barrier = p_barrier; + } + }; + + struct LightmapData { + float normal_xform[12]; + }; + + struct LightmapCaptureData { + float sh[9 * 4]; + }; + + enum { + INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 6, + INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 7, + INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 8, + INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 9, + INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 10, + INSTANCE_DATA_FLAG_USE_GIPROBE = 1 << 11, + INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12, + INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13, + INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14, + INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA = 1 << 15, + INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT = 16, + INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_MASK = 0x7, + INSTANCE_DATA_FLAG_SKELETON = 1 << 19, + }; + + struct SceneState { + struct UBO { + float projection_matrix[16]; + float inv_projection_matrix[16]; + + float camera_matrix[16]; + float inv_camera_matrix[16]; + + float viewport_size[2]; + float screen_pixel_size[2]; + + uint32_t cluster_shift; + uint32_t cluster_width; + uint32_t cluster_type_size; + uint32_t max_cluster_element_count_div_32; + + float directional_penumbra_shadow_kernel[128]; //32 vec4s + float directional_soft_shadow_kernel[128]; + float penumbra_shadow_kernel[128]; + float soft_shadow_kernel[128]; + + uint32_t directional_penumbra_shadow_samples; + uint32_t directional_soft_shadow_samples; + uint32_t penumbra_shadow_samples; + uint32_t soft_shadow_samples; + + float ambient_light_color_energy[4]; + + float ambient_color_sky_mix; + uint32_t use_ambient_light; + uint32_t use_ambient_cubemap; + uint32_t use_reflection_cubemap; + + float radiance_inverse_xform[12]; + + float shadow_atlas_pixel_size[2]; + float directional_shadow_pixel_size[2]; + + uint32_t directional_light_count; + float dual_paraboloid_side; + float z_far; + float z_near; + + uint32_t ssao_enabled; + float ssao_light_affect; + float ssao_ao_affect; + uint32_t roughness_limiter_enabled; + + float roughness_limiter_amount; + float roughness_limiter_limit; + uint32_t roughness_limiter_pad[2]; + + float ao_color[4]; + + float sdf_to_bounds[16]; + + int32_t sdf_offset[3]; + uint32_t material_uv2_mode; + + int32_t sdf_size[3]; + uint32_t gi_upscale_for_msaa; + + uint32_t volumetric_fog_enabled; + float volumetric_fog_inv_length; + float volumetric_fog_detail_spread; + uint32_t volumetric_fog_pad; + + // Fog + uint32_t fog_enabled; + float fog_density; + float fog_height; + float fog_height_density; + + float fog_light_color[3]; + float fog_sun_scatter; + + float fog_aerial_perspective; + + float time; + float reflection_multiplier; + + uint32_t pancake_shadows; + }; + + struct PushConstant { + uint32_t base_index; // + uint32_t uv_offset; //packed + uint32_t pad[2]; + }; + + struct InstanceData { + float transform[16]; + uint32_t flags; + uint32_t instance_uniforms_ofs; //base offset in global buffer for instance variables + uint32_t gi_offset; //GI information when using lightmapping (VCT or lightmap index) + uint32_t layer_mask; + float lightmap_uv_scale[4]; + }; + + UBO ubo; + + LocalVector<RID> uniform_buffers; + + LightmapData lightmaps[MAX_LIGHTMAPS]; + RID lightmap_ids[MAX_LIGHTMAPS]; + bool lightmap_has_sh[MAX_LIGHTMAPS]; + uint32_t lightmaps_used = 0; + uint32_t max_lightmaps; + RID lightmap_buffer; + + RID instance_buffer[RENDER_LIST_MAX]; + uint32_t instance_buffer_size[RENDER_LIST_MAX] = { 0, 0, 0 }; + LocalVector<InstanceData> instance_data[RENDER_LIST_MAX]; + + LightmapCaptureData *lightmap_captures; + uint32_t max_lightmap_captures; + RID lightmap_capture_buffer; + + RID giprobe_ids[MAX_GI_PROBES]; + uint32_t giprobes_used = 0; + + bool used_screen_texture = false; + bool used_normal_texture = false; + bool used_depth_texture = false; + bool used_sss = false; + + struct ShadowPass { + uint32_t element_from; + uint32_t element_count; + bool flip_cull; + PassMode pass_mode; + + RID rp_uniform_set; + Plane camera_plane; + float lod_distance_multiplier; + float screen_lod_threshold; + + RID framebuffer; + RD::InitialAction initial_depth_action; + RD::FinalAction final_depth_action; + Rect2i rect; + }; + + LocalVector<ShadowPass> shadow_passes; + + } scene_state; + + static RendererSceneRenderForward *singleton; + + double time; + RID default_shader; + RID default_material; + RID overdraw_material_shader; + RID overdraw_material; + RID wireframe_material_shader; + RID wireframe_material; + RID default_shader_rd; + RID default_shader_sdfgi_rd; + + RID default_vec4_xform_buffer; + RID default_vec4_xform_uniform_set; + + void _setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2i &p_screen_size, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false, int p_index = 0); + void _setup_giprobes(const PagedArray<RID> &p_giprobes); + void _setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform &p_cam_transform); + + struct RenderElementInfo { + uint32_t repeat : 22; + uint32_t uses_lightmap : 1; + uint32_t uses_forward_gi : 1; + uint32_t lod_index : 8; + }; + + template <PassMode p_pass_mode> + _FORCE_INLINE_ void _render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element); + + void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element); + + LocalVector<RD::DrawListID> thread_draw_lists; + void _render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params); + void _render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector<RID> &p_storage_textures = Vector<RID>()); + + uint32_t render_list_thread_threshold = 500; + + void _update_instance_data_buffer(RenderListType p_render_list); + void _fill_instance_data(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true); + void _fill_render_list(RenderListType p_render_list, const PagedArray<GeometryInstance *> &p_instances, PassMode p_pass_mode, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_using_sdfgi = false, bool p_using_opaque_gi = false, const Plane &p_lod_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, bool p_append = false); + + Map<Size2i, RID> sdfgi_framebuffer_size_cache; + + struct GeometryInstanceData; + struct GeometryInstanceForward; + + struct GeometryInstanceLightmapSH { + Color sh[9]; + }; + + // Cached data for drawing surfaces + struct GeometryInstanceSurfaceDataCache { + enum { + FLAG_PASS_DEPTH = 1, + FLAG_PASS_OPAQUE = 2, + FLAG_PASS_ALPHA = 4, + FLAG_PASS_SHADOW = 8, + FLAG_USES_SHARED_SHADOW_MATERIAL = 128, + FLAG_USES_SUBSURFACE_SCATTERING = 2048, + FLAG_USES_SCREEN_TEXTURE = 4096, + FLAG_USES_DEPTH_TEXTURE = 8192, + FLAG_USES_NORMAL_TEXTURE = 16384, + FLAG_USES_DOUBLE_SIDED_SHADOWS = 32768, + }; + + union { + struct { + uint64_t lod_index : 8; + uint64_t surface_index : 10; + uint64_t geometry_id : 32; + uint64_t material_id_low : 14; + + uint64_t material_id_hi : 18; + uint64_t shader_id : 32; + uint64_t uses_forward_gi : 1; + uint64_t uses_lightmap : 1; + uint64_t depth_layer : 4; + uint64_t priority : 8; + }; + struct { + uint64_t sort_key1; + uint64_t sort_key2; + }; + } sort; + + RS::PrimitiveType primitive = RS::PRIMITIVE_MAX; + uint32_t flags = 0; + uint32_t surface_index = 0; + + void *surface = nullptr; + RID material_uniform_set; + ShaderData *shader = nullptr; + + void *surface_shadow = nullptr; + RID material_uniform_set_shadow; + ShaderData *shader_shadow = nullptr; + + GeometryInstanceSurfaceDataCache *next = nullptr; + GeometryInstanceForward *owner = nullptr; + }; + + struct GeometryInstanceForward : public GeometryInstance { + //used during rendering + bool mirror = false; + bool non_uniform_scale = false; + float lod_bias = 0.0; + float lod_model_scale = 1.0; + AABB transformed_aabb; //needed for LOD + float depth = 0; + uint32_t gi_offset_cache = 0; + uint32_t flags_cache = 0; + bool store_transform_cache = true; + int32_t shader_parameters_offset = -1; + uint32_t lightmap_slice_index; + Rect2 lightmap_uv_scale; + uint32_t layer_mask = 1; + RID transforms_uniform_set; + uint32_t instance_count = 0; + RID mesh_instance; + bool can_sdfgi = false; + //used during setup + uint32_t base_flags = 0; + Transform transform; + RID gi_probes[MAX_GI_PROBES_PER_INSTANCE]; + RID lightmap_instance; + GeometryInstanceLightmapSH *lightmap_sh = nullptr; + GeometryInstanceSurfaceDataCache *surface_caches = nullptr; + SelfList<GeometryInstanceForward> dirty_list_element; + + struct Data { + //data used less often goes into regular heap + RID base; + RS::InstanceType base_type; + + RID skeleton; + Vector<RID> surface_materials; + RID material_override; + AABB aabb; + + bool use_dynamic_gi = false; + bool use_baked_light = false; + bool cast_double_sided_shaodows = false; + bool mirror = false; + bool dirty_dependencies = false; + + RendererStorage::DependencyTracker dependency_tracker; + }; + + Data *data = nullptr; + + GeometryInstanceForward() : + dirty_list_element(this) {} + }; + + static void _geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker); + static void _geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker); + + SelfList<GeometryInstanceForward>::List geometry_instance_dirty_list; + + PagedAllocator<GeometryInstanceForward> geometry_instance_alloc; + PagedAllocator<GeometryInstanceSurfaceDataCache> geometry_instance_surface_alloc; + PagedAllocator<GeometryInstanceLightmapSH> geometry_instance_lightmap_sh; + + void _geometry_instance_add_surface_with_material(GeometryInstanceForward *ginstance, uint32_t p_surface, MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh); + void _geometry_instance_add_surface(GeometryInstanceForward *ginstance, uint32_t p_surface, RID p_material, RID p_mesh); + void _geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance); + void _geometry_instance_update(GeometryInstance *p_geometry_instance); + void _update_dirty_geometry_instances(); + + bool low_end = false; + + /* Render List */ + + struct RenderList { + LocalVector<GeometryInstanceSurfaceDataCache *> elements; + LocalVector<RenderElementInfo> element_info; + + void clear() { + elements.clear(); + element_info.clear(); + } + + //should eventually be replaced by radix + + struct SortByKey { + _FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const { + return (A->sort.sort_key2 == B->sort.sort_key2) ? (A->sort.sort_key1 < B->sort.sort_key1) : (A->sort.sort_key2 < B->sort.sort_key2); + } + }; + + void sort_by_key() { + SortArray<GeometryInstanceSurfaceDataCache *, SortByKey> sorter; + sorter.sort(elements.ptr(), elements.size()); + } + + void sort_by_key_range(uint32_t p_from, uint32_t p_size) { + SortArray<GeometryInstanceSurfaceDataCache *, SortByKey> sorter; + sorter.sort(elements.ptr() + p_from, p_size); + } + + struct SortByDepth { + _FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const { + return (A->owner->depth < B->owner->depth); + } + }; + + void sort_by_depth() { //used for shadows + + SortArray<GeometryInstanceSurfaceDataCache *, SortByDepth> sorter; + sorter.sort(elements.ptr(), elements.size()); + } + + struct SortByReverseDepthAndPriority { + _FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const { + return (A->sort.priority == B->sort.priority) ? (A->owner->depth > B->owner->depth) : (A->sort.priority < B->sort.priority); + } + }; + + void sort_by_reverse_depth_and_priority(bool p_alpha) { //used for alpha + + SortArray<GeometryInstanceSurfaceDataCache *, SortByReverseDepthAndPriority> sorter; + sorter.sort(elements.ptr(), elements.size()); + } + + _FORCE_INLINE_ void add_element(GeometryInstanceSurfaceDataCache *p_element) { + elements.push_back(p_element); + } + }; + + RenderList render_list[RENDER_LIST_MAX]; + +protected: + virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_cluster_buffer, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color, float p_lod_threshold); + + virtual void _render_shadow_begin(); + virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true); + virtual void _render_shadow_process(); + virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL); + + virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region); + virtual void _render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region); + virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture); + virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances); + +public: + virtual GeometryInstance *geometry_instance_create(RID p_base); + virtual void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton); + virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override); + virtual void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials); + virtual void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance); + virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb); + virtual void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask); + virtual void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias); + virtual void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable); + virtual void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable); + virtual void geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index); + virtual void geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9); + virtual void geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset); + virtual void geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable); + + virtual Transform geometry_instance_get_transform(GeometryInstance *p_instance); + virtual AABB geometry_instance_get_aabb(GeometryInstance *p_instance); + + virtual void geometry_instance_free(GeometryInstance *p_geometry_instance); + + virtual uint32_t geometry_instance_get_pair_mask(); + virtual void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count); + virtual void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count); + virtual void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count); + virtual void geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count); + + virtual void set_time(double p_time, double p_step); + + virtual bool free(RID p_rid); + + RendererSceneRenderForward(RendererStorageRD *p_storage); + ~RendererSceneRenderForward(); +}; +#endif // RASTERIZER_SCENE_HIGHEND_RD_H diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 12fcc6fbb9..15e963f6e4 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rasterizer_scene_rd.cpp */ +/* renderer_scene_render_rd.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,14 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "rasterizer_scene_rd.h" +#include "renderer_scene_render_rd.h" #include "core/config/project_settings.h" #include "core/os/os.h" -#include "rasterizer_rd.h" -#include "servers/rendering/rendering_server_raster.h" +#include "renderer_compositor_rd.h" +#include "servers/rendering/rendering_server_default.h" -uint64_t RasterizerSceneRD::auto_exposure_counter = 2; +uint64_t RendererSceneRenderRD::auto_exposure_counter = 2; void get_vogel_disk(float *r_kernel, int p_sample_count) { const float golden_angle = 2.4; @@ -49,7 +49,7 @@ void get_vogel_disk(float *r_kernel, int p_sample_count) { } } -void RasterizerSceneRD::_clear_reflection_data(ReflectionData &rd) { +void RendererSceneRenderRD::_clear_reflection_data(ReflectionData &rd) { rd.layers.clear(); rd.radiance_base_cubemap = RID(); if (rd.downsampled_radiance_cubemap.is_valid()) { @@ -60,7 +60,7 @@ void RasterizerSceneRD::_clear_reflection_data(ReflectionData &rd) { rd.coefficient_buffer = RID(); } -void RasterizerSceneRD::_update_reflection_data(ReflectionData &rd, int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality) { +void RendererSceneRenderRD::_update_reflection_data(ReflectionData &rd, int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality) { //recreate radiance and all data int mipmaps = p_mipmaps; @@ -129,7 +129,7 @@ void RasterizerSceneRD::_update_reflection_data(ReflectionData &rd, int p_size, tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; tf.width = 64; // Always 64x64 tf.height = 64; - tf.type = RD::TEXTURE_TYPE_CUBE; + tf.texture_type = RD::TEXTURE_TYPE_CUBE; tf.array_layers = 6; tf.mipmaps = 7; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; @@ -151,7 +151,7 @@ void RasterizerSceneRD::_update_reflection_data(ReflectionData &rd, int p_size, } } -void RasterizerSceneRD::_create_reflection_fast_filter(ReflectionData &rd, bool p_use_arrays) { +void RendererSceneRenderRD::_create_reflection_fast_filter(ReflectionData &rd, bool p_use_arrays) { storage->get_effects()->cubemap_downsample(rd.radiance_base_cubemap, rd.downsampled_layer.mipmaps[0].view, rd.downsampled_layer.mipmaps[0].size); for (int i = 1; i < rd.downsampled_layer.mipmaps.size(); i++) { @@ -172,7 +172,7 @@ void RasterizerSceneRD::_create_reflection_fast_filter(ReflectionData &rd, bool storage->get_effects()->cubemap_filter(rd.downsampled_radiance_cubemap, views, p_use_arrays); } -void RasterizerSceneRD::_create_reflection_importance_sample(ReflectionData &rd, bool p_use_arrays, int p_cube_side, int p_base_layer) { +void RendererSceneRenderRD::_create_reflection_importance_sample(ReflectionData &rd, bool p_use_arrays, int p_cube_side, int p_base_layer) { if (p_use_arrays) { //render directly to the layers storage->get_effects()->cubemap_roughness(rd.radiance_base_cubemap, rd.layers[p_base_layer].views[0], p_cube_side, sky_ggx_samples_quality, float(p_base_layer) / (rd.layers.size() - 1.0), rd.layers[p_base_layer].mipmaps[0].size.x); @@ -181,20 +181,18 @@ void RasterizerSceneRD::_create_reflection_importance_sample(ReflectionData &rd, } } -void RasterizerSceneRD::_update_reflection_mipmaps(ReflectionData &rd, int p_start, int p_end) { +void RendererSceneRenderRD::_update_reflection_mipmaps(ReflectionData &rd, int p_start, int p_end) { for (int i = p_start; i < p_end; i++) { - for (int j = 0; j < rd.layers[i].mipmaps.size() - 1; j++) { - for (int k = 0; k < 6; k++) { - RID view = rd.layers[i].mipmaps[j].views[k]; - RID texture = rd.layers[i].mipmaps[j + 1].views[k]; - Size2i size = rd.layers[i].mipmaps[j + 1].size; - storage->get_effects()->make_mipmap(view, texture, size); - } + for (int j = 0; j < rd.layers[i].views.size() - 1; j++) { + RID view = rd.layers[i].views[j]; + RID texture = rd.layers[i].views[j + 1]; + Size2i size = rd.layers[i].mipmaps[j + 1].size; + storage->get_effects()->cubemap_downsample(view, texture, size); } } } -void RasterizerSceneRD::_sdfgi_erase(RenderBuffers *rb) { +void RendererSceneRenderRD::_sdfgi_erase(RenderBuffers *rb) { for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) { const SDFGI::Cascade &c = rb->sdfgi->cascades[i]; RD::get_singleton()->free(c.light_data); @@ -236,9 +234,9 @@ void RasterizerSceneRD::_sdfgi_erase(RenderBuffers *rb) { rb->sdfgi = nullptr; } -const Vector3i RasterizerSceneRD::SDFGI::Cascade::DIRTY_ALL = Vector3i(0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF); +const Vector3i RendererSceneRenderRD::SDFGI::Cascade::DIRTY_ALL = Vector3i(0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF); -void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) { +void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) { Environment *env = environment_owner.getornull(p_environment); RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); bool needs_sdfgi = env && env->sdfgi_enabled; @@ -284,7 +282,7 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co tf_sdf.width = sdfgi->cascade_size; // Always 64x64 tf_sdf.height = sdfgi->cascade_size; tf_sdf.depth = sdfgi->cascade_size; - tf_sdf.type = RD::TEXTURE_TYPE_3D; + tf_sdf.texture_type = RD::TEXTURE_TYPE_3D; tf_sdf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; { @@ -341,7 +339,7 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co tf_probes.width = sdfgi->probe_axis_count * sdfgi->probe_axis_count; tf_probes.height = sdfgi->probe_axis_count * SDFGI::SH_SIZE; tf_probes.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; - tf_probes.type = RD::TEXTURE_TYPE_2D_ARRAY; + tf_probes.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; sdfgi->history_size = requested_history_size; @@ -351,7 +349,7 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co RD::TextureFormat tf_probe_average = tf_probes; tf_probe_average.format = RD::DATA_FORMAT_R32G32B32A32_SINT; //signed integer because SH are signed - tf_probe_average.type = RD::TEXTURE_TYPE_2D; + tf_probe_average.texture_type = RD::TEXTURE_TYPE_2D; sdfgi->lightprobe_history_scroll = RD::get_singleton()->texture_create(tf_probe_history, RD::TextureView()); sdfgi->lightprobe_average_scroll = RD::get_singleton()->texture_create(tf_probe_average, RD::TextureView()); @@ -378,7 +376,7 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co tf_ambient.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; //pack well with RGBE tf_ambient.width = sdfgi->probe_axis_count * sdfgi->probe_axis_count; tf_ambient.height = sdfgi->probe_axis_count; - tf_ambient.type = RD::TEXTURE_TYPE_2D_ARRAY; + tf_ambient.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; //lightprobe texture is an octahedral texture sdfgi->ambient_texture = RD::get_singleton()->texture_create(tf_ambient, RD::TextureView()); } @@ -443,21 +441,21 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(sdfgi->render_sdf[(passes & 1) ? 1 : 0]); //if passes are even, we read from buffer 0, else we read from buffer 1 uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; u.ids.push_back(sdfgi->render_albedo); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 3; for (int j = 0; j < 8; j++) { u.ids.push_back(sdfgi->render_occlusion[j]); @@ -466,21 +464,21 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 4; u.ids.push_back(sdfgi->render_emission); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 5; u.ids.push_back(sdfgi->render_emission_aniso); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 6; u.ids.push_back(sdfgi->render_geom_facing); uniforms.push_back(u); @@ -488,28 +486,28 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 7; u.ids.push_back(cascade.sdf_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 8; u.ids.push_back(sdfgi->occlusion_data); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 10; u.ids.push_back(cascade.solid_cell_dispatch_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 11; u.ids.push_back(cascade.solid_cell_buffer); uniforms.push_back(u); @@ -522,42 +520,42 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(sdfgi->render_albedo); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; u.ids.push_back(sdfgi->render_geom_facing); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 3; u.ids.push_back(sdfgi->render_emission); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 4; u.ids.push_back(sdfgi->render_emission_aniso); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 5; u.ids.push_back(cascade.solid_cell_dispatch_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 6; u.ids.push_back(cascade.solid_cell_buffer); uniforms.push_back(u); @@ -569,7 +567,7 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; for (int j = 0; j < 8; j++) { u.ids.push_back(sdfgi->render_occlusion[j]); @@ -578,7 +576,7 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; u.ids.push_back(sdfgi->occlusion_data); uniforms.push_back(u); @@ -596,12 +594,12 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co { RD::Uniform u; u.binding = 1; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { if (j < rb->sdfgi->cascades.size()) { u.ids.push_back(rb->sdfgi->cascades[j].sdf_tex); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } } uniforms.push_back(u); @@ -609,66 +607,73 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co { RD::Uniform u; u.binding = 2; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); } { RD::Uniform u; u.binding = 3; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(cascade.solid_cell_dispatch_buffer); uniforms.push_back(u); } { RD::Uniform u; u.binding = 4; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(cascade.solid_cell_buffer); uniforms.push_back(u); } { RD::Uniform u; u.binding = 5; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.ids.push_back(cascade.light_data); uniforms.push_back(u); } { RD::Uniform u; u.binding = 6; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.ids.push_back(cascade.light_aniso_0_tex); uniforms.push_back(u); } { RD::Uniform u; u.binding = 7; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.ids.push_back(cascade.light_aniso_1_tex); uniforms.push_back(u); } { RD::Uniform u; u.binding = 8; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.ids.push_back(rb->sdfgi->cascades_ubo); uniforms.push_back(u); } { RD::Uniform u; u.binding = 9; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(cascade.lights_buffer); uniforms.push_back(u); } { RD::Uniform u; u.binding = 10; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.ids.push_back(rb->sdfgi->lightprobe_texture); uniforms.push_back(u); } + { + RD::Uniform u; + u.binding = 11; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.push_back(rb->sdfgi->occlusion_texture); + uniforms.push_back(u); + } cascade.sdf_direct_light_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.direct_light.version_get_shader(sdfgi_shader.direct_light_shader, 0), 0); } @@ -678,14 +683,14 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(sdfgi->render_albedo); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; u.ids.push_back(sdfgi->render_sdf[0]); uniforms.push_back(u); @@ -698,14 +703,14 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(sdfgi->render_albedo); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; u.ids.push_back(sdfgi->render_sdf_half[0]); uniforms.push_back(u); @@ -719,14 +724,14 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(sdfgi->render_sdf[0]); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; u.ids.push_back(sdfgi->render_sdf[1]); uniforms.push_back(u); @@ -741,14 +746,14 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(sdfgi->render_sdf_half[0]); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; u.ids.push_back(sdfgi->render_sdf_half[1]); uniforms.push_back(u); @@ -764,21 +769,21 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(sdfgi->render_albedo); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; u.ids.push_back(sdfgi->render_sdf_half[(passes & 1) ? 0 : 1]); //reverse pass order because half size uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 3; u.ids.push_back(sdfgi->render_sdf[(passes & 1) ? 0 : 1]); //reverse pass order because it needs an extra JFA pass uniforms.push_back(u); @@ -793,14 +798,14 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(sdfgi->render_albedo); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; for (int i = 0; i < 8; i++) { u.ids.push_back(sdfgi->render_occlusion[i]); @@ -809,7 +814,7 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 3; u.ids.push_back(sdfgi->render_geom_facing); uniforms.push_back(u); @@ -826,12 +831,12 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co { RD::Uniform u; u.binding = 1; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { if (j < sdfgi->cascades.size()) { u.ids.push_back(sdfgi->cascades[j].sdf_tex); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } } uniforms.push_back(u); @@ -839,12 +844,12 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co { RD::Uniform u; u.binding = 2; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { if (j < sdfgi->cascades.size()) { u.ids.push_back(sdfgi->cascades[j].light_tex); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } } uniforms.push_back(u); @@ -852,12 +857,12 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co { RD::Uniform u; u.binding = 3; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { if (j < sdfgi->cascades.size()) { u.ids.push_back(sdfgi->cascades[j].light_aniso_0_tex); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } } uniforms.push_back(u); @@ -865,19 +870,19 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co { RD::Uniform u; u.binding = 4; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { if (j < sdfgi->cascades.size()) { u.ids.push_back(sdfgi->cascades[j].light_aniso_1_tex); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } } uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 6; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); @@ -885,14 +890,14 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 7; u.ids.push_back(sdfgi->cascades_ubo); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 8; u.ids.push_back(sdfgi->lightprobe_data); uniforms.push_back(u); @@ -900,14 +905,14 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 9; u.ids.push_back(sdfgi->cascades[i].lightprobe_history_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 10; u.ids.push_back(sdfgi->cascades[i].lightprobe_average_tex); uniforms.push_back(u); @@ -915,21 +920,21 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 11; u.ids.push_back(sdfgi->lightprobe_history_scroll); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 12; u.ids.push_back(sdfgi->lightprobe_average_scroll); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 13; RID parent_average; if (i < sdfgi->cascades.size() - 1) { @@ -942,7 +947,7 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 14; u.ids.push_back(sdfgi->ambient_texture); uniforms.push_back(u); @@ -951,7 +956,7 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co sdfgi->cascades[i].integrate_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, 0), 0); } - sdfgi->uses_multibounce = env->sdfgi_use_multibounce; + sdfgi->bounce_feedback = env->sdfgi_bounce_feedback; sdfgi->energy = env->sdfgi_energy; sdfgi->normal_bias = env->sdfgi_normal_bias; sdfgi->probe_bias = env->sdfgi_probe_bias; @@ -964,7 +969,7 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co //check for updates - sdfgi->uses_multibounce = env->sdfgi_use_multibounce; + sdfgi->bounce_feedback = env->sdfgi_bounce_feedback; sdfgi->energy = env->sdfgi_energy; sdfgi->normal_bias = env->sdfgi_normal_bias; sdfgi->probe_bias = env->sdfgi_probe_bias; @@ -1021,7 +1026,7 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co } } -int RasterizerSceneRD::sdfgi_get_pending_region_count(RID p_render_buffers) const { +int RendererSceneRenderRD::sdfgi_get_pending_region_count(RID p_render_buffers) const { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(rb == nullptr, 0); @@ -1048,7 +1053,7 @@ int RasterizerSceneRD::sdfgi_get_pending_region_count(RID p_render_buffers) cons return dirty_count; } -int RasterizerSceneRD::_sdfgi_get_pending_region_data(RID p_render_buffers, int p_region, Vector3i &r_local_offset, Vector3i &r_local_size, AABB &r_bounds) const { +int RendererSceneRenderRD::_sdfgi_get_pending_region_data(RID p_render_buffers, int p_region, Vector3i &r_local_offset, Vector3i &r_local_size, AABB &r_bounds) const { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(rb == nullptr, -1); ERR_FAIL_COND_V(rb->sdfgi == nullptr, -1); @@ -1108,7 +1113,7 @@ int RasterizerSceneRD::_sdfgi_get_pending_region_data(RID p_render_buffers, int return -1; } -AABB RasterizerSceneRD::sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const { +AABB RendererSceneRenderRD::sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const { AABB bounds; Vector3i from; Vector3i size; @@ -1118,7 +1123,7 @@ AABB RasterizerSceneRD::sdfgi_get_pending_region_bounds(RID p_render_buffers, in return bounds; } -uint32_t RasterizerSceneRD::sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const { +uint32_t RendererSceneRenderRD::sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const { AABB bounds; Vector3i from; Vector3i size; @@ -1126,7 +1131,7 @@ uint32_t RasterizerSceneRD::sdfgi_get_pending_region_cascade(RID p_render_buffer return _sdfgi_get_pending_region_data(p_render_buffers, p_region, from, size, bounds); } -void RasterizerSceneRD::_sdfgi_update_cascades(RID p_render_buffers) { +void RendererSceneRenderRD::_sdfgi_update_cascades(RID p_render_buffers) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(rb == nullptr); if (rb->sdfgi == nullptr) { @@ -1150,145 +1155,72 @@ void RasterizerSceneRD::_sdfgi_update_cascades(RID p_render_buffers) { cascade_data[i].pad = 0; } - RD::get_singleton()->buffer_update(rb->sdfgi->cascades_ubo, 0, sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES, cascade_data, true); + RD::get_singleton()->buffer_update(rb->sdfgi->cascades_ubo, 0, sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES, cascade_data, RD::BARRIER_MASK_COMPUTE); } -void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environment, const RID *p_directional_light_instances, uint32_t p_directional_light_count, const RID *p_positional_light_instances, uint32_t p_positional_light_count) { +void RendererSceneRenderRD::_sdfgi_update_light(RID p_render_buffers, RID p_environment) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(rb == nullptr); if (rb->sdfgi == nullptr) { return; } - Environment *env = environment_owner.getornull(p_environment); - - RENDER_TIMESTAMP(">SDFGI Update Probes"); - - /* Update Cascades UBO */ - _sdfgi_update_cascades(p_render_buffers); - /* Update Dynamic Lights Buffer */ - - RENDER_TIMESTAMP("Update Lights"); - - /* Update dynamic lights */ - - { - int32_t cascade_light_count[SDFGI::MAX_CASCADES]; - - for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) { - SDFGI::Cascade &cascade = rb->sdfgi->cascades[i]; - - SDGIShader::Light lights[SDFGI::MAX_DYNAMIC_LIGHTS]; - uint32_t idx = 0; - for (uint32_t j = 0; j < p_directional_light_count; j++) { - if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) { - break; - } - - LightInstance *li = light_instance_owner.getornull(p_directional_light_instances[j]); - ERR_CONTINUE(!li); - Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z); - dir.y *= rb->sdfgi->y_mult; - dir.normalize(); - lights[idx].direction[0] = dir.x; - lights[idx].direction[1] = dir.y; - lights[idx].direction[2] = dir.z; - Color color = storage->light_get_color(li->light); - color = color.to_linear(); - lights[idx].color[0] = color.r; - lights[idx].color[1] = color.g; - lights[idx].color[2] = color.b; - lights[idx].type = RS::LIGHT_DIRECTIONAL; - lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY); - lights[idx].has_shadow = storage->light_has_shadow(li->light); - - idx++; - } - AABB cascade_aabb; - cascade_aabb.position = Vector3((Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + cascade.position)) * cascade.cell_size; - cascade_aabb.size = Vector3(1, 1, 1) * rb->sdfgi->cascade_size * cascade.cell_size; + RD::get_singleton()->draw_command_begin_label("SDFGI Update dynamic Light"); - for (uint32_t j = 0; j < p_positional_light_count; j++) { - if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) { - break; - } + /* Update dynamic light */ - LightInstance *li = light_instance_owner.getornull(p_positional_light_instances[j]); - ERR_CONTINUE(!li); + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.direct_light_pipeline[SDGIShader::DIRECT_LIGHT_MODE_DYNAMIC]); - uint32_t max_sdfgi_cascade = storage->light_get_max_sdfgi_cascade(li->light); - if (i > max_sdfgi_cascade) { - continue; - } + SDGIShader::DirectLightPushConstant push_constant; - if (!cascade_aabb.intersects(li->aabb)) { - continue; - } + push_constant.grid_size[0] = rb->sdfgi->cascade_size; + push_constant.grid_size[1] = rb->sdfgi->cascade_size; + push_constant.grid_size[2] = rb->sdfgi->cascade_size; + push_constant.max_cascades = rb->sdfgi->cascades.size(); + push_constant.probe_axis_size = rb->sdfgi->probe_axis_count; + push_constant.bounce_feedback = rb->sdfgi->bounce_feedback; + push_constant.y_mult = rb->sdfgi->y_mult; + push_constant.use_occlusion = rb->sdfgi->uses_occlusion; - Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z); - //faster to not do this here - //dir.y *= rb->sdfgi->y_mult; - //dir.normalize(); - lights[idx].direction[0] = dir.x; - lights[idx].direction[1] = dir.y; - lights[idx].direction[2] = dir.z; - Vector3 pos = li->transform.origin; - pos.y *= rb->sdfgi->y_mult; - lights[idx].position[0] = pos.x; - lights[idx].position[1] = pos.y; - lights[idx].position[2] = pos.z; - Color color = storage->light_get_color(li->light); - color = color.to_linear(); - lights[idx].color[0] = color.r; - lights[idx].color[1] = color.g; - lights[idx].color[2] = color.b; - lights[idx].type = storage->light_get_type(li->light); - lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY); - lights[idx].has_shadow = storage->light_has_shadow(li->light); - lights[idx].attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION); - lights[idx].radius = storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE); - lights[idx].spot_angle = Math::deg2rad(storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE)); - lights[idx].spot_attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION); + for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) { + SDFGI::Cascade &cascade = rb->sdfgi->cascades[i]; + push_constant.light_count = rb->sdfgi->cascade_dynamic_light_count[i]; + push_constant.cascade = i; - idx++; - } + if (rb->sdfgi->cascades[i].all_dynamic_lights_dirty || sdfgi_frames_to_update_light == RS::ENV_SDFGI_UPDATE_LIGHT_IN_1_FRAME) { + push_constant.process_offset = 0; + push_constant.process_increment = 1; + } else { + static uint32_t frames_to_update_table[RS::ENV_SDFGI_UPDATE_LIGHT_MAX] = { + 1, 2, 4, 8, 16 + }; - if (idx > 0) { - RD::get_singleton()->buffer_update(cascade.lights_buffer, 0, idx * sizeof(SDGIShader::Light), lights, true); - } + uint32_t frames_to_update = frames_to_update_table[sdfgi_frames_to_update_light]; - cascade_light_count[i] = idx; + push_constant.process_offset = RSG::rasterizer->get_frame_number() % frames_to_update; + push_constant.process_increment = frames_to_update; } + rb->sdfgi->cascades[i].all_dynamic_lights_dirty = false; - RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.direct_light_pipeline[SDGIShader::DIRECT_LIGHT_MODE_DYNAMIC]); - - SDGIShader::DirectLightPushConstant push_constant; - - push_constant.grid_size[0] = rb->sdfgi->cascade_size; - push_constant.grid_size[1] = rb->sdfgi->cascade_size; - push_constant.grid_size[2] = rb->sdfgi->cascade_size; - push_constant.max_cascades = rb->sdfgi->cascades.size(); - push_constant.probe_axis_size = rb->sdfgi->probe_axis_count; - push_constant.multibounce = rb->sdfgi->uses_multibounce; - push_constant.y_mult = rb->sdfgi->y_mult; - - push_constant.process_offset = 0; - push_constant.process_increment = 1; - - for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) { - SDFGI::Cascade &cascade = rb->sdfgi->cascades[i]; - push_constant.light_count = cascade_light_count[i]; - push_constant.cascade = i; + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascade.sdf_direct_light_uniform_set, 0); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::DirectLightPushConstant)); + RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cascade.solid_cell_dispatch_buffer, 0); + } + RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_COMPUTE); + RD::get_singleton()->draw_command_end_label(); +} - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascade.sdf_direct_light_uniform_set, 0); - RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::DirectLightPushConstant)); - RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cascade.solid_cell_dispatch_buffer, 0); - } - RD::get_singleton()->compute_list_end(); +void RendererSceneRenderRD::_sdfgi_update_probes(RID p_render_buffers, RID p_environment) { + RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + ERR_FAIL_COND(rb == nullptr); + if (rb->sdfgi == nullptr) { + return; } - RENDER_TIMESTAMP("Raytrace"); + RD::get_singleton()->draw_command_begin_label("SDFGI Update Probes"); + + Environment *env = environment_owner.getornull(p_environment); SDGIShader::IntegratePushConstant push_constant; push_constant.grid_size[1] = rb->sdfgi->cascade_size; @@ -1298,7 +1230,7 @@ void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environm push_constant.probe_axis_size = rb->sdfgi->probe_axis_count; push_constant.history_index = rb->sdfgi->render_pass % rb->sdfgi->history_size; push_constant.history_size = rb->sdfgi->history_size; - static const uint32_t ray_count[RS::ENV_SDFGI_RAY_COUNT_MAX] = { 8, 16, 32, 64, 96, 128 }; + static const uint32_t ray_count[RS::ENV_SDFGI_RAY_COUNT_MAX] = { 4, 8, 16, 32, 64, 96, 128 }; push_constant.ray_count = ray_count[sdfgi_ray_count]; push_constant.ray_bias = rb->sdfgi->probe_bias; push_constant.image_size[0] = rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count; @@ -1333,7 +1265,7 @@ void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environm { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 0; u.ids.push_back(sky->radiance); uniforms.push_back(u); @@ -1341,7 +1273,7 @@ void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environm { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 1; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); @@ -1357,7 +1289,7 @@ void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environm rb->sdfgi->render_pass++; - RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(true); RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.integrate_pipeline[SDGIShader::INTEGRATE_MODE_PROCESS]); int32_t probe_divisor = rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR; @@ -1371,14 +1303,47 @@ void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environm RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sky_uniform_set, 1); RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::IntegratePushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count, rb->sdfgi->probe_axis_count, 1, 8, 8, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count, rb->sdfgi->probe_axis_count, 1); + } + + //end later after raster to avoid barriering on layout changes + //RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); + + RD::get_singleton()->draw_command_end_label(); +} + +void RendererSceneRenderRD::_sdfgi_store_probes(RID p_render_buffers) { + RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + ERR_FAIL_COND(rb == nullptr); + if (rb->sdfgi == nullptr) { + return; } - RD::get_singleton()->compute_list_add_barrier(compute_list); //wait until done + RD::get_singleton()->barrier(RD::BARRIER_MASK_COMPUTE, RD::BARRIER_MASK_COMPUTE); + RD::get_singleton()->draw_command_begin_label("SDFGI Store Probes"); + + SDGIShader::IntegratePushConstant push_constant; + push_constant.grid_size[1] = rb->sdfgi->cascade_size; + push_constant.grid_size[2] = rb->sdfgi->cascade_size; + push_constant.grid_size[0] = rb->sdfgi->cascade_size; + push_constant.max_cascades = rb->sdfgi->cascades.size(); + push_constant.probe_axis_size = rb->sdfgi->probe_axis_count; + push_constant.history_index = rb->sdfgi->render_pass % rb->sdfgi->history_size; + push_constant.history_size = rb->sdfgi->history_size; + static const uint32_t ray_count[RS::ENV_SDFGI_RAY_COUNT_MAX] = { 4, 8, 16, 32, 64, 96, 128 }; + push_constant.ray_count = ray_count[sdfgi_ray_count]; + push_constant.ray_bias = rb->sdfgi->probe_bias; + push_constant.image_size[0] = rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count; + push_constant.image_size[1] = rb->sdfgi->probe_axis_count; + push_constant.store_ambient_texture = false; + + push_constant.sky_mode = 0; + push_constant.y_mult = rb->sdfgi->y_mult; // Then store values into the lightprobe texture. Separating these steps has a small performance hit, but it allows for multiple bounces RENDER_TIMESTAMP("Average Probes"); + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.integrate_pipeline[SDGIShader::INTEGRATE_MODE_STORE]); //convert to octahedral to store @@ -1388,20 +1353,22 @@ void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environm for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) { push_constant.cascade = i; RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[i].integrate_uniform_set, 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdfgi_shader.integrate_default_sky_uniform_set, 1); RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::IntegratePushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, rb->sdfgi->probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, 1, 8, 8, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, rb->sdfgi->probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, 1); } - RD::get_singleton()->compute_list_end(); + RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_COMPUTE); - RENDER_TIMESTAMP("<SDFGI Update Probes"); + RD::get_singleton()->draw_command_end_label(); } - -void RasterizerSceneRD::_setup_giprobes(RID p_render_buffers, const Transform &p_transform, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, uint32_t &r_gi_probes_used) { +void RendererSceneRenderRD::_setup_giprobes(RID p_render_buffers, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, uint32_t &r_gi_probes_used) { r_gi_probes_used = 0; RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(rb == nullptr); + RD::get_singleton()->draw_command_begin_label("GIProbes Setup"); + RID gi_probe_buffer = render_buffers_get_gi_probe_buffer(p_render_buffers); GI::GIProbeData gi_probe_data[RenderBuffers::MAX_GIPROBES]; @@ -1412,8 +1379,8 @@ void RasterizerSceneRD::_setup_giprobes(RID p_render_buffers, const Transform &p for (int i = 0; i < RenderBuffers::MAX_GIPROBES; i++) { RID texture; - if (i < p_gi_probe_cull_count) { - GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_gi_probe_cull_result[i]); + if (i < (int)p_gi_probes.size()) { + GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_gi_probes[i]); if (gipi) { texture = gipi->texture; @@ -1460,7 +1427,7 @@ void RasterizerSceneRD::_setup_giprobes(RID p_render_buffers, const Transform &p } if (texture == RID()) { - texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); + texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); } if (texture != rb->giprobe_textures[i]) { @@ -1484,57 +1451,26 @@ void RasterizerSceneRD::_setup_giprobes(RID p_render_buffers, const Transform &p } } - if (p_gi_probe_cull_count > 0) { - RD::get_singleton()->buffer_update(gi_probe_buffer, 0, sizeof(GI::GIProbeData) * MIN(RenderBuffers::MAX_GIPROBES, p_gi_probe_cull_count), gi_probe_data, true); + if (p_gi_probes.size() > 0) { + RD::get_singleton()->buffer_update(gi_probe_buffer, 0, sizeof(GI::GIProbeData) * MIN((uint64_t)RenderBuffers::MAX_GIPROBES, p_gi_probes.size()), gi_probe_data, RD::BARRIER_MASK_COMPUTE); } -} -void RasterizerSceneRD::_process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_ambient_buffer, RID p_reflection_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count) { - RENDER_TIMESTAMP("Render GI"); + RD::get_singleton()->draw_command_end_label(); +} +void RendererSceneRenderRD::_pre_process_gi(RID p_render_buffers, const Transform &p_transform) { + // Do the required buffer transfers and setup before the depth-pre pass, this way GI can + // run in parallel during depth-pre pass and shadow rendering. RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(rb == nullptr); - Environment *env = environment_owner.getornull(p_environment); - GI::PushConstant push_constant; - - push_constant.screen_size[0] = rb->width; - push_constant.screen_size[1] = rb->height; - push_constant.z_near = p_projection.get_z_near(); - push_constant.z_far = p_projection.get_z_far(); - push_constant.orthogonal = p_projection.is_orthogonal(); - push_constant.proj_info[0] = -2.0f / (rb->width * p_projection.matrix[0][0]); - push_constant.proj_info[1] = -2.0f / (rb->height * p_projection.matrix[1][1]); - push_constant.proj_info[2] = (1.0f - p_projection.matrix[0][2]) / p_projection.matrix[0][0]; - push_constant.proj_info[3] = (1.0f + p_projection.matrix[1][2]) / p_projection.matrix[1][1]; - push_constant.max_giprobes = MIN(RenderBuffers::MAX_GIPROBES, p_gi_probe_cull_count); - push_constant.high_quality_vct = gi_probe_quality == RS::GI_PROBE_QUALITY_HIGH; - push_constant.use_sdfgi = rb->sdfgi != nullptr; + /* Update Cascades UBO */ - if (env) { - push_constant.ao_color[0] = env->ao_color.r; - push_constant.ao_color[1] = env->ao_color.g; - push_constant.ao_color[2] = env->ao_color.b; - } else { - push_constant.ao_color[0] = 0; - push_constant.ao_color[1] = 0; - push_constant.ao_color[2] = 0; - } + if (rb->sdfgi) { + /* Update general SDFGI Buffer */ - push_constant.cam_rotation[0] = p_transform.basis[0][0]; - push_constant.cam_rotation[1] = p_transform.basis[1][0]; - push_constant.cam_rotation[2] = p_transform.basis[2][0]; - push_constant.cam_rotation[3] = 0; - push_constant.cam_rotation[4] = p_transform.basis[0][1]; - push_constant.cam_rotation[5] = p_transform.basis[1][1]; - push_constant.cam_rotation[6] = p_transform.basis[2][1]; - push_constant.cam_rotation[7] = 0; - push_constant.cam_rotation[8] = p_transform.basis[0][2]; - push_constant.cam_rotation[9] = p_transform.basis[1][2]; - push_constant.cam_rotation[10] = p_transform.basis[2][2]; - push_constant.cam_rotation[11] = 0; + _sdfgi_update_cascades(p_render_buffers); - if (rb->sdfgi) { GI::SDFGIData sdfgi_data; sdfgi_data.grid_size[0] = rb->sdfgi->cascade_size; @@ -1601,20 +1537,183 @@ void RasterizerSceneRD::_process_gi(RID p_render_buffers, RID p_normal_roughness c.to_cell = 1.0 / rb->sdfgi->cascades[i].cell_size; } - RD::get_singleton()->buffer_update(gi.sdfgi_ubo, 0, sizeof(GI::SDFGIData), &sdfgi_data, true); + RD::get_singleton()->buffer_update(gi.sdfgi_ubo, 0, sizeof(GI::SDFGIData), &sdfgi_data, RD::BARRIER_MASK_COMPUTE); + + /* Update dynamic lights in SDFGI cascades */ + + for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) { + SDFGI::Cascade &cascade = rb->sdfgi->cascades[i]; + + SDGIShader::Light lights[SDFGI::MAX_DYNAMIC_LIGHTS]; + uint32_t idx = 0; + for (uint32_t j = 0; j < (uint32_t)render_state.sdfgi_update_data->directional_lights->size(); j++) { + if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) { + break; + } + + LightInstance *li = light_instance_owner.getornull(render_state.sdfgi_update_data->directional_lights->get(j)); + ERR_CONTINUE(!li); + + if (storage->light_directional_is_sky_only(li->light)) { + continue; + } + + Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z); + dir.y *= rb->sdfgi->y_mult; + dir.normalize(); + lights[idx].direction[0] = dir.x; + lights[idx].direction[1] = dir.y; + lights[idx].direction[2] = dir.z; + Color color = storage->light_get_color(li->light); + color = color.to_linear(); + lights[idx].color[0] = color.r; + lights[idx].color[1] = color.g; + lights[idx].color[2] = color.b; + lights[idx].type = RS::LIGHT_DIRECTIONAL; + lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY); + lights[idx].has_shadow = storage->light_has_shadow(li->light); + + idx++; + } + + AABB cascade_aabb; + cascade_aabb.position = Vector3((Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + cascade.position)) * cascade.cell_size; + cascade_aabb.size = Vector3(1, 1, 1) * rb->sdfgi->cascade_size * cascade.cell_size; + + for (uint32_t j = 0; j < render_state.sdfgi_update_data->positional_light_count; j++) { + if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) { + break; + } + + LightInstance *li = light_instance_owner.getornull(render_state.sdfgi_update_data->positional_light_instances[j]); + ERR_CONTINUE(!li); + + uint32_t max_sdfgi_cascade = storage->light_get_max_sdfgi_cascade(li->light); + if (i > max_sdfgi_cascade) { + continue; + } + + if (!cascade_aabb.intersects(li->aabb)) { + continue; + } + + Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z); + //faster to not do this here + //dir.y *= rb->sdfgi->y_mult; + //dir.normalize(); + lights[idx].direction[0] = dir.x; + lights[idx].direction[1] = dir.y; + lights[idx].direction[2] = dir.z; + Vector3 pos = li->transform.origin; + pos.y *= rb->sdfgi->y_mult; + lights[idx].position[0] = pos.x; + lights[idx].position[1] = pos.y; + lights[idx].position[2] = pos.z; + Color color = storage->light_get_color(li->light); + color = color.to_linear(); + lights[idx].color[0] = color.r; + lights[idx].color[1] = color.g; + lights[idx].color[2] = color.b; + lights[idx].type = storage->light_get_type(li->light); + lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY); + lights[idx].has_shadow = storage->light_has_shadow(li->light); + lights[idx].attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION); + lights[idx].radius = storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE); + lights[idx].cos_spot_angle = Math::cos(Math::deg2rad(storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE))); + lights[idx].inv_spot_attenuation = 1.0f / storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION); + + idx++; + } + + if (idx > 0) { + RD::get_singleton()->buffer_update(cascade.lights_buffer, 0, idx * sizeof(SDGIShader::Light), lights, RD::BARRIER_MASK_COMPUTE); + } + + rb->sdfgi->cascade_dynamic_light_count[i] = idx; + } + } +} + +void RendererSceneRenderRD::_process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, const PagedArray<RID> &p_gi_probes) { + RD::get_singleton()->draw_command_begin_label("GI Render"); + + RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + ERR_FAIL_COND(rb == nullptr); + Environment *env = environment_owner.getornull(p_environment); + + if (rb->ambient_buffer.is_null() || rb->using_half_size_gi != gi.half_resolution) { + if (rb->ambient_buffer.is_valid()) { + RD::get_singleton()->free(rb->ambient_buffer); + RD::get_singleton()->free(rb->reflection_buffer); + } + + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tf.width = rb->width; + tf.height = rb->height; + if (gi.half_resolution) { + tf.width >>= 1; + tf.height >>= 1; + } + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + rb->reflection_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); + rb->ambient_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); + rb->using_half_size_gi = gi.half_resolution; + + _render_buffers_uniform_set_changed(p_render_buffers); + } + + GI::PushConstant push_constant; + + push_constant.screen_size[0] = rb->width; + push_constant.screen_size[1] = rb->height; + push_constant.z_near = p_projection.get_z_near(); + push_constant.z_far = p_projection.get_z_far(); + push_constant.orthogonal = p_projection.is_orthogonal(); + push_constant.proj_info[0] = -2.0f / (rb->width * p_projection.matrix[0][0]); + push_constant.proj_info[1] = -2.0f / (rb->height * p_projection.matrix[1][1]); + push_constant.proj_info[2] = (1.0f - p_projection.matrix[0][2]) / p_projection.matrix[0][0]; + push_constant.proj_info[3] = (1.0f + p_projection.matrix[1][2]) / p_projection.matrix[1][1]; + push_constant.max_giprobes = MIN((uint64_t)RenderBuffers::MAX_GIPROBES, p_gi_probes.size()); + push_constant.high_quality_vct = gi_probe_quality == RS::GI_PROBE_QUALITY_HIGH; + + bool use_sdfgi = rb->sdfgi != nullptr; + bool use_giprobes = push_constant.max_giprobes > 0; + + if (env) { + push_constant.ao_color[0] = env->ao_color.r; + push_constant.ao_color[1] = env->ao_color.g; + push_constant.ao_color[2] = env->ao_color.b; + } else { + push_constant.ao_color[0] = 0; + push_constant.ao_color[1] = 0; + push_constant.ao_color[2] = 0; } + push_constant.cam_rotation[0] = p_transform.basis[0][0]; + push_constant.cam_rotation[1] = p_transform.basis[1][0]; + push_constant.cam_rotation[2] = p_transform.basis[2][0]; + push_constant.cam_rotation[3] = 0; + push_constant.cam_rotation[4] = p_transform.basis[0][1]; + push_constant.cam_rotation[5] = p_transform.basis[1][1]; + push_constant.cam_rotation[6] = p_transform.basis[2][1]; + push_constant.cam_rotation[7] = 0; + push_constant.cam_rotation[8] = p_transform.basis[0][2]; + push_constant.cam_rotation[9] = p_transform.basis[1][2]; + push_constant.cam_rotation[10] = p_transform.basis[2][2]; + push_constant.cam_rotation[11] = 0; + if (rb->gi_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->gi_uniform_set)) { Vector<RD::Uniform> uniforms; { RD::Uniform u; u.binding = 1; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { if (rb->sdfgi && j < rb->sdfgi->cascades.size()) { u.ids.push_back(rb->sdfgi->cascades[j].sdf_tex); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } } uniforms.push_back(u); @@ -1622,12 +1721,12 @@ void RasterizerSceneRD::_process_gi(RID p_render_buffers, RID p_normal_roughness { RD::Uniform u; u.binding = 2; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { if (rb->sdfgi && j < rb->sdfgi->cascades.size()) { u.ids.push_back(rb->sdfgi->cascades[j].light_tex); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } } uniforms.push_back(u); @@ -1635,12 +1734,12 @@ void RasterizerSceneRD::_process_gi(RID p_render_buffers, RID p_normal_roughness { RD::Uniform u; u.binding = 3; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { if (rb->sdfgi && j < rb->sdfgi->cascades.size()) { u.ids.push_back(rb->sdfgi->cascades[j].light_aniso_0_tex); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } } uniforms.push_back(u); @@ -1648,37 +1747,37 @@ void RasterizerSceneRD::_process_gi(RID p_render_buffers, RID p_normal_roughness { RD::Uniform u; u.binding = 4; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { if (rb->sdfgi && j < rb->sdfgi->cascades.size()) { u.ids.push_back(rb->sdfgi->cascades[j].light_aniso_1_tex); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } } uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 5; if (rb->sdfgi) { u.ids.push_back(rb->sdfgi->occlusion_texture); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 6; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 7; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); @@ -1686,70 +1785,70 @@ void RasterizerSceneRD::_process_gi(RID p_render_buffers, RID p_normal_roughness { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 9; - u.ids.push_back(p_ambient_buffer); + u.ids.push_back(rb->ambient_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 10; - u.ids.push_back(p_reflection_buffer); + u.ids.push_back(rb->reflection_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 11; if (rb->sdfgi) { u.ids.push_back(rb->sdfgi->lightprobe_texture); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE)); } uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 12; u.ids.push_back(rb->depth_texture); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 13; u.ids.push_back(p_normal_roughness_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 14; - RID buffer = p_gi_probe_buffer.is_valid() ? p_gi_probe_buffer : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK); + RID buffer = p_gi_probe_buffer.is_valid() ? p_gi_probe_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); u.ids.push_back(buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 15; u.ids.push_back(gi.sdfgi_ubo); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 16; u.ids.push_back(rb->giprobe_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 17; for (int i = 0; i < RenderBuffers::MAX_GIPROBES; i++) { u.ids.push_back(rb->giprobe_textures[i]); @@ -1760,19 +1859,36 @@ void RasterizerSceneRD::_process_gi(RID p_render_buffers, RID p_normal_roughness rb->gi_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi.shader.version_get_shader(gi.shader_version, 0), 0); } - RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi.pipelines[0]); + GI::Mode mode; + + if (rb->using_half_size_gi) { + mode = (use_sdfgi && use_giprobes) ? GI::MODE_HALF_RES_COMBINED : (use_sdfgi ? GI::MODE_HALF_RES_SDFGI : GI::MODE_HALF_RES_GIPROBE); + } else { + mode = (use_sdfgi && use_giprobes) ? GI::MODE_COMBINED : (use_sdfgi ? GI::MODE_SDFGI : GI::MODE_GIPROBE); + } + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(true); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi.pipelines[mode]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->gi_uniform_set, 0); RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GI::PushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width, rb->height, 1, 8, 8, 1); - RD::get_singleton()->compute_list_end(); + + if (rb->using_half_size_gi) { + RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width >> 1, rb->height >> 1, 1); + } else { + RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width, rb->height, 1); + } + //do barrier later to allow oeverlap + //RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //no barriers, let other compute, raster and transfer happen at the same time + RD::get_singleton()->draw_command_end_label(); } -RID RasterizerSceneRD::sky_create() { - return sky_owner.make_rid(Sky()); +RID RendererSceneRenderRD::sky_allocate() { + return sky_owner.allocate_rid(); +} +void RendererSceneRenderRD::sky_initialize(RID p_rid) { + sky_owner.initialize_rid(p_rid, Sky()); } -void RasterizerSceneRD::_sky_invalidate(Sky *p_sky) { +void RendererSceneRenderRD::_sky_invalidate(Sky *p_sky) { if (!p_sky->dirty) { p_sky->dirty = true; p_sky->dirty_list = dirty_sky_list; @@ -1780,7 +1896,7 @@ void RasterizerSceneRD::_sky_invalidate(Sky *p_sky) { } } -void RasterizerSceneRD::sky_set_radiance_size(RID p_sky, int p_radiance_size) { +void RendererSceneRenderRD::sky_set_radiance_size(RID p_sky, int p_radiance_size) { Sky *sky = sky_owner.getornull(p_sky); ERR_FAIL_COND(!sky); ERR_FAIL_COND(p_radiance_size < 32 || p_radiance_size > 2048); @@ -1802,7 +1918,7 @@ void RasterizerSceneRD::sky_set_radiance_size(RID p_sky, int p_radiance_size) { _clear_reflection_data(sky->reflection); } -void RasterizerSceneRD::sky_set_mode(RID p_sky, RS::SkyMode p_mode) { +void RendererSceneRenderRD::sky_set_mode(RID p_sky, RS::SkyMode p_mode) { Sky *sky = sky_owner.getornull(p_sky); ERR_FAIL_COND(!sky); @@ -1825,14 +1941,14 @@ void RasterizerSceneRD::sky_set_mode(RID p_sky, RS::SkyMode p_mode) { _clear_reflection_data(sky->reflection); } -void RasterizerSceneRD::sky_set_material(RID p_sky, RID p_material) { +void RendererSceneRenderRD::sky_set_material(RID p_sky, RID p_material) { Sky *sky = sky_owner.getornull(p_sky); ERR_FAIL_COND(!sky); sky->material = p_material; _sky_invalidate(sky); } -Ref<Image> RasterizerSceneRD::sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) { +Ref<Image> RendererSceneRenderRD::sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) { Sky *sky = sky_owner.getornull(p_sky); ERR_FAIL_COND_V(!sky, Ref<Image>()); @@ -1868,7 +1984,7 @@ Ref<Image> RasterizerSceneRD::sky_bake_panorama(RID p_sky, float p_energy, bool return Ref<Image>(); } -void RasterizerSceneRD::_update_dirty_skys() { +void RendererSceneRenderRD::_update_dirty_skys() { Sky *sky = dirty_sky_list; while (sky) { @@ -1892,7 +2008,7 @@ void RasterizerSceneRD::_update_dirty_skys() { RD::TextureFormat tf; tf.array_layers = layers * 6; tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; - tf.type = RD::TEXTURE_TYPE_CUBE_ARRAY; + tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY; tf.mipmaps = mipmaps; tf.width = w; tf.height = h; @@ -1907,7 +2023,7 @@ void RasterizerSceneRD::_update_dirty_skys() { RD::TextureFormat tf; tf.array_layers = 6; tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; - tf.type = RD::TEXTURE_TYPE_CUBE; + tf.texture_type = RD::TEXTURE_TYPE_CUBE; tf.mipmaps = MIN(mipmaps, layers); tf.width = w; tf.height = h; @@ -1927,7 +2043,7 @@ void RasterizerSceneRD::_update_dirty_skys() { tformat.width = sky->screen_size.x / 2; tformat.height = sky->screen_size.y / 2; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; - tformat.type = RD::TEXTURE_TYPE_2D; + tformat.texture_type = RD::TEXTURE_TYPE_2D; sky->half_res_pass = RD::get_singleton()->texture_create(tformat, RD::TextureView()); Vector<RID> texs; @@ -1942,7 +2058,7 @@ void RasterizerSceneRD::_update_dirty_skys() { tformat.width = sky->screen_size.x / 4; tformat.height = sky->screen_size.y / 4; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; - tformat.type = RD::TEXTURE_TYPE_2D; + tformat.texture_type = RD::TEXTURE_TYPE_2D; sky->quarter_res_pass = RD::get_singleton()->texture_create(tformat, RD::TextureView()); Vector<RID> texs; @@ -1972,14 +2088,14 @@ void RasterizerSceneRD::_update_dirty_skys() { dirty_sky_list = nullptr; } -RID RasterizerSceneRD::sky_get_radiance_texture_rd(RID p_sky) const { +RID RendererSceneRenderRD::sky_get_radiance_texture_rd(RID p_sky) const { Sky *sky = sky_owner.getornull(p_sky); ERR_FAIL_COND_V(!sky, RID()); return sky->radiance; } -RID RasterizerSceneRD::sky_get_radiance_uniform_set_rd(RID p_sky, RID p_shader, int p_set) const { +RID RendererSceneRenderRD::sky_get_radiance_uniform_set_rd(RID p_sky, RID p_shader, int p_set) const { Sky *sky = sky_owner.getornull(p_sky); ERR_FAIL_COND_V(!sky, RID()); @@ -1989,7 +2105,7 @@ RID RasterizerSceneRD::sky_get_radiance_uniform_set_rd(RID p_sky, RID p_shader, Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 0; u.ids.push_back(sky->radiance); uniforms.push_back(u); @@ -2002,25 +2118,25 @@ RID RasterizerSceneRD::sky_get_radiance_uniform_set_rd(RID p_sky, RID p_shader, return sky->uniform_set; } -RID RasterizerSceneRD::_get_sky_textures(Sky *p_sky, SkyTextureSetVersion p_version) { +RID RendererSceneRenderRD::_get_sky_textures(Sky *p_sky, SkyTextureSetVersion p_version) { if (p_sky->texture_uniform_sets[p_version].is_valid() && RD::get_singleton()->uniform_set_is_valid(p_sky->texture_uniform_sets[p_version])) { return p_sky->texture_uniform_sets[p_version]; } Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 0; if (p_sky->radiance.is_valid() && p_version <= SKY_TEXTURE_SET_QUARTER_RES) { u.ids.push_back(p_sky->radiance); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); } uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; // half res if (p_sky->half_res_pass.is_valid() && p_version != SKY_TEXTURE_SET_HALF_RES && p_version != SKY_TEXTURE_SET_CUBEMAP_HALF_RES) { if (p_version >= SKY_TEXTURE_SET_CUBEMAP) { @@ -2030,16 +2146,16 @@ RID RasterizerSceneRD::_get_sky_textures(Sky *p_sky, SkyTextureSetVersion p_vers } } else { if (p_version < SKY_TEXTURE_SET_CUBEMAP) { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE)); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); } } uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; // quarter res if (p_sky->quarter_res_pass.is_valid() && p_version != SKY_TEXTURE_SET_QUARTER_RES && p_version != SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES) { if (p_version >= SKY_TEXTURE_SET_CUBEMAP) { @@ -2049,9 +2165,9 @@ RID RasterizerSceneRD::_get_sky_textures(Sky *p_sky, SkyTextureSetVersion p_vers } } else { if (p_version < SKY_TEXTURE_SET_CUBEMAP) { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE)); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); } } uniforms.push_back(u); @@ -2061,14 +2177,14 @@ RID RasterizerSceneRD::_get_sky_textures(Sky *p_sky, SkyTextureSetVersion p_vers return p_sky->texture_uniform_sets[p_version]; } -RID RasterizerSceneRD::sky_get_material(RID p_sky) const { +RID RendererSceneRenderRD::sky_get_material(RID p_sky) const { Sky *sky = sky_owner.getornull(p_sky); ERR_FAIL_COND_V(!sky, RID()); return sky->material; } -void RasterizerSceneRD::_draw_sky(bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform) { +void RendererSceneRenderRD::_draw_sky(bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform) { ERR_FAIL_COND(!is_environment(p_environment)); SkyMaterialData *material = nullptr; @@ -2084,7 +2200,7 @@ void RasterizerSceneRD::_draw_sky(bool p_can_continue_color, bool p_can_continue sky_material = sky_get_material(environment_get_sky(p_environment)); if (sky_material.is_valid()) { - material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY); + material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); if (!material || !material->shader_data->valid) { material = nullptr; } @@ -2092,13 +2208,13 @@ void RasterizerSceneRD::_draw_sky(bool p_can_continue_color, bool p_can_continue if (!material) { sky_material = sky_shader.default_material; - material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY); + material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); } } if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) { sky_material = sky_scene_state.fog_material; - material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY); + material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); } ERR_FAIL_COND(!material); @@ -2129,7 +2245,7 @@ void RasterizerSceneRD::_draw_sky(bool p_can_continue_color, bool p_can_continue sky_transform = p_transform.basis * sky_transform; if (shader_data->uses_quarter_res) { - RenderPipelineVertexFormatCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_QUARTER_RES]; + PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_QUARTER_RES]; RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_QUARTER_RES); @@ -2142,7 +2258,7 @@ void RasterizerSceneRD::_draw_sky(bool p_can_continue_color, bool p_can_continue } if (shader_data->uses_half_res) { - RenderPipelineVertexFormatCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_HALF_RES]; + PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_HALF_RES]; RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_HALF_RES); @@ -2154,7 +2270,7 @@ void RasterizerSceneRD::_draw_sky(bool p_can_continue_color, bool p_can_continue RD::get_singleton()->draw_list_end(); } - RenderPipelineVertexFormatCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_BACKGROUND]; + PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_BACKGROUND]; RID texture_uniform_set; if (sky) { @@ -2168,7 +2284,7 @@ void RasterizerSceneRD::_draw_sky(bool p_can_continue_color, bool p_can_continue RD::get_singleton()->draw_list_end(); } -void RasterizerSceneRD::_setup_sky(RID p_environment, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size) { +void RendererSceneRenderRD::_setup_sky(RID p_environment, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size) { ERR_FAIL_COND(!is_environment(p_environment)); SkyMaterialData *material = nullptr; @@ -2186,7 +2302,7 @@ void RasterizerSceneRD::_setup_sky(RID p_environment, RID p_render_buffers, cons sky_material = sky_get_material(environment_get_sky(p_environment)); if (sky_material.is_valid()) { - material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY); + material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); if (!material || !material->shader_data->valid) { material = nullptr; } @@ -2194,7 +2310,7 @@ void RasterizerSceneRD::_setup_sky(RID p_environment, RID p_render_buffers, cons if (!material) { sky_material = sky_shader.default_material; - material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY); + material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); } ERR_FAIL_COND(!material); @@ -2237,7 +2353,7 @@ void RasterizerSceneRD::_setup_sky(RID p_environment, RID p_render_buffers, cons if (shader_data->uses_time && time - sky->prev_time > 0.00001) { sky->prev_time = time; sky->reflection.dirty = true; - RenderingServerRaster::redraw_request(); + RenderingServerDefault::redraw_request(); } if (material != sky->prev_material) { @@ -2283,9 +2399,9 @@ void RasterizerSceneRD::_setup_sky(RID p_environment, RID p_render_buffers, cons } if (light_data_dirty) { - RD::get_singleton()->buffer_update(sky_scene_state.directional_light_buffer, 0, sizeof(SkyDirectionalLightData) * sky_scene_state.max_directional_lights, sky_scene_state.directional_lights, true); + RD::get_singleton()->buffer_update(sky_scene_state.directional_light_buffer, 0, sizeof(SkyDirectionalLightData) * sky_scene_state.max_directional_lights, sky_scene_state.directional_lights); - RasterizerSceneRD::SkyDirectionalLightData *temp = sky_scene_state.last_frame_directional_lights; + RendererSceneRenderRD::SkyDirectionalLightData *temp = sky_scene_state.last_frame_directional_lights; sky_scene_state.last_frame_directional_lights = sky_scene_state.directional_lights; sky_scene_state.directional_lights = temp; sky_scene_state.last_frame_directional_light_count = sky_scene_state.ubo.directional_light_count; @@ -2335,10 +2451,10 @@ void RasterizerSceneRD::_setup_sky(RID p_environment, RID p_render_buffers, cons sky_scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy; sky_scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_environment); - RD::get_singleton()->buffer_update(sky_scene_state.uniform_buffer, 0, sizeof(SkySceneState::UBO), &sky_scene_state.ubo, true); + RD::get_singleton()->buffer_update(sky_scene_state.uniform_buffer, 0, sizeof(SkySceneState::UBO), &sky_scene_state.ubo); } -void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform) { +void RendererSceneRenderRD::_update_sky(RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform) { ERR_FAIL_COND(!is_environment(p_environment)); Sky *sky = sky_owner.getornull(environment_get_sky(p_environment)); @@ -2349,7 +2465,7 @@ void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_pro SkyMaterialData *material = nullptr; if (sky_material.is_valid()) { - material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY); + material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); if (!material || !material->shader_data->valid) { material = nullptr; } @@ -2357,7 +2473,7 @@ void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_pro if (!material) { sky_material = sky_shader.default_material; - material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY); + material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); } ERR_FAIL_COND(!material); @@ -2418,7 +2534,7 @@ void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_pro cm = correction * cm; if (shader_data->uses_quarter_res) { - RenderPipelineVertexFormatCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_QUARTER_RES]; + PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_QUARTER_RES]; Vector<Color> clear_colors; clear_colors.push_back(Color(0.0, 0.0, 0.0)); @@ -2436,7 +2552,7 @@ void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_pro } if (shader_data->uses_half_res) { - RenderPipelineVertexFormatCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_HALF_RES]; + PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_HALF_RES]; Vector<Color> clear_colors; clear_colors.push_back(Color(0.0, 0.0, 0.0)); @@ -2454,7 +2570,7 @@ void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_pro } RD::DrawListID cubemap_draw_list; - RenderPipelineVertexFormatCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP]; + PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP]; for (int i = 0; i < 6; i++) { Transform local_view; @@ -2505,7 +2621,7 @@ void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_pro /* SKY SHADER */ -void RasterizerSceneRD::SkyShaderData::set_code(const String &p_code) { +void RendererSceneRenderRD::SkyShaderData::set_code(const String &p_code) { //compile code = p_code; @@ -2554,7 +2670,7 @@ void RasterizerSceneRD::SkyShaderData::set_code(const String &p_code) { actions.uniforms = &uniforms; - RasterizerSceneRD *scene_singleton = (RasterizerSceneRD *)RasterizerSceneRD::singleton; + RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton; Error err = scene_singleton->sky_shader.compiler.compile(RS::SHADER_SKY, code, &actions, path, gen_code); @@ -2599,7 +2715,7 @@ void RasterizerSceneRD::SkyShaderData::set_code(const String &p_code) { valid = true; } -void RasterizerSceneRD::SkyShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { +void RendererSceneRenderRD::SkyShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { if (!p_texture.is_valid()) { default_texture_params.erase(p_name); } else { @@ -2607,7 +2723,7 @@ void RasterizerSceneRD::SkyShaderData::set_default_texture_param(const StringNam } } -void RasterizerSceneRD::SkyShaderData::get_param_list(List<PropertyInfo> *p_param_list) const { +void RendererSceneRenderRD::SkyShaderData::get_param_list(List<PropertyInfo> *p_param_list) const { Map<int, StringName> order; for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { @@ -2629,13 +2745,13 @@ void RasterizerSceneRD::SkyShaderData::get_param_list(List<PropertyInfo> *p_para } } -void RasterizerSceneRD::SkyShaderData::get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const { +void RendererSceneRenderRD::SkyShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const { for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { continue; } - RasterizerStorage::InstanceShaderParam p; + RendererStorage::InstanceShaderParam p; p.info = ShaderLanguage::uniform_to_property_info(E->get()); p.info.name = E->key(); //supply name p.index = E->get().instance_index; @@ -2644,7 +2760,7 @@ void RasterizerSceneRD::SkyShaderData::get_instance_param_list(List<RasterizerSt } } -bool RasterizerSceneRD::SkyShaderData::is_param_texture(const StringName &p_param) const { +bool RendererSceneRenderRD::SkyShaderData::is_param_texture(const StringName &p_param) const { if (!uniforms.has(p_param)) { return false; } @@ -2652,15 +2768,15 @@ bool RasterizerSceneRD::SkyShaderData::is_param_texture(const StringName &p_para return uniforms[p_param].texture_order >= 0; } -bool RasterizerSceneRD::SkyShaderData::is_animated() const { +bool RendererSceneRenderRD::SkyShaderData::is_animated() const { return false; } -bool RasterizerSceneRD::SkyShaderData::casts_shadows() const { +bool RendererSceneRenderRD::SkyShaderData::casts_shadows() const { return false; } -Variant RasterizerSceneRD::SkyShaderData::get_default_parameter(const StringName &p_parameter) const { +Variant RendererSceneRenderRD::SkyShaderData::get_default_parameter(const StringName &p_parameter) const { if (uniforms.has(p_parameter)) { ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; @@ -2669,12 +2785,18 @@ Variant RasterizerSceneRD::SkyShaderData::get_default_parameter(const StringName return Variant(); } -RasterizerSceneRD::SkyShaderData::SkyShaderData() { +RS::ShaderNativeSourceCode RendererSceneRenderRD::SkyShaderData::get_native_source_code() const { + RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton; + + return scene_singleton->sky_shader.shader.version_get_native_source_code(version); +} + +RendererSceneRenderRD::SkyShaderData::SkyShaderData() { valid = false; } -RasterizerSceneRD::SkyShaderData::~SkyShaderData() { - RasterizerSceneRD *scene_singleton = (RasterizerSceneRD *)RasterizerSceneRD::singleton; +RendererSceneRenderRD::SkyShaderData::~SkyShaderData() { + RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton; ERR_FAIL_COND(!scene_singleton); //pipeline variants will clear themselves if shader is gone if (version.is_valid()) { @@ -2682,13 +2804,13 @@ RasterizerSceneRD::SkyShaderData::~SkyShaderData() { } } -RasterizerStorageRD::ShaderData *RasterizerSceneRD::_create_sky_shader_func() { +RendererStorageRD::ShaderData *RendererSceneRenderRD::_create_sky_shader_func() { SkyShaderData *shader_data = memnew(SkyShaderData); return shader_data; } -void RasterizerSceneRD::SkyMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { - RasterizerSceneRD *scene_singleton = (RasterizerSceneRD *)RasterizerSceneRD::singleton; +void RendererSceneRenderRD::SkyMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { + RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton; uniform_set_updated = true; @@ -2750,7 +2872,7 @@ void RasterizerSceneRD::SkyMaterialData::update_parameters(const Map<StringName, { if (shader_data->ubo_size) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 0; u.ids.push_back(uniform_buffer); uniforms.push_back(u); @@ -2759,7 +2881,7 @@ void RasterizerSceneRD::SkyMaterialData::update_parameters(const Map<StringName, const RID *textures = texture_cache.ptrw(); for (uint32_t i = 0; i < tex_uniform_count; i++) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1 + i; u.ids.push_back(textures[i]); uniforms.push_back(u); @@ -2769,7 +2891,7 @@ void RasterizerSceneRD::SkyMaterialData::update_parameters(const Map<StringName, uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_singleton->sky_shader.shader.version_get_shader(shader_data->version, 0), SKY_SET_MATERIAL); } -RasterizerSceneRD::SkyMaterialData::~SkyMaterialData() { +RendererSceneRenderRD::SkyMaterialData::~SkyMaterialData() { if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { RD::get_singleton()->free(uniform_set); } @@ -2779,7 +2901,7 @@ RasterizerSceneRD::SkyMaterialData::~SkyMaterialData() { } } -RasterizerStorageRD::MaterialData *RasterizerSceneRD::_create_sky_material_func(SkyShaderData *p_shader) { +RendererStorageRD::MaterialData *RendererSceneRenderRD::_create_sky_material_func(SkyShaderData *p_shader) { SkyMaterialData *material_data = memnew(SkyMaterialData); material_data->shader_data = p_shader; material_data->last_frame = false; @@ -2787,53 +2909,56 @@ RasterizerStorageRD::MaterialData *RasterizerSceneRD::_create_sky_material_func( return material_data; } -RID RasterizerSceneRD::environment_create() { - return environment_owner.make_rid(Environment()); +RID RendererSceneRenderRD::environment_allocate() { + return environment_owner.allocate_rid(); +} +void RendererSceneRenderRD::environment_initialize(RID p_rid) { + environment_owner.initialize_rid(p_rid, Environment()); } -void RasterizerSceneRD::environment_set_background(RID p_env, RS::EnvironmentBG p_bg) { +void RendererSceneRenderRD::environment_set_background(RID p_env, RS::EnvironmentBG p_bg) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); env->background = p_bg; } -void RasterizerSceneRD::environment_set_sky(RID p_env, RID p_sky) { +void RendererSceneRenderRD::environment_set_sky(RID p_env, RID p_sky) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); env->sky = p_sky; } -void RasterizerSceneRD::environment_set_sky_custom_fov(RID p_env, float p_scale) { +void RendererSceneRenderRD::environment_set_sky_custom_fov(RID p_env, float p_scale) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); env->sky_custom_fov = p_scale; } -void RasterizerSceneRD::environment_set_sky_orientation(RID p_env, const Basis &p_orientation) { +void RendererSceneRenderRD::environment_set_sky_orientation(RID p_env, const Basis &p_orientation) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); env->sky_orientation = p_orientation; } -void RasterizerSceneRD::environment_set_bg_color(RID p_env, const Color &p_color) { +void RendererSceneRenderRD::environment_set_bg_color(RID p_env, const Color &p_color) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); env->bg_color = p_color; } -void RasterizerSceneRD::environment_set_bg_energy(RID p_env, float p_energy) { +void RendererSceneRenderRD::environment_set_bg_energy(RID p_env, float p_energy) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); env->bg_energy = p_energy; } -void RasterizerSceneRD::environment_set_canvas_max_layer(RID p_env, int p_max_layer) { +void RendererSceneRenderRD::environment_set_canvas_max_layer(RID p_env, int p_max_layer) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); env->canvas_max_layer = p_max_layer; } -void RasterizerSceneRD::environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source, const Color &p_ao_color) { +void RendererSceneRenderRD::environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source, const Color &p_ao_color) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); env->ambient_light = p_color; @@ -2844,85 +2969,85 @@ void RasterizerSceneRD::environment_set_ambient_light(RID p_env, const Color &p_ env->ao_color = p_ao_color; } -RS::EnvironmentBG RasterizerSceneRD::environment_get_background(RID p_env) const { +RS::EnvironmentBG RendererSceneRenderRD::environment_get_background(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, RS::ENV_BG_MAX); return env->background; } -RID RasterizerSceneRD::environment_get_sky(RID p_env) const { +RID RendererSceneRenderRD::environment_get_sky(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, RID()); return env->sky; } -float RasterizerSceneRD::environment_get_sky_custom_fov(RID p_env) const { +float RendererSceneRenderRD::environment_get_sky_custom_fov(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->sky_custom_fov; } -Basis RasterizerSceneRD::environment_get_sky_orientation(RID p_env) const { +Basis RendererSceneRenderRD::environment_get_sky_orientation(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, Basis()); return env->sky_orientation; } -Color RasterizerSceneRD::environment_get_bg_color(RID p_env) const { +Color RendererSceneRenderRD::environment_get_bg_color(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, Color()); return env->bg_color; } -float RasterizerSceneRD::environment_get_bg_energy(RID p_env) const { +float RendererSceneRenderRD::environment_get_bg_energy(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->bg_energy; } -int RasterizerSceneRD::environment_get_canvas_max_layer(RID p_env) const { +int RendererSceneRenderRD::environment_get_canvas_max_layer(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->canvas_max_layer; } -Color RasterizerSceneRD::environment_get_ambient_light_color(RID p_env) const { +Color RendererSceneRenderRD::environment_get_ambient_light_color(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, Color()); return env->ambient_light; } -RS::EnvironmentAmbientSource RasterizerSceneRD::environment_get_ambient_source(RID p_env) const { +RS::EnvironmentAmbientSource RendererSceneRenderRD::environment_get_ambient_source(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, RS::ENV_AMBIENT_SOURCE_BG); return env->ambient_source; } -float RasterizerSceneRD::environment_get_ambient_light_energy(RID p_env) const { +float RendererSceneRenderRD::environment_get_ambient_light_energy(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->ambient_light_energy; } -float RasterizerSceneRD::environment_get_ambient_sky_contribution(RID p_env) const { +float RendererSceneRenderRD::environment_get_ambient_sky_contribution(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->ambient_sky_contribution; } -RS::EnvironmentReflectionSource RasterizerSceneRD::environment_get_reflection_source(RID p_env) const { +RS::EnvironmentReflectionSource RendererSceneRenderRD::environment_get_reflection_source(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, RS::ENV_REFLECTION_SOURCE_DISABLED); return env->reflection_source; } -Color RasterizerSceneRD::environment_get_ao_color(RID p_env) const { +Color RendererSceneRenderRD::environment_get_ao_color(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, Color()); return env->ao_color; } -void RasterizerSceneRD::environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) { +void RendererSceneRenderRD::environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); env->exposure = p_exposure; @@ -2938,7 +3063,7 @@ void RasterizerSceneRD::environment_set_tonemap(RID p_env, RS::EnvironmentToneMa env->auto_exp_scale = p_auto_exp_scale; } -void RasterizerSceneRD::environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) { +void RendererSceneRenderRD::environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); ERR_FAIL_COND_MSG(p_levels.size() != 7, "Size of array of glow levels must be 7"); @@ -2954,23 +3079,27 @@ void RasterizerSceneRD::environment_set_glow(RID p_env, bool p_enable, Vector<fl env->glow_hdr_luminance_cap = p_hdr_luminance_cap; } -void RasterizerSceneRD::environment_glow_set_use_bicubic_upscale(bool p_enable) { +void RendererSceneRenderRD::environment_glow_set_use_bicubic_upscale(bool p_enable) { glow_bicubic_upscale = p_enable; } -void RasterizerSceneRD::environment_glow_set_use_high_quality(bool p_enable) { +void RendererSceneRenderRD::environment_glow_set_use_high_quality(bool p_enable) { glow_high_quality = p_enable; } -void RasterizerSceneRD::environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, bool p_use_multibounce, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) { +void RendererSceneRenderRD::environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); + if (low_end) { + return; + } + env->sdfgi_enabled = p_enable; env->sdfgi_cascades = p_cascades; env->sdfgi_min_cell_size = p_min_cell_size; env->sdfgi_use_occlusion = p_use_occlusion; - env->sdfgi_use_multibounce = p_use_multibounce; + env->sdfgi_bounce_feedback = p_bounce_feedback; env->sdfgi_read_sky_light = p_read_sky; env->sdfgi_energy = p_energy; env->sdfgi_normal_bias = p_normal_bias; @@ -2978,7 +3107,7 @@ void RasterizerSceneRD::environment_set_sdfgi(RID p_env, bool p_enable, RS::Envi env->sdfgi_y_scale = p_y_scale; } -void RasterizerSceneRD::environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_fog_aerial_perspective) { +void RendererSceneRenderRD::environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_fog_aerial_perspective) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); @@ -2992,104 +3121,97 @@ void RasterizerSceneRD::environment_set_fog(RID p_env, bool p_enable, const Colo env->fog_aerial_perspective = p_fog_aerial_perspective; } -bool RasterizerSceneRD::environment_is_fog_enabled(RID p_env) const { +bool RendererSceneRenderRD::environment_is_fog_enabled(RID p_env) const { const Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, false); return env->fog_enabled; } -Color RasterizerSceneRD::environment_get_fog_light_color(RID p_env) const { +Color RendererSceneRenderRD::environment_get_fog_light_color(RID p_env) const { const Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, Color()); return env->fog_light_color; } -float RasterizerSceneRD::environment_get_fog_light_energy(RID p_env) const { +float RendererSceneRenderRD::environment_get_fog_light_energy(RID p_env) const { const Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->fog_light_energy; } -float RasterizerSceneRD::environment_get_fog_sun_scatter(RID p_env) const { +float RendererSceneRenderRD::environment_get_fog_sun_scatter(RID p_env) const { const Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->fog_sun_scatter; } -float RasterizerSceneRD::environment_get_fog_density(RID p_env) const { +float RendererSceneRenderRD::environment_get_fog_density(RID p_env) const { const Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->fog_density; } -float RasterizerSceneRD::environment_get_fog_height(RID p_env) const { +float RendererSceneRenderRD::environment_get_fog_height(RID p_env) const { const Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->fog_height; } -float RasterizerSceneRD::environment_get_fog_height_density(RID p_env) const { +float RendererSceneRenderRD::environment_get_fog_height_density(RID p_env) const { const Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->fog_height_density; } -float RasterizerSceneRD::environment_get_fog_aerial_perspective(RID p_env) const { +float RendererSceneRenderRD::environment_get_fog_aerial_perspective(RID p_env) const { const Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->fog_aerial_perspective; } -void RasterizerSceneRD::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, RenderingServer::EnvVolumetricFogShadowFilter p_shadow_filter) { +void RendererSceneRenderRD::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); + if (low_end) { + return; + } + env->volumetric_fog_enabled = p_enable; env->volumetric_fog_density = p_density; env->volumetric_fog_light = p_light; env->volumetric_fog_light_energy = p_light_energy; env->volumetric_fog_length = p_length; env->volumetric_fog_detail_spread = p_detail_spread; - env->volumetric_fog_shadow_filter = p_shadow_filter; env->volumetric_fog_gi_inject = p_gi_inject; + env->volumetric_fog_temporal_reprojection = p_temporal_reprojection; + env->volumetric_fog_temporal_reprojection_amount = p_temporal_reprojection_amount; } -void RasterizerSceneRD::environment_set_volumetric_fog_volume_size(int p_size, int p_depth) { +void RendererSceneRenderRD::environment_set_volumetric_fog_volume_size(int p_size, int p_depth) { volumetric_fog_size = p_size; volumetric_fog_depth = p_depth; } -void RasterizerSceneRD::environment_set_volumetric_fog_filter_active(bool p_enable) { +void RendererSceneRenderRD::environment_set_volumetric_fog_filter_active(bool p_enable) { volumetric_fog_filter_active = p_enable; } -void RasterizerSceneRD::environment_set_volumetric_fog_directional_shadow_shrink_size(int p_shrink_size) { - p_shrink_size = nearest_power_of_2_templated(p_shrink_size); - if (volumetric_fog_directional_shadow_shrink == (uint32_t)p_shrink_size) { - return; - } - - _clear_shadow_shrink_stages(directional_shadow.shrink_stages); -} -void RasterizerSceneRD::environment_set_volumetric_fog_positional_shadow_shrink_size(int p_shrink_size) { - p_shrink_size = nearest_power_of_2_templated(p_shrink_size); - if (volumetric_fog_positional_shadow_shrink == (uint32_t)p_shrink_size) { - return; - } - - for (uint32_t i = 0; i < shadow_atlas_owner.get_rid_count(); i++) { - ShadowAtlas *sa = shadow_atlas_owner.get_ptr_by_index(i); - _clear_shadow_shrink_stages(sa->shrink_stages); - } -} -void RasterizerSceneRD::environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) { +void RendererSceneRenderRD::environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) { sdfgi_ray_count = p_ray_count; } -void RasterizerSceneRD::environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) { +void RendererSceneRenderRD::environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) { sdfgi_frames_to_converge = p_frames; } +void RendererSceneRenderRD::environment_set_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update) { + sdfgi_frames_to_update_light = p_update; +} -void RasterizerSceneRD::environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) { +void RendererSceneRenderRD::environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); + if (low_end) { + return; + } + env->ssr_enabled = p_enable; env->ssr_max_steps = p_max_steps; env->ssr_fade_in = p_fade_int; @@ -3097,66 +3219,76 @@ void RasterizerSceneRD::environment_set_ssr(RID p_env, bool p_enable, int p_max_ env->ssr_depth_tolerance = p_depth_tolerance; } -void RasterizerSceneRD::environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) { +void RendererSceneRenderRD::environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) { ssr_roughness_quality = p_quality; } -RS::EnvironmentSSRRoughnessQuality RasterizerSceneRD::environment_get_ssr_roughness_quality() const { +RS::EnvironmentSSRRoughnessQuality RendererSceneRenderRD::environment_get_ssr_roughness_quality() const { return ssr_roughness_quality; } -void RasterizerSceneRD::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_bias, float p_light_affect, float p_ao_channel_affect, RS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) { +void RendererSceneRenderRD::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); + if (low_end) { + return; + } + env->ssao_enabled = p_enable; env->ssao_radius = p_radius; env->ssao_intensity = p_intensity; - env->ssao_bias = p_bias; + env->ssao_power = p_power; + env->ssao_detail = p_detail; + env->ssao_horizon = p_horizon; + env->ssao_sharpness = p_sharpness; env->ssao_direct_light_affect = p_light_affect; env->ssao_ao_channel_affect = p_ao_channel_affect; - env->ssao_blur = p_blur; } -void RasterizerSceneRD::environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size) { +void RendererSceneRenderRD::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) { ssao_quality = p_quality; ssao_half_size = p_half_size; + ssao_adaptive_target = p_adaptive_target; + ssao_blur_passes = p_blur_passes; + ssao_fadeout_from = p_fadeout_from; + ssao_fadeout_to = p_fadeout_to; } -bool RasterizerSceneRD::environment_is_ssao_enabled(RID p_env) const { +bool RendererSceneRenderRD::environment_is_ssao_enabled(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, false); return env->ssao_enabled; } -float RasterizerSceneRD::environment_get_ssao_ao_affect(RID p_env) const { +float RendererSceneRenderRD::environment_get_ssao_ao_affect(RID p_env) const { Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND_V(!env, false); + ERR_FAIL_COND_V(!env, 0.0); return env->ssao_ao_channel_affect; } -float RasterizerSceneRD::environment_get_ssao_light_affect(RID p_env) const { +float RendererSceneRenderRD::environment_get_ssao_light_affect(RID p_env) const { Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND_V(!env, false); + ERR_FAIL_COND_V(!env, 0.0); return env->ssao_direct_light_affect; } -bool RasterizerSceneRD::environment_is_ssr_enabled(RID p_env) const { +bool RendererSceneRenderRD::environment_is_ssr_enabled(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, false); return env->ssr_enabled; } -bool RasterizerSceneRD::environment_is_sdfgi_enabled(RID p_env) const { +bool RendererSceneRenderRD::environment_is_sdfgi_enabled(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, false); return env->sdfgi_enabled; } -bool RasterizerSceneRD::is_environment(RID p_env) const { +bool RendererSceneRenderRD::is_environment(RID p_env) const { return environment_owner.owns(p_env); } -Ref<Image> RasterizerSceneRD::environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) { +Ref<Image> RendererSceneRenderRD::environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, Ref<Image>()); @@ -3195,15 +3327,19 @@ Ref<Image> RasterizerSceneRD::environment_bake_panorama(RID p_env, bool p_bake_i //////////////////////////////////////////////////////////// -RID RasterizerSceneRD::reflection_atlas_create() { +RID RendererSceneRenderRD::reflection_atlas_create() { ReflectionAtlas ra; - ra.count = GLOBAL_GET("rendering/quality/reflection_atlas/reflection_count"); - ra.size = GLOBAL_GET("rendering/quality/reflection_atlas/reflection_size"); + ra.count = GLOBAL_GET("rendering/reflections/reflection_atlas/reflection_count"); + ra.size = GLOBAL_GET("rendering/reflections/reflection_atlas/reflection_size"); + + ra.cluster_builder = memnew(ClusterBuilderRD); + ra.cluster_builder->set_shared(&cluster_builder_shared); + ra.cluster_builder->setup(Size2i(ra.size, ra.size), max_cluster_elements, RID(), RID(), RID()); return reflection_atlas_owner.make_rid(ra); } -void RasterizerSceneRD::reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) { +void RendererSceneRenderRD::reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) { ReflectionAtlas *ra = reflection_atlas_owner.getornull(p_ref_atlas); ERR_FAIL_COND(!ra); @@ -3211,6 +3347,8 @@ void RasterizerSceneRD::reflection_atlas_set_size(RID p_ref_atlas, int p_reflect return; //no changes } + ra->cluster_builder->setup(Size2i(ra->size, ra->size), max_cluster_elements, RID(), RID(), RID()); + ra->size = p_reflection_size; ra->count = p_reflection_count; @@ -3220,7 +3358,6 @@ void RasterizerSceneRD::reflection_atlas_set_size(RID p_ref_atlas, int p_reflect ra->reflection = RID(); RD::get_singleton()->free(ra->depth_buffer); ra->depth_buffer = RID(); - for (int i = 0; i < ra->reflections.size(); i++) { _clear_reflection_data(ra->reflections.write[i].data); if (ra->reflections[i].owner.is_null()) { @@ -3234,14 +3371,21 @@ void RasterizerSceneRD::reflection_atlas_set_size(RID p_ref_atlas, int p_reflect } } +int RendererSceneRenderRD::reflection_atlas_get_size(RID p_ref_atlas) const { + ReflectionAtlas *ra = reflection_atlas_owner.getornull(p_ref_atlas); + ERR_FAIL_COND_V(!ra, 0); + + return ra->size; +} + //////////////////////// -RID RasterizerSceneRD::reflection_probe_instance_create(RID p_probe) { +RID RendererSceneRenderRD::reflection_probe_instance_create(RID p_probe) { ReflectionProbeInstance rpi; rpi.probe = p_probe; return reflection_probe_instance_owner.make_rid(rpi); } -void RasterizerSceneRD::reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) { +void RendererSceneRenderRD::reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) { ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); ERR_FAIL_COND(!rpi); @@ -3249,7 +3393,7 @@ void RasterizerSceneRD::reflection_probe_instance_set_transform(RID p_instance, rpi->dirty = true; } -void RasterizerSceneRD::reflection_probe_release_atlas_index(RID p_instance) { +void RendererSceneRenderRD::reflection_probe_release_atlas_index(RID p_instance) { ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); ERR_FAIL_COND(!rpi); @@ -3264,7 +3408,7 @@ void RasterizerSceneRD::reflection_probe_release_atlas_index(RID p_instance) { rpi->atlas = RID(); } -bool RasterizerSceneRD::reflection_probe_instance_needs_redraw(RID p_instance) { +bool RendererSceneRenderRD::reflection_probe_instance_needs_redraw(RID p_instance) { ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); ERR_FAIL_COND_V(!rpi, false); @@ -3283,14 +3427,14 @@ bool RasterizerSceneRD::reflection_probe_instance_needs_redraw(RID p_instance) { return rpi->atlas_index == -1; } -bool RasterizerSceneRD::reflection_probe_instance_has_reflection(RID p_instance) { +bool RendererSceneRenderRD::reflection_probe_instance_has_reflection(RID p_instance) { ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); ERR_FAIL_COND_V(!rpi, false); return rpi->atlas.is_valid(); } -bool RasterizerSceneRD::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) { +bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) { ReflectionAtlas *atlas = reflection_atlas_owner.getornull(p_reflection_atlas); ERR_FAIL_COND_V(!atlas, false); @@ -3326,7 +3470,7 @@ bool RasterizerSceneRD::reflection_probe_instance_begin_render(RID p_instance, R RD::TextureFormat tf; tf.array_layers = 6 * atlas->count; tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; - tf.type = RD::TEXTURE_TYPE_CUBE_ARRAY; + tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY; tf.mipmaps = mipmaps; tf.width = atlas->size; tf.height = atlas->size; @@ -3389,7 +3533,7 @@ bool RasterizerSceneRD::reflection_probe_instance_begin_render(RID p_instance, R return true; } -bool RasterizerSceneRD::reflection_probe_instance_postprocess_step(RID p_instance) { +bool RendererSceneRenderRD::reflection_probe_instance_postprocess_step(RID p_instance) { ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); ERR_FAIL_COND_V(!rpi, false); ERR_FAIL_COND_V(!rpi->rendering, false); @@ -3435,7 +3579,7 @@ bool RasterizerSceneRD::reflection_probe_instance_postprocess_step(RID p_instanc return false; } -uint32_t RasterizerSceneRD::reflection_probe_instance_get_resolution(RID p_instance) { +uint32_t RendererSceneRenderRD::reflection_probe_instance_get_resolution(RID p_instance) { ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); ERR_FAIL_COND_V(!rpi, 0); @@ -3444,7 +3588,7 @@ uint32_t RasterizerSceneRD::reflection_probe_instance_get_resolution(RID p_insta return atlas->size; } -RID RasterizerSceneRD::reflection_probe_instance_get_framebuffer(RID p_instance, int p_index) { +RID RendererSceneRenderRD::reflection_probe_instance_get_framebuffer(RID p_instance, int p_index) { ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); ERR_FAIL_COND_V(!rpi, RID()); ERR_FAIL_INDEX_V(p_index, 6, RID()); @@ -3454,7 +3598,7 @@ RID RasterizerSceneRD::reflection_probe_instance_get_framebuffer(RID p_instance, return atlas->reflections[rpi->atlas_index].fbs[p_index]; } -RID RasterizerSceneRD::reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index) { +RID RendererSceneRenderRD::reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index) { ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); ERR_FAIL_COND_V(!rpi, RID()); ERR_FAIL_INDEX_V(p_index, 6, RID()); @@ -3466,17 +3610,32 @@ RID RasterizerSceneRD::reflection_probe_instance_get_depth_framebuffer(RID p_ins /////////////////////////////////////////////////////////// -RID RasterizerSceneRD::shadow_atlas_create() { +RID RendererSceneRenderRD::shadow_atlas_create() { return shadow_atlas_owner.make_rid(ShadowAtlas()); } -void RasterizerSceneRD::shadow_atlas_set_size(RID p_atlas, int p_size) { +void RendererSceneRenderRD::_update_shadow_atlas(ShadowAtlas *shadow_atlas) { + if (shadow_atlas->size > 0 && shadow_atlas->depth.is_null()) { + RD::TextureFormat tf; + tf.format = shadow_atlas->use_16_bits ? RD::DATA_FORMAT_D16_UNORM : RD::DATA_FORMAT_D32_SFLOAT; + tf.width = shadow_atlas->size; + tf.height = shadow_atlas->size; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + + shadow_atlas->depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); + Vector<RID> fb_tex; + fb_tex.push_back(shadow_atlas->depth); + shadow_atlas->fb = RD::get_singleton()->framebuffer_create(fb_tex); + } +} + +void RendererSceneRenderRD::shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits) { ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas); ERR_FAIL_COND(!shadow_atlas); ERR_FAIL_COND(p_size < 0); p_size = next_power_of_2(p_size); - if (p_size == shadow_atlas->size) { + if (p_size == shadow_atlas->size && p_16_bits == shadow_atlas->use_16_bits) { return; } @@ -3484,7 +3643,6 @@ void RasterizerSceneRD::shadow_atlas_set_size(RID p_atlas, int p_size) { if (shadow_atlas->depth.is_valid()) { RD::get_singleton()->free(shadow_atlas->depth); shadow_atlas->depth = RID(); - _clear_shadow_shrink_stages(shadow_atlas->shrink_stages); } for (int i = 0; i < 4; i++) { //clear subdivisions @@ -3503,19 +3661,10 @@ void RasterizerSceneRD::shadow_atlas_set_size(RID p_atlas, int p_size) { shadow_atlas->shadow_owners.clear(); shadow_atlas->size = p_size; - - if (shadow_atlas->size) { - RD::TextureFormat tf; - tf.format = RD::DATA_FORMAT_R32_SFLOAT; - tf.width = shadow_atlas->size; - tf.height = shadow_atlas->size; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - - shadow_atlas->depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); - } + shadow_atlas->use_16_bits = p_size; } -void RasterizerSceneRD::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) { +void RendererSceneRenderRD::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) { ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas); ERR_FAIL_COND(!shadow_atlas); ERR_FAIL_INDEX(p_quadrant, 4); @@ -3577,7 +3726,7 @@ void RasterizerSceneRD::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p } while (swaps > 0); } -bool RasterizerSceneRD::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow) { +bool RendererSceneRenderRD::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow) { for (int i = p_quadrant_count - 1; i >= 0; i--) { int qidx = p_in_quadrants[i]; @@ -3632,7 +3781,7 @@ bool RasterizerSceneRD::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int return false; } -bool RasterizerSceneRD::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) { +bool RendererSceneRenderRD::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) { ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas); ERR_FAIL_COND_V(!shadow_atlas, false); @@ -3767,10 +3916,24 @@ bool RasterizerSceneRD::shadow_atlas_update_light(RID p_atlas, RID p_light_intan return false; } -void RasterizerSceneRD::directional_shadow_atlas_set_size(int p_size) { +void RendererSceneRenderRD::_update_directional_shadow_atlas() { + if (directional_shadow.depth.is_null() && directional_shadow.size > 0) { + RD::TextureFormat tf; + tf.format = directional_shadow.use_16_bits ? RD::DATA_FORMAT_D16_UNORM : RD::DATA_FORMAT_D32_SFLOAT; + tf.width = directional_shadow.size; + tf.height = directional_shadow.size; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + + directional_shadow.depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); + Vector<RID> fb_tex; + fb_tex.push_back(directional_shadow.depth); + directional_shadow.fb = RD::get_singleton()->framebuffer_create(fb_tex); + } +} +void RendererSceneRenderRD::directional_shadow_atlas_set_size(int p_size, bool p_16_bits) { p_size = nearest_power_of_2_templated(p_size); - if (directional_shadow.size == p_size) { + if (directional_shadow.size == p_size && directional_shadow.use_16_bits == p_16_bits) { return; } @@ -3778,24 +3941,12 @@ void RasterizerSceneRD::directional_shadow_atlas_set_size(int p_size) { if (directional_shadow.depth.is_valid()) { RD::get_singleton()->free(directional_shadow.depth); - _clear_shadow_shrink_stages(directional_shadow.shrink_stages); directional_shadow.depth = RID(); + _base_uniforms_changed(); } - - if (p_size > 0) { - RD::TextureFormat tf; - tf.format = RD::DATA_FORMAT_R32_SFLOAT; - tf.width = p_size; - tf.height = p_size; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - - directional_shadow.depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); - } - - _base_uniforms_changed(); } -void RasterizerSceneRD::set_directional_shadow_count(int p_count) { +void RendererSceneRenderRD::set_directional_shadow_count(int p_count) { directional_shadow.light_count = p_count; directional_shadow.current_light = 0; } @@ -3822,7 +3973,7 @@ static Rect2i _get_directional_shadow_rect(int p_size, int p_shadow_count, int p return rect; } -int RasterizerSceneRD::get_directional_light_shadow_size(RID p_light_intance) { +int RendererSceneRenderRD::get_directional_light_shadow_size(RID p_light_intance) { ERR_FAIL_COND_V(directional_shadow.light_count == 0, 0); Rect2i r = _get_directional_shadow_rect(directional_shadow.size, directional_shadow.light_count, 0); @@ -3846,20 +3997,23 @@ int RasterizerSceneRD::get_directional_light_shadow_size(RID p_light_intance) { ////////////////////////////////////////////////// -RID RasterizerSceneRD::camera_effects_create() { - return camera_effects_owner.make_rid(CameraEffects()); +RID RendererSceneRenderRD::camera_effects_allocate() { + return camera_effects_owner.allocate_rid(); +} +void RendererSceneRenderRD::camera_effects_initialize(RID p_rid) { + camera_effects_owner.initialize_rid(p_rid, CameraEffects()); } -void RasterizerSceneRD::camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) { +void RendererSceneRenderRD::camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) { dof_blur_quality = p_quality; dof_blur_use_jitter = p_use_jitter; } -void RasterizerSceneRD::camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) { +void RendererSceneRenderRD::camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) { dof_blur_bokeh_shape = p_shape; } -void RasterizerSceneRD::camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) { +void RendererSceneRenderRD::camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) { CameraEffects *camfx = camera_effects_owner.getornull(p_camera_effects); ERR_FAIL_COND(!camfx); @@ -3874,7 +4028,7 @@ void RasterizerSceneRD::camera_effects_set_dof_blur(RID p_camera_effects, bool p camfx->dof_blur_amount = p_amount; } -void RasterizerSceneRD::camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) { +void RendererSceneRenderRD::camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) { CameraEffects *camfx = camera_effects_owner.getornull(p_camera_effects); ERR_FAIL_COND(!camfx); @@ -3882,7 +4036,7 @@ void RasterizerSceneRD::camera_effects_set_custom_exposure(RID p_camera_effects, camfx->override_exposure = p_exposure; } -RID RasterizerSceneRD::light_instance_create(RID p_light) { +RID RendererSceneRenderRD::light_instance_create(RID p_light) { RID li = light_instance_owner.make_rid(LightInstance()); LightInstance *light_instance = light_instance_owner.getornull(li); @@ -3894,29 +4048,25 @@ RID RasterizerSceneRD::light_instance_create(RID p_light) { return li; } -void RasterizerSceneRD::light_instance_set_transform(RID p_light_instance, const Transform &p_transform) { +void RendererSceneRenderRD::light_instance_set_transform(RID p_light_instance, const Transform &p_transform) { LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); ERR_FAIL_COND(!light_instance); light_instance->transform = p_transform; } -void RasterizerSceneRD::light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) { +void RendererSceneRenderRD::light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) { LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); ERR_FAIL_COND(!light_instance); light_instance->aabb = p_aabb; } -void RasterizerSceneRD::light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) { +void RendererSceneRenderRD::light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) { LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); ERR_FAIL_COND(!light_instance); - if (storage->light_get_type(light_instance->light) != RS::LIGHT_DIRECTIONAL) { - p_pass = 0; - } - - ERR_FAIL_INDEX(p_pass, 4); + ERR_FAIL_INDEX(p_pass, 6); light_instance->shadow_transform[p_pass].camera = p_projection; light_instance->shadow_transform[p_pass].transform = p_transform; @@ -3928,14 +4078,14 @@ void RasterizerSceneRD::light_instance_set_shadow_transform(RID p_light_instance light_instance->shadow_transform[p_pass].uv_scale = p_uv_scale; } -void RasterizerSceneRD::light_instance_mark_visible(RID p_light_instance) { +void RendererSceneRenderRD::light_instance_mark_visible(RID p_light_instance) { LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); ERR_FAIL_COND(!light_instance); light_instance->last_scene_pass = scene_pass; } -RasterizerSceneRD::ShadowCubemap *RasterizerSceneRD::_get_shadow_cubemap(int p_size) { +RendererSceneRenderRD::ShadowCubemap *RendererSceneRenderRD::_get_shadow_cubemap(int p_size) { if (!shadow_cubemaps.has(p_size)) { ShadowCubemap sc; { @@ -3943,7 +4093,7 @@ RasterizerSceneRD::ShadowCubemap *RasterizerSceneRD::_get_shadow_cubemap(int p_s tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32; tf.width = p_size; tf.height = p_size; - tf.type = RD::TEXTURE_TYPE_CUBE; + tf.texture_type = RD::TEXTURE_TYPE_CUBE; tf.array_layers = 6; tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; sc.cubemap = RD::get_singleton()->texture_create(tf, RD::TextureView()); @@ -3962,38 +4112,15 @@ RasterizerSceneRD::ShadowCubemap *RasterizerSceneRD::_get_shadow_cubemap(int p_s return &shadow_cubemaps[p_size]; } -RasterizerSceneRD::ShadowMap *RasterizerSceneRD::_get_shadow_map(const Size2i &p_size) { - if (!shadow_maps.has(p_size)) { - ShadowMap sm; - { - RD::TextureFormat tf; - tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32; - tf.width = p_size.width; - tf.height = p_size.height; - tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; - - sm.depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); - } - - Vector<RID> fbtex; - fbtex.push_back(sm.depth); - sm.fb = RD::get_singleton()->framebuffer_create(fbtex); - - shadow_maps[p_size] = sm; - } - - return &shadow_maps[p_size]; -} - ////////////////////////// -RID RasterizerSceneRD::decal_instance_create(RID p_decal) { +RID RendererSceneRenderRD::decal_instance_create(RID p_decal) { DecalInstance di; di.decal = p_decal; return decal_instance_owner.make_rid(di); } -void RasterizerSceneRD::decal_instance_set_transform(RID p_decal, const Transform &p_transform) { +void RendererSceneRenderRD::decal_instance_set_transform(RID p_decal, const Transform &p_transform) { DecalInstance *di = decal_instance_owner.getornull(p_decal); ERR_FAIL_COND(!di); di->transform = p_transform; @@ -4001,32 +4128,53 @@ void RasterizerSceneRD::decal_instance_set_transform(RID p_decal, const Transfor ///////////////////////////////// -RID RasterizerSceneRD::gi_probe_instance_create(RID p_base) { +RID RendererSceneRenderRD::lightmap_instance_create(RID p_lightmap) { + LightmapInstance li; + li.lightmap = p_lightmap; + return lightmap_instance_owner.make_rid(li); +} +void RendererSceneRenderRD::lightmap_instance_set_transform(RID p_lightmap, const Transform &p_transform) { + LightmapInstance *li = lightmap_instance_owner.getornull(p_lightmap); + ERR_FAIL_COND(!li); + li->transform = p_transform; +} + +///////////////////////////////// + +RID RendererSceneRenderRD::gi_probe_instance_create(RID p_base) { GIProbeInstance gi_probe; gi_probe.probe = p_base; RID rid = gi_probe_instance_owner.make_rid(gi_probe); return rid; } -void RasterizerSceneRD::gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) { +void RendererSceneRenderRD::gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) { GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe); ERR_FAIL_COND(!gi_probe); gi_probe->transform = p_xform; } -bool RasterizerSceneRD::gi_probe_needs_update(RID p_probe) const { +bool RendererSceneRenderRD::gi_probe_needs_update(RID p_probe) const { GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe); ERR_FAIL_COND_V(!gi_probe, false); + if (low_end) { + return false; + } + //return true; return gi_probe->last_probe_version != storage->gi_probe_get_version(gi_probe->probe); } -void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, int p_dynamic_object_count, InstanceBase **p_dynamic_objects) { +void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<GeometryInstance *> &p_dynamic_objects) { GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe); ERR_FAIL_COND(!gi_probe); + if (low_end) { + return; + } + uint32_t data_version = storage->gi_probe_get_data_version(gi_probe->probe); // (RE)CREATE IF NEEDED @@ -4057,14 +4205,14 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc tf.width = octree_size.x; tf.height = octree_size.y; tf.depth = octree_size.z; - tf.type = RD::TEXTURE_TYPE_3D; + tf.texture_type = RD::TEXTURE_TYPE_3D; tf.mipmaps = levels.size(); tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; gi_probe->texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); - RD::get_singleton()->texture_clear(gi_probe->texture, Color(0, 0, 0, 0), 0, levels.size(), 0, 1, false); + RD::get_singleton()->texture_clear(gi_probe->texture, Color(0, 0, 0, 0), 0, levels.size(), 0, 1); { int total_elements = 0; @@ -4088,14 +4236,14 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 1; u.ids.push_back(storage->gi_probe_get_octree_buffer(gi_probe->probe)); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 2; u.ids.push_back(storage->gi_probe_get_data_buffer(gi_probe->probe)); uniforms.push_back(u); @@ -4103,21 +4251,21 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 4; u.ids.push_back(gi_probe->write_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 9; u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe)); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 10; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); @@ -4128,7 +4276,7 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc if (i == 0) { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 3; u.ids.push_back(gi_probe_lights_uniform); copy_uniforms.push_back(u); @@ -4140,7 +4288,7 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 5; u.ids.push_back(gi_probe->texture); copy_uniforms.push_back(u); @@ -4153,7 +4301,7 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 5; u.ids.push_back(mipmap.texture); uniforms.push_back(u); @@ -4227,7 +4375,7 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 3; u.ids.push_back(gi_probe_lights_uniform); uniforms.push_back(u); @@ -4235,56 +4383,56 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 5; u.ids.push_back(dmap.albedo); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 6; u.ids.push_back(dmap.normal); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 7; u.ids.push_back(dmap.orm); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 8; u.ids.push_back(dmap.fb_depth); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 9; u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe)); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 10; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 11; u.ids.push_back(dmap.texture); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 12; u.ids.push_back(dmap.depth); uniforms.push_back(u); @@ -4300,14 +4448,14 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 5; u.ids.push_back(gi_probe->dynamic_maps[gi_probe->dynamic_maps.size() - 1].texture); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 6; u.ids.push_back(gi_probe->dynamic_maps[gi_probe->dynamic_maps.size() - 1].depth); uniforms.push_back(u); @@ -4316,14 +4464,14 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc if (write) { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 7; u.ids.push_back(dmap.texture); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 8; u.ids.push_back(dmap.depth); uniforms.push_back(u); @@ -4332,14 +4480,14 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 9; u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe)); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 10; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); @@ -4348,14 +4496,17 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc if (plot) { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 11; u.ids.push_back(gi_probe->mipmaps[dmap.mipmap].texture); uniforms.push_back(u); } } - dmap.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_lighting_shader_version_shaders[(write && plot) ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT : write ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE : GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT], 0); + dmap.uniform_set = RD::get_singleton()->uniform_set_create( + uniforms, + giprobe_lighting_shader_version_shaders[(write && plot) ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT : (write ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE : GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT)], + 0); } gi_probe->dynamic_maps.push_back(dmap); @@ -4373,12 +4524,12 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc if (gi_probe->has_dynamic_object_data) { //if it has dynamic object data, it needs to be cleared - RD::get_singleton()->texture_clear(gi_probe->texture, Color(0, 0, 0, 0), 0, gi_probe->mipmaps.size(), 0, 1, true); + RD::get_singleton()->texture_clear(gi_probe->texture, Color(0, 0, 0, 0), 0, gi_probe->mipmaps.size(), 0, 1); } uint32_t light_count = 0; - if (p_update_light_instances || p_dynamic_object_count > 0) { + if (p_update_light_instances || p_dynamic_objects.size() > 0) { light_count = MIN(gi_probe_max_lights, (uint32_t)p_light_instances.size()); { @@ -4392,6 +4543,11 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc RID light = light_instance_get_base_light(light_instance); l.type = storage->light_get_type(light); + if (l.type == RS::LIGHT_DIRECTIONAL && storage->light_directional_is_sky_only(light)) { + light_count--; + continue; + } + l.attenuation = storage->light_get_param(light, RS::LIGHT_PARAM_ATTENUATION); l.energy = storage->light_get_param(light, RS::LIGHT_PARAM_ENERGY) * storage->light_get_param(light, RS::LIGHT_PARAM_INDIRECT_ENERGY); l.radius = to_cell.basis.xform(Vector3(storage->light_get_param(light, RS::LIGHT_PARAM_RANGE), 0, 0)).length(); @@ -4400,8 +4556,8 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc l.color[1] = color.g; l.color[2] = color.b; - l.spot_angle_radians = Math::deg2rad(storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ANGLE)); - l.spot_attenuation = storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ATTENUATION); + l.cos_spot_angle = Math::cos(Math::deg2rad(storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ANGLE))); + l.inv_spot_attenuation = 1.0f / storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ATTENUATION); Transform xform = light_instance_get_base_transform(light_instance); @@ -4419,11 +4575,11 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc l.has_shadow = storage->light_has_shadow(light); } - RD::get_singleton()->buffer_update(gi_probe_lights_uniform, 0, sizeof(GIProbeLight) * light_count, gi_probe_lights, true); + RD::get_singleton()->buffer_update(gi_probe_lights_uniform, 0, sizeof(GIProbeLight) * light_count, gi_probe_lights); } } - if (gi_probe->has_dynamic_object_data || p_update_light_instances || p_dynamic_object_count) { + if (gi_probe->has_dynamic_object_data || p_update_light_instances || p_dynamic_objects.size()) { // PROCESS MIPMAPS if (gi_probe->mipmaps.size()) { //can update mipmaps @@ -4516,7 +4672,7 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc gi_probe->has_dynamic_object_data = false; //clear until dynamic object data is used again - if (p_dynamic_object_count && gi_probe->dynamic_maps.size()) { + if (p_dynamic_objects.size() && gi_probe->dynamic_maps.size()) { Vector3i octree_size = storage->gi_probe_get_octree_size(gi_probe->probe); int multiplier = gi_probe->dynamic_maps[0].size / MAX(MAX(octree_size.x, octree_size.y), octree_size.z); @@ -4530,14 +4686,11 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc AABB probe_aabb(Vector3(), octree_size); //this could probably be better parallelized in compute.. - for (int i = 0; i < p_dynamic_object_count; i++) { - InstanceBase *instance = p_dynamic_objects[i]; - //not used, so clear - instance->depth_layer = 0; - instance->depth = 0; + for (int i = 0; i < (int)p_dynamic_objects.size(); i++) { + GeometryInstance *instance = p_dynamic_objects[i]; //transform aabb to giprobe - AABB aabb = (to_probe_xform * instance->transform).xform(instance->aabb); + AABB aabb = (to_probe_xform * geometry_instance_get_transform(instance)).xform(geometry_instance_get_aabb(instance)); //this needs to wrap to grid resolution to avoid jitter //also extend margin a bit just in case @@ -4601,7 +4754,12 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc CameraMatrix cm; cm.set_orthogonal(-rect.size.width / 2, rect.size.width / 2, -rect.size.height / 2, rect.size.height / 2, 0.0001, aabb.size[z_axis]); - _render_material(to_world_xform * xform, cm, true, &instance, 1, gi_probe->dynamic_maps[0].fb, Rect2i(Vector2i(), rect.size)); + if (cull_argument.size() == 0) { + cull_argument.push_back(nullptr); + } + cull_argument[0] = instance; + + _render_material(to_world_xform * xform, cm, true, cull_argument, gi_probe->dynamic_maps[0].fb, Rect2i(Vector2i(), rect.size)); GIProbeDynamicPushConstant push_constant; zeromem(&push_constant, sizeof(GIProbeDynamicPushConstant)); @@ -4718,7 +4876,7 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc gi_probe->last_probe_version = storage->gi_probe_get_version(gi_probe->probe); } -void RasterizerSceneRD::_debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) { +void RendererSceneRenderRD::_debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) { GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_gi_probe); ERR_FAIL_COND(!gi_probe); @@ -4754,21 +4912,21 @@ void RasterizerSceneRD::_debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_lis Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 1; u.ids.push_back(storage->gi_probe_get_data_buffer(gi_probe->probe)); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; u.ids.push_back(gi_probe->texture); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 3; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); @@ -4782,13 +4940,22 @@ void RasterizerSceneRD::_debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_lis } giprobe_debug_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_debug_shader_version_shaders[0], 0); - RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, giprobe_debug_shader_version_pipelines[p_emission ? GI_PROBE_DEBUG_EMISSION : p_lighting ? (gi_probe->has_dynamic_object_data ? GI_PROBE_DEBUG_LIGHT_FULL : GI_PROBE_DEBUG_LIGHT) : GI_PROBE_DEBUG_COLOR].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer))); + + int giprobe_debug_pipeline = GI_PROBE_DEBUG_COLOR; + if (p_emission) { + giprobe_debug_pipeline = GI_PROBE_DEBUG_EMISSION; + } else if (p_lighting) { + giprobe_debug_pipeline = gi_probe->has_dynamic_object_data ? GI_PROBE_DEBUG_LIGHT_FULL : GI_PROBE_DEBUG_LIGHT; + } + RD::get_singleton()->draw_list_bind_render_pipeline( + p_draw_list, + giprobe_debug_shader_version_pipelines[giprobe_debug_pipeline].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, giprobe_debug_uniform_set, 0); RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(GIProbeDebugPushConstant)); RD::get_singleton()->draw_list_draw(p_draw_list, false, cell_count, 36); } -void RasterizerSceneRD::_debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform) { +void RendererSceneRenderRD::_debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(!rb); @@ -4809,7 +4976,7 @@ void RasterizerSceneRD::_debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID push_constant.band_power = 4; push_constant.sections_in_band = ((band_points / 2) - 1); push_constant.band_mask = band_points - 2; - push_constant.section_arc = (Math_PI * 2.0) / float(push_constant.sections_in_band); + push_constant.section_arc = Math_TAU / float(push_constant.sections_in_band); push_constant.y_mult = rb->sdfgi->y_mult; uint32_t total_points = push_constant.sections_in_band * band_points; @@ -4827,28 +4994,28 @@ void RasterizerSceneRD::_debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID { RD::Uniform u; u.binding = 1; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.ids.push_back(rb->sdfgi->cascades_ubo); uniforms.push_back(u); } { RD::Uniform u; u.binding = 2; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.ids.push_back(rb->sdfgi->lightprobe_texture); uniforms.push_back(u); } { RD::Uniform u; u.binding = 3; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); } { RD::Uniform u; u.binding = 4; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.ids.push_back(rb->sdfgi->occlusion_texture); uniforms.push_back(u); } @@ -4925,13 +5092,13 @@ void RasterizerSceneRD::_debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID } //////////////////////////////// -RID RasterizerSceneRD::render_buffers_create() { +RID RendererSceneRenderRD::render_buffers_create() { RenderBuffers rb; rb.data = _create_render_buffer_data(); return render_buffers_owner.make_rid(rb); } -void RasterizerSceneRD::_allocate_blur_textures(RenderBuffers *rb) { +void RendererSceneRenderRD::_allocate_blur_textures(RenderBuffers *rb) { ERR_FAIL_COND(!rb->blur[0].texture.is_null()); uint32_t mipmaps_required = Image::get_image_required_mipmaps(rb->width, rb->height, Image::FORMAT_RGBAH); @@ -4940,7 +5107,7 @@ void RasterizerSceneRD::_allocate_blur_textures(RenderBuffers *rb) { tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; tf.width = rb->width; tf.height = rb->height; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; tf.mipmaps = mipmaps_required; @@ -4974,7 +5141,7 @@ void RasterizerSceneRD::_allocate_blur_textures(RenderBuffers *rb) { } } -void RasterizerSceneRD::_allocate_luminance_textures(RenderBuffers *rb) { +void RendererSceneRenderRD::_allocate_luminance_textures(RenderBuffers *rb) { ERR_FAIL_COND(!rb->luminance.current.is_null()); int w = rb->width; @@ -5007,7 +5174,7 @@ void RasterizerSceneRD::_allocate_luminance_textures(RenderBuffers *rb) { } } -void RasterizerSceneRD::_free_render_buffer_data(RenderBuffers *rb) { +void RendererSceneRenderRD::_free_render_buffer_data(RenderBuffers *rb) { if (rb->texture.is_valid()) { RD::get_singleton()->free(rb->texture); rb->texture = RID(); @@ -5030,9 +5197,6 @@ void RasterizerSceneRD::_free_render_buffer_data(RenderBuffers *rb) { RD::get_singleton()->free(rb->luminance.reduce[i]); } - for (int i = 0; i < rb->luminance.reduce.size(); i++) { - RD::get_singleton()->free(rb->luminance.reduce[i]); - } rb->luminance.reduce.clear(); if (rb->luminance.current.is_valid()) { @@ -5040,21 +5204,24 @@ void RasterizerSceneRD::_free_render_buffer_data(RenderBuffers *rb) { rb->luminance.current = RID(); } - if (rb->ssao.ao[0].is_valid()) { + if (rb->ssao.depth.is_valid()) { RD::get_singleton()->free(rb->ssao.depth); - RD::get_singleton()->free(rb->ssao.ao[0]); - if (rb->ssao.ao[1].is_valid()) { - RD::get_singleton()->free(rb->ssao.ao[1]); - } - if (rb->ssao.ao_full.is_valid()) { - RD::get_singleton()->free(rb->ssao.ao_full); - } + RD::get_singleton()->free(rb->ssao.ao_deinterleaved); + RD::get_singleton()->free(rb->ssao.ao_pong); + RD::get_singleton()->free(rb->ssao.ao_final); + + RD::get_singleton()->free(rb->ssao.importance_map[0]); + RD::get_singleton()->free(rb->ssao.importance_map[1]); rb->ssao.depth = RID(); - rb->ssao.ao[0] = RID(); - rb->ssao.ao[1] = RID(); - rb->ssao.ao_full = RID(); + rb->ssao.ao_deinterleaved = RID(); + rb->ssao.ao_pong = RID(); + rb->ssao.ao_final = RID(); + rb->ssao.importance_map[0] = RID(); + rb->ssao.importance_map[1] = RID(); rb->ssao.depth_slices.clear(); + rb->ssao.ao_deinterleaved_slices.clear(); + rb->ssao.ao_pong_slices.clear(); } if (rb->ssr.blur_radius[0].is_valid()) { @@ -5070,9 +5237,16 @@ void RasterizerSceneRD::_free_render_buffer_data(RenderBuffers *rb) { RD::get_singleton()->free(rb->ssr.normal_scaled); rb->ssr.normal_scaled = RID(); } + + if (rb->ambient_buffer.is_valid()) { + RD::get_singleton()->free(rb->ambient_buffer); + RD::get_singleton()->free(rb->reflection_buffer); + rb->ambient_buffer = RID(); + rb->reflection_buffer = RID(); + } } -void RasterizerSceneRD::_process_sss(RID p_render_buffers, const CameraMatrix &p_camera) { +void RendererSceneRenderRD::_process_sss(RID p_render_buffers, const CameraMatrix &p_camera) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(!rb); @@ -5091,7 +5265,7 @@ void RasterizerSceneRD::_process_sss(RID p_render_buffers, const CameraMatrix &p storage->get_effects()->sub_surface_scattering(rb->texture, rb->blur[0].mipmaps[0].texture, rb->depth_texture, p_camera, Size2i(rb->width, rb->height), sss_scale, sss_depth_scale, sss_quality); } -void RasterizerSceneRD::_process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive) { +void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(!rb); @@ -5113,7 +5287,7 @@ void RasterizerSceneRD::_process_ssr(RID p_render_buffers, RID p_dest_framebuffe tf.format = RD::DATA_FORMAT_R32_SFLOAT; tf.width = rb->width / 2; tf.height = rb->height / 2; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT; rb->ssr.depth_scaled = RD::get_singleton()->texture_create(tf, RD::TextureView()); @@ -5128,7 +5302,7 @@ void RasterizerSceneRD::_process_ssr(RID p_render_buffers, RID p_dest_framebuffe tf.format = RD::DATA_FORMAT_R8_UNORM; tf.width = rb->width / 2; tf.height = rb->height / 2; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; rb->ssr.blur_radius[0] = RD::get_singleton()->texture_create(tf, RD::TextureView()); @@ -5144,7 +5318,7 @@ void RasterizerSceneRD::_process_ssr(RID p_render_buffers, RID p_dest_framebuffe storage->get_effects()->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->texture, rb->blur[0].mipmaps[1].texture); } -void RasterizerSceneRD::_process_ssao(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection) { +void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(!rb); @@ -5153,67 +5327,144 @@ void RasterizerSceneRD::_process_ssao(RID p_render_buffers, RID p_environment, R RENDER_TIMESTAMP("Process SSAO"); - if (rb->ssao.ao[0].is_valid() && rb->ssao.ao_full.is_valid() != ssao_half_size) { + if (rb->ssao.ao_final.is_valid() && ssao_using_half_size != ssao_half_size) { RD::get_singleton()->free(rb->ssao.depth); - RD::get_singleton()->free(rb->ssao.ao[0]); - if (rb->ssao.ao[1].is_valid()) { - RD::get_singleton()->free(rb->ssao.ao[1]); - } - if (rb->ssao.ao_full.is_valid()) { - RD::get_singleton()->free(rb->ssao.ao_full); - } + RD::get_singleton()->free(rb->ssao.ao_deinterleaved); + RD::get_singleton()->free(rb->ssao.ao_pong); + RD::get_singleton()->free(rb->ssao.ao_final); + + RD::get_singleton()->free(rb->ssao.importance_map[0]); + RD::get_singleton()->free(rb->ssao.importance_map[1]); rb->ssao.depth = RID(); - rb->ssao.ao[0] = RID(); - rb->ssao.ao[1] = RID(); - rb->ssao.ao_full = RID(); + rb->ssao.ao_deinterleaved = RID(); + rb->ssao.ao_pong = RID(); + rb->ssao.ao_final = RID(); + rb->ssao.importance_map[0] = RID(); + rb->ssao.importance_map[1] = RID(); rb->ssao.depth_slices.clear(); + rb->ssao.ao_deinterleaved_slices.clear(); + rb->ssao.ao_pong_slices.clear(); + } + + int buffer_width; + int buffer_height; + int half_width; + int half_height; + if (ssao_half_size) { + buffer_width = (rb->width + 3) / 4; + buffer_height = (rb->height + 3) / 4; + half_width = (rb->width + 7) / 8; + half_height = (rb->height + 7) / 8; + } else { + buffer_width = (rb->width + 1) / 2; + buffer_height = (rb->height + 1) / 2; + half_width = (rb->width + 3) / 4; + half_height = (rb->height + 3) / 4; } - - if (!rb->ssao.ao[0].is_valid()) { + bool uniform_sets_are_invalid = false; + if (rb->ssao.depth.is_null()) { //allocate depth slices { RD::TextureFormat tf; - tf.format = RD::DATA_FORMAT_R32_SFLOAT; - tf.width = rb->width / 2; - tf.height = rb->height / 2; - tf.mipmaps = Image::get_image_required_mipmaps(tf.width, tf.height, Image::FORMAT_RF) + 1; + tf.format = RD::DATA_FORMAT_R16_SFLOAT; + tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; + tf.width = buffer_width; + tf.height = buffer_height; + tf.mipmaps = 4; + tf.array_layers = 4; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; rb->ssao.depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ssao.depth, "SSAO Depth"); for (uint32_t i = 0; i < tf.mipmaps; i++) { - RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ssao.depth, 0, i); + RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ssao.depth, 0, i, RD::TEXTURE_SLICE_2D_ARRAY); rb->ssao.depth_slices.push_back(slice); + RD::get_singleton()->set_resource_name(rb->ssao.depth_slices[i], "SSAO Depth Mip " + itos(i) + " "); } } { RD::TextureFormat tf; - tf.format = RD::DATA_FORMAT_R8_UNORM; - tf.width = ssao_half_size ? rb->width / 2 : rb->width; - tf.height = ssao_half_size ? rb->height / 2 : rb->height; + tf.format = RD::DATA_FORMAT_R8G8_UNORM; + tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; + tf.width = buffer_width; + tf.height = buffer_height; + tf.array_layers = 4; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - rb->ssao.ao[0] = RD::get_singleton()->texture_create(tf, RD::TextureView()); - rb->ssao.ao[1] = RD::get_singleton()->texture_create(tf, RD::TextureView()); + rb->ssao.ao_deinterleaved = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ssao.ao_deinterleaved, "SSAO De-interleaved Array"); + for (uint32_t i = 0; i < 4; i++) { + RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ssao.ao_deinterleaved, i, 0); + rb->ssao.ao_deinterleaved_slices.push_back(slice); + RD::get_singleton()->set_resource_name(rb->ssao.ao_deinterleaved_slices[i], "SSAO De-interleaved Array Layer " + itos(i) + " "); + } } - if (ssao_half_size) { - //upsample texture + { + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R8G8_UNORM; + tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; + tf.width = buffer_width; + tf.height = buffer_height; + tf.array_layers = 4; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + rb->ssao.ao_pong = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ssao.ao_pong, "SSAO De-interleaved Array Pong"); + for (uint32_t i = 0; i < 4; i++) { + RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ssao.ao_pong, i, 0); + rb->ssao.ao_pong_slices.push_back(slice); + RD::get_singleton()->set_resource_name(rb->ssao.ao_deinterleaved_slices[i], "SSAO De-interleaved Array Layer " + itos(i) + " Pong"); + } + } + + { + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R8_UNORM; + tf.width = half_width; + tf.height = half_height; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + rb->ssao.importance_map[0] = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ssao.importance_map[0], "SSAO Importance Map"); + rb->ssao.importance_map[1] = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ssao.importance_map[1], "SSAO Importance Map Pong"); + } + { RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R8_UNORM; tf.width = rb->width; tf.height = rb->height; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - rb->ssao.ao_full = RD::get_singleton()->texture_create(tf, RD::TextureView()); + rb->ssao.ao_final = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ssao.ao_final, "SSAO Final"); + _render_buffers_uniform_set_changed(p_render_buffers); } - - _render_buffers_uniform_set_changed(p_render_buffers); + ssao_using_half_size = ssao_half_size; + uniform_sets_are_invalid = true; } - storage->get_effects()->generate_ssao(rb->depth_texture, p_normal_buffer, Size2i(rb->width, rb->height), rb->ssao.depth, rb->ssao.depth_slices, rb->ssao.ao[0], rb->ssao.ao_full.is_valid(), rb->ssao.ao[1], rb->ssao.ao_full, env->ssao_intensity, env->ssao_radius, env->ssao_bias, p_projection, ssao_quality, env->ssao_blur, env->ssao_blur_edge_sharpness); + EffectsRD::SSAOSettings settings; + settings.radius = env->ssao_radius; + settings.intensity = env->ssao_intensity; + settings.power = env->ssao_power; + settings.detail = env->ssao_detail; + settings.horizon = env->ssao_horizon; + settings.sharpness = env->ssao_sharpness; + + settings.quality = ssao_quality; + settings.half_size = ssao_half_size; + settings.adaptive_target = ssao_adaptive_target; + settings.blur_passes = ssao_blur_passes; + settings.fadeout_from = ssao_fadeout_from; + settings.fadeout_to = ssao_fadeout_to; + settings.full_screen_size = Size2i(rb->width, rb->height); + settings.half_screen_size = Size2i(buffer_width, buffer_height); + settings.quarter_screen_size = Size2i(half_width, half_height); + + storage->get_effects()->generate_ssao(rb->depth_texture, p_normal_buffer, rb->ssao.depth, rb->ssao.depth_slices, rb->ssao.ao_deinterleaved, rb->ssao.ao_deinterleaved_slices, rb->ssao.ao_pong, rb->ssao.ao_pong_slices, rb->ssao.ao_final, rb->ssao.importance_map[0], rb->ssao.importance_map[1], p_projection, settings, uniform_sets_are_invalid); } -void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_buffers, RID p_environment, RID p_camera_effects, const CameraMatrix &p_projection) { +void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(RID p_render_buffers, RID p_environment, RID p_camera_effects, const CameraMatrix &p_projection) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(!rb); @@ -5247,7 +5498,7 @@ void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_bu //swap final reduce with prev luminance SWAP(rb->luminance.current, rb->luminance.reduce.write[rb->luminance.reduce.size() - 1]); - RenderingServerRaster::redraw_request(); //redraw all the time if auto exposure rendering is on + RenderingServerDefault::redraw_request(); //redraw all the time if auto exposure rendering is on } int max_glow_level = -1; @@ -5288,21 +5539,19 @@ void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_bu { //tonemap - RasterizerEffectsRD::TonemapSettings tonemap; - - tonemap.color_correction_texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); + EffectsRD::TonemapSettings tonemap; if (can_use_effects && env && env->auto_exposure && rb->luminance.current.is_valid()) { tonemap.use_auto_exposure = true; tonemap.exposure_texture = rb->luminance.current; tonemap.auto_exposure_grey = env->auto_exp_scale; } else { - tonemap.exposure_texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE); + tonemap.exposure_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); } if (can_use_effects && env && env->glow_enabled) { tonemap.use_glow = true; - tonemap.glow_mode = RasterizerEffectsRD::TonemapSettings::GlowMode(env->glow_blend_mode); + tonemap.glow_mode = EffectsRD::TonemapSettings::GlowMode(env->glow_blend_mode); tonemap.glow_intensity = env->glow_blend_mode == RS::ENV_GLOW_BLEND_MODE_MIX ? env->glow_mix : env->glow_intensity; for (int i = 0; i < RS::MAX_GLOW_LEVELS; i++) { tonemap.glow_levels[i] = env->glow_levels[i]; @@ -5312,7 +5561,7 @@ void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_bu tonemap.glow_use_bicubic_upscale = glow_bicubic_upscale; tonemap.glow_texture = rb->blur[1].texture; } else { - tonemap.glow_texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK); + tonemap.glow_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); } if (rb->screen_space_aa == RS::VIEWPORT_SCREEN_SPACE_AA_FXAA) { @@ -5328,14 +5577,30 @@ void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_bu tonemap.exposure = env->exposure; } + tonemap.use_color_correction = false; + tonemap.use_1d_color_correction = false; + tonemap.color_correction_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); + + if (can_use_effects && env) { + tonemap.use_bcs = env->adjustments_enabled; + tonemap.brightness = env->adjustments_brightness; + tonemap.contrast = env->adjustments_contrast; + tonemap.saturation = env->adjustments_saturation; + if (env->adjustments_enabled && env->color_correction.is_valid()) { + tonemap.use_color_correction = true; + tonemap.use_1d_color_correction = env->use_1d_color_correction; + tonemap.color_correction_texture = storage->texture_get_rd_texture(env->color_correction); + } + } + storage->get_effects()->tonemapper(rb->texture, storage->render_target_get_rd_framebuffer(rb->render_target), tonemap); } storage->render_target_disable_clear_request(rb->render_target); } -void RasterizerSceneRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas) { - RasterizerEffectsRD *effects = storage->get_effects(); +void RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas) { + EffectsRD *effects = storage->get_effects(); RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(!rb); @@ -5376,9 +5641,9 @@ void RasterizerSceneRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_s } } - if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SSAO && rb->ssao.ao[0].is_valid()) { + if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SSAO && rb->ssao.ao_final.is_valid()) { Size2 rtsize = storage->render_target_get_size(rb->render_target); - RID ao_buf = rb->ssao.ao_full.is_valid() ? rb->ssao.ao_full : rb->ssao.ao[0]; + RID ao_buf = rb->ssao.ao_final; effects->copy_to_fb_rect(ao_buf, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, true); } @@ -5387,15 +5652,27 @@ void RasterizerSceneRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_s effects->copy_to_fb_rect(_render_buffers_get_normal_texture(p_render_buffers), storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, false); } - if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_GI_BUFFER && _render_buffers_get_ambient_texture(p_render_buffers).is_valid()) { + if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_GI_BUFFER && rb->ambient_buffer.is_valid()) { Size2 rtsize = storage->render_target_get_size(rb->render_target); - RID ambient_texture = _render_buffers_get_ambient_texture(p_render_buffers); - RID reflection_texture = _render_buffers_get_reflection_texture(p_render_buffers); + RID ambient_texture = rb->ambient_buffer; + RID reflection_texture = rb->reflection_buffer; effects->copy_to_fb_rect(ambient_texture, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, false, false, true, reflection_texture); } } -void RasterizerSceneRD::_sdfgi_debug_draw(RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform) { +void RendererSceneRenderRD::environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) { + Environment *env = environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + + env->adjustments_enabled = p_enable; + env->adjustments_brightness = p_brightness; + env->adjustments_contrast = p_contrast; + env->adjustments_saturation = p_saturation; + env->use_1d_color_correction = p_use_1d_color_correction; + env->color_correction = p_color_correction; +} + +void RendererSceneRenderRD::_sdfgi_debug_draw(RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(!rb); @@ -5408,12 +5685,12 @@ void RasterizerSceneRD::_sdfgi_debug_draw(RID p_render_buffers, const CameraMatr { RD::Uniform u; u.binding = 1; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) { if (i < rb->sdfgi->cascades.size()) { u.ids.push_back(rb->sdfgi->cascades[i].sdf_tex); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } } uniforms.push_back(u); @@ -5421,12 +5698,12 @@ void RasterizerSceneRD::_sdfgi_debug_draw(RID p_render_buffers, const CameraMatr { RD::Uniform u; u.binding = 2; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) { if (i < rb->sdfgi->cascades.size()) { u.ids.push_back(rb->sdfgi->cascades[i].light_tex); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } } uniforms.push_back(u); @@ -5434,12 +5711,12 @@ void RasterizerSceneRD::_sdfgi_debug_draw(RID p_render_buffers, const CameraMatr { RD::Uniform u; u.binding = 3; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) { if (i < rb->sdfgi->cascades.size()) { u.ids.push_back(rb->sdfgi->cascades[i].light_aniso_0_tex); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } } uniforms.push_back(u); @@ -5447,12 +5724,12 @@ void RasterizerSceneRD::_sdfgi_debug_draw(RID p_render_buffers, const CameraMatr { RD::Uniform u; u.binding = 4; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) { if (i < rb->sdfgi->cascades.size()) { u.ids.push_back(rb->sdfgi->cascades[i].light_aniso_1_tex); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } } uniforms.push_back(u); @@ -5460,35 +5737,35 @@ void RasterizerSceneRD::_sdfgi_debug_draw(RID p_render_buffers, const CameraMatr { RD::Uniform u; u.binding = 5; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.ids.push_back(rb->sdfgi->occlusion_texture); uniforms.push_back(u); } { RD::Uniform u; u.binding = 8; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); } { RD::Uniform u; u.binding = 9; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.ids.push_back(rb->sdfgi->cascades_ubo); uniforms.push_back(u); } { RD::Uniform u; u.binding = 10; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.ids.push_back(rb->texture); uniforms.push_back(u); } { RD::Uniform u; u.binding = 11; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.ids.push_back(rb->sdfgi->lightprobe_texture); uniforms.push_back(u); } @@ -5534,14 +5811,14 @@ void RasterizerSceneRD::_sdfgi_debug_draw(RID p_render_buffers, const CameraMatr RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::DebugPushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width, rb->height, 1, 8, 8, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width, rb->height, 1); RD::get_singleton()->compute_list_end(); Size2 rtsize = storage->render_target_get_size(rb->render_target); storage->get_effects()->copy_to_fb_rect(rb->texture, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), true); } -RID RasterizerSceneRD::render_buffers_get_back_buffer_texture(RID p_render_buffers) { +RID RendererSceneRenderRD::render_buffers_get_back_buffer_texture(RID p_render_buffers) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, RID()); if (!rb->blur[0].texture.is_valid()) { @@ -5550,14 +5827,14 @@ RID RasterizerSceneRD::render_buffers_get_back_buffer_texture(RID p_render_buffe return rb->blur[0].texture; } -RID RasterizerSceneRD::render_buffers_get_ao_texture(RID p_render_buffers) { +RID RendererSceneRenderRD::render_buffers_get_ao_texture(RID p_render_buffers) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, RID()); - return rb->ssao.ao_full.is_valid() ? rb->ssao.ao_full : rb->ssao.ao[0]; + return rb->ssao.ao_final; } -RID RasterizerSceneRD::render_buffers_get_gi_probe_buffer(RID p_render_buffers) { +RID RendererSceneRenderRD::render_buffers_get_gi_probe_buffer(RID p_render_buffers) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, RID()); if (rb->giprobe_buffer.is_null()) { @@ -5566,24 +5843,35 @@ RID RasterizerSceneRD::render_buffers_get_gi_probe_buffer(RID p_render_buffers) return rb->giprobe_buffer; } -RID RasterizerSceneRD::render_buffers_get_default_gi_probe_buffer() { +RID RendererSceneRenderRD::render_buffers_get_default_gi_probe_buffer() { return default_giprobe_buffer; } -uint32_t RasterizerSceneRD::render_buffers_get_sdfgi_cascade_count(RID p_render_buffers) const { +RID RendererSceneRenderRD::render_buffers_get_gi_ambient_texture(RID p_render_buffers) { + RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + ERR_FAIL_COND_V(!rb, RID()); + return rb->ambient_buffer; +} +RID RendererSceneRenderRD::render_buffers_get_gi_reflection_texture(RID p_render_buffers) { + RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + ERR_FAIL_COND_V(!rb, RID()); + return rb->reflection_buffer; +} + +uint32_t RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_count(RID p_render_buffers) const { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, 0); ERR_FAIL_COND_V(!rb->sdfgi, 0); return rb->sdfgi->cascades.size(); } -bool RasterizerSceneRD::render_buffers_is_sdfgi_enabled(RID p_render_buffers) const { +bool RendererSceneRenderRD::render_buffers_is_sdfgi_enabled(RID p_render_buffers) const { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, false); return rb->sdfgi != nullptr; } -RID RasterizerSceneRD::render_buffers_get_sdfgi_irradiance_probes(RID p_render_buffers) const { +RID RendererSceneRenderRD::render_buffers_get_sdfgi_irradiance_probes(RID p_render_buffers) const { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, RID()); ERR_FAIL_COND_V(!rb->sdfgi, RID()); @@ -5591,7 +5879,7 @@ RID RasterizerSceneRD::render_buffers_get_sdfgi_irradiance_probes(RID p_render_b return rb->sdfgi->lightprobe_texture; } -Vector3 RasterizerSceneRD::render_buffers_get_sdfgi_cascade_offset(RID p_render_buffers, uint32_t p_cascade) const { +Vector3 RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_offset(RID p_render_buffers, uint32_t p_cascade) const { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, Vector3()); ERR_FAIL_COND_V(!rb->sdfgi, Vector3()); @@ -5600,7 +5888,7 @@ Vector3 RasterizerSceneRD::render_buffers_get_sdfgi_cascade_offset(RID p_render_ return Vector3((Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + rb->sdfgi->cascades[p_cascade].position)) * rb->sdfgi->cascades[p_cascade].cell_size; } -Vector3i RasterizerSceneRD::render_buffers_get_sdfgi_cascade_probe_offset(RID p_render_buffers, uint32_t p_cascade) const { +Vector3i RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_probe_offset(RID p_render_buffers, uint32_t p_cascade) const { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, Vector3i()); ERR_FAIL_COND_V(!rb->sdfgi, Vector3i()); @@ -5610,14 +5898,14 @@ Vector3i RasterizerSceneRD::render_buffers_get_sdfgi_cascade_probe_offset(RID p_ return rb->sdfgi->cascades[p_cascade].position / probe_divisor; } -float RasterizerSceneRD::render_buffers_get_sdfgi_normal_bias(RID p_render_buffers) const { +float RendererSceneRenderRD::render_buffers_get_sdfgi_normal_bias(RID p_render_buffers) const { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, 0); ERR_FAIL_COND_V(!rb->sdfgi, 0); return rb->sdfgi->normal_bias; } -float RasterizerSceneRD::render_buffers_get_sdfgi_cascade_probe_size(RID p_render_buffers, uint32_t p_cascade) const { +float RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_probe_size(RID p_render_buffers, uint32_t p_cascade) const { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, 0); ERR_FAIL_COND_V(!rb->sdfgi, 0); @@ -5625,7 +5913,7 @@ float RasterizerSceneRD::render_buffers_get_sdfgi_cascade_probe_size(RID p_rende return float(rb->sdfgi->cascade_size) * rb->sdfgi->cascades[p_cascade].cell_size / float(rb->sdfgi->probe_axis_count - 1); } -uint32_t RasterizerSceneRD::render_buffers_get_sdfgi_cascade_probe_count(RID p_render_buffers) const { +uint32_t RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_probe_count(RID p_render_buffers) const { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, 0); ERR_FAIL_COND_V(!rb->sdfgi, 0); @@ -5633,7 +5921,7 @@ uint32_t RasterizerSceneRD::render_buffers_get_sdfgi_cascade_probe_count(RID p_r return rb->sdfgi->probe_axis_count; } -uint32_t RasterizerSceneRD::render_buffers_get_sdfgi_cascade_size(RID p_render_buffers) const { +uint32_t RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_size(RID p_render_buffers) const { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, 0); ERR_FAIL_COND_V(!rb->sdfgi, 0); @@ -5641,7 +5929,7 @@ uint32_t RasterizerSceneRD::render_buffers_get_sdfgi_cascade_size(RID p_render_b return rb->sdfgi->cascade_size; } -bool RasterizerSceneRD::render_buffers_is_sdfgi_using_occlusion(RID p_render_buffers) const { +bool RendererSceneRenderRD::render_buffers_is_sdfgi_using_occlusion(RID p_render_buffers) const { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, false); ERR_FAIL_COND_V(!rb->sdfgi, false); @@ -5649,14 +5937,14 @@ bool RasterizerSceneRD::render_buffers_is_sdfgi_using_occlusion(RID p_render_buf return rb->sdfgi->uses_occlusion; } -float RasterizerSceneRD::render_buffers_get_sdfgi_energy(RID p_render_buffers) const { +float RendererSceneRenderRD::render_buffers_get_sdfgi_energy(RID p_render_buffers) const { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); - ERR_FAIL_COND_V(!rb, 0); - ERR_FAIL_COND_V(!rb->sdfgi, false); + ERR_FAIL_COND_V(!rb, 0.0); + ERR_FAIL_COND_V(!rb->sdfgi, 0.0); return rb->sdfgi->energy; } -RID RasterizerSceneRD::render_buffers_get_sdfgi_occlusion_texture(RID p_render_buffers) const { +RID RendererSceneRenderRD::render_buffers_get_sdfgi_occlusion_texture(RID p_render_buffers) const { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, RID()); ERR_FAIL_COND_V(!rb->sdfgi, RID()); @@ -5664,20 +5952,20 @@ RID RasterizerSceneRD::render_buffers_get_sdfgi_occlusion_texture(RID p_render_b return rb->sdfgi->occlusion_texture; } -bool RasterizerSceneRD::render_buffers_has_volumetric_fog(RID p_render_buffers) const { +bool RendererSceneRenderRD::render_buffers_has_volumetric_fog(RID p_render_buffers) const { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, false); return rb->volumetric_fog != nullptr; } -RID RasterizerSceneRD::render_buffers_get_volumetric_fog_texture(RID p_render_buffers) { +RID RendererSceneRenderRD::render_buffers_get_volumetric_fog_texture(RID p_render_buffers) { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb || !rb->volumetric_fog, RID()); return rb->volumetric_fog->fog_map; } -RID RasterizerSceneRD::render_buffers_get_volumetric_fog_sky_uniform_set(RID p_render_buffers) { +RID RendererSceneRenderRD::render_buffers_get_volumetric_fog_sky_uniform_set(RID p_render_buffers) { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, RID()); @@ -5688,18 +5976,18 @@ RID RasterizerSceneRD::render_buffers_get_volumetric_fog_sky_uniform_set(RID p_r return rb->volumetric_fog->sky_uniform_set; } -float RasterizerSceneRD::render_buffers_get_volumetric_fog_end(RID p_render_buffers) { +float RendererSceneRenderRD::render_buffers_get_volumetric_fog_end(RID p_render_buffers) { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb || !rb->volumetric_fog, 0); return rb->volumetric_fog->length; } -float RasterizerSceneRD::render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers) { +float RendererSceneRenderRD::render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers) { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb || !rb->volumetric_fog, 0); return rb->volumetric_fog->spread; } -void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding) { +void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); rb->width = p_width; rb->height = p_height; @@ -5707,6 +5995,11 @@ void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_ren rb->msaa = p_msaa; rb->screen_space_aa = p_screen_space_aa; rb->use_debanding = p_use_debanding; + if (rb->cluster_builder == nullptr) { + rb->cluster_builder = memnew(ClusterBuilderRD); + } + rb->cluster_builder->set_shared(&cluster_builder_shared); + _free_render_buffer_data(rb); { @@ -5747,22 +6040,28 @@ void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_ren rb->data->configure(rb->texture, rb->depth_texture, p_width, p_height, p_msaa); _render_buffers_uniform_set_changed(p_render_buffers); + + rb->cluster_builder->setup(Size2i(p_width, p_height), max_cluster_elements, rb->depth_texture, storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED), rb->texture); +} + +void RendererSceneRenderRD::gi_set_use_half_resolution(bool p_enable) { + gi.half_resolution = p_enable; } -void RasterizerSceneRD::sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) { +void RendererSceneRenderRD::sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) { sss_quality = p_quality; } -RS::SubSurfaceScatteringQuality RasterizerSceneRD::sub_surface_scattering_get_quality() const { +RS::SubSurfaceScatteringQuality RendererSceneRenderRD::sub_surface_scattering_get_quality() const { return sss_quality; } -void RasterizerSceneRD::sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) { +void RendererSceneRenderRD::sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) { sss_scale = p_scale; sss_depth_scale = p_depth_scale; } -void RasterizerSceneRD::shadows_quality_set(RS::ShadowQuality p_quality) { +void RendererSceneRenderRD::shadows_quality_set(RS::ShadowQuality p_quality) { ERR_FAIL_INDEX_MSG(p_quality, RS::SHADOW_QUALITY_MAX, "Shadow quality too high, please see RenderingServer's ShadowQuality enum"); if (shadows_quality != p_quality) { @@ -5802,7 +6101,7 @@ void RasterizerSceneRD::shadows_quality_set(RS::ShadowQuality p_quality) { } } -void RasterizerSceneRD::directional_shadow_quality_set(RS::ShadowQuality p_quality) { +void RendererSceneRenderRD::directional_shadow_quality_set(RS::ShadowQuality p_quality) { ERR_FAIL_INDEX_MSG(p_quality, RS::SHADOW_QUALITY_MAX, "Shadow quality too high, please see RenderingServer's ShadowQuality enum"); if (directional_shadow_quality != p_quality) { @@ -5842,32 +6141,49 @@ void RasterizerSceneRD::directional_shadow_quality_set(RS::ShadowQuality p_quali } } -int RasterizerSceneRD::get_roughness_layers() const { +int RendererSceneRenderRD::get_roughness_layers() const { return roughness_layers; } -bool RasterizerSceneRD::is_using_radiance_cubemap_array() const { +bool RendererSceneRenderRD::is_using_radiance_cubemap_array() const { return sky_use_cubemap_array; } -RasterizerSceneRD::RenderBufferData *RasterizerSceneRD::render_buffers_get_data(RID p_render_buffers) { +RendererSceneRenderRD::RenderBufferData *RendererSceneRenderRD::render_buffers_get_data(RID p_render_buffers) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, nullptr); return rb->data; } -void RasterizerSceneRD::_setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, RID p_environment) { - for (int i = 0; i < p_reflection_probe_cull_count; i++) { - RID rpi = p_reflection_probe_cull_result[i]; +void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflections, const Transform &p_camera_inverse_transform, RID p_environment) { + cluster.reflection_count = 0; + + for (uint32_t i = 0; i < (uint32_t)p_reflections.size(); i++) { + if (cluster.reflection_count == cluster.max_reflections) { + break; + } - if (i >= (int)cluster.max_reflections) { - reflection_probe_instance_set_render_index(rpi, 0); //invalid, but something needs to be set + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_reflections[i]); + if (!rpi) { continue; } - reflection_probe_instance_set_render_index(rpi, i); + cluster.reflection_sort[cluster.reflection_count].instance = rpi; + cluster.reflection_sort[cluster.reflection_count].depth = -p_camera_inverse_transform.xform(rpi->transform.origin).z; + cluster.reflection_count++; + } + + if (cluster.reflection_count > 0) { + SortArray<Cluster::InstanceSort<ReflectionProbeInstance>> sort_array; + sort_array.sort(cluster.reflection_sort, cluster.reflection_count); + } + + for (uint32_t i = 0; i < cluster.reflection_count; i++) { + ReflectionProbeInstance *rpi = cluster.reflection_sort[i].instance; - RID base_probe = reflection_probe_instance_get_probe(rpi); + rpi->render_index = i; + + RID base_probe = rpi->probe; Cluster::ReflectionData &reflection_ubo = cluster.reflections[i]; @@ -5876,7 +6192,7 @@ void RasterizerSceneRD::_setup_reflections(RID *p_reflection_probe_cull_result, reflection_ubo.box_extents[0] = extents.x; reflection_ubo.box_extents[1] = extents.y; reflection_ubo.box_extents[2] = extents.z; - reflection_ubo.index = reflection_probe_instance_get_atlas_index(rpi); + reflection_ubo.index = rpi->atlas_index; Vector3 origin_offset = storage->reflection_probe_get_origin_offset(base_probe); @@ -5885,61 +6201,98 @@ void RasterizerSceneRD::_setup_reflections(RID *p_reflection_probe_cull_result, reflection_ubo.box_offset[2] = origin_offset.z; reflection_ubo.mask = storage->reflection_probe_get_cull_mask(base_probe); - float intensity = storage->reflection_probe_get_intensity(base_probe); - bool interior = storage->reflection_probe_is_interior(base_probe); - bool box_projection = storage->reflection_probe_is_box_projection(base_probe); + reflection_ubo.intensity = storage->reflection_probe_get_intensity(base_probe); + reflection_ubo.ambient_mode = storage->reflection_probe_get_ambient_mode(base_probe); - reflection_ubo.params[0] = intensity; - reflection_ubo.params[1] = 0; - reflection_ubo.params[2] = interior ? 1.0 : 0.0; - reflection_ubo.params[3] = box_projection ? 1.0 : 0.0; + reflection_ubo.exterior = !storage->reflection_probe_is_interior(base_probe); + reflection_ubo.box_project = storage->reflection_probe_is_box_projection(base_probe); Color ambient_linear = storage->reflection_probe_get_ambient_color(base_probe).to_linear(); float interior_ambient_energy = storage->reflection_probe_get_ambient_color_energy(base_probe); - uint32_t ambient_mode = storage->reflection_probe_get_ambient_mode(base_probe); reflection_ubo.ambient[0] = ambient_linear.r * interior_ambient_energy; reflection_ubo.ambient[1] = ambient_linear.g * interior_ambient_energy; reflection_ubo.ambient[2] = ambient_linear.b * interior_ambient_energy; - reflection_ubo.ambient_mode = ambient_mode; - Transform transform = reflection_probe_instance_get_transform(rpi); + Transform transform = rpi->transform; Transform proj = (p_camera_inverse_transform * transform).inverse(); - RasterizerStorageRD::store_transform(proj, reflection_ubo.local_matrix); + RendererStorageRD::store_transform(proj, reflection_ubo.local_matrix); - cluster.builder.add_reflection_probe(transform, extents); + current_cluster_builder->add_box(ClusterBuilderRD::BOX_TYPE_REFLECTION_PROBE, transform, extents); - reflection_probe_instance_set_render_pass(rpi, RSG::rasterizer->get_frame_number()); + rpi->last_pass = RSG::rasterizer->get_frame_number(); } - if (p_reflection_probe_cull_count) { - RD::get_singleton()->buffer_update(cluster.reflection_buffer, 0, MIN(cluster.max_reflections, (unsigned int)p_reflection_probe_cull_count) * sizeof(ReflectionData), cluster.reflections, true); + if (cluster.reflection_count) { + RD::get_singleton()->buffer_update(cluster.reflection_buffer, 0, cluster.reflection_count * sizeof(ReflectionData), cluster.reflections, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); } } -void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count) { - uint32_t light_count = 0; +void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const Transform &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count) { + Transform inverse_transform = p_camera_transform.affine_inverse(); + r_directional_light_count = 0; r_positional_light_count = 0; sky_scene_state.ubo.directional_light_count = 0; - for (int i = 0; i < p_light_cull_count; i++) { - RID li = p_light_cull_result[i]; - RID base = light_instance_get_base_light(li); + Plane camera_plane(p_camera_transform.origin, -p_camera_transform.basis.get_axis(Vector3::AXIS_Z).normalized()); + + cluster.omni_light_count = 0; + cluster.spot_light_count = 0; + + for (int i = 0; i < (int)p_lights.size(); i++) { + LightInstance *li = light_instance_owner.getornull(p_lights[i]); + if (!li) { + continue; + } + RID base = li->light; ERR_CONTINUE(base.is_null()); RS::LightType type = storage->light_get_type(base); switch (type) { case RS::LIGHT_DIRECTIONAL: { - if (r_directional_light_count >= cluster.max_directional_lights) { + // Copy to SkyDirectionalLightData + if (r_directional_light_count < sky_scene_state.max_directional_lights) { + SkyDirectionalLightData &sky_light_data = sky_scene_state.directional_lights[r_directional_light_count]; + Transform light_transform = li->transform; + Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized(); + + sky_light_data.direction[0] = world_direction.x; + sky_light_data.direction[1] = world_direction.y; + sky_light_data.direction[2] = -world_direction.z; + + float sign = storage->light_is_negative(base) ? -1 : 1; + sky_light_data.energy = sign * storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY); + + Color linear_col = storage->light_get_color(base).to_linear(); + sky_light_data.color[0] = linear_col.r; + sky_light_data.color[1] = linear_col.g; + sky_light_data.color[2] = linear_col.b; + + sky_light_data.enabled = true; + + float angular_diameter = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE); + if (angular_diameter > 0.0) { + // I know tan(0) is 0, but let's not risk it with numerical precision. + // technically this will keep expanding until reaching the sun, but all we care + // is expand until we reach the radius of the near plane (there can't be more occluders than that) + angular_diameter = Math::tan(Math::deg2rad(angular_diameter)); + } else { + angular_diameter = 0.0; + } + sky_light_data.size = angular_diameter; + sky_scene_state.ubo.directional_light_count++; + } + + if (r_directional_light_count >= cluster.max_directional_lights || storage->light_directional_is_sky_only(base)) { continue; } Cluster::DirectionalLightData &light_data = cluster.directional_lights[r_directional_light_count]; - Transform light_transform = light_instance_get_base_transform(li); + Transform light_transform = li->transform; - Vector3 direction = p_camera_inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, 1))).normalized(); + Vector3 direction = inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, 1))).normalized(); light_data.direction[0] = direction.x; light_data.direction[1] = direction.y; @@ -6018,28 +6371,28 @@ void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull int limit = smode == RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL ? 0 : (smode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS ? 1 : 3); light_data.blend_splits = storage->light_directional_get_blend_splits(base); for (int j = 0; j < 4; j++) { - Rect2 atlas_rect = light_instance_get_directional_shadow_atlas_rect(li, j); - CameraMatrix matrix = light_instance_get_shadow_camera(li, j); - float split = light_instance_get_directional_shadow_split(li, MIN(limit, j)); + Rect2 atlas_rect = li->shadow_transform[j].atlas_rect; + CameraMatrix matrix = li->shadow_transform[j].camera; + float split = li->shadow_transform[MIN(limit, j)].split; CameraMatrix bias; bias.set_light_bias(); CameraMatrix rectm; rectm.set_light_atlas_rect(atlas_rect); - Transform modelview = (p_camera_inverse_transform * light_instance_get_shadow_transform(li, j)).inverse(); + Transform modelview = (inverse_transform * li->shadow_transform[j].transform).inverse(); CameraMatrix shadow_mtx = rectm * bias * matrix * modelview; light_data.shadow_split_offsets[j] = split; - float bias_scale = light_instance_get_shadow_bias_scale(li, j); + float bias_scale = li->shadow_transform[j].bias_scale; light_data.shadow_bias[j] = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * bias_scale; - light_data.shadow_normal_bias[j] = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * light_instance_get_directional_shadow_texel_size(li, j); + light_data.shadow_normal_bias[j] = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * li->shadow_transform[j].shadow_texel_size; light_data.shadow_transmittance_bias[j] = storage->light_get_transmittance_bias(base) * bias_scale; - light_data.shadow_z_range[j] = light_instance_get_shadow_range(li, j); - light_data.shadow_range_begin[j] = light_instance_get_shadow_range_begin(li, j); - RasterizerStorageRD::store_camera(shadow_mtx, light_data.shadow_matrices[j]); + light_data.shadow_z_range[j] = li->shadow_transform[j].farplane; + light_data.shadow_range_begin[j] = li->shadow_transform[j].range_begin; + RendererStorageRD::store_camera(shadow_mtx, light_data.shadow_matrices[j]); - Vector2 uv_scale = light_instance_get_shadow_uv_scale(li, j); + Vector2 uv_scale = li->shadow_transform[j].uv_scale; uv_scale *= atlas_rect.size; //adapt to atlas size switch (j) { case 0: { @@ -6074,213 +6427,231 @@ void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull } } - // Copy to SkyDirectionalLightData - if (r_directional_light_count < sky_scene_state.max_directional_lights) { - SkyDirectionalLightData &sky_light_data = sky_scene_state.directional_lights[r_directional_light_count]; - - Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized(); - - sky_light_data.direction[0] = world_direction.x; - sky_light_data.direction[1] = world_direction.y; - sky_light_data.direction[2] = -world_direction.z; - - sky_light_data.energy = light_data.energy / Math_PI; - - sky_light_data.color[0] = light_data.color[0]; - sky_light_data.color[1] = light_data.color[1]; - sky_light_data.color[2] = light_data.color[2]; - - sky_light_data.enabled = true; - sky_light_data.size = angular_diameter; - sky_scene_state.ubo.directional_light_count++; - } - r_directional_light_count++; } break; - case RS::LIGHT_SPOT: case RS::LIGHT_OMNI: { - if (light_count >= cluster.max_lights) { + if (cluster.omni_light_count >= cluster.max_lights) { + continue; + } + + cluster.omni_light_sort[cluster.omni_light_count].instance = li; + cluster.omni_light_sort[cluster.omni_light_count].depth = camera_plane.distance_to(li->transform.origin); + cluster.omni_light_count++; + } break; + case RS::LIGHT_SPOT: { + if (cluster.spot_light_count >= cluster.max_lights) { continue; } - Transform light_transform = light_instance_get_base_transform(li); + cluster.spot_light_sort[cluster.spot_light_count].instance = li; + cluster.spot_light_sort[cluster.spot_light_count].depth = camera_plane.distance_to(li->transform.origin); + cluster.spot_light_count++; + } break; + } - Cluster::LightData &light_data = cluster.lights[light_count]; - cluster.lights_instances[light_count] = li; + li->last_pass = RSG::rasterizer->get_frame_number(); + } - float sign = storage->light_is_negative(base) ? -1 : 1; - Color linear_col = storage->light_get_color(base).to_linear(); + if (cluster.omni_light_count) { + SortArray<Cluster::InstanceSort<LightInstance>> sorter; + sorter.sort(cluster.omni_light_sort, cluster.omni_light_count); + } - light_data.attenuation_energy[0] = Math::make_half_float(storage->light_get_param(base, RS::LIGHT_PARAM_ATTENUATION)); - light_data.attenuation_energy[1] = Math::make_half_float(sign * storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * Math_PI); + if (cluster.spot_light_count) { + SortArray<Cluster::InstanceSort<LightInstance>> sorter; + sorter.sort(cluster.spot_light_sort, cluster.spot_light_count); + } - light_data.color_specular[0] = MIN(uint32_t(linear_col.r * 255), 255); - light_data.color_specular[1] = MIN(uint32_t(linear_col.g * 255), 255); - light_data.color_specular[2] = MIN(uint32_t(linear_col.b * 255), 255); - light_data.color_specular[3] = MIN(uint32_t(storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR) * 255), 255); + ShadowAtlas *shadow_atlas = nullptr; - float radius = MAX(0.001, storage->light_get_param(base, RS::LIGHT_PARAM_RANGE)); - light_data.inv_radius = 1.0 / radius; + if (p_shadow_atlas.is_valid() && p_using_shadows) { + shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); + } - Vector3 pos = p_camera_inverse_transform.xform(light_transform.origin); + for (uint32_t i = 0; i < (cluster.omni_light_count + cluster.spot_light_count); i++) { + uint32_t index = (i < cluster.omni_light_count) ? i : i - (cluster.omni_light_count); + Cluster::LightData &light_data = (i < cluster.omni_light_count) ? cluster.omni_lights[index] : cluster.spot_lights[index]; + RS::LightType type = (i < cluster.omni_light_count) ? RS::LIGHT_OMNI : RS::LIGHT_SPOT; + LightInstance *li = (i < cluster.omni_light_count) ? cluster.omni_light_sort[index].instance : cluster.spot_light_sort[index].instance; + RID base = li->light; - light_data.position[0] = pos.x; - light_data.position[1] = pos.y; - light_data.position[2] = pos.z; + Transform light_transform = li->transform; - Vector3 direction = p_camera_inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, -1))).normalized(); + float sign = storage->light_is_negative(base) ? -1 : 1; + Color linear_col = storage->light_get_color(base).to_linear(); - light_data.direction[0] = direction.x; - light_data.direction[1] = direction.y; - light_data.direction[2] = direction.z; + light_data.attenuation = storage->light_get_param(base, RS::LIGHT_PARAM_ATTENUATION); - float size = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE); + float energy = sign * storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * Math_PI; - light_data.size = size; + light_data.color[0] = linear_col.r * energy; + light_data.color[1] = linear_col.g * energy; + light_data.color[2] = linear_col.b * energy; + light_data.specular_amount = storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR) * 2.0; - light_data.cone_attenuation_angle[0] = Math::make_half_float(storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ATTENUATION)); - float spot_angle = storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ANGLE); - light_data.cone_attenuation_angle[1] = Math::make_half_float(Math::cos(Math::deg2rad(spot_angle))); + float radius = MAX(0.001, storage->light_get_param(base, RS::LIGHT_PARAM_RANGE)); + light_data.inv_radius = 1.0 / radius; - light_data.mask = storage->light_get_cull_mask(base); + Vector3 pos = inverse_transform.xform(light_transform.origin); - light_data.atlas_rect[0] = 0; - light_data.atlas_rect[1] = 0; - light_data.atlas_rect[2] = 0; - light_data.atlas_rect[3] = 0; + light_data.position[0] = pos.x; + light_data.position[1] = pos.y; + light_data.position[2] = pos.z; - RID projector = storage->light_get_projector(base); + Vector3 direction = inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, -1))).normalized(); - if (projector.is_valid()) { - Rect2 rect = storage->decal_atlas_get_texture_rect(projector); + light_data.direction[0] = direction.x; + light_data.direction[1] = direction.y; + light_data.direction[2] = direction.z; - if (type == RS::LIGHT_SPOT) { - light_data.projector_rect[0] = rect.position.x; - light_data.projector_rect[1] = rect.position.y + rect.size.height; //flip because shadow is flipped - light_data.projector_rect[2] = rect.size.width; - light_data.projector_rect[3] = -rect.size.height; - } else { - light_data.projector_rect[0] = rect.position.x; - light_data.projector_rect[1] = rect.position.y; - light_data.projector_rect[2] = rect.size.width; - light_data.projector_rect[3] = rect.size.height * 0.5; //used by dp, so needs to be half - } - } else { - light_data.projector_rect[0] = 0; - light_data.projector_rect[1] = 0; - light_data.projector_rect[2] = 0; - light_data.projector_rect[3] = 0; - } + float size = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE); - if (p_using_shadows && p_shadow_atlas.is_valid() && shadow_atlas_owns_light_instance(p_shadow_atlas, li)) { - // fill in the shadow information + light_data.size = size; - Color shadow_color = storage->light_get_shadow_color(base); + light_data.inv_spot_attenuation = 1.0f / storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ATTENUATION); + float spot_angle = storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ANGLE); + light_data.cos_spot_angle = Math::cos(Math::deg2rad(spot_angle)); - light_data.shadow_color_enabled[0] = MIN(uint32_t(shadow_color.r * 255), 255); - light_data.shadow_color_enabled[1] = MIN(uint32_t(shadow_color.g * 255), 255); - light_data.shadow_color_enabled[2] = MIN(uint32_t(shadow_color.b * 255), 255); - light_data.shadow_color_enabled[3] = 255; + light_data.mask = storage->light_get_cull_mask(base); - if (type == RS::LIGHT_SPOT) { - light_data.shadow_bias = (storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * radius / 10.0); - float shadow_texel_size = Math::tan(Math::deg2rad(spot_angle)) * radius * 2.0; - shadow_texel_size *= light_instance_get_shadow_texel_size(li, p_shadow_atlas); + light_data.atlas_rect[0] = 0; + light_data.atlas_rect[1] = 0; + light_data.atlas_rect[2] = 0; + light_data.atlas_rect[3] = 0; - light_data.shadow_normal_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size; + RID projector = storage->light_get_projector(base); - } else { //omni - light_data.shadow_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * radius / 10.0; - float shadow_texel_size = light_instance_get_shadow_texel_size(li, p_shadow_atlas); - light_data.shadow_normal_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size * 2.0; // applied in -1 .. 1 space - } + if (projector.is_valid()) { + Rect2 rect = storage->decal_atlas_get_texture_rect(projector); + + if (type == RS::LIGHT_SPOT) { + light_data.projector_rect[0] = rect.position.x; + light_data.projector_rect[1] = rect.position.y + rect.size.height; //flip because shadow is flipped + light_data.projector_rect[2] = rect.size.width; + light_data.projector_rect[3] = -rect.size.height; + } else { + light_data.projector_rect[0] = rect.position.x; + light_data.projector_rect[1] = rect.position.y; + light_data.projector_rect[2] = rect.size.width; + light_data.projector_rect[3] = rect.size.height * 0.5; //used by dp, so needs to be half + } + } else { + light_data.projector_rect[0] = 0; + light_data.projector_rect[1] = 0; + light_data.projector_rect[2] = 0; + light_data.projector_rect[3] = 0; + } - light_data.transmittance_bias = storage->light_get_transmittance_bias(base); + if (shadow_atlas && shadow_atlas->shadow_owners.has(li->self)) { + // fill in the shadow information - Rect2 rect = light_instance_get_shadow_atlas_rect(li, p_shadow_atlas); + light_data.shadow_enabled = true; - light_data.atlas_rect[0] = rect.position.x; - light_data.atlas_rect[1] = rect.position.y; - light_data.atlas_rect[2] = rect.size.width; - light_data.atlas_rect[3] = rect.size.height; + if (type == RS::LIGHT_SPOT) { + light_data.shadow_bias = (storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * radius / 10.0); + float shadow_texel_size = Math::tan(Math::deg2rad(spot_angle)) * radius * 2.0; + shadow_texel_size *= light_instance_get_shadow_texel_size(li->self, p_shadow_atlas); - light_data.soft_shadow_scale = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR); - light_data.shadow_volumetric_fog_fade = 1.0 / storage->light_get_shadow_volumetric_fog_fade(base); + light_data.shadow_normal_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size; - if (type == RS::LIGHT_OMNI) { - light_data.atlas_rect[3] *= 0.5; //one paraboloid on top of another - Transform proj = (p_camera_inverse_transform * light_transform).inverse(); + } else { //omni + light_data.shadow_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * radius / 10.0; + float shadow_texel_size = light_instance_get_shadow_texel_size(li->self, p_shadow_atlas); + light_data.shadow_normal_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size * 2.0; // applied in -1 .. 1 space + } - RasterizerStorageRD::store_transform(proj, light_data.shadow_matrix); + light_data.transmittance_bias = storage->light_get_transmittance_bias(base); - if (size > 0.0) { - light_data.soft_shadow_size = size; - } else { - light_data.soft_shadow_size = 0.0; - light_data.soft_shadow_scale *= shadows_quality_radius_get(); // Only use quality radius for PCF - } + Rect2 rect = light_instance_get_shadow_atlas_rect(li->self, p_shadow_atlas); - } else if (type == RS::LIGHT_SPOT) { - Transform modelview = (p_camera_inverse_transform * light_transform).inverse(); - CameraMatrix bias; - bias.set_light_bias(); + light_data.atlas_rect[0] = rect.position.x; + light_data.atlas_rect[1] = rect.position.y; + light_data.atlas_rect[2] = rect.size.width; + light_data.atlas_rect[3] = rect.size.height; - CameraMatrix shadow_mtx = bias * light_instance_get_shadow_camera(li, 0) * modelview; - RasterizerStorageRD::store_camera(shadow_mtx, light_data.shadow_matrix); + light_data.soft_shadow_scale = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR); + light_data.shadow_volumetric_fog_fade = 1.0 / storage->light_get_shadow_volumetric_fog_fade(base); - if (size > 0.0) { - CameraMatrix cm = light_instance_get_shadow_camera(li, 0); - float half_np = cm.get_z_near() * Math::tan(Math::deg2rad(spot_angle)); - light_data.soft_shadow_size = (size * 0.5 / radius) / (half_np / cm.get_z_near()) * rect.size.width; - } else { - light_data.soft_shadow_size = 0.0; - light_data.soft_shadow_scale *= shadows_quality_radius_get(); // Only use quality radius for PCF - } - } + if (type == RS::LIGHT_OMNI) { + light_data.atlas_rect[3] *= 0.5; //one paraboloid on top of another + Transform proj = (inverse_transform * light_transform).inverse(); + + RendererStorageRD::store_transform(proj, light_data.shadow_matrix); + + if (size > 0.0) { + light_data.soft_shadow_size = size; } else { - light_data.shadow_color_enabled[3] = 0; + light_data.soft_shadow_size = 0.0; + light_data.soft_shadow_scale *= shadows_quality_radius_get(); // Only use quality radius for PCF } - light_instance_set_index(li, light_count); + } else if (type == RS::LIGHT_SPOT) { + Transform modelview = (inverse_transform * light_transform).inverse(); + CameraMatrix bias; + bias.set_light_bias(); - cluster.builder.add_light(type == RS::LIGHT_SPOT ? LightClusterBuilder::LIGHT_TYPE_SPOT : LightClusterBuilder::LIGHT_TYPE_OMNI, light_transform, radius, spot_angle); + CameraMatrix shadow_mtx = bias * li->shadow_transform[0].camera * modelview; + RendererStorageRD::store_camera(shadow_mtx, light_data.shadow_matrix); - light_count++; - r_positional_light_count++; - } break; + if (size > 0.0) { + CameraMatrix cm = li->shadow_transform[0].camera; + float half_np = cm.get_z_near() * Math::tan(Math::deg2rad(spot_angle)); + light_data.soft_shadow_size = (size * 0.5 / radius) / (half_np / cm.get_z_near()) * rect.size.width; + } else { + light_data.soft_shadow_size = 0.0; + light_data.soft_shadow_scale *= shadows_quality_radius_get(); // Only use quality radius for PCF + } + } + } else { + light_data.shadow_enabled = false; } - light_instance_set_render_pass(li, RSG::rasterizer->get_frame_number()); + li->light_index = index; + + current_cluster_builder->add_light(type == RS::LIGHT_SPOT ? ClusterBuilderRD::LIGHT_TYPE_SPOT : ClusterBuilderRD::LIGHT_TYPE_OMNI, light_transform, radius, spot_angle); + + r_positional_light_count++; + } - //update UBO for forward rendering, blit to texture for clustered + //update without barriers + if (cluster.omni_light_count) { + RD::get_singleton()->buffer_update(cluster.omni_light_buffer, 0, sizeof(Cluster::LightData) * cluster.omni_light_count, cluster.omni_lights, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); } - if (light_count) { - RD::get_singleton()->buffer_update(cluster.light_buffer, 0, sizeof(Cluster::LightData) * light_count, cluster.lights, true); + if (cluster.spot_light_count) { + RD::get_singleton()->buffer_update(cluster.spot_light_buffer, 0, sizeof(Cluster::LightData) * cluster.spot_light_count, cluster.spot_lights, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); } if (r_directional_light_count) { - RD::get_singleton()->buffer_update(cluster.directional_light_buffer, 0, sizeof(Cluster::DirectionalLightData) * r_directional_light_count, cluster.directional_lights, true); + RD::get_singleton()->buffer_update(cluster.directional_light_buffer, 0, sizeof(Cluster::DirectionalLightData) * r_directional_light_count, cluster.directional_lights, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); } } -void RasterizerSceneRD::_setup_decals(const RID *p_decal_instances, int p_decal_count, const Transform &p_camera_inverse_xform) { +void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const Transform &p_camera_inverse_xform) { Transform uv_xform; uv_xform.basis.scale(Vector3(2.0, 1.0, 2.0)); uv_xform.origin = Vector3(-1.0, 0.0, -1.0); - p_decal_count = MIN((uint32_t)p_decal_count, cluster.max_decals); - int idx = 0; - for (int i = 0; i < p_decal_count; i++) { - RID di = p_decal_instances[i]; - RID decal = decal_instance_get_base(di); + uint32_t decal_count = p_decals.size(); - Transform xform = decal_instance_get_transform(di); + cluster.decal_count = 0; - float fade = 1.0; + for (uint32_t i = 0; i < decal_count; i++) { + if (cluster.decal_count == cluster.max_decals) { + break; + } + + DecalInstance *di = decal_instance_owner.getornull(p_decals[i]); + if (!di) { + continue; + } + RID decal = di->decal; + + Transform xform = di->transform; + + real_t distance = -p_camera_inverse_xform.xform(xform.origin).z; if (storage->decal_is_distance_fade_enabled(decal)) { - real_t distance = -p_camera_inverse_xform.xform(xform.origin).z; float fade_begin = storage->decal_get_distance_fade_begin(decal); float fade_length = storage->decal_get_distance_fade_length(decal); @@ -6288,19 +6659,44 @@ void RasterizerSceneRD::_setup_decals(const RID *p_decal_instances, int p_decal_ if (distance > fade_begin + fade_length) { continue; // do not use this decal, its invisible } + } + } + cluster.decal_sort[cluster.decal_count].instance = di; + cluster.decal_sort[cluster.decal_count].depth = distance; + cluster.decal_count++; + } + + if (cluster.decal_count > 0) { + SortArray<Cluster::InstanceSort<DecalInstance>> sort_array; + sort_array.sort(cluster.decal_sort, cluster.decal_count); + } + + for (uint32_t i = 0; i < cluster.decal_count; i++) { + DecalInstance *di = cluster.decal_sort[i].instance; + RID decal = di->decal; + + Transform xform = di->transform; + float fade = 1.0; + + if (storage->decal_is_distance_fade_enabled(decal)) { + real_t distance = -p_camera_inverse_xform.xform(xform.origin).z; + float fade_begin = storage->decal_get_distance_fade_begin(decal); + float fade_length = storage->decal_get_distance_fade_length(decal); + + if (distance > fade_begin) { fade = 1.0 - (distance - fade_begin) / fade_length; } } - Cluster::DecalData &dd = cluster.decals[idx]; + Cluster::DecalData &dd = cluster.decals[i]; Vector3 decal_extents = storage->decal_get_extents(decal); Transform scale_xform; scale_xform.basis.scale(Vector3(decal_extents.x, decal_extents.y, decal_extents.z)); - Transform to_decal_xform = (p_camera_inverse_xform * decal_instance_get_transform(di) * scale_xform * uv_xform).affine_inverse(); - RasterizerStorageRD::store_transform(to_decal_xform, dd.xform); + Transform to_decal_xform = (p_camera_inverse_xform * di->transform * scale_xform * uv_xform).affine_inverse(); + RendererStorageRD::store_transform(to_decal_xform, dd.xform); Vector3 normal = xform.basis.get_axis(Vector3::AXIS_Y).normalized(); normal = p_camera_inverse_xform.basis.xform(normal); //camera is normalized, so fine @@ -6338,7 +6734,7 @@ void RasterizerSceneRD::_setup_decals(const RID *p_decal_instances, int p_decal_ dd.normal_rect[3] = rect.size.y; Basis normal_xform = p_camera_inverse_xform.basis * xform.basis.orthonormalized(); - RasterizerStorageRD::store_basis_3x4(normal_xform, dd.normal_xform); + RendererStorageRD::store_basis_3x4(normal_xform, dd.normal_xform); } else { dd.normal_rect[0] = 0; dd.normal_rect[1] = 0; @@ -6384,19 +6780,18 @@ void RasterizerSceneRD::_setup_decals(const RID *p_decal_instances, int p_decal_ dd.upper_fade = storage->decal_get_upper_fade(decal); dd.lower_fade = storage->decal_get_lower_fade(decal); - cluster.builder.add_decal(xform, decal_extents); - - idx++; + current_cluster_builder->add_box(ClusterBuilderRD::BOX_TYPE_DECAL, xform, decal_extents); } - if (idx > 0) { - RD::get_singleton()->buffer_update(cluster.decal_buffer, 0, sizeof(Cluster::DecalData) * idx, cluster.decals, true); + if (cluster.decal_count > 0) { + RD::get_singleton()->buffer_update(cluster.decal_buffer, 0, sizeof(Cluster::DecalData) * cluster.decal_count, cluster.decals, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); } } -void RasterizerSceneRD::_volumetric_fog_erase(RenderBuffers *rb) { +void RendererSceneRenderRD::_volumetric_fog_erase(RenderBuffers *rb) { ERR_FAIL_COND(!rb->volumetric_fog); + RD::get_singleton()->free(rb->volumetric_fog->prev_light_density_map); RD::get_singleton()->free(rb->volumetric_fog->light_density_map); RD::get_singleton()->free(rb->volumetric_fog->fog_map); @@ -6418,50 +6813,7 @@ void RasterizerSceneRD::_volumetric_fog_erase(RenderBuffers *rb) { rb->volumetric_fog = nullptr; } -void RasterizerSceneRD::_allocate_shadow_shrink_stages(RID p_base, int p_base_size, Vector<ShadowShrinkStage> &shrink_stages, uint32_t p_target_size) { - //create fog mipmaps - uint32_t fog_texture_size = p_target_size; - uint32_t base_texture_size = p_base_size; - - ShadowShrinkStage first; - first.size = base_texture_size; - first.texture = p_base; - shrink_stages.push_back(first); //put depth first in case we dont find smaller ones - - while (fog_texture_size < base_texture_size) { - base_texture_size = MAX(base_texture_size / 8, fog_texture_size); - - ShadowShrinkStage s; - s.size = base_texture_size; - - RD::TextureFormat tf; - tf.format = RD::DATA_FORMAT_R32_SFLOAT; - tf.width = base_texture_size; - tf.height = base_texture_size; - tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT; - - if (base_texture_size == fog_texture_size) { - s.filter_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); - tf.usage_bits |= RD::TEXTURE_USAGE_SAMPLING_BIT; - } - - s.texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); - - shrink_stages.push_back(s); - } -} - -void RasterizerSceneRD::_clear_shadow_shrink_stages(Vector<ShadowShrinkStage> &shrink_stages) { - for (int i = 1; i < shrink_stages.size(); i++) { - RD::get_singleton()->free(shrink_stages[i].texture); - if (shrink_stages[i].filter_texture.is_valid()) { - RD::get_singleton()->free(shrink_stages[i].filter_texture); - } - } - shrink_stages.clear(); -} - -void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_gi_probe_count) { +void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_gi_probe_count) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(!rb); Environment *env = environment_owner.getornull(p_environment); @@ -6483,6 +6835,8 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir return; } + RENDER_TIMESTAMP(">Volumetric Fog"); + if (env && env->volumetric_fog_enabled && !rb->volumetric_fog) { //required volumetric fog but not existing, create rb->volumetric_fog = memnew(VolumetricFog); @@ -6495,12 +6849,17 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir tf.width = target_width; tf.height = target_height; tf.depth = volumetric_fog_depth; - tf.type = RD::TEXTURE_TYPE_3D; - tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT; + tf.texture_type = RD::TEXTURE_TYPE_3D; + tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; rb->volumetric_fog->light_density_map = RD::get_singleton()->texture_create(tf, RD::TextureView()); - tf.usage_bits |= RD::TEXTURE_USAGE_SAMPLING_BIT; + tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + + rb->volumetric_fog->prev_light_density_map = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->texture_clear(rb->volumetric_fog->prev_light_density_map, Color(0, 0, 0, 0), 0, 1, 0, 1); + + tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; rb->volumetric_fog->fog_map = RD::get_singleton()->texture_create(tf, RD::TextureView()); _render_buffers_uniform_set_changed(p_render_buffers); @@ -6509,7 +6868,7 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir { RD::Uniform u; u.binding = 0; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.ids.push_back(rb->volumetric_fog->fog_map); uniforms.push_back(u); } @@ -6517,162 +6876,6 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir rb->volumetric_fog->sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_FOG); } - //update directional shadow - - if (p_use_directional_shadows) { - if (directional_shadow.shrink_stages.empty()) { - if (rb->volumetric_fog->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) { - //invalidate uniform set, we will need a new one - RD::get_singleton()->free(rb->volumetric_fog->uniform_set); - rb->volumetric_fog->uniform_set = RID(); - } - _allocate_shadow_shrink_stages(directional_shadow.depth, directional_shadow.size, directional_shadow.shrink_stages, volumetric_fog_directional_shadow_shrink); - } - - if (directional_shadow.shrink_stages.size() > 1) { - RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - for (int i = 1; i < directional_shadow.shrink_stages.size(); i++) { - int32_t src_size = directional_shadow.shrink_stages[i - 1].size; - int32_t dst_size = directional_shadow.shrink_stages[i].size; - Rect2i r(0, 0, src_size, src_size); - int32_t shrink_limit = 8 / (src_size / dst_size); - - storage->get_effects()->reduce_shadow(directional_shadow.shrink_stages[i - 1].texture, directional_shadow.shrink_stages[i].texture, Size2i(src_size, src_size), r, shrink_limit, compute_list); - RD::get_singleton()->compute_list_add_barrier(compute_list); - if (env->volumetric_fog_shadow_filter != RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_DISABLED && directional_shadow.shrink_stages[i].filter_texture.is_valid()) { - Rect2i rf(0, 0, dst_size, dst_size); - storage->get_effects()->filter_shadow(directional_shadow.shrink_stages[i].texture, directional_shadow.shrink_stages[i].filter_texture, Size2i(dst_size, dst_size), rf, env->volumetric_fog_shadow_filter, compute_list); - } - } - RD::get_singleton()->compute_list_end(); - } - } - - ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); - - if (shadow_atlas) { - //shrink shadows that need to be shrunk - - bool force_shrink_shadows = false; - - if (shadow_atlas->shrink_stages.empty()) { - if (rb->volumetric_fog->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) { - //invalidate uniform set, we will need a new one - RD::get_singleton()->free(rb->volumetric_fog->uniform_set); - rb->volumetric_fog->uniform_set = RID(); - } - _allocate_shadow_shrink_stages(shadow_atlas->depth, shadow_atlas->size, shadow_atlas->shrink_stages, volumetric_fog_positional_shadow_shrink); - force_shrink_shadows = true; - } - - if (rb->volumetric_fog->last_shadow_filter != env->volumetric_fog_shadow_filter) { - //if shadow filter changed, invalidate caches - rb->volumetric_fog->last_shadow_filter = env->volumetric_fog_shadow_filter; - force_shrink_shadows = true; - } - - cluster.lights_shadow_rect_cache_count = 0; - - for (int i = 0; i < p_positional_light_count; i++) { - if (cluster.lights[i].shadow_color_enabled[3] > 127) { - RID li = cluster.lights_instances[i]; - - ERR_CONTINUE(!shadow_atlas->shadow_owners.has(li)); - - uint32_t key = shadow_atlas->shadow_owners[li]; - - uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; - uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; - - ERR_CONTINUE((int)shadow >= shadow_atlas->quadrants[quadrant].shadows.size()); - - ShadowAtlas::Quadrant::Shadow &s = shadow_atlas->quadrants[quadrant].shadows.write[shadow]; - - if (!force_shrink_shadows && s.fog_version == s.version) { - continue; //do not update, no need - } - - s.fog_version = s.version; - - uint32_t quadrant_size = shadow_atlas->size >> 1; - - Rect2i atlas_rect; - - atlas_rect.position.x = (quadrant & 1) * quadrant_size; - atlas_rect.position.y = (quadrant >> 1) * quadrant_size; - - uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); - atlas_rect.position.x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; - atlas_rect.position.y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; - - atlas_rect.size.x = shadow_size; - atlas_rect.size.y = shadow_size; - - cluster.lights_shadow_rect_cache[cluster.lights_shadow_rect_cache_count] = atlas_rect; - - cluster.lights_shadow_rect_cache_count++; - - if (cluster.lights_shadow_rect_cache_count == cluster.max_lights) { - break; //light limit reached - } - } - } - - if (cluster.lights_shadow_rect_cache_count > 0) { - //there are shadows to be shrunk, try to do them in parallel - RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - - for (int i = 1; i < shadow_atlas->shrink_stages.size(); i++) { - int32_t base_size = shadow_atlas->shrink_stages[0].size; - int32_t src_size = shadow_atlas->shrink_stages[i - 1].size; - int32_t dst_size = shadow_atlas->shrink_stages[i].size; - - uint32_t rect_divisor = base_size / src_size; - - int32_t shrink_limit = 8 / (src_size / dst_size); - - //shrink in parallel for more performance - for (uint32_t j = 0; j < cluster.lights_shadow_rect_cache_count; j++) { - Rect2i src_rect = cluster.lights_shadow_rect_cache[j]; - - src_rect.position /= rect_divisor; - src_rect.size /= rect_divisor; - - storage->get_effects()->reduce_shadow(shadow_atlas->shrink_stages[i - 1].texture, shadow_atlas->shrink_stages[i].texture, Size2i(src_size, src_size), src_rect, shrink_limit, compute_list); - } - - RD::get_singleton()->compute_list_add_barrier(compute_list); - - if (env->volumetric_fog_shadow_filter != RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_DISABLED && shadow_atlas->shrink_stages[i].filter_texture.is_valid()) { - uint32_t filter_divisor = base_size / dst_size; - - //filter in parallel for more performance - for (uint32_t j = 0; j < cluster.lights_shadow_rect_cache_count; j++) { - Rect2i dst_rect = cluster.lights_shadow_rect_cache[j]; - - dst_rect.position /= filter_divisor; - dst_rect.size /= filter_divisor; - - storage->get_effects()->filter_shadow(shadow_atlas->shrink_stages[i].texture, shadow_atlas->shrink_stages[i].filter_texture, Size2i(dst_size, dst_size), dst_rect, env->volumetric_fog_shadow_filter, compute_list, true, false); - } - - RD::get_singleton()->compute_list_add_barrier(compute_list); - - for (uint32_t j = 0; j < cluster.lights_shadow_rect_cache_count; j++) { - Rect2i dst_rect = cluster.lights_shadow_rect_cache[j]; - - dst_rect.position /= filter_divisor; - dst_rect.size /= filter_divisor; - - storage->get_effects()->filter_shadow(shadow_atlas->shrink_stages[i].texture, shadow_atlas->shrink_stages[i].filter_texture, Size2i(dst_size, dst_size), dst_rect, env->volumetric_fog_shadow_filter, compute_list, false, true); - } - } - } - - RD::get_singleton()->compute_list_end(); - } - } - //update volumetric fog if (rb->volumetric_fog->uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) { @@ -6682,12 +6885,13 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; - if (shadow_atlas == nullptr || shadow_atlas->shrink_stages.size() == 0) { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK)); + ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); + if (shadow_atlas == nullptr || shadow_atlas->depth.is_null()) { + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK)); } else { - u.ids.push_back(shadow_atlas->shrink_stages[shadow_atlas->shrink_stages.size() - 1].texture); + u.ids.push_back(shadow_atlas->depth); } uniforms.push_back(u); @@ -6695,51 +6899,50 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; - if (directional_shadow.shrink_stages.size() == 0) { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK)); + if (directional_shadow.depth.is_valid()) { + u.ids.push_back(directional_shadow.depth); } else { - u.ids.push_back(directional_shadow.shrink_stages[directional_shadow.shrink_stages.size() - 1].texture); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK)); } uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 3; - u.ids.push_back(get_positional_light_buffer()); + u.ids.push_back(get_omni_light_buffer()); uniforms.push_back(u); } - { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 4; - u.ids.push_back(get_directional_light_buffer()); + u.ids.push_back(get_spot_light_buffer()); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 5; - u.ids.push_back(get_cluster_builder_texture()); + u.ids.push_back(get_directional_light_buffer()); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 6; - u.ids.push_back(get_cluster_builder_indices_buffer()); + u.ids.push_back(rb->cluster_builder->get_cluster_buffer()); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 7; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); @@ -6747,7 +6950,7 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 8; u.ids.push_back(rb->volumetric_fog->light_density_map); uniforms.push_back(u); @@ -6755,7 +6958,7 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 9; u.ids.push_back(rb->volumetric_fog->fog_map); uniforms.push_back(u); @@ -6763,7 +6966,7 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 10; u.ids.push_back(shadow_sampler); uniforms.push_back(u); @@ -6771,7 +6974,7 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 11; u.ids.push_back(render_buffers_get_gi_probe_buffer(p_render_buffers)); uniforms.push_back(u); @@ -6779,7 +6982,7 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 12; for (int i = 0; i < RenderBuffers::MAX_GIPROBES; i++) { u.ids.push_back(rb->giprobe_textures[i]); @@ -6788,11 +6991,25 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 13; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 14; + u.ids.push_back(volumetric_fog.params_ubo); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 15; + u.ids.push_back(rb->volumetric_fog->prev_light_density_map); + uniforms.push_back(u); + } rb->volumetric_fog->uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, 0), 0); @@ -6809,7 +7026,7 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 0; u.ids.push_back(gi.sdfgi_ubo); uniforms.push_back(u); @@ -6817,7 +7034,7 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; u.ids.push_back(rb->sdfgi->ambient_texture); uniforms.push_back(u); @@ -6825,7 +7042,7 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; u.ids.push_back(rb->sdfgi->occlusion_texture); uniforms.push_back(u); @@ -6838,7 +7055,7 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir rb->volumetric_fog->length = env->volumetric_fog_length; rb->volumetric_fog->spread = env->volumetric_fog_detail_spread; - VolumetricFogShader::PushConstant push_constant; + VolumetricFogShader::ParamsUBO params; Vector2 frustum_near_size = p_cam_projection.get_viewport_half_extents(); Vector2 frustum_far_size = p_cam_projection.get_far_plane_half_extents(); @@ -6854,51 +7071,78 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir fog_near_size = Vector2(); } - push_constant.fog_frustum_size_begin[0] = fog_near_size.x; - push_constant.fog_frustum_size_begin[1] = fog_near_size.y; + params.fog_frustum_size_begin[0] = fog_near_size.x; + params.fog_frustum_size_begin[1] = fog_near_size.y; - push_constant.fog_frustum_size_end[0] = fog_far_size.x; - push_constant.fog_frustum_size_end[1] = fog_far_size.y; + params.fog_frustum_size_end[0] = fog_far_size.x; + params.fog_frustum_size_end[1] = fog_far_size.y; - push_constant.z_near = z_near; - push_constant.z_far = z_far; + params.z_near = z_near; + params.z_far = z_far; - push_constant.fog_frustum_end = fog_end; + params.fog_frustum_end = fog_end; - push_constant.fog_volume_size[0] = rb->volumetric_fog->width; - push_constant.fog_volume_size[1] = rb->volumetric_fog->height; - push_constant.fog_volume_size[2] = rb->volumetric_fog->depth; + params.fog_volume_size[0] = rb->volumetric_fog->width; + params.fog_volume_size[1] = rb->volumetric_fog->height; + params.fog_volume_size[2] = rb->volumetric_fog->depth; - push_constant.directional_light_count = p_directional_light_count; + params.directional_light_count = p_directional_light_count; Color light = env->volumetric_fog_light.to_linear(); - push_constant.light_energy[0] = light.r * env->volumetric_fog_light_energy; - push_constant.light_energy[1] = light.g * env->volumetric_fog_light_energy; - push_constant.light_energy[2] = light.b * env->volumetric_fog_light_energy; - push_constant.base_density = env->volumetric_fog_density; + params.light_energy[0] = light.r * env->volumetric_fog_light_energy; + params.light_energy[1] = light.g * env->volumetric_fog_light_energy; + params.light_energy[2] = light.b * env->volumetric_fog_light_energy; + params.base_density = env->volumetric_fog_density; + + params.detail_spread = env->volumetric_fog_detail_spread; + params.gi_inject = env->volumetric_fog_gi_inject; + + params.cam_rotation[0] = p_cam_transform.basis[0][0]; + params.cam_rotation[1] = p_cam_transform.basis[1][0]; + params.cam_rotation[2] = p_cam_transform.basis[2][0]; + params.cam_rotation[3] = 0; + params.cam_rotation[4] = p_cam_transform.basis[0][1]; + params.cam_rotation[5] = p_cam_transform.basis[1][1]; + params.cam_rotation[6] = p_cam_transform.basis[2][1]; + params.cam_rotation[7] = 0; + params.cam_rotation[8] = p_cam_transform.basis[0][2]; + params.cam_rotation[9] = p_cam_transform.basis[1][2]; + params.cam_rotation[10] = p_cam_transform.basis[2][2]; + params.cam_rotation[11] = 0; + params.filter_axis = 0; + params.max_gi_probes = env->volumetric_fog_gi_inject > 0.001 ? p_gi_probe_count : 0; + params.temporal_frame = RSG::rasterizer->get_frame_number() % VolumetricFog::MAX_TEMPORAL_FRAMES; + + Transform to_prev_cam_view = rb->volumetric_fog->prev_cam_transform.affine_inverse() * p_cam_transform; + storage->store_transform(to_prev_cam_view, params.to_prev_view); + + params.use_temporal_reprojection = env->volumetric_fog_temporal_reprojection; + params.temporal_blend = env->volumetric_fog_temporal_reprojection_amount; - push_constant.detail_spread = env->volumetric_fog_detail_spread; - push_constant.gi_inject = env->volumetric_fog_gi_inject; + { + uint32_t cluster_size = rb->cluster_builder->get_cluster_size(); + params.cluster_shift = get_shift_from_power_of_2(cluster_size); - push_constant.cam_rotation[0] = p_cam_transform.basis[0][0]; - push_constant.cam_rotation[1] = p_cam_transform.basis[1][0]; - push_constant.cam_rotation[2] = p_cam_transform.basis[2][0]; - push_constant.cam_rotation[3] = 0; - push_constant.cam_rotation[4] = p_cam_transform.basis[0][1]; - push_constant.cam_rotation[5] = p_cam_transform.basis[1][1]; - push_constant.cam_rotation[6] = p_cam_transform.basis[2][1]; - push_constant.cam_rotation[7] = 0; - push_constant.cam_rotation[8] = p_cam_transform.basis[0][2]; - push_constant.cam_rotation[9] = p_cam_transform.basis[1][2]; - push_constant.cam_rotation[10] = p_cam_transform.basis[2][2]; - push_constant.cam_rotation[11] = 0; - push_constant.filter_axis = 0; - push_constant.max_gi_probes = env->volumetric_fog_gi_inject > 0.001 ? p_gi_probe_count : 0; + uint32_t cluster_screen_width = (rb->width - 1) / cluster_size + 1; + uint32_t cluster_screen_height = (rb->height - 1) / cluster_size + 1; + params.cluster_type_size = cluster_screen_width * cluster_screen_height * (32 + 32); + params.cluster_width = cluster_screen_width; + params.max_cluster_element_count_div_32 = max_cluster_elements / 32; + + params.screen_size[0] = rb->width; + params.screen_size[1] = rb->height; + } /* Vector2 dssize = directional_shadow_get_size(); push_constant.directional_shadow_pixel_size[0] = 1.0 / dssize.x; push_constant.directional_shadow_pixel_size[1] = 1.0 / dssize.y; */ + + RD::get_singleton()->draw_command_begin_label("Render Volumetric Fog"); + + RENDER_TIMESTAMP("Render Fog"); + RD::get_singleton()->buffer_update(volumetric_fog.params_ubo, 0, sizeof(VolumetricFogShader::ParamsUBO), ¶ms, RD::BARRIER_MASK_COMPUTE); + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); bool use_filter = volumetric_fog_filter_active; @@ -6906,87 +7150,212 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[using_sdfgi ? VOLUMETRIC_FOG_SHADER_DENSITY_WITH_SDFGI : VOLUMETRIC_FOG_SHADER_DENSITY]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set, 0); + if (using_sdfgi) { RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->sdfgi_uniform_set, 1); } - RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VolumetricFogShader::PushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth, 4, 4, 4); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth); + + RD::get_singleton()->draw_command_end_label(); + + RD::get_singleton()->compute_list_end(); + + RD::get_singleton()->texture_copy(rb->volumetric_fog->light_density_map, rb->volumetric_fog->prev_light_density_map, Vector3(0, 0, 0), Vector3(0, 0, 0), Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), 0, 0, 0, 0); - RD::get_singleton()->compute_list_add_barrier(compute_list); + compute_list = RD::get_singleton()->compute_list_begin(); if (use_filter) { + RD::get_singleton()->draw_command_begin_label("Filter Fog"); + + RENDER_TIMESTAMP("Filter Fog"); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[VOLUMETRIC_FOG_SHADER_FILTER]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set, 0); - RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VolumetricFogShader::PushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth, 8, 8, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth); - RD::get_singleton()->compute_list_add_barrier(compute_list); + RD::get_singleton()->compute_list_end(); + //need restart for buffer update - push_constant.filter_axis = 1; + params.filter_axis = 1; + RD::get_singleton()->buffer_update(volumetric_fog.params_ubo, 0, sizeof(VolumetricFogShader::ParamsUBO), ¶ms); + compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[VOLUMETRIC_FOG_SHADER_FILTER]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set2, 0); - RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VolumetricFogShader::PushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth, 8, 8, 1); + if (using_sdfgi) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->sdfgi_uniform_set, 1); + } + RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth); RD::get_singleton()->compute_list_add_barrier(compute_list); + RD::get_singleton()->draw_command_end_label(); } + RENDER_TIMESTAMP("Integrate Fog"); + RD::get_singleton()->draw_command_begin_label("Integrate Fog"); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[VOLUMETRIC_FOG_SHADER_FOG]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set, 0); - RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VolumetricFogShader::PushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, 1, 8, 8, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, 1); - RD::get_singleton()->compute_list_end(); + RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_RASTER); + + RENDER_TIMESTAMP("<Volumetric Fog"); + RD::get_singleton()->draw_command_end_label(); + + rb->volumetric_fog->prev_cam_transform = p_cam_transform; } -void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) { - Color clear_color; - if (p_render_buffers.is_valid()) { - RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); - ERR_FAIL_COND(!rb); - clear_color = storage->render_target_get_clear_request_color(rb->render_target); - } else { - clear_color = storage->get_default_clear_color(); +uint32_t RendererSceneRenderRD::_get_render_state_directional_light_count() const { + return render_state.directional_light_count; +} + +bool RendererSceneRenderRD::_needs_post_prepass_render(bool p_use_gi) { + if (render_state.render_buffers.is_valid()) { + RenderBuffers *rb = render_buffers_owner.getornull(render_state.render_buffers); + if (rb->sdfgi != nullptr) { + return true; + } } + return false; +} - //assign render indices to giprobes - for (int i = 0; i < p_gi_probe_cull_count; i++) { - GIProbeInstance *giprobe_inst = gi_probe_instance_owner.getornull(p_gi_probe_cull_result[i]); - if (giprobe_inst) { - giprobe_inst->render_index = i; +void RendererSceneRenderRD::_post_prepass_render(bool p_use_gi) { + if (render_state.render_buffers.is_valid()) { + if (p_use_gi) { + _sdfgi_update_probes(render_state.render_buffers, render_state.environment); } } +} - if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) { - p_light_cull_count = 0; - p_reflection_probe_cull_count = 0; - p_gi_probe_cull_count = 0; +void RendererSceneRenderRD::_pre_resolve_render(bool p_use_gi) { + if (render_state.render_buffers.is_valid()) { + if (p_use_gi) { + RD::get_singleton()->compute_list_end(); + } + } +} + +void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, RID p_normal_roughness_buffer, RID p_gi_probe_buffer) { + // Render shadows while GI is rendering, due to how barriers are handled, this should happen at the same time + + if (render_state.render_buffers.is_valid() && p_use_gi) { + _sdfgi_store_probes(render_state.render_buffers); + } + + render_state.cube_shadows.clear(); + render_state.shadows.clear(); + render_state.directional_shadows.clear(); + + Plane camera_plane(render_state.cam_transform.origin, -render_state.cam_transform.basis.get_axis(Vector3::AXIS_Z)); + float lod_distance_multiplier = render_state.cam_projection.get_lod_multiplier(); + + { + for (int i = 0; i < render_state.render_shadow_count; i++) { + LightInstance *li = light_instance_owner.getornull(render_state.render_shadows[i].light); + + if (storage->light_get_type(li->light) == RS::LIGHT_DIRECTIONAL) { + render_state.directional_shadows.push_back(i); + } else if (storage->light_get_type(li->light) == RS::LIGHT_OMNI && storage->light_omni_get_shadow_mode(li->light) == RS::LIGHT_OMNI_SHADOW_CUBE) { + render_state.cube_shadows.push_back(i); + } else { + render_state.shadows.push_back(i); + } + } + + //cube shadows are rendered in their own way + for (uint32_t i = 0; i < render_state.cube_shadows.size(); i++) { + _render_shadow_pass(render_state.render_shadows[render_state.cube_shadows[i]].light, render_state.shadow_atlas, render_state.render_shadows[render_state.cube_shadows[i]].pass, render_state.render_shadows[render_state.cube_shadows[i]].instances, camera_plane, lod_distance_multiplier, render_state.screen_lod_threshold, true, true, true); + } + + if (render_state.directional_shadows.size()) { + //open the pass for directional shadows + _update_directional_shadow_atlas(); + RD::get_singleton()->draw_list_begin(directional_shadow.fb, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE); + RD::get_singleton()->draw_list_end(); + } + } + + // Render GI + + bool render_shadows = render_state.directional_shadows.size() || render_state.shadows.size(); + bool render_gi = render_state.render_buffers.is_valid() && p_use_gi; + + if (render_shadows && render_gi) { + RENDER_TIMESTAMP("Render GI + Render Shadows (parallel)"); + } else if (render_shadows) { + RENDER_TIMESTAMP("Render Shadows"); + } else if (render_gi) { + RENDER_TIMESTAMP("Render GI"); } - cluster.builder.begin(p_cam_transform.affine_inverse(), p_cam_projection); //prepare cluster + //prepare shadow rendering + if (render_shadows) { + _render_shadow_begin(); + + //render directional shadows + for (uint32_t i = 0; i < render_state.directional_shadows.size(); i++) { + _render_shadow_pass(render_state.render_shadows[render_state.directional_shadows[i]].light, render_state.shadow_atlas, render_state.render_shadows[render_state.directional_shadows[i]].pass, render_state.render_shadows[render_state.directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, render_state.screen_lod_threshold, false, i == render_state.directional_shadows.size() - 1, false); + } + //render positional shadows + for (uint32_t i = 0; i < render_state.shadows.size(); i++) { + _render_shadow_pass(render_state.render_shadows[render_state.shadows[i]].light, render_state.shadow_atlas, render_state.render_shadows[render_state.shadows[i]].pass, render_state.render_shadows[render_state.shadows[i]].instances, camera_plane, lod_distance_multiplier, render_state.screen_lod_threshold, i == 0, i == render_state.shadows.size() - 1, true); + } + + _render_shadow_process(); + } + + //start GI + if (render_gi) { + _process_gi(render_state.render_buffers, p_normal_roughness_buffer, p_gi_probe_buffer, render_state.environment, render_state.cam_projection, render_state.cam_transform, *render_state.gi_probes); + } + + //Do shadow rendering (in parallel with GI) + if (render_shadows) { + _render_shadow_end(RD::BARRIER_MASK_NO_BARRIER); + } + + if (render_gi) { + RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //use a later barrier + } + + if (render_state.render_buffers.is_valid()) { + if (p_use_ssao) { + _process_ssao(render_state.render_buffers, render_state.environment, p_normal_roughness_buffer, render_state.cam_projection); + } + } + + //full barrier here, we need raster, transfer and compute and it depends from the previous work + RD::get_singleton()->barrier(RD::BARRIER_MASK_ALL, RD::BARRIER_MASK_ALL); + + if (current_cluster_builder) { + current_cluster_builder->begin(render_state.cam_transform, render_state.cam_projection, !render_state.reflection_probe.is_valid()); + } bool using_shadows = true; - if (p_reflection_probe.is_valid()) { - if (!storage->reflection_probe_renders_shadows(reflection_probe_instance_get_probe(p_reflection_probe))) { + if (render_state.reflection_probe.is_valid()) { + if (!storage->reflection_probe_renders_shadows(reflection_probe_instance_get_probe(render_state.reflection_probe))) { using_shadows = false; } } else { //do not render reflections when rendering a reflection probe - _setup_reflections(p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_cam_transform.affine_inverse(), p_environment); + _setup_reflections(*render_state.reflection_probes, render_state.cam_transform.affine_inverse(), render_state.environment); } uint32_t directional_light_count = 0; uint32_t positional_light_count = 0; - _setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_shadow_atlas, using_shadows, directional_light_count, positional_light_count); - _setup_decals(p_decal_cull_result, p_decal_cull_count, p_cam_transform.affine_inverse()); - cluster.builder.bake_cluster(); //bake to cluster + _setup_lights(*render_state.lights, render_state.cam_transform, render_state.shadow_atlas, using_shadows, directional_light_count, positional_light_count); + _setup_decals(*render_state.decals, render_state.cam_transform.affine_inverse()); - uint32_t gi_probe_count = 0; - _setup_giprobes(p_render_buffers, p_cam_transform, p_gi_probe_cull_result, p_gi_probe_cull_count, gi_probe_count); + render_state.directional_light_count = directional_light_count; - if (p_render_buffers.is_valid()) { + if (current_cluster_builder) { + current_cluster_builder->bake_cluster(); + } + + if (render_state.render_buffers.is_valid()) { bool directional_shadows = false; for (uint32_t i = 0; i < directional_light_count; i++) { if (cluster.directional_lights[i].shadow_enabled) { @@ -6994,12 +7363,126 @@ void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_ca break; } } - _update_volumetric_fog(p_render_buffers, p_environment, p_cam_projection, p_cam_transform, p_shadow_atlas, directional_light_count, directional_shadows, positional_light_count, gi_probe_count); + _update_volumetric_fog(render_state.render_buffers, render_state.environment, render_state.cam_projection, render_state.cam_transform, render_state.shadow_atlas, directional_light_count, directional_shadows, positional_light_count, render_state.gi_probe_count); + } +} + +void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data) { + //assign render data + { + render_state.render_buffers = p_render_buffers; + render_state.cam_transform = p_cam_transform; + render_state.cam_projection = p_cam_projection; + render_state.cam_ortogonal = p_cam_projection.is_orthogonal(); + render_state.instances = &p_instances; + render_state.lights = &p_lights; + render_state.reflection_probes = &p_reflection_probes; + render_state.gi_probes = &p_gi_probes; + render_state.decals = &p_decals; + render_state.lightmaps = &p_lightmaps; + render_state.environment = p_environment; + render_state.camera_effects = p_camera_effects; + render_state.shadow_atlas = p_shadow_atlas; + render_state.reflection_atlas = p_reflection_atlas; + render_state.reflection_probe = p_reflection_probe; + render_state.reflection_probe_pass = p_reflection_probe_pass; + render_state.screen_lod_threshold = p_screen_lod_threshold; + + render_state.render_shadows = p_render_shadows; + render_state.render_shadow_count = p_render_shadow_count; + render_state.render_sdfgi_regions = p_render_sdfgi_regions; + render_state.render_sdfgi_region_count = p_render_sdfgi_region_count; + render_state.sdfgi_update_data = p_sdfgi_update_data; + } + + PagedArray<RID> empty; + + if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) { + render_state.lights = ∅ + render_state.reflection_probes = ∅ + render_state.gi_probes = ∅ + } + + //sdfgi first + if (p_render_buffers.is_valid()) { + for (int i = 0; i < render_state.render_sdfgi_region_count; i++) { + _render_sdfgi_region(p_render_buffers, render_state.render_sdfgi_regions[i].region, render_state.render_sdfgi_regions[i].instances); + } + if (render_state.sdfgi_update_data->update_static) { + _render_sdfgi_static_lights(p_render_buffers, render_state.sdfgi_update_data->static_cascade_count, p_sdfgi_update_data->static_cascade_indices, render_state.sdfgi_update_data->static_positional_lights); + } + } + + Color clear_color; + if (p_render_buffers.is_valid()) { + RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + ERR_FAIL_COND(!rb); + clear_color = storage->render_target_get_clear_request_color(rb->render_target); + } else { + clear_color = storage->get_default_clear_color(); + } + + //assign render indices to giprobes + for (uint32_t i = 0; i < (uint32_t)p_gi_probes.size(); i++) { + GIProbeInstance *giprobe_inst = gi_probe_instance_owner.getornull(p_gi_probes[i]); + if (giprobe_inst) { + giprobe_inst->render_index = i; + } + } + + if (render_buffers_owner.owns(render_state.render_buffers)) { + RenderBuffers *rb = render_buffers_owner.getornull(render_state.render_buffers); + current_cluster_builder = rb->cluster_builder; + } else if (reflection_probe_instance_owner.owns(render_state.reflection_probe)) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(render_state.reflection_probe); + ReflectionAtlas *ra = reflection_atlas_owner.getornull(rpi->atlas); + if (!ra) { + ERR_PRINT("reflection probe has no reflection atlas! Bug?"); + current_cluster_builder = nullptr; + } else { + current_cluster_builder = ra->cluster_builder; + } + } else { + ERR_PRINT("No cluster builder, bug"); //should never happen, will crash + current_cluster_builder = nullptr; + } + + if (p_render_buffers.is_valid()) { + _pre_process_gi(p_render_buffers, p_cam_transform); + } + + render_state.gi_probe_count = 0; + if (render_state.render_buffers.is_valid()) { + _setup_giprobes(render_state.render_buffers, render_state.cam_transform, *render_state.gi_probes, render_state.gi_probe_count); + _sdfgi_update_light(render_state.render_buffers, render_state.environment); } - _render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, directional_light_count, p_gi_probe_cull_result, p_gi_probe_cull_count, p_lightmap_cull_result, p_lightmap_cull_count, p_environment, p_camera_effects, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass, clear_color); + render_state.depth_prepass_used = false; + //calls _pre_opaque_render between depth pre-pass and opaque pass + _render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_instances, *render_state.gi_probes, p_lightmaps, p_environment, current_cluster_builder->get_cluster_buffer(), current_cluster_builder->get_cluster_size(), current_cluster_builder->get_max_cluster_elements(), p_camera_effects, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass, clear_color, p_screen_lod_threshold); if (p_render_buffers.is_valid()) { + if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS || debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS || debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS || debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES) { + ClusterBuilderRD::ElementType elem_type = ClusterBuilderRD::ELEMENT_TYPE_MAX; + switch (debug_draw) { + case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS: + elem_type = ClusterBuilderRD::ELEMENT_TYPE_OMNI_LIGHT; + break; + case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS: + elem_type = ClusterBuilderRD::ELEMENT_TYPE_SPOT_LIGHT; + break; + case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS: + elem_type = ClusterBuilderRD::ELEMENT_TYPE_DECAL; + break; + case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES: + elem_type = ClusterBuilderRD::ELEMENT_TYPE_REFLECTION_PROBE; + break; + default: { + } + } + current_cluster_builder->debug(elem_type); + } + RENDER_TIMESTAMP("Tonemap"); _render_buffers_post_process_and_tonemap(p_render_buffers, p_environment, p_camera_effects, p_cam_projection); @@ -7010,27 +7493,26 @@ void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_ca } } -void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) { +void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<GeometryInstance *> &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, bool p_open_pass, bool p_close_pass, bool p_clear_region) { LightInstance *light_instance = light_instance_owner.getornull(p_light); ERR_FAIL_COND(!light_instance); Rect2i atlas_rect; - RID atlas_texture; + uint32_t atlas_size; + RID atlas_fb; bool using_dual_paraboloid = false; bool using_dual_paraboloid_flip = false; - float znear = 0; - float zfar = 0; RID render_fb; RID render_texture; - float bias = 0; - float normal_bias = 0; + float zfar; bool use_pancake = false; - bool use_linear_depth = false; bool render_cubemap = false; bool finalize_cubemap = false; + bool flip_y = false; + CameraMatrix light_projection; Transform light_transform; @@ -7063,7 +7545,6 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas atlas_rect.position.x += atlas_rect.size.width; atlas_rect.position.y += atlas_rect.size.height; } - } else if (storage->light_directional_get_shadow_mode(light_instance->light) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) { atlas_rect.size.height /= 2; @@ -7078,15 +7559,11 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas light_instance->shadow_transform[p_pass].atlas_rect.position /= directional_shadow.size; light_instance->shadow_transform[p_pass].atlas_rect.size /= directional_shadow.size; - float bias_mult = light_instance->shadow_transform[p_pass].bias_scale; zfar = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_RANGE); - bias = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_SHADOW_BIAS) * bias_mult; - normal_bias = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * bias_mult; - ShadowMap *shadow_map = _get_shadow_map(atlas_rect.size); - render_fb = shadow_map->fb; - render_texture = shadow_map->depth; - atlas_texture = directional_shadow.depth; + render_fb = directional_shadow.fb; + render_texture = RID(); + flip_y = true; } else { //set from shadow atlas @@ -7095,6 +7572,8 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas ERR_FAIL_COND(!shadow_atlas); ERR_FAIL_COND(!shadow_atlas->shadow_owners.has(p_light)); + _update_shadow_atlas(shadow_atlas); + uint32_t key = shadow_atlas->shadow_owners[p_light]; uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; @@ -7113,11 +7592,8 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas atlas_rect.size.width = shadow_size; atlas_rect.size.height = shadow_size; - atlas_texture = shadow_atlas->depth; zfar = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_RANGE); - bias = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_SHADOW_BIAS); - normal_bias = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS); if (storage->light_get_type(light_instance->light) == RS::LIGHT_OMNI) { if (storage->light_omni_get_shadow_mode(light_instance->light) == RS::LIGHT_OMNI_SHADOW_CUBE) { @@ -7126,10 +7602,17 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas render_fb = cubemap->side_fb[p_pass]; render_texture = cubemap->cubemap; - light_projection = light_instance->shadow_transform[0].camera; - light_transform = light_instance->shadow_transform[0].transform; + light_projection = light_instance->shadow_transform[p_pass].camera; + light_transform = light_instance->shadow_transform[p_pass].transform; render_cubemap = true; finalize_cubemap = p_pass == 5; + atlas_fb = shadow_atlas->fb; + + atlas_size = shadow_atlas->size; + + if (p_pass == 0) { + _render_shadow_begin(); + } } else { light_projection = light_instance->shadow_transform[0].camera; @@ -7140,57 +7623,52 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas using_dual_paraboloid = true; using_dual_paraboloid_flip = p_pass == 1; - - ShadowMap *shadow_map = _get_shadow_map(atlas_rect.size); - render_fb = shadow_map->fb; - render_texture = shadow_map->depth; + render_fb = shadow_atlas->fb; + flip_y = true; } } else if (storage->light_get_type(light_instance->light) == RS::LIGHT_SPOT) { light_projection = light_instance->shadow_transform[0].camera; light_transform = light_instance->shadow_transform[0].transform; - ShadowMap *shadow_map = _get_shadow_map(atlas_rect.size); - render_fb = shadow_map->fb; - render_texture = shadow_map->depth; + render_fb = shadow_atlas->fb; - znear = light_instance->shadow_transform[0].camera.get_z_near(); - use_linear_depth = true; + flip_y = true; } } if (render_cubemap) { //rendering to cubemap - _render_shadow(render_fb, p_cull_result, p_cull_count, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake); + _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold, Rect2(), false, true, true, true); if (finalize_cubemap) { + _render_shadow_process(); + _render_shadow_end(); //reblit - atlas_rect.size.height /= 2; - storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_texture, atlas_rect, light_projection.get_z_near(), light_projection.get_z_far(), 0.0, false); - atlas_rect.position.y += atlas_rect.size.height; - storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_texture, atlas_rect, light_projection.get_z_near(), light_projection.get_z_far(), 0.0, true); - } - } else { - //render shadow - - _render_shadow(render_fb, p_cull_result, p_cull_count, light_projection, light_transform, zfar, bias, normal_bias, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake); + Rect2 atlas_rect_norm = atlas_rect; + atlas_rect_norm.position.x /= float(atlas_size); + atlas_rect_norm.position.y /= float(atlas_size); + atlas_rect_norm.size.x /= float(atlas_size); + atlas_rect_norm.size.y /= float(atlas_size); + atlas_rect_norm.size.height /= 2; + storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, light_projection.get_z_near(), light_projection.get_z_far(), false); + atlas_rect_norm.position.y += atlas_rect_norm.size.height; + storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, light_projection.get_z_near(), light_projection.get_z_far(), true); - //copy to atlas - if (use_linear_depth) { - storage->get_effects()->copy_depth_to_rect_and_linearize(render_texture, atlas_texture, atlas_rect, true, znear, zfar); - } else { - storage->get_effects()->copy_depth_to_rect(render_texture, atlas_texture, atlas_rect, true); + //restore transform so it can be properly used + light_instance_set_shadow_transform(p_light, CameraMatrix(), light_instance->transform, zfar, 0, 0, 0); } - //does not work from depth to color - //RD::get_singleton()->texture_copy(render_texture, atlas_texture, Vector3(0, 0, 0), Vector3(atlas_rect.position.x, atlas_rect.position.y, 0), Vector3(atlas_rect.size.x, atlas_rect.size.y, 1), 0, 0, 0, 0, true); + } else { + //render shadow + _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold, atlas_rect, flip_y, p_clear_region, p_open_pass, p_close_pass); } } -void RasterizerSceneRD::render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) { - _render_material(p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, p_framebuffer, p_region); +void RendererSceneRenderRD::render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) { + _render_material(p_cam_transform, p_cam_projection, p_cam_ortogonal, p_instances, p_framebuffer, p_region); } -void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, InstanceBase **p_cull_result, int p_cull_count) { +void RendererSceneRenderRD::_render_sdfgi_region(RID p_render_buffers, int p_region, const PagedArray<GeometryInstance *> &p_instances) { //print_line("rendering region " + itos(p_region)); RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(!rb); @@ -7206,16 +7684,18 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc if (cascade_prev != cascade) { //initialize render - RD::get_singleton()->texture_clear(rb->sdfgi->render_albedo, Color(0, 0, 0, 0), 0, 1, 0, 1, true); - RD::get_singleton()->texture_clear(rb->sdfgi->render_emission, Color(0, 0, 0, 0), 0, 1, 0, 1, true); - RD::get_singleton()->texture_clear(rb->sdfgi->render_emission_aniso, Color(0, 0, 0, 0), 0, 1, 0, 1, true); - RD::get_singleton()->texture_clear(rb->sdfgi->render_geom_facing, Color(0, 0, 0, 0), 0, 1, 0, 1, true); + RD::get_singleton()->texture_clear(rb->sdfgi->render_albedo, Color(0, 0, 0, 0), 0, 1, 0, 1); + RD::get_singleton()->texture_clear(rb->sdfgi->render_emission, Color(0, 0, 0, 0), 0, 1, 0, 1); + RD::get_singleton()->texture_clear(rb->sdfgi->render_emission_aniso, Color(0, 0, 0, 0), 0, 1, 0, 1); + RD::get_singleton()->texture_clear(rb->sdfgi->render_geom_facing, Color(0, 0, 0, 0), 0, 1, 0, 1); } //print_line("rendering cascade " + itos(p_region) + " objects: " + itos(p_cull_count) + " bounds: " + bounds + " from: " + from + " size: " + size + " cell size: " + rtos(rb->sdfgi->cascades[cascade].cell_size)); - _render_sdfgi(p_render_buffers, from, size, bounds, p_cull_result, p_cull_count, rb->sdfgi->render_albedo, rb->sdfgi->render_emission, rb->sdfgi->render_emission_aniso, rb->sdfgi->render_geom_facing); + _render_sdfgi(p_render_buffers, from, size, bounds, p_instances, rb->sdfgi->render_albedo, rb->sdfgi->render_emission, rb->sdfgi->render_emission_aniso, rb->sdfgi->render_geom_facing); if (cascade_next != cascade) { + RD::get_singleton()->draw_command_begin_label("SDFGI Pre-Process Cascade"); + RENDER_TIMESTAMP(">SDFGI Update SDF"); //done rendering! must update SDF //clear dispatch indirect data @@ -7238,6 +7718,9 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc push_constant.scroll[1] = 0; push_constant.scroll[2] = 0; } + + rb->sdfgi->cascades[cascade].all_dynamic_lights_dirty = true; + push_constant.grid_size = rb->sdfgi->cascade_size; push_constant.cascade = cascade; @@ -7262,7 +7745,7 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc groups.z = rb->sdfgi->cascade_size - ABS(dirty.z); RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, groups.x, groups.y, groups.z, 4, 4, 4); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, groups.x, groups.y, groups.z); //no barrier, continue together @@ -7289,7 +7772,6 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc ipush_constant.image_size[0] = rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count; ipush_constant.image_size[1] = rb->sdfgi->probe_axis_count; - ipush_constant.image_size[1] = rb->sdfgi->probe_axis_count; int32_t probe_divisor = rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR; ipush_constant.cascade = cascade; @@ -7305,7 +7787,7 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[cascade].integrate_uniform_set, 0); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdfgi_shader.integrate_default_sky_uniform_set, 1); RD::get_singleton()->compute_list_set_push_constant(compute_list, &ipush_constant, sizeof(SDGIShader::IntegratePushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count, rb->sdfgi->probe_axis_count, 1, 8, 8, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count, rb->sdfgi->probe_axis_count, 1); RD::get_singleton()->compute_list_add_barrier(compute_list); @@ -7313,7 +7795,24 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[cascade].integrate_uniform_set, 0); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdfgi_shader.integrate_default_sky_uniform_set, 1); RD::get_singleton()->compute_list_set_push_constant(compute_list, &ipush_constant, sizeof(SDGIShader::IntegratePushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count, rb->sdfgi->probe_axis_count, 1, 8, 8, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count, rb->sdfgi->probe_axis_count, 1); + + RD::get_singleton()->compute_list_add_barrier(compute_list); + + if (rb->sdfgi->bounce_feedback > 0.0) { + //multibounce requires this to be stored so direct light can read from it + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.integrate_pipeline[SDGIShader::INTEGRATE_MODE_STORE]); + + //convert to octahedral to store + ipush_constant.image_size[0] *= SDFGI::LIGHTPROBE_OCT_SIZE; + ipush_constant.image_size[1] *= SDFGI::LIGHTPROBE_OCT_SIZE; + + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[cascade].integrate_uniform_set, 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdfgi_shader.integrate_default_sky_uniform_set, 1); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ipush_constant, sizeof(SDGIShader::IntegratePushConstant)); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, rb->sdfgi->probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, 1); + } } //ok finally barrier @@ -7322,7 +7821,7 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc //clear dispatch indirect data uint32_t dispatch_indirct_data[4] = { 0, 0, 0, 0 }; - RD::get_singleton()->buffer_update(rb->sdfgi->cascades[cascade].solid_cell_dispatch_buffer, 0, sizeof(uint32_t) * 4, dispatch_indirct_data, true); + RD::get_singleton()->buffer_update(rb->sdfgi->cascades[cascade].solid_cell_dispatch_buffer, 0, sizeof(uint32_t) * 4, dispatch_indirct_data); RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); @@ -7336,7 +7835,7 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE_HALF]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->sdf_initialize_half_uniform_set, 0); RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_half_size, cascade_half_size, cascade_half_size, 4, 4, 4); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_half_size, cascade_half_size, cascade_half_size); RD::get_singleton()->compute_list_add_barrier(compute_list); //must start with regular jumpflood @@ -7356,7 +7855,7 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc push_constant.step_size = s; RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->jump_flood_half_uniform_set[jf_us], 0); RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_half_size, cascade_half_size, cascade_half_size, 4, 4, 4); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_half_size, cascade_half_size, cascade_half_size); RD::get_singleton()->compute_list_add_barrier(compute_list); jf_us = jf_us == 0 ? 1 : 0; @@ -7374,7 +7873,7 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc push_constant.step_size = s; RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->jump_flood_half_uniform_set[jf_us], 0); RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_half_size, cascade_half_size, cascade_half_size, optimized_jf_group_size, optimized_jf_group_size, optimized_jf_group_size); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_half_size, cascade_half_size, cascade_half_size); RD::get_singleton()->compute_list_add_barrier(compute_list); jf_us = jf_us == 0 ? 1 : 0; } @@ -7386,7 +7885,7 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_UPSCALE]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->sdf_upscale_uniform_set, 0); RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, 4, 4, 4); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size); RD::get_singleton()->compute_list_add_barrier(compute_list); //run one pass of fullsize jumpflood to fix up half size arctifacts @@ -7396,7 +7895,7 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_OPTIMIZED]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->jump_flood_uniform_set[rb->sdfgi->upscale_jfa_uniform_set_index], 0); RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, optimized_jf_group_size, optimized_jf_group_size, optimized_jf_group_size); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size); RD::get_singleton()->compute_list_add_barrier(compute_list); } else { @@ -7406,7 +7905,7 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->sdf_initialize_uniform_set, 0); RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, 4, 4, 4); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size); RD::get_singleton()->compute_list_add_barrier(compute_list); @@ -7423,7 +7922,7 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc push_constant.step_size = s; RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->jump_flood_uniform_set[jf_us], 0); RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, 4, 4, 4); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size); RD::get_singleton()->compute_list_add_barrier(compute_list); jf_us = jf_us == 0 ? 1 : 0; @@ -7441,7 +7940,7 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc push_constant.step_size = s; RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->jump_flood_uniform_set[jf_us], 0); RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, optimized_jf_group_size, optimized_jf_group_size, optimized_jf_group_size); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size); RD::get_singleton()->compute_list_add_barrier(compute_list); jf_us = jf_us == 0 ? 1 : 0; } @@ -7488,14 +7987,14 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_STORE]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[cascade].sdf_store_uniform_set, 0); RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, 4, 4, 4); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size); RD::get_singleton()->compute_list_end(); //clear these textures, as they will have previous garbage on next draw - RD::get_singleton()->texture_clear(rb->sdfgi->cascades[cascade].light_tex, Color(0, 0, 0, 0), 0, 1, 0, 1, true); - RD::get_singleton()->texture_clear(rb->sdfgi->cascades[cascade].light_aniso_0_tex, Color(0, 0, 0, 0), 0, 1, 0, 1, true); - RD::get_singleton()->texture_clear(rb->sdfgi->cascades[cascade].light_aniso_1_tex, Color(0, 0, 0, 0), 0, 1, 0, 1, true); + RD::get_singleton()->texture_clear(rb->sdfgi->cascades[cascade].light_tex, Color(0, 0, 0, 0), 0, 1, 0, 1); + RD::get_singleton()->texture_clear(rb->sdfgi->cascades[cascade].light_aniso_0_tex, Color(0, 0, 0, 0), 0, 1, 0, 1); + RD::get_singleton()->texture_clear(rb->sdfgi->cascades[cascade].light_aniso_1_tex, Color(0, 0, 0, 0), 0, 1, 0, 1); #if 0 Vector<uint8_t> data = RD::get_singleton()->texture_get_data(rb->sdfgi->cascades[cascade].sdf, 0); @@ -7525,10 +8024,11 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc #endif RENDER_TIMESTAMP("<SDFGI Update SDF"); + RD::get_singleton()->draw_command_end_label(); } } -void RasterizerSceneRD::render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, InstanceBase **p_cull_result, int p_cull_count) { +void RendererSceneRenderRD::render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<GeometryInstance *> &p_instances) { ERR_FAIL_COND(!storage->particles_collision_is_heightfield(p_collider)); Vector3 extents = storage->particles_collision_get_extents(p_collider) * p_transform.basis.get_scale(); CameraMatrix cm; @@ -7542,37 +8042,20 @@ void RasterizerSceneRD::render_particle_collider_heightfield(RID p_collider, con RID fb = storage->particles_collision_get_heightfield_framebuffer(p_collider); - _render_particle_collider_heightfield(fb, cam_xform, cm, p_cull_result, p_cull_count); + _render_particle_collider_heightfield(fb, cam_xform, cm, p_instances); } -void RasterizerSceneRD::render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const RID **p_positional_light_cull_result, const uint32_t *p_positional_light_cull_count) { +void RendererSceneRenderRD::_render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(!rb); ERR_FAIL_COND(!rb->sdfgi); - ERR_FAIL_COND(p_positional_light_cull_count == 0); + RD::get_singleton()->draw_command_begin_label("SDFGI Render Static Lighs"); _sdfgi_update_cascades(p_render_buffers); //need cascades updated for this - RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.direct_light_pipeline[SDGIShader::DIRECT_LIGHT_MODE_STATIC]); - - SDGIShader::DirectLightPushConstant dl_push_constant; - - dl_push_constant.grid_size[0] = rb->sdfgi->cascade_size; - dl_push_constant.grid_size[1] = rb->sdfgi->cascade_size; - dl_push_constant.grid_size[2] = rb->sdfgi->cascade_size; - dl_push_constant.max_cascades = rb->sdfgi->cascades.size(); - dl_push_constant.probe_axis_size = rb->sdfgi->probe_axis_count; - dl_push_constant.multibounce = false; // this is static light, do not multibounce yet - dl_push_constant.y_mult = rb->sdfgi->y_mult; - - //all must be processed - dl_push_constant.process_offset = 0; - dl_push_constant.process_increment = 1; - SDGIShader::Light lights[SDFGI::MAX_STATIC_LIGHTS]; + uint32_t light_count[SDFGI::MAX_STATIC_LIGHTS]; for (uint32_t i = 0; i < p_cascade_count; i++) { ERR_CONTINUE(p_cascade_indices[i] >= rb->sdfgi->cascades.size()); @@ -7587,7 +8070,7 @@ void RasterizerSceneRD::render_sdfgi_static_lights(RID p_render_buffers, uint32_ int idx = 0; - for (uint32_t j = 0; j < p_positional_light_cull_count[i]; j++) { + for (uint32_t j = 0; j < (uint32_t)p_positional_light_cull_result[i].size(); j++) { if (idx == SDFGI::MAX_STATIC_LIGHTS) { break; } @@ -7628,18 +8111,46 @@ void RasterizerSceneRD::render_sdfgi_static_lights(RID p_render_buffers, uint32_ lights[idx].has_shadow = storage->light_has_shadow(li->light); lights[idx].attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION); lights[idx].radius = storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE); - lights[idx].spot_angle = Math::deg2rad(storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE)); - lights[idx].spot_attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION); + lights[idx].cos_spot_angle = Math::cos(Math::deg2rad(storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE))); + lights[idx].inv_spot_attenuation = 1.0f / storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION); idx++; } if (idx > 0) { - RD::get_singleton()->buffer_update(cc.lights_buffer, 0, idx * sizeof(SDGIShader::Light), lights, true); + RD::get_singleton()->buffer_update(cc.lights_buffer, 0, idx * sizeof(SDGIShader::Light), lights); } - dl_push_constant.light_count = idx; + + light_count[i] = idx; } + } + /* Static Lights */ + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.direct_light_pipeline[SDGIShader::DIRECT_LIGHT_MODE_STATIC]); + + SDGIShader::DirectLightPushConstant dl_push_constant; + + dl_push_constant.grid_size[0] = rb->sdfgi->cascade_size; + dl_push_constant.grid_size[1] = rb->sdfgi->cascade_size; + dl_push_constant.grid_size[2] = rb->sdfgi->cascade_size; + dl_push_constant.max_cascades = rb->sdfgi->cascades.size(); + dl_push_constant.probe_axis_size = rb->sdfgi->probe_axis_count; + dl_push_constant.bounce_feedback = 0.0; // this is static light, do not multibounce yet + dl_push_constant.y_mult = rb->sdfgi->y_mult; + dl_push_constant.use_occlusion = rb->sdfgi->uses_occlusion; + + //all must be processed + dl_push_constant.process_offset = 0; + dl_push_constant.process_increment = 1; + + for (uint32_t i = 0; i < p_cascade_count; i++) { + ERR_CONTINUE(p_cascade_indices[i] >= rb->sdfgi->cascades.size()); + + SDFGI::Cascade &cc = rb->sdfgi->cascades[p_cascade_indices[i]]; + + dl_push_constant.light_count = light_count[i]; dl_push_constant.cascade = p_cascade_indices[i]; if (dl_push_constant.light_count > 0) { @@ -7650,9 +8161,11 @@ void RasterizerSceneRD::render_sdfgi_static_lights(RID p_render_buffers, uint32_ } RD::get_singleton()->compute_list_end(); + + RD::get_singleton()->draw_command_end_label(); } -bool RasterizerSceneRD::free(RID p_rid) { +bool RendererSceneRenderRD::free(RID p_rid) { if (render_buffers_owner.owns(p_rid)) { RenderBuffers *rb = render_buffers_owner.getornull(p_rid); _free_render_buffer_data(rb); @@ -7663,6 +8176,9 @@ bool RasterizerSceneRD::free(RID p_rid) { if (rb->volumetric_fog) { _volumetric_fog_erase(rb); } + if (rb->cluster_builder) { + memdelete(rb->cluster_builder); + } render_buffers_owner.free(p_rid); } else if (environment_owner.owns(p_rid)) { //not much to delete, just free it @@ -7672,6 +8188,10 @@ bool RasterizerSceneRD::free(RID p_rid) { camera_effects_owner.free(p_rid); } else if (reflection_atlas_owner.owns(p_rid)) { reflection_atlas_set_size(p_rid, 0, 0); + ReflectionAtlas *ra = reflection_atlas_owner.getornull(p_rid); + if (ra->cluster_builder) { + memdelete(ra->cluster_builder); + } reflection_atlas_owner.free(p_rid); } else if (reflection_probe_instance_owner.owns(p_rid)) { //not much to delete, just free it @@ -7680,6 +8200,8 @@ bool RasterizerSceneRD::free(RID p_rid) { reflection_probe_instance_owner.free(p_rid); } else if (decal_instance_owner.owns(p_rid)) { decal_instance_owner.free(p_rid); + } else if (lightmap_instance_owner.owns(p_rid)) { + lightmap_instance_owner.free(p_rid); } else if (gi_probe_instance_owner.owns(p_rid)) { GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_rid); if (gi_probe->texture.is_valid()) { @@ -7751,38 +8273,38 @@ bool RasterizerSceneRD::free(RID p_rid) { return true; } -void RasterizerSceneRD::set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) { +void RendererSceneRenderRD::set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) { debug_draw = p_debug_draw; } -void RasterizerSceneRD::update() { +void RendererSceneRenderRD::update() { _update_dirty_skys(); } -void RasterizerSceneRD::set_time(double p_time, double p_step) { +void RendererSceneRenderRD::set_time(double p_time, double p_step) { time = p_time; time_step = p_step; } -void RasterizerSceneRD::screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_limit) { +void RendererSceneRenderRD::screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_limit) { screen_space_roughness_limiter = p_enable; screen_space_roughness_limiter_amount = p_amount; screen_space_roughness_limiter_limit = p_limit; } -bool RasterizerSceneRD::screen_space_roughness_limiter_is_active() const { +bool RendererSceneRenderRD::screen_space_roughness_limiter_is_active() const { return screen_space_roughness_limiter; } -float RasterizerSceneRD::screen_space_roughness_limiter_get_amount() const { +float RendererSceneRenderRD::screen_space_roughness_limiter_get_amount() const { return screen_space_roughness_limiter_amount; } -float RasterizerSceneRD::screen_space_roughness_limiter_get_limit() const { +float RendererSceneRenderRD::screen_space_roughness_limiter_get_limit() const { return screen_space_roughness_limiter_limit; } -TypedArray<Image> RasterizerSceneRD::bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) { +TypedArray<Image> RendererSceneRenderRD::bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) { RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; tf.width = p_image_size.width; // Always 64x64 @@ -7815,19 +8337,27 @@ TypedArray<Image> RasterizerSceneRD::bake_render_uv2(RID p_base, const Vector<RI //RID sampled_light; - InstanceBase ins; + GeometryInstance *gi = geometry_instance_create(p_base); - ins.base_type = RSG::storage->get_base_type(p_base); - ins.base = p_base; - ins.materials.resize(RSG::storage->mesh_get_surface_count(p_base)); - for (int i = 0; i < ins.materials.size(); i++) { - if (i < p_material_overrides.size()) { - ins.materials.write[i] = p_material_overrides[i]; + uint32_t sc = RSG::storage->mesh_get_surface_count(p_base); + Vector<RID> materials; + materials.resize(sc); + + for (uint32_t i = 0; i < sc; i++) { + if (i < (uint32_t)p_material_overrides.size()) { + materials.write[i] = p_material_overrides[i]; } } - InstanceBase *cull = &ins; - _render_uv2(&cull, 1, fb, Rect2i(0, 0, p_image_size.width, p_image_size.height)); + geometry_instance_set_surface_materials(gi, materials); + + if (cull_argument.size() == 0) { + cull_argument.push_back(nullptr); + } + cull_argument[0] = gi; + _render_uv2(cull_argument, fb, Rect2i(0, 0, p_image_size.width, p_image_size.height)); + + geometry_instance_free(gi); TypedArray<Image> ret; @@ -7873,56 +8403,71 @@ TypedArray<Image> RasterizerSceneRD::bake_render_uv2(RID p_base, const Vector<RI return ret; } -void RasterizerSceneRD::sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) { +void RendererSceneRenderRD::sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) { sdfgi_debug_probe_pos = p_position; sdfgi_debug_probe_dir = p_dir; } -RasterizerSceneRD *RasterizerSceneRD::singleton = nullptr; +RendererSceneRenderRD *RendererSceneRenderRD::singleton = nullptr; -RID RasterizerSceneRD::get_cluster_builder_texture() { - return cluster.builder.get_cluster_texture(); +RID RendererSceneRenderRD::get_reflection_probe_buffer() { + return cluster.reflection_buffer; } - -RID RasterizerSceneRD::get_cluster_builder_indices_buffer() { - return cluster.builder.get_cluster_indices_buffer(); +RID RendererSceneRenderRD::get_omni_light_buffer() { + return cluster.omni_light_buffer; } -RID RasterizerSceneRD::get_reflection_probe_buffer() { - return cluster.reflection_buffer; -} -RID RasterizerSceneRD::get_positional_light_buffer() { - return cluster.light_buffer; +RID RendererSceneRenderRD::get_spot_light_buffer() { + return cluster.spot_light_buffer; } -RID RasterizerSceneRD::get_directional_light_buffer() { + +RID RendererSceneRenderRD::get_directional_light_buffer() { return cluster.directional_light_buffer; } -RID RasterizerSceneRD::get_decal_buffer() { +RID RendererSceneRenderRD::get_decal_buffer() { return cluster.decal_buffer; } -int RasterizerSceneRD::get_max_directional_lights() const { +int RendererSceneRenderRD::get_max_directional_lights() const { return cluster.max_directional_lights; } -RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { +bool RendererSceneRenderRD::is_low_end() const { + return low_end; +} + +RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) { + max_cluster_elements = GLOBAL_GET("rendering/limits/cluster_builder/max_clustered_elements"); + storage = p_storage; singleton = this; - roughness_layers = GLOBAL_GET("rendering/quality/reflections/roughness_layers"); - sky_ggx_samples_quality = GLOBAL_GET("rendering/quality/reflections/ggx_samples"); - sky_use_cubemap_array = GLOBAL_GET("rendering/quality/reflections/texture_array_reflections"); - // sky_use_cubemap_array = false; + roughness_layers = GLOBAL_GET("rendering/reflections/sky_reflections/roughness_layers"); + sky_ggx_samples_quality = GLOBAL_GET("rendering/reflections/sky_reflections/ggx_samples"); + sky_use_cubemap_array = GLOBAL_GET("rendering/reflections/sky_reflections/texture_array_reflections"); - //uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE); + sdfgi_ray_count = RS::EnvironmentSDFGIRayCount(CLAMP(int32_t(GLOBAL_GET("rendering/global_illumination/sdfgi/probe_ray_count")), 0, int32_t(RS::ENV_SDFGI_RAY_COUNT_MAX - 1))); + sdfgi_frames_to_converge = RS::EnvironmentSDFGIFramesToConverge(CLAMP(int32_t(GLOBAL_GET("rendering/global_illumination/sdfgi/frames_to_converge")), 0, int32_t(RS::ENV_SDFGI_CONVERGE_MAX - 1))); + sdfgi_frames_to_update_light = RS::EnvironmentSDFGIFramesToUpdateLight(CLAMP(int32_t(GLOBAL_GET("rendering/global_illumination/sdfgi/frames_to_update_lights")), 0, int32_t(RS::ENV_SDFGI_UPDATE_LIGHT_MAX - 1))); - { + directional_shadow.size = GLOBAL_GET("rendering/shadows/directional_shadow/size"); + directional_shadow.use_16_bits = GLOBAL_GET("rendering/shadows/directional_shadow/16_bits"); + + uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE); + + low_end = GLOBAL_GET("rendering/driver/rd_renderer/use_low_end_renderer"); + + if (textures_per_stage < 48) { + low_end = true; + } + + if (!low_end) { //kinda complicated to compute the amount of slots, we try to use as many as we can gi_probe_max_lights = 32; gi_probe_lights = memnew_arr(GIProbeLight, gi_probe_max_lights); gi_probe_lights_uniform = RD::get_singleton()->uniform_buffer_create(gi_probe_max_lights * sizeof(GIProbeLight)); - gi_probe_quality = RS::GIProbeQuality(CLAMP(int(GLOBAL_GET("rendering/quality/gi_probes/quality")), 0, 1)); + gi_probe_quality = RS::GIProbeQuality(CLAMP(int(GLOBAL_GET("rendering/global_illumination/gi_probes/quality")), 0, 1)); String defines = "\n#define MAX_LIGHTS " + itos(gi_probe_max_lights) + "\n"; @@ -7944,7 +8489,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { } } - { + if (!low_end) { String defines; Vector<String> versions; versions.push_back("\n#define MODE_DEBUG_COLOR\n"); @@ -7993,8 +8538,8 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { } // register our shader funds - storage->shader_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_SKY, _create_sky_shader_funcs); - storage->material_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_SKY, _create_sky_material_funcs); + storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_SKY, _create_sky_shader_funcs); + storage->material_set_data_request_function(RendererStorageRD::SHADER_TYPE_SKY, _create_sky_material_funcs); { ShaderCompilerRD::DefaultIdentifierActions actions; @@ -8053,12 +8598,17 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { { // default material and shader for sky shader - sky_shader.default_shader = storage->shader_create(); + sky_shader.default_shader = storage->shader_allocate(); + storage->shader_initialize(sky_shader.default_shader); + storage->shader_set_code(sky_shader.default_shader, "shader_type sky; void fragment() { COLOR = vec3(0.0); } \n"); - sky_shader.default_material = storage->material_create(); + + sky_shader.default_material = storage->material_allocate(); + storage->material_initialize(sky_shader.default_material); + storage->material_set_shader(sky_shader.default_material, sky_shader.default_shader); - SkyMaterialData *md = (SkyMaterialData *)storage->material_get_data(sky_shader.default_material, RasterizerStorageRD::SHADER_TYPE_SKY); + SkyMaterialData *md = (SkyMaterialData *)storage->material_get_data(sky_shader.default_material, RendererStorageRD::SHADER_TYPE_SKY); sky_shader.default_shader_rd = sky_shader.shader.version_get_shader(md->shader_data->version, SKY_VERSION_BACKGROUND); sky_scene_state.uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SkySceneState::UBO)); @@ -8067,7 +8617,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 0; u.ids.resize(12); RID *ids_ptr = u.ids.ptrw(); @@ -8088,7 +8638,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 1; u.ids.push_back(storage->global_variables_get_storage_buffer()); uniforms.push_back(u); @@ -8097,7 +8647,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { { RD::Uniform u; u.binding = 2; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.ids.push_back(sky_scene_state.uniform_buffer); uniforms.push_back(u); } @@ -8105,7 +8655,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { { RD::Uniform u; u.binding = 3; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.ids.push_back(sky_scene_state.directional_light_buffer); uniforms.push_back(u); } @@ -8118,8 +8668,8 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { { RD::Uniform u; u.binding = 0; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID vfog = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID vfog = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); u.ids.push_back(vfog); uniforms.push_back(u); } @@ -8129,196 +8679,207 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { { // Need defaults for using fog with clear color - sky_scene_state.fog_shader = storage->shader_create(); + sky_scene_state.fog_shader = storage->shader_allocate(); + storage->shader_initialize(sky_scene_state.fog_shader); + storage->shader_set_code(sky_scene_state.fog_shader, "shader_type sky; uniform vec4 clear_color; void fragment() { COLOR = clear_color.rgb; } \n"); - sky_scene_state.fog_material = storage->material_create(); + sky_scene_state.fog_material = storage->material_allocate(); + storage->material_initialize(sky_scene_state.fog_material); + storage->material_set_shader(sky_scene_state.fog_material, sky_scene_state.fog_shader); Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 0; - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE)); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE)); uniforms.push_back(u); } sky_scene_state.fog_only_texture_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_TEXTURES); } - { - Vector<String> preprocess_modes; - preprocess_modes.push_back("\n#define MODE_SCROLL\n"); - preprocess_modes.push_back("\n#define MODE_SCROLL_OCCLUSION\n"); - preprocess_modes.push_back("\n#define MODE_INITIALIZE_JUMP_FLOOD\n"); - preprocess_modes.push_back("\n#define MODE_INITIALIZE_JUMP_FLOOD_HALF\n"); - preprocess_modes.push_back("\n#define MODE_JUMPFLOOD\n"); - preprocess_modes.push_back("\n#define MODE_JUMPFLOOD_OPTIMIZED\n"); - preprocess_modes.push_back("\n#define MODE_UPSCALE_JUMP_FLOOD\n"); - preprocess_modes.push_back("\n#define MODE_OCCLUSION\n"); - preprocess_modes.push_back("\n#define MODE_STORE\n"); - String defines = "\n#define OCCLUSION_SIZE " + itos(SDFGI::CASCADE_SIZE / SDFGI::PROBE_DIVISOR) + "\n"; - sdfgi_shader.preprocess.initialize(preprocess_modes, defines); - sdfgi_shader.preprocess_shader = sdfgi_shader.preprocess.version_create(); - for (int i = 0; i < SDGIShader::PRE_PROCESS_MAX; i++) { - sdfgi_shader.preprocess_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, i)); + if (!low_end) { + //SDFGI + { + Vector<String> preprocess_modes; + preprocess_modes.push_back("\n#define MODE_SCROLL\n"); + preprocess_modes.push_back("\n#define MODE_SCROLL_OCCLUSION\n"); + preprocess_modes.push_back("\n#define MODE_INITIALIZE_JUMP_FLOOD\n"); + preprocess_modes.push_back("\n#define MODE_INITIALIZE_JUMP_FLOOD_HALF\n"); + preprocess_modes.push_back("\n#define MODE_JUMPFLOOD\n"); + preprocess_modes.push_back("\n#define MODE_JUMPFLOOD_OPTIMIZED\n"); + preprocess_modes.push_back("\n#define MODE_UPSCALE_JUMP_FLOOD\n"); + preprocess_modes.push_back("\n#define MODE_OCCLUSION\n"); + preprocess_modes.push_back("\n#define MODE_STORE\n"); + String defines = "\n#define OCCLUSION_SIZE " + itos(SDFGI::CASCADE_SIZE / SDFGI::PROBE_DIVISOR) + "\n"; + sdfgi_shader.preprocess.initialize(preprocess_modes, defines); + sdfgi_shader.preprocess_shader = sdfgi_shader.preprocess.version_create(); + for (int i = 0; i < SDGIShader::PRE_PROCESS_MAX; i++) { + sdfgi_shader.preprocess_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, i)); + } } - } - { - //calculate tables - String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; + { + //calculate tables + String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; - Vector<String> direct_light_modes; - direct_light_modes.push_back("\n#define MODE_PROCESS_STATIC\n"); - direct_light_modes.push_back("\n#define MODE_PROCESS_DYNAMIC\n"); - sdfgi_shader.direct_light.initialize(direct_light_modes, defines); - sdfgi_shader.direct_light_shader = sdfgi_shader.direct_light.version_create(); - for (int i = 0; i < SDGIShader::DIRECT_LIGHT_MODE_MAX; i++) { - sdfgi_shader.direct_light_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.direct_light.version_get_shader(sdfgi_shader.direct_light_shader, i)); + Vector<String> direct_light_modes; + direct_light_modes.push_back("\n#define MODE_PROCESS_STATIC\n"); + direct_light_modes.push_back("\n#define MODE_PROCESS_DYNAMIC\n"); + sdfgi_shader.direct_light.initialize(direct_light_modes, defines); + sdfgi_shader.direct_light_shader = sdfgi_shader.direct_light.version_create(); + for (int i = 0; i < SDGIShader::DIRECT_LIGHT_MODE_MAX; i++) { + sdfgi_shader.direct_light_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.direct_light.version_get_shader(sdfgi_shader.direct_light_shader, i)); + } } - } - { - //calculate tables - String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; - defines += "\n#define SH_SIZE " + itos(SDFGI::SH_SIZE) + "\n"; - - Vector<String> integrate_modes; - integrate_modes.push_back("\n#define MODE_PROCESS\n"); - integrate_modes.push_back("\n#define MODE_STORE\n"); - integrate_modes.push_back("\n#define MODE_SCROLL\n"); - integrate_modes.push_back("\n#define MODE_SCROLL_STORE\n"); - sdfgi_shader.integrate.initialize(integrate_modes, defines); - sdfgi_shader.integrate_shader = sdfgi_shader.integrate.version_create(); + { + //calculate tables + String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; + defines += "\n#define SH_SIZE " + itos(SDFGI::SH_SIZE) + "\n"; + if (sky_use_cubemap_array) { + defines += "\n#define USE_CUBEMAP_ARRAY\n"; + } - for (int i = 0; i < SDGIShader::INTEGRATE_MODE_MAX; i++) { - sdfgi_shader.integrate_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, i)); - } + Vector<String> integrate_modes; + integrate_modes.push_back("\n#define MODE_PROCESS\n"); + integrate_modes.push_back("\n#define MODE_STORE\n"); + integrate_modes.push_back("\n#define MODE_SCROLL\n"); + integrate_modes.push_back("\n#define MODE_SCROLL_STORE\n"); + sdfgi_shader.integrate.initialize(integrate_modes, defines); + sdfgi_shader.integrate_shader = sdfgi_shader.integrate.version_create(); - { - Vector<RD::Uniform> uniforms; + for (int i = 0; i < SDGIShader::INTEGRATE_MODE_MAX; i++) { + sdfgi_shader.integrate_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, i)); + } { - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 0; - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_WHITE)); - uniforms.push_back(u); + Vector<RD::Uniform> uniforms; + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 0; + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_WHITE)); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; + u.binding = 1; + u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); + uniforms.push_back(u); + } + + sdfgi_shader.integrate_default_sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, 0), 1); } - { - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; - u.binding = 1; - u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); - uniforms.push_back(u); + } + //GK + { + //calculate tables + String defines = "\n#define SDFGI_OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; + Vector<String> gi_modes; + gi_modes.push_back("\n#define USE_GIPROBES\n"); + gi_modes.push_back("\n#define USE_SDFGI\n"); + gi_modes.push_back("\n#define USE_SDFGI\n\n#define USE_GIPROBES\n"); + gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_GIPROBES\n"); + gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n"); + gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n\n#define USE_GIPROBES\n"); + + gi.shader.initialize(gi_modes, defines); + gi.shader_version = gi.shader.version_create(); + for (int i = 0; i < GI::MODE_MAX; i++) { + gi.pipelines[i] = RD::get_singleton()->compute_pipeline_create(gi.shader.version_get_shader(gi.shader_version, i)); } - sdfgi_shader.integrate_default_sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, 0), 1); + gi.sdfgi_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(GI::SDFGIData)); } - } - { - //calculate tables - String defines = "\n#define SDFGI_OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; - Vector<String> gi_modes; - gi_modes.push_back(""); - gi.shader.initialize(gi_modes, defines); - gi.shader_version = gi.shader.version_create(); - for (int i = 0; i < GI::MODE_MAX; i++) { - gi.pipelines[i] = RD::get_singleton()->compute_pipeline_create(gi.shader.version_get_shader(gi.shader_version, i)); + { + String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; + Vector<String> debug_modes; + debug_modes.push_back(""); + sdfgi_shader.debug.initialize(debug_modes, defines); + sdfgi_shader.debug_shader = sdfgi_shader.debug.version_create(); + sdfgi_shader.debug_shader_version = sdfgi_shader.debug.version_get_shader(sdfgi_shader.debug_shader, 0); + sdfgi_shader.debug_pipeline = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.debug_shader_version); } + { + String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; - gi.sdfgi_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(GI::SDFGIData)); - } - { - String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; - Vector<String> debug_modes; - debug_modes.push_back(""); - sdfgi_shader.debug.initialize(debug_modes, defines); - sdfgi_shader.debug_shader = sdfgi_shader.debug.version_create(); - sdfgi_shader.debug_shader_version = sdfgi_shader.debug.version_get_shader(sdfgi_shader.debug_shader, 0); - sdfgi_shader.debug_pipeline = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.debug_shader_version); - } - { - String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; - - Vector<String> versions; - versions.push_back("\n#define MODE_PROBES\n"); - versions.push_back("\n#define MODE_VISIBILITY\n"); + Vector<String> versions; + versions.push_back("\n#define MODE_PROBES\n"); + versions.push_back("\n#define MODE_VISIBILITY\n"); - sdfgi_shader.debug_probes.initialize(versions, defines); - sdfgi_shader.debug_probes_shader = sdfgi_shader.debug_probes.version_create(); + sdfgi_shader.debug_probes.initialize(versions, defines); + sdfgi_shader.debug_probes_shader = sdfgi_shader.debug_probes.version_create(); - { - RD::PipelineRasterizationState rs; - rs.cull_mode = RD::POLYGON_CULL_DISABLED; - RD::PipelineDepthStencilState ds; - ds.enable_depth_test = true; - ds.enable_depth_write = true; - ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; - for (int i = 0; i < SDGIShader::PROBE_DEBUG_MAX; i++) { - RID debug_probes_shader_version = sdfgi_shader.debug_probes.version_get_shader(sdfgi_shader.debug_probes_shader, i); - sdfgi_shader.debug_probes_pipeline[i].setup(debug_probes_shader_version, RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0); + { + RD::PipelineRasterizationState rs; + rs.cull_mode = RD::POLYGON_CULL_DISABLED; + RD::PipelineDepthStencilState ds; + ds.enable_depth_test = true; + ds.enable_depth_write = true; + ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; + for (int i = 0; i < SDGIShader::PROBE_DEBUG_MAX; i++) { + RID debug_probes_shader_version = sdfgi_shader.debug_probes.version_get_shader(sdfgi_shader.debug_probes_shader, i); + sdfgi_shader.debug_probes_pipeline[i].setup(debug_probes_shader_version, RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0); + } } } + default_giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GI::GIProbeData) * RenderBuffers::MAX_GIPROBES); } - //cluster setup - uint32_t uniform_max_size = RD::get_singleton()->limit_get(RD::LIMIT_MAX_UNIFORM_BUFFER_SIZE); + { //decals + cluster.max_decals = max_cluster_elements; + uint32_t decal_buffer_size = cluster.max_decals * sizeof(Cluster::DecalData); + cluster.decals = memnew_arr(Cluster::DecalData, cluster.max_decals); + cluster.decal_sort = memnew_arr(Cluster::InstanceSort<DecalInstance>, cluster.max_decals); + cluster.decal_buffer = RD::get_singleton()->storage_buffer_create(decal_buffer_size); + } { //reflections - uint32_t reflection_buffer_size; - if (uniform_max_size < 65536) { - //Yes, you guessed right, ARM again - reflection_buffer_size = uniform_max_size; - } else { - reflection_buffer_size = 65536; - } - cluster.max_reflections = reflection_buffer_size / sizeof(Cluster::ReflectionData); + cluster.max_reflections = max_cluster_elements; cluster.reflections = memnew_arr(Cluster::ReflectionData, cluster.max_reflections); - cluster.reflection_buffer = RD::get_singleton()->storage_buffer_create(reflection_buffer_size); + cluster.reflection_sort = memnew_arr(Cluster::InstanceSort<ReflectionProbeInstance>, cluster.max_reflections); + cluster.reflection_buffer = RD::get_singleton()->storage_buffer_create(sizeof(Cluster::ReflectionData) * cluster.max_reflections); } { //lights - cluster.max_lights = MIN(1024 * 1024, uniform_max_size) / sizeof(Cluster::LightData); //1mb of lights + cluster.max_lights = max_cluster_elements; + uint32_t light_buffer_size = cluster.max_lights * sizeof(Cluster::LightData); - cluster.lights = memnew_arr(Cluster::LightData, cluster.max_lights); - cluster.light_buffer = RD::get_singleton()->storage_buffer_create(light_buffer_size); + cluster.omni_lights = memnew_arr(Cluster::LightData, cluster.max_lights); + cluster.omni_light_buffer = RD::get_singleton()->storage_buffer_create(light_buffer_size); + cluster.omni_light_sort = memnew_arr(Cluster::InstanceSort<LightInstance>, cluster.max_lights); + cluster.spot_lights = memnew_arr(Cluster::LightData, cluster.max_lights); + cluster.spot_light_buffer = RD::get_singleton()->storage_buffer_create(light_buffer_size); + cluster.spot_light_sort = memnew_arr(Cluster::InstanceSort<LightInstance>, cluster.max_lights); //defines += "\n#define MAX_LIGHT_DATA_STRUCTS " + itos(cluster.max_lights) + "\n"; - cluster.lights_instances = memnew_arr(RID, cluster.max_lights); - cluster.lights_shadow_rect_cache = memnew_arr(Rect2i, cluster.max_lights); - cluster.max_directional_lights = 8; + cluster.max_directional_lights = MAX_DIRECTIONAL_LIGHTS; uint32_t directional_light_buffer_size = cluster.max_directional_lights * sizeof(Cluster::DirectionalLightData); cluster.directional_lights = memnew_arr(Cluster::DirectionalLightData, cluster.max_directional_lights); cluster.directional_light_buffer = RD::get_singleton()->uniform_buffer_create(directional_light_buffer_size); } - { //decals - cluster.max_decals = MIN(1024 * 1024, uniform_max_size) / sizeof(Cluster::DecalData); //1mb of decals - uint32_t decal_buffer_size = cluster.max_decals * sizeof(Cluster::DecalData); - cluster.decals = memnew_arr(Cluster::DecalData, cluster.max_decals); - cluster.decal_buffer = RD::get_singleton()->storage_buffer_create(decal_buffer_size); - } - - cluster.builder.setup(16, 8, 24); - - { + if (!low_end) { String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(cluster.max_directional_lights) + "\n"; Vector<String> volumetric_fog_modes; volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n"); @@ -8330,8 +8891,8 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { for (int i = 0; i < VOLUMETRIC_FOG_SHADER_MAX; i++) { volumetric_fog.pipelines[i] = RD::get_singleton()->compute_pipeline_create(volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, i)); } + volumetric_fog.params_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(VolumetricFogShader::ParamsUBO)); } - default_giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GI::GIProbeData) * RenderBuffers::MAX_GIPROBES); { RD::SamplerState sampler; @@ -8342,35 +8903,34 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { shadow_sampler = RD::get_singleton()->sampler_create(sampler); } - camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape(int(GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_bokeh_shape")))); - camera_effects_set_dof_blur_quality(RS::DOFBlurQuality(int(GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_bokeh_quality"))), GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_use_jitter")); - environment_set_ssao_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/quality/ssao/quality"))), GLOBAL_GET("rendering/quality/ssao/half_size")); - screen_space_roughness_limiter = GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_enabled"); - screen_space_roughness_limiter_amount = GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_amount"); - screen_space_roughness_limiter_limit = GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_limit"); - glow_bicubic_upscale = int(GLOBAL_GET("rendering/quality/glow/upscale_mode")) > 0; - glow_high_quality = GLOBAL_GET("rendering/quality/glow/use_high_quality"); - ssr_roughness_quality = RS::EnvironmentSSRRoughnessQuality(int(GLOBAL_GET("rendering/quality/screen_space_reflection/roughness_quality"))); - sss_quality = RS::SubSurfaceScatteringQuality(int(GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_quality"))); - sss_scale = GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_scale"); - sss_depth_scale = GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_depth_scale"); + camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape(int(GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_bokeh_shape")))); + camera_effects_set_dof_blur_quality(RS::DOFBlurQuality(int(GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_bokeh_quality"))), GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_use_jitter")); + environment_set_ssao_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/environment/ssao/quality"))), GLOBAL_GET("rendering/environment/ssao/half_size"), GLOBAL_GET("rendering/environment/ssao/adaptive_target"), GLOBAL_GET("rendering/environment/ssao/blur_passes"), GLOBAL_GET("rendering/environment/ssao/fadeout_from"), GLOBAL_GET("rendering/environment/ssao/fadeout_to")); + screen_space_roughness_limiter = GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/enabled"); + screen_space_roughness_limiter_amount = GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/amount"); + screen_space_roughness_limiter_limit = GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/limit"); + glow_bicubic_upscale = int(GLOBAL_GET("rendering/environment/glow/upscale_mode")) > 0; + glow_high_quality = GLOBAL_GET("rendering/environment/glow/use_high_quality"); + ssr_roughness_quality = RS::EnvironmentSSRRoughnessQuality(int(GLOBAL_GET("rendering/environment/screen_space_reflection/roughness_quality"))); + sss_quality = RS::SubSurfaceScatteringQuality(int(GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_quality"))); + sss_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_scale"); + sss_depth_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_depth_scale"); directional_penumbra_shadow_kernel = memnew_arr(float, 128); directional_soft_shadow_kernel = memnew_arr(float, 128); penumbra_shadow_kernel = memnew_arr(float, 128); soft_shadow_kernel = memnew_arr(float, 128); - shadows_quality_set(RS::ShadowQuality(int(GLOBAL_GET("rendering/quality/shadows/soft_shadow_quality")))); - directional_shadow_quality_set(RS::ShadowQuality(int(GLOBAL_GET("rendering/quality/directional_shadow/soft_shadow_quality")))); + shadows_quality_set(RS::ShadowQuality(int(GLOBAL_GET("rendering/shadows/shadows/soft_shadow_quality")))); + directional_shadow_quality_set(RS::ShadowQuality(int(GLOBAL_GET("rendering/shadows/directional_shadow/soft_shadow_quality")))); + + environment_set_volumetric_fog_volume_size(GLOBAL_GET("rendering/environment/volumetric_fog/volume_size"), GLOBAL_GET("rendering/environment/volumetric_fog/volume_depth")); + environment_set_volumetric_fog_filter_active(GLOBAL_GET("rendering/environment/volumetric_fog/use_filter")); + + cull_argument.set_page_pool(&cull_argument_pool); - environment_set_volumetric_fog_volume_size(GLOBAL_GET("rendering/volumetric_fog/volume_size"), GLOBAL_GET("rendering/volumetric_fog/volume_depth")); - environment_set_volumetric_fog_filter_active(GLOBAL_GET("rendering/volumetric_fog/use_filter")); - environment_set_volumetric_fog_directional_shadow_shrink_size(GLOBAL_GET("rendering/volumetric_fog/directional_shadow_shrink")); - environment_set_volumetric_fog_positional_shadow_shrink_size(GLOBAL_GET("rendering/volumetric_fog/positional_shadow_shrink")); + gi.half_resolution = GLOBAL_GET("rendering/global_illumination/gi/use_half_resolution"); } -RasterizerSceneRD::~RasterizerSceneRD() { - for (Map<Vector2i, ShadowMap>::Element *E = shadow_maps.front(); E; E = E->next()) { - RD::get_singleton()->free(E->get().depth); - } +RendererSceneRenderRD::~RendererSceneRenderRD() { for (Map<int, ShadowCubemap>::Element *E = shadow_cubemaps.front(); E; E = E->next()) { RD::get_singleton()->free(E->get().cubemap); } @@ -8379,23 +8939,27 @@ RasterizerSceneRD::~RasterizerSceneRD() { RD::get_singleton()->free(sky_scene_state.uniform_set); } - RD::get_singleton()->free(default_giprobe_buffer); - RD::get_singleton()->free(gi_probe_lights_uniform); - RD::get_singleton()->free(gi.sdfgi_ubo); + if (!low_end) { + RD::get_singleton()->free(default_giprobe_buffer); + RD::get_singleton()->free(gi_probe_lights_uniform); + RD::get_singleton()->free(gi.sdfgi_ubo); + + giprobe_debug_shader.version_free(giprobe_debug_shader_version); + giprobe_shader.version_free(giprobe_lighting_shader_version); + gi.shader.version_free(gi.shader_version); + sdfgi_shader.debug_probes.version_free(sdfgi_shader.debug_probes_shader); + sdfgi_shader.debug.version_free(sdfgi_shader.debug_shader); + sdfgi_shader.direct_light.version_free(sdfgi_shader.direct_light_shader); + sdfgi_shader.integrate.version_free(sdfgi_shader.integrate_shader); + sdfgi_shader.preprocess.version_free(sdfgi_shader.preprocess_shader); - giprobe_debug_shader.version_free(giprobe_debug_shader_version); - giprobe_shader.version_free(giprobe_lighting_shader_version); - gi.shader.version_free(gi.shader_version); - sdfgi_shader.debug_probes.version_free(sdfgi_shader.debug_probes_shader); - sdfgi_shader.debug.version_free(sdfgi_shader.debug_shader); - sdfgi_shader.direct_light.version_free(sdfgi_shader.direct_light_shader); - sdfgi_shader.integrate.version_free(sdfgi_shader.integrate_shader); - sdfgi_shader.preprocess.version_free(sdfgi_shader.preprocess_shader); + volumetric_fog.shader.version_free(volumetric_fog.shader_version); + RD::get_singleton()->free(volumetric_fog.params_ubo); - volumetric_fog.shader.version_free(volumetric_fog.shader_version); + memdelete_arr(gi_probe_lights); + } - memdelete_arr(gi_probe_lights); - SkyMaterialData *md = (SkyMaterialData *)storage->material_get_data(sky_shader.default_material, RasterizerStorageRD::SHADER_TYPE_SKY); + SkyMaterialData *md = (SkyMaterialData *)storage->material_get_data(sky_shader.default_material, RendererStorageRD::SHADER_TYPE_SKY); sky_shader.shader.version_free(md->shader_data->version); RD::get_singleton()->free(sky_scene_state.directional_light_buffer); RD::get_singleton()->free(sky_scene_state.uniform_buffer); @@ -8412,18 +8976,23 @@ RasterizerSceneRD::~RasterizerSceneRD() { { RD::get_singleton()->free(cluster.directional_light_buffer); - RD::get_singleton()->free(cluster.light_buffer); + RD::get_singleton()->free(cluster.omni_light_buffer); + RD::get_singleton()->free(cluster.spot_light_buffer); RD::get_singleton()->free(cluster.reflection_buffer); RD::get_singleton()->free(cluster.decal_buffer); memdelete_arr(cluster.directional_lights); - memdelete_arr(cluster.lights); - memdelete_arr(cluster.lights_shadow_rect_cache); - memdelete_arr(cluster.lights_instances); + memdelete_arr(cluster.omni_lights); + memdelete_arr(cluster.spot_lights); + memdelete_arr(cluster.omni_light_sort); + memdelete_arr(cluster.spot_light_sort); memdelete_arr(cluster.reflections); + memdelete_arr(cluster.reflection_sort); memdelete_arr(cluster.decals); + memdelete_arr(cluster.decal_sort); } RD::get_singleton()->free(shadow_sampler); directional_shadow_atlas_set_size(0); + cull_argument.reset(); //avoid exit error } diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 3d5310bb7e..e4eaa93212 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rasterizer_scene_rd.h */ +/* renderer_scene_render_rd.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,27 +28,28 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef RASTERIZER_SCENE_RD_H -#define RASTERIZER_SCENE_RD_H +#ifndef RENDERING_SERVER_SCENE_RENDER_RD_H +#define RENDERING_SERVER_SCENE_RENDER_RD_H #include "core/templates/local_vector.h" #include "core/templates/rid_owner.h" -#include "servers/rendering/rasterizer.h" -#include "servers/rendering/rasterizer_rd/light_cluster_builder.h" -#include "servers/rendering/rasterizer_rd/rasterizer_storage_rd.h" -#include "servers/rendering/rasterizer_rd/shaders/gi.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/giprobe.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/giprobe_debug.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/sdfgi_debug.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/sdfgi_debug_probes.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/sdfgi_direct_light.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/sdfgi_integrate.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/sdfgi_preprocess.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/sky.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/volumetric_fog.glsl.gen.h" +#include "servers/rendering/renderer_compositor.h" +#include "servers/rendering/renderer_rd/cluster_builder_rd.h" +#include "servers/rendering/renderer_rd/renderer_storage_rd.h" +#include "servers/rendering/renderer_rd/shaders/gi.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/giprobe.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/giprobe_debug.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/sky.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/volumetric_fog.glsl.gen.h" +#include "servers/rendering/renderer_scene_render.h" #include "servers/rendering/rendering_device.h" -class RasterizerSceneRD : public RasterizerScene { +class RendererSceneRenderRD : public RendererSceneRender { protected: double time; @@ -103,17 +104,22 @@ protected: }; virtual RenderBufferData *_create_render_buffer_data() = 0; - void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count); - void _setup_decals(const RID *p_decal_instances, int p_decal_count, const Transform &p_camera_inverse_xform); - void _setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, RID p_environment); - void _setup_giprobes(RID p_render_buffers, const Transform &p_transform, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, uint32_t &r_gi_probes_used); + void _setup_lights(const PagedArray<RID> &p_lights, const Transform &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count); + void _setup_decals(const PagedArray<RID> &p_decals, const Transform &p_camera_inverse_xform); + void _setup_reflections(const PagedArray<RID> &p_reflections, const Transform &p_camera_inverse_transform, RID p_environment); + void _setup_giprobes(RID p_render_buffers, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, uint32_t &r_gi_probes_used); - virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, int p_directional_light_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_color) = 0; - virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool use_dp_flip, bool p_use_pancake) = 0; - virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 0; - virtual void _render_uv2(InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 0; - virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, InstanceBase **p_cull_result, int p_cull_count, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) = 0; - virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, InstanceBase **p_cull_result, int p_cull_count) = 0; + virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_cluster_buffer, uint32_t p_cluster_size, uint32_t p_cluster_max_elements, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_color, float p_screen_lod_threshold) = 0; + + virtual void _render_shadow_begin() = 0; + virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true) = 0; + virtual void _render_shadow_process() = 0; + virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL) = 0; + + virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0; + virtual void _render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0; + virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) = 0; + virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) = 0; virtual void _debug_giprobe(RID p_gi_probe, RenderingDevice::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha); void _debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform); @@ -123,8 +129,6 @@ protected: virtual void _base_uniforms_changed() = 0; virtual void _render_buffers_uniform_set_changed(RID p_render_buffers) = 0; virtual RID _render_buffers_get_normal_texture(RID p_render_buffers) = 0; - virtual RID _render_buffers_get_ambient_texture(RID p_render_buffers) = 0; - virtual RID _render_buffers_get_reflection_texture(RID p_render_buffers) = 0; void _process_ssao(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection); void _process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive); @@ -133,16 +137,27 @@ protected: void _setup_sky(RID p_environment, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size); void _update_sky(RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform); void _draw_sky(bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform); - void _process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_ambient_buffer, RID p_reflection_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count); + void _pre_process_gi(RID p_render_buffers, const Transform &p_transform); + void _process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, const PagedArray<RID> &p_gi_probes); + + bool _needs_post_prepass_render(bool p_use_gi); + void _post_prepass_render(bool p_use_gi); + void _pre_resolve_render(bool p_use_gi); + void _pre_opaque_render(bool p_use_ssao, bool p_use_gi, RID p_normal_roughness_buffer, RID p_gi_probe_buffer); + uint32_t _get_render_state_directional_light_count() const; + + // needed for a single argument calls (material and uv2) + PagedArrayPool<GeometryInstance *> cull_argument_pool; + PagedArray<GeometryInstance *> cull_argument; //need this to exist private: RS::ViewportDebugDraw debug_draw = RS::VIEWPORT_DEBUG_DRAW_DISABLED; double time_step = 0; - static RasterizerSceneRD *singleton; + static RendererSceneRenderRD *singleton; int roughness_layers; - RasterizerStorageRD *storage; + RendererStorageRD *storage; struct ReflectionData { struct Layer { @@ -200,11 +215,11 @@ private: RID default_shader_rd; } sky_shader; - struct SkyShaderData : public RasterizerStorageRD::ShaderData { + struct SkyShaderData : public RendererStorageRD::ShaderData { bool valid; RID version; - RenderPipelineVertexFormatCacheRD pipelines[SKY_VERSION_MAX]; + PipelineCacheRD pipelines[SKY_VERSION_MAX]; Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms; Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms; @@ -224,21 +239,22 @@ private: virtual void set_code(const String &p_Code); virtual void set_default_texture_param(const StringName &p_name, RID p_texture); virtual void get_param_list(List<PropertyInfo> *p_param_list) const; - virtual void get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const; + virtual void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const; virtual bool is_param_texture(const StringName &p_param) const; virtual bool is_animated() const; virtual bool casts_shadows() const; virtual Variant get_default_parameter(const StringName &p_parameter) const; + virtual RS::ShaderNativeSourceCode get_native_source_code() const; SkyShaderData(); virtual ~SkyShaderData(); }; - RasterizerStorageRD::ShaderData *_create_sky_shader_func(); - static RasterizerStorageRD::ShaderData *_create_sky_shader_funcs() { - return static_cast<RasterizerSceneRD *>(singleton)->_create_sky_shader_func(); + RendererStorageRD::ShaderData *_create_sky_shader_func(); + static RendererStorageRD::ShaderData *_create_sky_shader_funcs() { + return static_cast<RendererSceneRenderRD *>(singleton)->_create_sky_shader_func(); }; - struct SkyMaterialData : public RasterizerStorageRD::MaterialData { + struct SkyMaterialData : public RendererStorageRD::MaterialData { uint64_t last_frame; SkyShaderData *shader_data; RID uniform_buffer; @@ -253,9 +269,9 @@ private: virtual ~SkyMaterialData(); }; - RasterizerStorageRD::MaterialData *_create_sky_material_func(SkyShaderData *p_shader); - static RasterizerStorageRD::MaterialData *_create_sky_material_funcs(RasterizerStorageRD::ShaderData *p_shader) { - return static_cast<RasterizerSceneRD *>(singleton)->_create_sky_material_func(static_cast<SkyShaderData *>(p_shader)); + RendererStorageRD::MaterialData *_create_sky_material_func(SkyShaderData *p_shader); + static RendererStorageRD::MaterialData *_create_sky_material_funcs(RendererStorageRD::ShaderData *p_shader) { + return static_cast<RendererSceneRenderRD *>(singleton)->_create_sky_material_func(static_cast<SkyShaderData *>(p_shader)); }; enum SkyTextureSetVersion { @@ -317,7 +333,7 @@ private: uint32_t sky_ggx_samples_quality; bool sky_use_cubemap_array; - mutable RID_Owner<Sky> sky_owner; + mutable RID_Owner<Sky, true> sky_owner; /* REFLECTION ATLAS */ @@ -336,9 +352,11 @@ private: }; Vector<Reflection> reflections; + + ClusterBuilderRD *cluster_builder = nullptr; }; - RID_Owner<ReflectionAtlas> reflection_atlas_owner; + mutable RID_Owner<ReflectionAtlas> reflection_atlas_owner; /* REFLECTION PROBE INSTANCE */ @@ -370,6 +388,15 @@ private: mutable RID_Owner<DecalInstance> decal_instance_owner; + /* LIGHTMAP INSTANCE */ + + struct LightmapInstance { + RID lightmap; + Transform transform; + }; + + mutable RID_Owner<LightmapInstance> lightmap_instance_owner; + /* GIPROBE INSTANCE */ struct GIProbeLight { @@ -379,10 +406,10 @@ private: float attenuation; float color[3]; - float spot_angle_radians; + float cos_spot_angle; float position[3]; - float spot_attenuation; + float inv_spot_attenuation; float direction[3]; uint32_t has_shadow; @@ -512,7 +539,7 @@ private: GiprobeDebugShaderRD giprobe_debug_shader; RID giprobe_debug_shader_version; RID giprobe_debug_shader_version_shaders[GI_PROBE_DEBUG_MAX]; - RenderPipelineVertexFormatCacheRD giprobe_debug_shader_version_pipelines[GI_PROBE_DEBUG_MAX]; + PipelineCacheRD giprobe_debug_shader_version_pipelines[GI_PROBE_DEBUG_MAX]; RID giprobe_debug_uniform_set; /* SHADOW ATLAS */ @@ -558,17 +585,18 @@ private: uint32_t smallest_subdiv = 0; int size = 0; + bool use_16_bits = false; RID depth; RID fb; //for copying Map<RID, uint32_t> shadow_owners; - - Vector<ShadowShrinkStage> shrink_stages; }; RID_Owner<ShadowAtlas> shadow_atlas_owner; + void _update_shadow_atlas(ShadowAtlas *shadow_atlas); + bool _shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow); RS::ShadowQuality shadows_quality = RS::SHADOW_QUALITY_MAX; //So it always updates when first set @@ -589,17 +617,16 @@ private: struct DirectionalShadow { RID depth; + RID fb; //when renderign direct int light_count = 0; int size = 0; + bool use_16_bits = false; int current_light = 0; - Vector<ShadowShrinkStage> shrink_stages; - } directional_shadow; - void _allocate_shadow_shrink_stages(RID p_base, int p_base_size, Vector<ShadowShrinkStage> &shrink_stages, uint32_t p_target_size); - void _clear_shadow_shrink_stages(Vector<ShadowShrinkStage> &shrink_stages); + void _update_directional_shadow_atlas(); /* SHADOW CUBEMAPS */ @@ -611,14 +638,6 @@ private: Map<int, ShadowCubemap> shadow_cubemaps; ShadowCubemap *_get_shadow_cubemap(int p_size); - struct ShadowMap { - RID depth; - RID fb; - }; - - Map<Vector2i, ShadowMap> shadow_maps; - ShadowMap *_get_shadow_map(const Size2i &p_size); - void _create_shadow_cubemaps(); /* LIGHT INSTANCE */ @@ -638,7 +657,7 @@ private: RS::LightType light_type = RS::LIGHT_DIRECTIONAL; - ShadowTransform shadow_transform[4]; + ShadowTransform shadow_transform[6]; AABB aabb; RID self; @@ -717,8 +736,9 @@ private: float volumetric_fog_light_energy = 0.0; float volumetric_fog_length = 64.0; float volumetric_fog_detail_spread = 2.0; - RS::EnvVolumetricFogShadowFilter volumetric_fog_shadow_filter = RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_LOW; float volumetric_fog_gi_inject = 0.0; + bool volumetric_fog_temporal_reprojection = true; + float volumetric_fog_temporal_reprojection_amount = 0.9; /// Glow @@ -736,13 +756,14 @@ private: /// SSAO bool ssao_enabled = false; - float ssao_radius = 1; - float ssao_intensity = 1; - float ssao_bias = 0.01; + float ssao_radius = 1.0; + float ssao_intensity = 2.0; + float ssao_power = 1.5; + float ssao_detail = 0.5; + float ssao_horizon = 0.06; + float ssao_sharpness = 0.98; float ssao_direct_light_affect = 0.0; float ssao_ao_channel_affect = 0.0; - float ssao_blur_edge_sharpness = 4.0; - RS::EnvironmentSSAOBlur ssao_blur = RS::ENV_SSAO_BLUR_3x3; /// SSR /// @@ -757,23 +778,38 @@ private: RS::EnvironmentSDFGICascades sdfgi_cascades; float sdfgi_min_cell_size = 0.2; bool sdfgi_use_occlusion = false; - bool sdfgi_use_multibounce = false; + float sdfgi_bounce_feedback = 0.0; bool sdfgi_read_sky_light = false; float sdfgi_energy = 1.0; float sdfgi_normal_bias = 1.1; float sdfgi_probe_bias = 1.1; RS::EnvironmentSDFGIYScale sdfgi_y_scale = RS::ENV_SDFGI_Y_SCALE_DISABLED; + + /// Adjustments + + bool adjustments_enabled = false; + float adjustments_brightness = 1.0f; + float adjustments_contrast = 1.0f; + float adjustments_saturation = 1.0f; + bool use_1d_color_correction = false; + RID color_correction = RID(); }; RS::EnvironmentSSAOQuality ssao_quality = RS::ENV_SSAO_QUALITY_MEDIUM; bool ssao_half_size = false; + bool ssao_using_half_size = false; + float ssao_adaptive_target = 0.5; + int ssao_blur_passes = 2; + float ssao_fadeout_from = 50.0; + float ssao_fadeout_to = 300.0; + bool glow_bicubic_upscale = false; bool glow_high_quality = false; RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::ENV_SSR_ROUGNESS_QUALITY_LOW; static uint64_t auto_exposure_counter; - mutable RID_Owner<Environment> environment_owner; + mutable RID_Owner<Environment, true> environment_owner; /* CAMERA EFFECTS */ @@ -799,10 +835,13 @@ private: float sss_scale = 0.05; float sss_depth_scale = 0.01; - mutable RID_Owner<CameraEffects> camera_effects_owner; + mutable RID_Owner<CameraEffects, true> camera_effects_owner; /* RENDER BUFFERS */ + ClusterBuilderSharedDataRD cluster_builder_shared; + ClusterBuilderRD *current_cluster_builder = nullptr; + struct SDFGI; struct VolumetricFog; @@ -828,6 +867,8 @@ private: SDFGI *sdfgi = nullptr; VolumetricFog *volumetric_fog = nullptr; + ClusterBuilderRD *cluster_builder = nullptr; + //built-in textures used for ping pong image processing and blurring struct Blur { RID texture; @@ -851,8 +892,12 @@ private: struct SSAO { RID depth; Vector<RID> depth_slices; - RID ao[2]; - RID ao_full; //when using half-size + RID ao_deinterleaved; + Vector<RID> ao_deinterleaved_slices; + RID ao_pong; + Vector<RID> ao_pong_slices; + RID ao_final; + RID importance_map[2]; } ssao; struct SSR { @@ -863,6 +908,16 @@ private: RID giprobe_textures[MAX_GIPROBES]; RID giprobe_buffer; + + RID ambient_buffer; + RID reflection_buffer; + bool using_half_size_gi = false; + + struct GI { + RID full_buffer; + RID full_dispatch; + RID full_mask; + } gi; }; RID default_giprobe_buffer; @@ -924,6 +979,8 @@ private: RID scroll_occlusion_uniform_set; RID integrate_uniform_set; RID lights_buffer; + + bool all_dynamic_lights_dirty = true; }; //used for rendering (voxelization) @@ -971,7 +1028,7 @@ private: RID cascades_ubo; bool uses_occlusion = false; - bool uses_multibounce = false; + float bounce_feedback = 0.0; bool reads_sky = false; float energy = 1.0; float normal_bias = 1.1; @@ -981,10 +1038,18 @@ private: float y_mult = 1.0; uint32_t render_pass = 0; + + int32_t cascade_dynamic_light_count[SDFGI::MAX_CASCADES]; //used dynamically }; + void _sdfgi_update_light(RID p_render_buffers, RID p_environment); + void _sdfgi_update_probes(RID p_render_buffers, RID p_environment); + void _sdfgi_store_probes(RID p_render_buffers); + RS::EnvironmentSDFGIRayCount sdfgi_ray_count = RS::ENV_SDFGI_RAY_COUNT_16; RS::EnvironmentSDFGIFramesToConverge sdfgi_frames_to_converge = RS::ENV_SDFGI_CONVERGE_IN_10_FRAMES; + RS::EnvironmentSDFGIFramesToUpdateLight sdfgi_frames_to_update_light = RS::ENV_SDFGI_UPDATE_LIGHT_IN_4_FRAMES; + float sdfgi_solid_cell_ratio = 0.25; Vector3 sdfgi_debug_probe_pos; Vector3 sdfgi_debug_probe_dir; @@ -1068,7 +1133,7 @@ private: RID debug_probes_shader; RID debug_probes_shader_version; - RenderPipelineVertexFormatCacheRD debug_probes_pipeline[PROBE_DEBUG_MAX]; + PipelineCacheRD debug_probes_pipeline[PROBE_DEBUG_MAX]; struct Light { float color[3]; @@ -1081,8 +1146,8 @@ private: float attenuation; uint32_t type; - float spot_angle; - float spot_attenuation; + float cos_spot_angle; + float inv_spot_attenuation; float radius; float shadow_color[4]; @@ -1098,9 +1163,9 @@ private: uint32_t process_increment; int32_t probe_axis_size; - uint32_t multibounce; + float bounce_feedback; float y_mult; - uint32_t pad; + uint32_t use_occlusion; }; enum { @@ -1222,23 +1287,28 @@ private: float z_far; float proj_info[4]; - + float ao_color[3]; uint32_t max_giprobes; + uint32_t high_quality_vct; - uint32_t use_sdfgi; uint32_t orthogonal; - - float ao_color[3]; - uint32_t pad; + uint32_t pad[2]; float cam_rotation[12]; }; RID sdfgi_ubo; - enum { - MODE_MAX = 1 + enum Mode { + MODE_GIPROBE, + MODE_SDFGI, + MODE_COMBINED, + MODE_HALF_RES_GIPROBE, + MODE_HALF_RES_SDFGI, + MODE_HALF_RES_COMBINED, + MODE_MAX }; + bool half_resolution = false; GiShaderRD shader; RID shader_version; RID pipelines[MODE_MAX]; @@ -1263,14 +1333,23 @@ private: struct Cluster { /* Scene State UBO */ - struct ReflectionData { //should always be 128 bytes + enum { + REFLECTION_AMBIENT_DISABLED = 0, + REFLECTION_AMBIENT_ENVIRONMENT = 1, + REFLECTION_AMBIENT_COLOR = 2, + }; + + struct ReflectionData { float box_extents[3]; float index; float box_offset[3]; uint32_t mask; - float params[4]; // intensity, 0, interior , boxproject float ambient[3]; // ambient color, + float intensity; + bool exterior; + bool box_project; uint32_t ambient_mode; + uint32_t pad; float local_matrix[16]; // up to here for spot and omni, rest is for directional }; @@ -1279,10 +1358,15 @@ private: float inv_radius; float direction[3]; float size; - uint16_t attenuation_energy[2]; //16 bits attenuation, then energy - uint8_t color_specular[4]; //rgb color, a specular (8 bit unorm) - uint16_t cone_attenuation_angle[2]; // attenuation and angle, (16bit float) - uint8_t shadow_color_enabled[4]; //shadow rgb color, a>0.5 enabled (8bit unorm) + + float color[3]; + float attenuation; + + float inv_spot_attenuation; + float cos_spot_angle; + float specular_amount; + uint32_t shadow_enabled; + float atlas_rect[4]; // in omni, used for atlas uv, in spot, used for projector uv float shadow_matrix[16]; float shadow_bias; @@ -1346,31 +1430,85 @@ private: float normal_fade; }; + template <class T> + struct InstanceSort { + float depth; + T *instance; + bool operator<(const InstanceSort &p_sort) const { + return depth < p_sort.depth; + } + }; + ReflectionData *reflections; + InstanceSort<ReflectionProbeInstance> *reflection_sort; uint32_t max_reflections; RID reflection_buffer; uint32_t max_reflection_probes_per_instance; + uint32_t reflection_count = 0; DecalData *decals; + InstanceSort<DecalInstance> *decal_sort; uint32_t max_decals; RID decal_buffer; + uint32_t decal_count; + + LightData *omni_lights; + LightData *spot_lights; - LightData *lights; + InstanceSort<LightInstance> *omni_light_sort; + InstanceSort<LightInstance> *spot_light_sort; uint32_t max_lights; - RID light_buffer; - RID *lights_instances; - Rect2i *lights_shadow_rect_cache; - uint32_t lights_shadow_rect_cache_count = 0; + RID omni_light_buffer; + RID spot_light_buffer; + uint32_t omni_light_count = 0; + uint32_t spot_light_count = 0; DirectionalLightData *directional_lights; uint32_t max_directional_lights; RID directional_light_buffer; - LightClusterBuilder builder; - } cluster; + struct RenderState { + RID render_buffers; + Transform cam_transform; + CameraMatrix cam_projection; + bool cam_ortogonal = false; + const PagedArray<GeometryInstance *> *instances = nullptr; + const PagedArray<RID> *lights = nullptr; + const PagedArray<RID> *reflection_probes = nullptr; + const PagedArray<RID> *gi_probes = nullptr; + const PagedArray<RID> *decals = nullptr; + const PagedArray<RID> *lightmaps = nullptr; + RID environment; + RID camera_effects; + RID shadow_atlas; + RID reflection_atlas; + RID reflection_probe; + int reflection_probe_pass = 0; + float screen_lod_threshold = 0.0; + + const RenderShadowData *render_shadows = nullptr; + int render_shadow_count = 0; + const RenderSDFGIData *render_sdfgi_regions = nullptr; + int render_sdfgi_region_count = 0; + const RenderSDFGIUpdateData *sdfgi_update_data = nullptr; + + uint32_t directional_light_count = 0; + uint32_t gi_probe_count = 0; + + LocalVector<int> cube_shadows; + LocalVector<int> shadows; + LocalVector<int> directional_shadows; + + bool depth_prepass_used; + } render_state; + struct VolumetricFog { + enum { + MAX_TEMPORAL_FRAMES = 16 + }; + uint32_t width = 0; uint32_t height = 0; uint32_t depth = 0; @@ -1379,6 +1517,8 @@ private: float spread; RID light_density_map; + RID prev_light_density_map; + RID fog_map; RID uniform_set; RID uniform_set2; @@ -1386,6 +1526,8 @@ private: RID sky_uniform_set; int last_shadow_filter = -1; + + Transform prev_cam_transform; }; enum { @@ -1397,7 +1539,7 @@ private: }; struct VolumetricFogShader { - struct PushConstant { + struct ParamsUBO { float fog_frustum_size_begin[2]; float fog_frustum_size_end[2]; @@ -1415,13 +1557,24 @@ private: float detail_spread; float gi_inject; uint32_t max_gi_probes; - uint32_t pad; + uint32_t cluster_type_size; + + float screen_size[2]; + uint32_t cluster_shift; + uint32_t cluster_width; + + uint32_t max_cluster_element_count_div_32; + uint32_t use_temporal_reprojection; + uint32_t temporal_frame; + float temporal_blend; float cam_rotation[12]; + float to_prev_view[16]; }; VolumetricFogShaderRD shader; + RID params_ubo; RID shader_version; RID pipelines[VOLUMETRIC_FOG_SHADER_MAX]; @@ -1429,9 +1582,7 @@ private: uint32_t volumetric_fog_depth = 128; uint32_t volumetric_fog_size = 128; - bool volumetric_fog_filter_active = false; - uint32_t volumetric_fog_directional_shadow_shrink = 512; - uint32_t volumetric_fog_positional_shadow_shrink = 512; + bool volumetric_fog_filter_active = true; void _volumetric_fog_erase(RenderBuffers *rb); void _update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_gi_probe_count); @@ -1446,11 +1597,21 @@ private: float weight; }; + uint32_t max_cluster_elements = 512; + bool low_end = false; + + void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<GeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true); + void _render_sdfgi_region(RID p_render_buffers, int p_region, const PagedArray<GeometryInstance *> &p_instances); + void _render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result); + public: + virtual Transform geometry_instance_get_transform(GeometryInstance *p_instance) = 0; + virtual AABB geometry_instance_get_aabb(GeometryInstance *p_instance) = 0; + /* SHADOW ATLAS API */ RID shadow_atlas_create(); - void shadow_atlas_set_size(RID p_atlas, int p_size); + void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = false); void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision); bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version); _FORCE_INLINE_ bool shadow_atlas_owns_light_instance(RID p_atlas, RID p_light_intance) { @@ -1471,7 +1632,7 @@ public: return Size2(atlas->size, atlas->size); } - void directional_shadow_atlas_set_size(int p_size); + void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = false); int get_directional_light_shadow_size(RID p_light_intance); void set_directional_shadow_count(int p_count); @@ -1490,11 +1651,12 @@ public: virtual int sdfgi_get_pending_region_count(RID p_render_buffers) const; virtual AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const; virtual uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const; - virtual void sdfgi_update_probes(RID p_render_buffers, RID p_environment, const RID *p_directional_light_instances, uint32_t p_directional_light_count, const RID *p_positional_light_instances, uint32_t p_positional_light_count); RID sdfgi_get_ubo() const { return gi.sdfgi_ubo; } /* SKY API */ - RID sky_create(); + virtual RID sky_allocate(); + virtual void sky_initialize(RID p_rid); + void sky_set_radiance_size(RID p_sky, int p_radiance_size); void sky_set_mode(RID p_sky, RS::SkyMode p_mode); void sky_set_material(RID p_sky, RID p_material); @@ -1506,7 +1668,8 @@ public: /* ENVIRONMENT API */ - RID environment_create(); + virtual RID environment_allocate(); + virtual void environment_initialize(RID p_rid); void environment_set_background(RID p_env, RS::EnvironmentBG p_bg); void environment_set_sky(RID p_env, RID p_sky); @@ -1547,35 +1710,35 @@ public: float environment_get_fog_height_density(RID p_env) const; float environment_get_fog_aerial_perspective(RID p_env) const; - void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, RS::EnvVolumetricFogShadowFilter p_shadow_filter); + void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount); virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth); virtual void environment_set_volumetric_fog_filter_active(bool p_enable); - virtual void environment_set_volumetric_fog_directional_shadow_shrink_size(int p_shrink_size); - virtual void environment_set_volumetric_fog_positional_shadow_shrink_size(int p_shrink_size); void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance); - void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_bias, float p_light_affect, float p_ao_channel_affect, RS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness); - void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size); + void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect); + void 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); bool environment_is_ssao_enabled(RID p_env) const; float environment_get_ssao_ao_affect(RID p_env) const; float environment_get_ssao_light_affect(RID p_env) const; bool environment_is_ssr_enabled(RID p_env) const; bool environment_is_sdfgi_enabled(RID p_env) const; - virtual void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, bool p_use_multibounce, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias); + virtual void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias); virtual void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count); virtual void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames); + virtual void environment_set_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update); void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality); RS::EnvironmentSSRRoughnessQuality environment_get_ssr_roughness_quality() const; void environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale); - void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) {} + void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction); virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size); - virtual RID camera_effects_create(); + virtual RID camera_effects_allocate(); + virtual void camera_effects_initialize(RID p_rid); virtual void camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter); virtual void camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape); @@ -1716,6 +1879,8 @@ public: virtual RID reflection_atlas_create(); virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count); + virtual int reflection_atlas_get_size(RID p_ref_atlas) const; + _FORCE_INLINE_ RID reflection_atlas_get_texture(RID p_ref_atlas) { ReflectionAtlas *atlas = reflection_atlas_owner.getornull(p_ref_atlas); ERR_FAIL_COND_V(!atlas, RID()); @@ -1794,10 +1959,25 @@ public: return decal->transform; } + virtual RID lightmap_instance_create(RID p_lightmap); + virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform &p_transform); + _FORCE_INLINE_ bool lightmap_instance_is_valid(RID p_lightmap_instance) { + return lightmap_instance_owner.getornull(p_lightmap_instance) != nullptr; + } + + _FORCE_INLINE_ RID lightmap_instance_get_lightmap(RID p_lightmap_instance) { + LightmapInstance *li = lightmap_instance_owner.getornull(p_lightmap_instance); + return li->lightmap; + } + _FORCE_INLINE_ Transform lightmap_instance_get_transform(RID p_lightmap_instance) { + LightmapInstance *li = lightmap_instance_owner.getornull(p_lightmap_instance); + return li->transform; + } + RID gi_probe_instance_create(RID p_base); void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform); bool gi_probe_needs_update(RID p_probe) const; - void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, int p_dynamic_object_count, InstanceBase **p_dynamic_objects); + void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects); void gi_probe_set_quality(RS::GIProbeQuality p_quality) { gi_probe_quality = p_quality; } @@ -1847,11 +2027,14 @@ public: */ RID render_buffers_create(); void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding); + void gi_set_use_half_resolution(bool p_enable); RID render_buffers_get_ao_texture(RID p_render_buffers); RID render_buffers_get_back_buffer_texture(RID p_render_buffers); RID render_buffers_get_gi_probe_buffer(RID p_render_buffers); RID render_buffers_get_default_gi_probe_buffer(); + RID render_buffers_get_gi_ambient_texture(RID p_render_buffers); + RID render_buffers_get_gi_reflection_texture(RID p_render_buffers); uint32_t render_buffers_get_sdfgi_cascade_count(RID p_render_buffers) const; bool render_buffers_is_sdfgi_enabled(RID p_render_buffers) const; @@ -1872,16 +2055,11 @@ public: float render_buffers_get_volumetric_fog_end(RID p_render_buffers); float render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers); - void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_shadow_atlas, RID p_camera_effects, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass); - - void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count); + void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr); - void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region); + void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region); - void render_sdfgi(RID p_render_buffers, int p_region, InstanceBase **p_cull_result, int p_cull_count); - void render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const RID **p_positional_light_cull_result, const uint32_t *p_positional_light_cull_count); - - void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, InstanceBase **p_cull_result, int p_cull_count); + void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<GeometryInstance *> &p_instances); virtual void set_scene_pass(uint64_t p_pass) { scene_pass = p_pass; @@ -1932,18 +2110,19 @@ public: virtual void set_time(double p_time, double p_step); - RID get_cluster_builder_texture(); - RID get_cluster_builder_indices_buffer(); RID get_reflection_probe_buffer(); - RID get_positional_light_buffer(); + RID get_omni_light_buffer(); + RID get_spot_light_buffer(); RID get_directional_light_buffer(); RID get_decal_buffer(); int get_max_directional_lights() const; void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir); - RasterizerSceneRD(RasterizerStorageRD *p_storage); - ~RasterizerSceneRD(); + bool is_low_end() const; + + RendererSceneRenderRD(RendererStorageRD *p_storage); + ~RendererSceneRenderRD(); }; #endif // RASTERIZER_SCENE_RD_H diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index 444ef9c49a..2a34049675 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rasterizer_storage_rd.cpp */ +/* renderer_storage_rd.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,15 +28,19 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "rasterizer_storage_rd.h" +#include "renderer_storage_rd.h" #include "core/config/engine.h" #include "core/config/project_settings.h" #include "core/io/resource_loader.h" -#include "rasterizer_rd.h" +#include "renderer_compositor_rd.h" #include "servers/rendering/shader_language.h" -Ref<Image> RasterizerStorageRD::_validate_texture_format(const Ref<Image> &p_image, TextureToRDFormat &r_format) { +bool RendererStorageRD::can_create_resources_async() const { + return true; +} + +Ref<Image> RendererStorageRD::_validate_texture_format(const Ref<Image> &p_image, TextureToRDFormat &r_format) { Ref<Image> image = p_image->duplicate(); switch (p_image->get_format()) { @@ -318,7 +322,7 @@ Ref<Image> RasterizerStorageRD::_validate_texture_format(const Ref<Image> &p_ima r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; } break; //unsigned float bc6hu - case Image::FORMAT_PVRTC2: { + case Image::FORMAT_PVRTC1_2: { //this is not properly supported by MoltekVK it seems, so best to use ETC2 if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { r_format.format = RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG; @@ -336,7 +340,7 @@ Ref<Image> RasterizerStorageRD::_validate_texture_format(const Ref<Image> &p_ima r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; } break; //pvrtc - case Image::FORMAT_PVRTC2A: { + case Image::FORMAT_PVRTC1_2A: { //this is not properly supported by MoltekVK it seems, so best to use ETC2 if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { r_format.format = RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG; @@ -353,7 +357,7 @@ Ref<Image> RasterizerStorageRD::_validate_texture_format(const Ref<Image> &p_ima r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; } break; - case Image::FORMAT_PVRTC4: { + case Image::FORMAT_PVRTC1_4: { //this is not properly supported by MoltekVK it seems, so best to use ETC2 if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { r_format.format = RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG; @@ -370,7 +374,7 @@ Ref<Image> RasterizerStorageRD::_validate_texture_format(const Ref<Image> &p_ima r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; } break; - case Image::FORMAT_PVRTC4A: { + case Image::FORMAT_PVRTC1_4A: { //this is not properly supported by MoltekVK it seems, so best to use ETC2 if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { r_format.format = RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG; @@ -535,9 +539,13 @@ Ref<Image> RasterizerStorageRD::_validate_texture_format(const Ref<Image> &p_ima return image; } -RID RasterizerStorageRD::texture_2d_create(const Ref<Image> &p_image) { - ERR_FAIL_COND_V(p_image.is_null(), RID()); - ERR_FAIL_COND_V(p_image->empty(), RID()); +RID RendererStorageRD::texture_allocate() { + return texture_owner.allocate_rid(); +} + +void RendererStorageRD::texture_2d_initialize(RID p_texture, const Ref<Image> &p_image) { + ERR_FAIL_COND(p_image.is_null()); + ERR_FAIL_COND(p_image->is_empty()); TextureToRDFormat ret_format; Ref<Image> image = _validate_texture_format(p_image, ret_format); @@ -567,7 +575,7 @@ RID RasterizerStorageRD::texture_2d_create(const Ref<Image> &p_image) { rd_format.depth = 1; rd_format.array_layers = 1; rd_format.mipmaps = texture.mipmaps; - rd_format.type = texture.rd_type; + rd_format.texture_type = texture.rd_type; rd_format.samples = RD::TEXTURE_SAMPLES_1; rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; if (texture.rd_format_srgb != RD::DATA_FORMAT_MAX) { @@ -585,13 +593,13 @@ RID RasterizerStorageRD::texture_2d_create(const Ref<Image> &p_image) { Vector<Vector<uint8_t>> data_slices; data_slices.push_back(data); texture.rd_texture = RD::get_singleton()->texture_create(rd_format, rd_view, data_slices); - ERR_FAIL_COND_V(texture.rd_texture.is_null(), RID()); + ERR_FAIL_COND(texture.rd_texture.is_null()); if (texture.rd_format_srgb != RD::DATA_FORMAT_MAX) { rd_view.format_override = texture.rd_format_srgb; texture.rd_texture_srgb = RD::get_singleton()->texture_create_shared(rd_view, texture.rd_texture); if (texture.rd_texture_srgb.is_null()) { RD::get_singleton()->free(texture.rd_texture); - ERR_FAIL_COND_V(texture.rd_texture_srgb.is_null(), RID()); + ERR_FAIL_COND(texture.rd_texture_srgb.is_null()); } } @@ -602,14 +610,14 @@ RID RasterizerStorageRD::texture_2d_create(const Ref<Image> &p_image) { texture.rd_view = rd_view; texture.is_proxy = false; - return texture_owner.make_rid(texture); + texture_owner.initialize_rid(p_texture, texture); } -RID RasterizerStorageRD::texture_2d_layered_create(const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) { - ERR_FAIL_COND_V(p_layers.size() == 0, RID()); +void RendererStorageRD::texture_2d_layered_initialize(RID p_texture, const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) { + ERR_FAIL_COND(p_layers.size() == 0); - ERR_FAIL_COND_V(p_layered_type == RS::TEXTURE_LAYERED_CUBEMAP && p_layers.size() != 6, RID()); - ERR_FAIL_COND_V(p_layered_type == RS::TEXTURE_LAYERED_CUBEMAP_ARRAY && (p_layers.size() < 6 || (p_layers.size() % 6) != 0), RID()); + ERR_FAIL_COND(p_layered_type == RS::TEXTURE_LAYERED_CUBEMAP && p_layers.size() != 6); + ERR_FAIL_COND(p_layered_type == RS::TEXTURE_LAYERED_CUBEMAP_ARRAY && (p_layers.size() < 6 || (p_layers.size() % 6) != 0)); TextureToRDFormat ret_format; Vector<Ref<Image>> images; @@ -620,7 +628,7 @@ RID RasterizerStorageRD::texture_2d_layered_create(const Vector<Ref<Image>> &p_l Image::Format valid_format = Image::FORMAT_MAX; for (int i = 0; i < p_layers.size(); i++) { - ERR_FAIL_COND_V(p_layers[i]->empty(), RID()); + ERR_FAIL_COND(p_layers[i]->is_empty()); if (i == 0) { valid_width = p_layers[i]->get_width(); @@ -628,10 +636,10 @@ RID RasterizerStorageRD::texture_2d_layered_create(const Vector<Ref<Image>> &p_l valid_format = p_layers[i]->get_format(); valid_mipmaps = p_layers[i]->has_mipmaps(); } else { - ERR_FAIL_COND_V(p_layers[i]->get_width() != valid_width, RID()); - ERR_FAIL_COND_V(p_layers[i]->get_height() != valid_height, RID()); - ERR_FAIL_COND_V(p_layers[i]->get_format() != valid_format, RID()); - ERR_FAIL_COND_V(p_layers[i]->has_mipmaps() != valid_mipmaps, RID()); + ERR_FAIL_COND(p_layers[i]->get_width() != valid_width); + ERR_FAIL_COND(p_layers[i]->get_height() != valid_height); + ERR_FAIL_COND(p_layers[i]->get_format() != valid_format); + ERR_FAIL_COND(p_layers[i]->has_mipmaps() != valid_mipmaps); } images.push_back(_validate_texture_format(p_layers[i], ret_format)); @@ -675,7 +683,7 @@ RID RasterizerStorageRD::texture_2d_layered_create(const Vector<Ref<Image>> &p_l rd_format.depth = 1; rd_format.array_layers = texture.layers; rd_format.mipmaps = texture.mipmaps; - rd_format.type = texture.rd_type; + rd_format.texture_type = texture.rd_type; rd_format.samples = RD::TEXTURE_SAMPLES_1; rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; if (texture.rd_format_srgb != RD::DATA_FORMAT_MAX) { @@ -695,13 +703,13 @@ RID RasterizerStorageRD::texture_2d_layered_create(const Vector<Ref<Image>> &p_l data_slices.push_back(data); } texture.rd_texture = RD::get_singleton()->texture_create(rd_format, rd_view, data_slices); - ERR_FAIL_COND_V(texture.rd_texture.is_null(), RID()); + ERR_FAIL_COND(texture.rd_texture.is_null()); if (texture.rd_format_srgb != RD::DATA_FORMAT_MAX) { rd_view.format_override = texture.rd_format_srgb; texture.rd_texture_srgb = RD::get_singleton()->texture_create_shared(rd_view, texture.rd_texture); if (texture.rd_texture_srgb.is_null()) { RD::get_singleton()->free(texture.rd_texture); - ERR_FAIL_COND_V(texture.rd_texture_srgb.is_null(), RID()); + ERR_FAIL_COND(texture.rd_texture_srgb.is_null()); } } @@ -712,14 +720,14 @@ RID RasterizerStorageRD::texture_2d_layered_create(const Vector<Ref<Image>> &p_l texture.rd_view = rd_view; texture.is_proxy = false; - return texture_owner.make_rid(texture); + texture_owner.initialize_rid(p_texture, texture); } -RID RasterizerStorageRD::texture_3d_create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) { - ERR_FAIL_COND_V(p_data.size() == 0, RID()); +void RendererStorageRD::texture_3d_initialize(RID p_texture, Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) { + ERR_FAIL_COND(p_data.size() == 0); Image::Image3DValidateError verr = Image::validate_3d_image(p_format, p_width, p_height, p_depth, p_mipmaps, p_data); if (verr != Image::VALIDATE_3D_OK) { - ERR_FAIL_V_MSG(RID(), Image::get_3d_image_validation_error_text(verr)); + ERR_FAIL_MSG(Image::get_3d_image_validation_error_text(verr)); } TextureToRDFormat ret_format; @@ -793,7 +801,7 @@ RID RasterizerStorageRD::texture_3d_create(Image::Format p_format, int p_width, rd_format.depth = texture.depth; rd_format.array_layers = 1; rd_format.mipmaps = texture.mipmaps; - rd_format.type = texture.rd_type; + rd_format.texture_type = texture.rd_type; rd_format.samples = RD::TEXTURE_SAMPLES_1; rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; if (texture.rd_format_srgb != RD::DATA_FORMAT_MAX) { @@ -811,13 +819,13 @@ RID RasterizerStorageRD::texture_3d_create(Image::Format p_format, int p_width, data_slices.push_back(all_data); //one slice texture.rd_texture = RD::get_singleton()->texture_create(rd_format, rd_view, data_slices); - ERR_FAIL_COND_V(texture.rd_texture.is_null(), RID()); + ERR_FAIL_COND(texture.rd_texture.is_null()); if (texture.rd_format_srgb != RD::DATA_FORMAT_MAX) { rd_view.format_override = texture.rd_format_srgb; texture.rd_texture_srgb = RD::get_singleton()->texture_create_shared(rd_view, texture.rd_texture); if (texture.rd_texture_srgb.is_null()) { RD::get_singleton()->free(texture.rd_texture); - ERR_FAIL_COND_V(texture.rd_texture_srgb.is_null(), RID()); + ERR_FAIL_COND(texture.rd_texture_srgb.is_null()); } } @@ -828,12 +836,12 @@ RID RasterizerStorageRD::texture_3d_create(Image::Format p_format, int p_width, texture.rd_view = rd_view; texture.is_proxy = false; - return texture_owner.make_rid(texture); + texture_owner.initialize_rid(p_texture, texture); } -RID RasterizerStorageRD::texture_proxy_create(RID p_base) { +void RendererStorageRD::texture_proxy_initialize(RID p_texture, RID p_base) { Texture *tex = texture_owner.getornull(p_base); - ERR_FAIL_COND_V(!tex, RID()); + ERR_FAIL_COND(!tex); Texture proxy_tex = *tex; proxy_tex.rd_view.format_override = tex->rd_format; @@ -847,15 +855,13 @@ RID RasterizerStorageRD::texture_proxy_create(RID p_base) { proxy_tex.is_proxy = true; proxy_tex.proxies.clear(); - RID rid = texture_owner.make_rid(proxy_tex); - - tex->proxies.push_back(rid); + texture_owner.initialize_rid(p_texture, proxy_tex); - return rid; + tex->proxies.push_back(p_texture); } -void RasterizerStorageRD::_texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer, bool p_immediate) { - ERR_FAIL_COND(p_image.is_null() || p_image->empty()); +void RendererStorageRD::_texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer, bool p_immediate) { + ERR_FAIL_COND(p_image.is_null() || p_image->is_empty()); Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND(!tex); @@ -873,18 +879,18 @@ void RasterizerStorageRD::_texture_2d_update(RID p_texture, const Ref<Image> &p_ TextureToRDFormat f; Ref<Image> validated = _validate_texture_format(p_image, f); - RD::get_singleton()->texture_update(tex->rd_texture, p_layer, validated->get_data(), !p_immediate); + RD::get_singleton()->texture_update(tex->rd_texture, p_layer, validated->get_data()); } -void RasterizerStorageRD::texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer) { +void RendererStorageRD::texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer) { _texture_2d_update(p_texture, p_image, p_layer, true); } -void RasterizerStorageRD::texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer) { +void RendererStorageRD::texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer) { _texture_2d_update(p_texture, p_image, p_layer, false); } -void RasterizerStorageRD::texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) { +void RendererStorageRD::texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) { Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND(!tex); ERR_FAIL_COND(tex->type != Texture::TYPE_3D); @@ -918,10 +924,10 @@ void RasterizerStorageRD::texture_3d_update(RID p_texture, const Vector<Ref<Imag } } - RD::get_singleton()->texture_update(tex->rd_texture, 0, all_data, true); + RD::get_singleton()->texture_update(tex->rd_texture, 0, all_data); } -void RasterizerStorageRD::texture_proxy_update(RID p_texture, RID p_proxy_to) { +void RendererStorageRD::texture_proxy_update(RID p_texture, RID p_proxy_to) { Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND(!tex); ERR_FAIL_COND(!tex->is_proxy); @@ -961,7 +967,7 @@ void RasterizerStorageRD::texture_proxy_update(RID p_texture, RID p_proxy_to) { } //these two APIs can be used together or in combination with the others. -RID RasterizerStorageRD::texture_2d_placeholder_create() { +void RendererStorageRD::texture_2d_placeholder_initialize(RID p_texture) { //this could be better optimized to reuse an existing image , done this way //for now to get it working Ref<Image> image; @@ -974,10 +980,10 @@ RID RasterizerStorageRD::texture_2d_placeholder_create() { } } - return texture_2d_create(image); + texture_2d_initialize(p_texture, image); } -RID RasterizerStorageRD::texture_2d_layered_placeholder_create(RS::TextureLayeredType p_layered_type) { +void RendererStorageRD::texture_2d_layered_placeholder_initialize(RID p_texture, RS::TextureLayeredType p_layered_type) { //this could be better optimized to reuse an existing image , done this way //for now to get it working Ref<Image> image; @@ -1000,10 +1006,10 @@ RID RasterizerStorageRD::texture_2d_layered_placeholder_create(RS::TextureLayere } } - return texture_2d_layered_create(images, p_layered_type); + texture_2d_layered_initialize(p_texture, images, p_layered_type); } -RID RasterizerStorageRD::texture_3d_placeholder_create() { +void RendererStorageRD::texture_3d_placeholder_initialize(RID p_texture) { //this could be better optimized to reuse an existing image , done this way //for now to get it working Ref<Image> image; @@ -1022,10 +1028,10 @@ RID RasterizerStorageRD::texture_3d_placeholder_create() { images.push_back(image); } - return texture_3d_create(Image::FORMAT_RGBA8, 4, 4, 4, false, images); + texture_3d_initialize(p_texture, Image::FORMAT_RGBA8, 4, 4, 4, false, images); } -Ref<Image> RasterizerStorageRD::texture_2d_get(RID p_texture) const { +Ref<Image> RendererStorageRD::texture_2d_get(RID p_texture) const { Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND_V(!tex, Ref<Image>()); @@ -1039,7 +1045,7 @@ Ref<Image> RasterizerStorageRD::texture_2d_get(RID p_texture) const { Ref<Image> image; image.instance(); image->create(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data); - ERR_FAIL_COND_V(image->empty(), Ref<Image>()); + ERR_FAIL_COND_V(image->is_empty(), Ref<Image>()); if (tex->format != tex->validated_format) { image->convert(tex->format); } @@ -1053,7 +1059,7 @@ Ref<Image> RasterizerStorageRD::texture_2d_get(RID p_texture) const { return image; } -Ref<Image> RasterizerStorageRD::texture_2d_layer_get(RID p_texture, int p_layer) const { +Ref<Image> RendererStorageRD::texture_2d_layer_get(RID p_texture, int p_layer) const { Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND_V(!tex, Ref<Image>()); @@ -1062,7 +1068,7 @@ Ref<Image> RasterizerStorageRD::texture_2d_layer_get(RID p_texture, int p_layer) Ref<Image> image; image.instance(); image->create(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data); - ERR_FAIL_COND_V(image->empty(), Ref<Image>()); + ERR_FAIL_COND_V(image->is_empty(), Ref<Image>()); if (tex->format != tex->validated_format) { image->convert(tex->format); } @@ -1070,7 +1076,7 @@ Ref<Image> RasterizerStorageRD::texture_2d_layer_get(RID p_texture, int p_layer) return image; } -Vector<Ref<Image>> RasterizerStorageRD::texture_3d_get(RID p_texture) const { +Vector<Ref<Image>> RendererStorageRD::texture_3d_get(RID p_texture) const { Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND_V(!tex, Vector<Ref<Image>>()); ERR_FAIL_COND_V(tex->type != Texture::TYPE_3D, Vector<Ref<Image>>()); @@ -1090,7 +1096,7 @@ Vector<Ref<Image>> RasterizerStorageRD::texture_3d_get(RID p_texture) const { Ref<Image> img; img.instance(); img->create(bs.size.width, bs.size.height, false, tex->validated_format, sub_region); - ERR_FAIL_COND_V(img->empty(), Vector<Ref<Image>>()); + ERR_FAIL_COND_V(img->is_empty(), Vector<Ref<Image>>()); if (tex->format != tex->validated_format) { img->convert(tex->format); } @@ -1101,7 +1107,7 @@ Vector<Ref<Image>> RasterizerStorageRD::texture_3d_get(RID p_texture) const { return ret; } -void RasterizerStorageRD::texture_replace(RID p_texture, RID p_by_texture) { +void RendererStorageRD::texture_replace(RID p_texture, RID p_by_texture) { Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND(!tex); ERR_FAIL_COND(tex->proxy_to.is_valid()); //can't replace proxy @@ -1150,7 +1156,7 @@ void RasterizerStorageRD::texture_replace(RID p_texture, RID p_by_texture) { } } -void RasterizerStorageRD::texture_set_size_override(RID p_texture, int p_width, int p_height) { +void RendererStorageRD::texture_set_size_override(RID p_texture, int p_width, int p_height) { Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND(!tex); ERR_FAIL_COND(tex->type != Texture::TYPE_2D); @@ -1158,53 +1164,53 @@ void RasterizerStorageRD::texture_set_size_override(RID p_texture, int p_width, tex->height_2d = p_height; } -void RasterizerStorageRD::texture_set_path(RID p_texture, const String &p_path) { +void RendererStorageRD::texture_set_path(RID p_texture, const String &p_path) { Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND(!tex); tex->path = p_path; } -String RasterizerStorageRD::texture_get_path(RID p_texture) const { +String RendererStorageRD::texture_get_path(RID p_texture) const { return String(); } -void RasterizerStorageRD::texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) { +void RendererStorageRD::texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) { Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND(!tex); tex->detect_3d_callback_ud = p_userdata; tex->detect_3d_callback = p_callback; } -void RasterizerStorageRD::texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) { +void RendererStorageRD::texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) { Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND(!tex); tex->detect_normal_callback_ud = p_userdata; tex->detect_normal_callback = p_callback; } -void RasterizerStorageRD::texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) { +void RendererStorageRD::texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) { Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND(!tex); tex->detect_roughness_callback_ud = p_userdata; tex->detect_roughness_callback = p_callback; } -void RasterizerStorageRD::texture_debug_usage(List<RS::TextureInfo> *r_info) { +void RendererStorageRD::texture_debug_usage(List<RS::TextureInfo> *r_info) { } -void RasterizerStorageRD::texture_set_proxy(RID p_proxy, RID p_base) { +void RendererStorageRD::texture_set_proxy(RID p_proxy, RID p_base) { } -void RasterizerStorageRD::texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) { +void RendererStorageRD::texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) { } -Size2 RasterizerStorageRD::texture_size_with_proxy(RID p_proxy) { +Size2 RendererStorageRD::texture_size_with_proxy(RID p_proxy) { return texture_2d_get_size(p_proxy); } /* CANVAS TEXTURE */ -void RasterizerStorageRD::CanvasTexture::clear_sets() { +void RendererStorageRD::CanvasTexture::clear_sets() { if (cleared_cache) { return; } @@ -1219,22 +1225,25 @@ void RasterizerStorageRD::CanvasTexture::clear_sets() { cleared_cache = true; } -RasterizerStorageRD::CanvasTexture::~CanvasTexture() { +RendererStorageRD::CanvasTexture::~CanvasTexture() { clear_sets(); } -RID RasterizerStorageRD::canvas_texture_create() { - return canvas_texture_owner.make_rid(memnew(CanvasTexture)); +RID RendererStorageRD::canvas_texture_allocate() { + return canvas_texture_owner.allocate_rid(); +} +void RendererStorageRD::canvas_texture_initialize(RID p_rid) { + canvas_texture_owner.initialize_rid(p_rid, memnew(CanvasTexture)); } -void RasterizerStorageRD::canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) { +void RendererStorageRD::canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) { CanvasTexture *ct = canvas_texture_owner.getornull(p_canvas_texture); switch (p_channel) { case RS::CANVAS_TEXTURE_CHANNEL_DIFFUSE: { ct->diffuse = p_texture; } break; case RS::CANVAS_TEXTURE_CHANNEL_NORMAL: { - ct->normalmap = p_texture; + ct->normal_map = p_texture; } break; case RS::CANVAS_TEXTURE_CHANNEL_SPECULAR: { ct->specular = p_texture; @@ -1244,7 +1253,7 @@ void RasterizerStorageRD::canvas_texture_set_channel(RID p_canvas_texture, RS::C ct->clear_sets(); } -void RasterizerStorageRD::canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_specular_color, float p_shininess) { +void RendererStorageRD::canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_specular_color, float p_shininess) { CanvasTexture *ct = canvas_texture_owner.getornull(p_canvas_texture); ct->specular_color.r = p_specular_color.r; ct->specular_color.g = p_specular_color.g; @@ -1253,19 +1262,19 @@ void RasterizerStorageRD::canvas_texture_set_shading_parameters(RID p_canvas_tex ct->clear_sets(); } -void RasterizerStorageRD::canvas_texture_set_texture_filter(RID p_canvas_texture, RS::CanvasItemTextureFilter p_filter) { +void RendererStorageRD::canvas_texture_set_texture_filter(RID p_canvas_texture, RS::CanvasItemTextureFilter p_filter) { CanvasTexture *ct = canvas_texture_owner.getornull(p_canvas_texture); ct->texture_filter = p_filter; ct->clear_sets(); } -void RasterizerStorageRD::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS::CanvasItemTextureRepeat p_repeat) { +void RendererStorageRD::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS::CanvasItemTextureRepeat p_repeat) { CanvasTexture *ct = canvas_texture_owner.getornull(p_canvas_texture); ct->texture_repeat = p_repeat; ct->clear_sets(); } -bool RasterizerStorageRD::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular) { +bool RendererStorageRD::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular) { CanvasTexture *ct = nullptr; Texture *t = texture_owner.getornull(p_texture); @@ -1298,7 +1307,7 @@ bool RasterizerStorageRD::canvas_texture_get_uniform_set(RID p_texture, RS::Canv Vector<RD::Uniform> uniforms; { //diffuse RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 0; t = texture_owner.getornull(ct->diffuse); @@ -1313,10 +1322,10 @@ bool RasterizerStorageRD::canvas_texture_get_uniform_set(RID p_texture, RS::Canv } { //normal RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; - t = texture_owner.getornull(ct->normalmap); + t = texture_owner.getornull(ct->normal_map); if (!t) { u.ids.push_back(texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL)); ct->use_normal_cache = false; @@ -1328,7 +1337,7 @@ bool RasterizerStorageRD::canvas_texture_get_uniform_set(RID p_texture, RS::Canv } { //specular RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; t = texture_owner.getornull(ct->specular); @@ -1343,7 +1352,7 @@ bool RasterizerStorageRD::canvas_texture_get_uniform_set(RID p_texture, RS::Canv } { //sampler RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 3; u.ids.push_back(sampler_rd_get_default(filter, repeat)); uniforms.push_back(u); @@ -1365,15 +1374,18 @@ bool RasterizerStorageRD::canvas_texture_get_uniform_set(RID p_texture, RS::Canv /* SHADER API */ -RID RasterizerStorageRD::shader_create() { +RID RendererStorageRD::shader_allocate() { + return shader_owner.allocate_rid(); +} +void RendererStorageRD::shader_initialize(RID p_rid) { Shader shader; shader.data = nullptr; shader.type = SHADER_TYPE_MAX; - return shader_owner.make_rid(shader); + shader_owner.initialize_rid(p_rid, shader); } -void RasterizerStorageRD::shader_set_code(RID p_shader, const String &p_code) { +void RendererStorageRD::shader_set_code(RID p_shader, const String &p_code) { Shader *shader = shader_owner.getornull(p_shader); ERR_FAIL_COND(!shader); @@ -1438,18 +1450,18 @@ void RasterizerStorageRD::shader_set_code(RID p_shader, const String &p_code) { for (Set<Material *>::Element *E = shader->owners.front(); E; E = E->next()) { Material *material = E->get(); - material->instance_dependency.instance_notify_changed(false, true); + material->dependency.changed_notify(DEPENDENCY_CHANGED_MATERIAL); _material_queue_update(material, true, true); } } -String RasterizerStorageRD::shader_get_code(RID p_shader) const { +String RendererStorageRD::shader_get_code(RID p_shader) const { Shader *shader = shader_owner.getornull(p_shader); ERR_FAIL_COND_V(!shader, String()); return shader->code; } -void RasterizerStorageRD::shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const { +void RendererStorageRD::shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const { Shader *shader = shader_owner.getornull(p_shader); ERR_FAIL_COND(!shader); if (shader->data) { @@ -1457,7 +1469,7 @@ void RasterizerStorageRD::shader_get_param_list(RID p_shader, List<PropertyInfo> } } -void RasterizerStorageRD::shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) { +void RendererStorageRD::shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) { Shader *shader = shader_owner.getornull(p_shader); ERR_FAIL_COND(!shader); @@ -1475,7 +1487,7 @@ void RasterizerStorageRD::shader_set_default_texture_param(RID p_shader, const S } } -RID RasterizerStorageRD::shader_get_default_texture_param(RID p_shader, const StringName &p_name) const { +RID RendererStorageRD::shader_get_default_texture_param(RID p_shader, const StringName &p_name) const { Shader *shader = shader_owner.getornull(p_shader); ERR_FAIL_COND_V(!shader, RID()); if (shader->default_texture_parameter.has(p_name)) { @@ -1485,7 +1497,7 @@ RID RasterizerStorageRD::shader_get_default_texture_param(RID p_shader, const St return RID(); } -Variant RasterizerStorageRD::shader_get_param_default(RID p_shader, const StringName &p_param) const { +Variant RendererStorageRD::shader_get_param_default(RID p_shader, const StringName &p_param) const { Shader *shader = shader_owner.getornull(p_shader); ERR_FAIL_COND_V(!shader, Variant()); if (shader->data) { @@ -1494,14 +1506,26 @@ Variant RasterizerStorageRD::shader_get_param_default(RID p_shader, const String return Variant(); } -void RasterizerStorageRD::shader_set_data_request_function(ShaderType p_shader_type, ShaderDataRequestFunction p_function) { +void RendererStorageRD::shader_set_data_request_function(ShaderType p_shader_type, ShaderDataRequestFunction p_function) { ERR_FAIL_INDEX(p_shader_type, SHADER_TYPE_MAX); shader_data_request_func[p_shader_type] = p_function; } +RS::ShaderNativeSourceCode RendererStorageRD::shader_get_native_source_code(RID p_shader) const { + Shader *shader = shader_owner.getornull(p_shader); + ERR_FAIL_COND_V(!shader, RS::ShaderNativeSourceCode()); + if (shader->data) { + return shader->data->get_native_source_code(); + } + return RS::ShaderNativeSourceCode(); +} + /* COMMON MATERIAL API */ -RID RasterizerStorageRD::material_create() { +RID RendererStorageRD::material_allocate() { + return material_owner.allocate_rid(); +} +void RendererStorageRD::material_initialize(RID p_rid) { Material material; material.data = nullptr; material.shader = nullptr; @@ -1511,15 +1535,11 @@ RID RasterizerStorageRD::material_create() { material.uniform_dirty = false; material.texture_dirty = false; material.priority = 0; - RID id = material_owner.make_rid(material); - { - Material *material_ptr = material_owner.getornull(id); - material_ptr->self = id; - } - return id; + material.self = p_rid; + material_owner.initialize_rid(p_rid, material); } -void RasterizerStorageRD::_material_queue_update(Material *material, bool p_uniform, bool p_texture) { +void RendererStorageRD::_material_queue_update(Material *material, bool p_uniform, bool p_texture) { if (material->update_requested) { return; } @@ -1531,7 +1551,7 @@ void RasterizerStorageRD::_material_queue_update(Material *material, bool p_unif material->texture_dirty = material->texture_dirty || p_texture; } -void RasterizerStorageRD::material_set_shader(RID p_material, RID p_shader) { +void RendererStorageRD::material_set_shader(RID p_material, RID p_shader) { Material *material = material_owner.getornull(p_material); ERR_FAIL_COND(!material); @@ -1547,7 +1567,8 @@ void RasterizerStorageRD::material_set_shader(RID p_material, RID p_shader) { } if (p_shader.is_null()) { - material->instance_dependency.instance_notify_changed(false, true); + material->dependency.changed_notify(DEPENDENCY_CHANGED_MATERIAL); + material->shader_id = 0; return; } @@ -1555,6 +1576,7 @@ void RasterizerStorageRD::material_set_shader(RID p_material, RID p_shader) { ERR_FAIL_COND(!shader); material->shader = shader; material->shader_type = shader->type; + material->shader_id = p_shader.get_local_index(); shader->owners.insert(material); if (shader->type == SHADER_TYPE_MAX) { @@ -1568,11 +1590,11 @@ void RasterizerStorageRD::material_set_shader(RID p_material, RID p_shader) { material->data->set_next_pass(material->next_pass); material->data->set_render_priority(material->priority); //updating happens later - material->instance_dependency.instance_notify_changed(false, true); + material->dependency.changed_notify(DEPENDENCY_CHANGED_MATERIAL); _material_queue_update(material, true, true); } -void RasterizerStorageRD::material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) { +void RendererStorageRD::material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) { Material *material = material_owner.getornull(p_material); ERR_FAIL_COND(!material); @@ -1590,7 +1612,7 @@ void RasterizerStorageRD::material_set_param(RID p_material, const StringName &p } } -Variant RasterizerStorageRD::material_get_param(RID p_material, const StringName &p_param) const { +Variant RendererStorageRD::material_get_param(RID p_material, const StringName &p_param) const { Material *material = material_owner.getornull(p_material); ERR_FAIL_COND_V(!material, Variant()); if (material->params.has(p_param)) { @@ -1600,7 +1622,7 @@ Variant RasterizerStorageRD::material_get_param(RID p_material, const StringName } } -void RasterizerStorageRD::material_set_next_pass(RID p_material, RID p_next_material) { +void RendererStorageRD::material_set_next_pass(RID p_material, RID p_next_material) { Material *material = material_owner.getornull(p_material); ERR_FAIL_COND(!material); @@ -1613,10 +1635,10 @@ void RasterizerStorageRD::material_set_next_pass(RID p_material, RID p_next_mate material->data->set_next_pass(p_next_material); } - material->instance_dependency.instance_notify_changed(false, true); + material->dependency.changed_notify(DEPENDENCY_CHANGED_MATERIAL); } -void RasterizerStorageRD::material_set_render_priority(RID p_material, int priority) { +void RendererStorageRD::material_set_render_priority(RID p_material, int priority) { Material *material = material_owner.getornull(p_material); ERR_FAIL_COND(!material); material->priority = priority; @@ -1625,7 +1647,7 @@ void RasterizerStorageRD::material_set_render_priority(RID p_material, int prior } } -bool RasterizerStorageRD::material_is_animated(RID p_material) { +bool RendererStorageRD::material_is_animated(RID p_material) { Material *material = material_owner.getornull(p_material); ERR_FAIL_COND_V(!material, false); if (material->shader && material->shader->data) { @@ -1638,7 +1660,7 @@ bool RasterizerStorageRD::material_is_animated(RID p_material) { return false; //by default nothing is animated } -bool RasterizerStorageRD::material_casts_shadows(RID p_material) { +bool RendererStorageRD::material_casts_shadows(RID p_material) { Material *material = material_owner.getornull(p_material); ERR_FAIL_COND_V(!material, true); if (material->shader && material->shader->data) { @@ -1651,7 +1673,7 @@ bool RasterizerStorageRD::material_casts_shadows(RID p_material) { return true; //by default everything casts shadows } -void RasterizerStorageRD::material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) { +void RendererStorageRD::material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) { Material *material = material_owner.getornull(p_material); ERR_FAIL_COND(!material); if (material->shader && material->shader->data) { @@ -1663,16 +1685,16 @@ void RasterizerStorageRD::material_get_instance_shader_parameters(RID p_material } } -void RasterizerStorageRD::material_update_dependency(RID p_material, RasterizerScene::InstanceBase *p_instance) { +void RendererStorageRD::material_update_dependency(RID p_material, DependencyTracker *p_instance) { Material *material = material_owner.getornull(p_material); ERR_FAIL_COND(!material); - p_instance->update_dependency(&material->instance_dependency); + p_instance->update_dependency(&material->dependency); if (material->next_pass.is_valid()) { material_update_dependency(material->next_pass, p_instance); } } -void RasterizerStorageRD::material_set_data_request_function(ShaderType p_shader_type, MaterialDataRequestFunction p_function) { +void RendererStorageRD::material_set_data_request_function(ShaderType p_shader_type, MaterialDataRequestFunction p_function) { ERR_FAIL_INDEX(p_shader_type, SHADER_TYPE_MAX); material_data_request_func[p_shader_type] = p_function; } @@ -2119,7 +2141,7 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, } } -void RasterizerStorageRD::MaterialData::update_uniform_buffer(const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Map<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color) { +void RendererStorageRD::MaterialData::update_uniform_buffer(const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Map<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color) { bool uses_global_buffer = false; for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = p_uniforms.front(); E; E = E->next()) { @@ -2133,7 +2155,7 @@ void RasterizerStorageRD::MaterialData::update_uniform_buffer(const Map<StringNa if (E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL) { //this is a global variable, get the index to it - RasterizerStorageRD *rs = base_singleton; + RendererStorageRD *rs = base_singleton; GlobalVariables::Variable *gv = rs->global_variables.variables.getptr(E->key()); uint32_t index = 0; @@ -2180,7 +2202,7 @@ void RasterizerStorageRD::MaterialData::update_uniform_buffer(const Map<StringNa } if (uses_global_buffer != (global_buffer_E != nullptr)) { - RasterizerStorageRD *rs = base_singleton; + RendererStorageRD *rs = base_singleton; if (uses_global_buffer) { global_buffer_E = rs->global_variables.materials_using_buffer.push_back(self); } else { @@ -2190,16 +2212,16 @@ void RasterizerStorageRD::MaterialData::update_uniform_buffer(const Map<StringNa } } -RasterizerStorageRD::MaterialData::~MaterialData() { +RendererStorageRD::MaterialData::~MaterialData() { if (global_buffer_E) { //unregister global buffers - RasterizerStorageRD *rs = base_singleton; + RendererStorageRD *rs = base_singleton; rs->global_variables.materials_using_buffer.erase(global_buffer_E); } if (global_texture_E) { //unregister global textures - RasterizerStorageRD *rs = base_singleton; + RendererStorageRD *rs = base_singleton; for (Map<StringName, uint64_t>::Element *E = used_global_textures.front(); E; E = E->next()) { GlobalVariables::Variable *v = rs->global_variables.variables.getptr(E->key()); @@ -2212,11 +2234,11 @@ RasterizerStorageRD::MaterialData::~MaterialData() { } } -void RasterizerStorageRD::MaterialData::update_textures(const Map<StringName, Variant> &p_parameters, const Map<StringName, RID> &p_default_textures, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color) { - RasterizerStorageRD *singleton = (RasterizerStorageRD *)RasterizerStorage::base_singleton; +void RendererStorageRD::MaterialData::update_textures(const Map<StringName, Variant> &p_parameters, const Map<StringName, RID> &p_default_textures, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color) { + RendererStorageRD *singleton = (RendererStorageRD *)RendererStorage::base_singleton; #ifdef TOOLS_ENABLED Texture *roughness_detect_texture = nullptr; - RS::TextureDetectRoughnessChannel roughness_channel = RS::TEXTURE_DETECT_ROUGNHESS_R; + RS::TextureDetectRoughnessChannel roughness_channel = RS::TEXTURE_DETECT_ROUGHNESS_R; Texture *normal_detect_texture = nullptr; #endif @@ -2229,7 +2251,7 @@ void RasterizerStorageRD::MaterialData::update_textures(const Map<StringName, Va RID texture; if (p_texture_uniforms[i].global) { - RasterizerStorageRD *rs = base_singleton; + RendererStorageRD *rs = base_singleton; uses_global_textures = true; @@ -2330,7 +2352,7 @@ void RasterizerStorageRD::MaterialData::update_textures(const Map<StringName, Va { //for textures no longer used, unregister them List<Map<StringName, uint64_t>::Element *> to_delete; - RasterizerStorageRD *rs = base_singleton; + RendererStorageRD *rs = base_singleton; for (Map<StringName, uint64_t>::Element *E = used_global_textures.front(); E; E = E->next()) { if (E->get() != global_textures_pass) { @@ -2359,7 +2381,7 @@ void RasterizerStorageRD::MaterialData::update_textures(const Map<StringName, Va } } -void RasterizerStorageRD::material_force_update_textures(RID p_material, ShaderType p_shader_type) { +void RendererStorageRD::material_force_update_textures(RID p_material, ShaderType p_shader_type) { Material *material = material_owner.getornull(p_material); if (material->shader_type != p_shader_type) { return; @@ -2369,7 +2391,7 @@ void RasterizerStorageRD::material_force_update_textures(RID p_material, ShaderT } } -void RasterizerStorageRD::_update_queued_materials() { +void RendererStorageRD::_update_queued_materials() { Material *material = material_update_list; while (material) { Material *next = material->update_next; @@ -2388,23 +2410,35 @@ void RasterizerStorageRD::_update_queued_materials() { /* MESH API */ -RID RasterizerStorageRD::mesh_create() { - return mesh_owner.make_rid(Mesh()); +RID RendererStorageRD::mesh_allocate() { + return mesh_owner.allocate_rid(); +} +void RendererStorageRD::mesh_initialize(RID p_rid) { + mesh_owner.initialize_rid(p_rid, Mesh()); } -/// Returns stride -void RasterizerStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) { +void RendererStorageRD::mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) { + ERR_FAIL_COND(p_blend_shape_count < 0); + Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND(!mesh); - //ensure blend shape consistency - ERR_FAIL_COND(mesh->blend_shape_count && p_surface.blend_shapes.size() != (int)mesh->blend_shape_count); - ERR_FAIL_COND(mesh->blend_shape_count && p_surface.bone_aabbs.size() != mesh->bone_aabbs.size()); + ERR_FAIL_COND(mesh->surface_count > 0); //surfaces already exist + + mesh->blend_shape_count = p_blend_shape_count; +} + +/// Returns stride +void RendererStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) { + Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND(!mesh); #ifdef DEBUG_ENABLED //do a validation, to catch errors first { uint32_t stride = 0; + uint32_t attrib_stride = 0; + uint32_t skin_stride = 0; for (int i = 0; i < RS::ARRAY_WEIGHTS; i++) { if ((p_surface.format & (1 << i))) { @@ -2418,59 +2452,59 @@ void RasterizerStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_ } break; case RS::ARRAY_NORMAL: { - if (p_surface.format & RS::ARRAY_COMPRESS_NORMAL) { - stride += sizeof(int8_t) * 4; - } else { - stride += sizeof(float) * 4; - } + stride += sizeof(int32_t); } break; case RS::ARRAY_TANGENT: { - if (p_surface.format & RS::ARRAY_COMPRESS_TANGENT) { - stride += sizeof(int8_t) * 4; - } else { - stride += sizeof(float) * 4; - } + stride += sizeof(int32_t); } break; case RS::ARRAY_COLOR: { - if (p_surface.format & RS::ARRAY_COMPRESS_COLOR) { - stride += sizeof(int8_t) * 4; - } else { - stride += sizeof(float) * 4; - } - + attrib_stride += sizeof(int16_t) * 4; } break; case RS::ARRAY_TEX_UV: { - if (p_surface.format & RS::ARRAY_COMPRESS_TEX_UV) { - stride += sizeof(int16_t) * 2; - } else { - stride += sizeof(float) * 2; - } + attrib_stride += sizeof(float) * 2; } break; case RS::ARRAY_TEX_UV2: { - if (p_surface.format & RS::ARRAY_COMPRESS_TEX_UV2) { - stride += sizeof(int16_t) * 2; - } else { - stride += sizeof(float) * 2; - } + attrib_stride += sizeof(float) * 2; } break; - case RS::ARRAY_BONES: { - //assumed weights too - - //unique format, internally 16 bits, exposed as single array for 32 - - stride += sizeof(int32_t) * 4; + case RS::ARRAY_CUSTOM0: + case RS::ARRAY_CUSTOM1: + case RS::ARRAY_CUSTOM2: + case RS::ARRAY_CUSTOM3: { + int idx = i - RS::ARRAY_CUSTOM0; + uint32_t fmt_shift[RS::ARRAY_CUSTOM_COUNT] = { RS::ARRAY_FORMAT_CUSTOM0_SHIFT, RS::ARRAY_FORMAT_CUSTOM1_SHIFT, RS::ARRAY_FORMAT_CUSTOM2_SHIFT, RS::ARRAY_FORMAT_CUSTOM3_SHIFT }; + uint32_t fmt = (p_surface.format >> fmt_shift[idx]) & RS::ARRAY_FORMAT_CUSTOM_MASK; + uint32_t fmtsize[RS::ARRAY_CUSTOM_MAX] = { 4, 4, 4, 8, 4, 8, 12, 16 }; + attrib_stride += fmtsize[fmt]; } break; + case RS::ARRAY_WEIGHTS: + case RS::ARRAY_BONES: { + //uses a separate array + bool use_8 = p_surface.format & RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS; + skin_stride += sizeof(int16_t) * (use_8 ? 16 : 8); + } break; } } } int expected_size = stride * p_surface.vertex_count; - ERR_FAIL_COND_MSG(expected_size != p_surface.vertex_data.size(), "Size of data provided (" + itos(p_surface.vertex_data.size()) + ") does not match expected (" + itos(expected_size) + ")"); + ERR_FAIL_COND_MSG(expected_size != p_surface.vertex_data.size(), "Size of vertex data provided (" + itos(p_surface.vertex_data.size()) + ") does not match expected (" + itos(expected_size) + ")"); + + int bs_expected_size = expected_size * mesh->blend_shape_count; + + ERR_FAIL_COND_MSG(bs_expected_size != p_surface.blend_shape_data.size(), "Size of blend shape data provided (" + itos(p_surface.blend_shape_data.size()) + ") does not match expected (" + itos(bs_expected_size) + ")"); + + int expected_attrib_size = attrib_stride * p_surface.vertex_count; + ERR_FAIL_COND_MSG(expected_attrib_size != p_surface.attribute_data.size(), "Size of attribute data provided (" + itos(p_surface.attribute_data.size()) + ") does not match expected (" + itos(expected_attrib_size) + ")"); + + if ((p_surface.format & RS::ARRAY_FORMAT_WEIGHTS) && (p_surface.format & RS::ARRAY_FORMAT_BONES)) { + expected_size = skin_stride * p_surface.vertex_count; + ERR_FAIL_COND_MSG(expected_size != p_surface.skin_data.size(), "Size of skin data provided (" + itos(p_surface.skin_data.size()) + ") does not match expected (" + itos(expected_size) + ")"); + } } #endif @@ -2480,9 +2514,25 @@ void RasterizerStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_ s->format = p_surface.format; s->primitive = p_surface.primitive; - s->vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.vertex_data.size(), p_surface.vertex_data); + bool use_as_storage = (p_surface.skin_data.size() || mesh->blend_shape_count > 0); + + s->vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.vertex_data.size(), p_surface.vertex_data, use_as_storage); + s->vertex_buffer_size = p_surface.vertex_data.size(); + + if (p_surface.attribute_data.size()) { + s->attribute_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.attribute_data.size(), p_surface.attribute_data); + } + if (p_surface.skin_data.size()) { + s->skin_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.skin_data.size(), p_surface.skin_data, use_as_storage); + s->skin_buffer_size = p_surface.skin_data.size(); + } + s->vertex_count = p_surface.vertex_count; + if (p_surface.format & RS::ARRAY_FORMAT_BONES) { + mesh->has_bone_weights = true; + } + if (p_surface.index_count) { bool is_index_16 = p_surface.vertex_count <= 65536; @@ -2505,21 +2555,54 @@ void RasterizerStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_ s->aabb = p_surface.aabb; s->bone_aabbs = p_surface.bone_aabbs; //only really useful for returning them. - for (int i = 0; i < p_surface.blend_shapes.size(); i++) { - if (p_surface.blend_shapes[i].size() != p_surface.vertex_data.size()) { - memdelete(s); - ERR_FAIL_COND(p_surface.blend_shapes[i].size() != p_surface.vertex_data.size()); - } - RID vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.blend_shapes[i].size(), p_surface.blend_shapes[i]); - s->blend_shapes.push_back(vertex_buffer); + if (mesh->blend_shape_count > 0) { + s->blend_shape_buffer = RD::get_singleton()->storage_buffer_create(p_surface.blend_shape_data.size(), p_surface.blend_shape_data); } - mesh->blend_shape_count = p_surface.blend_shapes.size(); + if (use_as_storage) { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.binding = 0; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(s->vertex_buffer); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 1; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + if (s->skin_buffer.is_valid()) { + u.ids.push_back(s->skin_buffer); + } else { + u.ids.push_back(default_rd_storage_buffer); + } + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 2; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + if (s->blend_shape_buffer.is_valid()) { + u.ids.push_back(s->blend_shape_buffer); + } else { + u.ids.push_back(default_rd_storage_buffer); + } + uniforms.push_back(u); + } + + s->uniform_set = RD::get_singleton()->uniform_set_create(uniforms, skeleton_shader.version_shader[0], SkeletonShader::UNIFORM_SET_SURFACE); + } if (mesh->surface_count == 0) { mesh->bone_aabbs = p_surface.bone_aabbs; mesh->aabb = p_surface.aabb; } else { + if (mesh->bone_aabbs.size() < p_surface.bone_aabbs.size()) { + // ArrayMesh::_surface_set_data only allocates bone_aabbs up to max_bone + // Each surface may affect different numbers of bones. + mesh->bone_aabbs.resize(p_surface.bone_aabbs.size()); + } for (int i = 0; i < p_surface.bone_aabbs.size(); i++) { mesh->bone_aabbs.write[i].merge_with(p_surface.bone_aabbs[i]); } @@ -2532,18 +2615,30 @@ void RasterizerStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_ mesh->surfaces[mesh->surface_count] = s; mesh->surface_count++; - mesh->instance_dependency.instance_notify_changed(true, true); + for (List<MeshInstance *>::Element *E = mesh->instances.front(); E; E = E->next()) { + //update instances + MeshInstance *mi = E->get(); + _mesh_instance_add_surface(mi, mesh, mesh->surface_count - 1); + } + + mesh->dependency.changed_notify(DEPENDENCY_CHANGED_MESH); + + for (Set<Mesh *>::Element *E = mesh->shadow_owners.front(); E; E = E->next()) { + Mesh *shadow_owner = E->get(); + shadow_owner->shadow_mesh = RID(); + shadow_owner->dependency.changed_notify(DEPENDENCY_CHANGED_MESH); + } mesh->material_cache.clear(); } -int RasterizerStorageRD::mesh_get_blend_shape_count(RID p_mesh) const { +int RendererStorageRD::mesh_get_blend_shape_count(RID p_mesh) const { const Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!mesh, -1); return mesh->blend_shape_count; } -void RasterizerStorageRD::mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) { +void RendererStorageRD::mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) { Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND(!mesh); ERR_FAIL_INDEX((int)p_mode, 2); @@ -2551,13 +2646,13 @@ void RasterizerStorageRD::mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMo mesh->blend_shape_mode = p_mode; } -RS::BlendShapeMode RasterizerStorageRD::mesh_get_blend_shape_mode(RID p_mesh) const { +RS::BlendShapeMode RendererStorageRD::mesh_get_blend_shape_mode(RID p_mesh) const { Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!mesh, RS::BLEND_SHAPE_MODE_NORMALIZED); return mesh->blend_shape_mode; } -void RasterizerStorageRD::mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) { +void RendererStorageRD::mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) { Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND(!mesh); ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count); @@ -2568,17 +2663,17 @@ void RasterizerStorageRD::mesh_surface_update_region(RID p_mesh, int p_surface, RD::get_singleton()->buffer_update(mesh->surfaces[p_surface]->vertex_buffer, p_offset, data_size, r); } -void RasterizerStorageRD::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) { +void RendererStorageRD::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) { Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND(!mesh); ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count); mesh->surfaces[p_surface]->material = p_material; - mesh->instance_dependency.instance_notify_changed(false, true); + mesh->dependency.changed_notify(DEPENDENCY_CHANGED_MATERIAL); mesh->material_cache.clear(); } -RID RasterizerStorageRD::mesh_surface_get_material(RID p_mesh, int p_surface) const { +RID RendererStorageRD::mesh_surface_get_material(RID p_mesh, int p_surface) const { Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!mesh, RID()); ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_surface, mesh->surface_count, RID()); @@ -2586,7 +2681,7 @@ RID RasterizerStorageRD::mesh_surface_get_material(RID p_mesh, int p_surface) co return mesh->surfaces[p_surface]->material; } -RS::SurfaceData RasterizerStorageRD::mesh_get_surface(RID p_mesh, int p_surface) const { +RS::SurfaceData RendererStorageRD::mesh_get_surface(RID p_mesh, int p_surface) const { Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!mesh, RS::SurfaceData()); ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_surface, mesh->surface_count, RS::SurfaceData()); @@ -2596,6 +2691,12 @@ RS::SurfaceData RasterizerStorageRD::mesh_get_surface(RID p_mesh, int p_surface) RS::SurfaceData sd; sd.format = s.format; sd.vertex_data = RD::get_singleton()->buffer_get_data(s.vertex_buffer); + if (s.attribute_buffer.is_valid()) { + sd.attribute_data = RD::get_singleton()->buffer_get_data(s.attribute_buffer); + } + if (s.skin_buffer.is_valid()) { + sd.skin_data = RD::get_singleton()->buffer_get_data(s.skin_buffer); + } sd.vertex_count = s.vertex_count; sd.index_count = s.index_count; sd.primitive = s.primitive; @@ -2613,33 +2714,32 @@ RS::SurfaceData RasterizerStorageRD::mesh_get_surface(RID p_mesh, int p_surface) sd.bone_aabbs = s.bone_aabbs; - for (int i = 0; i < s.blend_shapes.size(); i++) { - Vector<uint8_t> bs = RD::get_singleton()->buffer_get_data(s.blend_shapes[i]); - sd.blend_shapes.push_back(bs); + if (s.blend_shape_buffer.is_valid()) { + sd.blend_shape_data = RD::get_singleton()->buffer_get_data(s.blend_shape_buffer); } return sd; } -int RasterizerStorageRD::mesh_get_surface_count(RID p_mesh) const { +int RendererStorageRD::mesh_get_surface_count(RID p_mesh) const { Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!mesh, 0); return mesh->surface_count; } -void RasterizerStorageRD::mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) { +void RendererStorageRD::mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) { Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND(!mesh); mesh->custom_aabb = p_aabb; } -AABB RasterizerStorageRD::mesh_get_custom_aabb(RID p_mesh) const { +AABB RendererStorageRD::mesh_get_custom_aabb(RID p_mesh) const { Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!mesh, AABB()); return mesh->custom_aabb; } -AABB RasterizerStorageRD::mesh_get_aabb(RID p_mesh, RID p_skeleton) { +AABB RendererStorageRD::mesh_get_aabb(RID p_mesh, RID p_skeleton) { Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!mesh, AABB()); @@ -2744,12 +2844,37 @@ AABB RasterizerStorageRD::mesh_get_aabb(RID p_mesh, RID p_skeleton) { return aabb; } -void RasterizerStorageRD::mesh_clear(RID p_mesh) { +void RendererStorageRD::mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) { + Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND(!mesh); + + Mesh *shadow_mesh = mesh_owner.getornull(mesh->shadow_mesh); + if (shadow_mesh) { + shadow_mesh->shadow_owners.erase(mesh); + } + mesh->shadow_mesh = p_shadow_mesh; + + shadow_mesh = mesh_owner.getornull(mesh->shadow_mesh); + + if (shadow_mesh) { + shadow_mesh->shadow_owners.insert(mesh); + } + + mesh->dependency.changed_notify(DEPENDENCY_CHANGED_MESH); +} + +void RendererStorageRD::mesh_clear(RID p_mesh) { Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND(!mesh); for (uint32_t i = 0; i < mesh->surface_count; i++) { Mesh::Surface &s = *mesh->surfaces[i]; RD::get_singleton()->free(s.vertex_buffer); //clears arrays as dependency automatically, including all versions + if (s.attribute_buffer.is_valid()) { + RD::get_singleton()->free(s.attribute_buffer); + } + if (s.skin_buffer.is_valid()) { + RD::get_singleton()->free(s.skin_buffer); + } if (s.versions) { memfree(s.versions); //reallocs, so free with memfree. } @@ -2765,12 +2890,8 @@ void RasterizerStorageRD::mesh_clear(RID p_mesh) { memdelete_arr(s.lods); } - for (int32_t j = 0; j < s.blend_shapes.size(); j++) { - RD::get_singleton()->free(s.blend_shapes[j]); - } - - if (s.blend_shape_base_buffer.is_valid()) { - RD::get_singleton()->free(s.blend_shape_base_buffer); + if (s.blend_shape_buffer.is_valid()) { + RD::get_singleton()->free(s.blend_shape_buffer); } memdelete(mesh->surfaces[i]); @@ -2782,22 +2903,237 @@ void RasterizerStorageRD::mesh_clear(RID p_mesh) { mesh->surfaces = nullptr; mesh->surface_count = 0; mesh->material_cache.clear(); - mesh->instance_dependency.instance_notify_changed(true, true); + //clear instance data + for (List<MeshInstance *>::Element *E = mesh->instances.front(); E; E = E->next()) { + MeshInstance *mi = E->get(); + _mesh_instance_clear(mi); + } + mesh->has_bone_weights = false; + mesh->dependency.changed_notify(DEPENDENCY_CHANGED_MESH); + + for (Set<Mesh *>::Element *E = mesh->shadow_owners.front(); E; E = E->next()) { + Mesh *shadow_owner = E->get(); + shadow_owner->shadow_mesh = RID(); + shadow_owner->dependency.changed_notify(DEPENDENCY_CHANGED_MESH); + } +} + +bool RendererStorageRD::mesh_needs_instance(RID p_mesh, bool p_has_skeleton) { + Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND_V(!mesh, false); + + return mesh->blend_shape_count > 0 || (mesh->has_bone_weights && p_has_skeleton); +} + +/* MESH INSTANCE */ + +RID RendererStorageRD::mesh_instance_create(RID p_base) { + Mesh *mesh = mesh_owner.getornull(p_base); + ERR_FAIL_COND_V(!mesh, RID()); + + MeshInstance *mi = memnew(MeshInstance); + + mi->mesh = mesh; + + for (uint32_t i = 0; i < mesh->surface_count; i++) { + _mesh_instance_add_surface(mi, mesh, i); + } + + mi->I = mesh->instances.push_back(mi); + + mi->dirty = true; + + return mesh_instance_owner.make_rid(mi); +} +void RendererStorageRD::mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) { + MeshInstance *mi = mesh_instance_owner.getornull(p_mesh_instance); + if (mi->skeleton == p_skeleton) { + return; + } + mi->skeleton = p_skeleton; + mi->skeleton_version = 0; + mi->dirty = true; +} + +void RendererStorageRD::mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) { + MeshInstance *mi = mesh_instance_owner.getornull(p_mesh_instance); + ERR_FAIL_COND(!mi); + ERR_FAIL_INDEX(p_shape, (int)mi->blend_weights.size()); + mi->blend_weights[p_shape] = p_weight; + mi->weights_dirty = true; + //will be eventually updated +} + +void RendererStorageRD::_mesh_instance_clear(MeshInstance *mi) { + for (uint32_t i = 0; i < mi->surfaces.size(); i++) { + if (mi->surfaces[i].vertex_buffer.is_valid()) { + RD::get_singleton()->free(mi->surfaces[i].vertex_buffer); + } + if (mi->surfaces[i].versions) { + for (uint32_t j = 0; j < mi->surfaces[i].version_count; j++) { + RD::get_singleton()->free(mi->surfaces[i].versions[j].vertex_array); + } + memfree(mi->surfaces[i].versions); + } + } + mi->surfaces.clear(); + + if (mi->blend_weights_buffer.is_valid()) { + RD::get_singleton()->free(mi->blend_weights_buffer); + } + mi->blend_weights.clear(); + mi->weights_dirty = false; + mi->skeleton_version = 0; +} + +void RendererStorageRD::_mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface) { + if (mesh->blend_shape_count > 0 && mi->blend_weights_buffer.is_null()) { + mi->blend_weights.resize(mesh->blend_shape_count); + for (uint32_t i = 0; i < mi->blend_weights.size(); i++) { + mi->blend_weights[i] = 0; + } + mi->blend_weights_buffer = RD::get_singleton()->storage_buffer_create(sizeof(float) * mi->blend_weights.size(), mi->blend_weights.to_byte_array()); + mi->weights_dirty = true; + } + + MeshInstance::Surface s; + if (mesh->blend_shape_count > 0 || (mesh->surfaces[p_surface]->format & RS::ARRAY_FORMAT_BONES)) { + //surface warrants transform + s.vertex_buffer = RD::get_singleton()->vertex_buffer_create(mesh->surfaces[p_surface]->vertex_buffer_size, Vector<uint8_t>(), true); + + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.binding = 1; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(s.vertex_buffer); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 2; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + if (mi->blend_weights_buffer.is_valid()) { + u.ids.push_back(mi->blend_weights_buffer); + } else { + u.ids.push_back(default_rd_storage_buffer); + } + uniforms.push_back(u); + } + s.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, skeleton_shader.version_shader[0], SkeletonShader::UNIFORM_SET_INSTANCE); + } + + mi->surfaces.push_back(s); + mi->dirty = true; +} + +void RendererStorageRD::mesh_instance_check_for_update(RID p_mesh_instance) { + MeshInstance *mi = mesh_instance_owner.getornull(p_mesh_instance); + + bool needs_update = mi->dirty; + + if (mi->weights_dirty && !mi->weight_update_list.in_list()) { + dirty_mesh_instance_weights.add(&mi->weight_update_list); + needs_update = true; + } + + if (mi->array_update_list.in_list()) { + return; + } + + if (!needs_update && mi->skeleton.is_valid()) { + Skeleton *sk = skeleton_owner.getornull(mi->skeleton); + if (sk && sk->version != mi->skeleton_version) { + needs_update = true; + } + } + + if (needs_update) { + dirty_mesh_instance_arrays.add(&mi->array_update_list); + } } -void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Surface *s, uint32_t p_input_mask) { - uint32_t version = s->version_count; - s->version_count++; - s->versions = (Mesh::Surface::Version *)memrealloc(s->versions, sizeof(Mesh::Surface::Version) * s->version_count); +void RendererStorageRD::update_mesh_instances() { + while (dirty_mesh_instance_weights.first()) { + MeshInstance *mi = dirty_mesh_instance_weights.first()->self(); + + if (mi->blend_weights_buffer.is_valid()) { + RD::get_singleton()->buffer_update(mi->blend_weights_buffer, 0, mi->blend_weights.size() * sizeof(float), mi->blend_weights.ptr()); + } + dirty_mesh_instance_weights.remove(&mi->weight_update_list); + mi->weights_dirty = false; + } + if (dirty_mesh_instance_arrays.first() == nullptr) { + return; //nothing to do + } + + //process skeletons and blend shapes + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + + while (dirty_mesh_instance_arrays.first()) { + MeshInstance *mi = dirty_mesh_instance_arrays.first()->self(); + + Skeleton *sk = skeleton_owner.getornull(mi->skeleton); + + for (uint32_t i = 0; i < mi->surfaces.size(); i++) { + if (mi->surfaces[i].uniform_set == RID() || mi->mesh->surfaces[i]->uniform_set == RID()) { + continue; + } + + bool array_is_2d = mi->mesh->surfaces[i]->format & RS::ARRAY_FLAG_USE_2D_VERTICES; + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, skeleton_shader.pipeline[array_is_2d ? SkeletonShader::SHADER_MODE_2D : SkeletonShader::SHADER_MODE_3D]); + + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, mi->surfaces[i].uniform_set, SkeletonShader::UNIFORM_SET_INSTANCE); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, mi->mesh->surfaces[i]->uniform_set, SkeletonShader::UNIFORM_SET_SURFACE); + if (sk && sk->uniform_set_mi.is_valid()) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sk->uniform_set_mi, SkeletonShader::UNIFORM_SET_SKELETON); + } else { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, skeleton_shader.default_skeleton_uniform_set, SkeletonShader::UNIFORM_SET_SKELETON); + } + + SkeletonShader::PushConstant push_constant; + + push_constant.has_normal = mi->mesh->surfaces[i]->format & RS::ARRAY_FORMAT_NORMAL; + push_constant.has_tangent = mi->mesh->surfaces[i]->format & RS::ARRAY_FORMAT_TANGENT; + push_constant.has_skeleton = sk != nullptr && sk->use_2d == array_is_2d && (mi->mesh->surfaces[i]->format & RS::ARRAY_FORMAT_BONES); + push_constant.has_blend_shape = mi->mesh->blend_shape_count > 0; - Mesh::Surface::Version &v = s->versions[version]; + push_constant.vertex_count = mi->mesh->surfaces[i]->vertex_count; + push_constant.vertex_stride = (mi->mesh->surfaces[i]->vertex_buffer_size / mi->mesh->surfaces[i]->vertex_count) / 4; + push_constant.skin_stride = (mi->mesh->surfaces[i]->skin_buffer_size / mi->mesh->surfaces[i]->vertex_count) / 4; + push_constant.skin_weight_offset = (mi->mesh->surfaces[i]->format & RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 4 : 2; + push_constant.blend_shape_count = mi->mesh->blend_shape_count; + push_constant.normalized_blend_shapes = mi->mesh->blend_shape_mode == RS::BLEND_SHAPE_MODE_NORMALIZED; + push_constant.pad0 = 0; + push_constant.pad1 = 0; + + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SkeletonShader::PushConstant)); + + //dispatch without barrier, so all is done at the same time + RD::get_singleton()->compute_list_dispatch_threads(compute_list, push_constant.vertex_count, 1, 1); + } + + mi->dirty = false; + if (sk) { + mi->skeleton_version = sk->version; + } + dirty_mesh_instance_arrays.remove(&mi->array_update_list); + } + + RD::get_singleton()->compute_list_end(); +} + +void RendererStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, MeshInstance::Surface *mis) { Vector<RD::VertexAttribute> attributes; Vector<RID> buffers; uint32_t stride = 0; + uint32_t attribute_stride = 0; + uint32_t skin_stride = 0; - for (int i = 0; i < RS::ARRAY_WEIGHTS; i++) { + for (int i = 0; i < RS::ARRAY_INDEX; i++) { RD::VertexAttribute vd; RID buffer; vd.location = i; @@ -2805,6 +3141,7 @@ void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Su if (!(s->format & (1 << i))) { // Not supplied by surface, use default value buffer = mesh_default_rd_buffers[i]; + vd.stride = 0; switch (i) { case RS::ARRAY_VERTEX: { vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT; @@ -2827,20 +3164,31 @@ void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Su case RS::ARRAY_TEX_UV2: { vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; } break; + case RS::ARRAY_CUSTOM0: + case RS::ARRAY_CUSTOM1: + case RS::ARRAY_CUSTOM2: + case RS::ARRAY_CUSTOM3: { + //assumed weights too + vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; + } break; case RS::ARRAY_BONES: { //assumed weights too vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT; } break; + case RS::ARRAY_WEIGHTS: { + //assumed weights too + vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT; + } break; } } else { //Supplied, use it - vd.offset = stride; - vd.stride = 1; //mark that it needs a stride set - buffer = s->vertex_buffer; + vd.stride = 1; //mark that it needs a stride set (default uses 0) switch (i) { case RS::ARRAY_VERTEX: { + vd.offset = stride; + if (s->format & RS::ARRAY_FLAG_USE_2D_VERTICES) { vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; stride += sizeof(float) * 2; @@ -2849,71 +3197,92 @@ void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Su stride += sizeof(float) * 3; } + if (mis) { + buffer = mis->vertex_buffer; + } else { + buffer = s->vertex_buffer; + } + } break; case RS::ARRAY_NORMAL: { - if (s->format & RS::ARRAY_COMPRESS_NORMAL) { - vd.format = RD::DATA_FORMAT_R8G8B8A8_SNORM; - stride += sizeof(int8_t) * 4; + vd.offset = stride; + + vd.format = RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32; + + stride += sizeof(uint32_t); + if (mis) { + buffer = mis->vertex_buffer; } else { - vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; - stride += sizeof(float) * 4; + buffer = s->vertex_buffer; } - } break; case RS::ARRAY_TANGENT: { - if (s->format & RS::ARRAY_COMPRESS_TANGENT) { - vd.format = RD::DATA_FORMAT_R8G8B8A8_SNORM; - stride += sizeof(int8_t) * 4; + vd.offset = stride; + + vd.format = RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32; + stride += sizeof(uint32_t); + if (mis) { + buffer = mis->vertex_buffer; } else { - vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; - stride += sizeof(float) * 4; + buffer = s->vertex_buffer; } - } break; case RS::ARRAY_COLOR: { - if (s->format & RS::ARRAY_COMPRESS_COLOR) { - vd.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; - stride += sizeof(int8_t) * 4; - } else { - vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; - stride += sizeof(float) * 4; - } + vd.offset = attribute_stride; + vd.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + attribute_stride += sizeof(int16_t) * 4; + buffer = s->attribute_buffer; } break; case RS::ARRAY_TEX_UV: { - if (s->format & RS::ARRAY_COMPRESS_TEX_UV) { - vd.format = RD::DATA_FORMAT_R16G16_SFLOAT; - stride += sizeof(int16_t) * 2; - } else { - vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; - stride += sizeof(float) * 2; - } + vd.offset = attribute_stride; + + vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; + attribute_stride += sizeof(float) * 2; + buffer = s->attribute_buffer; } break; case RS::ARRAY_TEX_UV2: { - if (s->format & RS::ARRAY_COMPRESS_TEX_UV2) { - vd.format = RD::DATA_FORMAT_R16G16_SFLOAT; - stride += sizeof(int16_t) * 2; - } else { - vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; - stride += sizeof(float) * 2; - } + vd.offset = attribute_stride; + vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; + attribute_stride += sizeof(float) * 2; + buffer = s->attribute_buffer; + } break; + case RS::ARRAY_CUSTOM0: + case RS::ARRAY_CUSTOM1: + case RS::ARRAY_CUSTOM2: + case RS::ARRAY_CUSTOM3: { + vd.offset = attribute_stride; + + int idx = i - RS::ARRAY_CUSTOM0; + uint32_t fmt_shift[RS::ARRAY_CUSTOM_COUNT] = { RS::ARRAY_FORMAT_CUSTOM0_SHIFT, RS::ARRAY_FORMAT_CUSTOM1_SHIFT, RS::ARRAY_FORMAT_CUSTOM2_SHIFT, RS::ARRAY_FORMAT_CUSTOM3_SHIFT }; + uint32_t fmt = (s->format >> fmt_shift[idx]) & RS::ARRAY_FORMAT_CUSTOM_MASK; + uint32_t fmtsize[RS::ARRAY_CUSTOM_MAX] = { 4, 4, 4, 8, 4, 8, 12, 16 }; + RD::DataFormat fmtrd[RS::ARRAY_CUSTOM_MAX] = { RD::DATA_FORMAT_R8G8B8A8_UNORM, RD::DATA_FORMAT_R8G8B8A8_SNORM, RD::DATA_FORMAT_R16G16_SFLOAT, RD::DATA_FORMAT_R16G16B16A16_SFLOAT, RD::DATA_FORMAT_R32_SFLOAT, RD::DATA_FORMAT_R32G32_SFLOAT, RD::DATA_FORMAT_R32G32B32_SFLOAT, RD::DATA_FORMAT_R32G32B32A32_SFLOAT }; + vd.format = fmtrd[fmt]; + attribute_stride += fmtsize[fmt]; + buffer = s->attribute_buffer; } break; case RS::ARRAY_BONES: { - //assumed weights too - - //unique format, internally 16 bits, exposed as single array for 32 + vd.offset = skin_stride; - vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT; - stride += sizeof(int32_t) * 4; + vd.format = RD::DATA_FORMAT_R16G16B16A16_UINT; + skin_stride += sizeof(int16_t) * 4; + buffer = s->skin_buffer; + } break; + case RS::ARRAY_WEIGHTS: { + vd.offset = skin_stride; + vd.format = RD::DATA_FORMAT_R16G16B16A16_UNORM; + skin_stride += sizeof(int16_t) * 4; + buffer = s->skin_buffer; } break; } } if (!(p_input_mask & (1 << i))) { - continue; // Shader does not need this, skip it + continue; // Shader does not need this, skip it (but computing stride was important anyway) } attributes.push_back(vd); @@ -2922,8 +3291,17 @@ void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Su //update final stride for (int i = 0; i < attributes.size(); i++) { - if (attributes[i].stride == 1) { + if (attributes[i].stride == 0) { + continue; //default location + } + int loc = attributes[i].location; + + if (loc < RS::ARRAY_COLOR) { attributes.write[i].stride = stride; + } else if (loc < RS::ARRAY_BONES) { + attributes.write[i].stride = attribute_stride; + } else { + attributes.write[i].stride = skin_stride; } } @@ -2934,11 +3312,14 @@ void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Su ////////////////// MULTIMESH -RID RasterizerStorageRD::multimesh_create() { - return multimesh_owner.make_rid(MultiMesh()); +RID RendererStorageRD::multimesh_allocate() { + return multimesh_owner.allocate_rid(); +} +void RendererStorageRD::multimesh_initialize(RID p_rid) { + multimesh_owner.initialize_rid(p_rid, MultiMesh()); } -void RasterizerStorageRD::multimesh_allocate(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors, bool p_use_custom_data) { +void RendererStorageRD::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors, bool p_use_custom_data) { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND(!multimesh); @@ -2976,15 +3357,17 @@ void RasterizerStorageRD::multimesh_allocate(RID p_multimesh, int p_instances, R if (multimesh->instances) { multimesh->buffer = RD::get_singleton()->storage_buffer_create(multimesh->instances * multimesh->stride_cache * 4); } + + multimesh->dependency.changed_notify(DEPENDENCY_CHANGED_MULTIMESH); } -int RasterizerStorageRD::multimesh_get_instance_count(RID p_multimesh) const { +int RendererStorageRD::multimesh_get_instance_count(RID p_multimesh) const { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND_V(!multimesh, 0); return multimesh->instances; } -void RasterizerStorageRD::multimesh_set_mesh(RID p_multimesh, RID p_mesh) { +void RendererStorageRD::multimesh_set_mesh(RID p_multimesh, RID p_mesh) { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND(!multimesh); if (multimesh->mesh == p_mesh) { @@ -3009,12 +3392,12 @@ void RasterizerStorageRD::multimesh_set_mesh(RID p_multimesh, RID p_mesh) { } } - multimesh->instance_dependency.instance_notify_changed(true, true); + multimesh->dependency.changed_notify(DEPENDENCY_CHANGED_MESH); } #define MULTIMESH_DIRTY_REGION_SIZE 512 -void RasterizerStorageRD::_multimesh_make_local(MultiMesh *multimesh) const { +void RendererStorageRD::_multimesh_make_local(MultiMesh *multimesh) const { if (multimesh->data_cache.size() > 0) { return; //already local } @@ -3043,7 +3426,7 @@ void RasterizerStorageRD::_multimesh_make_local(MultiMesh *multimesh) const { multimesh->data_cache_used_dirty_regions = 0; } -void RasterizerStorageRD::_multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool p_aabb) { +void RendererStorageRD::_multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool p_aabb) { uint32_t region_index = p_index / MULTIMESH_DIRTY_REGION_SIZE; #ifdef DEBUG_ENABLED uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; @@ -3065,7 +3448,7 @@ void RasterizerStorageRD::_multimesh_mark_dirty(MultiMesh *multimesh, int p_inde } } -void RasterizerStorageRD::_multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, bool p_aabb) { +void RendererStorageRD::_multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, bool p_aabb) { if (p_data) { uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; @@ -3088,7 +3471,7 @@ void RasterizerStorageRD::_multimesh_mark_all_dirty(MultiMesh *multimesh, bool p } } -void RasterizerStorageRD::_multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances) { +void RendererStorageRD::_multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances) { ERR_FAIL_COND(multimesh->mesh.is_null()); AABB aabb; AABB mesh_aabb = mesh_get_aabb(multimesh->mesh); @@ -3130,7 +3513,7 @@ void RasterizerStorageRD::_multimesh_re_create_aabb(MultiMesh *multimesh, const multimesh->aabb = aabb; } -void RasterizerStorageRD::multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) { +void RendererStorageRD::multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND(!multimesh); ERR_FAIL_INDEX(p_index, multimesh->instances); @@ -3160,7 +3543,7 @@ void RasterizerStorageRD::multimesh_instance_set_transform(RID p_multimesh, int _multimesh_mark_dirty(multimesh, p_index, true); } -void RasterizerStorageRD::multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) { +void RendererStorageRD::multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND(!multimesh); ERR_FAIL_INDEX(p_index, multimesh->instances); @@ -3186,7 +3569,7 @@ void RasterizerStorageRD::multimesh_instance_set_transform_2d(RID p_multimesh, i _multimesh_mark_dirty(multimesh, p_index, true); } -void RasterizerStorageRD::multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) { +void RendererStorageRD::multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND(!multimesh); ERR_FAIL_INDEX(p_index, multimesh->instances); @@ -3208,7 +3591,7 @@ void RasterizerStorageRD::multimesh_instance_set_color(RID p_multimesh, int p_in _multimesh_mark_dirty(multimesh, p_index, false); } -void RasterizerStorageRD::multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) { +void RendererStorageRD::multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND(!multimesh); ERR_FAIL_INDEX(p_index, multimesh->instances); @@ -3230,14 +3613,14 @@ void RasterizerStorageRD::multimesh_instance_set_custom_data(RID p_multimesh, in _multimesh_mark_dirty(multimesh, p_index, false); } -RID RasterizerStorageRD::multimesh_get_mesh(RID p_multimesh) const { +RID RendererStorageRD::multimesh_get_mesh(RID p_multimesh) const { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND_V(!multimesh, RID()); return multimesh->mesh; } -Transform RasterizerStorageRD::multimesh_instance_get_transform(RID p_multimesh, int p_index) const { +Transform RendererStorageRD::multimesh_instance_get_transform(RID p_multimesh, int p_index) const { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND_V(!multimesh, Transform()); ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform()); @@ -3268,7 +3651,7 @@ Transform RasterizerStorageRD::multimesh_instance_get_transform(RID p_multimesh, return t; } -Transform2D RasterizerStorageRD::multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const { +Transform2D RendererStorageRD::multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND_V(!multimesh, Transform2D()); ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform2D()); @@ -3293,7 +3676,7 @@ Transform2D RasterizerStorageRD::multimesh_instance_get_transform_2d(RID p_multi return t; } -Color RasterizerStorageRD::multimesh_instance_get_color(RID p_multimesh, int p_index) const { +Color RendererStorageRD::multimesh_instance_get_color(RID p_multimesh, int p_index) const { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND_V(!multimesh, Color()); ERR_FAIL_INDEX_V(p_index, multimesh->instances, Color()); @@ -3316,7 +3699,7 @@ Color RasterizerStorageRD::multimesh_instance_get_color(RID p_multimesh, int p_i return c; } -Color RasterizerStorageRD::multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const { +Color RendererStorageRD::multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND_V(!multimesh, Color()); ERR_FAIL_INDEX_V(p_index, multimesh->instances, Color()); @@ -3339,14 +3722,14 @@ Color RasterizerStorageRD::multimesh_instance_get_custom_data(RID p_multimesh, i return c; } -void RasterizerStorageRD::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) { +void RendererStorageRD::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND(!multimesh); ERR_FAIL_COND(p_buffer.size() != (multimesh->instances * (int)multimesh->stride_cache)); { const float *r = p_buffer.ptr(); - RD::get_singleton()->buffer_update(multimesh->buffer, 0, p_buffer.size() * sizeof(float), r, false); + RD::get_singleton()->buffer_update(multimesh->buffer, 0, p_buffer.size() * sizeof(float), r); multimesh->buffer_set = true; } @@ -3368,11 +3751,11 @@ void RasterizerStorageRD::multimesh_set_buffer(RID p_multimesh, const Vector<flo const float *data = p_buffer.ptr(); _multimesh_re_create_aabb(multimesh, data, multimesh->instances); - multimesh->instance_dependency.instance_notify_changed(true, false); + multimesh->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } } -Vector<float> RasterizerStorageRD::multimesh_get_buffer(RID p_multimesh) const { +Vector<float> RendererStorageRD::multimesh_get_buffer(RID p_multimesh) const { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND_V(!multimesh, Vector<float>()); if (multimesh->buffer.is_null()) { @@ -3395,7 +3778,7 @@ Vector<float> RasterizerStorageRD::multimesh_get_buffer(RID p_multimesh) const { } } -void RasterizerStorageRD::multimesh_set_visible_instances(RID p_multimesh, int p_visible) { +void RendererStorageRD::multimesh_set_visible_instances(RID p_multimesh, int p_visible) { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND(!multimesh); ERR_FAIL_COND(p_visible < -1 || p_visible > multimesh->instances); @@ -3409,24 +3792,26 @@ void RasterizerStorageRD::multimesh_set_visible_instances(RID p_multimesh, int p } multimesh->visible_instances = p_visible; + + multimesh->dependency.changed_notify(DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES); } -int RasterizerStorageRD::multimesh_get_visible_instances(RID p_multimesh) const { +int RendererStorageRD::multimesh_get_visible_instances(RID p_multimesh) const { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND_V(!multimesh, 0); return multimesh->visible_instances; } -AABB RasterizerStorageRD::multimesh_get_aabb(RID p_multimesh) const { +AABB RendererStorageRD::multimesh_get_aabb(RID p_multimesh) const { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND_V(!multimesh, AABB()); if (multimesh->aabb_dirty) { - const_cast<RasterizerStorageRD *>(this)->_update_dirty_multimeshes(); + const_cast<RendererStorageRD *>(this)->_update_dirty_multimeshes(); } return multimesh->aabb; } -void RasterizerStorageRD::_update_dirty_multimeshes() { +void RendererStorageRD::_update_dirty_multimeshes() { while (multimesh_dirty_list) { MultiMesh *multimesh = multimesh_dirty_list; @@ -3443,14 +3828,14 @@ void RasterizerStorageRD::_update_dirty_multimeshes() { if (multimesh->data_cache_used_dirty_regions > 32 || multimesh->data_cache_used_dirty_regions > visible_region_count / 2) { //if there too many dirty regions, or represent the majority of regions, just copy all, else transfer cost piles up too much - RD::get_singleton()->buffer_update(multimesh->buffer, 0, MIN(visible_region_count * region_size, multimesh->instances * multimesh->stride_cache * sizeof(float)), data, false); + RD::get_singleton()->buffer_update(multimesh->buffer, 0, MIN(visible_region_count * region_size, multimesh->instances * multimesh->stride_cache * sizeof(float)), data); } else { //not that many regions? update them all for (uint32_t i = 0; i < visible_region_count; i++) { if (multimesh->data_cache_dirty_regions[i]) { uint64_t offset = i * region_size; uint64_t size = multimesh->stride_cache * multimesh->instances * sizeof(float); - RD::get_singleton()->buffer_update(multimesh->buffer, offset, MIN(region_size, size - offset), &data[i * region_size], false); + RD::get_singleton()->buffer_update(multimesh->buffer, offset, MIN(region_size, size - offset), &data[i * region_size]); } } } @@ -3466,7 +3851,7 @@ void RasterizerStorageRD::_update_dirty_multimeshes() { //aabb is dirty.. _multimesh_re_create_aabb(multimesh, data, visible_instances); multimesh->aabb_dirty = false; - multimesh->instance_dependency.instance_notify_changed(true, false); + multimesh->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } } @@ -3481,25 +3866,28 @@ void RasterizerStorageRD::_update_dirty_multimeshes() { /* PARTICLES */ -RID RasterizerStorageRD::particles_create() { - return particles_owner.make_rid(Particles()); +RID RendererStorageRD::particles_allocate() { + return particles_owner.allocate_rid(); +} +void RendererStorageRD::particles_initialize(RID p_rid) { + particles_owner.initialize_rid(p_rid, Particles()); } -void RasterizerStorageRD::particles_set_emitting(RID p_particles, bool p_emitting) { +void RendererStorageRD::particles_set_emitting(RID p_particles, bool p_emitting) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->emitting = p_emitting; } -bool RasterizerStorageRD::particles_get_emitting(RID p_particles) { +bool RendererStorageRD::particles_get_emitting(RID p_particles) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND_V(!particles, false); return particles->emitting; } -void RasterizerStorageRD::_particles_free_data(Particles *particles) { +void RendererStorageRD::_particles_free_data(Particles *particles) { if (!particles->particle_buffer.is_valid()) { return; } @@ -3526,7 +3914,7 @@ void RasterizerStorageRD::_particles_free_data(Particles *particles) { } } -void RasterizerStorageRD::particles_set_amount(RID p_particles, int p_amount) { +void RendererStorageRD::particles_set_amount(RID p_particles, int p_amount) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); @@ -3549,14 +3937,14 @@ void RasterizerStorageRD::particles_set_amount(RID p_particles, int p_amount) { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 1; u.ids.push_back(particles->particle_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 2; u.ids.push_back(particles->particle_instance_buffer); uniforms.push_back(u); @@ -3572,111 +3960,111 @@ void RasterizerStorageRD::particles_set_amount(RID p_particles, int p_amount) { particles->clear = true; } -void RasterizerStorageRD::particles_set_lifetime(RID p_particles, float p_lifetime) { +void RendererStorageRD::particles_set_lifetime(RID p_particles, float p_lifetime) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->lifetime = p_lifetime; } -void RasterizerStorageRD::particles_set_one_shot(RID p_particles, bool p_one_shot) { +void RendererStorageRD::particles_set_one_shot(RID p_particles, bool p_one_shot) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->one_shot = p_one_shot; } -void RasterizerStorageRD::particles_set_pre_process_time(RID p_particles, float p_time) { +void RendererStorageRD::particles_set_pre_process_time(RID p_particles, float p_time) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->pre_process_time = p_time; } -void RasterizerStorageRD::particles_set_explosiveness_ratio(RID p_particles, float p_ratio) { +void RendererStorageRD::particles_set_explosiveness_ratio(RID p_particles, float p_ratio) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->explosiveness = p_ratio; } -void RasterizerStorageRD::particles_set_randomness_ratio(RID p_particles, float p_ratio) { +void RendererStorageRD::particles_set_randomness_ratio(RID p_particles, float p_ratio) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->randomness = p_ratio; } -void RasterizerStorageRD::particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) { +void RendererStorageRD::particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->custom_aabb = p_aabb; - particles->instance_dependency.instance_notify_changed(true, false); + particles->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } -void RasterizerStorageRD::particles_set_speed_scale(RID p_particles, float p_scale) { +void RendererStorageRD::particles_set_speed_scale(RID p_particles, float p_scale) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->speed_scale = p_scale; } -void RasterizerStorageRD::particles_set_use_local_coordinates(RID p_particles, bool p_enable) { +void RendererStorageRD::particles_set_use_local_coordinates(RID p_particles, bool p_enable) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->use_local_coords = p_enable; } -void RasterizerStorageRD::particles_set_fixed_fps(RID p_particles, int p_fps) { +void RendererStorageRD::particles_set_fixed_fps(RID p_particles, int p_fps) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->fixed_fps = p_fps; } -void RasterizerStorageRD::particles_set_fractional_delta(RID p_particles, bool p_enable) { +void RendererStorageRD::particles_set_fractional_delta(RID p_particles, bool p_enable) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->fractional_delta = p_enable; } -void RasterizerStorageRD::particles_set_collision_base_size(RID p_particles, float p_size) { +void RendererStorageRD::particles_set_collision_base_size(RID p_particles, float p_size) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->collision_base_size = p_size; } -void RasterizerStorageRD::particles_set_process_material(RID p_particles, RID p_material) { +void RendererStorageRD::particles_set_process_material(RID p_particles, RID p_material) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->process_material = p_material; } -void RasterizerStorageRD::particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) { +void RendererStorageRD::particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->draw_order = p_order; } -void RasterizerStorageRD::particles_set_draw_passes(RID p_particles, int p_passes) { +void RendererStorageRD::particles_set_draw_passes(RID p_particles, int p_passes) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->draw_passes.resize(p_passes); } -void RasterizerStorageRD::particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) { +void RendererStorageRD::particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); ERR_FAIL_INDEX(p_pass, particles->draw_passes.size()); particles->draw_passes.write[p_pass] = p_mesh; } -void RasterizerStorageRD::particles_restart(RID p_particles) { +void RendererStorageRD::particles_restart(RID p_particles) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->restart_request = true; } -void RasterizerStorageRD::_particles_allocate_emission_buffer(Particles *particles) { +void RendererStorageRD::_particles_allocate_emission_buffer(Particles *particles) { ERR_FAIL_COND(particles->emission_buffer != nullptr); particles->emission_buffer_data.resize(sizeof(ParticleEmissionBuffer::Data) * particles->amount + sizeof(uint32_t) * 4); @@ -3693,7 +4081,7 @@ void RasterizerStorageRD::_particles_allocate_emission_buffer(Particles *particl } } -void RasterizerStorageRD::particles_set_subemitter(RID p_particles, RID p_subemitter_particles) { +void RendererStorageRD::particles_set_subemitter(RID p_particles, RID p_subemitter_particles) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); ERR_FAIL_COND(p_particles == p_subemitter_particles); @@ -3706,7 +4094,7 @@ void RasterizerStorageRD::particles_set_subemitter(RID p_particles, RID p_subemi } } -void RasterizerStorageRD::particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) { +void RendererStorageRD::particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); ERR_FAIL_COND(particles->amount == 0); @@ -3749,7 +4137,7 @@ void RasterizerStorageRD::particles_emit(RID p_particles, const Transform &p_tra } } -void RasterizerStorageRD::particles_request_process(RID p_particles) { +void RendererStorageRD::particles_request_process(RID p_particles) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); @@ -3760,7 +4148,7 @@ void RasterizerStorageRD::particles_request_process(RID p_particles) { } } -AABB RasterizerStorageRD::particles_get_current_aabb(RID p_particles) { +AABB RendererStorageRD::particles_get_current_aabb(RID p_particles) { const Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND_V(!particles, AABB()); @@ -3804,28 +4192,28 @@ AABB RasterizerStorageRD::particles_get_current_aabb(RID p_particles) { return aabb; } -AABB RasterizerStorageRD::particles_get_aabb(RID p_particles) const { +AABB RendererStorageRD::particles_get_aabb(RID p_particles) const { const Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND_V(!particles, AABB()); return particles->custom_aabb; } -void RasterizerStorageRD::particles_set_emission_transform(RID p_particles, const Transform &p_transform) { +void RendererStorageRD::particles_set_emission_transform(RID p_particles, const Transform &p_transform) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->emission_transform = p_transform; } -int RasterizerStorageRD::particles_get_draw_passes(RID p_particles) const { +int RendererStorageRD::particles_get_draw_passes(RID p_particles) const { const Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND_V(!particles, 0); return particles->draw_passes.size(); } -RID RasterizerStorageRD::particles_get_draw_pass_mesh(RID p_particles, int p_pass) const { +RID RendererStorageRD::particles_get_draw_pass_mesh(RID p_particles, int p_pass) const { const Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND_V(!particles, RID()); ERR_FAIL_INDEX_V(p_pass, particles->draw_passes.size(), RID()); @@ -3833,36 +4221,34 @@ RID RasterizerStorageRD::particles_get_draw_pass_mesh(RID p_particles, int p_pas return particles->draw_passes[p_pass]; } -void RasterizerStorageRD::particles_add_collision(RID p_particles, RasterizerScene::InstanceBase *p_instance) { +void RendererStorageRD::particles_add_collision(RID p_particles, RID p_particles_collision_instance) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); - ERR_FAIL_COND(p_instance->base_type != RS::INSTANCE_PARTICLES_COLLISION); - - particles->collisions.insert(p_instance); + particles->collisions.insert(p_particles_collision_instance); } -void RasterizerStorageRD::particles_remove_collision(RID p_particles, RasterizerScene::InstanceBase *p_instance) { +void RendererStorageRD::particles_remove_collision(RID p_particles, RID p_particles_collision_instance) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); - particles->collisions.erase(p_instance); + particles->collisions.erase(p_particles_collision_instance); } -void RasterizerStorageRD::_particles_process(Particles *p_particles, float p_delta) { +void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta) { if (p_particles->particles_material_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(p_particles->particles_material_uniform_set)) { Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 0; u.ids.push_back(p_particles->frame_params_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 1; u.ids.push_back(p_particles->particle_buffer); uniforms.push_back(u); @@ -3870,7 +4256,7 @@ void RasterizerStorageRD::_particles_process(Particles *p_particles, float p_del { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 2; if (p_particles->emission_storage_buffer.is_valid()) { u.ids.push_back(p_particles->emission_storage_buffer); @@ -3881,7 +4267,7 @@ void RasterizerStorageRD::_particles_process(Particles *p_particles, float p_del } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 3; Particles *sub_emitter = particles_owner.getornull(p_particles->sub_emitter); if (sub_emitter) { @@ -3918,7 +4304,7 @@ void RasterizerStorageRD::_particles_process(Particles *p_particles, float p_del p_particles->phase = new_phase; - frame_params.time = RasterizerRD::singleton->get_total_time(); + frame_params.time = RendererCompositorRD::singleton->get_total_time(); frame_params.delta = p_delta * p_particles->speed_scale; frame_params.random_seed = p_particles->random_seed; frame_params.explosiveness = p_particles->explosiveness; @@ -3946,9 +4332,15 @@ void RasterizerStorageRD::_particles_process(Particles *p_particles, float p_del to_particles = p_particles->emission_transform.affine_inverse(); } uint32_t collision_3d_textures_used = 0; - for (const Set<RasterizerScene::InstanceBase *>::Element *E = p_particles->collisions.front(); E; E = E->next()) { - ParticlesCollision *pc = particles_collision_owner.getornull(E->get()->base); - Transform to_collider = E->get()->transform; + for (const Set<RID>::Element *E = p_particles->collisions.front(); E; E = E->next()) { + ParticlesCollisionInstance *pci = particles_collision_instance_owner.getornull(E->get()); + if (!pci || !pci->active) { + continue; + } + ParticlesCollision *pc = particles_collision_owner.getornull(pci->collision); + ERR_CONTINUE(!pc); + + Transform to_collider = pci->transform; if (p_particles->use_local_coords) { to_collider = to_particles * to_collider; } @@ -4088,7 +4480,7 @@ void RasterizerStorageRD::_particles_process(Particles *p_particles, float p_del { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 0; for (uint32_t i = 0; i < ParticlesFrameParams::MAX_3D_TEXTURES; i++) { RID rd_tex; @@ -4108,7 +4500,7 @@ void RasterizerStorageRD::_particles_process(Particles *p_particles, float p_del } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; if (collision_heightmap_texture.is_valid()) { u.ids.push_back(collision_heightmap_texture); @@ -4137,7 +4529,7 @@ void RasterizerStorageRD::_particles_process(Particles *p_particles, float p_del if (sub_emitter && sub_emitter->emission_storage_buffer.is_valid()) { // print_line("updating subemitter buffer"); int32_t zero[4] = { 0, sub_emitter->amount, 0, 0 }; - RD::get_singleton()->buffer_update(sub_emitter->emission_storage_buffer, 0, sizeof(uint32_t) * 4, zero, true); + RD::get_singleton()->buffer_update(sub_emitter->emission_storage_buffer, 0, sizeof(uint32_t) * 4, zero); push_constant.can_emit = true; if (sub_emitter->emitting) { @@ -4155,13 +4547,13 @@ void RasterizerStorageRD::_particles_process(Particles *p_particles, float p_del } if (p_particles->emission_buffer && p_particles->emission_buffer->particle_count) { - RD::get_singleton()->buffer_update(p_particles->emission_storage_buffer, 0, sizeof(uint32_t) * 4 + sizeof(ParticleEmissionBuffer::Data) * p_particles->emission_buffer->particle_count, p_particles->emission_buffer, true); + RD::get_singleton()->buffer_update(p_particles->emission_storage_buffer, 0, sizeof(uint32_t) * 4 + sizeof(ParticleEmissionBuffer::Data) * p_particles->emission_buffer->particle_count, p_particles->emission_buffer); p_particles->emission_buffer->particle_count = 0; } p_particles->clear = false; - RD::get_singleton()->buffer_update(p_particles->frame_params_buffer, 0, sizeof(ParticlesFrameParams), &frame_params, true); + RD::get_singleton()->buffer_update(p_particles->frame_params_buffer, 0, sizeof(ParticlesFrameParams), &frame_params); ParticlesMaterialData *m = (ParticlesMaterialData *)material_get_data(p_particles->process_material, SHADER_TYPE_PARTICLES); if (!m) { @@ -4183,12 +4575,12 @@ void RasterizerStorageRD::_particles_process(Particles *p_particles, float p_del RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ParticlesShader::PushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_particles->amount, 1, 1, 64, 1, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_particles->amount, 1, 1); RD::get_singleton()->compute_list_end(); } -void RasterizerStorageRD::particles_set_view_axis(RID p_particles, const Vector3 &p_axis) { +void RendererStorageRD::particles_set_view_axis(RID p_particles, const Vector3 &p_axis) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); @@ -4209,7 +4601,7 @@ void RasterizerStorageRD::particles_set_view_axis(RID p_particles, const Vector3 { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 0; u.ids.push_back(particles->particles_sort_buffer); uniforms.push_back(u); @@ -4237,7 +4629,7 @@ void RasterizerStorageRD::particles_set_view_axis(RID p_particles, const Vector3 RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_sort_uniform_set, 1); RD::get_singleton()->compute_list_set_push_constant(compute_list, ©_push_constant, sizeof(ParticlesShader::CopyPushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1, 64, 1, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1); RD::get_singleton()->compute_list_end(); @@ -4249,12 +4641,12 @@ void RasterizerStorageRD::particles_set_view_axis(RID p_particles, const Vector3 RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_sort_uniform_set, 1); RD::get_singleton()->compute_list_set_push_constant(compute_list, ©_push_constant, sizeof(ParticlesShader::CopyPushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1, 64, 1, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1); RD::get_singleton()->compute_list_end(); } -void RasterizerStorageRD::update_particles() { +void RendererStorageRD::update_particles() { while (particle_update_list) { //use transform feedback to process particles @@ -4289,7 +4681,7 @@ void RasterizerStorageRD::update_particles() { particles->inactive = false; particles->inactive_time = 0; } else { - particles->inactive_time += particles->speed_scale * RasterizerRD::singleton->get_frame_delta_time(); + particles->inactive_time += particles->speed_scale * RendererCompositorRD::singleton->get_frame_delta_time(); if (particles->inactive_time > particles->lifetime * 1.2) { particles->inactive = true; continue; @@ -4323,7 +4715,7 @@ void RasterizerStorageRD::update_particles() { frame_time = 1.0 / particles->fixed_fps; decr = frame_time; } - float delta = RasterizerRD::singleton->get_frame_delta_time(); + float delta = RendererCompositorRD::singleton->get_frame_delta_time(); if (delta > 0.1) { //avoid recursive stalls if fps goes below 10 delta = 0.1; } else if (delta <= 0.0) { //unlikely but.. @@ -4342,7 +4734,7 @@ void RasterizerStorageRD::update_particles() { if (zero_time_scale) _particles_process(particles, 0.0); else - _particles_process(particles, RasterizerRD::singleton->get_frame_delta_time()); + _particles_process(particles, RendererCompositorRD::singleton->get_frame_delta_time()); } //copy particles to instance buffer @@ -4356,16 +4748,16 @@ void RasterizerStorageRD::update_particles() { RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0); RD::get_singleton()->compute_list_set_push_constant(compute_list, ©_push_constant, sizeof(ParticlesShader::CopyPushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1, 64, 1, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1); RD::get_singleton()->compute_list_end(); } - particles->instance_dependency.instance_notify_changed(true, false); //make sure shadows are updated + particles->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } } -bool RasterizerStorageRD::particles_is_inactive(RID p_particles) const { +bool RendererStorageRD::particles_is_inactive(RID p_particles) const { const Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND_V(!particles, false); return !particles->emitting && particles->inactive; @@ -4373,7 +4765,7 @@ bool RasterizerStorageRD::particles_is_inactive(RID p_particles) const { /* SKY SHADER */ -void RasterizerStorageRD::ParticlesShaderData::set_code(const String &p_code) { +void RendererStorageRD::ParticlesShaderData::set_code(const String &p_code) { //compile code = p_code; @@ -4421,7 +4813,7 @@ void RasterizerStorageRD::ParticlesShaderData::set_code(const String &p_code) { valid = true; } -void RasterizerStorageRD::ParticlesShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { +void RendererStorageRD::ParticlesShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { if (!p_texture.is_valid()) { default_texture_params.erase(p_name); } else { @@ -4429,7 +4821,7 @@ void RasterizerStorageRD::ParticlesShaderData::set_default_texture_param(const S } } -void RasterizerStorageRD::ParticlesShaderData::get_param_list(List<PropertyInfo> *p_param_list) const { +void RendererStorageRD::ParticlesShaderData::get_param_list(List<PropertyInfo> *p_param_list) const { Map<int, StringName> order; for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { @@ -4451,13 +4843,13 @@ void RasterizerStorageRD::ParticlesShaderData::get_param_list(List<PropertyInfo> } } -void RasterizerStorageRD::ParticlesShaderData::get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const { +void RendererStorageRD::ParticlesShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const { for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { continue; } - RasterizerStorage::InstanceShaderParam p; + RendererStorage::InstanceShaderParam p; p.info = ShaderLanguage::uniform_to_property_info(E->get()); p.info.name = E->key(); //supply name p.index = E->get().instance_index; @@ -4466,7 +4858,7 @@ void RasterizerStorageRD::ParticlesShaderData::get_instance_param_list(List<Rast } } -bool RasterizerStorageRD::ParticlesShaderData::is_param_texture(const StringName &p_param) const { +bool RendererStorageRD::ParticlesShaderData::is_param_texture(const StringName &p_param) const { if (!uniforms.has(p_param)) { return false; } @@ -4474,15 +4866,15 @@ bool RasterizerStorageRD::ParticlesShaderData::is_param_texture(const StringName return uniforms[p_param].texture_order >= 0; } -bool RasterizerStorageRD::ParticlesShaderData::is_animated() const { +bool RendererStorageRD::ParticlesShaderData::is_animated() const { return false; } -bool RasterizerStorageRD::ParticlesShaderData::casts_shadows() const { +bool RendererStorageRD::ParticlesShaderData::casts_shadows() const { return false; } -Variant RasterizerStorageRD::ParticlesShaderData::get_default_parameter(const StringName &p_parameter) const { +Variant RendererStorageRD::ParticlesShaderData::get_default_parameter(const StringName &p_parameter) const { if (uniforms.has(p_parameter)) { ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; @@ -4491,23 +4883,27 @@ Variant RasterizerStorageRD::ParticlesShaderData::get_default_parameter(const St return Variant(); } -RasterizerStorageRD::ParticlesShaderData::ParticlesShaderData() { +RS::ShaderNativeSourceCode RendererStorageRD::ParticlesShaderData::get_native_source_code() const { + return base_singleton->particles_shader.shader.version_get_native_source_code(version); +} + +RendererStorageRD::ParticlesShaderData::ParticlesShaderData() { valid = false; } -RasterizerStorageRD::ParticlesShaderData::~ParticlesShaderData() { +RendererStorageRD::ParticlesShaderData::~ParticlesShaderData() { //pipeline variants will clear themselves if shader is gone if (version.is_valid()) { base_singleton->particles_shader.shader.version_free(version); } } -RasterizerStorageRD::ShaderData *RasterizerStorageRD::_create_particles_shader_func() { +RendererStorageRD::ShaderData *RendererStorageRD::_create_particles_shader_func() { ParticlesShaderData *shader_data = memnew(ParticlesShaderData); return shader_data; } -void RasterizerStorageRD::ParticlesMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { +void RendererStorageRD::ParticlesMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { uniform_set_updated = true; if ((uint32_t)ubo_data.size() != shader_data->ubo_size) { @@ -4568,7 +4964,7 @@ void RasterizerStorageRD::ParticlesMaterialData::update_parameters(const Map<Str { if (shader_data->ubo_size) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 0; u.ids.push_back(uniform_buffer); uniforms.push_back(u); @@ -4577,7 +4973,7 @@ void RasterizerStorageRD::ParticlesMaterialData::update_parameters(const Map<Str const RID *textures = texture_cache.ptrw(); for (uint32_t i = 0; i < tex_uniform_count; i++) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1 + i; u.ids.push_back(textures[i]); uniforms.push_back(u); @@ -4587,7 +4983,7 @@ void RasterizerStorageRD::ParticlesMaterialData::update_parameters(const Map<Str uniform_set = RD::get_singleton()->uniform_set_create(uniforms, base_singleton->particles_shader.shader.version_get_shader(shader_data->version, 0), 3); } -RasterizerStorageRD::ParticlesMaterialData::~ParticlesMaterialData() { +RendererStorageRD::ParticlesMaterialData::~ParticlesMaterialData() { if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { RD::get_singleton()->free(uniform_set); } @@ -4597,7 +4993,7 @@ RasterizerStorageRD::ParticlesMaterialData::~ParticlesMaterialData() { } } -RasterizerStorageRD::MaterialData *RasterizerStorageRD::_create_particles_material_func(ParticlesShaderData *p_shader) { +RendererStorageRD::MaterialData *RendererStorageRD::_create_particles_material_func(ParticlesShaderData *p_shader) { ParticlesMaterialData *material_data = memnew(ParticlesMaterialData); material_data->shader_data = p_shader; material_data->last_frame = false; @@ -4608,11 +5004,14 @@ RasterizerStorageRD::MaterialData *RasterizerStorageRD::_create_particles_materi /* PARTICLES COLLISION API */ -RID RasterizerStorageRD::particles_collision_create() { - return particles_collision_owner.make_rid(ParticlesCollision()); +RID RendererStorageRD::particles_collision_allocate() { + return particles_collision_owner.allocate_rid(); +} +void RendererStorageRD::particles_collision_initialize(RID p_rid) { + particles_collision_owner.initialize_rid(p_rid, ParticlesCollision()); } -RID RasterizerStorageRD::particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const { +RID RendererStorageRD::particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND_V(!particles_collision, RID()); ERR_FAIL_COND_V(particles_collision->type != RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE, RID()); @@ -4633,7 +5032,7 @@ RID RasterizerStorageRD::particles_collision_get_heightfield_framebuffer(RID p_p tf.format = RD::DATA_FORMAT_D32_SFLOAT; tf.width = size.x; tf.height = size.y; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; particles_collision->heightfield_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); @@ -4647,7 +5046,7 @@ RID RasterizerStorageRD::particles_collision_get_heightfield_framebuffer(RID p_p return particles_collision->heightfield_fb; } -void RasterizerStorageRD::particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) { +void RendererStorageRD::particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND(!particles_collision); @@ -4660,66 +5059,66 @@ void RasterizerStorageRD::particles_collision_set_collision_type(RID p_particles particles_collision->heightfield_texture = RID(); } particles_collision->type = p_type; - particles_collision->instance_dependency.instance_notify_changed(true, false); + particles_collision->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } -void RasterizerStorageRD::particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) { +void RendererStorageRD::particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND(!particles_collision); particles_collision->cull_mask = p_cull_mask; } -void RasterizerStorageRD::particles_collision_set_sphere_radius(RID p_particles_collision, float p_radius) { +void RendererStorageRD::particles_collision_set_sphere_radius(RID p_particles_collision, float p_radius) { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND(!particles_collision); particles_collision->radius = p_radius; - particles_collision->instance_dependency.instance_notify_changed(true, false); + particles_collision->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } -void RasterizerStorageRD::particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) { +void RendererStorageRD::particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND(!particles_collision); particles_collision->extents = p_extents; - particles_collision->instance_dependency.instance_notify_changed(true, false); + particles_collision->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } -void RasterizerStorageRD::particles_collision_set_attractor_strength(RID p_particles_collision, float p_strength) { +void RendererStorageRD::particles_collision_set_attractor_strength(RID p_particles_collision, float p_strength) { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND(!particles_collision); particles_collision->attractor_strength = p_strength; } -void RasterizerStorageRD::particles_collision_set_attractor_directionality(RID p_particles_collision, float p_directionality) { +void RendererStorageRD::particles_collision_set_attractor_directionality(RID p_particles_collision, float p_directionality) { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND(!particles_collision); particles_collision->attractor_directionality = p_directionality; } -void RasterizerStorageRD::particles_collision_set_attractor_attenuation(RID p_particles_collision, float p_curve) { +void RendererStorageRD::particles_collision_set_attractor_attenuation(RID p_particles_collision, float p_curve) { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND(!particles_collision); particles_collision->attractor_attenuation = p_curve; } -void RasterizerStorageRD::particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) { +void RendererStorageRD::particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND(!particles_collision); particles_collision->field_texture = p_texture; } -void RasterizerStorageRD::particles_collision_height_field_update(RID p_particles_collision) { +void RendererStorageRD::particles_collision_height_field_update(RID p_particles_collision) { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND(!particles_collision); - particles_collision->instance_dependency.instance_notify_changed(true, false); + particles_collision->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } -void RasterizerStorageRD::particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) { +void RendererStorageRD::particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND(!particles_collision); @@ -4735,7 +5134,7 @@ void RasterizerStorageRD::particles_collision_set_height_field_resolution(RID p_ } } -AABB RasterizerStorageRD::particles_collision_get_aabb(RID p_particles_collision) const { +AABB RendererStorageRD::particles_collision_get_aabb(RID p_particles_collision) const { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND_V(!particles_collision, AABB()); @@ -4758,25 +5157,44 @@ AABB RasterizerStorageRD::particles_collision_get_aabb(RID p_particles_collision return AABB(); } -Vector3 RasterizerStorageRD::particles_collision_get_extents(RID p_particles_collision) const { +Vector3 RendererStorageRD::particles_collision_get_extents(RID p_particles_collision) const { const ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND_V(!particles_collision, Vector3()); return particles_collision->extents; } -bool RasterizerStorageRD::particles_collision_is_heightfield(RID p_particles_collision) const { +bool RendererStorageRD::particles_collision_is_heightfield(RID p_particles_collision) const { const ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND_V(!particles_collision, false); return particles_collision->type == RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE; } +RID RendererStorageRD::particles_collision_instance_create(RID p_collision) { + ParticlesCollisionInstance pci; + pci.collision = p_collision; + return particles_collision_instance_owner.make_rid(pci); +} +void RendererStorageRD::particles_collision_instance_set_transform(RID p_collision_instance, const Transform &p_transform) { + ParticlesCollisionInstance *pci = particles_collision_instance_owner.getornull(p_collision_instance); + ERR_FAIL_COND(!pci); + pci->transform = p_transform; +} +void RendererStorageRD::particles_collision_instance_set_active(RID p_collision_instance, bool p_active) { + ParticlesCollisionInstance *pci = particles_collision_instance_owner.getornull(p_collision_instance); + ERR_FAIL_COND(!pci); + pci->active = p_active; +} + /* SKELETON API */ -RID RasterizerStorageRD::skeleton_create() { - return skeleton_owner.make_rid(Skeleton()); +RID RendererStorageRD::skeleton_allocate() { + return skeleton_owner.allocate_rid(); +} +void RendererStorageRD::skeleton_initialize(RID p_rid) { + skeleton_owner.initialize_rid(p_rid, Skeleton()); } -void RasterizerStorageRD::_skeleton_make_dirty(Skeleton *skeleton) { +void RendererStorageRD::_skeleton_make_dirty(Skeleton *skeleton) { if (!skeleton->dirty) { skeleton->dirty = true; skeleton->dirty_list = skeleton_dirty_list; @@ -4784,7 +5202,7 @@ void RasterizerStorageRD::_skeleton_make_dirty(Skeleton *skeleton) { } } -void RasterizerStorageRD::skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d_skeleton) { +void RendererStorageRD::skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton) { Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); ERR_FAIL_COND(!skeleton); ERR_FAIL_COND(p_bones < 0); @@ -4801,6 +5219,7 @@ void RasterizerStorageRD::skeleton_allocate(RID p_skeleton, int p_bones, bool p_ RD::get_singleton()->free(skeleton->buffer); skeleton->buffer = RID(); skeleton->data.resize(0); + skeleton->uniform_set_mi = RID(); } if (skeleton->size) { @@ -4809,17 +5228,31 @@ void RasterizerStorageRD::skeleton_allocate(RID p_skeleton, int p_bones, bool p_ zeromem(skeleton->data.ptrw(), skeleton->data.size() * sizeof(float)); _skeleton_make_dirty(skeleton); + + { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.binding = 0; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(skeleton->buffer); + uniforms.push_back(u); + } + skeleton->uniform_set_mi = RD::get_singleton()->uniform_set_create(uniforms, skeleton_shader.version_shader[0], SkeletonShader::UNIFORM_SET_SKELETON); + } } + + skeleton->dependency.changed_notify(DEPENDENCY_CHANGED_SKELETON_DATA); } -int RasterizerStorageRD::skeleton_get_bone_count(RID p_skeleton) const { +int RendererStorageRD::skeleton_get_bone_count(RID p_skeleton) const { Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); ERR_FAIL_COND_V(!skeleton, 0); return skeleton->size; } -void RasterizerStorageRD::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) { +void RendererStorageRD::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) { Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); ERR_FAIL_COND(!skeleton); @@ -4844,7 +5277,7 @@ void RasterizerStorageRD::skeleton_bone_set_transform(RID p_skeleton, int p_bone _skeleton_make_dirty(skeleton); } -Transform RasterizerStorageRD::skeleton_bone_get_transform(RID p_skeleton, int p_bone) const { +Transform RendererStorageRD::skeleton_bone_get_transform(RID p_skeleton, int p_bone) const { Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); ERR_FAIL_COND_V(!skeleton, Transform()); @@ -4871,7 +5304,7 @@ Transform RasterizerStorageRD::skeleton_bone_get_transform(RID p_skeleton, int p return t; } -void RasterizerStorageRD::skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) { +void RendererStorageRD::skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) { Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); ERR_FAIL_COND(!skeleton); @@ -4892,7 +5325,7 @@ void RasterizerStorageRD::skeleton_bone_set_transform_2d(RID p_skeleton, int p_b _skeleton_make_dirty(skeleton); } -Transform2D RasterizerStorageRD::skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const { +Transform2D RendererStorageRD::skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const { Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); ERR_FAIL_COND_V(!skeleton, Transform2D()); @@ -4912,7 +5345,7 @@ Transform2D RasterizerStorageRD::skeleton_bone_get_transform_2d(RID p_skeleton, return t; } -void RasterizerStorageRD::skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) { +void RendererStorageRD::skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) { Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); ERR_FAIL_COND(!skeleton->use_2d); @@ -4920,17 +5353,19 @@ void RasterizerStorageRD::skeleton_set_base_transform_2d(RID p_skeleton, const T skeleton->base_transform_2d = p_base_transform; } -void RasterizerStorageRD::_update_dirty_skeletons() { +void RendererStorageRD::_update_dirty_skeletons() { while (skeleton_dirty_list) { Skeleton *skeleton = skeleton_dirty_list; if (skeleton->size) { - RD::get_singleton()->buffer_update(skeleton->buffer, 0, skeleton->data.size() * sizeof(float), skeleton->data.ptr(), false); + RD::get_singleton()->buffer_update(skeleton->buffer, 0, skeleton->data.size() * sizeof(float), skeleton->data.ptr()); } skeleton_dirty_list = skeleton->dirty_list; - skeleton->instance_dependency.instance_notify_changed(true, false); + skeleton->dependency.changed_notify(DEPENDENCY_CHANGED_SKELETON_BONES); + + skeleton->version++; skeleton->dirty = false; skeleton->dirty_list = nullptr; @@ -4941,7 +5376,7 @@ void RasterizerStorageRD::_update_dirty_skeletons() { /* LIGHT */ -RID RasterizerStorageRD::light_create(RS::LightType p_type) { +void RendererStorageRD::_light_initialize(RID p_light, RS::LightType p_type) { Light light; light.type = p_type; @@ -4950,29 +5385,53 @@ RID RasterizerStorageRD::light_create(RS::LightType p_type) { light.param[RS::LIGHT_PARAM_SPECULAR] = 0.5; light.param[RS::LIGHT_PARAM_RANGE] = 1.0; light.param[RS::LIGHT_PARAM_SIZE] = 0.0; + light.param[RS::LIGHT_PARAM_ATTENUATION] = 1.0; light.param[RS::LIGHT_PARAM_SPOT_ANGLE] = 45; + light.param[RS::LIGHT_PARAM_SPOT_ATTENUATION] = 1.0; light.param[RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE] = 0; light.param[RS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET] = 0.1; light.param[RS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET] = 0.3; light.param[RS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET] = 0.6; light.param[RS::LIGHT_PARAM_SHADOW_FADE_START] = 0.8; - light.param[RS::LIGHT_PARAM_SHADOW_BIAS] = 0.02; light.param[RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] = 1.0; + light.param[RS::LIGHT_PARAM_SHADOW_BIAS] = 0.02; + light.param[RS::LIGHT_PARAM_SHADOW_BLUR] = 0; light.param[RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE] = 20.0; + light.param[RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE] = 0.1; light.param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS] = 0.05; - light.param[RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE] = 1.0; - return light_owner.make_rid(light); + light_owner.initialize_rid(p_light, light); +} + +RID RendererStorageRD::directional_light_allocate() { + return light_owner.allocate_rid(); +} +void RendererStorageRD::directional_light_initialize(RID p_light) { + _light_initialize(p_light, RS::LIGHT_DIRECTIONAL); +} + +RID RendererStorageRD::omni_light_allocate() { + return light_owner.allocate_rid(); +} +void RendererStorageRD::omni_light_initialize(RID p_light) { + _light_initialize(p_light, RS::LIGHT_OMNI); +} + +RID RendererStorageRD::spot_light_allocate() { + return light_owner.allocate_rid(); +} +void RendererStorageRD::spot_light_initialize(RID p_light) { + _light_initialize(p_light, RS::LIGHT_SPOT); } -void RasterizerStorageRD::light_set_color(RID p_light, const Color &p_color) { +void RendererStorageRD::light_set_color(RID p_light, const Color &p_color) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); light->color = p_color; } -void RasterizerStorageRD::light_set_param(RID p_light, RS::LightParam p_param, float p_value) { +void RendererStorageRD::light_set_param(RID p_light, RS::LightParam p_param, float p_value) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); ERR_FAIL_INDEX(p_param, RS::LIGHT_PARAM_MAX); @@ -4988,7 +5447,7 @@ void RasterizerStorageRD::light_set_param(RID p_light, RS::LightParam p_param, f case RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE: case RS::LIGHT_PARAM_SHADOW_BIAS: { light->version++; - light->instance_dependency.instance_notify_changed(true, false); + light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT); } break; default: { } @@ -4997,22 +5456,22 @@ void RasterizerStorageRD::light_set_param(RID p_light, RS::LightParam p_param, f light->param[p_param] = p_value; } -void RasterizerStorageRD::light_set_shadow(RID p_light, bool p_enabled) { +void RendererStorageRD::light_set_shadow(RID p_light, bool p_enabled) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); light->shadow = p_enabled; light->version++; - light->instance_dependency.instance_notify_changed(true, false); + light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT); } -void RasterizerStorageRD::light_set_shadow_color(RID p_light, const Color &p_color) { +void RendererStorageRD::light_set_shadow_color(RID p_light, const Color &p_color) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); light->shadow_color = p_color; } -void RasterizerStorageRD::light_set_projector(RID p_light, RID p_texture) { +void RendererStorageRD::light_set_projector(RID p_light, RID p_texture) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); @@ -5031,138 +5490,152 @@ void RasterizerStorageRD::light_set_projector(RID p_light, RID p_texture) { } } -void RasterizerStorageRD::light_set_negative(RID p_light, bool p_enable) { +void RendererStorageRD::light_set_negative(RID p_light, bool p_enable) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); light->negative = p_enable; } -void RasterizerStorageRD::light_set_cull_mask(RID p_light, uint32_t p_mask) { +void RendererStorageRD::light_set_cull_mask(RID p_light, uint32_t p_mask) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); light->cull_mask = p_mask; light->version++; - light->instance_dependency.instance_notify_changed(true, false); + light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT); } -void RasterizerStorageRD::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) { +void RendererStorageRD::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); light->reverse_cull = p_enabled; light->version++; - light->instance_dependency.instance_notify_changed(true, false); + light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT); } -void RasterizerStorageRD::light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) { +void RendererStorageRD::light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); light->bake_mode = p_bake_mode; light->version++; - light->instance_dependency.instance_notify_changed(true, false); + light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT); } -void RasterizerStorageRD::light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) { +void RendererStorageRD::light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); light->max_sdfgi_cascade = p_cascade; light->version++; - light->instance_dependency.instance_notify_changed(true, false); + light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT); } -void RasterizerStorageRD::light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) { +void RendererStorageRD::light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); light->omni_shadow_mode = p_mode; light->version++; - light->instance_dependency.instance_notify_changed(true, false); + light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT); } -RS::LightOmniShadowMode RasterizerStorageRD::light_omni_get_shadow_mode(RID p_light) { +RS::LightOmniShadowMode RendererStorageRD::light_omni_get_shadow_mode(RID p_light) { const Light *light = light_owner.getornull(p_light); ERR_FAIL_COND_V(!light, RS::LIGHT_OMNI_SHADOW_CUBE); return light->omni_shadow_mode; } -void RasterizerStorageRD::light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) { +void RendererStorageRD::light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); light->directional_shadow_mode = p_mode; light->version++; - light->instance_dependency.instance_notify_changed(true, false); + light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT); } -void RasterizerStorageRD::light_directional_set_blend_splits(RID p_light, bool p_enable) { +void RendererStorageRD::light_directional_set_blend_splits(RID p_light, bool p_enable) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); light->directional_blend_splits = p_enable; light->version++; - light->instance_dependency.instance_notify_changed(true, false); + light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT); } -bool RasterizerStorageRD::light_directional_get_blend_splits(RID p_light) const { +bool RendererStorageRD::light_directional_get_blend_splits(RID p_light) const { const Light *light = light_owner.getornull(p_light); ERR_FAIL_COND_V(!light, false); return light->directional_blend_splits; } -RS::LightDirectionalShadowMode RasterizerStorageRD::light_directional_get_shadow_mode(RID p_light) { +void RendererStorageRD::light_directional_set_sky_only(RID p_light, bool p_sky_only) { + Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + + light->directional_sky_only = p_sky_only; +} + +bool RendererStorageRD::light_directional_is_sky_only(RID p_light) const { + const Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light, false); + + return light->directional_sky_only; +} + +RS::LightDirectionalShadowMode RendererStorageRD::light_directional_get_shadow_mode(RID p_light) { const Light *light = light_owner.getornull(p_light); ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL); return light->directional_shadow_mode; } -void RasterizerStorageRD::light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode) { +void RendererStorageRD::light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); light->directional_range_mode = p_range_mode; } -RS::LightDirectionalShadowDepthRangeMode RasterizerStorageRD::light_directional_get_shadow_depth_range_mode(RID p_light) const { +RS::LightDirectionalShadowDepthRangeMode RendererStorageRD::light_directional_get_shadow_depth_range_mode(RID p_light) const { const Light *light = light_owner.getornull(p_light); ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE); return light->directional_range_mode; } -uint32_t RasterizerStorageRD::light_get_max_sdfgi_cascade(RID p_light) { +uint32_t RendererStorageRD::light_get_max_sdfgi_cascade(RID p_light) { const Light *light = light_owner.getornull(p_light); ERR_FAIL_COND_V(!light, 0); return light->max_sdfgi_cascade; } -RS::LightBakeMode RasterizerStorageRD::light_get_bake_mode(RID p_light) { +RS::LightBakeMode RendererStorageRD::light_get_bake_mode(RID p_light) { const Light *light = light_owner.getornull(p_light); ERR_FAIL_COND_V(!light, RS::LIGHT_BAKE_DISABLED); return light->bake_mode; } -uint64_t RasterizerStorageRD::light_get_version(RID p_light) const { +uint64_t RendererStorageRD::light_get_version(RID p_light) const { const Light *light = light_owner.getornull(p_light); ERR_FAIL_COND_V(!light, 0); return light->version; } -AABB RasterizerStorageRD::light_get_aabb(RID p_light) const { +AABB RendererStorageRD::light_get_aabb(RID p_light) const { const Light *light = light_owner.getornull(p_light); ERR_FAIL_COND_V(!light, AABB()); @@ -5186,56 +5659,59 @@ AABB RasterizerStorageRD::light_get_aabb(RID p_light) const { /* REFLECTION PROBE */ -RID RasterizerStorageRD::reflection_probe_create() { - return reflection_probe_owner.make_rid(ReflectionProbe()); +RID RendererStorageRD::reflection_probe_allocate() { + return reflection_probe_owner.allocate_rid(); +} +void RendererStorageRD::reflection_probe_initialize(RID p_reflection_probe) { + reflection_probe_owner.initialize_rid(p_reflection_probe, ReflectionProbe()); } -void RasterizerStorageRD::reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) { +void RendererStorageRD::reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->update_mode = p_mode; - reflection_probe->instance_dependency.instance_notify_changed(true, false); + reflection_probe->dependency.changed_notify(DEPENDENCY_CHANGED_REFLECTION_PROBE); } -void RasterizerStorageRD::reflection_probe_set_intensity(RID p_probe, float p_intensity) { +void RendererStorageRD::reflection_probe_set_intensity(RID p_probe, float p_intensity) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->intensity = p_intensity; } -void RasterizerStorageRD::reflection_probe_set_ambient_mode(RID p_probe, RS::ReflectionProbeAmbientMode p_mode) { +void RendererStorageRD::reflection_probe_set_ambient_mode(RID p_probe, RS::ReflectionProbeAmbientMode p_mode) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->ambient_mode = p_mode; } -void RasterizerStorageRD::reflection_probe_set_ambient_color(RID p_probe, const Color &p_color) { +void RendererStorageRD::reflection_probe_set_ambient_color(RID p_probe, const Color &p_color) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->ambient_color = p_color; } -void RasterizerStorageRD::reflection_probe_set_ambient_energy(RID p_probe, float p_energy) { +void RendererStorageRD::reflection_probe_set_ambient_energy(RID p_probe, float p_energy) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->ambient_color_energy = p_energy; } -void RasterizerStorageRD::reflection_probe_set_max_distance(RID p_probe, float p_distance) { +void RendererStorageRD::reflection_probe_set_max_distance(RID p_probe, float p_distance) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->max_distance = p_distance; - reflection_probe->instance_dependency.instance_notify_changed(true, false); + reflection_probe->dependency.changed_notify(DEPENDENCY_CHANGED_REFLECTION_PROBE); } -void RasterizerStorageRD::reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) { +void RendererStorageRD::reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND(!reflection_probe); @@ -5243,49 +5719,49 @@ void RasterizerStorageRD::reflection_probe_set_extents(RID p_probe, const Vector return; } reflection_probe->extents = p_extents; - reflection_probe->instance_dependency.instance_notify_changed(true, false); + reflection_probe->dependency.changed_notify(DEPENDENCY_CHANGED_REFLECTION_PROBE); } -void RasterizerStorageRD::reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) { +void RendererStorageRD::reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->origin_offset = p_offset; - reflection_probe->instance_dependency.instance_notify_changed(true, false); + reflection_probe->dependency.changed_notify(DEPENDENCY_CHANGED_REFLECTION_PROBE); } -void RasterizerStorageRD::reflection_probe_set_as_interior(RID p_probe, bool p_enable) { +void RendererStorageRD::reflection_probe_set_as_interior(RID p_probe, bool p_enable) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->interior = p_enable; - reflection_probe->instance_dependency.instance_notify_changed(true, false); + reflection_probe->dependency.changed_notify(DEPENDENCY_CHANGED_REFLECTION_PROBE); } -void RasterizerStorageRD::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) { +void RendererStorageRD::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->box_projection = p_enable; } -void RasterizerStorageRD::reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) { +void RendererStorageRD::reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->enable_shadows = p_enable; - reflection_probe->instance_dependency.instance_notify_changed(true, false); + reflection_probe->dependency.changed_notify(DEPENDENCY_CHANGED_REFLECTION_PROBE); } -void RasterizerStorageRD::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) { +void RendererStorageRD::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->cull_mask = p_layers; - reflection_probe->instance_dependency.instance_notify_changed(true, false); + reflection_probe->dependency.changed_notify(DEPENDENCY_CHANGED_REFLECTION_PROBE); } -void RasterizerStorageRD::reflection_probe_set_resolution(RID p_probe, int p_resolution) { +void RendererStorageRD::reflection_probe_set_resolution(RID p_probe, int p_resolution) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND(!reflection_probe); ERR_FAIL_COND(p_resolution < 32); @@ -5293,7 +5769,16 @@ void RasterizerStorageRD::reflection_probe_set_resolution(RID p_probe, int p_res reflection_probe->resolution = p_resolution; } -AABB RasterizerStorageRD::reflection_probe_get_aabb(RID p_probe) const { +void RendererStorageRD::reflection_probe_set_lod_threshold(RID p_probe, float p_ratio) { + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->lod_threshold = p_ratio; + + reflection_probe->dependency.changed_notify(DEPENDENCY_CHANGED_REFLECTION_PROBE); +} + +AABB RendererStorageRD::reflection_probe_get_aabb(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, AABB()); @@ -5304,107 +5789,117 @@ AABB RasterizerStorageRD::reflection_probe_get_aabb(RID p_probe) const { return aabb; } -RS::ReflectionProbeUpdateMode RasterizerStorageRD::reflection_probe_get_update_mode(RID p_probe) const { +RS::ReflectionProbeUpdateMode RendererStorageRD::reflection_probe_get_update_mode(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, RS::REFLECTION_PROBE_UPDATE_ALWAYS); return reflection_probe->update_mode; } -uint32_t RasterizerStorageRD::reflection_probe_get_cull_mask(RID p_probe) const { +uint32_t RendererStorageRD::reflection_probe_get_cull_mask(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, 0); return reflection_probe->cull_mask; } -Vector3 RasterizerStorageRD::reflection_probe_get_extents(RID p_probe) const { +Vector3 RendererStorageRD::reflection_probe_get_extents(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, Vector3()); return reflection_probe->extents; } -Vector3 RasterizerStorageRD::reflection_probe_get_origin_offset(RID p_probe) const { +Vector3 RendererStorageRD::reflection_probe_get_origin_offset(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, Vector3()); return reflection_probe->origin_offset; } -bool RasterizerStorageRD::reflection_probe_renders_shadows(RID p_probe) const { +bool RendererStorageRD::reflection_probe_renders_shadows(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, false); return reflection_probe->enable_shadows; } -float RasterizerStorageRD::reflection_probe_get_origin_max_distance(RID p_probe) const { +float RendererStorageRD::reflection_probe_get_origin_max_distance(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, 0); return reflection_probe->max_distance; } -int RasterizerStorageRD::reflection_probe_get_resolution(RID p_probe) const { +float RendererStorageRD::reflection_probe_get_lod_threshold(RID p_probe) const { + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, 0); + + return reflection_probe->lod_threshold; +} + +int RendererStorageRD::reflection_probe_get_resolution(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, 0); return reflection_probe->resolution; } -float RasterizerStorageRD::reflection_probe_get_intensity(RID p_probe) const { +float RendererStorageRD::reflection_probe_get_intensity(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, 0); return reflection_probe->intensity; } -bool RasterizerStorageRD::reflection_probe_is_interior(RID p_probe) const { +bool RendererStorageRD::reflection_probe_is_interior(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, false); return reflection_probe->interior; } -bool RasterizerStorageRD::reflection_probe_is_box_projection(RID p_probe) const { +bool RendererStorageRD::reflection_probe_is_box_projection(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, false); return reflection_probe->box_projection; } -RS::ReflectionProbeAmbientMode RasterizerStorageRD::reflection_probe_get_ambient_mode(RID p_probe) const { +RS::ReflectionProbeAmbientMode RendererStorageRD::reflection_probe_get_ambient_mode(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, RS::REFLECTION_PROBE_AMBIENT_DISABLED); return reflection_probe->ambient_mode; } -Color RasterizerStorageRD::reflection_probe_get_ambient_color(RID p_probe) const { +Color RendererStorageRD::reflection_probe_get_ambient_color(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, Color()); return reflection_probe->ambient_color; } -float RasterizerStorageRD::reflection_probe_get_ambient_color_energy(RID p_probe) const { +float RendererStorageRD::reflection_probe_get_ambient_color_energy(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, 0); return reflection_probe->ambient_color_energy; } -RID RasterizerStorageRD::decal_create() { - return decal_owner.make_rid(Decal()); +RID RendererStorageRD::decal_allocate() { + return decal_owner.allocate_rid(); +} +void RendererStorageRD::decal_initialize(RID p_decal) { + decal_owner.initialize_rid(p_decal, Decal()); } -void RasterizerStorageRD::decal_set_extents(RID p_decal, const Vector3 &p_extents) { +void RendererStorageRD::decal_set_extents(RID p_decal, const Vector3 &p_extents) { Decal *decal = decal_owner.getornull(p_decal); ERR_FAIL_COND(!decal); decal->extents = p_extents; - decal->instance_dependency.instance_notify_changed(true, false); + decal->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } -void RasterizerStorageRD::decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) { +void RendererStorageRD::decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) { Decal *decal = decal_owner.getornull(p_decal); ERR_FAIL_COND(!decal); ERR_FAIL_INDEX(p_type, RS::DECAL_TEXTURE_MAX); @@ -5425,35 +5920,35 @@ void RasterizerStorageRD::decal_set_texture(RID p_decal, RS::DecalTexture p_type texture_add_to_decal_atlas(decal->textures[p_type]); } - decal->instance_dependency.instance_notify_changed(false, true); + decal->dependency.changed_notify(DEPENDENCY_CHANGED_DECAL); } -void RasterizerStorageRD::decal_set_emission_energy(RID p_decal, float p_energy) { +void RendererStorageRD::decal_set_emission_energy(RID p_decal, float p_energy) { Decal *decal = decal_owner.getornull(p_decal); ERR_FAIL_COND(!decal); decal->emission_energy = p_energy; } -void RasterizerStorageRD::decal_set_albedo_mix(RID p_decal, float p_mix) { +void RendererStorageRD::decal_set_albedo_mix(RID p_decal, float p_mix) { Decal *decal = decal_owner.getornull(p_decal); ERR_FAIL_COND(!decal); decal->albedo_mix = p_mix; } -void RasterizerStorageRD::decal_set_modulate(RID p_decal, const Color &p_modulate) { +void RendererStorageRD::decal_set_modulate(RID p_decal, const Color &p_modulate) { Decal *decal = decal_owner.getornull(p_decal); ERR_FAIL_COND(!decal); decal->modulate = p_modulate; } -void RasterizerStorageRD::decal_set_cull_mask(RID p_decal, uint32_t p_layers) { +void RendererStorageRD::decal_set_cull_mask(RID p_decal, uint32_t p_layers) { Decal *decal = decal_owner.getornull(p_decal); ERR_FAIL_COND(!decal); decal->cull_mask = p_layers; - decal->instance_dependency.instance_notify_changed(true, false); + decal->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } -void RasterizerStorageRD::decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) { +void RendererStorageRD::decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) { Decal *decal = decal_owner.getornull(p_decal); ERR_FAIL_COND(!decal); decal->distance_fade = p_enabled; @@ -5461,31 +5956,34 @@ void RasterizerStorageRD::decal_set_distance_fade(RID p_decal, bool p_enabled, f decal->distance_fade_length = p_length; } -void RasterizerStorageRD::decal_set_fade(RID p_decal, float p_above, float p_below) { +void RendererStorageRD::decal_set_fade(RID p_decal, float p_above, float p_below) { Decal *decal = decal_owner.getornull(p_decal); ERR_FAIL_COND(!decal); decal->upper_fade = p_above; decal->lower_fade = p_below; } -void RasterizerStorageRD::decal_set_normal_fade(RID p_decal, float p_fade) { +void RendererStorageRD::decal_set_normal_fade(RID p_decal, float p_fade) { Decal *decal = decal_owner.getornull(p_decal); ERR_FAIL_COND(!decal); decal->normal_fade = p_fade; } -AABB RasterizerStorageRD::decal_get_aabb(RID p_decal) const { +AABB RendererStorageRD::decal_get_aabb(RID p_decal) const { Decal *decal = decal_owner.getornull(p_decal); ERR_FAIL_COND_V(!decal, AABB()); return AABB(-decal->extents, decal->extents * 2.0); } -RID RasterizerStorageRD::gi_probe_create() { - return gi_probe_owner.make_rid(GIProbe()); +RID RendererStorageRD::gi_probe_allocate() { + return gi_probe_owner.allocate_rid(); +} +void RendererStorageRD::gi_probe_initialize(RID p_gi_probe) { + gi_probe_owner.initialize_rid(p_gi_probe, GIProbe()); } -void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) { +void RendererStorageRD::gi_probe_allocate_data(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND(!gi_probe); @@ -5528,7 +6026,7 @@ void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_t tf.width = gi_probe->octree_size.x; tf.height = gi_probe->octree_size.y; tf.depth = gi_probe->octree_size.z; - tf.type = RD::TEXTURE_TYPE_3D; + tf.texture_type = RD::TEXTURE_TYPE_3D; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; Vector<Vector<uint8_t>> s; s.push_back(p_distance_field); @@ -5557,21 +6055,21 @@ void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_t Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 1; u.ids.push_back(gi_probe->octree_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 2; u.ids.push_back(gi_probe->data_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 3; u.ids.push_back(shared_tex); uniforms.push_back(u); @@ -5607,23 +6105,23 @@ void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_t gi_probe->version++; gi_probe->data_version++; - gi_probe->instance_dependency.instance_notify_changed(true, false); + gi_probe->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } -AABB RasterizerStorageRD::gi_probe_get_bounds(RID p_gi_probe) const { +AABB RendererStorageRD::gi_probe_get_bounds(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, AABB()); return gi_probe->bounds; } -Vector3i RasterizerStorageRD::gi_probe_get_octree_size(RID p_gi_probe) const { +Vector3i RendererStorageRD::gi_probe_get_octree_size(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, Vector3i()); return gi_probe->octree_size; } -Vector<uint8_t> RasterizerStorageRD::gi_probe_get_octree_cells(RID p_gi_probe) const { +Vector<uint8_t> RendererStorageRD::gi_probe_get_octree_cells(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, Vector<uint8_t>()); @@ -5633,7 +6131,7 @@ Vector<uint8_t> RasterizerStorageRD::gi_probe_get_octree_cells(RID p_gi_probe) c return Vector<uint8_t>(); } -Vector<uint8_t> RasterizerStorageRD::gi_probe_get_data_cells(RID p_gi_probe) const { +Vector<uint8_t> RendererStorageRD::gi_probe_get_data_cells(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, Vector<uint8_t>()); @@ -5643,7 +6141,7 @@ Vector<uint8_t> RasterizerStorageRD::gi_probe_get_data_cells(RID p_gi_probe) con return Vector<uint8_t>(); } -Vector<uint8_t> RasterizerStorageRD::gi_probe_get_distance_field(RID p_gi_probe) const { +Vector<uint8_t> RendererStorageRD::gi_probe_get_distance_field(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, Vector<uint8_t>()); @@ -5653,21 +6151,21 @@ Vector<uint8_t> RasterizerStorageRD::gi_probe_get_distance_field(RID p_gi_probe) return Vector<uint8_t>(); } -Vector<int> RasterizerStorageRD::gi_probe_get_level_counts(RID p_gi_probe) const { +Vector<int> RendererStorageRD::gi_probe_get_level_counts(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, Vector<int>()); return gi_probe->level_counts; } -Transform RasterizerStorageRD::gi_probe_get_to_cell_xform(RID p_gi_probe) const { +Transform RendererStorageRD::gi_probe_get_to_cell_xform(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, Transform()); return gi_probe->to_cell_xform; } -void RasterizerStorageRD::gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) { +void RendererStorageRD::gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND(!gi_probe); @@ -5675,14 +6173,14 @@ void RasterizerStorageRD::gi_probe_set_dynamic_range(RID p_gi_probe, float p_ran gi_probe->version++; } -float RasterizerStorageRD::gi_probe_get_dynamic_range(RID p_gi_probe) const { +float RendererStorageRD::gi_probe_get_dynamic_range(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, 0); return gi_probe->dynamic_range; } -void RasterizerStorageRD::gi_probe_set_propagation(RID p_gi_probe, float p_range) { +void RendererStorageRD::gi_probe_set_propagation(RID p_gi_probe, float p_range) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND(!gi_probe); @@ -5690,98 +6188,98 @@ void RasterizerStorageRD::gi_probe_set_propagation(RID p_gi_probe, float p_range gi_probe->version++; } -float RasterizerStorageRD::gi_probe_get_propagation(RID p_gi_probe) const { +float RendererStorageRD::gi_probe_get_propagation(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, 0); return gi_probe->propagation; } -void RasterizerStorageRD::gi_probe_set_energy(RID p_gi_probe, float p_energy) { +void RendererStorageRD::gi_probe_set_energy(RID p_gi_probe, float p_energy) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND(!gi_probe); gi_probe->energy = p_energy; } -float RasterizerStorageRD::gi_probe_get_energy(RID p_gi_probe) const { +float RendererStorageRD::gi_probe_get_energy(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, 0); return gi_probe->energy; } -void RasterizerStorageRD::gi_probe_set_ao(RID p_gi_probe, float p_ao) { +void RendererStorageRD::gi_probe_set_ao(RID p_gi_probe, float p_ao) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND(!gi_probe); gi_probe->ao = p_ao; } -float RasterizerStorageRD::gi_probe_get_ao(RID p_gi_probe) const { +float RendererStorageRD::gi_probe_get_ao(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, 0); return gi_probe->ao; } -void RasterizerStorageRD::gi_probe_set_ao_size(RID p_gi_probe, float p_strength) { +void RendererStorageRD::gi_probe_set_ao_size(RID p_gi_probe, float p_strength) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND(!gi_probe); gi_probe->ao_size = p_strength; } -float RasterizerStorageRD::gi_probe_get_ao_size(RID p_gi_probe) const { +float RendererStorageRD::gi_probe_get_ao_size(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, 0); return gi_probe->ao_size; } -void RasterizerStorageRD::gi_probe_set_bias(RID p_gi_probe, float p_bias) { +void RendererStorageRD::gi_probe_set_bias(RID p_gi_probe, float p_bias) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND(!gi_probe); gi_probe->bias = p_bias; } -float RasterizerStorageRD::gi_probe_get_bias(RID p_gi_probe) const { +float RendererStorageRD::gi_probe_get_bias(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, 0); return gi_probe->bias; } -void RasterizerStorageRD::gi_probe_set_normal_bias(RID p_gi_probe, float p_normal_bias) { +void RendererStorageRD::gi_probe_set_normal_bias(RID p_gi_probe, float p_normal_bias) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND(!gi_probe); gi_probe->normal_bias = p_normal_bias; } -float RasterizerStorageRD::gi_probe_get_normal_bias(RID p_gi_probe) const { +float RendererStorageRD::gi_probe_get_normal_bias(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, 0); return gi_probe->normal_bias; } -void RasterizerStorageRD::gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) { +void RendererStorageRD::gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND(!gi_probe); gi_probe->anisotropy_strength = p_strength; } -float RasterizerStorageRD::gi_probe_get_anisotropy_strength(RID p_gi_probe) const { +float RendererStorageRD::gi_probe_get_anisotropy_strength(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, 0); return gi_probe->anisotropy_strength; } -void RasterizerStorageRD::gi_probe_set_interior(RID p_gi_probe, bool p_enable) { +void RendererStorageRD::gi_probe_set_interior(RID p_gi_probe, bool p_enable) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND(!gi_probe); gi_probe->interior = p_enable; } -void RasterizerStorageRD::gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) { +void RendererStorageRD::gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND(!gi_probe); @@ -5789,43 +6287,43 @@ void RasterizerStorageRD::gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_en gi_probe->version++; } -bool RasterizerStorageRD::gi_probe_is_using_two_bounces(RID p_gi_probe) const { +bool RendererStorageRD::gi_probe_is_using_two_bounces(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, false); return gi_probe->use_two_bounces; } -bool RasterizerStorageRD::gi_probe_is_interior(RID p_gi_probe) const { +bool RendererStorageRD::gi_probe_is_interior(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, 0); return gi_probe->interior; } -uint32_t RasterizerStorageRD::gi_probe_get_version(RID p_gi_probe) { +uint32_t RendererStorageRD::gi_probe_get_version(RID p_gi_probe) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, 0); return gi_probe->version; } -uint32_t RasterizerStorageRD::gi_probe_get_data_version(RID p_gi_probe) { +uint32_t RendererStorageRD::gi_probe_get_data_version(RID p_gi_probe) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, 0); return gi_probe->data_version; } -RID RasterizerStorageRD::gi_probe_get_octree_buffer(RID p_gi_probe) const { +RID RendererStorageRD::gi_probe_get_octree_buffer(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, RID()); return gi_probe->octree_buffer; } -RID RasterizerStorageRD::gi_probe_get_data_buffer(RID p_gi_probe) const { +RID RendererStorageRD::gi_probe_get_data_buffer(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, RID()); return gi_probe->data_buffer; } -RID RasterizerStorageRD::gi_probe_get_sdf_texture(RID p_gi_probe) { +RID RendererStorageRD::gi_probe_get_sdf_texture(RID p_gi_probe) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, RID()); @@ -5834,11 +6332,15 @@ RID RasterizerStorageRD::gi_probe_get_sdf_texture(RID p_gi_probe) { /* LIGHTMAP API */ -RID RasterizerStorageRD::lightmap_create() { - return lightmap_owner.make_rid(Lightmap()); +RID RendererStorageRD::lightmap_allocate() { + return lightmap_owner.allocate_rid(); +} + +void RendererStorageRD::lightmap_initialize(RID p_lightmap) { + lightmap_owner.initialize_rid(p_lightmap, Lightmap()); } -void RasterizerStorageRD::lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) { +void RendererStorageRD::lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) { Lightmap *lm = lightmap_owner.getornull(p_lightmap); ERR_FAIL_COND(!lm); @@ -5886,19 +6388,19 @@ void RasterizerStorageRD::lightmap_set_textures(RID p_lightmap, RID p_light, boo } } -void RasterizerStorageRD::lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) { +void RendererStorageRD::lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) { Lightmap *lm = lightmap_owner.getornull(p_lightmap); ERR_FAIL_COND(!lm); lm->bounds = p_bounds; } -void RasterizerStorageRD::lightmap_set_probe_interior(RID p_lightmap, bool p_interior) { +void RendererStorageRD::lightmap_set_probe_interior(RID p_lightmap, bool p_interior) { Lightmap *lm = lightmap_owner.getornull(p_lightmap); ERR_FAIL_COND(!lm); lm->interior = p_interior; } -void RasterizerStorageRD::lightmap_set_probe_capture_data(RID p_lightmap, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) { +void RendererStorageRD::lightmap_set_probe_capture_data(RID p_lightmap, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) { Lightmap *lm = lightmap_owner.getornull(p_lightmap); ERR_FAIL_COND(!lm); @@ -5914,36 +6416,36 @@ void RasterizerStorageRD::lightmap_set_probe_capture_data(RID p_lightmap, const lm->tetrahedra = p_tetrahedra; } -PackedVector3Array RasterizerStorageRD::lightmap_get_probe_capture_points(RID p_lightmap) const { +PackedVector3Array RendererStorageRD::lightmap_get_probe_capture_points(RID p_lightmap) const { Lightmap *lm = lightmap_owner.getornull(p_lightmap); ERR_FAIL_COND_V(!lm, PackedVector3Array()); return lm->points; } -PackedColorArray RasterizerStorageRD::lightmap_get_probe_capture_sh(RID p_lightmap) const { +PackedColorArray RendererStorageRD::lightmap_get_probe_capture_sh(RID p_lightmap) const { Lightmap *lm = lightmap_owner.getornull(p_lightmap); ERR_FAIL_COND_V(!lm, PackedColorArray()); return lm->point_sh; } -PackedInt32Array RasterizerStorageRD::lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const { +PackedInt32Array RendererStorageRD::lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const { Lightmap *lm = lightmap_owner.getornull(p_lightmap); ERR_FAIL_COND_V(!lm, PackedInt32Array()); return lm->tetrahedra; } -PackedInt32Array RasterizerStorageRD::lightmap_get_probe_capture_bsp_tree(RID p_lightmap) const { +PackedInt32Array RendererStorageRD::lightmap_get_probe_capture_bsp_tree(RID p_lightmap) const { Lightmap *lm = lightmap_owner.getornull(p_lightmap); ERR_FAIL_COND_V(!lm, PackedInt32Array()); return lm->bsp_tree; } -void RasterizerStorageRD::lightmap_set_probe_capture_update_speed(float p_speed) { +void RendererStorageRD::lightmap_set_probe_capture_update_speed(float p_speed) { lightmap_probe_capture_update_speed = p_speed; } -void RasterizerStorageRD::lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_point, Color *r_sh) { +void RendererStorageRD::lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_point, Color *r_sh) { Lightmap *lm = lightmap_owner.getornull(p_lightmap); ERR_FAIL_COND(!lm); @@ -5993,13 +6495,13 @@ void RasterizerStorageRD::lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p } } -bool RasterizerStorageRD::lightmap_is_interior(RID p_lightmap) const { +bool RendererStorageRD::lightmap_is_interior(RID p_lightmap) const { const Lightmap *lm = lightmap_owner.getornull(p_lightmap); ERR_FAIL_COND_V(!lm, false); return lm->interior; } -AABB RasterizerStorageRD::lightmap_get_aabb(RID p_lightmap) const { +AABB RendererStorageRD::lightmap_get_aabb(RID p_lightmap) const { const Lightmap *lm = lightmap_owner.getornull(p_lightmap); ERR_FAIL_COND_V(!lm, AABB()); return lm->bounds; @@ -6007,7 +6509,7 @@ AABB RasterizerStorageRD::lightmap_get_aabb(RID p_lightmap) const { /* RENDER TARGET API */ -void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) { +void RendererStorageRD::_clear_render_target(RenderTarget *rt) { //free in reverse dependency order if (rt->framebuffer.is_valid()) { RD::get_singleton()->free(rt->framebuffer); @@ -6035,10 +6537,11 @@ void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) { rt->color = RID(); } -void RasterizerStorageRD::_update_render_target(RenderTarget *rt) { +void RendererStorageRD::_update_render_target(RenderTarget *rt) { if (rt->texture.is_null()) { //create a placeholder until updated - rt->texture = texture_2d_placeholder_create(); + rt->texture = texture_allocate(); + texture_2d_placeholder_initialize(rt->texture); Texture *tex = texture_owner.getornull(rt->texture); tex->is_render_target = true; } @@ -6062,7 +6565,7 @@ void RasterizerStorageRD::_update_render_target(RenderTarget *rt) { rd_format.depth = 1; rd_format.array_layers = 1; rd_format.mipmaps = 1; - rd_format.type = RD::TEXTURE_TYPE_2D; + rd_format.texture_type = RD::TEXTURE_TYPE_2D; rd_format.samples = RD::TEXTURE_SAMPLES_1; rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; rd_format.shareable_formats.push_back(rt->color_format); @@ -6123,7 +6626,7 @@ void RasterizerStorageRD::_update_render_target(RenderTarget *rt) { } } -void RasterizerStorageRD::_create_render_target_backbuffer(RenderTarget *rt) { +void RendererStorageRD::_create_render_target_backbuffer(RenderTarget *rt) { ERR_FAIL_COND(rt->backbuffer.is_valid()); uint32_t mipmaps_required = Image::get_image_required_mipmaps(rt->size.width, rt->size.height, Image::FORMAT_RGBA8); @@ -6131,7 +6634,7 @@ void RasterizerStorageRD::_create_render_target_backbuffer(RenderTarget *rt) { tf.format = rt->color_format; tf.width = rt->size.width; tf.height = rt->size.height; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; tf.mipmaps = mipmaps_required; @@ -6171,7 +6674,7 @@ void RasterizerStorageRD::_create_render_target_backbuffer(RenderTarget *rt) { } } -RID RasterizerStorageRD::render_target_create() { +RID RendererStorageRD::render_target_create() { RenderTarget render_target; render_target.was_used = false; @@ -6184,11 +6687,11 @@ RID RasterizerStorageRD::render_target_create() { return render_target_owner.make_rid(render_target); } -void RasterizerStorageRD::render_target_set_position(RID p_render_target, int p_x, int p_y) { +void RendererStorageRD::render_target_set_position(RID p_render_target, int p_x, int p_y) { //unused for this render target } -void RasterizerStorageRD::render_target_set_size(RID p_render_target, int p_width, int p_height) { +void RendererStorageRD::render_target_set_size(RID p_render_target, int p_width, int p_height) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); rt->size.x = p_width; @@ -6196,63 +6699,63 @@ void RasterizerStorageRD::render_target_set_size(RID p_render_target, int p_widt _update_render_target(rt); } -RID RasterizerStorageRD::render_target_get_texture(RID p_render_target) { +RID RendererStorageRD::render_target_get_texture(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, RID()); return rt->texture; } -void RasterizerStorageRD::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) { +void RendererStorageRD::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) { } -void RasterizerStorageRD::render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) { +void RendererStorageRD::render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); rt->flags[p_flag] = p_value; _update_render_target(rt); } -bool RasterizerStorageRD::render_target_was_used(RID p_render_target) { +bool RendererStorageRD::render_target_was_used(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, false); return rt->was_used; } -void RasterizerStorageRD::render_target_set_as_unused(RID p_render_target) { +void RendererStorageRD::render_target_set_as_unused(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); rt->was_used = false; } -Size2 RasterizerStorageRD::render_target_get_size(RID p_render_target) { +Size2 RendererStorageRD::render_target_get_size(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, Size2()); return rt->size; } -RID RasterizerStorageRD::render_target_get_rd_framebuffer(RID p_render_target) { +RID RendererStorageRD::render_target_get_rd_framebuffer(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, RID()); return rt->framebuffer; } -RID RasterizerStorageRD::render_target_get_rd_texture(RID p_render_target) { +RID RendererStorageRD::render_target_get_rd_texture(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, RID()); return rt->color; } -RID RasterizerStorageRD::render_target_get_rd_backbuffer(RID p_render_target) { +RID RendererStorageRD::render_target_get_rd_backbuffer(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, RID()); return rt->backbuffer; } -RID RasterizerStorageRD::render_target_get_rd_backbuffer_framebuffer(RID p_render_target) { +RID RendererStorageRD::render_target_get_rd_backbuffer_framebuffer(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, RID()); @@ -6263,32 +6766,32 @@ RID RasterizerStorageRD::render_target_get_rd_backbuffer_framebuffer(RID p_rende return rt->backbuffer_fb; } -void RasterizerStorageRD::render_target_request_clear(RID p_render_target, const Color &p_clear_color) { +void RendererStorageRD::render_target_request_clear(RID p_render_target, const Color &p_clear_color) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); rt->clear_requested = true; rt->clear_color = p_clear_color; } -bool RasterizerStorageRD::render_target_is_clear_requested(RID p_render_target) { +bool RendererStorageRD::render_target_is_clear_requested(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, false); return rt->clear_requested; } -Color RasterizerStorageRD::render_target_get_clear_request_color(RID p_render_target) { +Color RendererStorageRD::render_target_get_clear_request_color(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, Color()); return rt->clear_color; } -void RasterizerStorageRD::render_target_disable_clear_request(RID p_render_target) { +void RendererStorageRD::render_target_disable_clear_request(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); rt->clear_requested = false; } -void RasterizerStorageRD::render_target_do_clear_request(RID p_render_target) { +void RendererStorageRD::render_target_do_clear_request(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); if (!rt->clear_requested) { @@ -6301,7 +6804,7 @@ void RasterizerStorageRD::render_target_do_clear_request(RID p_render_target) { rt->clear_requested = false; } -void RasterizerStorageRD::render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) { +void RendererStorageRD::render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); if (rt->sdf_oversize == p_size && rt->sdf_scale == p_scale) { @@ -6314,7 +6817,7 @@ void RasterizerStorageRD::render_target_set_sdf_size_and_scale(RID p_render_targ _render_target_clear_sdf(rt); } -Rect2i RasterizerStorageRD::_render_target_get_sdf_rect(const RenderTarget *rt) const { +Rect2i RendererStorageRD::_render_target_get_sdf_rect(const RenderTarget *rt) const { Size2i margin; int scale; switch (rt->sdf_oversize) { @@ -6343,14 +6846,14 @@ Rect2i RasterizerStorageRD::_render_target_get_sdf_rect(const RenderTarget *rt) return r; } -Rect2i RasterizerStorageRD::render_target_get_sdf_rect(RID p_render_target) const { +Rect2i RendererStorageRD::render_target_get_sdf_rect(RID p_render_target) const { const RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, Rect2i()); return _render_target_get_sdf_rect(rt); } -RID RasterizerStorageRD::render_target_get_sdf_texture(RID p_render_target) { +RID RendererStorageRD::render_target_get_sdf_texture(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, RID()); if (rt->sdf_buffer_read.is_null()) { @@ -6360,7 +6863,7 @@ RID RasterizerStorageRD::render_target_get_sdf_texture(RID p_render_target) { tformat.width = 4; tformat.height = 4; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT; - tformat.type = RD::TEXTURE_TYPE_2D; + tformat.texture_type = RD::TEXTURE_TYPE_2D; Vector<uint8_t> pv; pv.resize(16 * 4); @@ -6373,7 +6876,7 @@ RID RasterizerStorageRD::render_target_get_sdf_texture(RID p_render_target) { return rt->sdf_buffer_read; } -void RasterizerStorageRD::_render_target_allocate_sdf(RenderTarget *rt) { +void RendererStorageRD::_render_target_allocate_sdf(RenderTarget *rt) { ERR_FAIL_COND(rt->sdf_buffer_write_fb.is_valid()); if (rt->sdf_buffer_read.is_valid()) { RD::get_singleton()->free(rt->sdf_buffer_read); @@ -6387,7 +6890,7 @@ void RasterizerStorageRD::_render_target_allocate_sdf(RenderTarget *rt) { tformat.width = size.width; tformat.height = size.height; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; - tformat.type = RD::TEXTURE_TYPE_2D; + tformat.texture_type = RD::TEXTURE_TYPE_2D; rt->sdf_buffer_write = RD::get_singleton()->texture_create(tformat, RD::TextureView()); @@ -6434,28 +6937,28 @@ void RasterizerStorageRD::_render_target_allocate_sdf(RenderTarget *rt) { Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(rt->sdf_buffer_write); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; u.ids.push_back(rt->sdf_buffer_read); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 3; u.ids.push_back(rt->sdf_buffer_process[0]); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 4; u.ids.push_back(rt->sdf_buffer_process[1]); uniforms.push_back(u); @@ -6467,7 +6970,7 @@ void RasterizerStorageRD::_render_target_allocate_sdf(RenderTarget *rt) { } } -void RasterizerStorageRD::_render_target_clear_sdf(RenderTarget *rt) { +void RendererStorageRD::_render_target_clear_sdf(RenderTarget *rt) { if (rt->sdf_buffer_read.is_valid()) { RD::get_singleton()->free(rt->sdf_buffer_read); rt->sdf_buffer_read = RID(); @@ -6485,7 +6988,7 @@ void RasterizerStorageRD::_render_target_clear_sdf(RenderTarget *rt) { } } -RID RasterizerStorageRD::render_target_get_sdf_framebuffer(RID p_render_target) { +RID RendererStorageRD::render_target_get_sdf_framebuffer(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, RID()); @@ -6495,7 +6998,7 @@ RID RasterizerStorageRD::render_target_get_sdf_framebuffer(RID p_render_target) return rt->sdf_buffer_write_fb; } -void RasterizerStorageRD::render_target_sdf_process(RID p_render_target) { +void RendererStorageRD::render_target_sdf_process(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); ERR_FAIL_COND(rt->sdf_buffer_write_fb.is_null()); @@ -6538,7 +7041,7 @@ void RasterizerStorageRD::render_target_sdf_process(RID p_render_target) { RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rt->sdf_buffer_process_uniform_sets[1], 0); //fill [0] RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(RenderTargetSDF::PushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, push_constant.size[0], push_constant.size[1], 1, 8, 8, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, push_constant.size[0], push_constant.size[1], 1); /* Process */ @@ -6554,7 +7057,7 @@ void RasterizerStorageRD::render_target_sdf_process(RID p_render_target) { RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rt->sdf_buffer_process_uniform_sets[swap ? 1 : 0], 0); push_constant.stride = stride; RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(RenderTargetSDF::PushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, push_constant.size[0], push_constant.size[1], 1, 8, 8, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, push_constant.size[0], push_constant.size[1], 1); stride /= 2; swap = !swap; RD::get_singleton()->compute_list_add_barrier(compute_list); @@ -6565,12 +7068,12 @@ void RasterizerStorageRD::render_target_sdf_process(RID p_render_target) { RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, rt_sdf.pipelines[shrink ? RenderTargetSDF::SHADER_STORE_SHRINK : RenderTargetSDF::SHADER_STORE]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rt->sdf_buffer_process_uniform_sets[swap ? 1 : 0], 0); RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(RenderTargetSDF::PushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, push_constant.size[0], push_constant.size[1], 1, 8, 8, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, push_constant.size[0], push_constant.size[1], 1); RD::get_singleton()->compute_list_end(); } -void RasterizerStorageRD::render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps) { +void RendererStorageRD::render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); if (!rt->backbuffer.is_valid()) { @@ -6581,7 +7084,7 @@ void RasterizerStorageRD::render_target_copy_to_back_buffer(RID p_render_target, if (p_region == Rect2i()) { region.size = rt->size; } else { - region = Rect2i(Size2i(), rt->size).clip(p_region); + region = Rect2i(Size2i(), rt->size).intersection(p_region); if (region.size == Size2i()) { return; //nothing to do } @@ -6610,7 +7113,7 @@ void RasterizerStorageRD::render_target_copy_to_back_buffer(RID p_render_target, } } -void RasterizerStorageRD::render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color) { +void RendererStorageRD::render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); if (!rt->backbuffer.is_valid()) { @@ -6621,7 +7124,7 @@ void RasterizerStorageRD::render_target_clear_back_buffer(RID p_render_target, c if (p_region == Rect2i()) { region.size = rt->size; } else { - region = Rect2i(Size2i(), rt->size).clip(p_region); + region = Rect2i(Size2i(), rt->size).intersection(p_region); if (region.size == Size2i()) { return; //nothing to do } @@ -6631,7 +7134,7 @@ void RasterizerStorageRD::render_target_clear_back_buffer(RID p_render_target, c effects.set_color(rt->backbuffer_mipmap0, p_color, region, true); } -void RasterizerStorageRD::render_target_gen_back_buffer_mipmaps(RID p_render_target, const Rect2i &p_region) { +void RendererStorageRD::render_target_gen_back_buffer_mipmaps(RID p_render_target, const Rect2i &p_region) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); if (!rt->backbuffer.is_valid()) { @@ -6642,7 +7145,7 @@ void RasterizerStorageRD::render_target_gen_back_buffer_mipmaps(RID p_render_tar if (p_region == Rect2i()) { region.size = rt->size; } else { - region = Rect2i(Size2i(), rt->size).clip(p_region); + region = Rect2i(Size2i(), rt->size).intersection(p_region); if (region.size == Size2i()) { return; //nothing to do } @@ -6663,70 +7166,70 @@ void RasterizerStorageRD::render_target_gen_back_buffer_mipmaps(RID p_render_tar } } -RID RasterizerStorageRD::render_target_get_framebuffer_uniform_set(RID p_render_target) { +RID RendererStorageRD::render_target_get_framebuffer_uniform_set(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, RID()); return rt->framebuffer_uniform_set; } -RID RasterizerStorageRD::render_target_get_backbuffer_uniform_set(RID p_render_target) { +RID RendererStorageRD::render_target_get_backbuffer_uniform_set(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, RID()); return rt->backbuffer_uniform_set; } -void RasterizerStorageRD::render_target_set_framebuffer_uniform_set(RID p_render_target, RID p_uniform_set) { +void RendererStorageRD::render_target_set_framebuffer_uniform_set(RID p_render_target, RID p_uniform_set) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); rt->framebuffer_uniform_set = p_uniform_set; } -void RasterizerStorageRD::render_target_set_backbuffer_uniform_set(RID p_render_target, RID p_uniform_set) { +void RendererStorageRD::render_target_set_backbuffer_uniform_set(RID p_render_target, RID p_uniform_set) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); rt->backbuffer_uniform_set = p_uniform_set; } -void RasterizerStorageRD::base_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) { +void RendererStorageRD::base_update_dependency(RID p_base, DependencyTracker *p_instance) { if (mesh_owner.owns(p_base)) { Mesh *mesh = mesh_owner.getornull(p_base); - p_instance->update_dependency(&mesh->instance_dependency); + p_instance->update_dependency(&mesh->dependency); } else if (multimesh_owner.owns(p_base)) { MultiMesh *multimesh = multimesh_owner.getornull(p_base); - p_instance->update_dependency(&multimesh->instance_dependency); + p_instance->update_dependency(&multimesh->dependency); if (multimesh->mesh.is_valid()) { base_update_dependency(multimesh->mesh, p_instance); } } else if (reflection_probe_owner.owns(p_base)) { ReflectionProbe *rp = reflection_probe_owner.getornull(p_base); - p_instance->update_dependency(&rp->instance_dependency); + p_instance->update_dependency(&rp->dependency); } else if (decal_owner.owns(p_base)) { Decal *decal = decal_owner.getornull(p_base); - p_instance->update_dependency(&decal->instance_dependency); + p_instance->update_dependency(&decal->dependency); } else if (gi_probe_owner.owns(p_base)) { GIProbe *gip = gi_probe_owner.getornull(p_base); - p_instance->update_dependency(&gip->instance_dependency); + p_instance->update_dependency(&gip->dependency); } else if (lightmap_owner.owns(p_base)) { Lightmap *lm = lightmap_owner.getornull(p_base); - p_instance->update_dependency(&lm->instance_dependency); + p_instance->update_dependency(&lm->dependency); } else if (light_owner.owns(p_base)) { Light *l = light_owner.getornull(p_base); - p_instance->update_dependency(&l->instance_dependency); + p_instance->update_dependency(&l->dependency); } else if (particles_owner.owns(p_base)) { Particles *p = particles_owner.getornull(p_base); - p_instance->update_dependency(&p->instance_dependency); + p_instance->update_dependency(&p->dependency); } else if (particles_collision_owner.owns(p_base)) { ParticlesCollision *pc = particles_collision_owner.getornull(p_base); - p_instance->update_dependency(&pc->instance_dependency); + p_instance->update_dependency(&pc->dependency); } } -void RasterizerStorageRD::skeleton_update_dependency(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) { +void RendererStorageRD::skeleton_update_dependency(RID p_skeleton, DependencyTracker *p_instance) { Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); ERR_FAIL_COND(!skeleton); - p_instance->update_dependency(&skeleton->instance_dependency); + p_instance->update_dependency(&skeleton->dependency); } -RS::InstanceType RasterizerStorageRD::get_base_type(RID p_rid) const { +RS::InstanceType RendererStorageRD::get_base_type(RID p_rid) const { if (mesh_owner.owns(p_rid)) { return RS::INSTANCE_MESH; } @@ -6758,7 +7261,7 @@ RS::InstanceType RasterizerStorageRD::get_base_type(RID p_rid) const { return RS::INSTANCE_NONE; } -void RasterizerStorageRD::texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp) { +void RendererStorageRD::texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp) { if (!decal_atlas.textures.has(p_texture)) { DecalAtlas::Texture t; t.users = 1; @@ -6774,7 +7277,7 @@ void RasterizerStorageRD::texture_add_to_decal_atlas(RID p_texture, bool p_panor } } -void RasterizerStorageRD::texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp) { +void RendererStorageRD::texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp) { DecalAtlas::Texture *t = decal_atlas.textures.getptr(p_texture); ERR_FAIL_COND(!t); t->users--; @@ -6788,15 +7291,15 @@ void RasterizerStorageRD::texture_remove_from_decal_atlas(RID p_texture, bool p_ } } -RID RasterizerStorageRD::decal_atlas_get_texture() const { +RID RendererStorageRD::decal_atlas_get_texture() const { return decal_atlas.texture; } -RID RasterizerStorageRD::decal_atlas_get_texture_srgb() const { +RID RendererStorageRD::decal_atlas_get_texture_srgb() const { return decal_atlas.texture_srgb; } -void RasterizerStorageRD::_update_decal_atlas() { +void RendererStorageRD::_update_decal_atlas() { if (!decal_atlas.dirty) { return; //nothing to do } @@ -6923,12 +7426,13 @@ void RasterizerStorageRD::_update_decal_atlas() { tformat.width = decal_atlas.size.width; tformat.height = decal_atlas.size.height; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; - tformat.type = RD::TEXTURE_TYPE_2D; + tformat.texture_type = RD::TEXTURE_TYPE_2D; tformat.mipmaps = decal_atlas.mipmaps; tformat.shareable_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_UNORM); tformat.shareable_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_SRGB); decal_atlas.texture = RD::get_singleton()->texture_create(tformat, RD::TextureView()); + RD::get_singleton()->texture_clear(decal_atlas.texture, Color(0, 0, 0, 0), 0, decal_atlas.mipmaps, 0, 1); { //create the framebuffer @@ -6983,12 +7487,12 @@ void RasterizerStorageRD::_update_decal_atlas() { prev_texture = mm.texture; } } else { - RD::get_singleton()->texture_clear(mm.texture, clear_color, 0, 1, 0, 1, false); + RD::get_singleton()->texture_clear(mm.texture, clear_color, 0, 1, 0, 1); } } } -int32_t RasterizerStorageRD::_global_variable_allocate(uint32_t p_elements) { +int32_t RendererStorageRD::_global_variable_allocate(uint32_t p_elements) { int32_t idx = 0; while (idx + p_elements <= global_variables.buffer_size) { if (global_variables.buffer_usage[idx].elements == 0) { @@ -7014,7 +7518,7 @@ int32_t RasterizerStorageRD::_global_variable_allocate(uint32_t p_elements) { return -1; } -void RasterizerStorageRD::_global_variable_store_in_buffer(int32_t p_index, RS::GlobalVariableType p_type, const Variant &p_value) { +void RendererStorageRD::_global_variable_store_in_buffer(int32_t p_index, RS::GlobalVariableType p_type, const Variant &p_value) { switch (p_type) { case RS::GLOBAL_VAR_TYPE_BOOL: { GlobalVariables::Value &bv = global_variables.buffer_values[p_index]; @@ -7291,7 +7795,7 @@ void RasterizerStorageRD::_global_variable_store_in_buffer(int32_t p_index, RS:: } } -void RasterizerStorageRD::_global_variable_mark_buffer_dirty(int32_t p_index, int32_t p_elements) { +void RendererStorageRD::_global_variable_mark_buffer_dirty(int32_t p_index, int32_t p_elements) { int32_t prev_chunk = -1; for (int32_t i = 0; i < p_elements; i++) { @@ -7307,7 +7811,7 @@ void RasterizerStorageRD::_global_variable_mark_buffer_dirty(int32_t p_index, in } } -void RasterizerStorageRD::global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value) { +void RendererStorageRD::global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value) { ERR_FAIL_COND(global_variables.variables.has(p_name)); GlobalVariables::Variable gv; gv.type = p_type; @@ -7345,7 +7849,7 @@ void RasterizerStorageRD::global_variable_add(const StringName &p_name, RS::Glob global_variables.variables[p_name] = gv; } -void RasterizerStorageRD::global_variable_remove(const StringName &p_name) { +void RendererStorageRD::global_variable_remove(const StringName &p_name) { if (!global_variables.variables.has(p_name)) { return; } @@ -7361,7 +7865,7 @@ void RasterizerStorageRD::global_variable_remove(const StringName &p_name) { global_variables.variables.erase(p_name); } -Vector<StringName> RasterizerStorageRD::global_variable_get_list() const { +Vector<StringName> RendererStorageRD::global_variable_get_list() const { if (!Engine::get_singleton()->is_editor_hint()) { ERR_FAIL_V_MSG(Vector<StringName>(), "This function should never be used outside the editor, it can severely damage performance."); } @@ -7375,7 +7879,7 @@ Vector<StringName> RasterizerStorageRD::global_variable_get_list() const { return names; } -void RasterizerStorageRD::global_variable_set(const StringName &p_name, const Variant &p_value) { +void RendererStorageRD::global_variable_set(const StringName &p_name, const Variant &p_value) { ERR_FAIL_COND(!global_variables.variables.has(p_name)); GlobalVariables::Variable &gv = global_variables.variables[p_name]; gv.value = p_value; @@ -7395,7 +7899,7 @@ void RasterizerStorageRD::global_variable_set(const StringName &p_name, const Va } } -void RasterizerStorageRD::global_variable_set_override(const StringName &p_name, const Variant &p_value) { +void RendererStorageRD::global_variable_set_override(const StringName &p_name, const Variant &p_value) { if (!global_variables.variables.has(p_name)) { return; //variable may not exist } @@ -7423,7 +7927,7 @@ void RasterizerStorageRD::global_variable_set_override(const StringName &p_name, } } -Variant RasterizerStorageRD::global_variable_get(const StringName &p_name) const { +Variant RendererStorageRD::global_variable_get(const StringName &p_name) const { if (!Engine::get_singleton()->is_editor_hint()) { ERR_FAIL_V_MSG(Variant(), "This function should never be used outside the editor, it can severely damage performance."); } @@ -7435,7 +7939,7 @@ Variant RasterizerStorageRD::global_variable_get(const StringName &p_name) const return global_variables.variables[p_name].value; } -RS::GlobalVariableType RasterizerStorageRD::global_variable_get_type_internal(const StringName &p_name) const { +RS::GlobalVariableType RendererStorageRD::global_variable_get_type_internal(const StringName &p_name) const { if (!global_variables.variables.has(p_name)) { return RS::GLOBAL_VAR_TYPE_MAX; } @@ -7443,7 +7947,7 @@ RS::GlobalVariableType RasterizerStorageRD::global_variable_get_type_internal(co return global_variables.variables[p_name].type; } -RS::GlobalVariableType RasterizerStorageRD::global_variable_get_type(const StringName &p_name) const { +RS::GlobalVariableType RendererStorageRD::global_variable_get_type(const StringName &p_name) const { if (!Engine::get_singleton()->is_editor_hint()) { ERR_FAIL_V_MSG(RS::GLOBAL_VAR_TYPE_MAX, "This function should never be used outside the editor, it can severely damage performance."); } @@ -7451,7 +7955,7 @@ RS::GlobalVariableType RasterizerStorageRD::global_variable_get_type(const Strin return global_variable_get_type_internal(p_name); } -void RasterizerStorageRD::global_variables_load_settings(bool p_load_textures) { +void RendererStorageRD::global_variables_load_settings(bool p_load_textures) { List<PropertyInfo> settings; ProjectSettings::get_singleton()->get_property_list(&settings); @@ -7532,15 +8036,15 @@ void RasterizerStorageRD::global_variables_load_settings(bool p_load_textures) { } } -void RasterizerStorageRD::global_variables_clear() { +void RendererStorageRD::global_variables_clear() { global_variables.variables.clear(); //not right but for now enough } -RID RasterizerStorageRD::global_variables_get_storage_buffer() const { +RID RendererStorageRD::global_variables_get_storage_buffer() const { return global_variables.buffer; } -int32_t RasterizerStorageRD::global_variables_instance_allocate(RID p_instance) { +int32_t RendererStorageRD::global_variables_instance_allocate(RID p_instance) { ERR_FAIL_COND_V(global_variables.instance_buffer_pos.has(p_instance), -1); int32_t pos = _global_variable_allocate(ShaderLanguage::MAX_INSTANCE_UNIFORM_INDICES); global_variables.instance_buffer_pos[p_instance] = pos; //save anyway @@ -7549,7 +8053,7 @@ int32_t RasterizerStorageRD::global_variables_instance_allocate(RID p_instance) return pos; } -void RasterizerStorageRD::global_variables_instance_free(RID p_instance) { +void RendererStorageRD::global_variables_instance_free(RID p_instance) { ERR_FAIL_COND(!global_variables.instance_buffer_pos.has(p_instance)); int32_t pos = global_variables.instance_buffer_pos[p_instance]; if (pos >= 0) { @@ -7558,7 +8062,7 @@ void RasterizerStorageRD::global_variables_instance_free(RID p_instance) { global_variables.instance_buffer_pos.erase(p_instance); } -void RasterizerStorageRD::global_variables_instance_update(RID p_instance, int p_index, const Variant &p_value) { +void RendererStorageRD::global_variables_instance_update(RID p_instance, int p_index, const Variant &p_value) { if (!global_variables.instance_buffer_pos.has(p_instance)) { return; //just not allocated, ignore } @@ -7601,7 +8105,7 @@ void RasterizerStorageRD::global_variables_instance_update(RID p_instance, int p _global_variable_mark_buffer_dirty(pos, 1); } -void RasterizerStorageRD::_update_global_variables() { +void RendererStorageRD::_update_global_variables() { if (global_variables.buffer_dirty_region_count > 0) { uint32_t total_regions = global_variables.buffer_size / GlobalVariables::BUFFER_DIRTY_REGION_SIZE; if (total_regions / global_variables.buffer_dirty_region_count <= 4) { @@ -7651,7 +8155,7 @@ void RasterizerStorageRD::_update_global_variables() { } } -void RasterizerStorageRD::update_dirty_resources() { +void RendererStorageRD::update_dirty_resources() { _update_global_variables(); //must do before materials, so it can queue them for update _update_queued_materials(); _update_dirty_multimeshes(); @@ -7659,7 +8163,7 @@ void RasterizerStorageRD::update_dirty_resources() { _update_decal_atlas(); } -bool RasterizerStorageRD::has_os_feature(const String &p_feature) const { +bool RendererStorageRD::has_os_feature(const String &p_feature) const { if (p_feature == "rgtc" && RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC5_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT)) { return true; } @@ -7683,7 +8187,7 @@ bool RasterizerStorageRD::has_os_feature(const String &p_feature) const { return false; } -bool RasterizerStorageRD::free(RID p_rid) { +bool RendererStorageRD::free(RID p_rid) { if (texture_owner.owns(p_rid)) { Texture *t = texture_owner.getornull(p_rid); @@ -7744,28 +8248,49 @@ bool RasterizerStorageRD::free(RID p_rid) { _update_queued_materials(); } material_set_shader(p_rid, RID()); //clean up shader - material->instance_dependency.instance_notify_deleted(p_rid); + material->dependency.deleted_notify(p_rid); + material_owner.free(p_rid); } else if (mesh_owner.owns(p_rid)) { mesh_clear(p_rid); + mesh_set_shadow_mesh(p_rid, RID()); Mesh *mesh = mesh_owner.getornull(p_rid); - mesh->instance_dependency.instance_notify_deleted(p_rid); + mesh->dependency.deleted_notify(p_rid); + if (mesh->instances.size()) { + ERR_PRINT("deleting mesh with active instances"); + } + if (mesh->shadow_owners.size()) { + for (Set<Mesh *>::Element *E = mesh->shadow_owners.front(); E; E = E->next()) { + Mesh *shadow_owner = E->get(); + shadow_owner->shadow_mesh = RID(); + shadow_owner->dependency.changed_notify(DEPENDENCY_CHANGED_MESH); + } + } mesh_owner.free(p_rid); + } else if (mesh_instance_owner.owns(p_rid)) { + MeshInstance *mi = mesh_instance_owner.getornull(p_rid); + _mesh_instance_clear(mi); + mi->mesh->instances.erase(mi->I); + mi->I = nullptr; + + mesh_instance_owner.free(p_rid); + memdelete(mi); + } else if (multimesh_owner.owns(p_rid)) { _update_dirty_multimeshes(); - multimesh_allocate(p_rid, 0, RS::MULTIMESH_TRANSFORM_2D); + multimesh_allocate_data(p_rid, 0, RS::MULTIMESH_TRANSFORM_2D); MultiMesh *multimesh = multimesh_owner.getornull(p_rid); - multimesh->instance_dependency.instance_notify_deleted(p_rid); + multimesh->dependency.deleted_notify(p_rid); multimesh_owner.free(p_rid); } else if (skeleton_owner.owns(p_rid)) { _update_dirty_skeletons(); - skeleton_allocate(p_rid, 0); + skeleton_allocate_data(p_rid, 0); Skeleton *skeleton = skeleton_owner.getornull(p_rid); - skeleton->instance_dependency.instance_notify_deleted(p_rid); + skeleton->dependency.deleted_notify(p_rid); skeleton_owner.free(p_rid); } else if (reflection_probe_owner.owns(p_rid)) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_rid); - reflection_probe->instance_dependency.instance_notify_deleted(p_rid); + reflection_probe->dependency.deleted_notify(p_rid); reflection_probe_owner.free(p_rid); } else if (decal_owner.owns(p_rid)) { Decal *decal = decal_owner.getornull(p_rid); @@ -7774,30 +8299,30 @@ bool RasterizerStorageRD::free(RID p_rid) { texture_remove_from_decal_atlas(decal->textures[i]); } } - decal->instance_dependency.instance_notify_deleted(p_rid); + decal->dependency.deleted_notify(p_rid); decal_owner.free(p_rid); } else if (gi_probe_owner.owns(p_rid)) { - gi_probe_allocate(p_rid, Transform(), AABB(), Vector3i(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<int>()); //deallocate + gi_probe_allocate_data(p_rid, Transform(), AABB(), Vector3i(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<int>()); //deallocate GIProbe *gi_probe = gi_probe_owner.getornull(p_rid); - gi_probe->instance_dependency.instance_notify_deleted(p_rid); + gi_probe->dependency.deleted_notify(p_rid); gi_probe_owner.free(p_rid); } else if (lightmap_owner.owns(p_rid)) { lightmap_set_textures(p_rid, RID(), false); Lightmap *lightmap = lightmap_owner.getornull(p_rid); - lightmap->instance_dependency.instance_notify_deleted(p_rid); + lightmap->dependency.deleted_notify(p_rid); lightmap_owner.free(p_rid); } else if (light_owner.owns(p_rid)) { light_set_projector(p_rid, RID()); //clear projector // delete the texture Light *light = light_owner.getornull(p_rid); - light->instance_dependency.instance_notify_deleted(p_rid); + light->dependency.deleted_notify(p_rid); light_owner.free(p_rid); } else if (particles_owner.owns(p_rid)) { Particles *particles = particles_owner.getornull(p_rid); _particles_free_data(particles); - particles->instance_dependency.instance_notify_deleted(p_rid); + particles->dependency.deleted_notify(p_rid); particles_owner.free(p_rid); } else if (particles_collision_owner.owns(p_rid)) { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_rid); @@ -7805,8 +8330,10 @@ bool RasterizerStorageRD::free(RID p_rid) { if (particles_collision->heightfield_texture.is_valid()) { RD::get_singleton()->free(particles_collision->heightfield_texture); } - particles_collision->instance_dependency.instance_notify_deleted(p_rid); + particles_collision->dependency.deleted_notify(p_rid); particles_collision_owner.free(p_rid); + } else if (particles_collision_instance_owner.owns(p_rid)) { + particles_collision_instance_owner.free(p_rid); } else if (render_target_owner.owns(p_rid)) { RenderTarget *rt = render_target_owner.getornull(p_rid); @@ -7826,41 +8353,41 @@ bool RasterizerStorageRD::free(RID p_rid) { return true; } -RasterizerEffectsRD *RasterizerStorageRD::get_effects() { +EffectsRD *RendererStorageRD::get_effects() { return &effects; } -void RasterizerStorageRD::capture_timestamps_begin() { - RD::get_singleton()->capture_timestamp("Frame Begin", false); +void RendererStorageRD::capture_timestamps_begin() { + RD::get_singleton()->capture_timestamp("Frame Begin"); } -void RasterizerStorageRD::capture_timestamp(const String &p_name) { - RD::get_singleton()->capture_timestamp(p_name, true); +void RendererStorageRD::capture_timestamp(const String &p_name) { + RD::get_singleton()->capture_timestamp(p_name); } -uint32_t RasterizerStorageRD::get_captured_timestamps_count() const { +uint32_t RendererStorageRD::get_captured_timestamps_count() const { return RD::get_singleton()->get_captured_timestamps_count(); } -uint64_t RasterizerStorageRD::get_captured_timestamps_frame() const { +uint64_t RendererStorageRD::get_captured_timestamps_frame() const { return RD::get_singleton()->get_captured_timestamps_frame(); } -uint64_t RasterizerStorageRD::get_captured_timestamp_gpu_time(uint32_t p_index) const { +uint64_t RendererStorageRD::get_captured_timestamp_gpu_time(uint32_t p_index) const { return RD::get_singleton()->get_captured_timestamp_gpu_time(p_index); } -uint64_t RasterizerStorageRD::get_captured_timestamp_cpu_time(uint32_t p_index) const { +uint64_t RendererStorageRD::get_captured_timestamp_cpu_time(uint32_t p_index) const { return RD::get_singleton()->get_captured_timestamp_cpu_time(p_index); } -String RasterizerStorageRD::get_captured_timestamp_name(uint32_t p_index) const { +String RendererStorageRD::get_captured_timestamp_name(uint32_t p_index) const { return RD::get_singleton()->get_captured_timestamp_name(p_index); } -RasterizerStorageRD *RasterizerStorageRD::base_singleton = nullptr; +RendererStorageRD *RendererStorageRD::base_singleton = nullptr; -RasterizerStorageRD::RasterizerStorageRD() { +RendererStorageRD::RendererStorageRD() { base_singleton = this; for (int i = 0; i < SHADER_TYPE_MAX; i++) { @@ -7869,7 +8396,7 @@ RasterizerStorageRD::RasterizerStorageRD() { static_assert(sizeof(GlobalVariables::Value) == 16); - global_variables.buffer_size = GLOBAL_GET("rendering/high_end/global_shader_variables_buffer_size"); + global_variables.buffer_size = GLOBAL_GET("rendering/limits/global_shader_variables/buffer_size"); global_variables.buffer_size = MAX(4096, global_variables.buffer_size); global_variables.buffer_values = memnew_arr(GlobalVariables::Value, global_variables.buffer_size); zeromem(global_variables.buffer_values, sizeof(GlobalVariables::Value) * global_variables.buffer_size); @@ -7886,7 +8413,7 @@ RasterizerStorageRD::RasterizerStorageRD() { tformat.width = 4; tformat.height = 4; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; - tformat.type = RD::TEXTURE_TYPE_2D; + tformat.texture_type = RD::TEXTURE_TYPE_2D; Vector<uint8_t> pv; pv.resize(16 * 4); @@ -7978,7 +8505,7 @@ RasterizerStorageRD::RasterizerStorageRD() { tformat.height = 4; tformat.array_layers = 6; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; - tformat.type = RD::TEXTURE_TYPE_CUBE_ARRAY; + tformat.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY; Vector<uint8_t> pv; pv.resize(16 * 4); @@ -8006,7 +8533,7 @@ RasterizerStorageRD::RasterizerStorageRD() { tformat.height = 4; tformat.array_layers = 6; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; - tformat.type = RD::TEXTURE_TYPE_CUBE; + tformat.texture_type = RD::TEXTURE_TYPE_CUBE; Vector<uint8_t> pv; pv.resize(16 * 4); @@ -8034,7 +8561,7 @@ RasterizerStorageRD::RasterizerStorageRD() { tformat.height = 4; tformat.array_layers = 6; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; - tformat.type = RD::TEXTURE_TYPE_CUBE; + tformat.texture_type = RD::TEXTURE_TYPE_CUBE; Vector<uint8_t> pv; pv.resize(16 * 4); @@ -8062,7 +8589,7 @@ RasterizerStorageRD::RasterizerStorageRD() { tformat.height = 4; tformat.depth = 4; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; - tformat.type = RD::TEXTURE_TYPE_3D; + tformat.texture_type = RD::TEXTURE_TYPE_3D; Vector<uint8_t> pv; pv.resize(64 * 4); @@ -8088,7 +8615,7 @@ RasterizerStorageRD::RasterizerStorageRD() { tformat.height = 4; tformat.array_layers = 1; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; - tformat.type = RD::TEXTURE_TYPE_2D_ARRAY; + tformat.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; Vector<uint8_t> pv; pv.resize(16 * 4); @@ -8137,14 +8664,14 @@ RasterizerStorageRD::RasterizerStorageRD() { sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR; sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR; sampler_state.use_anisotropy = true; - sampler_state.anisotropy_max = 1 << int(GLOBAL_GET("rendering/quality/texture_filters/anisotropic_filtering_level")); + sampler_state.anisotropy_max = 1 << int(GLOBAL_GET("rendering/textures/default_filters/anisotropic_filtering_level")); } break; case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC: { sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR; sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR; sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR; sampler_state.use_anisotropy = true; - sampler_state.anisotropy_max = 1 << int(GLOBAL_GET("rendering/quality/texture_filters/anisotropic_filtering_level")); + sampler_state.anisotropy_max = 1 << int(GLOBAL_GET("rendering/textures/default_filters/anisotropic_filtering_level")); } break; default: { @@ -8249,6 +8776,19 @@ RasterizerStorageRD::RasterizerStorageRD() { mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV2] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); } + for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) { + buffer.resize(sizeof(float) * 4); + { + uint8_t *w = buffer.ptrw(); + float *fptr = (float *)w; + fptr[0] = 0.0; + fptr[1] = 0.0; + fptr[2] = 0.0; + fptr[3] = 0.0; + } + mesh_default_rd_buffers[DEFAULT_RD_BUFFER_CUSTOM0 + i] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); + } + { //bones buffer.resize(sizeof(uint32_t) * 4); { @@ -8301,7 +8841,7 @@ RasterizerStorageRD::RasterizerStorageRD() { } } - lightmap_probe_capture_update_speed = GLOBAL_GET("rendering/lightmapper/probe_capture_update_speed"); + lightmap_probe_capture_update_speed = GLOBAL_GET("rendering/lightmapping/probe_capture/update_speed"); /* Particles */ @@ -8311,8 +8851,8 @@ RasterizerStorageRD::RasterizerStorageRD() { particles_modes.push_back(""); particles_shader.shader.initialize(particles_modes, String()); } - shader_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_PARTICLES, _create_particles_shader_funcs); - material_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_PARTICLES, _create_particles_material_funcs); + shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_PARTICLES, _create_particles_shader_funcs); + material_set_data_request_function(RendererStorageRD::SHADER_TYPE_PARTICLES, _create_particles_material_funcs); { ShaderCompilerRD::DefaultIdentifierActions actions; @@ -8342,7 +8882,7 @@ RasterizerStorageRD::RasterizerStorageRD() { actions.renames["RESTART_VELOCITY"] = "restart_velocity"; actions.renames["RESTART_COLOR"] = "restart_color"; actions.renames["RESTART_CUSTOM"] = "restart_custom"; - actions.renames["emit_particle"] = "emit_particle"; + actions.renames["emit_subparticle"] = "emit_subparticle"; actions.renames["COLLIDED"] = "collided"; actions.renames["COLLISION_NORMAL"] = "collision_normal"; actions.renames["COLLISION_DEPTH"] = "collision_depth"; @@ -8368,19 +8908,21 @@ RasterizerStorageRD::RasterizerStorageRD() { { // default material and shader for particles shader - particles_shader.default_shader = shader_create(); + particles_shader.default_shader = shader_allocate(); + shader_initialize(particles_shader.default_shader); shader_set_code(particles_shader.default_shader, "shader_type particles; void compute() { COLOR = vec4(1.0); } \n"); - particles_shader.default_material = material_create(); + particles_shader.default_material = material_allocate(); + material_initialize(particles_shader.default_material); material_set_shader(particles_shader.default_material, particles_shader.default_shader); - ParticlesMaterialData *md = (ParticlesMaterialData *)material_get_data(particles_shader.default_material, RasterizerStorageRD::SHADER_TYPE_PARTICLES); + ParticlesMaterialData *md = (ParticlesMaterialData *)material_get_data(particles_shader.default_material, RendererStorageRD::SHADER_TYPE_PARTICLES); particles_shader.default_shader_rd = particles_shader.shader.version_get_shader(md->shader_data->version, 0); Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 1; u.ids.resize(12); RID *ids_ptr = u.ids.ptrw(); @@ -8401,7 +8943,7 @@ RasterizerStorageRD::RasterizerStorageRD() { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 2; u.ids.push_back(global_variables_get_storage_buffer()); uniforms.push_back(u); @@ -8444,9 +8986,33 @@ RasterizerStorageRD::RasterizerStorageRD() { rt_sdf.pipelines[i] = RD::get_singleton()->compute_pipeline_create(rt_sdf.shader.version_get_shader(rt_sdf.shader_version, i)); } } + { + Vector<String> skeleton_modes; + skeleton_modes.push_back("\n#define MODE_2D\n"); + skeleton_modes.push_back(""); + + skeleton_shader.shader.initialize(skeleton_modes); + skeleton_shader.version = skeleton_shader.shader.version_create(); + for (int i = 0; i < SkeletonShader::SHADER_MODE_MAX; i++) { + skeleton_shader.version_shader[i] = skeleton_shader.shader.version_get_shader(skeleton_shader.version, i); + skeleton_shader.pipeline[i] = RD::get_singleton()->compute_pipeline_create(skeleton_shader.version_shader[i]); + } + + { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.binding = 0; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(default_rd_storage_buffer); + uniforms.push_back(u); + } + skeleton_shader.default_skeleton_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, skeleton_shader.version_shader[0], SkeletonShader::UNIFORM_SET_SKELETON); + } + } } -RasterizerStorageRD::~RasterizerStorageRD() { +RendererStorageRD::~RendererStorageRD() { memdelete_arr(global_variables.buffer_values); memdelete_arr(global_variables.buffer_usage); memdelete_arr(global_variables.buffer_dirty_regions); @@ -8471,6 +9037,9 @@ RasterizerStorageRD::~RasterizerStorageRD() { giprobe_sdf_shader.version_free(giprobe_sdf_shader_version); particles_shader.copy_shader.version_free(particles_shader.copy_shader_version); + rt_sdf.shader.version_free(rt_sdf.shader_version); + + skeleton_shader.shader.version_free(skeleton_shader.version); RenderingServer::get_singleton()->free(particles_shader.default_material); RenderingServer::get_singleton()->free(particles_shader.default_shader); diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h index 4a708fc94f..68256dc155 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h +++ b/servers/rendering/renderer_rd/renderer_storage_rd.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rasterizer_storage_rd.h */ +/* renderer_storage_rd.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,20 +28,23 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef RASTERIZER_STORAGE_RD_H -#define RASTERIZER_STORAGE_RD_H +#ifndef RENDERING_SERVER_STORAGE_RD_H +#define RENDERING_SERVER_STORAGE_RD_H +#include "core/templates/list.h" +#include "core/templates/local_vector.h" #include "core/templates/rid_owner.h" -#include "servers/rendering/rasterizer.h" -#include "servers/rendering/rasterizer_rd/rasterizer_effects_rd.h" -#include "servers/rendering/rasterizer_rd/shader_compiler_rd.h" -#include "servers/rendering/rasterizer_rd/shaders/canvas_sdf.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/giprobe_sdf.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/particles.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/particles_copy.glsl.gen.h" +#include "servers/rendering/renderer_compositor.h" +#include "servers/rendering/renderer_rd/effects_rd.h" +#include "servers/rendering/renderer_rd/shader_compiler_rd.h" +#include "servers/rendering/renderer_rd/shaders/canvas_sdf.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/particles.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/particles_copy.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/skeleton.glsl.gen.h" +#include "servers/rendering/renderer_scene_render.h" #include "servers/rendering/rendering_device.h" - -class RasterizerStorageRD : public RasterizerStorage { +class RendererStorageRD : public RendererStorage { public: static _FORCE_INLINE_ void store_transform(const Transform &p_mtx, float *p_array) { p_array[0] = p_mtx.basis.elements[0][0]; @@ -92,6 +95,21 @@ public: p_array[11] = 0; } + static _FORCE_INLINE_ void store_transform_transposed_3x4(const Transform &p_mtx, float *p_array) { + p_array[0] = p_mtx.basis.elements[0][0]; + p_array[1] = p_mtx.basis.elements[0][1]; + p_array[2] = p_mtx.basis.elements[0][2]; + p_array[3] = p_mtx.origin.x; + p_array[4] = p_mtx.basis.elements[1][0]; + p_array[5] = p_mtx.basis.elements[1][1]; + p_array[6] = p_mtx.basis.elements[1][2]; + p_array[7] = p_mtx.origin.y; + p_array[8] = p_mtx.basis.elements[2][0]; + p_array[9] = p_mtx.basis.elements[2][1]; + p_array[10] = p_mtx.basis.elements[2][2]; + p_array[11] = p_mtx.origin.z; + } + static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_array) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { @@ -124,6 +142,8 @@ public: virtual bool is_animated() const = 0; virtual bool casts_shadows() const = 0; virtual Variant get_default_parameter(const StringName &p_parameter) const = 0; + virtual RS::ShaderNativeSourceCode get_native_source_code() const { return RS::ShaderNativeSourceCode(); } + virtual ~ShaderData() {} }; @@ -139,7 +159,7 @@ public: virtual ~MaterialData(); private: - friend class RasterizerStorageRD; + friend class RendererStorageRD; RID self; List<RID>::Element *global_buffer_E = nullptr; List<RID>::Element *global_texture_E = nullptr; @@ -170,6 +190,10 @@ public: DEFAULT_RD_BUFFER_COLOR, DEFAULT_RD_BUFFER_TEX_UV, DEFAULT_RD_BUFFER_TEX_UV2, + DEFAULT_RD_BUFFER_CUSTOM0, + DEFAULT_RD_BUFFER_CUSTOM1, + DEFAULT_RD_BUFFER_CUSTOM2, + DEFAULT_RD_BUFFER_CUSTOM3, DEFAULT_RD_BUFFER_BONES, DEFAULT_RD_BUFFER_WEIGHTS, DEFAULT_RD_BUFFER_MAX, @@ -180,7 +204,7 @@ private: struct CanvasTexture { RID diffuse; - RID normalmap; + RID normal_map; RID specular; Color specular_color = Color(1, 1, 1, 1); float shininess = 1.0; @@ -197,7 +221,7 @@ private: ~CanvasTexture(); }; - RID_PtrOwner<CanvasTexture> canvas_texture_owner; + RID_PtrOwner<CanvasTexture, true> canvas_texture_owner; /* TEXTURE API */ struct Texture { @@ -343,7 +367,7 @@ private: }; ShaderDataRequestFunction shader_data_request_func[SHADER_TYPE_MAX]; - mutable RID_Owner<Shader> shader_owner; + mutable RID_Owner<Shader, true> shader_owner; /* Material */ @@ -353,6 +377,7 @@ private: Shader *shader; //shortcut to shader data and type ShaderType shader_type; + uint32_t shader_id = 0; bool update_requested; bool uniform_dirty; bool texture_dirty; @@ -360,11 +385,11 @@ private: Map<StringName, Variant> params; int32_t priority; RID next_pass; - RasterizerScene::InstanceDependency instance_dependency; + Dependency dependency; }; MaterialDataRequestFunction material_data_request_func[SHADER_TYPE_MAX]; - mutable RID_Owner<Material> material_owner; + mutable RID_Owner<Material, true> material_owner; Material *material_update_list; void _material_queue_update(Material *material, bool p_uniform, bool p_texture); @@ -372,13 +397,19 @@ private: /* Mesh */ + struct MeshInstance; + struct Mesh { struct Surface { RS::PrimitiveType primitive = RS::PRIMITIVE_POINTS; uint32_t format = 0; RID vertex_buffer; + RID attribute_buffer; + RID skin_buffer; uint32_t vertex_count = 0; + uint32_t vertex_buffer_size = 0; + uint32_t skin_buffer_size = 0; // A different pipeline needs to be allocated // depending on the inputs available in the @@ -414,8 +445,7 @@ private: Vector<AABB> bone_aabbs; - Vector<RID> blend_shapes; - RID blend_shape_base_buffer; //source buffer goes here when using blend shapes, and main one is uncompressed + RID blend_shape_buffer; RID material; @@ -427,6 +457,8 @@ private: uint32_t particles_render_index = 0; uint64_t particles_render_pass = 0; + + RID uniform_set; }; uint32_t blend_shape_count = 0; @@ -437,17 +469,93 @@ private: Vector<AABB> bone_aabbs; + bool has_bone_weights = false; + AABB aabb; AABB custom_aabb; Vector<RID> material_cache; - RasterizerScene::InstanceDependency instance_dependency; + List<MeshInstance *> instances; + + RID shadow_mesh; + Set<Mesh *> shadow_owners; + + Dependency dependency; + }; + + mutable RID_Owner<Mesh, true> mesh_owner; + + struct MeshInstance { + Mesh *mesh; + RID skeleton; + struct Surface { + RID vertex_buffer; + RID uniform_set; + + Mesh::Surface::Version *versions = nullptr; //allocated on demand + uint32_t version_count = 0; + }; + LocalVector<Surface> surfaces; + LocalVector<float> blend_weights; + + RID blend_weights_buffer; + List<MeshInstance *>::Element *I = nullptr; //used to erase itself + uint64_t skeleton_version = 0; + bool dirty = false; + bool weights_dirty = false; + SelfList<MeshInstance> weight_update_list; + SelfList<MeshInstance> array_update_list; + MeshInstance() : + weight_update_list(this), array_update_list(this) {} }; - mutable RID_Owner<Mesh> mesh_owner; + void _mesh_instance_clear(MeshInstance *mi); + void _mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface); + + mutable RID_PtrOwner<MeshInstance> mesh_instance_owner; + + SelfList<MeshInstance>::List dirty_mesh_instance_weights; + SelfList<MeshInstance>::List dirty_mesh_instance_arrays; + + struct SkeletonShader { + struct PushConstant { + uint32_t has_normal; + uint32_t has_tangent; + uint32_t has_skeleton; + uint32_t has_blend_shape; + + uint32_t vertex_count; + uint32_t vertex_stride; + uint32_t skin_stride; + uint32_t skin_weight_offset; + + uint32_t blend_shape_count; + uint32_t normalized_blend_shapes; + uint32_t pad0; + uint32_t pad1; + }; + + enum { + UNIFORM_SET_INSTANCE = 0, + UNIFORM_SET_SURFACE = 1, + UNIFORM_SET_SKELETON = 2, + }; + enum { + SHADER_MODE_2D, + SHADER_MODE_3D, + SHADER_MODE_MAX + }; - void _mesh_surface_generate_version_for_input_mask(Mesh::Surface *s, uint32_t p_input_mask); + SkeletonShaderRD shader; + RID version; + RID version_shader[SHADER_MODE_MAX]; + RID pipeline[SHADER_MODE_MAX]; + + RID default_skeleton_uniform_set; + } skeleton_shader; + + void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, MeshInstance::Surface *mis = nullptr); RID mesh_default_rd_buffers[DEFAULT_RD_BUFFER_MAX]; @@ -476,10 +584,10 @@ private: bool dirty = false; MultiMesh *dirty_list = nullptr; - RasterizerScene::InstanceDependency instance_dependency; + Dependency dependency; }; - mutable RID_Owner<MultiMesh> multimesh_owner; + mutable RID_Owner<MultiMesh, true> multimesh_owner; MultiMesh *multimesh_dirty_list = nullptr; @@ -647,7 +755,7 @@ private: ParticleEmissionBuffer *emission_buffer = nullptr; RID emission_storage_buffer; - Set<RasterizerScene::InstanceBase *> collisions; + Set<RID> collisions; Particles() : inactive(true), @@ -674,7 +782,7 @@ private: clear(true) { } - RasterizerScene::InstanceDependency instance_dependency; + Dependency dependency; ParticlesFrameParams frame_params; }; @@ -729,7 +837,7 @@ private: bool valid; RID version; - //RenderPipelineVertexFormatCacheRD pipelines[SKY_VERSION_MAX]; + //PipelineCacheRD pipelines[SKY_VERSION_MAX]; Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms; Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms; @@ -747,17 +855,19 @@ private: virtual void set_code(const String &p_Code); virtual void set_default_texture_param(const StringName &p_name, RID p_texture); virtual void get_param_list(List<PropertyInfo> *p_param_list) const; - virtual void get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const; + virtual void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const; virtual bool is_param_texture(const StringName &p_param) const; virtual bool is_animated() const; virtual bool casts_shadows() const; virtual Variant get_default_parameter(const StringName &p_parameter) const; + virtual RS::ShaderNativeSourceCode get_native_source_code() const; + ParticlesShaderData(); virtual ~ParticlesShaderData(); }; ShaderData *_create_particles_shader_func(); - static RasterizerStorageRD::ShaderData *_create_particles_shader_funcs() { + static RendererStorageRD::ShaderData *_create_particles_shader_funcs() { return base_singleton->_create_particles_shader_func(); } @@ -777,13 +887,13 @@ private: }; MaterialData *_create_particles_material_func(ParticlesShaderData *p_shader); - static RasterizerStorageRD::MaterialData *_create_particles_material_funcs(ShaderData *p_shader) { + static RendererStorageRD::MaterialData *_create_particles_material_funcs(ShaderData *p_shader) { return base_singleton->_create_particles_material_func(static_cast<ParticlesShaderData *>(p_shader)); } void update_particles(); - mutable RID_Owner<Particles> particles_owner; + mutable RID_Owner<Particles, true> particles_owner; /* Particles Collision */ @@ -802,10 +912,18 @@ private: RS::ParticlesCollisionHeightfieldResolution heightfield_resolution = RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_1024; - RasterizerScene::InstanceDependency instance_dependency; + Dependency dependency; + }; + + mutable RID_Owner<ParticlesCollision, true> particles_collision_owner; + + struct ParticlesCollisionInstance { + RID collision; + Transform transform; + bool active = false; }; - mutable RID_Owner<ParticlesCollision> particles_collision_owner; + mutable RID_Owner<ParticlesCollisionInstance> particles_collision_instance_owner; /* Skeleton */ @@ -820,11 +938,14 @@ private: Transform2D base_transform_2d; RID uniform_set_3d; + RID uniform_set_mi; - RasterizerScene::InstanceDependency instance_dependency; + uint64_t version = 1; + + Dependency dependency; }; - mutable RID_Owner<Skeleton> skeleton_owner; + mutable RID_Owner<Skeleton, true> skeleton_owner; _FORCE_INLINE_ void _skeleton_make_dirty(Skeleton *skeleton); @@ -850,12 +971,13 @@ private: RS::LightDirectionalShadowMode directional_shadow_mode = RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL; RS::LightDirectionalShadowDepthRangeMode directional_range_mode = RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE; bool directional_blend_splits = false; + bool directional_sky_only = false; uint64_t version = 0; - RasterizerScene::InstanceDependency instance_dependency; + Dependency dependency; }; - mutable RID_Owner<Light> light_owner; + mutable RID_Owner<Light, true> light_owner; /* REFLECTION PROBE */ @@ -873,11 +995,12 @@ private: bool box_projection = false; bool enable_shadows = false; uint32_t cull_mask = (1 << 20) - 1; + float lod_threshold = 0.01; - RasterizerScene::InstanceDependency instance_dependency; + Dependency dependency; }; - mutable RID_Owner<ReflectionProbe> reflection_probe_owner; + mutable RID_Owner<ReflectionProbe, true> reflection_probe_owner; /* DECAL */ @@ -895,10 +1018,10 @@ private: float distance_fade_length = 1; float normal_fade = 0.0; - RasterizerScene::InstanceDependency instance_dependency; + Dependency dependency; }; - mutable RID_Owner<Decal> decal_owner; + mutable RID_Owner<Decal, true> decal_owner; /* GI PROBE */ @@ -933,7 +1056,7 @@ private: uint32_t version = 1; uint32_t data_version = 1; - RasterizerScene::InstanceDependency instance_dependency; + Dependency dependency; }; GiprobeSdfShaderRD giprobe_sdf_shader; @@ -941,7 +1064,7 @@ private: RID giprobe_sdf_shader_version_shader; RID giprobe_sdf_shader_pipeline; - mutable RID_Owner<GIProbe> gi_probe_owner; + mutable RID_Owner<GIProbe, true> gi_probe_owner; /* REFLECTION PROBE */ @@ -962,7 +1085,7 @@ private: int32_t over = EMPTY_LEAF, under = EMPTY_LEAF; }; - RasterizerScene::InstanceDependency instance_dependency; + Dependency dependency; }; bool using_lightmap_array; //high end uses this @@ -972,7 +1095,7 @@ private: uint64_t lightmap_array_version = 0; - mutable RID_Owner<Lightmap> lightmap_owner; + mutable RID_Owner<Lightmap, true> lightmap_owner; float lightmap_probe_capture_update_speed = 4; @@ -1123,15 +1246,19 @@ private: void _update_global_variables(); /* EFFECTS */ - RasterizerEffectsRD effects; + EffectsRD effects; public: + virtual bool can_create_resources_async() const; + /* TEXTURE API */ - virtual RID texture_2d_create(const Ref<Image> &p_image); - virtual RID texture_2d_layered_create(const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type); - virtual RID texture_3d_create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data); //all slices, then all the mipmaps, must be coherent - virtual RID texture_proxy_create(RID p_base); + virtual RID texture_allocate(); + + virtual void texture_2d_initialize(RID p_texture, const Ref<Image> &p_image); + virtual void texture_2d_layered_initialize(RID p_texture, const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type); + virtual void texture_3d_initialize(RID p_texture, Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data); //all slices, then all the mipmaps, must be coherent + virtual void texture_proxy_initialize(RID p_texture, RID p_base); virtual void _texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer, bool p_immediate); @@ -1141,9 +1268,9 @@ public: virtual void texture_proxy_update(RID p_texture, RID p_proxy_to); //these two APIs can be used together or in combination with the others. - virtual RID texture_2d_placeholder_create(); - virtual RID texture_2d_layered_placeholder_create(RenderingServer::TextureLayeredType p_layered_type); - virtual RID texture_3d_placeholder_create(); + virtual void texture_2d_placeholder_initialize(RID p_texture); + virtual void texture_2d_layered_placeholder_initialize(RID p_texture, RenderingServer::TextureLayeredType p_layered_type); + virtual void texture_3d_placeholder_initialize(RID p_texture); virtual Ref<Image> texture_2d_get(RID p_texture) const; virtual Ref<Image> texture_2d_layer_get(RID p_texture, int p_layer) const; @@ -1215,7 +1342,8 @@ public: /* CANVAS TEXTURE API */ - virtual RID canvas_texture_create(); + RID canvas_texture_allocate(); + void canvas_texture_initialize(RID p_canvas_texture); virtual void canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture); virtual void canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_specular_color, float p_shininess); @@ -1227,7 +1355,8 @@ public: /* SHADER API */ - RID shader_create(); + RID shader_allocate(); + void shader_initialize(RID p_shader); void shader_set_code(RID p_shader, const String &p_code); String shader_get_code(RID p_shader) const; @@ -1238,9 +1367,12 @@ public: Variant shader_get_param_default(RID p_shader, const StringName &p_param) const; void shader_set_data_request_function(ShaderType p_shader_type, ShaderDataRequestFunction p_function); + virtual RS::ShaderNativeSourceCode shader_get_native_source_code(RID p_shader) const; + /* COMMON MATERIAL API */ - RID material_create(); + RID material_allocate(); + void material_initialize(RID p_material); void material_set_shader(RID p_material, RID p_shader); @@ -1255,11 +1387,16 @@ public: void material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters); - void material_update_dependency(RID p_material, RasterizerScene::InstanceBase *p_instance); + void material_update_dependency(RID p_material, DependencyTracker *p_instance); void material_force_update_textures(RID p_material, ShaderType p_shader_type); void material_set_data_request_function(ShaderType p_shader_type, MaterialDataRequestFunction p_function); + _FORCE_INLINE_ uint32_t material_get_shader_id(RID p_material) { + Material *material = material_owner.getornull(p_material); + return material->shader_id; + } + _FORCE_INLINE_ MaterialData *material_get_data(RID p_material, ShaderType p_shader_type) { Material *material = material_owner.getornull(p_material); if (!material || material->shader_type != p_shader_type) { @@ -1271,7 +1408,10 @@ public: /* MESH API */ - virtual RID mesh_create(); + RID mesh_allocate(); + void mesh_initialize(RID p_mesh); + + virtual void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count); /// Return stride virtual void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface); @@ -1294,9 +1434,20 @@ public: virtual AABB mesh_get_custom_aabb(RID p_mesh) const; virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()); + virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh); virtual void mesh_clear(RID p_mesh); + virtual bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton); + + /* MESH INSTANCE */ + + virtual RID mesh_instance_create(RID p_base); + virtual void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton); + virtual void mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight); + virtual void mesh_instance_check_for_update(RID p_mesh_instance); + virtual void update_mesh_instances(); + _FORCE_INLINE_ const RID *mesh_get_surface_count_and_materials(RID p_mesh, uint32_t &r_surface_count) { Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!mesh, nullptr); @@ -1304,7 +1455,7 @@ public: if (r_surface_count == 0) { return nullptr; } - if (mesh->material_cache.empty()) { + if (mesh->material_cache.is_empty()) { mesh->material_cache.resize(mesh->surface_count); for (uint32_t i = 0; i < r_surface_count; i++) { mesh->material_cache.write[i] = mesh->surfaces[i]->material; @@ -1314,22 +1465,61 @@ public: return mesh->material_cache.ptr(); } - _FORCE_INLINE_ RS::PrimitiveType mesh_surface_get_primitive(RID p_mesh, uint32_t p_surface_index) { + _FORCE_INLINE_ void *mesh_get_surface(RID p_mesh, uint32_t p_surface_index) { Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, RS::PRIMITIVE_MAX); - ERR_FAIL_UNSIGNED_INDEX_V(p_surface_index, mesh->surface_count, RS::PRIMITIVE_MAX); + ERR_FAIL_COND_V(!mesh, nullptr); + ERR_FAIL_UNSIGNED_INDEX_V(p_surface_index, mesh->surface_count, nullptr); - return mesh->surfaces[p_surface_index]->primitive; + return mesh->surfaces[p_surface_index]; } - _FORCE_INLINE_ void mesh_surface_get_arrays_and_format(RID p_mesh, uint32_t p_surface_index, uint32_t p_input_mask, RID &r_vertex_array_rd, RID &r_index_array_rd, RD::VertexFormatID &r_vertex_format) { + _FORCE_INLINE_ RID mesh_get_shadow_mesh(RID p_mesh) { Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND(!mesh); - ERR_FAIL_UNSIGNED_INDEX(p_surface_index, mesh->surface_count); + ERR_FAIL_COND_V(!mesh, RID()); - Mesh::Surface *s = mesh->surfaces[p_surface_index]; + return mesh->shadow_mesh; + } + + _FORCE_INLINE_ RS::PrimitiveType mesh_surface_get_primitive(void *p_surface) { + Mesh::Surface *surface = reinterpret_cast<Mesh::Surface *>(p_surface); + return surface->primitive; + } + + _FORCE_INLINE_ bool mesh_surface_has_lod(void *p_surface) const { + Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface); + return s->lod_count > 0; + } + + _FORCE_INLINE_ uint32_t mesh_surface_get_lod(void *p_surface, float p_model_scale, float p_distance_threshold, float p_lod_threshold) const { + Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface); + + int32_t current_lod = -1; + for (uint32_t i = 0; i < s->lod_count; i++) { + float screen_size = s->lods[i].edge_length * p_model_scale / p_distance_threshold; + if (screen_size > p_lod_threshold) { + break; + } + current_lod = i; + } + if (current_lod == -1) { + return 0; + } else { + return current_lod + 1; + } + } - r_index_array_rd = s->index_array; + _FORCE_INLINE_ RID mesh_surface_get_index_array(void *p_surface, uint32_t p_lod) const { + Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface); + + if (p_lod == 0) { + return s->index_array; + } else { + return s->lods[p_lod - 1].index_array; + } + } + + _FORCE_INLINE_ void mesh_surface_get_vertex_arrays_and_format(void *p_surface, uint32_t p_input_mask, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) { + Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface); s->version_lock.lock(); @@ -1346,9 +1536,11 @@ public: return; } - uint32_t version = s->version_count; //gets added at the end + uint32_t version = s->version_count; + s->version_count++; + s->versions = (Mesh::Surface::Version *)memrealloc(s->versions, sizeof(Mesh::Surface::Version) * s->version_count); - _mesh_surface_generate_version_for_input_mask(s, p_input_mask); + _mesh_surface_generate_version_for_input_mask(s->versions[version], s, p_input_mask); r_vertex_format = s->versions[version].vertex_format; r_vertex_array_rd = s->versions[version].vertex_array; @@ -1356,6 +1548,42 @@ public: s->version_lock.unlock(); } + _FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint32_t p_surface_index, uint32_t p_input_mask, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) { + MeshInstance *mi = mesh_instance_owner.getornull(p_mesh_instance); + ERR_FAIL_COND(!mi); + Mesh *mesh = mi->mesh; + ERR_FAIL_UNSIGNED_INDEX(p_surface_index, mesh->surface_count); + + MeshInstance::Surface *mis = &mi->surfaces[p_surface_index]; + Mesh::Surface *s = mesh->surfaces[p_surface_index]; + + s->version_lock.lock(); + + //there will never be more than, at much, 3 or 4 versions, so iterating is the fastest way + + for (uint32_t i = 0; i < mis->version_count; i++) { + if (mis->versions[i].input_mask != p_input_mask) { + continue; + } + //we have this version, hooray + r_vertex_format = mis->versions[i].vertex_format; + r_vertex_array_rd = mis->versions[i].vertex_array; + s->version_lock.unlock(); + return; + } + + uint32_t version = mis->version_count; + mis->version_count++; + mis->versions = (Mesh::Surface::Version *)memrealloc(mis->versions, sizeof(Mesh::Surface::Version) * mis->version_count); + + _mesh_surface_generate_version_for_input_mask(mis->versions[version], s, p_input_mask, mis); + + r_vertex_format = mis->versions[version].vertex_format; + r_vertex_array_rd = mis->versions[version].vertex_array; + + s->version_lock.unlock(); + } + _FORCE_INLINE_ RID mesh_get_default_rd_buffer(DefaultRDBuffer p_buffer) { ERR_FAIL_INDEX_V(p_buffer, DEFAULT_RD_BUFFER_MAX, RID()); return mesh_default_rd_buffers[p_buffer]; @@ -1402,9 +1630,10 @@ public: /* MULTIMESH API */ - RID multimesh_create(); + RID multimesh_allocate(); + void multimesh_initialize(RID p_multimesh); - void multimesh_allocate(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false); + void multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false); int multimesh_get_instance_count(RID p_multimesh) const; void multimesh_set_mesh(RID p_multimesh, RID p_mesh); @@ -1456,7 +1685,7 @@ public: if (!multimesh->uniform_set_3d.is_valid()) { Vector<RD::Uniform> uniforms; RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 0; u.ids.push_back(multimesh->buffer); uniforms.push_back(u); @@ -1468,24 +1697,28 @@ public: /* IMMEDIATE API */ - RID immediate_create() { return RID(); } - void immediate_begin(RID p_immediate, RS::PrimitiveType p_rimitive, RID p_texture = RID()) {} - void immediate_vertex(RID p_immediate, const Vector3 &p_vertex) {} - void immediate_normal(RID p_immediate, const Vector3 &p_normal) {} - void immediate_tangent(RID p_immediate, const Plane &p_tangent) {} - void immediate_color(RID p_immediate, const Color &p_color) {} - void immediate_uv(RID p_immediate, const Vector2 &tex_uv) {} - void immediate_uv2(RID p_immediate, const Vector2 &tex_uv) {} - void immediate_end(RID p_immediate) {} - void immediate_clear(RID p_immediate) {} - void immediate_set_material(RID p_immediate, RID p_material) {} - RID immediate_get_material(RID p_immediate) const { return RID(); } - AABB immediate_get_aabb(RID p_immediate) const { return AABB(); } + RID immediate_allocate() { return RID(); } + void immediate_initialize(RID p_immediate) {} + + virtual void immediate_begin(RID p_immediate, RS::PrimitiveType p_rimitive, RID p_texture = RID()) {} + virtual void immediate_vertex(RID p_immediate, const Vector3 &p_vertex) {} + virtual void immediate_normal(RID p_immediate, const Vector3 &p_normal) {} + virtual void immediate_tangent(RID p_immediate, const Plane &p_tangent) {} + virtual void immediate_color(RID p_immediate, const Color &p_color) {} + virtual void immediate_uv(RID p_immediate, const Vector2 &tex_uv) {} + virtual void immediate_uv2(RID p_immediate, const Vector2 &tex_uv) {} + virtual void immediate_end(RID p_immediate) {} + virtual void immediate_clear(RID p_immediate) {} + virtual void immediate_set_material(RID p_immediate, RID p_material) {} + virtual RID immediate_get_material(RID p_immediate) const { return RID(); } + virtual AABB immediate_get_aabb(RID p_immediate) const { return AABB(); } /* SKELETON API */ - RID skeleton_create(); - void skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d_skeleton = false); + RID skeleton_allocate(); + void skeleton_initialize(RID p_skeleton); + + void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false); void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform); void skeleton_set_world_transform(RID p_skeleton, bool p_enable, const Transform &p_world_transform); int skeleton_get_bone_count(RID p_skeleton) const; @@ -1494,6 +1727,10 @@ public: void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform); Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const; + _FORCE_INLINE_ bool skeleton_is_valid(RID p_skeleton) { + return skeleton_owner.getornull(p_skeleton) != nullptr; + } + _FORCE_INLINE_ RID skeleton_get_3d_uniform_set(RID p_skeleton, RID p_shader, uint32_t p_set) const { Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); ERR_FAIL_COND_V(!skeleton, RID()); @@ -1504,7 +1741,7 @@ public: if (!skeleton->uniform_set_3d.is_valid()) { Vector<RD::Uniform> uniforms; RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 0; u.ids.push_back(skeleton->buffer); uniforms.push_back(u); @@ -1515,11 +1752,16 @@ public: } /* Light API */ - RID light_create(RS::LightType p_type); + void _light_initialize(RID p_rid, RS::LightType p_type); - RID directional_light_create() { return light_create(RS::LIGHT_DIRECTIONAL); } - RID omni_light_create() { return light_create(RS::LIGHT_OMNI); } - RID spot_light_create() { return light_create(RS::LIGHT_SPOT); } + RID directional_light_allocate(); + void directional_light_initialize(RID p_light); + + RID omni_light_allocate(); + void omni_light_initialize(RID p_light); + + RID spot_light_allocate(); + void spot_light_initialize(RID p_light); void light_set_color(RID p_light, const Color &p_color); void light_set_param(RID p_light, RS::LightParam p_param, float p_value); @@ -1537,6 +1779,8 @@ public: void light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode); void light_directional_set_blend_splits(RID p_light, bool p_enable); bool light_directional_get_blend_splits(RID p_light) const; + void light_directional_set_sky_only(RID p_light, bool p_sky_only); + bool light_directional_is_sky_only(RID p_light) const; void light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode); RS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const; @@ -1620,7 +1864,8 @@ public: /* PROBE API */ - RID reflection_probe_create(); + RID reflection_probe_allocate(); + void reflection_probe_initialize(RID p_reflection_probe); void reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode); void reflection_probe_set_intensity(RID p_probe, float p_intensity); @@ -1635,6 +1880,7 @@ public: void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable); void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers); void reflection_probe_set_resolution(RID p_probe, int p_resolution); + void reflection_probe_set_lod_threshold(RID p_probe, float p_ratio); AABB reflection_probe_get_aabb(RID p_probe) const; RS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const; @@ -1642,6 +1888,8 @@ public: Vector3 reflection_probe_get_extents(RID p_probe) const; Vector3 reflection_probe_get_origin_offset(RID p_probe) const; float reflection_probe_get_origin_max_distance(RID p_probe) const; + float reflection_probe_get_lod_threshold(RID p_probe) const; + int reflection_probe_get_resolution(RID p_probe) const; bool reflection_probe_renders_shadows(RID p_probe) const; @@ -1652,12 +1900,14 @@ public: Color reflection_probe_get_ambient_color(RID p_probe) const; float reflection_probe_get_ambient_color_energy(RID p_probe) const; - void base_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance); - void skeleton_update_dependency(RID p_skeleton, RasterizerScene::InstanceBase *p_instance); + void base_update_dependency(RID p_base, DependencyTracker *p_instance); + void skeleton_update_dependency(RID p_skeleton, DependencyTracker *p_instance); /* DECAL API */ - virtual RID decal_create(); + RID decal_allocate(); + void decal_initialize(RID p_decal); + virtual void decal_set_extents(RID p_decal, const Vector3 &p_extents); virtual void decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture); virtual void decal_set_emission_energy(RID p_decal, float p_energy); @@ -1732,9 +1982,10 @@ public: /* GI PROBE API */ - RID gi_probe_create(); + RID gi_probe_allocate(); + void gi_probe_initialize(RID p_gi_probe); - void gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts); + void gi_probe_allocate_data(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts); AABB gi_probe_get_bounds(RID p_gi_probe) const; Vector3i gi_probe_get_octree_size(RID p_gi_probe) const; @@ -1785,7 +2036,8 @@ public: /* LIGHTMAP CAPTURE */ - virtual RID lightmap_create(); + RID lightmap_allocate(); + void lightmap_initialize(RID p_lightmap); virtual void lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics); virtual void lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds); @@ -1802,7 +2054,11 @@ public: _FORCE_INLINE_ float lightmap_get_probe_capture_update_speed() const { return lightmap_probe_capture_update_speed; } - + _FORCE_INLINE_ RID lightmap_get_texture(RID p_lightmap) const { + const Lightmap *lm = lightmap_owner.getornull(p_lightmap); + ERR_FAIL_COND_V(!lm, RID()); + return lm->light_texture; + } _FORCE_INLINE_ int32_t lightmap_get_array_index(RID p_lightmap) const { ERR_FAIL_COND_V(!using_lightmap_array, -1); //only for arrays const Lightmap *lm = lightmap_owner.getornull(p_lightmap); @@ -1830,7 +2086,8 @@ public: /* PARTICLES */ - RID particles_create(); + RID particles_allocate(); + void particles_initialize(RID p_particles_collision); void particles_set_emitting(RID p_particles, bool p_emitting); void particles_set_amount(RID p_particles, int p_amount); @@ -1891,7 +2148,7 @@ public: { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 0; u.ids.push_back(particles->particle_instance_buffer); uniforms.push_back(u); @@ -1903,12 +2160,14 @@ public: return particles->particles_transforms_buffer_uniform_set; } - virtual void particles_add_collision(RID p_particles, RasterizerScene::InstanceBase *p_instance); - virtual void particles_remove_collision(RID p_particles, RasterizerScene::InstanceBase *p_instance); + virtual void particles_add_collision(RID p_particles, RID p_particles_collision_instance); + virtual void particles_remove_collision(RID p_particles, RID p_particles_collision_instance); /* PARTICLES COLLISION */ - virtual RID particles_collision_create(); + RID particles_collision_allocate(); + void particles_collision_initialize(RID p_particles_collision); + virtual void particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type); virtual void particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask); virtual void particles_collision_set_sphere_radius(RID p_particles_collision, float p_radius); //for spheres @@ -1924,6 +2183,11 @@ public: virtual bool particles_collision_is_heightfield(RID p_particles_collision) const; RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const; + //used from 2D and 3D + virtual RID particles_collision_instance_create(RID p_collision); + virtual void particles_collision_instance_set_transform(RID p_collision_instance, const Transform &p_transform); + virtual void particles_collision_instance_set_active(RID p_collision_instance, bool p_active); + /* GLOBAL VARIABLES API */ virtual void global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value); @@ -2013,12 +2277,12 @@ public: RID get_default_rd_storage_buffer() { return default_rd_storage_buffer; } - static RasterizerStorageRD *base_singleton; + static RendererStorageRD *base_singleton; - RasterizerEffectsRD *get_effects(); + EffectsRD *get_effects(); - RasterizerStorageRD(); - ~RasterizerStorageRD(); + RendererStorageRD(); + ~RendererStorageRD(); }; #endif // RASTERIZER_STORAGE_RD_H diff --git a/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp b/servers/rendering/renderer_rd/shader_compiler_rd.cpp index df5513435a..8135d388e1 100644 --- a/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp +++ b/servers/rendering/renderer_rd/shader_compiler_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -32,7 +32,7 @@ #include "core/config/project_settings.h" #include "core/os/os.h" -#include "rasterizer_storage_rd.h" +#include "renderer_storage_rd.h" #include "servers/rendering_server.h" #define SL ShaderLanguage @@ -687,7 +687,15 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge uint32_t index = p_default_actions.base_varying_index; + List<Pair<StringName, SL::ShaderNode::Varying>> var_frag_to_light; + for (Map<StringName, SL::ShaderNode::Varying>::Element *E = pnode->varyings.front(); E; E = E->next()) { + if (E->get().stage == SL::ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT || E->get().stage == SL::ShaderNode::Varying::STAGE_FRAGMENT) { + var_frag_to_light.push_back(Pair<StringName, SL::ShaderNode::Varying>(E->key(), E->get())); + fragment_varyings.insert(E->key()); + continue; + } + String vcode; String interp_mode = _interpstr(E->get().interpolation); vcode += _prestr(E->get().precision); @@ -705,6 +713,21 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge index++; } + if (var_frag_to_light.size() > 0) { + String gcode = "\n\nstruct {\n"; + for (List<Pair<StringName, SL::ShaderNode::Varying>>::Element *E = var_frag_to_light.front(); E; E = E->next()) { + gcode += "\t" + _prestr(E->get().second.precision) + _typestr(E->get().second.type) + " " + _mkid(E->get().first); + if (E->get().second.array_size > 0) { + gcode += "["; + gcode += itos(E->get().second.array_size); + gcode += "]"; + } + gcode += ";\n"; + } + gcode += "} frag_to_light;\n"; + r_gen_code.fragment_global += gcode; + } + for (int i = 0; i < pnode->vconstants.size(); i++) { const SL::ShaderNode::Constant &cnode = pnode->vconstants[i]; String gcode; @@ -833,6 +856,19 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge } break; case SL::Node::TYPE_VARIABLE: { SL::VariableNode *vnode = (SL::VariableNode *)p_node; + bool use_fragment_varying = false; + + if (current_func_name != vertex_name) { + if (p_assigning) { + if (shader->varyings.has(vnode->name)) { + use_fragment_varying = true; + } + } else { + if (fragment_varyings.has(vnode->name)) { + use_fragment_varying = true; + } + } + } if (p_assigning && p_actions.write_flag_pointers.has(vnode->name)) { *p_actions.write_flag_pointers[vnode->name] = true; @@ -877,7 +913,10 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge } } else { - code = _mkid(vnode->name); //its something else (local var most likely) use as is + if (use_fragment_varying) { + code = "frag_to_light."; + } + code += _mkid(vnode->name); //its something else (local var most likely) use as is } } @@ -920,7 +959,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge if (adnode->datatype == SL::TYPE_STRUCT) { declaration += _mkid(adnode->struct_name); } else { - declaration = _prestr(adnode->precision) + _typestr(adnode->datatype); + declaration += _prestr(adnode->precision) + _typestr(adnode->datatype); } for (int i = 0; i < adnode->declarations.size(); i++) { if (i > 0) { @@ -930,7 +969,11 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge } declaration += _mkid(adnode->declarations[i].name); declaration += "["; - declaration += itos(adnode->declarations[i].size); + if (adnode->size_expression != nullptr) { + declaration += _dump_node_code(adnode->size_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + } else { + declaration += itos(adnode->declarations[i].size); + } declaration += "]"; int sz = adnode->declarations[i].initializer.size(); if (sz > 0) { @@ -958,6 +1001,23 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge } break; case SL::Node::TYPE_ARRAY: { SL::ArrayNode *anode = (SL::ArrayNode *)p_node; + bool use_fragment_varying = false; + + if (current_func_name != vertex_name) { + if (anode->assign_expression != nullptr) { + use_fragment_varying = true; + } else { + if (p_assigning) { + if (shader->varyings.has(anode->name)) { + use_fragment_varying = true; + } + } else { + if (fragment_varyings.has(anode->name)) { + use_fragment_varying = true; + } + } + } + } if (p_assigning && p_actions.write_flag_pointers.has(anode->name)) { *p_actions.write_flag_pointers[anode->name] = true; @@ -980,18 +1040,22 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge if (p_default_actions.renames.has(anode->name)) { code = p_default_actions.renames[anode->name]; } else { - code = _mkid(anode->name); + if (use_fragment_varying) { + code = "frag_to_light."; + } + code += _mkid(anode->name); } if (anode->call_expression != nullptr) { code += "."; code += _dump_node_code(anode->call_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning, false); - } - - if (anode->index_expression != nullptr) { + } else if (anode->index_expression != nullptr) { code += "["; code += _dump_node_code(anode->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); code += "]"; + } else if (anode->assign_expression != nullptr) { + code += "="; + code += _dump_node_code(anode->assign_expression, p_level, r_gen_code, p_actions, p_default_actions, true, false); } if (anode->name == time_name) { @@ -1229,8 +1293,10 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge code += "["; code += _dump_node_code(mnode->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); code += "]"; + } else if (mnode->assign_expression != nullptr) { + code += "="; + code += _dump_node_code(mnode->assign_expression, p_level, r_gen_code, p_actions, p_default_actions, true, false); } - } break; } @@ -1238,7 +1304,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge } ShaderLanguage::DataType ShaderCompilerRD::_get_variable_type(const StringName &p_type) { - RS::GlobalVariableType gvt = ((RasterizerStorageRD *)(RasterizerStorage::base_singleton))->global_variable_get_type_internal(p_type); + RS::GlobalVariableType gvt = ((RendererStorageRD *)(RendererStorage::base_singleton))->global_variable_get_type_internal(p_type); return RS::global_variable_type_get_shader_datatype(gvt); } @@ -1270,6 +1336,7 @@ Error ShaderCompilerRD::compile(RS::ShaderMode p_mode, const String &p_code, Ide used_name_defines.clear(); used_rmode_defines.clear(); used_flag_pointers.clear(); + fragment_varyings.clear(); shader = parser.get_shader(); function = nullptr; @@ -1333,8 +1400,8 @@ ShaderCompilerRD::ShaderCompilerRD() { actions[RS::SHADER_SPATIAL].renames["FRAGCOORD"] = "gl_FragCoord"; actions[RS::SHADER_SPATIAL].renames["FRONT_FACING"] = "gl_FrontFacing"; - actions[RS::SHADER_SPATIAL].renames["NORMALMAP"] = "normalmap"; - actions[RS::SHADER_SPATIAL].renames["NORMALMAP_DEPTH"] = "normaldepth"; + actions[RS::SHADER_SPATIAL].renames["NORMAL_MAP"] = "normal_map"; + actions[RS::SHADER_SPATIAL].renames["NORMAL_MAP_DEPTH"] = "normal_map_depth"; actions[RS::SHADER_SPATIAL].renames["ALBEDO"] = "albedo"; actions[RS::SHADER_SPATIAL].renames["ALPHA"] = "alpha"; actions[RS::SHADER_SPATIAL].renames["METALLIC"] = "metallic"; @@ -1380,8 +1447,8 @@ ShaderCompilerRD::ShaderCompilerRD() { actions[RS::SHADER_SPATIAL].usage_defines["AO_LIGHT_AFFECT"] = "#define ENABLE_AO\n"; actions[RS::SHADER_SPATIAL].usage_defines["UV"] = "#define ENABLE_UV_INTERP\n"; actions[RS::SHADER_SPATIAL].usage_defines["UV2"] = "#define ENABLE_UV2_INTERP\n"; - actions[RS::SHADER_SPATIAL].usage_defines["NORMALMAP"] = "#define ENABLE_NORMALMAP\n"; - actions[RS::SHADER_SPATIAL].usage_defines["NORMALMAP_DEPTH"] = "@NORMALMAP"; + actions[RS::SHADER_SPATIAL].usage_defines["NORMAL_MAP"] = "#define ENABLE_NORMAL_MAP\n"; + actions[RS::SHADER_SPATIAL].usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP"; actions[RS::SHADER_SPATIAL].usage_defines["COLOR"] = "#define ENABLE_COLOR_INTERP\n"; actions[RS::SHADER_SPATIAL].usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n"; actions[RS::SHADER_SPATIAL].usage_defines["ALPHA_SCISSOR"] = "#define ALPHA_SCISSOR_USED\n"; @@ -1401,7 +1468,7 @@ ShaderCompilerRD::ShaderCompilerRD() { actions[RS::SHADER_SPATIAL].render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n"; actions[RS::SHADER_SPATIAL].render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n"; - bool force_lambert = GLOBAL_GET("rendering/quality/shading/force_lambert_over_burley"); + bool force_lambert = GLOBAL_GET("rendering/shading/overrides/force_lambert_over_burley"); if (!force_lambert) { actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n"; @@ -1411,7 +1478,7 @@ ShaderCompilerRD::ShaderCompilerRD() { actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n"; actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n"; - bool force_blinn = GLOBAL_GET("rendering/quality/shading/force_blinn_over_ggx"); + bool force_blinn = GLOBAL_GET("rendering/shading/overrides/force_blinn_over_ggx"); if (!force_blinn) { actions[RS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; diff --git a/servers/rendering/rasterizer_rd/shader_compiler_rd.h b/servers/rendering/renderer_rd/shader_compiler_rd.h index 694f8fff91..6575829e73 100644 --- a/servers/rendering/rasterizer_rd/shader_compiler_rd.h +++ b/servers/rendering/renderer_rd/shader_compiler_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -114,6 +114,7 @@ private: Set<StringName> used_flag_pointers; Set<StringName> used_rmode_defines; Set<StringName> internal_functions; + Set<StringName> fragment_varyings; DefaultIdentifierActions actions; diff --git a/servers/rendering/rasterizer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp index 865a1e1bbe..e4a39ff813 100644 --- a/servers/rendering/rasterizer_rd/shader_rd.cpp +++ b/servers/rendering/renderer_rd/shader_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,7 +31,7 @@ #include "shader_rd.h" #include "core/string/string_builder.h" -#include "rasterizer_rd.h" +#include "renderer_compositor_rd.h" #include "servers/rendering/rendering_device.h" void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_compute_code, const char *p_name) { @@ -199,6 +199,10 @@ void ShaderRD::_clear_version(Version *p_version) { } void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) { + if (!variants_enabled[p_variant]) { + return; //variant is disabled, return + } + Vector<RD::ShaderStageData> stages; String error; @@ -297,6 +301,7 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) { builder.append(compute_codev.get_data()); // version info (if exists) builder.append("\n"); //make sure defines begin at newline + builder.append(base_compute_defines.get_data()); builder.append(general_defines.get_data()); builder.append(variant_defines[p_variant].get_data()); @@ -347,6 +352,127 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) { } } +RS::ShaderNativeSourceCode ShaderRD::version_get_native_source_code(RID p_version) { + Version *version = version_owner.getornull(p_version); + RS::ShaderNativeSourceCode source_code; + ERR_FAIL_COND_V(!version, source_code); + + source_code.versions.resize(variant_defines.size()); + + for (int i = 0; i < source_code.versions.size(); i++) { + if (!is_compute) { + //vertex stage + + StringBuilder builder; + + builder.append(vertex_codev.get_data()); // version info (if exists) + builder.append("\n"); //make sure defines begin at newline + builder.append(general_defines.get_data()); + builder.append(variant_defines[i].get_data()); + + for (int j = 0; j < version->custom_defines.size(); j++) { + builder.append(version->custom_defines[j].get_data()); + } + + builder.append(vertex_code0.get_data()); //first part of vertex + + builder.append(version->uniforms.get_data()); //uniforms (same for vertex and fragment) + + builder.append(vertex_code1.get_data()); //second part of vertex + + builder.append(version->vertex_globals.get_data()); // vertex globals + + builder.append(vertex_code2.get_data()); //third part of vertex + + builder.append(version->vertex_code.get_data()); // code + + builder.append(vertex_code3.get_data()); //fourth of vertex + + RS::ShaderNativeSourceCode::Version::Stage stage; + stage.name = "vertex"; + stage.code = builder.as_string(); + + source_code.versions.write[i].stages.push_back(stage); + } + + if (!is_compute) { + //fragment stage + + StringBuilder builder; + + builder.append(fragment_codev.get_data()); // version info (if exists) + builder.append("\n"); //make sure defines begin at newline + builder.append(general_defines.get_data()); + builder.append(variant_defines[i].get_data()); + for (int j = 0; j < version->custom_defines.size(); j++) { + builder.append(version->custom_defines[j].get_data()); + } + + builder.append(fragment_code0.get_data()); //first part of fragment + + builder.append(version->uniforms.get_data()); //uniforms (same for fragment and fragment) + + builder.append(fragment_code1.get_data()); //first part of fragment + + builder.append(version->fragment_globals.get_data()); // fragment globals + + builder.append(fragment_code2.get_data()); //third part of fragment + + builder.append(version->fragment_light.get_data()); // fragment light + + builder.append(fragment_code3.get_data()); //fourth part of fragment + + builder.append(version->fragment_code.get_data()); // fragment code + + builder.append(fragment_code4.get_data()); //fourth part of fragment + + RS::ShaderNativeSourceCode::Version::Stage stage; + stage.name = "fragment"; + stage.code = builder.as_string(); + + source_code.versions.write[i].stages.push_back(stage); + } + + if (is_compute) { + //compute stage + + StringBuilder builder; + + builder.append(compute_codev.get_data()); // version info (if exists) + builder.append("\n"); //make sure defines begin at newline + builder.append(base_compute_defines.get_data()); + builder.append(general_defines.get_data()); + builder.append(variant_defines[i].get_data()); + + for (int j = 0; j < version->custom_defines.size(); j++) { + builder.append(version->custom_defines[j].get_data()); + } + + builder.append(compute_code0.get_data()); //first part of compute + + builder.append(version->uniforms.get_data()); //uniforms (same for compute and fragment) + + builder.append(compute_code1.get_data()); //second part of compute + + builder.append(version->compute_globals.get_data()); // compute globals + + builder.append(compute_code2.get_data()); //third part of compute + + builder.append(version->compute_code.get_data()); // code + + builder.append(compute_code3.get_data()); //fourth of compute + + RS::ShaderNativeSourceCode::Version::Stage stage; + stage.name = "compute"; + stage.code = builder.as_string(); + + source_code.versions.write[i].stages.push_back(stage); + } + } + + return source_code; +} + void ShaderRD::_compile_version(Version *p_version) { _clear_version(p_version); @@ -356,7 +482,7 @@ void ShaderRD::_compile_version(Version *p_version) { p_version->variants = memnew_arr(RID, variant_defines.size()); #if 1 - RasterizerRD::thread_work_pool.do_work(variant_defines.size(), this, &ShaderRD::_compile_variant, p_version); + RendererThreadPool::singleton->thread_work_pool.do_work(variant_defines.size(), this, &ShaderRD::_compile_variant, p_version); #else for (int i = 0; i < variant_defines.size(); i++) { _compile_variant(i, p_version); @@ -365,6 +491,9 @@ void ShaderRD::_compile_version(Version *p_version) { bool all_valid = true; for (int i = 0; i < variant_defines.size(); i++) { + if (!variants_enabled[i]) { + continue; //disabled + } if (p_version->variants[i].is_null()) { all_valid = false; break; @@ -374,6 +503,9 @@ void ShaderRD::_compile_version(Version *p_version) { if (!all_valid) { //clear versions if they exist for (int i = 0; i < variant_defines.size(); i++) { + if (!variants_enabled[i]) { + continue; //disabled + } if (!p_version->variants[i].is_null()) { RD::get_singleton()->free(p_version->variants[i]); } @@ -454,12 +586,42 @@ bool ShaderRD::version_free(RID p_version) { return true; } +void ShaderRD::set_variant_enabled(int p_variant, bool p_enabled) { + ERR_FAIL_COND(version_owner.get_rid_count() > 0); //versions exist + ERR_FAIL_INDEX(p_variant, variants_enabled.size()); + variants_enabled.write[p_variant] = p_enabled; +} + +bool ShaderRD::is_variant_enabled(int p_variant) const { + ERR_FAIL_INDEX_V(p_variant, variants_enabled.size(), false); + return variants_enabled[p_variant]; +} + +ShaderRD::ShaderRD() { + // Do not feel forced to use this, in most cases it makes little to no difference. + bool use_32_threads = false; + if (RD::get_singleton()->get_device_vendor_name() == "NVIDIA") { + use_32_threads = true; + } + String base_compute_define_text; + if (use_32_threads) { + base_compute_define_text = "\n#define NATIVE_LOCAL_GROUP_SIZE 32\n#define NATIVE_LOCAL_SIZE_2D_X 8\n#define NATIVE_LOCAL_SIZE_2D_Y 4\n"; + } else { + base_compute_define_text = "\n#define NATIVE_LOCAL_GROUP_SIZE 64\n#define NATIVE_LOCAL_SIZE_2D_X 8\n#define NATIVE_LOCAL_SIZE_2D_Y 8\n"; + } + + base_compute_defines = base_compute_define_text.ascii(); +} + void ShaderRD::initialize(const Vector<String> &p_variant_defines, const String &p_general_defines) { ERR_FAIL_COND(variant_defines.size()); ERR_FAIL_COND(p_variant_defines.size() == 0); + general_defines = p_general_defines.utf8(); + for (int i = 0; i < p_variant_defines.size(); i++) { variant_defines.push_back(p_variant_defines[i].utf8()); + variants_enabled.push_back(true); } } diff --git a/servers/rendering/rasterizer_rd/shader_rd.h b/servers/rendering/renderer_rd/shader_rd.h index 0c379db6f2..e0f4dcf2d0 100644 --- a/servers/rendering/rasterizer_rd/shader_rd.h +++ b/servers/rendering/renderer_rd/shader_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -36,6 +36,7 @@ #include "core/templates/map.h" #include "core/templates/rid_owner.h" #include "core/variant/variant.h" +#include "servers/rendering_server.h" #include <stdio.h> /** @@ -46,6 +47,7 @@ class ShaderRD { //versions CharString general_defines; Vector<CharString> variant_defines; + Vector<bool> variants_enabled; struct Version { CharString uniforms; @@ -97,8 +99,10 @@ class ShaderRD { const char *name; + CharString base_compute_defines; + protected: - ShaderRD() {} + ShaderRD(); void setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_compute_code, const char *p_name); public: @@ -109,6 +113,7 @@ public: _FORCE_INLINE_ RID version_get_shader(RID p_version, int p_variant) { ERR_FAIL_INDEX_V(p_variant, variant_defines.size(), RID()); + ERR_FAIL_COND_V(!variants_enabled[p_variant], RID()); Version *version = version_owner.getornull(p_version); ERR_FAIL_COND_V(!version, RID()); @@ -128,6 +133,11 @@ public: bool version_free(RID p_version); + void set_variant_enabled(int p_variant, bool p_enabled); + bool is_variant_enabled(int p_variant) const; + + RS::ShaderNativeSourceCode version_get_native_source_code(RID p_version); + void initialize(const Vector<String> &p_variant_defines, const String &p_general_defines = ""); virtual ~ShaderRD(); }; diff --git a/servers/rendering/rasterizer_rd/shaders/SCsub b/servers/rendering/renderer_rd/shaders/SCsub index 4cddf0f685..c192574ff2 100644 --- a/servers/rendering/rasterizer_rd/shaders/SCsub +++ b/servers/rendering/renderer_rd/shaders/SCsub @@ -11,7 +11,7 @@ if "RD_GLSL" in env["BUILDERS"]: env.RD_GLSL("cubemap_roughness.glsl") env.RD_GLSL("cubemap_downsampler.glsl") env.RD_GLSL("cubemap_filter.glsl") - env.RD_GLSL("scene_high_end.glsl") + env.RD_GLSL("scene_forward.glsl") env.RD_GLSL("sky.glsl") env.RD_GLSL("tonemap.glsl") env.RD_GLSL("cube_to_dp.glsl") @@ -21,8 +21,10 @@ if "RD_GLSL" in env["BUILDERS"]: env.RD_GLSL("luminance_reduce.glsl") env.RD_GLSL("bokeh_dof.glsl") env.RD_GLSL("ssao.glsl") - env.RD_GLSL("ssao_minify.glsl") + env.RD_GLSL("ssao_downsample.glsl") + env.RD_GLSL("ssao_importance_map.glsl") env.RD_GLSL("ssao_blur.glsl") + env.RD_GLSL("ssao_interleave.glsl") env.RD_GLSL("roughness_limiter.glsl") env.RD_GLSL("screen_space_reflection.glsl") env.RD_GLSL("screen_space_reflection_filter.glsl") @@ -37,7 +39,10 @@ if "RD_GLSL" in env["BUILDERS"]: env.RD_GLSL("sdfgi_debug.glsl") env.RD_GLSL("sdfgi_debug_probes.glsl") env.RD_GLSL("volumetric_fog.glsl") - env.RD_GLSL("shadow_reduce.glsl") env.RD_GLSL("particles.glsl") env.RD_GLSL("particles_copy.glsl") env.RD_GLSL("sort.glsl") + env.RD_GLSL("skeleton.glsl") + env.RD_GLSL("cluster_render.glsl") + env.RD_GLSL("cluster_store.glsl") + env.RD_GLSL("cluster_debug.glsl") diff --git a/servers/rendering/rasterizer_rd/shaders/bokeh_dof.glsl b/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl index 63f086a83d..63f086a83d 100644 --- a/servers/rendering/rasterizer_rd/shaders/bokeh_dof.glsl +++ b/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl index 51d7193a03..3b39edc70e 100644 --- a/servers/rendering/rasterizer_rd/shaders/canvas.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas.glsl @@ -9,7 +9,8 @@ layout(location = 0) in vec2 vertex_attrib; layout(location = 3) in vec4 color_attrib; layout(location = 4) in vec2 uv_attrib; -layout(location = 6) in uvec4 bones_attrib; +layout(location = 10) in uvec4 bone_attrib; +layout(location = 11) in vec4 weight_attrib; #endif @@ -61,6 +62,7 @@ void main() { color = vec4(unpackHalf2x16(draw_data.colors[4]), unpackHalf2x16(draw_data.colors[5])); } uvec4 bones = uvec4(0, 0, 0, 0); + vec4 bone_weights = vec4(0.0); #elif defined(USE_ATTRIBUTES) @@ -68,7 +70,8 @@ void main() { vec4 color = color_attrib; vec2 uv = uv_attrib; - uvec4 bones = bones_attrib; + uvec4 bones = bone_attrib; + vec4 bone_weights = weight_attrib; #else vec2 vertex_base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)); @@ -393,7 +396,7 @@ vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv vec4 shadow_color = unpackUnorm4x8(light_array.data[light_base].shadow_color); #ifdef LIGHT_SHADER_CODE_USED - shadow_color *= shadow_modulate; + shadow_color.rgb *= shadow_modulate; #endif shadow_color.a *= light_color.a; //respect light alpha @@ -494,9 +497,9 @@ void main() { vec2 shadow_vertex = vertex; { - float normal_depth = 1.0; + float normal_map_depth = 1.0; -#if defined(NORMALMAP_USED) +#if defined(NORMAL_MAP_USED) vec3 normal_map = vec3(0.0, 0.0, 1.0); normal_used = true; #endif @@ -507,8 +510,8 @@ FRAGMENT_SHADER_CODE /* clang-format on */ -#if defined(NORMALMAP_USED) - normal = mix(vec3(0.0, 0.0, 1.0), normal_map * vec3(2.0, -2.0, 1.0) - vec3(1.0, -1.0, 0.0), normal_depth); +#if defined(NORMAL_MAP_USED) + normal = mix(vec3(0.0, 0.0, 1.0), normal_map * vec3(2.0, -2.0, 1.0) - vec3(1.0, -1.0, 0.0), normal_map_depth); #endif } @@ -543,7 +546,7 @@ FRAGMENT_SHADER_CODE #ifdef LIGHT_SHADER_CODE_USED vec4 shadow_modulate = vec4(1.0); - light_color = light_compute(light_vertex, direction, normal, light_color, light_color.a, specular_shininess, shadow_modulate, screen_uv, color, uv, true); + light_color = light_compute(light_vertex, vec3(direction, light_array.data[light_base].height), normal, light_color, light_color.a, specular_shininess, shadow_modulate, screen_uv, uv, color, true); #else if (normal_used) { @@ -560,7 +563,7 @@ FRAGMENT_SHADER_CODE light_color = light_shadow_compute(light_base, light_color, shadow_uv #ifdef LIGHT_SHADER_CODE_USED , - shadow_modulate + shadow_modulate.rgb #endif ); } @@ -602,7 +605,7 @@ FRAGMENT_SHADER_CODE vec3 light_position = vec3(light_array.data[light_base].position, light_array.data[light_base].height); light_color.rgb *= light_base_color.rgb; - light_color = light_compute(light_vertex, light_position, normal, light_color, light_base_color.a, specular_shininess, shadow_modulate, screen_uv, color, uv, false); + light_color = light_compute(light_vertex, light_position, normal, light_color, light_base_color.a, specular_shininess, shadow_modulate, screen_uv, uv, color, false); #else light_color.rgb *= light_base_color.rgb * light_base_color.a; @@ -656,7 +659,7 @@ FRAGMENT_SHADER_CODE light_color = light_shadow_compute(light_base, light_color, shadow_uv #ifdef LIGHT_SHADER_CODE_USED , - shadow_modulate + shadow_modulate.rgb #endif ); } diff --git a/servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl b/servers/rendering/renderer_rd/shaders/canvas_occlusion.glsl index 5c25235c58..5c25235c58 100644 --- a/servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas_occlusion.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/canvas_sdf.glsl b/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl index 302ad03b41..302ad03b41 100644 --- a/servers/rendering/rasterizer_rd/shaders/canvas_sdf.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl index cf7678ea31..cf7678ea31 100644 --- a/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/cluster_data_inc.glsl b/servers/rendering/renderer_rd/shaders/cluster_data_inc.glsl index e723468dd8..3a4bf4da07 100644 --- a/servers/rendering/rasterizer_rd/shaders/cluster_data_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/cluster_data_inc.glsl @@ -6,12 +6,18 @@ struct LightData { //this structure needs to be as packed as possible vec3 position; float inv_radius; + vec3 direction; float size; - uint attenuation_energy; //attenuation - uint color_specular; //rgb color, a specular (8 bit unorm) - uint cone_attenuation_angle; // attenuation and angle, (16bit float) - uint shadow_color_enabled; //shadow rgb color, a>0.5 enabled (8bit unorm) + + vec3 color; + float attenuation; + + float cone_attenuation; + float cone_angle; + float specular_amount; + bool shadow_enabled; + vec4 atlas_rect; // rect in the shadow atlas mat4 shadow_matrix; float shadow_bias; @@ -34,9 +40,13 @@ struct ReflectionData { float index; vec3 box_offset; uint mask; - vec4 params; // intensity, 0, interior , boxproject vec3 ambient; // ambient color + float intensity; + bool exterior; + bool box_project; uint ambient_mode; + uint pad; + //0-8 is intensity,8-9 is ambient, mode mat4 local_matrix; // up to here for spot and omni, rest is for directional // notes: for ambientblend, use distance to edge to blend between already existing global environment }; diff --git a/servers/rendering/renderer_rd/shaders/cluster_debug.glsl b/servers/rendering/renderer_rd/shaders/cluster_debug.glsl new file mode 100644 index 0000000000..70a875192c --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/cluster_debug.glsl @@ -0,0 +1,115 @@ +#[compute] + +#version 450 + +VERSION_DEFINES + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +const vec3 usage_gradient[33] = vec3[]( // 1 (none) + 32 + vec3(0.14, 0.17, 0.23), + vec3(0.24, 0.44, 0.83), + vec3(0.23, 0.57, 0.84), + vec3(0.22, 0.71, 0.84), + vec3(0.22, 0.85, 0.83), + vec3(0.21, 0.85, 0.72), + vec3(0.21, 0.85, 0.57), + vec3(0.20, 0.85, 0.42), + vec3(0.20, 0.85, 0.27), + vec3(0.27, 0.86, 0.19), + vec3(0.51, 0.85, 0.19), + vec3(0.57, 0.86, 0.19), + vec3(0.62, 0.85, 0.19), + vec3(0.67, 0.86, 0.20), + vec3(0.73, 0.85, 0.20), + vec3(0.78, 0.85, 0.20), + vec3(0.83, 0.85, 0.20), + vec3(0.85, 0.82, 0.20), + vec3(0.85, 0.76, 0.20), + vec3(0.85, 0.81, 0.20), + vec3(0.85, 0.65, 0.20), + vec3(0.84, 0.60, 0.21), + vec3(0.84, 0.56, 0.21), + vec3(0.84, 0.51, 0.21), + vec3(0.84, 0.46, 0.21), + vec3(0.84, 0.41, 0.21), + vec3(0.84, 0.36, 0.21), + vec3(0.84, 0.31, 0.21), + vec3(0.84, 0.27, 0.21), + vec3(0.83, 0.22, 0.22), + vec3(0.83, 0.22, 0.27), + vec3(0.83, 0.22, 0.32), + vec3(1.00, 0.63, 0.70)); +layout(push_constant, binding = 0, std430) uniform Params { + uvec2 screen_size; + uvec2 cluster_screen_size; + + uint cluster_shift; + uint cluster_type; + float z_near; + float z_far; + + bool orthogonal; + uint max_cluster_element_count_div_32; + uint pad1; + uint pad2; +} +params; + +layout(set = 0, binding = 1, std430) buffer restrict readonly ClusterData { + uint data[]; +} +cluster_data; + +layout(rgba16f, set = 0, binding = 2) uniform restrict writeonly image2D screen_buffer; +layout(set = 0, binding = 3) uniform texture2D depth_buffer; +layout(set = 0, binding = 4) uniform sampler depth_buffer_sampler; + +void main() { + uvec2 screen_pos = gl_GlobalInvocationID.xy; + if (any(greaterThanEqual(screen_pos, params.screen_size))) { + return; + } + + uvec2 cluster_pos = screen_pos >> params.cluster_shift; + + uint offset = cluster_pos.y * params.cluster_screen_size.x + cluster_pos.x; + offset += params.cluster_screen_size.x * params.cluster_screen_size.y * params.cluster_type; + offset *= (params.max_cluster_element_count_div_32 + 32); + + //depth buffers generally can't be accessed via image API + float depth = texelFetch(sampler2D(depth_buffer, depth_buffer_sampler), ivec2(screen_pos), 0).r * 2.0 - 1.0; + + if (params.orthogonal) { + depth = ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; + } else { + depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near)); + } + depth /= params.z_far; + + uint slice = uint(clamp(floor(depth * 32.0), 0.0, 31.0)); + uint slice_minmax = cluster_data.data[offset + params.max_cluster_element_count_div_32 + slice]; + uint item_min = slice_minmax & 0xFFFF; + uint item_max = slice_minmax >> 16; + + uint item_count = 0; + for (uint i = 0; i < params.max_cluster_element_count_div_32; i++) { + uint slice_bits = cluster_data.data[offset + i]; + while (slice_bits != 0) { + uint bit = findLSB(slice_bits); + uint item = i * 32 + bit; + if ((item >= item_min && item < item_max)) { + item_count++; + } + slice_bits &= ~(1 << bit); + } + } + + item_count = min(item_count, 32); + + vec3 color = usage_gradient[item_count]; + + color = mix(color * 1.2, color * 0.3, float(slice) / 31.0); + + imageStore(screen_buffer, ivec2(screen_pos), vec4(color, 1.0)); +} diff --git a/servers/rendering/renderer_rd/shaders/cluster_render.glsl b/servers/rendering/renderer_rd/shaders/cluster_render.glsl new file mode 100644 index 0000000000..8723ea78e4 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/cluster_render.glsl @@ -0,0 +1,168 @@ +#[vertex] + +#version 450 + +VERSION_DEFINES + +layout(location = 0) in vec3 vertex_attrib; + +layout(location = 0) out float depth_interp; +layout(location = 1) out flat uint element_index; + +layout(push_constant, binding = 0, std430) uniform Params { + uint base_index; + uint pad0; + uint pad1; + uint pad2; +} +params; + +layout(set = 0, binding = 1, std140) uniform State { + mat4 projection; + + float inv_z_far; + uint screen_to_clusters_shift; // shift to obtain coordinates in block indices + uint cluster_screen_width; // + uint cluster_data_size; // how much data for a single cluster takes + + uint cluster_depth_offset; + uint pad0; + uint pad1; + uint pad2; +} +state; + +struct RenderElement { + uint type; //0-4 + bool touches_near; + bool touches_far; + uint original_index; + mat3x4 transform_inv; + vec3 scale; + uint pad; +}; + +layout(set = 0, binding = 2, std430) buffer restrict readonly RenderElements { + RenderElement data[]; +} +render_elements; + +void main() { + element_index = params.base_index + gl_InstanceIndex; + + vec3 vertex = vertex_attrib; + vertex *= render_elements.data[element_index].scale; + + vertex = vec4(vertex, 1.0) * render_elements.data[element_index].transform_inv; + depth_interp = -vertex.z; + + gl_Position = state.projection * vec4(vertex, 1.0); +} + +#[fragment] + +#version 450 + +VERSION_DEFINES + +#if defined(GL_KHR_shader_subgroup_ballot) && defined(GL_KHR_shader_subgroup_arithmetic) && defined(GL_KHR_shader_subgroup_vote) + +#extension GL_KHR_shader_subgroup_ballot : enable +#extension GL_KHR_shader_subgroup_arithmetic : enable +#extension GL_KHR_shader_subgroup_vote : enable + +#define USE_SUBGROUPS +#endif + +layout(location = 0) in float depth_interp; +layout(location = 1) in flat uint element_index; + +layout(set = 0, binding = 1, std140) uniform State { + mat4 projection; + float inv_z_far; + uint screen_to_clusters_shift; // shift to obtain coordinates in block indices + uint cluster_screen_width; // + uint cluster_data_size; // how much data for a single cluster takes + uint cluster_depth_offset; + uint pad0; + uint pad1; + uint pad2; +} +state; + +//cluster data is layout linearly, each cell contains the follow information: +// - list of bits for every element to mark as used, so (max_elem_count/32)*4 uints +// - a uint for each element to mark the depth bits used when rendering (0-31) + +layout(set = 0, binding = 3, std430) buffer restrict ClusterRender { + uint data[]; +} +cluster_render; + +void main() { + //convert from screen to cluster + uvec2 cluster = uvec2(gl_FragCoord.xy) >> state.screen_to_clusters_shift; + + //get linear cluster offset from screen poss + uint cluster_offset = cluster.x + state.cluster_screen_width * cluster.y; + //multiply by data size to position at the beginning of the element list for this cluster + cluster_offset *= state.cluster_data_size; + + //find the current element in the list and plot the bit to mark it as used + uint usage_write_offset = cluster_offset + (element_index >> 5); + uint usage_write_bit = 1 << (element_index & 0x1F); + +#ifdef USE_SUBGROUPS + + uint cluster_thread_group_index; + + if (!gl_HelperInvocation) { + //http://advances.realtimerendering.com/s2017/2017_Sig_Improved_Culling_final.pdf + + uvec4 mask; + + while (true) { + // find the cluster offset of the first active thread + // threads that did break; go inactive and no longer count + uint first = subgroupBroadcastFirst(cluster_offset); + // update the mask for thread that match this cluster + mask = subgroupBallot(first == cluster_offset); + if (first == cluster_offset) { + // This thread belongs to the group of threads that match this offset, + // so exit the loop. + break; + } + } + + cluster_thread_group_index = subgroupBallotExclusiveBitCount(mask); + + if (cluster_thread_group_index == 0) { + atomicOr(cluster_render.data[usage_write_offset], usage_write_bit); + } + } +#else + if (!gl_HelperInvocation) { + atomicOr(cluster_render.data[usage_write_offset], usage_write_bit); + } +#endif + //find the current element in the depth usage list and mark the current depth as used + float unit_depth = depth_interp * state.inv_z_far; + + uint z_bit = clamp(uint(floor(unit_depth * 32.0)), 0, 31); + + uint z_write_offset = cluster_offset + state.cluster_depth_offset + element_index; + uint z_write_bit = 1 << z_bit; + +#ifdef USE_SUBGROUPS + if (!gl_HelperInvocation) { + z_write_bit = subgroupOr(z_write_bit); //merge all Zs + if (cluster_thread_group_index == 0) { + atomicOr(cluster_render.data[z_write_offset], z_write_bit); + } + } +#else + if (!gl_HelperInvocation) { + atomicOr(cluster_render.data[z_write_offset], z_write_bit); + } +#endif +} diff --git a/servers/rendering/renderer_rd/shaders/cluster_store.glsl b/servers/rendering/renderer_rd/shaders/cluster_store.glsl new file mode 100644 index 0000000000..5be0893c4f --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/cluster_store.glsl @@ -0,0 +1,119 @@ +#[compute] + +#version 450 + +VERSION_DEFINES + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +layout(push_constant, binding = 0, std430) uniform Params { + uint cluster_render_data_size; // how much data for a single cluster takes + uint max_render_element_count_div_32; //divided by 32 + uvec2 cluster_screen_size; + uint render_element_count_div_32; //divided by 32 + + uint max_cluster_element_count_div_32; //divided by 32 + uint pad1; + uint pad2; +} +params; + +layout(set = 0, binding = 1, std430) buffer restrict readonly ClusterRender { + uint data[]; +} +cluster_render; + +layout(set = 0, binding = 2, std430) buffer restrict ClusterStore { + uint data[]; +} +cluster_store; + +struct RenderElement { + uint type; //0-4 + bool touches_near; + bool touches_far; + uint original_index; + mat3x4 transform_inv; + vec3 scale; + uint pad; +}; + +layout(set = 0, binding = 3, std430) buffer restrict readonly RenderElements { + RenderElement data[]; +} +render_elements; + +void main() { + uvec2 pos = gl_GlobalInvocationID.xy; + if (any(greaterThanEqual(pos, params.cluster_screen_size))) { + return; + } + + //counter for each type of render_element + + //base offset for this cluster + uint base_offset = (pos.x + params.cluster_screen_size.x * pos.y); + uint src_offset = base_offset * params.cluster_render_data_size; + + uint render_element_offset = 0; + + //check all render_elements and see which one was written to + while (render_element_offset < params.render_element_count_div_32) { + uint bits = cluster_render.data[src_offset + render_element_offset]; + while (bits != 0) { + //if bits exist, check the render_element + uint index_bit = findLSB(bits); + uint index = render_element_offset * 32 + index_bit; + uint type = render_elements.data[index].type; + + uint z_range_offset = src_offset + params.max_render_element_count_div_32 + index; + uint z_range = cluster_render.data[z_range_offset]; + + //if object was written, z was written, but check just in case + if (z_range != 0) { //should always be > 0 + + uint from_z = findLSB(z_range); + uint to_z = findMSB(z_range) + 1; + + if (render_elements.data[index].touches_near) { + from_z = 0; + } + + if (render_elements.data[index].touches_far) { + to_z = 32; + } + + // find cluster offset in the buffer used for indexing in the renderer + uint dst_offset = (base_offset + type * (params.cluster_screen_size.x * params.cluster_screen_size.y)) * (params.max_cluster_element_count_div_32 + 32); + + uint orig_index = render_elements.data[index].original_index; + //store this index in the Z slices by setting the relevant bit + for (uint i = from_z; i < to_z; i++) { + uint slice_ofs = dst_offset + params.max_cluster_element_count_div_32 + i; + + uint minmax = cluster_store.data[slice_ofs]; + + if (minmax == 0) { + minmax = 0xFFFF; //min 0, max 0xFFFF + } + + uint elem_min = min(orig_index, minmax & 0xFFFF); + uint elem_max = max(orig_index + 1, minmax >> 16); //always store plus one, so zero means range is empty when not written to + + minmax = elem_min | (elem_max << 16); + cluster_store.data[slice_ofs] = minmax; + } + + uint store_word = orig_index >> 5; + uint store_bit = orig_index & 0x1F; + + //store the actual render_element index at the end, so the rendering code can reference it + cluster_store.data[dst_offset + store_word] |= 1 << store_bit; + } + + bits &= ~(1 << index_bit); //clear the bit to continue iterating + } + + render_element_offset++; + } +} diff --git a/servers/rendering/rasterizer_rd/shaders/copy.glsl b/servers/rendering/renderer_rd/shaders/copy.glsl index cdd35dfb3f..cdd35dfb3f 100644 --- a/servers/rendering/rasterizer_rd/shaders/copy.glsl +++ b/servers/rendering/renderer_rd/shaders/copy.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/copy_to_fb.glsl b/servers/rendering/renderer_rd/shaders/copy_to_fb.glsl index 9751e13b4e..9751e13b4e 100644 --- a/servers/rendering/rasterizer_rd/shaders/copy_to_fb.glsl +++ b/servers/rendering/renderer_rd/shaders/copy_to_fb.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/cube_to_dp.glsl b/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl index 54d67db6c6..c3ac0bee57 100644 --- a/servers/rendering/rasterizer_rd/shaders/cube_to_dp.glsl +++ b/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl @@ -1,33 +1,48 @@ -#[compute] +#[vertex] #version 450 VERSION_DEFINES -layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; +layout(push_constant, binding = 1, std430) uniform Params { + float z_far; + float z_near; + bool z_flip; + uint pad; + vec4 screen_rect; +} +params; + +layout(location = 0) out vec2 uv_interp; + +void main() { + vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)); + uv_interp = base_arr[gl_VertexIndex]; + vec2 screen_pos = uv_interp * params.screen_rect.zw + params.screen_rect.xy; + gl_Position = vec4(screen_pos * 2.0 - 1.0, 0.0, 1.0); +} + +#[fragment] + +#version 450 + +VERSION_DEFINES + +layout(location = 0) in vec2 uv_interp; layout(set = 0, binding = 0) uniform samplerCube source_cube; layout(push_constant, binding = 1, std430) uniform Params { - ivec2 screen_size; - ivec2 offset; - float bias; float z_far; float z_near; bool z_flip; + uint pad; + vec4 screen_rect; } params; -layout(r32f, set = 1, binding = 0) uniform restrict writeonly image2D depth_buffer; - void main() { - ivec2 pos = ivec2(gl_GlobalInvocationID.xy); - if (any(greaterThan(pos, params.screen_size))) { //too large, do nothing - return; - } - - vec2 pixel_size = 1.0 / vec2(params.screen_size); - vec2 uv = (vec2(pos) + 0.5) * pixel_size; + vec2 uv = uv_interp; vec3 normal = vec3(uv * 2.0 - 1.0, 0.0); @@ -65,5 +80,5 @@ void main() { float linear_depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near)); depth = (linear_depth * depth_fix) / params.z_far; - imageStore(depth_buffer, pos + params.offset, vec4(depth)); + gl_FragDepth = depth; } diff --git a/servers/rendering/rasterizer_rd/shaders/cubemap_downsampler.glsl b/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl index 7f269b7af3..7f269b7af3 100644 --- a/servers/rendering/rasterizer_rd/shaders/cubemap_downsampler.glsl +++ b/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/cubemap_filter.glsl b/servers/rendering/renderer_rd/shaders/cubemap_filter.glsl index 987545fb76..987545fb76 100644 --- a/servers/rendering/rasterizer_rd/shaders/cubemap_filter.glsl +++ b/servers/rendering/renderer_rd/shaders/cubemap_filter.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/cubemap_roughness.glsl b/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl index 5cbb00baa4..5cbb00baa4 100644 --- a/servers/rendering/rasterizer_rd/shaders/cubemap_roughness.glsl +++ b/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/gi.glsl b/servers/rendering/renderer_rd/shaders/gi.glsl index 8011dadc72..92a5682572 100644 --- a/servers/rendering/rasterizer_rd/shaders/gi.glsl +++ b/servers/rendering/renderer_rd/shaders/gi.glsl @@ -97,13 +97,12 @@ layout(push_constant, binding = 0, std430) uniform Params { vec4 proj_info; + vec3 ao_color; uint max_giprobes; + bool high_quality_vct; - bool use_sdfgi; bool orthogonal; - - vec3 ao_color; - uint pad; + uint pad[2]; mat3x4 cam_rotation; } @@ -331,7 +330,7 @@ void sdfgi_process(vec3 vertex, vec3 normal, vec3 reflection, float roughness, o } ambient_light.rgb = diffuse; -#if 1 + if (roughness < 0.2) { vec3 pos_to_uvw = 1.0 / sdfgi.grid_size; vec4 light_accum = vec4(0.0); @@ -363,59 +362,63 @@ void sdfgi_process(vec3 vertex, vec3 normal, vec3 reflection, float roughness, o //ray_pos += ray_dir * (bias / sdfgi.cascades[cascade].to_cell); //bias to avoid self occlusion ray_pos += (ray_dir * 1.0 / max(abs_ray_dir.x, max(abs_ray_dir.y, abs_ray_dir.z)) + cam_normal * 1.4) * bias / sdfgi.cascades[cascade].to_cell; } - float softness = 0.2 + min(1.0, roughness * 5.0) * 4.0; //approximation to roughness so it does not seem like a hard fade - while (length(ray_pos) < max_distance) { - for (uint i = 0; i < sdfgi.max_cascades; i++) { - if (i >= cascade && length(ray_pos) < radius_sizes[i]) { - cascade = max(i, cascade); //never go down - - vec3 pos = ray_pos - sdfgi.cascades[i].position; - pos *= sdfgi.cascades[i].to_cell * pos_to_uvw; - - float distance = texture(sampler3D(sdf_cascades[i], linear_sampler), pos).r * 255.0 - 1.1; - - vec4 hit_light = vec4(0.0); - if (distance < softness) { - hit_light.rgb = texture(sampler3D(light_cascades[i], linear_sampler), pos).rgb; - hit_light.rgb *= 0.5; //approximation given value read is actually meant for anisotropy - hit_light.a = clamp(1.0 - (distance / softness), 0.0, 1.0); - hit_light.rgb *= hit_light.a; - } + uint i = 0; + bool found = false; + while (true) { + if (length(ray_pos) >= max_distance || light_accum.a > 0.99) { + break; + } + if (!found && i >= cascade && length(ray_pos) < radius_sizes[i]) { + uint next_i = min(i + 1, sdfgi.max_cascades - 1); + cascade = max(i, cascade); //never go down - distance /= sdfgi.cascades[i].to_cell; + vec3 pos = ray_pos - sdfgi.cascades[i].position; + pos *= sdfgi.cascades[i].to_cell * pos_to_uvw; - if (i < (sdfgi.max_cascades - 1)) { - pos = ray_pos - sdfgi.cascades[i + 1].position; - pos *= sdfgi.cascades[i + 1].to_cell * pos_to_uvw; + float fdistance = textureLod(sampler3D(sdf_cascades[i], linear_sampler), pos, 0.0).r * 255.0 - 1.1; - float distance2 = texture(sampler3D(sdf_cascades[i + 1], linear_sampler), pos).r * 255.0 - 1.1; + vec4 hit_light = vec4(0.0); + if (fdistance < softness) { + hit_light.rgb = textureLod(sampler3D(light_cascades[i], linear_sampler), pos, 0.0).rgb; + hit_light.rgb *= 0.5; //approximation given value read is actually meant for anisotropy + hit_light.a = clamp(1.0 - (fdistance / softness), 0.0, 1.0); + hit_light.rgb *= hit_light.a; + } - vec4 hit_light2 = vec4(0.0); - if (distance2 < softness) { - hit_light2.rgb = texture(sampler3D(light_cascades[i + 1], linear_sampler), pos).rgb; - hit_light2.rgb *= 0.5; //approximation given value read is actually meant for anisotropy - hit_light2.a = clamp(1.0 - (distance2 / softness), 0.0, 1.0); - hit_light2.rgb *= hit_light2.a; - } + fdistance /= sdfgi.cascades[i].to_cell; - float prev_radius = i == 0 ? 0.0 : radius_sizes[i - 1]; - float blend = clamp((length(ray_pos) - prev_radius) / (radius_sizes[i] - prev_radius), 0.0, 1.0); + if (i < (sdfgi.max_cascades - 1)) { + pos = ray_pos - sdfgi.cascades[next_i].position; + pos *= sdfgi.cascades[next_i].to_cell * pos_to_uvw; - distance2 /= sdfgi.cascades[i + 1].to_cell; + float fdistance2 = textureLod(sampler3D(sdf_cascades[next_i], linear_sampler), pos, 0.0).r * 255.0 - 1.1; - hit_light = mix(hit_light, hit_light2, blend); - distance = mix(distance, distance2, blend); + vec4 hit_light2 = vec4(0.0); + if (fdistance2 < softness) { + hit_light2.rgb = textureLod(sampler3D(light_cascades[next_i], linear_sampler), pos, 0.0).rgb; + hit_light2.rgb *= 0.5; //approximation given value read is actually meant for anisotropy + hit_light2.a = clamp(1.0 - (fdistance2 / softness), 0.0, 1.0); + hit_light2.rgb *= hit_light2.a; } - light_accum += hit_light; - ray_pos += ray_dir * distance; - break; + float prev_radius = i == 0 ? 0.0 : radius_sizes[max(0, i - 1)]; + float blend = clamp((length(ray_pos) - prev_radius) / (radius_sizes[i] - prev_radius), 0.0, 1.0); + + fdistance2 /= sdfgi.cascades[next_i].to_cell; + + hit_light = mix(hit_light, hit_light2, blend); + fdistance = mix(fdistance, fdistance2, blend); } - } - if (light_accum.a > 0.99) { - break; + light_accum += hit_light; + ray_pos += ray_dir * fdistance; + found = true; + } + i++; + if (i == sdfgi.max_cascades) { + i = 0; + found = false; } } @@ -434,8 +437,6 @@ void sdfgi_process(vec3 vertex, vec3 normal, vec3 reflection, float roughness, o } } -#endif - reflection_light.rgb = specular; ambient_light.rgb *= sdfgi.energy; @@ -597,35 +598,24 @@ vec4 fetch_normal_and_roughness(ivec2 pos) { return normal_roughness; } -void main() { - // Pixel being shaded - ivec2 pos = ivec2(gl_GlobalInvocationID.xy); - if (any(greaterThanEqual(pos, params.screen_size))) { //too large, do nothing - return; - } - - vec3 vertex = reconstruct_position(pos); - vertex.y = -vertex.y; - +void process_gi(ivec2 pos, vec3 vertex, inout vec4 ambient_light, inout vec4 reflection_light) { vec4 normal_roughness = fetch_normal_and_roughness(pos); - vec3 normal = normal_roughness.xyz; - vec4 ambient_light = vec4(0.0), reflection_light = vec4(0.0); + vec3 normal = normal_roughness.xyz; if (normal.length() > 0.5) { //valid normal, can do GI float roughness = normal_roughness.w; - vertex = mat3(params.cam_rotation) * vertex; normal = normalize(mat3(params.cam_rotation) * normal); - vec3 reflection = normalize(reflect(normalize(vertex), normal)); - if (params.use_sdfgi) { - sdfgi_process(vertex, normal, reflection, roughness, ambient_light, reflection_light); - } +#ifdef USE_SDFGI + sdfgi_process(vertex, normal, reflection, roughness, ambient_light, reflection_light); +#endif - if (params.max_giprobes > 0) { +#ifdef USE_GIPROBES + { uvec2 giprobe_tex = texelFetch(usampler2D(giprobe_buffer, linear_sampler), pos, 0).rg; roughness *= roughness; //find arbitrary tangent and bitangent, then build a matrix @@ -648,16 +638,40 @@ void main() { spec_accum /= blend_accum; } - if (params.use_sdfgi) { - reflection_light = blend_color(spec_accum, reflection_light); - ambient_light = blend_color(amb_accum, ambient_light); - } else { - reflection_light = spec_accum; - ambient_light = amb_accum; - } +#ifdef USE_SDFGI + reflection_light = blend_color(spec_accum, reflection_light); + ambient_light = blend_color(amb_accum, ambient_light); +#else + reflection_light = spec_accum; + ambient_light = amb_accum; +#endif } +#endif + } +} + +void main() { + ivec2 pos = ivec2(gl_GlobalInvocationID.xy); + +#ifdef MODE_HALF_RES + pos <<= 1; +#endif + if (any(greaterThanEqual(pos, params.screen_size))) { //too large, do nothing + return; } + vec4 ambient_light = vec4(0.0); + vec4 reflection_light = vec4(0.0); + + vec3 vertex = reconstruct_position(pos); + vertex.y = -vertex.y; + + process_gi(pos, vertex, ambient_light, reflection_light); + +#ifdef MODE_HALF_RES + pos >>= 1; +#endif + imageStore(ambient_buffer, pos, ambient_light); imageStore(reflection_buffer, pos, reflection_light); } diff --git a/servers/rendering/rasterizer_rd/shaders/giprobe.glsl b/servers/rendering/renderer_rd/shaders/giprobe.glsl index ea4237a45e..b931461b31 100644 --- a/servers/rendering/rasterizer_rd/shaders/giprobe.glsl +++ b/servers/rendering/renderer_rd/shaders/giprobe.glsl @@ -51,10 +51,10 @@ struct Light { float attenuation; vec3 color; - float spot_angle_radians; + float cos_spot_angle; vec3 position; - float spot_attenuation; + float inv_spot_attenuation; vec3 direction; bool has_shadow; @@ -208,6 +208,15 @@ float raymarch(float distance, float distance_adv, vec3 from, vec3 direction) { return occlusion; //max(0.0,distance); } +float get_omni_attenuation(float distance, float inv_range, float decay) { + float nd = distance * inv_range; + nd *= nd; + nd *= nd; // nd^4 + nd = max(1.0 - nd, 0.0); + nd *= nd; // nd^2 + return nd * pow(max(distance, 0.0001), -decay); +} + bool compute_light_vector(uint light, vec3 pos, out float attenuation, out vec3 light_pos) { if (lights.data[light].type == LIGHT_TYPE_DIRECTIONAL) { light_pos = pos - lights.data[light].direction * length(vec3(params.limits)); @@ -220,17 +229,19 @@ bool compute_light_vector(uint light, vec3 pos, out float attenuation, out vec3 return false; } - attenuation = pow(clamp(1.0 - distance / lights.data[light].radius, 0.0001, 1.0), lights.data[light].attenuation); + attenuation = get_omni_attenuation(distance, 1.0 / lights.data[light].radius, lights.data[light].attenuation); if (lights.data[light].type == LIGHT_TYPE_SPOT) { vec3 rel = normalize(pos - light_pos); - float angle = acos(dot(rel, lights.data[light].direction)); - if (angle > lights.data[light].spot_angle_radians) { + float cos_spot_angle = lights.data[light].cos_spot_angle; + float cos_angle = dot(rel, lights.data[light].direction); + if (cos_angle < cos_spot_angle) { return false; } - float d = clamp(angle / lights.data[light].spot_angle_radians, 0, 1); - attenuation *= pow(1.0 - d, lights.data[light].spot_attenuation); + float scos = max(cos_angle, cos_spot_angle); + float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - cos_spot_angle)); + attenuation *= 1.0 - pow(spot_rim, lights.data[light].inv_spot_attenuation); } } diff --git a/servers/rendering/rasterizer_rd/shaders/giprobe_debug.glsl b/servers/rendering/renderer_rd/shaders/giprobe_debug.glsl index 515cc35507..515cc35507 100644 --- a/servers/rendering/rasterizer_rd/shaders/giprobe_debug.glsl +++ b/servers/rendering/renderer_rd/shaders/giprobe_debug.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/giprobe_sdf.glsl b/servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl index 5b3dec0ee7..5b3dec0ee7 100644 --- a/servers/rendering/rasterizer_rd/shaders/giprobe_sdf.glsl +++ b/servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/giprobe_write.glsl b/servers/rendering/renderer_rd/shaders/giprobe_write.glsl index 9c794f1bcc..56b3b7ccb4 100644 --- a/servers/rendering/rasterizer_rd/shaders/giprobe_write.glsl +++ b/servers/rendering/renderer_rd/shaders/giprobe_write.glsl @@ -43,10 +43,10 @@ struct Light { float attenuation; vec3 color; - float spot_angle_radians; + float cos_spot_angle; vec3 position; - float spot_attenuation; + float inv_spot_attenuation; vec3 direction; bool has_shadow; @@ -146,13 +146,15 @@ bool compute_light_vector(uint light, uint cell, vec3 pos, out float attenuation if (lights.data[light].type == LIGHT_TYPE_SPOT) { vec3 rel = normalize(pos - light_pos); - float angle = acos(dot(rel, lights.data[light].direction)); - if (angle > lights.data[light].spot_angle_radians) { + float cos_spot_angle = lights.data[light].cos_spot_angle; + float cos_angle = dot(rel, lights.data[light].direction); + if (cos_angle < cos_spot_angle) { return false; } - float d = clamp(angle / lights.data[light].spot_angle_radians, 0, 1); - attenuation *= pow(1.0 - d, lights.data[light].spot_attenuation); + float scos = max(cos_angle, cos_spot_angle); + float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - cos_spot_angle)); + attenuation *= 1.0 - pow(spot_rim, lights.data[light].inv_spot_attenuation); } } diff --git a/servers/rendering/rasterizer_rd/shaders/luminance_reduce.glsl b/servers/rendering/renderer_rd/shaders/luminance_reduce.glsl index 8a11c35b78..8a11c35b78 100644 --- a/servers/rendering/rasterizer_rd/shaders/luminance_reduce.glsl +++ b/servers/rendering/renderer_rd/shaders/luminance_reduce.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/particles.glsl b/servers/rendering/renderer_rd/shaders/particles.glsl index 926c7ef9fc..cb6d8dc7f6 100644 --- a/servers/rendering/rasterizer_rd/shaders/particles.glsl +++ b/servers/rendering/renderer_rd/shaders/particles.glsl @@ -173,7 +173,7 @@ uint hash(uint x) { return x; } -bool emit_particle(mat4 p_xform, vec3 p_velocity, vec4 p_color, vec4 p_custom, uint p_flags) { +bool emit_subparticle(mat4 p_xform, vec3 p_velocity, vec4 p_color, vec4 p_custom, uint p_flags) { if (!params.can_emit) { return false; } diff --git a/servers/rendering/rasterizer_rd/shaders/particles_copy.glsl b/servers/rendering/renderer_rd/shaders/particles_copy.glsl index 6c782b6045..6c782b6045 100644 --- a/servers/rendering/rasterizer_rd/shaders/particles_copy.glsl +++ b/servers/rendering/renderer_rd/shaders/particles_copy.glsl diff --git a/servers/rendering/renderer_rd/shaders/resolve.glsl b/servers/rendering/renderer_rd/shaders/resolve.glsl new file mode 100644 index 0000000000..e83c4ca93b --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/resolve.glsl @@ -0,0 +1,220 @@ +#[compute] + +#version 450 + +VERSION_DEFINES + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +#ifdef MODE_RESOLVE_GI +layout(set = 0, binding = 0) uniform sampler2DMS source_depth; +layout(set = 0, binding = 1) uniform sampler2DMS source_normal_roughness; + +layout(r32f, set = 1, binding = 0) uniform restrict writeonly image2D dest_depth; +layout(rgba8, set = 1, binding = 1) uniform restrict writeonly image2D dest_normal_roughness; + +#ifdef GIPROBE_RESOLVE +layout(set = 2, binding = 0) uniform usampler2DMS source_giprobe; +layout(rg8ui, set = 3, binding = 0) uniform restrict writeonly uimage2D dest_giprobe; +#endif + +#endif + +layout(push_constant, binding = 16, std430) uniform Params { + ivec2 screen_size; + int sample_count; + uint pad; +} +params; + +void main() { + // Pixel being shaded + ivec2 pos = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThanEqual(pos, params.screen_size))) { //too large, do nothing + return; + } + +#ifdef MODE_RESOLVE_GI + + float best_depth = 1e20; + vec4 best_normal_roughness = vec4(0.0); +#ifdef GIPROBE_RESOLVE + uvec2 best_giprobe; +#endif + +#if 0 + + for(int i=0;i<params.sample_count;i++) { + float depth = texelFetch(source_depth,pos,i).r; + if (depth < best_depth) { //use the depth closest to camera + best_depth = depth; + best_normal_roughness = texelFetch(source_normal_roughness,pos,i); + +#ifdef GIPROBE_RESOLVE + best_giprobe = texelFetch(source_giprobe,pos,i).rg; +#endif + } + } + +#else + +#if 1 + + vec4 group1; + vec4 group2; + vec4 group3; + vec4 group4; + int best_index = 0; + + //2X + group1.x = texelFetch(source_depth, pos, 0).r; + group1.y = texelFetch(source_depth, pos, 1).r; + + //4X + if (params.sample_count >= 4) { + group1.z = texelFetch(source_depth, pos, 2).r; + group1.w = texelFetch(source_depth, pos, 3).r; + } + //8X + if (params.sample_count >= 8) { + group2.x = texelFetch(source_depth, pos, 4).r; + group2.y = texelFetch(source_depth, pos, 5).r; + group2.z = texelFetch(source_depth, pos, 6).r; + group2.w = texelFetch(source_depth, pos, 7).r; + } + //16X + if (params.sample_count >= 16) { + group3.x = texelFetch(source_depth, pos, 8).r; + group3.y = texelFetch(source_depth, pos, 9).r; + group3.z = texelFetch(source_depth, pos, 10).r; + group3.w = texelFetch(source_depth, pos, 11).r; + + group4.x = texelFetch(source_depth, pos, 12).r; + group4.y = texelFetch(source_depth, pos, 13).r; + group4.z = texelFetch(source_depth, pos, 14).r; + group4.w = texelFetch(source_depth, pos, 15).r; + } + + if (params.sample_count == 2) { + best_index = (pos.x & 1) ^ ((pos.y >> 1) & 1); //not much can be done here + } else if (params.sample_count == 4) { + vec4 freq = vec4(equal(group1, vec4(group1.x))); + freq += vec4(equal(group1, vec4(group1.y))); + freq += vec4(equal(group1, vec4(group1.z))); + freq += vec4(equal(group1, vec4(group1.w))); + + float min_f = freq.x; + best_index = 0; + if (freq.y < min_f) { + best_index = 1; + min_f = freq.y; + } + if (freq.z < min_f) { + best_index = 2; + min_f = freq.z; + } + if (freq.w < min_f) { + best_index = 3; + } + } else if (params.sample_count == 8) { + vec4 freq0 = vec4(equal(group1, vec4(group1.x))); + vec4 freq1 = vec4(equal(group2, vec4(group1.x))); + freq0 += vec4(equal(group1, vec4(group1.y))); + freq1 += vec4(equal(group2, vec4(group1.y))); + freq0 += vec4(equal(group1, vec4(group1.z))); + freq1 += vec4(equal(group2, vec4(group1.z))); + freq0 += vec4(equal(group1, vec4(group1.w))); + freq1 += vec4(equal(group2, vec4(group1.w))); + freq0 += vec4(equal(group1, vec4(group2.x))); + freq1 += vec4(equal(group2, vec4(group2.x))); + freq0 += vec4(equal(group1, vec4(group2.y))); + freq1 += vec4(equal(group2, vec4(group2.y))); + freq0 += vec4(equal(group1, vec4(group2.z))); + freq1 += vec4(equal(group2, vec4(group2.z))); + freq0 += vec4(equal(group1, vec4(group2.w))); + freq1 += vec4(equal(group2, vec4(group2.w))); + + float min_f0 = freq0.x; + int best_index0 = 0; + if (freq0.y < min_f0) { + best_index0 = 1; + min_f0 = freq0.y; + } + if (freq0.z < min_f0) { + best_index0 = 2; + min_f0 = freq0.z; + } + if (freq0.w < min_f0) { + best_index0 = 3; + min_f0 = freq0.w; + } + + float min_f1 = freq1.x; + int best_index1 = 4; + if (freq1.y < min_f1) { + best_index1 = 5; + min_f1 = freq1.y; + } + if (freq1.z < min_f1) { + best_index1 = 6; + min_f1 = freq1.z; + } + if (freq1.w < min_f1) { + best_index1 = 7; + min_f1 = freq1.w; + } + + best_index = mix(best_index0, best_index1, min_f0 < min_f1); + } + +#else + float depths[16]; + int depth_indices[16]; + int depth_amount[16]; + int depth_count = 0; + + for (int i = 0; i < params.sample_count; i++) { + float depth = texelFetch(source_depth, pos, i).r; + int depth_index = -1; + for (int j = 0; j < depth_count; j++) { + if (abs(depths[j] - depth) < 0.000001) { + depth_index = j; + break; + } + } + + if (depth_index == -1) { + depths[depth_count] = depth; + depth_indices[depth_count] = i; + depth_amount[depth_count] = 1; + depth_count += 1; + } else { + depth_amount[depth_index] += 1; + } + } + + int depth_least = 0xFFFF; + int best_index = 0; + for (int j = 0; j < depth_count; j++) { + if (depth_amount[j] < depth_least) { + best_index = depth_indices[j]; + depth_least = depth_amount[j]; + } + } +#endif + best_depth = texelFetch(source_depth, pos, best_index).r; + best_normal_roughness = texelFetch(source_normal_roughness, pos, best_index); +#ifdef GIPROBE_RESOLVE + best_giprobe = texelFetch(source_giprobe, pos, best_index).rg; +#endif + +#endif + + imageStore(dest_depth, pos, vec4(best_depth)); + imageStore(dest_normal_roughness, pos, vec4(best_normal_roughness)); +#ifdef GIPROBE_RESOLVE + imageStore(dest_giprobe, pos, uvec4(best_giprobe, 0, 0)); +#endif + +#endif +} diff --git a/servers/rendering/rasterizer_rd/shaders/roughness_limiter.glsl b/servers/rendering/renderer_rd/shaders/roughness_limiter.glsl index 464895928a..464895928a 100644 --- a/servers/rendering/rasterizer_rd/shaders/roughness_limiter.glsl +++ b/servers/rendering/renderer_rd/shaders/roughness_limiter.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl b/servers/rendering/renderer_rd/shaders/scene_forward.glsl index 285698f060..1cea9bf8db 100644 --- a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward.glsl @@ -4,13 +4,19 @@ VERSION_DEFINES -#include "scene_high_end_inc.glsl" +#include "scene_forward_inc.glsl" /* INPUT ATTRIBS */ layout(location = 0) in vec3 vertex_attrib; + +//only for pure render depth when normal is not used + +#ifdef NORMAL_USED layout(location = 1) in vec3 normal_attrib; -#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#endif + +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) layout(location = 2) in vec4 tangent_attrib; #endif @@ -18,30 +24,59 @@ layout(location = 2) in vec4 tangent_attrib; layout(location = 3) in vec4 color_attrib; #endif +#ifdef UV_USED layout(location = 4) in vec2 uv_attrib; +#endif #if defined(UV2_USED) || defined(USE_LIGHTMAP) || defined(MODE_RENDER_MATERIAL) layout(location = 5) in vec2 uv2_attrib; #endif -layout(location = 6) in uvec4 bone_attrib; // always bound, even if unused +#if defined(CUSTOM0_USED) +layout(location = 6) in vec4 custom0_attrib; +#endif + +#if defined(CUSTOM1_USED) +layout(location = 7) in vec4 custom1_attrib; +#endif + +#if defined(CUSTOM2_USED) +layout(location = 8) in vec4 custom2_attrib; +#endif + +#if defined(CUSTOM3_USED) +layout(location = 9) in vec4 custom3_attrib; +#endif + +#if defined(BONES_USED) +layout(location = 10) in uvec4 bone_attrib; +#endif + +#if defined(WEIGHTS_USED) +layout(location = 11) in vec4 weight_attrib; +#endif /* Varyings */ layout(location = 0) out vec3 vertex_interp; + +#ifdef NORMAL_USED layout(location = 1) out vec3 normal_interp; +#endif #if defined(COLOR_USED) layout(location = 2) out vec4 color_interp; #endif +#ifdef UV_USED layout(location = 3) out vec2 uv_interp; +#endif #if defined(UV2_USED) || defined(USE_LIGHTMAP) layout(location = 4) out vec2 uv2_interp; #endif -#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) layout(location = 5) out vec3 tangent_interp; layout(location = 6) out vec3 binormal_interp; #endif @@ -54,33 +89,45 @@ MATERIAL_UNIFORMS } material; #endif -/* clang-format off */ - -VERTEX_SHADER_GLOBALS - -/* clang-format on */ - invariant gl_Position; -layout(location = 7) flat out uint instance_index; - #ifdef MODE_DUAL_PARABOLOID layout(location = 8) out float dp_clip; #endif +layout(location = 9) out flat uint instance_index; + +/* clang-format off */ + +VERTEX_SHADER_GLOBALS + +/* clang-format on */ + void main() { - instance_index = draw_call.instance_index; vec4 instance_custom = vec4(0.0); #if defined(COLOR_USED) color_interp = color_attrib; #endif + instance_index = draw_call.instance_index; + + bool is_multimesh = bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH); + if (!is_multimesh) { + instance_index += gl_InstanceIndex; + } + mat4 world_matrix = instances.data[instance_index].transform; - mat3 world_normal_matrix = mat3(instances.data[instance_index].normal_transform); - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH)) { + mat3 world_normal_matrix; + if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) { + world_normal_matrix = inverse(mat3(world_matrix)); + } else { + world_normal_matrix = mat3(world_matrix); + } + + if (is_multimesh) { //multimesh, instances are for it uint offset = (instances.data[instance_index].flags >> INSTANCE_FLAGS_MULTIMESH_STRIDE_SHIFT) & INSTANCE_FLAGS_MULTIMESH_STRIDE_MASK; offset *= gl_InstanceIndex; @@ -109,21 +156,20 @@ void main() { matrix = transpose(matrix); world_matrix = world_matrix * matrix; world_normal_matrix = world_normal_matrix * mat3(matrix); - - } else { - //not a multimesh, instances are for multiple draw calls - instance_index += gl_InstanceIndex; } vec3 vertex = vertex_attrib; - vec3 normal = normal_attrib; +#ifdef NORMAL_USED + vec3 normal = normal_attrib * 2.0 - 1.0; +#endif -#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) - vec3 tangent = tangent_attrib.xyz; - float binormalf = tangent_attrib.a; +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) + vec3 tangent = tangent_attrib.xyz * 2.0 - 1.0; + float binormalf = tangent_attrib.a * 2.0 - 1.0; vec3 binormal = normalize(cross(normal, tangent) * binormalf); #endif +#if 0 if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_SKELETON)) { //multimesh, instances are for it @@ -141,20 +187,23 @@ void main() { vertex = (vec4(vertex, 1.0) * m).xyz; normal = (vec4(normal, 0.0) * m).xyz; -#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) tangent = (vec4(tangent, 0.0) * m).xyz; binormal = (vec4(binormal, 0.0) * m).xyz; #endif } +#endif +#ifdef UV_USED uv_interp = uv_attrib; +#endif #if defined(UV2_USED) || defined(USE_LIGHTMAP) uv2_interp = uv2_attrib; #endif -#ifdef USE_OVERRIDE_POSITION +#ifdef OVERRIDE_POSITION vec4 position; #endif @@ -167,7 +216,7 @@ void main() { normal = world_normal_matrix * normal; -#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) tangent = world_normal_matrix * tangent; binormal = world_normal_matrix * binormal; @@ -192,10 +241,13 @@ VERTEX_SHADER_CODE #if !defined(SKIP_TRANSFORM_USED) && !defined(VERTEX_WORLD_COORDS_USED) vertex = (modelview * vec4(vertex, 1.0)).xyz; +#ifdef NORMAL_USED normal = modelview_normal * normal; #endif -#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#endif + +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) binormal = modelview_normal * binormal; tangent = modelview_normal * tangent; @@ -207,7 +259,7 @@ VERTEX_SHADER_CODE vertex = (scene_data.inv_camera_matrix * vec4(vertex, 1.0)).xyz; normal = mat3(scene_data.inverse_normal_matrix) * normal; -#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) binormal = mat3(scene_data.camera_inverse_binormal_matrix) * binormal; tangent = mat3(scene_data.camera_inverse_tangent_matrix) * tangent; @@ -215,9 +267,11 @@ VERTEX_SHADER_CODE #endif vertex_interp = vertex; +#ifdef NORMAL_USED normal_interp = normal; +#endif -#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) tangent_interp = tangent; binormal_interp = binormal; #endif @@ -227,7 +281,6 @@ VERTEX_SHADER_CODE #ifdef MODE_DUAL_PARABOLOID vertex_interp.z *= scene_data.dual_paraboloid_side; - normal_interp.z *= scene_data.dual_paraboloid_side; dp_clip = vertex_interp.z; //this attempts to avoid noise caused by objects sent to the other parabolloid side due to bias @@ -245,7 +298,7 @@ VERTEX_SHADER_CODE #endif //MODE_RENDER_DEPTH -#ifdef USE_OVERRIDE_POSITION +#ifdef OVERRIDE_POSITION gl_Position = position; #else gl_Position = projection_matrix * vec4(vertex_interp, 1.0); @@ -260,7 +313,8 @@ VERTEX_SHADER_CODE #endif #ifdef MODE_RENDER_MATERIAL if (scene_data.material_uv2_mode) { - gl_Position.xy = (uv2_attrib.xy + draw_call.bake_uv2_offset) * 2.0 - 1.0; + vec2 uv_offset = unpackHalf2x16(draw_call.uv_offset); + gl_Position.xy = (uv2_attrib.xy + uv_offset) * 2.0 - 1.0; gl_Position.z = 0.00001; gl_Position.w = 1.0; } @@ -273,40 +327,44 @@ VERTEX_SHADER_CODE VERSION_DEFINES -#include "scene_high_end_inc.glsl" +#include "scene_forward_inc.glsl" /* Varyings */ layout(location = 0) in vec3 vertex_interp; + +#ifdef NORMAL_USED layout(location = 1) in vec3 normal_interp; +#endif #if defined(COLOR_USED) layout(location = 2) in vec4 color_interp; #endif +#ifdef UV_USED layout(location = 3) in vec2 uv_interp; +#endif #if defined(UV2_USED) || defined(USE_LIGHTMAP) layout(location = 4) in vec2 uv2_interp; #endif -#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) layout(location = 5) in vec3 tangent_interp; layout(location = 6) in vec3 binormal_interp; #endif -layout(location = 7) flat in uint instance_index; - #ifdef MODE_DUAL_PARABOLOID layout(location = 8) in float dp_clip; #endif +layout(location = 9) in flat uint instance_index; + //defines to keep compatibility with vertex #define world_matrix instances.data[instance_index].transform -#define world_normal_matrix instances.data[instance_index].normal_transform #define projection_matrix scene_data.projection_matrix #if defined(ENABLE_SSS) && defined(ENABLE_TRANSMITTANCE) @@ -495,7 +553,7 @@ vec3 F0(float metallic, float specular, vec3 albedo) { return mix(vec3(dielectric), albedo, vec3(metallic)); } -void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float attenuation, vec3 shadow_attenuation, vec3 diffuse_color, float roughness, float metallic, float specular, float specular_blob_intensity, +void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation, vec3 f0, uint orms, float specular_amount, #ifdef LIGHT_BACKLIGHT_USED vec3 backlight, #endif @@ -507,7 +565,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte float transmittance_z, #endif #ifdef LIGHT_RIM_USED - float rim, float rim_tint, + float rim, float rim_tint, vec3 rim_color, #endif #ifdef LIGHT_CLEARCOAT_USED float clearcoat, float clearcoat_gloss, @@ -515,6 +573,9 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte #ifdef LIGHT_ANISOTROPY_USED vec3 B, vec3 T, float anisotropy, #endif +#ifdef USE_SOFT_SHADOWS + float A, +#endif #ifdef USE_SHADOW_TO_OPACITY inout float alpha, #endif @@ -524,7 +585,6 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte // light is written by the light shader vec3 normal = N; - vec3 albedo = diffuse_color; vec3 light = L; vec3 view = V; @@ -535,7 +595,12 @@ LIGHT_SHADER_CODE /* clang-format on */ #else + +#ifdef USE_SOFT_SHADOWS float NdotL = min(A + dot(N, L), 1.0); +#else + float NdotL = dot(N, L); +#endif float cNdotL = max(NdotL, 0.0); // clamped NdotL float NdotV = dot(N, V); float cNdotV = max(NdotV, 0.0); @@ -545,14 +610,25 @@ LIGHT_SHADER_CODE #endif #if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) +#ifdef USE_SOFT_SHADOWS float cNdotH = clamp(A + dot(N, H), 0.0, 1.0); +#else + float cNdotH = clamp(dot(N, H), 0.0, 1.0); +#endif #endif #if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) +#ifdef USE_SOFT_SHADOWS float cLdotH = clamp(A + dot(L, H), 0.0, 1.0); +#else + float cLdotH = clamp(dot(L, H), 0.0, 1.0); +#endif #endif + float metallic = unpackUnorm4x8(orms).z; if (metallic < 1.0) { + float roughness = unpackUnorm4x8(orms).y; + #if defined(DIFFUSE_OREN_NAYAR) vec3 diffuse_brdf_NL; #else @@ -562,23 +638,6 @@ LIGHT_SHADER_CODE #if defined(DIFFUSE_LAMBERT_WRAP) // energy conserving lambert wrap shader diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness))); - -#elif defined(DIFFUSE_OREN_NAYAR) - - { - // see http://mimosa-pudica.net/improved-oren-nayar.html - float LdotV = dot(L, V); - - float s = LdotV - NdotL * NdotV; - float t = mix(1.0, max(NdotL, NdotV), step(0.0, s)); - - float sigma2 = roughness * roughness; // TODO: this needs checking - vec3 A = 1.0 + sigma2 * (-0.5 / (sigma2 + 0.33) + 0.17 * diffuse_color / (sigma2 + 0.13)); - float B = 0.45 * sigma2 / (sigma2 + 0.09); - - diffuse_brdf_NL = cNdotL * (A + vec3(B) * s / t) * (1.0 / M_PI); - } - #elif defined(DIFFUSE_TOON) diffuse_brdf_NL = smoothstep(-roughness, max(roughness, 0.01), NdotL); @@ -606,15 +665,15 @@ LIGHT_SHADER_CODE diffuse_brdf_NL = cNdotL * (1.0 / M_PI); #endif - diffuse_light += light_color * diffuse_color * shadow_attenuation * diffuse_brdf_NL * attenuation; + diffuse_light += light_color * diffuse_brdf_NL * attenuation; #if defined(LIGHT_BACKLIGHT_USED) - diffuse_light += light_color * diffuse_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * backlight * attenuation; + diffuse_light += light_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * backlight * attenuation; #endif #if defined(LIGHT_RIM_USED) float rim_light = pow(max(0.0, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0)); - diffuse_light += rim_light * rim * mix(vec3(1.0), diffuse_color, rim_tint) * light_color; + diffuse_light += rim_light * rim * mix(vec3(1.0), rim_color, rim_tint) * light_color; #endif #ifdef LIGHT_TRANSMITTANCE_USED @@ -632,7 +691,7 @@ LIGHT_SHADER_CODE vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) + vec3(0.078, 0.0, 0.0) * exp(dd / 7.41); - diffuse_light += profile * transmittance_color.a * diffuse_color * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI) * attenuation; + diffuse_light += profile * transmittance_color.a * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI); } #else @@ -642,7 +701,7 @@ LIGHT_SHADER_CODE fade = pow(max(0.0, 1.0 - fade), transmittance_curve); fade *= clamp(transmittance_boost - NdotL, 0.0, 1.0); - diffuse_light += diffuse_color * transmittance_color.rgb * light_color * (1.0 / M_PI) * transmittance_color.a * fade * attenuation; + diffuse_light += transmittance_color.rgb * light_color * (1.0 / M_PI) * transmittance_color.a * fade; } #endif //SSS_MODE_SKIN @@ -650,6 +709,7 @@ LIGHT_SHADER_CODE #endif //LIGHT_TRANSMITTANCE_USED } + float roughness = unpackUnorm4x8(orms).y; if (roughness > 0.0) { // FIXME: roughness == 0 should not disable specular light entirely // D @@ -662,7 +722,7 @@ LIGHT_SHADER_CODE blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); float intensity = blinn; - specular_light += light_color * shadow_attenuation * intensity * specular_blob_intensity * attenuation; + specular_light += light_color * intensity * attenuation * specular_amount; #elif defined(SPECULAR_PHONG) @@ -673,7 +733,7 @@ LIGHT_SHADER_CODE phong *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); float intensity = (phong) / max(4.0 * cNdotV * cNdotL, 0.75); - specular_light += light_color * shadow_attenuation * intensity * specular_blob_intensity * attenuation; + specular_light += light_color * intensity * attenuation * specular_amount; #elif defined(SPECULAR_TOON) @@ -682,7 +742,7 @@ LIGHT_SHADER_CODE float mid = 1.0 - roughness; mid *= mid; float intensity = smoothstep(mid - roughness * 0.5, mid + roughness * 0.5, RdotV) * mid; - diffuse_light += light_color * shadow_attenuation * intensity * specular_blob_intensity * attenuation; // write to diffuse_light, as in toon shading you generally want no reflection + diffuse_light += light_color * intensity * attenuation * specular_amount; // write to diffuse_light, as in toon shading you generally want no reflection #elif defined(SPECULAR_DISABLED) // none.. @@ -707,13 +767,12 @@ LIGHT_SHADER_CODE float G = G_GGX_2cos(cNdotL, alpha_ggx) * G_GGX_2cos(cNdotV, alpha_ggx); #endif // F - vec3 f0 = F0(metallic, specular, diffuse_color); float cLdotH5 = SchlickFresnel(cLdotH); vec3 F = mix(vec3(cLdotH5), vec3(1.0), f0); vec3 specular_brdf_NL = cNdotL * D * F * G; - specular_light += specular_brdf_NL * light_color * shadow_attenuation * specular_blob_intensity * attenuation; + specular_light += specular_brdf_NL * light_color * attenuation * specular_amount; #endif #if defined(LIGHT_CLEARCOAT_USED) @@ -727,12 +786,12 @@ LIGHT_SHADER_CODE float clearcoat_specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL; - specular_light += clearcoat_specular_brdf_NL * light_color * shadow_attenuation * specular_blob_intensity * attenuation; + specular_light += clearcoat_specular_brdf_NL * light_color * attenuation * specular_amount; #endif } #ifdef USE_SHADOW_TO_OPACITY - alpha = min(alpha, clamp(1.0 - length(shadow_attenuation * attenuation), 0.0, 1.0)); + alpha = min(alpha, clamp(1.0 - attenuation), 0.0, 1.0)); #endif #endif //defined(USE_LIGHT_SHADER_CODE) @@ -740,13 +799,11 @@ LIGHT_SHADER_CODE #ifndef USE_NO_SHADOWS -// Produces cheap white noise, optimized for window-space -// Comes from: https://www.shadertoy.com/view/4djSRW -// Copyright: Dave Hoskins, MIT License +// Interleaved Gradient Noise +// http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare float quick_hash(vec2 pos) { - vec3 p3 = fract(vec3(pos.xyx) * .1031); - p3 += dot(p3, p3.yzx + 33.33); - return fract((p3.x + p3.y) * p3.z); + const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f); + return fract(magic.z * fract(dot(pos, magic.xy))); } float sample_directional_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) { @@ -845,69 +902,39 @@ float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex #endif //USE_NO_SHADOWS -void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 albedo, float roughness, float metallic, float specular, float p_blob_intensity, -#ifdef LIGHT_BACKLIGHT_USED - vec3 backlight, -#endif -#ifdef LIGHT_TRANSMITTANCE_USED - vec4 transmittance_color, - float transmittance_depth, - float transmittance_curve, - float transmittance_boost, -#endif -#ifdef LIGHT_RIM_USED - float rim, float rim_tint, -#endif -#ifdef LIGHT_CLEARCOAT_USED - float clearcoat, float clearcoat_gloss, -#endif -#ifdef LIGHT_ANISOTROPY_USED - vec3 binormal, vec3 tangent, float anisotropy, -#endif -#ifdef USE_SHADOW_TO_OPACITY - inout float alpha, -#endif - inout vec3 diffuse_light, inout vec3 specular_light) { - vec3 light_rel_vec = lights.data[idx].position - vertex; - float light_length = length(light_rel_vec); - float normalized_distance = light_length * lights.data[idx].inv_radius; - vec2 attenuation_energy = unpackHalf2x16(lights.data[idx].attenuation_energy); - float omni_attenuation = pow(max(1.0 - normalized_distance, 0.0), attenuation_energy.x); - float light_attenuation = omni_attenuation; - vec3 shadow_attenuation = vec3(1.0); - vec4 color_specular = unpackUnorm4x8(lights.data[idx].color_specular); - color_specular.rgb *= attenuation_energy.y; - float size_A = 0.0; - - if (lights.data[idx].size > 0.0) { - float t = lights.data[idx].size / max(0.001, light_length); - size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); - } - -#ifdef LIGHT_TRANSMITTANCE_USED - float transmittance_z = transmittance_depth; //no transmittance by default -#endif +float get_omni_attenuation(float distance, float inv_range, float decay) { + float nd = distance * inv_range; + nd *= nd; + nd *= nd; // nd^4 + nd = max(1.0 - nd, 0.0); + nd *= nd; // nd^2 + return nd * pow(max(distance, 0.0001), -decay); +} +float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { #ifndef USE_NO_SHADOWS - vec4 shadow_color_enabled = unpackUnorm4x8(lights.data[idx].shadow_color_enabled); - if (shadow_color_enabled.w > 0.5) { + if (omni_lights.data[idx].shadow_enabled) { // there is a shadowmap + vec3 light_rel_vec = omni_lights.data[idx].position - vertex; + float light_length = length(light_rel_vec); + vec4 v = vec4(vertex, 1.0); - vec4 splane = (lights.data[idx].shadow_matrix * v); + vec4 splane = (omni_lights.data[idx].shadow_matrix * v); float shadow_len = length(splane.xyz); //need to remember shadow len from here { - vec3 nofs = normal_interp * lights.data[idx].shadow_normal_bias / lights.data[idx].inv_radius; + vec3 nofs = normal_interp * omni_lights.data[idx].shadow_normal_bias / omni_lights.data[idx].inv_radius; nofs *= (1.0 - max(0.0, dot(normalize(light_rel_vec), normalize(normal_interp)))); v.xyz += nofs; - splane = (lights.data[idx].shadow_matrix * v); + splane = (omni_lights.data[idx].shadow_matrix * v); } float shadow; - if (lights.data[idx].soft_shadow_size > 0.0) { +#ifdef USE_SOFT_SHADOWS + if (omni_lights.data[idx].soft_shadow_size > 0.0) { //soft shadow //find blocker @@ -927,10 +954,10 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); vec3 tangent = normalize(cross(v0, normal)); vec3 bitangent = normalize(cross(tangent, normal)); - float z_norm = shadow_len * lights.data[idx].inv_radius; + float z_norm = shadow_len * omni_lights.data[idx].inv_radius; - tangent *= lights.data[idx].soft_shadow_size * lights.data[idx].soft_shadow_scale; - bitangent *= lights.data[idx].soft_shadow_size * lights.data[idx].soft_shadow_scale; + tangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale; + bitangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale; for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy; @@ -938,7 +965,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y; pos = normalize(pos); - vec4 uv_rect = lights.data[idx].atlas_rect; + vec4 uv_rect = omni_lights.data[idx].atlas_rect; if (pos.z >= 0.0) { pos.z += 1.0; @@ -966,7 +993,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v tangent *= penumbra; bitangent *= penumbra; - z_norm -= lights.data[idx].inv_radius * lights.data[idx].shadow_bias; + z_norm -= omni_lights.data[idx].inv_radius * omni_lights.data[idx].shadow_bias; shadow = 0.0; for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { @@ -974,7 +1001,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y; pos = normalize(pos); - vec4 uv_rect = lights.data[idx].atlas_rect; + vec4 uv_rect = omni_lights.data[idx].atlas_rect; if (pos.z >= 0.0) { pos.z += 1.0; @@ -997,8 +1024,9 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v shadow = 1.0; } } else { +#endif splane.xyz = normalize(splane.xyz); - vec4 clamp_rect = lights.data[idx].atlas_rect; + vec4 clamp_rect = omni_lights.data[idx].atlas_rect; if (splane.z >= 0.0) { splane.z += 1.0; @@ -1012,101 +1040,149 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v splane.xy /= splane.z; splane.xy = splane.xy * 0.5 + 0.5; - splane.z = (shadow_len - lights.data[idx].shadow_bias) * lights.data[idx].inv_radius; + splane.z = (shadow_len - omni_lights.data[idx].shadow_bias) * omni_lights.data[idx].inv_radius; splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; splane.w = 1.0; //needed? i think it should be 1 already - shadow = sample_pcf_shadow(shadow_atlas, lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, splane); + shadow = sample_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, splane); +#ifdef USE_SOFT_SHADOWS } +#endif + + return shadow; + } +#endif + + return 1.0; +} +void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, +#ifdef LIGHT_BACKLIGHT_USED + vec3 backlight, +#endif #ifdef LIGHT_TRANSMITTANCE_USED - { - vec4 clamp_rect = lights.data[idx].atlas_rect; + vec4 transmittance_color, + float transmittance_depth, + float transmittance_curve, + float transmittance_boost, +#endif +#ifdef LIGHT_RIM_USED + float rim, float rim_tint, vec3 rim_color, +#endif +#ifdef LIGHT_CLEARCOAT_USED + float clearcoat, float clearcoat_gloss, +#endif +#ifdef LIGHT_ANISOTROPY_USED + vec3 binormal, vec3 tangent, float anisotropy, +#endif +#ifdef USE_SHADOW_TO_OPACITY + inout float alpha, +#endif + inout vec3 diffuse_light, inout vec3 specular_light) { + vec3 light_rel_vec = omni_lights.data[idx].position - vertex; + float light_length = length(light_rel_vec); + float omni_attenuation = get_omni_attenuation(light_length, omni_lights.data[idx].inv_radius, omni_lights.data[idx].attenuation); + float light_attenuation = omni_attenuation; + vec3 color = omni_lights.data[idx].color; - //redo shadowmapping, but shrink the model a bit to avoid arctifacts - splane = (lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * lights.data[idx].transmittance_bias, 1.0)); +#ifdef USE_SOFT_SHADOWS + float size_A = 0.0; - shadow_len = length(splane.xyz); - splane = normalize(splane.xyz); + if (omni_lights.data[idx].size > 0.0) { + float t = omni_lights.data[idx].size / max(0.001, light_length); + size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); + } +#endif - if (splane.z >= 0.0) { - splane.z += 1.0; +#ifdef LIGHT_TRANSMITTANCE_USED + float transmittance_z = transmittance_depth; //no transmittance by default + transmittance_color.a *= light_attenuation; + { + vec4 clamp_rect = omni_lights.data[idx].atlas_rect; - } else { - splane.z = 1.0 - splane.z; - } + //redo shadowmapping, but shrink the model a bit to avoid arctifacts + vec4 splane = (omni_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * omni_lights.data[idx].transmittance_bias, 1.0)); - splane.xy /= splane.z; - splane.xy = splane.xy * 0.5 + 0.5; - splane.z = shadow_len * lights.data[idx].inv_radius; - splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; - splane.w = 1.0; //needed? i think it should be 1 already + shadow_len = length(splane.xyz); + splane = normalize(splane.xyz); - float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r; - transmittance_z = (splane.z - shadow_z) / lights.data[idx].inv_radius; + if (splane.z >= 0.0) { + splane.z += 1.0; + + } else { + splane.z = 1.0 - splane.z; } -#endif - vec3 no_shadow = vec3(1.0); + splane.xy /= splane.z; + splane.xy = splane.xy * 0.5 + 0.5; + splane.z = shadow_len * omni_lights.data[idx].inv_radius; + splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; + splane.w = 1.0; //needed? i think it should be 1 already - if (lights.data[idx].projector_rect != vec4(0.0)) { - vec3 local_v = (lights.data[idx].shadow_matrix * vec4(vertex, 1.0)).xyz; - local_v = normalize(local_v); + float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r; + transmittance_z = (splane.z - shadow_z) / omni_lights.data[idx].inv_radius; + } +#endif - vec4 atlas_rect = lights.data[idx].projector_rect; +#if 0 - if (local_v.z >= 0.0) { - local_v.z += 1.0; - atlas_rect.y += atlas_rect.w; + if (omni_lights.data[idx].projector_rect != vec4(0.0)) { + vec3 local_v = (omni_lights.data[idx].shadow_matrix * vec4(vertex, 1.0)).xyz; + local_v = normalize(local_v); - } else { - local_v.z = 1.0 - local_v.z; - } + vec4 atlas_rect = omni_lights.data[idx].projector_rect; - local_v.xy /= local_v.z; - local_v.xy = local_v.xy * 0.5 + 0.5; - vec2 proj_uv = local_v.xy * atlas_rect.zw; + if (local_v.z >= 0.0) { + local_v.z += 1.0; + atlas_rect.y += atlas_rect.w; - vec2 proj_uv_ddx; - vec2 proj_uv_ddy; - { - vec3 local_v_ddx = (lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0)).xyz; - local_v_ddx = normalize(local_v_ddx); + } else { + local_v.z = 1.0 - local_v.z; + } - if (local_v_ddx.z >= 0.0) { - local_v_ddx.z += 1.0; - } else { - local_v_ddx.z = 1.0 - local_v_ddx.z; - } + local_v.xy /= local_v.z; + local_v.xy = local_v.xy * 0.5 + 0.5; + vec2 proj_uv = local_v.xy * atlas_rect.zw; - local_v_ddx.xy /= local_v_ddx.z; - local_v_ddx.xy = local_v_ddx.xy * 0.5 + 0.5; + vec2 proj_uv_ddx; + vec2 proj_uv_ddy; + { + vec3 local_v_ddx = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0)).xyz; + local_v_ddx = normalize(local_v_ddx); - proj_uv_ddx = local_v_ddx.xy * atlas_rect.zw - proj_uv; + if (local_v_ddx.z >= 0.0) { + local_v_ddx.z += 1.0; + } else { + local_v_ddx.z = 1.0 - local_v_ddx.z; + } - vec3 local_v_ddy = (lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0)).xyz; - local_v_ddy = normalize(local_v_ddy); + local_v_ddx.xy /= local_v_ddx.z; + local_v_ddx.xy = local_v_ddx.xy * 0.5 + 0.5; - if (local_v_ddy.z >= 0.0) { - local_v_ddy.z += 1.0; - } else { - local_v_ddy.z = 1.0 - local_v_ddy.z; - } + proj_uv_ddx = local_v_ddx.xy * atlas_rect.zw - proj_uv; - local_v_ddy.xy /= local_v_ddy.z; - local_v_ddy.xy = local_v_ddy.xy * 0.5 + 0.5; + vec3 local_v_ddy = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0)).xyz; + local_v_ddy = normalize(local_v_ddy); - proj_uv_ddy = local_v_ddy.xy * atlas_rect.zw - proj_uv; + if (local_v_ddy.z >= 0.0) { + local_v_ddy.z += 1.0; + } else { + local_v_ddy.z = 1.0 - local_v_ddy.z; } - vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), proj_uv + atlas_rect.xy, proj_uv_ddx, proj_uv_ddy); - no_shadow = mix(no_shadow, proj.rgb, proj.a); + local_v_ddy.xy /= local_v_ddy.z; + local_v_ddy.xy = local_v_ddy.xy * 0.5 + 0.5; + + proj_uv_ddy = local_v_ddy.xy * atlas_rect.zw - proj_uv; } - shadow_attenuation = mix(shadow_color_enabled.rgb, no_shadow, shadow); + vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), proj_uv + atlas_rect.xy, proj_uv_ddx, proj_uv_ddy); + no_shadow = mix(no_shadow, proj.rgb, proj.a); } -#endif //USE_NO_SHADOWS +#endif - light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color_specular.rgb, light_attenuation, shadow_attenuation, albedo, roughness, metallic, specular, color_specular.a * p_blob_intensity, + light_attenuation *= shadow; + + light_compute(normal, normalize(light_rel_vec), eye_vec, color, light_attenuation, f0, orms, omni_lights.data[idx].specular_amount, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -1118,7 +1194,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v transmittance_z, #endif #ifdef LIGHT_RIM_USED - rim * omni_attenuation, rim_tint, + rim * omni_attenuation, rim_tint, rim_color, #endif #ifdef LIGHT_CLEARCOAT_USED clearcoat, clearcoat_gloss, @@ -1126,6 +1202,9 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v #ifdef LIGHT_ANISOTROPY_USED binormal, tangent, anisotropy, #endif +#ifdef USE_SOFT_SHADOWS + size_A, +#endif #ifdef USE_SHADOW_TO_OPACITY alpha, #endif @@ -1133,89 +1212,39 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v specular_light); } -void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 albedo, float roughness, float metallic, float specular, float p_blob_intensity, -#ifdef LIGHT_BACKLIGHT_USED - vec3 backlight, -#endif -#ifdef LIGHT_TRANSMITTANCE_USED - vec4 transmittance_color, - float transmittance_depth, - float transmittance_curve, - float transmittance_boost, -#endif -#ifdef LIGHT_RIM_USED - float rim, float rim_tint, -#endif -#ifdef LIGHT_CLEARCOAT_USED - float clearcoat, float clearcoat_gloss, -#endif -#ifdef LIGHT_ANISOTROPY_USED - vec3 binormal, vec3 tangent, float anisotropy, -#endif -#ifdef USE_SHADOW_TO_OPACITY - inout float alpha, -#endif - inout vec3 diffuse_light, - inout vec3 specular_light) { - vec3 light_rel_vec = lights.data[idx].position - vertex; - float light_length = length(light_rel_vec); - float normalized_distance = light_length * lights.data[idx].inv_radius; - vec2 attenuation_energy = unpackHalf2x16(lights.data[idx].attenuation_energy); - float spot_attenuation = pow(max(1.0 - normalized_distance, 0.001), attenuation_energy.x); - vec3 spot_dir = lights.data[idx].direction; - vec2 spot_att_angle = unpackHalf2x16(lights.data[idx].cone_attenuation_angle); - float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_att_angle.y); - float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_att_angle.y)); - spot_attenuation *= 1.0 - pow(spot_rim, spot_att_angle.x); - float light_attenuation = spot_attenuation; - vec3 shadow_attenuation = vec3(1.0); - vec4 color_specular = unpackUnorm4x8(lights.data[idx].color_specular); - color_specular.rgb *= attenuation_energy.y; - - float size_A = 0.0; - - if (lights.data[idx].size > 0.0) { - float t = lights.data[idx].size / max(0.001, light_length); - size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); - } -/* - if (lights.data[idx].atlas_rect!=vec4(0.0)) { - //use projector texture - } - */ -#ifdef LIGHT_TRANSMITTANCE_USED - float transmittance_z = transmittance_depth; -#endif - +float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) { #ifndef USE_NO_SHADOWS - vec4 shadow_color_enabled = unpackUnorm4x8(lights.data[idx].shadow_color_enabled); - if (shadow_color_enabled.w > 0.5) { + if (spot_lights.data[idx].shadow_enabled) { + vec3 light_rel_vec = spot_lights.data[idx].position - vertex; + float light_length = length(light_rel_vec); + vec3 spot_dir = spot_lights.data[idx].direction; //there is a shadowmap vec4 v = vec4(vertex, 1.0); - v.xyz -= spot_dir * lights.data[idx].shadow_bias; + v.xyz -= spot_dir * spot_lights.data[idx].shadow_bias; - float z_norm = dot(spot_dir, -light_rel_vec) * lights.data[idx].inv_radius; + float z_norm = dot(spot_dir, -light_rel_vec) * spot_lights.data[idx].inv_radius; float depth_bias_scale = 1.0 / (max(0.0001, z_norm)); //the closer to the light origin, the more you have to offset to reach 1px in the map - vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(spot_dir, -normalize(normal_interp)))) * lights.data[idx].shadow_normal_bias * depth_bias_scale; + vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(spot_dir, -normalize(normal_interp)))) * spot_lights.data[idx].shadow_normal_bias * depth_bias_scale; normal_bias -= spot_dir * dot(spot_dir, normal_bias); //only XY, no Z v.xyz += normal_bias; //adjust with bias - z_norm = dot(spot_dir, v.xyz - lights.data[idx].position) * lights.data[idx].inv_radius; + z_norm = dot(spot_dir, v.xyz - spot_lights.data[idx].position) * spot_lights.data[idx].inv_radius; float shadow; - vec4 splane = (lights.data[idx].shadow_matrix * v); + vec4 splane = (spot_lights.data[idx].shadow_matrix * v); splane /= splane.w; - if (lights.data[idx].soft_shadow_size > 0.0) { +#ifdef USE_SOFT_SHADOWS + if (spot_lights.data[idx].soft_shadow_size > 0.0) { //soft shadow //find blocker - vec2 shadow_uv = splane.xy * lights.data[idx].atlas_rect.zw + lights.data[idx].atlas_rect.xy; + vec2 shadow_uv = splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy; float blocker_count = 0.0; float blocker_average = 0.0; @@ -1228,11 +1257,11 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); } - float uv_size = lights.data[idx].soft_shadow_size * z_norm * lights.data[idx].soft_shadow_scale; - vec2 clamp_max = lights.data[idx].atlas_rect.xy + lights.data[idx].atlas_rect.zw; + float uv_size = spot_lights.data[idx].soft_shadow_size * z_norm * spot_lights.data[idx].soft_shadow_scale; + vec2 clamp_max = spot_lights.data[idx].atlas_rect.xy + spot_lights.data[idx].atlas_rect.zw; for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size; - suv = clamp(suv, lights.data[idx].atlas_rect.xy, clamp_max); + suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max); float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r; if (d < z_norm) { blocker_average += d; @@ -1249,7 +1278,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v shadow = 0.0; for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size; - suv = clamp(suv, lights.data[idx].atlas_rect.xy, clamp_max); + suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max); shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(suv, z_norm, 1.0)); } @@ -1261,54 +1290,93 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v } } else { +#endif //hard shadow - vec4 shadow_uv = vec4(splane.xy * lights.data[idx].atlas_rect.zw + lights.data[idx].atlas_rect.xy, z_norm, 1.0); + vec4 shadow_uv = vec4(splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy, splane.z, 1.0); - shadow = sample_pcf_shadow(shadow_atlas, lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, shadow_uv); + shadow = sample_pcf_shadow(shadow_atlas, spot_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, shadow_uv); +#ifdef USE_SOFT_SHADOWS } +#endif - vec3 no_shadow = vec3(1.0); + return shadow; + } - if (lights.data[idx].projector_rect != vec4(0.0)) { - splane = (lights.data[idx].shadow_matrix * vec4(vertex, 1.0)); - splane /= splane.w; +#endif //USE_NO_SHADOWS - vec2 proj_uv = splane.xy * lights.data[idx].projector_rect.zw; + return 1.0; +} - //ensure we have proper mipmaps - vec4 splane_ddx = (lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0)); - splane_ddx /= splane_ddx.w; - vec2 proj_uv_ddx = splane_ddx.xy * lights.data[idx].projector_rect.zw - proj_uv; +void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, +#ifdef LIGHT_BACKLIGHT_USED + vec3 backlight, +#endif +#ifdef LIGHT_TRANSMITTANCE_USED + vec4 transmittance_color, + float transmittance_depth, + float transmittance_curve, + float transmittance_boost, +#endif +#ifdef LIGHT_RIM_USED + float rim, float rim_tint, vec3 rim_color, +#endif +#ifdef LIGHT_CLEARCOAT_USED + float clearcoat, float clearcoat_gloss, +#endif +#ifdef LIGHT_ANISOTROPY_USED + vec3 binormal, vec3 tangent, float anisotropy, +#endif +#ifdef USE_SHADOW_TO_OPACITY + inout float alpha, +#endif + inout vec3 diffuse_light, + inout vec3 specular_light) { + vec3 light_rel_vec = spot_lights.data[idx].position - vertex; + float light_length = length(light_rel_vec); + float spot_attenuation = get_omni_attenuation(light_length, spot_lights.data[idx].inv_radius, spot_lights.data[idx].attenuation); + vec3 spot_dir = spot_lights.data[idx].direction; + float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights.data[idx].cone_angle); + float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights.data[idx].cone_angle)); + spot_attenuation *= 1.0 - pow(spot_rim, spot_lights.data[idx].cone_attenuation); + float light_attenuation = spot_attenuation; + vec3 color = spot_lights.data[idx].color; + float specular_amount = spot_lights.data[idx].specular_amount; - vec4 splane_ddy = (lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0)); - splane_ddy /= splane_ddy.w; - vec2 proj_uv_ddy = splane_ddy.xy * lights.data[idx].projector_rect.zw - proj_uv; +#ifdef USE_SOFT_SHADOWS + float size_A = 0.0; - vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), proj_uv + lights.data[idx].projector_rect.xy, proj_uv_ddx, proj_uv_ddy); - no_shadow = mix(no_shadow, proj.rgb, proj.a); - } + if (spot_lights.data[idx].size > 0.0) { + float t = spot_lights.data[idx].size / max(0.001, light_length); + size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); + } +#endif - shadow_attenuation = mix(shadow_color_enabled.rgb, no_shadow, shadow); + /* + if (spot_lights.data[idx].atlas_rect!=vec4(0.0)) { + //use projector texture + } + */ #ifdef LIGHT_TRANSMITTANCE_USED - { - splane = (lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * lights.data[idx].transmittance_bias, 1.0)); - splane /= splane.w; - splane.xy = splane.xy * lights.data[idx].atlas_rect.zw + lights.data[idx].atlas_rect.xy; - - float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r; - //reconstruct depth - shadow_z /= lights.data[idx].inv_radius; - //distance to light plane - float z = dot(spot_dir, -light_rel_vec); - transmittance_z = z - shadow_z; - } -#endif //LIGHT_TRANSMITTANCE_USED + float transmittance_z = transmittance_depth; + transmittance_color.a *= light_attenuation; + { + splane = (spot_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * spot_lights.data[idx].transmittance_bias, 1.0)); + splane /= splane.w; + splane.xy = splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy; + + float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r; + //reconstruct depth + shadow_z /= spot_lights.data[idx].inv_radius; + //distance to light plane + float z = dot(spot_dir, -light_rel_vec); + transmittance_z = z - shadow_z; } +#endif //LIGHT_TRANSMITTANCE_USED -#endif //USE_NO_SHADOWS + light_attenuation *= shadow; - light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color_specular.rgb, light_attenuation, shadow_attenuation, albedo, roughness, metallic, specular, color_specular.a * p_blob_intensity, + light_compute(normal, normalize(light_rel_vec), eye_vec, color, light_attenuation, f0, orms, spot_lights.data[idx].specular_amount, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -1320,7 +1388,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v transmittance_z, #endif #ifdef LIGHT_RIM_USED - rim * spot_attenuation, rim_tint, + rim * spot_attenuation, rim_tint, rim_color, #endif #ifdef LIGHT_CLEARCOAT_USED clearcoat, clearcoat_gloss, @@ -1328,6 +1396,9 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v #ifdef LIGHT_ANISOTROPY_USED binormal, tangent, anisotropy, #endif +#ifdef USE_SOFT_SHADOW + size_A, +#endif #ifdef USE_SHADOW_TO_OPACITY alpha, #endif @@ -1351,11 +1422,11 @@ void reflection_process(uint ref_index, vec3 vertex, vec3 normal, float roughnes blend *= blend; blend = max(0.0, 1.0 - blend); - if (reflections.data[ref_index].params.x > 0.0) { // compute reflection + if (reflections.data[ref_index].intensity > 0.0) { // compute reflection vec3 local_ref_vec = (reflections.data[ref_index].local_matrix * vec4(ref_vec, 0.0)).xyz; - if (reflections.data[ref_index].params.w > 0.5) { //box project + if (reflections.data[ref_index].box_project) { //box project vec3 nrdir = normalize(local_ref_vec); vec3 rbmax = (box_extents - local_pos) / nrdir; @@ -1372,11 +1443,11 @@ void reflection_process(uint ref_index, vec3 vertex, vec3 normal, float roughnes reflection.rgb = textureLod(samplerCubeArray(reflection_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_ref_vec, reflections.data[ref_index].index), roughness * MAX_ROUGHNESS_LOD).rgb; - if (reflections.data[ref_index].params.z < 0.5) { + if (reflections.data[ref_index].exterior) { reflection.rgb = mix(specular_light, reflection.rgb, blend); } - reflection.rgb *= reflections.data[ref_index].params.x; + reflection.rgb *= reflections.data[ref_index].intensity; //intensity reflection.a = blend; reflection.rgb *= reflection.a; @@ -1395,7 +1466,7 @@ void reflection_process(uint ref_index, vec3 vertex, vec3 normal, float roughnes ambient_out.rgb = textureLod(samplerCubeArray(reflection_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_amb_vec, reflections.data[ref_index].index), MAX_ROUGHNESS_LOD).rgb; ambient_out.a = blend; - if (reflections.data[ref_index].params.z < 0.5) { //interior + if (reflections.data[ref_index].exterior) { ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend); } @@ -1406,7 +1477,7 @@ void reflection_process(uint ref_index, vec3 vertex, vec3 normal, float roughnes vec4 ambient_out; ambient_out.a = blend; ambient_out.rgb = reflections.data[ref_index].ambient; - if (reflections.data[ref_index].params.z < 0.5) { + if (reflections.data[ref_index].exterior) { ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend); } ambient_out.rgb *= ambient_out.a; @@ -1525,8 +1596,6 @@ void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 out_spec += vec4(irr_light.rgb * blend, blend); } -#endif //USE_FORWARD_GI - vec2 octahedron_wrap(vec2 v) { vec2 signVal; signVal.x = v.x >= 0.0 ? 1.0 : -1.0; @@ -1660,10 +1729,14 @@ void sdfgi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal } } +#endif //USE_FORWARD_GI + #endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) #ifndef MODE_RENDER_DEPTH +#ifndef LOW_END_MODE + vec4 volumetric_fog_process(vec2 screen_uv, float z) { vec3 fog_pos = vec3(screen_uv, z * scene_data.volumetric_fog_inv_length); if (fog_pos.z < 0.0) { @@ -1674,6 +1747,7 @@ vec4 volumetric_fog_process(vec2 screen_uv, float z) { return texture(sampler3D(volumetric_fog_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), fog_pos); } +#endif vec4 fog_process(vec3 vertex) { vec3 fog_color = scene_data.fog_light_color; @@ -1706,7 +1780,7 @@ vec4 fog_process(vec3 vertex) { } } - float fog_amount = 1.0 - exp(vertex.z * scene_data.fog_density); + float fog_amount = 1.0 - exp(min(0.0, vertex.z * scene_data.fog_density)); if (abs(scene_data.fog_height_density) > 0.001) { float y = (scene_data.camera_matrix * vec4(vertex, 1.0)).y; @@ -1721,7 +1795,43 @@ vec4 fog_process(vec3 vertex) { return vec4(fog_color, fog_amount); } +void cluster_get_item_range(uint p_offset, out uint item_min, out uint item_max, out uint item_from, out uint item_to) { + uint item_min_max = cluster_buffer.data[p_offset]; + item_min = item_min_max & 0xFFFF; + item_max = item_min_max >> 16; + ; + + item_from = item_min >> 5; + item_to = (item_max == 0) ? 0 : ((item_max - 1) >> 5) + 1; //side effect of how it is stored, as item_max 0 means no elements +} + +uint cluster_get_range_clip_mask(uint i, uint z_min, uint z_max) { + int local_min = clamp(int(z_min) - int(i) * 32, 0, 31); + int mask_width = min(int(z_max) - int(z_min), 32 - local_min); + return bitfieldInsert(uint(0), uint(0xFFFFFFFF), local_min, mask_width); +} + +float blur_shadow(float shadow) { + return shadow; +#if 0 + //disabling for now, will investigate later + float interp_shadow = shadow; + if (gl_HelperInvocation) { + interp_shadow = -4.0; // technically anything below -4 will do but just to make sure + } + + uvec2 fc2 = uvec2(gl_FragCoord.xy); + interp_shadow -= dFdx(interp_shadow) * (float(fc2.x & 1) - 0.5); + interp_shadow -= dFdy(interp_shadow) * (float(fc2.y & 1) - 0.5); + + if (interp_shadow >= 0.0) { + shadow = interp_shadow; + } + return shadow; #endif +} + +#endif //!MODE_RENDER DEPTH void main() { #ifdef MODE_DUAL_PARABOLOID @@ -1749,9 +1859,7 @@ void main() { float clearcoat_gloss = 0.0; float anisotropy = 0.0; vec2 anisotropy_flow = vec2(1.0, 0.0); -#if defined(CUSTOM_FOG_USED) - vec4 custom_fog = vec4(0.0); -#endif + vec4 fog = vec4(0.0); #if defined(CUSTOM_RADIANCE_USED) vec4 custom_radiance = vec4(0.0); #endif @@ -1759,20 +1867,20 @@ void main() { vec4 custom_irradiance = vec4(0.0); #endif -#if defined(AO_USED) float ao = 1.0; float ao_light_affect = 0.0; -#endif float alpha = 1.0; -#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) vec3 binormal = normalize(binormal_interp); vec3 tangent = normalize(tangent_interp); #else vec3 binormal = vec3(0.0); vec3 tangent = vec3(0.0); #endif + +#ifdef NORMAL_USED vec3 normal = normalize(normal_interp); #if defined(DO_SIDE_CHECK) @@ -1781,7 +1889,11 @@ void main() { } #endif +#endif //NORMAL_USED + +#ifdef UV_USED vec2 uv = uv_interp; +#endif #if defined(UV2_USED) || defined(USE_LIGHTMAP) vec2 uv2 = uv2_interp; @@ -1791,12 +1903,12 @@ void main() { vec4 color = color_interp; #endif -#if defined(NORMALMAP_USED) +#if defined(NORMAL_MAP_USED) - vec3 normalmap = vec3(0.5); + vec3 normal_map = vec3(0.5); #endif - float normaldepth = 1.0; + float normal_map_depth = 1.0; vec2 screen_uv = gl_FragCoord.xy * scene_data.screen_pixel_size + scene_data.screen_pixel_size * 0.5; //account for center @@ -1867,12 +1979,12 @@ FRAGMENT_SHADER_CODE #endif // !USE_SHADOW_TO_OPACITY -#ifdef NORMALMAP_USED +#ifdef NORMAL_MAP_USED - normalmap.xy = normalmap.xy * 2.0 - 1.0; - normalmap.z = sqrt(max(0.0, 1.0 - dot(normalmap.xy, normalmap.xy))); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc. + normal_map.xy = normal_map.xy * 2.0 - 1.0; + normal_map.z = sqrt(max(0.0, 1.0 - dot(normal_map.xy, normal_map.xy))); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc. - normal = normalize(mix(normal, tangent * normalmap.x + binormal * normalmap.y + normal * normalmap.z, normaldepth)); + normal = normalize(mix(normal, tangent * normal_map.x + binormal * normal_map.y + normal * normal_map.z, normal_map_depth)); #endif @@ -1894,80 +2006,151 @@ FRAGMENT_SHADER_CODE discard; } #endif + + /////////////////////// FOG ////////////////////// +#ifndef MODE_RENDER_DEPTH + +#ifndef CUSTOM_FOG_USED + // fog must be processed as early as possible and then packed. + // to maximize VGPR usage + // Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky. + + if (scene_data.fog_enabled) { + fog = fog_process(vertex); + } + +#ifndef LOW_END_MODE + if (scene_data.volumetric_fog_enabled) { + vec4 volumetric_fog = volumetric_fog_process(screen_uv, -vertex.z); + if (scene_data.fog_enabled) { + //must use the full blending equation here to blend fogs + vec4 res; + float sa = 1.0 - volumetric_fog.a; + res.a = fog.a * sa + volumetric_fog.a; + if (res.a == 0.0) { + res.rgb = vec3(0.0); + } else { + res.rgb = (fog.rgb * fog.a * sa + volumetric_fog.rgb * volumetric_fog.a) / res.a; + } + fog = res; + } else { + fog = volumetric_fog; + } + } +#endif //!LOW_END_MODE +#endif //!CUSTOM_FOG_USED + + uint fog_rg = packHalf2x16(fog.rg); + uint fog_ba = packHalf2x16(fog.ba); + +#endif //!MODE_RENDER_DEPTH + /////////////////////// DECALS //////////////////////////////// #ifndef MODE_RENDER_DEPTH - uvec4 cluster_cell = texture(usampler3D(cluster_texture, material_samplers[SAMPLER_NEAREST_CLAMP]), vec3(screen_uv, (abs(vertex.z) - scene_data.z_near) / (scene_data.z_far - scene_data.z_near))); + uvec2 cluster_pos = uvec2(gl_FragCoord.xy) >> scene_data.cluster_shift; + uint cluster_offset = (scene_data.cluster_width * cluster_pos.y + cluster_pos.x) * (scene_data.max_cluster_element_count_div_32 + 32); + + uint cluster_z = uint(clamp((-vertex.z / scene_data.z_far) * 32.0, 0.0, 31.0)); + //used for interpolating anything cluster related vec3 vertex_ddx = dFdx(vertex); vec3 vertex_ddy = dFdy(vertex); { // process decals - uint decal_count = cluster_cell.w >> CLUSTER_COUNTER_SHIFT; - uint decal_pointer = cluster_cell.w & CLUSTER_POINTER_MASK; + uint cluster_decal_offset = cluster_offset + scene_data.cluster_type_size * 2; - //do outside for performance and avoiding arctifacts + uint item_min; + uint item_max; + uint item_from; + uint item_to; - for (uint i = 0; i < decal_count; i++) { - uint decal_index = cluster_data.indices[decal_pointer + i]; - if (!bool(decals.data[decal_index].mask & instances.data[instance_index].layer_mask)) { - continue; //not masked - } + cluster_get_item_range(cluster_decal_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); - vec3 uv_local = (decals.data[decal_index].xform * vec4(vertex, 1.0)).xyz; - if (any(lessThan(uv_local, vec3(0.0, -1.0, 0.0))) || any(greaterThan(uv_local, vec3(1.0)))) { - continue; //out of decal - } +#ifdef USE_SUBGROUPS + item_from = subgroupBroadcastFirst(subgroupMin(item_from)); + item_to = subgroupBroadcastFirst(subgroupMax(item_to)); +#endif - //we need ddx/ddy for mipmaps, so simulate them - vec2 ddx = (decals.data[decal_index].xform * vec4(vertex_ddx, 0.0)).xz; - vec2 ddy = (decals.data[decal_index].xform * vec4(vertex_ddy, 0.0)).xz; + for (uint i = item_from; i < item_to; i++) { + uint mask = cluster_buffer.data[cluster_decal_offset + i]; + mask &= cluster_get_range_clip_mask(i, item_min, item_max); +#ifdef USE_SUBGROUPS + uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); +#else + uint merged_mask = mask; +#endif - float fade = pow(1.0 - (uv_local.y > 0.0 ? uv_local.y : -uv_local.y), uv_local.y > 0.0 ? decals.data[decal_index].upper_fade : decals.data[decal_index].lower_fade); + while (merged_mask != 0) { + uint bit = findMSB(merged_mask); + merged_mask &= ~(1 << bit); +#ifdef USE_SUBGROUPS + if (((1 << bit) & mask) == 0) { //do not process if not originally here + continue; + } +#endif + uint decal_index = 32 * i + bit; - if (decals.data[decal_index].normal_fade > 0.0) { - fade *= smoothstep(decals.data[decal_index].normal_fade, 1.0, dot(normal_interp, decals.data[decal_index].normal) * 0.5 + 0.5); - } + if (!bool(decals.data[decal_index].mask & instances.data[instance_index].layer_mask)) { + continue; //not masked + } - if (decals.data[decal_index].albedo_rect != vec4(0.0)) { - //has albedo - vec4 decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, ddx * decals.data[decal_index].albedo_rect.zw, ddy * decals.data[decal_index].albedo_rect.zw); - decal_albedo *= decals.data[decal_index].modulate; - decal_albedo.a *= fade; - albedo = mix(albedo, decal_albedo.rgb, decal_albedo.a * decals.data[decal_index].albedo_mix); - - if (decals.data[decal_index].normal_rect != vec4(0.0)) { - vec3 decal_normal = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, ddx * decals.data[decal_index].normal_rect.zw, ddy * decals.data[decal_index].normal_rect.zw).xyz; - decal_normal.xy = decal_normal.xy * vec2(2.0, -2.0) - vec2(1.0, -1.0); //users prefer flipped y normal maps in most authoring software - decal_normal.z = sqrt(max(0.0, 1.0 - dot(decal_normal.xy, decal_normal.xy))); - //convert to view space, use xzy because y is up - decal_normal = (decals.data[decal_index].normal_xform * decal_normal.xzy).xyz; - - normal = normalize(mix(normal, decal_normal, decal_albedo.a)); + vec3 uv_local = (decals.data[decal_index].xform * vec4(vertex, 1.0)).xyz; + if (any(lessThan(uv_local, vec3(0.0, -1.0, 0.0))) || any(greaterThan(uv_local, vec3(1.0)))) { + continue; //out of decal } - if (decals.data[decal_index].orm_rect != vec4(0.0)) { - vec3 decal_orm = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, ddx * decals.data[decal_index].orm_rect.zw, ddy * decals.data[decal_index].orm_rect.zw).xyz; -#if defined(AO_USED) - ao = mix(ao, decal_orm.r, decal_albedo.a); -#endif - roughness = mix(roughness, decal_orm.g, decal_albedo.a); - metallic = mix(metallic, decal_orm.b, decal_albedo.a); + //we need ddx/ddy for mipmaps, so simulate them + vec2 ddx = (decals.data[decal_index].xform * vec4(vertex_ddx, 0.0)).xz; + vec2 ddy = (decals.data[decal_index].xform * vec4(vertex_ddy, 0.0)).xz; + + float fade = pow(1.0 - (uv_local.y > 0.0 ? uv_local.y : -uv_local.y), uv_local.y > 0.0 ? decals.data[decal_index].upper_fade : decals.data[decal_index].lower_fade); + + if (decals.data[decal_index].normal_fade > 0.0) { + fade *= smoothstep(decals.data[decal_index].normal_fade, 1.0, dot(normal_interp, decals.data[decal_index].normal) * 0.5 + 0.5); + } + + if (decals.data[decal_index].albedo_rect != vec4(0.0)) { + //has albedo + vec4 decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, ddx * decals.data[decal_index].albedo_rect.zw, ddy * decals.data[decal_index].albedo_rect.zw); + decal_albedo *= decals.data[decal_index].modulate; + decal_albedo.a *= fade; + albedo = mix(albedo, decal_albedo.rgb, decal_albedo.a * decals.data[decal_index].albedo_mix); + + if (decals.data[decal_index].normal_rect != vec4(0.0)) { + vec3 decal_normal = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, ddx * decals.data[decal_index].normal_rect.zw, ddy * decals.data[decal_index].normal_rect.zw).xyz; + decal_normal.xy = decal_normal.xy * vec2(2.0, -2.0) - vec2(1.0, -1.0); //users prefer flipped y normal maps in most authoring software + decal_normal.z = sqrt(max(0.0, 1.0 - dot(decal_normal.xy, decal_normal.xy))); + //convert to view space, use xzy because y is up + decal_normal = (decals.data[decal_index].normal_xform * decal_normal.xzy).xyz; + + normal = normalize(mix(normal, decal_normal, decal_albedo.a)); + } + + if (decals.data[decal_index].orm_rect != vec4(0.0)) { + vec3 decal_orm = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, ddx * decals.data[decal_index].orm_rect.zw, ddy * decals.data[decal_index].orm_rect.zw).xyz; + ao = mix(ao, decal_orm.r, decal_albedo.a); + roughness = mix(roughness, decal_orm.g, decal_albedo.a); + metallic = mix(metallic, decal_orm.b, decal_albedo.a); + } } - } - if (decals.data[decal_index].emission_rect != vec4(0.0)) { - //emission is additive, so its independent from albedo - emission += textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, ddx * decals.data[decal_index].emission_rect.zw, ddy * decals.data[decal_index].emission_rect.zw).xyz * decals.data[decal_index].emission_energy * fade; + if (decals.data[decal_index].emission_rect != vec4(0.0)) { + //emission is additive, so its independent from albedo + emission += textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, ddx * decals.data[decal_index].emission_rect.zw, ddy * decals.data[decal_index].emission_rect.zw).xyz * decals.data[decal_index].emission_energy * fade; + } } } } + //pack albedo until needed again, saves 2 VGPRs in the meantime + #endif //not render depth /////////////////////// LIGHTING ////////////////////////////// +#ifdef NORMAL_USED if (scene_data.roughness_limiter_enabled) { //http://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf float roughness2 = roughness * roughness; @@ -1977,6 +2160,7 @@ FRAGMENT_SHADER_CODE float filteredRoughness2 = min(1.0, roughness2 + kernelRoughness2); roughness = sqrt(filteredRoughness2); } +#endif //apply energy conservation vec3 specular_light = vec3(0.0, 0.0, 0.0); @@ -2030,12 +2214,7 @@ FRAGMENT_SHADER_CODE //radiance - float specular_blob_intensity = 1.0; - -#if defined(SPECULAR_TOON) - specular_blob_intensity *= specular * 2.0; -#endif - +/// GI /// #if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) #ifdef USE_LIGHTMAP @@ -2063,10 +2242,10 @@ FRAGMENT_SHADER_CODE } else if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap bool uses_sh = bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP); - uint ofs = instances.data[instance_index].gi_offset & 0xFFF; + uint ofs = instances.data[instance_index].gi_offset & 0xFFFF; vec3 uvw; uvw.xy = uv2 * instances.data[instance_index].lightmap_uv_scale.zw + instances.data[instance_index].lightmap_uv_scale.xy; - uvw.z = float((instances.data[instance_index].gi_offset >> 12) & 0xFF); + uvw.z = float((instances.data[instance_index].gi_offset >> 16) & 0xFFFF); if (uses_sh) { uvw.z *= 4.0; //SH textures use 4 times more data @@ -2198,38 +2377,21 @@ FRAGMENT_SHADER_CODE specular_light = spec_accum.rgb; ambient_light = amb_accum.rgb; } -#else +#elif !defined(LOW_END_MODE) + if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GI_BUFFERS)) { //use GI buffers - ivec2 coord; + vec2 coord; if (scene_data.gi_upscale_for_msaa) { - /* - //find the closest depth to upscale from, based on neighbours - ivec2 base_coord = ivec2(gl_FragCoord.xy); - float z_dist = gl_FragCoord.z; - ivec2 closest_coord = base_coord; - float closest_z_dist = abs(texelFetch(sampler2D(depth_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), base_coord,0).r-z_dist); - - for(int i=0;i<4;i++) { - const ivec2 neighbours[4]=ivec2[](ivec2(-1,0),ivec2(1,0),ivec2(0,-1),ivec2(0,1)); - ivec2 neighbour_coord = base_coord + neighbours[i]; - float neighbour_z_dist = abs(texelFetch(sampler2D(depth_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), neighbour_coord,0).r-z_dist); - if (neighbour_z_dist < closest_z_dist) { - closest_z_dist = neighbour_z_dist; - closest_coord = neighbour_coord; - } - } - -*/ - ivec2 base_coord = ivec2(gl_FragCoord.xy); - ivec2 closest_coord = base_coord; - float closest_ang = dot(normal, texelFetch(sampler2D(normal_roughness_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), base_coord, 0).xyz * 2.0 - 1.0); + vec2 base_coord = screen_uv; + vec2 closest_coord = base_coord; + float closest_ang = dot(normal, textureLod(sampler2D(normal_roughness_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), base_coord, 0.0).xyz * 2.0 - 1.0); for (int i = 0; i < 4; i++) { - const ivec2 neighbours[4] = ivec2[](ivec2(-1, 0), ivec2(1, 0), ivec2(0, -1), ivec2(0, 1)); - ivec2 neighbour_coord = base_coord + neighbours[i]; - float neighbour_ang = dot(normal, texelFetch(sampler2D(normal_roughness_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), neighbour_coord, 0).xyz * 2.0 - 1.0); + const vec2 neighbours[4] = vec2[](vec2(-1, 0), vec2(1, 0), vec2(0, -1), vec2(0, 1)); + vec2 neighbour_coord = base_coord + neighbours[i] * scene_data.screen_pixel_size; + float neighbour_ang = dot(normal, textureLod(sampler2D(normal_roughness_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), neighbour_coord, 0.0).xyz * 2.0 - 1.0); if (neighbour_ang > closest_ang) { closest_ang = neighbour_ang; closest_coord = neighbour_coord; @@ -2239,28 +2401,69 @@ FRAGMENT_SHADER_CODE coord = closest_coord; } else { - coord = ivec2(gl_FragCoord.xy); + coord = screen_uv; } - vec4 buffer_ambient = texelFetch(sampler2D(ambient_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), coord, 0); - vec4 buffer_reflection = texelFetch(sampler2D(reflection_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), coord, 0); + vec4 buffer_ambient = textureLod(sampler2D(ambient_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), coord, 0.0); + vec4 buffer_reflection = textureLod(sampler2D(reflection_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), coord, 0.0); ambient_light = mix(ambient_light, buffer_ambient.rgb, buffer_ambient.a); specular_light = mix(specular_light, buffer_reflection.rgb, buffer_reflection.a); } #endif +#ifndef LOW_END_MODE + if (scene_data.ssao_enabled) { + float ssao = texture(sampler2D(ao_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv).r; + ao = min(ao, ssao); + ao_light_affect = mix(ao_light_affect, max(ao_light_affect, scene_data.ssao_light_affect), scene_data.ssao_ao_affect); + } +#endif //LOW_END_MODE + { // process reflections vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0); vec4 ambient_accum = vec4(0.0, 0.0, 0.0, 0.0); - uint reflection_probe_count = cluster_cell.z >> CLUSTER_COUNTER_SHIFT; - uint reflection_probe_pointer = cluster_cell.z & CLUSTER_POINTER_MASK; + uint cluster_reflection_offset = cluster_offset + scene_data.cluster_type_size * 3; + + uint item_min; + uint item_max; + uint item_from; + uint item_to; - for (uint i = 0; i < reflection_probe_count; i++) { - uint ref_index = cluster_data.indices[reflection_probe_pointer + i]; - reflection_process(ref_index, vertex, normal, roughness, ambient_light, specular_light, ambient_accum, reflection_accum); + cluster_get_item_range(cluster_reflection_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); + +#ifdef USE_SUBGROUPS + item_from = subgroupBroadcastFirst(subgroupMin(item_from)); + item_to = subgroupBroadcastFirst(subgroupMax(item_to)); +#endif + + for (uint i = item_from; i < item_to; i++) { + uint mask = cluster_buffer.data[cluster_reflection_offset + i]; + mask &= cluster_get_range_clip_mask(i, item_min, item_max); +#ifdef USE_SUBGROUPS + uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); +#else + uint merged_mask = mask; +#endif + + while (merged_mask != 0) { + uint bit = findMSB(merged_mask); + merged_mask &= ~(1 << bit); +#ifdef USE_SUBGROUPS + if (((1 << bit) & mask) == 0) { //do not process if not originally here + continue; + } +#endif + uint reflection_index = 32 * i + bit; + + if (!bool(reflections.data[reflection_index].mask & instances.data[instance_index].layer_mask)) { + continue; //not masked + } + + reflection_process(reflection_index, vertex, normal, roughness, ambient_light, specular_light, ambient_accum, reflection_accum); + } } if (reflection_accum.a > 0.0) { @@ -2274,6 +2477,16 @@ FRAGMENT_SHADER_CODE #endif } + //finalize ambient light here + ambient_light *= albedo.rgb; + ambient_light *= ao; + + // convert ao to direct light ao + ao = mix(1.0, ao, ao_light_affect); + + //this saves some VGPRs + vec3 f0 = F0(metallic, specular, albedo); + { #if defined(DIFFUSE_TOON) //simplify for toon, as @@ -2291,24 +2504,39 @@ FRAGMENT_SHADER_CODE float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y; vec2 env = vec2(-1.04, 1.04) * a004 + r.zw; - vec3 f0 = F0(metallic, specular, albedo); specular_light *= env.x * f0 + env.y; #endif } +#endif //GI !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) + +#if !defined(MODE_RENDER_DEPTH) + //this saves some VGPRs + uint orms = packUnorm4x8(vec4(ao, roughness, metallic, specular)); +#endif + +// LIGHTING +#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) + { //directional light - for (uint i = 0; i < scene_data.directional_light_count; i++) { + // Do shadow and lighting in two passes to reduce register pressure + uint shadow0 = 0; + uint shadow1 = 0; + + for (uint i = 0; i < 8; i++) { + if (i >= scene_data.directional_light_count) { + break; + } + if (!bool(directional_lights.data[i].mask & instances.data[instance_index].layer_mask)) { continue; //not masked } - vec3 shadow_attenuation = vec3(1.0); - -#ifdef LIGHT_TRANSMITTANCE_USED - float transmittance_z = transmittance_depth; -#endif + float shadow = 1.0; +#ifdef USE_SOFT_SHADOWS + //version with soft shadows, more expensive if (directional_lights.data[i].shadow_enabled) { float depth_z = -vertex.z; @@ -2322,8 +2550,6 @@ FRAGMENT_SHADER_CODE normal_bias -= light_dir * dot(light_dir, normal_bias); \ m_var.xyz += normal_bias; - float shadow = 0.0; - if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { vec4 v = vec4(vertex, 1.0); @@ -2344,19 +2570,6 @@ FRAGMENT_SHADER_CODE shadow_color = directional_lights.data[i].shadow_color1.rgb; -#ifdef LIGHT_TRANSMITTANCE_USED - { - vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.x, 1.0); - vec4 trans_coord = directional_lights.data[i].shadow_matrix1 * trans_vertex; - trans_coord /= trans_coord.w; - - float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; - shadow_z *= directional_lights.data[i].shadow_z_range.x; - float z = trans_coord.z * directional_lights.data[i].shadow_z_range.x; - - transmittance_z = z - shadow_z; - } -#endif } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { vec4 v = vec4(vertex, 1.0); @@ -2376,19 +2589,6 @@ FRAGMENT_SHADER_CODE } shadow_color = directional_lights.data[i].shadow_color2.rgb; -#ifdef LIGHT_TRANSMITTANCE_USED - { - vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.y, 1.0); - vec4 trans_coord = directional_lights.data[i].shadow_matrix2 * trans_vertex; - trans_coord /= trans_coord.w; - - float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; - shadow_z *= directional_lights.data[i].shadow_z_range.y; - float z = trans_coord.z * directional_lights.data[i].shadow_z_range.y; - - transmittance_z = z - shadow_z; - } -#endif } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { vec4 v = vec4(vertex, 1.0); @@ -2408,19 +2608,6 @@ FRAGMENT_SHADER_CODE } shadow_color = directional_lights.data[i].shadow_color3.rgb; -#ifdef LIGHT_TRANSMITTANCE_USED - { - vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.z, 1.0); - vec4 trans_coord = directional_lights.data[i].shadow_matrix3 * trans_vertex; - trans_coord /= trans_coord.w; - - float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; - shadow_z *= directional_lights.data[i].shadow_z_range.z; - float z = trans_coord.z * directional_lights.data[i].shadow_z_range.z; - - transmittance_z = z - shadow_z; - } -#endif } else { vec4 v = vec4(vertex, 1.0); @@ -2441,20 +2628,6 @@ FRAGMENT_SHADER_CODE } shadow_color = directional_lights.data[i].shadow_color4.rgb; - -#ifdef LIGHT_TRANSMITTANCE_USED - { - vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.w, 1.0); - vec4 trans_coord = directional_lights.data[i].shadow_matrix4 * trans_vertex; - trans_coord /= trans_coord.w; - - float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; - shadow_z *= directional_lights.data[i].shadow_z_range.w; - float z = trans_coord.z * directional_lights.data[i].shadow_z_range.w; - - transmittance_z = z - shadow_z; - } -#endif } if (directional_lights.data[i].blend_splits) { @@ -2528,130 +2701,407 @@ FRAGMENT_SHADER_CODE shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance - shadow_attenuation = mix(shadow_color, vec3(1.0), shadow); +#undef BIAS_FUNC + } +#else + // Soft shadow disabled version + + if (directional_lights.data[i].shadow_enabled) { + float depth_z = -vertex.z; + + vec4 pssm_coord; + vec3 light_dir = directional_lights.data[i].direction; + vec3 base_normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp)))); + +#define BIAS_FUNC(m_var, m_idx) \ + m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \ + vec3 normal_bias = base_normal_bias * directional_lights.data[i].shadow_normal_bias[m_idx]; \ + normal_bias -= light_dir * dot(light_dir, normal_bias); \ + m_var.xyz += normal_bias; + + if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 0) + + pssm_coord = (directional_lights.data[i].shadow_matrix1 * v); +#ifdef LIGHT_TRANSMITTANCE_USED + { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.x, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix1 * trans_vertex; + trans_coord /= trans_coord.w; + + float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; + shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.x; + float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.x; + + transmittance_z = z - shadow_z; + } +#endif + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 1) + + pssm_coord = (directional_lights.data[i].shadow_matrix2 * v); +#ifdef LIGHT_TRANSMITTANCE_USED + { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.y, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix2 * trans_vertex; + trans_coord /= trans_coord.w; + + float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; + shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.y; + float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.y; + + transmittance_z = z - shadow_z; + } +#endif + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 2) + + pssm_coord = (directional_lights.data[i].shadow_matrix3 * v); +#ifdef LIGHT_TRANSMITTANCE_USED + { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.z, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix3 * trans_vertex; + trans_coord /= trans_coord.w; + + float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; + shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.z; + float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.z; + + transmittance_z = z - shadow_z; + } +#endif + + } else { + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 3) + + pssm_coord = (directional_lights.data[i].shadow_matrix4 * v); +#ifdef LIGHT_TRANSMITTANCE_USED + { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.w, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix4 * trans_vertex; + trans_coord /= trans_coord.w; + + float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; + shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.w; + float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.w; + + transmittance_z = z - shadow_z; + } +#endif + } + + pssm_coord /= pssm_coord.w; + + shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); + + if (directional_lights.data[i].blend_splits) { + float pssm_blend; + + if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { + vec4 v = vec4(vertex, 1.0); + BIAS_FUNC(v, 1) + pssm_coord = (directional_lights.data[i].shadow_matrix2 * v); + pssm_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z); + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { + vec4 v = vec4(vertex, 1.0); + BIAS_FUNC(v, 2) + pssm_coord = (directional_lights.data[i].shadow_matrix3 * v); + pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z); + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { + vec4 v = vec4(vertex, 1.0); + BIAS_FUNC(v, 3) + pssm_coord = (directional_lights.data[i].shadow_matrix4 * v); + pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z); + } else { + pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached) + } + + pssm_coord /= pssm_coord.w; + + float shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); + shadow = mix(shadow, shadow2, pssm_blend); + } + + shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance #undef BIAS_FUNC } +#endif + + if (i < 4) { + shadow0 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << (i * 8); + } else { + shadow1 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << ((i - 4) * 8); + } + } + + for (uint i = 0; i < 8; i++) { + if (i >= scene_data.directional_light_count) { + break; + } + + if (!bool(directional_lights.data[i].mask & instances.data[instance_index].layer_mask)) { + continue; //not masked + } + +#ifdef LIGHT_TRANSMITTANCE_USED + float transmittance_z = transmittance_depth; + + if (directional_lights.data[i].shadow_enabled) { + float depth_z = -vertex.z; + + if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.x, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix1 * trans_vertex; + trans_coord /= trans_coord.w; + + float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; + shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.x; + float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.x; + + transmittance_z = z - shadow_z; + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.y, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix2 * trans_vertex; + trans_coord /= trans_coord.w; + + float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; + shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.y; + float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.y; + + transmittance_z = z - shadow_z; + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.z, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix3 * trans_vertex; + trans_coord /= trans_coord.w; + + float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; + shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.z; + float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.z; + + transmittance_z = z - shadow_z; + + } else { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.w, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix4 * trans_vertex; + trans_coord /= trans_coord.w; + + float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; + shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.w; + float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.w; - light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].size, directional_lights.data[i].color * directional_lights.data[i].energy, 1.0, shadow_attenuation, albedo, roughness, metallic, specular, directional_lights.data[i].specular * specular_blob_intensity, + transmittance_z = z - shadow_z; + } +#endif + + float shadow = 1.0; + + if (i < 4) { + shadow = float(shadow0 >> (i * 8) & 0xFF) / 255.0; + } else { + shadow = float(shadow1 >> ((i - 4) * 8) & 0xFF) / 255.0; + } + + blur_shadow(shadow); + + light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].color * directional_lights.data[i].energy, shadow, f0, orms, 1.0, #ifdef LIGHT_BACKLIGHT_USED - backlight, + backlight, #endif #ifdef LIGHT_TRANSMITTANCE_USED - transmittance_color, - transmittance_depth, - transmittance_curve, - transmittance_boost, - transmittance_z, + transmittance_color, + transmittance_depth, + transmittance_curve, + transmittance_boost, + transmittance_z, #endif #ifdef LIGHT_RIM_USED - rim, rim_tint, + rim, rim_tint, albedo, #endif #ifdef LIGHT_CLEARCOAT_USED - clearcoat, clearcoat_gloss, + clearcoat, clearcoat_gloss, #endif #ifdef LIGHT_ANISOTROPY_USED - binormal, tangent, anisotropy, + binormal, tangent, anisotropy, +#endif +#ifdef USE_SOFT_SHADOW + directional_lights.data[i].size, #endif #ifdef USE_SHADOW_TO_OPACITY - alpha, + alpha, #endif - diffuse_light, - specular_light); + diffuse_light, + specular_light); + } } - } - { //omni lights + { //omni lights - uint omni_light_count = cluster_cell.x >> CLUSTER_COUNTER_SHIFT; - uint omni_light_pointer = cluster_cell.x & CLUSTER_POINTER_MASK; + uint cluster_omni_offset = cluster_offset; - for (uint i = 0; i < omni_light_count; i++) { - uint light_index = cluster_data.indices[omni_light_pointer + i]; + uint item_min; + uint item_max; + uint item_from; + uint item_to; - if (!bool(lights.data[light_index].mask & instances.data[instance_index].layer_mask)) { - continue; //not masked - } + cluster_get_item_range(cluster_omni_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); + +#ifdef USE_SUBGROUPS + item_from = subgroupBroadcastFirst(subgroupMin(item_from)); + item_to = subgroupBroadcastFirst(subgroupMax(item_to)); +#endif + + for (uint i = item_from; i < item_to; i++) { + uint mask = cluster_buffer.data[cluster_omni_offset + i]; + mask &= cluster_get_range_clip_mask(i, item_min, item_max); +#ifdef USE_SUBGROUPS + uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); +#else + uint merged_mask = mask; +#endif + + while (merged_mask != 0) { + uint bit = findMSB(merged_mask); + merged_mask &= ~(1 << bit); +#ifdef USE_SUBGROUPS + if (((1 << bit) & mask) == 0) { //do not process if not originally here + continue; + } +#endif + uint light_index = 32 * i + bit; + + if (!bool(omni_lights.data[light_index].mask & instances.data[instance_index].layer_mask)) { + continue; //not masked + } - light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, albedo, roughness, metallic, specular, specular_blob_intensity, + float shadow = light_process_omni_shadow(light_index, vertex, view); + + shadow = blur_shadow(shadow); + + light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, #ifdef LIGHT_BACKLIGHT_USED - backlight, + backlight, #endif #ifdef LIGHT_TRANSMITTANCE_USED - transmittance_color, - transmittance_depth, - transmittance_curve, - transmittance_boost, + transmittance_color, + transmittance_depth, + transmittance_curve, + transmittance_boost, #endif #ifdef LIGHT_RIM_USED - rim, - rim_tint, + rim, + rim_tint, + albedo, #endif #ifdef LIGHT_CLEARCOAT_USED - clearcoat, clearcoat_gloss, + clearcoat, clearcoat_gloss, #endif #ifdef LIGHT_ANISOTROPY_USED - tangent, binormal, anisotropy, + tangent, binormal, anisotropy, #endif #ifdef USE_SHADOW_TO_OPACITY - alpha, + alpha, #endif - diffuse_light, specular_light); + diffuse_light, specular_light); + } + } } - } - { //spot lights - uint spot_light_count = cluster_cell.y >> CLUSTER_COUNTER_SHIFT; - uint spot_light_pointer = cluster_cell.y & CLUSTER_POINTER_MASK; + { //spot lights - for (uint i = 0; i < spot_light_count; i++) { - uint light_index = cluster_data.indices[spot_light_pointer + i]; + uint cluster_spot_offset = cluster_offset + scene_data.cluster_type_size; - if (!bool(lights.data[light_index].mask & instances.data[instance_index].layer_mask)) { - continue; //not masked - } + uint item_min; + uint item_max; + uint item_from; + uint item_to; + + cluster_get_item_range(cluster_spot_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); - light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, albedo, roughness, metallic, specular, specular_blob_intensity, +#ifdef USE_SUBGROUPS + item_from = subgroupBroadcastFirst(subgroupMin(item_from)); + item_to = subgroupBroadcastFirst(subgroupMax(item_to)); +#endif + + for (uint i = item_from; i < item_to; i++) { + uint mask = cluster_buffer.data[cluster_spot_offset + i]; + mask &= cluster_get_range_clip_mask(i, item_min, item_max); +#ifdef USE_SUBGROUPS + uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); +#else + uint merged_mask = mask; +#endif + + while (merged_mask != 0) { + uint bit = findMSB(merged_mask); + merged_mask &= ~(1 << bit); +#ifdef USE_SUBGROUPS + if (((1 << bit) & mask) == 0) { //do not process if not originally here + continue; + } +#endif + + uint light_index = 32 * i + bit; + + if (!bool(spot_lights.data[light_index].mask & instances.data[instance_index].layer_mask)) { + continue; //not masked + } + + float shadow = light_process_spot_shadow(light_index, vertex, view); + + shadow = blur_shadow(shadow); + + light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, #ifdef LIGHT_BACKLIGHT_USED - backlight, + backlight, #endif #ifdef LIGHT_TRANSMITTANCE_USED - transmittance_color, - transmittance_depth, - transmittance_curve, - transmittance_boost, + transmittance_color, + transmittance_depth, + transmittance_curve, + transmittance_boost, #endif #ifdef LIGHT_RIM_USED - rim, - rim_tint, + rim, + rim_tint, + albedo, #endif #ifdef LIGHT_CLEARCOAT_USED - clearcoat, clearcoat_gloss, + clearcoat, clearcoat_gloss, #endif #ifdef LIGHT_ANISOTROPY_USED - tangent, binormal, anisotropy, + tangent, binormal, anisotropy, #endif #ifdef USE_SHADOW_TO_OPACITY - alpha, + alpha, #endif - diffuse_light, specular_light); + diffuse_light, specular_light); + } + } } - } #ifdef USE_SHADOW_TO_OPACITY - alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0)); + alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0)); #if defined(ALPHA_SCISSOR_USED) - if (alpha < alpha_scissor) { - discard; - } + if (alpha < alpha_scissor) { + discard; + } #endif // ALPHA_SCISSOR_USED #ifdef USE_OPAQUE_PREPASS - if (alpha < opaque_prepass_threshold) { - discard; - } + if (alpha < opaque_prepass_threshold) { + discard; + } #endif // USE_OPAQUE_PREPASS @@ -2663,169 +3113,149 @@ FRAGMENT_SHADER_CODE #ifdef MODE_RENDER_SDF - { - vec3 local_pos = (scene_data.sdf_to_bounds * vec4(vertex, 1.0)).xyz; - ivec3 grid_pos = scene_data.sdf_offset + ivec3(local_pos * vec3(scene_data.sdf_size)); - - uint albedo16 = 0x1; //solid flag - albedo16 |= clamp(uint(albedo.r * 31.0), 0, 31) << 11; - albedo16 |= clamp(uint(albedo.g * 31.0), 0, 31) << 6; - albedo16 |= clamp(uint(albedo.b * 31.0), 0, 31) << 1; - - imageStore(albedo_volume_grid, grid_pos, uvec4(albedo16)); - - uint facing_bits = 0; - const vec3 aniso_dir[6] = vec3[]( - vec3(1, 0, 0), - vec3(0, 1, 0), - vec3(0, 0, 1), - vec3(-1, 0, 0), - vec3(0, -1, 0), - vec3(0, 0, -1)); - - vec3 cam_normal = mat3(scene_data.camera_matrix) * normalize(normal_interp); - - float closest_dist = -1e20; - - for (uint i = 0; i < 6; i++) { - float d = dot(cam_normal, aniso_dir[i]); - if (d > closest_dist) { - closest_dist = d; - facing_bits = (1 << i); + { + vec3 local_pos = (scene_data.sdf_to_bounds * vec4(vertex, 1.0)).xyz; + ivec3 grid_pos = scene_data.sdf_offset + ivec3(local_pos * vec3(scene_data.sdf_size)); + + uint albedo16 = 0x1; //solid flag + albedo16 |= clamp(uint(albedo.r * 31.0), 0, 31) << 11; + albedo16 |= clamp(uint(albedo.g * 31.0), 0, 31) << 6; + albedo16 |= clamp(uint(albedo.b * 31.0), 0, 31) << 1; + + imageStore(albedo_volume_grid, grid_pos, uvec4(albedo16)); + + uint facing_bits = 0; + const vec3 aniso_dir[6] = vec3[]( + vec3(1, 0, 0), + vec3(0, 1, 0), + vec3(0, 0, 1), + vec3(-1, 0, 0), + vec3(0, -1, 0), + vec3(0, 0, -1)); + + vec3 cam_normal = mat3(scene_data.camera_matrix) * normalize(normal_interp); + + float closest_dist = -1e20; + + for (uint i = 0; i < 6; i++) { + float d = dot(cam_normal, aniso_dir[i]); + if (d > closest_dist) { + closest_dist = d; + facing_bits = (1 << i); + } } - } - imageAtomicOr(geom_facing_grid, grid_pos, facing_bits); //store facing bits + imageAtomicOr(geom_facing_grid, grid_pos, facing_bits); //store facing bits - if (length(emission) > 0.001) { - float lumas[6]; - vec3 light_total = vec3(0); + if (length(emission) > 0.001) { + float lumas[6]; + vec3 light_total = vec3(0); - for (int i = 0; i < 6; i++) { - float strength = max(0.0, dot(cam_normal, aniso_dir[i])); - vec3 light = emission * strength; - light_total += light; - lumas[i] = max(light.r, max(light.g, light.b)); - } + for (int i = 0; i < 6; i++) { + float strength = max(0.0, dot(cam_normal, aniso_dir[i])); + vec3 light = emission * strength; + light_total += light; + lumas[i] = max(light.r, max(light.g, light.b)); + } - float luma_total = max(light_total.r, max(light_total.g, light_total.b)); + float luma_total = max(light_total.r, max(light_total.g, light_total.b)); - uint light_aniso = 0; + uint light_aniso = 0; - for (int i = 0; i < 6; i++) { - light_aniso |= min(31, uint((lumas[i] / luma_total) * 31.0)) << (i * 5); - } + for (int i = 0; i < 6; i++) { + light_aniso |= min(31, uint((lumas[i] / luma_total) * 31.0)) << (i * 5); + } - //compress to RGBE9995 to save space + //compress to RGBE9995 to save space - const float pow2to9 = 512.0f; - const float B = 15.0f; - const float N = 9.0f; - const float LN2 = 0.6931471805599453094172321215; + const float pow2to9 = 512.0f; + const float B = 15.0f; + const float N = 9.0f; + const float LN2 = 0.6931471805599453094172321215; - float cRed = clamp(light_total.r, 0.0, 65408.0); - float cGreen = clamp(light_total.g, 0.0, 65408.0); - float cBlue = clamp(light_total.b, 0.0, 65408.0); + float cRed = clamp(light_total.r, 0.0, 65408.0); + float cGreen = clamp(light_total.g, 0.0, 65408.0); + float cBlue = clamp(light_total.b, 0.0, 65408.0); - float cMax = max(cRed, max(cGreen, cBlue)); + float cMax = max(cRed, max(cGreen, cBlue)); - float expp = max(-B - 1.0f, floor(log(cMax) / LN2)) + 1.0f + B; + float expp = max(-B - 1.0f, floor(log(cMax) / LN2)) + 1.0f + B; - float sMax = floor((cMax / pow(2.0f, expp - B - N)) + 0.5f); + float sMax = floor((cMax / pow(2.0f, expp - B - N)) + 0.5f); - float exps = expp + 1.0f; + float exps = expp + 1.0f; - if (0.0 <= sMax && sMax < pow2to9) { - exps = expp; - } + if (0.0 <= sMax && sMax < pow2to9) { + exps = expp; + } - float sRed = floor((cRed / pow(2.0f, exps - B - N)) + 0.5f); - float sGreen = floor((cGreen / pow(2.0f, exps - B - N)) + 0.5f); - float sBlue = floor((cBlue / pow(2.0f, exps - B - N)) + 0.5f); - //store as 8985 to have 2 extra neighbour bits - uint light_rgbe = ((uint(sRed) & 0x1FF) >> 1) | ((uint(sGreen) & 0x1FF) << 8) | (((uint(sBlue) & 0x1FF) >> 1) << 17) | ((uint(exps) & 0x1F) << 25); + float sRed = floor((cRed / pow(2.0f, exps - B - N)) + 0.5f); + float sGreen = floor((cGreen / pow(2.0f, exps - B - N)) + 0.5f); + float sBlue = floor((cBlue / pow(2.0f, exps - B - N)) + 0.5f); + //store as 8985 to have 2 extra neighbour bits + uint light_rgbe = ((uint(sRed) & 0x1FF) >> 1) | ((uint(sGreen) & 0x1FF) << 8) | (((uint(sBlue) & 0x1FF) >> 1) << 17) | ((uint(exps) & 0x1F) << 25); - imageStore(emission_grid, grid_pos, uvec4(light_rgbe)); - imageStore(emission_aniso_grid, grid_pos, uvec4(light_aniso)); + imageStore(emission_grid, grid_pos, uvec4(light_rgbe)); + imageStore(emission_aniso_grid, grid_pos, uvec4(light_aniso)); + } } - } #endif #ifdef MODE_RENDER_MATERIAL - albedo_output_buffer.rgb = albedo; - albedo_output_buffer.a = alpha; + albedo_output_buffer.rgb = albedo; + albedo_output_buffer.a = alpha; - normal_output_buffer.rgb = normal * 0.5 + 0.5; - normal_output_buffer.a = 0.0; - depth_output_buffer.r = -vertex.z; + normal_output_buffer.rgb = normal * 0.5 + 0.5; + normal_output_buffer.a = 0.0; + depth_output_buffer.r = -vertex.z; -#if defined(AO_USED) - orm_output_buffer.r = ao; -#else - orm_output_buffer.r = 0.0; -#endif - orm_output_buffer.g = roughness; - orm_output_buffer.b = metallic; - orm_output_buffer.a = sss_strength; + orm_output_buffer.r = ao; + orm_output_buffer.g = roughness; + orm_output_buffer.b = metallic; + orm_output_buffer.a = sss_strength; - emission_output_buffer.rgb = emission; - emission_output_buffer.a = 0.0; + emission_output_buffer.rgb = emission; + emission_output_buffer.a = 0.0; #endif #ifdef MODE_RENDER_NORMAL_ROUGHNESS - normal_roughness_output_buffer = vec4(normal * 0.5 + 0.5, roughness); + normal_roughness_output_buffer = vec4(normal * 0.5 + 0.5, roughness); #ifdef MODE_RENDER_GIPROBE - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GIPROBE)) { // process giprobes - uint index1 = instances.data[instance_index].gi_offset & 0xFFFF; - uint index2 = instances.data[instance_index].gi_offset >> 16; - giprobe_buffer.x = index1 & 0xFF; - giprobe_buffer.y = index2 & 0xFF; - } else { - giprobe_buffer.x = 0xFF; - giprobe_buffer.y = 0xFF; - } + if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GIPROBE)) { // process giprobes + uint index1 = instances.data[instance_index].gi_offset & 0xFFFF; + uint index2 = instances.data[instance_index].gi_offset >> 16; + giprobe_buffer.x = index1 & 0xFF; + giprobe_buffer.y = index2 & 0xFF; + } else { + giprobe_buffer.x = 0xFF; + giprobe_buffer.y = 0xFF; + } #endif -#endif //MODE_RENDER_NORMAL +#endif //MODE_RENDER_NORMAL_ROUGHNESS //nothing happens, so a tree-ssa optimizer will result in no fragment shader :) #else - specular_light *= scene_data.reflection_multiplier; - ambient_light *= albedo; //ambient must be multiplied by albedo at the end - -//ambient occlusion -#if defined(AO_USED) + // multiply by albedo + diffuse_light *= albedo; // ambient must be multiplied by albedo at the end - if (scene_data.ssao_enabled && scene_data.ssao_ao_affect > 0.0) { - float ssao = texture(sampler2D(ao_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv).r; - ao = mix(ao, min(ao, ssao), scene_data.ssao_ao_affect); - ao_light_affect = mix(ao_light_affect, max(ao_light_affect, scene_data.ssao_light_affect), scene_data.ssao_ao_affect); - } - - ambient_light = mix(scene_data.ao_color.rgb, ambient_light, ao); - ao_light_affect = mix(1.0, ao, ao_light_affect); - specular_light = mix(scene_data.ao_color.rgb, specular_light, ao_light_affect); - diffuse_light = mix(scene_data.ao_color.rgb, diffuse_light, ao_light_affect); -#else + // apply direct light AO + ao = unpackUnorm4x8(orms).x; + specular_light *= ao; + diffuse_light *= ao; - if (scene_data.ssao_enabled) { - float ao = texture(sampler2D(ao_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv).r; - ambient_light = mix(scene_data.ao_color.rgb, ambient_light, ao); - float ao_light_affect = mix(1.0, ao, scene_data.ssao_light_affect); - specular_light = mix(scene_data.ao_color.rgb, specular_light, ao_light_affect); - diffuse_light = mix(scene_data.ao_color.rgb, diffuse_light, ao_light_affect); - } - -#endif // AO_USED - - // base color remapping - diffuse_light *= 1.0 - metallic; // TODO: avoid all diffuse and ambient light calculations when metallic == 1 up to this point + // apply metallic + metallic = unpackUnorm4x8(orms).z; + diffuse_light *= 1.0 - metallic; ambient_light *= 1.0 - metallic; + //restore fog + fog = vec4(unpackHalf2x16(fog_rg), unpackHalf2x16(fog_ba)); + #ifdef MODE_MULTIPLE_RENDER_TARGETS #ifdef MODE_UNSHADED @@ -2841,23 +3271,8 @@ FRAGMENT_SHADER_CODE specular_buffer = vec4(specular_light, metallic); #endif - // Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky. - if (scene_data.fog_enabled) { - vec4 fog = fog_process(vertex); - diffuse_buffer.rgb = mix(diffuse_buffer.rgb, fog.rgb, fog.a); - specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), fog.a); - } - - if (scene_data.volumetric_fog_enabled) { - vec4 fog = volumetric_fog_process(screen_uv, -vertex.z); - diffuse_buffer.rgb = mix(diffuse_buffer.rgb, fog.rgb, fog.a); - specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), fog.a); - } - -#if defined(CUSTOM_FOG_USED) - diffuse_buffer.rgb = mix(diffuse_buffer.rgb, custom_fog.rgb, custom_fog.a); - specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), custom_fog.a); -#endif //CUSTOM_FOG_USED + diffuse_buffer.rgb = mix(diffuse_buffer.rgb, fog.rgb, fog.a); + specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), fog.a); #else //MODE_MULTIPLE_RENDER_TARGETS @@ -2869,21 +3284,10 @@ FRAGMENT_SHADER_CODE #endif //USE_NO_SHADING // Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky. - if (scene_data.fog_enabled) { - vec4 fog = fog_process(vertex); - frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); - } - - if (scene_data.volumetric_fog_enabled) { - vec4 fog = volumetric_fog_process(screen_uv, -vertex.z); - frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); - } - -#if defined(CUSTOM_FOG_USED) - frag_color.rgb = mix(frag_color.rgb, custom_fog.rgb, custom_fog.a); -#endif //CUSTOM_FOG_USED + frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); + ; #endif //MODE_MULTIPLE_RENDER_TARGETS #endif //MODE_RENDER_DEPTH -} + } diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_inc.glsl index e29a490ca1..d78890fa9e 100644 --- a/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_inc.glsl @@ -3,12 +3,28 @@ #define MAX_GI_PROBES 8 +#if defined(GL_KHR_shader_subgroup_ballot) && defined(GL_KHR_shader_subgroup_arithmetic) + +#extension GL_KHR_shader_subgroup_ballot : enable +#extension GL_KHR_shader_subgroup_arithmetic : enable + +#define USE_SUBGROUPS + +#endif + #include "cluster_data_inc.glsl" +#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(MODE_RENDER_SDF) || defined(MODE_RENDER_NORMAL_ROUGHNESS) || defined(MODE_RENDER_GIPROBE) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) +#ifndef NORMAL_USED +#define NORMAL_USED +#endif +#endif + layout(push_constant, binding = 0, std430) uniform DrawCall { uint instance_index; - uint pad; //16 bits minimum size - vec2 bake_uv2_offset; //used for bake to uv2, ignored otherwise + uint uv_offset; + uint pad0; + uint pad1; } draw_call; @@ -27,91 +43,13 @@ draw_call; #define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10 #define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11 -layout(set = 0, binding = 1) uniform sampler material_samplers[12]; - -layout(set = 0, binding = 2) uniform sampler shadow_sampler; - #define SDFGI_MAX_CASCADES 8 -layout(set = 0, binding = 3, std140) uniform SceneData { - mat4 projection_matrix; - mat4 inv_projection_matrix; - - mat4 camera_matrix; - mat4 inv_camera_matrix; - - vec2 viewport_size; - vec2 screen_pixel_size; - - //use vec4s because std140 doesnt play nice with vec2s, z and w are wasted - vec4 directional_penumbra_shadow_kernel[32]; - vec4 directional_soft_shadow_kernel[32]; - vec4 penumbra_shadow_kernel[32]; - vec4 soft_shadow_kernel[32]; - - uint directional_penumbra_shadow_samples; - uint directional_soft_shadow_samples; - uint penumbra_shadow_samples; - uint soft_shadow_samples; - - vec4 ambient_light_color_energy; - - float ambient_color_sky_mix; - bool use_ambient_light; - bool use_ambient_cubemap; - bool use_reflection_cubemap; - - mat3 radiance_inverse_xform; - - vec2 shadow_atlas_pixel_size; - vec2 directional_shadow_pixel_size; - - uint directional_light_count; - float dual_paraboloid_side; - float z_far; - float z_near; - - bool ssao_enabled; - float ssao_light_affect; - float ssao_ao_affect; - bool roughness_limiter_enabled; - - float roughness_limiter_amount; - float roughness_limiter_limit; - uvec2 roughness_limiter_pad; - - vec4 ao_color; - - mat4 sdf_to_bounds; - - ivec3 sdf_offset; - bool material_uv2_mode; - - ivec3 sdf_size; - bool gi_upscale_for_msaa; - - bool volumetric_fog_enabled; - float volumetric_fog_inv_length; - float volumetric_fog_detail_spread; - uint volumetric_fog_pad; - - bool fog_enabled; - float fog_density; - float fog_height; - float fog_height_density; - - vec3 fog_light_color; - float fog_sun_scatter; - - float fog_aerial_perspective; - - float time; - float reflection_multiplier; // one normally, zero when rendering reflections +/* Set 1: Base Pass (never changes) */ - bool pancake_shadows; -} +layout(set = 0, binding = 1) uniform sampler material_samplers[12]; -scene_data; +layout(set = 0, binding = 2) uniform sampler shadow_sampler; #define INSTANCE_FLAGS_USE_GI_BUFFERS (1 << 6) #define INSTANCE_FLAGS_USE_SDFGI (1 << 7) @@ -128,33 +66,24 @@ scene_data; #define INSTANCE_FLAGS_MULTIMESH_STRIDE_MASK 0x7 #define INSTANCE_FLAGS_SKELETON (1 << 19) +#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 20) -struct InstanceData { - mat4 transform; - mat4 normal_transform; - uint flags; - uint instance_uniforms_ofs; //base offset in global buffer for instance variables - uint gi_offset; //GI information when using lightmapping (VCT or lightmap index) - uint layer_mask; - vec4 lightmap_uv_scale; -}; - -layout(set = 0, binding = 4, std430) restrict readonly buffer Instances { - InstanceData data[]; +layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights { + LightData data[]; } -instances; +omni_lights; -layout(set = 0, binding = 5, std430) restrict readonly buffer Lights { +layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights { LightData data[]; } -lights; +spot_lights; -layout(set = 0, binding = 6) buffer restrict readonly ReflectionProbeData { +layout(set = 0, binding = 5) buffer restrict readonly ReflectionProbeData { ReflectionData data[]; } reflections; -layout(set = 0, binding = 7, std140) uniform DirectionalLights { +layout(set = 0, binding = 6, std140) uniform DirectionalLights { DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS]; } directional_lights; @@ -166,44 +95,35 @@ struct Lightmap { mat3 normal_xform; }; -layout(set = 0, binding = 10, std140) restrict readonly buffer Lightmaps { +layout(set = 0, binding = 7, std140) restrict readonly buffer Lightmaps { Lightmap data[]; } lightmaps; -layout(set = 0, binding = 11) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES]; - struct LightmapCapture { vec4 sh[9]; }; -layout(set = 0, binding = 12, std140) restrict readonly buffer LightmapCaptures { +layout(set = 0, binding = 8, std140) restrict readonly buffer LightmapCaptures { LightmapCapture data[]; } lightmap_captures; -layout(set = 0, binding = 13) uniform texture2D decal_atlas; -layout(set = 0, binding = 14) uniform texture2D decal_atlas_srgb; +layout(set = 0, binding = 9) uniform texture2D decal_atlas; +layout(set = 0, binding = 10) uniform texture2D decal_atlas_srgb; -layout(set = 0, binding = 15, std430) restrict readonly buffer Decals { +layout(set = 0, binding = 11, std430) restrict readonly buffer Decals { DecalData data[]; } decals; -layout(set = 0, binding = 16) uniform utexture3D cluster_texture; - -layout(set = 0, binding = 17, std430) restrict readonly buffer ClusterData { - uint indices[]; -} -cluster_data; - -layout(set = 0, binding = 18) uniform texture2D directional_shadow_atlas; - -layout(set = 0, binding = 19, std430) restrict readonly buffer GlobalVariableData { +layout(set = 0, binding = 12, std430) restrict readonly buffer GlobalVariableData { vec4 data[]; } global_variables; +#ifndef LOW_END_MODE + struct SDFGIProbeCascadeData { vec3 position; float to_probe; @@ -211,7 +131,7 @@ struct SDFGIProbeCascadeData { float to_cell; // 1/bounds * grid_size }; -layout(set = 0, binding = 20, std140) uniform SDFGI { +layout(set = 0, binding = 13, std140) uniform SDFGI { vec3 grid_size; uint max_cascades; @@ -239,36 +159,142 @@ layout(set = 0, binding = 20, std140) uniform SDFGI { } sdfgi; -// decal atlas +#endif //LOW_END_MODE + +/* Set 2: Render Pass (changes per render pass) */ + +layout(set = 1, binding = 0, std140) uniform SceneData { + mat4 projection_matrix; + mat4 inv_projection_matrix; + + mat4 camera_matrix; + mat4 inv_camera_matrix; + + vec2 viewport_size; + vec2 screen_pixel_size; + + uint cluster_shift; + uint cluster_width; + uint cluster_type_size; + uint max_cluster_element_count_div_32; + + //use vec4s because std140 doesnt play nice with vec2s, z and w are wasted + vec4 directional_penumbra_shadow_kernel[32]; + vec4 directional_soft_shadow_kernel[32]; + vec4 penumbra_shadow_kernel[32]; + vec4 soft_shadow_kernel[32]; + + uint directional_penumbra_shadow_samples; + uint directional_soft_shadow_samples; + uint penumbra_shadow_samples; + uint soft_shadow_samples; + + vec4 ambient_light_color_energy; + + float ambient_color_sky_mix; + bool use_ambient_light; + bool use_ambient_cubemap; + bool use_reflection_cubemap; + + mat3 radiance_inverse_xform; + + vec2 shadow_atlas_pixel_size; + vec2 directional_shadow_pixel_size; + + uint directional_light_count; + float dual_paraboloid_side; + float z_far; + float z_near; -/* Set 1, Radiance */ + bool ssao_enabled; + float ssao_light_affect; + float ssao_ao_affect; + bool roughness_limiter_enabled; + + float roughness_limiter_amount; + float roughness_limiter_limit; + uvec2 roughness_limiter_pad; + + vec4 ao_color; + + mat4 sdf_to_bounds; + + ivec3 sdf_offset; + bool material_uv2_mode; + + ivec3 sdf_size; + bool gi_upscale_for_msaa; + + bool volumetric_fog_enabled; + float volumetric_fog_inv_length; + float volumetric_fog_detail_spread; + uint volumetric_fog_pad; + + bool fog_enabled; + float fog_density; + float fog_height; + float fog_height_density; + + vec3 fog_light_color; + float fog_sun_scatter; + + float fog_aerial_perspective; + + float time; + float reflection_multiplier; // one normally, zero when rendering reflections + + bool pancake_shadows; +} + +scene_data; + +struct InstanceData { + mat4 transform; + uint flags; + uint instance_uniforms_ofs; //base offset in global buffer for instance variables + uint gi_offset; //GI information when using lightmapping (VCT or lightmap index) + uint layer_mask; + vec4 lightmap_uv_scale; +}; + +layout(set = 1, binding = 1, std430) buffer restrict readonly InstanceDataBuffer { + InstanceData data[]; +} +instances; #ifdef USE_RADIANCE_CUBEMAP_ARRAY -layout(set = 1, binding = 0) uniform textureCubeArray radiance_cubemap; +layout(set = 1, binding = 2) uniform textureCubeArray radiance_cubemap; #else -layout(set = 1, binding = 0) uniform textureCube radiance_cubemap; +layout(set = 1, binding = 2) uniform textureCube radiance_cubemap; #endif -/* Set 2, Reflection and Shadow Atlases (view dependent) */ +layout(set = 1, binding = 3) uniform textureCubeArray reflection_atlas; -layout(set = 2, binding = 0) uniform textureCubeArray reflection_atlas; +layout(set = 1, binding = 4) uniform texture2D shadow_atlas; -layout(set = 2, binding = 1) uniform texture2D shadow_atlas; +layout(set = 1, binding = 5) uniform texture2D directional_shadow_atlas; -layout(set = 2, binding = 2) uniform texture3D gi_probe_textures[MAX_GI_PROBES]; +layout(set = 1, binding = 6) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES]; -/* Set 3, Render Buffers */ +#ifndef LOW_END_MOD +layout(set = 1, binding = 7) uniform texture3D gi_probe_textures[MAX_GI_PROBES]; +#endif + +layout(set = 1, binding = 8, std430) buffer restrict readonly ClusterBuffer { + uint data[]; +} +cluster_buffer; #ifdef MODE_RENDER_SDF -layout(r16ui, set = 3, binding = 0) uniform restrict writeonly uimage3D albedo_volume_grid; -layout(r32ui, set = 3, binding = 1) uniform restrict writeonly uimage3D emission_grid; -layout(r32ui, set = 3, binding = 2) uniform restrict writeonly uimage3D emission_aniso_grid; -layout(r32ui, set = 3, binding = 3) uniform restrict uimage3D geom_facing_grid; +layout(r16ui, set = 1, binding = 9) uniform restrict writeonly uimage3D albedo_volume_grid; +layout(r32ui, set = 1, binding = 10) uniform restrict writeonly uimage3D emission_grid; +layout(r32ui, set = 1, binding = 11) uniform restrict writeonly uimage3D emission_aniso_grid; +layout(r32ui, set = 1, binding = 12) uniform restrict uimage3D geom_facing_grid; //still need to be present for shaders that use it, so remap them to something #define depth_buffer shadow_atlas @@ -277,14 +303,17 @@ layout(r32ui, set = 3, binding = 3) uniform restrict uimage3D geom_facing_grid; #else -layout(set = 3, binding = 0) uniform texture2D depth_buffer; -layout(set = 3, binding = 1) uniform texture2D color_buffer; -layout(set = 3, binding = 2) uniform texture2D normal_roughness_buffer; -layout(set = 3, binding = 4) uniform texture2D ao_buffer; -layout(set = 3, binding = 5) uniform texture2D ambient_buffer; -layout(set = 3, binding = 6) uniform texture2D reflection_buffer; -layout(set = 3, binding = 7) uniform texture2DArray sdfgi_lightprobe_texture; -layout(set = 3, binding = 8) uniform texture3D sdfgi_occlusion_cascades; +layout(set = 1, binding = 9) uniform texture2D depth_buffer; +layout(set = 1, binding = 10) uniform texture2D color_buffer; + +#ifndef LOW_END_MODE + +layout(set = 1, binding = 11) uniform texture2D normal_roughness_buffer; +layout(set = 1, binding = 12) uniform texture2D ao_buffer; +layout(set = 1, binding = 13) uniform texture2D ambient_buffer; +layout(set = 1, binding = 14) uniform texture2D reflection_buffer; +layout(set = 1, binding = 15) uniform texture2DArray sdfgi_lightprobe_texture; +layout(set = 1, binding = 16) uniform texture3D sdfgi_occlusion_cascades; struct GIProbeData { mat4 xform; @@ -302,20 +331,22 @@ struct GIProbeData { uint mipmaps; }; -layout(set = 3, binding = 9, std140) uniform GIProbes { +layout(set = 1, binding = 17, std140) uniform GIProbes { GIProbeData data[MAX_GI_PROBES]; } gi_probes; -layout(set = 3, binding = 10) uniform texture3D volumetric_fog_texture; +layout(set = 1, binding = 18) uniform texture3D volumetric_fog_texture; + +#endif // LOW_END_MODE #endif -/* Set 4 Skeleton & Instancing (Multimesh) */ +/* Set 2 Skeleton & Instancing (can change per item) */ -layout(set = 4, binding = 0, std430) restrict readonly buffer Transforms { +layout(set = 2, binding = 0, std430) restrict readonly buffer Transforms { vec4 data[]; } transforms; -/* Set 5 User Material */ +/* Set 3 User Material */ diff --git a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl b/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl index 06dc4b13de..06dc4b13de 100644 --- a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl +++ b/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_filter.glsl b/servers/rendering/renderer_rd/shaders/screen_space_reflection_filter.glsl index a5afe74cb2..a5afe74cb2 100644 --- a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_filter.glsl +++ b/servers/rendering/renderer_rd/shaders/screen_space_reflection_filter.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_scale.glsl b/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl index 218605a962..218605a962 100644 --- a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_scale.glsl +++ b/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/sdfgi_debug.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl index 813ea29fa1..e4c3f3a84b 100644 --- a/servers/rendering/rasterizer_rd/shaders/sdfgi_debug.glsl +++ b/servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl @@ -97,6 +97,8 @@ void main() { float blend = 0.0; #if 1 + // No interpolation + vec3 inv_dir = 1.0 / ray_dir; float rough = 0.5; @@ -161,114 +163,11 @@ void main() { hit_light *= (dot(max(vec3(0.0), (hit_normal * hit_aniso0)), vec3(1.0)) + dot(max(vec3(0.0), (-hit_normal * hit_aniso1)), vec3(1.0))); - if (blend > 0.0) { - light = mix(light, hit_light, blend); - blend = 0.0; - } else { - light = hit_light; - - //process blend - float blend_from = (float(params.probe_axis_size - 1) / 2.0) - 2.5; - float blend_to = blend_from + 2.0; - - vec3 cam_pos = params.cam_transform[3].xyz - cascades.data[i].offset; - cam_pos *= cascades.data[i].to_cell; - - pos += ray_dir * min(advance, max_advance); - vec3 inner_pos = pos - cam_pos; - - inner_pos = inner_pos * float(params.probe_axis_size - 1) / params.grid_size.x; - - float len = length(inner_pos); - - inner_pos = abs(normalize(inner_pos)); - len *= max(inner_pos.x, max(inner_pos.y, inner_pos.z)); - - if (len >= blend_from) { - blend = smoothstep(blend_from, blend_to, len); - - pos /= cascades.data[i].to_cell; - pos += cascades.data[i].offset; - ray_pos = pos; - hit = false; //continue trace for blend - - continue; - } - } + light = hit_light; break; } - light = mix(light, vec3(0.0), blend); - -#else - - vec3 inv_dir = 1.0 / ray_dir; - - bool hit = false; - vec4 light_accum = vec4(0.0); - - float blend_size = (params.grid_size.x / float(params.probe_axis_size - 1)) * 0.5; - - float radius_sizes[MAX_CASCADES]; - for (uint i = 0; i < params.max_cascades; i++) { - radius_sizes[i] = (1.0 / cascades.data[i].to_cell) * (params.grid_size.x * 0.5 - blend_size); - } - - float max_distance = radius_sizes[params.max_cascades - 1]; - float advance = 0; - while (advance < max_distance) { - for (uint i = 0; i < params.max_cascades; i++) { - if (advance < radius_sizes[i]) { - vec3 pos = (ray_pos + ray_dir * advance) - cascades.data[i].offset; - pos *= cascades.data[i].to_cell * pos_to_uvw; - - float distance = texture(sampler3D(sdf_cascades[i], linear_sampler), pos).r * 255.0 - 1.0; - - vec4 hit_light = vec4(0.0); - if (distance < 1.0) { - hit_light.a = max(0.0, 1.0 - distance); - hit_light.rgb = texture(sampler3D(light_cascades[i], linear_sampler), pos).rgb; - hit_light.rgb *= hit_light.a; - } - - distance /= cascades.data[i].to_cell; - - if (i < (params.max_cascades - 1)) { - pos = (ray_pos + ray_dir * advance) - cascades.data[i + 1].offset; - pos *= cascades.data[i + 1].to_cell * pos_to_uvw; - - float distance2 = texture(sampler3D(sdf_cascades[i + 1], linear_sampler), pos).r * 255.0 - 1.0; - - vec4 hit_light2 = vec4(0.0); - if (distance2 < 1.0) { - hit_light2.a = max(0.0, 1.0 - distance2); - hit_light2.rgb = texture(sampler3D(light_cascades[i + 1], linear_sampler), pos).rgb; - hit_light2.rgb *= hit_light2.a; - } - - float prev_radius = i == 0 ? 0.0 : radius_sizes[i - 1]; - float blend = (advance - prev_radius) / (radius_sizes[i] - prev_radius); - - distance2 /= cascades.data[i + 1].to_cell; - - hit_light = mix(hit_light, hit_light2, blend); - distance = mix(distance, distance2, blend); - } - - light_accum += hit_light; - advance += distance; - break; - } - } - - if (light_accum.a > 0.98) { - break; - } - } - - light = light_accum.rgb / light_accum.a; - #endif imageStore(screen_buffer, screen_pos, vec4(linear_to_srgb(light), 1.0)); diff --git a/servers/rendering/rasterizer_rd/shaders/sdfgi_debug_probes.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl index 08da283dad..08da283dad 100644 --- a/servers/rendering/rasterizer_rd/shaders/sdfgi_debug_probes.glsl +++ b/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/sdfgi_direct_light.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl index 61e4bf5e18..dc7238abed 100644 --- a/servers/rendering/rasterizer_rd/shaders/sdfgi_direct_light.glsl +++ b/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl @@ -67,8 +67,8 @@ struct Light { float attenuation; uint type; - float spot_angle; - float spot_attenuation; + float cos_spot_angle; + float inv_spot_attenuation; float radius; vec4 shadow_color; @@ -80,6 +80,7 @@ layout(set = 0, binding = 9, std140) buffer restrict readonly Lights { lights; layout(set = 0, binding = 10) uniform texture2DArray lightprobe_texture; +layout(set = 0, binding = 11) uniform texture3D occlusion_texture; layout(push_constant, binding = 0, std430) uniform Params { vec3 grid_size; @@ -91,9 +92,9 @@ layout(push_constant, binding = 0, std430) uniform Params { uint process_increment; int probe_axis_size; - bool multibounce; + float bounce_feedback; float y_mult; - uint pad; + bool use_occlusion; } params; @@ -112,11 +113,23 @@ vec2 octahedron_encode(vec3 n) { return n.xy; } +float get_omni_attenuation(float distance, float inv_range, float decay) { + float nd = distance * inv_range; + nd *= nd; + nd *= nd; // nd^4 + nd = max(1.0 - nd, 0.0); + nd *= nd; // nd^2 + return nd * pow(max(distance, 0.0001), -decay); +} + void main() { uint voxel_index = uint(gl_GlobalInvocationID.x); //used for skipping voxels every N frames - voxel_index = params.process_offset + voxel_index * params.process_increment; + if (params.process_increment > 1) { + voxel_index *= params.process_increment; + voxel_index += params.process_offset; + } if (voxel_index >= dispatch_data.total_count) { return; @@ -134,10 +147,96 @@ void main() { uint voxel_albedo = process_voxels.data[voxel_index].albedo; vec3 albedo = vec3(uvec3(voxel_albedo >> 10, voxel_albedo >> 5, voxel_albedo) & uvec3(0x1F)) / float(0x1F); - vec3 light_accum[6]; - + vec3 light_accum[6] = vec3[](vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0)); uint valid_aniso = (voxel_albedo >> 15) & 0x3F; + const vec3 aniso_dir[6] = vec3[]( + vec3(1, 0, 0), + vec3(0, 1, 0), + vec3(0, 0, 1), + vec3(-1, 0, 0), + vec3(0, -1, 0), + vec3(0, 0, -1)); + + // Add indirect light first, in order to save computation resources +#ifdef MODE_PROCESS_DYNAMIC + if (params.bounce_feedback > 0.001) { + vec3 feedback = (params.bounce_feedback < 1.0) ? (albedo * params.bounce_feedback) : mix(albedo, vec3(1.0), params.bounce_feedback - 1.0); + vec3 pos = (vec3(positioni) + vec3(0.5)) * float(params.probe_axis_size - 1) / params.grid_size; + ivec3 probe_base_pos = ivec3(pos); + + float weight_accum[6] = float[](0, 0, 0, 0, 0, 0); + + ivec3 tex_pos = ivec3(probe_base_pos.xy, int(params.cascade)); + tex_pos.x += probe_base_pos.z * int(params.probe_axis_size); + + tex_pos.xy = tex_pos.xy * (OCT_SIZE + 2) + ivec2(1); + + vec3 base_tex_posf = vec3(tex_pos); + vec2 tex_pixel_size = 1.0 / vec2(ivec2((OCT_SIZE + 2) * params.probe_axis_size * params.probe_axis_size, (OCT_SIZE + 2) * params.probe_axis_size)); + vec3 probe_uv_offset = vec3(ivec3(OCT_SIZE + 2, OCT_SIZE + 2, (OCT_SIZE + 2) * params.probe_axis_size)) * tex_pixel_size.xyx; + + for (uint j = 0; j < 8; j++) { + ivec3 offset = (ivec3(j) >> ivec3(0, 1, 2)) & ivec3(1, 1, 1); + ivec3 probe_posi = probe_base_pos; + probe_posi += offset; + + // Compute weight + + vec3 probe_pos = vec3(probe_posi); + vec3 probe_to_pos = pos - probe_pos; + vec3 probe_dir = normalize(-probe_to_pos); + + // Compute lightprobe texture position + + vec3 trilinear = vec3(1.0) - abs(probe_to_pos); + + for (uint k = 0; k < 6; k++) { + if (bool(valid_aniso & (1 << k))) { + vec3 n = aniso_dir[k]; + float weight = trilinear.x * trilinear.y * trilinear.z * max(0, dot(n, probe_dir)); + + if (weight > 0.0 && params.use_occlusion) { + ivec3 occ_indexv = abs((cascades.data[params.cascade].probe_world_offset + probe_posi) & ivec3(1, 1, 1)) * ivec3(1, 2, 4); + vec4 occ_mask = mix(vec4(0.0), vec4(1.0), equal(ivec4(occ_indexv.x | occ_indexv.y), ivec4(0, 1, 2, 3))); + + vec3 occ_pos = (vec3(positioni) + aniso_dir[k] + vec3(0.5)) / params.grid_size; + occ_pos.z += float(params.cascade); + if (occ_indexv.z != 0) { //z bit is on, means index is >=4, so make it switch to the other half of textures + occ_pos.x += 1.0; + } + occ_pos *= vec3(0.5, 1.0, 1.0 / float(params.max_cascades)); //renormalize + float occlusion = dot(textureLod(sampler3D(occlusion_texture, linear_sampler), occ_pos, 0.0), occ_mask); + + weight *= occlusion; + } + + if (weight > 0.0) { + vec3 tex_posf = base_tex_posf + vec3(octahedron_encode(n) * float(OCT_SIZE), 0.0); + tex_posf.xy *= tex_pixel_size; + + vec3 pos_uvw = tex_posf; + pos_uvw.xy += vec2(offset.xy) * probe_uv_offset.xy; + pos_uvw.x += float(offset.z) * probe_uv_offset.z; + vec3 indirect_light = textureLod(sampler2DArray(lightprobe_texture, linear_sampler), pos_uvw, 0.0).rgb; + + light_accum[k] += indirect_light * weight; + weight_accum[k] += weight; + } + } + } + } + + for (uint k = 0; k < 6; k++) { + if (weight_accum[k] > 0.0) { + light_accum[k] /= weight_accum[k]; + light_accum[k] *= feedback; + } + } + } + +#endif + { uint rgbe = process_voxels.data[voxel_index].light; @@ -153,18 +252,10 @@ void main() { uint aniso = process_voxels.data[voxel_index].light_aniso; for (uint i = 0; i < 6; i++) { float strength = ((aniso >> (i * 5)) & 0x1F) / float(0x1F); - light_accum[i] = l * strength; + light_accum[i] += l * strength; } } - const vec3 aniso_dir[6] = vec3[]( - vec3(1, 0, 0), - vec3(0, 1, 0), - vec3(0, 0, 1), - vec3(-1, 0, 0), - vec3(0, -1, 0), - vec3(0, 0, -1)); - // Raytrace light vec3 pos_to_uvw = 1.0 / params.grid_size; @@ -184,22 +275,26 @@ void main() { direction = normalize(rel_vec); light_distance = length(rel_vec); rel_vec.y /= params.y_mult; - attenuation = pow(clamp(1.0 - length(rel_vec) / lights.data[i].radius, 0.0, 1.0), lights.data[i].attenuation); + attenuation = get_omni_attenuation(light_distance, 1.0 / lights.data[i].radius, lights.data[i].attenuation); + } break; case LIGHT_TYPE_SPOT: { vec3 rel_vec = lights.data[i].position - position; direction = normalize(rel_vec); light_distance = length(rel_vec); rel_vec.y /= params.y_mult; - attenuation = pow(clamp(1.0 - length(rel_vec) / lights.data[i].radius, 0.0, 1.0), lights.data[i].attenuation); - - float angle = acos(dot(normalize(rel_vec), -lights.data[i].direction)); - if (angle > lights.data[i].spot_angle) { - attenuation = 0.0; - } else { - float d = clamp(angle / lights.data[i].spot_angle, 0, 1); - attenuation *= pow(1.0 - d, lights.data[i].spot_attenuation); + attenuation = get_omni_attenuation(light_distance, 1.0 / lights.data[i].radius, lights.data[i].attenuation); + + float cos_spot_angle = lights.data[i].cos_spot_angle; + float cos_angle = dot(-direction, lights.data[i].direction); + + if (cos_angle < cos_spot_angle) { + continue; } + + float scos = max(cos_angle, cos_spot_angle); + float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - cos_spot_angle)); + attenuation *= 1.0 - pow(spot_rim, lights.data[i].inv_spot_attenuation); } break; } @@ -282,65 +377,6 @@ void main() { } } - // Add indirect light - - if (params.multibounce) { - vec3 pos = (vec3(positioni) + vec3(0.5)) * float(params.probe_axis_size - 1) / params.grid_size; - ivec3 probe_base_pos = ivec3(pos); - - vec4 probe_accum[6] = vec4[](vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0)); - float weight_accum[6] = float[](0, 0, 0, 0, 0, 0); - - ivec3 tex_pos = ivec3(probe_base_pos.xy, int(params.cascade)); - tex_pos.x += probe_base_pos.z * int(params.probe_axis_size); - - tex_pos.xy = tex_pos.xy * (OCT_SIZE + 2) + ivec2(1); - - vec3 base_tex_posf = vec3(tex_pos); - vec2 tex_pixel_size = 1.0 / vec2(ivec2((OCT_SIZE + 2) * params.probe_axis_size * params.probe_axis_size, (OCT_SIZE + 2) * params.probe_axis_size)); - vec3 probe_uv_offset = (ivec3(OCT_SIZE + 2, OCT_SIZE + 2, (OCT_SIZE + 2) * params.probe_axis_size)) * tex_pixel_size.xyx; - - for (uint j = 0; j < 8; j++) { - ivec3 offset = (ivec3(j) >> ivec3(0, 1, 2)) & ivec3(1, 1, 1); - ivec3 probe_posi = probe_base_pos; - probe_posi += offset; - - // Compute weight - - vec3 probe_pos = vec3(probe_posi); - vec3 probe_to_pos = pos - probe_pos; - vec3 probe_dir = normalize(-probe_to_pos); - - // Compute lightprobe texture position - - vec3 trilinear = vec3(1.0) - abs(probe_to_pos); - - for (uint k = 0; k < 6; k++) { - if (bool(valid_aniso & (1 << k))) { - vec3 n = aniso_dir[k]; - float weight = trilinear.x * trilinear.y * trilinear.z * max(0.005, dot(n, probe_dir)); - - vec3 tex_posf = base_tex_posf + vec3(octahedron_encode(n) * float(OCT_SIZE), 0.0); - tex_posf.xy *= tex_pixel_size; - - vec3 pos_uvw = tex_posf; - pos_uvw.xy += vec2(offset.xy) * probe_uv_offset.xy; - pos_uvw.x += float(offset.z) * probe_uv_offset.z; - vec4 indirect_light = textureLod(sampler2DArray(lightprobe_texture, linear_sampler), pos_uvw, 0.0); - - probe_accum[k] += indirect_light * weight; - weight_accum[k] += weight; - } - } - } - - for (uint k = 0; k < 6; k++) { - if (weight_accum[k] > 0.0) { - light_accum[k] += probe_accum[k].rgb * albedo / weight_accum[k]; - } - } - } - // Store the light in the light texture float lumas[6]; diff --git a/servers/rendering/rasterizer_rd/shaders/sdfgi_fields.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_fields.glsl index eec0a90c0d..69d8824d8a 100644 --- a/servers/rendering/rasterizer_rd/shaders/sdfgi_fields.glsl +++ b/servers/rendering/renderer_rd/shaders/sdfgi_fields.glsl @@ -14,7 +14,7 @@ layout(local_size_x = OCT_RES, local_size_y = OCT_RES, local_size_z = 1) in; layout(rgba16f, set = 0, binding = 1) uniform restrict image2DArray irradiance_texture; layout(rg16f, set = 0, binding = 2) uniform restrict image2DArray depth_texture; -ayout(rgba32ui, set = 0, binding = 3) uniform restrict uimage2DArray irradiance_history_texture; +layout(rgba32ui, set = 0, binding = 3) uniform restrict uimage2DArray irradiance_history_texture; layout(rg32ui, set = 0, binding = 4) uniform restrict uimage2DArray depth_history_texture; struct CascadeData { diff --git a/servers/rendering/rasterizer_rd/shaders/sdfgi_integrate.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl index d516ab22c3..007e4c113a 100644 --- a/servers/rendering/rasterizer_rd/shaders/sdfgi_integrate.glsl +++ b/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl @@ -39,8 +39,11 @@ layout(rgba32i, set = 0, binding = 13) uniform restrict iimage2D lightprobe_aver layout(rgba16f, set = 0, binding = 14) uniform restrict writeonly image2DArray lightprobe_ambient_texture; +#ifdef USE_CUBEMAP_ARRAY +layout(set = 1, binding = 0) uniform textureCubeArray sky_irradiance; +#else layout(set = 1, binding = 0) uniform textureCube sky_irradiance; - +#endif layout(set = 1, binding = 1) uniform sampler linear_sampler_mipmaps; #define HISTORY_BITS 10 @@ -136,12 +139,24 @@ uint rgbe_encode(vec3 color) { return (uint(sRed) & 0x1FF) | ((uint(sGreen) & 0x1FF) << 9) | ((uint(sBlue) & 0x1FF) << 18) | ((uint(exps) & 0x1F) << 27); } +struct SH { +#if (SH_SIZE == 16) + float c[48]; +#else + float c[28]; +#endif +}; + +shared SH sh_accum[64]; //8x8 + void main() { ivec2 pos = ivec2(gl_GlobalInvocationID.xy); if (any(greaterThanEqual(pos, params.image_size))) { //too large, do nothing return; } + uint probe_index = gl_LocalInvocationID.x + gl_LocalInvocationID.y * 8; + #ifdef MODE_PROCESS float probe_cell_size = float(params.grid_size.x / float(params.probe_axis_size - 1)) / cascades.data[params.cascade].to_cell; @@ -154,27 +169,9 @@ void main() { vec3 probe_pos = cascades.data[params.cascade].offset + vec3(probe_cell) * probe_cell_size; vec3 pos_to_uvw = 1.0 / params.grid_size; - vec4 probe_sh_accum[SH_SIZE] = vec4[]( - vec4(0.0), - vec4(0.0), - vec4(0.0), - vec4(0.0), - vec4(0.0), - vec4(0.0), - vec4(0.0), - vec4(0.0), - vec4(0.0) -#if (SH_SIZE == 16) - , - vec4(0.0), - vec4(0.0), - vec4(0.0), - vec4(0.0), - vec4(0.0), - vec4(0.0), - vec4(0.0) -#endif - ); + for (uint i = 0; i < SH_SIZE * 3; i++) { + sh_accum[probe_index].c[i] = 0.0; + } // quickly ensure each probe has a different "offset" for the vogel function, based on integer world position uvec3 h3 = hash3(uvec3(params.world_offset + probe_cell)); @@ -195,14 +192,12 @@ void main() { vec3 inv_dir = 1.0 / ray_dir; bool hit = false; - vec3 hit_normal; - vec3 hit_light; - vec3 hit_aniso0; - vec3 hit_aniso1; + uint hit_cascade; float bias = params.ray_bias; vec3 abs_ray_dir = abs(ray_dir); ray_pos += ray_dir * 1.0 / max(abs_ray_dir.x, max(abs_ray_dir.y, abs_ray_dir.z)) * bias / cascades.data[params.cascade].to_cell; + vec3 uvw; for (uint j = params.cascade; j < params.max_cascades; j++) { //convert to local bounds @@ -221,14 +216,12 @@ void main() { float advance = 0.0; - vec3 uvw; - while (advance < max_advance) { //read how much to advance from SDF uvw = (pos + ray_dir * advance) * pos_to_uvw; float distance = texture(sampler3D(sdf_cascades[j], linear_sampler), uvw).r * 255.0 - 1.0; - if (distance < 0.001) { + if (distance < 0.05) { //consider hit hit = true; break; @@ -238,17 +231,7 @@ void main() { } if (hit) { - const float EPSILON = 0.001; - hit_normal = normalize(vec3( - texture(sampler3D(sdf_cascades[j], linear_sampler), uvw + vec3(EPSILON, 0.0, 0.0)).r - texture(sampler3D(sdf_cascades[j], linear_sampler), uvw - vec3(EPSILON, 0.0, 0.0)).r, - texture(sampler3D(sdf_cascades[j], linear_sampler), uvw + vec3(0.0, EPSILON, 0.0)).r - texture(sampler3D(sdf_cascades[j], linear_sampler), uvw - vec3(0.0, EPSILON, 0.0)).r, - texture(sampler3D(sdf_cascades[j], linear_sampler), uvw + vec3(0.0, 0.0, EPSILON)).r - texture(sampler3D(sdf_cascades[j], linear_sampler), uvw - vec3(0.0, 0.0, EPSILON)).r)); - - hit_light = texture(sampler3D(light_cascades[j], linear_sampler), uvw).rgb; - vec4 aniso0 = texture(sampler3D(aniso0_cascades[j], linear_sampler), uvw); - hit_aniso0 = aniso0.rgb; - hit_aniso1 = vec3(aniso0.a, texture(sampler3D(aniso1_cascades[j], linear_sampler), uvw).rg); - + hit_cascade = j; break; } @@ -261,11 +244,32 @@ void main() { vec4 light; if (hit) { - //one liner magic - light.rgb = hit_light * (dot(max(vec3(0.0), (hit_normal * hit_aniso0)), vec3(1.0)) + dot(max(vec3(0.0), (-hit_normal * hit_aniso1)), vec3(1.0))); - light.a = 1.0; + //avoid reading different texture from different threads + for (uint j = params.cascade; j < params.max_cascades; j++) { + if (j == hit_cascade) { + const float EPSILON = 0.001; + vec3 hit_normal = normalize(vec3( + texture(sampler3D(sdf_cascades[hit_cascade], linear_sampler), uvw + vec3(EPSILON, 0.0, 0.0)).r - texture(sampler3D(sdf_cascades[hit_cascade], linear_sampler), uvw - vec3(EPSILON, 0.0, 0.0)).r, + texture(sampler3D(sdf_cascades[hit_cascade], linear_sampler), uvw + vec3(0.0, EPSILON, 0.0)).r - texture(sampler3D(sdf_cascades[hit_cascade], linear_sampler), uvw - vec3(0.0, EPSILON, 0.0)).r, + texture(sampler3D(sdf_cascades[hit_cascade], linear_sampler), uvw + vec3(0.0, 0.0, EPSILON)).r - texture(sampler3D(sdf_cascades[hit_cascade], linear_sampler), uvw - vec3(0.0, 0.0, EPSILON)).r)); + + vec3 hit_light = texture(sampler3D(light_cascades[hit_cascade], linear_sampler), uvw).rgb; + vec4 aniso0 = texture(sampler3D(aniso0_cascades[hit_cascade], linear_sampler), uvw); + vec3 hit_aniso0 = aniso0.rgb; + vec3 hit_aniso1 = vec3(aniso0.a, texture(sampler3D(aniso1_cascades[hit_cascade], linear_sampler), uvw).rg); + + //one liner magic + light.rgb = hit_light * (dot(max(vec3(0.0), (hit_normal * hit_aniso0)), vec3(1.0)) + dot(max(vec3(0.0), (-hit_normal * hit_aniso1)), vec3(1.0))); + light.a = 1.0; + } + } + } else if (params.sky_mode == SKY_MODE_SKY) { +#ifdef USE_CUBEMAP_ARRAY + light.rgb = textureLod(samplerCubeArray(sky_irradiance, linear_sampler_mipmaps), vec4(ray_dir, 0.0), 2.0).rgb; //use second mipmap because we dont usually throw a lot of rays, so this compensates +#else light.rgb = textureLod(samplerCube(sky_irradiance, linear_sampler_mipmaps), ray_dir, 2.0).rgb; //use second mipmap because we dont usually throw a lot of rays, so this compensates +#endif light.rgb *= params.sky_energy; light.a = 0.0; @@ -278,33 +282,33 @@ void main() { } vec3 ray_dir2 = ray_dir * ray_dir; - float c[SH_SIZE] = float[]( - - 0.282095, //l0 - 0.488603 * ray_dir.y, //l1n1 - 0.488603 * ray_dir.z, //l1n0 - 0.488603 * ray_dir.x, //l1p1 - 1.092548 * ray_dir.x * ray_dir.y, //l2n2 - 1.092548 * ray_dir.y * ray_dir.z, //l2n1 - 0.315392 * (3.0 * ray_dir2.z - 1.0), //l20 - 1.092548 * ray_dir.x * ray_dir.z, //l2p1 - 0.546274 * (ray_dir2.x - ray_dir2.y) //l2p2 + +#define SH_ACCUM(m_idx, m_value) \ + { \ + vec3 l = light.rgb * (m_value); \ + sh_accum[probe_index].c[m_idx * 3 + 0] += l.r; \ + sh_accum[probe_index].c[m_idx * 3 + 1] += l.g; \ + sh_accum[probe_index].c[m_idx * 3 + 2] += l.b; \ + } + SH_ACCUM(0, 0.282095); //l0 + SH_ACCUM(1, 0.488603 * ray_dir.y); //l1n1 + SH_ACCUM(2, 0.488603 * ray_dir.z); //l1n0 + SH_ACCUM(3, 0.488603 * ray_dir.x); //l1p1 + SH_ACCUM(4, 1.092548 * ray_dir.x * ray_dir.y); //l2n2 + SH_ACCUM(5, 1.092548 * ray_dir.y * ray_dir.z); //l2n1 + SH_ACCUM(6, 0.315392 * (3.0 * ray_dir2.z - 1.0)); //l20 + SH_ACCUM(7, 1.092548 * ray_dir.x * ray_dir.z); //l2p1 + SH_ACCUM(8, 0.546274 * (ray_dir2.x - ray_dir2.y)); //l2p2 #if (SH_SIZE == 16) - , - 0.590043 * ray_dir.y * (3.0f * ray_dir2.x - ray_dir2.y), - 2.890611 * ray_dir.y * ray_dir.x * ray_dir.z, - 0.646360 * ray_dir.y * (-1.0f + 5.0f * ray_dir2.z), - 0.373176 * (5.0f * ray_dir2.z * ray_dir.z - 3.0f * ray_dir.z), - 0.457045 * ray_dir.x * (-1.0f + 5.0f * ray_dir2.z), - 1.445305 * (ray_dir2.x - ray_dir2.y) * ray_dir.z, - 0.590043 * ray_dir.x * (ray_dir2.x - 3.0f * ray_dir2.y) + SH_ACCUM(9, 0.590043 * ray_dir.y * (3.0f * ray_dir2.x - ray_dir2.y)); + SH_ACCUM(10, 2.890611 * ray_dir.y * ray_dir.x * ray_dir.z); + SH_ACCUM(11, 0.646360 * ray_dir.y * (-1.0f + 5.0f * ray_dir2.z)); + SH_ACCUM(12, 0.373176 * (5.0f * ray_dir2.z * ray_dir.z - 3.0f * ray_dir.z)); + SH_ACCUM(13, 0.457045 * ray_dir.x * (-1.0f + 5.0f * ray_dir2.z)); + SH_ACCUM(14, 1.445305 * (ray_dir2.x - ray_dir2.y) * ray_dir.z); + SH_ACCUM(15, 0.590043 * ray_dir.x * (ray_dir2.x - 3.0f * ray_dir2.y)); #endif - ); - - for (uint j = 0; j < SH_SIZE; j++) { - probe_sh_accum[j] += light * c[j]; - } } for (uint i = 0; i < SH_SIZE; i++) { @@ -312,7 +316,7 @@ void main() { ivec3 prev_pos = ivec3(pos.x, pos.y * SH_SIZE + i, int(params.history_index)); ivec2 average_pos = prev_pos.xy; - vec4 value = probe_sh_accum[i] * 4.0 / float(params.ray_count); + vec4 value = vec4(sh_accum[probe_index].c[i * 3 + 0], sh_accum[probe_index].c[i * 3 + 1], sh_accum[probe_index].c[i * 3 + 2], 1.0) * 4.0 / float(params.ray_count); ivec4 ivalue = clamp(ivec4(value * float(1 << HISTORY_BITS)), -32768, 32767); //clamp to 16 bits, so higher values don't break average @@ -344,37 +348,11 @@ void main() { ivec2 oct_pos = (pos / OCT_SIZE) * (OCT_SIZE + 2) + ivec2(1); ivec2 local_pos = pos % OCT_SIZE; - //fill the spherical harmonic - vec4 sh[SH_SIZE]; - - for (uint i = 0; i < SH_SIZE; i++) { - // store in history texture - ivec2 average_pos = sh_pos + ivec2(0, i); - ivec4 average = imageLoad(lightprobe_average_texture, average_pos); - - sh[i] = (vec4(average) / float(params.history_size)) / float(1 << HISTORY_BITS); - } - //compute the octahedral normal for this texel vec3 normal = octahedron_encode(vec2(local_pos) / float(OCT_SIZE)); - /* + // read the spherical harmonic - const float c1 = 0.429043; - const float c2 = 0.511664; - const float c3 = 0.743125; - const float c4 = 0.886227; - const float c5 = 0.247708; - vec4 light = (c1 * sh[8] * (normal.x * normal.x - normal.y * normal.y) + - c3 * sh[6] * normal.z * normal.z + - c4 * sh[0] - - c5 * sh[6] + - 2.0 * c1 * sh[4] * normal.x * normal.y + - 2.0 * c1 * sh[7] * normal.x * normal.z + - 2.0 * c1 * sh[5] * normal.y * normal.z + - 2.0 * c2 * sh[3] * normal.x + - 2.0 * c2 * sh[1] * normal.y + - 2.0 * c2 * sh[2] * normal.z); -*/ + vec3 normal2 = normal * normal; float c[SH_SIZE] = float[]( @@ -426,7 +404,14 @@ void main() { vec3 radiance = vec3(0.0); for (uint i = 0; i < SH_SIZE; i++) { - vec3 m = sh[i].rgb * c[i] * 4.0; + // store in history texture + ivec2 average_pos = sh_pos + ivec2(0, i); + ivec4 average = imageLoad(lightprobe_average_texture, average_pos); + + vec4 sh = (vec4(average) / float(params.history_size)) / float(1 << HISTORY_BITS); + + vec3 m = sh.rgb * c[i] * 4.0; + irradiance += m * l_mult[i]; radiance += m; } @@ -515,13 +500,15 @@ void main() { //can't scroll, must look for position in parent cascade //to global coords - float probe_cell_size = float(params.grid_size.x / float(params.probe_axis_size - 1)) / cascades.data[params.cascade].to_cell; + float cell_to_probe = float(params.grid_size.x / float(params.probe_axis_size - 1)); + + float probe_cell_size = cell_to_probe / cascades.data[params.cascade].to_cell; vec3 probe_pos = cascades.data[params.cascade].offset + vec3(probe_cell) * probe_cell_size; //to parent local coords + float probe_cell_size_next = cell_to_probe / cascades.data[params.cascade + 1].to_cell; probe_pos -= cascades.data[params.cascade + 1].offset; - probe_pos *= cascades.data[params.cascade + 1].to_cell; - probe_pos = probe_pos * float(params.probe_axis_size - 1) / float(params.grid_size.x); + probe_pos /= probe_cell_size_next; ivec3 probe_posi = ivec3(probe_pos); //add up all light, no need to use occlusion here, since occlusion will do its work afterwards @@ -574,20 +561,28 @@ void main() { } } else { - // clear and let it re-raytrace, only for the last cascade, which happens very un-often - //scroll + //scroll at the edge of the highest cascade, just copy what is there, + //since its the closest we have anyway + for (uint j = 0; j < params.history_size; j++) { + ivec2 tex_pos; + tex_pos = probe_cell.xy; + tex_pos.x += probe_cell.z * int(params.probe_axis_size); + for (int i = 0; i < SH_SIZE; i++) { // copy from history texture + ivec3 src_pos = ivec3(tex_pos.x, tex_pos.y * SH_SIZE + i, int(j)); ivec3 dst_pos = ivec3(pos.x, pos.y * SH_SIZE + i, int(j)); - imageStore(lightprobe_history_scroll_texture, dst_pos, ivec4(0)); + ivec4 value = imageLoad(lightprobe_history_texture, dst_pos); + imageStore(lightprobe_history_scroll_texture, dst_pos, value); } } for (int i = 0; i < SH_SIZE; i++) { // copy from average texture - ivec2 dst_pos = ivec2(pos.x, pos.y * SH_SIZE + i); - imageStore(lightprobe_average_scroll_texture, dst_pos, ivec4(0)); + ivec2 spos = ivec2(pos.x, pos.y * SH_SIZE + i); + ivec4 average = imageLoad(lightprobe_average_texture, spos); + imageStore(lightprobe_average_scroll_texture, spos, average); } } diff --git a/servers/rendering/rasterizer_rd/shaders/sdfgi_preprocess.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl index 916c60ac89..916c60ac89 100644 --- a/servers/rendering/rasterizer_rd/shaders/sdfgi_preprocess.glsl +++ b/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl diff --git a/servers/rendering/renderer_rd/shaders/skeleton.glsl b/servers/rendering/renderer_rd/shaders/skeleton.glsl new file mode 100644 index 0000000000..680d1045cd --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/skeleton.glsl @@ -0,0 +1,199 @@ +#[compute] + +#version 450 + +VERSION_DEFINES + +layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; + +layout(set = 0, binding = 1, std430) buffer restrict writeonly DstVertexData { + uint data[]; +} +dst_vertices; + +layout(set = 0, binding = 2, std430) buffer restrict readonly BlendShapeWeights { + float data[]; +} +blend_shape_weights; + +layout(set = 1, binding = 0, std430) buffer restrict readonly SrcVertexData { + uint data[]; +} +src_vertices; + +layout(set = 1, binding = 1, std430) buffer restrict readonly BoneWeightData { + uint data[]; +} +src_bone_weights; + +layout(set = 1, binding = 2, std430) buffer restrict readonly BlendShapeData { + uint data[]; +} +src_blend_shapes; + +layout(set = 2, binding = 0, std430) buffer restrict readonly SkeletonData { + vec4 data[]; +} +bone_transforms; + +layout(push_constant, binding = 0, std430) uniform Params { + bool has_normal; + bool has_tangent; + bool has_skeleton; + bool has_blend_shape; + + uint vertex_count; + uint vertex_stride; + uint skin_stride; + uint skin_weight_offset; + + uint blend_shape_count; + bool normalized_blend_shapes; + uint pad0; + uint pad1; +} +params; + +vec4 decode_abgr_2_10_10_10(uint base) { + uvec4 abgr_2_10_10_10 = (uvec4(base) >> uvec4(0, 10, 20, 30)) & uvec4(0x3FF, 0x3FF, 0x3FF, 0x3); + return vec4(abgr_2_10_10_10) / vec4(1023.0, 1023.0, 1023.0, 3.0) * 2.0 - 1.0; +} + +uint encode_abgr_2_10_10_10(vec4 base) { + uvec4 abgr_2_10_10_10 = uvec4(clamp(ivec4((base * 0.5 + 0.5) * vec4(1023.0, 1023.0, 1023.0, 3.0)), ivec4(0), ivec4(0x3FF, 0x3FF, 0x3FF, 0x3))) << uvec4(0, 10, 20, 30); + return abgr_2_10_10_10.x | abgr_2_10_10_10.y | abgr_2_10_10_10.z | abgr_2_10_10_10.w; +} + +void main() { + uint index = gl_GlobalInvocationID.x; + if (index >= params.vertex_count) { + return; + } + + uint src_offset = index * params.vertex_stride; + +#ifdef MODE_2D + vec2 vertex = uintBitsToFloat(uvec2(src_vertices.data[src_offset + 0], src_vertices.data[src_offset + 1])); +#else + vec3 vertex; + vec3 normal; + vec4 tangent; + + vertex = uintBitsToFloat(uvec3(src_vertices.data[src_offset + 0], src_vertices.data[src_offset + 1], src_vertices.data[src_offset + 2])); + + src_offset += 3; + + if (params.has_normal) { + normal = decode_abgr_2_10_10_10(src_vertices.data[src_offset]).rgb; + src_offset++; + } + + if (params.has_tangent) { + tangent = decode_abgr_2_10_10_10(src_vertices.data[src_offset]); + } + + if (params.has_blend_shape) { + float blend_total = 0.0; + vec3 blend_vertex = vec3(0.0); + vec3 blend_normal = vec3(0.0); + vec3 blend_tangent = vec3(0.0); + + for (uint i = 0; i < params.blend_shape_count; i++) { + float w = blend_shape_weights.data[i]; + if (abs(w) > 0.0001) { + uint base_offset = (params.vertex_count * i + index) * params.vertex_stride; + + blend_vertex += uintBitsToFloat(uvec3(src_blend_shapes.data[base_offset + 0], src_blend_shapes.data[base_offset + 1], src_blend_shapes.data[base_offset + 2])) * w; + + base_offset += 3; + + if (params.has_normal) { + blend_normal += decode_abgr_2_10_10_10(src_blend_shapes.data[base_offset]).rgb * w; + base_offset++; + } + + if (params.has_tangent) { + blend_tangent += decode_abgr_2_10_10_10(src_blend_shapes.data[base_offset]).rgb; + } + + blend_total += w; + } + } + + if (params.normalized_blend_shapes) { + vertex = (1.0 - blend_total) * vertex; + normal = (1.0 - blend_total) * normal; + tangent.rgb = (1.0 - blend_total) * tangent.rgb; + } + + vertex += blend_vertex; + normal += normalize(normal + blend_normal); + tangent.rgb += normalize(tangent.rgb + blend_tangent); + } + + if (params.has_skeleton) { + uint skin_offset = params.skin_stride * index; + + uvec2 bones = uvec2(src_bone_weights.data[skin_offset + 0], src_bone_weights.data[skin_offset + 1]); + uvec2 bones_01 = uvec2(bones.x & 0xFFFF, bones.x >> 16) * 3; //pre-add xform offset + uvec2 bones_23 = uvec2(bones.y & 0xFFFF, bones.y >> 16) * 3; + + skin_offset += params.skin_weight_offset; + + uvec2 weights = uvec2(src_bone_weights.data[skin_offset + 0], src_bone_weights.data[skin_offset + 1]); + + vec2 weights_01 = unpackUnorm2x16(weights.x); + vec2 weights_23 = unpackUnorm2x16(weights.y); + + mat4 m = mat4(bone_transforms.data[bones_01.x], bone_transforms.data[bones_01.x + 1], bone_transforms.data[bones_01.x + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.x; + m += mat4(bone_transforms.data[bones_01.y], bone_transforms.data[bones_01.y + 1], bone_transforms.data[bones_01.y + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.y; + m += mat4(bone_transforms.data[bones_23.x], bone_transforms.data[bones_23.x + 1], bone_transforms.data[bones_23.x + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.x; + m += mat4(bone_transforms.data[bones_23.y], bone_transforms.data[bones_23.y + 1], bone_transforms.data[bones_23.y + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.y; + + if (params.skin_weight_offset == 4) { + //using 8 bones/weights + skin_offset = params.skin_stride * index + 2; + + bones = uvec2(src_bone_weights.data[skin_offset + 0], src_bone_weights.data[skin_offset + 1]); + bones_01 = uvec2(bones.x & 0xFFFF, bones.x >> 16) * 3; //pre-add xform offset + bones_23 = uvec2(bones.y & 0xFFFF, bones.y >> 16) * 3; + + skin_offset += params.skin_weight_offset; + + weights = uvec2(src_bone_weights.data[skin_offset + 0], src_bone_weights.data[skin_offset + 1]); + + weights_01 = unpackUnorm2x16(weights.x); + weights_23 = unpackUnorm2x16(weights.y); + + m += mat4(bone_transforms.data[bones_01.x], bone_transforms.data[bones_01.x + 1], bone_transforms.data[bones_01.x + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.x; + m += mat4(bone_transforms.data[bones_01.y], bone_transforms.data[bones_01.y + 1], bone_transforms.data[bones_01.y + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.y; + m += mat4(bone_transforms.data[bones_23.x], bone_transforms.data[bones_23.x + 1], bone_transforms.data[bones_23.x + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.x; + m += mat4(bone_transforms.data[bones_23.y], bone_transforms.data[bones_23.y + 1], bone_transforms.data[bones_23.y + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.y; + } + + //reverse order because its transposed + vertex = (vec4(vertex, 1.0) * m).xyz; + normal = normalize((vec4(normal, 0.0) * m).xyz); + tangent.xyz = normalize((vec4(tangent.xyz, 0.0) * m).xyz); + } + + uint dst_offset = index * params.vertex_stride; + + uvec3 uvertex = floatBitsToUint(vertex); + dst_vertices.data[dst_offset + 0] = uvertex.x; + dst_vertices.data[dst_offset + 1] = uvertex.y; + dst_vertices.data[dst_offset + 2] = uvertex.z; + + dst_offset += 3; + + if (params.has_normal) { + dst_vertices.data[dst_offset] = encode_abgr_2_10_10_10(vec4(normal, 0.0)); + dst_offset++; + } + + if (params.has_tangent) { + dst_vertices.data[dst_offset] = encode_abgr_2_10_10_10(tangent); + } + +#endif +} diff --git a/servers/rendering/rasterizer_rd/shaders/sky.glsl b/servers/rendering/renderer_rd/shaders/sky.glsl index 6c985e1f5c..6c985e1f5c 100644 --- a/servers/rendering/rasterizer_rd/shaders/sky.glsl +++ b/servers/rendering/renderer_rd/shaders/sky.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/sort.glsl b/servers/rendering/renderer_rd/shaders/sort.glsl index e5ebb9c64b..e5ebb9c64b 100644 --- a/servers/rendering/rasterizer_rd/shaders/sort.glsl +++ b/servers/rendering/renderer_rd/shaders/sort.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/specular_merge.glsl b/servers/rendering/renderer_rd/shaders/specular_merge.glsl index 0b8f406213..0b8f406213 100644 --- a/servers/rendering/rasterizer_rd/shaders/specular_merge.glsl +++ b/servers/rendering/renderer_rd/shaders/specular_merge.glsl diff --git a/servers/rendering/renderer_rd/shaders/ssao.glsl b/servers/rendering/renderer_rd/shaders/ssao.glsl new file mode 100644 index 0000000000..231f8f91ec --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/ssao.glsl @@ -0,0 +1,486 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2016, Intel Corporation +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to the following conditions: +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of +// the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// File changes (yyyy-mm-dd) +// 2016-09-07: filip.strugar@intel.com: first commit +// 2020-12-05: clayjohn: convert to Vulkan and Godot +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#[compute] + +#version 450 + +VERSION_DEFINES + +#define SSAO_ADAPTIVE_TAP_BASE_COUNT 5 + +#define INTELSSAO_MAIN_DISK_SAMPLE_COUNT (32) +const vec4 sample_pattern[INTELSSAO_MAIN_DISK_SAMPLE_COUNT] = { + vec4(0.78488064, 0.56661671, 1.500000, -0.126083), vec4(0.26022232, -0.29575172, 1.500000, -1.064030), vec4(0.10459357, 0.08372527, 1.110000, -2.730563), vec4(-0.68286800, 0.04963045, 1.090000, -0.498827), + vec4(-0.13570161, -0.64190155, 1.250000, -0.532765), vec4(-0.26193795, -0.08205118, 0.670000, -1.783245), vec4(-0.61177456, 0.66664219, 0.710000, -0.044234), vec4(0.43675563, 0.25119025, 0.610000, -1.167283), + vec4(0.07884444, 0.86618668, 0.640000, -0.459002), vec4(-0.12790935, -0.29869005, 0.600000, -1.729424), vec4(-0.04031125, 0.02413622, 0.600000, -4.792042), vec4(0.16201244, -0.52851415, 0.790000, -1.067055), + vec4(-0.70991218, 0.47301072, 0.640000, -0.335236), vec4(0.03277707, -0.22349690, 0.600000, -1.982384), vec4(0.68921727, 0.36800742, 0.630000, -0.266718), vec4(0.29251814, 0.37775412, 0.610000, -1.422520), + vec4(-0.12224089, 0.96582592, 0.600000, -0.426142), vec4(0.11071457, -0.16131058, 0.600000, -2.165947), vec4(0.46562141, -0.59747696, 0.600000, -0.189760), vec4(-0.51548797, 0.11804193, 0.600000, -1.246800), + vec4(0.89141309, -0.42090443, 0.600000, 0.028192), vec4(-0.32402530, -0.01591529, 0.600000, -1.543018), vec4(0.60771245, 0.41635221, 0.600000, -0.605411), vec4(0.02379565, -0.08239821, 0.600000, -3.809046), + vec4(0.48951152, -0.23657045, 0.600000, -1.189011), vec4(-0.17611565, -0.81696892, 0.600000, -0.513724), vec4(-0.33930185, -0.20732205, 0.600000, -1.698047), vec4(-0.91974425, 0.05403209, 0.600000, 0.062246), + vec4(-0.15064627, -0.14949332, 0.600000, -1.896062), vec4(0.53180975, -0.35210401, 0.600000, -0.758838), vec4(0.41487166, 0.81442589, 0.600000, -0.505648), vec4(-0.24106961, -0.32721516, 0.600000, -1.665244) +}; + +// these values can be changed (up to SSAO_MAX_TAPS) with no changes required elsewhere; values for 4th and 5th preset are ignored but array needed to avoid compilation errors +// the actual number of texture samples is two times this value (each "tap" has two symmetrical depth texture samples) +const int num_taps[5] = { 3, 5, 12, 0, 0 }; + +#define SSAO_TILT_SAMPLES_ENABLE_AT_QUALITY_PRESET (99) // to disable simply set to 99 or similar +#define SSAO_TILT_SAMPLES_AMOUNT (0.4) +// +#define SSAO_HALOING_REDUCTION_ENABLE_AT_QUALITY_PRESET (1) // to disable simply set to 99 or similar +#define SSAO_HALOING_REDUCTION_AMOUNT (0.6) // values from 0.0 - 1.0, 1.0 means max weighting (will cause artifacts, 0.8 is more reasonable) +// +#define SSAO_NORMAL_BASED_EDGES_ENABLE_AT_QUALITY_PRESET (2) // to disable simply set to 99 or similar +#define SSAO_NORMAL_BASED_EDGES_DOT_THRESHOLD (0.5) // use 0-0.1 for super-sharp normal-based edges +// +#define SSAO_DETAIL_AO_ENABLE_AT_QUALITY_PRESET (1) // whether to use detail; to disable simply set to 99 or similar +// +#define SSAO_DEPTH_MIPS_ENABLE_AT_QUALITY_PRESET (2) // !!warning!! the MIP generation on the C++ side will be enabled on quality preset 2 regardless of this value, so if changing here, change the C++ side too +#define SSAO_DEPTH_MIPS_GLOBAL_OFFSET (-4.3) // best noise/quality/performance tradeoff, found empirically +// +// !!warning!! the edge handling is hard-coded to 'disabled' on quality level 0, and enabled above, on the C++ side; while toggling it here will work for +// testing purposes, it will not yield performance gains (or correct results) +#define SSAO_DEPTH_BASED_EDGES_ENABLE_AT_QUALITY_PRESET (1) +// +#define SSAO_REDUCE_RADIUS_NEAR_SCREEN_BORDER_ENABLE_AT_QUALITY_PRESET (1) + +#define SSAO_MAX_TAPS 32 +#define SSAO_MAX_REF_TAPS 512 +#define SSAO_ADAPTIVE_TAP_BASE_COUNT 5 +#define SSAO_ADAPTIVE_TAP_FLEXIBLE_COUNT (SSAO_MAX_TAPS - SSAO_ADAPTIVE_TAP_BASE_COUNT) +#define SSAO_DEPTH_MIP_LEVELS 4 + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +layout(set = 0, binding = 0) uniform sampler2DArray source_depth_mipmaps; +layout(rgba8, set = 0, binding = 1) uniform restrict readonly image2D source_normal; +layout(set = 0, binding = 2) uniform Constants { //get into a lower set + vec4 rotation_matrices[20]; +} +constants; + +#ifdef ADAPTIVE +layout(rg8, set = 1, binding = 0) uniform restrict readonly image2DArray source_ssao; +layout(set = 1, binding = 1) uniform sampler2D source_importance; +layout(set = 1, binding = 2, std430) buffer Counter { + uint sum; +} +counter; +#endif + +layout(rg8, set = 2, binding = 0) uniform restrict writeonly image2D dest_image; + +// This push_constant is full - 128 bytes - if you need to add more data, consider adding to the uniform buffer instead +layout(push_constant, binding = 3, std430) uniform Params { + ivec2 screen_size; + int pass; + int quality; + + vec2 half_screen_pixel_size; + int size_multiplier; + float detail_intensity; + + vec2 NDC_to_view_mul; + vec2 NDC_to_view_add; + + vec2 pad2; + vec2 half_screen_pixel_size_x025; + + float radius; + float intensity; + float shadow_power; + float shadow_clamp; + + float fade_out_mul; + float fade_out_add; + float horizon_angle_threshold; + float inv_radius_near_limit; + + bool is_orthogonal; + float neg_inv_radius; + float load_counter_avg_div; + float adaptive_sample_limit; + + ivec2 pass_coord_offset; + vec2 pass_uv_offset; +} +params; + +// packing/unpacking for edges; 2 bits per edge mean 4 gradient values (0, 0.33, 0.66, 1) for smoother transitions! +float pack_edges(vec4 p_edgesLRTB) { + p_edgesLRTB = round(clamp(p_edgesLRTB, 0.0, 1.0) * 3.05); + return dot(p_edgesLRTB, vec4(64.0 / 255.0, 16.0 / 255.0, 4.0 / 255.0, 1.0 / 255.0)); +} + +vec3 NDC_to_view_space(vec2 p_pos, float p_viewspace_depth) { + if (params.is_orthogonal) { + return vec3((params.NDC_to_view_mul * p_pos.xy + params.NDC_to_view_add), p_viewspace_depth); + } else { + return vec3((params.NDC_to_view_mul * p_pos.xy + params.NDC_to_view_add) * p_viewspace_depth, p_viewspace_depth); + } +} + +// calculate effect radius and fit our screen sampling pattern inside it +void calculate_radius_parameters(const float p_pix_center_length, const vec2 p_pixel_size_at_center, out float r_lookup_radius, out float r_radius, out float r_fallof_sq) { + r_radius = params.radius; + + // when too close, on-screen sampling disk will grow beyond screen size; limit this to avoid closeup temporal artifacts + const float too_close_limit = clamp(p_pix_center_length * params.inv_radius_near_limit, 0.0, 1.0) * 0.8 + 0.2; + + r_radius *= too_close_limit; + + // 0.85 is to reduce the radius to allow for more samples on a slope to still stay within influence + r_lookup_radius = (0.85 * r_radius) / p_pixel_size_at_center.x; + + // used to calculate falloff (both for AO samples and per-sample weights) + r_fallof_sq = -1.0 / (r_radius * r_radius); +} + +vec4 calculate_edges(const float p_center_z, const float p_left_z, const float p_right_z, const float p_top_z, const float p_bottom_z) { + // slope-sensitive depth-based edge detection + vec4 edgesLRTB = vec4(p_left_z, p_right_z, p_top_z, p_bottom_z) - p_center_z; + vec4 edgesLRTB_slope_adjusted = edgesLRTB + edgesLRTB.yxwz; + edgesLRTB = min(abs(edgesLRTB), abs(edgesLRTB_slope_adjusted)); + return clamp((1.3 - edgesLRTB / (p_center_z * 0.040)), 0.0, 1.0); +} + +vec3 decode_normal(vec3 p_encoded_normal) { + vec3 normal = p_encoded_normal * 2.0 - 1.0; + return normal; +} + +vec3 load_normal(ivec2 p_pos) { + vec3 encoded_normal = imageLoad(source_normal, p_pos).xyz; + encoded_normal.z = 1.0 - encoded_normal.z; + return decode_normal(encoded_normal); +} + +vec3 load_normal(ivec2 p_pos, ivec2 p_offset) { + vec3 encoded_normal = imageLoad(source_normal, p_pos + p_offset).xyz; + encoded_normal.z = 1.0 - encoded_normal.z; + return decode_normal(encoded_normal); +} + +// all vectors in viewspace +float calculate_pixel_obscurance(vec3 p_pixel_normal, vec3 p_hit_delta, float p_fallof_sq) { + float length_sq = dot(p_hit_delta, p_hit_delta); + float NdotD = dot(p_pixel_normal, p_hit_delta) / sqrt(length_sq); + + float falloff_mult = max(0.0, length_sq * p_fallof_sq + 1.0); + + return max(0, NdotD - params.horizon_angle_threshold) * falloff_mult; +} + +void SSAO_tap_inner(const int p_quality_level, inout float r_obscurance_sum, inout float r_weight_sum, const vec2 p_sampling_uv, const float p_mip_level, const vec3 p_pix_center_pos, vec3 p_pixel_normal, const float p_fallof_sq, const float p_weight_mod) { + // get depth at sample + float viewspace_sample_z = textureLod(source_depth_mipmaps, vec3(p_sampling_uv, params.pass), p_mip_level).x; + + // convert to viewspace + vec3 hit_pos = NDC_to_view_space(p_sampling_uv.xy, viewspace_sample_z).xyz; + vec3 hit_delta = hit_pos - p_pix_center_pos; + + float obscurance = calculate_pixel_obscurance(p_pixel_normal, hit_delta, p_fallof_sq); + float weight = 1.0; + + if (p_quality_level >= SSAO_HALOING_REDUCTION_ENABLE_AT_QUALITY_PRESET) { + float reduct = max(0, -hit_delta.z); + reduct = clamp(reduct * params.neg_inv_radius + 2.0, 0.0, 1.0); + weight = SSAO_HALOING_REDUCTION_AMOUNT * reduct + (1.0 - SSAO_HALOING_REDUCTION_AMOUNT); + } + weight *= p_weight_mod; + r_obscurance_sum += obscurance * weight; + r_weight_sum += weight; +} + +void SSAOTap(const int p_quality_level, inout float r_obscurance_sum, inout float r_weight_sum, const int p_tap_index, const mat2 p_rot_scale, const vec3 p_pix_center_pos, vec3 p_pixel_normal, const vec2 p_normalized_screen_pos, const float p_mip_offset, const float p_fallof_sq, float p_weight_mod, vec2 p_norm_xy, float p_norm_xy_length) { + vec2 sample_offset; + float sample_pow_2_len; + + // patterns + { + vec4 new_sample = sample_pattern[p_tap_index]; + sample_offset = new_sample.xy * p_rot_scale; + sample_pow_2_len = new_sample.w; // precalculated, same as: sample_pow_2_len = log2( length( new_sample.xy ) ); + p_weight_mod *= new_sample.z; + } + + // snap to pixel center (more correct obscurance math, avoids artifacts) + sample_offset = round(sample_offset); + + // calculate MIP based on the sample distance from the centre, similar to as described + // in http://graphics.cs.williams.edu/papers/SAOHPG12/. + float mip_level = (p_quality_level < SSAO_DEPTH_MIPS_ENABLE_AT_QUALITY_PRESET) ? (0) : (sample_pow_2_len + p_mip_offset); + + vec2 sampling_uv = sample_offset * params.half_screen_pixel_size + p_normalized_screen_pos; + + SSAO_tap_inner(p_quality_level, r_obscurance_sum, r_weight_sum, sampling_uv, mip_level, p_pix_center_pos, p_pixel_normal, p_fallof_sq, p_weight_mod); + + // for the second tap, just use the mirrored offset + vec2 sample_offset_mirrored_uv = -sample_offset; + + // tilt the second set of samples so that the disk is effectively rotated by the normal + // effective at removing one set of artifacts, but too expensive for lower quality settings + if (p_quality_level >= SSAO_TILT_SAMPLES_ENABLE_AT_QUALITY_PRESET) { + float dot_norm = dot(sample_offset_mirrored_uv, p_norm_xy); + sample_offset_mirrored_uv -= dot_norm * p_norm_xy_length * p_norm_xy; + sample_offset_mirrored_uv = round(sample_offset_mirrored_uv); + } + + // snap to pixel center (more correct obscurance math, avoids artifacts) + vec2 sampling_mirrored_uv = sample_offset_mirrored_uv * params.half_screen_pixel_size + p_normalized_screen_pos; + + SSAO_tap_inner(p_quality_level, r_obscurance_sum, r_weight_sum, sampling_mirrored_uv, mip_level, p_pix_center_pos, p_pixel_normal, p_fallof_sq, p_weight_mod); +} + +void generate_SSAO_shadows_internal(out float r_shadow_term, out vec4 r_edges, out float r_weight, const vec2 p_pos, int p_quality_level, bool p_adaptive_base) { + vec2 pos_rounded = trunc(p_pos); + uvec2 upos = uvec2(pos_rounded); + + const int number_of_taps = (p_adaptive_base) ? (SSAO_ADAPTIVE_TAP_BASE_COUNT) : (num_taps[p_quality_level]); + float pix_z, pix_left_z, pix_top_z, pix_right_z, pix_bottom_z; + + vec4 valuesUL = textureGather(source_depth_mipmaps, vec3(pos_rounded * params.half_screen_pixel_size, params.pass)); + vec4 valuesBR = textureGather(source_depth_mipmaps, vec3((pos_rounded + vec2(1.0)) * params.half_screen_pixel_size, params.pass)); + + // get this pixel's viewspace depth + pix_z = valuesUL.y; + + // get left right top bottom neighbouring pixels for edge detection (gets compiled out on quality_level == 0) + pix_left_z = valuesUL.x; + pix_top_z = valuesUL.z; + pix_right_z = valuesBR.z; + pix_bottom_z = valuesBR.x; + + vec2 normalized_screen_pos = pos_rounded * params.half_screen_pixel_size + params.half_screen_pixel_size_x025; + vec3 pix_center_pos = NDC_to_view_space(normalized_screen_pos, pix_z); + + // Load this pixel's viewspace normal + uvec2 full_res_coord = upos * 2 * params.size_multiplier + params.pass_coord_offset.xy; + vec3 pixel_normal = load_normal(ivec2(full_res_coord)); + + const vec2 pixel_size_at_center = NDC_to_view_space(normalized_screen_pos.xy + params.half_screen_pixel_size, pix_center_pos.z).xy - pix_center_pos.xy; + + float pixel_lookup_radius; + float fallof_sq; + + // calculate effect radius and fit our screen sampling pattern inside it + float viewspace_radius; + calculate_radius_parameters(length(pix_center_pos), pixel_size_at_center, pixel_lookup_radius, viewspace_radius, fallof_sq); + + // calculate samples rotation/scaling + mat2 rot_scale_matrix; + uint pseudo_random_index; + + { + vec4 rotation_scale; + // reduce effect radius near the screen edges slightly; ideally, one would render a larger depth buffer (5% on each side) instead + if (!p_adaptive_base && (p_quality_level >= SSAO_REDUCE_RADIUS_NEAR_SCREEN_BORDER_ENABLE_AT_QUALITY_PRESET)) { + float near_screen_border = min(min(normalized_screen_pos.x, 1.0 - normalized_screen_pos.x), min(normalized_screen_pos.y, 1.0 - normalized_screen_pos.y)); + near_screen_border = clamp(10.0 * near_screen_border + 0.6, 0.0, 1.0); + pixel_lookup_radius *= near_screen_border; + } + + // load & update pseudo-random rotation matrix + pseudo_random_index = uint(pos_rounded.y * 2 + pos_rounded.x) % 5; + rotation_scale = constants.rotation_matrices[params.pass * 5 + pseudo_random_index]; + rot_scale_matrix = mat2(rotation_scale.x * pixel_lookup_radius, rotation_scale.y * pixel_lookup_radius, rotation_scale.z * pixel_lookup_radius, rotation_scale.w * pixel_lookup_radius); + } + + // the main obscurance & sample weight storage + float obscurance_sum = 0.0; + float weight_sum = 0.0; + + // edge mask for between this and left/right/top/bottom neighbour pixels - not used in quality level 0 so initialize to "no edge" (1 is no edge, 0 is edge) + vec4 edgesLRTB = vec4(1.0, 1.0, 1.0, 1.0); + + // Move center pixel slightly towards camera to avoid imprecision artifacts due to using of 16bit depth buffer; a lot smaller offsets needed when using 32bit floats + pix_center_pos *= 0.9992; + + if (!p_adaptive_base && (p_quality_level >= SSAO_DEPTH_BASED_EDGES_ENABLE_AT_QUALITY_PRESET)) { + edgesLRTB = calculate_edges(pix_z, pix_left_z, pix_right_z, pix_top_z, pix_bottom_z); + } + + // adds a more high definition sharp effect, which gets blurred out (reuses left/right/top/bottom samples that we used for edge detection) + if (!p_adaptive_base && (p_quality_level >= SSAO_DETAIL_AO_ENABLE_AT_QUALITY_PRESET)) { + // disable in case of quality level 4 (reference) + if (p_quality_level != 4) { + //approximate neighbouring pixels positions (actually just deltas or "positions - pix_center_pos" ) + vec3 normalized_viewspace_dir = vec3(pix_center_pos.xy / pix_center_pos.zz, 1.0); + vec3 pixel_left_delta = vec3(-pixel_size_at_center.x, 0.0, 0.0) + normalized_viewspace_dir * (pix_left_z - pix_center_pos.z); + vec3 pixel_right_delta = vec3(+pixel_size_at_center.x, 0.0, 0.0) + normalized_viewspace_dir * (pix_right_z - pix_center_pos.z); + vec3 pixel_top_delta = vec3(0.0, -pixel_size_at_center.y, 0.0) + normalized_viewspace_dir * (pix_top_z - pix_center_pos.z); + vec3 pixel_bottom_delta = vec3(0.0, +pixel_size_at_center.y, 0.0) + normalized_viewspace_dir * (pix_bottom_z - pix_center_pos.z); + + const float range_reduction = 4.0f; // this is to avoid various artifacts + const float modified_fallof_sq = range_reduction * fallof_sq; + + vec4 additional_obscurance; + additional_obscurance.x = calculate_pixel_obscurance(pixel_normal, pixel_left_delta, modified_fallof_sq); + additional_obscurance.y = calculate_pixel_obscurance(pixel_normal, pixel_right_delta, modified_fallof_sq); + additional_obscurance.z = calculate_pixel_obscurance(pixel_normal, pixel_top_delta, modified_fallof_sq); + additional_obscurance.w = calculate_pixel_obscurance(pixel_normal, pixel_bottom_delta, modified_fallof_sq); + + obscurance_sum += params.detail_intensity * dot(additional_obscurance, edgesLRTB); + } + } + + // Sharp normals also create edges - but this adds to the cost as well + if (!p_adaptive_base && (p_quality_level >= SSAO_NORMAL_BASED_EDGES_ENABLE_AT_QUALITY_PRESET)) { + vec3 neighbour_normal_left = load_normal(ivec2(full_res_coord), ivec2(-2, 0)); + vec3 neighbour_normal_right = load_normal(ivec2(full_res_coord), ivec2(2, 0)); + vec3 neighbour_normal_top = load_normal(ivec2(full_res_coord), ivec2(0, -2)); + vec3 neighbour_normal_bottom = load_normal(ivec2(full_res_coord), ivec2(0, 2)); + + const float dot_threshold = SSAO_NORMAL_BASED_EDGES_DOT_THRESHOLD; + + vec4 normal_edgesLRTB; + normal_edgesLRTB.x = clamp((dot(pixel_normal, neighbour_normal_left) + dot_threshold), 0.0, 1.0); + normal_edgesLRTB.y = clamp((dot(pixel_normal, neighbour_normal_right) + dot_threshold), 0.0, 1.0); + normal_edgesLRTB.z = clamp((dot(pixel_normal, neighbour_normal_top) + dot_threshold), 0.0, 1.0); + normal_edgesLRTB.w = clamp((dot(pixel_normal, neighbour_normal_bottom) + dot_threshold), 0.0, 1.0); + + edgesLRTB *= normal_edgesLRTB; + } + + const float global_mip_offset = SSAO_DEPTH_MIPS_GLOBAL_OFFSET; + float mip_offset = (p_quality_level < SSAO_DEPTH_MIPS_ENABLE_AT_QUALITY_PRESET) ? (0) : (log2(pixel_lookup_radius) + global_mip_offset); + + // Used to tilt the second set of samples so that the disk is effectively rotated by the normal + // effective at removing one set of artifacts, but too expensive for lower quality settings + vec2 norm_xy = vec2(pixel_normal.x, pixel_normal.y); + float norm_xy_length = length(norm_xy); + norm_xy /= vec2(norm_xy_length, -norm_xy_length); + norm_xy_length *= SSAO_TILT_SAMPLES_AMOUNT; + + // standard, non-adaptive approach + if ((p_quality_level != 3) || p_adaptive_base) { + for (int i = 0; i < number_of_taps; i++) { + SSAOTap(p_quality_level, obscurance_sum, weight_sum, i, rot_scale_matrix, pix_center_pos, pixel_normal, normalized_screen_pos, mip_offset, fallof_sq, 1.0, norm_xy, norm_xy_length); + } + } +#ifdef ADAPTIVE + else { + // add new ones if needed + vec2 full_res_uv = normalized_screen_pos + params.pass_uv_offset.xy; + float importance = textureLod(source_importance, full_res_uv, 0.0).x; + + // this is to normalize SSAO_DETAIL_AO_AMOUNT across all pixel regardless of importance + obscurance_sum *= (SSAO_ADAPTIVE_TAP_BASE_COUNT / float(SSAO_MAX_TAPS)) + (importance * SSAO_ADAPTIVE_TAP_FLEXIBLE_COUNT / float(SSAO_MAX_TAPS)); + + // load existing base values + vec2 base_values = imageLoad(source_ssao, ivec3(upos, params.pass)).xy; + weight_sum += base_values.y * float(SSAO_ADAPTIVE_TAP_BASE_COUNT * 4.0); + obscurance_sum += (base_values.x) * weight_sum; + + // increase importance around edges + float edge_count = dot(1.0 - edgesLRTB, vec4(1.0, 1.0, 1.0, 1.0)); + + float avg_total_importance = float(counter.sum) * params.load_counter_avg_div; + + float importance_limiter = clamp(params.adaptive_sample_limit / avg_total_importance, 0.0, 1.0); + importance *= importance_limiter; + + float additional_sample_count = SSAO_ADAPTIVE_TAP_FLEXIBLE_COUNT * importance; + + const float blend_range = 3.0; + const float blend_range_inv = 1.0 / blend_range; + + additional_sample_count += 0.5; + uint additional_samples = uint(additional_sample_count); + uint additional_samples_to = min(SSAO_MAX_TAPS, additional_samples + SSAO_ADAPTIVE_TAP_BASE_COUNT); + + for (uint i = SSAO_ADAPTIVE_TAP_BASE_COUNT; i < additional_samples_to; i++) { + additional_sample_count -= 1.0f; + float weight_mod = clamp(additional_sample_count * blend_range_inv, 0.0, 1.0); + SSAOTap(p_quality_level, obscurance_sum, weight_sum, int(i), rot_scale_matrix, pix_center_pos, pixel_normal, normalized_screen_pos, mip_offset, fallof_sq, weight_mod, norm_xy, norm_xy_length); + } + } +#endif + + // early out for adaptive base - just output weight (used for the next pass) + if (p_adaptive_base) { + float obscurance = obscurance_sum / weight_sum; + + r_shadow_term = obscurance; + r_edges = vec4(0.0); + r_weight = weight_sum; + return; + } + + // calculate weighted average + float obscurance = obscurance_sum / weight_sum; + + // calculate fadeout (1 close, gradient, 0 far) + float fade_out = clamp(pix_center_pos.z * params.fade_out_mul + params.fade_out_add, 0.0, 1.0); + + // Reduce the SSAO shadowing if we're on the edge to remove artifacts on edges (we don't care for the lower quality one) + if (!p_adaptive_base && (p_quality_level >= SSAO_DEPTH_BASED_EDGES_ENABLE_AT_QUALITY_PRESET)) { + // when there's more than 2 opposite edges, start fading out the occlusion to reduce aliasing artifacts + float edge_fadeout_factor = clamp((1.0 - edgesLRTB.x - edgesLRTB.y) * 0.35, 0.0, 1.0) + clamp((1.0 - edgesLRTB.z - edgesLRTB.w) * 0.35, 0.0, 1.0); + + fade_out *= clamp(1.0 - edge_fadeout_factor, 0.0, 1.0); + } + + // strength + obscurance = params.intensity * obscurance; + + // clamp + obscurance = min(obscurance, params.shadow_clamp); + + // fadeout + obscurance *= fade_out; + + // conceptually switch to occlusion with the meaning being visibility (grows with visibility, occlusion == 1 implies full visibility), + // to be in line with what is more commonly used. + float occlusion = 1.0 - obscurance; + + // modify the gradient + // note: this cannot be moved to a later pass because of loss of precision after storing in the render target + occlusion = pow(clamp(occlusion, 0.0, 1.0), params.shadow_power); + + // outputs! + r_shadow_term = occlusion; // Our final 'occlusion' term (0 means fully occluded, 1 means fully lit) + r_edges = edgesLRTB; // These are used to prevent blurring across edges, 1 means no edge, 0 means edge, 0.5 means half way there, etc. + r_weight = weight_sum; +} + +void main() { + float out_shadow_term; + float out_weight; + vec4 out_edges; + ivec2 ssC = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThanEqual(ssC, params.screen_size))) { //too large, do nothing + return; + } + + vec2 uv = vec2(gl_GlobalInvocationID) + vec2(0.5); +#ifdef SSAO_BASE + generate_SSAO_shadows_internal(out_shadow_term, out_edges, out_weight, uv, params.quality, true); + + imageStore(dest_image, ivec2(gl_GlobalInvocationID.xy), vec4(out_shadow_term, out_weight / (float(SSAO_ADAPTIVE_TAP_BASE_COUNT) * 4.0), 0.0, 0.0)); +#else + generate_SSAO_shadows_internal(out_shadow_term, out_edges, out_weight, uv, params.quality, false); // pass in quality levels + if (params.quality == 0) { + out_edges = vec4(1.0); + } + + imageStore(dest_image, ivec2(gl_GlobalInvocationID.xy), vec4(out_shadow_term, pack_edges(out_edges), 0.0, 0.0)); +#endif +} diff --git a/servers/rendering/renderer_rd/shaders/ssao_blur.glsl b/servers/rendering/renderer_rd/shaders/ssao_blur.glsl new file mode 100644 index 0000000000..510a777048 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/ssao_blur.glsl @@ -0,0 +1,154 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2016, Intel Corporation +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to the following conditions: +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of +// the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// File changes (yyyy-mm-dd) +// 2016-09-07: filip.strugar@intel.com: first commit +// 2020-12-05: clayjohn: convert to Vulkan and Godot +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#[compute] + +#version 450 + +VERSION_DEFINES + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +layout(set = 0, binding = 0) uniform sampler2D source_ssao; + +layout(rg8, set = 1, binding = 0) uniform restrict writeonly image2D dest_image; + +layout(push_constant, binding = 1, std430) uniform Params { + float edge_sharpness; + float pad; + vec2 half_screen_pixel_size; +} +params; + +vec4 unpack_edges(float p_packed_val) { + uint packed_val = uint(p_packed_val * 255.5); + vec4 edgesLRTB; + edgesLRTB.x = float((packed_val >> 6) & 0x03) / 3.0; + edgesLRTB.y = float((packed_val >> 4) & 0x03) / 3.0; + edgesLRTB.z = float((packed_val >> 2) & 0x03) / 3.0; + edgesLRTB.w = float((packed_val >> 0) & 0x03) / 3.0; + + return clamp(edgesLRTB + params.edge_sharpness, 0.0, 1.0); +} + +void add_sample(float p_ssao_value, float p_edge_value, inout float r_sum, inout float r_sum_weight) { + float weight = p_edge_value; + + r_sum += (weight * p_ssao_value); + r_sum_weight += weight; +} + +#ifdef MODE_WIDE +vec2 sample_blurred_wide(vec2 p_coord) { + vec2 vC = textureLodOffset(source_ssao, vec2(p_coord), 0.0, ivec2(0, 0)).xy; + vec2 vL = textureLodOffset(source_ssao, vec2(p_coord), 0.0, ivec2(-2, 0)).xy; + vec2 vT = textureLodOffset(source_ssao, vec2(p_coord), 0.0, ivec2(0, -2)).xy; + vec2 vR = textureLodOffset(source_ssao, vec2(p_coord), 0.0, ivec2(2, 0)).xy; + vec2 vB = textureLodOffset(source_ssao, vec2(p_coord), 0.0, ivec2(0, 2)).xy; + + float packed_edges = vC.y; + vec4 edgesLRTB = unpack_edges(packed_edges); + edgesLRTB.x *= unpack_edges(vL.y).y; + edgesLRTB.z *= unpack_edges(vT.y).w; + edgesLRTB.y *= unpack_edges(vR.y).x; + edgesLRTB.w *= unpack_edges(vB.y).z; + + float ssao_value = vC.x; + float ssao_valueL = vL.x; + float ssao_valueT = vT.x; + float ssao_valueR = vR.x; + float ssao_valueB = vB.x; + + float sum_weight = 0.8f; + float sum = ssao_value * sum_weight; + + add_sample(ssao_valueL, edgesLRTB.x, sum, sum_weight); + add_sample(ssao_valueR, edgesLRTB.y, sum, sum_weight); + add_sample(ssao_valueT, edgesLRTB.z, sum, sum_weight); + add_sample(ssao_valueB, edgesLRTB.w, sum, sum_weight); + + float ssao_avg = sum / sum_weight; + + ssao_value = ssao_avg; + + return vec2(ssao_value, packed_edges); +} +#endif + +#ifdef MODE_SMART +vec2 sample_blurred(vec3 p_pos, vec2 p_coord) { + float packed_edges = texelFetch(source_ssao, ivec2(p_pos.xy), 0).y; + vec4 edgesLRTB = unpack_edges(packed_edges); + + vec4 valuesUL = textureGather(source_ssao, vec2(p_coord - params.half_screen_pixel_size * 0.5)); + vec4 valuesBR = textureGather(source_ssao, vec2(p_coord + params.half_screen_pixel_size * 0.5)); + + float ssao_value = valuesUL.y; + float ssao_valueL = valuesUL.x; + float ssao_valueT = valuesUL.z; + float ssao_valueR = valuesBR.z; + float ssao_valueB = valuesBR.x; + + float sum_weight = 0.5; + float sum = ssao_value * sum_weight; + + add_sample(ssao_valueL, edgesLRTB.x, sum, sum_weight); + add_sample(ssao_valueR, edgesLRTB.y, sum, sum_weight); + + add_sample(ssao_valueT, edgesLRTB.z, sum, sum_weight); + add_sample(ssao_valueB, edgesLRTB.w, sum, sum_weight); + + float ssao_avg = sum / sum_weight; + + ssao_value = ssao_avg; + + return vec2(ssao_value, packed_edges); +} +#endif + +void main() { + // Pixel being shaded + ivec2 ssC = ivec2(gl_GlobalInvocationID.xy); + +#ifdef MODE_NON_SMART + + vec2 halfPixel = params.half_screen_pixel_size * 0.5f; + + vec2 uv = (vec2(gl_GlobalInvocationID.xy) + vec2(0.5, 0.5)) * params.half_screen_pixel_size; + + vec2 centre = textureLod(source_ssao, vec2(uv), 0.0).xy; + + vec4 vals; + vals.x = textureLod(source_ssao, vec2(uv + vec2(-halfPixel.x * 3, -halfPixel.y)), 0.0).x; + vals.y = textureLod(source_ssao, vec2(uv + vec2(+halfPixel.x, -halfPixel.y * 3)), 0.0).x; + vals.z = textureLod(source_ssao, vec2(uv + vec2(-halfPixel.x, +halfPixel.y * 3)), 0.0).x; + vals.w = textureLod(source_ssao, vec2(uv + vec2(+halfPixel.x * 3, +halfPixel.y)), 0.0).x; + + vec2 sampled = vec2(dot(vals, vec4(0.2)) + centre.x * 0.2, centre.y); + +#else +#ifdef MODE_SMART + vec2 sampled = sample_blurred(vec3(gl_GlobalInvocationID), (vec2(gl_GlobalInvocationID.xy) + vec2(0.5, 0.5)) * params.half_screen_pixel_size); +#else // MODE_WIDE + vec2 sampled = sample_blurred_wide((vec2(gl_GlobalInvocationID.xy) + vec2(0.5, 0.5)) * params.half_screen_pixel_size); +#endif + +#endif + imageStore(dest_image, ivec2(ssC), vec4(sampled, 0.0, 0.0)); +} diff --git a/servers/rendering/renderer_rd/shaders/ssao_downsample.glsl b/servers/rendering/renderer_rd/shaders/ssao_downsample.glsl new file mode 100644 index 0000000000..cb2d31f70d --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/ssao_downsample.glsl @@ -0,0 +1,206 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2016, Intel Corporation +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to the following conditions: +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of +// the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// File changes (yyyy-mm-dd) +// 2016-09-07: filip.strugar@intel.com: first commit +// 2020-12-05: clayjohn: convert to Vulkan and Godot +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#[compute] + +#version 450 + +VERSION_DEFINES + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +layout(push_constant, binding = 1, std430) uniform Params { + vec2 pixel_size; + float z_far; + float z_near; + bool orthogonal; + float radius_sq; + uvec2 pad; +} +params; + +layout(set = 0, binding = 0) uniform sampler2D source_depth; + +layout(r16f, set = 1, binding = 0) uniform restrict writeonly image2DArray dest_image0; //rename +#ifdef GENERATE_MIPS +layout(r16f, set = 2, binding = 0) uniform restrict writeonly image2DArray dest_image1; +layout(r16f, set = 2, binding = 1) uniform restrict writeonly image2DArray dest_image2; +layout(r16f, set = 2, binding = 2) uniform restrict writeonly image2DArray dest_image3; +#endif + +vec4 screen_space_to_view_space_depth(vec4 p_depth) { + if (params.orthogonal) { + vec4 depth = p_depth * 2.0 - 1.0; + return ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; + } + + float depth_linearize_mul = params.z_near; + float depth_linearize_add = params.z_far; + + // Optimised version of "-cameraClipNear / (cameraClipFar - projDepth * (cameraClipFar - cameraClipNear)) * cameraClipFar" + + // Set your depth_linearize_mul and depth_linearize_add to: + // depth_linearize_mul = ( cameraClipFar * cameraClipNear) / ( cameraClipFar - cameraClipNear ); + // depth_linearize_add = cameraClipFar / ( cameraClipFar - cameraClipNear ); + + return depth_linearize_mul / (depth_linearize_add - p_depth); +} + +float screen_space_to_view_space_depth(float p_depth) { + if (params.orthogonal) { + float depth = p_depth * 2.0 - 1.0; + return ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / (2.0 * params.z_far); + } + + float depth_linearize_mul = params.z_near; + float depth_linearize_add = params.z_far; + + return depth_linearize_mul / (depth_linearize_add - p_depth); +} + +#ifdef GENERATE_MIPS + +shared float depth_buffer[4][8][8]; + +float mip_smart_average(vec4 p_depths) { + float closest = min(min(p_depths.x, p_depths.y), min(p_depths.z, p_depths.w)); + float fallof_sq = -1.0f / params.radius_sq; + vec4 dists = p_depths - closest.xxxx; + vec4 weights = clamp(dists * dists * fallof_sq + 1.0, 0.0, 1.0); + return dot(weights, p_depths) / dot(weights, vec4(1.0, 1.0, 1.0, 1.0)); +} + +void prepare_depths_and_mips(vec4 p_samples, uvec2 p_output_coord, uvec2 p_gtid) { + p_samples = screen_space_to_view_space_depth(p_samples); + + depth_buffer[0][p_gtid.x][p_gtid.y] = p_samples.w; + depth_buffer[1][p_gtid.x][p_gtid.y] = p_samples.z; + depth_buffer[2][p_gtid.x][p_gtid.y] = p_samples.x; + depth_buffer[3][p_gtid.x][p_gtid.y] = p_samples.y; + + imageStore(dest_image0, ivec3(p_output_coord.x, p_output_coord.y, 0), vec4(p_samples.w)); + imageStore(dest_image0, ivec3(p_output_coord.x, p_output_coord.y, 1), vec4(p_samples.z)); + imageStore(dest_image0, ivec3(p_output_coord.x, p_output_coord.y, 2), vec4(p_samples.x)); + imageStore(dest_image0, ivec3(p_output_coord.x, p_output_coord.y, 3), vec4(p_samples.y)); + + uint depth_array_index = 2 * (p_gtid.y % 2) + (p_gtid.x % 2); + uvec2 depth_array_offset = ivec2(p_gtid.x % 2, p_gtid.y % 2); + ivec2 buffer_coord = ivec2(p_gtid) - ivec2(depth_array_offset); + + p_output_coord /= 2; + groupMemoryBarrier(); + barrier(); + + // if (still_alive) <-- all threads alive here + { + float sample_00 = depth_buffer[depth_array_index][buffer_coord.x + 0][buffer_coord.y + 0]; + float sample_01 = depth_buffer[depth_array_index][buffer_coord.x + 0][buffer_coord.y + 1]; + float sample_10 = depth_buffer[depth_array_index][buffer_coord.x + 1][buffer_coord.y + 0]; + float sample_11 = depth_buffer[depth_array_index][buffer_coord.x + 1][buffer_coord.y + 1]; + + float avg = mip_smart_average(vec4(sample_00, sample_01, sample_10, sample_11)); + imageStore(dest_image1, ivec3(p_output_coord.x, p_output_coord.y, depth_array_index), vec4(avg)); + depth_buffer[depth_array_index][buffer_coord.x][buffer_coord.y] = avg; + } + + bool still_alive = p_gtid.x % 4 == depth_array_offset.x && p_gtid.y % 4 == depth_array_offset.y; + + p_output_coord /= 2; + groupMemoryBarrier(); + barrier(); + + if (still_alive) { + float sample_00 = depth_buffer[depth_array_index][buffer_coord.x + 0][buffer_coord.y + 0]; + float sample_01 = depth_buffer[depth_array_index][buffer_coord.x + 0][buffer_coord.y + 2]; + float sample_10 = depth_buffer[depth_array_index][buffer_coord.x + 2][buffer_coord.y + 0]; + float sample_11 = depth_buffer[depth_array_index][buffer_coord.x + 2][buffer_coord.y + 2]; + + float avg = mip_smart_average(vec4(sample_00, sample_01, sample_10, sample_11)); + imageStore(dest_image2, ivec3(p_output_coord.x, p_output_coord.y, depth_array_index), vec4(avg)); + depth_buffer[depth_array_index][buffer_coord.x][buffer_coord.y] = avg; + } + + still_alive = p_gtid.x % 8 == depth_array_offset.x && depth_array_offset.y % 8 == depth_array_offset.y; + + p_output_coord /= 2; + groupMemoryBarrier(); + barrier(); + + if (still_alive) { + float sample_00 = depth_buffer[depth_array_index][buffer_coord.x + 0][buffer_coord.y + 0]; + float sample_01 = depth_buffer[depth_array_index][buffer_coord.x + 0][buffer_coord.y + 4]; + float sample_10 = depth_buffer[depth_array_index][buffer_coord.x + 4][buffer_coord.y + 0]; + float sample_11 = depth_buffer[depth_array_index][buffer_coord.x + 4][buffer_coord.y + 4]; + + float avg = mip_smart_average(vec4(sample_00, sample_01, sample_10, sample_11)); + imageStore(dest_image3, ivec3(p_output_coord.x, p_output_coord.y, depth_array_index), vec4(avg)); + } +} +#else +#ifndef USE_HALF_BUFFERS +void prepare_depths(vec4 p_samples, uvec2 p_tid) { + p_samples = screen_space_to_view_space_depth(p_samples); + + imageStore(dest_image0, ivec3(p_tid, 0), vec4(p_samples.w)); + imageStore(dest_image0, ivec3(p_tid, 1), vec4(p_samples.z)); + imageStore(dest_image0, ivec3(p_tid, 2), vec4(p_samples.x)); + imageStore(dest_image0, ivec3(p_tid, 3), vec4(p_samples.y)); +} +#endif +#endif + +void main() { +#ifdef USE_HALF_BUFFERS +#ifdef USE_HALF_SIZE + float sample_00 = texelFetch(source_depth, ivec2(4 * gl_GlobalInvocationID.x + 0, 4 * gl_GlobalInvocationID.y + 0), 0).x; + float sample_11 = texelFetch(source_depth, ivec2(4 * gl_GlobalInvocationID.x + 2, 4 * gl_GlobalInvocationID.y + 2), 0).x; +#else + float sample_00 = texelFetch(source_depth, ivec2(2 * gl_GlobalInvocationID.x + 0, 2 * gl_GlobalInvocationID.y + 0), 0).x; + float sample_11 = texelFetch(source_depth, ivec2(2 * gl_GlobalInvocationID.x + 1, 2 * gl_GlobalInvocationID.y + 1), 0).x; +#endif + sample_00 = screen_space_to_view_space_depth(sample_00); + sample_11 = screen_space_to_view_space_depth(sample_11); + + imageStore(dest_image0, ivec3(gl_GlobalInvocationID.xy, 0), vec4(sample_00)); + imageStore(dest_image0, ivec3(gl_GlobalInvocationID.xy, 3), vec4(sample_11)); +#else //!USE_HALF_BUFFERS +#ifdef USE_HALF_SIZE + ivec2 depth_buffer_coord = 4 * ivec2(gl_GlobalInvocationID.xy); + ivec2 output_coord = ivec2(gl_GlobalInvocationID); + + vec2 uv = (vec2(depth_buffer_coord) + 0.5f) * params.pixel_size; + vec4 samples; + samples.x = textureLodOffset(source_depth, uv, 0, ivec2(0, 2)).x; + samples.y = textureLodOffset(source_depth, uv, 0, ivec2(2, 2)).x; + samples.z = textureLodOffset(source_depth, uv, 0, ivec2(2, 0)).x; + samples.w = textureLodOffset(source_depth, uv, 0, ivec2(0, 0)).x; +#else + ivec2 depth_buffer_coord = 2 * ivec2(gl_GlobalInvocationID.xy); + ivec2 output_coord = ivec2(gl_GlobalInvocationID); + + vec2 uv = (vec2(depth_buffer_coord) + 0.5f) * params.pixel_size; + vec4 samples = textureGather(source_depth, uv); +#endif +#ifdef GENERATE_MIPS + prepare_depths_and_mips(samples, output_coord, gl_LocalInvocationID.xy); +#else + prepare_depths(samples, gl_GlobalInvocationID.xy); +#endif +#endif +} diff --git a/servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl b/servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl new file mode 100644 index 0000000000..6aa7624261 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl @@ -0,0 +1,126 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2016, Intel Corporation +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to the following conditions: +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of +// the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// File changes (yyyy-mm-dd) +// 2016-09-07: filip.strugar@intel.com: first commit +// 2020-12-05: clayjohn: convert to Vulkan and Godot +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#[compute] + +#version 450 + +VERSION_DEFINES + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +#ifdef GENERATE_MAP +layout(set = 0, binding = 0) uniform sampler2DArray source_ssao; +#else +layout(set = 0, binding = 0) uniform sampler2D source_importance; +#endif +layout(r8, set = 1, binding = 0) uniform restrict writeonly image2D dest_image; + +#ifdef PROCESS_MAPB +layout(set = 2, binding = 0, std430) buffer Counter { + uint sum; +} +counter; +#endif + +layout(push_constant, binding = 1, std430) uniform Params { + vec2 half_screen_pixel_size; + float intensity; + float power; +} +params; + +void main() { + // Pixel being shaded + ivec2 ssC = ivec2(gl_GlobalInvocationID.xy); + +#ifdef GENERATE_MAP + // importance map stuff + uvec2 base_position = ssC * 2; + + vec2 base_uv = (vec2(base_position) + vec2(0.5f, 0.5f)) * params.half_screen_pixel_size; + + float avg = 0.0; + float minV = 1.0; + float maxV = 0.0; + for (int i = 0; i < 4; i++) { + vec4 vals = textureGather(source_ssao, vec3(base_uv, i)); + + // apply the same modifications that would have been applied in the main shader + vals = params.intensity * vals; + + vals = 1 - vals; + + vals = pow(clamp(vals, 0.0, 1.0), vec4(params.power)); + + avg += dot(vec4(vals.x, vals.y, vals.z, vals.w), vec4(1.0 / 16.0, 1.0 / 16.0, 1.0 / 16.0, 1.0 / 16.0)); + + maxV = max(maxV, max(max(vals.x, vals.y), max(vals.z, vals.w))); + minV = min(minV, min(min(vals.x, vals.y), min(vals.z, vals.w))); + } + + float min_max_diff = maxV - minV; + + imageStore(dest_image, ssC, vec4(pow(clamp(min_max_diff * 2.0, 0.0, 1.0), 0.8))); +#endif + +#ifdef PROCESS_MAPA + vec2 uv = (vec2(ssC) + 0.5f) * params.half_screen_pixel_size * 2.0; + + float centre = textureLod(source_importance, uv, 0.0).x; + + vec2 half_pixel = params.half_screen_pixel_size; + + vec4 vals; + vals.x = textureLod(source_importance, uv + vec2(-half_pixel.x * 3, -half_pixel.y), 0.0).x; + vals.y = textureLod(source_importance, uv + vec2(+half_pixel.x, -half_pixel.y * 3), 0.0).x; + vals.z = textureLod(source_importance, uv + vec2(+half_pixel.x * 3, +half_pixel.y), 0.0).x; + vals.w = textureLod(source_importance, uv + vec2(-half_pixel.x, +half_pixel.y * 3), 0.0).x; + + float avg = dot(vals, vec4(0.25, 0.25, 0.25, 0.25)); + + imageStore(dest_image, ssC, vec4(avg)); +#endif + +#ifdef PROCESS_MAPB + vec2 uv = (vec2(ssC) + 0.5f) * params.half_screen_pixel_size * 2.0; + + float centre = textureLod(source_importance, uv, 0.0).x; + + vec2 half_pixel = params.half_screen_pixel_size; + + vec4 vals; + vals.x = textureLod(source_importance, uv + vec2(-half_pixel.x, -half_pixel.y * 3), 0.0).x; + vals.y = textureLod(source_importance, uv + vec2(+half_pixel.x * 3, -half_pixel.y), 0.0).x; + vals.z = textureLod(source_importance, uv + vec2(+half_pixel.x, +half_pixel.y * 3), 0.0).x; + vals.w = textureLod(source_importance, uv + vec2(-half_pixel.x * 3, +half_pixel.y), 0.0).x; + + float avg = dot(vals, vec4(0.25, 0.25, 0.25, 0.25)); + + imageStore(dest_image, ssC, vec4(avg)); + + // sum the average; to avoid overflowing we assume max AO resolution is not bigger than 16384x16384; so quarter res (used here) will be 4096x4096, which leaves us with 8 bits per pixel + uint sum = uint(clamp(avg, 0.0, 1.0) * 255.0 + 0.5); + + // save every 9th to avoid InterlockedAdd congestion - since we're blurring, this is good enough; compensated by multiplying load_counter_avg_div by 9 + if (((ssC.x % 3) + (ssC.y % 3)) == 0) { + atomicAdd(counter.sum, sum); + } +#endif +} diff --git a/servers/rendering/renderer_rd/shaders/ssao_interleave.glsl b/servers/rendering/renderer_rd/shaders/ssao_interleave.glsl new file mode 100644 index 0000000000..4fdf334aa5 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/ssao_interleave.glsl @@ -0,0 +1,119 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2016, Intel Corporation +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to the following conditions: +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of +// the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// File changes (yyyy-mm-dd) +// 2016-09-07: filip.strugar@intel.com: first commit +// 2020-12-05: clayjohn: convert to Vulkan and Godot +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#[compute] + +#version 450 + +VERSION_DEFINES + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +layout(rgba8, set = 0, binding = 0) uniform restrict writeonly image2D dest_image; +layout(set = 1, binding = 0) uniform sampler2DArray source_texture; + +layout(push_constant, binding = 1, std430) uniform Params { + float inv_sharpness; + uint size_modifier; + vec2 pixel_size; +} +params; + +vec4 unpack_edges(float p_packed_val) { + uint packed_val = uint(p_packed_val * 255.5); + vec4 edgesLRTB; + edgesLRTB.x = float((packed_val >> 6) & 0x03) / 3.0; + edgesLRTB.y = float((packed_val >> 4) & 0x03) / 3.0; + edgesLRTB.z = float((packed_val >> 2) & 0x03) / 3.0; + edgesLRTB.w = float((packed_val >> 0) & 0x03) / 3.0; + + return clamp(edgesLRTB + params.inv_sharpness, 0.0, 1.0); +} + +void main() { + ivec2 ssC = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThanEqual(ssC, ivec2(1.0 / params.pixel_size)))) { //too large, do nothing + return; + } + +#ifdef MODE_SMART + float ao; + uvec2 pix_pos = uvec2(gl_GlobalInvocationID.xy); + vec2 uv = (gl_GlobalInvocationID.xy + vec2(0.5)) * params.pixel_size; + + // calculate index in the four deinterleaved source array texture + int mx = int(pix_pos.x % 2); + int my = int(pix_pos.y % 2); + int index_center = mx + my * 2; // center index + int index_horizontal = (1 - mx) + my * 2; // neighbouring, horizontal + int index_vertical = mx + (1 - my) * 2; // neighbouring, vertical + int index_diagonal = (1 - mx) + (1 - my) * 2; // diagonal + + vec2 center_val = texelFetch(source_texture, ivec3(pix_pos / uvec2(params.size_modifier), index_center), 0).xy; + + ao = center_val.x; + + vec4 edgesLRTB = unpack_edges(center_val.y); + + // convert index shifts to sampling offsets + float fmx = float(mx); + float fmy = float(my); + + // in case of an edge, push sampling offsets away from the edge (towards pixel center) + float fmxe = (edgesLRTB.y - edgesLRTB.x); + float fmye = (edgesLRTB.w - edgesLRTB.z); + + // calculate final sampling offsets and sample using bilinear filter + vec2 uv_horizontal = (gl_GlobalInvocationID.xy + vec2(0.5) + vec2(fmx + fmxe - 0.5, 0.5 - fmy)) * params.pixel_size; + float ao_horizontal = textureLod(source_texture, vec3(uv_horizontal, index_horizontal), 0.0).x; + vec2 uv_vertical = (gl_GlobalInvocationID.xy + vec2(0.5) + vec2(0.5 - fmx, fmy - 0.5 + fmye)) * params.pixel_size; + float ao_vertical = textureLod(source_texture, vec3(uv_vertical, index_vertical), 0.0).x; + vec2 uv_diagonal = (gl_GlobalInvocationID.xy + vec2(0.5) + vec2(fmx - 0.5 + fmxe, fmy - 0.5 + fmye)) * params.pixel_size; + float ao_diagonal = textureLod(source_texture, vec3(uv_diagonal, index_diagonal), 0.0).x; + + // reduce weight for samples near edge - if the edge is on both sides, weight goes to 0 + vec4 blendWeights; + blendWeights.x = 1.0; + blendWeights.y = (edgesLRTB.x + edgesLRTB.y) * 0.5; + blendWeights.z = (edgesLRTB.z + edgesLRTB.w) * 0.5; + blendWeights.w = (blendWeights.y + blendWeights.z) * 0.5; + + // calculate weighted average + float blendWeightsSum = dot(blendWeights, vec4(1.0, 1.0, 1.0, 1.0)); + ao = dot(vec4(ao, ao_horizontal, ao_vertical, ao_diagonal), blendWeights) / blendWeightsSum; + + imageStore(dest_image, ivec2(gl_GlobalInvocationID.xy), vec4(ao)); +#else // !MODE_SMART + + vec2 uv = (gl_GlobalInvocationID.xy + vec2(0.5)) * params.pixel_size; +#ifdef MODE_HALF + float a = textureLod(source_texture, vec3(uv, 0), 0.0).x; + float d = textureLod(source_texture, vec3(uv, 3), 0.0).x; + float avg = (a + d) * 0.5; + +#else + float a = textureLod(source_texture, vec3(uv, 0), 0.0).x; + float b = textureLod(source_texture, vec3(uv, 1), 0.0).x; + float c = textureLod(source_texture, vec3(uv, 2), 0.0).x; + float d = textureLod(source_texture, vec3(uv, 3), 0.0).x; + float avg = (a + b + c + d) * 0.25; + +#endif + imageStore(dest_image, ivec2(gl_GlobalInvocationID.xy), vec4(avg)); +#endif +} diff --git a/servers/rendering/rasterizer_rd/shaders/subsurface_scattering.glsl b/servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl index 88a953562f..88a953562f 100644 --- a/servers/rendering/rasterizer_rd/shaders/subsurface_scattering.glsl +++ b/servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/tonemap.glsl b/servers/rendering/renderer_rd/shaders/tonemap.glsl index 4cc4fd3f64..7de91fd541 100644 --- a/servers/rendering/rasterizer_rd/shaders/tonemap.glsl +++ b/servers/rendering/renderer_rd/shaders/tonemap.glsl @@ -23,7 +23,11 @@ layout(location = 0) in vec2 uv_interp; layout(set = 0, binding = 0) uniform sampler2D source_color; layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure; layout(set = 2, binding = 0) uniform sampler2D source_glow; -layout(set = 3, binding = 0) uniform sampler3D color_correction; +#ifdef USE_1D_LUT +layout(set = 3, binding = 0) uniform sampler2D source_color_correction; +#else +layout(set = 3, binding = 0) uniform sampler3D source_color_correction; +#endif layout(push_constant, binding = 1, std430) uniform Params { vec3 bcs; @@ -35,9 +39,9 @@ layout(push_constant, binding = 1, std430) uniform Params { uint tonemapper; uvec2 glow_texture_size; - float glow_intensity; uint pad3; + uint glow_mode; float glow_levels[7]; @@ -255,10 +259,18 @@ vec3 apply_bcs(vec3 color, vec3 bcs) { return color; } - -vec3 apply_color_correction(vec3 color, sampler3D correction_tex) { - return texture(correction_tex, color).rgb; +#ifdef USE_1D_LUT +vec3 apply_color_correction(vec3 color) { + color.r = texture(source_color_correction, vec2(color.r, 0.0f)).r; + color.g = texture(source_color_correction, vec2(color.g, 0.0f)).g; + color.b = texture(source_color_correction, vec2(color.b, 0.0f)).b; + return color; +} +#else +vec3 apply_color_correction(vec3 color) { + return textureLod(source_color_correction, color, 0.0).rgb; } +#endif vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) { const float FXAA_REDUCE_MIN = (1.0 / 128.0); @@ -367,7 +379,7 @@ void main() { } if (params.use_color_correction) { - color = apply_color_correction(color, color_correction); + color = apply_color_correction(color); } frag_color = vec4(color, 1.0f); diff --git a/servers/rendering/rasterizer_rd/shaders/volumetric_fog.glsl b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl index 13b162f0c9..e7ba8feb80 100644 --- a/servers/rendering/rasterizer_rd/shaders/volumetric_fog.glsl +++ b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl @@ -4,6 +4,15 @@ VERSION_DEFINES +/* Do not use subgroups here, seems there is not much advantage and causes glitches +#extension GL_KHR_shader_subgroup_ballot: enable +#extension GL_KHR_shader_subgroup_arithmetic: enable + +#if defined(GL_KHR_shader_subgroup_ballot) && defined(GL_KHR_shader_subgroup_arithmetic) +#define USE_SUBGROUPS +#endif +*/ + #if defined(MODE_FOG) || defined(MODE_FILTER) layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; @@ -23,22 +32,25 @@ layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in; layout(set = 0, binding = 1) uniform texture2D shadow_atlas; layout(set = 0, binding = 2) uniform texture2D directional_shadow_atlas; -layout(set = 0, binding = 3, std430) restrict readonly buffer Lights { +layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights { LightData data[]; } -lights; +omni_lights; -layout(set = 0, binding = 4, std140) uniform DirectionalLights { +layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights { + LightData data[]; +} +spot_lights; + +layout(set = 0, binding = 5, std140) uniform DirectionalLights { DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS]; } directional_lights; -layout(set = 0, binding = 5) uniform utexture3D cluster_texture; - -layout(set = 0, binding = 6, std430) restrict readonly buffer ClusterData { - uint indices[]; +layout(set = 0, binding = 6, std430) buffer restrict readonly ClusterBuffer { + uint data[]; } -cluster_data; +cluster_buffer; layout(set = 0, binding = 7) uniform sampler linear_sampler; @@ -132,7 +144,7 @@ layout(set = 1, binding = 2) uniform texture3D sdfgi_occlusion_texture; #endif //SDFGI -layout(push_constant, binding = 0, std430) uniform Params { +layout(set = 0, binding = 14, std140) uniform Params { vec2 fog_frustum_size_begin; vec2 fog_frustum_size_end; @@ -150,12 +162,24 @@ layout(push_constant, binding = 0, std430) uniform Params { float detail_spread; float gi_inject; uint max_gi_probes; - uint pad; + uint cluster_type_size; + + vec2 screen_size; + uint cluster_shift; + uint cluster_width; + + uint max_cluster_element_count_div_32; + bool use_temporal_reprojection; + uint temporal_frame; + float temporal_blend; mat3x4 cam_rotation; + mat4 to_prev_view; } params; +layout(set = 0, binding = 15) uniform texture3D prev_density_texture; + float get_depth_at_pos(float cell_depth_size, int z) { float d = float(z) * cell_depth_size + cell_depth_size * 0.5; //center of voxels d = pow(d, params.detail_spread); @@ -169,6 +193,51 @@ vec3 hash3f(uvec3 x) { return vec3(x & 0xFFFFF) / vec3(float(0xFFFFF)); } +float get_omni_attenuation(float distance, float inv_range, float decay) { + float nd = distance * inv_range; + nd *= nd; + nd *= nd; // nd^4 + nd = max(1.0 - nd, 0.0); + nd *= nd; // nd^2 + return nd * pow(max(distance, 0.0001), -decay); +} + +void cluster_get_item_range(uint p_offset, out uint item_min, out uint item_max, out uint item_from, out uint item_to) { + uint item_min_max = cluster_buffer.data[p_offset]; + item_min = item_min_max & 0xFFFF; + item_max = item_min_max >> 16; + ; + + item_from = item_min >> 5; + item_to = (item_max == 0) ? 0 : ((item_max - 1) >> 5) + 1; //side effect of how it is stored, as item_max 0 means no elements +} + +uint cluster_get_range_clip_mask(uint i, uint z_min, uint z_max) { + int local_min = clamp(int(z_min) - int(i) * 32, 0, 31); + int mask_width = min(int(z_max) - int(z_min), 32 - local_min); + return bitfieldInsert(uint(0), uint(0xFFFFFFFF), local_min, mask_width); +} + +#define TEMPORAL_FRAMES 16 + +const vec3 halton_map[TEMPORAL_FRAMES] = vec3[]( + vec3(0.5, 0.33333333, 0.2), + vec3(0.25, 0.66666667, 0.4), + vec3(0.75, 0.11111111, 0.6), + vec3(0.125, 0.44444444, 0.8), + vec3(0.625, 0.77777778, 0.04), + vec3(0.375, 0.22222222, 0.24), + vec3(0.875, 0.55555556, 0.44), + vec3(0.0625, 0.88888889, 0.64), + vec3(0.5625, 0.03703704, 0.84), + vec3(0.3125, 0.37037037, 0.08), + vec3(0.8125, 0.7037037, 0.28), + vec3(0.1875, 0.14814815, 0.48), + vec3(0.6875, 0.48148148, 0.68), + vec3(0.4375, 0.81481481, 0.88), + vec3(0.9375, 0.25925926, 0.12), + vec3(0.03125, 0.59259259, 0.32)); + void main() { vec3 fog_cell_size = 1.0 / vec3(params.fog_volume_size); @@ -184,6 +253,12 @@ void main() { //posf += mix(vec3(0.0),vec3(1.0),0.3) * hash3f(uvec3(pos)) * 2.0 - 1.0; vec3 fog_unit_pos = posf * fog_cell_size + fog_cell_size * 0.5; //center of voxels + + uvec2 screen_pos = uvec2(fog_unit_pos.xy * params.screen_size); + uvec2 cluster_pos = screen_pos >> params.cluster_shift; + uint cluster_offset = (params.cluster_width * cluster_pos.y + cluster_pos.x) * (params.max_cluster_element_count_div_32 + 32); + //positions in screen are too spread apart, no hopes for optimizing with subgroups + fog_unit_pos.z = pow(fog_unit_pos.z, params.detail_spread); vec3 view_pos; @@ -191,6 +266,47 @@ void main() { view_pos.z = -params.fog_frustum_end * fog_unit_pos.z; view_pos.y = -view_pos.y; + vec4 reprojected_density = vec4(0.0); + float reproject_amount = 0.0; + + if (params.use_temporal_reprojection) { + vec3 prev_view = (params.to_prev_view * vec4(view_pos, 1.0)).xyz; + //undo transform into prev view + prev_view.y = -prev_view.y; + //z back to unit size + prev_view.z /= -params.fog_frustum_end; + //xy back to unit size + prev_view.xy /= mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(prev_view.z)); + prev_view.xy = prev_view.xy * 0.5 + 0.5; + //z back to unspread value + prev_view.z = pow(prev_view.z, 1.0 / params.detail_spread); + + if (all(greaterThan(prev_view, vec3(0.0))) && all(lessThan(prev_view, vec3(1.0)))) { + //reprojectinon fits + + reprojected_density = textureLod(sampler3D(prev_density_texture, linear_sampler), prev_view, 0.0); + reproject_amount = params.temporal_blend; + + // Since we can reproject, now we must jitter the current view pos. + // This is done here because cells that can't reproject should not jitter. + + fog_unit_pos = posf * fog_cell_size + fog_cell_size * halton_map[params.temporal_frame]; //center of voxels, offset by halton table + + screen_pos = uvec2(fog_unit_pos.xy * params.screen_size); + cluster_pos = screen_pos >> params.cluster_shift; + cluster_offset = (params.cluster_width * cluster_pos.y + cluster_pos.x) * (params.max_cluster_element_count_div_32 + 32); + //positions in screen are too spread apart, no hopes for optimizing with subgroups + + fog_unit_pos.z = pow(fog_unit_pos.z, params.detail_spread); + + view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(fog_unit_pos.z)); + view_pos.z = -params.fog_frustum_end * fog_unit_pos.z; + view_pos.y = -view_pos.y; + } + } + + uint cluster_z = uint(clamp((abs(view_pos.z) / params.z_far) * 32.0, 0.0, 31.0)); + vec3 total_light = params.light_color; float total_density = params.base_density; @@ -257,108 +373,160 @@ void main() { //compute lights from cluster - vec3 cluster_pos; - cluster_pos.xy = fog_unit_pos.xy; - cluster_pos.z = clamp((abs(view_pos.z) - params.z_near) / (params.z_far - params.z_near), 0.0, 1.0); + { //omni lights - uvec4 cluster_cell = texture(usampler3D(cluster_texture, linear_sampler), cluster_pos); + uint cluster_omni_offset = cluster_offset; - uint omni_light_count = cluster_cell.x >> CLUSTER_COUNTER_SHIFT; - uint omni_light_pointer = cluster_cell.x & CLUSTER_POINTER_MASK; + uint item_min; + uint item_max; + uint item_from; + uint item_to; - for (uint i = 0; i < omni_light_count; i++) { - uint light_index = cluster_data.indices[omni_light_pointer + i]; + cluster_get_item_range(cluster_omni_offset + params.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); - vec3 light_pos = lights.data[i].position; - float d = distance(lights.data[i].position, view_pos) * lights.data[i].inv_radius; - vec3 shadow_attenuation = vec3(1.0); +#ifdef USE_SUBGROUPS + item_from = subgroupBroadcastFirst(subgroupMin(item_from)); + item_to = subgroupBroadcastFirst(subgroupMax(item_to)); +#endif - if (d < 1.0) { - vec2 attenuation_energy = unpackHalf2x16(lights.data[i].attenuation_energy); - vec4 color_specular = unpackUnorm4x8(lights.data[i].color_specular); + for (uint i = item_from; i < item_to; i++) { + uint mask = cluster_buffer.data[cluster_omni_offset + i]; + mask &= cluster_get_range_clip_mask(i, item_min, item_max); +#ifdef USE_SUBGROUPS + uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); +#else + uint merged_mask = mask; +#endif - float attenuation = pow(max(1.0 - d, 0.0), attenuation_energy.x); + while (merged_mask != 0) { + uint bit = findMSB(merged_mask); + merged_mask &= ~(1 << bit); +#ifdef USE_SUBGROUPS + if (((1 << bit) & mask) == 0) { //do not process if not originally here + continue; + } +#endif + uint light_index = 32 * i + bit; - vec3 light = attenuation_energy.y * color_specular.rgb / M_PI; + //if (!bool(omni_omni_lights.data[light_index].mask & draw_call.layer_mask)) { + // continue; //not masked + //} - vec4 shadow_color_enabled = unpackUnorm4x8(lights.data[i].shadow_color_enabled); + vec3 light_pos = omni_lights.data[light_index].position; + float d = distance(omni_lights.data[light_index].position, view_pos); + float shadow_attenuation = 1.0; - if (shadow_color_enabled.a > 0.5) { - //has shadow - vec4 v = vec4(view_pos, 1.0); + if (d * omni_lights.data[light_index].inv_radius < 1.0) { + float attenuation = get_omni_attenuation(d, omni_lights.data[light_index].inv_radius, omni_lights.data[light_index].attenuation); - vec4 splane = (lights.data[i].shadow_matrix * v); - float shadow_len = length(splane.xyz); //need to remember shadow len from here + vec3 light = omni_lights.data[light_index].color / M_PI; - splane.xyz = normalize(splane.xyz); - vec4 clamp_rect = lights.data[i].atlas_rect; + if (omni_lights.data[light_index].shadow_enabled) { + //has shadow + vec4 v = vec4(view_pos, 1.0); - if (splane.z >= 0.0) { - splane.z += 1.0; + vec4 splane = (omni_lights.data[light_index].shadow_matrix * v); + float shadow_len = length(splane.xyz); //need to remember shadow len from here - clamp_rect.y += clamp_rect.w; + splane.xyz = normalize(splane.xyz); + vec4 clamp_rect = omni_lights.data[light_index].atlas_rect; - } else { - splane.z = 1.0 - splane.z; - } + if (splane.z >= 0.0) { + splane.z += 1.0; + + clamp_rect.y += clamp_rect.w; - splane.xy /= splane.z; + } else { + splane.z = 1.0 - splane.z; + } - splane.xy = splane.xy * 0.5 + 0.5; - splane.z = shadow_len * lights.data[i].inv_radius; - splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; - splane.w = 1.0; //needed? i think it should be 1 already + splane.xy /= splane.z; - float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r; - float shadow = exp(min(0.0, (depth - splane.z)) / lights.data[i].inv_radius * lights.data[i].shadow_volumetric_fog_fade); + splane.xy = splane.xy * 0.5 + 0.5; + splane.z = shadow_len * omni_lights.data[light_index].inv_radius; + splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; + splane.w = 1.0; //needed? i think it should be 1 already - shadow_attenuation = mix(shadow_color_enabled.rgb, vec3(1.0), shadow); + float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r; + + shadow_attenuation = exp(min(0.0, (depth - splane.z)) / omni_lights.data[light_index].inv_radius * omni_lights.data[light_index].shadow_volumetric_fog_fade); + } + total_light += light * attenuation * shadow_attenuation; + } } - total_light += light * attenuation * shadow_attenuation; } } - uint spot_light_count = cluster_cell.y >> CLUSTER_COUNTER_SHIFT; - uint spot_light_pointer = cluster_cell.y & CLUSTER_POINTER_MASK; + { //spot lights - for (uint i = 0; i < spot_light_count; i++) { - uint light_index = cluster_data.indices[spot_light_pointer + i]; + uint cluster_spot_offset = cluster_offset + params.cluster_type_size; - vec3 light_pos = lights.data[i].position; - vec3 light_rel_vec = lights.data[i].position - view_pos; - float d = length(light_rel_vec) * lights.data[i].inv_radius; - vec3 shadow_attenuation = vec3(1.0); + uint item_min; + uint item_max; + uint item_from; + uint item_to; - if (d < 1.0) { - vec2 attenuation_energy = unpackHalf2x16(lights.data[i].attenuation_energy); - vec4 color_specular = unpackUnorm4x8(lights.data[i].color_specular); + cluster_get_item_range(cluster_spot_offset + params.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); - float attenuation = pow(max(1.0 - d, 0.0), attenuation_energy.x); +#ifdef USE_SUBGROUPS + item_from = subgroupBroadcastFirst(subgroupMin(item_from)); + item_to = subgroupBroadcastFirst(subgroupMax(item_to)); +#endif - vec3 spot_dir = lights.data[i].direction; - vec2 spot_att_angle = unpackHalf2x16(lights.data[i].cone_attenuation_angle); - float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_att_angle.y); - float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_att_angle.y)); - attenuation *= 1.0 - pow(spot_rim, spot_att_angle.x); + for (uint i = item_from; i < item_to; i++) { + uint mask = cluster_buffer.data[cluster_spot_offset + i]; + mask &= cluster_get_range_clip_mask(i, item_min, item_max); +#ifdef USE_SUBGROUPS + uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); +#else + uint merged_mask = mask; +#endif - vec3 light = attenuation_energy.y * color_specular.rgb / M_PI; + while (merged_mask != 0) { + uint bit = findMSB(merged_mask); + merged_mask &= ~(1 << bit); +#ifdef USE_SUBGROUPS + if (((1 << bit) & mask) == 0) { //do not process if not originally here + continue; + } +#endif - vec4 shadow_color_enabled = unpackUnorm4x8(lights.data[i].shadow_color_enabled); + //if (!bool(omni_lights.data[light_index].mask & draw_call.layer_mask)) { + // continue; //not masked + //} - if (shadow_color_enabled.a > 0.5) { - //has shadow - vec4 v = vec4(view_pos, 1.0); + uint light_index = 32 * i + bit; - vec4 splane = (lights.data[i].shadow_matrix * v); - splane /= splane.w; + vec3 light_pos = spot_lights.data[light_index].position; + vec3 light_rel_vec = spot_lights.data[light_index].position - view_pos; + float d = length(light_rel_vec); + float shadow_attenuation = 1.0; - float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r; - float shadow = exp(min(0.0, (depth - splane.z)) / lights.data[i].inv_radius * lights.data[i].shadow_volumetric_fog_fade); + if (d * spot_lights.data[light_index].inv_radius < 1.0) { + float attenuation = get_omni_attenuation(d, spot_lights.data[light_index].inv_radius, spot_lights.data[light_index].attenuation); - shadow_attenuation = mix(shadow_color_enabled.rgb, vec3(1.0), shadow); - } + vec3 spot_dir = spot_lights.data[light_index].direction; + float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights.data[light_index].cone_angle); + float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights.data[light_index].cone_angle)); + attenuation *= 1.0 - pow(spot_rim, spot_lights.data[light_index].cone_attenuation); + + vec3 light = spot_lights.data[light_index].color / M_PI; + + if (spot_lights.data[light_index].shadow_enabled) { + //has shadow + vec4 v = vec4(view_pos, 1.0); + + vec4 splane = (spot_lights.data[light_index].shadow_matrix * v); + splane /= splane.w; - total_light += light * attenuation * shadow_attenuation; + float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r; + + shadow_attenuation = exp(min(0.0, (depth - splane.z)) / spot_lights.data[light_index].inv_radius * spot_lights.data[light_index].shadow_volumetric_fog_fade); + } + + total_light += light * attenuation * shadow_attenuation; + } + } } } @@ -461,7 +629,11 @@ void main() { #endif - imageStore(density_map, pos, vec4(total_light, total_density)); + vec4 final_density = vec4(total_light, total_density); + + final_density = mix(final_density, reprojected_density, reproject_amount); + + imageStore(density_map, pos, final_density); #endif #ifdef MODE_FOG diff --git a/servers/rendering/renderer_scene.cpp b/servers/rendering/renderer_scene.cpp new file mode 100644 index 0000000000..dd544d4f3f --- /dev/null +++ b/servers/rendering/renderer_scene.cpp @@ -0,0 +1,37 @@ +/*************************************************************************/ +/* renderer_scene.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "renderer_scene.h" + +RendererScene::RendererScene() { +} + +RendererScene::~RendererScene() { +} diff --git a/servers/rendering/renderer_scene.h b/servers/rendering/renderer_scene.h new file mode 100644 index 0000000000..b546001843 --- /dev/null +++ b/servers/rendering/renderer_scene.h @@ -0,0 +1,212 @@ +/*************************************************************************/ +/* renderer_scene.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RENDERINGSERVERSCENE_H +#define RENDERINGSERVERSCENE_H + +#include "servers/rendering/renderer_compositor.h" +#include "servers/xr/xr_interface.h" + +class RendererScene { +public: + virtual RID camera_allocate() = 0; + virtual void camera_initialize(RID p_rid) = 0; + + virtual void camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far) = 0; + virtual void camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far) = 0; + virtual void camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far) = 0; + virtual void camera_set_transform(RID p_camera, const Transform &p_transform) = 0; + virtual void camera_set_cull_mask(RID p_camera, uint32_t p_layers) = 0; + virtual void camera_set_environment(RID p_camera, RID p_env) = 0; + virtual void camera_set_camera_effects(RID p_camera, RID p_fx) = 0; + virtual void camera_set_use_vertical_aspect(RID p_camera, bool p_enable) = 0; + virtual bool is_camera(RID p_camera) const = 0; + + virtual RID scenario_allocate() = 0; + virtual void scenario_initialize(RID p_rid) = 0; + + virtual void scenario_set_debug(RID p_scenario, RS::ScenarioDebugMode p_debug_mode) = 0; + virtual void scenario_set_environment(RID p_scenario, RID p_environment) = 0; + virtual void scenario_set_camera_effects(RID p_scenario, RID p_fx) = 0; + virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment) = 0; + virtual void scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count) = 0; + virtual bool is_scenario(RID p_scenario) const = 0; + virtual RID scenario_get_environment(RID p_scenario) = 0; + + virtual RID instance_allocate() = 0; + virtual void instance_initialize(RID p_rid) = 0; + + virtual void instance_set_base(RID p_instance, RID p_base) = 0; + virtual void instance_set_scenario(RID p_instance, RID p_scenario) = 0; + virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask) = 0; + virtual void instance_set_transform(RID p_instance, const Transform &p_transform) = 0; + virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id) = 0; + virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight) = 0; + virtual void instance_set_surface_material(RID p_instance, int p_surface, RID p_material) = 0; + virtual void instance_set_visible(RID p_instance, bool p_visible) = 0; + + virtual void instance_set_custom_aabb(RID p_instance, AABB p_aabb) = 0; + + virtual void instance_attach_skeleton(RID p_instance, RID p_skeleton) = 0; + virtual void instance_set_exterior(RID p_instance, bool p_enabled) = 0; + + virtual void instance_set_extra_visibility_margin(RID p_instance, real_t p_margin) = 0; + + // don't use these in a game! + virtual Vector<ObjectID> instances_cull_aabb(const AABB &p_aabb, RID p_scenario = RID()) const = 0; + virtual Vector<ObjectID> instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario = RID()) const = 0; + virtual Vector<ObjectID> instances_cull_convex(const Vector<Plane> &p_convex, RID p_scenario = RID()) const = 0; + + virtual void instance_geometry_set_flag(RID p_instance, RS::InstanceFlags p_flags, bool p_enabled) = 0; + virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, RS::ShadowCastingSetting p_shadow_casting_setting) = 0; + virtual void instance_geometry_set_material_override(RID p_instance, RID p_material) = 0; + + virtual void instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) = 0; + virtual void instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance) = 0; + virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index) = 0; + virtual void instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias) = 0; + + virtual void instance_geometry_set_shader_parameter(RID p_instance, const StringName &p_parameter, const Variant &p_value) = 0; + virtual void instance_geometry_get_shader_parameter_list(RID p_instance, List<PropertyInfo> *p_parameters) const = 0; + virtual Variant instance_geometry_get_shader_parameter(RID p_instance, const StringName &p_parameter) const = 0; + virtual Variant instance_geometry_get_shader_parameter_default_value(RID p_instance, const StringName &p_parameter) const = 0; + + virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = false) = 0; + + /* SKY API */ + + virtual RID sky_allocate() = 0; + virtual void sky_initialize(RID p_rid) = 0; + + virtual void sky_set_radiance_size(RID p_sky, int p_radiance_size) = 0; + virtual void sky_set_mode(RID p_sky, RS::SkyMode p_samples) = 0; + virtual void sky_set_material(RID p_sky, RID p_material) = 0; + virtual Ref<Image> sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) = 0; + + /* ENVIRONMENT API */ + + virtual RID environment_allocate() = 0; + virtual void environment_initialize(RID p_rid) = 0; + + virtual void environment_set_background(RID p_env, RS::EnvironmentBG p_bg) = 0; + virtual void environment_set_sky(RID p_env, RID p_sky) = 0; + virtual void environment_set_sky_custom_fov(RID p_env, float p_scale) = 0; + virtual void environment_set_sky_orientation(RID p_env, const Basis &p_orientation) = 0; + virtual void environment_set_bg_color(RID p_env, const Color &p_color) = 0; + virtual void environment_set_bg_energy(RID p_env, float p_energy) = 0; + virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer) = 0; + virtual void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG, const Color &p_ao_color = Color()) = 0; + + virtual void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) = 0; + virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) = 0; + virtual void environment_glow_set_use_high_quality(bool p_enable) = 0; + + virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) = 0; + + virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) = 0; + virtual void environment_set_volumetric_fog_filter_active(bool p_enable) = 0; + + virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) = 0; + virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) = 0; + + virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) = 0; + + virtual void 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) = 0; + + virtual void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) = 0; + + virtual void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) = 0; + virtual void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) = 0; + virtual void environment_set_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update) = 0; + + virtual void environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) = 0; + + virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) = 0; + + virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective) = 0; + + virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) = 0; + + virtual RS::EnvironmentBG environment_get_background(RID p_Env) const = 0; + virtual int environment_get_canvas_max_layer(RID p_env) const = 0; + + virtual bool is_environment(RID p_environment) const = 0; + + virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_limit) = 0; + virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) = 0; + virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) = 0; + + /* Camera Effects */ + + virtual RID camera_effects_allocate() = 0; + virtual void camera_effects_initialize(RID p_rid) = 0; + + virtual void camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) = 0; + virtual void camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) = 0; + + virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) = 0; + virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) = 0; + + virtual void shadows_quality_set(RS::ShadowQuality p_quality) = 0; + virtual void directional_shadow_quality_set(RS::ShadowQuality p_quality) = 0; + + virtual RID shadow_atlas_create() = 0; + virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_use_16_bits = false) = 0; + virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) = 0; + + /* Render Buffers */ + + virtual RID render_buffers_create() = 0; + + virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding) = 0; + + virtual void gi_set_use_half_resolution(bool p_enable) = 0; + + virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) = 0; + + virtual TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) = 0; + virtual void gi_probe_set_quality(RS::GIProbeQuality) = 0; + + virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) = 0; + + virtual void render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) = 0; + virtual void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_lod_threshold, RID p_shadow_atlas) = 0; + virtual void render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_lod_threshold, RID p_shadow_atlas) = 0; + + virtual void update() = 0; + virtual void render_probes() = 0; + + virtual bool free(RID p_rid) = 0; + + RendererScene(); + virtual ~RendererScene(); +}; + +#endif // RENDERINGSERVERSCENE_H diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp new file mode 100644 index 0000000000..e8155e4025 --- /dev/null +++ b/servers/rendering/renderer_scene_cull.cpp @@ -0,0 +1,3557 @@ +/*************************************************************************/ +/* renderer_scene_cull.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "renderer_scene_cull.h" + +#include "core/config/project_settings.h" +#include "core/os/os.h" +#include "rendering_server_default.h" +#include "rendering_server_globals.h" + +#include <new> + +/* CAMERA API */ + +RID RendererSceneCull::camera_allocate() { + return camera_owner.allocate_rid(); +} +void RendererSceneCull::camera_initialize(RID p_rid) { + camera_owner.initialize_rid(p_rid, memnew(Camera)); +} + +void RendererSceneCull::camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far) { + Camera *camera = camera_owner.getornull(p_camera); + ERR_FAIL_COND(!camera); + camera->type = Camera::PERSPECTIVE; + camera->fov = p_fovy_degrees; + camera->znear = p_z_near; + camera->zfar = p_z_far; +} + +void RendererSceneCull::camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far) { + Camera *camera = camera_owner.getornull(p_camera); + ERR_FAIL_COND(!camera); + camera->type = Camera::ORTHOGONAL; + camera->size = p_size; + camera->znear = p_z_near; + camera->zfar = p_z_far; +} + +void RendererSceneCull::camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far) { + Camera *camera = camera_owner.getornull(p_camera); + ERR_FAIL_COND(!camera); + camera->type = Camera::FRUSTUM; + camera->size = p_size; + camera->offset = p_offset; + camera->znear = p_z_near; + camera->zfar = p_z_far; +} + +void RendererSceneCull::camera_set_transform(RID p_camera, const Transform &p_transform) { + Camera *camera = camera_owner.getornull(p_camera); + ERR_FAIL_COND(!camera); + camera->transform = p_transform.orthonormalized(); +} + +void RendererSceneCull::camera_set_cull_mask(RID p_camera, uint32_t p_layers) { + Camera *camera = camera_owner.getornull(p_camera); + ERR_FAIL_COND(!camera); + + camera->visible_layers = p_layers; +} + +void RendererSceneCull::camera_set_environment(RID p_camera, RID p_env) { + Camera *camera = camera_owner.getornull(p_camera); + ERR_FAIL_COND(!camera); + camera->env = p_env; +} + +void RendererSceneCull::camera_set_camera_effects(RID p_camera, RID p_fx) { + Camera *camera = camera_owner.getornull(p_camera); + ERR_FAIL_COND(!camera); + camera->effects = p_fx; +} + +void RendererSceneCull::camera_set_use_vertical_aspect(RID p_camera, bool p_enable) { + Camera *camera = camera_owner.getornull(p_camera); + ERR_FAIL_COND(!camera); + camera->vaspect = p_enable; +} + +bool RendererSceneCull::is_camera(RID p_camera) const { + return camera_owner.owns(p_camera); +} + +/* SCENARIO API */ + +void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) { + RendererSceneCull *self = (RendererSceneCull *)singleton; + Instance *A = p_A; + Instance *B = p_B; + + //instance indices are designed so greater always contains lesser + if (A->base_type > B->base_type) { + SWAP(A, B); //lesser always first + } + + if (B->base_type == RS::INSTANCE_LIGHT && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + InstanceLightData *light = static_cast<InstanceLightData *>(B->base_data); + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); + + geom->lights.insert(B); + light->geometries.insert(A); + + if (geom->can_cast_shadows) { + light->shadow_dirty = true; + } + + if (A->scenario && A->array_index >= 0) { + InstanceData &idata = A->scenario->instance_data[A->array_index]; + idata.flags |= InstanceData::FLAG_GEOM_LIGHTING_DIRTY; + } + + } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && B->base_type == RS::INSTANCE_REFLECTION_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(B->base_data); + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); + + geom->reflection_probes.insert(B); + reflection_probe->geometries.insert(A); + + if (A->scenario && A->array_index >= 0) { + InstanceData &idata = A->scenario->instance_data[A->array_index]; + idata.flags |= InstanceData::FLAG_GEOM_REFLECTION_DIRTY; + } + + } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && B->base_type == RS::INSTANCE_DECAL && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + InstanceDecalData *decal = static_cast<InstanceDecalData *>(B->base_data); + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); + + geom->decals.insert(B); + decal->geometries.insert(A); + + if (A->scenario && A->array_index >= 0) { + InstanceData &idata = A->scenario->instance_data[A->array_index]; + idata.flags |= InstanceData::FLAG_GEOM_DECAL_DIRTY; + } + + } else if (B->base_type == RS::INSTANCE_LIGHTMAP && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(B->base_data); + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); + + if (A->dynamic_gi) { + geom->lightmap_captures.insert(A); + lightmap_data->geometries.insert(B); + + if (A->scenario && A->array_index >= 0) { + InstanceData &idata = A->scenario->instance_data[A->array_index]; + idata.flags |= InstanceData::FLAG_LIGHTMAP_CAPTURE; + } + ((RendererSceneCull *)self)->_instance_queue_update(A, false, false); //need to update capture + } + + } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_GI_PROBE) && B->base_type == RS::INSTANCE_GI_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data); + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); + + geom->gi_probes.insert(B); + + if (A->dynamic_gi) { + gi_probe->dynamic_geometries.insert(A); + } else { + gi_probe->geometries.insert(A); + } + + if (A->scenario && A->array_index >= 0) { + InstanceData &idata = A->scenario->instance_data[A->array_index]; + idata.flags |= InstanceData::FLAG_GEOM_GI_PROBE_DIRTY; + } + + } else if (B->base_type == RS::INSTANCE_GI_PROBE && A->base_type == RS::INSTANCE_LIGHT) { + InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data); + gi_probe->lights.insert(A); + } else if (B->base_type == RS::INSTANCE_PARTICLES_COLLISION && A->base_type == RS::INSTANCE_PARTICLES) { + InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(B->base_data); + RSG::storage->particles_add_collision(A->base, collision->instance); + } +} + +void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_B) { + RendererSceneCull *self = (RendererSceneCull *)singleton; + Instance *A = p_A; + Instance *B = p_B; + + //instance indices are designed so greater always contains lesser + if (A->base_type > B->base_type) { + SWAP(A, B); //lesser always first + } + + if (B->base_type == RS::INSTANCE_LIGHT && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + InstanceLightData *light = static_cast<InstanceLightData *>(B->base_data); + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); + + geom->lights.erase(B); + light->geometries.erase(A); + + if (geom->can_cast_shadows) { + light->shadow_dirty = true; + } + + if (A->scenario && A->array_index >= 0) { + InstanceData &idata = A->scenario->instance_data[A->array_index]; + idata.flags |= InstanceData::FLAG_GEOM_LIGHTING_DIRTY; + } + + } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && B->base_type == RS::INSTANCE_REFLECTION_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(B->base_data); + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); + + geom->reflection_probes.erase(B); + reflection_probe->geometries.erase(A); + + if (A->scenario && A->array_index >= 0) { + InstanceData &idata = A->scenario->instance_data[A->array_index]; + idata.flags |= InstanceData::FLAG_GEOM_REFLECTION_DIRTY; + } + + } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && B->base_type == RS::INSTANCE_DECAL && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + InstanceDecalData *decal = static_cast<InstanceDecalData *>(B->base_data); + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); + + geom->decals.erase(B); + decal->geometries.erase(A); + + if (A->scenario && A->array_index >= 0) { + InstanceData &idata = A->scenario->instance_data[A->array_index]; + idata.flags |= InstanceData::FLAG_GEOM_DECAL_DIRTY; + } + + } else if (B->base_type == RS::INSTANCE_LIGHTMAP && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(B->base_data); + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); + if (A->dynamic_gi) { + geom->lightmap_captures.erase(B); + + if (geom->lightmap_captures.is_empty() && A->scenario && A->array_index >= 0) { + InstanceData &idata = A->scenario->instance_data[A->array_index]; + idata.flags &= ~uint32_t(InstanceData::FLAG_LIGHTMAP_CAPTURE); + } + + lightmap_data->geometries.erase(A); + ((RendererSceneCull *)self)->_instance_queue_update(A, false, false); //need to update capture + } + + } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_GI_PROBE) && B->base_type == RS::INSTANCE_GI_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data); + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); + + geom->gi_probes.erase(B); + if (A->dynamic_gi) { + gi_probe->dynamic_geometries.erase(A); + } else { + gi_probe->geometries.erase(A); + } + + if (A->scenario && A->array_index >= 0) { + InstanceData &idata = A->scenario->instance_data[A->array_index]; + idata.flags |= InstanceData::FLAG_GEOM_GI_PROBE_DIRTY; + } + + } else if (B->base_type == RS::INSTANCE_GI_PROBE && A->base_type == RS::INSTANCE_LIGHT) { + InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data); + gi_probe->lights.erase(A); + } else if (B->base_type == RS::INSTANCE_PARTICLES_COLLISION && A->base_type == RS::INSTANCE_PARTICLES) { + InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(B->base_data); + RSG::storage->particles_remove_collision(A->base, collision->instance); + } +} + +RID RendererSceneCull::scenario_allocate() { + return scenario_owner.allocate_rid(); +} +void RendererSceneCull::scenario_initialize(RID p_rid) { + Scenario *scenario = memnew(Scenario); + scenario->self = p_rid; + + scenario->reflection_probe_shadow_atlas = scene_render->shadow_atlas_create(); + scene_render->shadow_atlas_set_size(scenario->reflection_probe_shadow_atlas, 1024); //make enough shadows for close distance, don't bother with rest + scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 0, 4); + scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 1, 4); + scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 2, 4); + scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 3, 8); + scenario->reflection_atlas = scene_render->reflection_atlas_create(); + + scenario->instance_aabbs.set_page_pool(&instance_aabb_page_pool); + scenario->instance_data.set_page_pool(&instance_data_page_pool); + + scenario_owner.initialize_rid(p_rid, scenario); +} + +void RendererSceneCull::scenario_set_debug(RID p_scenario, RS::ScenarioDebugMode p_debug_mode) { + Scenario *scenario = scenario_owner.getornull(p_scenario); + ERR_FAIL_COND(!scenario); + scenario->debug = p_debug_mode; +} + +void RendererSceneCull::scenario_set_environment(RID p_scenario, RID p_environment) { + Scenario *scenario = scenario_owner.getornull(p_scenario); + ERR_FAIL_COND(!scenario); + scenario->environment = p_environment; +} + +void RendererSceneCull::scenario_set_camera_effects(RID p_scenario, RID p_camera_effects) { + Scenario *scenario = scenario_owner.getornull(p_scenario); + ERR_FAIL_COND(!scenario); + scenario->camera_effects = p_camera_effects; +} + +void RendererSceneCull::scenario_set_fallback_environment(RID p_scenario, RID p_environment) { + Scenario *scenario = scenario_owner.getornull(p_scenario); + ERR_FAIL_COND(!scenario); + scenario->fallback_environment = p_environment; +} + +void RendererSceneCull::scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count) { + Scenario *scenario = scenario_owner.getornull(p_scenario); + ERR_FAIL_COND(!scenario); + scene_render->reflection_atlas_set_size(scenario->reflection_atlas, p_reflection_size, p_reflection_count); +} + +bool RendererSceneCull::is_scenario(RID p_scenario) const { + return scenario_owner.owns(p_scenario); +} + +RID RendererSceneCull::scenario_get_environment(RID p_scenario) { + Scenario *scenario = scenario_owner.getornull(p_scenario); + ERR_FAIL_COND_V(!scenario, RID()); + return scenario->environment; +} + +/* INSTANCING API */ + +void RendererSceneCull::_instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_dependencies) { + if (p_update_aabb) { + p_instance->update_aabb = true; + } + if (p_update_dependencies) { + p_instance->update_dependencies = true; + } + + if (p_instance->update_item.in_list()) { + return; + } + + _instance_update_list.add(&p_instance->update_item); +} + +RID RendererSceneCull::instance_allocate() { + return instance_owner.allocate_rid(); +} +void RendererSceneCull::instance_initialize(RID p_rid) { + Instance *instance = memnew(Instance); + instance->self = p_rid; + + instance_owner.initialize_rid(p_rid, instance); +} + +void RendererSceneCull::_instance_update_mesh_instance(Instance *p_instance) { + bool needs_instance = RSG::storage->mesh_needs_instance(p_instance->base, p_instance->skeleton.is_valid()); + if (needs_instance != p_instance->mesh_instance.is_valid()) { + if (needs_instance) { + p_instance->mesh_instance = RSG::storage->mesh_instance_create(p_instance->base); + + } else { + RSG::storage->free(p_instance->mesh_instance); + p_instance->mesh_instance = RID(); + } + + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); + scene_render->geometry_instance_set_mesh_instance(geom->geometry_instance, p_instance->mesh_instance); + + if (p_instance->scenario && p_instance->array_index >= 0) { + InstanceData &idata = p_instance->scenario->instance_data[p_instance->array_index]; + if (p_instance->mesh_instance.is_valid()) { + idata.flags |= InstanceData::FLAG_USES_MESH_INSTANCE; + } else { + idata.flags &= ~uint32_t(InstanceData::FLAG_USES_MESH_INSTANCE); + } + } + } + + if (p_instance->mesh_instance.is_valid()) { + RSG::storage->mesh_instance_set_skeleton(p_instance->mesh_instance, p_instance->skeleton); + } +} + +void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + Scenario *scenario = instance->scenario; + + if (instance->base_type != RS::INSTANCE_NONE) { + //free anything related to that base + + if (scenario && instance->indexer_id.is_valid()) { + _unpair_instance(instance); + } + + if (instance->mesh_instance.is_valid()) { + RSG::storage->free(instance->mesh_instance); + instance->mesh_instance = RID(); + // no need to set instance data flag here, as it was freed above + } + + switch (instance->base_type) { + case RS::INSTANCE_MESH: + case RS::INSTANCE_MULTIMESH: + case RS::INSTANCE_IMMEDIATE: + case RS::INSTANCE_PARTICLES: { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_free(geom->geometry_instance); + } break; + case RS::INSTANCE_LIGHT: { + InstanceLightData *light = static_cast<InstanceLightData *>(instance->base_data); + + if (scenario && instance->visible && RSG::storage->light_get_type(instance->base) != RS::LIGHT_DIRECTIONAL && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) { + scenario->dynamic_lights.erase(light->instance); + } + +#ifdef DEBUG_ENABLED + if (light->geometries.size()) { + ERR_PRINT("BUG, indexing did not unpair geometries from light."); + } +#endif + if (scenario && light->D) { + scenario->directional_lights.erase(light->D); + light->D = nullptr; + } + scene_render->free(light->instance); + } break; + case RS::INSTANCE_PARTICLES_COLLISION: { + InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(instance->base_data); + RSG::storage->free(collision->instance); + } break; + case RS::INSTANCE_REFLECTION_PROBE: { + InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(instance->base_data); + scene_render->free(reflection_probe->instance); + if (reflection_probe->update_list.in_list()) { + reflection_probe_render_list.remove(&reflection_probe->update_list); + } + } break; + case RS::INSTANCE_DECAL: { + InstanceDecalData *decal = static_cast<InstanceDecalData *>(instance->base_data); + scene_render->free(decal->instance); + + } break; + case RS::INSTANCE_LIGHTMAP: { + InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(instance->base_data); + //erase dependencies, since no longer a lightmap + while (lightmap_data->users.front()) { + instance_geometry_set_lightmap(lightmap_data->users.front()->get()->self, RID(), Rect2(), 0); + } + scene_render->free(lightmap_data->instance); + } break; + case RS::INSTANCE_GI_PROBE: { + InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data); +#ifdef DEBUG_ENABLED + if (gi_probe->geometries.size()) { + ERR_PRINT("BUG, indexing did not unpair geometries from GIProbe."); + } +#endif +#ifdef DEBUG_ENABLED + if (gi_probe->lights.size()) { + ERR_PRINT("BUG, indexing did not unpair lights from GIProbe."); + } +#endif + if (gi_probe->update_element.in_list()) { + gi_probe_update_list.remove(&gi_probe->update_element); + } + + scene_render->free(gi_probe->probe_instance); + + } break; + default: { + } + } + + if (instance->base_data) { + memdelete(instance->base_data); + instance->base_data = nullptr; + } + + instance->materials.clear(); + } + + instance->base_type = RS::INSTANCE_NONE; + instance->base = RID(); + + if (p_base.is_valid()) { + instance->base_type = RSG::storage->get_base_type(p_base); + ERR_FAIL_COND(instance->base_type == RS::INSTANCE_NONE); + + switch (instance->base_type) { + case RS::INSTANCE_LIGHT: { + InstanceLightData *light = memnew(InstanceLightData); + + if (scenario && RSG::storage->light_get_type(p_base) == RS::LIGHT_DIRECTIONAL) { + light->D = scenario->directional_lights.push_back(instance); + } + + light->instance = scene_render->light_instance_create(p_base); + + instance->base_data = light; + } break; + case RS::INSTANCE_MESH: + case RS::INSTANCE_MULTIMESH: + case RS::INSTANCE_IMMEDIATE: + case RS::INSTANCE_PARTICLES: { + InstanceGeometryData *geom = memnew(InstanceGeometryData); + instance->base_data = geom; + geom->geometry_instance = scene_render->geometry_instance_create(p_base); + + scene_render->geometry_instance_set_skeleton(geom->geometry_instance, instance->skeleton); + scene_render->geometry_instance_set_material_override(geom->geometry_instance, instance->material_override); + scene_render->geometry_instance_set_surface_materials(geom->geometry_instance, instance->materials); + scene_render->geometry_instance_set_transform(geom->geometry_instance, instance->transform, instance->aabb, instance->transformed_aabb); + scene_render->geometry_instance_set_layer_mask(geom->geometry_instance, instance->layer_mask); + scene_render->geometry_instance_set_lod_bias(geom->geometry_instance, instance->lod_bias); + scene_render->geometry_instance_set_use_baked_light(geom->geometry_instance, instance->baked_light); + scene_render->geometry_instance_set_use_dynamic_gi(geom->geometry_instance, instance->dynamic_gi); + scene_render->geometry_instance_set_cast_double_sided_shadows(geom->geometry_instance, instance->cast_shadows == RS::SHADOW_CASTING_SETTING_DOUBLE_SIDED); + scene_render->geometry_instance_set_use_lightmap(geom->geometry_instance, RID(), instance->lightmap_uv_scale, instance->lightmap_slice_index); + if (instance->lightmap_sh.size() == 9) { + scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, instance->lightmap_sh.ptr()); + } + + } break; + case RS::INSTANCE_PARTICLES_COLLISION: { + InstanceParticlesCollisionData *collision = memnew(InstanceParticlesCollisionData); + collision->instance = RSG::storage->particles_collision_instance_create(p_base); + RSG::storage->particles_collision_instance_set_active(collision->instance, instance->visible); + instance->base_data = collision; + } break; + case RS::INSTANCE_REFLECTION_PROBE: { + InstanceReflectionProbeData *reflection_probe = memnew(InstanceReflectionProbeData); + reflection_probe->owner = instance; + instance->base_data = reflection_probe; + + reflection_probe->instance = scene_render->reflection_probe_instance_create(p_base); + } break; + case RS::INSTANCE_DECAL: { + InstanceDecalData *decal = memnew(InstanceDecalData); + decal->owner = instance; + instance->base_data = decal; + + decal->instance = scene_render->decal_instance_create(p_base); + } break; + case RS::INSTANCE_LIGHTMAP: { + InstanceLightmapData *lightmap_data = memnew(InstanceLightmapData); + instance->base_data = lightmap_data; + lightmap_data->instance = scene_render->lightmap_instance_create(p_base); + } break; + case RS::INSTANCE_GI_PROBE: { + InstanceGIProbeData *gi_probe = memnew(InstanceGIProbeData); + instance->base_data = gi_probe; + gi_probe->owner = instance; + + if (scenario && !gi_probe->update_element.in_list()) { + gi_probe_update_list.add(&gi_probe->update_element); + } + + gi_probe->probe_instance = scene_render->gi_probe_instance_create(p_base); + + } break; + default: { + } + } + + instance->base = p_base; + + if (instance->base_type == RS::INSTANCE_MESH) { + _instance_update_mesh_instance(instance); + } + + //forcefully update the dependency now, so if for some reason it gets removed, we can immediately clear it + RSG::storage->base_update_dependency(p_base, &instance->dependency_tracker); + } + + _instance_queue_update(instance, true, true); +} + +void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + if (instance->scenario) { + instance->scenario->instances.remove(&instance->scenario_item); + + if (instance->indexer_id.is_valid()) { + _unpair_instance(instance); + } + + switch (instance->base_type) { + case RS::INSTANCE_LIGHT: { + InstanceLightData *light = static_cast<InstanceLightData *>(instance->base_data); +#ifdef DEBUG_ENABLED + if (light->geometries.size()) { + ERR_PRINT("BUG, indexing did not unpair geometries from light."); + } +#endif + if (light->D) { + instance->scenario->directional_lights.erase(light->D); + light->D = nullptr; + } + } break; + case RS::INSTANCE_REFLECTION_PROBE: { + InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(instance->base_data); + scene_render->reflection_probe_release_atlas_index(reflection_probe->instance); + + } break; + case RS::INSTANCE_PARTICLES_COLLISION: { + heightfield_particle_colliders_update_list.erase(instance); + } break; + case RS::INSTANCE_GI_PROBE: { + InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data); + +#ifdef DEBUG_ENABLED + if (gi_probe->geometries.size()) { + ERR_PRINT("BUG, indexing did not unpair geometries from GIProbe."); + } +#endif +#ifdef DEBUG_ENABLED + if (gi_probe->lights.size()) { + ERR_PRINT("BUG, indexing did not unpair lights from GIProbe."); + } +#endif + + if (gi_probe->update_element.in_list()) { + gi_probe_update_list.remove(&gi_probe->update_element); + } + } break; + default: { + } + } + + instance->scenario = nullptr; + } + + if (p_scenario.is_valid()) { + Scenario *scenario = scenario_owner.getornull(p_scenario); + ERR_FAIL_COND(!scenario); + + instance->scenario = scenario; + + scenario->instances.add(&instance->scenario_item); + + switch (instance->base_type) { + case RS::INSTANCE_LIGHT: { + InstanceLightData *light = static_cast<InstanceLightData *>(instance->base_data); + + if (RSG::storage->light_get_type(instance->base) == RS::LIGHT_DIRECTIONAL) { + light->D = scenario->directional_lights.push_back(instance); + } + } break; + case RS::INSTANCE_GI_PROBE: { + InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data); + if (!gi_probe->update_element.in_list()) { + gi_probe_update_list.add(&gi_probe->update_element); + } + } break; + default: { + } + } + + _instance_queue_update(instance, true, true); + } +} + +void RendererSceneCull::instance_set_layer_mask(RID p_instance, uint32_t p_mask) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + instance->layer_mask = p_mask; + if (instance->scenario && instance->array_index >= 0) { + instance->scenario->instance_data[instance->array_index].layer_mask = p_mask; + } + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_set_layer_mask(geom->geometry_instance, p_mask); + } +} + +void RendererSceneCull::instance_set_transform(RID p_instance, const Transform &p_transform) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + if (instance->transform == p_transform) { + return; //must be checked to avoid worst evil + } + +#ifdef DEBUG_ENABLED + + for (int i = 0; i < 4; i++) { + const Vector3 &v = i < 3 ? p_transform.basis.elements[i] : p_transform.origin; + ERR_FAIL_COND(Math::is_inf(v.x)); + ERR_FAIL_COND(Math::is_nan(v.x)); + ERR_FAIL_COND(Math::is_inf(v.y)); + ERR_FAIL_COND(Math::is_nan(v.y)); + ERR_FAIL_COND(Math::is_inf(v.z)); + ERR_FAIL_COND(Math::is_nan(v.z)); + } + +#endif + instance->transform = p_transform; + _instance_queue_update(instance, true); +} + +void RendererSceneCull::instance_attach_object_instance_id(RID p_instance, ObjectID p_id) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + instance->object_id = p_id; +} + +void RendererSceneCull::instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + if (instance->update_item.in_list()) { + _update_dirty_instance(instance); + } + + if (instance->mesh_instance.is_valid()) { + RSG::storage->mesh_instance_set_blend_shape_weight(instance->mesh_instance, p_shape, p_weight); + } +} + +void RendererSceneCull::instance_set_surface_material(RID p_instance, int p_surface, RID p_material) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + if (instance->base_type == RS::INSTANCE_MESH) { + //may not have been updated yet, may also have not been set yet. When updated will be correcte, worst case + instance->materials.resize(MAX(p_surface + 1, RSG::storage->mesh_get_surface_count(instance->base))); + } + + ERR_FAIL_INDEX(p_surface, instance->materials.size()); + + instance->materials.write[p_surface] = p_material; + + _instance_queue_update(instance, false, true); +} + +void RendererSceneCull::instance_set_visible(RID p_instance, bool p_visible) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + if (instance->visible == p_visible) { + return; + } + + instance->visible = p_visible; + + if (p_visible) { + if (instance->scenario != nullptr) { + _instance_queue_update(instance, true, false); + } + } else if (instance->indexer_id.is_valid()) { + _unpair_instance(instance); + } + + if (instance->base_type == RS::INSTANCE_LIGHT) { + InstanceLightData *light = static_cast<InstanceLightData *>(instance->base_data); + if (instance->scenario && RSG::storage->light_get_type(instance->base) != RS::LIGHT_DIRECTIONAL && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) { + if (p_visible) { + instance->scenario->dynamic_lights.push_back(light->instance); + } else { + instance->scenario->dynamic_lights.erase(light->instance); + } + } + } + + if (instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) { + InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(instance->base_data); + RSG::storage->particles_collision_instance_set_active(collision->instance, p_visible); + } +} + +inline bool is_geometry_instance(RenderingServer::InstanceType p_type) { + return p_type == RS::INSTANCE_MESH || p_type == RS::INSTANCE_MULTIMESH || p_type == RS::INSTANCE_PARTICLES || p_type == RS::INSTANCE_IMMEDIATE; +} + +void RendererSceneCull::instance_set_custom_aabb(RID p_instance, AABB p_aabb) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + ERR_FAIL_COND(!is_geometry_instance(instance->base_type)); + + if (p_aabb != AABB()) { + // Set custom AABB + if (instance->custom_aabb == nullptr) { + instance->custom_aabb = memnew(AABB); + } + *instance->custom_aabb = p_aabb; + + } else { + // Clear custom AABB + if (instance->custom_aabb != nullptr) { + memdelete(instance->custom_aabb); + instance->custom_aabb = nullptr; + } + } + + if (instance->scenario) { + _instance_queue_update(instance, true, false); + } +} + +void RendererSceneCull::instance_attach_skeleton(RID p_instance, RID p_skeleton) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + if (instance->skeleton == p_skeleton) { + return; + } + + instance->skeleton = p_skeleton; + + if (p_skeleton.is_valid()) { + //update the dependency now, so if cleared, we remove it + RSG::storage->skeleton_update_dependency(p_skeleton, &instance->dependency_tracker); + } + + _instance_queue_update(instance, true, true); + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + _instance_update_mesh_instance(instance); + + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_set_skeleton(geom->geometry_instance, p_skeleton); + } +} + +void RendererSceneCull::instance_set_exterior(RID p_instance, bool p_enabled) { +} + +void RendererSceneCull::instance_set_extra_visibility_margin(RID p_instance, real_t p_margin) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + instance->extra_margin = p_margin; + _instance_queue_update(instance, true, false); +} + +Vector<ObjectID> RendererSceneCull::instances_cull_aabb(const AABB &p_aabb, RID p_scenario) const { + Vector<ObjectID> instances; + Scenario *scenario = scenario_owner.getornull(p_scenario); + ERR_FAIL_COND_V(!scenario, instances); + + const_cast<RendererSceneCull *>(this)->update_dirty_instances(); // check dirty instances before culling + + struct CullAABB { + Vector<ObjectID> instances; + _FORCE_INLINE_ bool operator()(void *p_data) { + Instance *p_instance = (Instance *)p_data; + if (!p_instance->object_id.is_null()) { + instances.push_back(p_instance->object_id); + } + return false; + } + }; + + CullAABB cull_aabb; + scenario->indexers[Scenario::INDEXER_GEOMETRY].aabb_query(p_aabb, cull_aabb); + scenario->indexers[Scenario::INDEXER_VOLUMES].aabb_query(p_aabb, cull_aabb); + return cull_aabb.instances; +} + +Vector<ObjectID> RendererSceneCull::instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario) const { + Vector<ObjectID> instances; + Scenario *scenario = scenario_owner.getornull(p_scenario); + ERR_FAIL_COND_V(!scenario, instances); + const_cast<RendererSceneCull *>(this)->update_dirty_instances(); // check dirty instances before culling + + struct CullRay { + Vector<ObjectID> instances; + _FORCE_INLINE_ bool operator()(void *p_data) { + Instance *p_instance = (Instance *)p_data; + if (!p_instance->object_id.is_null()) { + instances.push_back(p_instance->object_id); + } + return false; + } + }; + + CullRay cull_ray; + scenario->indexers[Scenario::INDEXER_GEOMETRY].ray_query(p_from, p_to, cull_ray); + scenario->indexers[Scenario::INDEXER_VOLUMES].ray_query(p_from, p_to, cull_ray); + return cull_ray.instances; +} + +Vector<ObjectID> RendererSceneCull::instances_cull_convex(const Vector<Plane> &p_convex, RID p_scenario) const { + Vector<ObjectID> instances; + Scenario *scenario = scenario_owner.getornull(p_scenario); + ERR_FAIL_COND_V(!scenario, instances); + const_cast<RendererSceneCull *>(this)->update_dirty_instances(); // check dirty instances before culling + + Vector<Vector3> points = Geometry3D::compute_convex_mesh_points(&p_convex[0], p_convex.size()); + + struct CullConvex { + Vector<ObjectID> instances; + _FORCE_INLINE_ bool operator()(void *p_data) { + Instance *p_instance = (Instance *)p_data; + if (!p_instance->object_id.is_null()) { + instances.push_back(p_instance->object_id); + } + return false; + } + }; + + CullConvex cull_convex; + scenario->indexers[Scenario::INDEXER_GEOMETRY].convex_query(p_convex.ptr(), p_convex.size(), points.ptr(), points.size(), cull_convex); + scenario->indexers[Scenario::INDEXER_VOLUMES].convex_query(p_convex.ptr(), p_convex.size(), points.ptr(), points.size(), cull_convex); + return cull_convex.instances; +} + +void RendererSceneCull::instance_geometry_set_flag(RID p_instance, RS::InstanceFlags p_flags, bool p_enabled) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + //ERR_FAIL_COND(((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK)); + + switch (p_flags) { + case RS::INSTANCE_FLAG_USE_BAKED_LIGHT: { + instance->baked_light = p_enabled; + + if (instance->scenario && instance->array_index >= 0) { + InstanceData &idata = instance->scenario->instance_data[instance->array_index]; + if (instance->baked_light) { + idata.flags |= InstanceData::FLAG_USES_BAKED_LIGHT; + } else { + idata.flags &= ~uint32_t(InstanceData::FLAG_USES_BAKED_LIGHT); + } + } + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_set_use_baked_light(geom->geometry_instance, p_enabled); + } + + } break; + case RS::INSTANCE_FLAG_USE_DYNAMIC_GI: { + if (p_enabled == instance->dynamic_gi) { + //bye, redundant + return; + } + + if (instance->indexer_id.is_valid()) { + _unpair_instance(instance); + _instance_queue_update(instance, true, true); + } + + //once out of octree, can be changed + instance->dynamic_gi = p_enabled; + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_set_use_dynamic_gi(geom->geometry_instance, p_enabled); + } + + } break; + case RS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE: { + instance->redraw_if_visible = p_enabled; + + if (instance->scenario && instance->array_index >= 0) { + InstanceData &idata = instance->scenario->instance_data[instance->array_index]; + if (instance->redraw_if_visible) { + idata.flags |= InstanceData::FLAG_REDRAW_IF_VISIBLE; + } else { + idata.flags &= ~uint32_t(InstanceData::FLAG_REDRAW_IF_VISIBLE); + } + } + + } break; + default: { + } + } +} + +void RendererSceneCull::instance_geometry_set_cast_shadows_setting(RID p_instance, RS::ShadowCastingSetting p_shadow_casting_setting) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + instance->cast_shadows = p_shadow_casting_setting; + + if (instance->scenario && instance->array_index >= 0) { + InstanceData &idata = instance->scenario->instance_data[instance->array_index]; + + if (instance->cast_shadows != RS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) { + idata.flags |= InstanceData::FLAG_CAST_SHADOWS; + } else { + idata.flags &= ~uint32_t(InstanceData::FLAG_CAST_SHADOWS); + } + + if (instance->cast_shadows == RS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) { + idata.flags |= InstanceData::FLAG_CAST_SHADOWS_ONLY; + } else { + idata.flags &= ~uint32_t(InstanceData::FLAG_CAST_SHADOWS_ONLY); + } + } + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_set_cast_double_sided_shadows(geom->geometry_instance, instance->cast_shadows == RS::SHADOW_CASTING_SETTING_DOUBLE_SIDED); + } + + _instance_queue_update(instance, false, true); +} + +void RendererSceneCull::instance_geometry_set_material_override(RID p_instance, RID p_material) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + instance->material_override = p_material; + _instance_queue_update(instance, false, true); + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_set_material_override(geom->geometry_instance, p_material); + } +} + +void RendererSceneCull::instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) { +} + +void RendererSceneCull::instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance) { +} + +void RendererSceneCull::instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + if (instance->lightmap) { + InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(((Instance *)instance->lightmap)->base_data); + lightmap_data->users.erase(instance); + instance->lightmap = nullptr; + } + + Instance *lightmap_instance = instance_owner.getornull(p_lightmap); + + instance->lightmap = lightmap_instance; + instance->lightmap_uv_scale = p_lightmap_uv_scale; + instance->lightmap_slice_index = p_slice_index; + + RID lightmap_instance_rid; + + if (lightmap_instance) { + InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(lightmap_instance->base_data); + lightmap_data->users.insert(instance); + lightmap_instance_rid = lightmap_data->instance; + } + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_set_use_lightmap(geom->geometry_instance, lightmap_instance_rid, p_lightmap_uv_scale, p_slice_index); + } +} + +void RendererSceneCull::instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + instance->lod_bias = p_lod_bias; + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_set_lod_bias(geom->geometry_instance, p_lod_bias); + } +} + +void RendererSceneCull::instance_geometry_set_shader_parameter(RID p_instance, const StringName &p_parameter, const Variant &p_value) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + Map<StringName, Instance::InstanceShaderParameter>::Element *E = instance->instance_shader_parameters.find(p_parameter); + + if (!E) { + Instance::InstanceShaderParameter isp; + isp.index = -1; + isp.info = PropertyInfo(); + isp.value = p_value; + instance->instance_shader_parameters[p_parameter] = isp; + } else { + E->get().value = p_value; + if (E->get().index >= 0 && instance->instance_allocated_shader_parameters) { + //update directly + RSG::storage->global_variables_instance_update(p_instance, E->get().index, p_value); + } + } +} + +Variant RendererSceneCull::instance_geometry_get_shader_parameter(RID p_instance, const StringName &p_parameter) const { + const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!instance, Variant()); + + if (instance->instance_shader_parameters.has(p_parameter)) { + return instance->instance_shader_parameters[p_parameter].value; + } + return Variant(); +} + +Variant RendererSceneCull::instance_geometry_get_shader_parameter_default_value(RID p_instance, const StringName &p_parameter) const { + const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!instance, Variant()); + + if (instance->instance_shader_parameters.has(p_parameter)) { + return instance->instance_shader_parameters[p_parameter].default_value; + } + return Variant(); +} + +void RendererSceneCull::instance_geometry_get_shader_parameter_list(RID p_instance, List<PropertyInfo> *p_parameters) const { + const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + const_cast<RendererSceneCull *>(this)->update_dirty_instances(); + + Vector<StringName> names; + for (Map<StringName, Instance::InstanceShaderParameter>::Element *E = instance->instance_shader_parameters.front(); E; E = E->next()) { + names.push_back(E->key()); + } + names.sort_custom<StringName::AlphCompare>(); + for (int i = 0; i < names.size(); i++) { + PropertyInfo pinfo = instance->instance_shader_parameters[names[i]].info; + p_parameters->push_back(pinfo); + } +} + +void RendererSceneCull::_update_instance(Instance *p_instance) { + p_instance->version++; + + if (p_instance->base_type == RS::INSTANCE_LIGHT) { + InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data); + + scene_render->light_instance_set_transform(light->instance, p_instance->transform); + scene_render->light_instance_set_aabb(light->instance, p_instance->transform.xform(p_instance->aabb)); + light->shadow_dirty = true; + + RS::LightBakeMode bake_mode = RSG::storage->light_get_bake_mode(p_instance->base); + if (RSG::storage->light_get_type(p_instance->base) != RS::LIGHT_DIRECTIONAL && bake_mode != light->bake_mode) { + if (p_instance->visible && p_instance->scenario && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) { + p_instance->scenario->dynamic_lights.erase(light->instance); + } + + light->bake_mode = bake_mode; + + if (p_instance->visible && p_instance->scenario && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) { + p_instance->scenario->dynamic_lights.push_back(light->instance); + } + } + + uint32_t max_sdfgi_cascade = RSG::storage->light_get_max_sdfgi_cascade(p_instance->base); + if (light->max_sdfgi_cascade != max_sdfgi_cascade) { + light->max_sdfgi_cascade = max_sdfgi_cascade; //should most likely make sdfgi dirty in scenario + } + } else if (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE) { + InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(p_instance->base_data); + + scene_render->reflection_probe_instance_set_transform(reflection_probe->instance, p_instance->transform); + + if (p_instance->scenario && p_instance->array_index >= 0) { + InstanceData &idata = p_instance->scenario->instance_data[p_instance->array_index]; + idata.flags |= InstanceData::FLAG_REFLECTION_PROBE_DIRTY; + } + } else if (p_instance->base_type == RS::INSTANCE_DECAL) { + InstanceDecalData *decal = static_cast<InstanceDecalData *>(p_instance->base_data); + + scene_render->decal_instance_set_transform(decal->instance, p_instance->transform); + } else if (p_instance->base_type == RS::INSTANCE_LIGHTMAP) { + InstanceLightmapData *lightmap = static_cast<InstanceLightmapData *>(p_instance->base_data); + + scene_render->lightmap_instance_set_transform(lightmap->instance, p_instance->transform); + } else if (p_instance->base_type == RS::INSTANCE_GI_PROBE) { + InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(p_instance->base_data); + + scene_render->gi_probe_instance_set_transform_to_data(gi_probe->probe_instance, p_instance->transform); + } else if (p_instance->base_type == RS::INSTANCE_PARTICLES) { + RSG::storage->particles_set_emission_transform(p_instance->base, p_instance->transform); + } else if (p_instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) { + InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(p_instance->base_data); + + //remove materials no longer used and un-own them + if (RSG::storage->particles_collision_is_heightfield(p_instance->base)) { + heightfield_particle_colliders_update_list.insert(p_instance); + } + RSG::storage->particles_collision_instance_set_transform(collision->instance, p_instance->transform); + } + + if (p_instance->aabb.has_no_surface()) { + return; + } + + if (p_instance->base_type == RS::INSTANCE_LIGHTMAP) { + //if this moved, update the captured objects + InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(p_instance->base_data); + //erase dependencies, since no longer a lightmap + + for (Set<Instance *>::Element *E = lightmap_data->geometries.front(); E; E = E->next()) { + Instance *geom = E->get(); + _instance_queue_update(geom, true, false); + } + } + + AABB new_aabb; + new_aabb = p_instance->transform.xform(p_instance->aabb); + p_instance->transformed_aabb = new_aabb; + + if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); + //make sure lights are updated if it casts shadow + + if (geom->can_cast_shadows) { + for (Set<Instance *>::Element *E = geom->lights.front(); E; E = E->next()) { + InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data); + light->shadow_dirty = true; + } + } + + if (!p_instance->lightmap && geom->lightmap_captures.size()) { + //affected by lightmap captures, must update capture info! + _update_instance_lightmap_captures(p_instance); + } else { + if (!p_instance->lightmap_sh.is_empty()) { + p_instance->lightmap_sh.clear(); //don't need SH + p_instance->lightmap_target_sh.clear(); //don't need SH + scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, nullptr); + } + } + + scene_render->geometry_instance_set_transform(geom->geometry_instance, p_instance->transform, p_instance->aabb, p_instance->transformed_aabb); + } + + // note: we had to remove is equal approx check here, it meant that det == 0.000004 won't work, which is the case for some of our scenes. + if (p_instance->scenario == nullptr || !p_instance->visible || p_instance->transform.basis.determinant() == 0) { + p_instance->prev_transformed_aabb = p_instance->transformed_aabb; + return; + } + + //quantize to improve moving object performance + AABB bvh_aabb = p_instance->transformed_aabb; + + if (p_instance->indexer_id.is_valid() && bvh_aabb != p_instance->prev_transformed_aabb) { + //assume motion, see if bounds need to be quantized + AABB motion_aabb = bvh_aabb.merge(p_instance->prev_transformed_aabb); + float motion_longest_axis = motion_aabb.get_longest_axis_size(); + float longest_axis = p_instance->transformed_aabb.get_longest_axis_size(); + + if (motion_longest_axis < longest_axis * 2) { + //moved but not a lot, use motion aabb quantizing + float quantize_size = Math::pow(2.0, Math::ceil(Math::log(motion_longest_axis) / Math::log(2.0))) * 0.5; //one fifth + bvh_aabb.quantize(quantize_size); + } + } + + if (!p_instance->indexer_id.is_valid()) { + if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { + p_instance->indexer_id = p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY].insert(bvh_aabb, p_instance); + } else { + p_instance->indexer_id = p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES].insert(bvh_aabb, p_instance); + } + + p_instance->array_index = p_instance->scenario->instance_data.size(); + InstanceData idata; + idata.instance = p_instance; + idata.layer_mask = p_instance->layer_mask; + idata.flags = p_instance->base_type; //changing it means de-indexing, so this never needs to be changed later + idata.base_rid = p_instance->base; + switch (p_instance->base_type) { + case RS::INSTANCE_MESH: + case RS::INSTANCE_MULTIMESH: + case RS::INSTANCE_IMMEDIATE: + case RS::INSTANCE_PARTICLES: { + idata.instance_geometry = static_cast<InstanceGeometryData *>(p_instance->base_data)->geometry_instance; + } break; + case RS::INSTANCE_LIGHT: { + idata.instance_data_rid = static_cast<InstanceLightData *>(p_instance->base_data)->instance.get_id(); + } break; + case RS::INSTANCE_REFLECTION_PROBE: { + idata.instance_data_rid = static_cast<InstanceReflectionProbeData *>(p_instance->base_data)->instance.get_id(); + } break; + case RS::INSTANCE_DECAL: { + idata.instance_data_rid = static_cast<InstanceDecalData *>(p_instance->base_data)->instance.get_id(); + } break; + case RS::INSTANCE_LIGHTMAP: { + idata.instance_data_rid = static_cast<InstanceLightmapData *>(p_instance->base_data)->instance.get_id(); + } break; + case RS::INSTANCE_GI_PROBE: { + idata.instance_data_rid = static_cast<InstanceGIProbeData *>(p_instance->base_data)->probe_instance.get_id(); + } break; + default: { + } + } + + if (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE) { + //always dirty when added + idata.flags |= InstanceData::FLAG_REFLECTION_PROBE_DIRTY; + } + if (p_instance->cast_shadows != RS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) { + idata.flags |= InstanceData::FLAG_CAST_SHADOWS; + } + if (p_instance->cast_shadows == RS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) { + idata.flags |= InstanceData::FLAG_CAST_SHADOWS_ONLY; + } + if (p_instance->redraw_if_visible) { + idata.flags |= InstanceData::FLAG_REDRAW_IF_VISIBLE; + } + // dirty flags should not be set here, since no pairing has happened + if (p_instance->baked_light) { + idata.flags |= InstanceData::FLAG_USES_BAKED_LIGHT; + } + if (p_instance->mesh_instance.is_valid()) { + idata.flags |= InstanceData::FLAG_USES_MESH_INSTANCE; + } + + p_instance->scenario->instance_data.push_back(idata); + p_instance->scenario->instance_aabbs.push_back(InstanceBounds(p_instance->transformed_aabb)); + } else { + if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { + p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY].update(p_instance->indexer_id, bvh_aabb); + } else { + p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES].update(p_instance->indexer_id, bvh_aabb); + } + p_instance->scenario->instance_aabbs[p_instance->array_index] = InstanceBounds(p_instance->transformed_aabb); + } + + //move instance and repair + pair_pass++; + + PairInstances pair; + + pair.instance = p_instance; + pair.pair_allocator = &pair_allocator; + pair.pair_pass = pair_pass; + pair.pair_mask = 0; + + if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { + pair.pair_mask |= 1 << RS::INSTANCE_LIGHT; + pair.pair_mask |= 1 << RS::INSTANCE_GI_PROBE; + pair.pair_mask |= 1 << RS::INSTANCE_LIGHTMAP; + + pair.pair_mask |= geometry_instance_pair_mask; + + pair.bvh2 = &p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES]; + } else if (p_instance->base_type == RS::INSTANCE_LIGHT) { + pair.pair_mask |= RS::INSTANCE_GEOMETRY_MASK; + pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; + + if (RSG::storage->light_get_bake_mode(p_instance->base) == RS::LIGHT_BAKE_DYNAMIC) { + pair.pair_mask |= (1 << RS::INSTANCE_GI_PROBE); + pair.bvh2 = &p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES]; + } + } else if (geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE)) { + pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK; + pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; + } else if (geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && (p_instance->base_type == RS::INSTANCE_DECAL)) { + pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK; + pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; + } else if (p_instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) { + pair.pair_mask = (1 << RS::INSTANCE_PARTICLES); + pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; + } else if (p_instance->base_type == RS::INSTANCE_GI_PROBE) { + //lights and geometries + pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK | (1 << RS::INSTANCE_LIGHT); + pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; + pair.bvh2 = &p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES]; + } + + pair.pair(); + + p_instance->prev_transformed_aabb = p_instance->transformed_aabb; +} + +void RendererSceneCull::_unpair_instance(Instance *p_instance) { + if (!p_instance->indexer_id.is_valid()) { + return; //nothing to do + } + + while (p_instance->pairs.first()) { + InstancePair *pair = p_instance->pairs.first()->self(); + Instance *other_instance = p_instance == pair->a ? pair->b : pair->a; + _instance_unpair(p_instance, other_instance); + pair_allocator.free(pair); + } + + if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { + p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY].remove(p_instance->indexer_id); + } else { + p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES].remove(p_instance->indexer_id); + } + + p_instance->indexer_id = DynamicBVH::ID(); + + //replace this by last + int32_t swap_with_index = p_instance->scenario->instance_data.size() - 1; + if (swap_with_index != p_instance->array_index) { + p_instance->scenario->instance_data[swap_with_index].instance->array_index = p_instance->array_index; //swap + p_instance->scenario->instance_data[p_instance->array_index] = p_instance->scenario->instance_data[swap_with_index]; + p_instance->scenario->instance_aabbs[p_instance->array_index] = p_instance->scenario->instance_aabbs[swap_with_index]; + } + + // pop last + p_instance->scenario->instance_data.pop_back(); + p_instance->scenario->instance_aabbs.pop_back(); + + //uninitialize + p_instance->array_index = -1; + if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { + // Clear these now because the InstanceData containing the dirty flags is gone + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); + + scene_render->geometry_instance_pair_light_instances(geom->geometry_instance, nullptr, 0); + scene_render->geometry_instance_pair_reflection_probe_instances(geom->geometry_instance, nullptr, 0); + scene_render->geometry_instance_pair_decal_instances(geom->geometry_instance, nullptr, 0); + scene_render->geometry_instance_pair_gi_probe_instances(geom->geometry_instance, nullptr, 0); + } +} + +void RendererSceneCull::_update_instance_aabb(Instance *p_instance) { + AABB new_aabb; + + ERR_FAIL_COND(p_instance->base_type != RS::INSTANCE_NONE && !p_instance->base.is_valid()); + + switch (p_instance->base_type) { + case RenderingServer::INSTANCE_NONE: { + // do nothing + } break; + case RenderingServer::INSTANCE_MESH: { + if (p_instance->custom_aabb) { + new_aabb = *p_instance->custom_aabb; + } else { + new_aabb = RSG::storage->mesh_get_aabb(p_instance->base, p_instance->skeleton); + } + + } break; + + case RenderingServer::INSTANCE_MULTIMESH: { + if (p_instance->custom_aabb) { + new_aabb = *p_instance->custom_aabb; + } else { + new_aabb = RSG::storage->multimesh_get_aabb(p_instance->base); + } + + } break; + case RenderingServer::INSTANCE_IMMEDIATE: { + if (p_instance->custom_aabb) { + new_aabb = *p_instance->custom_aabb; + } else { + new_aabb = RSG::storage->immediate_get_aabb(p_instance->base); + } + + } break; + case RenderingServer::INSTANCE_PARTICLES: { + if (p_instance->custom_aabb) { + new_aabb = *p_instance->custom_aabb; + } else { + new_aabb = RSG::storage->particles_get_aabb(p_instance->base); + } + + } break; + case RenderingServer::INSTANCE_PARTICLES_COLLISION: { + new_aabb = RSG::storage->particles_collision_get_aabb(p_instance->base); + + } break; + case RenderingServer::INSTANCE_LIGHT: { + new_aabb = RSG::storage->light_get_aabb(p_instance->base); + + } break; + case RenderingServer::INSTANCE_REFLECTION_PROBE: { + new_aabb = RSG::storage->reflection_probe_get_aabb(p_instance->base); + + } break; + case RenderingServer::INSTANCE_DECAL: { + new_aabb = RSG::storage->decal_get_aabb(p_instance->base); + + } break; + case RenderingServer::INSTANCE_GI_PROBE: { + new_aabb = RSG::storage->gi_probe_get_bounds(p_instance->base); + + } break; + case RenderingServer::INSTANCE_LIGHTMAP: { + new_aabb = RSG::storage->lightmap_get_aabb(p_instance->base); + + } break; + default: { + } + } + + // <Zylann> This is why I didn't re-use Instance::aabb to implement custom AABBs + if (p_instance->extra_margin) { + new_aabb.grow_by(p_instance->extra_margin); + } + + p_instance->aabb = new_aabb; +} + +void RendererSceneCull::_update_instance_lightmap_captures(Instance *p_instance) { + bool first_set = p_instance->lightmap_sh.size() == 0; + p_instance->lightmap_sh.resize(9); //using SH + p_instance->lightmap_target_sh.resize(9); //using SH + Color *instance_sh = p_instance->lightmap_target_sh.ptrw(); + bool inside = false; + Color accum_sh[9]; + float accum_blend = 0.0; + + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); + for (Set<Instance *>::Element *E = geom->lightmap_captures.front(); E; E = E->next()) { + Instance *lightmap = E->get(); + + bool interior = RSG::storage->lightmap_is_interior(lightmap->base); + + if (inside && !interior) { + continue; //we are inside, ignore exteriors + } + + Transform to_bounds = lightmap->transform.affine_inverse(); + Vector3 center = p_instance->transform.xform(p_instance->aabb.position + p_instance->aabb.size * 0.5); //use aabb center + + Vector3 lm_pos = to_bounds.xform(center); + + AABB bounds = RSG::storage->lightmap_get_aabb(lightmap->base); + if (!bounds.has_point(lm_pos)) { + continue; //not in this lightmap + } + + Color sh[9]; + RSG::storage->lightmap_tap_sh_light(lightmap->base, lm_pos, sh); + + //rotate it + Basis rot = lightmap->transform.basis.orthonormalized(); + for (int i = 0; i < 3; i++) { + float csh[9]; + for (int j = 0; j < 9; j++) { + csh[j] = sh[j][i]; + } + rot.rotate_sh(csh); + for (int j = 0; j < 9; j++) { + sh[j][i] = csh[j]; + } + } + + Vector3 inner_pos = ((lm_pos - bounds.position) / bounds.size) * 2.0 - Vector3(1.0, 1.0, 1.0); + + float blend = MAX(inner_pos.x, MAX(inner_pos.y, inner_pos.z)); + //make blend more rounded + blend = Math::lerp(inner_pos.length(), blend, blend); + blend *= blend; + blend = MAX(0.0, 1.0 - blend); + + if (interior && !inside) { + //do not blend, just replace + for (int j = 0; j < 9; j++) { + accum_sh[j] = sh[j] * blend; + } + accum_blend = blend; + inside = true; + } else { + for (int j = 0; j < 9; j++) { + accum_sh[j] += sh[j] * blend; + } + accum_blend += blend; + } + } + + if (accum_blend > 0.0) { + for (int j = 0; j < 9; j++) { + instance_sh[j] = accum_sh[j] / accum_blend; + if (first_set) { + p_instance->lightmap_sh.write[j] = instance_sh[j]; + } + } + } + + scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, p_instance->lightmap_sh.ptr()); +} + +void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_index, Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect) { + InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data); + + Transform light_transform = p_instance->transform; + light_transform.orthonormalize(); //scale does not count on lights + + real_t max_distance = p_cam_projection.get_z_far(); + real_t shadow_max = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE); + if (shadow_max > 0 && !p_cam_orthogonal) { //its impractical (and leads to unwanted behaviors) to set max distance in orthogonal camera + max_distance = MIN(shadow_max, max_distance); + } + max_distance = MAX(max_distance, p_cam_projection.get_z_near() + 0.001); + real_t min_distance = MIN(p_cam_projection.get_z_near(), max_distance); + + RS::LightDirectionalShadowDepthRangeMode depth_range_mode = RSG::storage->light_directional_get_shadow_depth_range_mode(p_instance->base); + + real_t pancake_size = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE); + + real_t range = max_distance - min_distance; + + int splits = 0; + switch (RSG::storage->light_directional_get_shadow_mode(p_instance->base)) { + case RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: + splits = 1; + break; + case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: + splits = 2; + break; + case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: + splits = 4; + break; + } + + real_t distances[5]; + + distances[0] = min_distance; + for (int i = 0; i < splits; i++) { + distances[i + 1] = min_distance + RSG::storage->light_get_param(p_instance->base, RS::LightParam(RS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET + i)) * range; + }; + + distances[splits] = max_distance; + + real_t texture_size = scene_render->get_directional_light_shadow_size(light->instance); + + bool overlap = RSG::storage->light_directional_get_blend_splits(p_instance->base); + + real_t first_radius = 0.0; + + real_t min_distance_bias_scale = distances[1]; + + cull.shadow_count = p_shadow_index + 1; + cull.shadows[p_shadow_index].cascade_count = splits; + cull.shadows[p_shadow_index].light_instance = light->instance; + + for (int i = 0; i < splits; i++) { + RENDER_TIMESTAMP("Culling Directional Light split" + itos(i)); + + // setup a camera matrix for that range! + CameraMatrix camera_matrix; + + real_t aspect = p_cam_projection.get_aspect(); + + if (p_cam_orthogonal) { + Vector2 vp_he = p_cam_projection.get_viewport_half_extents(); + + camera_matrix.set_orthogonal(vp_he.y * 2.0, aspect, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false); + } else { + real_t fov = p_cam_projection.get_fov(); //this is actually yfov, because set aspect tries to keep it + camera_matrix.set_perspective(fov, aspect, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], true); + } + + //obtain the frustum endpoints + + Vector3 endpoints[8]; // frustum plane endpoints + bool res = camera_matrix.get_endpoints(p_cam_transform, endpoints); + ERR_CONTINUE(!res); + + // obtain the light frustum ranges (given endpoints) + + Transform transform = light_transform; //discard scale and stabilize light + + Vector3 x_vec = transform.basis.get_axis(Vector3::AXIS_X).normalized(); + Vector3 y_vec = transform.basis.get_axis(Vector3::AXIS_Y).normalized(); + Vector3 z_vec = transform.basis.get_axis(Vector3::AXIS_Z).normalized(); + //z_vec points against the camera, like in default opengl + + real_t x_min = 0.f, x_max = 0.f; + real_t y_min = 0.f, y_max = 0.f; + real_t z_min = 0.f, z_max = 0.f; + + // FIXME: z_max_cam is defined, computed, but not used below when setting up + // ortho_camera. Commented out for now to fix warnings but should be investigated. + real_t x_min_cam = 0.f, x_max_cam = 0.f; + real_t y_min_cam = 0.f, y_max_cam = 0.f; + real_t z_min_cam = 0.f; + //real_t z_max_cam = 0.f; + + real_t bias_scale = 1.0; + real_t aspect_bias_scale = 1.0; + + //used for culling + + for (int j = 0; j < 8; j++) { + real_t d_x = x_vec.dot(endpoints[j]); + real_t d_y = y_vec.dot(endpoints[j]); + real_t d_z = z_vec.dot(endpoints[j]); + + if (j == 0 || d_x < x_min) { + x_min = d_x; + } + if (j == 0 || d_x > x_max) { + x_max = d_x; + } + + if (j == 0 || d_y < y_min) { + y_min = d_y; + } + if (j == 0 || d_y > y_max) { + y_max = d_y; + } + + if (j == 0 || d_z < z_min) { + z_min = d_z; + } + if (j == 0 || d_z > z_max) { + z_max = d_z; + } + } + + real_t radius = 0; + real_t soft_shadow_expand = 0; + Vector3 center; + + { + //camera viewport stuff + + for (int j = 0; j < 8; j++) { + center += endpoints[j]; + } + center /= 8.0; + + //center=x_vec*(x_max-x_min)*0.5 + y_vec*(y_max-y_min)*0.5 + z_vec*(z_max-z_min)*0.5; + + for (int j = 0; j < 8; j++) { + real_t d = center.distance_to(endpoints[j]); + if (d > radius) { + radius = d; + } + } + + radius *= texture_size / (texture_size - 2.0); //add a texel by each side + + if (i == 0) { + first_radius = radius; + } else { + bias_scale = radius / first_radius; + } + + z_min_cam = z_vec.dot(center) - radius; + + { + float soft_shadow_angle = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SIZE); + + if (soft_shadow_angle > 0.0) { + float z_range = (z_vec.dot(center) + radius + pancake_size) - z_min_cam; + soft_shadow_expand = Math::tan(Math::deg2rad(soft_shadow_angle)) * z_range; + + x_max += soft_shadow_expand; + y_max += soft_shadow_expand; + + x_min -= soft_shadow_expand; + y_min -= soft_shadow_expand; + } + } + + x_max_cam = x_vec.dot(center) + radius + soft_shadow_expand; + x_min_cam = x_vec.dot(center) - radius - soft_shadow_expand; + y_max_cam = y_vec.dot(center) + radius + soft_shadow_expand; + y_min_cam = y_vec.dot(center) - radius - soft_shadow_expand; + + if (depth_range_mode == RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE) { + //this trick here is what stabilizes the shadow (make potential jaggies to not move) + //at the cost of some wasted resolution. Still the quality increase is very well worth it + + real_t unit = radius * 2.0 / texture_size; + + x_max_cam = Math::snapped(x_max_cam, unit); + x_min_cam = Math::snapped(x_min_cam, unit); + y_max_cam = Math::snapped(y_max_cam, unit); + y_min_cam = Math::snapped(y_min_cam, unit); + } + } + + //now that we know all ranges, we can proceed to make the light frustum planes, for culling octree + + Vector<Plane> light_frustum_planes; + light_frustum_planes.resize(6); + + //right/left + light_frustum_planes.write[0] = Plane(x_vec, x_max); + light_frustum_planes.write[1] = Plane(-x_vec, -x_min); + //top/bottom + light_frustum_planes.write[2] = Plane(y_vec, y_max); + light_frustum_planes.write[3] = Plane(-y_vec, -y_min); + //near/far + light_frustum_planes.write[4] = Plane(z_vec, z_max + 1e6); + light_frustum_planes.write[5] = Plane(-z_vec, -z_min); // z_min is ok, since casters further than far-light plane are not needed + + // a pre pass will need to be needed to determine the actual z-near to be used + + if (pancake_size > 0) { + z_max = z_vec.dot(center) + radius + pancake_size; + } + + if (aspect != 1.0) { + // if the aspect is different, then the radius will become larger. + // if this happens, then bias needs to be adjusted too, as depth will increase + // to do this, compare the depth of one that would have resulted from a square frustum + + CameraMatrix camera_matrix_square; + if (p_cam_orthogonal) { + Vector2 vp_he = camera_matrix.get_viewport_half_extents(); + if (p_cam_vaspect) { + camera_matrix_square.set_orthogonal(vp_he.x * 2.0, 1.0, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], true); + } else { + camera_matrix_square.set_orthogonal(vp_he.y * 2.0, 1.0, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false); + } + } else { + Vector2 vp_he = camera_matrix.get_viewport_half_extents(); + if (p_cam_vaspect) { + camera_matrix_square.set_frustum(vp_he.x * 2.0, 1.0, Vector2(), distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], true); + } else { + camera_matrix_square.set_frustum(vp_he.y * 2.0, 1.0, Vector2(), distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false); + } + } + + Vector3 endpoints_square[8]; // frustum plane endpoints + res = camera_matrix_square.get_endpoints(p_cam_transform, endpoints_square); + ERR_CONTINUE(!res); + Vector3 center_square; + + for (int j = 0; j < 8; j++) { + center_square += endpoints_square[j]; + } + + center_square /= 8.0; + + real_t radius_square = 0; + + for (int j = 0; j < 8; j++) { + real_t d = center_square.distance_to(endpoints_square[j]); + if (d > radius_square) { + radius_square = d; + } + } + + radius_square *= texture_size / (texture_size - 2.0); //add a texel by each side + + float z_max_square = z_vec.dot(center_square) + radius_square + pancake_size; + + real_t z_min_cam_square = z_vec.dot(center_square) - radius_square; + + aspect_bias_scale = (z_max - z_min_cam) / (z_max_square - z_min_cam_square); + + // this is not entirely perfect, because the cull-adjusted z-max may be different + // but at least it's warranted that it results in a greater bias, so no acne should be present either way. + // pancaking also helps with this. + } + + { + CameraMatrix ortho_camera; + real_t half_x = (x_max_cam - x_min_cam) * 0.5; + real_t half_y = (y_max_cam - y_min_cam) * 0.5; + + ortho_camera.set_orthogonal(-half_x, half_x, -half_y, half_y, 0, (z_max - z_min_cam)); + + Vector2 uv_scale(1.0 / (x_max_cam - x_min_cam), 1.0 / (y_max_cam - y_min_cam)); + + Transform ortho_transform; + ortho_transform.basis = transform.basis; + ortho_transform.origin = x_vec * (x_min_cam + half_x) + y_vec * (y_min_cam + half_y) + z_vec * z_max; + + cull.shadows[p_shadow_index].cascades[i].frustum = Frustum(light_frustum_planes); + cull.shadows[p_shadow_index].cascades[i].projection = ortho_camera; + cull.shadows[p_shadow_index].cascades[i].transform = ortho_transform; + cull.shadows[p_shadow_index].cascades[i].zfar = z_max - z_min_cam; + cull.shadows[p_shadow_index].cascades[i].split = distances[i + 1]; + cull.shadows[p_shadow_index].cascades[i].shadow_texel_size = radius * 2.0 / texture_size; + cull.shadows[p_shadow_index].cascades[i].bias_scale = bias_scale * aspect_bias_scale * min_distance_bias_scale; + cull.shadows[p_shadow_index].cascades[i].range_begin = z_max; + cull.shadows[p_shadow_index].cascades[i].uv_scale = uv_scale; + } + } +} + +bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario, float p_screen_lod_threshold) { + InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data); + + Transform light_transform = p_instance->transform; + light_transform.orthonormalize(); //scale does not count on lights + + bool animated_material_found = false; + + switch (RSG::storage->light_get_type(p_instance->base)) { + case RS::LIGHT_DIRECTIONAL: { + } break; + case RS::LIGHT_OMNI: { + RS::LightOmniShadowMode shadow_mode = RSG::storage->light_omni_get_shadow_mode(p_instance->base); + + if (shadow_mode == RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID || !scene_render->light_instances_can_render_shadow_cube()) { + if (max_shadows_used + 2 > MAX_UPDATE_SHADOWS) { + return true; + } + for (int i = 0; i < 2; i++) { + //using this one ensures that raster deferred will have it + RENDER_TIMESTAMP("Culling Shadow Paraboloid" + itos(i)); + + real_t radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE); + + real_t z = i == 0 ? -1 : 1; + Vector<Plane> planes; + planes.resize(6); + planes.write[0] = light_transform.xform(Plane(Vector3(0, 0, z), radius)); + planes.write[1] = light_transform.xform(Plane(Vector3(1, 0, z).normalized(), radius)); + planes.write[2] = light_transform.xform(Plane(Vector3(-1, 0, z).normalized(), radius)); + planes.write[3] = light_transform.xform(Plane(Vector3(0, 1, z).normalized(), radius)); + planes.write[4] = light_transform.xform(Plane(Vector3(0, -1, z).normalized(), radius)); + planes.write[5] = light_transform.xform(Plane(Vector3(0, 0, -z), 0)); + + instance_shadow_cull_result.clear(); + + Vector<Vector3> points = Geometry3D::compute_convex_mesh_points(&planes[0], planes.size()); + + struct CullConvex { + PagedArray<Instance *> *result; + _FORCE_INLINE_ bool operator()(void *p_data) { + Instance *p_instance = (Instance *)p_data; + result->push_back(p_instance); + return false; + } + }; + + CullConvex cull_convex; + cull_convex.result = &instance_shadow_cull_result; + + p_scenario->indexers[Scenario::INDEXER_GEOMETRY].convex_query(planes.ptr(), planes.size(), points.ptr(), points.size(), cull_convex); + + Plane near_plane(light_transform.origin, light_transform.basis.get_axis(2) * z); + + RendererSceneRender::RenderShadowData &shadow_data = render_shadow_data[max_shadows_used++]; + + for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) { + Instance *instance = instance_shadow_cull_result[j]; + if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) { + continue; + } else { + if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) { + animated_material_found = true; + } + + if (instance->mesh_instance.is_valid()) { + RSG::storage->mesh_instance_check_for_update(instance->mesh_instance); + } + } + + shadow_data.instances.push_back(static_cast<InstanceGeometryData *>(instance->base_data)->geometry_instance); + } + + RSG::storage->update_mesh_instances(); + + scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, i, 0); + shadow_data.light = light->instance; + shadow_data.pass = i; + } + } else { //shadow cube + + if (max_shadows_used + 6 > MAX_UPDATE_SHADOWS) { + return true; + } + + real_t radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE); + CameraMatrix cm; + cm.set_perspective(90, 1, 0.01, radius); + + for (int i = 0; i < 6; i++) { + RENDER_TIMESTAMP("Culling Shadow Cube side" + itos(i)); + //using this one ensures that raster deferred will have it + + static const Vector3 view_normals[6] = { + Vector3(+1, 0, 0), + Vector3(-1, 0, 0), + Vector3(0, -1, 0), + Vector3(0, +1, 0), + Vector3(0, 0, +1), + Vector3(0, 0, -1) + }; + static const Vector3 view_up[6] = { + Vector3(0, -1, 0), + Vector3(0, -1, 0), + Vector3(0, 0, -1), + Vector3(0, 0, +1), + Vector3(0, -1, 0), + Vector3(0, -1, 0) + }; + + Transform xform = light_transform * Transform().looking_at(view_normals[i], view_up[i]); + + Vector<Plane> planes = cm.get_projection_planes(xform); + + instance_shadow_cull_result.clear(); + + Vector<Vector3> points = Geometry3D::compute_convex_mesh_points(&planes[0], planes.size()); + + struct CullConvex { + PagedArray<Instance *> *result; + _FORCE_INLINE_ bool operator()(void *p_data) { + Instance *p_instance = (Instance *)p_data; + result->push_back(p_instance); + return false; + } + }; + + CullConvex cull_convex; + cull_convex.result = &instance_shadow_cull_result; + + p_scenario->indexers[Scenario::INDEXER_GEOMETRY].convex_query(planes.ptr(), planes.size(), points.ptr(), points.size(), cull_convex); + + RendererSceneRender::RenderShadowData &shadow_data = render_shadow_data[max_shadows_used++]; + + for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) { + Instance *instance = instance_shadow_cull_result[j]; + if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) { + continue; + } else { + if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) { + animated_material_found = true; + } + if (instance->mesh_instance.is_valid()) { + RSG::storage->mesh_instance_check_for_update(instance->mesh_instance); + } + } + + shadow_data.instances.push_back(static_cast<InstanceGeometryData *>(instance->base_data)->geometry_instance); + } + + RSG::storage->update_mesh_instances(); + scene_render->light_instance_set_shadow_transform(light->instance, cm, xform, radius, 0, i, 0); + + shadow_data.light = light->instance; + shadow_data.pass = i; + } + + //restore the regular DP matrix + //scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, 0, 0); + } + + } break; + case RS::LIGHT_SPOT: { + RENDER_TIMESTAMP("Culling Spot Light"); + + if (max_shadows_used + 1 > MAX_UPDATE_SHADOWS) { + return true; + } + + real_t radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE); + real_t angle = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SPOT_ANGLE); + + CameraMatrix cm; + cm.set_perspective(angle * 2.0, 1.0, 0.01, radius); + + Vector<Plane> planes = cm.get_projection_planes(light_transform); + + instance_shadow_cull_result.clear(); + + Vector<Vector3> points = Geometry3D::compute_convex_mesh_points(&planes[0], planes.size()); + + struct CullConvex { + PagedArray<Instance *> *result; + _FORCE_INLINE_ bool operator()(void *p_data) { + Instance *p_instance = (Instance *)p_data; + result->push_back(p_instance); + return false; + } + }; + + CullConvex cull_convex; + cull_convex.result = &instance_shadow_cull_result; + + p_scenario->indexers[Scenario::INDEXER_GEOMETRY].convex_query(planes.ptr(), planes.size(), points.ptr(), points.size(), cull_convex); + + RendererSceneRender::RenderShadowData &shadow_data = render_shadow_data[max_shadows_used++]; + + for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) { + Instance *instance = instance_shadow_cull_result[j]; + if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) { + continue; + } else { + if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) { + animated_material_found = true; + } + + if (instance->mesh_instance.is_valid()) { + RSG::storage->mesh_instance_check_for_update(instance->mesh_instance); + } + } + shadow_data.instances.push_back(static_cast<InstanceGeometryData *>(instance->base_data)->geometry_instance); + } + + RSG::storage->update_mesh_instances(); + + scene_render->light_instance_set_shadow_transform(light->instance, cm, light_transform, radius, 0, 0, 0); + shadow_data.light = light->instance; + shadow_data.pass = 0; + + } break; + } + + return animated_material_found; +} + +void RendererSceneCull::render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas) { +// render to mono camera +#ifndef _3D_DISABLED + + Camera *camera = camera_owner.getornull(p_camera); + ERR_FAIL_COND(!camera); + + /* STEP 1 - SETUP CAMERA */ + CameraMatrix camera_matrix; + bool ortho = false; + + switch (camera->type) { + case Camera::ORTHOGONAL: { + camera_matrix.set_orthogonal( + camera->size, + p_viewport_size.width / (float)p_viewport_size.height, + camera->znear, + camera->zfar, + camera->vaspect); + ortho = true; + } break; + case Camera::PERSPECTIVE: { + camera_matrix.set_perspective( + camera->fov, + p_viewport_size.width / (float)p_viewport_size.height, + camera->znear, + camera->zfar, + camera->vaspect); + ortho = false; + + } break; + case Camera::FRUSTUM: { + camera_matrix.set_frustum( + camera->size, + p_viewport_size.width / (float)p_viewport_size.height, + camera->offset, + camera->znear, + camera->zfar, + camera->vaspect); + ortho = false; + } break; + } + + RID environment = _render_get_environment(p_camera, p_scenario); + + _render_scene(camera->transform, camera_matrix, ortho, camera->vaspect, p_render_buffers, environment, camera->effects, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), -1, p_screen_lod_threshold); +#endif +} + +void RendererSceneCull::render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas) { + // render for AR/VR interface +#if 0 + Camera *camera = camera_owner.getornull(p_camera); + ERR_FAIL_COND(!camera); + + /* SETUP CAMERA, we are ignoring type and FOV here */ + float aspect = p_viewport_size.width / (float)p_viewport_size.height; + CameraMatrix camera_matrix = p_interface->get_projection_for_eye(p_eye, aspect, camera->znear, camera->zfar); + + // We also ignore our camera position, it will have been positioned with a slightly old tracking position. + // Instead we take our origin point and have our ar/vr interface add fresh tracking data! Whoohoo! + Transform world_origin = XRServer::get_singleton()->get_world_origin(); + Transform cam_transform = p_interface->get_transform_for_eye(p_eye, world_origin); + + RID environment = _render_get_environment(p_camera, p_scenario); + + // For stereo render we only prepare for our left eye and then reuse the outcome for our right eye + if (p_eye == XRInterface::EYE_LEFT) { + // Center our transform, we assume basis is equal. + Transform mono_transform = cam_transform; + Transform right_transform = p_interface->get_transform_for_eye(XRInterface::EYE_RIGHT, world_origin); + mono_transform.origin += right_transform.origin; + mono_transform.origin *= 0.5; + + // We need to combine our projection frustums for culling. + // Ideally we should use our clipping planes for this and combine them, + // however our shadow map logic uses our projection matrix. + // Note: as our left and right frustums should be mirrored, we don't need our right projection matrix. + + // - get some base values we need + float eye_dist = (mono_transform.origin - cam_transform.origin).length(); + float z_near = camera_matrix.get_z_near(); // get our near plane + float z_far = camera_matrix.get_z_far(); // get our far plane + float width = (2.0 * z_near) / camera_matrix.matrix[0][0]; + float x_shift = width * camera_matrix.matrix[2][0]; + float height = (2.0 * z_near) / camera_matrix.matrix[1][1]; + float y_shift = height * camera_matrix.matrix[2][1]; + + // printf("Eye_dist = %f, Near = %f, Far = %f, Width = %f, Shift = %f\n", eye_dist, z_near, z_far, width, x_shift); + + // - calculate our near plane size (horizontal only, right_near is mirrored) + float left_near = -eye_dist - ((width - x_shift) * 0.5); + + // - calculate our far plane size (horizontal only, right_far is mirrored) + float left_far = -eye_dist - (z_far * (width - x_shift) * 0.5 / z_near); + float left_far_right_eye = eye_dist - (z_far * (width + x_shift) * 0.5 / z_near); + if (left_far > left_far_right_eye) { + // on displays smaller then double our iod, the right eye far frustrum can overtake the left eyes. + left_far = left_far_right_eye; + } + + // - figure out required z-shift + float slope = (left_far - left_near) / (z_far - z_near); + float z_shift = (left_near / slope) - z_near; + + // - figure out new vertical near plane size (this will be slightly oversized thanks to our z-shift) + float top_near = (height - y_shift) * 0.5; + top_near += (top_near / z_near) * z_shift; + float bottom_near = -(height + y_shift) * 0.5; + bottom_near += (bottom_near / z_near) * z_shift; + + // printf("Left_near = %f, Left_far = %f, Top_near = %f, Bottom_near = %f, Z_shift = %f\n", left_near, left_far, top_near, bottom_near, z_shift); + + // - generate our frustum + CameraMatrix combined_matrix; + combined_matrix.set_frustum(left_near, -left_near, bottom_near, top_near, z_near + z_shift, z_far + z_shift); + + // and finally move our camera back + Transform apply_z_shift; + apply_z_shift.origin = Vector3(0.0, 0.0, z_shift); // z negative is forward so this moves it backwards + mono_transform *= apply_z_shift; + + // now prepare our scene with our adjusted transform projection matrix + _prepare_scene(mono_transform, combined_matrix, false, false, p_render_buffers, environment, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), p_screen_lod_threshold); + } else if (p_eye == XRInterface::EYE_MONO) { + // For mono render, prepare as per usual + _prepare_scene(cam_transform, camera_matrix, false, false, p_render_buffers, environment, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), p_screen_lod_threshold); + } + + // And render our scene... + _render_scene(p_render_buffers, cam_transform, camera_matrix, false, environment, camera->effects, p_scenario, p_shadow_atlas, RID(), -1, p_screen_lod_threshold); +#endif +}; + +void RendererSceneCull::_frustum_cull_threaded(uint32_t p_thread, FrustumCullData *cull_data) { + uint32_t cull_total = cull_data->scenario->instance_data.size(); + uint32_t total_threads = RendererThreadPool::singleton->thread_work_pool.get_thread_count(); + uint32_t cull_from = p_thread * cull_total / total_threads; + uint32_t cull_to = (p_thread + 1 == total_threads) ? cull_total : ((p_thread + 1) * cull_total / total_threads); + + _frustum_cull(*cull_data, frustum_cull_result_threads[p_thread], cull_from, cull_to); +} + +void RendererSceneCull::_frustum_cull(FrustumCullData &cull_data, FrustumCullResult &cull_result, uint64_t p_from, uint64_t p_to) { + uint64_t frame_number = RSG::rasterizer->get_frame_number(); + float lightmap_probe_update_speed = RSG::storage->lightmap_get_probe_capture_update_speed() * RSG::rasterizer->get_frame_delta_time(); + + uint32_t sdfgi_last_light_index = 0xFFFFFFFF; + uint32_t sdfgi_last_light_cascade = 0xFFFFFFFF; + + RID instance_pair_buffer[MAX_INSTANCE_PAIRS]; + + for (uint64_t i = p_from; i < p_to; i++) { + bool mesh_visible = false; + + if (cull_data.scenario->instance_aabbs[i].in_frustum(cull_data.cull->frustum)) { + InstanceData &idata = cull_data.scenario->instance_data[i]; + uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK; + + if ((cull_data.visible_layers & idata.layer_mask) == 0) { + //failure + } else if (base_type == RS::INSTANCE_LIGHT) { + cull_result.lights.push_back(idata.instance); + cull_result.light_instances.push_back(RID::from_uint64(idata.instance_data_rid)); + if (cull_data.shadow_atlas.is_valid() && RSG::storage->light_has_shadow(idata.base_rid)) { + scene_render->light_instance_mark_visible(RID::from_uint64(idata.instance_data_rid)); //mark it visible for shadow allocation later + } + + } else if (base_type == RS::INSTANCE_REFLECTION_PROBE) { + if (cull_data.render_reflection_probe != idata.instance) { + //avoid entering The Matrix + + if ((idata.flags & InstanceData::FLAG_REFLECTION_PROBE_DIRTY) || scene_render->reflection_probe_instance_needs_redraw(RID::from_uint64(idata.instance_data_rid))) { + InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(idata.instance->base_data); + cull_data.cull->lock.lock(); + if (!reflection_probe->update_list.in_list()) { + reflection_probe->render_step = 0; + reflection_probe_render_list.add_last(&reflection_probe->update_list); + } + cull_data.cull->lock.unlock(); + + idata.flags &= ~uint32_t(InstanceData::FLAG_REFLECTION_PROBE_DIRTY); + } + + if (scene_render->reflection_probe_instance_has_reflection(RID::from_uint64(idata.instance_data_rid))) { + cull_result.reflections.push_back(RID::from_uint64(idata.instance_data_rid)); + } + } + } else if (base_type == RS::INSTANCE_DECAL) { + cull_result.decals.push_back(RID::from_uint64(idata.instance_data_rid)); + + } else if (base_type == RS::INSTANCE_GI_PROBE) { + InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(idata.instance->base_data); + cull_data.cull->lock.lock(); + if (!gi_probe->update_element.in_list()) { + gi_probe_update_list.add(&gi_probe->update_element); + } + cull_data.cull->lock.unlock(); + cull_result.gi_probes.push_back(RID::from_uint64(idata.instance_data_rid)); + + } else if (base_type == RS::INSTANCE_LIGHTMAP) { + cull_result.gi_probes.push_back(RID::from_uint64(idata.instance_data_rid)); + } else if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && !(idata.flags & InstanceData::FLAG_CAST_SHADOWS_ONLY)) { + bool keep = true; + + if (idata.flags & InstanceData::FLAG_REDRAW_IF_VISIBLE) { + RenderingServerDefault::redraw_request(); + } + + if (base_type == RS::INSTANCE_MESH) { + mesh_visible = true; + } else if (base_type == RS::INSTANCE_PARTICLES) { + //particles visible? process them + if (RSG::storage->particles_is_inactive(idata.base_rid)) { + //but if nothing is going on, don't do it. + keep = false; + } else { + cull_data.cull->lock.lock(); + RSG::storage->particles_request_process(idata.base_rid); + cull_data.cull->lock.unlock(); + RSG::storage->particles_set_view_axis(idata.base_rid, -cull_data.cam_transform.basis.get_axis(2).normalized()); + //particles visible? request redraw + RenderingServerDefault::redraw_request(); + } + } + + if (geometry_instance_pair_mask & (1 << RS::INSTANCE_LIGHT) && (idata.flags & InstanceData::FLAG_GEOM_LIGHTING_DIRTY)) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); + uint32_t idx = 0; + + for (Set<Instance *>::Element *E = geom->lights.front(); E; E = E->next()) { + InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data); + instance_pair_buffer[idx++] = light->instance; + if (idx == MAX_INSTANCE_PAIRS) { + break; + } + } + + scene_render->geometry_instance_pair_light_instances(geom->geometry_instance, instance_pair_buffer, idx); + idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_LIGHTING_DIRTY); + } + + if (geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && (idata.flags & InstanceData::FLAG_GEOM_REFLECTION_DIRTY)) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); + uint32_t idx = 0; + + for (Set<Instance *>::Element *E = geom->reflection_probes.front(); E; E = E->next()) { + InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(E->get()->base_data); + + instance_pair_buffer[idx++] = reflection_probe->instance; + if (idx == MAX_INSTANCE_PAIRS) { + break; + } + } + + scene_render->geometry_instance_pair_reflection_probe_instances(geom->geometry_instance, instance_pair_buffer, idx); + idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_REFLECTION_DIRTY); + } + + if (geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && (idata.flags & InstanceData::FLAG_GEOM_DECAL_DIRTY)) { + //InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); + //todo for GLES3 + idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_DECAL_DIRTY); + /*for (Set<Instance *>::Element *E = geom->dec.front(); E; E = E->next()) { + InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(E->get()->base_data); + + instance_pair_buffer[idx++] = reflection_probe->instance; + if (idx==MAX_INSTANCE_PAIRS) { + break; + } + }*/ + //scene_render->geometry_instance_pair_decal_instances(geom->geometry_instance, light_instances, idx); + } + + if (idata.flags & InstanceData::FLAG_GEOM_GI_PROBE_DIRTY) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); + uint32_t idx = 0; + for (Set<Instance *>::Element *E = geom->gi_probes.front(); E; E = E->next()) { + InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(E->get()->base_data); + + instance_pair_buffer[idx++] = gi_probe->probe_instance; + if (idx == MAX_INSTANCE_PAIRS) { + break; + } + } + + scene_render->geometry_instance_pair_gi_probe_instances(geom->geometry_instance, instance_pair_buffer, idx); + idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_GI_PROBE_DIRTY); + } + + if ((idata.flags & InstanceData::FLAG_LIGHTMAP_CAPTURE) && idata.instance->last_frame_pass != frame_number && !idata.instance->lightmap_target_sh.is_empty() && !idata.instance->lightmap_sh.is_empty()) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); + Color *sh = idata.instance->lightmap_sh.ptrw(); + const Color *target_sh = idata.instance->lightmap_target_sh.ptr(); + for (uint32_t j = 0; j < 9; j++) { + sh[j] = sh[j].lerp(target_sh[j], MIN(1.0, lightmap_probe_update_speed)); + } + scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, sh); + idata.instance->last_frame_pass = frame_number; + } + + if (keep) { + cull_result.geometry_instances.push_back(idata.instance_geometry); + } + } + } + + for (uint32_t j = 0; j < cull_data.cull->shadow_count; j++) { + for (uint32_t k = 0; k < cull_data.cull->shadows[j].cascade_count; k++) { + if (cull_data.scenario->instance_aabbs[i].in_frustum(cull_data.cull->shadows[j].cascades[k].frustum)) { + InstanceData &idata = cull_data.scenario->instance_data[i]; + uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK; + + if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && idata.flags & InstanceData::FLAG_CAST_SHADOWS) { + cull_result.directional_shadows[j].cascade_geometry_instances[k].push_back(idata.instance_geometry); + mesh_visible = true; + } + } + } + } + + for (uint32_t j = 0; j < cull_data.cull->sdfgi.region_count; j++) { + if (cull_data.scenario->instance_aabbs[i].in_aabb(cull_data.cull->sdfgi.region_aabb[j])) { + InstanceData &idata = cull_data.scenario->instance_data[i]; + uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK; + + if (base_type == RS::INSTANCE_LIGHT) { + InstanceLightData *instance_light = (InstanceLightData *)idata.instance->base_data; + if (instance_light->bake_mode == RS::LIGHT_BAKE_STATIC && cull_data.cull->sdfgi.region_cascade[j] <= instance_light->max_sdfgi_cascade) { + if (sdfgi_last_light_index != i || sdfgi_last_light_cascade != cull_data.cull->sdfgi.region_cascade[j]) { + sdfgi_last_light_index = i; + sdfgi_last_light_cascade = cull_data.cull->sdfgi.region_cascade[j]; + cull_result.sdfgi_cascade_lights[sdfgi_last_light_cascade].push_back(instance_light->instance); + } + } + } else if ((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) { + if (idata.flags & InstanceData::FLAG_USES_BAKED_LIGHT) { + cull_result.sdfgi_region_geometry_instances[j].push_back(idata.instance_geometry); + mesh_visible = true; + } + } + } + } + + if (mesh_visible && cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_USES_MESH_INSTANCE) { + cull_result.mesh_instances.push_back(cull_data.scenario->instance_data[i].instance->mesh_instance); + } + } +} + +void RendererSceneCull::_render_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_render_buffers, RID p_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, bool p_using_shadows) { + // Note, in stereo rendering: + // - p_cam_transform will be a transform in the middle of our two eyes + // - p_cam_projection is a wider frustrum that encompasses both eyes + + Instance *render_reflection_probe = instance_owner.getornull(p_reflection_probe); //if null, not rendering to it + + Scenario *scenario = scenario_owner.getornull(p_scenario); + + render_pass++; + + scene_render->set_scene_pass(render_pass); + + if (p_render_buffers.is_valid()) { + //no rendering code here, this is only to set up what needs to be done, request regions, etc. + scene_render->sdfgi_update(p_render_buffers, p_environment, p_cam_transform.origin); //update conditions for SDFGI (whether its used or not) + } + + RENDER_TIMESTAMP("Frustum Culling"); + + //rasterizer->set_camera(camera->transform, camera_matrix,ortho); + + Vector<Plane> planes = p_cam_projection.get_projection_planes(p_cam_transform); + + Plane near_plane(p_cam_transform.origin, -p_cam_transform.basis.get_axis(2).normalized()); + + /* STEP 2 - CULL */ + + cull.frustum = Frustum(planes); + + Vector<RID> directional_lights; + // directional lights + { + cull.shadow_count = 0; + + Vector<Instance *> lights_with_shadow; + + for (List<Instance *>::Element *E = scenario->directional_lights.front(); E; E = E->next()) { + if (!E->get()->visible) { + continue; + } + + if (directional_lights.size() > RendererSceneRender::MAX_DIRECTIONAL_LIGHTS) { + break; + } + + InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data); + + //check shadow.. + + if (light) { + if (p_using_shadows && p_shadow_atlas.is_valid() && RSG::storage->light_has_shadow(E->get()->base) && !(RSG::storage->light_get_type(E->get()->base) == RS::LIGHT_DIRECTIONAL && RSG::storage->light_directional_is_sky_only(E->get()->base))) { + lights_with_shadow.push_back(E->get()); + } + //add to list + directional_lights.push_back(light->instance); + } + } + + scene_render->set_directional_shadow_count(lights_with_shadow.size()); + + for (int i = 0; i < lights_with_shadow.size(); i++) { + _light_instance_setup_directional_shadow(i, lights_with_shadow[i], p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect); + } + } + + { //sdfgi + cull.sdfgi.region_count = 0; + + if (p_render_buffers.is_valid()) { + cull.sdfgi.cascade_light_count = 0; + + uint32_t prev_cascade = 0xFFFFFFFF; + uint32_t pending_region_count = scene_render->sdfgi_get_pending_region_count(p_render_buffers); + + for (uint32_t i = 0; i < pending_region_count; i++) { + cull.sdfgi.region_aabb[i] = scene_render->sdfgi_get_pending_region_bounds(p_render_buffers, i); + uint32_t region_cascade = scene_render->sdfgi_get_pending_region_cascade(p_render_buffers, i); + cull.sdfgi.region_cascade[i] = region_cascade; + + if (region_cascade != prev_cascade) { + cull.sdfgi.cascade_light_index[cull.sdfgi.cascade_light_count] = region_cascade; + cull.sdfgi.cascade_light_count++; + prev_cascade = region_cascade; + } + } + + cull.sdfgi.region_count = pending_region_count; + } + } + + frustum_cull_result.clear(); + + { + uint64_t cull_from = 0; + uint64_t cull_to = scenario->instance_data.size(); + + FrustumCullData cull_data; + + //prepare for eventual thread usage + cull_data.cull = &cull; + cull_data.scenario = scenario; + cull_data.shadow_atlas = p_shadow_atlas; + cull_data.cam_transform = p_cam_transform; + cull_data.visible_layers = p_visible_layers; + cull_data.render_reflection_probe = render_reflection_probe; +//#define DEBUG_CULL_TIME +#ifdef DEBUG_CULL_TIME + uint64_t time_from = OS::get_singleton()->get_ticks_usec(); +#endif + if (cull_to > thread_cull_threshold) { + //multiple threads + for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) { + frustum_cull_result_threads[i].clear(); + } + + RendererThreadPool::singleton->thread_work_pool.do_work(frustum_cull_result_threads.size(), this, &RendererSceneCull::_frustum_cull_threaded, &cull_data); + + for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) { + frustum_cull_result.append_from(frustum_cull_result_threads[i]); + } + + } else { + //single threaded + _frustum_cull(cull_data, frustum_cull_result, cull_from, cull_to); + } + +#ifdef DEBUG_CULL_TIME + static float time_avg = 0; + static uint32_t time_count = 0; + time_avg += double(OS::get_singleton()->get_ticks_usec() - time_from) / 1000.0; + time_count++; + print_line("time taken: " + rtos(time_avg / time_count)); +#endif + + if (frustum_cull_result.mesh_instances.size()) { + for (uint64_t i = 0; i < frustum_cull_result.mesh_instances.size(); i++) { + RSG::storage->mesh_instance_check_for_update(frustum_cull_result.mesh_instances[i]); + } + RSG::storage->update_mesh_instances(); + } + } + + //render shadows + + max_shadows_used = 0; + + if (p_using_shadows) { //setup shadow maps + + // Directional Shadows + + for (uint32_t i = 0; i < cull.shadow_count; i++) { + for (uint32_t j = 0; j < cull.shadows[i].cascade_count; j++) { + const Cull::Shadow::Cascade &c = cull.shadows[i].cascades[j]; + // print_line("shadow " + itos(i) + " cascade " + itos(j) + " elements: " + itos(c.cull_result.size())); + scene_render->light_instance_set_shadow_transform(cull.shadows[i].light_instance, c.projection, c.transform, c.zfar, c.split, j, c.shadow_texel_size, c.bias_scale, c.range_begin, c.uv_scale); + if (max_shadows_used == MAX_UPDATE_SHADOWS) { + continue; + } + render_shadow_data[max_shadows_used].light = cull.shadows[i].light_instance; + render_shadow_data[max_shadows_used].pass = j; + render_shadow_data[max_shadows_used].instances.merge_unordered(frustum_cull_result.directional_shadows[i].cascade_geometry_instances[j]); + max_shadows_used++; + } + } + + // Positional Shadowss + for (uint32_t i = 0; i < (uint32_t)frustum_cull_result.lights.size(); i++) { + Instance *ins = frustum_cull_result.lights[i]; + + if (!p_shadow_atlas.is_valid() || !RSG::storage->light_has_shadow(ins->base)) { + continue; + } + + InstanceLightData *light = static_cast<InstanceLightData *>(ins->base_data); + + float coverage = 0.f; + + { //compute coverage + + Transform cam_xf = p_cam_transform; + float zn = p_cam_projection.get_z_near(); + Plane p(cam_xf.origin + cam_xf.basis.get_axis(2) * -zn, -cam_xf.basis.get_axis(2)); //camera near plane + + // near plane half width and height + Vector2 vp_half_extents = p_cam_projection.get_viewport_half_extents(); + + switch (RSG::storage->light_get_type(ins->base)) { + case RS::LIGHT_OMNI: { + float radius = RSG::storage->light_get_param(ins->base, RS::LIGHT_PARAM_RANGE); + + //get two points parallel to near plane + Vector3 points[2] = { + ins->transform.origin, + ins->transform.origin + cam_xf.basis.get_axis(0) * radius + }; + + if (!p_cam_orthogonal) { + //if using perspetive, map them to near plane + for (int j = 0; j < 2; j++) { + if (p.distance_to(points[j]) < 0) { + points[j].z = -zn; //small hack to keep size constant when hitting the screen + } + + p.intersects_segment(cam_xf.origin, points[j], &points[j]); //map to plane + } + } + + float screen_diameter = points[0].distance_to(points[1]) * 2; + coverage = screen_diameter / (vp_half_extents.x + vp_half_extents.y); + } break; + case RS::LIGHT_SPOT: { + float radius = RSG::storage->light_get_param(ins->base, RS::LIGHT_PARAM_RANGE); + float angle = RSG::storage->light_get_param(ins->base, RS::LIGHT_PARAM_SPOT_ANGLE); + + float w = radius * Math::sin(Math::deg2rad(angle)); + float d = radius * Math::cos(Math::deg2rad(angle)); + + Vector3 base = ins->transform.origin - ins->transform.basis.get_axis(2).normalized() * d; + + Vector3 points[2] = { + base, + base + cam_xf.basis.get_axis(0) * w + }; + + if (!p_cam_orthogonal) { + //if using perspetive, map them to near plane + for (int j = 0; j < 2; j++) { + if (p.distance_to(points[j]) < 0) { + points[j].z = -zn; //small hack to keep size constant when hitting the screen + } + + p.intersects_segment(cam_xf.origin, points[j], &points[j]); //map to plane + } + } + + float screen_diameter = points[0].distance_to(points[1]) * 2; + coverage = screen_diameter / (vp_half_extents.x + vp_half_extents.y); + + } break; + default: { + ERR_PRINT("Invalid Light Type"); + } + } + } + + if (light->shadow_dirty) { + light->last_version++; + light->shadow_dirty = false; + } + + bool redraw = scene_render->shadow_atlas_update_light(p_shadow_atlas, light->instance, coverage, light->last_version); + + if (redraw && max_shadows_used < MAX_UPDATE_SHADOWS) { + //must redraw! + RENDER_TIMESTAMP(">Rendering Light " + itos(i)); + light->shadow_dirty = _light_instance_update_shadow(ins, p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect, p_shadow_atlas, scenario, p_screen_lod_threshold); + RENDER_TIMESTAMP("<Rendering Light " + itos(i)); + } else { + light->shadow_dirty = redraw; + } + } + } + + //render SDFGI + + { + sdfgi_update_data.update_static = false; + + if (cull.sdfgi.region_count > 0) { + //update regions + for (uint32_t i = 0; i < cull.sdfgi.region_count; i++) { + render_sdfgi_data[i].instances.merge_unordered(frustum_cull_result.sdfgi_region_geometry_instances[i]); + render_sdfgi_data[i].region = i; + } + //check if static lights were culled + bool static_lights_culled = false; + for (uint32_t i = 0; i < cull.sdfgi.cascade_light_count; i++) { + if (frustum_cull_result.sdfgi_cascade_lights[i].size()) { + static_lights_culled = true; + break; + } + } + + if (static_lights_culled) { + sdfgi_update_data.static_cascade_count = cull.sdfgi.cascade_light_count; + sdfgi_update_data.static_cascade_indices = cull.sdfgi.cascade_light_index; + sdfgi_update_data.static_positional_lights = frustum_cull_result.sdfgi_cascade_lights; + sdfgi_update_data.update_static = true; + } + } + + if (p_render_buffers.is_valid()) { + sdfgi_update_data.directional_lights = &directional_lights; + sdfgi_update_data.positional_light_instances = scenario->dynamic_lights.ptr(); + sdfgi_update_data.positional_light_count = scenario->dynamic_lights.size(); + } + } + + //append the directional lights to the lights culled + for (int i = 0; i < directional_lights.size(); i++) { + frustum_cull_result.light_instances.push_back(directional_lights[i]); + } + + RID camera_effects; + if (p_force_camera_effects.is_valid()) { + camera_effects = p_force_camera_effects; + } else { + camera_effects = scenario->camera_effects; + } + /* PROCESS GEOMETRY AND DRAW SCENE */ + + RENDER_TIMESTAMP("Render Scene "); + scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, frustum_cull_result.geometry_instances, frustum_cull_result.light_instances, frustum_cull_result.reflections, frustum_cull_result.gi_probes, frustum_cull_result.decals, frustum_cull_result.lightmaps, p_environment, camera_effects, p_shadow_atlas, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass, p_screen_lod_threshold, render_shadow_data, max_shadows_used, render_sdfgi_data, cull.sdfgi.region_count, &sdfgi_update_data); + + for (uint32_t i = 0; i < max_shadows_used; i++) { + render_shadow_data[i].instances.clear(); + } + max_shadows_used = 0; + + for (uint32_t i = 0; i < cull.sdfgi.region_count; i++) { + render_sdfgi_data[i].instances.clear(); + } + + // virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold,const RenderShadowData *p_render_shadows,int p_render_shadow_count,const RenderSDFGIData *p_render_sdfgi_regions,int p_render_sdfgi_region_count,const RenderSDFGIStaticLightData *p_render_sdfgi_static_lights=nullptr) = 0; +} + +RID RendererSceneCull::_render_get_environment(RID p_camera, RID p_scenario) { + Camera *camera = camera_owner.getornull(p_camera); + if (camera && scene_render->is_environment(camera->env)) { + return camera->env; + } + + Scenario *scenario = scenario_owner.getornull(p_scenario); + if (!scenario) { + return RID(); + } + if (scene_render->is_environment(scenario->environment)) { + return scenario->environment; + } + + if (scene_render->is_environment(scenario->fallback_environment)) { + return scenario->fallback_environment; + } + + return RID(); +} + +void RendererSceneCull::render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) { +#ifndef _3D_DISABLED + + Scenario *scenario = scenario_owner.getornull(p_scenario); + + RID environment; + if (scenario->environment.is_valid()) { + environment = scenario->environment; + } else { + environment = scenario->fallback_environment; + } + RENDER_TIMESTAMP("Render Empty Scene "); + scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, PagedArray<RendererSceneRender::GeometryInstance *>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), RID(), RID(), p_shadow_atlas, scenario->reflection_atlas, RID(), 0, 0, nullptr, 0, nullptr, 0, nullptr); +#endif +} + +bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int p_step) { + InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(p_instance->base_data); + Scenario *scenario = p_instance->scenario; + ERR_FAIL_COND_V(!scenario, true); + + RenderingServerDefault::redraw_request(); //update, so it updates in editor + + if (p_step == 0) { + if (!scene_render->reflection_probe_instance_begin_render(reflection_probe->instance, scenario->reflection_atlas)) { + return true; //all full + } + } + + if (p_step >= 0 && p_step < 6) { + static const Vector3 view_normals[6] = { + Vector3(+1, 0, 0), + Vector3(-1, 0, 0), + Vector3(0, +1, 0), + Vector3(0, -1, 0), + Vector3(0, 0, +1), + Vector3(0, 0, -1) + }; + static const Vector3 view_up[6] = { + Vector3(0, -1, 0), + Vector3(0, -1, 0), + Vector3(0, 0, +1), + Vector3(0, 0, -1), + Vector3(0, -1, 0), + Vector3(0, -1, 0) + }; + + Vector3 extents = RSG::storage->reflection_probe_get_extents(p_instance->base); + Vector3 origin_offset = RSG::storage->reflection_probe_get_origin_offset(p_instance->base); + float max_distance = RSG::storage->reflection_probe_get_origin_max_distance(p_instance->base); + float size = scene_render->reflection_atlas_get_size(scenario->reflection_atlas); + float lod_threshold = RSG::storage->reflection_probe_get_lod_threshold(p_instance->base) / size; + + Vector3 edge = view_normals[p_step] * extents; + float distance = ABS(view_normals[p_step].dot(edge) - view_normals[p_step].dot(origin_offset)); //distance from origin offset to actual view distance limit + + max_distance = MAX(max_distance, distance); + + //render cubemap side + CameraMatrix cm; + cm.set_perspective(90, 1, 0.01, max_distance); + + Transform local_view; + local_view.set_look_at(origin_offset, origin_offset + view_normals[p_step], view_up[p_step]); + + Transform xform = p_instance->transform * local_view; + + RID shadow_atlas; + + bool use_shadows = RSG::storage->reflection_probe_renders_shadows(p_instance->base); + if (use_shadows) { + shadow_atlas = scenario->reflection_probe_shadow_atlas; + } + + RENDER_TIMESTAMP("Render Reflection Probe, Step " + itos(p_step)); + _render_scene(xform, cm, false, false, RID(), RID(), RID(), RSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, p_step, lod_threshold, use_shadows); + + } else { + //do roughness postprocess step until it believes it's done + RENDER_TIMESTAMP("Post-Process Reflection Probe, Step " + itos(p_step)); + return scene_render->reflection_probe_instance_postprocess_step(reflection_probe->instance); + } + + return false; +} + +void RendererSceneCull::render_probes() { + /* REFLECTION PROBES */ + + SelfList<InstanceReflectionProbeData> *ref_probe = reflection_probe_render_list.first(); + + bool busy = false; + + while (ref_probe) { + SelfList<InstanceReflectionProbeData> *next = ref_probe->next(); + RID base = ref_probe->self()->owner->base; + + switch (RSG::storage->reflection_probe_get_update_mode(base)) { + case RS::REFLECTION_PROBE_UPDATE_ONCE: { + if (busy) { //already rendering something + break; + } + + bool done = _render_reflection_probe_step(ref_probe->self()->owner, ref_probe->self()->render_step); + if (done) { + reflection_probe_render_list.remove(ref_probe); + } else { + ref_probe->self()->render_step++; + } + + busy = true; //do not render another one of this kind + } break; + case RS::REFLECTION_PROBE_UPDATE_ALWAYS: { + int step = 0; + bool done = false; + while (!done) { + done = _render_reflection_probe_step(ref_probe->self()->owner, step); + step++; + } + + reflection_probe_render_list.remove(ref_probe); + } break; + } + + ref_probe = next; + } + + /* GI PROBES */ + + SelfList<InstanceGIProbeData> *gi_probe = gi_probe_update_list.first(); + + if (gi_probe) { + RENDER_TIMESTAMP("Render GI Probes"); + } + + while (gi_probe) { + SelfList<InstanceGIProbeData> *next = gi_probe->next(); + + InstanceGIProbeData *probe = gi_probe->self(); + //Instance *instance_probe = probe->owner; + + //check if probe must be setup, but don't do if on the lighting thread + + bool cache_dirty = false; + int cache_count = 0; + { + int light_cache_size = probe->light_cache.size(); + const InstanceGIProbeData::LightCache *caches = probe->light_cache.ptr(); + const RID *instance_caches = probe->light_instances.ptr(); + + int idx = 0; //must count visible lights + for (Set<Instance *>::Element *E = probe->lights.front(); E; E = E->next()) { + Instance *instance = E->get(); + InstanceLightData *instance_light = (InstanceLightData *)instance->base_data; + if (!instance->visible) { + continue; + } + if (cache_dirty) { + //do nothing, since idx must count all visible lights anyway + } else if (idx >= light_cache_size) { + cache_dirty = true; + } else { + const InstanceGIProbeData::LightCache *cache = &caches[idx]; + + if ( + instance_caches[idx] != instance_light->instance || + cache->has_shadow != RSG::storage->light_has_shadow(instance->base) || + cache->type != RSG::storage->light_get_type(instance->base) || + cache->transform != instance->transform || + cache->color != RSG::storage->light_get_color(instance->base) || + cache->energy != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ENERGY) || + cache->bake_energy != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_INDIRECT_ENERGY) || + cache->radius != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_RANGE) || + cache->attenuation != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION) || + cache->spot_angle != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ANGLE) || + cache->spot_attenuation != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ATTENUATION)) { + cache_dirty = true; + } + } + + idx++; + } + + for (List<Instance *>::Element *E = probe->owner->scenario->directional_lights.front(); E; E = E->next()) { + Instance *instance = E->get(); + InstanceLightData *instance_light = (InstanceLightData *)instance->base_data; + if (!instance->visible) { + continue; + } + if (cache_dirty) { + //do nothing, since idx must count all visible lights anyway + } else if (idx >= light_cache_size) { + cache_dirty = true; + } else { + const InstanceGIProbeData::LightCache *cache = &caches[idx]; + + if ( + instance_caches[idx] != instance_light->instance || + cache->has_shadow != RSG::storage->light_has_shadow(instance->base) || + cache->type != RSG::storage->light_get_type(instance->base) || + cache->transform != instance->transform || + cache->color != RSG::storage->light_get_color(instance->base) || + cache->energy != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ENERGY) || + cache->bake_energy != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_INDIRECT_ENERGY) || + cache->radius != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_RANGE) || + cache->attenuation != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION) || + cache->spot_angle != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ANGLE) || + cache->spot_attenuation != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ATTENUATION) || + cache->sky_only != RSG::storage->light_directional_is_sky_only(instance->base)) { + cache_dirty = true; + } + } + + idx++; + } + + if (idx != light_cache_size) { + cache_dirty = true; + } + + cache_count = idx; + } + + bool update_lights = scene_render->gi_probe_needs_update(probe->probe_instance); + + if (cache_dirty) { + probe->light_cache.resize(cache_count); + probe->light_instances.resize(cache_count); + + if (cache_count) { + InstanceGIProbeData::LightCache *caches = probe->light_cache.ptrw(); + RID *instance_caches = probe->light_instances.ptrw(); + + int idx = 0; //must count visible lights + for (Set<Instance *>::Element *E = probe->lights.front(); E; E = E->next()) { + Instance *instance = E->get(); + InstanceLightData *instance_light = (InstanceLightData *)instance->base_data; + if (!instance->visible) { + continue; + } + + InstanceGIProbeData::LightCache *cache = &caches[idx]; + + instance_caches[idx] = instance_light->instance; + cache->has_shadow = RSG::storage->light_has_shadow(instance->base); + cache->type = RSG::storage->light_get_type(instance->base); + cache->transform = instance->transform; + cache->color = RSG::storage->light_get_color(instance->base); + cache->energy = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ENERGY); + cache->bake_energy = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_INDIRECT_ENERGY); + cache->radius = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_RANGE); + cache->attenuation = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION); + cache->spot_angle = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ANGLE); + cache->spot_attenuation = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ATTENUATION); + + idx++; + } + for (List<Instance *>::Element *E = probe->owner->scenario->directional_lights.front(); E; E = E->next()) { + Instance *instance = E->get(); + InstanceLightData *instance_light = (InstanceLightData *)instance->base_data; + if (!instance->visible) { + continue; + } + + InstanceGIProbeData::LightCache *cache = &caches[idx]; + + instance_caches[idx] = instance_light->instance; + cache->has_shadow = RSG::storage->light_has_shadow(instance->base); + cache->type = RSG::storage->light_get_type(instance->base); + cache->transform = instance->transform; + cache->color = RSG::storage->light_get_color(instance->base); + cache->energy = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ENERGY); + cache->bake_energy = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_INDIRECT_ENERGY); + cache->radius = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_RANGE); + cache->attenuation = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION); + cache->spot_angle = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ANGLE); + cache->spot_attenuation = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ATTENUATION); + cache->sky_only = RSG::storage->light_directional_is_sky_only(instance->base); + + idx++; + } + } + + update_lights = true; + } + + frustum_cull_result.geometry_instances.clear(); + + RID instance_pair_buffer[MAX_INSTANCE_PAIRS]; + + for (Set<Instance *>::Element *E = probe->dynamic_geometries.front(); E; E = E->next()) { + Instance *ins = E->get(); + if (!ins->visible) { + continue; + } + InstanceGeometryData *geom = (InstanceGeometryData *)ins->base_data; + + if (ins->scenario && ins->array_index >= 0 && (ins->scenario->instance_data[ins->array_index].flags & InstanceData::FLAG_GEOM_GI_PROBE_DIRTY)) { + uint32_t idx = 0; + for (Set<Instance *>::Element *F = geom->gi_probes.front(); F; F = F->next()) { + InstanceGIProbeData *gi_probe2 = static_cast<InstanceGIProbeData *>(F->get()->base_data); + + instance_pair_buffer[idx++] = gi_probe2->probe_instance; + if (idx == MAX_INSTANCE_PAIRS) { + break; + } + } + + scene_render->geometry_instance_pair_gi_probe_instances(geom->geometry_instance, instance_pair_buffer, idx); + + ins->scenario->instance_data[ins->array_index].flags &= ~uint32_t(InstanceData::FLAG_GEOM_GI_PROBE_DIRTY); + } + + frustum_cull_result.geometry_instances.push_back(geom->geometry_instance); + } + + scene_render->gi_probe_update(probe->probe_instance, update_lights, probe->light_instances, frustum_cull_result.geometry_instances); + + gi_probe_update_list.remove(gi_probe); + + gi_probe = next; + } +} + +void RendererSceneCull::render_particle_colliders() { + while (heightfield_particle_colliders_update_list.front()) { + Instance *hfpc = heightfield_particle_colliders_update_list.front()->get(); + + if (hfpc->scenario && hfpc->base_type == RS::INSTANCE_PARTICLES_COLLISION && RSG::storage->particles_collision_is_heightfield(hfpc->base)) { + //update heightfield + instance_cull_result.clear(); + frustum_cull_result.geometry_instances.clear(); + + struct CullAABB { + PagedArray<Instance *> *result; + _FORCE_INLINE_ bool operator()(void *p_data) { + Instance *p_instance = (Instance *)p_data; + result->push_back(p_instance); + return false; + } + }; + + CullAABB cull_aabb; + cull_aabb.result = &instance_cull_result; + hfpc->scenario->indexers[Scenario::INDEXER_GEOMETRY].aabb_query(hfpc->transformed_aabb, cull_aabb); + hfpc->scenario->indexers[Scenario::INDEXER_VOLUMES].aabb_query(hfpc->transformed_aabb, cull_aabb); + + for (int i = 0; i < (int)instance_cull_result.size(); i++) { + Instance *instance = instance_cull_result[i]; + if (!instance || !((1 << instance->base_type) & (RS::INSTANCE_GEOMETRY_MASK & (~(1 << RS::INSTANCE_PARTICLES))))) { //all but particles to avoid self collision + continue; + } + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + frustum_cull_result.geometry_instances.push_back(geom->geometry_instance); + } + + scene_render->render_particle_collider_heightfield(hfpc->base, hfpc->transform, frustum_cull_result.geometry_instances); + } + heightfield_particle_colliders_update_list.erase(heightfield_particle_colliders_update_list.front()); + } +} + +void RendererSceneCull::_update_instance_shader_parameters_from_material(Map<StringName, Instance::InstanceShaderParameter> &isparams, const Map<StringName, Instance::InstanceShaderParameter> &existing_isparams, RID p_material) { + List<RendererStorage::InstanceShaderParam> plist; + RSG::storage->material_get_instance_shader_parameters(p_material, &plist); + for (List<RendererStorage::InstanceShaderParam>::Element *E = plist.front(); E; E = E->next()) { + StringName name = E->get().info.name; + if (isparams.has(name)) { + if (isparams[name].info.type != E->get().info.type) { + WARN_PRINT("More than one material in instance export the same instance shader uniform '" + E->get().info.name + "', but they do it with different data types. Only the first one (in order) will display correctly."); + } + if (isparams[name].index != E->get().index) { + WARN_PRINT("More than one material in instance export the same instance shader uniform '" + E->get().info.name + "', but they do it with different indices. Only the first one (in order) will display correctly."); + } + continue; //first one found always has priority + } + + Instance::InstanceShaderParameter isp; + isp.index = E->get().index; + isp.info = E->get().info; + isp.default_value = E->get().default_value; + if (existing_isparams.has(name)) { + isp.value = existing_isparams[name].value; + } else { + isp.value = E->get().default_value; + } + isparams[name] = isp; + } +} + +void RendererSceneCull::_update_dirty_instance(Instance *p_instance) { + if (p_instance->update_aabb) { + _update_instance_aabb(p_instance); + } + + if (p_instance->update_dependencies) { + p_instance->dependency_tracker.update_begin(); + + if (p_instance->base.is_valid()) { + RSG::storage->base_update_dependency(p_instance->base, &p_instance->dependency_tracker); + } + + if (p_instance->material_override.is_valid()) { + RSG::storage->material_update_dependency(p_instance->material_override, &p_instance->dependency_tracker); + } + + if (p_instance->base_type == RS::INSTANCE_MESH) { + //remove materials no longer used and un-own them + + int new_mat_count = RSG::storage->mesh_get_surface_count(p_instance->base); + p_instance->materials.resize(new_mat_count); + + _instance_update_mesh_instance(p_instance); + } + + if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); + + bool can_cast_shadows = true; + bool is_animated = false; + Map<StringName, Instance::InstanceShaderParameter> isparams; + + if (p_instance->cast_shadows == RS::SHADOW_CASTING_SETTING_OFF) { + can_cast_shadows = false; + } + + if (p_instance->material_override.is_valid()) { + if (!RSG::storage->material_casts_shadows(p_instance->material_override)) { + can_cast_shadows = false; + } + is_animated = RSG::storage->material_is_animated(p_instance->material_override); + _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, p_instance->material_override); + } else { + if (p_instance->base_type == RS::INSTANCE_MESH) { + RID mesh = p_instance->base; + + if (mesh.is_valid()) { + bool cast_shadows = false; + + for (int i = 0; i < p_instance->materials.size(); i++) { + RID mat = p_instance->materials[i].is_valid() ? p_instance->materials[i] : RSG::storage->mesh_surface_get_material(mesh, i); + + if (!mat.is_valid()) { + cast_shadows = true; + } else { + if (RSG::storage->material_casts_shadows(mat)) { + cast_shadows = true; + } + + if (RSG::storage->material_is_animated(mat)) { + is_animated = true; + } + + _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat); + + RSG::storage->material_update_dependency(mat, &p_instance->dependency_tracker); + } + } + + if (!cast_shadows) { + can_cast_shadows = false; + } + } + + } else if (p_instance->base_type == RS::INSTANCE_MULTIMESH) { + RID mesh = RSG::storage->multimesh_get_mesh(p_instance->base); + if (mesh.is_valid()) { + bool cast_shadows = false; + + int sc = RSG::storage->mesh_get_surface_count(mesh); + for (int i = 0; i < sc; i++) { + RID mat = RSG::storage->mesh_surface_get_material(mesh, i); + + if (!mat.is_valid()) { + cast_shadows = true; + + } else { + if (RSG::storage->material_casts_shadows(mat)) { + cast_shadows = true; + } + if (RSG::storage->material_is_animated(mat)) { + is_animated = true; + } + + _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat); + + RSG::storage->material_update_dependency(mat, &p_instance->dependency_tracker); + } + } + + if (!cast_shadows) { + can_cast_shadows = false; + } + + RSG::storage->base_update_dependency(mesh, &p_instance->dependency_tracker); + } + } else if (p_instance->base_type == RS::INSTANCE_IMMEDIATE) { + RID mat = RSG::storage->immediate_get_material(p_instance->base); + + if (!(!mat.is_valid() || RSG::storage->material_casts_shadows(mat))) { + can_cast_shadows = false; + } + + if (mat.is_valid() && RSG::storage->material_is_animated(mat)) { + is_animated = true; + } + + if (mat.is_valid()) { + _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat); + } + + if (mat.is_valid()) { + RSG::storage->material_update_dependency(mat, &p_instance->dependency_tracker); + } + + } else if (p_instance->base_type == RS::INSTANCE_PARTICLES) { + bool cast_shadows = false; + + int dp = RSG::storage->particles_get_draw_passes(p_instance->base); + + for (int i = 0; i < dp; i++) { + RID mesh = RSG::storage->particles_get_draw_pass_mesh(p_instance->base, i); + if (!mesh.is_valid()) { + continue; + } + + int sc = RSG::storage->mesh_get_surface_count(mesh); + for (int j = 0; j < sc; j++) { + RID mat = RSG::storage->mesh_surface_get_material(mesh, j); + + if (!mat.is_valid()) { + cast_shadows = true; + } else { + if (RSG::storage->material_casts_shadows(mat)) { + cast_shadows = true; + } + + if (RSG::storage->material_is_animated(mat)) { + is_animated = true; + } + + _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat); + + RSG::storage->material_update_dependency(mat, &p_instance->dependency_tracker); + } + } + } + + if (!cast_shadows) { + can_cast_shadows = false; + } + } + } + + if (can_cast_shadows != geom->can_cast_shadows) { + //ability to cast shadows change, let lights now + for (Set<Instance *>::Element *E = geom->lights.front(); E; E = E->next()) { + InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data); + light->shadow_dirty = true; + } + + geom->can_cast_shadows = can_cast_shadows; + } + + geom->material_is_animated = is_animated; + p_instance->instance_shader_parameters = isparams; + + if (p_instance->instance_allocated_shader_parameters != (p_instance->instance_shader_parameters.size() > 0)) { + p_instance->instance_allocated_shader_parameters = (p_instance->instance_shader_parameters.size() > 0); + if (p_instance->instance_allocated_shader_parameters) { + p_instance->instance_allocated_shader_parameters_offset = RSG::storage->global_variables_instance_allocate(p_instance->self); + scene_render->geometry_instance_set_instance_shader_parameters_offset(geom->geometry_instance, p_instance->instance_allocated_shader_parameters_offset); + + for (Map<StringName, Instance::InstanceShaderParameter>::Element *E = p_instance->instance_shader_parameters.front(); E; E = E->next()) { + if (E->get().value.get_type() != Variant::NIL) { + RSG::storage->global_variables_instance_update(p_instance->self, E->get().index, E->get().value); + } + } + } else { + RSG::storage->global_variables_instance_free(p_instance->self); + p_instance->instance_allocated_shader_parameters_offset = -1; + scene_render->geometry_instance_set_instance_shader_parameters_offset(geom->geometry_instance, -1); + } + } + } + + if (p_instance->skeleton.is_valid()) { + RSG::storage->skeleton_update_dependency(p_instance->skeleton, &p_instance->dependency_tracker); + } + + p_instance->dependency_tracker.update_end(); + + if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); + scene_render->geometry_instance_set_surface_materials(geom->geometry_instance, p_instance->materials); + } + } + + _instance_update_list.remove(&p_instance->update_item); + + _update_instance(p_instance); + + p_instance->update_aabb = false; + p_instance->update_dependencies = false; +} + +void RendererSceneCull::update_dirty_instances() { + RSG::storage->update_dirty_resources(); + + while (_instance_update_list.first()) { + _update_dirty_instance(_instance_update_list.first()->self()); + } +} + +void RendererSceneCull::update() { + //optimize bvhs + for (uint32_t i = 0; i < scenario_owner.get_rid_count(); i++) { + Scenario *s = scenario_owner.get_ptr_by_index(i); + s->indexers[Scenario::INDEXER_GEOMETRY].optimize_incremental(indexer_update_iterations); + s->indexers[Scenario::INDEXER_VOLUMES].optimize_incremental(indexer_update_iterations); + } + scene_render->update(); + update_dirty_instances(); + render_particle_colliders(); +} + +bool RendererSceneCull::free(RID p_rid) { + if (scene_render->free(p_rid)) { + return true; + } + + if (camera_owner.owns(p_rid)) { + Camera *camera = camera_owner.getornull(p_rid); + + camera_owner.free(p_rid); + memdelete(camera); + + } else if (scenario_owner.owns(p_rid)) { + Scenario *scenario = scenario_owner.getornull(p_rid); + + while (scenario->instances.first()) { + instance_set_scenario(scenario->instances.first()->self()->self, RID()); + } + scenario->instance_aabbs.reset(); + scenario->instance_data.reset(); + + scene_render->free(scenario->reflection_probe_shadow_atlas); + scene_render->free(scenario->reflection_atlas); + scenario_owner.free(p_rid); + memdelete(scenario); + + } else if (instance_owner.owns(p_rid)) { + // delete the instance + + update_dirty_instances(); + + Instance *instance = instance_owner.getornull(p_rid); + + instance_geometry_set_lightmap(p_rid, RID(), Rect2(), 0); + instance_set_scenario(p_rid, RID()); + instance_set_base(p_rid, RID()); + instance_geometry_set_material_override(p_rid, RID()); + instance_attach_skeleton(p_rid, RID()); + + if (instance->instance_allocated_shader_parameters) { + //free the used shader parameters + RSG::storage->global_variables_instance_free(instance->self); + } + update_dirty_instances(); //in case something changed this + + instance_owner.free(p_rid); + memdelete(instance); + } else { + return false; + } + + return true; +} + +TypedArray<Image> RendererSceneCull::bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) { + return scene_render->bake_render_uv2(p_base, p_material_overrides, p_image_size); +} + +/*******************************/ +/* Passthrough to Scene Render */ +/*******************************/ + +/* ENVIRONMENT API */ + +RendererSceneCull *RendererSceneCull::singleton = nullptr; + +void RendererSceneCull::set_scene_render(RendererSceneRender *p_scene_render) { + scene_render = p_scene_render; + geometry_instance_pair_mask = scene_render->geometry_instance_get_pair_mask(); +} + +RendererSceneCull::RendererSceneCull() { + render_pass = 1; + singleton = this; + + instance_cull_result.set_page_pool(&instance_cull_page_pool); + instance_shadow_cull_result.set_page_pool(&instance_cull_page_pool); + + for (uint32_t i = 0; i < MAX_UPDATE_SHADOWS; i++) { + render_shadow_data[i].instances.set_page_pool(&geometry_instance_cull_page_pool); + } + for (uint32_t i = 0; i < SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE; i++) { + render_sdfgi_data[i].instances.set_page_pool(&geometry_instance_cull_page_pool); + } + + frustum_cull_result.init(&rid_cull_page_pool, &geometry_instance_cull_page_pool, &instance_cull_page_pool); + frustum_cull_result_threads.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count()); + for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) { + frustum_cull_result_threads[i].init(&rid_cull_page_pool, &geometry_instance_cull_page_pool, &instance_cull_page_pool); + } + + indexer_update_iterations = GLOBAL_GET("rendering/limits/spatial_indexer/update_iterations_per_frame"); + thread_cull_threshold = GLOBAL_GET("rendering/limits/spatial_indexer/threaded_cull_minimum_instances"); + thread_cull_threshold = MAX(thread_cull_threshold, (uint32_t)RendererThreadPool::singleton->thread_work_pool.get_thread_count()); //make sure there is at least one thread per CPU +} + +RendererSceneCull::~RendererSceneCull() { + instance_cull_result.reset(); + instance_shadow_cull_result.reset(); + + for (uint32_t i = 0; i < MAX_UPDATE_SHADOWS; i++) { + render_shadow_data[i].instances.reset(); + } + for (uint32_t i = 0; i < SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE; i++) { + render_sdfgi_data[i].instances.reset(); + } + + frustum_cull_result.reset(); + for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) { + frustum_cull_result_threads[i].reset(); + } + frustum_cull_result_threads.clear(); +} diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h new file mode 100644 index 0000000000..32f4334288 --- /dev/null +++ b/servers/rendering/renderer_scene_cull.h @@ -0,0 +1,1059 @@ +/*************************************************************************/ +/* renderer_scene_cull.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RENDERING_SERVER_SCENE_CULL_H +#define RENDERING_SERVER_SCENE_CULL_H + +#include "core/templates/pass_func.h" +#include "servers/rendering/renderer_compositor.h" + +#include "core/math/dynamic_bvh.h" +#include "core/math/geometry_3d.h" +#include "core/math/octree.h" +#include "core/os/semaphore.h" +#include "core/os/thread.h" +#include "core/templates/local_vector.h" +#include "core/templates/paged_allocator.h" +#include "core/templates/paged_array.h" +#include "core/templates/rid_owner.h" +#include "core/templates/self_list.h" +#include "servers/rendering/renderer_scene.h" +#include "servers/rendering/renderer_scene_render.h" +#include "servers/xr/xr_interface.h" +class RendererSceneCull : public RendererScene { +public: + RendererSceneRender *scene_render; + + enum { + SDFGI_MAX_CASCADES = 8, + SDFGI_MAX_REGIONS_PER_CASCADE = 3, + MAX_INSTANCE_PAIRS = 32, + MAX_UPDATE_SHADOWS = 512 + }; + + uint64_t render_pass; + + static RendererSceneCull *singleton; + + /* CAMERA API */ + + struct Camera { + enum Type { + PERSPECTIVE, + ORTHOGONAL, + FRUSTUM + }; + Type type; + float fov; + float znear, zfar; + float size; + Vector2 offset; + uint32_t visible_layers; + bool vaspect; + RID env; + RID effects; + + Transform transform; + + Camera() { + visible_layers = 0xFFFFFFFF; + fov = 75; + type = PERSPECTIVE; + znear = 0.05; + zfar = 4000; + size = 1.0; + offset = Vector2(); + vaspect = false; + } + }; + + mutable RID_PtrOwner<Camera, true> camera_owner; + + virtual RID camera_allocate(); + virtual void camera_initialize(RID p_rid); + + virtual void camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far); + virtual void camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far); + virtual void camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far); + virtual void camera_set_transform(RID p_camera, const Transform &p_transform); + virtual void camera_set_cull_mask(RID p_camera, uint32_t p_layers); + virtual void camera_set_environment(RID p_camera, RID p_env); + virtual void camera_set_camera_effects(RID p_camera, RID p_fx); + virtual void camera_set_use_vertical_aspect(RID p_camera, bool p_enable); + virtual bool is_camera(RID p_camera) const; + + /* SCENARIO API */ + + struct Instance; + + struct PlaneSign { + _ALWAYS_INLINE_ PlaneSign() {} + _ALWAYS_INLINE_ PlaneSign(const Plane &p_plane) { + if (p_plane.normal.x > 0) { + signs[0] = 0; + } else { + signs[0] = 3; + } + if (p_plane.normal.y > 0) { + signs[1] = 1; + } else { + signs[1] = 4; + } + if (p_plane.normal.z > 0) { + signs[2] = 2; + } else { + signs[2] = 5; + } + } + + uint32_t signs[3]; + }; + + struct Frustum { + Vector<Plane> planes; + Vector<PlaneSign> plane_signs; + const Plane *planes_ptr; + const PlaneSign *plane_signs_ptr; + uint32_t plane_count; + + _ALWAYS_INLINE_ Frustum() {} + _ALWAYS_INLINE_ Frustum(const Frustum &p_frustum) { + planes = p_frustum.planes; + plane_signs = p_frustum.plane_signs; + + planes_ptr = planes.ptr(); + plane_signs_ptr = plane_signs.ptr(); + plane_count = p_frustum.plane_count; + } + _ALWAYS_INLINE_ void operator=(const Frustum &p_frustum) { + planes = p_frustum.planes; + plane_signs = p_frustum.plane_signs; + + planes_ptr = planes.ptr(); + plane_signs_ptr = plane_signs.ptr(); + plane_count = p_frustum.plane_count; + } + _ALWAYS_INLINE_ Frustum(const Vector<Plane> &p_planes) { + planes = p_planes; + planes_ptr = planes.ptrw(); + plane_count = planes.size(); + for (int i = 0; i < planes.size(); i++) { + PlaneSign ps(p_planes[i]); + plane_signs.push_back(ps); + } + + plane_signs_ptr = plane_signs.ptr(); + } + }; + + struct InstanceBounds { + // Efficiently store instance bounds. + // Because bounds checking is performed first, + // keep it separated from data. + + real_t bounds[6]; + _ALWAYS_INLINE_ InstanceBounds() {} + + _ALWAYS_INLINE_ InstanceBounds(const AABB &p_aabb) { + bounds[0] = p_aabb.position.x; + bounds[1] = p_aabb.position.y; + bounds[2] = p_aabb.position.z; + bounds[3] = p_aabb.position.x + p_aabb.size.x; + bounds[4] = p_aabb.position.y + p_aabb.size.y; + bounds[5] = p_aabb.position.z + p_aabb.size.z; + } + _ALWAYS_INLINE_ bool in_frustum(const Frustum &p_frustum) const { + // This is not a full SAT check and the possibility of false positives exist, + // but the tradeoff vs performance is still very good. + + for (uint32_t i = 0; i < p_frustum.plane_count; i++) { + Vector3 min( + bounds[p_frustum.plane_signs_ptr[i].signs[0]], + bounds[p_frustum.plane_signs_ptr[i].signs[1]], + bounds[p_frustum.plane_signs_ptr[i].signs[2]]); + + if (p_frustum.planes_ptr[i].distance_to(min) >= 0.0) { + return false; + } + } + + return true; + } + _ALWAYS_INLINE_ bool in_aabb(const AABB &p_aabb) const { + Vector3 end = p_aabb.position + p_aabb.size; + + if (bounds[0] >= end.x) { + return false; + } + if (bounds[3] <= p_aabb.position.x) { + return false; + } + if (bounds[1] >= end.y) { + return false; + } + if (bounds[4] <= p_aabb.position.y) { + return false; + } + if (bounds[2] >= end.z) { + return false; + } + if (bounds[5] <= p_aabb.position.z) { + return false; + } + + return true; + } + }; + + struct InstanceData { + // Store instance pointer as well as common instance processing information, + // to make processing more cache friendly. + enum Flags { + FLAG_BASE_TYPE_MASK = 0xFF, + FLAG_CAST_SHADOWS = (1 << 8), + FLAG_CAST_SHADOWS_ONLY = (1 << 9), + FLAG_REDRAW_IF_VISIBLE = (1 << 10), + FLAG_GEOM_LIGHTING_DIRTY = (1 << 11), + FLAG_GEOM_REFLECTION_DIRTY = (1 << 12), + FLAG_GEOM_DECAL_DIRTY = (1 << 13), + FLAG_GEOM_GI_PROBE_DIRTY = (1 << 14), + FLAG_LIGHTMAP_CAPTURE = (1 << 15), + FLAG_USES_BAKED_LIGHT = (1 << 16), + FLAG_USES_MESH_INSTANCE = (1 << 17), + FLAG_REFLECTION_PROBE_DIRTY = (1 << 18), + }; + + uint32_t flags = 0; + uint32_t layer_mask = 0; //for fast layer-mask discard + RID base_rid; + union { + uint64_t instance_data_rid; + RendererSceneRender::GeometryInstance *instance_geometry; + }; + Instance *instance = nullptr; + }; + + PagedArrayPool<InstanceBounds> instance_aabb_page_pool; + PagedArrayPool<InstanceData> instance_data_page_pool; + + struct Scenario { + enum IndexerType { + INDEXER_GEOMETRY, //for geometry + INDEXER_VOLUMES, //for everything else + INDEXER_MAX + }; + + DynamicBVH indexers[INDEXER_MAX]; + + RS::ScenarioDebugMode debug; + RID self; + + List<Instance *> directional_lights; + RID environment; + RID fallback_environment; + RID camera_effects; + RID reflection_probe_shadow_atlas; + RID reflection_atlas; + + SelfList<Instance>::List instances; + + LocalVector<RID> dynamic_lights; + + PagedArray<InstanceBounds> instance_aabbs; + PagedArray<InstanceData> instance_data; + + Scenario() { + indexers[INDEXER_GEOMETRY].set_index(INDEXER_GEOMETRY); + indexers[INDEXER_VOLUMES].set_index(INDEXER_VOLUMES); + debug = RS::SCENARIO_DEBUG_DISABLED; + } + }; + + int indexer_update_iterations = 0; + + mutable RID_PtrOwner<Scenario, true> scenario_owner; + + static void _instance_pair(Instance *p_A, Instance *p_B); + static void _instance_unpair(Instance *p_A, Instance *p_B); + + void _instance_update_mesh_instance(Instance *p_instance); + + virtual RID scenario_allocate(); + virtual void scenario_initialize(RID p_rid); + + virtual void scenario_set_debug(RID p_scenario, RS::ScenarioDebugMode p_debug_mode); + virtual void scenario_set_environment(RID p_scenario, RID p_environment); + virtual void scenario_set_camera_effects(RID p_scenario, RID p_fx); + virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment); + virtual void scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count); + virtual bool is_scenario(RID p_scenario) const; + virtual RID scenario_get_environment(RID p_scenario); + + /* INSTANCING API */ + + struct InstancePair { + Instance *a; + Instance *b; + SelfList<InstancePair> list_a; + SelfList<InstancePair> list_b; + InstancePair() : + list_a(this), list_b(this) {} + }; + + PagedAllocator<InstancePair> pair_allocator; + + struct InstanceBaseData { + virtual ~InstanceBaseData() {} + }; + + struct Instance { + RS::InstanceType base_type; + RID base; + + RID skeleton; + RID material_override; + + RID mesh_instance; //only used for meshes and when skeleton/blendshapes exist + + Transform transform; + + float lod_bias; + + Vector<RID> materials; + + RS::ShadowCastingSetting cast_shadows; + + uint32_t layer_mask; + //fit in 32 bits + bool mirror : 8; + bool receive_shadows : 8; + bool visible : 8; + bool baked_light : 2; //this flag is only to know if it actually did use baked light + bool dynamic_gi : 2; //same above for dynamic objects + bool redraw_if_visible : 4; + + Instance *lightmap; + Rect2 lightmap_uv_scale; + int lightmap_slice_index; + uint32_t lightmap_cull_index; + Vector<Color> lightmap_sh; //spherical harmonic + + AABB aabb; + AABB transformed_aabb; + AABB prev_transformed_aabb; + + struct InstanceShaderParameter { + int32_t index = -1; + Variant value; + Variant default_value; + PropertyInfo info; + }; + + Map<StringName, InstanceShaderParameter> instance_shader_parameters; + bool instance_allocated_shader_parameters = false; + int32_t instance_allocated_shader_parameters_offset = -1; + + // + + RID self; + //scenario stuff + DynamicBVH::ID indexer_id; + int32_t array_index; + Scenario *scenario; + SelfList<Instance> scenario_item; + + //aabb stuff + bool update_aabb; + bool update_dependencies; + + SelfList<Instance> update_item; + + AABB *custom_aabb; // <Zylann> would using aabb directly with a bool be better? + float extra_margin; + ObjectID object_id; + + float lod_begin; + float lod_end; + float lod_begin_hysteresis; + float lod_end_hysteresis; + RID lod_instance; + + Vector<Color> lightmap_target_sh; //target is used for incrementally changing the SH over time, this avoids pops in some corner cases and when going interior <-> exterior + + uint64_t last_frame_pass; + + uint64_t version; // changes to this, and changes to base increase version + + InstanceBaseData *base_data; + + SelfList<InstancePair>::List pairs; + uint64_t pair_check; + + RendererStorage::DependencyTracker dependency_tracker; + + static void dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *tracker) { + Instance *instance = (Instance *)tracker->userdata; + switch (p_notification) { + case RendererStorage::DEPENDENCY_CHANGED_SKELETON_DATA: + case RendererStorage::DEPENDENCY_CHANGED_AABB: { + singleton->_instance_queue_update(instance, true, false); + + } break; + case RendererStorage::DEPENDENCY_CHANGED_MATERIAL: { + singleton->_instance_queue_update(instance, false, true); + } break; + case RendererStorage::DEPENDENCY_CHANGED_MESH: + case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH: + case RendererStorage::DEPENDENCY_CHANGED_DECAL: + case RendererStorage::DEPENDENCY_CHANGED_LIGHT: + case RendererStorage::DEPENDENCY_CHANGED_REFLECTION_PROBE: { + singleton->_instance_queue_update(instance, true, true); + } break; + case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES: + case RendererStorage::DEPENDENCY_CHANGED_SKELETON_BONES: { + //ignored + } break; + } + } + + static void dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *tracker) { + Instance *instance = (Instance *)tracker->userdata; + + if (p_dependency == instance->base) { + singleton->instance_set_base(instance->self, RID()); + } else if (p_dependency == instance->skeleton) { + singleton->instance_attach_skeleton(instance->self, RID()); + } else { + singleton->_instance_queue_update(instance, false, true); + } + } + + Instance() : + scenario_item(this), + update_item(this) { + base_type = RS::INSTANCE_NONE; + cast_shadows = RS::SHADOW_CASTING_SETTING_ON; + receive_shadows = true; + visible = true; + layer_mask = 1; + baked_light = false; + dynamic_gi = false; + redraw_if_visible = false; + lightmap_slice_index = 0; + lightmap = nullptr; + lightmap_cull_index = 0; + lod_bias = 1.0; + + scenario = nullptr; + + update_aabb = false; + update_dependencies = false; + + extra_margin = 0; + + visible = true; + + lod_begin = 0; + lod_end = 0; + lod_begin_hysteresis = 0; + lod_end_hysteresis = 0; + + last_frame_pass = 0; + version = 1; + base_data = nullptr; + + custom_aabb = nullptr; + + pair_check = 0; + array_index = -1; + + dependency_tracker.userdata = this; + dependency_tracker.changed_callback = dependency_changed; + dependency_tracker.deleted_callback = dependency_deleted; + } + + ~Instance() { + if (base_data) { + memdelete(base_data); + } + if (custom_aabb) { + memdelete(custom_aabb); + } + } + }; + + SelfList<Instance>::List _instance_update_list; + void _instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_dependencies = false); + + struct InstanceGeometryData : public InstanceBaseData { + RendererSceneRender::GeometryInstance *geometry_instance = nullptr; + Set<Instance *> lights; + bool can_cast_shadows; + bool material_is_animated; + + Set<Instance *> decals; + Set<Instance *> reflection_probes; + Set<Instance *> gi_probes; + Set<Instance *> lightmap_captures; + + InstanceGeometryData() { + can_cast_shadows = true; + material_is_animated = true; + } + }; + + struct InstanceReflectionProbeData : public InstanceBaseData { + Instance *owner; + + Set<Instance *> geometries; + + RID instance; + SelfList<InstanceReflectionProbeData> update_list; + + int render_step; + + InstanceReflectionProbeData() : + update_list(this) { + render_step = -1; + } + }; + + struct InstanceDecalData : public InstanceBaseData { + Instance *owner; + RID instance; + + Set<Instance *> geometries; + + InstanceDecalData() { + } + }; + + SelfList<InstanceReflectionProbeData>::List reflection_probe_render_list; + + struct InstanceParticlesCollisionData : public InstanceBaseData { + RID instance; + }; + + struct InstanceLightData : public InstanceBaseData { + RID instance; + uint64_t last_version; + List<Instance *>::Element *D; // directional light in scenario + + bool shadow_dirty; + + Set<Instance *> geometries; + + Instance *baked_light; + + RS::LightBakeMode bake_mode; + uint32_t max_sdfgi_cascade = 2; + + InstanceLightData() { + bake_mode = RS::LIGHT_BAKE_DISABLED; + shadow_dirty = true; + D = nullptr; + last_version = 0; + baked_light = nullptr; + } + }; + + struct InstanceGIProbeData : public InstanceBaseData { + Instance *owner; + + Set<Instance *> geometries; + Set<Instance *> dynamic_geometries; + + Set<Instance *> lights; + + struct LightCache { + RS::LightType type; + Transform transform; + Color color; + float energy; + float bake_energy; + float radius; + float attenuation; + float spot_angle; + float spot_attenuation; + bool has_shadow; + bool sky_only; + }; + + Vector<LightCache> light_cache; + Vector<RID> light_instances; + + RID probe_instance; + + bool invalid; + uint32_t base_version; + + SelfList<InstanceGIProbeData> update_element; + + InstanceGIProbeData() : + update_element(this) { + invalid = true; + base_version = 0; + } + }; + + SelfList<InstanceGIProbeData>::List gi_probe_update_list; + + struct InstanceLightmapData : public InstanceBaseData { + RID instance; + Set<Instance *> geometries; + Set<Instance *> users; + + InstanceLightmapData() { + } + }; + + uint64_t pair_pass = 1; + + struct PairInstances { + Instance *instance = nullptr; + PagedAllocator<InstancePair> *pair_allocator = nullptr; + SelfList<InstancePair>::List pairs_found; + DynamicBVH *bvh = nullptr; + DynamicBVH *bvh2 = nullptr; //some may need to cull in two + uint32_t pair_mask; + uint64_t pair_pass; + + _FORCE_INLINE_ bool operator()(void *p_data) { + Instance *p_instance = (Instance *)p_data; + if (instance != p_instance && instance->transformed_aabb.intersects(p_instance->transformed_aabb) && (pair_mask & (1 << p_instance->base_type))) { + //test is more coarse in indexer + p_instance->pair_check = pair_pass; + InstancePair *pair = pair_allocator->alloc(); + pair->a = instance; + pair->b = p_instance; + pairs_found.add(&pair->list_a); + } + return false; + } + + void pair() { + if (bvh) { + bvh->aabb_query(instance->transformed_aabb, *this); + } + if (bvh2) { + bvh2->aabb_query(instance->transformed_aabb, *this); + } + while (instance->pairs.first()) { + InstancePair *pair = instance->pairs.first()->self(); + Instance *other_instance = instance == pair->a ? pair->b : pair->a; + if (other_instance->pair_check != pair_pass) { + //unpaired + _instance_unpair(instance, other_instance); + } else { + //kept + other_instance->pair_check = 0; // if kept, then put pair check to zero, so we can distinguish with the newly added ones + } + + pair_allocator->free(pair); + } + while (pairs_found.first()) { + InstancePair *pair = pairs_found.first()->self(); + pairs_found.remove(pairs_found.first()); + + if (pair->b->pair_check == pair_pass) { + //paired + _instance_pair(instance, pair->b); + } + pair->a->pairs.add(&pair->list_a); + pair->b->pairs.add(&pair->list_b); + } + } + }; + + Set<Instance *> heightfield_particle_colliders_update_list; + + PagedArrayPool<Instance *> instance_cull_page_pool; + PagedArrayPool<RendererSceneRender::GeometryInstance *> geometry_instance_cull_page_pool; + PagedArrayPool<RID> rid_cull_page_pool; + + PagedArray<Instance *> instance_cull_result; + PagedArray<Instance *> instance_shadow_cull_result; + + struct FrustumCullResult { + PagedArray<RendererSceneRender::GeometryInstance *> geometry_instances; + PagedArray<Instance *> lights; + PagedArray<RID> light_instances; + PagedArray<RID> lightmaps; + PagedArray<RID> reflections; + PagedArray<RID> decals; + PagedArray<RID> gi_probes; + PagedArray<RID> mesh_instances; + + struct DirectionalShadow { + PagedArray<RendererSceneRender::GeometryInstance *> cascade_geometry_instances[RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES]; + } directional_shadows[RendererSceneRender::MAX_DIRECTIONAL_LIGHTS]; + + PagedArray<RendererSceneRender::GeometryInstance *> sdfgi_region_geometry_instances[SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE]; + PagedArray<RID> sdfgi_cascade_lights[SDFGI_MAX_CASCADES]; + + void clear() { + geometry_instances.clear(); + lights.clear(); + light_instances.clear(); + lightmaps.clear(); + reflections.clear(); + decals.clear(); + gi_probes.clear(); + mesh_instances.clear(); + for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) { + for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) { + directional_shadows[i].cascade_geometry_instances[j].clear(); + } + } + + for (int i = 0; i < SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE; i++) { + sdfgi_region_geometry_instances[i].clear(); + } + + for (int i = 0; i < SDFGI_MAX_CASCADES; i++) { + sdfgi_cascade_lights[i].clear(); + } + } + + void reset() { + geometry_instances.reset(); + lights.reset(); + light_instances.reset(); + lightmaps.reset(); + reflections.reset(); + decals.reset(); + gi_probes.reset(); + mesh_instances.reset(); + for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) { + for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) { + directional_shadows[i].cascade_geometry_instances[j].reset(); + } + } + + for (int i = 0; i < SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE; i++) { + sdfgi_region_geometry_instances[i].reset(); + } + + for (int i = 0; i < SDFGI_MAX_CASCADES; i++) { + sdfgi_cascade_lights[i].reset(); + } + } + + void append_from(FrustumCullResult &p_cull_result) { + geometry_instances.merge_unordered(p_cull_result.geometry_instances); + lights.merge_unordered(p_cull_result.lights); + light_instances.merge_unordered(p_cull_result.light_instances); + lightmaps.merge_unordered(p_cull_result.lightmaps); + reflections.merge_unordered(p_cull_result.reflections); + decals.merge_unordered(p_cull_result.decals); + gi_probes.merge_unordered(p_cull_result.gi_probes); + mesh_instances.merge_unordered(p_cull_result.mesh_instances); + + for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) { + for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) { + directional_shadows[i].cascade_geometry_instances[j].merge_unordered(p_cull_result.directional_shadows[i].cascade_geometry_instances[j]); + } + } + + for (int i = 0; i < SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE; i++) { + sdfgi_region_geometry_instances[i].merge_unordered(p_cull_result.sdfgi_region_geometry_instances[i]); + } + + for (int i = 0; i < SDFGI_MAX_CASCADES; i++) { + sdfgi_cascade_lights[i].merge_unordered(p_cull_result.sdfgi_cascade_lights[i]); + } + } + + void init(PagedArrayPool<RID> *p_rid_pool, PagedArrayPool<RendererSceneRender::GeometryInstance *> *p_geometry_instance_pool, PagedArrayPool<Instance *> *p_instance_pool) { + geometry_instances.set_page_pool(p_geometry_instance_pool); + light_instances.set_page_pool(p_rid_pool); + lights.set_page_pool(p_instance_pool); + lightmaps.set_page_pool(p_rid_pool); + reflections.set_page_pool(p_rid_pool); + decals.set_page_pool(p_rid_pool); + gi_probes.set_page_pool(p_rid_pool); + mesh_instances.set_page_pool(p_rid_pool); + for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) { + for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) { + directional_shadows[i].cascade_geometry_instances[j].set_page_pool(p_geometry_instance_pool); + } + } + + for (int i = 0; i < SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE; i++) { + sdfgi_region_geometry_instances[i].set_page_pool(p_geometry_instance_pool); + } + + for (int i = 0; i < SDFGI_MAX_CASCADES; i++) { + sdfgi_cascade_lights[i].set_page_pool(p_rid_pool); + } + } + }; + + FrustumCullResult frustum_cull_result; + LocalVector<FrustumCullResult> frustum_cull_result_threads; + + RendererSceneRender::RenderShadowData render_shadow_data[MAX_UPDATE_SHADOWS]; + uint32_t max_shadows_used = 0; + + RendererSceneRender::RenderSDFGIData render_sdfgi_data[SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE]; + RendererSceneRender::RenderSDFGIUpdateData sdfgi_update_data; + + uint32_t thread_cull_threshold = 200; + + RID_PtrOwner<Instance, true> instance_owner; + + uint32_t geometry_instance_pair_mask; // used in traditional forward, unnecesary on clustered + + virtual RID instance_allocate(); + virtual void instance_initialize(RID p_rid); + + virtual void instance_set_base(RID p_instance, RID p_base); + virtual void instance_set_scenario(RID p_instance, RID p_scenario); + virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask); + virtual void instance_set_transform(RID p_instance, const Transform &p_transform); + virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id); + virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight); + virtual void instance_set_surface_material(RID p_instance, int p_surface, RID p_material); + virtual void instance_set_visible(RID p_instance, bool p_visible); + + virtual void instance_set_custom_aabb(RID p_instance, AABB p_aabb); + + virtual void instance_attach_skeleton(RID p_instance, RID p_skeleton); + virtual void instance_set_exterior(RID p_instance, bool p_enabled); + + virtual void instance_set_extra_visibility_margin(RID p_instance, real_t p_margin); + + // don't use these in a game! + virtual Vector<ObjectID> instances_cull_aabb(const AABB &p_aabb, RID p_scenario = RID()) const; + virtual Vector<ObjectID> instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario = RID()) const; + virtual Vector<ObjectID> instances_cull_convex(const Vector<Plane> &p_convex, RID p_scenario = RID()) const; + + virtual void instance_geometry_set_flag(RID p_instance, RS::InstanceFlags p_flags, bool p_enabled); + virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, RS::ShadowCastingSetting p_shadow_casting_setting); + virtual void instance_geometry_set_material_override(RID p_instance, RID p_material); + + virtual void instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin); + virtual void instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance); + virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index); + virtual void instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias); + + void _update_instance_shader_parameters_from_material(Map<StringName, Instance::InstanceShaderParameter> &isparams, const Map<StringName, Instance::InstanceShaderParameter> &existing_isparams, RID p_material); + + virtual void instance_geometry_set_shader_parameter(RID p_instance, const StringName &p_parameter, const Variant &p_value); + virtual void instance_geometry_get_shader_parameter_list(RID p_instance, List<PropertyInfo> *p_parameters) const; + virtual Variant instance_geometry_get_shader_parameter(RID p_instance, const StringName &p_parameter) const; + virtual Variant instance_geometry_get_shader_parameter_default_value(RID p_instance, const StringName &p_parameter) const; + + _FORCE_INLINE_ void _update_instance(Instance *p_instance); + _FORCE_INLINE_ void _update_instance_aabb(Instance *p_instance); + _FORCE_INLINE_ void _update_dirty_instance(Instance *p_instance); + _FORCE_INLINE_ void _update_instance_lightmap_captures(Instance *p_instance); + void _unpair_instance(Instance *p_instance); + + void _light_instance_setup_directional_shadow(int p_shadow_index, Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect); + + _FORCE_INLINE_ bool _light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario, float p_scren_lod_threshold); + + RID _render_get_environment(RID p_camera, RID p_scenario); + + struct Cull { + struct Shadow { + RID light_instance; + struct Cascade { + Frustum frustum; + + CameraMatrix projection; + Transform transform; + real_t zfar; + real_t split; + real_t shadow_texel_size; + real_t bias_scale; + real_t range_begin; + Vector2 uv_scale; + + } cascades[RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES]; //max 4 cascades + uint32_t cascade_count; + + } shadows[RendererSceneRender::MAX_DIRECTIONAL_LIGHTS]; + + uint32_t shadow_count; + + struct SDFGI { + //have arrays here because SDFGI functions expects this, plus regions can have areas + AABB region_aabb[SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE]; //max 3 regions per cascade + uint32_t region_cascade[SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE]; //max 3 regions per cascade + uint32_t region_count = 0; + + uint32_t cascade_light_index[SDFGI_MAX_CASCADES]; + uint32_t cascade_light_count = 0; + + } sdfgi; + + SpinLock lock; + + Frustum frustum; + } cull; + + struct FrustumCullData { + Cull *cull; + Scenario *scenario; + RID shadow_atlas; + Transform cam_transform; + uint32_t visible_layers; + Instance *render_reflection_probe; + }; + + void _frustum_cull_threaded(uint32_t p_thread, FrustumCullData *cull_data); + void _frustum_cull(FrustumCullData &cull_data, FrustumCullResult &cull_result, uint64_t p_from, uint64_t p_to); + + bool _render_reflection_probe_step(Instance *p_instance, int p_step); + void _render_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_render_buffers, RID p_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, bool p_using_shadows = true); + void render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas); + + void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas); + void render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas); + void update_dirty_instances(); + + void render_particle_colliders(); + virtual void render_probes(); + + TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size); + + //pass to scene render + + /* ENVIRONMENT API */ + +#ifdef PASSBASE +#undef PASSBASE +#endif + +#define PASSBASE scene_render + + PASS2(directional_shadow_atlas_set_size, int, bool) + PASS1(gi_probe_set_quality, RS::GIProbeQuality) + + /* SKY API */ + + PASS0R(RID, sky_allocate) + PASS1(sky_initialize, RID) + + PASS2(sky_set_radiance_size, RID, int) + PASS2(sky_set_mode, RID, RS::SkyMode) + PASS2(sky_set_material, RID, RID) + PASS4R(Ref<Image>, sky_bake_panorama, RID, float, bool, const Size2i &) + + PASS0R(RID, environment_allocate) + PASS1(environment_initialize, RID) + + PASS1RC(bool, is_environment, RID) + + PASS2(environment_set_background, RID, RS::EnvironmentBG) + PASS2(environment_set_sky, RID, RID) + PASS2(environment_set_sky_custom_fov, RID, float) + PASS2(environment_set_sky_orientation, RID, const Basis &) + PASS2(environment_set_bg_color, RID, const Color &) + PASS2(environment_set_bg_energy, RID, float) + PASS2(environment_set_canvas_max_layer, RID, int) + PASS7(environment_set_ambient_light, RID, const Color &, RS::EnvironmentAmbientSource, float, float, RS::EnvironmentReflectionSource, const Color &) + + PASS6(environment_set_ssr, RID, bool, int, float, float, float) + PASS1(environment_set_ssr_roughness_quality, RS::EnvironmentSSRRoughnessQuality) + + PASS10(environment_set_ssao, RID, bool, float, float, float, float, float, float, float, float) + PASS6(environment_set_ssao_quality, RS::EnvironmentSSAOQuality, bool, float, int, float, float) + + PASS11(environment_set_glow, RID, bool, Vector<float>, float, float, float, float, RS::EnvironmentGlowBlendMode, float, float, float) + PASS1(environment_glow_set_use_bicubic_upscale, bool) + PASS1(environment_glow_set_use_high_quality, bool) + + PASS9(environment_set_tonemap, RID, RS::EnvironmentToneMapper, float, float, bool, float, float, float, float) + + PASS7(environment_set_adjustment, RID, bool, float, float, float, bool, RID) + + PASS9(environment_set_fog, RID, bool, const Color &, float, float, float, float, float, float) + PASS10(environment_set_volumetric_fog, RID, bool, float, const Color &, float, float, float, float, bool, float) + + PASS2(environment_set_volumetric_fog_volume_size, int, int) + PASS1(environment_set_volumetric_fog_filter_active, bool) + + PASS11(environment_set_sdfgi, RID, bool, RS::EnvironmentSDFGICascades, float, RS::EnvironmentSDFGIYScale, bool, float, bool, float, float, float) + PASS1(environment_set_sdfgi_ray_count, RS::EnvironmentSDFGIRayCount) + PASS1(environment_set_sdfgi_frames_to_converge, RS::EnvironmentSDFGIFramesToConverge) + PASS1(environment_set_sdfgi_frames_to_update_light, RS::EnvironmentSDFGIFramesToUpdateLight) + + PASS1RC(RS::EnvironmentBG, environment_get_background, RID) + PASS1RC(int, environment_get_canvas_max_layer, RID) + + PASS3R(Ref<Image>, environment_bake_panorama, RID, bool, const Size2i &) + + PASS3(screen_space_roughness_limiter_set_active, bool, float, float) + PASS1(sub_surface_scattering_set_quality, RS::SubSurfaceScatteringQuality) + PASS2(sub_surface_scattering_set_scale, float, float) + + /* CAMERA EFFECTS */ + + PASS0R(RID, camera_effects_allocate) + PASS1(camera_effects_initialize, RID) + + PASS2(camera_effects_set_dof_blur_quality, RS::DOFBlurQuality, bool) + PASS1(camera_effects_set_dof_blur_bokeh_shape, RS::DOFBokehShape) + + PASS8(camera_effects_set_dof_blur, RID, bool, float, float, bool, float, float, float) + PASS3(camera_effects_set_custom_exposure, RID, bool, float) + + PASS1(shadows_quality_set, RS::ShadowQuality) + PASS1(directional_shadow_quality_set, RS::ShadowQuality) + + PASS2(sdfgi_set_debug_probe_select, const Vector3 &, const Vector3 &) + + /* Render Buffers */ + + PASS0R(RID, render_buffers_create) + PASS7(render_buffers_configure, RID, RID, int, int, RS::ViewportMSAA, RS::ViewportScreenSpaceAA, bool) + PASS1(gi_set_use_half_resolution, bool) + + /* Shadow Atlas */ + PASS0R(RID, shadow_atlas_create) + PASS3(shadow_atlas_set_size, RID, int, bool) + PASS3(shadow_atlas_set_quadrant_subdivision, RID, int, int) + + PASS1(set_debug_draw_mode, RS::ViewportDebugDraw) + + virtual void update(); + + bool free(RID p_rid); + + void set_scene_render(RendererSceneRender *p_scene_render); + + RendererSceneCull(); + virtual ~RendererSceneCull(); +}; + +#endif // VISUALSERVERSCENE_H diff --git a/servers/rendering/renderer_scene_render.cpp b/servers/rendering/renderer_scene_render.cpp new file mode 100644 index 0000000000..f27bdc6798 --- /dev/null +++ b/servers/rendering/renderer_scene_render.cpp @@ -0,0 +1,31 @@ +/*************************************************************************/ +/* renderer_scene_render.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "renderer_scene_render.h" diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h new file mode 100644 index 0000000000..1dea3580b6 --- /dev/null +++ b/servers/rendering/renderer_scene_render.h @@ -0,0 +1,250 @@ +/*************************************************************************/ +/* renderer_scene_render.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RENDERINGSERVERSCENERENDER_H +#define RENDERINGSERVERSCENERENDER_H + +#include "core/math/camera_matrix.h" +#include "core/templates/paged_array.h" +#include "servers/rendering/renderer_storage.h" + +class RendererSceneRender { +public: + enum { + MAX_DIRECTIONAL_LIGHTS = 8, + MAX_DIRECTIONAL_LIGHT_CASCADES = 4 + }; + + struct GeometryInstance { + virtual ~GeometryInstance() {} + }; + + virtual GeometryInstance *geometry_instance_create(RID p_base) = 0; + virtual void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) = 0; + virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) = 0; + virtual void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_material) = 0; + virtual void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) = 0; + virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) = 0; + virtual void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) = 0; + virtual void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) = 0; + virtual void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) = 0; + virtual void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) = 0; + virtual void geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) = 0; + virtual void geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) = 0; + virtual void geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) = 0; + virtual void geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) = 0; + + virtual uint32_t geometry_instance_get_pair_mask() = 0; + virtual void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) = 0; + virtual void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) = 0; + virtual void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) = 0; + virtual void geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) = 0; + + virtual void geometry_instance_free(GeometryInstance *p_geometry_instance) = 0; + + /* SHADOW ATLAS API */ + + virtual RID shadow_atlas_create() = 0; + virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = false) = 0; + virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) = 0; + virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) = 0; + + virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = false) = 0; + virtual int get_directional_light_shadow_size(RID p_light_intance) = 0; + virtual void set_directional_shadow_count(int p_count) = 0; + + /* SDFGI UPDATE */ + + virtual void sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) = 0; + virtual int sdfgi_get_pending_region_count(RID p_render_buffers) const = 0; + virtual AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const = 0; + virtual uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const = 0; + + /* SKY API */ + + virtual RID sky_allocate() = 0; + virtual void sky_initialize(RID p_rid) = 0; + + virtual void sky_set_radiance_size(RID p_sky, int p_radiance_size) = 0; + virtual void sky_set_mode(RID p_sky, RS::SkyMode p_samples) = 0; + virtual void sky_set_material(RID p_sky, RID p_material) = 0; + virtual Ref<Image> sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) = 0; + + /* ENVIRONMENT API */ + + virtual RID environment_allocate() = 0; + virtual void environment_initialize(RID p_rid) = 0; + + virtual void environment_set_background(RID p_env, RS::EnvironmentBG p_bg) = 0; + virtual void environment_set_sky(RID p_env, RID p_sky) = 0; + virtual void environment_set_sky_custom_fov(RID p_env, float p_scale) = 0; + virtual void environment_set_sky_orientation(RID p_env, const Basis &p_orientation) = 0; + virtual void environment_set_bg_color(RID p_env, const Color &p_color) = 0; + virtual void environment_set_bg_energy(RID p_env, float p_energy) = 0; + virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer) = 0; + virtual void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG, const Color &p_ao_color = Color()) = 0; +// FIXME: Disabled during Vulkan refactoring, should be ported. +#if 0 + virtual void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) = 0; +#endif + + virtual void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) = 0; + virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) = 0; + virtual void environment_glow_set_use_high_quality(bool p_enable) = 0; + + virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) = 0; + virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) = 0; + virtual void environment_set_volumetric_fog_filter_active(bool p_enable) = 0; + + virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) = 0; + virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) = 0; + + virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) = 0; + + virtual void 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) = 0; + + virtual void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) = 0; + + virtual void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) = 0; + virtual void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) = 0; + virtual void environment_set_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update) = 0; + + virtual void environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) = 0; + + virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) = 0; + + virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective) = 0; + + virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) = 0; + + virtual bool is_environment(RID p_env) const = 0; + virtual RS::EnvironmentBG environment_get_background(RID p_env) const = 0; + virtual int environment_get_canvas_max_layer(RID p_env) const = 0; + + virtual RID camera_effects_allocate() = 0; + virtual void camera_effects_initialize(RID p_rid) = 0; + + virtual void camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) = 0; + virtual void camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) = 0; + + virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) = 0; + virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) = 0; + + virtual void shadows_quality_set(RS::ShadowQuality p_quality) = 0; + virtual void directional_shadow_quality_set(RS::ShadowQuality p_quality) = 0; + + virtual RID light_instance_create(RID p_light) = 0; + virtual void light_instance_set_transform(RID p_light_instance, const Transform &p_transform) = 0; + virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) = 0; + virtual void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) = 0; + virtual void light_instance_mark_visible(RID p_light_instance) = 0; + virtual bool light_instances_can_render_shadow_cube() const { + return true; + } + + virtual RID reflection_atlas_create() = 0; + virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) = 0; + virtual int reflection_atlas_get_size(RID p_ref_atlas) const = 0; + + virtual RID reflection_probe_instance_create(RID p_probe) = 0; + virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) = 0; + virtual void reflection_probe_release_atlas_index(RID p_instance) = 0; + virtual bool reflection_probe_instance_needs_redraw(RID p_instance) = 0; + virtual bool reflection_probe_instance_has_reflection(RID p_instance) = 0; + virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) = 0; + virtual bool reflection_probe_instance_postprocess_step(RID p_instance) = 0; + + virtual RID decal_instance_create(RID p_decal) = 0; + virtual void decal_instance_set_transform(RID p_decal, const Transform &p_transform) = 0; + + virtual RID lightmap_instance_create(RID p_lightmap) = 0; + virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform &p_transform) = 0; + + virtual RID gi_probe_instance_create(RID p_gi_probe) = 0; + virtual void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) = 0; + virtual bool gi_probe_needs_update(RID p_probe) const = 0; + virtual void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<GeometryInstance *> &p_dynamic_objects) = 0; + + virtual void gi_probe_set_quality(RS::GIProbeQuality) = 0; + + struct RenderShadowData { + RID light; + int pass = 0; + PagedArray<GeometryInstance *> instances; + }; + + struct RenderSDFGIData { + int region = 0; + PagedArray<GeometryInstance *> instances; + }; + + struct RenderSDFGIUpdateData { + bool update_static = false; + uint32_t static_cascade_count; + uint32_t *static_cascade_indices; + PagedArray<RID> *static_positional_lights; + + const Vector<RID> *directional_lights; + const RID *positional_light_instances; + uint32_t positional_light_count; + }; + + virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr) = 0; + + virtual void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0; + virtual void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<GeometryInstance *> &p_instances) = 0; + + virtual void set_scene_pass(uint64_t p_pass) = 0; + virtual void set_time(double p_time, double p_step) = 0; + virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) = 0; + + virtual RID render_buffers_create() = 0; + virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding) = 0; + virtual void gi_set_use_half_resolution(bool p_enable) = 0; + + virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_limit) = 0; + virtual bool screen_space_roughness_limiter_is_active() const = 0; + + virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) = 0; + virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) = 0; + + virtual TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) = 0; + + virtual bool free(RID p_rid) = 0; + + virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) = 0; + + virtual bool is_low_end() const = 0; + + virtual void update() = 0; + virtual ~RendererSceneRender() {} +}; + +#endif // RENDERINGSERVERSCENERENDER_H diff --git a/servers/rendering/rasterizer.cpp b/servers/rendering/renderer_storage.cpp index 32084c8a3e..a402ecc668 100644 --- a/servers/rendering/rasterizer.cpp +++ b/servers/rendering/renderer_storage.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rasterizer.cpp */ +/* renderer_storage.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,49 +28,41 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "rasterizer.h" +#include "renderer_storage.h" -#include "core/os/os.h" -#include "core/string/print_string.h" +RendererStorage *RendererStorage::base_singleton = nullptr; -Rasterizer *(*Rasterizer::_create_func)() = nullptr; - -void RasterizerScene::InstanceDependency::instance_notify_changed(bool p_aabb, bool p_dependencies) { - for (Map<InstanceBase *, uint32_t>::Element *E = instances.front(); E; E = E->next()) { - E->key()->dependency_changed(p_aabb, p_dependencies); +void RendererStorage::Dependency::changed_notify(DependencyChangedNotification p_notification) { + for (Map<DependencyTracker *, uint32_t>::Element *E = instances.front(); E; E = E->next()) { + if (E->key()->changed_callback) { + E->key()->changed_callback(p_notification, E->key()); + } } } -void RasterizerScene::InstanceDependency::instance_notify_deleted(RID p_deleted) { - for (Map<InstanceBase *, uint32_t>::Element *E = instances.front(); E; E = E->next()) { - E->key()->dependency_deleted(p_deleted); +void RendererStorage::Dependency::deleted_notify(const RID &p_rid) { + for (Map<DependencyTracker *, uint32_t>::Element *E = instances.front(); E; E = E->next()) { + if (E->key()->deleted_callback) { + E->key()->deleted_callback(p_rid, E->key()); + } } - for (Map<InstanceBase *, uint32_t>::Element *E = instances.front(); E; E = E->next()) { + for (Map<DependencyTracker *, uint32_t>::Element *E = instances.front(); E; E = E->next()) { E->key()->dependencies.erase(this); } - instances.clear(); } -RasterizerScene::InstanceDependency::~InstanceDependency() { +RendererStorage::Dependency::~Dependency() { #ifdef DEBUG_ENABLED if (instances.size()) { WARN_PRINT("Leaked instance dependency: Bug - did not call instance_notify_deleted when freeing."); - for (Map<InstanceBase *, uint32_t>::Element *E = instances.front(); E; E = E->next()) { + for (Map<DependencyTracker *, uint32_t>::Element *E = instances.front(); E; E = E->next()) { E->key()->dependencies.erase(this); } } #endif } -Rasterizer *Rasterizer::create() { - return _create_func(); -} - -RasterizerCanvas *RasterizerCanvas::singleton = nullptr; - -RasterizerStorage *RasterizerStorage::base_singleton = nullptr; - -RasterizerStorage::RasterizerStorage() { +RendererStorage::RendererStorage() { base_singleton = this; } diff --git a/servers/rendering/renderer_storage.h b/servers/rendering/renderer_storage.h new file mode 100644 index 0000000000..69ad2cc191 --- /dev/null +++ b/servers/rendering/renderer_storage.h @@ -0,0 +1,650 @@ +/*************************************************************************/ +/* renderer_storage.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RENDERINGSERVERSTORAGE_H +#define RENDERINGSERVERSTORAGE_H + +#include "servers/rendering_server.h" + +class RendererStorage { + Color default_clear_color; + +public: + enum DependencyChangedNotification { + DEPENDENCY_CHANGED_AABB, + DEPENDENCY_CHANGED_MATERIAL, + DEPENDENCY_CHANGED_MESH, + DEPENDENCY_CHANGED_MULTIMESH, + DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES, + DEPENDENCY_CHANGED_DECAL, + DEPENDENCY_CHANGED_SKELETON_DATA, + DEPENDENCY_CHANGED_SKELETON_BONES, + DEPENDENCY_CHANGED_LIGHT, + DEPENDENCY_CHANGED_REFLECTION_PROBE, + }; + + struct DependencyTracker; + +protected: + struct Dependency { + void changed_notify(DependencyChangedNotification p_notification); + void deleted_notify(const RID &p_rid); + + ~Dependency(); + + private: + friend struct DependencyTracker; + Map<DependencyTracker *, uint32_t> instances; + }; + +public: + struct DependencyTracker { + void *userdata = nullptr; + typedef void (*ChangedCallback)(DependencyChangedNotification, DependencyTracker *); + typedef void (*DeletedCallback)(const RID &, DependencyTracker *); + + ChangedCallback changed_callback = nullptr; + DeletedCallback deleted_callback = nullptr; + + void update_begin() { // call before updating dependencies + instance_version++; + } + + void update_dependency(Dependency *p_dependency) { //called internally, can't be used directly, use update functions in Storage + dependencies.insert(p_dependency); + p_dependency->instances[this] = instance_version; + } + + void update_end() { //call after updating dependencies + List<Pair<Dependency *, Map<DependencyTracker *, uint32_t>::Element *>> to_clean_up; + for (Set<Dependency *>::Element *E = dependencies.front(); E; E = E->next()) { + Dependency *dep = E->get(); + Map<DependencyTracker *, uint32_t>::Element *F = dep->instances.find(this); + ERR_CONTINUE(!F); + if (F->get() != instance_version) { + Pair<Dependency *, Map<DependencyTracker *, uint32_t>::Element *> p; + p.first = dep; + p.second = F; + to_clean_up.push_back(p); + } + } + + while (to_clean_up.size()) { + to_clean_up.front()->get().first->instances.erase(to_clean_up.front()->get().second); + dependencies.erase(to_clean_up.front()->get().first); + to_clean_up.pop_front(); + } + } + + void clear() { // clear all dependencies + for (Set<Dependency *>::Element *E = dependencies.front(); E; E = E->next()) { + Dependency *dep = E->get(); + dep->instances.erase(this); + } + dependencies.clear(); + } + + ~DependencyTracker() { clear(); } + + private: + friend struct Dependency; + uint32_t instance_version = 0; + Set<Dependency *> dependencies; + }; + + virtual bool can_create_resources_async() const = 0; + /* TEXTURE API */ + + virtual RID texture_allocate() = 0; + + virtual void texture_2d_initialize(RID p_texture, const Ref<Image> &p_image) = 0; + virtual void texture_2d_layered_initialize(RID p_texture, const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) = 0; + virtual void texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) = 0; + virtual void texture_proxy_initialize(RID p_texture, RID p_base) = 0; //all slices, then all the mipmaps, must be coherent + + virtual void texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0; //mostly used for video and streaming + virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0; + virtual void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) = 0; + virtual void texture_proxy_update(RID p_proxy, RID p_base) = 0; + + //these two APIs can be used together or in combination with the others. + virtual void texture_2d_placeholder_initialize(RID p_texture) = 0; + virtual void texture_2d_layered_placeholder_initialize(RID p_texture, RenderingServer::TextureLayeredType p_layered_type) = 0; + virtual void texture_3d_placeholder_initialize(RID p_texture) = 0; + + virtual Ref<Image> texture_2d_get(RID p_texture) const = 0; + virtual Ref<Image> texture_2d_layer_get(RID p_texture, int p_layer) const = 0; + virtual Vector<Ref<Image>> texture_3d_get(RID p_texture) const = 0; + + virtual void texture_replace(RID p_texture, RID p_by_texture) = 0; + virtual void texture_set_size_override(RID p_texture, int p_width, int p_height) = 0; + + virtual void texture_set_path(RID p_texture, const String &p_path) = 0; + virtual String texture_get_path(RID p_texture) const = 0; + + virtual void texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) = 0; + virtual void texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) = 0; + virtual void texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) = 0; + + virtual void texture_debug_usage(List<RS::TextureInfo> *r_info) = 0; + + virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) = 0; + + virtual Size2 texture_size_with_proxy(RID p_proxy) = 0; + + virtual void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) = 0; + virtual void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) = 0; + + /* CANVAS TEXTURE API */ + + virtual RID canvas_texture_allocate() = 0; + virtual void canvas_texture_initialize(RID p_rid) = 0; + + virtual void canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) = 0; + virtual void canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_base_color, float p_shininess) = 0; + + virtual void canvas_texture_set_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) = 0; + virtual void canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) = 0; + + /* SHADER API */ + + virtual RID shader_allocate() = 0; + virtual void shader_initialize(RID p_rid) = 0; + + virtual void shader_set_code(RID p_shader, const String &p_code) = 0; + virtual String shader_get_code(RID p_shader) const = 0; + virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const = 0; + + virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) = 0; + virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const = 0; + virtual Variant shader_get_param_default(RID p_material, const StringName &p_param) const = 0; + + virtual RS::ShaderNativeSourceCode shader_get_native_source_code(RID p_shader) const = 0; + + /* COMMON MATERIAL API */ + + virtual RID material_allocate() = 0; + virtual void material_initialize(RID p_rid) = 0; + + virtual void material_set_render_priority(RID p_material, int priority) = 0; + virtual void material_set_shader(RID p_shader_material, RID p_shader) = 0; + + virtual void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) = 0; + virtual Variant material_get_param(RID p_material, const StringName &p_param) const = 0; + + virtual void material_set_next_pass(RID p_material, RID p_next_material) = 0; + + virtual bool material_is_animated(RID p_material) = 0; + virtual bool material_casts_shadows(RID p_material) = 0; + + struct InstanceShaderParam { + PropertyInfo info; + int index; + Variant default_value; + }; + + virtual void material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) = 0; + + virtual void material_update_dependency(RID p_material, DependencyTracker *p_instance) = 0; + + /* MESH API */ + + virtual RID mesh_allocate() = 0; + virtual void mesh_initialize(RID p_rid) = 0; + + virtual void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) = 0; + + /// Returns stride + virtual void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) = 0; + + virtual int mesh_get_blend_shape_count(RID p_mesh) const = 0; + + virtual void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) = 0; + virtual RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const = 0; + + virtual void mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) = 0; + + virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) = 0; + virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const = 0; + + virtual RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const = 0; + + virtual int mesh_get_surface_count(RID p_mesh) const = 0; + + virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) = 0; + virtual AABB mesh_get_custom_aabb(RID p_mesh) const = 0; + + virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) = 0; + + virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) = 0; + + virtual void mesh_clear(RID p_mesh) = 0; + + virtual bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) = 0; + + /* MESH INSTANCE */ + + virtual RID mesh_instance_create(RID p_base) = 0; + virtual void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) = 0; + virtual void mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) = 0; + virtual void mesh_instance_check_for_update(RID p_mesh_instance) = 0; + virtual void update_mesh_instances() = 0; + + /* MULTIMESH API */ + + virtual RID multimesh_allocate() = 0; + virtual void multimesh_initialize(RID p_rid) = 0; + + virtual void multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) = 0; + + virtual int multimesh_get_instance_count(RID p_multimesh) const = 0; + + virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh) = 0; + virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) = 0; + virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) = 0; + virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) = 0; + virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) = 0; + + virtual RID multimesh_get_mesh(RID p_multimesh) const = 0; + + virtual Transform multimesh_instance_get_transform(RID p_multimesh, int p_index) const = 0; + virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const = 0; + virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const = 0; + virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const = 0; + + virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) = 0; + virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const = 0; + + virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible) = 0; + virtual int multimesh_get_visible_instances(RID p_multimesh) const = 0; + + virtual AABB multimesh_get_aabb(RID p_multimesh) const = 0; + + /* IMMEDIATE API */ + + virtual RID immediate_allocate() = 0; + virtual void immediate_initialize(RID p_rid) = 0; + + virtual void immediate_begin(RID p_immediate, RS::PrimitiveType p_rimitive, RID p_texture = RID()) = 0; + virtual void immediate_vertex(RID p_immediate, const Vector3 &p_vertex) = 0; + virtual void immediate_normal(RID p_immediate, const Vector3 &p_normal) = 0; + virtual void immediate_tangent(RID p_immediate, const Plane &p_tangent) = 0; + virtual void immediate_color(RID p_immediate, const Color &p_color) = 0; + virtual void immediate_uv(RID p_immediate, const Vector2 &tex_uv) = 0; + virtual void immediate_uv2(RID p_immediate, const Vector2 &tex_uv) = 0; + virtual void immediate_end(RID p_immediate) = 0; + virtual void immediate_clear(RID p_immediate) = 0; + virtual void immediate_set_material(RID p_immediate, RID p_material) = 0; + virtual RID immediate_get_material(RID p_immediate) const = 0; + virtual AABB immediate_get_aabb(RID p_immediate) const = 0; + + /* SKELETON API */ + + virtual RID skeleton_allocate() = 0; + virtual void skeleton_initialize(RID p_rid) = 0; + + virtual void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) = 0; + virtual int skeleton_get_bone_count(RID p_skeleton) const = 0; + virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) = 0; + virtual Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const = 0; + virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) = 0; + virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const = 0; + virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) = 0; + + /* Light API */ + + virtual RID directional_light_allocate() = 0; + virtual void directional_light_initialize(RID p_rid) = 0; + + virtual RID omni_light_allocate() = 0; + virtual void omni_light_initialize(RID p_rid) = 0; + + virtual RID spot_light_allocate() = 0; + virtual void spot_light_initialize(RID p_rid) = 0; + + virtual void light_set_color(RID p_light, const Color &p_color) = 0; + virtual void light_set_param(RID p_light, RS::LightParam p_param, float p_value) = 0; + virtual void light_set_shadow(RID p_light, bool p_enabled) = 0; + virtual void light_set_shadow_color(RID p_light, const Color &p_color) = 0; + virtual void light_set_projector(RID p_light, RID p_texture) = 0; + virtual void light_set_negative(RID p_light, bool p_enable) = 0; + virtual void light_set_cull_mask(RID p_light, uint32_t p_mask) = 0; + virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) = 0; + virtual void light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) = 0; + virtual void light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) = 0; + + virtual void light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) = 0; + + virtual void light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) = 0; + virtual void light_directional_set_blend_splits(RID p_light, bool p_enable) = 0; + virtual bool light_directional_get_blend_splits(RID p_light) const = 0; + virtual void light_directional_set_sky_only(RID p_light, bool p_sky_only) = 0; + virtual bool light_directional_is_sky_only(RID p_light) const = 0; + virtual void light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode) = 0; + virtual RS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const = 0; + + virtual RS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light) = 0; + virtual RS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light) = 0; + + virtual bool light_has_shadow(RID p_light) const = 0; + + virtual RS::LightType light_get_type(RID p_light) const = 0; + virtual AABB light_get_aabb(RID p_light) const = 0; + virtual float light_get_param(RID p_light, RS::LightParam p_param) = 0; + virtual Color light_get_color(RID p_light) = 0; + virtual RS::LightBakeMode light_get_bake_mode(RID p_light) = 0; + virtual uint32_t light_get_max_sdfgi_cascade(RID p_light) = 0; + virtual uint64_t light_get_version(RID p_light) const = 0; + + /* PROBE API */ + + virtual RID reflection_probe_allocate() = 0; + virtual void reflection_probe_initialize(RID p_rid) = 0; + + virtual void reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) = 0; + virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution) = 0; + virtual void reflection_probe_set_intensity(RID p_probe, float p_intensity) = 0; + virtual void reflection_probe_set_ambient_mode(RID p_probe, RS::ReflectionProbeAmbientMode p_mode) = 0; + virtual void reflection_probe_set_ambient_color(RID p_probe, const Color &p_color) = 0; + virtual void reflection_probe_set_ambient_energy(RID p_probe, float p_energy) = 0; + virtual void reflection_probe_set_max_distance(RID p_probe, float p_distance) = 0; + virtual void reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) = 0; + virtual void reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) = 0; + virtual void reflection_probe_set_as_interior(RID p_probe, bool p_enable) = 0; + virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) = 0; + virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) = 0; + virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) = 0; + virtual void reflection_probe_set_lod_threshold(RID p_probe, float p_ratio) = 0; + + virtual AABB reflection_probe_get_aabb(RID p_probe) const = 0; + virtual RS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const = 0; + virtual uint32_t reflection_probe_get_cull_mask(RID p_probe) const = 0; + virtual Vector3 reflection_probe_get_extents(RID p_probe) const = 0; + virtual Vector3 reflection_probe_get_origin_offset(RID p_probe) const = 0; + virtual float reflection_probe_get_origin_max_distance(RID p_probe) const = 0; + virtual bool reflection_probe_renders_shadows(RID p_probe) const = 0; + virtual float reflection_probe_get_lod_threshold(RID p_probe) const = 0; + + virtual void base_update_dependency(RID p_base, DependencyTracker *p_instance) = 0; + virtual void skeleton_update_dependency(RID p_base, DependencyTracker *p_instance) = 0; + + /* DECAL API */ + + virtual RID decal_allocate() = 0; + virtual void decal_initialize(RID p_rid) = 0; + + virtual void decal_set_extents(RID p_decal, const Vector3 &p_extents) = 0; + virtual void decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) = 0; + virtual void decal_set_emission_energy(RID p_decal, float p_energy) = 0; + virtual void decal_set_albedo_mix(RID p_decal, float p_mix) = 0; + virtual void decal_set_modulate(RID p_decal, const Color &p_modulate) = 0; + virtual void decal_set_cull_mask(RID p_decal, uint32_t p_layers) = 0; + virtual void decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) = 0; + virtual void decal_set_fade(RID p_decal, float p_above, float p_below) = 0; + virtual void decal_set_normal_fade(RID p_decal, float p_fade) = 0; + + virtual AABB decal_get_aabb(RID p_decal) const = 0; + + /* GI PROBE API */ + + virtual RID gi_probe_allocate() = 0; + virtual void gi_probe_initialize(RID p_rid) = 0; + + virtual void gi_probe_allocate_data(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) = 0; + + virtual AABB gi_probe_get_bounds(RID p_gi_probe) const = 0; + virtual Vector3i gi_probe_get_octree_size(RID p_gi_probe) const = 0; + virtual Vector<uint8_t> gi_probe_get_octree_cells(RID p_gi_probe) const = 0; + virtual Vector<uint8_t> gi_probe_get_data_cells(RID p_gi_probe) const = 0; + virtual Vector<uint8_t> gi_probe_get_distance_field(RID p_gi_probe) const = 0; + + virtual Vector<int> gi_probe_get_level_counts(RID p_gi_probe) const = 0; + virtual Transform gi_probe_get_to_cell_xform(RID p_gi_probe) const = 0; + + virtual void gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) = 0; + virtual float gi_probe_get_dynamic_range(RID p_gi_probe) const = 0; + + virtual void gi_probe_set_propagation(RID p_gi_probe, float p_range) = 0; + virtual float gi_probe_get_propagation(RID p_gi_probe) const = 0; + + virtual void gi_probe_set_energy(RID p_gi_probe, float p_energy) = 0; + virtual float gi_probe_get_energy(RID p_gi_probe) const = 0; + + virtual void gi_probe_set_ao(RID p_gi_probe, float p_ao) = 0; + virtual float gi_probe_get_ao(RID p_gi_probe) const = 0; + + virtual void gi_probe_set_ao_size(RID p_gi_probe, float p_strength) = 0; + virtual float gi_probe_get_ao_size(RID p_gi_probe) const = 0; + + virtual void gi_probe_set_bias(RID p_gi_probe, float p_bias) = 0; + virtual float gi_probe_get_bias(RID p_gi_probe) const = 0; + + virtual void gi_probe_set_normal_bias(RID p_gi_probe, float p_range) = 0; + virtual float gi_probe_get_normal_bias(RID p_gi_probe) const = 0; + + virtual void gi_probe_set_interior(RID p_gi_probe, bool p_enable) = 0; + virtual bool gi_probe_is_interior(RID p_gi_probe) const = 0; + + virtual void gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) = 0; + virtual bool gi_probe_is_using_two_bounces(RID p_gi_probe) const = 0; + + virtual void gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) = 0; + virtual float gi_probe_get_anisotropy_strength(RID p_gi_probe) const = 0; + + virtual uint32_t gi_probe_get_version(RID p_probe) = 0; + + /* LIGHTMAP */ + + virtual RID lightmap_allocate() = 0; + virtual void lightmap_initialize(RID p_rid) = 0; + + virtual void lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) = 0; + virtual void lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) = 0; + virtual void lightmap_set_probe_interior(RID p_lightmap, bool p_interior) = 0; + virtual void lightmap_set_probe_capture_data(RID p_lightmap, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) = 0; + virtual PackedVector3Array lightmap_get_probe_capture_points(RID p_lightmap) const = 0; + virtual PackedColorArray lightmap_get_probe_capture_sh(RID p_lightmap) const = 0; + virtual PackedInt32Array lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const = 0; + virtual PackedInt32Array lightmap_get_probe_capture_bsp_tree(RID p_lightmap) const = 0; + virtual AABB lightmap_get_aabb(RID p_lightmap) const = 0; + virtual void lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_point, Color *r_sh) = 0; + virtual bool lightmap_is_interior(RID p_lightmap) const = 0; + virtual void lightmap_set_probe_capture_update_speed(float p_speed) = 0; + virtual float lightmap_get_probe_capture_update_speed() const = 0; + + /* PARTICLES */ + + virtual RID particles_allocate() = 0; + virtual void particles_initialize(RID p_rid) = 0; + + virtual void particles_set_emitting(RID p_particles, bool p_emitting) = 0; + virtual bool particles_get_emitting(RID p_particles) = 0; + + virtual void particles_set_amount(RID p_particles, int p_amount) = 0; + virtual void particles_set_lifetime(RID p_particles, float p_lifetime) = 0; + virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) = 0; + virtual void particles_set_pre_process_time(RID p_particles, float p_time) = 0; + virtual void particles_set_explosiveness_ratio(RID p_particles, float p_ratio) = 0; + virtual void particles_set_randomness_ratio(RID p_particles, float p_ratio) = 0; + virtual void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) = 0; + virtual void particles_set_speed_scale(RID p_particles, float p_scale) = 0; + virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable) = 0; + virtual void particles_set_process_material(RID p_particles, RID p_material) = 0; + virtual void particles_set_fixed_fps(RID p_particles, int p_fps) = 0; + virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) = 0; + virtual void particles_set_collision_base_size(RID p_particles, float p_size) = 0; + virtual void particles_restart(RID p_particles) = 0; + virtual void particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) = 0; + virtual void particles_set_subemitter(RID p_particles, RID p_subemitter_particles) = 0; + + virtual bool particles_is_inactive(RID p_particles) const = 0; + + virtual void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) = 0; + + virtual void particles_set_draw_passes(RID p_particles, int p_count) = 0; + virtual void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) = 0; + + virtual void particles_request_process(RID p_particles) = 0; + virtual AABB particles_get_current_aabb(RID p_particles) = 0; + virtual AABB particles_get_aabb(RID p_particles) const = 0; + + virtual void particles_set_emission_transform(RID p_particles, const Transform &p_transform) = 0; + + virtual int particles_get_draw_passes(RID p_particles) const = 0; + virtual RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const = 0; + + virtual void particles_set_view_axis(RID p_particles, const Vector3 &p_axis) = 0; + + virtual void particles_add_collision(RID p_particles, RID p_particles_collision_instance) = 0; + virtual void particles_remove_collision(RID p_particles, RID p_particles_collision_instance) = 0; + + virtual void update_particles() = 0; + + /* PARTICLES COLLISION */ + + virtual RID particles_collision_allocate() = 0; + virtual void particles_collision_initialize(RID p_rid) = 0; + + virtual void particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) = 0; + virtual void particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) = 0; + virtual void particles_collision_set_sphere_radius(RID p_particles_collision, float p_radius) = 0; //for spheres + virtual void particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) = 0; //for non-spheres + virtual void particles_collision_set_attractor_strength(RID p_particles_collision, float p_strength) = 0; + virtual void particles_collision_set_attractor_directionality(RID p_particles_collision, float p_directionality) = 0; + virtual void particles_collision_set_attractor_attenuation(RID p_particles_collision, float p_curve) = 0; + virtual void particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) = 0; //for SDF and vector field, heightfield is dynamic + virtual void particles_collision_height_field_update(RID p_particles_collision) = 0; //for SDF and vector field + virtual void particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) = 0; //for SDF and vector field + virtual AABB particles_collision_get_aabb(RID p_particles_collision) const = 0; + virtual bool particles_collision_is_heightfield(RID p_particles_collision) const = 0; + virtual RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const = 0; + + //used from 2D and 3D + virtual RID particles_collision_instance_create(RID p_collision) = 0; + virtual void particles_collision_instance_set_transform(RID p_collision_instance, const Transform &p_transform) = 0; + virtual void particles_collision_instance_set_active(RID p_collision_instance, bool p_active) = 0; + + /* GLOBAL VARIABLES */ + + virtual void global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value) = 0; + virtual void global_variable_remove(const StringName &p_name) = 0; + virtual Vector<StringName> global_variable_get_list() const = 0; + + virtual void global_variable_set(const StringName &p_name, const Variant &p_value) = 0; + virtual void global_variable_set_override(const StringName &p_name, const Variant &p_value) = 0; + virtual Variant global_variable_get(const StringName &p_name) const = 0; + virtual RS::GlobalVariableType global_variable_get_type(const StringName &p_name) const = 0; + + virtual void global_variables_load_settings(bool p_load_textures = true) = 0; + virtual void global_variables_clear() = 0; + + virtual int32_t global_variables_instance_allocate(RID p_instance) = 0; + virtual void global_variables_instance_free(RID p_instance) = 0; + virtual void global_variables_instance_update(RID p_instance, int p_index, const Variant &p_value) = 0; + + /* RENDER TARGET */ + + enum RenderTargetFlags { + RENDER_TARGET_TRANSPARENT, + RENDER_TARGET_DIRECT_TO_SCREEN, + RENDER_TARGET_FLAG_MAX + }; + + virtual RID render_target_create() = 0; + virtual void render_target_set_position(RID p_render_target, int p_x, int p_y) = 0; + virtual void render_target_set_size(RID p_render_target, int p_width, int p_height) = 0; + virtual RID render_target_get_texture(RID p_render_target) = 0; + virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) = 0; + virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) = 0; + virtual bool render_target_was_used(RID p_render_target) = 0; + virtual void render_target_set_as_unused(RID p_render_target) = 0; + + virtual void render_target_request_clear(RID p_render_target, const Color &p_clear_color) = 0; + virtual bool render_target_is_clear_requested(RID p_render_target) = 0; + virtual Color render_target_get_clear_request_color(RID p_render_target) = 0; + virtual void render_target_disable_clear_request(RID p_render_target) = 0; + virtual void render_target_do_clear_request(RID p_render_target) = 0; + + virtual void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) = 0; + virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const = 0; + + virtual RS::InstanceType get_base_type(RID p_rid) const = 0; + virtual bool free(RID p_rid) = 0; + + virtual bool has_os_feature(const String &p_feature) const = 0; + + virtual void update_dirty_resources() = 0; + + virtual void set_debug_generate_wireframes(bool p_generate) = 0; + + virtual void render_info_begin_capture() = 0; + virtual void render_info_end_capture() = 0; + virtual int get_captured_render_info(RS::RenderInfo p_info) = 0; + + virtual int get_render_info(RS::RenderInfo p_info) = 0; + virtual String get_video_adapter_name() const = 0; + virtual String get_video_adapter_vendor() const = 0; + + static RendererStorage *base_singleton; + + void set_default_clear_color(const Color &p_color) { + default_clear_color = p_color; + } + + Color get_default_clear_color() const { + return default_clear_color; + } +#define TIMESTAMP_BEGIN() \ + { \ + if (RSG::storage->capturing_timestamps) \ + RSG::storage->capture_timestamps_begin(); \ + } + +#define RENDER_TIMESTAMP(m_text) \ + { \ + if (RSG::storage->capturing_timestamps) \ + RSG::storage->capture_timestamp(m_text); \ + } + + bool capturing_timestamps = false; + + virtual void capture_timestamps_begin() = 0; + virtual void capture_timestamp(const String &p_name) = 0; + virtual uint32_t get_captured_timestamps_count() const = 0; + virtual uint64_t get_captured_timestamps_frame() const = 0; + virtual uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const = 0; + virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const = 0; + virtual String get_captured_timestamp_name(uint32_t p_index) const = 0; + + RendererStorage(); + virtual ~RendererStorage() {} +}; + +#endif // RENDERINGSERVERSTORAGE_H diff --git a/servers/rendering/renderer_thread_pool.cpp b/servers/rendering/renderer_thread_pool.cpp new file mode 100644 index 0000000000..98050dd508 --- /dev/null +++ b/servers/rendering/renderer_thread_pool.cpp @@ -0,0 +1,42 @@ +/*************************************************************************/ +/* renderer_thread_pool.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "renderer_thread_pool.h" + +RendererThreadPool *RendererThreadPool::singleton = nullptr; + +RendererThreadPool::RendererThreadPool() { + singleton = this; + thread_work_pool.init(); +} + +RendererThreadPool::~RendererThreadPool() { + thread_work_pool.finish(); +} diff --git a/servers/rendering/renderer_thread_pool.h b/servers/rendering/renderer_thread_pool.h new file mode 100644 index 0000000000..ae25415a0d --- /dev/null +++ b/servers/rendering/renderer_thread_pool.h @@ -0,0 +1,45 @@ +/*************************************************************************/ +/* renderer_thread_pool.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RENDERERTHREADPOOL_H +#define RENDERERTHREADPOOL_H + +#include "core/templates/thread_work_pool.h" + +class RendererThreadPool { +public: + ThreadWorkPool thread_work_pool; + + static RendererThreadPool *singleton; + RendererThreadPool(); + ~RendererThreadPool(); +}; + +#endif // RENDERERTHREADPOOL_H diff --git a/servers/rendering/rendering_server_viewport.cpp b/servers/rendering/renderer_viewport.cpp index c048aa381f..a5d5033c18 100644 --- a/servers/rendering/rendering_server_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rendering_server_viewport.cpp */ +/* renderer_viewport.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,14 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "rendering_server_viewport.h" +#include "renderer_viewport.h" #include "core/config/project_settings.h" -#include "rendering_server_canvas.h" +#include "renderer_canvas_cull.h" +#include "renderer_scene_cull.h" #include "rendering_server_globals.h" -#include "rendering_server_scene.h" -static Transform2D _canvas_get_transform(RenderingServerViewport::Viewport *p_viewport, RenderingServerCanvas::Canvas *p_canvas, RenderingServerViewport::Viewport::CanvasData *p_canvas_data, const Vector2 &p_vp_size) { +static Transform2D _canvas_get_transform(RendererViewport::Viewport *p_viewport, RendererCanvasCull::Canvas *p_canvas, RendererViewport::Viewport::CanvasData *p_canvas_data, const Vector2 &p_vp_size) { Transform2D xf = p_viewport->global_transform; float scale = 1.0; @@ -71,7 +71,7 @@ static Transform2D _canvas_get_transform(RenderingServerViewport::Viewport *p_vi return xf; } -void RenderingServerViewport::_draw_3d(Viewport *p_viewport, XRInterface::Eyes p_eye) { +void RendererViewport::_draw_3d(Viewport *p_viewport, XRInterface::Eyes p_eye) { RENDER_TIMESTAMP(">Begin Rendering 3D Scene"); Ref<XRInterface> xr_interface; @@ -79,15 +79,16 @@ void RenderingServerViewport::_draw_3d(Viewport *p_viewport, XRInterface::Eyes p xr_interface = XRServer::get_singleton()->get_primary_interface(); } + float screen_lod_threshold = p_viewport->lod_threshold / float(p_viewport->size.width); if (p_viewport->use_xr && xr_interface.is_valid()) { - RSG::scene->render_camera(p_viewport->render_buffers, xr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas); + RSG::scene->render_camera(p_viewport->render_buffers, xr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->size, screen_lod_threshold, p_viewport->shadow_atlas); } else { - RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas); + RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->size, screen_lod_threshold, p_viewport->shadow_atlas); } RENDER_TIMESTAMP("<End Rendering 3D Scene"); } -void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_eye) { +void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_eye) { if (p_viewport->measure_render_time) { String rt_id = "vp_begin_" + itos(p_viewport->self.get_id()); RSG::storage->capture_timestamp(rt_id); @@ -101,17 +102,15 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface:: Color bgcolor = RSG::storage->get_default_clear_color(); - if (!p_viewport->hide_canvas && !p_viewport->disable_environment && RSG::scene->scenario_owner.owns(p_viewport->scenario)) { - RenderingServerScene::Scenario *scenario = RSG::scene->scenario_owner.getornull(p_viewport->scenario); - ERR_FAIL_COND(!scenario); - if (RSG::scene_render->is_environment(scenario->environment)) { - scenario_draw_canvas_bg = RSG::scene_render->environment_get_background(scenario->environment) == RS::ENV_BG_CANVAS; - - scenario_canvas_max_layer = RSG::scene_render->environment_get_canvas_max_layer(scenario->environment); + if (!p_viewport->hide_canvas && !p_viewport->disable_environment && RSG::scene->is_scenario(p_viewport->scenario)) { + RID environment = RSG::scene->scenario_get_environment(p_viewport->scenario); + if (RSG::scene->is_environment(environment)) { + scenario_draw_canvas_bg = RSG::scene->environment_get_background(environment) == RS::ENV_BG_CANVAS; + scenario_canvas_max_layer = RSG::scene->environment_get_canvas_max_layer(environment); } } - bool can_draw_3d = RSG::scene->camera_owner.owns(p_viewport->camera); + bool can_draw_3d = RSG::scene->is_camera(p_viewport->camera); if (p_viewport->clear_mode != RS::VIEWPORT_CLEAR_NEVER) { if (p_viewport->transparent_bg) { @@ -124,8 +123,8 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface:: if ((scenario_draw_canvas_bg || can_draw_3d) && !p_viewport->render_buffers.is_valid()) { //wants to draw 3D but there is no render buffer, create - p_viewport->render_buffers = RSG::scene_render->render_buffers_create(); - RSG::scene_render->render_buffers_configure(p_viewport->render_buffers, p_viewport->render_target, p_viewport->size.width, p_viewport->size.height, p_viewport->msaa, p_viewport->screen_space_aa, p_viewport->use_debanding); + p_viewport->render_buffers = RSG::scene->render_buffers_create(); + RSG::scene->render_buffers_configure(p_viewport->render_buffers, p_viewport->render_target, p_viewport->size.width, p_viewport->size.height, p_viewport->msaa, p_viewport->screen_space_aa, p_viewport->use_debanding); } RSG::storage->render_target_request_clear(p_viewport->render_target, bgcolor); @@ -140,25 +139,25 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface:: Map<Viewport::CanvasKey, Viewport::CanvasData *> canvas_map; Rect2 clip_rect(0, 0, p_viewport->size.x, p_viewport->size.y); - RasterizerCanvas::Light *lights = nullptr; - RasterizerCanvas::Light *lights_with_shadow = nullptr; + RendererCanvasRender::Light *lights = nullptr; + RendererCanvasRender::Light *lights_with_shadow = nullptr; - RasterizerCanvas::Light *directional_lights = nullptr; - RasterizerCanvas::Light *directional_lights_with_shadow = nullptr; + RendererCanvasRender::Light *directional_lights = nullptr; + RendererCanvasRender::Light *directional_lights_with_shadow = nullptr; if (p_viewport->sdf_active) { //process SDF Rect2 sdf_rect = RSG::storage->render_target_get_sdf_rect(p_viewport->render_target); - RasterizerCanvas::LightOccluderInstance *occluders = nullptr; + RendererCanvasRender::LightOccluderInstance *occluders = nullptr; //make list of occluders for (Map<RID, Viewport::CanvasData>::Element *E = p_viewport->canvas_map.front(); E; E = E->next()) { - RenderingServerCanvas::Canvas *canvas = static_cast<RenderingServerCanvas::Canvas *>(E->get().canvas); + RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E->get().canvas); Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E->get(), clip_rect.size); - for (Set<RasterizerCanvas::LightOccluderInstance *>::Element *F = canvas->occluders.front(); F; F = F->next()) { + for (Set<RendererCanvasRender::LightOccluderInstance *>::Element *F = canvas->occluders.front(); F; F = F->next()) { if (!F->get()->enabled) { continue; } @@ -184,14 +183,14 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface:: RENDER_TIMESTAMP("Cull Canvas Lights"); for (Map<RID, Viewport::CanvasData>::Element *E = p_viewport->canvas_map.front(); E; E = E->next()) { - RenderingServerCanvas::Canvas *canvas = static_cast<RenderingServerCanvas::Canvas *>(E->get().canvas); + RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E->get().canvas); Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E->get(), clip_rect.size); //find lights in canvas - for (Set<RasterizerCanvas::Light *>::Element *F = canvas->lights.front(); F; F = F->next()) { - RasterizerCanvas::Light *cl = F->get(); + for (Set<RendererCanvasRender::Light *>::Element *F = canvas->lights.front(); F; F = F->next()) { + RendererCanvasRender::Light *cl = F->get(); if (cl->enabled && cl->texture.is_valid()) { //not super efficient.. Size2 tsize = RSG::storage->texture_size_with_proxy(cl->texture); @@ -228,8 +227,8 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface:: } } - for (Set<RasterizerCanvas::Light *>::Element *F = canvas->directional_lights.front(); F; F = F->next()) { - RasterizerCanvas::Light *cl = F->get(); + for (Set<RendererCanvasRender::Light *>::Element *F = canvas->directional_lights.front(); F; F = F->next()) { + RendererCanvasRender::Light *cl = F->get(); if (cl->enabled) { cl->filter_next_ptr = directional_lights; directional_lights = cl; @@ -254,17 +253,17 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface:: if (lights_with_shadow) { //update shadows if any - RasterizerCanvas::LightOccluderInstance *occluders = nullptr; + RendererCanvasRender::LightOccluderInstance *occluders = nullptr; RENDER_TIMESTAMP(">Render 2D Shadows"); RENDER_TIMESTAMP("Cull Occluders"); //make list of occluders for (Map<RID, Viewport::CanvasData>::Element *E = p_viewport->canvas_map.front(); E; E = E->next()) { - RenderingServerCanvas::Canvas *canvas = static_cast<RenderingServerCanvas::Canvas *>(E->get().canvas); + RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E->get().canvas); Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E->get(), clip_rect.size); - for (Set<RasterizerCanvas::LightOccluderInstance *>::Element *F = canvas->occluders.front(); F; F = F->next()) { + for (Set<RendererCanvasRender::LightOccluderInstance *>::Element *F = canvas->occluders.front(); F; F = F->next()) { if (!F->get()->enabled) { continue; } @@ -277,7 +276,7 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface:: } //update the light shadowmaps with them - RasterizerCanvas::Light *light = lights_with_shadow; + RendererCanvasRender::Light *light = lights_with_shadow; while (light) { RENDER_TIMESTAMP("Render Shadow"); @@ -290,7 +289,7 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface:: if (directional_lights_with_shadow) { //update shadows if any - RasterizerCanvas::Light *light = directional_lights_with_shadow; + RendererCanvasRender::Light *light = directional_lights_with_shadow; while (light) { Vector2 light_dir = -light->xform_cache.elements[1].normalized(); // Y is light direction float cull_distance = light->directional_distance; @@ -335,17 +334,17 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface:: Vector2 xf_points[6]; - RasterizerCanvas::LightOccluderInstance *occluders = nullptr; + RendererCanvasRender::LightOccluderInstance *occluders = nullptr; RENDER_TIMESTAMP(">Render Directional 2D Shadows"); //make list of occluders int occ_cullded = 0; for (Map<RID, Viewport::CanvasData>::Element *E = p_viewport->canvas_map.front(); E; E = E->next()) { - RenderingServerCanvas::Canvas *canvas = static_cast<RenderingServerCanvas::Canvas *>(E->get().canvas); + RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E->get().canvas); Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E->get(), clip_rect.size); - for (Set<RasterizerCanvas::LightOccluderInstance *>::Element *F = canvas->occluders.front(); F; F = F->next()) { + for (Set<RendererCanvasRender::LightOccluderInstance *>::Element *F = canvas->occluders.front(); F; F = F->next()) { if (!F->get()->enabled) { continue; } @@ -381,14 +380,14 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface:: } for (Map<Viewport::CanvasKey, Viewport::CanvasData *>::Element *E = canvas_map.front(); E; E = E->next()) { - RenderingServerCanvas::Canvas *canvas = static_cast<RenderingServerCanvas::Canvas *>(E->get()->canvas); + RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E->get()->canvas); Transform2D xform = _canvas_get_transform(p_viewport, canvas, E->get(), clip_rect.size); - RasterizerCanvas::Light *canvas_lights = nullptr; - RasterizerCanvas::Light *canvas_directional_lights = nullptr; + RendererCanvasRender::Light *canvas_lights = nullptr; + RendererCanvasRender::Light *canvas_directional_lights = nullptr; - RasterizerCanvas::Light *ptr = lights; + RendererCanvasRender::Light *ptr = lights; while (ptr) { if (E->get()->layer >= ptr->layer_min && E->get()->layer <= ptr->layer_max) { ptr->next_ptr = canvas_lights; @@ -444,7 +443,7 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface:: } } -void RenderingServerViewport::draw_viewports() { +void RendererViewport::draw_viewports() { timestamp_vp_map.clear(); // get our xr interface in case we need it @@ -458,13 +457,13 @@ void RenderingServerViewport::draw_viewports() { } if (Engine::get_singleton()->is_editor_hint()) { - set_default_clear_color(GLOBAL_GET("rendering/environment/default_clear_color")); + set_default_clear_color(GLOBAL_GET("rendering/environment/defaults/default_clear_color")); } //sort viewports active_viewports.sort_custom<ViewportSort>(); - Map<DisplayServer::WindowID, Vector<Rasterizer::BlitToScreen>> blit_to_screen_list; + Map<DisplayServer::WindowID, Vector<RendererCompositor::BlitToScreen>> blit_to_screen_list; //draw viewports RENDER_TIMESTAMP(">Render Viewports"); @@ -559,7 +558,7 @@ void RenderingServerViewport::draw_viewports() { { RSG::storage->render_target_set_external_texture(vp->render_target, 0); - RSG::scene_render->set_debug_draw_mode(vp->debug_draw); + RSG::scene->set_debug_draw_mode(vp->debug_draw); RSG::storage->render_info_begin_capture(); // render standard mono camera @@ -575,7 +574,7 @@ void RenderingServerViewport::draw_viewports() { if (vp->viewport_to_screen != DisplayServer::INVALID_WINDOW_ID && (!vp->viewport_render_direct_to_screen || !RSG::rasterizer->is_low_end())) { //copy to screen if set as such - Rasterizer::BlitToScreen blit; + RendererCompositor::BlitToScreen blit; blit.render_target = vp->render_target; if (vp->viewport_to_screen_rect != Rect2()) { blit.rect = vp->viewport_to_screen_rect; @@ -585,7 +584,7 @@ void RenderingServerViewport::draw_viewports() { } if (!blit_to_screen_list.has(vp->viewport_to_screen)) { - blit_to_screen_list[vp->viewport_to_screen] = Vector<Rasterizer::BlitToScreen>(); + blit_to_screen_list[vp->viewport_to_screen] = Vector<RendererCompositor::BlitToScreen>(); } blit_to_screen_list[vp->viewport_to_screen].push_back(blit); @@ -598,40 +597,41 @@ void RenderingServerViewport::draw_viewports() { RENDER_TIMESTAMP("<Rendering Viewport " + itos(i)); } - RSG::scene_render->set_debug_draw_mode(RS::VIEWPORT_DEBUG_DRAW_DISABLED); + RSG::scene->set_debug_draw_mode(RS::VIEWPORT_DEBUG_DRAW_DISABLED); RENDER_TIMESTAMP("<Render Viewports"); //this needs to be called to make screen swapping more efficient RSG::rasterizer->prepare_for_blitting_render_targets(); - for (Map<int, Vector<Rasterizer::BlitToScreen>>::Element *E = blit_to_screen_list.front(); E; E = E->next()) { + for (Map<int, Vector<RendererCompositor::BlitToScreen>>::Element *E = blit_to_screen_list.front(); E; E = E->next()) { RSG::rasterizer->blit_render_targets_to_screen(E->key(), E->get().ptr(), E->get().size()); } } -RID RenderingServerViewport::viewport_create() { - Viewport *viewport = memnew(Viewport); - - RID rid = viewport_owner.make_rid(viewport); +RID RendererViewport::viewport_allocate() { + return viewport_owner.allocate_rid(); +} - viewport->self = rid; +void RendererViewport::viewport_initialize(RID p_rid) { + Viewport *viewport = memnew(Viewport); + viewport->self = p_rid; viewport->hide_scenario = false; viewport->hide_canvas = false; viewport->render_target = RSG::storage->render_target_create(); - viewport->shadow_atlas = RSG::scene_render->shadow_atlas_create(); + viewport->shadow_atlas = RSG::scene->shadow_atlas_create(); viewport->viewport_render_direct_to_screen = false; - return rid; + viewport_owner.initialize_rid(p_rid, viewport); } -void RenderingServerViewport::viewport_set_use_xr(RID p_viewport, bool p_use_xr) { +void RendererViewport::viewport_set_use_xr(RID p_viewport, bool p_use_xr) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->use_xr = p_use_xr; } -void RenderingServerViewport::viewport_set_size(RID p_viewport, int p_width, int p_height) { +void RendererViewport::viewport_set_size(RID p_viewport, int p_width, int p_height) { ERR_FAIL_COND(p_width < 0 && p_height < 0); Viewport *viewport = viewport_owner.getornull(p_viewport); @@ -641,15 +641,15 @@ void RenderingServerViewport::viewport_set_size(RID p_viewport, int p_width, int RSG::storage->render_target_set_size(viewport->render_target, p_width, p_height); if (viewport->render_buffers.is_valid()) { if (p_width == 0 || p_height == 0) { - RSG::scene_render->free(viewport->render_buffers); + RSG::scene->free(viewport->render_buffers); viewport->render_buffers = RID(); } else { - RSG::scene_render->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, viewport->screen_space_aa, viewport->use_debanding); + RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, viewport->screen_space_aa, viewport->use_debanding); } } } -void RenderingServerViewport::viewport_set_active(RID p_viewport, bool p_active) { +void RendererViewport::viewport_set_active(RID p_viewport, bool p_active) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); @@ -661,21 +661,21 @@ void RenderingServerViewport::viewport_set_active(RID p_viewport, bool p_active) } } -void RenderingServerViewport::viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport) { +void RendererViewport::viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->parent = p_parent_viewport; } -void RenderingServerViewport::viewport_set_clear_mode(RID p_viewport, RS::ViewportClearMode p_clear_mode) { +void RendererViewport::viewport_set_clear_mode(RID p_viewport, RS::ViewportClearMode p_clear_mode) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->clear_mode = p_clear_mode; } -void RenderingServerViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_rect, DisplayServer::WindowID p_screen) { +void RendererViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_rect, DisplayServer::WindowID p_screen) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); @@ -701,7 +701,7 @@ void RenderingServerViewport::viewport_attach_to_screen(RID p_viewport, const Re } } -void RenderingServerViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool p_enable) { +void RendererViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool p_enable) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); @@ -715,7 +715,7 @@ void RenderingServerViewport::viewport_set_render_direct_to_screen(RID p_viewpor RSG::storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y); } - RSG::storage->render_target_set_flag(viewport->render_target, RasterizerStorage::RENDER_TARGET_DIRECT_TO_SCREEN, p_enable); + RSG::storage->render_target_set_flag(viewport->render_target, RendererStorage::RENDER_TARGET_DIRECT_TO_SCREEN, p_enable); viewport->viewport_render_direct_to_screen = p_enable; // if attached to screen already, setup screen size and position, this needs to happen after setting flag to avoid an unnecessary buffer allocation @@ -725,61 +725,61 @@ void RenderingServerViewport::viewport_set_render_direct_to_screen(RID p_viewpor } } -void RenderingServerViewport::viewport_set_update_mode(RID p_viewport, RS::ViewportUpdateMode p_mode) { +void RendererViewport::viewport_set_update_mode(RID p_viewport, RS::ViewportUpdateMode p_mode) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->update_mode = p_mode; } -RID RenderingServerViewport::viewport_get_texture(RID p_viewport) const { +RID RendererViewport::viewport_get_texture(RID p_viewport) const { const Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND_V(!viewport, RID()); return RSG::storage->render_target_get_texture(viewport->render_target); } -void RenderingServerViewport::viewport_set_hide_scenario(RID p_viewport, bool p_hide) { +void RendererViewport::viewport_set_hide_scenario(RID p_viewport, bool p_hide) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->hide_scenario = p_hide; } -void RenderingServerViewport::viewport_set_hide_canvas(RID p_viewport, bool p_hide) { +void RendererViewport::viewport_set_hide_canvas(RID p_viewport, bool p_hide) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->hide_canvas = p_hide; } -void RenderingServerViewport::viewport_set_disable_environment(RID p_viewport, bool p_disable) { +void RendererViewport::viewport_set_disable_environment(RID p_viewport, bool p_disable) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->disable_environment = p_disable; } -void RenderingServerViewport::viewport_attach_camera(RID p_viewport, RID p_camera) { +void RendererViewport::viewport_attach_camera(RID p_viewport, RID p_camera) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->camera = p_camera; } -void RenderingServerViewport::viewport_set_scenario(RID p_viewport, RID p_scenario) { +void RendererViewport::viewport_set_scenario(RID p_viewport, RID p_scenario) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->scenario = p_scenario; } -void RenderingServerViewport::viewport_attach_canvas(RID p_viewport, RID p_canvas) { +void RendererViewport::viewport_attach_canvas(RID p_viewport, RID p_canvas) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); ERR_FAIL_COND(viewport->canvas_map.has(p_canvas)); - RenderingServerCanvas::Canvas *canvas = RSG::canvas->canvas_owner.getornull(p_canvas); + RendererCanvasCull::Canvas *canvas = RSG::canvas->canvas_owner.getornull(p_canvas); ERR_FAIL_COND(!canvas); canvas->viewports.insert(p_viewport); @@ -789,18 +789,18 @@ void RenderingServerViewport::viewport_attach_canvas(RID p_viewport, RID p_canva viewport->canvas_map[p_canvas].canvas = canvas; } -void RenderingServerViewport::viewport_remove_canvas(RID p_viewport, RID p_canvas) { +void RendererViewport::viewport_remove_canvas(RID p_viewport, RID p_canvas) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); - RenderingServerCanvas::Canvas *canvas = RSG::canvas->canvas_owner.getornull(p_canvas); + RendererCanvasCull::Canvas *canvas = RSG::canvas->canvas_owner.getornull(p_canvas); ERR_FAIL_COND(!canvas); viewport->canvas_map.erase(p_canvas); canvas->viewports.erase(p_viewport); } -void RenderingServerViewport::viewport_set_canvas_transform(RID p_viewport, RID p_canvas, const Transform2D &p_offset) { +void RendererViewport::viewport_set_canvas_transform(RID p_viewport, RID p_canvas, const Transform2D &p_offset) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); @@ -808,22 +808,22 @@ void RenderingServerViewport::viewport_set_canvas_transform(RID p_viewport, RID viewport->canvas_map[p_canvas].transform = p_offset; } -void RenderingServerViewport::viewport_set_transparent_background(RID p_viewport, bool p_enabled) { +void RendererViewport::viewport_set_transparent_background(RID p_viewport, bool p_enabled) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); - RSG::storage->render_target_set_flag(viewport->render_target, RasterizerStorage::RENDER_TARGET_TRANSPARENT, p_enabled); + RSG::storage->render_target_set_flag(viewport->render_target, RendererStorage::RENDER_TARGET_TRANSPARENT, p_enabled); viewport->transparent_bg = p_enabled; } -void RenderingServerViewport::viewport_set_global_canvas_transform(RID p_viewport, const Transform2D &p_transform) { +void RendererViewport::viewport_set_global_canvas_transform(RID p_viewport, const Transform2D &p_transform) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->global_transform = p_transform; } -void RenderingServerViewport::viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer) { +void RendererViewport::viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); @@ -832,23 +832,24 @@ void RenderingServerViewport::viewport_set_canvas_stacking(RID p_viewport, RID p viewport->canvas_map[p_canvas].sublayer = p_sublayer; } -void RenderingServerViewport::viewport_set_shadow_atlas_size(RID p_viewport, int p_size) { +void RendererViewport::viewport_set_shadow_atlas_size(RID p_viewport, int p_size, bool p_16_bits) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->shadow_atlas_size = p_size; + viewport->shadow_atlas_16_bits = p_16_bits; - RSG::scene_render->shadow_atlas_set_size(viewport->shadow_atlas, viewport->shadow_atlas_size); + RSG::scene->shadow_atlas_set_size(viewport->shadow_atlas, viewport->shadow_atlas_size, viewport->shadow_atlas_16_bits); } -void RenderingServerViewport::viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv) { +void RendererViewport::viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); - RSG::scene_render->shadow_atlas_set_quadrant_subdivision(viewport->shadow_atlas, p_quadrant, p_subdiv); + RSG::scene->shadow_atlas_set_quadrant_subdivision(viewport->shadow_atlas, p_quadrant, p_subdiv); } -void RenderingServerViewport::viewport_set_msaa(RID p_viewport, RS::ViewportMSAA p_msaa) { +void RendererViewport::viewport_set_msaa(RID p_viewport, RS::ViewportMSAA p_msaa) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); @@ -857,11 +858,11 @@ void RenderingServerViewport::viewport_set_msaa(RID p_viewport, RS::ViewportMSAA } viewport->msaa = p_msaa; if (viewport->render_buffers.is_valid()) { - RSG::scene_render->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, p_msaa, viewport->screen_space_aa, viewport->use_debanding); + RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, p_msaa, viewport->screen_space_aa, viewport->use_debanding); } } -void RenderingServerViewport::viewport_set_screen_space_aa(RID p_viewport, RS::ViewportScreenSpaceAA p_mode) { +void RendererViewport::viewport_set_screen_space_aa(RID p_viewport, RS::ViewportScreenSpaceAA p_mode) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); @@ -870,11 +871,11 @@ void RenderingServerViewport::viewport_set_screen_space_aa(RID p_viewport, RS::V } viewport->screen_space_aa = p_mode; if (viewport->render_buffers.is_valid()) { - RSG::scene_render->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, p_mode, viewport->use_debanding); + RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, p_mode, viewport->use_debanding); } } -void RenderingServerViewport::viewport_set_use_debanding(RID p_viewport, bool p_use_debanding) { +void RendererViewport::viewport_set_use_debanding(RID p_viewport, bool p_use_debanding) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); @@ -883,11 +884,18 @@ void RenderingServerViewport::viewport_set_use_debanding(RID p_viewport, bool p_ } viewport->use_debanding = p_use_debanding; if (viewport->render_buffers.is_valid()) { - RSG::scene_render->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, viewport->screen_space_aa, p_use_debanding); + RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, viewport->screen_space_aa, p_use_debanding); } } -int RenderingServerViewport::viewport_get_render_info(RID p_viewport, RS::ViewportRenderInfo p_info) { +void RendererViewport::viewport_set_lod_threshold(RID p_viewport, float p_pixels) { + Viewport *viewport = viewport_owner.getornull(p_viewport); + ERR_FAIL_COND(!viewport); + + viewport->lod_threshold = p_pixels; +} + +int RendererViewport::viewport_get_render_info(RID p_viewport, RS::ViewportRenderInfo p_info) { ERR_FAIL_INDEX_V(p_info, RS::VIEWPORT_RENDER_INFO_MAX, -1); Viewport *viewport = viewport_owner.getornull(p_viewport); @@ -898,54 +906,54 @@ int RenderingServerViewport::viewport_get_render_info(RID p_viewport, RS::Viewpo return viewport->render_info[p_info]; } -void RenderingServerViewport::viewport_set_debug_draw(RID p_viewport, RS::ViewportDebugDraw p_draw) { +void RendererViewport::viewport_set_debug_draw(RID p_viewport, RS::ViewportDebugDraw p_draw) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->debug_draw = p_draw; } -void RenderingServerViewport::viewport_set_measure_render_time(RID p_viewport, bool p_enable) { +void RendererViewport::viewport_set_measure_render_time(RID p_viewport, bool p_enable) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->measure_render_time = p_enable; } -float RenderingServerViewport::viewport_get_measured_render_time_cpu(RID p_viewport) const { +float RendererViewport::viewport_get_measured_render_time_cpu(RID p_viewport) const { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND_V(!viewport, 0); return double(viewport->time_cpu_end - viewport->time_cpu_begin) / 1000.0; } -float RenderingServerViewport::viewport_get_measured_render_time_gpu(RID p_viewport) const { +float RendererViewport::viewport_get_measured_render_time_gpu(RID p_viewport) const { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND_V(!viewport, 0); return double((viewport->time_gpu_end - viewport->time_gpu_begin) / 1000) / 1000.0; } -void RenderingServerViewport::viewport_set_snap_2d_transforms_to_pixel(RID p_viewport, bool p_enabled) { +void RendererViewport::viewport_set_snap_2d_transforms_to_pixel(RID p_viewport, bool p_enabled) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->snap_2d_transforms_to_pixel = p_enabled; } -void RenderingServerViewport::viewport_set_snap_2d_vertices_to_pixel(RID p_viewport, bool p_enabled) { +void RendererViewport::viewport_set_snap_2d_vertices_to_pixel(RID p_viewport, bool p_enabled) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->snap_2d_vertices_to_pixel = p_enabled; } -void RenderingServerViewport::viewport_set_default_canvas_item_texture_filter(RID p_viewport, RS::CanvasItemTextureFilter p_filter) { +void RendererViewport::viewport_set_default_canvas_item_texture_filter(RID p_viewport, RS::CanvasItemTextureFilter p_filter) { ERR_FAIL_COND_MSG(p_filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, "Viewport does not accept DEFAULT as texture filter (it's the topmost choice already).)"); Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->texture_filter = p_filter; } -void RenderingServerViewport::viewport_set_default_canvas_item_texture_repeat(RID p_viewport, RS::CanvasItemTextureRepeat p_repeat) { +void RendererViewport::viewport_set_default_canvas_item_texture_repeat(RID p_viewport, RS::CanvasItemTextureRepeat p_repeat) { ERR_FAIL_COND_MSG(p_repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, "Viewport does not accept DEFAULT as texture repeat (it's the topmost choice already).)"); Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); @@ -953,21 +961,21 @@ void RenderingServerViewport::viewport_set_default_canvas_item_texture_repeat(RI viewport->texture_repeat = p_repeat; } -void RenderingServerViewport::viewport_set_sdf_oversize_and_scale(RID p_viewport, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) { +void RendererViewport::viewport_set_sdf_oversize_and_scale(RID p_viewport, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); RSG::storage->render_target_set_sdf_size_and_scale(viewport->render_target, p_size, p_scale); } -bool RenderingServerViewport::free(RID p_rid) { +bool RendererViewport::free(RID p_rid) { if (viewport_owner.owns(p_rid)) { Viewport *viewport = viewport_owner.getornull(p_rid); RSG::storage->free(viewport->render_target); - RSG::scene_render->free(viewport->shadow_atlas); + RSG::scene->free(viewport->shadow_atlas); if (viewport->render_buffers.is_valid()) { - RSG::scene_render->free(viewport->render_buffers); + RSG::scene->free(viewport->render_buffers); } while (viewport->canvas_map.front()) { @@ -986,7 +994,7 @@ bool RenderingServerViewport::free(RID p_rid) { return false; } -void RenderingServerViewport::handle_timestamp(String p_timestamp, uint64_t p_cpu_time, uint64_t p_gpu_time) { +void RendererViewport::handle_timestamp(String p_timestamp, uint64_t p_cpu_time, uint64_t p_gpu_time) { RID *vp = timestamp_vp_map.getptr(p_timestamp); if (!vp) { return; @@ -1008,9 +1016,14 @@ void RenderingServerViewport::handle_timestamp(String p_timestamp, uint64_t p_cp } } -void RenderingServerViewport::set_default_clear_color(const Color &p_color) { +void RendererViewport::set_default_clear_color(const Color &p_color) { RSG::storage->set_default_clear_color(p_color); } -RenderingServerViewport::RenderingServerViewport() { +//workaround for setting this on thread +void RendererViewport::call_set_use_vsync(bool p_enable) { + DisplayServer::get_singleton()->_set_use_vsync(p_enable); +} + +RendererViewport::RendererViewport() { } diff --git a/servers/rendering/rendering_server_viewport.h b/servers/rendering/renderer_viewport.h index ba55b2e66e..f5ed543e8d 100644 --- a/servers/rendering/rendering_server_viewport.h +++ b/servers/rendering/renderer_viewport.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rendering_server_viewport.h */ +/* renderer_viewport.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -33,11 +33,11 @@ #include "core/templates/rid_owner.h" #include "core/templates/self_list.h" -#include "rasterizer.h" +#include "renderer_compositor.h" #include "servers/rendering_server.h" #include "servers/xr/xr_interface.h" -class RenderingServerViewport { +class RendererViewport { public: struct CanvasBase { }; @@ -81,9 +81,12 @@ public: RID shadow_atlas; int shadow_atlas_size; + bool shadow_atlas_16_bits = false; bool sdf_active; + float lod_threshold = 1.0; + uint64_t last_pass = 0; int render_info[RS::VIEWPORT_RENDER_INFO_MAX]; @@ -162,7 +165,7 @@ public: uint64_t draw_viewports_pass = 0; - mutable RID_PtrOwner<Viewport> viewport_owner; + mutable RID_PtrOwner<Viewport, true> viewport_owner; struct ViewportSort { _FORCE_INLINE_ bool operator()(const Viewport *p_left, const Viewport *p_right) const { @@ -183,7 +186,8 @@ private: void _draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_eye = XRInterface::EYE_MONO); public: - RID viewport_create(); + RID viewport_allocate(); + void viewport_initialize(RID p_rid); void viewport_set_use_xr(RID p_viewport, bool p_use_xr); @@ -215,13 +219,15 @@ public: void viewport_set_global_canvas_transform(RID p_viewport, const Transform2D &p_transform); void viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer); - void viewport_set_shadow_atlas_size(RID p_viewport, int p_size); + void viewport_set_shadow_atlas_size(RID p_viewport, int p_size, bool p_16_bits = false); void viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv); void viewport_set_msaa(RID p_viewport, RS::ViewportMSAA p_msaa); void viewport_set_screen_space_aa(RID p_viewport, RS::ViewportScreenSpaceAA p_mode); void viewport_set_use_debanding(RID p_viewport, bool p_use_debanding); + void viewport_set_lod_threshold(RID p_viewport, float p_pixels); + virtual int viewport_get_render_info(RID p_viewport, RS::ViewportRenderInfo p_info); virtual void viewport_set_debug_draw(RID p_viewport, RS::ViewportDebugDraw p_draw); @@ -244,8 +250,11 @@ public: bool free(RID p_rid); - RenderingServerViewport(); - virtual ~RenderingServerViewport() {} + //workaround for setting this on thread + void call_set_use_vsync(bool p_enable); + + RendererViewport(); + virtual ~RendererViewport() {} }; #endif // VISUALSERVERVIEWPORT_H diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 1259b161bd..27a9353e4e 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -68,7 +68,7 @@ RID RenderingDevice::_texture_create(const Ref<RDTextureFormat> &p_format, const Vector<Vector<uint8_t>> data; for (int i = 0; i < p_data.size(); i++) { Vector<uint8_t> byte_slice = p_data[i]; - ERR_FAIL_COND_V(byte_slice.empty(), RID()); + ERR_FAIL_COND_V(byte_slice.is_empty(), RID()); data.push_back(byte_slice); } return texture_create(p_format->base, p_view->base, data); @@ -154,7 +154,7 @@ RID RenderingDevice::shader_create_from_bytecode(const Ref<RDShaderBytecode> &p_ String error = p_bytecode->get_stage_compile_error(stage); ERR_FAIL_COND_V_MSG(error != String(), RID(), "Can't create a shader from an errored bytecode. Check errors in source bytecode."); sd.spir_v = p_bytecode->get_stage_bytecode(stage); - if (sd.spir_v.empty()) { + if (sd.spir_v.is_empty()) { continue; } stage_data.push_back(sd); @@ -174,8 +174,8 @@ RID RenderingDevice::_uniform_set_create(const Array &p_uniforms, RID p_shader, return uniform_set_create(uniforms, p_shader, p_shader_set); } -Error RenderingDevice::_buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, bool p_sync_with_draw) { - return buffer_update(p_buffer, p_offset, p_size, p_data.ptr(), p_sync_with_draw); +Error RenderingDevice::_buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, uint32_t p_post_barrier) { + return buffer_update(p_buffer, p_offset, p_size, p_data.ptr(), p_post_barrier); } RID RenderingDevice::_render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, int p_dynamic_state_flags) { @@ -240,16 +240,12 @@ void RenderingDevice::_compute_list_set_push_constant(ComputeListID p_list, cons compute_list_set_push_constant(p_list, p_data.ptr(), p_data_size); } -void RenderingDevice::compute_list_dispatch_threads(ComputeListID p_list, uint32_t p_x_threads, uint32_t p_y_threads, uint32_t p_z_threads, uint32_t p_x_local_group, uint32_t p_y_local_group, uint32_t p_z_local_group) { - compute_list_dispatch(p_list, (p_x_threads - 1) / p_x_local_group + 1, (p_y_threads - 1) / p_y_local_group + 1, (p_z_threads - 1) / p_z_local_group + 1); -} - void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("texture_create", "format", "view", "data"), &RenderingDevice::_texture_create, DEFVAL(Array())); ClassDB::bind_method(D_METHOD("texture_create_shared", "view", "with_texture"), &RenderingDevice::_texture_create_shared); ClassDB::bind_method(D_METHOD("texture_create_shared_from_slice", "view", "with_texture", "layer", "mipmap", "slice_type"), &RenderingDevice::_texture_create_shared_from_slice, DEFVAL(TEXTURE_SLICE_2D)); - ClassDB::bind_method(D_METHOD("texture_update", "texture", "layer", "data", "sync_with_draw"), &RenderingDevice::texture_update, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("texture_update", "texture", "layer", "data", "post_barrier"), &RenderingDevice::texture_update, DEFVAL(BARRIER_MASK_ALL)); ClassDB::bind_method(D_METHOD("texture_get_data", "texture", "layer"), &RenderingDevice::texture_get_data); ClassDB::bind_method(D_METHOD("texture_is_format_supported_for_usage", "format", "usage_flags"), &RenderingDevice::texture_is_format_supported_for_usage); @@ -257,23 +253,23 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("texture_is_shared", "texture"), &RenderingDevice::texture_is_shared); ClassDB::bind_method(D_METHOD("texture_is_valid", "texture"), &RenderingDevice::texture_is_valid); - ClassDB::bind_method(D_METHOD("texture_copy", "from_texture", "to_texture", "from_pos", "to_pos", "size", "src_mipmap", "dst_mipmap", "src_layer", "dst_layer", "sync_with_draw"), &RenderingDevice::texture_copy, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("texture_clear", "texture", "color", "base_mipmap", "mipmap_count", "base_layer", "layer_count", "sync_with_draw"), &RenderingDevice::texture_clear, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("texture_resolve_multisample", "from_texture", "to_texture", "sync_with_draw"), &RenderingDevice::texture_resolve_multisample, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("texture_copy", "from_texture", "to_texture", "from_pos", "to_pos", "size", "src_mipmap", "dst_mipmap", "src_layer", "dst_layer", "post_barrier"), &RenderingDevice::texture_copy, DEFVAL(BARRIER_MASK_ALL)); + ClassDB::bind_method(D_METHOD("texture_clear", "texture", "color", "base_mipmap", "mipmap_count", "base_layer", "layer_count", "post_barrier"), &RenderingDevice::texture_clear, DEFVAL(BARRIER_MASK_ALL)); + ClassDB::bind_method(D_METHOD("texture_resolve_multisample", "from_texture", "to_texture", "post_barrier"), &RenderingDevice::texture_resolve_multisample, DEFVAL(BARRIER_MASK_ALL)); ClassDB::bind_method(D_METHOD("framebuffer_format_create", "attachments"), &RenderingDevice::_framebuffer_format_create); - ClassDB::bind_method(D_METHOD("framebuffer_format_create_empty", "size"), &RenderingDevice::framebuffer_format_create_empty); + ClassDB::bind_method(D_METHOD("framebuffer_format_create_empty", "samples"), &RenderingDevice::framebuffer_format_create_empty, DEFVAL(TEXTURE_SAMPLES_1)); ClassDB::bind_method(D_METHOD("framebuffer_format_get_texture_samples", "format"), &RenderingDevice::framebuffer_format_get_texture_samples); ClassDB::bind_method(D_METHOD("framebuffer_create", "textures", "validate_with_format"), &RenderingDevice::_framebuffer_create, DEFVAL(INVALID_FORMAT_ID)); - ClassDB::bind_method(D_METHOD("framebuffer_create_empty", "size", "validate_with_format"), &RenderingDevice::framebuffer_create_empty, DEFVAL(INVALID_FORMAT_ID)); + ClassDB::bind_method(D_METHOD("framebuffer_create_empty", "size", "samples", "validate_with_format"), &RenderingDevice::framebuffer_create_empty, DEFVAL(TEXTURE_SAMPLES_1), DEFVAL(INVALID_FORMAT_ID)); ClassDB::bind_method(D_METHOD("framebuffer_get_format", "framebuffer"), &RenderingDevice::framebuffer_get_format); ClassDB::bind_method(D_METHOD("sampler_create", "state"), &RenderingDevice::_sampler_create); - ClassDB::bind_method(D_METHOD("vertex_buffer_create", "size_bytes", "data"), &RenderingDevice::vertex_buffer_create, DEFVAL(Vector<uint8_t>())); + ClassDB::bind_method(D_METHOD("vertex_buffer_create", "size_bytes", "data", "use_as_storage"), &RenderingDevice::vertex_buffer_create, DEFVAL(Vector<uint8_t>()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("vertex_format_create", "vertex_descriptions"), &RenderingDevice::_vertex_format_create); - ClassDB::bind_method(D_METHOD("index_buffer_create", "size_indices", "format", "data"), &RenderingDevice::index_buffer_create, DEFVAL(Vector<uint8_t>()), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("index_buffer_create", "size_indices", "format", "data", "use_restart_indices"), &RenderingDevice::index_buffer_create, DEFVAL(Vector<uint8_t>()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("index_array_create", "index_buffer", "index_offset", "index_count"), &RenderingDevice::index_array_create); ClassDB::bind_method(D_METHOD("shader_compile_from_source", "shader_source", "allow_cache"), &RenderingDevice::_shader_compile_from_source, DEFVAL(true)); @@ -287,7 +283,8 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("uniform_set_create", "uniforms", "shader", "shader_set"), &RenderingDevice::_uniform_set_create); ClassDB::bind_method(D_METHOD("uniform_set_is_valid", "uniform_set"), &RenderingDevice::uniform_set_is_valid); - ClassDB::bind_method(D_METHOD("buffer_update", "buffer", "offset", "size_bytes", "data", "sync_with_draw"), &RenderingDevice::_buffer_update, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("buffer_update", "buffer", "offset", "size_bytes", "data", "post_barrier"), &RenderingDevice::_buffer_update, DEFVAL(BARRIER_MASK_ALL)); + ClassDB::bind_method(D_METHOD("buffer_clear", "buffer", "offset", "size_bytes", "post_barrier"), &RenderingDevice::buffer_clear, DEFVAL(BARRIER_MASK_ALL)); ClassDB::bind_method(D_METHOD("buffer_get_data", "buffer"), &RenderingDevice::buffer_get_data); ClassDB::bind_method(D_METHOD("render_pipeline_create", "shader", "framebuffer_format", "vertex_format", "primitive", "rasterization_state", "multisample_state", "stencil_state", "color_blend_state", "dynamic_state_flags"), &RenderingDevice::_render_pipeline_create, DEFVAL(0)); @@ -316,19 +313,19 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("draw_list_enable_scissor", "draw_list", "rect"), &RenderingDevice::draw_list_enable_scissor, DEFVAL(Rect2i())); ClassDB::bind_method(D_METHOD("draw_list_disable_scissor", "draw_list"), &RenderingDevice::draw_list_disable_scissor); - ClassDB::bind_method(D_METHOD("draw_list_end"), &RenderingDevice::draw_list_end); + ClassDB::bind_method(D_METHOD("draw_list_end", "post_barrier"), &RenderingDevice::draw_list_end, DEFVAL(BARRIER_MASK_ALL)); - ClassDB::bind_method(D_METHOD("compute_list_begin"), &RenderingDevice::compute_list_begin); + ClassDB::bind_method(D_METHOD("compute_list_begin", "allow_draw_overlap"), &RenderingDevice::compute_list_begin, DEFVAL(false)); ClassDB::bind_method(D_METHOD("compute_list_bind_compute_pipeline", "compute_list", "compute_pipeline"), &RenderingDevice::compute_list_bind_compute_pipeline); ClassDB::bind_method(D_METHOD("compute_list_set_push_constant", "compute_list", "buffer", "size_bytes"), &RenderingDevice::_compute_list_set_push_constant); ClassDB::bind_method(D_METHOD("compute_list_bind_uniform_set", "compute_list", "uniform_set", "set_index"), &RenderingDevice::compute_list_bind_uniform_set); ClassDB::bind_method(D_METHOD("compute_list_dispatch", "compute_list", "x_groups", "y_groups", "z_groups"), &RenderingDevice::compute_list_dispatch); ClassDB::bind_method(D_METHOD("compute_list_add_barrier", "compute_list"), &RenderingDevice::compute_list_add_barrier); - ClassDB::bind_method(D_METHOD("compute_list_end"), &RenderingDevice::compute_list_end); + ClassDB::bind_method(D_METHOD("compute_list_end", "post_barrier"), &RenderingDevice::compute_list_end, DEFVAL(BARRIER_MASK_ALL)); ClassDB::bind_method(D_METHOD("free", "rid"), &RenderingDevice::free); - ClassDB::bind_method(D_METHOD("capture_timestamp", "name", "sync_to_draw"), &RenderingDevice::capture_timestamp); + ClassDB::bind_method(D_METHOD("capture_timestamp", "name"), &RenderingDevice::capture_timestamp); ClassDB::bind_method(D_METHOD("get_captured_timestamps_count"), &RenderingDevice::get_captured_timestamps_count); ClassDB::bind_method(D_METHOD("get_captured_timestamps_frame"), &RenderingDevice::get_captured_timestamps_frame); ClassDB::bind_method(D_METHOD("get_captured_timestamp_gpu_time", "index"), &RenderingDevice::get_captured_timestamp_gpu_time); @@ -340,8 +337,27 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("submit"), &RenderingDevice::submit); ClassDB::bind_method(D_METHOD("sync"), &RenderingDevice::sync); + ClassDB::bind_method(D_METHOD("barrier", "from", "to"), &RenderingDevice::barrier, DEFVAL(BARRIER_MASK_ALL), DEFVAL(BARRIER_MASK_ALL)); + ClassDB::bind_method(D_METHOD("full_barrier"), &RenderingDevice::full_barrier); + ClassDB::bind_method(D_METHOD("create_local_device"), &RenderingDevice::create_local_device); + ClassDB::bind_method(D_METHOD("set_resource_name", "id", "name"), &RenderingDevice::set_resource_name); + + ClassDB::bind_method(D_METHOD("draw_command_begin_label", "name", "color"), &RenderingDevice::draw_command_begin_label); + ClassDB::bind_method(D_METHOD("draw_command_insert_label", "name", "color"), &RenderingDevice::draw_command_insert_label); + ClassDB::bind_method(D_METHOD("draw_command_end_label"), &RenderingDevice::draw_command_end_label); + + ClassDB::bind_method(D_METHOD("get_device_vendor_name"), &RenderingDevice::get_device_vendor_name); + ClassDB::bind_method(D_METHOD("get_device_name"), &RenderingDevice::get_device_name); + ClassDB::bind_method(D_METHOD("get_device_pipeline_cache_uuid"), &RenderingDevice::get_device_pipeline_cache_uuid); + + BIND_CONSTANT(BARRIER_MASK_RASTER); + BIND_CONSTANT(BARRIER_MASK_COMPUTE); + BIND_CONSTANT(BARRIER_MASK_TRANSFER); + BIND_CONSTANT(BARRIER_MASK_ALL); + BIND_CONSTANT(BARRIER_MASK_NO_BARRIER); + BIND_ENUM_CONSTANT(DATA_FORMAT_R4G4_UNORM_PACK8); BIND_ENUM_CONSTANT(DATA_FORMAT_R4G4B4A4_UNORM_PACK16); BIND_ENUM_CONSTANT(DATA_FORMAT_B4G4R4A4_UNORM_PACK16); @@ -744,6 +760,8 @@ void RenderingDevice::_bind_methods() { BIND_ENUM_CONSTANT(DYNAMIC_STATE_STENCIL_REFERENCE); BIND_ENUM_CONSTANT(INITIAL_ACTION_CLEAR); //start rendering and clear the framebuffer (supply params) + BIND_ENUM_CONSTANT(INITIAL_ACTION_CLEAR_REGION); //start rendering and clear the framebuffer (supply params) + BIND_ENUM_CONSTANT(INITIAL_ACTION_CLEAR_REGION_CONTINUE); //continue rendering and clear the framebuffer (supply params) BIND_ENUM_CONSTANT(INITIAL_ACTION_KEEP); //start rendering); but keep attached color texture contents (depth will be cleared) BIND_ENUM_CONSTANT(INITIAL_ACTION_DROP); //start rendering); ignore what is there); just write above it BIND_ENUM_CONSTANT(INITIAL_ACTION_CONTINUE); //continue rendering (framebuffer must have been left in "continue" state as final action previously) diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index f1f8b3cda0..9fbf58d131 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -336,6 +336,18 @@ public: }; /*****************/ + /**** BARRIER ****/ + /*****************/ + + enum BarrierMask { + BARRIER_MASK_RASTER = 1, + BARRIER_MASK_COMPUTE = 2, + BARRIER_MASK_TRANSFER = 4, + BARRIER_MASK_NO_BARRIER = 8, + BARRIER_MASK_ALL = BARRIER_MASK_RASTER | BARRIER_MASK_COMPUTE | BARRIER_MASK_TRANSFER + }; + + /*****************/ /**** TEXTURE ****/ /*****************/ @@ -392,7 +404,7 @@ public: uint32_t depth; uint32_t array_layers; uint32_t mipmaps; - TextureType type; + TextureType texture_type; TextureSamples samples; uint32_t usage_bits; Vector<DataFormat> shareable_formats; @@ -404,7 +416,7 @@ public: depth = 1; array_layers = 1; mipmaps = 1; - type = TEXTURE_TYPE_2D; + texture_type = TEXTURE_TYPE_2D; samples = TEXTURE_SAMPLES_1; usage_bits = 0; } @@ -433,20 +445,21 @@ public: TEXTURE_SLICE_2D, TEXTURE_SLICE_CUBEMAP, TEXTURE_SLICE_3D, + TEXTURE_SLICE_2D_ARRAY, }; virtual RID texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, TextureSliceType p_slice_type = TEXTURE_SLICE_2D) = 0; - virtual Error texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, bool p_sync_with_draw = false) = 0; //this function can be used from any thread and it takes effect at the beginning of the frame, unless sync with draw is used, which is used to mix updates with draw calls + virtual Error texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; virtual Vector<uint8_t> texture_get_data(RID p_texture, uint32_t p_layer) = 0; // CPU textures will return immediately, while GPU textures will most likely force a flush virtual bool texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const = 0; virtual bool texture_is_shared(RID p_texture) = 0; virtual bool texture_is_valid(RID p_texture) = 0; - virtual Error texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, bool p_sync_with_draw = false) = 0; - virtual Error texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, bool p_sync_with_draw = false) = 0; - virtual Error texture_resolve_multisample(RID p_from_texture, RID p_to_texture, bool p_sync_with_draw = false) = 0; + virtual Error texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; + virtual Error texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; + virtual Error texture_resolve_multisample(RID p_from_texture, RID p_to_texture, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; /*********************/ /**** FRAMEBUFFER ****/ @@ -467,11 +480,11 @@ public: // This ID is warranted to be unique for the same formats, does not need to be freed virtual FramebufferFormatID framebuffer_format_create(const Vector<AttachmentFormat> &p_format) = 0; - virtual FramebufferFormatID framebuffer_format_create_empty(const Size2i &p_size) = 0; + virtual FramebufferFormatID framebuffer_format_create_empty(TextureSamples p_samples = TEXTURE_SAMPLES_1) = 0; virtual TextureSamples framebuffer_format_get_texture_samples(FramebufferFormatID p_format) = 0; virtual RID framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID) = 0; - virtual RID framebuffer_create_empty(const Size2i &p_size, FramebufferFormatID p_format_check = INVALID_ID) = 0; + virtual RID framebuffer_create_empty(const Size2i &p_size, TextureSamples p_samples = TEXTURE_SAMPLES_1, FramebufferFormatID p_format_check = INVALID_ID) = 0; virtual FramebufferFormatID framebuffer_get_format(RID p_framebuffer) = 0; @@ -564,7 +577,7 @@ public: frequency = VERTEX_FREQUENCY_VERTEX; } }; - virtual RID vertex_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>()) = 0; + virtual RID vertex_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>(), bool p_use_as_storage = false) = 0; typedef int64_t VertexFormatID; @@ -629,7 +642,7 @@ public: virtual RID texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const Vector<uint8_t> &p_data = Vector<uint8_t>()) = 0; struct Uniform { - UniformType type; + UniformType uniform_type; int binding; //binding index as specified in shader //for single items, provide one ID, for @@ -640,7 +653,7 @@ public: Vector<RID> ids; Uniform() { - type = UNIFORM_TYPE_IMAGE; + uniform_type = UNIFORM_TYPE_IMAGE; binding = 0; } }; @@ -648,7 +661,8 @@ public: virtual RID uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set) = 0; virtual bool uniform_set_is_valid(RID p_uniform_set) = 0; - virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, bool p_sync_with_draw = false) = 0; //this function can be used from any thread and it takes effect at the beginning of the frame, unless sync with draw is used, which is used to mix updates with draw calls + virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; + virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; virtual Vector<uint8_t> buffer_get_data(RID p_buffer) = 0; //this causes stall, only use to retrieve large buffers for saving /*************************/ @@ -929,7 +943,9 @@ public: /********************/ enum InitialAction { - INITIAL_ACTION_CLEAR, //start rendering and clear the framebuffer (supply params) + INITIAL_ACTION_CLEAR, //start rendering and clear the whole framebuffer (region or not) (supply params) + INITIAL_ACTION_CLEAR_REGION, //start rendering and clear the framebuffer in the specified region (supply params) + INITIAL_ACTION_CLEAR_REGION_CONTINUE, //countinue rendering and clear the framebuffer in the specified region (supply params) INITIAL_ACTION_KEEP, //start rendering, but keep attached color texture contents (depth will be cleared) INITIAL_ACTION_DROP, //start rendering, ignore what is there, just write above it INITIAL_ACTION_CONTINUE, //continue rendering (framebuffer must have been left in "continue" state as final action previously) @@ -961,7 +977,7 @@ public: virtual void draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) = 0; virtual void draw_list_disable_scissor(DrawListID p_list) = 0; - virtual void draw_list_end() = 0; + virtual void draw_list_end(uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; /***********************/ /**** COMPUTE LISTS ****/ @@ -969,17 +985,18 @@ public: typedef int64_t ComputeListID; - virtual ComputeListID compute_list_begin() = 0; + virtual ComputeListID compute_list_begin(bool p_allow_draw_overlap = false) = 0; virtual void compute_list_bind_compute_pipeline(ComputeListID p_list, RID p_compute_pipeline) = 0; virtual void compute_list_bind_uniform_set(ComputeListID p_list, RID p_uniform_set, uint32_t p_index) = 0; virtual void compute_list_set_push_constant(ComputeListID p_list, const void *p_data, uint32_t p_data_size) = 0; virtual void compute_list_dispatch(ComputeListID p_list, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) = 0; - virtual void compute_list_dispatch_threads(ComputeListID p_list, uint32_t p_x_threads, uint32_t p_y_threads, uint32_t p_z_threads, uint32_t p_x_local_group, uint32_t p_y_local_group, uint32_t p_z_local_group); + virtual void compute_list_dispatch_threads(ComputeListID p_list, uint32_t p_x_threads, uint32_t p_y_threads, uint32_t p_z_threads) = 0; virtual void compute_list_dispatch_indirect(ComputeListID p_list, RID p_buffer, uint32_t p_offset) = 0; virtual void compute_list_add_barrier(ComputeListID p_list) = 0; - virtual void compute_list_end() = 0; + virtual void compute_list_end(uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; + virtual void barrier(uint32_t p_from = BARRIER_MASK_ALL, uint32_t p_to = BARRIER_MASK_ALL) = 0; virtual void full_barrier() = 0; /***************/ @@ -992,7 +1009,7 @@ public: /**** Timing ****/ /****************/ - virtual void capture_timestamp(const String &p_name, bool p_sync_to_draw) = 0; + virtual void capture_timestamp(const String &p_name) = 0; virtual uint32_t get_captured_timestamps_count() const = 0; virtual uint64_t get_captured_timestamps_frame() const = 0; virtual uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const = 0; @@ -1057,6 +1074,16 @@ public: virtual RenderingDevice *create_local_device() = 0; + virtual void set_resource_name(RID p_id, const String p_name) = 0; + + virtual void draw_command_begin_label(String p_label_name, const Color p_color = Color(1, 1, 1, 1)) = 0; + virtual void draw_command_insert_label(String p_label_name, const Color p_color = Color(1, 1, 1, 1)) = 0; + virtual void draw_command_end_label() = 0; + + virtual String get_device_vendor_name() const = 0; + virtual String get_device_name() const = 0; + virtual String get_device_pipeline_cache_uuid() const = 0; + static RenderingDevice *get_singleton(); RenderingDevice(); @@ -1076,7 +1103,7 @@ protected: RID _uniform_set_create(const Array &p_uniforms, RID p_shader, uint32_t p_shader_set); - Error _buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, bool p_sync_with_draw = false); + Error _buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL); RID _render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, int p_dynamic_state_flags = 0); diff --git a/servers/rendering/rendering_device_binds.cpp b/servers/rendering/rendering_device_binds.cpp index af9ecef0dd..2f11360364 100644 --- a/servers/rendering/rendering_device_binds.cpp +++ b/servers/rendering/rendering_device_binds.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -163,7 +163,7 @@ Error RDShaderFile::parse_versions_from_text(const String &p_text, const String ERR_FAIL_V_MSG(ERR_PARSE_ERROR, "When writing compute shaders, [compute] mustbe the only stage present."); } - if (version_texts.empty()) { + if (version_texts.is_empty()) { version_texts[""] = ""; //make sure a default version exists } diff --git a/servers/rendering/rendering_device_binds.h b/servers/rendering/rendering_device_binds.h index 66c6a1c3a9..e43c3669b5 100644 --- a/servers/rendering/rendering_device_binds.h +++ b/servers/rendering/rendering_device_binds.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -64,7 +64,7 @@ public: RD_SETGET(uint32_t, depth) RD_SETGET(uint32_t, array_layers) RD_SETGET(uint32_t, mipmaps) - RD_SETGET(RD::TextureType, type) + RD_SETGET(RD::TextureType, texture_type) RD_SETGET(RD::TextureSamples, samples) RD_SETGET(uint32_t, usage_bits) @@ -79,7 +79,7 @@ protected: RD_BIND(Variant::INT, RDTextureFormat, depth); RD_BIND(Variant::INT, RDTextureFormat, array_layers); RD_BIND(Variant::INT, RDTextureFormat, mipmaps); - RD_BIND(Variant::INT, RDTextureFormat, type); + RD_BIND(Variant::INT, RDTextureFormat, texture_type); RD_BIND(Variant::INT, RDTextureFormat, samples); RD_BIND(Variant::INT, RDTextureFormat, usage_bits); ClassDB::bind_method(D_METHOD("add_shareable_format", "format"), &RDTextureFormat::add_shareable_format); @@ -392,7 +392,7 @@ class RDUniform : public Reference { RD::Uniform base; public: - RD_SETGET(RD::UniformType, type) + RD_SETGET(RD::UniformType, uniform_type) RD_SETGET(int32_t, binding) void add_id(const RID &p_id) { base.ids.push_back(p_id); } @@ -415,7 +415,7 @@ protected: } } static void _bind_methods() { - RD_BIND(Variant::INT, RDUniform, type); + RD_BIND(Variant::INT, RDUniform, uniform_type); RD_BIND(Variant::INT, RDUniform, binding); ClassDB::bind_method(D_METHOD("add_id", "id"), &RDUniform::add_id); ClassDB::bind_method(D_METHOD("clear_ids"), &RDUniform::clear_ids); diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp new file mode 100644 index 0000000000..61d1efaf22 --- /dev/null +++ b/servers/rendering/rendering_server_default.cpp @@ -0,0 +1,421 @@ +/*************************************************************************/ +/* rendering_server_default.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "rendering_server_default.h" + +#include "core/config/project_settings.h" +#include "core/io/marshalls.h" +#include "core/os/os.h" +#include "core/templates/sort_array.h" +#include "renderer_canvas_cull.h" +#include "renderer_scene_cull.h" +#include "rendering_server_globals.h" + +// careful, these may run in different threads than the visual server + +int RenderingServerDefault::changes = 0; + +/* BLACK BARS */ + +void RenderingServerDefault::black_bars_set_margins(int p_left, int p_top, int p_right, int p_bottom) { + black_margin[SIDE_LEFT] = p_left; + black_margin[SIDE_TOP] = p_top; + black_margin[SIDE_RIGHT] = p_right; + black_margin[SIDE_BOTTOM] = p_bottom; +} + +void RenderingServerDefault::black_bars_set_images(RID p_left, RID p_top, RID p_right, RID p_bottom) { + black_image[SIDE_LEFT] = p_left; + black_image[SIDE_TOP] = p_top; + black_image[SIDE_RIGHT] = p_right; + black_image[SIDE_BOTTOM] = p_bottom; +} + +void RenderingServerDefault::_draw_margins() { + RSG::canvas_render->draw_window_margins(black_margin, black_image); +}; + +/* FREE */ + +void RenderingServerDefault::_free(RID p_rid) { + if (RSG::storage->free(p_rid)) { + return; + } + if (RSG::canvas->free(p_rid)) { + return; + } + if (RSG::viewport->free(p_rid)) { + return; + } + if (RSG::scene->free(p_rid)) { + return; + } +} + +/* EVENT QUEUING */ + +void RenderingServerDefault::request_frame_drawn_callback(Object *p_where, const StringName &p_method, const Variant &p_userdata) { + ERR_FAIL_NULL(p_where); + FrameDrawnCallbacks fdc; + fdc.object = p_where->get_instance_id(); + fdc.method = p_method; + fdc.param = p_userdata; + + frame_drawn_callbacks.push_back(fdc); +} + +void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) { + //needs to be done before changes is reset to 0, to not force the editor to redraw + RS::get_singleton()->emit_signal("frame_pre_draw"); + + changes = 0; + + RSG::rasterizer->begin_frame(frame_step); + + TIMESTAMP_BEGIN() + + uint64_t time_usec = OS::get_singleton()->get_ticks_usec(); + + RSG::scene->update(); //update scenes stuff before updating instances + + frame_setup_time = double(OS::get_singleton()->get_ticks_usec() - time_usec) / 1000.0; + + RSG::storage->update_particles(); //need to be done after instances are updated (colliders and particle transforms), and colliders are rendered + + RSG::scene->render_probes(); + + RSG::viewport->draw_viewports(); + RSG::canvas_render->update(); + + _draw_margins(); + RSG::rasterizer->end_frame(p_swap_buffers); + + while (frame_drawn_callbacks.front()) { + Object *obj = ObjectDB::get_instance(frame_drawn_callbacks.front()->get().object); + if (obj) { + Callable::CallError ce; + const Variant *v = &frame_drawn_callbacks.front()->get().param; + obj->call(frame_drawn_callbacks.front()->get().method, &v, 1, ce); + if (ce.error != Callable::CallError::CALL_OK) { + String err = Variant::get_call_error_text(obj, frame_drawn_callbacks.front()->get().method, &v, 1, ce); + ERR_PRINT("Error calling frame drawn function: " + err); + } + } + + frame_drawn_callbacks.pop_front(); + } + RS::get_singleton()->emit_signal("frame_post_draw"); + + if (RSG::storage->get_captured_timestamps_count()) { + Vector<FrameProfileArea> new_profile; + if (RSG::storage->capturing_timestamps) { + new_profile.resize(RSG::storage->get_captured_timestamps_count()); + } + + uint64_t base_cpu = RSG::storage->get_captured_timestamp_cpu_time(0); + uint64_t base_gpu = RSG::storage->get_captured_timestamp_gpu_time(0); + for (uint32_t i = 0; i < RSG::storage->get_captured_timestamps_count(); i++) { + uint64_t time_cpu = RSG::storage->get_captured_timestamp_cpu_time(i); + uint64_t time_gpu = RSG::storage->get_captured_timestamp_gpu_time(i); + + String name = RSG::storage->get_captured_timestamp_name(i); + + if (name.begins_with("vp_")) { + RSG::viewport->handle_timestamp(name, time_cpu, time_gpu); + } + + if (RSG::storage->capturing_timestamps) { + new_profile.write[i].gpu_msec = float((time_gpu - base_gpu) / 1000) / 1000.0; + new_profile.write[i].cpu_msec = float(time_cpu - base_cpu) / 1000.0; + new_profile.write[i].name = RSG::storage->get_captured_timestamp_name(i); + } + } + + frame_profile = new_profile; + } + + frame_profile_frame = RSG::storage->get_captured_timestamps_frame(); + + if (print_gpu_profile) { + if (print_frame_profile_ticks_from == 0) { + print_frame_profile_ticks_from = OS::get_singleton()->get_ticks_usec(); + } + float total_time = 0.0; + + for (int i = 0; i < frame_profile.size() - 1; i++) { + String name = frame_profile[i].name; + if (name[0] == '<' || name[0] == '>') { + continue; + } + + float time = frame_profile[i + 1].gpu_msec - frame_profile[i].gpu_msec; + + if (name[0] != '<' && name[0] != '>') { + if (print_gpu_profile_task_time.has(name)) { + print_gpu_profile_task_time[name] += time; + } else { + print_gpu_profile_task_time[name] = time; + } + } + } + + if (frame_profile.size()) { + total_time = frame_profile[frame_profile.size() - 1].gpu_msec; + } + + uint64_t ticks_elapsed = OS::get_singleton()->get_ticks_usec() - print_frame_profile_ticks_from; + print_frame_profile_frame_count++; + if (ticks_elapsed > 1000000) { + print_line("GPU PROFILE (total " + rtos(total_time) + "ms): "); + + float print_threshold = 0.01; + for (OrderedHashMap<String, float>::Element E = print_gpu_profile_task_time.front(); E; E = E.next()) { + float time = E.value() / float(print_frame_profile_frame_count); + if (time > print_threshold) { + print_line("\t-" + E.key() + ": " + rtos(time) + "ms"); + } + } + print_gpu_profile_task_time.clear(); + print_frame_profile_ticks_from = OS::get_singleton()->get_ticks_usec(); + print_frame_profile_frame_count = 0; + } + } +} + +float RenderingServerDefault::get_frame_setup_time_cpu() const { + return frame_setup_time; +} + +bool RenderingServerDefault::has_changed() const { + return changes > 0; +} + +void RenderingServerDefault::_init() { + RSG::rasterizer->initialize(); +} + +void RenderingServerDefault::_finish() { + if (test_cube.is_valid()) { + free(test_cube); + } + + RSG::rasterizer->finalize(); +} + +void RenderingServerDefault::init() { + if (create_thread) { + print_verbose("RenderingServerWrapMT: Creating render thread"); + DisplayServer::get_singleton()->release_rendering_thread(); + if (create_thread) { + thread.start(_thread_callback, this); + print_verbose("RenderingServerWrapMT: Starting render thread"); + } + while (!draw_thread_up.is_set()) { + OS::get_singleton()->delay_usec(1000); + } + print_verbose("RenderingServerWrapMT: Finished render thread"); + } else { + _init(); + } +} + +void RenderingServerDefault::finish() { + if (create_thread) { + command_queue.push(this, &RenderingServerDefault::_thread_exit); + thread.wait_to_finish(); + } else { + _finish(); + } +} + +/* STATUS INFORMATION */ + +int RenderingServerDefault::get_render_info(RenderInfo p_info) { + return RSG::storage->get_render_info(p_info); +} + +String RenderingServerDefault::get_video_adapter_name() const { + return RSG::storage->get_video_adapter_name(); +} + +String RenderingServerDefault::get_video_adapter_vendor() const { + return RSG::storage->get_video_adapter_vendor(); +} + +void RenderingServerDefault::set_frame_profiling_enabled(bool p_enable) { + RSG::storage->capturing_timestamps = p_enable; +} + +uint64_t RenderingServerDefault::get_frame_profile_frame() { + return frame_profile_frame; +} + +Vector<RenderingServer::FrameProfileArea> RenderingServerDefault::get_frame_profile() { + return frame_profile; +} + +/* TESTING */ + +void RenderingServerDefault::set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter) { + redraw_request(); + RSG::rasterizer->set_boot_image(p_image, p_color, p_scale, p_use_filter); +} + +void RenderingServerDefault::set_default_clear_color(const Color &p_color) { + RSG::viewport->set_default_clear_color(p_color); +} + +bool RenderingServerDefault::has_feature(Features p_feature) const { + return false; +} + +void RenderingServerDefault::sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) { + RSG::scene->sdfgi_set_debug_probe_select(p_position, p_dir); +} + +void RenderingServerDefault::set_print_gpu_profile(bool p_enable) { + RSG::storage->capturing_timestamps = p_enable; + print_gpu_profile = p_enable; +} + +RID RenderingServerDefault::get_test_cube() { + if (!test_cube.is_valid()) { + test_cube = _make_test_cube(); + } + return test_cube; +} + +bool RenderingServerDefault::has_os_feature(const String &p_feature) const { + return RSG::storage->has_os_feature(p_feature); +} + +void RenderingServerDefault::set_debug_generate_wireframes(bool p_generate) { + RSG::storage->set_debug_generate_wireframes(p_generate); +} + +bool RenderingServerDefault::is_low_end() const { + // FIXME: Commented out when rebasing vulkan branch on master, + // causes a crash, it seems rasterizer is not initialized yet the + // first time it's called. + //return RSG::rasterizer->is_low_end(); + return false; +} + +void RenderingServerDefault::_thread_exit() { + exit.set(); +} + +void RenderingServerDefault::_thread_draw(bool p_swap_buffers, double frame_step) { + if (!draw_pending.decrement()) { + _draw(p_swap_buffers, frame_step); + } +} + +void RenderingServerDefault::_thread_flush() { + draw_pending.decrement(); +} + +void RenderingServerDefault::_thread_callback(void *_instance) { + RenderingServerDefault *vsmt = reinterpret_cast<RenderingServerDefault *>(_instance); + + vsmt->_thread_loop(); +} + +void RenderingServerDefault::_thread_loop() { + server_thread = Thread::get_caller_id(); + + DisplayServer::get_singleton()->make_rendering_thread(); + + _init(); + + draw_thread_up.set(); + while (!exit.is_set()) { + // flush commands one by one, until exit is requested + command_queue.wait_and_flush_one(); + } + + command_queue.flush_all(); // flush all + + _finish(); +} + +/* EVENT QUEUING */ + +void RenderingServerDefault::sync() { + if (create_thread) { + draw_pending.increment(); + command_queue.push_and_sync(this, &RenderingServerDefault::_thread_flush); + } else { + command_queue.flush_all(); //flush all pending from other threads + } +} + +void RenderingServerDefault::draw(bool p_swap_buffers, double frame_step) { + if (create_thread) { + draw_pending.increment(); + command_queue.push(this, &RenderingServerDefault::_thread_draw, p_swap_buffers, frame_step); + } else { + _draw(p_swap_buffers, frame_step); + } +} + +RenderingServerDefault::RenderingServerDefault(bool p_create_thread) : + command_queue(p_create_thread) { + create_thread = p_create_thread; + + if (!p_create_thread) { + server_thread = Thread::get_caller_id(); + } else { + server_thread = 0; + } + + RSG::canvas = memnew(RendererCanvasCull); + RSG::viewport = memnew(RendererViewport); + RendererSceneCull *sr = memnew(RendererSceneCull); + RSG::scene = sr; + RSG::rasterizer = RendererCompositor::create(); + RSG::storage = RSG::rasterizer->get_storage(); + RSG::canvas_render = RSG::rasterizer->get_canvas(); + sr->set_scene_render(RSG::rasterizer->get_scene()); + + frame_profile_frame = 0; + + for (int i = 0; i < 4; i++) { + black_margin[i] = 0; + black_image[i] = RID(); + } +} + +RenderingServerDefault::~RenderingServerDefault() { + memdelete(RSG::canvas); + memdelete(RSG::viewport); + memdelete(RSG::rasterizer); + memdelete(RSG::scene); +} diff --git a/servers/rendering/rendering_server_wrap_mt.h b/servers/rendering/rendering_server_default.h index d33bdb043a..73b463f6e7 100644 --- a/servers/rendering/rendering_server_wrap_mt.h +++ b/servers/rendering/rendering_server_default.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rendering_server_wrap_mt.h */ +/* rendering_server_default.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,41 +28,105 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef RENDERING_SERVER_WRAP_MT_H -#define RENDERING_SERVER_WRAP_MT_H +#ifndef RENDERING_SERVER_DEFAULT_H +#define RENDERING_SERVER_DEFAULT_H -#include "core/os/thread.h" +#include "core/math/octree.h" #include "core/templates/command_queue_mt.h" +#include "core/templates/ordered_hash_map.h" +#include "renderer_canvas_cull.h" +#include "renderer_scene_cull.h" +#include "renderer_viewport.h" +#include "rendering_server_globals.h" +#include "servers/rendering/renderer_compositor.h" #include "servers/rendering_server.h" +#include "servers/server_wrap_mt_common.h" + +class RenderingServerDefault : public RenderingServer { + enum { + MAX_INSTANCE_CULL = 8192, + MAX_INSTANCE_LIGHTS = 4, + LIGHT_CACHE_DIRTY = -1, + MAX_LIGHTS_CULLED = 256, + MAX_ROOM_CULL = 32, + MAX_EXTERIOR_PORTALS = 128, + MAX_LIGHT_SAMPLERS = 256, + INSTANCE_ROOMLESS_MASK = (1 << 20) + + }; + + static int changes; + RID test_cube; + + int black_margin[4]; + RID black_image[4]; + + struct FrameDrawnCallbacks { + ObjectID object; + StringName method; + Variant param; + }; + + List<FrameDrawnCallbacks> frame_drawn_callbacks; -class RenderingServerWrapMT : public RenderingServer { - // the real visual server - mutable RenderingServer *rendering_server; + void _draw_margins(); + static void _changes_changed() {} + + uint64_t frame_profile_frame; + Vector<FrameProfileArea> frame_profile; + + float frame_setup_time = 0; + + //for printing + bool print_gpu_profile = false; + OrderedHashMap<String, float> print_gpu_profile_task_time; + uint64_t print_frame_profile_ticks_from = 0; + uint32_t print_frame_profile_frame_count = 0; mutable CommandQueueMT command_queue; static void _thread_callback(void *_instance); - void thread_loop(); + void _thread_loop(); Thread::ID server_thread; - volatile bool exit; - Thread *thread; - volatile bool draw_thread_up; + SafeFlag exit; + Thread thread; + SafeFlag draw_thread_up; bool create_thread; - uint64_t draw_pending; - void thread_draw(bool p_swap_buffers, double frame_step); - void thread_flush(); + SafeNumeric<uint64_t> draw_pending; + void _thread_draw(bool p_swap_buffers, double frame_step); + void _thread_flush(); - void thread_exit(); + void _thread_exit(); Mutex alloc_mutex; - int pool_max_size; + void _draw(bool p_swap_buffers, double frame_step); + void _init(); + void _finish(); + + void _free(RID p_rid); + +public: + //if editor is redrawing when it shouldn't, enable this and put a breakpoint in _changes_changed() + //#define DEBUG_CHANGES + +#ifdef DEBUG_CHANGES + _FORCE_INLINE_ static void redraw_request() { + changes++; + _changes_changed(); + } + +#define DISPLAY_CHANGED \ + changes++; \ + _changes_changed(); - //#define DEBUG_SYNC +#else + _FORCE_INLINE_ static void redraw_request() { changes++; } +#endif - static RenderingServerWrapMT *singleton_mt; +#define WRITE_ACTION redraw_request(); #ifdef DEBUG_SYNC #define SYNC_DEBUG print_line("sync on: " + String(__FUNCTION__)); @@ -70,29 +134,75 @@ class RenderingServerWrapMT : public RenderingServer { #define SYNC_DEBUG #endif -public: -#define ServerName RenderingServer -#define ServerNameWrapMT RenderingServerWrapMT -#define server_name rendering_server #include "servers/server_wrap_mt_common.h" +//from now on, calls forwarded to this singleton +#define ServerName RendererStorage +#define server_name RSG::storage + + /* TEXTURE API */ + +#define FUNCRIDTEX0(m_type) \ + virtual RID m_type##_create() override { \ + RID ret = RSG::storage->texture_allocate(); \ + if (Thread::get_caller_id() == server_thread || RSG::storage->can_create_resources_async()) { \ + RSG::storage->m_type##_initialize(ret); \ + } else { \ + command_queue.push(RSG::storage, &RendererStorage::m_type##_initialize, ret); \ + } \ + return ret; \ + } + +#define FUNCRIDTEX1(m_type, m_type1) \ + virtual RID m_type##_create(m_type1 p1) override { \ + RID ret = RSG::storage->texture_allocate(); \ + if (Thread::get_caller_id() == server_thread || RSG::storage->can_create_resources_async()) { \ + RSG::storage->m_type##_initialize(ret, p1); \ + } else { \ + command_queue.push(RSG::storage, &RendererStorage::m_type##_initialize, ret, p1); \ + } \ + return ret; \ + } + +#define FUNCRIDTEX2(m_type, m_type1, m_type2) \ + virtual RID m_type##_create(m_type1 p1, m_type2 p2) override { \ + RID ret = RSG::storage->texture_allocate(); \ + if (Thread::get_caller_id() == server_thread || RSG::storage->can_create_resources_async()) { \ + RSG::storage->m_type##_initialize(ret, p1, p2); \ + } else { \ + command_queue.push(RSG::storage, &RendererStorage::m_type##_initialize, ret, p1, p2); \ + } \ + return ret; \ + } + +#define FUNCRIDTEX6(m_type, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6) \ + virtual RID m_type##_create(m_type1 p1, m_type2 p2, m_type3 p3, m_type4 p4, m_type5 p5, m_type6 p6) override { \ + RID ret = RSG::storage->texture_allocate(); \ + if (Thread::get_caller_id() == server_thread || RSG::storage->can_create_resources_async()) { \ + RSG::storage->m_type##_initialize(ret, p1, p2, p3, p4, p5, p6); \ + } else { \ + command_queue.push(RSG::storage, &RendererStorage::m_type##_initialize, ret, p1, p2, p3, p4, p5, p6); \ + } \ + return ret; \ + } + //these go pass-through, as they can be called from any thread - virtual RID texture_2d_create(const Ref<Image> &p_image) { return rendering_server->texture_2d_create(p_image); } - virtual RID texture_2d_layered_create(const Vector<Ref<Image>> &p_layers, TextureLayeredType p_layered_type) { return rendering_server->texture_2d_layered_create(p_layers, p_layered_type); } - virtual RID texture_3d_create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) { return rendering_server->texture_3d_create(p_format, p_width, p_height, p_depth, p_mipmaps, p_data); } - virtual RID texture_proxy_create(RID p_base) { return rendering_server->texture_proxy_create(p_base); } + FUNCRIDTEX1(texture_2d, const Ref<Image> &) + FUNCRIDTEX2(texture_2d_layered, const Vector<Ref<Image>> &, TextureLayeredType) + FUNCRIDTEX6(texture_3d, Image::Format, int, int, int, bool, const Vector<Ref<Image>> &) + FUNCRIDTEX1(texture_proxy, RID) //goes pass-through - virtual void texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) { rendering_server->texture_2d_update_immediate(p_texture, p_image, p_layer); } + FUNC3(texture_2d_update_immediate, RID, const Ref<Image> &, int) //these go through command queue if they are in another thread FUNC3(texture_2d_update, RID, const Ref<Image> &, int) FUNC2(texture_3d_update, RID, const Vector<Ref<Image>> &) FUNC2(texture_proxy_update, RID, RID) //these also go pass-through - virtual RID texture_2d_placeholder_create() { return rendering_server->texture_2d_placeholder_create(); } - virtual RID texture_2d_layered_placeholder_create(TextureLayeredType p_type) { return rendering_server->texture_2d_layered_placeholder_create(p_type); } - virtual RID texture_3d_placeholder_create() { return rendering_server->texture_3d_placeholder_create(); } + FUNCRIDTEX0(texture_2d_placeholder) + FUNCRIDTEX1(texture_2d_layered_placeholder, TextureLayeredType) + FUNCRIDTEX0(texture_3d_placeholder) FUNC1RC(Ref<Image>, texture_2d_get, RID) FUNC2RC(Ref<Image>, texture_2d_layer_get, RID, int) @@ -112,26 +222,28 @@ public: FUNC2(texture_set_path, RID, const String &) FUNC1RC(String, texture_get_path, RID) - FUNC1S(texture_debug_usage, List<TextureInfo> *) + FUNC1(texture_debug_usage, List<TextureInfo> *) FUNC2(texture_set_force_redraw_if_visible, RID, bool) /* SHADER API */ - FUNCRID(shader) + FUNCRIDSPLIT(shader) FUNC2(shader_set_code, RID, const String &) FUNC1RC(String, shader_get_code, RID) - FUNC2SC(shader_get_param_list, RID, List<PropertyInfo> *) + FUNC2C(shader_get_param_list, RID, List<PropertyInfo> *) FUNC3(shader_set_default_texture_param, RID, const StringName &, RID) FUNC2RC(RID, shader_get_default_texture_param, RID, const StringName &) FUNC2RC(Variant, shader_get_param_default, RID, const StringName &) + FUNC1RC(ShaderNativeSourceCode, shader_get_native_source_code, RID) + /* COMMON MATERIAL API */ - FUNCRID(material) + FUNCRIDSPLIT(material) FUNC2(material_set_shader, RID, RID) @@ -143,11 +255,33 @@ public: /* MESH API */ - virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces) { - return rendering_server->mesh_create_from_surfaces(p_surfaces); + virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces, int p_blend_shape_count = 0) override { + RID mesh = RSG::storage->mesh_allocate(); + + if (Thread::get_caller_id() == server_thread || RSG::storage->can_create_resources_async()) { + if (Thread::get_caller_id() == server_thread) { + command_queue.flush_if_pending(); + } + RSG::storage->mesh_initialize(mesh); + RSG::storage->mesh_set_blend_shape_count(mesh, p_blend_shape_count); + for (int i = 0; i < p_surfaces.size(); i++) { + RSG::storage->mesh_add_surface(mesh, p_surfaces[i]); + } + } else { + command_queue.push(RSG::storage, &RendererStorage::mesh_initialize, mesh); + command_queue.push(RSG::storage, &RendererStorage::mesh_set_blend_shape_count, mesh, p_blend_shape_count); + for (int i = 0; i < p_surfaces.size(); i++) { + RSG::storage->mesh_add_surface(mesh, p_surfaces[i]); + command_queue.push(RSG::storage, &RendererStorage::mesh_add_surface, mesh, p_surfaces[i]); + } + } + + return mesh; } - FUNCRID(mesh) + FUNC2(mesh_set_blend_shape_count, RID, int) + + FUNCRIDSPLIT(mesh) FUNC2(mesh_add_surface, RID, const SurfaceData &) @@ -168,13 +302,15 @@ public: FUNC2(mesh_set_custom_aabb, RID, const AABB &) FUNC1RC(AABB, mesh_get_custom_aabb, RID) + FUNC2(mesh_set_shadow_mesh, RID, RID) + FUNC1(mesh_clear, RID) /* MULTIMESH API */ - FUNCRID(multimesh) + FUNCRIDSPLIT(multimesh) - FUNC5(multimesh_allocate, RID, int, MultimeshTransformFormat, bool, bool) + FUNC5(multimesh_allocate_data, RID, int, MultimeshTransformFormat, bool, bool) FUNC1RC(int, multimesh_get_instance_count, RID) FUNC2(multimesh_set_mesh, RID, RID) @@ -199,7 +335,7 @@ public: /* IMMEDIATE API */ - FUNCRID(immediate) + FUNCRIDSPLIT(immediate) FUNC3(immediate_begin, RID, PrimitiveType, RID) FUNC2(immediate_vertex, RID, const Vector3 &) FUNC2(immediate_normal, RID, const Vector3 &) @@ -214,8 +350,8 @@ public: /* SKELETON API */ - FUNCRID(skeleton) - FUNC3(skeleton_allocate, RID, int, bool) + FUNCRIDSPLIT(skeleton) + FUNC3(skeleton_allocate_data, RID, int, bool) FUNC1RC(int, skeleton_get_bone_count, RID) FUNC3(skeleton_bone_set_transform, RID, int, const Transform &) FUNC2RC(Transform, skeleton_bone_get_transform, RID, int) @@ -225,9 +361,9 @@ public: /* Light API */ - FUNCRID(directional_light) - FUNCRID(omni_light) - FUNCRID(spot_light) + FUNCRIDSPLIT(directional_light) + FUNCRIDSPLIT(omni_light) + FUNCRIDSPLIT(spot_light) FUNC2(light_set_color, RID, const Color &) FUNC3(light_set_param, RID, LightParam, float) @@ -244,11 +380,12 @@ public: FUNC2(light_directional_set_shadow_mode, RID, LightDirectionalShadowMode) FUNC2(light_directional_set_blend_splits, RID, bool) + FUNC2(light_directional_set_sky_only, RID, bool) FUNC2(light_directional_set_shadow_depth_range_mode, RID, LightDirectionalShadowDepthRangeMode) /* PROBE API */ - FUNCRID(reflection_probe) + FUNCRIDSPLIT(reflection_probe) FUNC2(reflection_probe_set_update_mode, RID, ReflectionProbeUpdateMode) FUNC2(reflection_probe_set_intensity, RID, float) @@ -263,10 +400,11 @@ public: FUNC2(reflection_probe_set_enable_shadows, RID, bool) FUNC2(reflection_probe_set_cull_mask, RID, uint32_t) FUNC2(reflection_probe_set_resolution, RID, int) + FUNC2(reflection_probe_set_lod_threshold, RID, float) /* DECAL API */ - FUNCRID(decal) + FUNCRIDSPLIT(decal) FUNC2(decal_set_extents, RID, const Vector3 &) FUNC3(decal_set_texture, RID, DecalTexture, RID) @@ -280,9 +418,9 @@ public: /* BAKED LIGHT API */ - FUNCRID(gi_probe) + FUNCRIDSPLIT(gi_probe) - FUNC8(gi_probe_allocate, RID, const Transform &, const AABB &, const Vector3i &, const Vector<uint8_t> &, const Vector<uint8_t> &, const Vector<uint8_t> &, const Vector<int> &) + FUNC8(gi_probe_allocate_data, RID, const Transform &, const AABB &, const Vector3i &, const Vector<uint8_t> &, const Vector<uint8_t> &, const Vector<uint8_t> &, const Vector<int> &) FUNC1RC(AABB, gi_probe_get_bounds, RID) FUNC1RC(Vector3i, gi_probe_get_octree_size, RID) @@ -322,11 +460,10 @@ public: FUNC2(gi_probe_set_anisotropy_strength, RID, float) FUNC1RC(float, gi_probe_get_anisotropy_strength, RID) - FUNC1(gi_probe_set_quality, GIProbeQuality) + /* LIGHTMAP */ - /* LIGHTMAP CAPTURE */ + FUNCRIDSPLIT(lightmap) - FUNCRID(lightmap) FUNC3(lightmap_set_textures, RID, RID, bool) FUNC2(lightmap_set_probe_bounds, RID, const AABB &) FUNC2(lightmap_set_probe_interior, RID, bool) @@ -335,12 +472,11 @@ public: FUNC1RC(PackedColorArray, lightmap_get_probe_capture_sh, RID) FUNC1RC(PackedInt32Array, lightmap_get_probe_capture_tetrahedra, RID) FUNC1RC(PackedInt32Array, lightmap_get_probe_capture_bsp_tree, RID) - FUNC1(lightmap_set_probe_capture_update_speed, float) /* PARTICLES */ - FUNCRID(particles) + FUNCRIDSPLIT(particles) FUNC2(particles_set_emitting, RID, bool) FUNC1R(bool, particles_get_emitting, RID) @@ -356,26 +492,24 @@ public: FUNC2(particles_set_process_material, RID, RID) FUNC2(particles_set_fixed_fps, RID, int) FUNC2(particles_set_fractional_delta, RID, bool) - FUNC2(particles_set_collision_base_size, RID, float) - FUNC1R(bool, particles_is_inactive, RID) FUNC1(particles_request_process, RID) FUNC1(particles_restart, RID) - FUNC6(particles_emit, RID, const Transform &, const Vector3 &, const Color &, const Color &, uint32_t) + FUNC2(particles_set_subemitter, RID, RID) + FUNC2(particles_set_collision_base_size, RID, float) FUNC2(particles_set_draw_order, RID, RS::ParticlesDrawOrder) FUNC2(particles_set_draw_passes, RID, int) FUNC3(particles_set_draw_pass_mesh, RID, int, RID) - FUNC2(particles_set_emission_transform, RID, const Transform &) - FUNC2(particles_set_subemitter, RID, RID) FUNC1R(AABB, particles_get_current_aabb, RID) + FUNC2(particles_set_emission_transform, RID, const Transform &) /* PARTICLES COLLISION */ - FUNCRID(particles_collision) + FUNCRIDSPLIT(particles_collision) FUNC2(particles_collision_set_collision_type, RID, ParticlesCollisionType) FUNC2(particles_collision_set_cull_mask, RID, uint32_t) @@ -388,9 +522,15 @@ public: FUNC1(particles_collision_height_field_update, RID) FUNC2(particles_collision_set_height_field_resolution, RID, ParticlesCollisionHeightfieldResolution) +#undef server_name +#undef ServerName +//from now on, calls forwarded to this singleton +#define ServerName RendererScene +#define server_name RSG::scene + /* CAMERA API */ - FUNCRID(camera) + FUNCRIDSPLIT(camera) FUNC4(camera_set_perspective, RID, float, float, float) FUNC4(camera_set_orthogonal, RID, float, float, float) FUNC5(camera_set_frustum, RID, float, Vector2, float, float) @@ -400,12 +540,17 @@ public: FUNC2(camera_set_camera_effects, RID, RID) FUNC2(camera_set_use_vertical_aspect, RID, bool) +#undef server_name +#undef ServerName +//from now on, calls forwarded to this singleton +#define ServerName RendererViewport +#define server_name RSG::viewport + /* VIEWPORT TARGET API */ - FUNCRID(viewport) + FUNCRIDSPLIT(viewport) FUNC2(viewport_set_use_xr, RID, bool) - FUNC3(viewport_set_size, RID, int, int) FUNC2(viewport_set_active, RID, bool) @@ -413,7 +558,7 @@ public: FUNC2(viewport_set_clear_mode, RID, ViewportClearMode) - FUNC3(viewport_attach_to_screen, RID, const Rect2 &, DisplayServer::WindowID) + FUNC3(viewport_attach_to_screen, RID, const Rect2 &, int) FUNC2(viewport_set_render_direct_to_screen, RID, bool) FUNC2(viewport_set_update_mode, RID, ViewportUpdateMode) @@ -439,42 +584,43 @@ public: FUNC2(viewport_set_global_canvas_transform, RID, const Transform2D &) FUNC4(viewport_set_canvas_stacking, RID, RID, int, int) - FUNC2(viewport_set_shadow_atlas_size, RID, int) + FUNC3(viewport_set_shadow_atlas_size, RID, int, bool) FUNC3(viewport_set_sdf_oversize_and_scale, RID, ViewportSDFOversize, ViewportSDFScale) - FUNC3(viewport_set_shadow_atlas_quadrant_subdivision, RID, int, int) FUNC2(viewport_set_msaa, RID, ViewportMSAA) FUNC2(viewport_set_screen_space_aa, RID, ViewportScreenSpaceAA) FUNC2(viewport_set_use_debanding, RID, bool) + FUNC2(viewport_set_lod_threshold, RID, float) - //this passes directly to avoid stalling, but it's pretty dangerous, so don't call after freeing a viewport - virtual int viewport_get_render_info(RID p_viewport, ViewportRenderInfo p_info) { - return rendering_server->viewport_get_render_info(p_viewport, p_info); - } - + FUNC2R(int, viewport_get_render_info, RID, ViewportRenderInfo) FUNC2(viewport_set_debug_draw, RID, ViewportDebugDraw) FUNC2(viewport_set_measure_render_time, RID, bool) - virtual float viewport_get_measured_render_time_cpu(RID p_viewport) const { - return rendering_server->viewport_get_measured_render_time_cpu(p_viewport); - } - virtual float viewport_get_measured_render_time_gpu(RID p_viewport) const { - return rendering_server->viewport_get_measured_render_time_gpu(p_viewport); - } + FUNC1RC(float, viewport_get_measured_render_time_cpu, RID) + FUNC1RC(float, viewport_get_measured_render_time_gpu, RID) - FUNC1(directional_shadow_atlas_set_size, int) + FUNC1(call_set_use_vsync, bool) + + /* ENVIRONMENT API */ + +#undef server_name +#undef ServerName +//from now on, calls forwarded to this singleton +#define ServerName RendererScene +#define server_name RSG::scene + + FUNC2(directional_shadow_atlas_set_size, int, bool) + FUNC1(gi_probe_set_quality, GIProbeQuality) /* SKY API */ - FUNCRID(sky) + FUNCRIDSPLIT(sky) FUNC2(sky_set_radiance_size, RID, int) FUNC2(sky_set_mode, RID, SkyMode) FUNC2(sky_set_material, RID, RID) FUNC4R(Ref<Image>, sky_bake_panorama, RID, float, bool, const Size2i &) - /* ENVIRONMENT API */ - - FUNCRID(environment) + FUNCRIDSPLIT(environment) FUNC2(environment_set_background, RID, EnvironmentBG) FUNC2(environment_set_sky, RID, RID) @@ -492,13 +638,8 @@ public: FUNC6(environment_set_ssr, RID, bool, int, float, float, float) FUNC1(environment_set_ssr_roughness_quality, EnvironmentSSRRoughnessQuality) - FUNC9(environment_set_ssao, RID, bool, float, float, float, float, float, EnvironmentSSAOBlur, float) - - FUNC2(environment_set_ssao_quality, EnvironmentSSAOQuality, bool) - - FUNC11(environment_set_sdfgi, RID, bool, EnvironmentSDFGICascades, float, EnvironmentSDFGIYScale, bool, bool, bool, float, float, float) - FUNC1(environment_set_sdfgi_ray_count, EnvironmentSDFGIRayCount) - FUNC1(environment_set_sdfgi_frames_to_converge, EnvironmentSDFGIFramesToConverge) + FUNC10(environment_set_ssao, RID, bool, float, float, float, float, float, float, float, float) + FUNC6(environment_set_ssao_quality, EnvironmentSSAOQuality, bool, float, int, float, float) FUNC11(environment_set_glow, RID, bool, Vector<float>, float, float, float, float, EnvironmentGlowBlendMode, float, float, float) FUNC1(environment_glow_set_use_bicubic_upscale, bool) @@ -506,16 +647,18 @@ public: FUNC9(environment_set_tonemap, RID, EnvironmentToneMapper, float, float, bool, float, float, float, float) - FUNC6(environment_set_adjustment, RID, bool, float, float, float, RID) + FUNC7(environment_set_adjustment, RID, bool, float, float, float, bool, RID) FUNC9(environment_set_fog, RID, bool, const Color &, float, float, float, float, float, float) - - FUNC9(environment_set_volumetric_fog, RID, bool, float, const Color &, float, float, float, float, EnvVolumetricFogShadowFilter) + FUNC10(environment_set_volumetric_fog, RID, bool, float, const Color &, float, float, float, float, bool, float) FUNC2(environment_set_volumetric_fog_volume_size, int, int) FUNC1(environment_set_volumetric_fog_filter_active, bool) - FUNC1(environment_set_volumetric_fog_directional_shadow_shrink_size, int) - FUNC1(environment_set_volumetric_fog_positional_shadow_shrink_size, int) + + FUNC11(environment_set_sdfgi, RID, bool, EnvironmentSDFGICascades, float, EnvironmentSDFGIYScale, bool, float, bool, float, float, float) + FUNC1(environment_set_sdfgi_ray_count, EnvironmentSDFGIRayCount) + FUNC1(environment_set_sdfgi_frames_to_converge, EnvironmentSDFGIFramesToConverge) + FUNC1(environment_set_sdfgi_frames_to_update_light, EnvironmentSDFGIFramesToUpdateLight) FUNC3R(Ref<Image>, environment_bake_panorama, RID, bool, const Size2i &) @@ -523,7 +666,9 @@ public: FUNC1(sub_surface_scattering_set_quality, SubSurfaceScatteringQuality) FUNC2(sub_surface_scattering_set_scale, float, float) - FUNCRID(camera_effects) + /* CAMERA EFFECTS */ + + FUNCRIDSPLIT(camera_effects) FUNC2(camera_effects_set_dof_blur_quality, DOFBlurQuality, bool) FUNC1(camera_effects_set_dof_blur_bokeh_shape, DOFBokehShape) @@ -534,7 +679,15 @@ public: FUNC1(shadows_quality_set, ShadowQuality); FUNC1(directional_shadow_quality_set, ShadowQuality); - FUNCRID(scenario) + /* SCENARIO API */ + +#undef server_name +#undef ServerName + +#define ServerName RendererScene +#define server_name RSG::scene + + FUNCRIDSPLIT(scenario) FUNC2(scenario_set_debug, RID, ScenarioDebugMode) FUNC2(scenario_set_environment, RID, RID) @@ -542,7 +695,7 @@ public: FUNC2(scenario_set_fallback_environment, RID, RID) /* INSTANCING API */ - FUNCRID(instance) + FUNCRIDSPLIT(instance) FUNC2(instance_set_base, RID, RID) FUNC2(instance_set_scenario, RID, RID) @@ -572,32 +725,39 @@ public: FUNC5(instance_geometry_set_draw_range, RID, float, float, float, float) FUNC2(instance_geometry_set_as_instance_lod, RID, RID) FUNC4(instance_geometry_set_lightmap, RID, RID, const Rect2 &, int) + FUNC2(instance_geometry_set_lod_bias, RID, float) FUNC3(instance_geometry_set_shader_parameter, RID, const StringName &, const Variant &) FUNC2RC(Variant, instance_geometry_get_shader_parameter, RID, const StringName &) FUNC2RC(Variant, instance_geometry_get_shader_parameter_default_value, RID, const StringName &) - FUNC2SC(instance_geometry_get_shader_parameter_list, RID, List<PropertyInfo> *) - - /* BAKE */ + FUNC2C(instance_geometry_get_shader_parameter_list, RID, List<PropertyInfo> *) FUNC3R(TypedArray<Image>, bake_render_uv2, RID, const Vector<RID> &, const Size2i &) + FUNC1(gi_set_use_half_resolution, bool) + +#undef server_name +#undef ServerName +//from now on, calls forwarded to this singleton +#define ServerName RendererCanvasCull +#define server_name RSG::canvas + /* CANVAS (2D) */ - FUNCRID(canvas) + FUNCRIDSPLIT(canvas) FUNC3(canvas_set_item_mirroring, RID, RID, const Point2 &) FUNC2(canvas_set_modulate, RID, const Color &) FUNC3(canvas_set_parent, RID, RID, float) FUNC1(canvas_set_disable_scale, bool) - FUNCRID(canvas_texture) + FUNCRIDSPLIT(canvas_texture) FUNC3(canvas_texture_set_channel, RID, CanvasTextureChannel, RID) FUNC3(canvas_texture_set_shading_parameters, RID, const Color &, float) FUNC2(canvas_texture_set_texture_filter, RID, CanvasItemTextureFilter) FUNC2(canvas_texture_set_texture_repeat, RID, CanvasItemTextureRepeat) - FUNCRID(canvas_item) + FUNCRIDSPLIT(canvas_item) FUNC2(canvas_item_set_parent, RID, RID) FUNC2(canvas_item_set_default_texture_filter, RID, CanvasItemTextureFilter) @@ -618,7 +778,7 @@ public: FUNC2(canvas_item_set_draw_behind_parent, RID, bool) FUNC5(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float) - FUNC4(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float) + FUNC5(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool) FUNC4(canvas_item_add_multiline, RID, const Vector<Point2> &, const Vector<Color> &, float) FUNC3(canvas_item_add_rect, RID, const Rect2 &, const Color &) FUNC4(canvas_item_add_circle, RID, const Point2 &, float, const Color &) @@ -648,7 +808,7 @@ public: FUNC6(canvas_item_set_canvas_group_mode, RID, CanvasGroupMode, float, bool, float, bool) - FUNC0R(RID, canvas_light_create) + FUNCRIDSPLIT(canvas_light) FUNC2(canvas_light_set_mode, RID, CanvasLightMode) @@ -674,7 +834,7 @@ public: FUNC2(canvas_light_set_shadow_color, RID, const Color &) FUNC2(canvas_light_set_shadow_smooth, RID, float) - FUNCRID(canvas_light_occluder) + FUNCRIDSPLIT(canvas_light_occluder) FUNC2(canvas_light_occluder_attach_to_canvas, RID, RID) FUNC2(canvas_light_occluder_set_enabled, RID, bool) FUNC2(canvas_light_occluder_set_polygon, RID, RID) @@ -682,7 +842,7 @@ public: FUNC2(canvas_light_occluder_set_transform, RID, const Transform2D &) FUNC2(canvas_light_occluder_set_light_mask, RID, int) - FUNCRID(canvas_occluder_polygon) + FUNCRIDSPLIT(canvas_occluder_polygon) FUNC3(canvas_occluder_polygon_set_shape, RID, const Vector<Vector2> &, bool) FUNC2(canvas_occluder_polygon_set_cull_mode, RID, CanvasOccluderPolygonCullMode) @@ -691,6 +851,12 @@ public: /* GLOBAL VARIABLES */ +#undef server_name +#undef ServerName +//from now on, calls forwarded to this singleton +#define ServerName RendererStorage +#define server_name RSG::storage + FUNC3(global_variable_add, const StringName &, GlobalVariableType, const Variant &) FUNC1(global_variable_remove, const StringName &) FUNC0RC(Vector<StringName>, global_variable_get_list) @@ -698,92 +864,73 @@ public: FUNC2(global_variable_set_override, const StringName &, const Variant &) FUNC1RC(GlobalVariableType, global_variable_get_type, const StringName &) FUNC1RC(Variant, global_variable_get, const StringName &) + FUNC1(global_variables_load_settings, bool) FUNC0(global_variables_clear) +#undef server_name +#undef ServerName +#undef WRITE_ACTION +#undef SYNC_DEBUG + /* BLACK BARS */ - FUNC4(black_bars_set_margins, int, int, int, int) - FUNC4(black_bars_set_images, RID, RID, RID, RID) + virtual void black_bars_set_margins(int p_left, int p_top, int p_right, int p_bottom) override; + virtual void black_bars_set_images(RID p_left, RID p_top, RID p_right, RID p_bottom) override; /* FREE */ - FUNC1(free, RID) + virtual void free(RID p_rid) override { + if (Thread::get_caller_id() == server_thread) { + command_queue.flush_if_pending(); + _free(p_rid); + } else { + command_queue.push(this, &RenderingServerDefault::_free, p_rid); + } + } /* EVENT QUEUING */ - FUNC3(request_frame_drawn_callback, Object *, const StringName &, const Variant &) + virtual void request_frame_drawn_callback(Object *p_where, const StringName &p_method, const Variant &p_userdata) override; - virtual void init(); - virtual void finish(); - virtual void draw(bool p_swap_buffers, double frame_step); - virtual void sync(); - FUNC0RC(bool, has_changed) + virtual void draw(bool p_swap_buffers, double frame_step) override; + virtual void sync() override; + virtual bool has_changed() const override; + virtual void init() override; + virtual void finish() override; - /* RENDER INFO */ + /* STATUS INFORMATION */ - //this passes directly to avoid stalling - virtual int get_render_info(RenderInfo p_info) { - return rendering_server->get_render_info(p_info); - } + virtual int get_render_info(RenderInfo p_info) override; + virtual String get_video_adapter_name() const override; + virtual String get_video_adapter_vendor() const override; - virtual String get_video_adapter_name() const { - return rendering_server->get_video_adapter_name(); - } + virtual void set_frame_profiling_enabled(bool p_enable) override; + virtual Vector<FrameProfileArea> get_frame_profile() override; + virtual uint64_t get_frame_profile_frame() override; - virtual String get_video_adapter_vendor() const { - return rendering_server->get_video_adapter_vendor(); - } + virtual RID get_test_cube() override; - FUNC4(set_boot_image, const Ref<Image> &, const Color &, bool, bool) - FUNC1(set_default_clear_color, const Color &) + /* TESTING */ - FUNC0R(RID, get_test_cube) + virtual float get_frame_setup_time_cpu() const override; - FUNC1(set_debug_generate_wireframes, bool) + virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true) override; + virtual void set_default_clear_color(const Color &p_color) override; - virtual bool has_feature(Features p_feature) const { - return rendering_server->has_feature(p_feature); - } - virtual bool has_os_feature(const String &p_feature) const { - return rendering_server->has_os_feature(p_feature); - } + virtual bool has_feature(Features p_feature) const override; - FUNC1(call_set_use_vsync, bool) + virtual bool has_os_feature(const String &p_feature) const override; + virtual void set_debug_generate_wireframes(bool p_generate) override; - static void set_use_vsync_callback(bool p_enable); + virtual bool is_low_end() const override; - virtual bool is_low_end() const { - return rendering_server->is_low_end(); - } + virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) override; - virtual uint64_t get_frame_profile_frame() { - return rendering_server->get_frame_profile_frame(); - } + virtual void set_print_gpu_profile(bool p_enable) override; - virtual void set_frame_profiling_enabled(bool p_enabled) { - rendering_server->set_frame_profiling_enabled(p_enabled); - } - - virtual Vector<FrameProfileArea> get_frame_profile() { - return rendering_server->get_frame_profile(); - } - - virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) { - rendering_server->sdfgi_set_debug_probe_select(p_position, p_dir); - } - - RenderingServerWrapMT(RenderingServer *p_contained, bool p_create_thread); - ~RenderingServerWrapMT(); - -#undef ServerName -#undef ServerNameWrapMT -#undef server_name + RenderingServerDefault(bool p_create_thread = false); + ~RenderingServerDefault(); }; -#ifdef DEBUG_SYNC -#undef DEBUG_SYNC -#endif -#undef SYNC_DEBUG - #endif diff --git a/servers/rendering/rendering_server_globals.cpp b/servers/rendering/rendering_server_globals.cpp index 5a270520a9..c0d9988e85 100644 --- a/servers/rendering/rendering_server_globals.cpp +++ b/servers/rendering/rendering_server_globals.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,11 +30,10 @@ #include "rendering_server_globals.h" -RasterizerStorage *RenderingServerGlobals::storage = nullptr; -RasterizerCanvas *RenderingServerGlobals::canvas_render = nullptr; -RasterizerScene *RenderingServerGlobals::scene_render = nullptr; -Rasterizer *RenderingServerGlobals::rasterizer = nullptr; +RendererStorage *RenderingServerGlobals::storage = nullptr; +RendererCanvasRender *RenderingServerGlobals::canvas_render = nullptr; +RendererCompositor *RenderingServerGlobals::rasterizer = nullptr; -RenderingServerCanvas *RenderingServerGlobals::canvas = nullptr; -RenderingServerViewport *RenderingServerGlobals::viewport = nullptr; -RenderingServerScene *RenderingServerGlobals::scene = nullptr; +RendererCanvasCull *RenderingServerGlobals::canvas = nullptr; +RendererViewport *RenderingServerGlobals::viewport = nullptr; +RendererScene *RenderingServerGlobals::scene = nullptr; diff --git a/servers/rendering/rendering_server_globals.h b/servers/rendering/rendering_server_globals.h index b33f328b69..a28a0f5180 100644 --- a/servers/rendering/rendering_server_globals.h +++ b/servers/rendering/rendering_server_globals.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,22 +31,23 @@ #ifndef RENDERING_SERVER_GLOBALS_H #define RENDERING_SERVER_GLOBALS_H -#include "rasterizer.h" +#include "servers/rendering/renderer_canvas_cull.h" +#include "servers/rendering/renderer_canvas_render.h" +#include "servers/rendering/renderer_scene.h" -class RenderingServerCanvas; -class RenderingServerViewport; -class RenderingServerScene; +class RendererCanvasCull; +class RendererViewport; +class RendererScene; class RenderingServerGlobals { public: - static RasterizerStorage *storage; - static RasterizerCanvas *canvas_render; - static RasterizerScene *scene_render; - static Rasterizer *rasterizer; + static RendererStorage *storage; + static RendererCanvasRender *canvas_render; + static RendererCompositor *rasterizer; - static RenderingServerCanvas *canvas; - static RenderingServerViewport *viewport; - static RenderingServerScene *scene; + static RendererCanvasCull *canvas; + static RendererViewport *viewport; + static RendererScene *scene; }; #define RSG RenderingServerGlobals diff --git a/servers/rendering/rendering_server_raster.cpp b/servers/rendering/rendering_server_raster.cpp deleted file mode 100644 index 94cfb6b752..0000000000 --- a/servers/rendering/rendering_server_raster.cpp +++ /dev/null @@ -1,281 +0,0 @@ -/*************************************************************************/ -/* rendering_server_raster.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "rendering_server_raster.h" - -#include "core/config/project_settings.h" -#include "core/io/marshalls.h" -#include "core/os/os.h" -#include "core/templates/sort_array.h" -#include "rendering_server_canvas.h" -#include "rendering_server_globals.h" -#include "rendering_server_scene.h" - -// careful, these may run in different threads than the visual server - -int RenderingServerRaster::changes = 0; - -/* BLACK BARS */ - -void RenderingServerRaster::black_bars_set_margins(int p_left, int p_top, int p_right, int p_bottom) { - black_margin[MARGIN_LEFT] = p_left; - black_margin[MARGIN_TOP] = p_top; - black_margin[MARGIN_RIGHT] = p_right; - black_margin[MARGIN_BOTTOM] = p_bottom; -} - -void RenderingServerRaster::black_bars_set_images(RID p_left, RID p_top, RID p_right, RID p_bottom) { - black_image[MARGIN_LEFT] = p_left; - black_image[MARGIN_TOP] = p_top; - black_image[MARGIN_RIGHT] = p_right; - black_image[MARGIN_BOTTOM] = p_bottom; -} - -void RenderingServerRaster::_draw_margins() { - RSG::canvas_render->draw_window_margins(black_margin, black_image); -}; - -/* FREE */ - -void RenderingServerRaster::free(RID p_rid) { - if (RSG::storage->free(p_rid)) { - return; - } - if (RSG::canvas->free(p_rid)) { - return; - } - if (RSG::viewport->free(p_rid)) { - return; - } - if (RSG::scene->free(p_rid)) { - return; - } - if (RSG::scene_render->free(p_rid)) { - return; - } -} - -/* EVENT QUEUING */ - -void RenderingServerRaster::request_frame_drawn_callback(Object *p_where, const StringName &p_method, const Variant &p_userdata) { - ERR_FAIL_NULL(p_where); - FrameDrawnCallbacks fdc; - fdc.object = p_where->get_instance_id(); - fdc.method = p_method; - fdc.param = p_userdata; - - frame_drawn_callbacks.push_back(fdc); -} - -void RenderingServerRaster::draw(bool p_swap_buffers, double frame_step) { - //needs to be done before changes is reset to 0, to not force the editor to redraw - RS::get_singleton()->emit_signal("frame_pre_draw"); - - changes = 0; - - RSG::rasterizer->begin_frame(frame_step); - - TIMESTAMP_BEGIN() - - RSG::scene_render->update(); //update scenes stuff before updating instances - - RSG::scene->update_dirty_instances(); //update scene stuff - - RSG::scene->render_particle_colliders(); - RSG::storage->update_particles(); //need to be done after instances are updated (colliders and particle transforms), and colliders are rendered - - RSG::scene->render_probes(); - RSG::viewport->draw_viewports(); - RSG::canvas_render->update(); - - _draw_margins(); - RSG::rasterizer->end_frame(p_swap_buffers); - - while (frame_drawn_callbacks.front()) { - Object *obj = ObjectDB::get_instance(frame_drawn_callbacks.front()->get().object); - if (obj) { - Callable::CallError ce; - const Variant *v = &frame_drawn_callbacks.front()->get().param; - obj->call(frame_drawn_callbacks.front()->get().method, &v, 1, ce); - if (ce.error != Callable::CallError::CALL_OK) { - String err = Variant::get_call_error_text(obj, frame_drawn_callbacks.front()->get().method, &v, 1, ce); - ERR_PRINT("Error calling frame drawn function: " + err); - } - } - - frame_drawn_callbacks.pop_front(); - } - RS::get_singleton()->emit_signal("frame_post_draw"); - - if (RSG::storage->get_captured_timestamps_count()) { - Vector<FrameProfileArea> new_profile; - if (RSG::storage->capturing_timestamps) { - new_profile.resize(RSG::storage->get_captured_timestamps_count()); - } - - uint64_t base_cpu = RSG::storage->get_captured_timestamp_cpu_time(0); - uint64_t base_gpu = RSG::storage->get_captured_timestamp_gpu_time(0); - for (uint32_t i = 0; i < RSG::storage->get_captured_timestamps_count(); i++) { - uint64_t time_cpu = RSG::storage->get_captured_timestamp_cpu_time(i); - uint64_t time_gpu = RSG::storage->get_captured_timestamp_gpu_time(i); - - String name = RSG::storage->get_captured_timestamp_name(i); - - if (name.begins_with("vp_")) { - RSG::viewport->handle_timestamp(name, time_cpu, time_gpu); - } - - if (RSG::storage->capturing_timestamps) { - new_profile.write[i].gpu_msec = float((time_gpu - base_gpu) / 1000) / 1000.0; - new_profile.write[i].cpu_msec = float(time_cpu - base_cpu) / 1000.0; - new_profile.write[i].name = RSG::storage->get_captured_timestamp_name(i); - } - } - - frame_profile = new_profile; - } - - frame_profile_frame = RSG::storage->get_captured_timestamps_frame(); -} - -void RenderingServerRaster::sync() { -} - -bool RenderingServerRaster::has_changed() const { - return changes > 0; -} - -void RenderingServerRaster::init() { - RSG::rasterizer->initialize(); -} - -void RenderingServerRaster::finish() { - if (test_cube.is_valid()) { - free(test_cube); - } - - RSG::rasterizer->finalize(); -} - -/* STATUS INFORMATION */ - -int RenderingServerRaster::get_render_info(RenderInfo p_info) { - return RSG::storage->get_render_info(p_info); -} - -String RenderingServerRaster::get_video_adapter_name() const { - return RSG::storage->get_video_adapter_name(); -} - -String RenderingServerRaster::get_video_adapter_vendor() const { - return RSG::storage->get_video_adapter_vendor(); -} - -void RenderingServerRaster::set_frame_profiling_enabled(bool p_enable) { - RSG::storage->capturing_timestamps = p_enable; -} - -uint64_t RenderingServerRaster::get_frame_profile_frame() { - return frame_profile_frame; -} - -Vector<RenderingServer::FrameProfileArea> RenderingServerRaster::get_frame_profile() { - return frame_profile; -} - -/* TESTING */ - -void RenderingServerRaster::set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter) { - redraw_request(); - RSG::rasterizer->set_boot_image(p_image, p_color, p_scale, p_use_filter); -} - -void RenderingServerRaster::set_default_clear_color(const Color &p_color) { - RSG::viewport->set_default_clear_color(p_color); -} - -bool RenderingServerRaster::has_feature(Features p_feature) const { - return false; -} - -void RenderingServerRaster::sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) { - RSG::scene_render->sdfgi_set_debug_probe_select(p_position, p_dir); -} - -RID RenderingServerRaster::get_test_cube() { - if (!test_cube.is_valid()) { - test_cube = _make_test_cube(); - } - return test_cube; -} - -bool RenderingServerRaster::has_os_feature(const String &p_feature) const { - return RSG::storage->has_os_feature(p_feature); -} - -void RenderingServerRaster::set_debug_generate_wireframes(bool p_generate) { - RSG::storage->set_debug_generate_wireframes(p_generate); -} - -void RenderingServerRaster::call_set_use_vsync(bool p_enable) { - DisplayServer::get_singleton()->_set_use_vsync(p_enable); -} - -bool RenderingServerRaster::is_low_end() const { - // FIXME: Commented out when rebasing vulkan branch on master, - // causes a crash, it seems rasterizer is not initialized yet the - // first time it's called. - //return RSG::rasterizer->is_low_end(); - return false; -} - -RenderingServerRaster::RenderingServerRaster() { - RSG::canvas = memnew(RenderingServerCanvas); - RSG::viewport = memnew(RenderingServerViewport); - RSG::scene = memnew(RenderingServerScene); - RSG::rasterizer = Rasterizer::create(); - RSG::storage = RSG::rasterizer->get_storage(); - RSG::canvas_render = RSG::rasterizer->get_canvas(); - RSG::scene_render = RSG::rasterizer->get_scene(); - - frame_profile_frame = 0; - - for (int i = 0; i < 4; i++) { - black_margin[i] = 0; - black_image[i] = RID(); - } -} - -RenderingServerRaster::~RenderingServerRaster() { - memdelete(RSG::canvas); - memdelete(RSG::viewport); - memdelete(RSG::rasterizer); - memdelete(RSG::scene); -} diff --git a/servers/rendering/rendering_server_raster.h b/servers/rendering/rendering_server_raster.h deleted file mode 100644 index 413fcda581..0000000000 --- a/servers/rendering/rendering_server_raster.h +++ /dev/null @@ -1,878 +0,0 @@ -/*************************************************************************/ -/* rendering_server_raster.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef RENDERING_SERVER_RASTER_H -#define RENDERING_SERVER_RASTER_H - -#include "core/math/octree.h" -#include "rendering_server_canvas.h" -#include "rendering_server_globals.h" -#include "rendering_server_scene.h" -#include "rendering_server_viewport.h" -#include "servers/rendering/rasterizer.h" -#include "servers/rendering_server.h" - -class RenderingServerRaster : public RenderingServer { - enum { - MAX_INSTANCE_CULL = 8192, - MAX_INSTANCE_LIGHTS = 4, - LIGHT_CACHE_DIRTY = -1, - MAX_LIGHTS_CULLED = 256, - MAX_ROOM_CULL = 32, - MAX_EXTERIOR_PORTALS = 128, - MAX_LIGHT_SAMPLERS = 256, - INSTANCE_ROOMLESS_MASK = (1 << 20) - - }; - - static int changes; - RID test_cube; - - int black_margin[4]; - RID black_image[4]; - - struct FrameDrawnCallbacks { - ObjectID object; - StringName method; - Variant param; - }; - - List<FrameDrawnCallbacks> frame_drawn_callbacks; - - void _draw_margins(); - static void _changes_changed() {} - - uint64_t frame_profile_frame; - Vector<FrameProfileArea> frame_profile; - -public: - //if editor is redrawing when it shouldn't, enable this and put a breakpoint in _changes_changed() - //#define DEBUG_CHANGES - -#ifdef DEBUG_CHANGES - _FORCE_INLINE_ static void redraw_request() { - changes++; - _changes_changed(); - } - -#define DISPLAY_CHANGED \ - changes++; \ - _changes_changed(); - -#else - _FORCE_INLINE_ static void redraw_request() { changes++; } - -#define DISPLAY_CHANGED \ - changes++; -#endif - -#define BIND0R(m_r, m_name) \ - m_r m_name() { return BINDBASE->m_name(); } -#define BIND0RC(m_r, m_name) \ - m_r m_name() const { return BINDBASE->m_name(); } -#define BIND1R(m_r, m_name, m_type1) \ - m_r m_name(m_type1 arg1) { return BINDBASE->m_name(arg1); } -#define BIND1RC(m_r, m_name, m_type1) \ - m_r m_name(m_type1 arg1) const { return BINDBASE->m_name(arg1); } -#define BIND2R(m_r, m_name, m_type1, m_type2) \ - m_r m_name(m_type1 arg1, m_type2 arg2) { return BINDBASE->m_name(arg1, arg2); } -#define BIND2RC(m_r, m_name, m_type1, m_type2) \ - m_r m_name(m_type1 arg1, m_type2 arg2) const { return BINDBASE->m_name(arg1, arg2); } -#define BIND3R(m_r, m_name, m_type1, m_type2, m_type3) \ - m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3) { return BINDBASE->m_name(arg1, arg2, arg3); } -#define BIND3RC(m_r, m_name, m_type1, m_type2, m_type3) \ - m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3) const { return BINDBASE->m_name(arg1, arg2, arg3); } -#define BIND4R(m_r, m_name, m_type1, m_type2, m_type3, m_type4) \ - m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4) { return BINDBASE->m_name(arg1, arg2, arg3, arg4); } -#define BIND4RC(m_r, m_name, m_type1, m_type2, m_type3, m_type4) \ - m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4) const { return BINDBASE->m_name(arg1, arg2, arg3, arg4); } -#define BIND5R(m_r, m_name, m_type1, m_type2, m_type3, m_type4, m_type5) \ - m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5) { return BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5); } -#define BIND5RC(m_r, m_name, m_type1, m_type2, m_type3, m_type4, m_type5) \ - m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5) const { return BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5); } -#define BIND6R(m_r, m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6) \ - m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6) { return BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6); } -#define BIND6RC(m_r, m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6) \ - m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6) const { return BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6); } - -#define BIND0(m_name) \ - void m_name() { DISPLAY_CHANGED BINDBASE->m_name(); } -#define BIND1(m_name, m_type1) \ - void m_name(m_type1 arg1) { DISPLAY_CHANGED BINDBASE->m_name(arg1); } -#define BIND1C(m_name, m_type1) \ - void m_name(m_type1 arg1) const { DISPLAY_CHANGED BINDBASE->m_name(arg1); } -#define BIND2(m_name, m_type1, m_type2) \ - void m_name(m_type1 arg1, m_type2 arg2) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2); } -#define BIND2C(m_name, m_type1, m_type2) \ - void m_name(m_type1 arg1, m_type2 arg2) const { BINDBASE->m_name(arg1, arg2); } -#define BIND3(m_name, m_type1, m_type2, m_type3) \ - void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3); } -#define BIND4(m_name, m_type1, m_type2, m_type3, m_type4) \ - void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4); } -#define BIND5(m_name, m_type1, m_type2, m_type3, m_type4, m_type5) \ - void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5); } -#define BIND6(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6) \ - void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6); } -#define BIND7(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7) \ - void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7); } -#define BIND8(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8) \ - void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } -#define BIND9(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9) \ - void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); } -#define BIND10(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10) \ - void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); } -#define BIND11(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10, m_type11) \ - void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10, m_type11 arg11) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); } -#define BIND12(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10, m_type11, m_type12) \ - void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10, m_type11 arg11, m_type12 arg12) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); } -#define BIND13(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10, m_type11, m_type12, m_type13) \ - void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10, m_type11 arg11, m_type12 arg12, m_type13 arg13) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13); } -#define BIND14(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10, m_type11, m_type12, m_type13, m_type14) \ - void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10, m_type11 arg11, m_type12 arg12, m_type13 arg13, m_type14 arg14) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); } -#define BIND15(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10, m_type11, m_type12, m_type13, m_type14, m_type15) \ - void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10, m_type11 arg11, m_type12 arg12, m_type13 arg13, m_type14 arg14, m_type15 arg15) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15); } - -//from now on, calls forwarded to this singleton -#define BINDBASE RSG::storage - - /* TEXTURE API */ - - //these go pass-through, as they can be called from any thread - BIND1R(RID, texture_2d_create, const Ref<Image> &) - BIND2R(RID, texture_2d_layered_create, const Vector<Ref<Image>> &, TextureLayeredType) - BIND6R(RID, texture_3d_create, Image::Format, int, int, int, bool, const Vector<Ref<Image>> &) - BIND1R(RID, texture_proxy_create, RID) - - //goes pass-through - BIND3(texture_2d_update_immediate, RID, const Ref<Image> &, int) - //these go through command queue if they are in another thread - BIND3(texture_2d_update, RID, const Ref<Image> &, int) - BIND2(texture_3d_update, RID, const Vector<Ref<Image>> &) - BIND2(texture_proxy_update, RID, RID) - - //these also go pass-through - BIND0R(RID, texture_2d_placeholder_create) - BIND1R(RID, texture_2d_layered_placeholder_create, TextureLayeredType) - BIND0R(RID, texture_3d_placeholder_create) - - BIND1RC(Ref<Image>, texture_2d_get, RID) - BIND2RC(Ref<Image>, texture_2d_layer_get, RID, int) - BIND1RC(Vector<Ref<Image>>, texture_3d_get, RID) - - BIND2(texture_replace, RID, RID) - - BIND3(texture_set_size_override, RID, int, int) -// FIXME: Disabled during Vulkan refactoring, should be ported. -#if 0 - BIND2(texture_bind, RID, uint32_t) -#endif - - BIND3(texture_set_detect_3d_callback, RID, TextureDetectCallback, void *) - BIND3(texture_set_detect_normal_callback, RID, TextureDetectCallback, void *) - BIND3(texture_set_detect_roughness_callback, RID, TextureDetectRoughnessCallback, void *) - - BIND2(texture_set_path, RID, const String &) - BIND1RC(String, texture_get_path, RID) - BIND1(texture_debug_usage, List<TextureInfo> *) - - BIND2(texture_set_force_redraw_if_visible, RID, bool) - - /* SHADER API */ - - BIND0R(RID, shader_create) - - BIND2(shader_set_code, RID, const String &) - BIND1RC(String, shader_get_code, RID) - - BIND2C(shader_get_param_list, RID, List<PropertyInfo> *) - - BIND3(shader_set_default_texture_param, RID, const StringName &, RID) - BIND2RC(RID, shader_get_default_texture_param, RID, const StringName &) - BIND2RC(Variant, shader_get_param_default, RID, const StringName &) - - /* COMMON MATERIAL API */ - - BIND0R(RID, material_create) - - BIND2(material_set_shader, RID, RID) - - BIND3(material_set_param, RID, const StringName &, const Variant &) - BIND2RC(Variant, material_get_param, RID, const StringName &) - - BIND2(material_set_render_priority, RID, int) - BIND2(material_set_next_pass, RID, RID) - - /* MESH API */ - - virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces) { - RID mesh = mesh_create(); - for (int i = 0; i < p_surfaces.size(); i++) { - mesh_add_surface(mesh, p_surfaces[i]); - } - return mesh; - } - - BIND0R(RID, mesh_create) - - BIND2(mesh_add_surface, RID, const SurfaceData &) - - BIND1RC(int, mesh_get_blend_shape_count, RID) - - BIND2(mesh_set_blend_shape_mode, RID, BlendShapeMode) - BIND1RC(BlendShapeMode, mesh_get_blend_shape_mode, RID) - - BIND4(mesh_surface_update_region, RID, int, int, const Vector<uint8_t> &) - - BIND3(mesh_surface_set_material, RID, int, RID) - BIND2RC(RID, mesh_surface_get_material, RID, int) - - BIND2RC(SurfaceData, mesh_get_surface, RID, int) - - BIND1RC(int, mesh_get_surface_count, RID) - - BIND2(mesh_set_custom_aabb, RID, const AABB &) - BIND1RC(AABB, mesh_get_custom_aabb, RID) - - BIND1(mesh_clear, RID) - - /* MULTIMESH API */ - - BIND0R(RID, multimesh_create) - - BIND5(multimesh_allocate, RID, int, MultimeshTransformFormat, bool, bool) - BIND1RC(int, multimesh_get_instance_count, RID) - - BIND2(multimesh_set_mesh, RID, RID) - BIND3(multimesh_instance_set_transform, RID, int, const Transform &) - BIND3(multimesh_instance_set_transform_2d, RID, int, const Transform2D &) - BIND3(multimesh_instance_set_color, RID, int, const Color &) - BIND3(multimesh_instance_set_custom_data, RID, int, const Color &) - - BIND1RC(RID, multimesh_get_mesh, RID) - BIND1RC(AABB, multimesh_get_aabb, RID) - - BIND2RC(Transform, multimesh_instance_get_transform, RID, int) - BIND2RC(Transform2D, multimesh_instance_get_transform_2d, RID, int) - BIND2RC(Color, multimesh_instance_get_color, RID, int) - BIND2RC(Color, multimesh_instance_get_custom_data, RID, int) - - BIND2(multimesh_set_buffer, RID, const Vector<float> &) - BIND1RC(Vector<float>, multimesh_get_buffer, RID) - - BIND2(multimesh_set_visible_instances, RID, int) - BIND1RC(int, multimesh_get_visible_instances, RID) - - /* IMMEDIATE API */ - - BIND0R(RID, immediate_create) - BIND3(immediate_begin, RID, PrimitiveType, RID) - BIND2(immediate_vertex, RID, const Vector3 &) - BIND2(immediate_normal, RID, const Vector3 &) - BIND2(immediate_tangent, RID, const Plane &) - BIND2(immediate_color, RID, const Color &) - BIND2(immediate_uv, RID, const Vector2 &) - BIND2(immediate_uv2, RID, const Vector2 &) - BIND1(immediate_end, RID) - BIND1(immediate_clear, RID) - BIND2(immediate_set_material, RID, RID) - BIND1RC(RID, immediate_get_material, RID) - - /* SKELETON API */ - - BIND0R(RID, skeleton_create) - BIND3(skeleton_allocate, RID, int, bool) - BIND1RC(int, skeleton_get_bone_count, RID) - BIND3(skeleton_bone_set_transform, RID, int, const Transform &) - BIND2RC(Transform, skeleton_bone_get_transform, RID, int) - BIND3(skeleton_bone_set_transform_2d, RID, int, const Transform2D &) - BIND2RC(Transform2D, skeleton_bone_get_transform_2d, RID, int) - BIND2(skeleton_set_base_transform_2d, RID, const Transform2D &) - - /* Light API */ - - BIND0R(RID, directional_light_create) - BIND0R(RID, omni_light_create) - BIND0R(RID, spot_light_create) - - BIND2(light_set_color, RID, const Color &) - BIND3(light_set_param, RID, LightParam, float) - BIND2(light_set_shadow, RID, bool) - BIND2(light_set_shadow_color, RID, const Color &) - BIND2(light_set_projector, RID, RID) - BIND2(light_set_negative, RID, bool) - BIND2(light_set_cull_mask, RID, uint32_t) - BIND2(light_set_reverse_cull_face_mode, RID, bool) - BIND2(light_set_bake_mode, RID, LightBakeMode) - BIND2(light_set_max_sdfgi_cascade, RID, uint32_t) - - BIND2(light_omni_set_shadow_mode, RID, LightOmniShadowMode) - - BIND2(light_directional_set_shadow_mode, RID, LightDirectionalShadowMode) - BIND2(light_directional_set_blend_splits, RID, bool) - BIND2(light_directional_set_shadow_depth_range_mode, RID, LightDirectionalShadowDepthRangeMode) - - /* PROBE API */ - - BIND0R(RID, reflection_probe_create) - - BIND2(reflection_probe_set_update_mode, RID, ReflectionProbeUpdateMode) - BIND2(reflection_probe_set_intensity, RID, float) - BIND2(reflection_probe_set_ambient_color, RID, const Color &) - BIND2(reflection_probe_set_ambient_energy, RID, float) - BIND2(reflection_probe_set_ambient_mode, RID, ReflectionProbeAmbientMode) - BIND2(reflection_probe_set_max_distance, RID, float) - BIND2(reflection_probe_set_extents, RID, const Vector3 &) - BIND2(reflection_probe_set_origin_offset, RID, const Vector3 &) - BIND2(reflection_probe_set_as_interior, RID, bool) - BIND2(reflection_probe_set_enable_box_projection, RID, bool) - BIND2(reflection_probe_set_enable_shadows, RID, bool) - BIND2(reflection_probe_set_cull_mask, RID, uint32_t) - BIND2(reflection_probe_set_resolution, RID, int) - - /* DECAL API */ - - BIND0R(RID, decal_create) - - BIND2(decal_set_extents, RID, const Vector3 &) - BIND3(decal_set_texture, RID, DecalTexture, RID) - BIND2(decal_set_emission_energy, RID, float) - BIND2(decal_set_albedo_mix, RID, float) - BIND2(decal_set_modulate, RID, const Color &) - BIND2(decal_set_cull_mask, RID, uint32_t) - BIND4(decal_set_distance_fade, RID, bool, float, float) - BIND3(decal_set_fade, RID, float, float) - BIND2(decal_set_normal_fade, RID, float) - - /* BAKED LIGHT API */ - - BIND0R(RID, gi_probe_create) - - BIND8(gi_probe_allocate, RID, const Transform &, const AABB &, const Vector3i &, const Vector<uint8_t> &, const Vector<uint8_t> &, const Vector<uint8_t> &, const Vector<int> &) - - BIND1RC(AABB, gi_probe_get_bounds, RID) - BIND1RC(Vector3i, gi_probe_get_octree_size, RID) - BIND1RC(Vector<uint8_t>, gi_probe_get_octree_cells, RID) - BIND1RC(Vector<uint8_t>, gi_probe_get_data_cells, RID) - BIND1RC(Vector<uint8_t>, gi_probe_get_distance_field, RID) - BIND1RC(Vector<int>, gi_probe_get_level_counts, RID) - BIND1RC(Transform, gi_probe_get_to_cell_xform, RID) - - BIND2(gi_probe_set_dynamic_range, RID, float) - BIND1RC(float, gi_probe_get_dynamic_range, RID) - - BIND2(gi_probe_set_propagation, RID, float) - BIND1RC(float, gi_probe_get_propagation, RID) - - BIND2(gi_probe_set_energy, RID, float) - BIND1RC(float, gi_probe_get_energy, RID) - - BIND2(gi_probe_set_ao, RID, float) - BIND1RC(float, gi_probe_get_ao, RID) - - BIND2(gi_probe_set_ao_size, RID, float) - BIND1RC(float, gi_probe_get_ao_size, RID) - - BIND2(gi_probe_set_bias, RID, float) - BIND1RC(float, gi_probe_get_bias, RID) - - BIND2(gi_probe_set_normal_bias, RID, float) - BIND1RC(float, gi_probe_get_normal_bias, RID) - - BIND2(gi_probe_set_interior, RID, bool) - BIND1RC(bool, gi_probe_is_interior, RID) - - BIND2(gi_probe_set_use_two_bounces, RID, bool) - BIND1RC(bool, gi_probe_is_using_two_bounces, RID) - - BIND2(gi_probe_set_anisotropy_strength, RID, float) - BIND1RC(float, gi_probe_get_anisotropy_strength, RID) - - /* LIGHTMAP */ - - BIND0R(RID, lightmap_create) - - BIND3(lightmap_set_textures, RID, RID, bool) - BIND2(lightmap_set_probe_bounds, RID, const AABB &) - BIND2(lightmap_set_probe_interior, RID, bool) - BIND5(lightmap_set_probe_capture_data, RID, const PackedVector3Array &, const PackedColorArray &, const PackedInt32Array &, const PackedInt32Array &) - BIND1RC(PackedVector3Array, lightmap_get_probe_capture_points, RID) - BIND1RC(PackedColorArray, lightmap_get_probe_capture_sh, RID) - BIND1RC(PackedInt32Array, lightmap_get_probe_capture_tetrahedra, RID) - BIND1RC(PackedInt32Array, lightmap_get_probe_capture_bsp_tree, RID) - BIND1(lightmap_set_probe_capture_update_speed, float) - - /* PARTICLES */ - - BIND0R(RID, particles_create) - - BIND2(particles_set_emitting, RID, bool) - BIND1R(bool, particles_get_emitting, RID) - BIND2(particles_set_amount, RID, int) - BIND2(particles_set_lifetime, RID, float) - BIND2(particles_set_one_shot, RID, bool) - BIND2(particles_set_pre_process_time, RID, float) - BIND2(particles_set_explosiveness_ratio, RID, float) - BIND2(particles_set_randomness_ratio, RID, float) - BIND2(particles_set_custom_aabb, RID, const AABB &) - BIND2(particles_set_speed_scale, RID, float) - BIND2(particles_set_use_local_coordinates, RID, bool) - BIND2(particles_set_process_material, RID, RID) - BIND2(particles_set_fixed_fps, RID, int) - BIND2(particles_set_fractional_delta, RID, bool) - BIND1R(bool, particles_is_inactive, RID) - BIND1(particles_request_process, RID) - BIND1(particles_restart, RID) - BIND6(particles_emit, RID, const Transform &, const Vector3 &, const Color &, const Color &, uint32_t) - BIND2(particles_set_subemitter, RID, RID) - BIND2(particles_set_collision_base_size, RID, float) - - BIND2(particles_set_draw_order, RID, RS::ParticlesDrawOrder) - - BIND2(particles_set_draw_passes, RID, int) - BIND3(particles_set_draw_pass_mesh, RID, int, RID) - - BIND1R(AABB, particles_get_current_aabb, RID) - BIND2(particles_set_emission_transform, RID, const Transform &) - - /* PARTICLES COLLISION */ - - BIND0R(RID, particles_collision_create) - - BIND2(particles_collision_set_collision_type, RID, ParticlesCollisionType) - BIND2(particles_collision_set_cull_mask, RID, uint32_t) - BIND2(particles_collision_set_sphere_radius, RID, float) - BIND2(particles_collision_set_box_extents, RID, const Vector3 &) - BIND2(particles_collision_set_attractor_strength, RID, float) - BIND2(particles_collision_set_attractor_directionality, RID, float) - BIND2(particles_collision_set_attractor_attenuation, RID, float) - BIND2(particles_collision_set_field_texture, RID, RID) - BIND1(particles_collision_height_field_update, RID) - BIND2(particles_collision_set_height_field_resolution, RID, ParticlesCollisionHeightfieldResolution) - -#undef BINDBASE -//from now on, calls forwarded to this singleton -#define BINDBASE RSG::scene - - /* CAMERA API */ - - BIND0R(RID, camera_create) - BIND4(camera_set_perspective, RID, float, float, float) - BIND4(camera_set_orthogonal, RID, float, float, float) - BIND5(camera_set_frustum, RID, float, Vector2, float, float) - BIND2(camera_set_transform, RID, const Transform &) - BIND2(camera_set_cull_mask, RID, uint32_t) - BIND2(camera_set_environment, RID, RID) - BIND2(camera_set_camera_effects, RID, RID) - BIND2(camera_set_use_vertical_aspect, RID, bool) - -#undef BINDBASE -//from now on, calls forwarded to this singleton -#define BINDBASE RSG::viewport - - /* VIEWPORT TARGET API */ - - BIND0R(RID, viewport_create) - - BIND2(viewport_set_use_xr, RID, bool) - BIND3(viewport_set_size, RID, int, int) - - BIND2(viewport_set_active, RID, bool) - BIND2(viewport_set_parent_viewport, RID, RID) - - BIND2(viewport_set_clear_mode, RID, ViewportClearMode) - - BIND3(viewport_attach_to_screen, RID, const Rect2 &, int) - BIND2(viewport_set_render_direct_to_screen, RID, bool) - - BIND2(viewport_set_update_mode, RID, ViewportUpdateMode) - BIND2(viewport_set_vflip, RID, bool) - - BIND1RC(RID, viewport_get_texture, RID) - - BIND2(viewport_set_hide_scenario, RID, bool) - BIND2(viewport_set_hide_canvas, RID, bool) - BIND2(viewport_set_disable_environment, RID, bool) - - BIND2(viewport_attach_camera, RID, RID) - BIND2(viewport_set_scenario, RID, RID) - BIND2(viewport_attach_canvas, RID, RID) - - BIND2(viewport_remove_canvas, RID, RID) - BIND3(viewport_set_canvas_transform, RID, RID, const Transform2D &) - BIND2(viewport_set_transparent_background, RID, bool) - BIND2(viewport_set_snap_2d_transforms_to_pixel, RID, bool) - BIND2(viewport_set_snap_2d_vertices_to_pixel, RID, bool) - - BIND2(viewport_set_default_canvas_item_texture_filter, RID, CanvasItemTextureFilter) - BIND2(viewport_set_default_canvas_item_texture_repeat, RID, CanvasItemTextureRepeat) - - BIND2(viewport_set_global_canvas_transform, RID, const Transform2D &) - BIND4(viewport_set_canvas_stacking, RID, RID, int, int) - BIND2(viewport_set_shadow_atlas_size, RID, int) - BIND3(viewport_set_sdf_oversize_and_scale, RID, ViewportSDFOversize, ViewportSDFScale) - BIND3(viewport_set_shadow_atlas_quadrant_subdivision, RID, int, int) - BIND2(viewport_set_msaa, RID, ViewportMSAA) - BIND2(viewport_set_screen_space_aa, RID, ViewportScreenSpaceAA) - BIND2(viewport_set_use_debanding, RID, bool) - - BIND2R(int, viewport_get_render_info, RID, ViewportRenderInfo) - BIND2(viewport_set_debug_draw, RID, ViewportDebugDraw) - - BIND2(viewport_set_measure_render_time, RID, bool) - BIND1RC(float, viewport_get_measured_render_time_cpu, RID) - BIND1RC(float, viewport_get_measured_render_time_gpu, RID) - - /* ENVIRONMENT API */ - -#undef BINDBASE -//from now on, calls forwarded to this singleton -#define BINDBASE RSG::scene_render - - BIND1(directional_shadow_atlas_set_size, int) - BIND1(gi_probe_set_quality, GIProbeQuality) - - /* SKY API */ - - BIND0R(RID, sky_create) - BIND2(sky_set_radiance_size, RID, int) - BIND2(sky_set_mode, RID, SkyMode) - BIND2(sky_set_material, RID, RID) - BIND4R(Ref<Image>, sky_bake_panorama, RID, float, bool, const Size2i &) - - BIND0R(RID, environment_create) - - BIND2(environment_set_background, RID, EnvironmentBG) - BIND2(environment_set_sky, RID, RID) - BIND2(environment_set_sky_custom_fov, RID, float) - BIND2(environment_set_sky_orientation, RID, const Basis &) - BIND2(environment_set_bg_color, RID, const Color &) - BIND2(environment_set_bg_energy, RID, float) - BIND2(environment_set_canvas_max_layer, RID, int) - BIND7(environment_set_ambient_light, RID, const Color &, EnvironmentAmbientSource, float, float, EnvironmentReflectionSource, const Color &) - -// FIXME: Disabled during Vulkan refactoring, should be ported. -#if 0 - BIND2(environment_set_camera_feed_id, RID, int) -#endif - BIND6(environment_set_ssr, RID, bool, int, float, float, float) - BIND1(environment_set_ssr_roughness_quality, EnvironmentSSRRoughnessQuality) - - BIND9(environment_set_ssao, RID, bool, float, float, float, float, float, EnvironmentSSAOBlur, float) - BIND2(environment_set_ssao_quality, EnvironmentSSAOQuality, bool) - - BIND11(environment_set_glow, RID, bool, Vector<float>, float, float, float, float, EnvironmentGlowBlendMode, float, float, float) - BIND1(environment_glow_set_use_bicubic_upscale, bool) - BIND1(environment_glow_set_use_high_quality, bool) - - BIND9(environment_set_tonemap, RID, EnvironmentToneMapper, float, float, bool, float, float, float, float) - - BIND6(environment_set_adjustment, RID, bool, float, float, float, RID) - - BIND9(environment_set_fog, RID, bool, const Color &, float, float, float, float, float, float) - BIND9(environment_set_volumetric_fog, RID, bool, float, const Color &, float, float, float, float, EnvVolumetricFogShadowFilter) - - BIND2(environment_set_volumetric_fog_volume_size, int, int) - BIND1(environment_set_volumetric_fog_filter_active, bool) - BIND1(environment_set_volumetric_fog_directional_shadow_shrink_size, int) - BIND1(environment_set_volumetric_fog_positional_shadow_shrink_size, int) - - BIND11(environment_set_sdfgi, RID, bool, EnvironmentSDFGICascades, float, EnvironmentSDFGIYScale, bool, bool, bool, float, float, float) - BIND1(environment_set_sdfgi_ray_count, EnvironmentSDFGIRayCount) - BIND1(environment_set_sdfgi_frames_to_converge, EnvironmentSDFGIFramesToConverge) - - BIND3R(Ref<Image>, environment_bake_panorama, RID, bool, const Size2i &) - - BIND3(screen_space_roughness_limiter_set_active, bool, float, float) - BIND1(sub_surface_scattering_set_quality, SubSurfaceScatteringQuality) - BIND2(sub_surface_scattering_set_scale, float, float) - - /* CAMERA EFFECTS */ - - BIND0R(RID, camera_effects_create) - - BIND2(camera_effects_set_dof_blur_quality, DOFBlurQuality, bool) - BIND1(camera_effects_set_dof_blur_bokeh_shape, DOFBokehShape) - - BIND8(camera_effects_set_dof_blur, RID, bool, float, float, bool, float, float, float) - BIND3(camera_effects_set_custom_exposure, RID, bool, float) - - BIND1(shadows_quality_set, ShadowQuality); - BIND1(directional_shadow_quality_set, ShadowQuality); - - /* SCENARIO API */ - -#undef BINDBASE -#define BINDBASE RSG::scene - - BIND0R(RID, scenario_create) - - BIND2(scenario_set_debug, RID, ScenarioDebugMode) - BIND2(scenario_set_environment, RID, RID) - BIND2(scenario_set_camera_effects, RID, RID) - BIND2(scenario_set_fallback_environment, RID, RID) - - /* INSTANCING API */ - BIND0R(RID, instance_create) - - BIND2(instance_set_base, RID, RID) - BIND2(instance_set_scenario, RID, RID) - BIND2(instance_set_layer_mask, RID, uint32_t) - BIND2(instance_set_transform, RID, const Transform &) - BIND2(instance_attach_object_instance_id, RID, ObjectID) - BIND3(instance_set_blend_shape_weight, RID, int, float) - BIND3(instance_set_surface_material, RID, int, RID) - BIND2(instance_set_visible, RID, bool) - - BIND2(instance_set_custom_aabb, RID, AABB) - - BIND2(instance_attach_skeleton, RID, RID) - BIND2(instance_set_exterior, RID, bool) - - BIND2(instance_set_extra_visibility_margin, RID, real_t) - - // don't use these in a game! - BIND2RC(Vector<ObjectID>, instances_cull_aabb, const AABB &, RID) - BIND3RC(Vector<ObjectID>, instances_cull_ray, const Vector3 &, const Vector3 &, RID) - BIND2RC(Vector<ObjectID>, instances_cull_convex, const Vector<Plane> &, RID) - - BIND3(instance_geometry_set_flag, RID, InstanceFlags, bool) - BIND2(instance_geometry_set_cast_shadows_setting, RID, ShadowCastingSetting) - BIND2(instance_geometry_set_material_override, RID, RID) - - BIND5(instance_geometry_set_draw_range, RID, float, float, float, float) - BIND2(instance_geometry_set_as_instance_lod, RID, RID) - BIND4(instance_geometry_set_lightmap, RID, RID, const Rect2 &, int) - - BIND3(instance_geometry_set_shader_parameter, RID, const StringName &, const Variant &) - BIND2RC(Variant, instance_geometry_get_shader_parameter, RID, const StringName &) - BIND2RC(Variant, instance_geometry_get_shader_parameter_default_value, RID, const StringName &) - BIND2C(instance_geometry_get_shader_parameter_list, RID, List<PropertyInfo> *) - - BIND3R(TypedArray<Image>, bake_render_uv2, RID, const Vector<RID> &, const Size2i &) - -#undef BINDBASE -//from now on, calls forwarded to this singleton -#define BINDBASE RSG::canvas - - /* CANVAS (2D) */ - - BIND0R(RID, canvas_create) - BIND3(canvas_set_item_mirroring, RID, RID, const Point2 &) - BIND2(canvas_set_modulate, RID, const Color &) - BIND3(canvas_set_parent, RID, RID, float) - BIND1(canvas_set_disable_scale, bool) - - BIND0R(RID, canvas_texture_create) - BIND3(canvas_texture_set_channel, RID, CanvasTextureChannel, RID) - BIND3(canvas_texture_set_shading_parameters, RID, const Color &, float) - - BIND2(canvas_texture_set_texture_filter, RID, CanvasItemTextureFilter) - BIND2(canvas_texture_set_texture_repeat, RID, CanvasItemTextureRepeat) - - BIND0R(RID, canvas_item_create) - BIND2(canvas_item_set_parent, RID, RID) - - BIND2(canvas_item_set_default_texture_filter, RID, CanvasItemTextureFilter) - BIND2(canvas_item_set_default_texture_repeat, RID, CanvasItemTextureRepeat) - - BIND2(canvas_item_set_visible, RID, bool) - BIND2(canvas_item_set_light_mask, RID, int) - - BIND2(canvas_item_set_update_when_visible, RID, bool) - - BIND2(canvas_item_set_transform, RID, const Transform2D &) - BIND2(canvas_item_set_clip, RID, bool) - BIND2(canvas_item_set_distance_field_mode, RID, bool) - BIND3(canvas_item_set_custom_rect, RID, bool, const Rect2 &) - BIND2(canvas_item_set_modulate, RID, const Color &) - BIND2(canvas_item_set_self_modulate, RID, const Color &) - - BIND2(canvas_item_set_draw_behind_parent, RID, bool) - - BIND5(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float) - BIND4(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float) - BIND4(canvas_item_add_multiline, RID, const Vector<Point2> &, const Vector<Color> &, float) - BIND3(canvas_item_add_rect, RID, const Rect2 &, const Color &) - BIND4(canvas_item_add_circle, RID, const Point2 &, float, const Color &) - BIND6(canvas_item_add_texture_rect, RID, const Rect2 &, RID, bool, const Color &, bool) - BIND7(canvas_item_add_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, bool, bool) - BIND10(canvas_item_add_nine_patch, RID, const Rect2 &, const Rect2 &, RID, const Vector2 &, const Vector2 &, NinePatchAxisMode, NinePatchAxisMode, bool, const Color &) - BIND6(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, float) - BIND5(canvas_item_add_polygon, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID) - BIND9(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, const Vector<int> &, const Vector<float> &, RID, int) - BIND5(canvas_item_add_mesh, RID, const RID &, const Transform2D &, const Color &, RID) - BIND3(canvas_item_add_multimesh, RID, RID, RID) - BIND3(canvas_item_add_particles, RID, RID, RID) - BIND2(canvas_item_add_set_transform, RID, const Transform2D &) - BIND2(canvas_item_add_clip_ignore, RID, bool) - BIND2(canvas_item_set_sort_children_by_y, RID, bool) - BIND2(canvas_item_set_z_index, RID, int) - BIND2(canvas_item_set_z_as_relative_to_parent, RID, bool) - BIND3(canvas_item_set_copy_to_backbuffer, RID, bool, const Rect2 &) - BIND2(canvas_item_attach_skeleton, RID, RID) - - BIND1(canvas_item_clear, RID) - BIND2(canvas_item_set_draw_index, RID, int) - - BIND2(canvas_item_set_material, RID, RID) - - BIND2(canvas_item_set_use_parent_material, RID, bool) - - BIND6(canvas_item_set_canvas_group_mode, RID, CanvasGroupMode, float, bool, float, bool) - - BIND0R(RID, canvas_light_create) - - BIND2(canvas_light_set_mode, RID, CanvasLightMode) - - BIND2(canvas_light_attach_to_canvas, RID, RID) - BIND2(canvas_light_set_enabled, RID, bool) - BIND2(canvas_light_set_texture_scale, RID, float) - BIND2(canvas_light_set_transform, RID, const Transform2D &) - BIND2(canvas_light_set_texture, RID, RID) - BIND2(canvas_light_set_texture_offset, RID, const Vector2 &) - BIND2(canvas_light_set_color, RID, const Color &) - BIND2(canvas_light_set_height, RID, float) - BIND2(canvas_light_set_energy, RID, float) - BIND3(canvas_light_set_z_range, RID, int, int) - BIND3(canvas_light_set_layer_range, RID, int, int) - BIND2(canvas_light_set_item_cull_mask, RID, int) - BIND2(canvas_light_set_item_shadow_cull_mask, RID, int) - BIND2(canvas_light_set_directional_distance, RID, float) - - BIND2(canvas_light_set_blend_mode, RID, CanvasLightBlendMode) - - BIND2(canvas_light_set_shadow_enabled, RID, bool) - BIND2(canvas_light_set_shadow_filter, RID, CanvasLightShadowFilter) - BIND2(canvas_light_set_shadow_color, RID, const Color &) - BIND2(canvas_light_set_shadow_smooth, RID, float) - - BIND0R(RID, canvas_light_occluder_create) - BIND2(canvas_light_occluder_attach_to_canvas, RID, RID) - BIND2(canvas_light_occluder_set_enabled, RID, bool) - BIND2(canvas_light_occluder_set_polygon, RID, RID) - BIND2(canvas_light_occluder_set_as_sdf_collision, RID, bool) - BIND2(canvas_light_occluder_set_transform, RID, const Transform2D &) - BIND2(canvas_light_occluder_set_light_mask, RID, int) - - BIND0R(RID, canvas_occluder_polygon_create) - BIND3(canvas_occluder_polygon_set_shape, RID, const Vector<Vector2> &, bool) - - BIND2(canvas_occluder_polygon_set_cull_mode, RID, CanvasOccluderPolygonCullMode) - - BIND1(canvas_set_shadow_texture_size, int) - - /* GLOBAL VARIABLES */ - -#undef BINDBASE -//from now on, calls forwarded to this singleton -#define BINDBASE RSG::storage - - BIND3(global_variable_add, const StringName &, GlobalVariableType, const Variant &) - BIND1(global_variable_remove, const StringName &) - BIND0RC(Vector<StringName>, global_variable_get_list) - BIND2(global_variable_set, const StringName &, const Variant &) - BIND2(global_variable_set_override, const StringName &, const Variant &) - BIND1RC(GlobalVariableType, global_variable_get_type, const StringName &) - BIND1RC(Variant, global_variable_get, const StringName &) - - BIND1(global_variables_load_settings, bool) - BIND0(global_variables_clear) - - /* BLACK BARS */ - - virtual void black_bars_set_margins(int p_left, int p_top, int p_right, int p_bottom); - virtual void black_bars_set_images(RID p_left, RID p_top, RID p_right, RID p_bottom); - - /* FREE */ - - virtual void free(RID p_rid); ///< free RIDs associated with the visual server - - /* EVENT QUEUING */ - - virtual void request_frame_drawn_callback(Object *p_where, const StringName &p_method, const Variant &p_userdata); - - virtual void draw(bool p_swap_buffers, double frame_step); - virtual void sync(); - virtual bool has_changed() const; - virtual void init(); - virtual void finish(); - - /* STATUS INFORMATION */ - - virtual int get_render_info(RenderInfo p_info); - virtual String get_video_adapter_name() const; - virtual String get_video_adapter_vendor() const; - - virtual void set_frame_profiling_enabled(bool p_enable); - virtual Vector<FrameProfileArea> get_frame_profile(); - virtual uint64_t get_frame_profile_frame(); - - virtual RID get_test_cube(); - - /* TESTING */ - - virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true); - virtual void set_default_clear_color(const Color &p_color); - - virtual bool has_feature(Features p_feature) const; - - virtual bool has_os_feature(const String &p_feature) const; - virtual void set_debug_generate_wireframes(bool p_generate); - - virtual void call_set_use_vsync(bool p_enable); - - virtual bool is_low_end() const; - - virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir); - - RenderingServerRaster(); - ~RenderingServerRaster(); - -#undef DISPLAY_CHANGED - -#undef BIND0R -#undef BIND1RC -#undef BIND2RC -#undef BIND3RC -#undef BIND4RC - -#undef BIND1 -#undef BIND2 -#undef BIND3 -#undef BIND4 -#undef BIND5 -#undef BIND6 -#undef BIND7 -#undef BIND8 -#undef BIND9 -#undef BIND10 -}; - -#endif diff --git a/servers/rendering/rendering_server_scene.cpp b/servers/rendering/rendering_server_scene.cpp deleted file mode 100644 index ae6786090a..0000000000 --- a/servers/rendering/rendering_server_scene.cpp +++ /dev/null @@ -1,3040 +0,0 @@ -/*************************************************************************/ -/* rendering_server_scene.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "rendering_server_scene.h" - -#include "core/os/os.h" -#include "rendering_server_globals.h" -#include "rendering_server_raster.h" - -#include <new> - -/* CAMERA API */ - -RID RenderingServerScene::camera_create() { - Camera *camera = memnew(Camera); - return camera_owner.make_rid(camera); -} - -void RenderingServerScene::camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far) { - Camera *camera = camera_owner.getornull(p_camera); - ERR_FAIL_COND(!camera); - camera->type = Camera::PERSPECTIVE; - camera->fov = p_fovy_degrees; - camera->znear = p_z_near; - camera->zfar = p_z_far; -} - -void RenderingServerScene::camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far) { - Camera *camera = camera_owner.getornull(p_camera); - ERR_FAIL_COND(!camera); - camera->type = Camera::ORTHOGONAL; - camera->size = p_size; - camera->znear = p_z_near; - camera->zfar = p_z_far; -} - -void RenderingServerScene::camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far) { - Camera *camera = camera_owner.getornull(p_camera); - ERR_FAIL_COND(!camera); - camera->type = Camera::FRUSTUM; - camera->size = p_size; - camera->offset = p_offset; - camera->znear = p_z_near; - camera->zfar = p_z_far; -} - -void RenderingServerScene::camera_set_transform(RID p_camera, const Transform &p_transform) { - Camera *camera = camera_owner.getornull(p_camera); - ERR_FAIL_COND(!camera); - camera->transform = p_transform.orthonormalized(); -} - -void RenderingServerScene::camera_set_cull_mask(RID p_camera, uint32_t p_layers) { - Camera *camera = camera_owner.getornull(p_camera); - ERR_FAIL_COND(!camera); - - camera->visible_layers = p_layers; -} - -void RenderingServerScene::camera_set_environment(RID p_camera, RID p_env) { - Camera *camera = camera_owner.getornull(p_camera); - ERR_FAIL_COND(!camera); - camera->env = p_env; -} - -void RenderingServerScene::camera_set_camera_effects(RID p_camera, RID p_fx) { - Camera *camera = camera_owner.getornull(p_camera); - ERR_FAIL_COND(!camera); - camera->effects = p_fx; -} - -void RenderingServerScene::camera_set_use_vertical_aspect(RID p_camera, bool p_enable) { - Camera *camera = camera_owner.getornull(p_camera); - ERR_FAIL_COND(!camera); - camera->vaspect = p_enable; -} - -/* SCENARIO API */ - -void *RenderingServerScene::_instance_pair(void *p_self, OctreeElementID, Instance *p_A, int, OctreeElementID, Instance *p_B, int) { - //RenderingServerScene *self = (RenderingServerScene*)p_self; - Instance *A = p_A; - Instance *B = p_B; - - //instance indices are designed so greater always contains lesser - if (A->base_type > B->base_type) { - SWAP(A, B); //lesser always first - } - - if (B->base_type == RS::INSTANCE_LIGHT && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { - InstanceLightData *light = static_cast<InstanceLightData *>(B->base_data); - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); - - InstanceLightData::PairInfo pinfo; - pinfo.geometry = A; - pinfo.L = geom->lighting.push_back(B); - - List<InstanceLightData::PairInfo>::Element *E = light->geometries.push_back(pinfo); - - if (geom->can_cast_shadows) { - light->shadow_dirty = true; - } - geom->lighting_dirty = true; - - return E; //this element should make freeing faster - } else if (B->base_type == RS::INSTANCE_REFLECTION_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { - InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(B->base_data); - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); - - InstanceReflectionProbeData::PairInfo pinfo; - pinfo.geometry = A; - pinfo.L = geom->reflection_probes.push_back(B); - - List<InstanceReflectionProbeData::PairInfo>::Element *E = reflection_probe->geometries.push_back(pinfo); - - geom->reflection_dirty = true; - - return E; //this element should make freeing faster - } else if (B->base_type == RS::INSTANCE_DECAL && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { - InstanceDecalData *decal = static_cast<InstanceDecalData *>(B->base_data); - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); - - InstanceDecalData::PairInfo pinfo; - pinfo.geometry = A; - pinfo.L = geom->decals.push_back(B); - - List<InstanceDecalData::PairInfo>::Element *E = decal->geometries.push_back(pinfo); - - geom->decal_dirty = true; - - return E; //this element should make freeing faster - } else if (B->base_type == RS::INSTANCE_LIGHTMAP && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { - InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(B->base_data); - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); - - if (A->dynamic_gi) { - InstanceLightmapData::PairInfo pinfo; - pinfo.geometry = A; - pinfo.L = geom->lightmap_captures.push_back(B); - List<InstanceLightmapData::PairInfo>::Element *E = lightmap_data->geometries.push_back(pinfo); - ((RenderingServerScene *)p_self)->_instance_queue_update(A, false, false); //need to update capture - return E; //this element should make freeing faster - } else { - return nullptr; - } - - } else if (B->base_type == RS::INSTANCE_GI_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data); - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); - - InstanceGIProbeData::PairInfo pinfo; - pinfo.geometry = A; - pinfo.L = geom->gi_probes.push_back(B); - - List<InstanceGIProbeData::PairInfo>::Element *E; - if (A->dynamic_gi) { - E = gi_probe->dynamic_geometries.push_back(pinfo); - } else { - E = gi_probe->geometries.push_back(pinfo); - } - - geom->gi_probes_dirty = true; - - return E; //this element should make freeing faster - - } else if (B->base_type == RS::INSTANCE_GI_PROBE && A->base_type == RS::INSTANCE_LIGHT) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data); - return gi_probe->lights.insert(A); - } else if (B->base_type == RS::INSTANCE_PARTICLES_COLLISION && A->base_type == RS::INSTANCE_PARTICLES) { - RSG::storage->particles_add_collision(A->base, B); - } - - return nullptr; -} - -void RenderingServerScene::_instance_unpair(void *p_self, OctreeElementID, Instance *p_A, int, OctreeElementID, Instance *p_B, int, void *udata) { - //RenderingServerScene *self = (RenderingServerScene*)p_self; - Instance *A = p_A; - Instance *B = p_B; - - //instance indices are designed so greater always contains lesser - if (A->base_type > B->base_type) { - SWAP(A, B); //lesser always first - } - - if (B->base_type == RS::INSTANCE_LIGHT && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { - InstanceLightData *light = static_cast<InstanceLightData *>(B->base_data); - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); - - List<InstanceLightData::PairInfo>::Element *E = reinterpret_cast<List<InstanceLightData::PairInfo>::Element *>(udata); - - geom->lighting.erase(E->get().L); - light->geometries.erase(E); - - if (geom->can_cast_shadows) { - light->shadow_dirty = true; - } - geom->lighting_dirty = true; - - } else if (B->base_type == RS::INSTANCE_REFLECTION_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { - InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(B->base_data); - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); - - List<InstanceReflectionProbeData::PairInfo>::Element *E = reinterpret_cast<List<InstanceReflectionProbeData::PairInfo>::Element *>(udata); - - geom->reflection_probes.erase(E->get().L); - reflection_probe->geometries.erase(E); - - geom->reflection_dirty = true; - } else if (B->base_type == RS::INSTANCE_DECAL && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { - InstanceDecalData *decal = static_cast<InstanceDecalData *>(B->base_data); - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); - - List<InstanceDecalData::PairInfo>::Element *E = reinterpret_cast<List<InstanceDecalData::PairInfo>::Element *>(udata); - - geom->decals.erase(E->get().L); - decal->geometries.erase(E); - - geom->decal_dirty = true; - } else if (B->base_type == RS::INSTANCE_LIGHTMAP && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { - if (udata) { //only for dynamic geometries - InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(B->base_data); - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); - - List<InstanceLightmapData::PairInfo>::Element *E = reinterpret_cast<List<InstanceLightmapData::PairInfo>::Element *>(udata); - - geom->lightmap_captures.erase(E->get().L); - lightmap_data->geometries.erase(E); - ((RenderingServerScene *)p_self)->_instance_queue_update(A, false, false); //need to update capture - } - - } else if (B->base_type == RS::INSTANCE_GI_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data); - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); - - List<InstanceGIProbeData::PairInfo>::Element *E = reinterpret_cast<List<InstanceGIProbeData::PairInfo>::Element *>(udata); - - geom->gi_probes.erase(E->get().L); - if (A->dynamic_gi) { - gi_probe->dynamic_geometries.erase(E); - } else { - gi_probe->geometries.erase(E); - } - - geom->gi_probes_dirty = true; - - } else if (B->base_type == RS::INSTANCE_GI_PROBE && A->base_type == RS::INSTANCE_LIGHT) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data); - Set<Instance *>::Element *E = reinterpret_cast<Set<Instance *>::Element *>(udata); - - gi_probe->lights.erase(E); - } else if (B->base_type == RS::INSTANCE_PARTICLES_COLLISION && A->base_type == RS::INSTANCE_PARTICLES) { - RSG::storage->particles_remove_collision(A->base, B); - } -} - -RID RenderingServerScene::scenario_create() { - Scenario *scenario = memnew(Scenario); - ERR_FAIL_COND_V(!scenario, RID()); - RID scenario_rid = scenario_owner.make_rid(scenario); - scenario->self = scenario_rid; - - scenario->octree.set_pair_callback(_instance_pair, this); - scenario->octree.set_unpair_callback(_instance_unpair, this); - scenario->reflection_probe_shadow_atlas = RSG::scene_render->shadow_atlas_create(); - RSG::scene_render->shadow_atlas_set_size(scenario->reflection_probe_shadow_atlas, 1024); //make enough shadows for close distance, don't bother with rest - RSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 0, 4); - RSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 1, 4); - RSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 2, 4); - RSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 3, 8); - scenario->reflection_atlas = RSG::scene_render->reflection_atlas_create(); - return scenario_rid; -} - -void RenderingServerScene::scenario_set_debug(RID p_scenario, RS::ScenarioDebugMode p_debug_mode) { - Scenario *scenario = scenario_owner.getornull(p_scenario); - ERR_FAIL_COND(!scenario); - scenario->debug = p_debug_mode; -} - -void RenderingServerScene::scenario_set_environment(RID p_scenario, RID p_environment) { - Scenario *scenario = scenario_owner.getornull(p_scenario); - ERR_FAIL_COND(!scenario); - scenario->environment = p_environment; -} - -void RenderingServerScene::scenario_set_camera_effects(RID p_scenario, RID p_camera_effects) { - Scenario *scenario = scenario_owner.getornull(p_scenario); - ERR_FAIL_COND(!scenario); - scenario->camera_effects = p_camera_effects; -} - -void RenderingServerScene::scenario_set_fallback_environment(RID p_scenario, RID p_environment) { - Scenario *scenario = scenario_owner.getornull(p_scenario); - ERR_FAIL_COND(!scenario); - scenario->fallback_environment = p_environment; -} - -void RenderingServerScene::scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count) { - Scenario *scenario = scenario_owner.getornull(p_scenario); - ERR_FAIL_COND(!scenario); - RSG::scene_render->reflection_atlas_set_size(scenario->reflection_atlas, p_reflection_size, p_reflection_count); -} - -/* INSTANCING API */ - -void RenderingServerScene::_instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_dependencies) { - if (p_update_aabb) { - p_instance->update_aabb = true; - } - if (p_update_dependencies) { - p_instance->update_dependencies = true; - } - - if (p_instance->update_item.in_list()) { - return; - } - - _instance_update_list.add(&p_instance->update_item); -} - -RID RenderingServerScene::instance_create() { - Instance *instance = memnew(Instance); - ERR_FAIL_COND_V(!instance, RID()); - - RID instance_rid = instance_owner.make_rid(instance); - instance->self = instance_rid; - - return instance_rid; -} - -void RenderingServerScene::instance_set_base(RID p_instance, RID p_base) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - Scenario *scenario = instance->scenario; - - if (instance->base_type != RS::INSTANCE_NONE) { - //free anything related to that base - - if (scenario && instance->octree_id) { - scenario->octree.erase(instance->octree_id); //make dependencies generated by the octree go away - instance->octree_id = 0; - } - - switch (instance->base_type) { - case RS::INSTANCE_LIGHT: { - InstanceLightData *light = static_cast<InstanceLightData *>(instance->base_data); - - if (scenario && RSG::storage->light_get_type(instance->base) != RS::LIGHT_DIRECTIONAL && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) { - scenario->dynamic_lights.erase(light->instance); - } - -#ifdef DEBUG_ENABLED - if (light->geometries.size()) { - ERR_PRINT("BUG, indexing did not unpair geometries from light."); - } -#endif - if (scenario && light->D) { - scenario->directional_lights.erase(light->D); - light->D = nullptr; - } - RSG::scene_render->free(light->instance); - } break; - case RS::INSTANCE_REFLECTION_PROBE: { - InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(instance->base_data); - RSG::scene_render->free(reflection_probe->instance); - if (reflection_probe->update_list.in_list()) { - reflection_probe_render_list.remove(&reflection_probe->update_list); - } - } break; - case RS::INSTANCE_DECAL: { - InstanceDecalData *decal = static_cast<InstanceDecalData *>(instance->base_data); - RSG::scene_render->free(decal->instance); - - } break; - case RS::INSTANCE_LIGHTMAP: { - InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(instance->base_data); - //erase dependencies, since no longer a lightmap - while (lightmap_data->users.front()) { - instance_geometry_set_lightmap(lightmap_data->users.front()->get()->self, RID(), Rect2(), 0); - } - } break; - case RS::INSTANCE_GI_PROBE: { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data); -#ifdef DEBUG_ENABLED - if (gi_probe->geometries.size()) { - ERR_PRINT("BUG, indexing did not unpair geometries from GIProbe."); - } -#endif -#ifdef DEBUG_ENABLED - if (gi_probe->lights.size()) { - ERR_PRINT("BUG, indexing did not unpair lights from GIProbe."); - } -#endif - if (gi_probe->update_element.in_list()) { - gi_probe_update_list.remove(&gi_probe->update_element); - } - - RSG::scene_render->free(gi_probe->probe_instance); - - } break; - default: { - } - } - - if (instance->base_data) { - memdelete(instance->base_data); - instance->base_data = nullptr; - } - - instance->blend_values.clear(); - instance->materials.clear(); - } - - instance->base_type = RS::INSTANCE_NONE; - instance->base = RID(); - - if (p_base.is_valid()) { - instance->base_type = RSG::storage->get_base_type(p_base); - ERR_FAIL_COND(instance->base_type == RS::INSTANCE_NONE); - - switch (instance->base_type) { - case RS::INSTANCE_LIGHT: { - InstanceLightData *light = memnew(InstanceLightData); - - if (scenario && RSG::storage->light_get_type(p_base) == RS::LIGHT_DIRECTIONAL) { - light->D = scenario->directional_lights.push_back(instance); - } - - light->instance = RSG::scene_render->light_instance_create(p_base); - - instance->base_data = light; - } break; - case RS::INSTANCE_MESH: - case RS::INSTANCE_MULTIMESH: - case RS::INSTANCE_IMMEDIATE: - case RS::INSTANCE_PARTICLES: { - InstanceGeometryData *geom = memnew(InstanceGeometryData); - instance->base_data = geom; - if (instance->base_type == RS::INSTANCE_MESH) { - instance->blend_values.resize(RSG::storage->mesh_get_blend_shape_count(p_base)); - } - } break; - case RS::INSTANCE_REFLECTION_PROBE: { - InstanceReflectionProbeData *reflection_probe = memnew(InstanceReflectionProbeData); - reflection_probe->owner = instance; - instance->base_data = reflection_probe; - - reflection_probe->instance = RSG::scene_render->reflection_probe_instance_create(p_base); - } break; - case RS::INSTANCE_DECAL: { - InstanceDecalData *decal = memnew(InstanceDecalData); - decal->owner = instance; - instance->base_data = decal; - - decal->instance = RSG::scene_render->decal_instance_create(p_base); - } break; - case RS::INSTANCE_LIGHTMAP: { - InstanceLightmapData *lightmap_data = memnew(InstanceLightmapData); - instance->base_data = lightmap_data; - //lightmap_data->instance = RSG::scene_render->lightmap_data_instance_create(p_base); - } break; - case RS::INSTANCE_GI_PROBE: { - InstanceGIProbeData *gi_probe = memnew(InstanceGIProbeData); - instance->base_data = gi_probe; - gi_probe->owner = instance; - - if (scenario && !gi_probe->update_element.in_list()) { - gi_probe_update_list.add(&gi_probe->update_element); - } - - gi_probe->probe_instance = RSG::scene_render->gi_probe_instance_create(p_base); - - } break; - default: { - } - } - - instance->base = p_base; - - //forcefully update the dependency now, so if for some reason it gets removed, we can immediately clear it - RSG::storage->base_update_dependency(p_base, instance); - } - - _instance_queue_update(instance, true, true); -} - -void RenderingServerScene::instance_set_scenario(RID p_instance, RID p_scenario) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - if (instance->scenario) { - instance->scenario->instances.remove(&instance->scenario_item); - - if (instance->octree_id) { - instance->scenario->octree.erase(instance->octree_id); //make dependencies generated by the octree go away - instance->octree_id = 0; - } - - switch (instance->base_type) { - case RS::INSTANCE_LIGHT: { - InstanceLightData *light = static_cast<InstanceLightData *>(instance->base_data); -#ifdef DEBUG_ENABLED - if (light->geometries.size()) { - ERR_PRINT("BUG, indexing did not unpair geometries from light."); - } -#endif - if (light->D) { - instance->scenario->directional_lights.erase(light->D); - light->D = nullptr; - } - } break; - case RS::INSTANCE_REFLECTION_PROBE: { - InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(instance->base_data); - RSG::scene_render->reflection_probe_release_atlas_index(reflection_probe->instance); - - } break; - case RS::INSTANCE_PARTICLES_COLLISION: { - heightfield_particle_colliders_update_list.erase(instance); - } break; - case RS::INSTANCE_GI_PROBE: { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data); - -#ifdef DEBUG_ENABLED - if (gi_probe->geometries.size()) { - ERR_PRINT("BUG, indexing did not unpair geometries from GIProbe."); - } -#endif -#ifdef DEBUG_ENABLED - if (gi_probe->lights.size()) { - ERR_PRINT("BUG, indexing did not unpair lights from GIProbe."); - } -#endif - - if (gi_probe->update_element.in_list()) { - gi_probe_update_list.remove(&gi_probe->update_element); - } - } break; - default: { - } - } - - instance->scenario = nullptr; - } - - if (p_scenario.is_valid()) { - Scenario *scenario = scenario_owner.getornull(p_scenario); - ERR_FAIL_COND(!scenario); - - instance->scenario = scenario; - - scenario->instances.add(&instance->scenario_item); - - switch (instance->base_type) { - case RS::INSTANCE_LIGHT: { - InstanceLightData *light = static_cast<InstanceLightData *>(instance->base_data); - - if (RSG::storage->light_get_type(instance->base) == RS::LIGHT_DIRECTIONAL) { - light->D = scenario->directional_lights.push_back(instance); - } - } break; - case RS::INSTANCE_GI_PROBE: { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data); - if (!gi_probe->update_element.in_list()) { - gi_probe_update_list.add(&gi_probe->update_element); - } - } break; - default: { - } - } - - _instance_queue_update(instance, true, true); - } -} - -void RenderingServerScene::instance_set_layer_mask(RID p_instance, uint32_t p_mask) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - instance->layer_mask = p_mask; -} - -void RenderingServerScene::instance_set_transform(RID p_instance, const Transform &p_transform) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - if (instance->transform == p_transform) { - return; //must be checked to avoid worst evil - } - -#ifdef DEBUG_ENABLED - - for (int i = 0; i < 4; i++) { - const Vector3 &v = i < 3 ? p_transform.basis.elements[i] : p_transform.origin; - ERR_FAIL_COND(Math::is_inf(v.x)); - ERR_FAIL_COND(Math::is_nan(v.x)); - ERR_FAIL_COND(Math::is_inf(v.y)); - ERR_FAIL_COND(Math::is_nan(v.y)); - ERR_FAIL_COND(Math::is_inf(v.z)); - ERR_FAIL_COND(Math::is_nan(v.z)); - } - -#endif - instance->transform = p_transform; - _instance_queue_update(instance, true); -} - -void RenderingServerScene::instance_attach_object_instance_id(RID p_instance, ObjectID p_id) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - instance->object_id = p_id; -} - -void RenderingServerScene::instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - if (instance->update_item.in_list()) { - _update_dirty_instance(instance); - } - - ERR_FAIL_INDEX(p_shape, instance->blend_values.size()); - instance->blend_values.write[p_shape] = p_weight; -} - -void RenderingServerScene::instance_set_surface_material(RID p_instance, int p_surface, RID p_material) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - if (instance->base_type == RS::INSTANCE_MESH) { - //may not have been updated yet, may also have not been set yet. When updated will be correcte, worst case - instance->materials.resize(MAX(p_surface + 1, RSG::storage->mesh_get_surface_count(instance->base))); - } - - ERR_FAIL_INDEX(p_surface, instance->materials.size()); - - instance->materials.write[p_surface] = p_material; - - _instance_queue_update(instance, false, true); -} - -void RenderingServerScene::instance_set_visible(RID p_instance, bool p_visible) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - if (instance->visible == p_visible) { - return; - } - - instance->visible = p_visible; - - switch (instance->base_type) { - case RS::INSTANCE_LIGHT: { - if (RSG::storage->light_get_type(instance->base) != RS::LIGHT_DIRECTIONAL && instance->octree_id && instance->scenario) { - instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << RS::INSTANCE_LIGHT, p_visible ? RS::INSTANCE_GEOMETRY_MASK : 0); - } - - } break; - case RS::INSTANCE_REFLECTION_PROBE: { - if (instance->octree_id && instance->scenario) { - instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << RS::INSTANCE_REFLECTION_PROBE, p_visible ? RS::INSTANCE_GEOMETRY_MASK : 0); - } - - } break; - case RS::INSTANCE_DECAL: { - if (instance->octree_id && instance->scenario) { - instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << RS::INSTANCE_DECAL, p_visible ? RS::INSTANCE_GEOMETRY_MASK : 0); - } - - } break; - case RS::INSTANCE_LIGHTMAP: { - if (instance->octree_id && instance->scenario) { - instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << RS::INSTANCE_LIGHTMAP, p_visible ? RS::INSTANCE_GEOMETRY_MASK : 0); - } - - } break; - case RS::INSTANCE_GI_PROBE: { - if (instance->octree_id && instance->scenario) { - instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << RS::INSTANCE_GI_PROBE, p_visible ? (RS::INSTANCE_GEOMETRY_MASK | (1 << RS::INSTANCE_LIGHT)) : 0); - } - - } break; - case RS::INSTANCE_PARTICLES_COLLISION: { - if (instance->octree_id && instance->scenario) { - instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << RS::INSTANCE_PARTICLES_COLLISION, p_visible ? (1 << RS::INSTANCE_PARTICLES) : 0); - } - - } break; - default: { - } - } -} - -inline bool is_geometry_instance(RenderingServer::InstanceType p_type) { - return p_type == RS::INSTANCE_MESH || p_type == RS::INSTANCE_MULTIMESH || p_type == RS::INSTANCE_PARTICLES || p_type == RS::INSTANCE_IMMEDIATE; -} - -void RenderingServerScene::instance_set_custom_aabb(RID p_instance, AABB p_aabb) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - ERR_FAIL_COND(!is_geometry_instance(instance->base_type)); - - if (p_aabb != AABB()) { - // Set custom AABB - if (instance->custom_aabb == nullptr) { - instance->custom_aabb = memnew(AABB); - } - *instance->custom_aabb = p_aabb; - - } else { - // Clear custom AABB - if (instance->custom_aabb != nullptr) { - memdelete(instance->custom_aabb); - instance->custom_aabb = nullptr; - } - } - - if (instance->scenario) { - _instance_queue_update(instance, true, false); - } -} - -void RenderingServerScene::instance_attach_skeleton(RID p_instance, RID p_skeleton) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - if (instance->skeleton == p_skeleton) { - return; - } - - instance->skeleton = p_skeleton; - - if (p_skeleton.is_valid()) { - //update the dependency now, so if cleared, we remove it - RSG::storage->skeleton_update_dependency(p_skeleton, instance); - } - _instance_queue_update(instance, true, true); -} - -void RenderingServerScene::instance_set_exterior(RID p_instance, bool p_enabled) { -} - -void RenderingServerScene::instance_set_extra_visibility_margin(RID p_instance, real_t p_margin) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - instance->extra_margin = p_margin; - _instance_queue_update(instance, true, false); -} - -Vector<ObjectID> RenderingServerScene::instances_cull_aabb(const AABB &p_aabb, RID p_scenario) const { - Vector<ObjectID> instances; - Scenario *scenario = scenario_owner.getornull(p_scenario); - ERR_FAIL_COND_V(!scenario, instances); - - const_cast<RenderingServerScene *>(this)->update_dirty_instances(); // check dirty instances before culling - - int culled = 0; - Instance *cull[1024]; - culled = scenario->octree.cull_aabb(p_aabb, cull, 1024); - - for (int i = 0; i < culled; i++) { - Instance *instance = cull[i]; - ERR_CONTINUE(!instance); - if (instance->object_id.is_null()) { - continue; - } - - instances.push_back(instance->object_id); - } - - return instances; -} - -Vector<ObjectID> RenderingServerScene::instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario) const { - Vector<ObjectID> instances; - Scenario *scenario = scenario_owner.getornull(p_scenario); - ERR_FAIL_COND_V(!scenario, instances); - const_cast<RenderingServerScene *>(this)->update_dirty_instances(); // check dirty instances before culling - - int culled = 0; - Instance *cull[1024]; - culled = scenario->octree.cull_segment(p_from, p_from + p_to * 10000, cull, 1024); - - for (int i = 0; i < culled; i++) { - Instance *instance = cull[i]; - ERR_CONTINUE(!instance); - if (instance->object_id.is_null()) { - continue; - } - - instances.push_back(instance->object_id); - } - - return instances; -} - -Vector<ObjectID> RenderingServerScene::instances_cull_convex(const Vector<Plane> &p_convex, RID p_scenario) const { - Vector<ObjectID> instances; - Scenario *scenario = scenario_owner.getornull(p_scenario); - ERR_FAIL_COND_V(!scenario, instances); - const_cast<RenderingServerScene *>(this)->update_dirty_instances(); // check dirty instances before culling - - int culled = 0; - Instance *cull[1024]; - - culled = scenario->octree.cull_convex(p_convex, cull, 1024); - - for (int i = 0; i < culled; i++) { - Instance *instance = cull[i]; - ERR_CONTINUE(!instance); - if (instance->object_id.is_null()) { - continue; - } - - instances.push_back(instance->object_id); - } - - return instances; -} - -void RenderingServerScene::instance_geometry_set_flag(RID p_instance, RS::InstanceFlags p_flags, bool p_enabled) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - //ERR_FAIL_COND(((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK)); - - switch (p_flags) { - case RS::INSTANCE_FLAG_USE_BAKED_LIGHT: { - instance->baked_light = p_enabled; - - } break; - case RS::INSTANCE_FLAG_USE_DYNAMIC_GI: { - if (p_enabled == instance->dynamic_gi) { - //bye, redundant - return; - } - - if (instance->octree_id != 0) { - //remove from octree, it needs to be re-paired - instance->scenario->octree.erase(instance->octree_id); - instance->octree_id = 0; - _instance_queue_update(instance, true, true); - } - - //once out of octree, can be changed - instance->dynamic_gi = p_enabled; - - } break; - case RS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE: { - instance->redraw_if_visible = p_enabled; - - } break; - default: { - } - } -} - -void RenderingServerScene::instance_geometry_set_cast_shadows_setting(RID p_instance, RS::ShadowCastingSetting p_shadow_casting_setting) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - instance->cast_shadows = p_shadow_casting_setting; - _instance_queue_update(instance, false, true); -} - -void RenderingServerScene::instance_geometry_set_material_override(RID p_instance, RID p_material) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - instance->material_override = p_material; - _instance_queue_update(instance, false, true); -} - -void RenderingServerScene::instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) { -} - -void RenderingServerScene::instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance) { -} - -void RenderingServerScene::instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - if (instance->lightmap) { - InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(((Instance *)instance->lightmap)->base_data); - lightmap_data->users.erase(instance); - instance->lightmap = nullptr; - } - - Instance *lightmap_instance = instance_owner.getornull(p_lightmap); - - instance->lightmap = lightmap_instance; - instance->lightmap_uv_scale = p_lightmap_uv_scale; - instance->lightmap_slice_index = p_slice_index; - - if (lightmap_instance) { - InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(lightmap_instance->base_data); - lightmap_data->users.insert(instance); - } -} - -void RenderingServerScene::instance_geometry_set_shader_parameter(RID p_instance, const StringName &p_parameter, const Variant &p_value) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - Map<StringName, RasterizerScene::InstanceBase::InstanceShaderParameter>::Element *E = instance->instance_shader_parameters.find(p_parameter); - - if (!E) { - RasterizerScene::InstanceBase::InstanceShaderParameter isp; - isp.index = -1; - isp.info = PropertyInfo(); - isp.value = p_value; - instance->instance_shader_parameters[p_parameter] = isp; - } else { - E->get().value = p_value; - if (E->get().index >= 0 && instance->instance_allocated_shader_parameters) { - //update directly - RSG::storage->global_variables_instance_update(p_instance, E->get().index, p_value); - } - } -} - -Variant RenderingServerScene::instance_geometry_get_shader_parameter(RID p_instance, const StringName &p_parameter) const { - const Instance *instance = const_cast<RenderingServerScene *>(this)->instance_owner.getornull(p_instance); - ERR_FAIL_COND_V(!instance, Variant()); - - if (instance->instance_shader_parameters.has(p_parameter)) { - return instance->instance_shader_parameters[p_parameter].value; - } - return Variant(); -} - -Variant RenderingServerScene::instance_geometry_get_shader_parameter_default_value(RID p_instance, const StringName &p_parameter) const { - const Instance *instance = const_cast<RenderingServerScene *>(this)->instance_owner.getornull(p_instance); - ERR_FAIL_COND_V(!instance, Variant()); - - if (instance->instance_shader_parameters.has(p_parameter)) { - return instance->instance_shader_parameters[p_parameter].default_value; - } - return Variant(); -} - -void RenderingServerScene::instance_geometry_get_shader_parameter_list(RID p_instance, List<PropertyInfo> *p_parameters) const { - const Instance *instance = const_cast<RenderingServerScene *>(this)->instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - const_cast<RenderingServerScene *>(this)->update_dirty_instances(); - - Vector<StringName> names; - for (Map<StringName, RasterizerScene::InstanceBase::InstanceShaderParameter>::Element *E = instance->instance_shader_parameters.front(); E; E = E->next()) { - names.push_back(E->key()); - } - names.sort_custom<StringName::AlphCompare>(); - for (int i = 0; i < names.size(); i++) { - PropertyInfo pinfo = instance->instance_shader_parameters[names[i]].info; - p_parameters->push_back(pinfo); - } -} - -void RenderingServerScene::_update_instance(Instance *p_instance) { - p_instance->version++; - - if (p_instance->base_type == RS::INSTANCE_LIGHT) { - InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data); - - RSG::scene_render->light_instance_set_transform(light->instance, p_instance->transform); - RSG::scene_render->light_instance_set_aabb(light->instance, p_instance->transform.xform(p_instance->aabb)); - light->shadow_dirty = true; - - RS::LightBakeMode bake_mode = RSG::storage->light_get_bake_mode(p_instance->base); - if (RSG::storage->light_get_type(p_instance->base) != RS::LIGHT_DIRECTIONAL && bake_mode != light->bake_mode) { - if (p_instance->scenario && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) { - p_instance->scenario->dynamic_lights.erase(light->instance); - } - - light->bake_mode = bake_mode; - - if (p_instance->scenario && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) { - p_instance->scenario->dynamic_lights.push_back(light->instance); - } - } - - uint32_t max_sdfgi_cascade = RSG::storage->light_get_max_sdfgi_cascade(p_instance->base); - if (light->max_sdfgi_cascade != max_sdfgi_cascade) { - light->max_sdfgi_cascade = max_sdfgi_cascade; //should most likely make sdfgi dirty in scenario - } - } - - if (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE) { - InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(p_instance->base_data); - - RSG::scene_render->reflection_probe_instance_set_transform(reflection_probe->instance, p_instance->transform); - reflection_probe->reflection_dirty = true; - } - - if (p_instance->base_type == RS::INSTANCE_DECAL) { - InstanceDecalData *decal = static_cast<InstanceDecalData *>(p_instance->base_data); - - RSG::scene_render->decal_instance_set_transform(decal->instance, p_instance->transform); - } - - if (p_instance->base_type == RS::INSTANCE_GI_PROBE) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(p_instance->base_data); - - RSG::scene_render->gi_probe_instance_set_transform_to_data(gi_probe->probe_instance, p_instance->transform); - } - - if (p_instance->base_type == RS::INSTANCE_PARTICLES) { - RSG::storage->particles_set_emission_transform(p_instance->base, p_instance->transform); - } - - if (p_instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) { - //remove materials no longer used and un-own them - if (RSG::storage->particles_collision_is_heightfield(p_instance->base)) { - heightfield_particle_colliders_update_list.insert(p_instance); - } - } - - if (p_instance->aabb.has_no_surface()) { - return; - } - - if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); - //make sure lights are updated if it casts shadow - - if (geom->can_cast_shadows) { - for (List<Instance *>::Element *E = geom->lighting.front(); E; E = E->next()) { - InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data); - light->shadow_dirty = true; - } - } - - if (!p_instance->lightmap && geom->lightmap_captures.size()) { - //affected by lightmap captures, must update capture info! - _update_instance_lightmap_captures(p_instance); - } else { - if (!p_instance->lightmap_sh.empty()) { - p_instance->lightmap_sh.clear(); //don't need SH - p_instance->lightmap_target_sh.clear(); //don't need SH - } - } - } - - if (p_instance->base_type == RS::INSTANCE_LIGHTMAP) { - //if this moved, update the captured objects - InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(p_instance->base_data); - //erase dependencies, since no longer a lightmap - - for (List<InstanceLightmapData::PairInfo>::Element *E = lightmap_data->geometries.front(); E; E = E->next()) { - Instance *geom = E->get().geometry; - _instance_queue_update(geom, true, false); - } - } - - p_instance->mirror = p_instance->transform.basis.determinant() < 0.0; - - AABB new_aabb; - - new_aabb = p_instance->transform.xform(p_instance->aabb); - - p_instance->transformed_aabb = new_aabb; - - if (!p_instance->scenario) { - return; - } - - if (p_instance->octree_id == 0) { - uint32_t base_type = 1 << p_instance->base_type; - uint32_t pairable_mask = 0; - bool pairable = false; - - if (p_instance->base_type == RS::INSTANCE_LIGHT || p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE || p_instance->base_type == RS::INSTANCE_DECAL || p_instance->base_type == RS::INSTANCE_LIGHTMAP) { - pairable_mask = p_instance->visible ? RS::INSTANCE_GEOMETRY_MASK : 0; - pairable = true; - } - - if (p_instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) { - pairable_mask = p_instance->visible ? (1 << RS::INSTANCE_PARTICLES) : 0; - pairable = true; - } - - if (p_instance->base_type == RS::INSTANCE_GI_PROBE) { - //lights and geometries - pairable_mask = p_instance->visible ? RS::INSTANCE_GEOMETRY_MASK | (1 << RS::INSTANCE_LIGHT) : 0; - pairable = true; - } - - // not inside octree - p_instance->octree_id = p_instance->scenario->octree.create(p_instance, new_aabb, 0, pairable, base_type, pairable_mask); - - } else { - /* - if (new_aabb==p_instance->data.transformed_aabb) - return; - */ - - p_instance->scenario->octree.move(p_instance->octree_id, new_aabb); - } -} - -void RenderingServerScene::_update_instance_aabb(Instance *p_instance) { - AABB new_aabb; - - ERR_FAIL_COND(p_instance->base_type != RS::INSTANCE_NONE && !p_instance->base.is_valid()); - - switch (p_instance->base_type) { - case RenderingServer::INSTANCE_NONE: { - // do nothing - } break; - case RenderingServer::INSTANCE_MESH: { - if (p_instance->custom_aabb) { - new_aabb = *p_instance->custom_aabb; - } else { - new_aabb = RSG::storage->mesh_get_aabb(p_instance->base, p_instance->skeleton); - } - - } break; - - case RenderingServer::INSTANCE_MULTIMESH: { - if (p_instance->custom_aabb) { - new_aabb = *p_instance->custom_aabb; - } else { - new_aabb = RSG::storage->multimesh_get_aabb(p_instance->base); - } - - } break; - case RenderingServer::INSTANCE_IMMEDIATE: { - if (p_instance->custom_aabb) { - new_aabb = *p_instance->custom_aabb; - } else { - new_aabb = RSG::storage->immediate_get_aabb(p_instance->base); - } - - } break; - case RenderingServer::INSTANCE_PARTICLES: { - if (p_instance->custom_aabb) { - new_aabb = *p_instance->custom_aabb; - } else { - new_aabb = RSG::storage->particles_get_aabb(p_instance->base); - } - - } break; - case RenderingServer::INSTANCE_PARTICLES_COLLISION: { - new_aabb = RSG::storage->particles_collision_get_aabb(p_instance->base); - - } break; - case RenderingServer::INSTANCE_LIGHT: { - new_aabb = RSG::storage->light_get_aabb(p_instance->base); - - } break; - case RenderingServer::INSTANCE_REFLECTION_PROBE: { - new_aabb = RSG::storage->reflection_probe_get_aabb(p_instance->base); - - } break; - case RenderingServer::INSTANCE_DECAL: { - new_aabb = RSG::storage->decal_get_aabb(p_instance->base); - - } break; - case RenderingServer::INSTANCE_GI_PROBE: { - new_aabb = RSG::storage->gi_probe_get_bounds(p_instance->base); - - } break; - case RenderingServer::INSTANCE_LIGHTMAP: { - new_aabb = RSG::storage->lightmap_get_aabb(p_instance->base); - - } break; - default: { - } - } - - // <Zylann> This is why I didn't re-use Instance::aabb to implement custom AABBs - if (p_instance->extra_margin) { - new_aabb.grow_by(p_instance->extra_margin); - } - - p_instance->aabb = new_aabb; -} - -void RenderingServerScene::_update_instance_lightmap_captures(Instance *p_instance) { - bool first_set = p_instance->lightmap_sh.size() == 0; - p_instance->lightmap_sh.resize(9); //using SH - p_instance->lightmap_target_sh.resize(9); //using SH - Color *instance_sh = p_instance->lightmap_target_sh.ptrw(); - bool inside = false; - Color accum_sh[9]; - float accum_blend = 0.0; - - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); - for (List<Instance *>::Element *E = geom->lightmap_captures.front(); E; E = E->next()) { - Instance *lightmap = E->get(); - - bool interior = RSG::storage->lightmap_is_interior(lightmap->base); - - if (inside && !interior) { - continue; //we are inside, ignore exteriors - } - - Transform to_bounds = lightmap->transform.affine_inverse(); - Vector3 center = p_instance->transform.xform(p_instance->aabb.position + p_instance->aabb.size * 0.5); //use aabb center - - Vector3 lm_pos = to_bounds.xform(center); - - AABB bounds = RSG::storage->lightmap_get_aabb(lightmap->base); - if (!bounds.has_point(lm_pos)) { - continue; //not in this lightmap - } - - Color sh[9]; - RSG::storage->lightmap_tap_sh_light(lightmap->base, lm_pos, sh); - - //rotate it - Basis rot = lightmap->transform.basis.orthonormalized(); - for (int i = 0; i < 3; i++) { - float csh[9]; - for (int j = 0; j < 9; j++) { - csh[j] = sh[j][i]; - } - rot.rotate_sh(csh); - for (int j = 0; j < 9; j++) { - sh[j][i] = csh[j]; - } - } - - Vector3 inner_pos = ((lm_pos - bounds.position) / bounds.size) * 2.0 - Vector3(1.0, 1.0, 1.0); - - float blend = MAX(inner_pos.x, MAX(inner_pos.y, inner_pos.z)); - //make blend more rounded - blend = Math::lerp(inner_pos.length(), blend, blend); - blend *= blend; - blend = MAX(0.0, 1.0 - blend); - - if (interior && !inside) { - //do not blend, just replace - for (int j = 0; j < 9; j++) { - accum_sh[j] = sh[j] * blend; - } - accum_blend = blend; - inside = true; - } else { - for (int j = 0; j < 9; j++) { - accum_sh[j] += sh[j] * blend; - } - accum_blend += blend; - } - } - - if (accum_blend > 0.0) { - for (int j = 0; j < 9; j++) { - instance_sh[j] = accum_sh[j] / accum_blend; - if (first_set) { - p_instance->lightmap_sh.write[j] = instance_sh[j]; - } - } - } -} - -bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario) { - InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data); - - Transform light_transform = p_instance->transform; - light_transform.orthonormalize(); //scale does not count on lights - - bool animated_material_found = false; - - switch (RSG::storage->light_get_type(p_instance->base)) { - case RS::LIGHT_DIRECTIONAL: { - real_t max_distance = p_cam_projection.get_z_far(); - real_t shadow_max = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE); - if (shadow_max > 0 && !p_cam_orthogonal) { //its impractical (and leads to unwanted behaviors) to set max distance in orthogonal camera - max_distance = MIN(shadow_max, max_distance); - } - max_distance = MAX(max_distance, p_cam_projection.get_z_near() + 0.001); - real_t min_distance = MIN(p_cam_projection.get_z_near(), max_distance); - - RS::LightDirectionalShadowDepthRangeMode depth_range_mode = RSG::storage->light_directional_get_shadow_depth_range_mode(p_instance->base); - - real_t pancake_size = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE); - - if (depth_range_mode == RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_OPTIMIZED) { - //optimize min/max - Vector<Plane> planes = p_cam_projection.get_projection_planes(p_cam_transform); - int cull_count = p_scenario->octree.cull_convex(planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, RS::INSTANCE_GEOMETRY_MASK); - Plane base(p_cam_transform.origin, -p_cam_transform.basis.get_axis(2)); - //check distance max and min - - bool found_items = false; - real_t z_max = -1e20; - real_t z_min = 1e20; - - for (int i = 0; i < cull_count; i++) { - Instance *instance = instance_shadow_cull_result[i]; - if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) { - continue; - } - - if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) { - animated_material_found = true; - } - - real_t max, min; - instance->transformed_aabb.project_range_in_plane(base, min, max); - - if (max > z_max) { - z_max = max; - } - - if (min < z_min) { - z_min = min; - } - - found_items = true; - } - - if (found_items) { - min_distance = MAX(min_distance, z_min); - max_distance = MIN(max_distance, z_max); - } - } - - real_t range = max_distance - min_distance; - - int splits = 0; - switch (RSG::storage->light_directional_get_shadow_mode(p_instance->base)) { - case RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: - splits = 1; - break; - case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: - splits = 2; - break; - case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: - splits = 4; - break; - } - - real_t distances[5]; - - distances[0] = min_distance; - for (int i = 0; i < splits; i++) { - distances[i + 1] = min_distance + RSG::storage->light_get_param(p_instance->base, RS::LightParam(RS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET + i)) * range; - }; - - distances[splits] = max_distance; - - real_t texture_size = RSG::scene_render->get_directional_light_shadow_size(light->instance); - - bool overlap = RSG::storage->light_directional_get_blend_splits(p_instance->base); - - real_t first_radius = 0.0; - - real_t min_distance_bias_scale = pancake_size > 0 ? distances[1] / 10.0 : 0; - - for (int i = 0; i < splits; i++) { - RENDER_TIMESTAMP("Culling Directional Light split" + itos(i)); - - // setup a camera matrix for that range! - CameraMatrix camera_matrix; - - real_t aspect = p_cam_projection.get_aspect(); - - if (p_cam_orthogonal) { - Vector2 vp_he = p_cam_projection.get_viewport_half_extents(); - - camera_matrix.set_orthogonal(vp_he.y * 2.0, aspect, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false); - } else { - real_t fov = p_cam_projection.get_fov(); //this is actually yfov, because set aspect tries to keep it - camera_matrix.set_perspective(fov, aspect, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], true); - } - - //obtain the frustum endpoints - - Vector3 endpoints[8]; // frustum plane endpoints - bool res = camera_matrix.get_endpoints(p_cam_transform, endpoints); - ERR_CONTINUE(!res); - - // obtain the light frustm ranges (given endpoints) - - Transform transform = light_transform; //discard scale and stabilize light - - Vector3 x_vec = transform.basis.get_axis(Vector3::AXIS_X).normalized(); - Vector3 y_vec = transform.basis.get_axis(Vector3::AXIS_Y).normalized(); - Vector3 z_vec = transform.basis.get_axis(Vector3::AXIS_Z).normalized(); - //z_vec points agsint the camera, like in default opengl - - real_t x_min = 0.f, x_max = 0.f; - real_t y_min = 0.f, y_max = 0.f; - real_t z_min = 0.f, z_max = 0.f; - - // FIXME: z_max_cam is defined, computed, but not used below when setting up - // ortho_camera. Commented out for now to fix warnings but should be investigated. - real_t x_min_cam = 0.f, x_max_cam = 0.f; - real_t y_min_cam = 0.f, y_max_cam = 0.f; - real_t z_min_cam = 0.f; - //real_t z_max_cam = 0.f; - - real_t bias_scale = 1.0; - real_t aspect_bias_scale = 1.0; - - //used for culling - - for (int j = 0; j < 8; j++) { - real_t d_x = x_vec.dot(endpoints[j]); - real_t d_y = y_vec.dot(endpoints[j]); - real_t d_z = z_vec.dot(endpoints[j]); - - if (j == 0 || d_x < x_min) { - x_min = d_x; - } - if (j == 0 || d_x > x_max) { - x_max = d_x; - } - - if (j == 0 || d_y < y_min) { - y_min = d_y; - } - if (j == 0 || d_y > y_max) { - y_max = d_y; - } - - if (j == 0 || d_z < z_min) { - z_min = d_z; - } - if (j == 0 || d_z > z_max) { - z_max = d_z; - } - } - - real_t radius = 0; - real_t soft_shadow_expand = 0; - Vector3 center; - - { - //camera viewport stuff - - for (int j = 0; j < 8; j++) { - center += endpoints[j]; - } - center /= 8.0; - - //center=x_vec*(x_max-x_min)*0.5 + y_vec*(y_max-y_min)*0.5 + z_vec*(z_max-z_min)*0.5; - - for (int j = 0; j < 8; j++) { - real_t d = center.distance_to(endpoints[j]); - if (d > radius) { - radius = d; - } - } - - radius *= texture_size / (texture_size - 2.0); //add a texel by each side - - if (i == 0) { - first_radius = radius; - } else { - bias_scale = radius / first_radius; - } - - z_min_cam = z_vec.dot(center) - radius; - - { - float soft_shadow_angle = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SIZE); - - if (soft_shadow_angle > 0.0 && pancake_size > 0.0) { - float z_range = (z_vec.dot(center) + radius + pancake_size) - z_min_cam; - soft_shadow_expand = Math::tan(Math::deg2rad(soft_shadow_angle)) * z_range; - - x_max += soft_shadow_expand; - y_max += soft_shadow_expand; - - x_min -= soft_shadow_expand; - y_min -= soft_shadow_expand; - } - } - - x_max_cam = x_vec.dot(center) + radius + soft_shadow_expand; - x_min_cam = x_vec.dot(center) - radius - soft_shadow_expand; - y_max_cam = y_vec.dot(center) + radius + soft_shadow_expand; - y_min_cam = y_vec.dot(center) - radius - soft_shadow_expand; - - if (depth_range_mode == RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE) { - //this trick here is what stabilizes the shadow (make potential jaggies to not move) - //at the cost of some wasted resolution. Still the quality increase is very well worth it - - real_t unit = radius * 2.0 / texture_size; - - x_max_cam = Math::stepify(x_max_cam, unit); - x_min_cam = Math::stepify(x_min_cam, unit); - y_max_cam = Math::stepify(y_max_cam, unit); - y_min_cam = Math::stepify(y_min_cam, unit); - } - } - - //now that we now all ranges, we can proceed to make the light frustum planes, for culling octree - - Vector<Plane> light_frustum_planes; - light_frustum_planes.resize(6); - - //right/left - light_frustum_planes.write[0] = Plane(x_vec, x_max); - light_frustum_planes.write[1] = Plane(-x_vec, -x_min); - //top/bottom - light_frustum_planes.write[2] = Plane(y_vec, y_max); - light_frustum_planes.write[3] = Plane(-y_vec, -y_min); - //near/far - light_frustum_planes.write[4] = Plane(z_vec, z_max + 1e6); - light_frustum_planes.write[5] = Plane(-z_vec, -z_min); // z_min is ok, since casters further than far-light plane are not needed - - int cull_count = p_scenario->octree.cull_convex(light_frustum_planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, RS::INSTANCE_GEOMETRY_MASK); - - // a pre pass will need to be needed to determine the actual z-near to be used - - Plane near_plane(light_transform.origin, -light_transform.basis.get_axis(2)); - - real_t cull_max = 0; - for (int j = 0; j < cull_count; j++) { - real_t min, max; - Instance *instance = instance_shadow_cull_result[j]; - if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) { - cull_count--; - SWAP(instance_shadow_cull_result[j], instance_shadow_cull_result[cull_count]); - j--; - continue; - } - - instance->transformed_aabb.project_range_in_plane(Plane(z_vec, 0), min, max); - instance->depth = near_plane.distance_to(instance->transform.origin); - instance->depth_layer = 0; - if (j == 0 || max > cull_max) { - cull_max = max; - } - } - - if (cull_max > z_max) { - z_max = cull_max; - } - - if (pancake_size > 0) { - z_max = z_vec.dot(center) + radius + pancake_size; - } - - if (aspect != 1.0) { - // if the aspect is different, then the radius will become larger. - // if this happens, then bias needs to be adjusted too, as depth will increase - // to do this, compare the depth of one that would have resulted from a square frustum - - CameraMatrix camera_matrix_square; - if (p_cam_orthogonal) { - Vector2 vp_he = camera_matrix.get_viewport_half_extents(); - if (p_cam_vaspect) { - camera_matrix_square.set_orthogonal(vp_he.x * 2.0, 1.0, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], true); - } else { - camera_matrix_square.set_orthogonal(vp_he.y * 2.0, 1.0, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false); - } - } else { - Vector2 vp_he = camera_matrix.get_viewport_half_extents(); - if (p_cam_vaspect) { - camera_matrix_square.set_frustum(vp_he.x * 2.0, 1.0, Vector2(), distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], true); - } else { - camera_matrix_square.set_frustum(vp_he.y * 2.0, 1.0, Vector2(), distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false); - } - } - - Vector3 endpoints_square[8]; // frustum plane endpoints - res = camera_matrix_square.get_endpoints(p_cam_transform, endpoints_square); - ERR_CONTINUE(!res); - Vector3 center_square; - real_t z_max_square = 0; - - for (int j = 0; j < 8; j++) { - center_square += endpoints_square[j]; - - real_t d_z = z_vec.dot(endpoints_square[j]); - - if (j == 0 || d_z > z_max_square) { - z_max_square = d_z; - } - } - - if (cull_max > z_max_square) { - z_max_square = cull_max; - } - - center_square /= 8.0; - - real_t radius_square = 0; - - for (int j = 0; j < 8; j++) { - real_t d = center_square.distance_to(endpoints_square[j]); - if (d > radius_square) { - radius_square = d; - } - } - - radius_square *= texture_size / (texture_size - 2.0); //add a texel by each side - - if (pancake_size > 0) { - z_max_square = z_vec.dot(center_square) + radius_square + pancake_size; - } - - real_t z_min_cam_square = z_vec.dot(center_square) - radius_square; - - aspect_bias_scale = (z_max - z_min_cam) / (z_max_square - z_min_cam_square); - - // this is not entirely perfect, because the cull-adjusted z-max may be different - // but at least it's warranted that it results in a greater bias, so no acne should be present either way. - // pancaking also helps with this. - } - - { - CameraMatrix ortho_camera; - real_t half_x = (x_max_cam - x_min_cam) * 0.5; - real_t half_y = (y_max_cam - y_min_cam) * 0.5; - - ortho_camera.set_orthogonal(-half_x, half_x, -half_y, half_y, 0, (z_max - z_min_cam)); - - Vector2 uv_scale(1.0 / (x_max_cam - x_min_cam), 1.0 / (y_max_cam - y_min_cam)); - - Transform ortho_transform; - ortho_transform.basis = transform.basis; - ortho_transform.origin = x_vec * (x_min_cam + half_x) + y_vec * (y_min_cam + half_y) + z_vec * z_max; - - { - Vector3 max_in_view = p_cam_transform.affine_inverse().xform(z_vec * cull_max); - Vector3 dir_in_view = p_cam_transform.xform_inv(z_vec).normalized(); - cull_max = dir_in_view.dot(max_in_view); - } - - RSG::scene_render->light_instance_set_shadow_transform(light->instance, ortho_camera, ortho_transform, z_max - z_min_cam, distances[i + 1], i, radius * 2.0 / texture_size, bias_scale * aspect_bias_scale * min_distance_bias_scale, z_max, uv_scale); - } - - RSG::scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count); - } - - } break; - case RS::LIGHT_OMNI: { - RS::LightOmniShadowMode shadow_mode = RSG::storage->light_omni_get_shadow_mode(p_instance->base); - - if (shadow_mode == RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID || !RSG::scene_render->light_instances_can_render_shadow_cube()) { - for (int i = 0; i < 2; i++) { - //using this one ensures that raster deferred will have it - RENDER_TIMESTAMP("Culling Shadow Paraboloid" + itos(i)); - - real_t radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE); - - real_t z = i == 0 ? -1 : 1; - Vector<Plane> planes; - planes.resize(6); - planes.write[0] = light_transform.xform(Plane(Vector3(0, 0, z), radius)); - planes.write[1] = light_transform.xform(Plane(Vector3(1, 0, z).normalized(), radius)); - planes.write[2] = light_transform.xform(Plane(Vector3(-1, 0, z).normalized(), radius)); - planes.write[3] = light_transform.xform(Plane(Vector3(0, 1, z).normalized(), radius)); - planes.write[4] = light_transform.xform(Plane(Vector3(0, -1, z).normalized(), radius)); - planes.write[5] = light_transform.xform(Plane(Vector3(0, 0, -z), 0)); - - int cull_count = p_scenario->octree.cull_convex(planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, RS::INSTANCE_GEOMETRY_MASK); - Plane near_plane(light_transform.origin, light_transform.basis.get_axis(2) * z); - - for (int j = 0; j < cull_count; j++) { - Instance *instance = instance_shadow_cull_result[j]; - if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) { - cull_count--; - SWAP(instance_shadow_cull_result[j], instance_shadow_cull_result[cull_count]); - j--; - } else { - if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) { - animated_material_found = true; - } - - instance->depth = near_plane.distance_to(instance->transform.origin); - instance->depth_layer = 0; - } - } - - RSG::scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, i, 0); - RSG::scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count); - } - } else { //shadow cube - - real_t radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE); - CameraMatrix cm; - cm.set_perspective(90, 1, 0.01, radius); - - for (int i = 0; i < 6; i++) { - RENDER_TIMESTAMP("Culling Shadow Cube side" + itos(i)); - //using this one ensures that raster deferred will have it - - static const Vector3 view_normals[6] = { - Vector3(+1, 0, 0), - Vector3(-1, 0, 0), - Vector3(0, -1, 0), - Vector3(0, +1, 0), - Vector3(0, 0, +1), - Vector3(0, 0, -1) - }; - static const Vector3 view_up[6] = { - Vector3(0, -1, 0), - Vector3(0, -1, 0), - Vector3(0, 0, -1), - Vector3(0, 0, +1), - Vector3(0, -1, 0), - Vector3(0, -1, 0) - }; - - Transform xform = light_transform * Transform().looking_at(view_normals[i], view_up[i]); - - Vector<Plane> planes = cm.get_projection_planes(xform); - - int cull_count = p_scenario->octree.cull_convex(planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, RS::INSTANCE_GEOMETRY_MASK); - - Plane near_plane(xform.origin, -xform.basis.get_axis(2)); - for (int j = 0; j < cull_count; j++) { - Instance *instance = instance_shadow_cull_result[j]; - if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) { - cull_count--; - SWAP(instance_shadow_cull_result[j], instance_shadow_cull_result[cull_count]); - j--; - } else { - if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) { - animated_material_found = true; - } - instance->depth = near_plane.distance_to(instance->transform.origin); - instance->depth_layer = 0; - } - } - - RSG::scene_render->light_instance_set_shadow_transform(light->instance, cm, xform, radius, 0, i, 0); - RSG::scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count); - } - - //restore the regular DP matrix - RSG::scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, 0, 0); - } - - } break; - case RS::LIGHT_SPOT: { - RENDER_TIMESTAMP("Culling Spot Light"); - - real_t radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE); - real_t angle = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SPOT_ANGLE); - - CameraMatrix cm; - cm.set_perspective(angle * 2.0, 1.0, 0.01, radius); - - Vector<Plane> planes = cm.get_projection_planes(light_transform); - int cull_count = p_scenario->octree.cull_convex(planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, RS::INSTANCE_GEOMETRY_MASK); - - Plane near_plane(light_transform.origin, -light_transform.basis.get_axis(2)); - for (int j = 0; j < cull_count; j++) { - Instance *instance = instance_shadow_cull_result[j]; - if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) { - cull_count--; - SWAP(instance_shadow_cull_result[j], instance_shadow_cull_result[cull_count]); - j--; - } else { - if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) { - animated_material_found = true; - } - instance->depth = near_plane.distance_to(instance->transform.origin); - instance->depth_layer = 0; - } - } - - RSG::scene_render->light_instance_set_shadow_transform(light->instance, cm, light_transform, radius, 0, 0, 0); - RSG::scene_render->render_shadow(light->instance, p_shadow_atlas, 0, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count); - - } break; - } - - return animated_material_found; -} - -void RenderingServerScene::render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas) { -// render to mono camera -#ifndef _3D_DISABLED - - Camera *camera = camera_owner.getornull(p_camera); - ERR_FAIL_COND(!camera); - - /* STEP 1 - SETUP CAMERA */ - CameraMatrix camera_matrix; - bool ortho = false; - - switch (camera->type) { - case Camera::ORTHOGONAL: { - camera_matrix.set_orthogonal( - camera->size, - p_viewport_size.width / (float)p_viewport_size.height, - camera->znear, - camera->zfar, - camera->vaspect); - ortho = true; - } break; - case Camera::PERSPECTIVE: { - camera_matrix.set_perspective( - camera->fov, - p_viewport_size.width / (float)p_viewport_size.height, - camera->znear, - camera->zfar, - camera->vaspect); - ortho = false; - - } break; - case Camera::FRUSTUM: { - camera_matrix.set_frustum( - camera->size, - p_viewport_size.width / (float)p_viewport_size.height, - camera->offset, - camera->znear, - camera->zfar, - camera->vaspect); - ortho = false; - } break; - } - - RID environment = _render_get_environment(p_camera, p_scenario); - - _prepare_scene(camera->transform, camera_matrix, ortho, camera->vaspect, p_render_buffers, environment, camera->visible_layers, p_scenario, p_shadow_atlas, RID()); - _render_scene(p_render_buffers, camera->transform, camera_matrix, ortho, environment, camera->effects, p_scenario, p_shadow_atlas, RID(), -1); -#endif -} - -void RenderingServerScene::render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas) { - // render for AR/VR interface - - Camera *camera = camera_owner.getornull(p_camera); - ERR_FAIL_COND(!camera); - - /* SETUP CAMERA, we are ignoring type and FOV here */ - float aspect = p_viewport_size.width / (float)p_viewport_size.height; - CameraMatrix camera_matrix = p_interface->get_projection_for_eye(p_eye, aspect, camera->znear, camera->zfar); - - // We also ignore our camera position, it will have been positioned with a slightly old tracking position. - // Instead we take our origin point and have our ar/vr interface add fresh tracking data! Whoohoo! - Transform world_origin = XRServer::get_singleton()->get_world_origin(); - Transform cam_transform = p_interface->get_transform_for_eye(p_eye, world_origin); - - RID environment = _render_get_environment(p_camera, p_scenario); - - // For stereo render we only prepare for our left eye and then reuse the outcome for our right eye - if (p_eye == XRInterface::EYE_LEFT) { - // Center our transform, we assume basis is equal. - Transform mono_transform = cam_transform; - Transform right_transform = p_interface->get_transform_for_eye(XRInterface::EYE_RIGHT, world_origin); - mono_transform.origin += right_transform.origin; - mono_transform.origin *= 0.5; - - // We need to combine our projection frustums for culling. - // Ideally we should use our clipping planes for this and combine them, - // however our shadow map logic uses our projection matrix. - // Note: as our left and right frustums should be mirrored, we don't need our right projection matrix. - - // - get some base values we need - float eye_dist = (mono_transform.origin - cam_transform.origin).length(); - float z_near = camera_matrix.get_z_near(); // get our near plane - float z_far = camera_matrix.get_z_far(); // get our far plane - float width = (2.0 * z_near) / camera_matrix.matrix[0][0]; - float x_shift = width * camera_matrix.matrix[2][0]; - float height = (2.0 * z_near) / camera_matrix.matrix[1][1]; - float y_shift = height * camera_matrix.matrix[2][1]; - - // printf("Eye_dist = %f, Near = %f, Far = %f, Width = %f, Shift = %f\n", eye_dist, z_near, z_far, width, x_shift); - - // - calculate our near plane size (horizontal only, right_near is mirrored) - float left_near = -eye_dist - ((width - x_shift) * 0.5); - - // - calculate our far plane size (horizontal only, right_far is mirrored) - float left_far = -eye_dist - (z_far * (width - x_shift) * 0.5 / z_near); - float left_far_right_eye = eye_dist - (z_far * (width + x_shift) * 0.5 / z_near); - if (left_far > left_far_right_eye) { - // on displays smaller then double our iod, the right eye far frustrum can overtake the left eyes. - left_far = left_far_right_eye; - } - - // - figure out required z-shift - float slope = (left_far - left_near) / (z_far - z_near); - float z_shift = (left_near / slope) - z_near; - - // - figure out new vertical near plane size (this will be slightly oversized thanks to our z-shift) - float top_near = (height - y_shift) * 0.5; - top_near += (top_near / z_near) * z_shift; - float bottom_near = -(height + y_shift) * 0.5; - bottom_near += (bottom_near / z_near) * z_shift; - - // printf("Left_near = %f, Left_far = %f, Top_near = %f, Bottom_near = %f, Z_shift = %f\n", left_near, left_far, top_near, bottom_near, z_shift); - - // - generate our frustum - CameraMatrix combined_matrix; - combined_matrix.set_frustum(left_near, -left_near, bottom_near, top_near, z_near + z_shift, z_far + z_shift); - - // and finally move our camera back - Transform apply_z_shift; - apply_z_shift.origin = Vector3(0.0, 0.0, z_shift); // z negative is forward so this moves it backwards - mono_transform *= apply_z_shift; - - // now prepare our scene with our adjusted transform projection matrix - _prepare_scene(mono_transform, combined_matrix, false, false, p_render_buffers, environment, camera->visible_layers, p_scenario, p_shadow_atlas, RID()); - } else if (p_eye == XRInterface::EYE_MONO) { - // For mono render, prepare as per usual - _prepare_scene(cam_transform, camera_matrix, false, false, p_render_buffers, environment, camera->visible_layers, p_scenario, p_shadow_atlas, RID()); - } - - // And render our scene... - _render_scene(p_render_buffers, cam_transform, camera_matrix, false, environment, camera->effects, p_scenario, p_shadow_atlas, RID(), -1); -}; - -void RenderingServerScene::_prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_render_buffers, RID p_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, bool p_using_shadows) { - // Note, in stereo rendering: - // - p_cam_transform will be a transform in the middle of our two eyes - // - p_cam_projection is a wider frustrum that encompasses both eyes - - Scenario *scenario = scenario_owner.getornull(p_scenario); - - render_pass++; - uint32_t camera_layer_mask = p_visible_layers; - - RSG::scene_render->set_scene_pass(render_pass); - - if (p_render_buffers.is_valid()) { - RSG::scene_render->sdfgi_update(p_render_buffers, p_environment, p_cam_transform.origin); //update conditions for SDFGI (whether its used or not) - } - - RENDER_TIMESTAMP("Frustum Culling"); - - //rasterizer->set_camera(camera->transform, camera_matrix,ortho); - - Vector<Plane> planes = p_cam_projection.get_projection_planes(p_cam_transform); - - Plane near_plane(p_cam_transform.origin, -p_cam_transform.basis.get_axis(2).normalized()); - float z_far = p_cam_projection.get_z_far(); - - /* STEP 2 - CULL */ - instance_cull_count = scenario->octree.cull_convex(planes, instance_cull_result, MAX_INSTANCE_CULL); - light_cull_count = 0; - - reflection_probe_cull_count = 0; - decal_cull_count = 0; - gi_probe_cull_count = 0; - lightmap_cull_count = 0; - - //light_samplers_culled=0; - - /* - print_line("OT: "+rtos( (OS::get_singleton()->get_ticks_usec()-t)/1000.0)); - print_line("OTO: "+itos(p_scenario->octree.get_octant_count())); - print_line("OTE: "+itos(p_scenario->octree.get_elem_count())); - print_line("OTP: "+itos(p_scenario->octree.get_pair_count())); - */ - - /* STEP 3 - PROCESS PORTALS, VALIDATE ROOMS */ - //removed, will replace with culling - - /* STEP 4 - REMOVE FURTHER CULLED OBJECTS, ADD LIGHTS */ - uint64_t frame_number = RSG::rasterizer->get_frame_number(); - float lightmap_probe_update_speed = RSG::storage->lightmap_get_probe_capture_update_speed() * RSG::rasterizer->get_frame_delta_time(); - - for (int i = 0; i < instance_cull_count; i++) { - Instance *ins = instance_cull_result[i]; - - bool keep = false; - - if ((camera_layer_mask & ins->layer_mask) == 0) { - //failure - } else if (ins->base_type == RS::INSTANCE_LIGHT && ins->visible) { - if (light_cull_count < MAX_LIGHTS_CULLED) { - InstanceLightData *light = static_cast<InstanceLightData *>(ins->base_data); - - if (!light->geometries.empty()) { - //do not add this light if no geometry is affected by it.. - light_cull_result[light_cull_count] = ins; - light_instance_cull_result[light_cull_count] = light->instance; - if (p_shadow_atlas.is_valid() && RSG::storage->light_has_shadow(ins->base)) { - RSG::scene_render->light_instance_mark_visible(light->instance); //mark it visible for shadow allocation later - } - - light_cull_count++; - } - } - } else if (ins->base_type == RS::INSTANCE_REFLECTION_PROBE && ins->visible) { - if (reflection_probe_cull_count < MAX_REFLECTION_PROBES_CULLED) { - InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(ins->base_data); - - if (p_reflection_probe != reflection_probe->instance) { - //avoid entering The Matrix - - if (!reflection_probe->geometries.empty()) { - //do not add this light if no geometry is affected by it.. - - if (reflection_probe->reflection_dirty || RSG::scene_render->reflection_probe_instance_needs_redraw(reflection_probe->instance)) { - if (!reflection_probe->update_list.in_list()) { - reflection_probe->render_step = 0; - reflection_probe_render_list.add_last(&reflection_probe->update_list); - } - - reflection_probe->reflection_dirty = false; - } - - if (RSG::scene_render->reflection_probe_instance_has_reflection(reflection_probe->instance)) { - reflection_probe_instance_cull_result[reflection_probe_cull_count] = reflection_probe->instance; - reflection_probe_cull_count++; - } - } - } - } - } else if (ins->base_type == RS::INSTANCE_DECAL && ins->visible) { - if (decal_cull_count < MAX_DECALS_CULLED) { - InstanceDecalData *decal = static_cast<InstanceDecalData *>(ins->base_data); - - if (!decal->geometries.empty()) { - //do not add this decal if no geometry is affected by it.. - decal_instance_cull_result[decal_cull_count] = decal->instance; - decal_cull_count++; - } - } - - } else if (ins->base_type == RS::INSTANCE_GI_PROBE && ins->visible) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(ins->base_data); - if (!gi_probe->update_element.in_list()) { - gi_probe_update_list.add(&gi_probe->update_element); - } - - if (gi_probe_cull_count < MAX_GI_PROBES_CULLED) { - gi_probe_instance_cull_result[gi_probe_cull_count] = gi_probe->probe_instance; - gi_probe_cull_count++; - } - } else if (ins->base_type == RS::INSTANCE_LIGHTMAP && ins->visible) { - if (lightmap_cull_count < MAX_LIGHTMAPS_CULLED) { - lightmap_cull_result[lightmap_cull_count] = ins; - lightmap_cull_count++; - } - - } else if (((1 << ins->base_type) & RS::INSTANCE_GEOMETRY_MASK) && ins->visible && ins->cast_shadows != RS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) { - keep = true; - - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(ins->base_data); - - if (ins->redraw_if_visible) { - RenderingServerRaster::redraw_request(); - } - - if (ins->base_type == RS::INSTANCE_PARTICLES) { - //particles visible? process them - if (RSG::storage->particles_is_inactive(ins->base)) { - //but if nothing is going on, don't do it. - keep = false; - } else { - RSG::storage->particles_request_process(ins->base); - RSG::storage->particles_set_view_axis(ins->base, -p_cam_transform.basis.get_axis(2).normalized()); - //particles visible? request redraw - RenderingServerRaster::redraw_request(); - } - } - - if (geom->lighting_dirty) { - int l = 0; - //only called when lights AABB enter/exit this geometry - ins->light_instances.resize(geom->lighting.size()); - - for (List<Instance *>::Element *E = geom->lighting.front(); E; E = E->next()) { - InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data); - - ins->light_instances.write[l++] = light->instance; - } - - geom->lighting_dirty = false; - } - - if (geom->reflection_dirty) { - int l = 0; - //only called when reflection probe AABB enter/exit this geometry - ins->reflection_probe_instances.resize(geom->reflection_probes.size()); - - for (List<Instance *>::Element *E = geom->reflection_probes.front(); E; E = E->next()) { - InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(E->get()->base_data); - - ins->reflection_probe_instances.write[l++] = reflection_probe->instance; - } - - geom->reflection_dirty = false; - } - - if (geom->gi_probes_dirty) { - int l = 0; - //only called when reflection probe AABB enter/exit this geometry - ins->gi_probe_instances.resize(geom->gi_probes.size()); - - for (List<Instance *>::Element *E = geom->gi_probes.front(); E; E = E->next()) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(E->get()->base_data); - - ins->gi_probe_instances.write[l++] = gi_probe->probe_instance; - } - - geom->gi_probes_dirty = false; - } - - if (ins->last_frame_pass != frame_number && !ins->lightmap_target_sh.empty() && !ins->lightmap_sh.empty()) { - Color *sh = ins->lightmap_sh.ptrw(); - const Color *target_sh = ins->lightmap_target_sh.ptr(); - for (uint32_t j = 0; j < 9; j++) { - sh[j] = sh[j].lerp(target_sh[j], MIN(1.0, lightmap_probe_update_speed)); - } - } - - ins->depth = near_plane.distance_to(ins->transform.origin); - ins->depth_layer = CLAMP(int(ins->depth * 16 / z_far), 0, 15); - } - - if (!keep) { - // remove, no reason to keep - instance_cull_count--; - SWAP(instance_cull_result[i], instance_cull_result[instance_cull_count]); - i--; - ins->last_render_pass = 0; // make invalid - } else { - ins->last_render_pass = render_pass; - } - ins->last_frame_pass = frame_number; - } - - /* STEP 5 - PROCESS LIGHTS */ - - RID *directional_light_ptr = &light_instance_cull_result[light_cull_count]; - directional_light_count = 0; - - // directional lights - { - Instance **lights_with_shadow = (Instance **)alloca(sizeof(Instance *) * scenario->directional_lights.size()); - int directional_shadow_count = 0; - - for (List<Instance *>::Element *E = scenario->directional_lights.front(); E; E = E->next()) { - if (light_cull_count + directional_light_count >= MAX_LIGHTS_CULLED) { - break; - } - - if (!E->get()->visible) { - continue; - } - - InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data); - - //check shadow.. - - if (light) { - if (p_using_shadows && p_shadow_atlas.is_valid() && RSG::storage->light_has_shadow(E->get()->base)) { - lights_with_shadow[directional_shadow_count++] = E->get(); - } - //add to list - directional_light_ptr[directional_light_count++] = light->instance; - } - } - - RSG::scene_render->set_directional_shadow_count(directional_shadow_count); - - for (int i = 0; i < directional_shadow_count; i++) { - RENDER_TIMESTAMP(">Rendering Directional Light " + itos(i)); - - _light_instance_update_shadow(lights_with_shadow[i], p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect, p_shadow_atlas, scenario); - - RENDER_TIMESTAMP("<Rendering Directional Light " + itos(i)); - } - } - - if (p_using_shadows) { //setup shadow maps - - //SortArray<Instance*,_InstanceLightsort> sorter; - //sorter.sort(light_cull_result,light_cull_count); - for (int i = 0; i < light_cull_count; i++) { - Instance *ins = light_cull_result[i]; - - if (!p_shadow_atlas.is_valid() || !RSG::storage->light_has_shadow(ins->base)) { - continue; - } - - InstanceLightData *light = static_cast<InstanceLightData *>(ins->base_data); - - float coverage = 0.f; - - { //compute coverage - - Transform cam_xf = p_cam_transform; - float zn = p_cam_projection.get_z_near(); - Plane p(cam_xf.origin + cam_xf.basis.get_axis(2) * -zn, -cam_xf.basis.get_axis(2)); //camera near plane - - // near plane half width and height - Vector2 vp_half_extents = p_cam_projection.get_viewport_half_extents(); - - switch (RSG::storage->light_get_type(ins->base)) { - case RS::LIGHT_OMNI: { - float radius = RSG::storage->light_get_param(ins->base, RS::LIGHT_PARAM_RANGE); - - //get two points parallel to near plane - Vector3 points[2] = { - ins->transform.origin, - ins->transform.origin + cam_xf.basis.get_axis(0) * radius - }; - - if (!p_cam_orthogonal) { - //if using perspetive, map them to near plane - for (int j = 0; j < 2; j++) { - if (p.distance_to(points[j]) < 0) { - points[j].z = -zn; //small hack to keep size constant when hitting the screen - } - - p.intersects_segment(cam_xf.origin, points[j], &points[j]); //map to plane - } - } - - float screen_diameter = points[0].distance_to(points[1]) * 2; - coverage = screen_diameter / (vp_half_extents.x + vp_half_extents.y); - } break; - case RS::LIGHT_SPOT: { - float radius = RSG::storage->light_get_param(ins->base, RS::LIGHT_PARAM_RANGE); - float angle = RSG::storage->light_get_param(ins->base, RS::LIGHT_PARAM_SPOT_ANGLE); - - float w = radius * Math::sin(Math::deg2rad(angle)); - float d = radius * Math::cos(Math::deg2rad(angle)); - - Vector3 base = ins->transform.origin - ins->transform.basis.get_axis(2).normalized() * d; - - Vector3 points[2] = { - base, - base + cam_xf.basis.get_axis(0) * w - }; - - if (!p_cam_orthogonal) { - //if using perspetive, map them to near plane - for (int j = 0; j < 2; j++) { - if (p.distance_to(points[j]) < 0) { - points[j].z = -zn; //small hack to keep size constant when hitting the screen - } - - p.intersects_segment(cam_xf.origin, points[j], &points[j]); //map to plane - } - } - - float screen_diameter = points[0].distance_to(points[1]) * 2; - coverage = screen_diameter / (vp_half_extents.x + vp_half_extents.y); - - } break; - default: { - ERR_PRINT("Invalid Light Type"); - } - } - } - - if (light->shadow_dirty) { - light->last_version++; - light->shadow_dirty = false; - } - - bool redraw = RSG::scene_render->shadow_atlas_update_light(p_shadow_atlas, light->instance, coverage, light->last_version); - - if (redraw) { - //must redraw! - RENDER_TIMESTAMP(">Rendering Light " + itos(i)); - light->shadow_dirty = _light_instance_update_shadow(ins, p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect, p_shadow_atlas, scenario); - RENDER_TIMESTAMP("<Rendering Light " + itos(i)); - } - } - } - - /* UPDATE SDFGI */ - - if (p_render_buffers.is_valid()) { - uint32_t cascade_index[8]; - uint32_t cascade_sizes[8]; - const RID *cascade_ptrs[8]; - uint32_t cascade_count = 0; - uint32_t sdfgi_light_cull_count = 0; - - uint32_t prev_cascade = 0xFFFFFFFF; - for (int i = 0; i < RSG::scene_render->sdfgi_get_pending_region_count(p_render_buffers); i++) { - AABB region = RSG::scene_render->sdfgi_get_pending_region_bounds(p_render_buffers, i); - uint32_t region_cascade = RSG::scene_render->sdfgi_get_pending_region_cascade(p_render_buffers, i); - - if (region_cascade != prev_cascade) { - cascade_sizes[cascade_count] = 0; - cascade_index[cascade_count] = region_cascade; - cascade_ptrs[cascade_count] = &sdfgi_light_cull_result[sdfgi_light_cull_count]; - cascade_count++; - sdfgi_light_cull_pass++; - prev_cascade = region_cascade; - } - uint32_t sdfgi_cull_count = scenario->octree.cull_aabb(region, instance_shadow_cull_result, MAX_INSTANCE_CULL); - - for (uint32_t j = 0; j < sdfgi_cull_count; j++) { - Instance *ins = instance_shadow_cull_result[j]; - - bool keep = false; - - if (ins->base_type == RS::INSTANCE_LIGHT && ins->visible) { - InstanceLightData *instance_light = (InstanceLightData *)ins->base_data; - if (instance_light->bake_mode != RS::LIGHT_BAKE_STATIC || region_cascade > instance_light->max_sdfgi_cascade) { - continue; - } - - if (sdfgi_light_cull_pass != instance_light->sdfgi_cascade_light_pass && sdfgi_light_cull_count < MAX_LIGHTS_CULLED) { - instance_light->sdfgi_cascade_light_pass = sdfgi_light_cull_pass; - sdfgi_light_cull_result[sdfgi_light_cull_count++] = instance_light->instance; - cascade_sizes[cascade_count - 1]++; - } - } else if ((1 << ins->base_type) & RS::INSTANCE_GEOMETRY_MASK) { - if (ins->baked_light) { - keep = true; - } - } - - if (!keep) { - // remove, no reason to keep - sdfgi_cull_count--; - SWAP(instance_shadow_cull_result[j], instance_shadow_cull_result[sdfgi_cull_count]); - j--; - } - } - - RSG::scene_render->render_sdfgi(p_render_buffers, i, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, sdfgi_cull_count); - //have to save updated cascades, then update static lights. - } - - if (sdfgi_light_cull_count) { - RSG::scene_render->render_sdfgi_static_lights(p_render_buffers, cascade_count, cascade_index, cascade_ptrs, cascade_sizes); - } - - RSG::scene_render->sdfgi_update_probes(p_render_buffers, p_environment, directional_light_ptr, directional_light_count, scenario->dynamic_lights.ptr(), scenario->dynamic_lights.size()); - } -} - -RID RenderingServerScene::_render_get_environment(RID p_camera, RID p_scenario) { - Camera *camera = camera_owner.getornull(p_camera); - if (camera && RSG::scene_render->is_environment(camera->env)) { - return camera->env; - } - - Scenario *scenario = scenario_owner.getornull(p_scenario); - if (!scenario) { - return RID(); - } - if (RSG::scene_render->is_environment(scenario->environment)) { - return scenario->environment; - } - - if (RSG::scene_render->is_environment(scenario->fallback_environment)) { - return scenario->fallback_environment; - } - - return RID(); -} - -void RenderingServerScene::_render_scene(RID p_render_buffers, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_environment, RID p_force_camera_effects, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass) { - Scenario *scenario = scenario_owner.getornull(p_scenario); - - RID camera_effects; - if (p_force_camera_effects.is_valid()) { - camera_effects = p_force_camera_effects; - } else { - camera_effects = scenario->camera_effects; - } - /* PROCESS GEOMETRY AND DRAW SCENE */ - - RENDER_TIMESTAMP("Render Scene "); - RSG::scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, (RasterizerScene::InstanceBase **)instance_cull_result, instance_cull_count, light_instance_cull_result, light_cull_count + directional_light_count, reflection_probe_instance_cull_result, reflection_probe_cull_count, gi_probe_instance_cull_result, gi_probe_cull_count, decal_instance_cull_result, decal_cull_count, (RasterizerScene::InstanceBase **)lightmap_cull_result, lightmap_cull_count, p_environment, camera_effects, p_shadow_atlas, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass); -} - -void RenderingServerScene::render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) { -#ifndef _3D_DISABLED - - Scenario *scenario = scenario_owner.getornull(p_scenario); - - RID environment; - if (scenario->environment.is_valid()) { - environment = scenario->environment; - } else { - environment = scenario->fallback_environment; - } - RENDER_TIMESTAMP("Render Empty Scene "); - RSG::scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0, environment, RID(), p_shadow_atlas, scenario->reflection_atlas, RID(), 0); -#endif -} - -bool RenderingServerScene::_render_reflection_probe_step(Instance *p_instance, int p_step) { - InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(p_instance->base_data); - Scenario *scenario = p_instance->scenario; - ERR_FAIL_COND_V(!scenario, true); - - RenderingServerRaster::redraw_request(); //update, so it updates in editor - - if (p_step == 0) { - if (!RSG::scene_render->reflection_probe_instance_begin_render(reflection_probe->instance, scenario->reflection_atlas)) { - return true; //all full - } - } - - if (p_step >= 0 && p_step < 6) { - static const Vector3 view_normals[6] = { - Vector3(+1, 0, 0), - Vector3(-1, 0, 0), - Vector3(0, +1, 0), - Vector3(0, -1, 0), - Vector3(0, 0, +1), - Vector3(0, 0, -1) - }; - static const Vector3 view_up[6] = { - Vector3(0, -1, 0), - Vector3(0, -1, 0), - Vector3(0, 0, +1), - Vector3(0, 0, -1), - Vector3(0, -1, 0), - Vector3(0, -1, 0) - }; - - Vector3 extents = RSG::storage->reflection_probe_get_extents(p_instance->base); - Vector3 origin_offset = RSG::storage->reflection_probe_get_origin_offset(p_instance->base); - float max_distance = RSG::storage->reflection_probe_get_origin_max_distance(p_instance->base); - - Vector3 edge = view_normals[p_step] * extents; - float distance = ABS(view_normals[p_step].dot(edge) - view_normals[p_step].dot(origin_offset)); //distance from origin offset to actual view distance limit - - max_distance = MAX(max_distance, distance); - - //render cubemap side - CameraMatrix cm; - cm.set_perspective(90, 1, 0.01, max_distance); - - Transform local_view; - local_view.set_look_at(origin_offset, origin_offset + view_normals[p_step], view_up[p_step]); - - Transform xform = p_instance->transform * local_view; - - RID shadow_atlas; - - bool use_shadows = RSG::storage->reflection_probe_renders_shadows(p_instance->base); - if (use_shadows) { - shadow_atlas = scenario->reflection_probe_shadow_atlas; - } - - RENDER_TIMESTAMP("Render Reflection Probe, Step " + itos(p_step)); - _prepare_scene(xform, cm, false, false, RID(), RID(), RSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, use_shadows); - _render_scene(RID(), xform, cm, false, RID(), RID(), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, p_step); - - } else { - //do roughness postprocess step until it believes it's done - RENDER_TIMESTAMP("Post-Process Reflection Probe, Step " + itos(p_step)); - return RSG::scene_render->reflection_probe_instance_postprocess_step(reflection_probe->instance); - } - - return false; -} - -void RenderingServerScene::render_probes() { - /* REFLECTION PROBES */ - - SelfList<InstanceReflectionProbeData> *ref_probe = reflection_probe_render_list.first(); - - bool busy = false; - - while (ref_probe) { - SelfList<InstanceReflectionProbeData> *next = ref_probe->next(); - RID base = ref_probe->self()->owner->base; - - switch (RSG::storage->reflection_probe_get_update_mode(base)) { - case RS::REFLECTION_PROBE_UPDATE_ONCE: { - if (busy) { //already rendering something - break; - } - - bool done = _render_reflection_probe_step(ref_probe->self()->owner, ref_probe->self()->render_step); - if (done) { - reflection_probe_render_list.remove(ref_probe); - } else { - ref_probe->self()->render_step++; - } - - busy = true; //do not render another one of this kind - } break; - case RS::REFLECTION_PROBE_UPDATE_ALWAYS: { - int step = 0; - bool done = false; - while (!done) { - done = _render_reflection_probe_step(ref_probe->self()->owner, step); - step++; - } - - reflection_probe_render_list.remove(ref_probe); - } break; - } - - ref_probe = next; - } - - /* GI PROBES */ - - SelfList<InstanceGIProbeData> *gi_probe = gi_probe_update_list.first(); - - if (gi_probe) { - RENDER_TIMESTAMP("Render GI Probes"); - } - - while (gi_probe) { - SelfList<InstanceGIProbeData> *next = gi_probe->next(); - - InstanceGIProbeData *probe = gi_probe->self(); - //Instance *instance_probe = probe->owner; - - //check if probe must be setup, but don't do if on the lighting thread - - bool cache_dirty = false; - int cache_count = 0; - { - int light_cache_size = probe->light_cache.size(); - const InstanceGIProbeData::LightCache *caches = probe->light_cache.ptr(); - const RID *instance_caches = probe->light_instances.ptr(); - - int idx = 0; //must count visible lights - for (Set<Instance *>::Element *E = probe->lights.front(); E; E = E->next()) { - Instance *instance = E->get(); - InstanceLightData *instance_light = (InstanceLightData *)instance->base_data; - if (!instance->visible) { - continue; - } - if (cache_dirty) { - //do nothing, since idx must count all visible lights anyway - } else if (idx >= light_cache_size) { - cache_dirty = true; - } else { - const InstanceGIProbeData::LightCache *cache = &caches[idx]; - - if ( - instance_caches[idx] != instance_light->instance || - cache->has_shadow != RSG::storage->light_has_shadow(instance->base) || - cache->type != RSG::storage->light_get_type(instance->base) || - cache->transform != instance->transform || - cache->color != RSG::storage->light_get_color(instance->base) || - cache->energy != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ENERGY) || - cache->bake_energy != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_INDIRECT_ENERGY) || - cache->radius != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_RANGE) || - cache->attenuation != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION) || - cache->spot_angle != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ANGLE) || - cache->spot_attenuation != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ATTENUATION)) { - cache_dirty = true; - } - } - - idx++; - } - - for (List<Instance *>::Element *E = probe->owner->scenario->directional_lights.front(); E; E = E->next()) { - Instance *instance = E->get(); - InstanceLightData *instance_light = (InstanceLightData *)instance->base_data; - if (!instance->visible) { - continue; - } - if (cache_dirty) { - //do nothing, since idx must count all visible lights anyway - } else if (idx >= light_cache_size) { - cache_dirty = true; - } else { - const InstanceGIProbeData::LightCache *cache = &caches[idx]; - - if ( - instance_caches[idx] != instance_light->instance || - cache->has_shadow != RSG::storage->light_has_shadow(instance->base) || - cache->type != RSG::storage->light_get_type(instance->base) || - cache->transform != instance->transform || - cache->color != RSG::storage->light_get_color(instance->base) || - cache->energy != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ENERGY) || - cache->bake_energy != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_INDIRECT_ENERGY) || - cache->radius != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_RANGE) || - cache->attenuation != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION) || - cache->spot_angle != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ANGLE) || - cache->spot_attenuation != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ATTENUATION)) { - cache_dirty = true; - } - } - - idx++; - } - - if (idx != light_cache_size) { - cache_dirty = true; - } - - cache_count = idx; - } - - bool update_lights = RSG::scene_render->gi_probe_needs_update(probe->probe_instance); - - if (cache_dirty) { - probe->light_cache.resize(cache_count); - probe->light_instances.resize(cache_count); - - if (cache_count) { - InstanceGIProbeData::LightCache *caches = probe->light_cache.ptrw(); - RID *instance_caches = probe->light_instances.ptrw(); - - int idx = 0; //must count visible lights - for (Set<Instance *>::Element *E = probe->lights.front(); E; E = E->next()) { - Instance *instance = E->get(); - InstanceLightData *instance_light = (InstanceLightData *)instance->base_data; - if (!instance->visible) { - continue; - } - - InstanceGIProbeData::LightCache *cache = &caches[idx]; - - instance_caches[idx] = instance_light->instance; - cache->has_shadow = RSG::storage->light_has_shadow(instance->base); - cache->type = RSG::storage->light_get_type(instance->base); - cache->transform = instance->transform; - cache->color = RSG::storage->light_get_color(instance->base); - cache->energy = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ENERGY); - cache->bake_energy = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_INDIRECT_ENERGY); - cache->radius = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_RANGE); - cache->attenuation = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION); - cache->spot_angle = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ANGLE); - cache->spot_attenuation = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ATTENUATION); - - idx++; - } - for (List<Instance *>::Element *E = probe->owner->scenario->directional_lights.front(); E; E = E->next()) { - Instance *instance = E->get(); - InstanceLightData *instance_light = (InstanceLightData *)instance->base_data; - if (!instance->visible) { - continue; - } - - InstanceGIProbeData::LightCache *cache = &caches[idx]; - - instance_caches[idx] = instance_light->instance; - cache->has_shadow = RSG::storage->light_has_shadow(instance->base); - cache->type = RSG::storage->light_get_type(instance->base); - cache->transform = instance->transform; - cache->color = RSG::storage->light_get_color(instance->base); - cache->energy = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ENERGY); - cache->bake_energy = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_INDIRECT_ENERGY); - cache->radius = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_RANGE); - cache->attenuation = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION); - cache->spot_angle = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ANGLE); - cache->spot_attenuation = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ATTENUATION); - - idx++; - } - } - - update_lights = true; - } - - instance_cull_count = 0; - for (List<InstanceGIProbeData::PairInfo>::Element *E = probe->dynamic_geometries.front(); E; E = E->next()) { - if (instance_cull_count < MAX_INSTANCE_CULL) { - Instance *ins = E->get().geometry; - if (!ins->visible) { - continue; - } - InstanceGeometryData *geom = (InstanceGeometryData *)ins->base_data; - - if (geom->gi_probes_dirty) { - //giprobes may be dirty, so update - int l = 0; - //only called when reflection probe AABB enter/exit this geometry - ins->gi_probe_instances.resize(geom->gi_probes.size()); - - for (List<Instance *>::Element *F = geom->gi_probes.front(); F; F = F->next()) { - InstanceGIProbeData *gi_probe2 = static_cast<InstanceGIProbeData *>(F->get()->base_data); - - ins->gi_probe_instances.write[l++] = gi_probe2->probe_instance; - } - - geom->gi_probes_dirty = false; - } - - instance_cull_result[instance_cull_count++] = E->get().geometry; - } - } - - RSG::scene_render->gi_probe_update(probe->probe_instance, update_lights, probe->light_instances, instance_cull_count, (RasterizerScene::InstanceBase **)instance_cull_result); - - gi_probe_update_list.remove(gi_probe); - - gi_probe = next; - } -} - -void RenderingServerScene::render_particle_colliders() { - while (heightfield_particle_colliders_update_list.front()) { - Instance *hfpc = heightfield_particle_colliders_update_list.front()->get(); - - if (hfpc->scenario && hfpc->base_type == RS::INSTANCE_PARTICLES_COLLISION && RSG::storage->particles_collision_is_heightfield(hfpc->base)) { - //update heightfield - int cull_count = hfpc->scenario->octree.cull_aabb(hfpc->transformed_aabb, instance_cull_result, MAX_INSTANCE_CULL); //@TODO: cull mask missing - for (int i = 0; i < cull_count; i++) { - Instance *instance = instance_cull_result[i]; - if (!instance->visible || !((1 << instance->base_type) & (RS::INSTANCE_GEOMETRY_MASK & (~(1 << RS::INSTANCE_PARTICLES))))) { //all but particles to avoid self collision - cull_count--; - SWAP(instance_cull_result[i], instance_cull_result[cull_count]); - } - } - - RSG::scene_render->render_particle_collider_heightfield(hfpc->base, hfpc->transform, (RasterizerScene::InstanceBase **)instance_cull_result, cull_count); - } - heightfield_particle_colliders_update_list.erase(heightfield_particle_colliders_update_list.front()); - } -} - -void RenderingServerScene::_update_instance_shader_parameters_from_material(Map<StringName, RasterizerScene::InstanceBase::InstanceShaderParameter> &isparams, const Map<StringName, RasterizerScene::InstanceBase::InstanceShaderParameter> &existing_isparams, RID p_material) { - List<RasterizerStorage::InstanceShaderParam> plist; - RSG::storage->material_get_instance_shader_parameters(p_material, &plist); - for (List<RasterizerStorage::InstanceShaderParam>::Element *E = plist.front(); E; E = E->next()) { - StringName name = E->get().info.name; - if (isparams.has(name)) { - if (isparams[name].info.type != E->get().info.type) { - WARN_PRINT("More than one material in instance export the same instance shader uniform '" + E->get().info.name + "', but they do it with different data types. Only the first one (in order) will display correctly."); - } - if (isparams[name].index != E->get().index) { - WARN_PRINT("More than one material in instance export the same instance shader uniform '" + E->get().info.name + "', but they do it with different indices. Only the first one (in order) will display correctly."); - } - continue; //first one found always has priority - } - - RasterizerScene::InstanceBase::InstanceShaderParameter isp; - isp.index = E->get().index; - isp.info = E->get().info; - isp.default_value = E->get().default_value; - if (existing_isparams.has(name)) { - isp.value = existing_isparams[name].value; - } else { - isp.value = E->get().default_value; - } - isparams[name] = isp; - } -} - -void RenderingServerScene::_update_dirty_instance(Instance *p_instance) { - if (p_instance->update_aabb) { - _update_instance_aabb(p_instance); - } - - if (p_instance->update_dependencies) { - p_instance->instance_increase_version(); - - if (p_instance->base.is_valid()) { - RSG::storage->base_update_dependency(p_instance->base, p_instance); - } - - if (p_instance->material_override.is_valid()) { - RSG::storage->material_update_dependency(p_instance->material_override, p_instance); - } - - if (p_instance->base_type == RS::INSTANCE_MESH) { - //remove materials no longer used and un-own them - - int new_mat_count = RSG::storage->mesh_get_surface_count(p_instance->base); - p_instance->materials.resize(new_mat_count); - - int new_blend_shape_count = RSG::storage->mesh_get_blend_shape_count(p_instance->base); - if (new_blend_shape_count != p_instance->blend_values.size()) { - p_instance->blend_values.resize(new_blend_shape_count); - for (int i = 0; i < new_blend_shape_count; i++) { - p_instance->blend_values.write[i] = 0; - } - } - } - - if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); - - bool can_cast_shadows = true; - bool is_animated = false; - Map<StringName, RasterizerScene::InstanceBase::InstanceShaderParameter> isparams; - - if (p_instance->cast_shadows == RS::SHADOW_CASTING_SETTING_OFF) { - can_cast_shadows = false; - } - - if (p_instance->material_override.is_valid()) { - if (!RSG::storage->material_casts_shadows(p_instance->material_override)) { - can_cast_shadows = false; - } - is_animated = RSG::storage->material_is_animated(p_instance->material_override); - _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, p_instance->material_override); - } else { - if (p_instance->base_type == RS::INSTANCE_MESH) { - RID mesh = p_instance->base; - - if (mesh.is_valid()) { - bool cast_shadows = false; - - for (int i = 0; i < p_instance->materials.size(); i++) { - RID mat = p_instance->materials[i].is_valid() ? p_instance->materials[i] : RSG::storage->mesh_surface_get_material(mesh, i); - - if (!mat.is_valid()) { - cast_shadows = true; - } else { - if (RSG::storage->material_casts_shadows(mat)) { - cast_shadows = true; - } - - if (RSG::storage->material_is_animated(mat)) { - is_animated = true; - } - - _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat); - - RSG::storage->material_update_dependency(mat, p_instance); - } - } - - if (!cast_shadows) { - can_cast_shadows = false; - } - } - - } else if (p_instance->base_type == RS::INSTANCE_MULTIMESH) { - RID mesh = RSG::storage->multimesh_get_mesh(p_instance->base); - if (mesh.is_valid()) { - bool cast_shadows = false; - - int sc = RSG::storage->mesh_get_surface_count(mesh); - for (int i = 0; i < sc; i++) { - RID mat = RSG::storage->mesh_surface_get_material(mesh, i); - - if (!mat.is_valid()) { - cast_shadows = true; - - } else { - if (RSG::storage->material_casts_shadows(mat)) { - cast_shadows = true; - } - if (RSG::storage->material_is_animated(mat)) { - is_animated = true; - } - - _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat); - - RSG::storage->material_update_dependency(mat, p_instance); - } - } - - if (!cast_shadows) { - can_cast_shadows = false; - } - - RSG::storage->base_update_dependency(mesh, p_instance); - } - } else if (p_instance->base_type == RS::INSTANCE_IMMEDIATE) { - RID mat = RSG::storage->immediate_get_material(p_instance->base); - - if (!(!mat.is_valid() || RSG::storage->material_casts_shadows(mat))) { - can_cast_shadows = false; - } - - if (mat.is_valid() && RSG::storage->material_is_animated(mat)) { - is_animated = true; - } - - if (mat.is_valid()) { - _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat); - } - - if (mat.is_valid()) { - RSG::storage->material_update_dependency(mat, p_instance); - } - - } else if (p_instance->base_type == RS::INSTANCE_PARTICLES) { - bool cast_shadows = false; - - int dp = RSG::storage->particles_get_draw_passes(p_instance->base); - - for (int i = 0; i < dp; i++) { - RID mesh = RSG::storage->particles_get_draw_pass_mesh(p_instance->base, i); - if (!mesh.is_valid()) { - continue; - } - - int sc = RSG::storage->mesh_get_surface_count(mesh); - for (int j = 0; j < sc; j++) { - RID mat = RSG::storage->mesh_surface_get_material(mesh, j); - - if (!mat.is_valid()) { - cast_shadows = true; - } else { - if (RSG::storage->material_casts_shadows(mat)) { - cast_shadows = true; - } - - if (RSG::storage->material_is_animated(mat)) { - is_animated = true; - } - - _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat); - - RSG::storage->material_update_dependency(mat, p_instance); - } - } - } - - if (!cast_shadows) { - can_cast_shadows = false; - } - } - } - - if (can_cast_shadows != geom->can_cast_shadows) { - //ability to cast shadows change, let lights now - for (List<Instance *>::Element *E = geom->lighting.front(); E; E = E->next()) { - InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data); - light->shadow_dirty = true; - } - - geom->can_cast_shadows = can_cast_shadows; - } - - geom->material_is_animated = is_animated; - p_instance->instance_shader_parameters = isparams; - - if (p_instance->instance_allocated_shader_parameters != (p_instance->instance_shader_parameters.size() > 0)) { - p_instance->instance_allocated_shader_parameters = (p_instance->instance_shader_parameters.size() > 0); - if (p_instance->instance_allocated_shader_parameters) { - p_instance->instance_allocated_shader_parameters_offset = RSG::storage->global_variables_instance_allocate(p_instance->self); - for (Map<StringName, RasterizerScene::InstanceBase::InstanceShaderParameter>::Element *E = p_instance->instance_shader_parameters.front(); E; E = E->next()) { - if (E->get().value.get_type() != Variant::NIL) { - RSG::storage->global_variables_instance_update(p_instance->self, E->get().index, E->get().value); - } - } - } else { - RSG::storage->global_variables_instance_free(p_instance->self); - p_instance->instance_allocated_shader_parameters_offset = -1; - } - } - } - - if (p_instance->skeleton.is_valid()) { - RSG::storage->skeleton_update_dependency(p_instance->skeleton, p_instance); - } - - p_instance->clean_up_dependencies(); - } - - _instance_update_list.remove(&p_instance->update_item); - - _update_instance(p_instance); - - p_instance->update_aabb = false; - p_instance->update_dependencies = false; -} - -void RenderingServerScene::update_dirty_instances() { - RSG::storage->update_dirty_resources(); - - while (_instance_update_list.first()) { - _update_dirty_instance(_instance_update_list.first()->self()); - } -} - -bool RenderingServerScene::free(RID p_rid) { - if (camera_owner.owns(p_rid)) { - Camera *camera = camera_owner.getornull(p_rid); - - camera_owner.free(p_rid); - memdelete(camera); - - } else if (scenario_owner.owns(p_rid)) { - Scenario *scenario = scenario_owner.getornull(p_rid); - - while (scenario->instances.first()) { - instance_set_scenario(scenario->instances.first()->self()->self, RID()); - } - RSG::scene_render->free(scenario->reflection_probe_shadow_atlas); - RSG::scene_render->free(scenario->reflection_atlas); - scenario_owner.free(p_rid); - memdelete(scenario); - - } else if (instance_owner.owns(p_rid)) { - // delete the instance - - update_dirty_instances(); - - Instance *instance = instance_owner.getornull(p_rid); - - instance_geometry_set_lightmap(p_rid, RID(), Rect2(), 0); - instance_set_scenario(p_rid, RID()); - instance_set_base(p_rid, RID()); - instance_geometry_set_material_override(p_rid, RID()); - instance_attach_skeleton(p_rid, RID()); - - if (instance->instance_allocated_shader_parameters) { - //free the used shader parameters - RSG::storage->global_variables_instance_free(instance->self); - } - update_dirty_instances(); //in case something changed this - - instance_owner.free(p_rid); - memdelete(instance); - } else { - return false; - } - - return true; -} - -TypedArray<Image> RenderingServerScene::bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) { - return RSG::scene_render->bake_render_uv2(p_base, p_material_overrides, p_image_size); -} - -RenderingServerScene *RenderingServerScene::singleton = nullptr; - -RenderingServerScene::RenderingServerScene() { - render_pass = 1; - singleton = this; -} - -RenderingServerScene::~RenderingServerScene() { -} diff --git a/servers/rendering/rendering_server_scene.h b/servers/rendering/rendering_server_scene.h deleted file mode 100644 index 646b2a666f..0000000000 --- a/servers/rendering/rendering_server_scene.h +++ /dev/null @@ -1,476 +0,0 @@ -/*************************************************************************/ -/* rendering_server_scene.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef VISUALSERVERSCENE_H -#define VISUALSERVERSCENE_H - -#include "servers/rendering/rasterizer.h" - -#include "core/math/geometry_3d.h" -#include "core/math/octree.h" -#include "core/os/semaphore.h" -#include "core/os/thread.h" -#include "core/templates/local_vector.h" -#include "core/templates/rid_owner.h" -#include "core/templates/self_list.h" -#include "servers/xr/xr_interface.h" - -class RenderingServerScene { -public: - enum { - MAX_INSTANCE_CULL = 65536, - MAX_LIGHTS_CULLED = 4096, - MAX_REFLECTION_PROBES_CULLED = 4096, - MAX_DECALS_CULLED = 4096, - MAX_GI_PROBES_CULLED = 4096, - MAX_ROOM_CULL = 32, - MAX_LIGHTMAPS_CULLED = 4096, - MAX_EXTERIOR_PORTALS = 128, - }; - - uint64_t render_pass; - - static RenderingServerScene *singleton; - - /* CAMERA API */ - - struct Camera { - enum Type { - PERSPECTIVE, - ORTHOGONAL, - FRUSTUM - }; - Type type; - float fov; - float znear, zfar; - float size; - Vector2 offset; - uint32_t visible_layers; - bool vaspect; - RID env; - RID effects; - - Transform transform; - - Camera() { - visible_layers = 0xFFFFFFFF; - fov = 75; - type = PERSPECTIVE; - znear = 0.05; - zfar = 100; - size = 1.0; - offset = Vector2(); - vaspect = false; - } - }; - - mutable RID_PtrOwner<Camera> camera_owner; - - virtual RID camera_create(); - virtual void camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far); - virtual void camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far); - virtual void camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far); - virtual void camera_set_transform(RID p_camera, const Transform &p_transform); - virtual void camera_set_cull_mask(RID p_camera, uint32_t p_layers); - virtual void camera_set_environment(RID p_camera, RID p_env); - virtual void camera_set_camera_effects(RID p_camera, RID p_fx); - virtual void camera_set_use_vertical_aspect(RID p_camera, bool p_enable); - - /* SCENARIO API */ - - struct Instance; - - struct Scenario { - RS::ScenarioDebugMode debug; - RID self; - - Octree<Instance, true> octree; - - List<Instance *> directional_lights; - RID environment; - RID fallback_environment; - RID camera_effects; - RID reflection_probe_shadow_atlas; - RID reflection_atlas; - - SelfList<Instance>::List instances; - - LocalVector<RID> dynamic_lights; - - Scenario() { debug = RS::SCENARIO_DEBUG_DISABLED; } - }; - - mutable RID_PtrOwner<Scenario> scenario_owner; - - static void *_instance_pair(void *p_self, OctreeElementID, Instance *p_A, int, OctreeElementID, Instance *p_B, int); - static void _instance_unpair(void *p_self, OctreeElementID, Instance *p_A, int, OctreeElementID, Instance *p_B, int, void *); - - virtual RID scenario_create(); - - virtual void scenario_set_debug(RID p_scenario, RS::ScenarioDebugMode p_debug_mode); - virtual void scenario_set_environment(RID p_scenario, RID p_environment); - virtual void scenario_set_camera_effects(RID p_scenario, RID p_fx); - virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment); - virtual void scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count); - - /* INSTANCING API */ - - struct InstanceBaseData { - virtual ~InstanceBaseData() {} - }; - - struct Instance : RasterizerScene::InstanceBase { - RID self; - //scenario stuff - OctreeElementID octree_id; - Scenario *scenario; - SelfList<Instance> scenario_item; - - //aabb stuff - bool update_aabb; - bool update_dependencies; - - SelfList<Instance> update_item; - - AABB *custom_aabb; // <Zylann> would using aabb directly with a bool be better? - float extra_margin; - ObjectID object_id; - - float lod_begin; - float lod_end; - float lod_begin_hysteresis; - float lod_end_hysteresis; - RID lod_instance; - - Vector<Color> lightmap_target_sh; //target is used for incrementally changing the SH over time, this avoids pops in some corner cases and when going interior <-> exterior - - uint64_t last_render_pass; - uint64_t last_frame_pass; - - uint64_t version; // changes to this, and changes to base increase version - - InstanceBaseData *base_data; - - virtual void dependency_deleted(RID p_dependency) { - if (p_dependency == base) { - singleton->instance_set_base(self, RID()); - } else if (p_dependency == skeleton) { - singleton->instance_attach_skeleton(self, RID()); - } else { - singleton->_instance_queue_update(this, false, true); - } - } - - virtual void dependency_changed(bool p_aabb, bool p_dependencies) { - singleton->_instance_queue_update(this, p_aabb, p_dependencies); - } - - Instance() : - scenario_item(this), - update_item(this) { - octree_id = 0; - scenario = nullptr; - - update_aabb = false; - update_dependencies = false; - - extra_margin = 0; - - visible = true; - - lod_begin = 0; - lod_end = 0; - lod_begin_hysteresis = 0; - lod_end_hysteresis = 0; - - last_render_pass = 0; - last_frame_pass = 0; - version = 1; - base_data = nullptr; - - custom_aabb = nullptr; - } - - ~Instance() { - if (base_data) { - memdelete(base_data); - } - if (custom_aabb) { - memdelete(custom_aabb); - } - } - }; - - SelfList<Instance>::List _instance_update_list; - void _instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_dependencies = false); - - struct InstanceGeometryData : public InstanceBaseData { - List<Instance *> lighting; - bool lighting_dirty; - bool can_cast_shadows; - bool material_is_animated; - - List<Instance *> decals; - bool decal_dirty; - - List<Instance *> reflection_probes; - bool reflection_dirty; - - List<Instance *> gi_probes; - bool gi_probes_dirty; - - List<Instance *> lightmap_captures; - - InstanceGeometryData() { - lighting_dirty = false; - reflection_dirty = true; - can_cast_shadows = true; - material_is_animated = true; - gi_probes_dirty = true; - decal_dirty = true; - } - }; - - struct InstanceReflectionProbeData : public InstanceBaseData { - Instance *owner; - - struct PairInfo { - List<Instance *>::Element *L; //reflection iterator in geometry - Instance *geometry; - }; - List<PairInfo> geometries; - - RID instance; - bool reflection_dirty; - SelfList<InstanceReflectionProbeData> update_list; - - int render_step; - - InstanceReflectionProbeData() : - update_list(this) { - reflection_dirty = true; - render_step = -1; - } - }; - - struct InstanceDecalData : public InstanceBaseData { - Instance *owner; - RID instance; - - struct PairInfo { - List<Instance *>::Element *L; //reflection iterator in geometry - Instance *geometry; - }; - List<PairInfo> geometries; - - InstanceDecalData() { - } - }; - - SelfList<InstanceReflectionProbeData>::List reflection_probe_render_list; - - struct InstanceLightData : public InstanceBaseData { - struct PairInfo { - List<Instance *>::Element *L; //light iterator in geometry - Instance *geometry; - }; - - RID instance; - uint64_t last_version; - List<Instance *>::Element *D; // directional light in scenario - - bool shadow_dirty; - - List<PairInfo> geometries; - - Instance *baked_light; - - RS::LightBakeMode bake_mode; - uint32_t max_sdfgi_cascade = 2; - - uint64_t sdfgi_cascade_light_pass = 0; - - InstanceLightData() { - bake_mode = RS::LIGHT_BAKE_DISABLED; - shadow_dirty = true; - D = nullptr; - last_version = 0; - baked_light = nullptr; - } - }; - - struct InstanceGIProbeData : public InstanceBaseData { - Instance *owner; - - struct PairInfo { - List<Instance *>::Element *L; //gi probe iterator in geometry - Instance *geometry; - }; - - List<PairInfo> geometries; - List<PairInfo> dynamic_geometries; - - Set<Instance *> lights; - - struct LightCache { - RS::LightType type; - Transform transform; - Color color; - float energy; - float bake_energy; - float radius; - float attenuation; - float spot_angle; - float spot_attenuation; - bool has_shadow; - }; - - Vector<LightCache> light_cache; - Vector<RID> light_instances; - - RID probe_instance; - - bool invalid; - uint32_t base_version; - - SelfList<InstanceGIProbeData> update_element; - - InstanceGIProbeData() : - update_element(this) { - invalid = true; - base_version = 0; - } - }; - - SelfList<InstanceGIProbeData>::List gi_probe_update_list; - - struct InstanceLightmapData : public InstanceBaseData { - struct PairInfo { - List<Instance *>::Element *L; //iterator in geometry - Instance *geometry; - }; - List<PairInfo> geometries; - - Set<Instance *> users; - - InstanceLightmapData() { - } - }; - - Set<Instance *> heightfield_particle_colliders_update_list; - - int instance_cull_count; - Instance *instance_cull_result[MAX_INSTANCE_CULL]; - Instance *instance_shadow_cull_result[MAX_INSTANCE_CULL]; //used for generating shadowmaps - Instance *light_cull_result[MAX_LIGHTS_CULLED]; - RID sdfgi_light_cull_result[MAX_LIGHTS_CULLED]; - RID light_instance_cull_result[MAX_LIGHTS_CULLED]; - uint64_t sdfgi_light_cull_pass = 0; - int light_cull_count; - int directional_light_count; - RID reflection_probe_instance_cull_result[MAX_REFLECTION_PROBES_CULLED]; - RID decal_instance_cull_result[MAX_DECALS_CULLED]; - int reflection_probe_cull_count; - int decal_cull_count; - RID gi_probe_instance_cull_result[MAX_GI_PROBES_CULLED]; - int gi_probe_cull_count; - Instance *lightmap_cull_result[MAX_LIGHTS_CULLED]; - int lightmap_cull_count; - - RID_PtrOwner<Instance> instance_owner; - - virtual RID instance_create(); - - virtual void instance_set_base(RID p_instance, RID p_base); - virtual void instance_set_scenario(RID p_instance, RID p_scenario); - virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask); - virtual void instance_set_transform(RID p_instance, const Transform &p_transform); - virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id); - virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight); - virtual void instance_set_surface_material(RID p_instance, int p_surface, RID p_material); - virtual void instance_set_visible(RID p_instance, bool p_visible); - - virtual void instance_set_custom_aabb(RID p_instance, AABB p_aabb); - - virtual void instance_attach_skeleton(RID p_instance, RID p_skeleton); - virtual void instance_set_exterior(RID p_instance, bool p_enabled); - - virtual void instance_set_extra_visibility_margin(RID p_instance, real_t p_margin); - - // don't use these in a game! - virtual Vector<ObjectID> instances_cull_aabb(const AABB &p_aabb, RID p_scenario = RID()) const; - virtual Vector<ObjectID> instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario = RID()) const; - virtual Vector<ObjectID> instances_cull_convex(const Vector<Plane> &p_convex, RID p_scenario = RID()) const; - - virtual void instance_geometry_set_flag(RID p_instance, RS::InstanceFlags p_flags, bool p_enabled); - virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, RS::ShadowCastingSetting p_shadow_casting_setting); - virtual void instance_geometry_set_material_override(RID p_instance, RID p_material); - - virtual void instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin); - virtual void instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance); - virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index); - - void _update_instance_shader_parameters_from_material(Map<StringName, RasterizerScene::InstanceBase::InstanceShaderParameter> &isparams, const Map<StringName, RasterizerScene::InstanceBase::InstanceShaderParameter> &existing_isparams, RID p_material); - - virtual void instance_geometry_set_shader_parameter(RID p_instance, const StringName &p_parameter, const Variant &p_value); - virtual void instance_geometry_get_shader_parameter_list(RID p_instance, List<PropertyInfo> *p_parameters) const; - virtual Variant instance_geometry_get_shader_parameter(RID p_instance, const StringName &p_parameter) const; - virtual Variant instance_geometry_get_shader_parameter_default_value(RID p_instance, const StringName &p_parameter) const; - - _FORCE_INLINE_ void _update_instance(Instance *p_instance); - _FORCE_INLINE_ void _update_instance_aabb(Instance *p_instance); - _FORCE_INLINE_ void _update_dirty_instance(Instance *p_instance); - _FORCE_INLINE_ void _update_instance_lightmap_captures(Instance *p_instance); - - _FORCE_INLINE_ bool _light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario); - - RID _render_get_environment(RID p_camera, RID p_scenario); - - bool _render_reflection_probe_step(Instance *p_instance, int p_step); - void _prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_render_buffers, RID p_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, bool p_using_shadows = true); - void _render_scene(RID p_render_buffers, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_environment, RID p_force_camera_effects, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass); - void render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas); - - void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas); - void render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas); - void update_dirty_instances(); - - void render_particle_colliders(); - void render_probes(); - - TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size); - - bool free(RID p_rid); - - RenderingServerScene(); - virtual ~RenderingServerScene(); -}; - -#endif // VISUALSERVERSCENE_H diff --git a/servers/rendering/rendering_server_wrap_mt.cpp b/servers/rendering/rendering_server_wrap_mt.cpp deleted file mode 100644 index 40ad228fd0..0000000000 --- a/servers/rendering/rendering_server_wrap_mt.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/*************************************************************************/ -/* rendering_server_wrap_mt.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "rendering_server_wrap_mt.h" -#include "core/config/project_settings.h" -#include "core/os/os.h" -#include "servers/display_server.h" - -void RenderingServerWrapMT::thread_exit() { - exit = true; -} - -void RenderingServerWrapMT::thread_draw(bool p_swap_buffers, double frame_step) { - if (!atomic_decrement(&draw_pending)) { - rendering_server->draw(p_swap_buffers, frame_step); - } -} - -void RenderingServerWrapMT::thread_flush() { - atomic_decrement(&draw_pending); -} - -void RenderingServerWrapMT::_thread_callback(void *_instance) { - RenderingServerWrapMT *vsmt = reinterpret_cast<RenderingServerWrapMT *>(_instance); - - vsmt->thread_loop(); -} - -void RenderingServerWrapMT::thread_loop() { - server_thread = Thread::get_caller_id(); - - DisplayServer::get_singleton()->make_rendering_thread(); - - rendering_server->init(); - - exit = false; - draw_thread_up = true; - while (!exit) { - // flush commands one by one, until exit is requested - command_queue.wait_and_flush_one(); - } - - command_queue.flush_all(); // flush all - - rendering_server->finish(); -} - -/* EVENT QUEUING */ - -void RenderingServerWrapMT::sync() { - if (create_thread) { - atomic_increment(&draw_pending); - command_queue.push_and_sync(this, &RenderingServerWrapMT::thread_flush); - } else { - command_queue.flush_all(); //flush all pending from other threads - } -} - -void RenderingServerWrapMT::draw(bool p_swap_buffers, double frame_step) { - if (create_thread) { - atomic_increment(&draw_pending); - command_queue.push(this, &RenderingServerWrapMT::thread_draw, p_swap_buffers, frame_step); - } else { - rendering_server->draw(p_swap_buffers, frame_step); - } -} - -void RenderingServerWrapMT::init() { - if (create_thread) { - print_verbose("RenderingServerWrapMT: Creating render thread"); - DisplayServer::get_singleton()->release_rendering_thread(); - if (create_thread) { - thread = Thread::create(_thread_callback, this); - print_verbose("RenderingServerWrapMT: Starting render thread"); - } - while (!draw_thread_up) { - OS::get_singleton()->delay_usec(1000); - } - print_verbose("RenderingServerWrapMT: Finished render thread"); - } else { - rendering_server->init(); - } -} - -void RenderingServerWrapMT::finish() { - sky_free_cached_ids(); - shader_free_cached_ids(); - material_free_cached_ids(); - mesh_free_cached_ids(); - multimesh_free_cached_ids(); - immediate_free_cached_ids(); - skeleton_free_cached_ids(); - directional_light_free_cached_ids(); - omni_light_free_cached_ids(); - spot_light_free_cached_ids(); - reflection_probe_free_cached_ids(); - gi_probe_free_cached_ids(); - lightmap_free_cached_ids(); - particles_free_cached_ids(); - particles_collision_free_cached_ids(); - camera_free_cached_ids(); - viewport_free_cached_ids(); - environment_free_cached_ids(); - camera_effects_free_cached_ids(); - scenario_free_cached_ids(); - instance_free_cached_ids(); - canvas_free_cached_ids(); - canvas_item_free_cached_ids(); - canvas_light_occluder_free_cached_ids(); - canvas_occluder_polygon_free_cached_ids(); - - if (thread) { - command_queue.push(this, &RenderingServerWrapMT::thread_exit); - Thread::wait_to_finish(thread); - memdelete(thread); - - thread = nullptr; - } else { - rendering_server->finish(); - } -} - -void RenderingServerWrapMT::set_use_vsync_callback(bool p_enable) { - singleton_mt->call_set_use_vsync(p_enable); -} - -RenderingServerWrapMT *RenderingServerWrapMT::singleton_mt = nullptr; - -RenderingServerWrapMT::RenderingServerWrapMT(RenderingServer *p_contained, bool p_create_thread) : - command_queue(p_create_thread) { - singleton_mt = this; - DisplayServer::switch_vsync_function = set_use_vsync_callback; //as this goes to another thread, make sure it goes properly - - rendering_server = p_contained; - create_thread = p_create_thread; - thread = nullptr; - draw_pending = 0; - draw_thread_up = false; - pool_max_size = GLOBAL_GET("memory/limits/multithreaded_server/rid_pool_prealloc"); - - if (!p_create_thread) { - server_thread = Thread::get_caller_id(); - } else { - server_thread = 0; - } -} - -RenderingServerWrapMT::~RenderingServerWrapMT() { - memdelete(rendering_server); - //finish(); -} diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 1ab353c9d0..cb98a71e86 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -223,7 +223,7 @@ const char *ShaderLanguage::token_names[TK_MAX] = { String ShaderLanguage::get_token_text(Token p_token) { String name = token_names[p_token.type]; - if (p_token.type == TK_INT_CONSTANT || p_token.type == TK_REAL_CONSTANT) { + if (p_token.type == TK_INT_CONSTANT || p_token.type == TK_FLOAT_CONSTANT) { name += "(" + rtos(p_token.constant) + ")"; } else if (p_token.type == TK_IDENTIFIER) { name += "(" + String(p_token.text) + ")"; @@ -637,13 +637,13 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { char_idx += str.length(); Token tk; if (period_found || exponent_found || float_suffix_found) { - tk.type = TK_REAL_CONSTANT; + tk.type = TK_FLOAT_CONSTANT; } else { tk.type = TK_INT_CONSTANT; } if (hexa_found) { - tk.constant = (double)str.hex_to_int(true); + tk.constant = (double)str.hex_to_int(); } else { tk.constant = str.to_float(); } @@ -913,6 +913,7 @@ void ShaderLanguage::clear() { char_idx = 0; error_set = false; error_str = ""; + last_const = false; while (nodes) { Node *n = nodes; nodes = nodes->next; @@ -920,7 +921,7 @@ void ShaderLanguage::clear() { } } -bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_reassign, const FunctionInfo &p_function_info, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type, bool *r_is_const, int *r_array_size, StringName *r_struct_name) { +bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_reassign, const FunctionInfo &p_function_info, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type, bool *r_is_const, int *r_array_size, StringName *r_struct_name, ConstantNode::Value *r_constant_value) { if (p_function_info.built_ins.has(p_identifier)) { if (r_data_type) { *r_data_type = p_function_info.built_ins[p_identifier].type; @@ -968,6 +969,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea if (r_struct_name) { *r_struct_name = p_block->variables[p_identifier].struct_name; } + if (r_constant_value) { + *r_constant_value = p_block->variables[p_identifier].value; + } return true; } @@ -1028,6 +1032,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea } if (shader->constants.has(p_identifier)) { + if (r_is_const) { + *r_is_const = true; + } if (r_data_type) { *r_data_type = shader->constants[p_identifier].type; } @@ -1040,6 +1047,11 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea if (r_struct_name) { *r_struct_name = shader->constants[p_identifier].type_str; } + 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]; + } + } return true; } @@ -3090,6 +3102,72 @@ bool ShaderLanguage::_is_operator_assign(Operator p_op) const { return false; } +bool ShaderLanguage::_validate_varying_assign(ShaderNode::Varying &p_varying, String *r_message) { + if (current_function == String("light")) { + *r_message = RTR("Varying may not be assigned in the 'light' function."); + return false; + } + switch (p_varying.stage) { + case ShaderNode::Varying::STAGE_UNKNOWN: // first assign + if (current_function == String("vertex")) { + p_varying.stage = ShaderNode::Varying::STAGE_VERTEX; + } else if (current_function == String("fragment")) { + p_varying.stage = ShaderNode::Varying::STAGE_FRAGMENT; + } + break; + case ShaderNode::Varying::STAGE_VERTEX: + if (current_function == String("fragment")) { + *r_message = RTR("Varyings which assigned in 'vertex' function may not be reassigned in 'fragment' or 'light'."); + return false; + } + break; + case ShaderNode::Varying::STAGE_FRAGMENT: + if (current_function == String("vertex")) { + *r_message = RTR("Varyings which assigned in 'fragment' function may not be reassigned in 'vertex' or 'light'."); + return false; + } + break; + default: + break; + } + return true; +} + +bool ShaderLanguage::_validate_varying_using(ShaderNode::Varying &p_varying, String *r_message) { + switch (p_varying.stage) { + case ShaderNode::Varying::STAGE_UNKNOWN: + *r_message = RTR("Varying must be assigned before using!"); + return false; + case ShaderNode::Varying::STAGE_VERTEX: + if (current_function == String("fragment")) { + p_varying.stage = ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT; + } else if (current_function == String("light")) { + p_varying.stage = ShaderNode::Varying::STAGE_VERTEX_TO_LIGHT; + } + break; + case ShaderNode::Varying::STAGE_FRAGMENT: + if (current_function == String("light")) { + p_varying.stage = ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT; + } + break; + case ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT: + if (current_function == String("light")) { + *r_message = RTR("Varying must only be used in two different stages, which can be 'vertex' 'fragment' and 'light'"); + return false; + } + break; + case ShaderNode::Varying::STAGE_VERTEX_TO_LIGHT: + if (current_function == String("fragment")) { + *r_message = RTR("Varying must only be used in two different stages, which can be 'vertex' 'fragment' and 'light'"); + return false; + } + break; + default: + break; + } + return true; +} + bool ShaderLanguage::_validate_assign(Node *p_node, const FunctionInfo &p_function_info, String *r_message) { if (p_node->type == Node::TYPE_OPERATOR) { OperatorNode *op = static_cast<OperatorNode *>(p_node); @@ -3130,13 +3208,6 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const FunctionInfo &p_functi return false; } - if (shader->varyings.has(var->name) && current_function != String("vertex")) { - if (r_message) { - *r_message = RTR("Varyings can only be assigned in vertex function."); - } - return false; - } - if (shader->constants.has(var->name) || var->is_const) { if (r_message) { *r_message = RTR("Constants cannot be modified."); @@ -3157,13 +3228,6 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const FunctionInfo &p_functi return false; } - if (shader->varyings.has(arr->name) && current_function != String("vertex")) { - if (r_message) { - *r_message = RTR("Varyings can only be assigned in vertex function."); - } - return false; - } - return true; } @@ -3174,7 +3238,7 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const FunctionInfo &p_functi } bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(StringName p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat) { - for (int i = 0; shader->functions.size(); i++) { + for (int i = 0; i < shader->functions.size(); i++) { if (shader->functions[i].name == p_name) { ERR_FAIL_INDEX_V(p_argument, shader->functions[i].function->arguments.size(), false); FunctionNode::Argument *arg = &shader->functions[i].function->arguments.write[p_argument]; @@ -3208,7 +3272,7 @@ bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(StringNam } bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringName p_name, int p_argument, const StringName &p_builtin) { - for (int i = 0; shader->functions.size(); i++) { + for (int i = 0; i < shader->functions.size(); i++) { if (shader->functions[i].name == p_name) { ERR_FAIL_INDEX_V(p_argument, shader->functions[i].function->arguments.size(), false); FunctionNode::Argument *arg = &shader->functions[i].function->arguments.write[p_argument]; @@ -3241,6 +3305,137 @@ bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringNa ERR_FAIL_V(false); //bug? function not found } +ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info, DataType p_type, const StringName &p_struct_name, int p_array_size) { + DataType type = TYPE_VOID; + String struct_name = ""; + int array_size = 0; + bool auto_size = false; + Token tk = _get_token(); + + if (tk.type == TK_CURLY_BRACKET_OPEN) { + auto_size = true; + } else { + if (shader->structs.has(tk.text)) { + type = TYPE_STRUCT; + struct_name = tk.text; + } else { + if (!is_token_variable_datatype(tk.type)) { + _set_error("Invalid data type for array"); + return nullptr; + } + type = get_token_datatype(tk.type); + } + tk = _get_token(); + if (tk.type == TK_BRACKET_OPEN) { + TkPos pos = _get_tkpos(); + tk = _get_token(); + if (tk.type == TK_BRACKET_CLOSE) { + array_size = p_array_size; + tk = _get_token(); + } else { + _set_tkpos(pos); + + Node *n = _parse_and_reduce_expression(p_block, p_function_info); + if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) { + _set_error("Expected single integer constant > 0"); + return nullptr; + } + + ConstantNode *cnode = (ConstantNode *)n; + if (cnode->values.size() == 1) { + array_size = cnode->values[0].sint; + if (array_size <= 0) { + _set_error("Expected single integer constant > 0"); + return nullptr; + } + } else { + _set_error("Expected single integer constant > 0"); + return nullptr; + } + + tk = _get_token(); + if (tk.type != TK_BRACKET_CLOSE) { + _set_error("Expected ']'"); + return nullptr; + } else { + tk = _get_token(); + } + } + } else { + _set_error("Expected '['"); + return nullptr; + } + + if (type != p_type || struct_name != p_struct_name || array_size != p_array_size) { + String error_str = "Cannot convert from '"; + if (type == TYPE_STRUCT) { + error_str += struct_name; + } else { + error_str += get_datatype_name(type); + } + error_str += "["; + error_str += itos(array_size); + error_str += "]'"; + error_str += " to '"; + if (type == TYPE_STRUCT) { + error_str += p_struct_name; + } else { + error_str += get_datatype_name(p_type); + } + error_str += "["; + error_str += itos(p_array_size); + error_str += "]'"; + _set_error(error_str); + return nullptr; + } + } + + ArrayConstructNode *an = alloc_node<ArrayConstructNode>(); + an->datatype = p_type; + an->struct_name = p_struct_name; + + if (tk.type == TK_PARENTHESIS_OPEN || auto_size) { // initialization + while (true) { + Node *n = _parse_and_reduce_expression(p_block, p_function_info); + if (!n) { + return nullptr; + } + + if (p_type != n->get_datatype() || p_struct_name != n->get_datatype_name()) { + _set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (type == TYPE_STRUCT ? struct_name : get_datatype_name(type)) + "'"); + return nullptr; + } + + tk = _get_token(); + if (tk.type == TK_COMMA) { + an->initializer.push_back(n); + } else if (!auto_size && tk.type == TK_PARENTHESIS_CLOSE) { + an->initializer.push_back(n); + break; + } else if (auto_size && tk.type == TK_CURLY_BRACKET_CLOSE) { + an->initializer.push_back(n); + break; + } else { + if (auto_size) { + _set_error("Expected '}' or ','"); + } else { + _set_error("Expected ')' or ','"); + } + return nullptr; + } + } + if (an->initializer.size() != p_array_size) { + _set_error("Array size mismatch"); + return nullptr; + } + } else { + _set_error("Expected array initialization!"); + return nullptr; + } + + return an; +} + ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, const FunctionInfo &p_function_info) { Vector<Expression> expression; @@ -3269,7 +3464,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons return nullptr; } - } else if (tk.type == TK_REAL_CONSTANT) { + } else if (tk.type == TK_FLOAT_CONSTANT) { ConstantNode *constant = alloc_node<ConstantNode>(); ConstantNode::Value v; v.real = tk.constant; @@ -3384,142 +3579,10 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons Node *nexpr; if (pstruct->members[i]->array_size != 0) { - DataType type = pstruct->members[i]->get_datatype(); - String struct_name = pstruct->members[i]->struct_name; - int array_size = pstruct->members[i]->array_size; - - DataType type2; - String struct_name2 = ""; - int array_size2 = 0; - - bool auto_size = false; - - tk = _get_token(); - - if (tk.type == TK_CURLY_BRACKET_OPEN) { - auto_size = true; - } else { - if (shader->structs.has(tk.text)) { - type2 = TYPE_STRUCT; - struct_name2 = tk.text; - } else { - if (!is_token_variable_datatype(tk.type)) { - _set_error("Invalid data type for array"); - return nullptr; - } - type2 = get_token_datatype(tk.type); - } - - tk = _get_token(); - if (tk.type == TK_BRACKET_OPEN) { - TkPos pos2 = _get_tkpos(); - tk = _get_token(); - if (tk.type == TK_BRACKET_CLOSE) { - array_size2 = array_size; - tk = _get_token(); - } else { - _set_tkpos(pos2); - - Node *n = _parse_and_reduce_expression(p_block, p_function_info); - if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) { - _set_error("Expected single integer constant > 0"); - return nullptr; - } - - ConstantNode *cnode = (ConstantNode *)n; - if (cnode->values.size() == 1) { - array_size2 = cnode->values[0].sint; - if (array_size2 <= 0) { - _set_error("Expected single integer constant > 0"); - return nullptr; - } - } else { - _set_error("Expected single integer constant > 0"); - return nullptr; - } - - tk = _get_token(); - if (tk.type != TK_BRACKET_CLOSE) { - _set_error("Expected ']'"); - return nullptr; - } else { - tk = _get_token(); - } - } - } else { - _set_error("Expected '['"); - return nullptr; - } - - if (type != type2 || struct_name != struct_name2 || array_size != array_size2) { - String error_str = "Cannot convert from '"; - if (type2 == TYPE_STRUCT) { - error_str += struct_name2; - } else { - error_str += get_datatype_name(type2); - } - error_str += "["; - error_str += itos(array_size2); - error_str += "]'"; - error_str += " to '"; - if (type == TYPE_STRUCT) { - error_str += struct_name; - } else { - error_str += get_datatype_name(type); - } - error_str += "["; - error_str += itos(array_size); - error_str += "]'"; - _set_error(error_str); - return nullptr; - } - } - - ArrayConstructNode *an = alloc_node<ArrayConstructNode>(); - an->datatype = type; - an->struct_name = struct_name; - - if (tk.type == TK_PARENTHESIS_OPEN || auto_size) { // initialization - while (true) { - Node *n = _parse_and_reduce_expression(p_block, p_function_info); - if (!n) { - return nullptr; - } - - if (type != n->get_datatype() || struct_name != n->get_datatype_name()) { - _set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (type == TYPE_STRUCT ? struct_name : get_datatype_name(type)) + "'"); - return nullptr; - } - - tk = _get_token(); - if (tk.type == TK_COMMA) { - an->initializer.push_back(n); - continue; - } else if (!auto_size && tk.type == TK_PARENTHESIS_CLOSE) { - an->initializer.push_back(n); - break; - } else if (auto_size && tk.type == TK_CURLY_BRACKET_CLOSE) { - an->initializer.push_back(n); - break; - } else { - if (auto_size) { - _set_error("Expected '}' or ','"); - } else { - _set_error("Expected ')' or ','"); - } - return nullptr; - } - } - if (an->initializer.size() != array_size) { - _set_error("Array size mismatch"); - return nullptr; - } - } else { - _set_error("Expected array initialization!"); + nexpr = _parse_array_constructor(p_block, p_function_info, pstruct->members[i]->get_datatype(), pstruct->members[i]->struct_name, pstruct->members[i]->array_size); + if (!nexpr) { return nullptr; } - - nexpr = an; } else { nexpr = _parse_and_reduce_expression(p_block, p_function_info); if (!nexpr) { @@ -3722,6 +3785,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } else { //an identifier + last_const = false; _set_tkpos(pos); DataType data_type; @@ -3749,6 +3813,24 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons _set_error("Unknown identifier in expression: " + String(identifier)); return nullptr; } + if (ident_type == IDENTIFIER_VARYING) { + TkPos prev_pos = _get_tkpos(); + Token next_token = _get_token(); + _set_tkpos(prev_pos); + String error; + if (next_token.type == TK_OP_ASSIGN) { + if (!_validate_varying_assign(shader->varyings[identifier], &error)) { + _set_error(error); + return nullptr; + } + } else { + if (!_validate_varying_using(shader->varyings[identifier], &error)) { + _set_error(error); + return nullptr; + } + } + } + last_const = is_const; if (ident_type == IDENTIFIER_FUNCTION) { _set_error("Can't use function as identifier: " + String(identifier)); @@ -3758,16 +3840,26 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons Node *index_expression = nullptr; Node *call_expression = nullptr; + Node *assign_expression = nullptr; if (array_size > 0) { tk = _get_token(); - if (tk.type != TK_BRACKET_OPEN && tk.type != TK_PERIOD) { - _set_error("Expected '[' or '.'"); + if (tk.type != TK_BRACKET_OPEN && tk.type != TK_PERIOD && tk.type != TK_OP_ASSIGN) { + _set_error("Expected '[','.' or '='"); return nullptr; } - if (tk.type == TK_PERIOD) { + if (tk.type == TK_OP_ASSIGN) { + if (is_const) { + _set_error("Constants cannot be modified."); + return nullptr; + } + assign_expression = _parse_array_constructor(p_block, p_function_info, data_type, struct_name, array_size); + if (!assign_expression) { + return nullptr; + } + } else if (tk.type == TK_PERIOD) { completion_class = TAG_ARRAY; p_block->block_tag = SubClassTag::TAG_ARRAY; call_expression = _parse_and_reduce_expression(p_block, p_function_info); @@ -3791,7 +3883,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (index_expression->type == Node::TYPE_CONSTANT) { ConstantNode *cnode = (ConstantNode *)index_expression; if (cnode) { - if (!cnode->values.empty()) { + if (!cnode->values.is_empty()) { int value = cnode->values[0].sint; if (value < 0 || value >= array_size) { _set_error(vformat("Index [%s] out of range [%s..%s]", value, 0, array_size - 1)); @@ -3814,6 +3906,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons arrname->struct_name = struct_name; arrname->index_expression = index_expression; arrname->call_expression = call_expression; + arrname->assign_expression = assign_expression; arrname->is_const = is_const; expr = arrname; @@ -4154,7 +4247,18 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (array_size > 0) { tk = _get_token(); - if (tk.type == TK_PERIOD) { + if (tk.type == TK_OP_ASSIGN) { + if (last_const) { + last_const = false; + _set_error("Constants cannot be modified."); + return nullptr; + } + Node *assign_expression = _parse_array_constructor(p_block, p_function_info, member_type, member_struct_name, array_size); + if (!assign_expression) { + return nullptr; + } + mn->assign_expression = assign_expression; + } else if (tk.type == TK_PERIOD) { _set_error("Nested array length() is not yet implemented"); return nullptr; } else if (tk.type == TK_BRACKET_OPEN) { @@ -4171,7 +4275,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (index_expression->type == Node::TYPE_CONSTANT) { ConstantNode *cnode = (ConstantNode *)index_expression; if (cnode) { - if (!cnode->values.empty()) { + if (!cnode->values.is_empty()) { int value = cnode->values[0].sint; if (value < 0 || value >= array_size) { _set_error(vformat("Index [%s] out of range [%s..%s]", value, 0, array_size - 1)); @@ -4189,7 +4293,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons mn->index_expression = index_expression; } else { - _set_error("Expected '[' or '.'"); + _set_error("Expected '[','.' or '='"); return nullptr; } } @@ -5010,17 +5114,53 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun decl.name = name; decl.size = 0U; + pos = _get_tkpos(); tk = _get_token(); if (tk.type == TK_BRACKET_CLOSE) { unknown_size = true; } else { if (tk.type != TK_INT_CONSTANT || ((int)tk.constant) <= 0) { + _set_tkpos(pos); + Node *n = _parse_and_reduce_expression(p_block, p_function_info); + if (n) { + if (n->type == Node::TYPE_VARIABLE) { + VariableNode *vn = static_cast<VariableNode *>(n); + if (vn) { + ConstantNode::Value v; + DataType data_type; + + _find_identifier(p_block, false, p_function_info, vn->name, &data_type, nullptr, &is_const, nullptr, nullptr, &v); + + if (is_const) { + if (data_type == TYPE_INT) { + int32_t value = v.sint; + if (value > 0) { + node->size_expression = n; + decl.size = (uint32_t)value; + } + } else if (data_type == TYPE_UINT) { + uint32_t value = v.uint; + if (value > 0U) { + node->size_expression = n; + decl.size = value; + } + } + } + } + } else if (n->type == Node::TYPE_OPERATOR) { + _set_error("Array size expressions are not yet implemented."); + return ERR_PARSE_ERROR; + } + } + } else if (((int)tk.constant) > 0) { + decl.size = (uint32_t)tk.constant; + } + + if (decl.size == 0U) { _set_error("Expected integer constant > 0 or ']'"); return ERR_PARSE_ERROR; } - - decl.size = ((uint32_t)tk.constant); tk = _get_token(); if (tk.type != TK_BRACKET_CLOSE) { @@ -5218,7 +5358,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun _set_error("Expected array initialization"); return ERR_PARSE_ERROR; } - if (is_const) { + if (node->is_const) { _set_error("Expected initialization of constant"); return ERR_PARSE_ERROR; } @@ -5252,6 +5392,13 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun } decl.initializer = n; + if (n->type == Node::TYPE_CONSTANT) { + ConstantNode *const_node = static_cast<ConstantNode *>(n); + if (const_node && const_node->values.size() == 1) { + var.value = const_node->values[0]; + } + } + if (var.type == TYPE_STRUCT ? (var.struct_name != n->get_datatype_name()) : (var.type != n->get_datatype())) { _set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (var.type == TYPE_STRUCT ? String(var.struct_name) : get_datatype_name(var.type)) + "'"); return ERR_PARSE_ERROR; @@ -5420,18 +5567,29 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun ControlFlowNode *flow = (ControlFlowNode *)switch_block->statements[i]; if (flow) { if (flow->flow_op == FLOW_OP_CASE) { - ConstantNode *n2 = static_cast<ConstantNode *>(flow->expressions[0]); - if (!n2) { - return ERR_PARSE_ERROR; - } - if (n2->values.empty()) { - return ERR_PARSE_ERROR; - } - if (constants.has(n2->values[0].sint)) { - _set_error("Duplicated case label: '" + itos(n2->values[0].sint) + "'"); - return ERR_PARSE_ERROR; + if (flow->expressions[0]->type == Node::TYPE_CONSTANT) { + ConstantNode *cn = static_cast<ConstantNode *>(flow->expressions[0]); + if (!cn || cn->values.is_empty()) { + return ERR_PARSE_ERROR; + } + if (constants.has(cn->values[0].sint)) { + _set_error("Duplicated case label: '" + itos(cn->values[0].sint) + "'"); + return ERR_PARSE_ERROR; + } + constants.insert(cn->values[0].sint); + } else if (flow->expressions[0]->type == Node::TYPE_VARIABLE) { + VariableNode *vn = static_cast<VariableNode *>(flow->expressions[0]); + if (!vn) { + return ERR_PARSE_ERROR; + } + ConstantNode::Value v; + _find_identifier(p_block, false, p_function_info, vn->name, nullptr, nullptr, nullptr, nullptr, nullptr, &v); + if (constants.has(v.sint)) { + _set_error("Duplicated case label: '" + itos(v.sint) + "'"); + return ERR_PARSE_ERROR; + } + constants.insert(v.sint); } - constants.insert(n2->values[0].sint); } else if (flow->flow_op == FLOW_OP_DEFAULT) { continue; } else { @@ -5467,12 +5625,38 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun tk = _get_token(); } + Node *n = nullptr; + if (tk.type != TK_INT_CONSTANT) { - _set_error("Expected integer constant"); - return ERR_PARSE_ERROR; - } + bool correct_constant_expression = false; + DataType data_type; + + if (tk.type == TK_IDENTIFIER) { + bool is_const; + _find_identifier(p_block, false, p_function_info, tk.text, &data_type, nullptr, &is_const); + if (is_const) { + if (data_type == TYPE_INT) { + correct_constant_expression = true; + } + } + } + if (!correct_constant_expression) { + _set_error("Expected integer constant"); + return ERR_PARSE_ERROR; + } + + VariableNode *vn = alloc_node<VariableNode>(); + vn->name = tk.text; + n = vn; + } else { + ConstantNode::Value v; + v.sint = (int)tk.constant * sign; - int constant = (int)tk.constant * sign; + ConstantNode *cn = alloc_node<ConstantNode>(); + cn->values.push_back(v); + cn->datatype = TYPE_INT; + n = cn; + } tk = _get_token(); @@ -5484,12 +5668,6 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun ControlFlowNode *cf = alloc_node<ControlFlowNode>(); cf->flow_op = FLOW_OP_CASE; - ConstantNode *n = alloc_node<ConstantNode>(); - ConstantNode::Value v; - v.sint = constant; - n->values.push_back(v); - n->datatype = TYPE_INT; - BlockNode *case_block = alloc_node<BlockNode>(); case_block->block_type = BlockNode::BLOCK_TYPE_CASE; case_block->parent_block = p_block; @@ -5683,6 +5861,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun return ERR_BUG; } + String return_struct_name = String(b->parent_function->return_struct_name); + ControlFlowNode *flow = alloc_node<ControlFlowNode>(); flow->flow_op = FLOW_OP_RETURN; @@ -5691,7 +5871,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun if (tk.type == TK_SEMICOLON) { //all is good if (b->parent_function->return_type != TYPE_VOID) { - _set_error("Expected return with expression of type '" + get_datatype_name(b->parent_function->return_type) + "'"); + _set_error("Expected return with an expression of type '" + (return_struct_name != "" ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + "'"); return ERR_PARSE_ERROR; } } else { @@ -5701,8 +5881,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun return ERR_PARSE_ERROR; } - if (b->parent_function->return_type != expr->get_datatype()) { - _set_error("Expected return expression of type '" + get_datatype_name(b->parent_function->return_type) + "'"); + if (b->parent_function->return_type != expr->get_datatype() || return_struct_name != expr->get_datatype_name()) { + _set_error("Expected return with an expression of type '" + (return_struct_name != "" ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + "'"); return ERR_PARSE_ERROR; } @@ -5955,6 +6135,10 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); if (tk.type == TK_IDENTIFIER) { st.name = tk.text; + if (shader->structs.has(st.name)) { + _set_error("Redefinition of '" + String(st.name) + "'"); + return ERR_PARSE_ERROR; + } tk = _get_token(); if (tk.type != TK_CURLY_BRACKET_OPEN) { _set_error("Expected '{'"); @@ -6147,6 +6331,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct return ERR_PARSE_ERROR; } + TkPos name_pos = _get_tkpos(); name = tk.text; if (_find_identifier(nullptr, false, FunctionInfo(), name)) { @@ -6192,7 +6377,9 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } uniform2.texture_order = -1; - uniform2.order = uniforms++; + if (uniform_scope != ShaderNode::Uniform::SCOPE_INSTANCE) { + uniform2.order = uniforms++; + } } uniform2.type = type; uniform2.scope = uniform_scope; @@ -6260,7 +6447,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); } - if (tk.type != TK_REAL_CONSTANT && tk.type != TK_INT_CONSTANT) { + if (tk.type != TK_FLOAT_CONSTANT && tk.type != TK_INT_CONSTANT) { _set_error("Expected integer constant"); return ERR_PARSE_ERROR; } @@ -6284,7 +6471,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); } - if (tk.type != TK_REAL_CONSTANT && tk.type != TK_INT_CONSTANT) { + if (tk.type != TK_FLOAT_CONSTANT && tk.type != TK_INT_CONSTANT) { _set_error("Expected integer constant after ','"); return ERR_PARSE_ERROR; } @@ -6297,7 +6484,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (tk.type == TK_COMMA) { tk = _get_token(); - if (tk.type != TK_REAL_CONSTANT && tk.type != TK_INT_CONSTANT) { + if (tk.type != TK_FLOAT_CONSTANT && tk.type != TK_INT_CONSTANT) { _set_error("Expected integer constant after ','"); return ERR_PARSE_ERROR; } @@ -6426,11 +6613,12 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct _set_error("Expected ';'"); return ERR_PARSE_ERROR; } - } else { + } else { // varying ShaderNode::Varying varying; varying.type = type; varying.precision = precision; varying.interpolation = interpolation; + varying.tkpos = name_pos; tk = _get_token(); if (tk.type != TK_SEMICOLON && tk.type != TK_BRACKET_OPEN) { @@ -7043,6 +7231,14 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); } + for (Map<StringName, ShaderNode::Varying>::Element *E = shader->varyings.front(); E; E = E->next()) { + if (E->get().stage == ShaderNode::Varying::STAGE_VERTEX || E->get().stage == ShaderNode::Varying::STAGE_FRAGMENT) { + _set_tkpos(E->get().tkpos); + _set_error(RTR("Varying must only be used in two different stages, which can be 'vertex' 'fragment' and 'light'")); + return ERR_PARSE_ERROR; + } + } + return OK; } diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index 3a9f408dc0..14594b039c 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -41,12 +41,17 @@ class ShaderLanguage { public: + struct TkPos { + int char_idx; + int tk_line; + }; + enum TokenType { TK_EMPTY, TK_IDENTIFIER, TK_TRUE, TK_FALSE, - TK_REAL_CONSTANT, + TK_FLOAT_CONSTANT, TK_INT_CONSTANT, TK_TYPE_VOID, TK_TYPE_BOOL, @@ -414,6 +419,7 @@ public: StringName name; Node *index_expression = nullptr; Node *call_expression = nullptr; + Node *assign_expression = nullptr; bool is_const = false; virtual DataType get_datatype() const { return datatype_cache; } @@ -437,6 +443,7 @@ public: DataType datatype = TYPE_VOID; String struct_name; bool is_const = false; + Node *size_expression = nullptr; struct Declaration { StringName name; @@ -496,6 +503,7 @@ public: int line; //for completion int array_size; bool is_const; + ConstantNode::Value value; }; Map<StringName, Variable> variables; @@ -519,13 +527,14 @@ public: DataType basetype = TYPE_VOID; bool basetype_const = false; StringName base_struct_name; - DataPrecision precision; + DataPrecision precision = PRECISION_DEFAULT; DataType datatype = TYPE_VOID; int array_size = 0; StringName struct_name; StringName name; Node *owner = nullptr; Node *index_expression = nullptr; + Node *assign_expression = nullptr; bool has_swizzling_duplicates = false; virtual DataType get_datatype() const { return datatype; } @@ -594,10 +603,21 @@ public: }; struct Varying { + enum Stage { + STAGE_UNKNOWN, + STAGE_VERTEX, // transition stage to STAGE_VERTEX_TO_FRAGMENT or STAGE_VERTEX_TO_LIGHT, emits error if they are not used + STAGE_FRAGMENT, // transition stage to STAGE_FRAGMENT_TO_LIGHT, emits error if it's not used + STAGE_VERTEX_TO_FRAGMENT, + STAGE_VERTEX_TO_LIGHT, + STAGE_FRAGMENT_TO_LIGHT, + }; + + Stage stage = STAGE_UNKNOWN; DataType type = TYPE_VOID; DataInterpolation interpolation = INTERPOLATION_FLAT; DataPrecision precision = PRECISION_DEFAULT; int array_size = 0; + TkPos tkpos; Varying() {} }; @@ -774,11 +794,7 @@ private: int tk_line; StringName current_function; - - struct TkPos { - int char_idx; - int tk_line; - }; + bool last_const = false; TkPos _get_tkpos() { TkPos tkp; @@ -819,7 +835,7 @@ private: IDENTIFIER_CONSTANT, }; - bool _find_identifier(const BlockNode *p_block, bool p_allow_reassign, const FunctionInfo &p_function_info, const StringName &p_identifier, DataType *r_data_type = nullptr, IdentifierType *r_type = nullptr, bool *r_is_const = nullptr, int *r_array_size = nullptr, StringName *r_struct_name = nullptr); + bool _find_identifier(const BlockNode *p_block, bool p_allow_reassign, const FunctionInfo &p_function_info, const StringName &p_identifier, DataType *r_data_type = nullptr, IdentifierType *r_type = nullptr, bool *r_is_const = nullptr, int *r_array_size = nullptr, StringName *r_struct_name = nullptr, ConstantNode::Value *r_constant_value = nullptr); bool _is_operator_assign(Operator p_op) const; 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); @@ -859,8 +875,11 @@ private: bool _parse_function_arguments(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, int *r_complete_arg = nullptr); bool _propagate_function_call_sampler_uniform_settings(StringName p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat); bool _propagate_function_call_sampler_builtin_reference(StringName p_name, int p_argument, const StringName &p_builtin); + bool _validate_varying_assign(ShaderNode::Varying &p_varying, String *r_message); + bool _validate_varying_using(ShaderNode::Varying &p_varying, String *r_message); Node *_parse_expression(BlockNode *p_block, const FunctionInfo &p_function_info); + Node *_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info, DataType p_type, const StringName &p_struct_name, int p_array_size); ShaderLanguage::Node *_reduce_expression(BlockNode *p_block, ShaderLanguage::Node *p_node); Node *_parse_and_reduce_expression(BlockNode *p_block, const FunctionInfo &p_function_info); diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp index bd61f2a549..e99b8504bb 100644 --- a/servers/rendering/shader_types.cpp +++ b/servers/rendering/shader_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -67,6 +67,12 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["INSTANCE_ID"] = constt(ShaderLanguage::TYPE_INT); shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["INSTANCE_CUSTOM"] = constt(ShaderLanguage::TYPE_VEC4); 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"].can_discard = false; //builtins @@ -88,8 +94,8 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["TANGENT"] = ShaderLanguage::TYPE_VEC3; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["BINORMAL"] = ShaderLanguage::TYPE_VEC3; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW"] = constt(ShaderLanguage::TYPE_VEC3); - shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NORMALMAP"] = ShaderLanguage::TYPE_VEC3; - shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NORMALMAP_DEPTH"] = ShaderLanguage::TYPE_FLOAT; + shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NORMAL_MAP"] = ShaderLanguage::TYPE_VEC3; + shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NORMAL_MAP_DEPTH"] = ShaderLanguage::TYPE_FLOAT; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["UV"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["UV2"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["COLOR"] = constt(ShaderLanguage::TYPE_VEC4); @@ -236,8 +242,8 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["LIGHT_VERTEX"] = ShaderLanguage::TYPE_VEC3; shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4); shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMAL"] = ShaderLanguage::TYPE_VEC3; - shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMALMAP"] = ShaderLanguage::TYPE_VEC3; - shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMALMAP_DEPTH"] = ShaderLanguage::TYPE_FLOAT; + shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMAL_MAP"] = ShaderLanguage::TYPE_VEC3; + shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMAL_MAP_DEPTH"] = ShaderLanguage::TYPE_FLOAT; shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["UV"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4; shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D); @@ -341,7 +347,7 @@ ShaderTypes::ShaderTypes() { emit_vertex_func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("custom", ShaderLanguage::TYPE_VEC4)); emit_vertex_func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("flags", ShaderLanguage::TYPE_UINT)); emit_vertex_func.return_type = ShaderLanguage::TYPE_BOOL; //whether it could emit - shader_modes[RS::SHADER_PARTICLES].functions["compute"].stage_functions["emit_particle"] = emit_vertex_func; + shader_modes[RS::SHADER_PARTICLES].functions["compute"].stage_functions["emit_subparticle"] = emit_vertex_func; } shader_modes[RS::SHADER_PARTICLES].modes.push_back("collision_use_scale"); diff --git a/servers/rendering/shader_types.h b/servers/rendering/shader_types.h index 50f910babb..e59cef6b79 100644 --- a/servers/rendering/shader_types.h +++ b/servers/rendering/shader_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index ea37e0c143..809343114c 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -242,22 +242,24 @@ RID RenderingServer::_make_test_cube() { RID RenderingServer::make_sphere_mesh(int p_lats, int p_lons, float p_radius) { Vector<Vector3> vertices; Vector<Vector3> normals; + const double lat_step = Math_TAU / p_lats; + const double lon_step = Math_TAU / p_lons; for (int i = 1; i <= p_lats; i++) { - double lat0 = Math_PI * (-0.5 + (double)(i - 1) / p_lats); + double lat0 = lat_step * (i - 1) - Math_TAU / 4; double z0 = Math::sin(lat0); double zr0 = Math::cos(lat0); - double lat1 = Math_PI * (-0.5 + (double)i / p_lats); + double lat1 = lat_step * i - Math_TAU / 4; double z1 = Math::sin(lat1); double zr1 = Math::cos(lat1); for (int j = p_lons; j >= 1; j--) { - double lng0 = 2 * Math_PI * (double)(j - 1) / p_lons; + double lng0 = lon_step * (j - 1); double x0 = Math::cos(lng0); double y0 = Math::sin(lng0); - double lng1 = 2 * Math_PI * (double)(j) / p_lons; + double lng1 = lon_step * j; double x1 = Math::cos(lng1); double y1 = Math::sin(lng1); @@ -315,8 +317,10 @@ RID RenderingServer::get_white_texture() { #define SMALL_VEC2 Vector2(0.00001, 0.00001) #define SMALL_VEC3 Vector3(0.00001, 0.00001, 0.00001) -Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t p_stride, Vector<uint8_t> &r_vertex_array, int p_vertex_array_len, Vector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> &r_bone_aabb) { +Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t p_vertex_stride, uint32_t p_attrib_stride, uint32_t p_skin_stride, Vector<uint8_t> &r_vertex_array, Vector<uint8_t> &r_attrib_array, Vector<uint8_t> &r_skin_array, int p_vertex_array_len, Vector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> &r_bone_aabb) { uint8_t *vw = r_vertex_array.ptrw(); + uint8_t *aw = r_attrib_array.ptrw(); + uint8_t *sw = r_skin_array.ptrw(); uint8_t *iw = nullptr; if (r_index_array.size()) { @@ -345,7 +349,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint for (int i = 0; i < p_vertex_array_len; i++) { float vector[2] = { src[i].x, src[i].y }; - copymem(&vw[p_offsets[ai] + i * p_stride], vector, sizeof(float) * 2); + copymem(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(float) * 2); if (i == 0) { aabb = Rect2(src[i], SMALL_VEC2); //must have a bit of size @@ -370,7 +374,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint for (int i = 0; i < p_vertex_array_len; i++) { float vector[3] = { src[i].x, src[i].y, src[i].z }; - copymem(&vw[p_offsets[ai] + i * p_stride], vector, sizeof(float) * 3); + copymem(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(float) * 3); if (i == 0) { aabb = AABB(src[i], SMALL_VEC3); @@ -391,26 +395,15 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint ERR_FAIL_COND_V(array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER); const Vector3 *src = array.ptr(); + for (int i = 0; i < p_vertex_array_len; i++) { + Vector3 n = src[i] * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5); - // setting vertices means regenerating the AABB + uint32_t value = 0; + value |= CLAMP(int(n.x * 1023.0), 0, 1023); + value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10; + value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20; - if (p_format & ARRAY_COMPRESS_NORMAL) { - for (int i = 0; i < p_vertex_array_len; i++) { - int8_t vector[4] = { - (int8_t)CLAMP(src[i].x * 127, -128, 127), - (int8_t)CLAMP(src[i].y * 127, -128, 127), - (int8_t)CLAMP(src[i].z * 127, -128, 127), - 0, - }; - - copymem(&vw[p_offsets[ai] + i * p_stride], vector, 4); - } - - } else { - for (int i = 0; i < p_vertex_array_len; i++) { - float vector[3] = { src[i].x, src[i].y, src[i].z }; - copymem(&vw[p_offsets[ai] + i * p_stride], vector, 3 * 4); - } + copymem(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4); } } break; @@ -424,29 +417,14 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint const real_t *src = array.ptr(); - if (p_format & ARRAY_COMPRESS_TANGENT) { - for (int i = 0; i < p_vertex_array_len; i++) { - int8_t xyzw[4] = { - (int8_t)CLAMP(src[i * 4 + 0] * 127, -128, 127), - (int8_t)CLAMP(src[i * 4 + 1] * 127, -128, 127), - (int8_t)CLAMP(src[i * 4 + 2] * 127, -128, 127), - (int8_t)CLAMP(src[i * 4 + 3] * 127, -128, 127) - }; - - copymem(&vw[p_offsets[ai] + i * p_stride], xyzw, 4); - } + for (int i = 0; i < p_vertex_array_len; i++) { + uint32_t value = 0; + value |= CLAMP(int((src[i * 4 + 0] * 0.5 + 0.5) * 1023.0), 0, 1023); + value |= CLAMP(int((src[i * 4 + 1] * 0.5 + 0.5) * 1023.0), 0, 1023) << 10; + value |= CLAMP(int((src[i * 4 + 2] * 0.5 + 0.5) * 1023.0), 0, 1023) << 20; + value |= CLAMP(int((src[i * 4 + 3] * 0.5 + 0.5) * 3.0), 0, 3) << 30; - } else { - for (int i = 0; i < p_vertex_array_len; i++) { - float xyzw[4] = { - src[i * 4 + 0], - src[i * 4 + 1], - src[i * 4 + 2], - src[i * 4 + 3] - }; - - copymem(&vw[p_offsets[ai] + i * p_stride], xyzw, 4 * 4); - } + copymem(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4); } } break; @@ -458,23 +436,14 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint ERR_FAIL_COND_V(array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER); const Color *src = array.ptr(); - - if (p_format & ARRAY_COMPRESS_COLOR) { - for (int i = 0; i < p_vertex_array_len; i++) { - uint8_t colors[4]; - - for (int j = 0; j < 4; j++) { - colors[j] = CLAMP(int((src[i][j]) * 255.0), 0, 255); - } - - copymem(&vw[p_offsets[ai] + i * p_stride], colors, 4); - } - } else { - for (int i = 0; i < p_vertex_array_len; i++) { - copymem(&vw[p_offsets[ai] + i * p_stride], &src[i], 4 * 4); - } + uint16_t color16[4]; + for (int i = 0; i < p_vertex_array_len; i++) { + color16[0] = Math::make_half_float(src[i].r); + color16[1] = Math::make_half_float(src[i].g); + color16[2] = Math::make_half_float(src[i].b); + color16[3] = Math::make_half_float(src[i].a); + copymem(&aw[p_offsets[ai] + i * p_attrib_stride], color16, 8); } - } break; case RS::ARRAY_TEX_UV: { ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_VECTOR3_ARRAY && p_arrays[ai].get_type() != Variant::PACKED_VECTOR2_ARRAY, ERR_INVALID_PARAMETER); @@ -485,18 +454,10 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint const Vector2 *src = array.ptr(); - if (p_format & ARRAY_COMPRESS_TEX_UV) { - for (int i = 0; i < p_vertex_array_len; i++) { - uint16_t uv[2] = { Math::make_half_float(src[i].x), Math::make_half_float(src[i].y) }; - copymem(&vw[p_offsets[ai] + i * p_stride], uv, 2 * 2); - } - - } else { - for (int i = 0; i < p_vertex_array_len; i++) { - float uv[2] = { src[i].x, src[i].y }; + for (int i = 0; i < p_vertex_array_len; i++) { + float uv[2] = { src[i].x, src[i].y }; - copymem(&vw[p_offsets[ai] + i * p_stride], uv, 2 * 4); - } + copymem(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 4); } } break; @@ -510,37 +471,90 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint const Vector2 *src = array.ptr(); - if (p_format & ARRAY_COMPRESS_TEX_UV2) { - for (int i = 0; i < p_vertex_array_len; i++) { - uint16_t uv[2] = { Math::make_half_float(src[i].x), Math::make_half_float(src[i].y) }; - copymem(&vw[p_offsets[ai] + i * p_stride], uv, 2 * 2); - } + for (int i = 0; i < p_vertex_array_len; i++) { + uint16_t uv[2] = { Math::make_half_float(src[i].x), Math::make_half_float(src[i].y) }; + copymem(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 2); + } + } break; + case RS::ARRAY_CUSTOM0: + case RS::ARRAY_CUSTOM1: + case RS::ARRAY_CUSTOM2: + case RS::ARRAY_CUSTOM3: { + uint32_t type = (p_format >> (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * (RS::ARRAY_CUSTOM0 - ai))) & ARRAY_FORMAT_CUSTOM_MASK; + switch (type) { + case ARRAY_CUSTOM_RGBA8_UNORM: + case ARRAY_CUSTOM_RGBA8_SNORM: + case ARRAY_CUSTOM_RG_HALF: { + //size 4 + ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_BYTE_ARRAY, ERR_INVALID_PARAMETER); - } else { - for (int i = 0; i < p_vertex_array_len; i++) { - float uv[2] = { src[i].x, src[i].y }; + Vector<uint8_t> array = p_arrays[ai]; + + ERR_FAIL_COND_V(array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER); - copymem(&vw[p_offsets[ai] + i * p_stride], uv, 2 * 4); + const uint8_t *src = array.ptr(); + + for (int i = 0; i < p_vertex_array_len; i++) { + copymem(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * 4], 4); + } + + } break; + case ARRAY_CUSTOM_RGBA_HALF: { + //size 8 + ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_BYTE_ARRAY, ERR_INVALID_PARAMETER); + + Vector<uint8_t> array = p_arrays[ai]; + + ERR_FAIL_COND_V(array.size() != p_vertex_array_len * 8, ERR_INVALID_PARAMETER); + + const uint8_t *src = array.ptr(); + + for (int i = 0; i < p_vertex_array_len; i++) { + copymem(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * 8], 8); + } + } break; + case ARRAY_CUSTOM_R_FLOAT: + case ARRAY_CUSTOM_RG_FLOAT: + case ARRAY_CUSTOM_RGB_FLOAT: + case ARRAY_CUSTOM_RGBA_FLOAT: { + //RF + ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_FLOAT32_ARRAY, ERR_INVALID_PARAMETER); + + Vector<float> array = p_arrays[ai]; + int32_t s = ARRAY_CUSTOM_R_FLOAT - ai + 1; + + ERR_FAIL_COND_V(array.size() != p_vertex_array_len * s, ERR_INVALID_PARAMETER); + + const float *src = array.ptr(); + + for (int i = 0; i < p_vertex_array_len; i++) { + copymem(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * s], 4 * s); + } + } break; + default: { } } + } break; case RS::ARRAY_WEIGHTS: { ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_FLOAT32_ARRAY, ERR_INVALID_PARAMETER); + uint32_t bone_count = (p_format & ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 8 : 4; + Vector<real_t> array = p_arrays[ai]; - ERR_FAIL_COND_V(array.size() != p_vertex_array_len * RS::ARRAY_WEIGHTS_SIZE, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(array.size() != (int32_t)(p_vertex_array_len * bone_count), ERR_INVALID_PARAMETER); const real_t *src = array.ptr(); { + uint16_t data[8]; for (int i = 0; i < p_vertex_array_len; i++) { - uint16_t data[RS::ARRAY_WEIGHTS_SIZE]; - for (int j = 0; j < RS::ARRAY_WEIGHTS_SIZE; j++) { - data[j] = CLAMP(src[i * RS::ARRAY_WEIGHTS_SIZE + j] * 65535, 0, 65535); + for (uint32_t j = 0; j < bone_count; j++) { + data[j] = CLAMP(src[i * bone_count + j] * 65535, 0, 65535); } - copymem(&vw[p_offsets[ai] + i * p_stride], data, 2 * 4); + copymem(&sw[p_offsets[ai] + i * p_skin_stride], data, 2 * bone_count); } } @@ -550,21 +564,25 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint Vector<int> array = p_arrays[ai]; - ERR_FAIL_COND_V(array.size() != p_vertex_array_len * RS::ARRAY_WEIGHTS_SIZE, ERR_INVALID_PARAMETER); + uint32_t bone_count = (p_format & ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 8 : 4; + + ERR_FAIL_COND_V(array.size() != (int32_t)(p_vertex_array_len * bone_count), ERR_INVALID_PARAMETER); const int *src = array.ptr(); + uint16_t data[8]; + for (int i = 0; i < p_vertex_array_len; i++) { - uint16_t data[RS::ARRAY_WEIGHTS_SIZE]; - for (int j = 0; j < RS::ARRAY_WEIGHTS_SIZE; j++) { - data[j] = src[i * RS::ARRAY_WEIGHTS_SIZE + j]; + for (uint32_t j = 0; j < bone_count; j++) { + data[j] = src[i * bone_count + j]; max_bone = MAX(data[j], max_bone); } - copymem(&vw[p_offsets[ai] + i * p_stride], data, 2 * 4); + copymem(&sw[p_offsets[ai] + i * p_skin_stride], data, 2 * bone_count); } } break; + case RS::ARRAY_INDEX: { ERR_FAIL_NULL_V(iw, ERR_INVALID_DATA); ERR_FAIL_COND_V(p_index_array_len <= 0, ERR_INVALID_DATA); @@ -604,6 +622,8 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint r_bone_aabb.resize(total_bones); + int weight_count = (p_format & ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 8 : 4; + if (first) { for (int i = 0; i < total_bones; i++) { r_bone_aabb.write[i].size = Vector3(-1, -1, -1); //negative means unused @@ -616,7 +636,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint bool any_valid = false; - if (vertices.size() && bones.size() == vertices.size() * 4 && weights.size() == bones.size()) { + if (vertices.size() && bones.size() == vertices.size() * weight_count && weights.size() == bones.size()) { int vs = vertices.size(); const Vector3 *rv = vertices.ptr(); const int *rb = bones.ptr(); @@ -626,9 +646,9 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint for (int i = 0; i < vs; i++) { Vector3 v = rv[i]; - for (int j = 0; j < 4; j++) { - int idx = rb[i * 4 + j]; - float w = rw[i * 4 + j]; + for (int j = 0; j < weight_count; j++) { + int idx = rb[i * weight_count + j]; + float w = rw[i * weight_count + j]; if (w == 0) { continue; //break; } @@ -652,23 +672,62 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint return OK; } -uint32_t RenderingServer::mesh_surface_get_format_offset(uint32_t p_format, int p_vertex_len, int p_index_len, int p_array_index) const { +uint32_t RenderingServer::mesh_surface_get_format_offset(uint32_t p_format, int p_vertex_len, int p_array_index) const { + p_format &= ~ARRAY_FORMAT_INDEX; uint32_t offsets[ARRAY_MAX]; - mesh_surface_make_offsets_from_format(p_format, p_vertex_len, p_index_len, offsets); + uint32_t vstr; + uint32_t astr; + uint32_t sstr; + mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, astr, sstr); return offsets[p_array_index]; } -uint32_t RenderingServer::mesh_surface_get_format_stride(uint32_t p_format, int p_vertex_len, int p_index_len) const { +uint32_t RenderingServer::mesh_surface_get_format_vertex_stride(uint32_t p_format, int p_vertex_len) const { + p_format &= ~ARRAY_FORMAT_INDEX; + uint32_t offsets[ARRAY_MAX]; + uint32_t vstr; + uint32_t astr; + uint32_t sstr; + mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, astr, sstr); + return vstr; +} +uint32_t RenderingServer::mesh_surface_get_format_attribute_stride(uint32_t p_format, int p_vertex_len) const { + p_format &= ~ARRAY_FORMAT_INDEX; + uint32_t offsets[ARRAY_MAX]; + uint32_t vstr; + uint32_t astr; + uint32_t sstr; + mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, astr, sstr); + return astr; +} +uint32_t RenderingServer::mesh_surface_get_format_skin_stride(uint32_t p_format, int p_vertex_len) const { + p_format &= ~ARRAY_FORMAT_INDEX; uint32_t offsets[ARRAY_MAX]; - return mesh_surface_make_offsets_from_format(p_format, p_vertex_len, p_index_len, offsets); + uint32_t vstr; + uint32_t astr; + uint32_t sstr; + mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, astr, sstr); + return sstr; } -uint32_t RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets) const { - int total_elem_size = 0; +void RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets, uint32_t &r_vertex_element_size, uint32_t &r_attrib_element_size, uint32_t &r_skin_element_size) const { + r_vertex_element_size = 0; + r_attrib_element_size = 0; + r_skin_element_size = 0; + + uint32_t *size_accum; for (int i = 0; i < RS::ARRAY_MAX; i++) { r_offsets[i] = 0; //reset + if (i == RS::ARRAY_VERTEX) { + size_accum = &r_vertex_element_size; + } else if (i == RS::ARRAY_COLOR) { + size_accum = &r_attrib_element_size; + } else if (i == RS::ARRAY_BONES) { + size_accum = &r_skin_element_size; + } + if (!(p_format & (1 << i))) { // no array continue; } @@ -693,53 +752,64 @@ uint32_t RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_forma } break; case RS::ARRAY_NORMAL: { - if (p_format & ARRAY_COMPRESS_NORMAL) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 3; - } - + elem_size = 4; } break; case RS::ARRAY_TANGENT: { - if (p_format & ARRAY_COMPRESS_TANGENT) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 4; - } - + elem_size = 4; } break; case RS::ARRAY_COLOR: { - if (p_format & ARRAY_COMPRESS_COLOR) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 4; - } + elem_size = 8; } break; case RS::ARRAY_TEX_UV: { - if (p_format & ARRAY_COMPRESS_TEX_UV) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 2; - } + elem_size = 8; } break; case RS::ARRAY_TEX_UV2: { - if (p_format & ARRAY_COMPRESS_TEX_UV2) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 2; - } + elem_size = 8; } break; + case RS::ARRAY_CUSTOM0: + case RS::ARRAY_CUSTOM1: + case RS::ARRAY_CUSTOM2: + case RS::ARRAY_CUSTOM3: { + uint32_t format = (p_format >> (ARRAY_FORMAT_CUSTOM_BASE + (ARRAY_FORMAT_CUSTOM_BITS * (i - ARRAY_CUSTOM0)))) & ARRAY_FORMAT_CUSTOM_MASK; + switch (format) { + case ARRAY_CUSTOM_RGBA8_UNORM: { + elem_size = 4; + } break; + case ARRAY_CUSTOM_RGBA8_SNORM: { + elem_size = 4; + } break; + case ARRAY_CUSTOM_RG_HALF: { + elem_size = 4; + } break; + case ARRAY_CUSTOM_RGBA_HALF: { + elem_size = 8; + } break; + case ARRAY_CUSTOM_R_FLOAT: { + elem_size = 4; + } break; + case ARRAY_CUSTOM_RG_FLOAT: { + elem_size = 8; + } break; + case ARRAY_CUSTOM_RGB_FLOAT: { + elem_size = 12; + } break; + case ARRAY_CUSTOM_RGBA_FLOAT: { + elem_size = 16; + } break; + } + } break; case RS::ARRAY_WEIGHTS: { - elem_size = sizeof(uint16_t) * 4; + uint32_t bone_count = (p_format & ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 8 : 4; + elem_size = sizeof(uint16_t) * bone_count; } break; case RS::ARRAY_BONES: { - elem_size = sizeof(uint16_t) * 4; - + uint32_t bone_count = (p_format & ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 8 : 4; + elem_size = sizeof(uint16_t) * bone_count; } break; case RS::ARRAY_INDEX: { if (p_index_len <= 0) { @@ -757,14 +827,13 @@ uint32_t RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_forma continue; } default: { - ERR_FAIL_V(0); + ERR_FAIL(); } } - r_offsets[i] = total_elem_size; - total_elem_size += elem_size; + r_offsets[i] = (*size_accum); + (*size_accum) += elem_size; } - return total_elem_size; } Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surface_data, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, uint32_t p_compress_format) { @@ -785,21 +854,35 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa format |= (1 << i); if (i == RS::ARRAY_VERTEX) { - Variant var = p_arrays[i]; - switch (var.get_type()) { + switch (p_arrays[i].get_type()) { case Variant::PACKED_VECTOR2_ARRAY: { - Vector<Vector2> v2 = var; + Vector<Vector2> v2 = p_arrays[i]; + array_len = v2.size(); } break; case Variant::PACKED_VECTOR3_ARRAY: { - Vector<Vector3> v3 = var; + Vector<Vector3> v3 = p_arrays[i]; + array_len = v3.size(); } break; default: { - Array v = var; + ERR_FAIL_V(ERR_INVALID_DATA); } break; } - - array_len = PackedVector3Array(p_arrays[i]).size(); ERR_FAIL_COND_V(array_len == 0, ERR_INVALID_DATA); + } else if (i == RS::ARRAY_BONES) { + switch (p_arrays[i].get_type()) { + case Variant::PACKED_INT32_ARRAY: { + Vector<Vector3> vertexes = p_arrays[RS::ARRAY_VERTEX]; + Vector<int32_t> bones = p_arrays[i]; + int32_t bone_8_group_count = bones.size() / (ARRAY_WEIGHTS_SIZE * 2); + int32_t vertex_count = vertexes.size(); + if (vertex_count == bone_8_group_count) { + format |= RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS; + } + } break; + default: { + ERR_FAIL_V(ERR_INVALID_DATA); + } break; + } } else if (i == RS::ARRAY_INDEX) { index_array_len = PackedInt32Array(p_arrays[i]).size(); } @@ -824,117 +907,28 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa uint32_t offsets[RS::ARRAY_MAX]; - int total_elem_size = 0; - - for (int i = 0; i < RS::ARRAY_MAX; i++) { - offsets[i] = 0; //reset - - if (!(format & (1 << i))) { // no array - continue; - } - - int elem_size = 0; - - switch (i) { - case RS::ARRAY_VERTEX: { - Variant arr = p_arrays[0]; - if (arr.get_type() == Variant::PACKED_VECTOR2_ARRAY) { - elem_size = 2; - p_compress_format |= ARRAY_FLAG_USE_2D_VERTICES; - } else if (arr.get_type() == Variant::PACKED_VECTOR3_ARRAY) { - p_compress_format &= ~ARRAY_FLAG_USE_2D_VERTICES; - elem_size = 3; - } else { - elem_size = (p_compress_format & ARRAY_FLAG_USE_2D_VERTICES) ? 2 : 3; - } - - { - elem_size *= sizeof(float); - } - - } break; - case RS::ARRAY_NORMAL: { - if (p_compress_format & ARRAY_COMPRESS_NORMAL) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 3; - } - - } break; - - case RS::ARRAY_TANGENT: { - if (p_compress_format & ARRAY_COMPRESS_TANGENT) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 4; - } - - } break; - case RS::ARRAY_COLOR: { - if (p_compress_format & ARRAY_COMPRESS_COLOR) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 4; - } - } break; - case RS::ARRAY_TEX_UV: { - if (p_compress_format & ARRAY_COMPRESS_TEX_UV) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 2; - } - - } break; - - case RS::ARRAY_TEX_UV2: { - if (p_compress_format & ARRAY_COMPRESS_TEX_UV2) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 2; - } - - } break; - case RS::ARRAY_WEIGHTS: { - elem_size = sizeof(uint16_t) * 4; - - } break; - case RS::ARRAY_BONES: { - elem_size = sizeof(uint16_t) * 4; - - } break; - case RS::ARRAY_INDEX: { - if (index_array_len <= 0) { - ERR_PRINT("index_array_len==NO_INDEX_ARRAY"); - break; - } - /* determine whether using 16 or 32 bits indices */ - if (array_len >= (1 << 16)) { - elem_size = 4; - - } else { - elem_size = 2; - } - offsets[i] = elem_size; - continue; - } - default: { - ERR_FAIL_V(ERR_BUG); - } - } + uint32_t vertex_element_size; + uint32_t attrib_element_size; + uint32_t skin_element_size; - offsets[i] = total_elem_size; - total_elem_size += elem_size; - } + mesh_surface_make_offsets_from_format(format, array_len, index_array_len, offsets, vertex_element_size, attrib_element_size, skin_element_size); uint32_t mask = (1 << ARRAY_MAX) - 1; format |= (~mask) & p_compress_format; //make the full format - int array_size = total_elem_size * array_len; + int vertex_array_size = vertex_element_size * array_len; + int attrib_array_size = attrib_element_size * array_len; + int skin_array_size = skin_element_size * array_len; + int index_array_size = offsets[RS::ARRAY_INDEX] * index_array_len; Vector<uint8_t> vertex_array; - vertex_array.resize(array_size); + vertex_array.resize(vertex_array_size); - int index_array_size = offsets[RS::ARRAY_INDEX] * index_array_len; + Vector<uint8_t> attrib_array; + attrib_array.resize(attrib_array_size); + + Vector<uint8_t> skin_array; + skin_array.resize(skin_array_size); Vector<uint8_t> index_array; index_array.resize(index_array_size); @@ -942,22 +936,29 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa AABB aabb; Vector<AABB> bone_aabb; - Error err = _surface_set_data(p_arrays, format, offsets, total_elem_size, vertex_array, array_len, index_array, index_array_len, aabb, bone_aabb); + Error err = _surface_set_data(p_arrays, format, offsets, vertex_element_size, attrib_element_size, skin_element_size, vertex_array, attrib_array, skin_array, array_len, index_array, index_array_len, aabb, bone_aabb); ERR_FAIL_COND_V_MSG(err != OK, ERR_INVALID_DATA, "Invalid array format for surface."); - Vector<Vector<uint8_t>> blend_shape_data; - - for (int i = 0; i < p_blend_shapes.size(); i++) { - Vector<uint8_t> vertex_array_shape; - vertex_array_shape.resize(array_size); - Vector<uint8_t> noindex; - - AABB laabb; - Error err2 = _surface_set_data(p_blend_shapes[i], format & ~ARRAY_FORMAT_INDEX, offsets, total_elem_size, vertex_array_shape, array_len, noindex, 0, laabb, bone_aabb); - aabb.merge_with(laabb); - ERR_FAIL_COND_V_MSG(err2 != OK, ERR_INVALID_DATA, "Invalid blend shape array format for surface."); + Vector<uint8_t> blend_shape_data; + uint32_t blend_shape_count = 0; - blend_shape_data.push_back(vertex_array_shape); + if (p_blend_shapes.size()) { + uint32_t bs_format = format & RS::ARRAY_FORMAT_BLEND_SHAPE_MASK; + for (int i = 0; i < p_blend_shapes.size(); i++) { + Vector<uint8_t> vertex_array_shape; + vertex_array_shape.resize(vertex_array_size); + Vector<uint8_t> noindex; + Vector<uint8_t> noattrib; + Vector<uint8_t> noskin; + + AABB laabb; + Error err2 = _surface_set_data(p_blend_shapes[i], bs_format, offsets, vertex_element_size, 0, 0, vertex_array_shape, noattrib, noskin, array_len, noindex, 0, laabb, bone_aabb); + aabb.merge_with(laabb); + ERR_FAIL_COND_V_MSG(err2 != OK, ERR_INVALID_DATA, "Invalid blend shape array format for surface."); + + blend_shape_data.append_array(vertex_array_shape); + blend_shape_count++; + } } Vector<SurfaceData::LOD> lods; if (index_array_len) { @@ -1004,10 +1005,12 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa surface_data.primitive = p_primitive; surface_data.aabb = aabb; surface_data.vertex_data = vertex_array; + surface_data.attribute_data = attrib_array; + surface_data.skin_data = skin_array; surface_data.vertex_count = array_len; surface_data.index_data = index_array; surface_data.index_count = index_array_len; - surface_data.blend_shapes = blend_shape_data; + surface_data.blend_shape_data = blend_shape_data; surface_data.bone_aabbs = bone_aabb; surface_data.lods = lods; @@ -1023,110 +1026,20 @@ void RenderingServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_p mesh_add_surface(p_mesh, sd); } -Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t> p_vertex_data, int p_vertex_len, Vector<uint8_t> p_index_data, int p_index_len) const { - uint32_t offsets[ARRAY_MAX]; - - int total_elem_size = 0; - - for (int i = 0; i < RS::ARRAY_MAX; i++) { - offsets[i] = 0; //reset - - if (!(p_format & (1 << i))) { // no array - continue; - } - - int elem_size = 0; - - switch (i) { - case RS::ARRAY_VERTEX: { - if (p_format & ARRAY_FLAG_USE_2D_VERTICES) { - elem_size = 2; - } else { - elem_size = 3; - } - - { - elem_size *= sizeof(float); - } - - } break; - case RS::ARRAY_NORMAL: { - if (p_format & ARRAY_COMPRESS_NORMAL) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 3; - } - - } break; - - case RS::ARRAY_TANGENT: { - if (p_format & ARRAY_COMPRESS_TANGENT) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 4; - } - - } break; - case RS::ARRAY_COLOR: { - if (p_format & ARRAY_COMPRESS_COLOR) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 4; - } - } break; - case RS::ARRAY_TEX_UV: { - if (p_format & ARRAY_COMPRESS_TEX_UV) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 2; - } - - } break; - - case RS::ARRAY_TEX_UV2: { - if (p_format & ARRAY_COMPRESS_TEX_UV2) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 2; - } - - } break; - case RS::ARRAY_WEIGHTS: { - elem_size = sizeof(uint16_t) * 4; - - } break; - case RS::ARRAY_BONES: { - elem_size = sizeof(uint16_t) * 4; - - } break; - case RS::ARRAY_INDEX: { - if (p_index_len <= 0) { - ERR_PRINT("index_array_len==NO_INDEX_ARRAY"); - break; - } - /* determine whether using 16 or 32 bits indices */ - if (p_vertex_len >= (1 << 16)) { - elem_size = 4; - - } else { - elem_size = 2; - } - offsets[i] = elem_size; - continue; - } - default: { - ERR_FAIL_V(Array()); - } - } +Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t> p_vertex_data, Vector<uint8_t> p_attrib_data, Vector<uint8_t> p_skin_data, int p_vertex_len, Vector<uint8_t> p_index_data, int p_index_len) const { + uint32_t offsets[RS::ARRAY_MAX]; - offsets[i] = total_elem_size; - total_elem_size += elem_size; - } + uint32_t vertex_elem_size; + uint32_t attrib_elem_size; + uint32_t skin_elem_size; + mesh_surface_make_offsets_from_format(p_format, p_vertex_len, p_index_len, offsets, vertex_elem_size, attrib_elem_size, skin_elem_size); Array ret; ret.resize(RS::ARRAY_MAX); const uint8_t *r = p_vertex_data.ptr(); + const uint8_t *ar = p_attrib_data.ptr(); + const uint8_t *sr = p_skin_data.ptr(); for (int i = 0; i < RS::ARRAY_MAX; i++) { if (!(p_format & (1 << i))) { @@ -1143,7 +1056,7 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t Vector2 *w = arr_2d.ptrw(); for (int j = 0; j < p_vertex_len; j++) { - const float *v = (const float *)&r[j * total_elem_size + offsets[i]]; + const float *v = (const float *)&r[j * vertex_elem_size + offsets[i]]; w[j] = Vector2(v[0], v[1]); } } @@ -1157,7 +1070,7 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t Vector3 *w = arr_3d.ptrw(); for (int j = 0; j < p_vertex_len; j++) { - const float *v = (const float *)&r[j * total_elem_size + offsets[i]]; + const float *v = (const float *)&r[j * vertex_elem_size + offsets[i]]; w[j] = Vector3(v[0], v[1], v[2]); } } @@ -1170,21 +1083,11 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t Vector<Vector3> arr; arr.resize(p_vertex_len); - if (p_format & ARRAY_COMPRESS_NORMAL) { - Vector3 *w = arr.ptrw(); - const float multiplier = 1.f / 127.f; - - for (int j = 0; j < p_vertex_len; j++) { - const int8_t *v = (const int8_t *)&r[j * total_elem_size + offsets[i]]; - w[j] = Vector3(float(v[0]) * multiplier, float(v[1]) * multiplier, float(v[2]) * multiplier); - } - } else { - Vector3 *w = arr.ptrw(); + Vector3 *w = arr.ptrw(); - for (int j = 0; j < p_vertex_len; j++) { - const float *v = (const float *)&r[j * total_elem_size + offsets[i]]; - w[j] = Vector3(v[0], v[1], v[2]); - } + for (int j = 0; j < p_vertex_len; j++) { + const uint32_t v = *(const uint32_t *)&r[j * vertex_elem_size + offsets[i]]; + w[j] = Vector3((v & 0x3FF) / 1023.0, ((v >> 10) & 0x3FF) / 1023.0, ((v >> 20) & 0x3FF) / 1023.0) * Vector3(2, 2, 2) - Vector3(1, 1, 1); } ret[i] = arr; @@ -1194,24 +1097,16 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t case RS::ARRAY_TANGENT: { Vector<float> arr; arr.resize(p_vertex_len * 4); - if (p_format & ARRAY_COMPRESS_TANGENT) { - float *w = arr.ptrw(); - for (int j = 0; j < p_vertex_len; j++) { - const int8_t *v = (const int8_t *)&r[j * total_elem_size + offsets[i]]; - for (int k = 0; k < 4; k++) { - w[j * 4 + k] = float(v[k] / 127.0); - } - } - } else { - float *w = arr.ptrw(); + float *w = arr.ptrw(); - for (int j = 0; j < p_vertex_len; j++) { - const float *v = (const float *)&r[j * total_elem_size + offsets[i]]; - for (int k = 0; k < 4; k++) { - w[j * 4 + k] = v[k]; - } - } + for (int j = 0; j < p_vertex_len; j++) { + const uint32_t v = *(const uint32_t *)&r[j * vertex_elem_size + offsets[i]]; + + w[j * 4 + 0] = ((v & 0x3FF) / 1023.0) * 2.0 - 1.0; + w[j * 4 + 1] = (((v >> 10) & 0x3FF) / 1023.0) * 2.0 - 1.0; + w[j * 4 + 2] = (((v >> 20) & 0x3FF) / 1023.0) * 2.0 - 1.0; + w[j * 4 + 3] = ((v >> 30) / 3.0) * 2.0 - 1.0; } ret[i] = arr; @@ -1221,20 +1116,11 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t Vector<Color> arr; arr.resize(p_vertex_len); - if (p_format & ARRAY_COMPRESS_COLOR) { - Color *w = arr.ptrw(); - - for (int j = 0; j < p_vertex_len; j++) { - const uint8_t *v = (const uint8_t *)&r[j * total_elem_size + offsets[i]]; - w[j] = Color(float(v[0] / 255.0), float(v[1] / 255.0), float(v[2] / 255.0), float(v[3] / 255.0)); - } - } else { - Color *w = arr.ptrw(); + Color *w = arr.ptrw(); - for (int j = 0; j < p_vertex_len; j++) { - const float *v = (const float *)&r[j * total_elem_size + offsets[i]]; - w[j] = Color(v[0], v[1], v[2], v[3]); - } + for (int32_t j = 0; j < p_vertex_len; j++) { + const uint16_t *v = (const uint16_t *)&ar[j * attrib_elem_size + offsets[i]]; + w[j] = Color(Math::half_to_float(v[0]), Math::half_to_float(v[1]), Math::half_to_float(v[2]), Math::half_to_float(v[3])); } ret[i] = arr; @@ -1243,20 +1129,11 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t Vector<Vector2> arr; arr.resize(p_vertex_len); - if (p_format & ARRAY_COMPRESS_TEX_UV) { - Vector2 *w = arr.ptrw(); + Vector2 *w = arr.ptrw(); - for (int j = 0; j < p_vertex_len; j++) { - const uint16_t *v = (const uint16_t *)&r[j * total_elem_size + offsets[i]]; - w[j] = Vector2(Math::halfptr_to_float(&v[0]), Math::halfptr_to_float(&v[1])); - } - } else { - Vector2 *w = arr.ptrw(); - - for (int j = 0; j < p_vertex_len; j++) { - const float *v = (const float *)&r[j * total_elem_size + offsets[i]]; - w[j] = Vector2(v[0], v[1]); - } + for (int j = 0; j < p_vertex_len; j++) { + const float *v = (const float *)&ar[j * attrib_elem_size + offsets[i]]; + w[j] = Vector2(v[0], v[1]); } ret[i] = arr; @@ -1266,35 +1143,74 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t Vector<Vector2> arr; arr.resize(p_vertex_len); - if (p_format & ARRAY_COMPRESS_TEX_UV2) { - Vector2 *w = arr.ptrw(); + Vector2 *w = arr.ptrw(); - for (int j = 0; j < p_vertex_len; j++) { - const uint16_t *v = (const uint16_t *)&r[j * total_elem_size + offsets[i]]; - w[j] = Vector2(Math::halfptr_to_float(&v[0]), Math::halfptr_to_float(&v[1])); - } - } else { - Vector2 *w = arr.ptrw(); - - for (int j = 0; j < p_vertex_len; j++) { - const float *v = (const float *)&r[j * total_elem_size + offsets[i]]; - w[j] = Vector2(v[0], v[1]); - } + for (int j = 0; j < p_vertex_len; j++) { + const float *v = (const float *)&ar[j * attrib_elem_size + offsets[i]]; + w[j] = Vector2(v[0], v[1]); } ret[i] = arr; } break; + case RS::ARRAY_CUSTOM0: + case RS::ARRAY_CUSTOM1: + case RS::ARRAY_CUSTOM2: + case RS::ARRAY_CUSTOM3: { + uint32_t type = (p_format >> (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * (RS::ARRAY_CUSTOM0 - i))) & ARRAY_FORMAT_CUSTOM_MASK; + switch (type) { + case ARRAY_CUSTOM_RGBA8_UNORM: + case ARRAY_CUSTOM_RGBA8_SNORM: + case ARRAY_CUSTOM_RG_HALF: + case ARRAY_CUSTOM_RGBA_HALF: { + //size 4 + int s = type == ARRAY_CUSTOM_RGBA_HALF ? 8 : 4; + Vector<uint8_t> arr; + arr.resize(p_vertex_len * s); + + uint8_t *w = arr.ptrw(); + + for (int j = 0; j < p_vertex_len; j++) { + const uint8_t *v = (const uint8_t *)&ar[j * attrib_elem_size + offsets[i]]; + copymem(&w[j * s], v, s); + } + + ret[i] = arr; + + } break; + case ARRAY_CUSTOM_R_FLOAT: + case ARRAY_CUSTOM_RG_FLOAT: + case ARRAY_CUSTOM_RGB_FLOAT: + case ARRAY_CUSTOM_RGBA_FLOAT: { + uint32_t s = type - ARRAY_CUSTOM_R_FLOAT + 1; + + Vector<float> arr; + float *w = arr.ptrw(); + + for (int j = 0; j < p_vertex_len; j++) { + const float *v = (const float *)&ar[j * attrib_elem_size + offsets[i]]; + copymem(&w[j * s], v, s * sizeof(float)); + } + ret[i] = arr; + + } break; + default: { + } + } + + } break; case RS::ARRAY_WEIGHTS: { + uint32_t bone_count = (p_format & ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 8 : 4; + Vector<float> arr; - arr.resize(p_vertex_len * 4); + arr.resize(p_vertex_len * bone_count); { float *w = arr.ptrw(); for (int j = 0; j < p_vertex_len; j++) { - const uint16_t *v = (const uint16_t *)&r[j * total_elem_size + offsets[i]]; - for (int k = 0; k < 4; k++) { - w[j * 4 + k] = float(v[k] / 65535.0); + const uint16_t *v = (const uint16_t *)&sr[j * skin_elem_size + offsets[i]]; + for (uint32_t k = 0; k < bone_count; k++) { + w[j * bone_count + k] = float(v[k] / 65535.0); } } } @@ -1303,15 +1219,17 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t } break; case RS::ARRAY_BONES: { + uint32_t bone_count = (p_format & ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 8 : 4; + Vector<int> arr; - arr.resize(p_vertex_len * 4); + arr.resize(p_vertex_len * bone_count); int *w = arr.ptrw(); for (int j = 0; j < p_vertex_len; j++) { - const uint16_t *v = (const uint16_t *)&r[j * total_elem_size + offsets[i]]; - for (int k = 0; k < 4; k++) { - w[j * 4 + k] = v[k]; + const uint16_t *v = (const uint16_t *)&sr[j * skin_elem_size + offsets[i]]; + for (uint32_t k = 0; k < bone_count; k++) { + w[j * bone_count + k] = v[k]; } } @@ -1394,20 +1312,30 @@ Array RenderingServer::mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_sur SurfaceData sd = mesh_get_surface(p_mesh, p_surface); ERR_FAIL_COND_V(sd.vertex_count == 0, Array()); - Vector<Vector<uint8_t>> blend_shape_data = sd.blend_shapes; + Vector<uint8_t> blend_shape_data = sd.blend_shape_data; if (blend_shape_data.size() > 0) { - int vertex_len = sd.vertex_count; + uint32_t bs_offsets[RS::ARRAY_MAX]; + uint32_t bs_format = (sd.format & RS::ARRAY_FORMAT_BLEND_SHAPE_MASK); + uint32_t vertex_elem_size; + uint32_t attrib_elem_size; + uint32_t skin_elem_size; + + mesh_surface_make_offsets_from_format(bs_format, sd.vertex_count, 0, bs_offsets, vertex_elem_size, attrib_elem_size, skin_elem_size); + + int divisor = vertex_elem_size * sd.vertex_count; + ERR_FAIL_COND_V((blend_shape_data.size() % divisor) != 0, Array()); - Vector<uint8_t> index_data = sd.index_data; - int index_len = sd.index_count; + uint32_t blend_shape_count = blend_shape_data.size() / divisor; - uint32_t format = sd.format; + ERR_FAIL_COND_V(blend_shape_count != (uint32_t)mesh_get_blend_shape_count(p_mesh), Array()); Array blend_shape_array; - blend_shape_array.resize(blend_shape_data.size()); - for (int i = 0; i < blend_shape_data.size(); i++) { - blend_shape_array.set(i, _get_array_from_surface(format, blend_shape_data[i], vertex_len, index_data, index_len)); + blend_shape_array.resize(mesh_get_blend_shape_count(p_mesh)); + for (uint32_t i = 0; i < blend_shape_count; i++) { + Vector<uint8_t> bs_data = blend_shape_data.subarray(i * divisor, (i + 1) * divisor - 1); + Vector<uint8_t> unused; + blend_shape_array.set(i, _get_array_from_surface(bs_format, bs_data, unused, unused, sd.vertex_count, unused, 0)); } return blend_shape_array; @@ -1418,6 +1346,8 @@ Array RenderingServer::mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_sur Array RenderingServer::mesh_create_arrays_from_surface_data(const SurfaceData &p_data) const { Vector<uint8_t> vertex_data = p_data.vertex_data; + Vector<uint8_t> attrib_data = p_data.attribute_data; + Vector<uint8_t> skin_data = p_data.skin_data; ERR_FAIL_COND_V(vertex_data.size() == 0, Array()); int vertex_len = p_data.vertex_count; @@ -1427,7 +1357,7 @@ Array RenderingServer::mesh_create_arrays_from_surface_data(const SurfaceData &p uint32_t format = p_data.format; - return _get_array_from_surface(format, vertex_data, vertex_len, index_data, index_len); + return _get_array_from_surface(format, vertex_data, attrib_data, skin_data, vertex_len, index_data, index_len); } #if 0 Array RenderingServer::_mesh_surface_get_skeleton_aabb_bind(RID p_mesh, int p_surface) const { @@ -1540,9 +1470,11 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("material_set_next_pass", "material", "next_material"), &RenderingServer::material_set_next_pass); ClassDB::bind_method(D_METHOD("mesh_create"), &RenderingServer::mesh_create); - ClassDB::bind_method(D_METHOD("mesh_surface_get_format_offset", "format", "vertex_len", "index_len", "array_index"), &RenderingServer::mesh_surface_get_format_offset); - ClassDB::bind_method(D_METHOD("mesh_surface_get_format_stride", "format", "vertex_len", "index_len"), &RenderingServer::mesh_surface_get_format_stride); - ClassDB::bind_method(D_METHOD("mesh_add_surface_from_arrays", "mesh", "primitive", "arrays", "blend_shapes", "lods", "compress_format"), &RenderingServer::mesh_add_surface_from_arrays, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(ARRAY_COMPRESS_DEFAULT)); + ClassDB::bind_method(D_METHOD("mesh_surface_get_format_offset", "format", "vertex_count", "array_index"), &RenderingServer::mesh_surface_get_format_offset); + ClassDB::bind_method(D_METHOD("mesh_surface_get_format_vertex_stride", "format", "vertex_count"), &RenderingServer::mesh_surface_get_format_vertex_stride); + ClassDB::bind_method(D_METHOD("mesh_surface_get_format_attribute_stride", "format", "vertex_count"), &RenderingServer::mesh_surface_get_format_attribute_stride); + ClassDB::bind_method(D_METHOD("mesh_surface_get_format_skin_stride", "format", "vertex_count"), &RenderingServer::mesh_surface_get_format_skin_stride); + //ClassDB::bind_method(D_METHOD("mesh_add_surface_from_arrays", "mesh", "primitive", "arrays", "blend_shapes", "lods", "compress_format"), &RenderingServer::mesh_add_surface_from_arrays, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(ARRAY_COMPRESS_DEFAULT)); ClassDB::bind_method(D_METHOD("mesh_get_blend_shape_count", "mesh"), &RenderingServer::mesh_get_blend_shape_count); ClassDB::bind_method(D_METHOD("mesh_set_blend_shape_mode", "mesh", "mode"), &RenderingServer::mesh_set_blend_shape_mode); ClassDB::bind_method(D_METHOD("mesh_get_blend_shape_mode", "mesh"), &RenderingServer::mesh_get_blend_shape_mode); @@ -1557,7 +1489,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("mesh_clear", "mesh"), &RenderingServer::mesh_clear); ClassDB::bind_method(D_METHOD("multimesh_create"), &RenderingServer::multimesh_create); - ClassDB::bind_method(D_METHOD("multimesh_allocate", "multimesh", "instances", "transform_format", "color_format", "custom_data_format"), &RenderingServer::multimesh_allocate, DEFVAL(false), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("multimesh_allocate_data", "multimesh", "instances", "transform_format", "color_format", "custom_data_format"), &RenderingServer::multimesh_allocate_data, DEFVAL(false), DEFVAL(false)); ClassDB::bind_method(D_METHOD("multimesh_get_instance_count", "multimesh"), &RenderingServer::multimesh_get_instance_count); ClassDB::bind_method(D_METHOD("multimesh_set_mesh", "multimesh", "mesh"), &RenderingServer::multimesh_set_mesh); ClassDB::bind_method(D_METHOD("multimesh_instance_set_transform", "multimesh", "index", "transform"), &RenderingServer::multimesh_instance_set_transform); @@ -1591,7 +1523,7 @@ void RenderingServer::_bind_methods() { #endif ClassDB::bind_method(D_METHOD("skeleton_create"), &RenderingServer::skeleton_create); - ClassDB::bind_method(D_METHOD("skeleton_allocate", "skeleton", "bones", "is_2d_skeleton"), &RenderingServer::skeleton_allocate, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("skeleton_allocate_data", "skeleton", "bones", "is_2d_skeleton"), &RenderingServer::skeleton_allocate_data, DEFVAL(false)); ClassDB::bind_method(D_METHOD("skeleton_get_bone_count", "skeleton"), &RenderingServer::skeleton_get_bone_count); ClassDB::bind_method(D_METHOD("skeleton_bone_set_transform", "skeleton", "bone", "transform"), &RenderingServer::skeleton_bone_set_transform); ClassDB::bind_method(D_METHOD("skeleton_bone_get_transform", "skeleton", "bone"), &RenderingServer::skeleton_bone_get_transform); @@ -1617,6 +1549,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("light_directional_set_shadow_mode", "light", "mode"), &RenderingServer::light_directional_set_shadow_mode); ClassDB::bind_method(D_METHOD("light_directional_set_blend_splits", "light", "enable"), &RenderingServer::light_directional_set_blend_splits); + ClassDB::bind_method(D_METHOD("light_directional_set_sky_only", "light", "enable"), &RenderingServer::light_directional_set_sky_only); ClassDB::bind_method(D_METHOD("light_directional_set_shadow_depth_range_mode", "light", "range_mode"), &RenderingServer::light_directional_set_shadow_depth_range_mode); ClassDB::bind_method(D_METHOD("reflection_probe_create"), &RenderingServer::reflection_probe_create); @@ -1730,7 +1663,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("viewport_set_transparent_background", "viewport", "enabled"), &RenderingServer::viewport_set_transparent_background); ClassDB::bind_method(D_METHOD("viewport_set_global_canvas_transform", "viewport", "transform"), &RenderingServer::viewport_set_global_canvas_transform); ClassDB::bind_method(D_METHOD("viewport_set_canvas_stacking", "viewport", "canvas", "layer", "sublayer"), &RenderingServer::viewport_set_canvas_stacking); - ClassDB::bind_method(D_METHOD("viewport_set_shadow_atlas_size", "viewport", "size"), &RenderingServer::viewport_set_shadow_atlas_size); + ClassDB::bind_method(D_METHOD("viewport_set_shadow_atlas_size", "viewport", "size", "use_16_bits"), &RenderingServer::viewport_set_shadow_atlas_size, DEFVAL(false)); ClassDB::bind_method(D_METHOD("viewport_set_shadow_atlas_quadrant_subdivision", "viewport", "quadrant", "subdivision"), &RenderingServer::viewport_set_shadow_atlas_quadrant_subdivision); ClassDB::bind_method(D_METHOD("viewport_set_msaa", "viewport", "msaa"), &RenderingServer::viewport_set_msaa); ClassDB::bind_method(D_METHOD("viewport_set_use_debanding", "viewport", "enable"), &RenderingServer::viewport_set_use_debanding); @@ -1738,6 +1671,10 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("viewport_get_render_info", "viewport", "info"), &RenderingServer::viewport_get_render_info); ClassDB::bind_method(D_METHOD("viewport_set_debug_draw", "viewport", "draw"), &RenderingServer::viewport_set_debug_draw); + ClassDB::bind_method(D_METHOD("viewport_set_measure_render_time", "viewport", "enable"), &RenderingServer::viewport_set_measure_render_time); + ClassDB::bind_method(D_METHOD("viewport_get_measured_render_time_cpu", "viewport"), &RenderingServer::viewport_get_measured_render_time_cpu); + ClassDB::bind_method(D_METHOD("viewport_get_measured_render_time_gpu", "viewport"), &RenderingServer::viewport_get_measured_render_time_gpu); + ClassDB::bind_method(D_METHOD("environment_create"), &RenderingServer::environment_create); ClassDB::bind_method(D_METHOD("environment_set_background", "env", "bg"), &RenderingServer::environment_set_background); ClassDB::bind_method(D_METHOD("environment_set_sky", "env", "sky"), &RenderingServer::environment_set_sky); @@ -1749,9 +1686,9 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("environment_set_ambient_light", "env", "color", "ambient", "energy", "sky_contibution", "reflection_source", "ao_color"), &RenderingServer::environment_set_ambient_light, DEFVAL(RS::ENV_AMBIENT_SOURCE_BG), DEFVAL(1.0), DEFVAL(0.0), DEFVAL(RS::ENV_REFLECTION_SOURCE_BG), DEFVAL(Color())); ClassDB::bind_method(D_METHOD("environment_set_glow", "env", "enable", "levels", "intensity", "strength", "mix", "bloom_threshold", "blend_mode", "hdr_bleed_threshold", "hdr_bleed_scale", "hdr_luminance_cap"), &RenderingServer::environment_set_glow); ClassDB::bind_method(D_METHOD("environment_set_tonemap", "env", "tone_mapper", "exposure", "white", "auto_exposure", "min_luminance", "max_luminance", "auto_exp_speed", "auto_exp_grey"), &RenderingServer::environment_set_tonemap); - ClassDB::bind_method(D_METHOD("environment_set_adjustment", "env", "enable", "brightness", "contrast", "saturation", "ramp"), &RenderingServer::environment_set_adjustment); + ClassDB::bind_method(D_METHOD("environment_set_adjustment", "env", "enable", "brightness", "contrast", "saturation", "use_1d_color_correction", "color_correction"), &RenderingServer::environment_set_adjustment); ClassDB::bind_method(D_METHOD("environment_set_ssr", "env", "enable", "max_steps", "fade_in", "fade_out", "depth_tolerance"), &RenderingServer::environment_set_ssr); - ClassDB::bind_method(D_METHOD("environment_set_ssao", "env", "enable", "radius", "intensity", "bias", "light_affect", "ao_channel_affect", "blur", "bilateral_sharpness"), &RenderingServer::environment_set_ssao); + ClassDB::bind_method(D_METHOD("environment_set_ssao", "env", "enable", "radius", "intensity", "power", "detail", "horizon", "sharpness", "light_affect", "ao_channel_affect"), &RenderingServer::environment_set_ssao); ClassDB::bind_method(D_METHOD("environment_set_fog", "env", "enable", "light_color", "light_energy", "sun_scatter", "density", "height", "height_density", "aerial_perspective"), &RenderingServer::environment_set_fog); ClassDB::bind_method(D_METHOD("scenario_create"), &RenderingServer::scenario_create); @@ -1896,6 +1833,9 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("is_render_loop_enabled"), &RenderingServer::is_render_loop_enabled); ClassDB::bind_method(D_METHOD("set_render_loop_enabled", "enabled"), &RenderingServer::set_render_loop_enabled); + + ClassDB::bind_method(D_METHOD("get_frame_setup_time_cpu"), &RenderingServer::get_frame_setup_time_cpu); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "render_loop_enabled"), "set_render_loop_enabled", "is_render_loop_enabled"); BIND_CONSTANT(NO_INDEX_ARRAY); @@ -1931,6 +1871,10 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(ARRAY_COLOR); BIND_ENUM_CONSTANT(ARRAY_TEX_UV); BIND_ENUM_CONSTANT(ARRAY_TEX_UV2); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM0); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM1); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM2); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM3); BIND_ENUM_CONSTANT(ARRAY_BONES); BIND_ENUM_CONSTANT(ARRAY_WEIGHTS); BIND_ENUM_CONSTANT(ARRAY_INDEX); @@ -1942,20 +1886,28 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(ARRAY_FORMAT_COLOR); BIND_ENUM_CONSTANT(ARRAY_FORMAT_TEX_UV); BIND_ENUM_CONSTANT(ARRAY_FORMAT_TEX_UV2); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM0); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM1); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM2); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM3); BIND_ENUM_CONSTANT(ARRAY_FORMAT_BONES); BIND_ENUM_CONSTANT(ARRAY_FORMAT_WEIGHTS); BIND_ENUM_CONSTANT(ARRAY_FORMAT_INDEX); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_NORMAL); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TANGENT); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_COLOR); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TEX_UV); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TEX_UV2); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_INDEX); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_DEFAULT); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_BLEND_SHAPE_MASK); + + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM_BASE); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM0_SHIFT); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM1_SHIFT); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM2_SHIFT); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM3_SHIFT); + + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM_MASK); + BIND_ENUM_CONSTANT(ARRAY_COMPRESS_FLAGS_BASE); BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_2D_VERTICES); BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_DYNAMIC_UPDATE); + BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_8_BONE_WEIGHTS); BIND_ENUM_CONSTANT(PRIMITIVE_POINTS); BIND_ENUM_CONSTANT(PRIMITIVE_LINES); @@ -2109,11 +2061,7 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(ENV_SSR_ROUGNESS_QUALITY_MEDIUM); BIND_ENUM_CONSTANT(ENV_SSR_ROUGNESS_QUALITY_HIGH); - BIND_ENUM_CONSTANT(ENV_SSAO_BLUR_DISABLED); - BIND_ENUM_CONSTANT(ENV_SSAO_BLUR_1x1); - BIND_ENUM_CONSTANT(ENV_SSAO_BLUR_2x2); - BIND_ENUM_CONSTANT(ENV_SSAO_BLUR_3x3); - + BIND_ENUM_CONSTANT(ENV_SSAO_QUALITY_VERY_LOW); BIND_ENUM_CONSTANT(ENV_SSAO_QUALITY_LOW); BIND_ENUM_CONSTANT(ENV_SSAO_QUALITY_MEDIUM); BIND_ENUM_CONSTANT(ENV_SSAO_QUALITY_HIGH); @@ -2256,15 +2204,6 @@ void RenderingServer::_bind_methods() { ADD_SIGNAL(MethodInfo("frame_post_draw")); } -void RenderingServer::_canvas_item_add_style_box(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector<float> &p_margins, const Color &p_modulate) { - ERR_FAIL_COND(p_margins.size() != 4); - //canvas_item_add_style_box(p_item,p_rect,p_source,p_texture,Vector2(p_margins[0],p_margins[1]),Vector2(p_margins[2],p_margins[3]),true,p_modulate); -} - -void RenderingServer::_camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far) { - camera_set_orthogonal(p_camera, p_size, p_z_near, p_z_far); -} - void RenderingServer::mesh_add_surface_from_mesh_data(RID p_mesh, const Geometry3D::MeshData &p_mesh_data) { Vector<Vector3> vertices; Vector<Vector3> normals; @@ -2316,123 +2255,137 @@ void RenderingServer::set_render_loop_enabled(bool p_enabled) { RenderingServer::RenderingServer() { //ERR_FAIL_COND(singleton); + + thread_pool = memnew(RendererThreadPool); singleton = this; - GLOBAL_DEF_RST("rendering/vram_compression/import_bptc", false); - GLOBAL_DEF_RST("rendering/vram_compression/import_s3tc", true); - GLOBAL_DEF_RST("rendering/vram_compression/import_etc", false); - GLOBAL_DEF_RST("rendering/vram_compression/import_etc2", true); - GLOBAL_DEF_RST("rendering/vram_compression/import_pvrtc", false); + GLOBAL_DEF_RST("rendering/textures/vram_compression/import_bptc", false); + GLOBAL_DEF_RST("rendering/textures/vram_compression/import_s3tc", true); + GLOBAL_DEF_RST("rendering/textures/vram_compression/import_etc", false); + GLOBAL_DEF_RST("rendering/textures/vram_compression/import_etc2", true); + GLOBAL_DEF_RST("rendering/textures/vram_compression/import_pvrtc", false); GLOBAL_DEF("rendering/limits/time/time_rollover_secs", 3600); ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/time/time_rollover_secs", PropertyInfo(Variant::FLOAT, "rendering/limits/time/time_rollover_secs", PROPERTY_HINT_RANGE, "0,10000,1,or_greater")); - GLOBAL_DEF("rendering/quality/directional_shadow/size", 4096); - GLOBAL_DEF("rendering/quality/directional_shadow/size.mobile", 2048); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/directional_shadow/size", PropertyInfo(Variant::INT, "rendering/quality/directional_shadow/size", PROPERTY_HINT_RANGE, "256,16384")); - GLOBAL_DEF("rendering/quality/directional_shadow/soft_shadow_quality", 2); - GLOBAL_DEF("rendering/quality/directional_shadow/soft_shadow_quality.mobile", 0); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/directional_shadow/soft_shadow_quality", PropertyInfo(Variant::INT, "rendering/quality/directional_shadow/soft_shadow_quality", PROPERTY_HINT_ENUM, "Hard (Fastest),Soft Low (Fast),Soft Medium (Average),Soft High (Slow),Soft Ultra (Slowest)")); - - GLOBAL_DEF("rendering/quality/shadows/soft_shadow_quality", 2); - GLOBAL_DEF("rendering/quality/shadows/soft_shadow_quality.mobile", 0); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadows/soft_shadow_quality", PropertyInfo(Variant::INT, "rendering/quality/shadows/soft_shadow_quality", PROPERTY_HINT_ENUM, "Hard (Fastest),Soft Low (Fast),Soft Medium (Average),Soft High (Slow),Soft Ultra (Slowest)")); - - GLOBAL_DEF("rendering/quality/2d_shadow_atlas/size", 2048); - - GLOBAL_DEF("rendering/quality/shadow_atlas/size", 4096); - GLOBAL_DEF("rendering/quality/shadow_atlas/size.mobile", 2048); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/size", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/size", PROPERTY_HINT_RANGE, "256,16384")); - GLOBAL_DEF("rendering/quality/shadow_atlas/quadrant_0_subdiv", 1); - GLOBAL_DEF("rendering/quality/shadow_atlas/quadrant_1_subdiv", 2); - GLOBAL_DEF("rendering/quality/shadow_atlas/quadrant_2_subdiv", 3); - GLOBAL_DEF("rendering/quality/shadow_atlas/quadrant_3_subdiv", 4); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/quadrant_0_subdiv", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/quadrant_0_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/quadrant_1_subdiv", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/quadrant_1_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/quadrant_2_subdiv", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/quadrant_2_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/quadrant_3_subdiv", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/quadrant_3_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); - - GLOBAL_DEF("rendering/quality/reflections/roughness_layers", 8); - GLOBAL_DEF("rendering/quality/reflections/texture_array_reflections", true); - GLOBAL_DEF("rendering/quality/reflections/texture_array_reflections.mobile", false); - GLOBAL_DEF("rendering/quality/reflections/ggx_samples", 1024); - GLOBAL_DEF("rendering/quality/reflections/ggx_samples.mobile", 128); - GLOBAL_DEF("rendering/quality/reflections/fast_filter_high_quality", false); - GLOBAL_DEF("rendering/quality/reflection_atlas/reflection_size", 256); - GLOBAL_DEF("rendering/quality/reflection_atlas/reflection_size.mobile", 128); - GLOBAL_DEF("rendering/quality/reflection_atlas/reflection_count", 64); - - GLOBAL_DEF("rendering/quality/gi_probes/anisotropic", false); - GLOBAL_DEF("rendering/quality/gi_probes/quality", 1); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/gi_probes/quality", PropertyInfo(Variant::INT, "rendering/quality/gi_probes/quality", PROPERTY_HINT_ENUM, "Low (4 Cones - Fast),High (6 Cones - Slow)")); - - GLOBAL_DEF("rendering/quality/shading/force_vertex_shading", false); - GLOBAL_DEF("rendering/quality/shading/force_vertex_shading.mobile", true); - GLOBAL_DEF("rendering/quality/shading/force_lambert_over_burley", false); - GLOBAL_DEF("rendering/quality/shading/force_lambert_over_burley.mobile", true); - GLOBAL_DEF("rendering/quality/shading/force_blinn_over_ggx", false); - GLOBAL_DEF("rendering/quality/shading/force_blinn_over_ggx.mobile", true); - - GLOBAL_DEF("rendering/quality/depth_prepass/enable", true); - GLOBAL_DEF("rendering/quality/depth_prepass/disable_for_vendors", "PowerVR,Mali,Adreno,Apple"); - - GLOBAL_DEF("rendering/quality/texture_filters/use_nearest_mipmap_filter", false); - GLOBAL_DEF("rendering/quality/texture_filters/anisotropic_filtering_level", 2); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/texture_filters/anisotropic_filtering_level", PropertyInfo(Variant::INT, "rendering/quality/texture_filters/anisotropic_filtering_level", PROPERTY_HINT_ENUM, "Disabled (Fastest),2x (Faster),4x (Fast),8x (Average),16x (Slow)")); - - GLOBAL_DEF("rendering/quality/depth_of_field/depth_of_field_bokeh_shape", 1); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/depth_of_field/depth_of_field_bokeh_shape", PropertyInfo(Variant::INT, "rendering/quality/depth_of_field/depth_of_field_bokeh_shape", PROPERTY_HINT_ENUM, "Box (Fast),Hexagon (Average),Circle (Slow)")); - GLOBAL_DEF("rendering/quality/depth_of_field/depth_of_field_bokeh_quality", 2); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/depth_of_field/depth_of_field_bokeh_quality", PropertyInfo(Variant::INT, "rendering/quality/depth_of_field/depth_of_field_bokeh_quality", PROPERTY_HINT_ENUM, "Very Low (Fastest),Low (Fast),Medium (Average),High (Slow)")); - GLOBAL_DEF("rendering/quality/depth_of_field/depth_of_field_use_jitter", false); - - GLOBAL_DEF("rendering/quality/ssao/quality", 1); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/ssao/quality", PropertyInfo(Variant::INT, "rendering/quality/ssao/quality", PROPERTY_HINT_ENUM, "Low (Fast),Medium (Average),High (Slow),Ultra (Slower)")); - GLOBAL_DEF("rendering/quality/ssao/half_size", false); - - GLOBAL_DEF("rendering/quality/screen_filters/screen_space_roughness_limiter_enabled", true); - GLOBAL_DEF("rendering/quality/screen_filters/screen_space_roughness_limiter_amount", 0.25); - GLOBAL_DEF("rendering/quality/screen_filters/screen_space_roughness_limiter_limit", 0.18); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/screen_filters/screen_space_roughness_limiter_amount", PropertyInfo(Variant::FLOAT, "rendering/quality/screen_filters/screen_space_roughness_limiter_amount", PROPERTY_HINT_RANGE, "0.01,4.0,0.01")); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/screen_filters/screen_space_roughness_limiter_limit", PropertyInfo(Variant::FLOAT, "rendering/quality/screen_filters/screen_space_roughness_limiter_limit", PROPERTY_HINT_RANGE, "0.01,1.0,0.01")); - - GLOBAL_DEF("rendering/quality/glow/upscale_mode", 1); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/glow/upscale_mode", PropertyInfo(Variant::INT, "rendering/quality/glow/upscale_mode", PROPERTY_HINT_ENUM, "Linear (Fast),Bicubic (Slow)")); - GLOBAL_DEF("rendering/quality/glow/upscale_mode.mobile", 0); - GLOBAL_DEF("rendering/quality/glow/use_high_quality", false); - - GLOBAL_DEF("rendering/quality/screen_space_reflection/roughness_quality", 1); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/screen_space_reflection/roughness_quality", PropertyInfo(Variant::INT, "rendering/quality/screen_space_reflection/roughness_quality", PROPERTY_HINT_ENUM, "Disabled (Fastest),Low (Fast),Medium (Average),High (Slow)")); - - GLOBAL_DEF("rendering/quality/subsurface_scattering/subsurface_scattering_quality", 1); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/subsurface_scattering/subsurface_scattering_quality", PropertyInfo(Variant::INT, "rendering/quality/subsurface_scattering/subsurface_scattering_quality", PROPERTY_HINT_ENUM, "Disabled (Fastest),Low (Fast),Medium (Average),High (Slow)")); - GLOBAL_DEF("rendering/quality/subsurface_scattering/subsurface_scattering_scale", 0.05); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/subsurface_scattering/subsurface_scattering_scale", PropertyInfo(Variant::FLOAT, "rendering/quality/subsurface_scattering/subsurface_scattering_scale", PROPERTY_HINT_RANGE, "0.001,1,0.001")); - GLOBAL_DEF("rendering/quality/subsurface_scattering/subsurface_scattering_depth_scale", 0.01); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/subsurface_scattering/subsurface_scattering_depth_scale", PropertyInfo(Variant::FLOAT, "rendering/quality/subsurface_scattering/subsurface_scattering_depth_scale", PROPERTY_HINT_RANGE, "0.001,1,0.001")); - - GLOBAL_DEF("rendering/high_end/global_shader_variables_buffer_size", 65536); - - GLOBAL_DEF("rendering/lightmapper/probe_capture_update_speed", 15); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/lightmapper/probe_capture_update_speed", PropertyInfo(Variant::FLOAT, "rendering/lightmapper/probe_capture_update_speed", PROPERTY_HINT_RANGE, "0.001,256,0.001")); - - GLOBAL_DEF("rendering/sdfgi/probe_ray_count", 2); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/sdfgi/probe_ray_count", PropertyInfo(Variant::INT, "rendering/sdfgi/probe_ray_count", PROPERTY_HINT_ENUM, "8 (Fastest),16,32,64,96,128 (Slowest)")); - GLOBAL_DEF("rendering/sdfgi/frames_to_converge", 1); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/sdfgi/frames_to_converge", PropertyInfo(Variant::INT, "rendering/sdfgi/frames_to_converge", PROPERTY_HINT_ENUM, "5 (Less Latency but Lower Quality),10,15,20,25,30 (More Latency but Higher Quality)")); - - GLOBAL_DEF("rendering/volumetric_fog/volume_size", 64); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/volumetric_fog/volume_size", PropertyInfo(Variant::INT, "rendering/volumetric_fog/volume_size", PROPERTY_HINT_RANGE, "16,512,1")); - GLOBAL_DEF("rendering/volumetric_fog/volume_depth", 128); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/volumetric_fog/volume_depth", PropertyInfo(Variant::INT, "rendering/volumetric_fog/volume_depth", PROPERTY_HINT_RANGE, "16,512,1")); - GLOBAL_DEF("rendering/volumetric_fog/use_filter", 0); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/volumetric_fog/use_filter", PropertyInfo(Variant::INT, "rendering/volumetric_fog/use_filter", PROPERTY_HINT_ENUM, "No (Faster),Yes (Higher Quality)")); - GLOBAL_DEF("rendering/volumetric_fog/directional_shadow_shrink", 512); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/volumetric_fog/directional_shadow_shrink", PropertyInfo(Variant::INT, "rendering/volumetric_fog/directional_shadow_shrink", PROPERTY_HINT_RANGE, "32,2048,1")); - GLOBAL_DEF("rendering/volumetric_fog/positional_shadow_shrink", 512); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/volumetric_fog/positional_shadow_shrink", PropertyInfo(Variant::INT, "rendering/volumetric_fog/positional_shadow_shrink", PROPERTY_HINT_RANGE, "32,2048,1")); + GLOBAL_DEF("rendering/shadows/directional_shadow/size", 4096); + GLOBAL_DEF("rendering/shadows/directional_shadow/size.mobile", 2048); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/directional_shadow/size", PropertyInfo(Variant::INT, "rendering/shadows/directional_shadow/size", PROPERTY_HINT_RANGE, "256,16384")); + GLOBAL_DEF("rendering/shadows/directional_shadow/soft_shadow_quality", 2); + GLOBAL_DEF("rendering/shadows/directional_shadow/soft_shadow_quality.mobile", 0); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/directional_shadow/soft_shadow_quality", PropertyInfo(Variant::INT, "rendering/shadows/directional_shadow/soft_shadow_quality", PROPERTY_HINT_ENUM, "Hard (Fastest),Soft Low (Fast),Soft Medium (Average),Soft High (Slow),Soft Ultra (Slowest)")); + GLOBAL_DEF("rendering/shadows/directional_shadow/16_bits", true); + + GLOBAL_DEF("rendering/shadows/shadows/soft_shadow_quality", 2); + GLOBAL_DEF("rendering/shadows/shadows/soft_shadow_quality.mobile", 0); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/shadows/soft_shadow_quality", PropertyInfo(Variant::INT, "rendering/shadows/shadows/soft_shadow_quality", PROPERTY_HINT_ENUM, "Hard (Fastest),Soft Low (Fast),Soft Medium (Average),Soft High (Slow),Soft Ultra (Slowest)")); + + GLOBAL_DEF("rendering/2d/shadow_atlas/size", 2048); + + GLOBAL_DEF("rendering/driver/rd_renderer/use_low_end_renderer", false); + GLOBAL_DEF("rendering/driver/rd_renderer/use_low_end_renderer.mobile", true); + + GLOBAL_DEF("rendering/reflections/sky_reflections/roughness_layers", 8); + GLOBAL_DEF("rendering/reflections/sky_reflections/texture_array_reflections", true); + GLOBAL_DEF("rendering/reflections/sky_reflections/texture_array_reflections.mobile", false); + GLOBAL_DEF("rendering/reflections/sky_reflections/ggx_samples", 1024); + GLOBAL_DEF("rendering/reflections/sky_reflections/ggx_samples.mobile", 128); + GLOBAL_DEF("rendering/reflections/sky_reflections/fast_filter_high_quality", false); + GLOBAL_DEF("rendering/reflections/reflection_atlas/reflection_size", 256); + GLOBAL_DEF("rendering/reflections/reflection_atlas/reflection_size.mobile", 128); + GLOBAL_DEF("rendering/reflections/reflection_atlas/reflection_count", 64); + + GLOBAL_DEF("rendering/global_illumination/gi/use_half_resolution", false); + + GLOBAL_DEF("rendering/global_illumination/gi_probes/anisotropic", false); + GLOBAL_DEF("rendering/global_illumination/gi_probes/quality", 1); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/global_illumination/gi_probes/quality", PropertyInfo(Variant::INT, "rendering/global_illumination/gi_probes/quality", PROPERTY_HINT_ENUM, "Low (4 Cones - Fast),High (6 Cones - Slow)")); + + GLOBAL_DEF("rendering/shading/overrides/force_vertex_shading", false); + GLOBAL_DEF("rendering/shading/overrides/force_vertex_shading.mobile", true); + GLOBAL_DEF("rendering/shading/overrides/force_lambert_over_burley", false); + GLOBAL_DEF("rendering/shading/overrides/force_lambert_over_burley.mobile", true); + GLOBAL_DEF("rendering/shading/overrides/force_blinn_over_ggx", false); + GLOBAL_DEF("rendering/shading/overrides/force_blinn_over_ggx.mobile", true); + + GLOBAL_DEF("rendering/driver/depth_prepass/enable", true); + GLOBAL_DEF("rendering/driver/depth_prepass/disable_for_vendors", "PowerVR,Mali,Adreno,Apple"); + + GLOBAL_DEF("rendering/textures/default_filters/use_nearest_mipmap_filter", false); + GLOBAL_DEF("rendering/textures/default_filters/anisotropic_filtering_level", 2); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/textures/default_filters/anisotropic_filtering_level", PropertyInfo(Variant::INT, "rendering/textures/default_filters/anisotropic_filtering_level", PROPERTY_HINT_ENUM, "Disabled (Fastest),2x (Faster),4x (Fast),8x (Average),16x (Slow)")); + + GLOBAL_DEF("rendering/camera/depth_of_field/depth_of_field_bokeh_shape", 1); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/camera/depth_of_field/depth_of_field_bokeh_shape", PropertyInfo(Variant::INT, "rendering/camera/depth_of_field/depth_of_field_bokeh_shape", PROPERTY_HINT_ENUM, "Box (Fast),Hexagon (Average),Circle (Slow)")); + GLOBAL_DEF("rendering/camera/depth_of_field/depth_of_field_bokeh_quality", 2); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/camera/depth_of_field/depth_of_field_bokeh_quality", PropertyInfo(Variant::INT, "rendering/camera/depth_of_field/depth_of_field_bokeh_quality", PROPERTY_HINT_ENUM, "Very Low (Fastest),Low (Fast),Medium (Average),High (Slow)")); + GLOBAL_DEF("rendering/camera/depth_of_field/depth_of_field_use_jitter", false); + + GLOBAL_DEF("rendering/environment/ssao/quality", 2); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/ssao/quality", PropertyInfo(Variant::INT, "rendering/environment/ssao/quality", PROPERTY_HINT_ENUM, "Very Low (Fast),Low (Fast),Medium (Average),High (Slow),Ultra (Custom)")); + GLOBAL_DEF("rendering/environment/ssao/half_size", false); + GLOBAL_DEF("rendering/environment/ssao/half_size.mobile", true); + GLOBAL_DEF("rendering/environment/ssao/adaptive_target", 0.5); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/ssao/adaptive_target", PropertyInfo(Variant::FLOAT, "rendering/environment/ssao/adaptive_target", PROPERTY_HINT_RANGE, "0.0,1.0,0.01")); + GLOBAL_DEF("rendering/environment/ssao/blur_passes", 2); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/ssao/blur_passes", PropertyInfo(Variant::INT, "rendering/environment/ssao/blur_passes", PROPERTY_HINT_RANGE, "0,6")); + GLOBAL_DEF("rendering/environment/ssao/fadeout_from", 50.0); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/ssao/fadeout_from", PropertyInfo(Variant::FLOAT, "rendering/environment/ssao/fadeout_from", PROPERTY_HINT_RANGE, "0.0,512,0.1,or_greater")); + GLOBAL_DEF("rendering/environment/ssao/fadeout_to", 300.0); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/ssao/fadeout_to", PropertyInfo(Variant::FLOAT, "rendering/environment/ssao/fadeout_to", PROPERTY_HINT_RANGE, "64,65536,0.1,or_greater")); + + GLOBAL_DEF("rendering/anti_aliasing/screen_space_roughness_limiter/enabled", true); + GLOBAL_DEF("rendering/anti_aliasing/screen_space_roughness_limiter/amount", 0.25); + GLOBAL_DEF("rendering/anti_aliasing/screen_space_roughness_limiter/limit", 0.18); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/screen_space_roughness_limiter/amount", PropertyInfo(Variant::FLOAT, "rendering/anti_aliasing/screen_space_roughness_limiter/amount", PROPERTY_HINT_RANGE, "0.01,4.0,0.01")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/screen_space_roughness_limiter/limit", PropertyInfo(Variant::FLOAT, "rendering/anti_aliasing/screen_space_roughness_limiter/limit", PROPERTY_HINT_RANGE, "0.01,1.0,0.01")); + + GLOBAL_DEF("rendering/environment/glow/upscale_mode", 1); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/glow/upscale_mode", PropertyInfo(Variant::INT, "rendering/environment/glow/upscale_mode", PROPERTY_HINT_ENUM, "Linear (Fast),Bicubic (Slow)")); + GLOBAL_DEF("rendering/environment/glow/upscale_mode.mobile", 0); + GLOBAL_DEF("rendering/environment/glow/use_high_quality", false); + + GLOBAL_DEF("rendering/environment/screen_space_reflection/roughness_quality", 1); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/screen_space_reflection/roughness_quality", PropertyInfo(Variant::INT, "rendering/environment/screen_space_reflection/roughness_quality", PROPERTY_HINT_ENUM, "Disabled (Fastest),Low (Fast),Medium (Average),High (Slow)")); + + GLOBAL_DEF("rendering/environment/subsurface_scattering/subsurface_scattering_quality", 1); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/subsurface_scattering/subsurface_scattering_quality", PropertyInfo(Variant::INT, "rendering/environment/subsurface_scattering/subsurface_scattering_quality", PROPERTY_HINT_ENUM, "Disabled (Fastest),Low (Fast),Medium (Average),High (Slow)")); + GLOBAL_DEF("rendering/environment/subsurface_scattering/subsurface_scattering_scale", 0.05); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/subsurface_scattering/subsurface_scattering_scale", PropertyInfo(Variant::FLOAT, "rendering/environment/subsurface_scattering/subsurface_scattering_scale", PROPERTY_HINT_RANGE, "0.001,1,0.001")); + GLOBAL_DEF("rendering/environment/subsurface_scattering/subsurface_scattering_depth_scale", 0.01); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/subsurface_scattering/subsurface_scattering_depth_scale", PropertyInfo(Variant::FLOAT, "rendering/environment/subsurface_scattering/subsurface_scattering_depth_scale", PROPERTY_HINT_RANGE, "0.001,1,0.001")); + + GLOBAL_DEF("rendering/limits/global_shader_variables/buffer_size", 65536); + + GLOBAL_DEF("rendering/lightmapping/probe_capture/update_speed", 15); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/lightmapping/probe_capture/update_speed", PropertyInfo(Variant::FLOAT, "rendering/lightmapping/probe_capture/update_speed", PROPERTY_HINT_RANGE, "0.001,256,0.001")); + + GLOBAL_DEF("rendering/global_illumination/sdfgi/probe_ray_count", 1); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/global_illumination/sdfgi/probe_ray_count", PropertyInfo(Variant::INT, "rendering/global_illumination/sdfgi/probe_ray_count", PROPERTY_HINT_ENUM, "8 (Fastest),16,32,64,96,128 (Slowest)")); + GLOBAL_DEF("rendering/global_illumination/sdfgi/frames_to_converge", 4); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/global_illumination/sdfgi/frames_to_converge", PropertyInfo(Variant::INT, "rendering/global_illumination/sdfgi/frames_to_converge", PROPERTY_HINT_ENUM, "5 (Less Latency but Lower Quality),10,15,20,25,30 (More Latency but Higher Quality)")); + GLOBAL_DEF("rendering/global_illumination/sdfgi/frames_to_update_lights", 2); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/global_illumination/sdfgi/frames_to_update_lights", PropertyInfo(Variant::INT, "rendering/global_illumination/sdfgi/frames_to_update_lights", PROPERTY_HINT_ENUM, "1 (Slower),2,4,8,16 (Faster)")); + + GLOBAL_DEF("rendering/environment/volumetric_fog/volume_size", 64); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/volumetric_fog/volume_size", PropertyInfo(Variant::INT, "rendering/environment/volumetric_fog/volume_size", PROPERTY_HINT_RANGE, "16,512,1")); + GLOBAL_DEF("rendering/environment/volumetric_fog/volume_depth", 128); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/volumetric_fog/volume_depth", PropertyInfo(Variant::INT, "rendering/environment/volumetric_fog/volume_depth", PROPERTY_HINT_RANGE, "16,512,1")); + GLOBAL_DEF("rendering/environment/volumetric_fog/use_filter", 1); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/volumetric_fog/use_filter", PropertyInfo(Variant::INT, "rendering/environment/volumetric_fog/use_filter", PROPERTY_HINT_ENUM, "No (Faster),Yes (Higher Quality)")); + + GLOBAL_DEF("rendering/limits/spatial_indexer/update_iterations_per_frame", 10); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/spatial_indexer/update_iterations_per_frame", PropertyInfo(Variant::INT, "rendering/limits/spatial_indexer/update_iterations_per_frame", PROPERTY_HINT_RANGE, "0,1024,1")); + GLOBAL_DEF("rendering/limits/spatial_indexer/threaded_cull_minimum_instances", 1000); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/spatial_indexer/threaded_cull_minimum_instances", PropertyInfo(Variant::INT, "rendering/limits/spatial_indexer/threaded_cull_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1")); + GLOBAL_DEF("rendering/limits/forward_renderer/threaded_render_minimum_instances", 500); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/forward_renderer/threaded_render_minimum_instances", PropertyInfo(Variant::INT, "rendering/limits/forward_renderer/threaded_render_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1")); + + GLOBAL_DEF("rendering/limits/cluster_builder/max_clustered_elements", 512); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/cluster_builder/max_clustered_elements", PropertyInfo(Variant::FLOAT, "rendering/limits/cluster_builder/max_clustered_elements", PROPERTY_HINT_RANGE, "32,8192,1")); } RenderingServer::~RenderingServer() { + memdelete(thread_pool); singleton = nullptr; } diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 236112c3fb..65065841a6 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -39,6 +39,7 @@ #include "core/variant/typed_array.h" #include "core/variant/variant.h" #include "servers/display_server.h" +#include "servers/rendering/renderer_thread_pool.h" #include "servers/rendering/rendering_device.h" #include "servers/rendering/shader_language.h" @@ -50,9 +51,9 @@ class RenderingServer : public Object { int mm_policy; bool render_loop_enabled = true; - void _camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far); - void _canvas_item_add_style_box(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector<float> &p_margins, const Color &p_modulate = Color(1, 1, 1)); - Array _get_array_from_surface(uint32_t p_format, Vector<uint8_t> p_vertex_data, int p_vertex_len, Vector<uint8_t> p_index_data, int p_index_len) const; + Array _get_array_from_surface(uint32_t p_format, Vector<uint8_t> p_vertex_data, Vector<uint8_t> p_attrib_data, Vector<uint8_t> p_skin_data, int p_vertex_len, Vector<uint8_t> p_index_data, int p_index_len) const; + + RendererThreadPool *thread_pool = nullptr; protected: RID _make_test_cube(); @@ -61,7 +62,7 @@ protected: RID white_texture; RID test_material; - Error _surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t p_stride, Vector<uint8_t> &r_vertex_array, int p_vertex_array_len, Vector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> &r_bone_aabb); + Error _surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t p_vertex_stride, uint32_t p_attrib_stride, uint32_t p_skin_stride, Vector<uint8_t> &r_vertex_array, Vector<uint8_t> &r_attrib_array, Vector<uint8_t> &r_skin_array, int p_vertex_array_len, Vector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> &r_bone_aabb); static RenderingServer *(*create_func)(); static void _bind_methods(); @@ -132,11 +133,11 @@ public: virtual void texture_set_detect_normal_callback(RID p_texture, TextureDetectCallback p_callback, void *p_userdata) = 0; enum TextureDetectRoughnessChannel { - TEXTURE_DETECT_ROUGNHESS_R, - TEXTURE_DETECT_ROUGNHESS_G, - TEXTURE_DETECT_ROUGNHESS_B, - TEXTURE_DETECT_ROUGNHESS_A, - TEXTURE_DETECT_ROUGNHESS_GRAY, + TEXTURE_DETECT_ROUGHNESS_R, + TEXTURE_DETECT_ROUGHNESS_G, + TEXTURE_DETECT_ROUGHNESS_B, + TEXTURE_DETECT_ROUGHNESS_A, + TEXTURE_DETECT_ROUGHNESS_GRAY, }; typedef void (*TextureDetectRoughnessCallback)(void *, const String &, TextureDetectRoughnessChannel); @@ -178,6 +179,19 @@ public: virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) = 0; virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const = 0; + struct ShaderNativeSourceCode { + struct Version { + struct Stage { + String name; + String code; + }; + Vector<Stage> stages; + }; + Vector<Version> versions; + }; + + virtual ShaderNativeSourceCode shader_get_native_source_code(RID p_shader) const = 0; + /* COMMON MATERIAL API */ enum { @@ -199,16 +213,36 @@ public: /* MESH API */ enum ArrayType { - ARRAY_VERTEX = 0, - ARRAY_NORMAL = 1, - ARRAY_TANGENT = 2, - ARRAY_COLOR = 3, - ARRAY_TEX_UV = 4, - ARRAY_TEX_UV2 = 5, - ARRAY_BONES = 6, - ARRAY_WEIGHTS = 7, - ARRAY_INDEX = 8, - ARRAY_MAX = 9 + ARRAY_VERTEX = 0, // RG32F or RGB32F (depending on 2D bit) + ARRAY_NORMAL = 1, // A2B10G10R10 + ARRAY_TANGENT = 2, // A2B10G10R10, A flips sign of binormal + ARRAY_COLOR = 3, // RGBA16F + ARRAY_TEX_UV = 4, // RG32F + ARRAY_TEX_UV2 = 5, // RG32F + ARRAY_CUSTOM0 = 6, // depends on ArrayCustomFormat + ARRAY_CUSTOM1 = 7, + ARRAY_CUSTOM2 = 8, + ARRAY_CUSTOM3 = 9, + ARRAY_BONES = 10, // RGBA16UI (x2 if 8 weights) + ARRAY_WEIGHTS = 11, // RGBA16UNORM (x2 if 8 weights) + ARRAY_INDEX = 12, // 16 or 32 bits depending on length > 0xFFFF + ARRAY_MAX = 13 + }; + + enum { + ARRAY_CUSTOM_COUNT = ARRAY_BONES - ARRAY_CUSTOM0 + }; + + enum ArrayCustomFormat { + ARRAY_CUSTOM_RGBA8_UNORM, + ARRAY_CUSTOM_RGBA8_SNORM, + ARRAY_CUSTOM_RG_HALF, + ARRAY_CUSTOM_RGBA_HALF, + ARRAY_CUSTOM_R_FLOAT, + ARRAY_CUSTOM_RG_FLOAT, + ARRAY_CUSTOM_RGB_FLOAT, + ARRAY_CUSTOM_RGBA_FLOAT, + ARRAY_CUSTOM_MAX }; enum ArrayFormat { @@ -219,21 +253,29 @@ public: ARRAY_FORMAT_COLOR = 1 << ARRAY_COLOR, ARRAY_FORMAT_TEX_UV = 1 << ARRAY_TEX_UV, ARRAY_FORMAT_TEX_UV2 = 1 << ARRAY_TEX_UV2, + ARRAY_FORMAT_CUSTOM0 = 1 << ARRAY_CUSTOM0, + ARRAY_FORMAT_CUSTOM1 = 1 << ARRAY_CUSTOM1, + ARRAY_FORMAT_CUSTOM2 = 1 << ARRAY_CUSTOM2, + ARRAY_FORMAT_CUSTOM3 = 1 << ARRAY_CUSTOM3, ARRAY_FORMAT_BONES = 1 << ARRAY_BONES, ARRAY_FORMAT_WEIGHTS = 1 << ARRAY_WEIGHTS, ARRAY_FORMAT_INDEX = 1 << ARRAY_INDEX, - ARRAY_COMPRESS_BASE = (ARRAY_INDEX + 1), - ARRAY_COMPRESS_NORMAL = 1 << (ARRAY_NORMAL + ARRAY_COMPRESS_BASE), - ARRAY_COMPRESS_TANGENT = 1 << (ARRAY_TANGENT + ARRAY_COMPRESS_BASE), - ARRAY_COMPRESS_COLOR = 1 << (ARRAY_COLOR + ARRAY_COMPRESS_BASE), - ARRAY_COMPRESS_TEX_UV = 1 << (ARRAY_TEX_UV + ARRAY_COMPRESS_BASE), - ARRAY_COMPRESS_TEX_UV2 = 1 << (ARRAY_TEX_UV2 + ARRAY_COMPRESS_BASE), - ARRAY_COMPRESS_INDEX = 1 << (ARRAY_INDEX + ARRAY_COMPRESS_BASE), - ARRAY_COMPRESS_DEFAULT = ARRAY_COMPRESS_NORMAL | ARRAY_COMPRESS_TANGENT | ARRAY_COMPRESS_COLOR | ARRAY_COMPRESS_TEX_UV | ARRAY_COMPRESS_TEX_UV2, + ARRAY_FORMAT_BLEND_SHAPE_MASK = (~(ARRAY_FORMAT_COLOR | ARRAY_FORMAT_TEX_UV | ARRAY_FORMAT_TEX_UV2 | ARRAY_FORMAT_BONES | ARRAY_FORMAT_WEIGHTS | ARRAY_FORMAT_CUSTOM0 | ARRAY_FORMAT_CUSTOM1 | ARRAY_FORMAT_CUSTOM2 | ARRAY_FORMAT_CUSTOM3 | ARRAY_FORMAT_INDEX)) & 0x7FFFFFFF, + + ARRAY_FORMAT_CUSTOM_BASE = (ARRAY_INDEX + 1), + ARRAY_FORMAT_CUSTOM_BITS = 3, + ARRAY_FORMAT_CUSTOM0_SHIFT = (ARRAY_FORMAT_CUSTOM_BASE + 0), + ARRAY_FORMAT_CUSTOM1_SHIFT = (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS), + ARRAY_FORMAT_CUSTOM2_SHIFT = (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * 2), + ARRAY_FORMAT_CUSTOM3_SHIFT = (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * 3), - ARRAY_FLAG_USE_2D_VERTICES = ARRAY_COMPRESS_INDEX << 1, - ARRAY_FLAG_USE_DYNAMIC_UPDATE = ARRAY_COMPRESS_INDEX << 3, + ARRAY_FORMAT_CUSTOM_MASK = 0x7, + ARRAY_COMPRESS_FLAGS_BASE = (ARRAY_INDEX + 1 + 12), + + ARRAY_FLAG_USE_2D_VERTICES = 1 << (ARRAY_COMPRESS_FLAGS_BASE + 0), + ARRAY_FLAG_USE_DYNAMIC_UPDATE = 1 << (ARRAY_COMPRESS_FLAGS_BASE + 1), + ARRAY_FLAG_USE_8_BONE_WEIGHTS = 1 << (ARRAY_COMPRESS_FLAGS_BASE + 2), }; enum PrimitiveType { @@ -249,7 +291,9 @@ public: PrimitiveType primitive = PRIMITIVE_MAX; uint32_t format = 0; - Vector<uint8_t> vertex_data; + Vector<uint8_t> vertex_data; // vertex, normal, tangent (change with skinning, blendshape) + Vector<uint8_t> attribute_data; // color,uv, uv2, custom0-3 + Vector<uint8_t> skin_data; // bone index, bone weight uint32_t vertex_count = 0; Vector<uint8_t> index_data; uint32_t index_count = 0; @@ -262,25 +306,30 @@ public: Vector<LOD> lods; Vector<AABB> bone_aabbs; - Vector<Vector<uint8_t>> blend_shapes; + Vector<uint8_t> blend_shape_data; RID material; }; - virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces) = 0; + virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces, int p_blend_shape_count = 0) = 0; virtual RID mesh_create() = 0; - virtual uint32_t mesh_surface_get_format_offset(uint32_t p_format, int p_vertex_len, int p_index_len, int p_array_index) const; - virtual uint32_t mesh_surface_get_format_stride(uint32_t p_format, int p_vertex_len, int p_index_len) const; + virtual void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) = 0; + + virtual uint32_t mesh_surface_get_format_offset(uint32_t p_format, int p_vertex_len, int p_array_index) const; + virtual uint32_t mesh_surface_get_format_vertex_stride(uint32_t p_format, int p_vertex_len) const; + virtual uint32_t mesh_surface_get_format_attribute_stride(uint32_t p_format, int p_vertex_len) const; + virtual uint32_t mesh_surface_get_format_skin_stride(uint32_t p_format, int p_vertex_len) const; + /// Returns stride - virtual uint32_t mesh_surface_make_offsets_from_format(uint32_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets) const; - virtual Error mesh_create_surface_data_from_arrays(SurfaceData *r_surface_data, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_compress_format = ARRAY_COMPRESS_DEFAULT); + virtual void mesh_surface_make_offsets_from_format(uint32_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets, uint32_t &r_vertex_element_size, uint32_t &r_attrib_element_size, uint32_t &r_skin_element_size) const; + virtual Error mesh_create_surface_data_from_arrays(SurfaceData *r_surface_data, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_compress_format = 0); Array mesh_create_arrays_from_surface_data(const SurfaceData &p_data) const; Array mesh_surface_get_arrays(RID p_mesh, int p_surface) const; Array mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_surface) const; Dictionary mesh_surface_get_lods(RID p_mesh, int p_surface) const; - virtual void mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_compress_format = ARRAY_COMPRESS_DEFAULT); + virtual void mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_compress_format = 0); virtual void mesh_add_surface(RID p_mesh, const SurfaceData &p_surface) = 0; virtual int mesh_get_blend_shape_count(RID p_mesh) const = 0; @@ -305,6 +354,8 @@ public: virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) = 0; virtual AABB mesh_get_custom_aabb(RID p_mesh) const = 0; + virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) = 0; + virtual void mesh_clear(RID p_mesh) = 0; /* MULTIMESH API */ @@ -316,7 +367,7 @@ public: MULTIMESH_TRANSFORM_3D, }; - virtual void multimesh_allocate(RID p_multimesh, int p_instances, MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) = 0; + virtual void multimesh_allocate_data(RID p_multimesh, int p_instances, MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) = 0; virtual int multimesh_get_instance_count(RID p_multimesh) const = 0; virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh) = 0; @@ -358,7 +409,7 @@ public: /* SKELETON API */ virtual RID skeleton_create() = 0; - virtual void skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) = 0; + virtual void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) = 0; virtual int skeleton_get_bone_count(RID p_skeleton) const = 0; virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) = 0; virtual Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const = 0; @@ -436,6 +487,7 @@ public: virtual void light_directional_set_shadow_mode(RID p_light, LightDirectionalShadowMode p_mode) = 0; virtual void light_directional_set_blend_splits(RID p_light, bool p_enable) = 0; + virtual void light_directional_set_sky_only(RID p_light, bool p_sky_only) = 0; enum LightDirectionalShadowDepthRangeMode { LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE, @@ -473,6 +525,7 @@ public: virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) = 0; virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) = 0; virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution) = 0; + virtual void reflection_probe_set_lod_threshold(RID p_probe, float p_pixels) = 0; /* DECAL API */ @@ -499,7 +552,7 @@ public: virtual RID gi_probe_create() = 0; - virtual void gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) = 0; + virtual void gi_probe_allocate_data(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) = 0; virtual AABB gi_probe_get_bounds(RID p_gi_probe) const = 0; virtual Vector3i gi_probe_get_octree_size(RID p_gi_probe) const = 0; @@ -747,7 +800,7 @@ public: virtual void viewport_set_sdf_oversize_and_scale(RID p_viewport, ViewportSDFOversize p_oversize, ViewportSDFScale p_scale) = 0; - virtual void viewport_set_shadow_atlas_size(RID p_viewport, int p_size) = 0; + virtual void viewport_set_shadow_atlas_size(RID p_viewport, int p_size, bool p_16_bits = false) = 0; virtual void viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv) = 0; enum ViewportMSAA { @@ -771,6 +824,8 @@ public: virtual void viewport_set_use_debanding(RID p_viewport, bool p_use_debanding) = 0; + virtual void viewport_set_lod_threshold(RID p_viewport, float p_pixels) = 0; + enum ViewportRenderInfo { VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME, VIEWPORT_RENDER_INFO_VERTICES_IN_FRAME, @@ -802,7 +857,11 @@ public: VIEWPORT_DEBUG_DRAW_SDFGI, VIEWPORT_DEBUG_DRAW_SDFGI_PROBES, VIEWPORT_DEBUG_DRAW_GI_BUFFER, - + VIEWPORT_DEBUG_DRAW_DISABLE_LOD, + VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS, + VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS, + VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS, + VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES, }; virtual void viewport_set_debug_draw(RID p_viewport, ViewportDebugDraw p_draw) = 0; @@ -811,7 +870,7 @@ public: virtual float viewport_get_measured_render_time_cpu(RID p_viewport) const = 0; virtual float viewport_get_measured_render_time_gpu(RID p_viewport) const = 0; - virtual void directional_shadow_atlas_set_size(int p_size) = 0; + virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = false) = 0; /* SKY API */ @@ -889,7 +948,7 @@ public: }; virtual void environment_set_tonemap(RID p_env, EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_grey) = 0; - virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) = 0; + virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) = 0; virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance) = 0; @@ -902,23 +961,17 @@ public: virtual void environment_set_ssr_roughness_quality(EnvironmentSSRRoughnessQuality p_quality) = 0; - enum EnvironmentSSAOBlur { - ENV_SSAO_BLUR_DISABLED, - ENV_SSAO_BLUR_1x1, - ENV_SSAO_BLUR_2x2, - ENV_SSAO_BLUR_3x3, - }; - - virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_bias, float p_light_affect, float p_ao_channel_affect, EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) = 0; + virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) = 0; enum EnvironmentSSAOQuality { + ENV_SSAO_QUALITY_VERY_LOW, ENV_SSAO_QUALITY_LOW, ENV_SSAO_QUALITY_MEDIUM, ENV_SSAO_QUALITY_HIGH, ENV_SSAO_QUALITY_ULTRA, }; - virtual void environment_set_ssao_quality(EnvironmentSSAOQuality p_quality, bool p_half_size) = 0; + virtual void environment_set_ssao_quality(EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) = 0; enum EnvironmentSDFGICascades { ENV_SDFGI_CASCADES_4, @@ -932,9 +985,10 @@ public: ENV_SDFGI_Y_SCALE_50_PERCENT }; - virtual void environment_set_sdfgi(RID p_env, bool p_enable, EnvironmentSDFGICascades p_cascades, float p_min_cell_size, EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, bool p_use_multibounce, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) = 0; + virtual void environment_set_sdfgi(RID p_env, bool p_enable, EnvironmentSDFGICascades p_cascades, float p_min_cell_size, EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) = 0; enum EnvironmentSDFGIRayCount { + ENV_SDFGI_RAY_COUNT_4, ENV_SDFGI_RAY_COUNT_8, ENV_SDFGI_RAY_COUNT_16, ENV_SDFGI_RAY_COUNT_32, @@ -958,20 +1012,22 @@ public: virtual void environment_set_sdfgi_frames_to_converge(EnvironmentSDFGIFramesToConverge p_frames) = 0; - virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective) = 0; - - enum EnvVolumetricFogShadowFilter { - ENV_VOLUMETRIC_FOG_SHADOW_FILTER_DISABLED, - ENV_VOLUMETRIC_FOG_SHADOW_FILTER_LOW, - ENV_VOLUMETRIC_FOG_SHADOW_FILTER_MEDIUM, - ENV_VOLUMETRIC_FOG_SHADOW_FILTER_HIGH, + enum EnvironmentSDFGIFramesToUpdateLight { + ENV_SDFGI_UPDATE_LIGHT_IN_1_FRAME, + ENV_SDFGI_UPDATE_LIGHT_IN_2_FRAMES, + ENV_SDFGI_UPDATE_LIGHT_IN_4_FRAMES, + ENV_SDFGI_UPDATE_LIGHT_IN_8_FRAMES, + ENV_SDFGI_UPDATE_LIGHT_IN_16_FRAMES, + ENV_SDFGI_UPDATE_LIGHT_MAX, }; - virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, EnvVolumetricFogShadowFilter p_shadow_filter) = 0; + virtual void environment_set_sdfgi_frames_to_update_light(EnvironmentSDFGIFramesToUpdateLight p_update) = 0; + + virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective) = 0; + + virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) = 0; virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) = 0; virtual void environment_set_volumetric_fog_filter_active(bool p_enable) = 0; - virtual void environment_set_volumetric_fog_directional_shadow_shrink_size(int p_shrink_size) = 0; - virtual void environment_set_volumetric_fog_positional_shadow_shrink_size(int p_shrink_size) = 0; virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) = 0; @@ -1108,6 +1164,7 @@ public: virtual void instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) = 0; virtual void instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance) = 0; virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice) = 0; + virtual void instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias) = 0; virtual void instance_geometry_set_shader_parameter(RID p_instance, const StringName &, const Variant &p_value) = 0; virtual Variant instance_geometry_get_shader_parameter(RID p_instance, const StringName &) const = 0; @@ -1175,7 +1232,7 @@ public: }; virtual void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0) = 0; - virtual void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0) = 0; + virtual void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false) = 0; virtual void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0) = 0; virtual void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) = 0; virtual void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) = 0; @@ -1376,6 +1433,10 @@ public: virtual Vector<FrameProfileArea> get_frame_profile() = 0; virtual uint64_t get_frame_profile_frame() = 0; + virtual float get_frame_setup_time_cpu() const = 0; + + virtual void gi_set_use_half_resolution(bool p_enable) = 0; + /* TESTING */ virtual RID get_test_cube() = 0; @@ -1408,6 +1469,8 @@ public: virtual bool is_low_end() const = 0; + virtual void set_print_gpu_profile(bool p_enable) = 0; + RenderingDevice *create_local_rendering_device() const; bool is_render_loop_enabled() const; @@ -1449,7 +1512,6 @@ VARIANT_ENUM_CAST(RenderingServer::EnvironmentReflectionSource); VARIANT_ENUM_CAST(RenderingServer::EnvironmentGlowBlendMode); VARIANT_ENUM_CAST(RenderingServer::EnvironmentToneMapper); VARIANT_ENUM_CAST(RenderingServer::EnvironmentSSRRoughnessQuality); -VARIANT_ENUM_CAST(RenderingServer::EnvironmentSSAOBlur); VARIANT_ENUM_CAST(RenderingServer::EnvironmentSSAOQuality); VARIANT_ENUM_CAST(RenderingServer::SubSurfaceScatteringQuality); VARIANT_ENUM_CAST(RenderingServer::DOFBlurQuality); diff --git a/servers/server_wrap_mt_common.h b/servers/server_wrap_mt_common.h index 4481b296c6..95d2e2254e 100644 --- a/servers/server_wrap_mt_common.h +++ b/servers/server_wrap_mt_common.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -29,245 +29,89 @@ /*************************************************************************/ #define FUNC0R(m_r, m_type) \ - virtual m_r m_type() { \ + virtual m_r m_type() override { \ if (Thread::get_caller_id() != server_thread) { \ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, &ret); \ SYNC_DEBUG \ return ret; \ } else { \ + command_queue.flush_if_pending(); \ return server_name->m_type(); \ } \ } -#define FUNCRID(m_type) \ - List<RID> m_type##_id_pool; \ - int m_type##allocn() { \ - for (int i = 0; i < pool_max_size; i++) { \ - m_type##_id_pool.push_back(server_name->m_type##_create()); \ - } \ - return 0; \ - } \ - void m_type##_free_cached_ids() { \ - while (m_type##_id_pool.size()) { \ - server_name->free(m_type##_id_pool.front()->get()); \ - m_type##_id_pool.pop_front(); \ - } \ - } \ - virtual RID m_type##_create() { \ - if (Thread::get_caller_id() != server_thread) { \ - RID rid; \ - MutexLock lock(alloc_mutex); \ - if (m_type##_id_pool.size() == 0) { \ - int ret; \ - command_queue.push_and_ret(this, &ServerNameWrapMT::m_type##allocn, &ret); \ - SYNC_DEBUG \ - } \ - rid = m_type##_id_pool.front()->get(); \ - m_type##_id_pool.pop_front(); \ - return rid; \ - } else { \ - return server_name->m_type##_create(); \ - } \ - } - -#define FUNC1RID(m_type, m_arg1) \ - int m_type##allocn() { \ - for (int i = 0; i < m_type##_pool_max_size; i++) { \ - m_type##_id_pool.push_back(server_name->m_type##_create()); \ - } \ - return 0; \ - } \ - void m_type##_free_cached_ids() { \ - while (m_type##_id_pool.size()) { \ - free(m_type##_id_pool.front()->get()); \ - m_type##_id_pool.pop_front(); \ - } \ - } \ - virtual RID m_type##_create(m_arg1 p1) { \ - if (Thread::get_caller_id() != server_thread) { \ - RID rid; \ - MutexLock lock(alloc_mutex); \ - if (m_type##_id_pool.size() == 0) { \ - int ret; \ - command_queue.push_and_ret(this, &ServerNameWrapMT::m_type##allocn, p1, &ret); \ - SYNC_DEBUG \ - } \ - rid = m_type##_id_pool.front()->get(); \ - m_type##_id_pool.pop_front(); \ - return rid; \ - } else { \ - return server_name->m_type##_create(p1); \ - } \ - } - -#define FUNC2RID(m_type, m_arg1, m_arg2) \ - int m_type##allocn() { \ - for (int i = 0; i < m_type##_pool_max_size; i++) { \ - m_type##_id_pool.push_back(server_name->m_type##_create()); \ - } \ - return 0; \ - } \ - void m_type##_free_cached_ids() { \ - while (m_type##_id_pool.size()) { \ - free(m_type##_id_pool.front()->get()); \ - m_type##_id_pool.pop_front(); \ - } \ - } \ - virtual RID m_type##_create(m_arg1 p1, m_arg2 p2) { \ - if (Thread::get_caller_id() != server_thread) { \ - RID rid; \ - MutexLock lock(alloc_mutex); \ - if (m_type##_id_pool.size() == 0) { \ - int ret; \ - command_queue.push_and_ret(this, &ServerNameWrapMT::m_type##allocn, p1, p2, &ret); \ - SYNC_DEBUG \ - } \ - rid = m_type##_id_pool.front()->get(); \ - m_type##_id_pool.pop_front(); \ - return rid; \ - } else { \ - return server_name->m_type##_create(p1, p2); \ - } \ - } - -#define FUNC3RID(m_type, m_arg1, m_arg2, m_arg3) \ - int m_type##allocn() { \ - for (int i = 0; i < m_type##_pool_max_size; i++) { \ - m_type##_id_pool.push_back(server_name->m_type##_create()); \ - } \ - return 0; \ - } \ - void m_type##_free_cached_ids() { \ - while (m_type##_id_pool.size()) { \ - free(m_type##_id_pool.front()->get()); \ - m_type##_id_pool.pop_front(); \ - } \ - } \ - virtual RID m_type##_create(m_arg1 p1, m_arg2 p2, m_arg3 p3) { \ - if (Thread::get_caller_id() != server_thread) { \ - RID rid; \ - MutexLock lock(alloc_mutex); \ - if (m_type##_id_pool.size() == 0) { \ - int ret; \ - command_queue.push_and_ret(this, &ServerNameWrapMT::m_type##allocn, p1, p2, p3, &ret); \ - SYNC_DEBUG \ - } \ - rid = m_type##_id_pool.front()->get(); \ - m_type##_id_pool.pop_front(); \ - return rid; \ - } else { \ - return server_name->m_type##_create(p1, p2, p3); \ - } \ - } - -#define FUNC4RID(m_type, m_arg1, m_arg2, m_arg3, m_arg4) \ - int m_type##allocn() { \ - for (int i = 0; i < m_type##_pool_max_size; i++) { \ - m_type##_id_pool.push_back(server_name->m_type##_create()); \ - } \ - return 0; \ - } \ - void m_type##_free_cached_ids() { \ - while (m_type##_id_pool.size()) { \ - free(m_type##_id_pool.front()->get()); \ - m_type##_id_pool.pop_front(); \ - } \ - } \ - virtual RID m_type##_create(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) { \ - if (Thread::get_caller_id() != server_thread) { \ - RID rid; \ - MutexLock lock(alloc_mutex); \ - if (m_type##_id_pool.size() == 0) { \ - int ret; \ - command_queue.push_and_ret(this, &ServerNameWrapMT::m_type##allocn, p1, p2, p3, p4, &ret); \ - SYNC_DEBUG \ - } \ - rid = m_type##_id_pool.front()->get(); \ - m_type##_id_pool.pop_front(); \ - return rid; \ - } else { \ - return server_name->m_type##_create(p1, p2, p3, p4); \ - } \ +#define FUNCRIDSPLIT(m_type) \ + virtual RID m_type##_create() override { \ + RID ret = server_name->m_type##_allocate(); \ + if (Thread::get_caller_id() != server_thread) { \ + command_queue.push(server_name, &ServerName::m_type##_initialize, ret); \ + } else { \ + server_name->m_type##_initialize(ret); \ + } \ + return ret; \ } -#define FUNC5RID(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5) \ - List<RID> m_type##_id_pool; \ - int m_type##allocn(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \ - for (int i = 0; i < pool_max_size; i++) { \ - m_type##_id_pool.push_back(server_name->m_type##_create(p1, p2, p3, p4, p5)); \ - } \ - return 0; \ - } \ - void m_type##_free_cached_ids() { \ - while (m_type##_id_pool.size()) { \ - free(m_type##_id_pool.front()->get()); \ - m_type##_id_pool.pop_front(); \ - } \ - } \ - virtual RID m_type##_create(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \ - if (Thread::get_caller_id() != server_thread) { \ - RID rid; \ - MutexLock lock(alloc_mutex); \ - if (m_type##_id_pool.size() == 0) { \ - int ret; \ - command_queue.push_and_ret(this, &ServerNameWrapMT::m_type##allocn, p1, p2, p3, p4, p5, &ret); \ - SYNC_DEBUG \ - } \ - rid = m_type##_id_pool.front()->get(); \ - m_type##_id_pool.pop_front(); \ - return rid; \ - } else { \ - return server_name->m_type##_create(p1, p2, p3, p4, p5); \ - } \ +//RID now returns directly, ensure thread safety yourself +#define FUNCRID(m_type) \ + virtual RID m_type##_create() override { \ + return server_name->m_type##_create(); \ } #define FUNC0RC(m_r, m_type) \ - virtual m_r m_type() const { \ + virtual m_r m_type() const override { \ + WRITE_ACTION \ if (Thread::get_caller_id() != server_thread) { \ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, &ret); \ SYNC_DEBUG \ return ret; \ } else { \ + command_queue.flush_if_pending(); \ return server_name->m_type(); \ } \ } #define FUNC0(m_type) \ - virtual void m_type() { \ + virtual void m_type() override { \ + WRITE_ACTION \ if (Thread::get_caller_id() != server_thread) { \ command_queue.push(server_name, &ServerName::m_type); \ } else { \ + command_queue.flush_if_pending(); \ server_name->m_type(); \ } \ } #define FUNC0C(m_type) \ - virtual void m_type() const { \ + virtual void m_type() const override { \ if (Thread::get_caller_id() != server_thread) { \ command_queue.push(server_name, &ServerName::m_type); \ } else { \ + command_queue.flush_if_pending(); \ server_name->m_type(); \ } \ } #define FUNC0S(m_type) \ - virtual void m_type() { \ + virtual void m_type() override { \ + WRITE_ACTION \ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type); \ SYNC_DEBUG \ } else { \ + command_queue.flush_if_pending(); \ server_name->m_type(); \ } \ } #define FUNC0SC(m_type) \ - virtual void m_type() const { \ + virtual void m_type() const override { \ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type); \ SYNC_DEBUG \ } else { \ + command_queue.flush_if_pending(); \ server_name->m_type(); \ } \ } @@ -275,560 +119,646 @@ /////////////////////////////////////////////// #define FUNC1R(m_r, m_type, m_arg1) \ - virtual m_r m_type(m_arg1 p1) { \ + virtual m_r m_type(m_arg1 p1) override { \ + WRITE_ACTION \ if (Thread::get_caller_id() != server_thread) { \ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, &ret); \ SYNC_DEBUG \ return ret; \ } else { \ + command_queue.flush_if_pending(); \ return server_name->m_type(p1); \ } \ } #define FUNC1RC(m_r, m_type, m_arg1) \ - virtual m_r m_type(m_arg1 p1) const { \ + virtual m_r m_type(m_arg1 p1) const override { \ if (Thread::get_caller_id() != server_thread) { \ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, &ret); \ SYNC_DEBUG \ return ret; \ } else { \ + command_queue.flush_if_pending(); \ return server_name->m_type(p1); \ } \ } #define FUNC1S(m_type, m_arg1) \ - virtual void m_type(m_arg1 p1) { \ + virtual void m_type(m_arg1 p1) override { \ + WRITE_ACTION \ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1); \ SYNC_DEBUG \ } else { \ + command_queue.flush_if_pending(); \ server_name->m_type(p1); \ } \ } #define FUNC1SC(m_type, m_arg1) \ - virtual void m_type(m_arg1 p1) const { \ + virtual void m_type(m_arg1 p1) const override { \ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1); \ SYNC_DEBUG \ } else { \ + command_queue.flush_if_pending(); \ server_name->m_type(p1); \ } \ } #define FUNC1(m_type, m_arg1) \ - virtual void m_type(m_arg1 p1) { \ + virtual void m_type(m_arg1 p1) override { \ + WRITE_ACTION \ if (Thread::get_caller_id() != server_thread) { \ command_queue.push(server_name, &ServerName::m_type, p1); \ } else { \ + command_queue.flush_if_pending(); \ server_name->m_type(p1); \ } \ } #define FUNC1C(m_type, m_arg1) \ - virtual void m_type(m_arg1 p1) const { \ + virtual void m_type(m_arg1 p1) const override { \ if (Thread::get_caller_id() != server_thread) { \ command_queue.push(server_name, &ServerName::m_type, p1); \ } else { \ + command_queue.flush_if_pending(); \ server_name->m_type(p1); \ } \ } #define FUNC2R(m_r, m_type, m_arg1, m_arg2) \ - virtual m_r m_type(m_arg1 p1, m_arg2 p2) { \ + virtual m_r m_type(m_arg1 p1, m_arg2 p2) override { \ + WRITE_ACTION \ if (Thread::get_caller_id() != server_thread) { \ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, &ret); \ SYNC_DEBUG \ return ret; \ } else { \ + command_queue.flush_if_pending(); \ return server_name->m_type(p1, p2); \ } \ } #define FUNC2RC(m_r, m_type, m_arg1, m_arg2) \ - virtual m_r m_type(m_arg1 p1, m_arg2 p2) const { \ + virtual m_r m_type(m_arg1 p1, m_arg2 p2) const override { \ if (Thread::get_caller_id() != server_thread) { \ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, &ret); \ SYNC_DEBUG \ return ret; \ } else { \ + command_queue.flush_if_pending(); \ return server_name->m_type(p1, p2); \ } \ } #define FUNC2S(m_type, m_arg1, m_arg2) \ - virtual void m_type(m_arg1 p1, m_arg2 p2) { \ + virtual void m_type(m_arg1 p1, m_arg2 p2) override { \ + WRITE_ACTION \ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2); \ SYNC_DEBUG \ } else { \ + command_queue.flush_if_pending(); \ server_name->m_type(p1, p2); \ } \ } #define FUNC2SC(m_type, m_arg1, m_arg2) \ - virtual void m_type(m_arg1 p1, m_arg2 p2) const { \ + virtual void m_type(m_arg1 p1, m_arg2 p2) const override { \ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2); \ SYNC_DEBUG \ } else { \ + command_queue.flush_if_pending(); \ server_name->m_type(p1, p2); \ } \ } #define FUNC2(m_type, m_arg1, m_arg2) \ - virtual void m_type(m_arg1 p1, m_arg2 p2) { \ + virtual void m_type(m_arg1 p1, m_arg2 p2) override { \ + WRITE_ACTION \ if (Thread::get_caller_id() != server_thread) { \ command_queue.push(server_name, &ServerName::m_type, p1, p2); \ } else { \ + command_queue.flush_if_pending(); \ server_name->m_type(p1, p2); \ } \ } #define FUNC2C(m_type, m_arg1, m_arg2) \ - virtual void m_type(m_arg1 p1, m_arg2 p2) const { \ + virtual void m_type(m_arg1 p1, m_arg2 p2) const override { \ if (Thread::get_caller_id() != server_thread) { \ command_queue.push(server_name, &ServerName::m_type, p1, p2); \ } else { \ + command_queue.flush_if_pending(); \ server_name->m_type(p1, p2); \ } \ } #define FUNC3R(m_r, m_type, m_arg1, m_arg2, m_arg3) \ - virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) { \ + virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) override { \ + WRITE_ACTION \ if (Thread::get_caller_id() != server_thread) { \ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, &ret); \ SYNC_DEBUG \ return ret; \ } else { \ + command_queue.flush_if_pending(); \ return server_name->m_type(p1, p2, p3); \ } \ } #define FUNC3RC(m_r, m_type, m_arg1, m_arg2, m_arg3) \ - virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const { \ + virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const override { \ if (Thread::get_caller_id() != server_thread) { \ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, &ret); \ SYNC_DEBUG \ return ret; \ } else { \ + command_queue.flush_if_pending(); \ return server_name->m_type(p1, p2, p3); \ } \ } #define FUNC3S(m_type, m_arg1, m_arg2, m_arg3) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) { \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) override { \ + WRITE_ACTION \ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3); \ SYNC_DEBUG \ } else { \ + command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3); \ } \ } #define FUNC3SC(m_type, m_arg1, m_arg2, m_arg3) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const { \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const override { \ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3); \ SYNC_DEBUG \ } else { \ + command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3); \ } \ } #define FUNC3(m_type, m_arg1, m_arg2, m_arg3) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) { \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) override { \ + WRITE_ACTION \ if (Thread::get_caller_id() != server_thread) { \ command_queue.push(server_name, &ServerName::m_type, p1, p2, p3); \ } else { \ + command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3); \ } \ } #define FUNC3C(m_type, m_arg1, m_arg2, m_arg3) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const { \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const override { \ if (Thread::get_caller_id() != server_thread) { \ command_queue.push(server_name, &ServerName::m_type, p1, p2, p3); \ } else { \ + command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3); \ } \ } #define FUNC4R(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4) \ - virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) { \ + virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) override { \ + WRITE_ACTION \ if (Thread::get_caller_id() != server_thread) { \ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, &ret); \ SYNC_DEBUG \ return ret; \ } else { \ + command_queue.flush_if_pending(); \ return server_name->m_type(p1, p2, p3, p4); \ } \ } #define FUNC4RC(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4) \ - virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const { \ + virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const override { \ if (Thread::get_caller_id() != server_thread) { \ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, &ret); \ SYNC_DEBUG \ return ret; \ } else { \ + command_queue.flush_if_pending(); \ return server_name->m_type(p1, p2, p3, p4); \ } \ } #define FUNC4S(m_type, m_arg1, m_arg2, m_arg3, m_arg4) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) { \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) override { \ + WRITE_ACTION \ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4); \ SYNC_DEBUG \ } else { \ + command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3, p4); \ } \ } #define FUNC4SC(m_type, m_arg1, m_arg2, m_arg3, m_arg4) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const { \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const override { \ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4); \ SYNC_DEBUG \ } else { \ + command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3, p4); \ } \ } #define FUNC4(m_type, m_arg1, m_arg2, m_arg3, m_arg4) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) { \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) override { \ + WRITE_ACTION \ if (Thread::get_caller_id() != server_thread) { \ command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4); \ } else { \ + command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3, p4); \ } \ } -#define FUNC4C(m_type, m_arg1, m_arg2, m_arg3, m_arg4) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const { \ - if (Thread::get_caller_id() != server_thread) { \ - command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4); \ - } else { \ - server_name->m_type(p1, p2, p3, p4); \ - } \ +#define FUNC4C(m_type, m_arg1, m_arg2, m_arg3, m_arg4) \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const override { \ + if (Thread::get_caller_id() != server_thread) { \ + command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4); \ + } else { \ + command_queue.flush_if_pending(); \ + server_name->m_type(p1, p2, p3, p4); \ + } \ } #define FUNC5R(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5) \ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \ + WRITE_ACTION \ if (Thread::get_caller_id() != server_thread) { \ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, &ret); \ SYNC_DEBUG \ return ret; \ } else { \ + command_queue.flush_if_pending(); \ return server_name->m_type(p1, p2, p3, p4, p5); \ } \ } #define FUNC5RC(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5) \ - virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const { \ + virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const override { \ if (Thread::get_caller_id() != server_thread) { \ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, &ret); \ SYNC_DEBUG \ return ret; \ } else { \ + command_queue.flush_if_pending(); \ return server_name->m_type(p1, p2, p3, p4, p5); \ } \ } #define FUNC5S(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) override { \ + WRITE_ACTION \ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5); \ SYNC_DEBUG \ } else { \ + command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3, p4, p5); \ } \ } -#define FUNC5SC(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const { \ - if (Thread::get_caller_id() != server_thread) { \ - command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5); \ - SYNC_DEBUG \ - } else { \ - server_name->m_type(p1, p2, p3, p4, p5); \ - } \ +#define FUNC5SC(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5) \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const override { \ + if (Thread::get_caller_id() != server_thread) { \ + command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5); \ + SYNC_DEBUG \ + } else { \ + command_queue.flush_if_pending(); \ + server_name->m_type(p1, p2, p3, p4, p5); \ + } \ } -#define FUNC5(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \ - if (Thread::get_caller_id() != server_thread) { \ - command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5); \ - } else { \ - server_name->m_type(p1, p2, p3, p4, p5); \ - } \ +#define FUNC5(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5) \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) override { \ + WRITE_ACTION \ + if (Thread::get_caller_id() != server_thread) { \ + command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5); \ + } else { \ + command_queue.flush_if_pending(); \ + server_name->m_type(p1, p2, p3, p4, p5); \ + } \ } -#define FUNC5C(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const { \ - if (Thread::get_caller_id() != server_thread) { \ - command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5); \ - } else { \ - server_name->m_type(p1, p2, p3, p4, p5); \ - } \ +#define FUNC5C(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5) \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const override { \ + if (Thread::get_caller_id() != server_thread) { \ + command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5); \ + } else { \ + command_queue.flush_if_pending(); \ + server_name->m_type(p1, p2, p3, p4, p5); \ + } \ } #define FUNC6R(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6) \ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) { \ + WRITE_ACTION \ if (Thread::get_caller_id() != server_thread) { \ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, &ret); \ SYNC_DEBUG \ return ret; \ } else { \ + command_queue.flush_if_pending(); \ return server_name->m_type(p1, p2, p3, p4, p5, p6); \ } \ } -#define FUNC6RC(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6) \ - virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const { \ - if (Thread::get_caller_id() != server_thread) { \ - m_r ret; \ - command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, &ret); \ - SYNC_DEBUG \ - return ret; \ - } else { \ - return server_name->m_type(p1, p2, p3, p4, p5, p6); \ - } \ +#define FUNC6RC(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6) \ + virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const override { \ + if (Thread::get_caller_id() != server_thread) { \ + m_r ret; \ + command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, &ret); \ + SYNC_DEBUG \ + return ret; \ + } else { \ + command_queue.flush_if_pending(); \ + return server_name->m_type(p1, p2, p3, p4, p5, p6); \ + } \ + } + +#define FUNC6S(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6) \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) override { \ + WRITE_ACTION \ + if (Thread::get_caller_id() != server_thread) { \ + command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6); \ + SYNC_DEBUG \ + } else { \ + command_queue.flush_if_pending(); \ + server_name->m_type(p1, p2, p3, p4, p5, p6); \ + } \ + } + +#define FUNC6SC(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6) \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const override { \ + if (Thread::get_caller_id() != server_thread) { \ + command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6); \ + SYNC_DEBUG \ + } else { \ + command_queue.flush_if_pending(); \ + server_name->m_type(p1, p2, p3, p4, p5, p6); \ + } \ } -#define FUNC6S(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) { \ - if (Thread::get_caller_id() != server_thread) { \ - command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6); \ - SYNC_DEBUG \ - } else { \ - server_name->m_type(p1, p2, p3, p4, p5, p6); \ - } \ +#define FUNC6(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6) \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) override { \ + WRITE_ACTION \ + if (Thread::get_caller_id() != server_thread) { \ + command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6); \ + } else { \ + command_queue.flush_if_pending(); \ + server_name->m_type(p1, p2, p3, p4, p5, p6); \ + } \ } -#define FUNC6SC(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const { \ - if (Thread::get_caller_id() != server_thread) { \ - command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6); \ - SYNC_DEBUG \ - } else { \ - server_name->m_type(p1, p2, p3, p4, p5, p6); \ - } \ +#define FUNC6C(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6) \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const override { \ + if (Thread::get_caller_id() != server_thread) { \ + command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6); \ + } else { \ + command_queue.flush_if_pending(); \ + server_name->m_type(p1, p2, p3, p4, p5, p6); \ + } \ } -#define FUNC6(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) { \ - if (Thread::get_caller_id() != server_thread) { \ - command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6); \ - } else { \ - server_name->m_type(p1, p2, p3, p4, p5, p6); \ - } \ +#define FUNC7R(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7) \ + virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) override { \ + WRITE_ACTION \ + if (Thread::get_caller_id() != server_thread) { \ + m_r ret; \ + command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, &ret); \ + SYNC_DEBUG \ + return ret; \ + } else { \ + command_queue.flush_if_pending(); \ + return server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \ + } \ } -#define FUNC6C(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const { \ - if (Thread::get_caller_id() != server_thread) { \ - command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6); \ - } else { \ - server_name->m_type(p1, p2, p3, p4, p5, p6); \ - } \ - } - -#define FUNC7R(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7) \ - virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) { \ - if (Thread::get_caller_id() != server_thread) { \ - m_r ret; \ - command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, &ret); \ - SYNC_DEBUG \ - return ret; \ - } else { \ - return server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \ - } \ - } - -#define FUNC7RC(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7) \ - virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const { \ - if (Thread::get_caller_id() != server_thread) { \ - m_r ret; \ - command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, &ret); \ - SYNC_DEBUG \ - return ret; \ - } else { \ - return server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \ - } \ - } - -#define FUNC7S(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) { \ - if (Thread::get_caller_id() != server_thread) { \ - command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7); \ - SYNC_DEBUG \ - } else { \ - server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \ - } \ - } - -#define FUNC7SC(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const { \ - if (Thread::get_caller_id() != server_thread) { \ - command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7); \ - SYNC_DEBUG \ - } else { \ - server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \ - } \ - } - -#define FUNC7(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) { \ - if (Thread::get_caller_id() != server_thread) { \ - command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7); \ - } else { \ - server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \ - } \ - } - -#define FUNC7C(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const { \ - if (Thread::get_caller_id() != server_thread) { \ - command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7); \ - } else { \ - server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \ - } \ - } - -#define FUNC8R(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8) \ - virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8) { \ - if (Thread::get_caller_id() != server_thread) { \ - m_r ret; \ - command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, &ret); \ - SYNC_DEBUG \ - return ret; \ - } else { \ - return server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \ - } \ - } - -#define FUNC8RC(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8) \ - virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8) const { \ - if (Thread::get_caller_id() != server_thread) { \ - m_r ret; \ - command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, &ret); \ - SYNC_DEBUG \ - return ret; \ - } else { \ - return server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \ - } \ - } - -#define FUNC8S(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8) { \ - if (Thread::get_caller_id() != server_thread) { \ - command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8); \ - SYNC_DEBUG \ - } else { \ - server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \ - } \ - } - -#define FUNC8SC(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8) const { \ - if (Thread::get_caller_id() != server_thread) { \ - command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8); \ - SYNC_DEBUG \ - } else { \ - server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \ - } \ - } - -#define FUNC8(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8) { \ - if (Thread::get_caller_id() != server_thread) { \ - command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8); \ - } else { \ - server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \ - } \ - } - -#define FUNC8C(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8) const { \ - if (Thread::get_caller_id() != server_thread) { \ - command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8); \ - } else { \ - server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \ - } \ - } - -#define FUNC9(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9) { \ - if (Thread::get_caller_id() != server_thread) { \ - command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9); \ - } else { \ - server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9); \ - } \ - } - -#define FUNC10(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9, m_arg10 p10) { \ - if (Thread::get_caller_id() != server_thread) { \ - command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \ - } else { \ - server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \ - } \ - } - -#define FUNC11(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9, m_arg10 p10, m_arg11 p11) { \ - if (Thread::get_caller_id() != server_thread) { \ - command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \ - } else { \ - server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \ - } \ - } - -#define FUNC12(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9, m_arg10 p10, m_arg11 p11, m_arg12 p12) { \ - if (Thread::get_caller_id() != server_thread) { \ - command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \ - } else { \ - server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \ - } \ - } - -#define FUNC13(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12, m_arg13) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9, m_arg10 p10, m_arg11 p11, m_arg12 p12, m_arg13 p13) { \ - if (Thread::get_caller_id() != server_thread) { \ - command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \ - } else { \ - server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \ - } \ - } - -#define FUNC14(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12, m_arg13, m_arg14) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9, m_arg10 p10, m_arg11 p11, m_arg12 p12, m_arg13 p13, m_arg14 p14) { \ - if (Thread::get_caller_id() != server_thread) { \ - command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \ - } else { \ - server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \ - } \ - } - -#define FUNC15(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12, m_arg13, m_arg14, m_arg15) \ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9, m_arg10 p10, m_arg11 p11, m_arg12 p12, m_arg13 p13, m_arg14 p14, m_arg15 p15) { \ - if (Thread::get_caller_id() != server_thread) { \ - command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); \ - } else { \ - server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); \ - } \ +#define FUNC7RC(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7) \ + virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const override { \ + if (Thread::get_caller_id() != server_thread) { \ + m_r ret; \ + command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, &ret); \ + SYNC_DEBUG \ + return ret; \ + } else { \ + command_queue.flush_if_pending(); \ + return server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \ + } \ + } + +#define FUNC7S(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7) \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) override { \ + WRITE_ACTION \ + if (Thread::get_caller_id() != server_thread) { \ + command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7); \ + SYNC_DEBUG \ + } else { \ + command_queue.flush_if_pending(); \ + server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \ + } \ + } + +#define FUNC7SC(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7) \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const override { \ + if (Thread::get_caller_id() != server_thread) { \ + command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7); \ + SYNC_DEBUG \ + } else { \ + command_queue.flush_if_pending(); \ + server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \ + } \ + } + +#define FUNC7(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7) \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) override { \ + WRITE_ACTION \ + if (Thread::get_caller_id() != server_thread) { \ + command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7); \ + } else { \ + command_queue.flush_if_pending(); \ + server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \ + } \ + } + +#define FUNC7C(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7) \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const override { \ + if (Thread::get_caller_id() != server_thread) { \ + command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7); \ + } else { \ + command_queue.flush_if_pending(); \ + server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \ + } \ + } + +#define FUNC8R(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8) \ + virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8) override { \ + WRITE_ACTION \ + if (Thread::get_caller_id() != server_thread) { \ + m_r ret; \ + command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, &ret); \ + SYNC_DEBUG \ + return ret; \ + } else { \ + command_queue.flush_if_pending(); \ + return server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \ + } \ + } + +#define FUNC8RC(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8) \ + virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8) const override { \ + if (Thread::get_caller_id() != server_thread) { \ + m_r ret; \ + command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, &ret); \ + SYNC_DEBUG \ + return ret; \ + } else { \ + command_queue.flush_if_pending(); \ + return server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \ + } \ + } + +#define FUNC8S(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8) \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8) override { \ + WRITE_ACTION \ + if (Thread::get_caller_id() != server_thread) { \ + command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8); \ + SYNC_DEBUG \ + } else { \ + command_queue.flush_if_pending(); \ + server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \ + } \ + } + +#define FUNC8SC(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8) \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8) const override { \ + if (Thread::get_caller_id() != server_thread) { \ + command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8); \ + SYNC_DEBUG \ + } else { \ + command_queue.flush_if_pending(); \ + server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \ + } \ + } + +#define FUNC8(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8) \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8) override { \ + WRITE_ACTION \ + if (Thread::get_caller_id() != server_thread) { \ + command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8); \ + } else { \ + command_queue.flush_if_pending(); \ + server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \ + } \ + } + +#define FUNC8C(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8) \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8) const override { \ + if (Thread::get_caller_id() != server_thread) { \ + command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8); \ + } else { \ + command_queue.flush_if_pending(); \ + server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \ + } \ + } + +#define FUNC9(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9) \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9) override { \ + WRITE_ACTION \ + if (Thread::get_caller_id() != server_thread) { \ + command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9); \ + } else { \ + command_queue.flush_if_pending(); \ + server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9); \ + } \ + } + +#define FUNC10(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10) \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9, m_arg10 p10) override { \ + WRITE_ACTION \ + if (Thread::get_caller_id() != server_thread) { \ + command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \ + } else { \ + command_queue.flush_if_pending(); \ + server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \ + } \ + } + +#define FUNC11(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11) \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9, m_arg10 p10, m_arg11 p11) override { \ + WRITE_ACTION \ + if (Thread::get_caller_id() != server_thread) { \ + command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \ + } else { \ + command_queue.flush_if_pending(); \ + server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \ + } \ + } + +#define FUNC12(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12) \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9, m_arg10 p10, m_arg11 p11, m_arg12 p12) override { \ + WRITE_ACTION \ + if (Thread::get_caller_id() != server_thread) { \ + command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \ + } else { \ + command_queue.flush_if_pending(); \ + server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \ + } \ + } + +#define FUNC13(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12, m_arg13) \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9, m_arg10 p10, m_arg11 p11, m_arg12 p12, m_arg13 p13) override { \ + WRITE_ACTION \ + if (Thread::get_caller_id() != server_thread) { \ + command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \ + } else { \ + command_queue.flush_if_pending(); \ + server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \ + } \ + } + +#define FUNC14(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12, m_arg13, m_arg14) \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9, m_arg10 p10, m_arg11 p11, m_arg12 p12, m_arg13 p13, m_arg14 p14) override { \ + WRITE_ACTION \ + if (Thread::get_caller_id() != server_thread) { \ + command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \ + } else { \ + command_queue.flush_if_pending(); \ + server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \ + } \ + } + +#define FUNC15(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12, m_arg13, m_arg14, m_arg15) \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9, m_arg10 p10, m_arg11 p11, m_arg12 p12, m_arg13 p13, m_arg14 p14, m_arg15 p15) override { \ + WRITE_ACTION \ + if (Thread::get_caller_id() != server_thread) { \ + command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); \ + } else { \ + command_queue.flush_if_pending(); \ + server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); \ + } \ } diff --git a/servers/text_server.cpp b/servers/text_server.cpp new file mode 100644 index 0000000000..27fdd090f1 --- /dev/null +++ b/servers/text_server.cpp @@ -0,0 +1,1305 @@ +/*************************************************************************/ +/* text_server.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "servers/text_server.h" +#include "scene/main/canvas_item.h" + +TextServerManager *TextServerManager::singleton = nullptr; +TextServer *TextServerManager::server = nullptr; +TextServerManager::TextServerCreate TextServerManager::server_create_functions[TextServerManager::MAX_SERVERS]; +int TextServerManager::server_create_count = 0; + +void TextServerManager::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_interface_count"), &TextServerManager::_get_interface_count); + ClassDB::bind_method(D_METHOD("get_interface_name", "index"), &TextServerManager::_get_interface_name); + ClassDB::bind_method(D_METHOD("get_interface_features", "index"), &TextServerManager::_get_interface_features); + ClassDB::bind_method(D_METHOD("get_interface", "index"), &TextServerManager::_get_interface); + ClassDB::bind_method(D_METHOD("get_interfaces"), &TextServerManager::_get_interfaces); + ClassDB::bind_method(D_METHOD("find_interface", "name"), &TextServerManager::_find_interface); + + ClassDB::bind_method(D_METHOD("set_primary_interface", "index"), &TextServerManager::_set_primary_interface); + ClassDB::bind_method(D_METHOD("get_primary_interface"), &TextServerManager::_get_primary_interface); +} + +void TextServerManager::register_create_function(const String &p_name, uint32_t p_features, TextServerManager::CreateFunction p_function, void *p_user_data) { + ERR_FAIL_COND(server_create_count == MAX_SERVERS); + server_create_functions[server_create_count].name = p_name; + server_create_functions[server_create_count].create_function = p_function; + server_create_functions[server_create_count].user_data = p_user_data; + server_create_functions[server_create_count].features = p_features; + server_create_count++; +} + +int TextServerManager::get_interface_count() { + return server_create_count; +} + +String TextServerManager::get_interface_name(int p_index) { + ERR_FAIL_INDEX_V(p_index, server_create_count, String()); + return server_create_functions[p_index].name; +} + +uint32_t TextServerManager::get_interface_features(int p_index) { + ERR_FAIL_INDEX_V(p_index, server_create_count, 0); + return server_create_functions[p_index].features; +} + +TextServer *TextServerManager::initialize(int p_index, Error &r_error) { + ERR_FAIL_INDEX_V(p_index, server_create_count, nullptr); + if (server_create_functions[p_index].instance == nullptr) { + server_create_functions[p_index].instance = server_create_functions[p_index].create_function(r_error, server_create_functions[p_index].user_data); + if (server_create_functions[p_index].instance != nullptr) { + server_create_functions[p_index].instance->load_support_data(""); // Try loading default data. + } + } + if (server_create_functions[p_index].instance != nullptr) { + server = server_create_functions[p_index].instance; + if (OS::get_singleton()->get_main_loop()) { + OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_TEXT_SERVER_CHANGED); + } + } + return server_create_functions[p_index].instance; +} + +TextServer *TextServerManager::get_primary_interface() { + return server; +} + +int TextServerManager::_get_interface_count() const { + return server_create_count; +} + +String TextServerManager::_get_interface_name(int p_index) const { + return get_interface_name(p_index); +} + +uint32_t TextServerManager::_get_interface_features(int p_index) const { + return get_interface_features(p_index); +} + +TextServer *TextServerManager::_get_interface(int p_index) const { + ERR_FAIL_INDEX_V(p_index, server_create_count, nullptr); + if (server_create_functions[p_index].instance == nullptr) { + Error error; + server_create_functions[p_index].instance = server_create_functions[p_index].create_function(error, server_create_functions[p_index].user_data); + if (server_create_functions[p_index].instance != nullptr) { + server_create_functions[p_index].instance->load_support_data(""); // Try loading default data. + } + } + return server_create_functions[p_index].instance; +} + +TextServer *TextServerManager::_find_interface(const String &p_name) const { + for (int i = 0; i < server_create_count; i++) { + if (server_create_functions[i].name == p_name) { + return _get_interface(i); + } + } + return nullptr; +} + +Array TextServerManager::_get_interfaces() const { + Array ret; + + for (int i = 0; i < server_create_count; i++) { + Dictionary iface_info; + + iface_info["id"] = i; + iface_info["name"] = server_create_functions[i].name; + + ret.push_back(iface_info); + }; + + return ret; +}; + +bool TextServerManager::_set_primary_interface(int p_index) { + Error error; + TextServerManager::initialize(p_index, error); + return (error == OK); +} + +TextServer *TextServerManager::_get_primary_interface() const { + return server; +} + +TextServerManager::TextServerManager() { + singleton = this; +} + +TextServerManager::~TextServerManager() { + singleton = nullptr; + for (int i = 0; i < server_create_count; i++) { + if (server_create_functions[i].instance != nullptr) { + memdelete(server_create_functions[i].instance); + server_create_functions[i].instance = nullptr; + } + } +} + +/*************************************************************************/ + +bool TextServer::Glyph::operator==(const Glyph &p_a) const { + return (p_a.index == index) && (p_a.font_rid == font_rid) && (p_a.font_size == font_size) && (p_a.start == start); +} + +bool TextServer::Glyph::operator!=(const Glyph &p_a) const { + return (p_a.index != index) || (p_a.font_rid != font_rid) || (p_a.font_size != font_size) || (p_a.start != start); +} + +bool TextServer::Glyph::operator<(const Glyph &p_a) const { + if (p_a.start == start) { + if (p_a.count == count) { + if ((p_a.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) { + return true; + } else { + return false; + } + } + return p_a.count > count; + } + return p_a.start < start; +} + +bool TextServer::Glyph::operator>(const Glyph &p_a) const { + if (p_a.start == start) { + if (p_a.count == count) { + if ((p_a.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) { + return false; + } else { + return true; + } + } + return p_a.count < count; + } + return p_a.start > start; +} + +void TextServer::_bind_methods() { + ClassDB::bind_method(D_METHOD("has_feature", "feature"), &TextServer::has_feature); + ClassDB::bind_method(D_METHOD("get_name"), &TextServer::get_name); + ClassDB::bind_method(D_METHOD("load_support_data", "filename"), &TextServer::load_support_data); + + ClassDB::bind_method(D_METHOD("is_locale_right_to_left", "locale"), &TextServer::is_locale_right_to_left); + + ClassDB::bind_method(D_METHOD("name_to_tag", "name"), &TextServer::name_to_tag); + ClassDB::bind_method(D_METHOD("tag_to_name", "tag"), &TextServer::tag_to_name); + + ClassDB::bind_method(D_METHOD("has", "rid"), &TextServer::has); + ClassDB::bind_method(D_METHOD("free_rid", "rid"), &TextServer::free); // shouldn't conflict with Object::free() + + /* Font Interface */ + ClassDB::bind_method(D_METHOD("create_font_system", "name", "base_size"), &TextServer::create_font_system, DEFVAL(16)); + ClassDB::bind_method(D_METHOD("create_font_resource", "filename", "base_size"), &TextServer::create_font_resource, DEFVAL(16)); + ClassDB::bind_method(D_METHOD("create_font_memory", "data", "type", "base_size"), &TextServer::_create_font_memory, DEFVAL(16)); + + ClassDB::bind_method(D_METHOD("font_get_height", "font", "size"), &TextServer::font_get_height); + ClassDB::bind_method(D_METHOD("font_get_ascent", "font", "size"), &TextServer::font_get_ascent); + ClassDB::bind_method(D_METHOD("font_get_descent", "font", "size"), &TextServer::font_get_descent); + + ClassDB::bind_method(D_METHOD("font_get_underline_position", "font", "size"), &TextServer::font_get_underline_position); + ClassDB::bind_method(D_METHOD("font_get_underline_thickness", "font", "size"), &TextServer::font_get_underline_thickness); + + ClassDB::bind_method(D_METHOD("font_get_spacing_space", "font"), &TextServer::font_get_spacing_space); + ClassDB::bind_method(D_METHOD("font_set_spacing_space", "font", "value"), &TextServer::font_set_spacing_space); + + ClassDB::bind_method(D_METHOD("font_get_spacing_glyph", "font"), &TextServer::font_get_spacing_glyph); + ClassDB::bind_method(D_METHOD("font_set_spacing_glyph", "font", "value"), &TextServer::font_set_spacing_glyph); + + ClassDB::bind_method(D_METHOD("font_set_antialiased", "font", "antialiased"), &TextServer::font_set_antialiased); + ClassDB::bind_method(D_METHOD("font_get_antialiased", "font"), &TextServer::font_get_antialiased); + + ClassDB::bind_method(D_METHOD("font_get_feature_list", "font"), &TextServer::font_get_feature_list); + ClassDB::bind_method(D_METHOD("font_get_variation_list", "font"), &TextServer::font_get_variation_list); + + ClassDB::bind_method(D_METHOD("font_set_variation", "font", "tag", "value"), &TextServer::font_set_variation); + ClassDB::bind_method(D_METHOD("font_get_variation", "font", "tag"), &TextServer::font_get_variation); + + ClassDB::bind_method(D_METHOD("font_set_hinting", "font", "hinting"), &TextServer::font_set_hinting); + ClassDB::bind_method(D_METHOD("font_get_hinting", "font"), &TextServer::font_get_hinting); + + ClassDB::bind_method(D_METHOD("font_set_distance_field_hint", "font", "distance_field"), &TextServer::font_set_distance_field_hint); + ClassDB::bind_method(D_METHOD("font_get_distance_field_hint", "font"), &TextServer::font_get_distance_field_hint); + + ClassDB::bind_method(D_METHOD("font_set_force_autohinter", "font", "enabeld"), &TextServer::font_set_force_autohinter); + ClassDB::bind_method(D_METHOD("font_get_force_autohinter", "font"), &TextServer::font_get_force_autohinter); + + ClassDB::bind_method(D_METHOD("font_has_char", "font", "char"), &TextServer::font_has_char); + ClassDB::bind_method(D_METHOD("font_get_supported_chars", "font"), &TextServer::font_get_supported_chars); + + ClassDB::bind_method(D_METHOD("font_has_outline", "font"), &TextServer::font_has_outline); + ClassDB::bind_method(D_METHOD("font_get_base_size", "font"), &TextServer::font_get_base_size); + + ClassDB::bind_method(D_METHOD("font_is_language_supported", "font", "language"), &TextServer::font_is_language_supported); + ClassDB::bind_method(D_METHOD("font_set_language_support_override", "font", "language", "supported"), &TextServer::font_set_language_support_override); + + ClassDB::bind_method(D_METHOD("font_get_language_support_override", "font", "language"), &TextServer::font_get_language_support_override); + ClassDB::bind_method(D_METHOD("font_remove_language_support_override", "font", "language"), &TextServer::font_remove_language_support_override); + ClassDB::bind_method(D_METHOD("font_get_language_support_overrides", "font"), &TextServer::font_get_language_support_overrides); + + ClassDB::bind_method(D_METHOD("font_is_script_supported", "font", "script"), &TextServer::font_is_script_supported); + ClassDB::bind_method(D_METHOD("font_set_script_support_override", "font", "script", "supported"), &TextServer::font_set_script_support_override); + + ClassDB::bind_method(D_METHOD("font_get_script_support_override", "font", "script"), &TextServer::font_get_script_support_override); + ClassDB::bind_method(D_METHOD("font_remove_script_support_override", "font", "script"), &TextServer::font_remove_script_support_override); + ClassDB::bind_method(D_METHOD("font_get_script_support_overrides", "font"), &TextServer::font_get_script_support_overrides); + + ClassDB::bind_method(D_METHOD("font_get_glyph_index", "font", "char", "variation_selector"), &TextServer::font_get_glyph_index, DEFVAL(0x0000)); + ClassDB::bind_method(D_METHOD("font_get_glyph_advance", "font", "index", "size"), &TextServer::font_get_glyph_advance); + ClassDB::bind_method(D_METHOD("font_get_glyph_kerning", "font", "index_a", "index_b", "size"), &TextServer::font_get_glyph_kerning); + + ClassDB::bind_method(D_METHOD("font_draw_glyph", "font", "canvas", "size", "pos", "index", "color"), &TextServer::font_draw_glyph, DEFVAL(Color(1, 1, 1))); + ClassDB::bind_method(D_METHOD("font_draw_glyph_outline", "font", "canvas", "size", "outline_size", "pos", "index", "color"), &TextServer::font_draw_glyph_outline, DEFVAL(Color(1, 1, 1))); + + ClassDB::bind_method(D_METHOD("font_get_oversampling"), &TextServer::font_get_oversampling); + ClassDB::bind_method(D_METHOD("font_set_oversampling", "oversampling"), &TextServer::font_set_oversampling); + + ClassDB::bind_method(D_METHOD("get_system_fonts"), &TextServer::get_system_fonts); + + ClassDB::bind_method(D_METHOD("get_hex_code_box_size", "size", "index"), &TextServer::get_hex_code_box_size); + ClassDB::bind_method(D_METHOD("draw_hex_code_box", "canvas", "size", "pos", "index", "color"), &TextServer::draw_hex_code_box); + + /* Shaped text buffer interface */ + + ClassDB::bind_method(D_METHOD("create_shaped_text", "direction", "orientation"), &TextServer::create_shaped_text, DEFVAL(DIRECTION_AUTO), DEFVAL(ORIENTATION_HORIZONTAL)); + + ClassDB::bind_method(D_METHOD("shaped_text_clear", "rid"), &TextServer::shaped_text_clear); + + ClassDB::bind_method(D_METHOD("shaped_text_set_direction", "shaped", "direction"), &TextServer::shaped_text_set_direction, DEFVAL(DIRECTION_AUTO)); + ClassDB::bind_method(D_METHOD("shaped_text_get_direction", "shaped"), &TextServer::shaped_text_get_direction); + + ClassDB::bind_method(D_METHOD("shaped_text_set_bidi_override", "shaped", "override"), &TextServer::_shaped_text_set_bidi_override); + + ClassDB::bind_method(D_METHOD("shaped_text_set_orientation", "shaped", "orientation"), &TextServer::shaped_text_set_orientation, DEFVAL(ORIENTATION_HORIZONTAL)); + ClassDB::bind_method(D_METHOD("shaped_text_get_orientation", "shaped"), &TextServer::shaped_text_get_orientation); + + ClassDB::bind_method(D_METHOD("shaped_text_set_preserve_invalid", "shaped", "enabled"), &TextServer::shaped_text_set_preserve_invalid); + ClassDB::bind_method(D_METHOD("shaped_text_get_preserve_invalid", "shaped"), &TextServer::shaped_text_get_preserve_invalid); + + ClassDB::bind_method(D_METHOD("shaped_text_set_preserve_control", "shaped", "enabled"), &TextServer::shaped_text_set_preserve_control); + ClassDB::bind_method(D_METHOD("shaped_text_get_preserve_control", "shaped"), &TextServer::shaped_text_get_preserve_control); + + ClassDB::bind_method(D_METHOD("shaped_text_add_string", "shaped", "text", "fonts", "size", "opentype_features", "language"), &TextServer::shaped_text_add_string, DEFVAL(Dictionary()), DEFVAL("")); + ClassDB::bind_method(D_METHOD("shaped_text_add_object", "shaped", "key", "size", "inline_align", "length"), &TextServer::shaped_text_add_object, DEFVAL(VALIGN_CENTER), DEFVAL(1)); + ClassDB::bind_method(D_METHOD("shaped_text_resize_object", "shaped", "key", "size", "inline_align"), &TextServer::shaped_text_resize_object, DEFVAL(VALIGN_CENTER)); + + ClassDB::bind_method(D_METHOD("shaped_text_substr", "shaped", "start", "length"), &TextServer::shaped_text_substr); + ClassDB::bind_method(D_METHOD("shaped_text_get_parent", "shaped"), &TextServer::shaped_text_get_parent); + ClassDB::bind_method(D_METHOD("shaped_text_fit_to_width", "shaped", "width", "jst_flags"), &TextServer::shaped_text_fit_to_width, DEFVAL(JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA)); + ClassDB::bind_method(D_METHOD("shaped_text_tab_align", "shaped", "tab_stops"), &TextServer::shaped_text_tab_align); + + ClassDB::bind_method(D_METHOD("shaped_text_shape", "shaped"), &TextServer::shaped_text_shape); + ClassDB::bind_method(D_METHOD("shaped_text_is_ready", "shaped"), &TextServer::shaped_text_is_ready); + + ClassDB::bind_method(D_METHOD("shaped_text_get_glyphs", "shaped"), &TextServer::_shaped_text_get_glyphs); + + ClassDB::bind_method(D_METHOD("shaped_text_get_range", "shaped"), &TextServer::shaped_text_get_range); + ClassDB::bind_method(D_METHOD("shaped_text_get_line_breaks_adv", "shaped", "width", "start", "once", "break_flags"), &TextServer::_shaped_text_get_line_breaks_adv, DEFVAL(0), DEFVAL(true), DEFVAL(BREAK_MANDATORY | BREAK_WORD_BOUND)); + ClassDB::bind_method(D_METHOD("shaped_text_get_line_breaks", "shaped", "width", "start", "break_flags"), &TextServer::_shaped_text_get_line_breaks, DEFVAL(0), DEFVAL(BREAK_MANDATORY | BREAK_WORD_BOUND)); + ClassDB::bind_method(D_METHOD("shaped_text_get_word_breaks", "shaped"), &TextServer::_shaped_text_get_word_breaks); + ClassDB::bind_method(D_METHOD("shaped_text_get_objects", "shaped"), &TextServer::shaped_text_get_objects); + ClassDB::bind_method(D_METHOD("shaped_text_get_object_rect", "shaped", "key"), &TextServer::shaped_text_get_object_rect); + + ClassDB::bind_method(D_METHOD("shaped_text_get_size", "shaped"), &TextServer::shaped_text_get_size); + ClassDB::bind_method(D_METHOD("shaped_text_get_ascent", "shaped"), &TextServer::shaped_text_get_ascent); + ClassDB::bind_method(D_METHOD("shaped_text_get_descent", "shaped"), &TextServer::shaped_text_get_descent); + ClassDB::bind_method(D_METHOD("shaped_text_get_width", "shaped"), &TextServer::shaped_text_get_width); + ClassDB::bind_method(D_METHOD("shaped_text_get_underline_position", "shaped"), &TextServer::shaped_text_get_underline_position); + ClassDB::bind_method(D_METHOD("shaped_text_get_underline_thickness", "shaped"), &TextServer::shaped_text_get_underline_thickness); + + ClassDB::bind_method(D_METHOD("shaped_text_get_carets", "shaped", "position"), &TextServer::_shaped_text_get_carets); + ClassDB::bind_method(D_METHOD("shaped_text_get_selection", "shaped", "start", "end"), &TextServer::_shaped_text_get_selection); + + ClassDB::bind_method(D_METHOD("shaped_text_hit_test_grapheme", "shaped", "coords"), &TextServer::shaped_text_hit_test_grapheme); + ClassDB::bind_method(D_METHOD("shaped_text_hit_test_position", "shaped", "coords"), &TextServer::shaped_text_hit_test_position); + + ClassDB::bind_method(D_METHOD("shaped_text_next_grapheme_pos", "shaped", "pos"), &TextServer::shaped_text_next_grapheme_pos); + ClassDB::bind_method(D_METHOD("shaped_text_prev_grapheme_pos", "shaped", "pos"), &TextServer::shaped_text_prev_grapheme_pos); + + ClassDB::bind_method(D_METHOD("shaped_text_draw", "shaped", "canvas", "pos", "clip_l", "clip_r", "color"), &TextServer::shaped_text_draw, DEFVAL(-1), DEFVAL(-1), DEFVAL(Color(1, 1, 1))); + ClassDB::bind_method(D_METHOD("shaped_text_draw_outline", "shaped", "canvas", "pos", "clip_l", "clip_r", "outline_size", "color"), &TextServer::shaped_text_draw_outline, DEFVAL(-1), DEFVAL(-1), DEFVAL(1), DEFVAL(Color(1, 1, 1))); + + ClassDB::bind_method(D_METHOD("shaped_text_get_dominant_direciton_in_range", "shaped", "start", "end"), &TextServer::shaped_text_get_dominant_direciton_in_range); + + ClassDB::bind_method(D_METHOD("format_number", "number", "language"), &TextServer::format_number, DEFVAL("")); + ClassDB::bind_method(D_METHOD("parse_number", "number", "language"), &TextServer::parse_number, DEFVAL("")); + ClassDB::bind_method(D_METHOD("percent_sign", "language"), &TextServer::percent_sign, DEFVAL("")); + + /* Direction */ + BIND_ENUM_CONSTANT(DIRECTION_AUTO); + BIND_ENUM_CONSTANT(DIRECTION_LTR); + BIND_ENUM_CONSTANT(DIRECTION_RTL); + + /* Orientation */ + BIND_ENUM_CONSTANT(ORIENTATION_HORIZONTAL); + BIND_ENUM_CONSTANT(ORIENTATION_VERTICAL); + + /* JustificationFlag */ + BIND_ENUM_CONSTANT(JUSTIFICATION_NONE); + BIND_ENUM_CONSTANT(JUSTIFICATION_KASHIDA); + BIND_ENUM_CONSTANT(JUSTIFICATION_WORD_BOUND); + BIND_ENUM_CONSTANT(JUSTIFICATION_TRIM_EDGE_SPACES); + BIND_ENUM_CONSTANT(JUSTIFICATION_AFTER_LAST_TAB); + + /* LineBreakFlag */ + BIND_ENUM_CONSTANT(BREAK_NONE); + BIND_ENUM_CONSTANT(BREAK_MANDATORY); + BIND_ENUM_CONSTANT(BREAK_WORD_BOUND); + BIND_ENUM_CONSTANT(BREAK_GRAPHEME_BOUND); + + /* GraphemeFlag */ + BIND_ENUM_CONSTANT(GRAPHEME_IS_RTL); + BIND_ENUM_CONSTANT(GRAPHEME_IS_VIRTUAL); + BIND_ENUM_CONSTANT(GRAPHEME_IS_SPACE); + BIND_ENUM_CONSTANT(GRAPHEME_IS_BREAK_HARD); + BIND_ENUM_CONSTANT(GRAPHEME_IS_BREAK_SOFT); + BIND_ENUM_CONSTANT(GRAPHEME_IS_TAB); + BIND_ENUM_CONSTANT(GRAPHEME_IS_ELONGATION); + BIND_ENUM_CONSTANT(GRAPHEME_IS_PUNCTUATION); + + /* Hinting */ + BIND_ENUM_CONSTANT(HINTING_NONE); + BIND_ENUM_CONSTANT(HINTING_LIGHT); + BIND_ENUM_CONSTANT(HINTING_NORMAL); + + /* Feature */ + BIND_ENUM_CONSTANT(FEATURE_BIDI_LAYOUT); + BIND_ENUM_CONSTANT(FEATURE_VERTICAL_LAYOUT); + BIND_ENUM_CONSTANT(FEATURE_SHAPING); + BIND_ENUM_CONSTANT(FEATURE_KASHIDA_JUSTIFICATION); + BIND_ENUM_CONSTANT(FEATURE_BREAK_ITERATORS); + BIND_ENUM_CONSTANT(FEATURE_FONT_SYSTEM); + BIND_ENUM_CONSTANT(FEATURE_FONT_VARIABLE); + BIND_ENUM_CONSTANT(FEATURE_USE_SUPPORT_DATA); +} + +Vector3 TextServer::hex_code_box_font_size[2] = { Vector3(5, 5, 1), Vector3(10, 10, 2) }; +Ref<CanvasTexture> TextServer::hex_code_box_font_tex[2] = { nullptr, nullptr }; + +void TextServer::initialize_hex_code_box_fonts() { + static unsigned int tamsyn5x9_png_len = 175; + static unsigned char tamsyn5x9_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x05, + 0x04, 0x03, 0x00, 0x00, 0x00, 0x20, 0x7c, 0x76, 0xda, 0x00, 0x00, 0x00, + 0x0f, 0x50, 0x4c, 0x54, 0x45, 0xfd, 0x07, 0x00, 0x00, 0x00, 0x00, 0x06, + 0x7e, 0x74, 0x00, 0x40, 0xc6, 0xff, 0xff, 0xff, 0x47, 0x9a, 0xd4, 0xc7, + 0x00, 0x00, 0x00, 0x01, 0x74, 0x52, 0x4e, 0x53, 0x00, 0x40, 0xe6, 0xd8, + 0x66, 0x00, 0x00, 0x00, 0x4e, 0x49, 0x44, 0x41, 0x54, 0x08, 0x1d, 0x05, + 0xc1, 0x21, 0x01, 0x00, 0x00, 0x00, 0x83, 0x30, 0x04, 0xc1, 0x10, 0xef, + 0x9f, 0xe9, 0x1b, 0x86, 0x2c, 0x17, 0xb9, 0xcc, 0x65, 0x0c, 0x73, 0x38, + 0xc7, 0xe6, 0x22, 0x19, 0x88, 0x98, 0x10, 0x48, 0x4a, 0x29, 0x85, 0x14, + 0x02, 0x89, 0x10, 0xa3, 0x1c, 0x0b, 0x31, 0xd6, 0xe6, 0x08, 0x69, 0x39, + 0x48, 0x44, 0xa0, 0x0d, 0x4a, 0x22, 0xa1, 0x94, 0x42, 0x0a, 0x01, 0x63, + 0x6d, 0x0e, 0x72, 0x18, 0x61, 0x8c, 0x74, 0x38, 0xc7, 0x26, 0x1c, 0xf3, + 0x71, 0x16, 0x15, 0x27, 0x6a, 0xc2, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x49, + 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + }; + + static unsigned int tamsyn10x20_png_len = 270; + static unsigned char tamsyn10x20_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x0a, + 0x04, 0x03, 0x00, 0x00, 0x00, 0xc1, 0x66, 0x48, 0x96, 0x00, 0x00, 0x00, + 0x0f, 0x50, 0x4c, 0x54, 0x45, 0x00, 0x00, 0x00, 0xf9, 0x07, 0x00, 0x5d, + 0x71, 0xa5, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x49, 0xdb, 0xcb, 0x7f, + 0x00, 0x00, 0x00, 0x01, 0x74, 0x52, 0x4e, 0x53, 0x00, 0x40, 0xe6, 0xd8, + 0x66, 0x00, 0x00, 0x00, 0xad, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0xa5, + 0x92, 0x4b, 0x0e, 0x03, 0x31, 0x08, 0x43, 0xdf, 0x82, 0x83, 0x79, 0xe1, + 0xfb, 0x9f, 0xa9, 0x0b, 0x3e, 0x61, 0xa6, 0x1f, 0x55, 0xad, 0x14, 0x31, + 0x66, 0x42, 0x1c, 0x70, 0x0c, 0xb6, 0x00, 0x01, 0xb6, 0x08, 0xdb, 0x00, + 0x8d, 0xc2, 0x14, 0xb2, 0x55, 0xa1, 0xfe, 0x09, 0xc2, 0x26, 0xdc, 0x25, + 0x75, 0x22, 0x97, 0x1a, 0x25, 0x77, 0x28, 0x31, 0x02, 0x80, 0xc8, 0xdd, + 0x2c, 0x11, 0x1a, 0x54, 0x9f, 0xc8, 0xa2, 0x8a, 0x06, 0xa9, 0x93, 0x22, + 0xbd, 0xd4, 0xd0, 0x0c, 0xcf, 0x81, 0x2b, 0xca, 0xbb, 0x83, 0xe0, 0x10, + 0xe6, 0xad, 0xff, 0x10, 0x2a, 0x66, 0x34, 0x41, 0x58, 0x35, 0x54, 0x49, + 0x5a, 0x63, 0xa5, 0xc2, 0x87, 0xab, 0x52, 0x76, 0x9a, 0xba, 0xc6, 0xf4, + 0x75, 0x7a, 0x9e, 0x3c, 0x46, 0x86, 0x5c, 0xa3, 0xfd, 0x87, 0x0e, 0x75, + 0x08, 0x7b, 0xee, 0x7e, 0xea, 0x21, 0x5c, 0x4f, 0xf6, 0xc5, 0xc8, 0x4b, + 0xb9, 0x11, 0xf2, 0xd6, 0xe1, 0x8f, 0x84, 0x62, 0x7b, 0x67, 0xf9, 0x24, + 0xde, 0x6d, 0xbc, 0xb2, 0xcd, 0xb1, 0xf3, 0xf2, 0x2f, 0xe8, 0xe2, 0xe4, + 0xae, 0x4b, 0x4f, 0xcf, 0x2b, 0xdc, 0x8d, 0x0d, 0xf0, 0x00, 0x8f, 0x22, + 0x26, 0x65, 0x75, 0x8a, 0xe6, 0x84, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, + 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + }; + + if (RenderingServer::get_singleton() != nullptr) { + Vector<uint8_t> hex_box_data; + + Ref<Image> image; + image.instance(); + + Ref<ImageTexture> hex_code_image_tex[2]; + + hex_box_data.resize(tamsyn5x9_png_len); + memcpy(hex_box_data.ptrw(), tamsyn5x9_png, tamsyn5x9_png_len); + image->load_png_from_buffer(hex_box_data); + hex_code_image_tex[0].instance(); + hex_code_image_tex[0]->create_from_image(image); + hex_code_box_font_tex[0].instance(); + hex_code_box_font_tex[0]->set_diffuse_texture(hex_code_image_tex[0]); + hex_code_box_font_tex[0]->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST); + hex_box_data.clear(); + + hex_box_data.resize(tamsyn10x20_png_len); + memcpy(hex_box_data.ptrw(), tamsyn10x20_png, tamsyn10x20_png_len); + image->load_png_from_buffer(hex_box_data); + hex_code_image_tex[1].instance(); + hex_code_image_tex[1]->create_from_image(image); + hex_code_box_font_tex[1].instance(); + hex_code_box_font_tex[1]->set_diffuse_texture(hex_code_image_tex[1]); + hex_code_box_font_tex[1]->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST); + hex_box_data.clear(); + } +} + +void TextServer::finish_hex_code_box_fonts() { + if (hex_code_box_font_tex[0].is_valid()) { + hex_code_box_font_tex[0].unref(); + } + if (hex_code_box_font_tex[1].is_valid()) { + hex_code_box_font_tex[1].unref(); + } +} + +Vector2 TextServer::get_hex_code_box_size(int p_size, char32_t p_index) const { + int fnt = (p_size < 20) ? 0 : 1; + + float w = ((p_index <= 0xFF) ? 1 : ((p_index <= 0xFFFF) ? 2 : 3)) * hex_code_box_font_size[fnt].x; + float h = 2 * hex_code_box_font_size[fnt].y; + return Vector2(w + 4, h + 3 + 2 * hex_code_box_font_size[fnt].z); +} + +void TextServer::draw_hex_code_box(RID p_canvas, int p_size, const Vector2 &p_pos, char32_t p_index, const Color &p_color) const { + int fnt = (p_size < 20) ? 0 : 1; + + ERR_FAIL_COND(hex_code_box_font_tex[fnt].is_null()); + + uint8_t a = p_index & 0x0F; + uint8_t b = (p_index >> 4) & 0x0F; + uint8_t c = (p_index >> 8) & 0x0F; + uint8_t d = (p_index >> 12) & 0x0F; + uint8_t e = (p_index >> 16) & 0x0F; + uint8_t f = (p_index >> 20) & 0x0F; + + Vector2 pos = p_pos; + Rect2 dest = Rect2(Vector2(), Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y)); + + float w = ((p_index <= 0xFF) ? 1 : ((p_index <= 0xFFFF) ? 2 : 3)) * hex_code_box_font_size[fnt].x; + float h = 2 * hex_code_box_font_size[fnt].y; + + pos.y -= Math::floor((h + 3 + hex_code_box_font_size[fnt].z) * 0.75); + + RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(0, 0), Size2(1, h + 2 + 2 * hex_code_box_font_size[fnt].z)), p_color); + RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(w + 2, 0), Size2(1, h + 2 + 2 * hex_code_box_font_size[fnt].z)), p_color); + RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(0, 0), Size2(w + 2, 1)), p_color); + RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(0, h + 2 + 2 * hex_code_box_font_size[fnt].z), Size2(w + 2, 1)), p_color); + + pos += Point2(2, 2); + if (p_index <= 0xFF) { + dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(0, 0); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(b * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); + dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(0, 1) + Point2(0, hex_code_box_font_size[fnt].z); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(a * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); + } else if (p_index <= 0xFFFF) { + dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(0, 0); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(d * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); + dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(1, 0); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(c * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); + dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(0, 1) + Point2(0, hex_code_box_font_size[fnt].z); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(b * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); + dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(1, 1) + Point2(0, hex_code_box_font_size[fnt].z); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(a * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); + } else { + dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(0, 0); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(f * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); + dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(1, 0); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(e * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); + dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(2, 0); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(d * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); + dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(0, 1) + Point2(0, hex_code_box_font_size[fnt].z); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(c * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); + dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(1, 1) + Point2(0, hex_code_box_font_size[fnt].z); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(b * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); + dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(2, 1) + Point2(0, hex_code_box_font_size[fnt].z); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(a * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); + } +} + +Vector<Vector2i> TextServer::shaped_text_get_line_breaks_adv(RID p_shaped, const Vector<float> &p_width, int p_start, bool p_once, uint8_t /*TextBreakFlag*/ p_break_flags) const { + Vector<Vector2i> lines; + + ERR_FAIL_COND_V(p_width.is_empty(), lines); + + const_cast<TextServer *>(this)->shaped_text_update_breaks(p_shaped); + const Vector<Glyph> &logical = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped); + const Vector2i &range = shaped_text_get_range(p_shaped); + + float width = 0.f; + int line_start = MAX(p_start, range.x); + int last_safe_break = -1; + int chunk = 0; + + int l_size = logical.size(); + const Glyph *l_gl = logical.ptr(); + + for (int i = 0; i < l_size; i++) { + if (l_gl[i].start < p_start) { + continue; + } + if (l_gl[i].count > 0) { + if ((p_width[chunk] > 0) && (width + l_gl[i].advance > p_width[chunk]) && (last_safe_break >= 0)) { + lines.push_back(Vector2i(line_start, l_gl[last_safe_break].end)); + line_start = l_gl[last_safe_break].end; + i = last_safe_break; + last_safe_break = -1; + width = 0; + chunk++; + if (chunk >= p_width.size()) { + chunk = 0; + if (p_once) { + return lines; + } + } + continue; + } + if ((p_break_flags & BREAK_MANDATORY) == BREAK_MANDATORY) { + if ((l_gl[i].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD) { + lines.push_back(Vector2i(line_start, l_gl[i].end)); + line_start = l_gl[i].end; + last_safe_break = -1; + width = 0; + chunk = 0; + if (p_once) { + return lines; + } + continue; + } + } + if ((p_break_flags & BREAK_WORD_BOUND) == BREAK_WORD_BOUND) { + if ((l_gl[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) { + last_safe_break = i; + } + } + if ((p_break_flags & BREAK_GRAPHEME_BOUND) == BREAK_GRAPHEME_BOUND) { + last_safe_break = i; + } + } + width += l_gl[i].advance; + } + + if (l_size > 0) { + lines.push_back(Vector2i(line_start, range.y)); + } else { + lines.push_back(Vector2i(0, 0)); + } + + return lines; +} + +Vector<Vector2i> TextServer::shaped_text_get_line_breaks(RID p_shaped, float p_width, int p_start, uint8_t /*TextBreakFlag*/ p_break_flags) const { + Vector<Vector2i> lines; + + const_cast<TextServer *>(this)->shaped_text_update_breaks(p_shaped); + const Vector<Glyph> &logical = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped); + const Vector2i &range = shaped_text_get_range(p_shaped); + + float width = 0.f; + int line_start = MAX(p_start, range.x); + int last_safe_break = -1; + + int l_size = logical.size(); + const Glyph *l_gl = logical.ptr(); + + for (int i = 0; i < l_size; i++) { + if (l_gl[i].start < p_start) { + continue; + } + if (l_gl[i].count > 0) { + if ((p_width > 0) && (width + l_gl[i].advance > p_width) && (last_safe_break >= 0)) { + lines.push_back(Vector2i(line_start, l_gl[last_safe_break].end)); + line_start = l_gl[last_safe_break].end; + i = last_safe_break; + last_safe_break = -1; + width = 0; + continue; + } + if ((p_break_flags & BREAK_MANDATORY) == BREAK_MANDATORY) { + if ((l_gl[i].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD) { + lines.push_back(Vector2i(line_start, l_gl[i].end)); + line_start = l_gl[i].end; + last_safe_break = -1; + width = 0; + continue; + } + } + if ((p_break_flags & BREAK_WORD_BOUND) == BREAK_WORD_BOUND) { + if ((l_gl[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) { + last_safe_break = i; + } + } + if ((p_break_flags & BREAK_GRAPHEME_BOUND) == BREAK_GRAPHEME_BOUND) { + last_safe_break = i; + } + } + width += l_gl[i].advance; + } + + if (l_size > 0) { + if (lines.size() == 0 || lines[lines.size() - 1].y < range.y) { + lines.push_back(Vector2i(line_start, range.y)); + } + } else { + lines.push_back(Vector2i(0, 0)); + } + + return lines; +} + +Vector<Vector2i> TextServer::shaped_text_get_word_breaks(RID p_shaped) const { + Vector<Vector2i> words; + + const_cast<TextServer *>(this)->shaped_text_update_justification_ops(p_shaped); + const Vector<Glyph> &logical = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped); + const Vector2i &range = shaped_text_get_range(p_shaped); + + int word_start = range.x; + + int l_size = logical.size(); + const Glyph *l_gl = logical.ptr(); + + for (int i = 0; i < l_size; i++) { + if (l_gl[i].count > 0) { + if (((l_gl[i].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) || ((l_gl[i].flags & GRAPHEME_IS_PUNCTUATION) == GRAPHEME_IS_PUNCTUATION)) { + words.push_back(Vector2i(word_start, l_gl[i].start)); + word_start = l_gl[i].end; + } + } + } + if (l_size > 0) { + words.push_back(Vector2i(word_start, range.y)); + } + + return words; +} + +void TextServer::shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_leading_caret, Direction &p_leading_dir, Rect2 &p_trailing_caret, Direction &p_trailing_dir) const { + Vector<Rect2> carets; + const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); + TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped); + const Vector2 &range = shaped_text_get_range(p_shaped); + float ascent = shaped_text_get_ascent(p_shaped); + float descent = shaped_text_get_descent(p_shaped); + float height = (ascent + descent) / 2; + + float off = 0.0f; + p_leading_dir = DIRECTION_AUTO; + p_trailing_dir = DIRECTION_AUTO; + + int v_size = visual.size(); + const Glyph *glyphs = visual.ptr(); + + for (int i = 0; i < v_size; i++) { + if (glyphs[i].count > 0) { + // Caret before grapheme (top / left). + if (p_position == glyphs[i].start && ((glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL)) { + Rect2 cr; + if (orientation == ORIENTATION_HORIZONTAL) { + if (glyphs[i].start == range.x) { + cr.size.y = height * 2; + } else { + cr.size.y = height; + } + cr.position.y = -ascent; + cr.position.x = off; + if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { + p_trailing_dir = DIRECTION_RTL; + for (int j = 0; j < glyphs[i].count; j++) { + cr.position.x += glyphs[i + j].advance * glyphs[i + j].repeat; + cr.size.x -= glyphs[i + j].advance * glyphs[i + j].repeat; + } + } else { + p_trailing_dir = DIRECTION_LTR; + for (int j = 0; j < glyphs[i].count; j++) { + cr.size.x += glyphs[i + j].advance * glyphs[i + j].repeat; + } + } + } else { + if (glyphs[i].start == range.x) { + cr.size.x = height * 2; + } else { + cr.size.x = height; + } + cr.position.x = -ascent; + cr.position.y = off; + if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { + p_trailing_dir = DIRECTION_RTL; + for (int j = 0; j < glyphs[i].count; j++) { + cr.position.y += glyphs[i + j].advance * glyphs[i + j].repeat; + cr.size.y -= glyphs[i + j].advance * glyphs[i + j].repeat; + } + } else { + p_trailing_dir = DIRECTION_LTR; + for (int j = 0; j < glyphs[i].count; j++) { + cr.size.y += glyphs[i + j].advance * glyphs[i + j].repeat; + } + } + } + p_trailing_caret = cr; + } + // Caret after grapheme (bottom / right). + if (p_position == glyphs[i].end && ((glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL)) { + Rect2 cr; + if (orientation == ORIENTATION_HORIZONTAL) { + if (glyphs[i].end == range.y) { + cr.size.y = height * 2; + cr.position.y = -ascent; + } else { + cr.size.y = height; + cr.position.y = -ascent + height; + } + cr.position.x = off; + if ((glyphs[i].flags & GRAPHEME_IS_RTL) != GRAPHEME_IS_RTL) { + p_leading_dir = DIRECTION_LTR; + for (int j = 0; j < glyphs[i].count; j++) { + cr.position.x += glyphs[i + j].advance * glyphs[i + j].repeat; + cr.size.x -= glyphs[i + j].advance * glyphs[i + j].repeat; + } + } else { + p_leading_dir = DIRECTION_RTL; + for (int j = 0; j < glyphs[i].count; j++) { + cr.size.x += glyphs[i + j].advance * glyphs[i + j].repeat; + } + } + } else { + cr.size.y = 1.0f; + if (glyphs[i].end == range.y) { + cr.size.x = height * 2; + cr.position.x = -ascent; + } else { + cr.size.x = height; + cr.position.x = -ascent + height; + } + cr.position.y = off; + if ((glyphs[i].flags & GRAPHEME_IS_RTL) != GRAPHEME_IS_RTL) { + p_leading_dir = DIRECTION_LTR; + for (int j = 0; j < glyphs[i].count; j++) { + cr.position.y += glyphs[i + j].advance * glyphs[i + j].repeat; + cr.size.y -= glyphs[i + j].advance * glyphs[i + j].repeat; + } + } else { + p_leading_dir = DIRECTION_RTL; + for (int j = 0; j < glyphs[i].count; j++) { + cr.size.y += glyphs[i + j].advance * glyphs[i + j].repeat; + } + } + } + p_leading_caret = cr; + } + // Caret inside grapheme (middle). + if (p_position > glyphs[i].start && p_position < glyphs[i].end && (glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL) { + float advance = 0.f; + for (int j = 0; j < glyphs[i].count; j++) { + advance += glyphs[i + j].advance * glyphs[i + j].repeat; + } + float char_adv = advance / (float)(glyphs[i].end - glyphs[i].start); + Rect2 cr; + if (orientation == ORIENTATION_HORIZONTAL) { + cr.size.x = 1.0f; + cr.size.y = height * 2; + cr.position.y = -ascent; + if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { + cr.position.x = off + char_adv * (glyphs[i].end - p_position); + } else { + cr.position.x = off + char_adv * (p_position - glyphs[i].start); + } + } else { + cr.size.y = 1.0f; + cr.size.x = height * 2; + cr.position.x = -ascent; + if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { + cr.position.y = off + char_adv * (glyphs[i].end - p_position); + } else { + cr.position.y = off + char_adv * (p_position - glyphs[i].start); + } + } + p_trailing_caret = cr; + p_leading_caret = cr; + } + } + off += glyphs[i].advance * glyphs[i].repeat; + } +} + +TextServer::Direction TextServer::shaped_text_get_dominant_direciton_in_range(RID p_shaped, int p_start, int p_end) const { + const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); + + if (p_start == p_end) { + return DIRECTION_AUTO; + } + + int start = MIN(p_start, p_end); + int end = MAX(p_start, p_end); + + int rtl = 0; + int ltr = 0; + + int v_size = visual.size(); + const Glyph *glyphs = visual.ptr(); + + for (int i = 0; i < v_size; i++) { + if ((glyphs[i].end > start) && (glyphs[i].start < end)) { + if (glyphs[i].count > 0) { + if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { + rtl++; + } else { + ltr++; + } + } + } + } + if (ltr == rtl) { + return DIRECTION_AUTO; + } else if (ltr > rtl) { + return DIRECTION_LTR; + } else { + return DIRECTION_RTL; + } +} + +Vector<Vector2> TextServer::shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const { + Vector<Vector2> ranges; + const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); + + if (p_start == p_end) { + return ranges; + } + + int start = MIN(p_start, p_end); + int end = MAX(p_start, p_end); + + int v_size = visual.size(); + const Glyph *glyphs = visual.ptr(); + + float off = 0.0f; + for (int i = 0; i < v_size; i++) { + for (int k = 0; k < glyphs[i].repeat; k++) { + if ((glyphs[i].count > 0) && ((glyphs[i].index != 0) || ((glyphs[i].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE))) { + if (glyphs[i].start < end && glyphs[i].end > start) { + // Grapheme fully in selection range. + if (glyphs[i].start >= start && glyphs[i].end <= end) { + float advance = 0.f; + for (int j = 0; j < glyphs[i].count; j++) { + advance += glyphs[i + j].advance; + } + ranges.push_back(Vector2(off, off + advance)); + } + // Only start of grapheme is in selection range. + if (glyphs[i].start >= start && glyphs[i].end > end) { + float advance = 0.f; + for (int j = 0; j < glyphs[i].count; j++) { + advance += glyphs[i + j].advance; + } + float char_adv = advance / (float)(glyphs[i].end - glyphs[i].start); + if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { + ranges.push_back(Vector2(off + char_adv * (glyphs[i].end - end), off + advance)); + } else { + ranges.push_back(Vector2(off, off + char_adv * (end - glyphs[i].start))); + } + } + // Only end of grapheme is in selection range. + if (glyphs[i].start < start && glyphs[i].end <= end) { + float advance = 0.f; + for (int j = 0; j < glyphs[i].count; j++) { + advance += glyphs[i + j].advance; + } + float char_adv = advance / (float)(glyphs[i].end - glyphs[i].start); + if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { + ranges.push_back(Vector2(off, off + char_adv * (start - glyphs[i].start))); + } else { + ranges.push_back(Vector2(off + char_adv * (glyphs[i].end - start), off + advance)); + } + } + // Selection range is within grapheme + if (glyphs[i].start < start && glyphs[i].end > end) { + float advance = 0.f; + for (int j = 0; j < glyphs[i].count; j++) { + advance += glyphs[i + j].advance; + } + float char_adv = advance / (float)(glyphs[i].end - glyphs[i].start); + if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { + ranges.push_back(Vector2(off + char_adv * (glyphs[i].end - end), off + char_adv * (glyphs[i].end - start))); + } else { + ranges.push_back(Vector2(off + char_adv * (start - glyphs[i].start), off + char_adv * (end - glyphs[i].start))); + } + } + } + } + off += glyphs[i].advance; + } + } + + // Merge intersecting ranges. + int i = 0; + while (i < ranges.size()) { + i++; + } + i = 0; + while (i < ranges.size()) { + int j = i + 1; + while (j < ranges.size()) { + if (Math::is_equal_approx(ranges[i].y, ranges[j].x, UNIT_EPSILON)) { + ranges.write[i].y = ranges[j].y; + ranges.remove(j); + continue; + } + j++; + } + i++; + } + + return ranges; +} + +int TextServer::shaped_text_hit_test_grapheme(RID p_shaped, float p_coords) const { + const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); + + // Exact grapheme hit test, return -1 if missed. + float off = 0.0f; + + int v_size = visual.size(); + const Glyph *glyphs = visual.ptr(); + + for (int i = 0; i < v_size; i++) { + for (int j = 0; j < glyphs[i].repeat; j++) { + if (p_coords >= off && p_coords < off + glyphs[i].advance) { + return i; + } + off += glyphs[i].advance; + } + } + return -1; +} + +int TextServer::shaped_text_hit_test_position(RID p_shaped, float p_coords) const { + const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); + + int v_size = visual.size(); + const Glyph *glyphs = visual.ptr(); + + // Cursor placement hit test. + + // Place caret to the left of the leftmost grapheme, or to position 0 if string is empty. + if (p_coords <= 0) { + if (v_size > 0) { + if ((glyphs[0].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { + return glyphs[0].end; + } else { + return glyphs[0].start; + } + } else { + return 0; + } + } + + // Place caret to the right of the rightmost grapheme, or to position 0 if string is empty. + if (p_coords >= shaped_text_get_width(p_shaped)) { + if (v_size > 0) { + if ((glyphs[v_size - 1].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { + return glyphs[v_size - 1].start; + } else { + return glyphs[v_size - 1].end; + } + } else { + return 0; + } + } + + float off = 0.0f; + for (int i = 0; i < v_size; i++) { + if (glyphs[i].count > 0) { + float advance = 0.f; + for (int j = 0; j < glyphs[i].count; j++) { + advance += glyphs[i + j].advance * glyphs[i + j].repeat; + } + if (((glyphs[i].flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) && (p_coords >= off && p_coords < off + advance)) { + if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { + return glyphs[i].end; + } else { + return glyphs[i].start; + } + } + // Place caret to the left of clicked grapheme. + if (p_coords >= off && p_coords < off + advance / 2) { + if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { + return glyphs[i].end; + } else { + return glyphs[i].start; + } + } + // Place caret to the right of clicked grapheme. + if (p_coords >= off + advance / 2 && p_coords < off + advance) { + if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { + return glyphs[i].start; + } else { + return glyphs[i].end; + } + } + } + off += glyphs[i].advance * glyphs[i].repeat; + } + return 0; +} + +int TextServer::shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) { + const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); + int v_size = visual.size(); + const Glyph *glyphs = visual.ptr(); + for (int i = 0; i < v_size; i++) { + if (p_pos >= glyphs[i].start && p_pos < glyphs[i].end) { + return glyphs[i].end; + } + } + return p_pos; +} + +int TextServer::shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos) { + const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); + int v_size = visual.size(); + const Glyph *glyphs = visual.ptr(); + for (int i = 0; i < v_size; i++) { + if (p_pos > glyphs[i].start && p_pos <= glyphs[i].end) { + return glyphs[i].start; + } + } + + return p_pos; +} + +void TextServer::shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l, float p_clip_r, const Color &p_color) const { + const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); + TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped); + bool hex_codes = shaped_text_get_preserve_control(p_shaped) || shaped_text_get_preserve_invalid(p_shaped); + + int v_size = visual.size(); + const Glyph *glyphs = visual.ptr(); + + Vector2 ofs = p_pos; + // Draw at the baseline. + for (int i = 0; i < v_size; i++) { + for (int j = 0; j < glyphs[i].repeat; j++) { + if (p_clip_r > 0) { + // Clip right / bottom. + if (orientation == ORIENTATION_HORIZONTAL) { + if (ofs.x - p_pos.x > p_clip_r) { + return; + } + } else { + if (ofs.y - p_pos.y > p_clip_r) { + return; + } + } + } + if (p_clip_l > 0) { + // Clip left / top. + if (orientation == ORIENTATION_HORIZONTAL) { + if (ofs.x - p_pos.x < p_clip_l) { + ofs.x += glyphs[i].advance; + continue; + } + } else { + if (ofs.y - p_pos.y < p_clip_l) { + ofs.y += glyphs[i].advance; + continue; + } + } + } + if (glyphs[i].font_rid != RID()) { + font_draw_glyph(glyphs[i].font_rid, p_canvas, glyphs[i].font_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, p_color); + } else if (hex_codes && ((glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL)) { + TextServer::draw_hex_code_box(p_canvas, glyphs[i].font_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, p_color); + } + if (orientation == ORIENTATION_HORIZONTAL) { + ofs.x += glyphs[i].advance; + } else { + ofs.y += glyphs[i].advance; + } + } + } +} + +void TextServer::shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l, float p_clip_r, int p_outline_size, const Color &p_color) const { + const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); + TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped); + + int v_size = visual.size(); + const Glyph *glyphs = visual.ptr(); + Vector2 ofs = p_pos; + // Draw at the baseline. + for (int i = 0; i < v_size; i++) { + for (int j = 0; j < glyphs[i].repeat; j++) { + if (p_clip_r > 0) { + // Clip right / bottom. + if (orientation == ORIENTATION_HORIZONTAL) { + if (ofs.x - p_pos.x > p_clip_r) { + return; + } + } else { + if (ofs.y - p_pos.y > p_clip_r) { + return; + } + } + } + if (p_clip_l > 0) { + // Clip left / top. + if (orientation == ORIENTATION_HORIZONTAL) { + if (ofs.x - p_pos.x < p_clip_l) { + ofs.x += glyphs[i].advance; + continue; + } + } else { + if (ofs.y - p_pos.y < p_clip_l) { + ofs.y += glyphs[i].advance; + continue; + } + } + } + if (glyphs[i].font_rid != RID()) { + font_draw_glyph_outline(glyphs[i].font_rid, p_canvas, glyphs[i].font_size, p_outline_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, p_color); + } + if (orientation == ORIENTATION_HORIZONTAL) { + ofs.x += glyphs[i].advance; + } else { + ofs.y += glyphs[i].advance; + } + } + } +} + +RID TextServer::_create_font_memory(const PackedByteArray &p_data, const String &p_type, int p_base_size) { + return create_font_memory(p_data.ptr(), p_data.size(), p_type, p_base_size); +} + +void TextServer::_shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) { + Vector<Vector2i> overrides; + for (int i = 0; i < p_override.size(); i++) { + overrides.push_back(p_override[i]); + } + shaped_text_set_bidi_override(p_shaped, overrides); +} + +Array TextServer::_shaped_text_get_glyphs(RID p_shaped) const { + Array ret; + + Vector<Glyph> glyphs = shaped_text_get_glyphs(p_shaped); + for (int i = 0; i < glyphs.size(); i++) { + Dictionary glyph; + + glyph["start"] = glyphs[i].start; + glyph["end"] = glyphs[i].end; + glyph["repeat"] = glyphs[i].repeat; + glyph["count"] = glyphs[i].count; + glyph["flags"] = glyphs[i].flags; + glyph["offset"] = Vector2(glyphs[i].x_off, glyphs[i].y_off); + glyph["advance"] = glyphs[i].advance; + glyph["font_rid"] = glyphs[i].font_rid; + glyph["font_size"] = glyphs[i].font_size; + glyph["index"] = glyphs[i].index; + + ret.push_back(glyph); + } + + return ret; +} + +Array TextServer::_shaped_text_get_line_breaks_adv(RID p_shaped, const PackedFloat32Array &p_width, int p_start, bool p_once, uint8_t p_break_flags) const { + Array ret; + + Vector<Vector2i> lines = shaped_text_get_line_breaks_adv(p_shaped, p_width, p_start, p_once, p_break_flags); + for (int i = 0; i < lines.size(); i++) { + ret.push_back(lines[i]); + } + + return ret; +} + +Array TextServer::_shaped_text_get_line_breaks(RID p_shaped, float p_width, int p_start, uint8_t p_break_flags) const { + Array ret; + + Vector<Vector2i> lines = shaped_text_get_line_breaks(p_shaped, p_width, p_start, p_break_flags); + for (int i = 0; i < lines.size(); i++) { + ret.push_back(lines[i]); + } + + return ret; +} + +Array TextServer::_shaped_text_get_word_breaks(RID p_shaped) const { + Array ret; + + Vector<Vector2i> words = shaped_text_get_word_breaks(p_shaped); + for (int i = 0; i < words.size(); i++) { + ret.push_back(words[i]); + } + + return ret; +} + +Dictionary TextServer::_shaped_text_get_carets(RID p_shaped, int p_position) const { + Dictionary ret; + + Rect2 l_caret, t_caret; + Direction l_dir, t_dir; + shaped_text_get_carets(p_shaped, p_position, l_caret, l_dir, t_caret, t_dir); + + ret["leading_rect"] = l_caret; + ret["leading_direction"] = l_dir; + ret["trailing_rect"] = t_caret; + ret["trailing_direction"] = t_dir; + + return ret; +} + +Array TextServer::_shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const { + Array ret; + + Vector<Vector2> ranges = shaped_text_get_selection(p_shaped, p_start, p_end); + for (int i = 0; i < ranges.size(); i++) { + ret.push_back(ranges[i]); + } + + return ret; +} + +TextServer::TextServer() { +} + +TextServer::~TextServer() { +} diff --git a/servers/text_server.h b/servers/text_server.h index e69de29bb2..3268741a74 100644 --- a/servers/text_server.h +++ b/servers/text_server.h @@ -0,0 +1,465 @@ +/*************************************************************************/ +/* text_server.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TEXT_SERVER_H +#define TEXT_SERVER_H + +#include "core/object/reference.h" +#include "core/os/os.h" +#include "core/templates/rid.h" +#include "core/variant/variant.h" +#include "scene/resources/texture.h" + +class CanvasTexture; + +class TextServer : public Object { + GDCLASS(TextServer, Object); + +public: + enum Direction { + DIRECTION_AUTO, + DIRECTION_LTR, + DIRECTION_RTL + }; + + enum Orientation { + ORIENTATION_HORIZONTAL, + ORIENTATION_VERTICAL + }; + + enum JustificationFlag { + JUSTIFICATION_NONE = 0, + JUSTIFICATION_KASHIDA = 1 << 0, + JUSTIFICATION_WORD_BOUND = 1 << 1, + JUSTIFICATION_TRIM_EDGE_SPACES = 1 << 2, + JUSTIFICATION_AFTER_LAST_TAB = 1 << 3 + }; + + enum LineBreakFlag { + BREAK_NONE = 0, + BREAK_MANDATORY = 1 << 4, + BREAK_WORD_BOUND = 1 << 5, + BREAK_GRAPHEME_BOUND = 1 << 6 + //RESERVED = 1 << 7 + }; + + enum GraphemeFlag { + GRAPHEME_IS_VALID = 1 << 0, // Glyph is valid. + GRAPHEME_IS_RTL = 1 << 1, // Glyph is right-to-left. + GRAPHEME_IS_VIRTUAL = 1 << 2, // Glyph is not part of source string (added by fit_to_width function, do not affect caret movement). + GRAPHEME_IS_SPACE = 1 << 3, // Is whitespace (for justification and word breaks). + GRAPHEME_IS_BREAK_HARD = 1 << 4, // Is line break (mandatory break, e.g. "\n"). + GRAPHEME_IS_BREAK_SOFT = 1 << 5, // Is line break (optional break, e.g. space). + GRAPHEME_IS_TAB = 1 << 6, // Is tab or vertical tab. + GRAPHEME_IS_ELONGATION = 1 << 7, // Elongation (e.g. kashida), glyph can be duplicated or truncated to fit line to width. + GRAPHEME_IS_PUNCTUATION = 1 << 8 // Punctuation (can be used as word break, but not line break or justifiction). + }; + + enum Hinting { + HINTING_NONE, + HINTING_LIGHT, + HINTING_NORMAL + }; + + enum Feature { + FEATURE_BIDI_LAYOUT = 1 << 0, + FEATURE_VERTICAL_LAYOUT = 1 << 1, + FEATURE_SHAPING = 1 << 2, + FEATURE_KASHIDA_JUSTIFICATION = 1 << 3, + FEATURE_BREAK_ITERATORS = 1 << 4, + FEATURE_FONT_SYSTEM = 1 << 5, + FEATURE_FONT_VARIABLE = 1 << 6, + FEATURE_USE_SUPPORT_DATA = 1 << 7 + }; + + struct Glyph { + int start = -1; // Start offset in the source string. + int end = -1; // End offset in the source string. + + uint8_t count = 0; // Number of glyphs in the grapheme, set in the first glyph only. + uint8_t repeat = 1; // Draw multiple times in the row. + uint16_t flags = 0; // Grapheme flags (valid, rtl, virtual), set in the first glyph only. + + float x_off = 0.f; // Offset from the origin of the glyph on baseline. + float y_off = 0.f; + float advance = 0.f; // Advance to the next glyph along baseline(x for horizontal layout, y for vertical). + + RID font_rid; // Font resource. + int font_size = 0; // Font size; + uint32_t index = 0; // Glyph index (font specific) or UTF-32 codepoint (for the invalid glyphs). + + bool operator==(const Glyph &p_a) const; + bool operator!=(const Glyph &p_a) const; + + bool operator<(const Glyph &p_a) const; + bool operator>(const Glyph &p_a) const; + }; + + struct GlyphCompare { // For line breaking reordering. + _FORCE_INLINE_ bool operator()(const Glyph &l, const Glyph &r) const { + if (l.start == r.start) { + if (l.count == r.count) { + if ((l.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) { + return false; + } else { + return true; + } + } + return l.count > r.count; // Sort first glyoh with count & flags, order of the rest are irrelevant. + } else { + return l.start < r.start; + } + } + }; + + struct ShapedTextData { + /* Source data */ + RID parent; // Substring parent ShapedTextData. + + int start = 0; // Substring start offset in the parent string. + int end = 0; // Substring end offset in the parent string. + + String text; + TextServer::Direction direction = DIRECTION_LTR; // Desired text direction. + TextServer::Orientation orientation = ORIENTATION_HORIZONTAL; + + struct Span { + int start = -1; + int end = -1; + + Vector<RID> fonts; + int font_size = 0; + + Variant embedded_key; + + String language; + Dictionary features; + }; + Vector<Span> spans; + + struct EmbeddedObject { + int pos = 0; + VAlign inline_align = VALIGN_TOP; + Rect2 rect; + }; + Map<Variant, EmbeddedObject> objects; + + /* Shaped data */ + TextServer::Direction para_direction = DIRECTION_LTR; // Detected text direction. + bool valid = false; // String is shaped. + bool line_breaks_valid = false; // Line and word break flags are populated (and virtual zero width spaces inserted). + bool justification_ops_valid = false; // Virtual elongation glyphs are added to the string. + bool sort_valid = false; + + bool preserve_invalid = true; // Draw hex code box instead of missing characters. + bool preserve_control = false; // Draw control characters. + + float ascent = 0.f; // Ascent for horizontal layout, 1/2 of width for vertical. + float descent = 0.f; // Descent for horizontal layout, 1/2 of width for vertical. + float width = 0.f; // Width for horizontal layout, height for vertical. + + float upos = 0.f; + float uthk = 0.f; + + Vector<TextServer::Glyph> glyphs; + Vector<TextServer::Glyph> glyphs_logical; + }; + + struct BitmapFontData { + int height = 0; + int ascent = 0; + int charcount = 0; + const int *char_rects = nullptr; + int kerning_count = 0; + const int *kernings = nullptr; + int w = 0; + int h = 0; + const unsigned char *img = nullptr; + }; + +protected: + static void _bind_methods(); + + static Vector3 hex_code_box_font_size[2]; + static Ref<CanvasTexture> hex_code_box_font_tex[2]; + +public: + static void initialize_hex_code_box_fonts(); + static void finish_hex_code_box_fonts(); + + virtual bool has_feature(Feature p_feature) = 0; + virtual String get_name() const = 0; + + virtual void free(RID p_rid) = 0; + virtual bool has(RID p_rid) = 0; + virtual bool load_support_data(const String &p_filename) = 0; + +#ifdef TOOLS_ENABLED + virtual String get_support_data_filename() = 0; + virtual String get_support_data_info() = 0; + virtual bool save_support_data(const String &p_filename) = 0; +#endif + + virtual bool is_locale_right_to_left(const String &p_locale) = 0; + + virtual int32_t name_to_tag(const String &p_name) { return 0; }; + virtual String tag_to_name(int32_t p_tag) { return ""; }; + + /* Font interface */ + virtual RID create_font_system(const String &p_name, int p_base_size = 16) = 0; + virtual RID create_font_resource(const String &p_filename, int p_base_size = 16) = 0; + virtual RID create_font_memory(const uint8_t *p_data, size_t p_size, const String &p_type, int p_base_size = 16) = 0; + + virtual float font_get_height(RID p_font, int p_size) const = 0; + virtual float font_get_ascent(RID p_font, int p_size) const = 0; + virtual float font_get_descent(RID p_font, int p_size) const = 0; + + virtual int font_get_spacing_space(RID p_font) const = 0; + virtual void font_set_spacing_space(RID p_font, int p_value) = 0; + + virtual int font_get_spacing_glyph(RID p_font) const = 0; + virtual void font_set_spacing_glyph(RID p_font, int p_value) = 0; + + virtual float font_get_underline_position(RID p_font, int p_size) const = 0; + virtual float font_get_underline_thickness(RID p_font, int p_size) const = 0; + + virtual void font_set_antialiased(RID p_font, bool p_antialiased) = 0; + virtual bool font_get_antialiased(RID p_font) const = 0; + + virtual Dictionary font_get_feature_list(RID p_font) const { return Dictionary(); }; + virtual Dictionary font_get_variation_list(RID p_font) const { return Dictionary(); }; + + virtual void font_set_variation(RID p_font, const String &p_name, double p_value){}; + virtual double font_get_variation(RID p_font, const String &p_name) const { return 0; }; + + virtual void font_set_distance_field_hint(RID p_font, bool p_distance_field) = 0; + virtual bool font_get_distance_field_hint(RID p_font) const = 0; + + virtual void font_set_hinting(RID p_font, Hinting p_hinting) = 0; + virtual Hinting font_get_hinting(RID p_font) const = 0; + + virtual void font_set_force_autohinter(RID p_font, bool p_enabeld) = 0; + virtual bool font_get_force_autohinter(RID p_font) const = 0; + + virtual bool font_has_char(RID p_font, char32_t p_char) const = 0; + virtual String font_get_supported_chars(RID p_font) const = 0; + + virtual bool font_has_outline(RID p_font) const = 0; + virtual float font_get_base_size(RID p_font) const = 0; + + virtual bool font_is_language_supported(RID p_font, const String &p_language) const = 0; + virtual void font_set_language_support_override(RID p_font, const String &p_language, bool p_supported) = 0; + virtual bool font_get_language_support_override(RID p_font, const String &p_language) = 0; + virtual void font_remove_language_support_override(RID p_font, const String &p_language) = 0; + virtual Vector<String> font_get_language_support_overrides(RID p_font) = 0; + + virtual bool font_is_script_supported(RID p_font, const String &p_script) const = 0; + virtual void font_set_script_support_override(RID p_font, const String &p_script, bool p_supported) = 0; + virtual bool font_get_script_support_override(RID p_font, const String &p_script) = 0; + virtual void font_remove_script_support_override(RID p_font, const String &p_script) = 0; + virtual Vector<String> font_get_script_support_overrides(RID p_font) = 0; + + virtual uint32_t font_get_glyph_index(RID p_font, char32_t p_char, char32_t p_variation_selector = 0x0000) const = 0; + virtual Vector2 font_get_glyph_advance(RID p_font, uint32_t p_index, int p_size) const = 0; + virtual Vector2 font_get_glyph_kerning(RID p_font, uint32_t p_index_a, uint32_t p_index_b, int p_size) const = 0; + + virtual Vector2 font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const = 0; + virtual Vector2 font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const = 0; + + virtual float font_get_oversampling() const = 0; + virtual void font_set_oversampling(float p_oversampling) = 0; + + Vector2 get_hex_code_box_size(int p_size, char32_t p_index) const; + void draw_hex_code_box(RID p_canvas, int p_size, const Vector2 &p_pos, char32_t p_index, const Color &p_color) const; + + virtual Vector<String> get_system_fonts() const = 0; + + /* Shaped text buffer interface */ + + virtual RID create_shaped_text(Direction p_direction = DIRECTION_AUTO, Orientation p_orientation = ORIENTATION_HORIZONTAL) = 0; + + virtual void shaped_text_clear(RID p_shaped) = 0; + + virtual void shaped_text_set_direction(RID p_shaped, Direction p_direction = DIRECTION_AUTO) = 0; + virtual Direction shaped_text_get_direction(RID p_shaped) const = 0; + + virtual void shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) = 0; + + virtual void shaped_text_set_orientation(RID p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) = 0; + virtual Orientation shaped_text_get_orientation(RID p_shaped) const = 0; + + virtual void shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) = 0; + virtual bool shaped_text_get_preserve_invalid(RID p_shaped) const = 0; + + virtual void shaped_text_set_preserve_control(RID p_shaped, bool p_enabled) = 0; + virtual bool shaped_text_get_preserve_control(RID p_shaped) const = 0; + + virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "") = 0; + virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER, int p_length = 1) = 0; + virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER) = 0; + + virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const = 0; // Copy shaped substring (e.g. line break) without reshaping, but correctly reordered, preservers range. + virtual RID shaped_text_get_parent(RID p_shaped) const = 0; + + virtual float shaped_text_fit_to_width(RID p_shaped, float p_width, uint8_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) = 0; + virtual float shaped_text_tab_align(RID p_shaped, const Vector<float> &p_tab_stops) = 0; + + virtual bool shaped_text_shape(RID p_shaped) = 0; + virtual bool shaped_text_update_breaks(RID p_shaped) = 0; + virtual bool shaped_text_update_justification_ops(RID p_shaped) = 0; + + virtual bool shaped_text_is_ready(RID p_shaped) const = 0; + + virtual Vector<Glyph> shaped_text_get_glyphs(RID p_shaped) const = 0; + + virtual Vector2i shaped_text_get_range(RID p_shaped) const = 0; + + virtual Vector<Glyph> shaped_text_sort_logical(RID p_shaped) = 0; + + virtual Vector<Vector2i> shaped_text_get_line_breaks_adv(RID p_shaped, const Vector<float> &p_width, int p_start = 0, bool p_once = true, uint8_t /*TextBreakFlag*/ p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const; + virtual Vector<Vector2i> shaped_text_get_line_breaks(RID p_shaped, float p_width, int p_start = 0, uint8_t /*TextBreakFlag*/ p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const; + virtual Vector<Vector2i> shaped_text_get_word_breaks(RID p_shaped) const; + virtual Array shaped_text_get_objects(RID p_shaped) const = 0; + virtual Rect2 shaped_text_get_object_rect(RID p_shaped, Variant p_key) const = 0; + + virtual Size2 shaped_text_get_size(RID p_shaped) const = 0; + virtual float shaped_text_get_ascent(RID p_shaped) const = 0; + virtual float shaped_text_get_descent(RID p_shaped) const = 0; + virtual float shaped_text_get_width(RID p_shaped) const = 0; + virtual float shaped_text_get_underline_position(RID p_shaped) const = 0; + virtual float shaped_text_get_underline_thickness(RID p_shaped) const = 0; + + virtual Direction shaped_text_get_dominant_direciton_in_range(RID p_shaped, int p_start, int p_end) const; + + virtual void shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_leading_caret, Direction &p_leading_dir, Rect2 &p_trailing_caret, Direction &p_trailing_dir) const; + virtual Vector<Vector2> shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const; + + virtual int shaped_text_hit_test_grapheme(RID p_shaped, float p_coords) const; // Return grapheme index. + virtual int shaped_text_hit_test_position(RID p_shaped, float p_coords) const; // Return caret/selection position. + + virtual int shaped_text_next_grapheme_pos(RID p_shaped, int p_pos); + virtual int shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos); + + // The pen position is always placed on the baseline and moveing left to right. + virtual void shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l = -1.f, float p_clip_r = -1.f, const Color &p_color = Color(1, 1, 1)) const; + virtual void shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l = -1.f, float p_clip_r = -1.f, int p_outline_size = 1, const Color &p_color = Color(1, 1, 1)) const; + + // Number conversion. + virtual String format_number(const String &p_string, const String &p_language = "") const { return p_string; }; + virtual String parse_number(const String &p_string, const String &p_language = "") const { return p_string; }; + virtual String percent_sign(const String &p_language = "") const { return "%"; }; + + /* GDScript wrappers */ + RID _create_font_memory(const PackedByteArray &p_data, const String &p_type, int p_base_size = 16); + + Array _shaped_text_get_glyphs(RID p_shaped) const; + Dictionary _shaped_text_get_carets(RID p_shaped, int p_position) const; + + void _shaped_text_set_bidi_override(RID p_shaped, const Array &p_override); + + Array _shaped_text_get_line_breaks_adv(RID p_shaped, const PackedFloat32Array &p_width, int p_start, bool p_once, uint8_t p_break_flags) const; + Array _shaped_text_get_line_breaks(RID p_shaped, float p_width, int p_start, uint8_t p_break_flags) const; + Array _shaped_text_get_word_breaks(RID p_shaped) const; + + Array _shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const; + + TextServer(); + ~TextServer(); +}; + +/*************************************************************************/ + +class TextServerManager : public Object { + GDCLASS(TextServerManager, Object); + +public: + typedef TextServer *(*CreateFunction)(Error &r_error, void *p_user_data); + +protected: + static void _bind_methods(); + +private: + static TextServerManager *singleton; + static TextServer *server; + enum { + MAX_SERVERS = 64 + }; + + struct TextServerCreate { + String name; + CreateFunction create_function = nullptr; + uint32_t features = 0; + TextServer *instance = nullptr; + void *user_data = nullptr; + }; + + static TextServerCreate server_create_functions[MAX_SERVERS]; + static int server_create_count; + +public: + _FORCE_INLINE_ static TextServerManager *get_singleton() { + return singleton; + } + + static void register_create_function(const String &p_name, uint32_t p_features, CreateFunction p_function, void *p_user_data); + static int get_interface_count(); + static String get_interface_name(int p_index); + static uint32_t get_interface_features(int p_index); + static TextServer *initialize(int p_index, Error &r_error); + static TextServer *get_primary_interface(); + + /* GDScript wrappers */ + int _get_interface_count() const; + String _get_interface_name(int p_index) const; + uint32_t _get_interface_features(int p_index) const; + TextServer *_get_interface(int p_index) const; + Array _get_interfaces() const; + TextServer *_find_interface(const String &p_name) const; + + bool _set_primary_interface(int p_index); + TextServer *_get_primary_interface() const; + + TextServerManager(); + ~TextServerManager(); +}; + +/*************************************************************************/ + +#define TS TextServerManager::get_primary_interface() + +VARIANT_ENUM_CAST(TextServer::Direction); +VARIANT_ENUM_CAST(TextServer::Orientation); +VARIANT_ENUM_CAST(TextServer::JustificationFlag); +VARIANT_ENUM_CAST(TextServer::LineBreakFlag); +VARIANT_ENUM_CAST(TextServer::GraphemeFlag); +VARIANT_ENUM_CAST(TextServer::Hinting); +VARIANT_ENUM_CAST(TextServer::Feature); + +#endif // TEXT_SERVER_H diff --git a/servers/xr/xr_interface.cpp b/servers/xr/xr_interface.cpp index e9858416ec..9148631899 100644 --- a/servers/xr/xr_interface.cpp +++ b/servers/xr/xr_interface.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/xr/xr_interface.h b/servers/xr/xr_interface.h index 99fcef7925..8039018f35 100644 --- a/servers/xr/xr_interface.h +++ b/servers/xr/xr_interface.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -33,7 +33,6 @@ #include "core/math/camera_matrix.h" #include "core/os/thread_safe.h" -#include "scene/main/window.h" #include "servers/xr_server.h" /** diff --git a/servers/xr/xr_positional_tracker.cpp b/servers/xr/xr_positional_tracker.cpp index ad5cee92ea..5341390045 100644 --- a/servers/xr/xr_positional_tracker.cpp +++ b/servers/xr/xr_positional_tracker.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -34,25 +34,25 @@ void XRPositionalTracker::_bind_methods() { BIND_ENUM_CONSTANT(TRACKER_HAND_UNKNOWN); - BIND_ENUM_CONSTANT(TRACKER_LEFT_HAND); - BIND_ENUM_CONSTANT(TRACKER_RIGHT_HAND); + BIND_ENUM_CONSTANT(TRACKER_HAND_LEFT); + BIND_ENUM_CONSTANT(TRACKER_HAND_RIGHT); // this class is read only from GDScript, so we only have access to getters.. - ClassDB::bind_method(D_METHOD("get_type"), &XRPositionalTracker::get_type); + ClassDB::bind_method(D_METHOD("get_tracker_type"), &XRPositionalTracker::get_tracker_type); ClassDB::bind_method(D_METHOD("get_tracker_id"), &XRPositionalTracker::get_tracker_id); - ClassDB::bind_method(D_METHOD("get_name"), &XRPositionalTracker::get_name); + ClassDB::bind_method(D_METHOD("get_tracker_name"), &XRPositionalTracker::get_tracker_name); ClassDB::bind_method(D_METHOD("get_joy_id"), &XRPositionalTracker::get_joy_id); - ClassDB::bind_method(D_METHOD("get_tracks_orientation"), &XRPositionalTracker::get_tracks_orientation); + ClassDB::bind_method(D_METHOD("is_tracking_orientation"), &XRPositionalTracker::is_tracking_orientation); ClassDB::bind_method(D_METHOD("get_orientation"), &XRPositionalTracker::get_orientation); - ClassDB::bind_method(D_METHOD("get_tracks_position"), &XRPositionalTracker::get_tracks_position); + ClassDB::bind_method(D_METHOD("is_tracking_position"), &XRPositionalTracker::is_tracking_position); ClassDB::bind_method(D_METHOD("get_position"), &XRPositionalTracker::get_position); - ClassDB::bind_method(D_METHOD("get_hand"), &XRPositionalTracker::get_hand); + ClassDB::bind_method(D_METHOD("get_tracker_hand"), &XRPositionalTracker::get_tracker_hand); ClassDB::bind_method(D_METHOD("get_transform", "adjust_by_reference_frame"), &XRPositionalTracker::get_transform); ClassDB::bind_method(D_METHOD("get_mesh"), &XRPositionalTracker::get_mesh); // these functions we don't want to expose to normal users but do need to be callable from GDNative - ClassDB::bind_method(D_METHOD("_set_type", "type"), &XRPositionalTracker::set_type); - ClassDB::bind_method(D_METHOD("_set_name", "name"), &XRPositionalTracker::set_name); + ClassDB::bind_method(D_METHOD("_set_tracker_type", "type"), &XRPositionalTracker::set_tracker_type); + ClassDB::bind_method(D_METHOD("_set_tracker_name", "name"), &XRPositionalTracker::set_tracker_name); ClassDB::bind_method(D_METHOD("_set_joy_id", "joy_id"), &XRPositionalTracker::set_joy_id); ClassDB::bind_method(D_METHOD("_set_orientation", "orientation"), &XRPositionalTracker::set_orientation); ClassDB::bind_method(D_METHOD("_set_rw_position", "rw_position"), &XRPositionalTracker::set_rw_position); @@ -63,7 +63,7 @@ void XRPositionalTracker::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rumble"), "set_rumble", "get_rumble"); }; -void XRPositionalTracker::set_type(XRServer::TrackerType p_type) { +void XRPositionalTracker::set_tracker_type(XRServer::TrackerType p_type) { if (type != p_type) { type = p_type; hand = XRPositionalTracker::TRACKER_HAND_UNKNOWN; @@ -77,15 +77,15 @@ void XRPositionalTracker::set_type(XRServer::TrackerType p_type) { }; }; -XRServer::TrackerType XRPositionalTracker::get_type() const { +XRServer::TrackerType XRPositionalTracker::get_tracker_type() const { return type; }; -void XRPositionalTracker::set_name(const String &p_name) { +void XRPositionalTracker::set_tracker_name(const String &p_name) { name = p_name; }; -StringName XRPositionalTracker::get_name() const { +StringName XRPositionalTracker::get_tracker_name() const { return name; }; @@ -101,14 +101,14 @@ int XRPositionalTracker::get_joy_id() const { return joy_id; }; -bool XRPositionalTracker::get_tracks_orientation() const { - return tracks_orientation; +bool XRPositionalTracker::is_tracking_orientation() const { + return tracking_orientation; }; void XRPositionalTracker::set_orientation(const Basis &p_orientation) { _THREAD_SAFE_METHOD_ - tracks_orientation = true; // obviously we have this + tracking_orientation = true; // obviously we have this orientation = p_orientation; }; @@ -118,8 +118,8 @@ Basis XRPositionalTracker::get_orientation() const { return orientation; }; -bool XRPositionalTracker::get_tracks_position() const { - return tracks_position; +bool XRPositionalTracker::is_tracking_position() const { + return tracking_position; }; void XRPositionalTracker::set_position(const Vector3 &p_position) { @@ -130,7 +130,7 @@ void XRPositionalTracker::set_position(const Vector3 &p_position) { real_t world_scale = xr_server->get_world_scale(); ERR_FAIL_COND(world_scale == 0); - tracks_position = true; // obviously we have this + tracking_position = true; // obviously we have this rw_position = p_position / world_scale; }; @@ -147,7 +147,7 @@ Vector3 XRPositionalTracker::get_position() const { void XRPositionalTracker::set_rw_position(const Vector3 &p_rw_position) { _THREAD_SAFE_METHOD_ - tracks_position = true; // obviously we have this + tracking_position = true; // obviously we have this rw_position = p_rw_position; }; @@ -169,11 +169,11 @@ Ref<Mesh> XRPositionalTracker::get_mesh() const { return mesh; }; -XRPositionalTracker::TrackerHand XRPositionalTracker::get_hand() const { +XRPositionalTracker::TrackerHand XRPositionalTracker::get_tracker_hand() const { return hand; }; -void XRPositionalTracker::set_hand(const XRPositionalTracker::TrackerHand p_hand) { +void XRPositionalTracker::set_tracker_hand(const XRPositionalTracker::TrackerHand p_hand) { XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL(xr_server); @@ -182,11 +182,11 @@ void XRPositionalTracker::set_hand(const XRPositionalTracker::TrackerHand p_hand ERR_FAIL_COND((type != XRServer::TRACKER_CONTROLLER) && (p_hand != XRPositionalTracker::TRACKER_HAND_UNKNOWN)); hand = p_hand; - if (hand == XRPositionalTracker::TRACKER_LEFT_HAND) { + if (hand == XRPositionalTracker::TRACKER_HAND_LEFT) { if (!xr_server->is_tracker_id_in_use_for_type(type, 1)) { tracker_id = 1; }; - } else if (hand == XRPositionalTracker::TRACKER_RIGHT_HAND) { + } else if (hand == XRPositionalTracker::TRACKER_HAND_RIGHT) { if (!xr_server->is_tracker_id_in_use_for_type(type, 2)) { tracker_id = 2; }; @@ -227,8 +227,8 @@ XRPositionalTracker::XRPositionalTracker() { name = "Unknown"; joy_id = -1; tracker_id = 0; - tracks_orientation = false; - tracks_position = false; + tracking_orientation = false; + tracking_position = false; hand = TRACKER_HAND_UNKNOWN; rumble = 0.0; }; diff --git a/servers/xr/xr_positional_tracker.h b/servers/xr/xr_positional_tracker.h index 515359e9b1..420d818342 100644 --- a/servers/xr/xr_positional_tracker.h +++ b/servers/xr/xr_positional_tracker.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -50,8 +50,8 @@ class XRPositionalTracker : public Object { public: enum TrackerHand { TRACKER_HAND_UNKNOWN, /* unknown or not applicable */ - TRACKER_LEFT_HAND, /* controller is the left hand controller */ - TRACKER_RIGHT_HAND /* controller is the right hand controller */ + TRACKER_HAND_LEFT, /* controller is the left hand controller */ + TRACKER_HAND_RIGHT /* controller is the right hand controller */ }; private: @@ -59,9 +59,9 @@ private: StringName name; // (unique) name of the tracker int tracker_id; // tracker index id that is unique per type int joy_id; // if we also have a related joystick entity, the id of the joystick - bool tracks_orientation; // do we track orientation? + bool tracking_orientation; // do we track orientation? Basis orientation; // our orientation - bool tracks_position; // do we track position? + bool tracking_position; // do we track position? Vector3 rw_position; // our position "in the real world, so without world_scale applied" Ref<Mesh> mesh; // when available, a mesh that can be used to render this tracker TrackerHand hand; // if known, the hand this tracker is held in @@ -71,23 +71,23 @@ protected: static void _bind_methods(); public: - void set_type(XRServer::TrackerType p_type); - XRServer::TrackerType get_type() const; - void set_name(const String &p_name); - StringName get_name() const; + void set_tracker_type(XRServer::TrackerType p_type); + XRServer::TrackerType get_tracker_type() const; + void set_tracker_name(const String &p_name); + StringName get_tracker_name() const; int get_tracker_id() const; void set_joy_id(int p_joy_id); int get_joy_id() const; - bool get_tracks_orientation() const; + bool is_tracking_orientation() const; void set_orientation(const Basis &p_orientation); Basis get_orientation() const; - bool get_tracks_position() const; + bool is_tracking_position() const; void set_position(const Vector3 &p_position); // set position with world_scale applied Vector3 get_position() const; // get position with world_scale applied void set_rw_position(const Vector3 &p_rw_position); Vector3 get_rw_position() const; - XRPositionalTracker::TrackerHand get_hand() const; - void set_hand(const XRPositionalTracker::TrackerHand p_hand); + XRPositionalTracker::TrackerHand get_tracker_hand() const; + void set_tracker_hand(const XRPositionalTracker::TrackerHand p_hand); real_t get_rumble() const; void set_rumble(real_t p_rumble); void set_mesh(const Ref<Mesh> &p_mesh); diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp index 45199edd24..2acc2e398c 100644 --- a/servers/xr_server.cpp +++ b/servers/xr_server.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -235,7 +235,7 @@ Array XRServer::get_interfaces() const { bool XRServer::is_tracker_id_in_use_for_type(TrackerType p_tracker_type, int p_tracker_id) const { for (int i = 0; i < trackers.size(); i++) { - if (trackers[i]->get_type() == p_tracker_type && trackers[i]->get_tracker_id() == p_tracker_id) { + if (trackers[i]->get_tracker_type() == p_tracker_type && trackers[i]->get_tracker_id() == p_tracker_id) { return true; }; }; @@ -264,7 +264,7 @@ void XRServer::add_tracker(XRPositionalTracker *p_tracker) { ERR_FAIL_NULL(p_tracker); trackers.push_back(p_tracker); - emit_signal("tracker_added", p_tracker->get_name(), p_tracker->get_type(), p_tracker->get_tracker_id()); + emit_signal("tracker_added", p_tracker->get_tracker_name(), p_tracker->get_tracker_type(), p_tracker->get_tracker_id()); }; void XRServer::remove_tracker(XRPositionalTracker *p_tracker) { @@ -280,7 +280,7 @@ void XRServer::remove_tracker(XRPositionalTracker *p_tracker) { ERR_FAIL_COND(idx == -1); - emit_signal("tracker_removed", p_tracker->get_name(), p_tracker->get_type(), p_tracker->get_tracker_id()); + emit_signal("tracker_removed", p_tracker->get_tracker_name(), p_tracker->get_tracker_type(), p_tracker->get_tracker_id()); trackers.remove(idx); }; @@ -298,7 +298,7 @@ XRPositionalTracker *XRServer::find_by_type_and_id(TrackerType p_tracker_type, i ERR_FAIL_COND_V(p_tracker_id == 0, nullptr); for (int i = 0; i < trackers.size(); i++) { - if (trackers[i]->get_type() == p_tracker_type && trackers[i]->get_tracker_id() == p_tracker_id) { + if (trackers[i]->get_tracker_type() == p_tracker_type && trackers[i]->get_tracker_id() == p_tracker_id) { return trackers[i]; }; }; @@ -336,7 +336,7 @@ uint64_t XRServer::get_last_frame_usec() { }; void XRServer::_process() { - /* called from rendering_server_viewport.draw_viewports right before we start drawing our viewports */ + /* called from renderer_viewport.draw_viewports right before we start drawing our viewports */ /* mark for our frame timing */ last_process_usec = OS::get_singleton()->get_ticks_usec(); diff --git a/servers/xr_server.h b/servers/xr_server.h index d66d4e778a..d3972be838 100644 --- a/servers/xr_server.h +++ b/servers/xr_server.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ |